Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 9 additions & 2 deletions src/nanoarrow/ipc/decoder.c
Original file line number Diff line number Diff line change
Expand Up @@ -1612,15 +1612,22 @@ static inline int ArrowIpcDecoderReadHeaderPrefix(struct ArrowIpcDecoder* decode
length = ArrowIpcReadInt32LE(data_mut, swap_endian);
*prefix_size_bytes = sizeof(continuation) + sizeof(length);
}
decoder->header_size_bytes = *prefix_size_bytes + length;

if (length < 0) {
ArrowErrorSet(error,
"Expected message size > 0 but found message size of %" PRId32 " bytes",
length);
return EINVAL;
}

// The prefix and the message size must together fit in header_size_bytes
if (length > INT32_MAX - *prefix_size_bytes) {
ArrowErrorSet(error, "Expected message size <= %" PRId32 " but found %" PRId32,
INT32_MAX - *prefix_size_bytes, length);
return EINVAL;
}

decoder->header_size_bytes = *prefix_size_bytes + length;

if (length == 0) {
ArrowErrorSet(error, "End of Arrow stream");
return ENODATA;
Expand Down
34 changes: 34 additions & 0 deletions src/nanoarrow/ipc/decoder_test.cc
Original file line number Diff line number Diff line change
Expand Up @@ -371,6 +371,40 @@ TEST(NanoarrowIpcTest, NanoarrowIpcCheckHeader) {
ArrowIpcDecoderReset(&decoder);
}

TEST(NanoarrowIpcTest, NanoarrowIpcCheckHeaderSizeOverflow) {
struct ArrowIpcDecoder decoder;
struct ArrowError error;

uint32_t int32_max_le = INT32_MAX;
uint32_t pre_015_max_le = INT32_MAX - 3;
if (ArrowIpcSystemEndianness() == NANOARROW_IPC_ENDIANNESS_BIG) {
int32_max_le = bswap32(int32_max_le);
pre_015_max_le = bswap32(pre_015_max_le);
}

int32_t prefix_size_bytes;
ArrowIpcDecoderInit(&decoder);

// A message size whose sum with the 8-byte prefix overflows int32_t
uint32_t continued[] = {0xFFFFFFFF, int32_max_le};
struct ArrowBufferView data;
data.data.as_uint32 = continued;
data.size_bytes = sizeof(continued);
EXPECT_EQ(ArrowIpcDecoderPeekHeader(&decoder, data, &prefix_size_bytes, &error),
EINVAL);
EXPECT_STREQ(error.message, "Expected message size <= 2147483639 but found 2147483647");

// A pre-0.15 message with only the 4-byte length prefix
uint32_t legacy[] = {pre_015_max_le, 0};
data.data.as_uint32 = legacy;
data.size_bytes = sizeof(legacy);
EXPECT_EQ(ArrowIpcDecoderPeekHeader(&decoder, data, &prefix_size_bytes, &error),
EINVAL);
EXPECT_STREQ(error.message, "Expected message size <= 2147483643 but found 2147483644");

ArrowIpcDecoderReset(&decoder);
}

TEST(NanoarrowIpcTest, NanoarrowIpcPeekSimpleSchema) {
struct ArrowIpcDecoder decoder;
struct ArrowError error;
Expand Down