LuciferYang opened a new issue, #9617:
URL: https://github.com/apache/paimon/issues/9617

   ### Search before asking
   
   - [x] I searched in the [issues](https://github.com/apache/paimon/issues) 
and found nothing similar.
   
   ### Paimon version
   
   master, `475be566f` (2.1-SNAPSHOT).
   
   ### Compute Engine
   
   Spark and Flink. `descriptor_to_string` and `descriptor_to_presigned_url` 
are registered scalar functions over `BINARY`, so the bytes come straight from 
the query; the same code also runs when a blob column's descriptor is read back 
through `Blob.fromBytes` or `FlinkRowWrapper`.
   
   ### Minimal reproduce step
   
   Take a valid video-frame descriptor and overwrite its 4-byte URI length 
field with a value near `Integer.MAX_VALUE`:
   
   ```java
   VideoFrameDescriptor descriptor = new 
VideoFrameDescriptor("file:/video.mp4", 0, 9, 7);
   byte[] bytes = descriptor.serialize();
   ByteBuffer.wrap(bytes)
           .order(ByteOrder.LITTLE_ENDIAN)
           .putInt(Byte.BYTES + Long.BYTES, Integer.MAX_VALUE - 23);
   VideoFrameDescriptor.deserialize(bytes);
   ```
   
   This throws `OutOfMemoryError: Java heap space` on a default heap, and on a 
large enough heap it allocates a 2GB array and then fails with 
`BufferUnderflowException`. Through SQL the same thing happens on an executor 
for `SELECT descriptor_to_string(<those bytes>)`.
   
   The length check adds before it compares:
   
   ```java
   int uriLength = buffer.getInt();
   if (uriLength < 0 || buffer.remaining() < uriLength + 3 * Long.BYTES) {
       throw invalidPayload("invalid URI length: " + uriLength);
   }
   
   byte[] uriBytes = new byte[uriLength];
   ```
   
   With `uriLength = Integer.MAX_VALUE - 23`, `uriLength + 24` wraps to 
`Integer.MIN_VALUE`, so `buffer.remaining() < Integer.MIN_VALUE` is false and 
the check passes. `new byte[uriLength]` then tries to allocate the array.
   
   ### What doesn't meet your expectations?
   
   Malformed descriptor bytes should be rejected with the 
`IllegalArgumentException` that every other malformed case in this method 
produces, not with an `OutOfMemoryError` from a 2GB allocation.
   
   The sibling `BlobDescriptor.deserialize`, which dispatches to this one by 
magic number, already gets this right and validates by subtraction with one 
message per case:
   
   ```java
   if (uriLength < 0) {
       throw invalidPayload("negative URI length: " + uriLength);
   }
   if (uriLength > buffer.remaining()) {
       throw invalidPayload("URI length exceeds data size");
   }
   if (buffer.remaining() - uriLength < Long.BYTES + Long.BYTES) {
       throw invalidPayload("missing offset/length");
   }
   ```
   
   `VideoFrameDescriptor` is the one of the two that folded all three into a 
single addition.
   
   ### Anything else?
   
   Nothing in the write path produces a `uriLength` like this, so reaching it 
needs either crafted input to one of the descriptor functions or a corrupted 
blob column.
   
   ### Are you willing to submit a PR?
   
   - [x] I'm willing to submit a PR!
   


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: [email protected]

For queries about this service, please contact Infrastructure at:
[email protected]

Reply via email to