You are viewing a plain text version of this content. The canonical link for it is here.
Posted to github@arrow.apache.org by "jmestwa-coder (via GitHub)" <gi...@apache.org> on 2026/05/23 10:33:37 UTC

[PR] MINOR: [C++][Parquet] Reject too-short statistics values in FormatStatValue [arrow]

jmestwa-coder opened a new pull request, #50025:
URL: https://github.com/apache/arrow/pull/50025

   FormatStatValue in cpp/src/parquet/types.cc memcpys sizeof(physical_type) bytes from a string_view that comes straight out of the Thrift statistics block, so a crafted file with min_value or max_value shorter than the column's width (for example, a zero-byte stat on an INT96 column) reads past the buffer. The check belongs in this callee since callers in printer.cc just forward whatever the metadata holds. New ASSERT_THROW coverage in types_test.cc exercises the short-value paths for BOOLEAN, INT32, INT64, FLOAT, DOUBLE, INT96, Decimal and Float16.


-- 
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: github-unsubscribe@arrow.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


Re: [PR] GH-50184: [C++][Parquet] Reject too-short statistics values in FormatStatValue [arrow]

Posted by "wgtmac (via GitHub)" <gi...@apache.org>.
wgtmac commented on code in PR #50025:
URL: https://github.com/apache/arrow/pull/50025#discussion_r3417721291


##########
cpp/src/parquet/types.cc:
##########
@@ -184,6 +184,43 @@ std::string FormatFloat16Value(::std::string_view val) {
 
 std::string FormatStatValue(Type::type parquet_type, ::std::string_view val,
                             const std::shared_ptr<const LogicalType>& logical_type) {
+  // Statistics blobs come from the file's Thrift-encoded metadata and may have
+  // arbitrary length under a malicious writer. Reject any value that is shorter
+  // than what the physical (and, for FLOAT16, logical) type requires so the
+  // memcpy/byte loads below cannot run past the buffer.
+  size_t required = 0;
+  switch (parquet_type) {
+    case Type::BOOLEAN:
+      required = sizeof(bool);
+      break;
+    case Type::INT32:
+    case Type::FLOAT:
+      required = 4;
+      break;
+    case Type::INT64:
+    case Type::DOUBLE:
+      required = 8;
+      break;
+    case Type::INT96:
+      required = 3 * sizeof(int32_t);
+      break;
+    case Type::BYTE_ARRAY:
+    case Type::FIXED_LEN_BYTE_ARRAY:
+      if (logical_type != nullptr && logical_type->is_float16()) {
+        required = 2;
+      }
+      break;
+    case Type::UNDEFINED:
+    default:
+      break;
+  }
+  if (val.size() < required) {

Review Comment:
   (I thought I have posted the above comment but it was a draft before I just posted it just now)



-- 
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: github-unsubscribe@arrow.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


Re: [PR] MINOR: [C++][Parquet] Reject too-short statistics values in FormatStatValue [arrow]

Posted by "wgtmac (via GitHub)" <gi...@apache.org>.
wgtmac commented on code in PR #50025:
URL: https://github.com/apache/arrow/pull/50025#discussion_r3308017566


##########
cpp/src/parquet/types.cc:
##########
@@ -184,6 +184,43 @@ std::string FormatFloat16Value(::std::string_view val) {
 
 std::string FormatStatValue(Type::type parquet_type, ::std::string_view val,
                             const std::shared_ptr<const LogicalType>& logical_type) {
+  // Statistics blobs come from the file's Thrift-encoded metadata and may have
+  // arbitrary length under a malicious writer. Reject any value that is shorter
+  // than what the physical (and, for FLOAT16, logical) type requires so the
+  // memcpy/byte loads below cannot run past the buffer.
+  size_t required = 0;
+  switch (parquet_type) {
+    case Type::BOOLEAN:
+      required = sizeof(bool);
+      break;
+    case Type::INT32:
+    case Type::FLOAT:
+      required = 4;
+      break;
+    case Type::INT64:
+    case Type::DOUBLE:
+      required = 8;
+      break;
+    case Type::INT96:
+      required = 3 * sizeof(int32_t);
+      break;
+    case Type::BYTE_ARRAY:
+    case Type::FIXED_LEN_BYTE_ARRAY:
+      if (logical_type != nullptr && logical_type->is_float16()) {

Review Comment:
   I admit that it is better than nothing to check types with known sizes. It still looks confusing with this partial support. If we do want to add the check, I think we need to support all types. We can either pass the type instance instead of only the enum or pass the type length to `FormatStatValue`. The challenge is that `FormatStatValue` is a public API so we cannot changing its signature without breaking backward compatibility.



##########
cpp/src/parquet/types.cc:
##########
@@ -184,6 +184,43 @@ std::string FormatFloat16Value(::std::string_view val) {
 
 std::string FormatStatValue(Type::type parquet_type, ::std::string_view val,
                             const std::shared_ptr<const LogicalType>& logical_type) {
+  // Statistics blobs come from the file's Thrift-encoded metadata and may have
+  // arbitrary length under a malicious writer. Reject any value that is shorter
+  // than what the physical (and, for FLOAT16, logical) type requires so the
+  // memcpy/byte loads below cannot run past the buffer.
+  size_t required = 0;
+  switch (parquet_type) {
+    case Type::BOOLEAN:
+      required = sizeof(bool);
+      break;
+    case Type::INT32:
+    case Type::FLOAT:
+      required = 4;
+      break;
+    case Type::INT64:
+    case Type::DOUBLE:
+      required = 8;
+      break;
+    case Type::INT96:
+      required = 3 * sizeof(int32_t);
+      break;
+    case Type::BYTE_ARRAY:
+    case Type::FIXED_LEN_BYTE_ARRAY:
+      if (logical_type != nullptr && logical_type->is_float16()) {

Review Comment:
   BTW, we need to create an issue for changes like this.



-- 
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: github-unsubscribe@arrow.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


Re: [PR] GH-50184: [C++][Parquet] Avoid reading past truncated statistics values in FormatStatValue [arrow]

Posted by "jmestwa-coder (via GitHub)" <gi...@apache.org>.
jmestwa-coder commented on code in PR #50025:
URL: https://github.com/apache/arrow/pull/50025#discussion_r3422000122


##########
cpp/src/parquet/types.cc:
##########
@@ -184,6 +184,43 @@ std::string FormatFloat16Value(::std::string_view val) {
 
 std::string FormatStatValue(Type::type parquet_type, ::std::string_view val,
                             const std::shared_ptr<const LogicalType>& logical_type) {
+  // Statistics blobs come from the file's Thrift-encoded metadata and may have
+  // arbitrary length under a malicious writer. Reject any value that is shorter
+  // than what the physical (and, for FLOAT16, logical) type requires so the
+  // memcpy/byte loads below cannot run past the buffer.
+  size_t required = 0;
+  switch (parquet_type) {
+    case Type::BOOLEAN:
+      required = sizeof(bool);
+      break;
+    case Type::INT32:
+    case Type::FLOAT:
+      required = 4;
+      break;
+    case Type::INT64:
+    case Type::DOUBLE:
+      required = 8;
+      break;
+    case Type::INT96:
+      required = 3 * sizeof(int32_t);
+      break;
+    case Type::BYTE_ARRAY:
+    case Type::FIXED_LEN_BYTE_ARRAY:
+      if (logical_type != nullptr && logical_type->is_float16()) {
+        required = 2;
+      }
+      break;
+    case Type::UNDEFINED:
+    default:
+      break;
+  }
+  if (val.size() < required) {

Review Comment:
   switched to clamping each fixed-width read to val.size() rather than the required-length table, so every over-reading path is covered without touching the public signature, and there's no throw since truncated stats are valid.



-- 
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: github-unsubscribe@arrow.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


Re: [PR] MINOR: [C++][Parquet] Reject too-short statistics values in FormatStatValue [arrow]

Posted by "jmestwa-coder (via GitHub)" <gi...@apache.org>.
jmestwa-coder commented on code in PR #50025:
URL: https://github.com/apache/arrow/pull/50025#discussion_r3306345360


##########
cpp/src/parquet/types.cc:
##########
@@ -184,6 +184,43 @@ std::string FormatFloat16Value(::std::string_view val) {
 
 std::string FormatStatValue(Type::type parquet_type, ::std::string_view val,
                             const std::shared_ptr<const LogicalType>& logical_type) {
+  // Statistics blobs come from the file's Thrift-encoded metadata and may have
+  // arbitrary length under a malicious writer. Reject any value that is shorter
+  // than what the physical (and, for FLOAT16, logical) type requires so the
+  // memcpy/byte loads below cannot run past the buffer.
+  size_t required = 0;
+  switch (parquet_type) {
+    case Type::BOOLEAN:
+      required = sizeof(bool);
+      break;
+    case Type::INT32:
+    case Type::FLOAT:
+      required = 4;
+      break;
+    case Type::INT64:
+    case Type::DOUBLE:
+      required = 8;
+      break;
+    case Type::INT96:
+      required = 3 * sizeof(int32_t);
+      break;
+    case Type::BYTE_ARRAY:

Review Comment:
   Good point. Moved BYTE_ARRAY down with UNDEFINED since it can't carry a float16 logical type and has no fixed-width load here anyway.



##########
cpp/src/parquet/types.cc:
##########
@@ -184,6 +184,43 @@ std::string FormatFloat16Value(::std::string_view val) {
 
 std::string FormatStatValue(Type::type parquet_type, ::std::string_view val,
                             const std::shared_ptr<const LogicalType>& logical_type) {
+  // Statistics blobs come from the file's Thrift-encoded metadata and may have
+  // arbitrary length under a malicious writer. Reject any value that is shorter
+  // than what the physical (and, for FLOAT16, logical) type requires so the
+  // memcpy/byte loads below cannot run past the buffer.
+  size_t required = 0;
+  switch (parquet_type) {
+    case Type::BOOLEAN:
+      required = sizeof(bool);
+      break;
+    case Type::INT32:
+    case Type::FLOAT:
+      required = 4;
+      break;
+    case Type::INT64:
+    case Type::DOUBLE:
+      required = 8;
+      break;
+    case Type::INT96:
+      required = 3 * sizeof(int32_t);
+      break;
+    case Type::BYTE_ARRAY:
+    case Type::FIXED_LEN_BYTE_ARRAY:
+      if (logical_type != nullptr && logical_type->is_float16()) {

Review Comment:
   FormatStatValue doesn't receive the column's type_length, so it can't validate the full FLBA width here. The only fixed-size read for FLBA is the 2-byte float16 load, which is what this case guards. The decimal, string and hex paths all key off val.size() and stay in bounds.



##########
cpp/src/parquet/types.cc:
##########
@@ -184,6 +184,43 @@ std::string FormatFloat16Value(::std::string_view val) {
 
 std::string FormatStatValue(Type::type parquet_type, ::std::string_view val,
                             const std::shared_ptr<const LogicalType>& logical_type) {
+  // Statistics blobs come from the file's Thrift-encoded metadata and may have
+  // arbitrary length under a malicious writer. Reject any value that is shorter
+  // than what the physical (and, for FLOAT16, logical) type requires so the
+  // memcpy/byte loads below cannot run past the buffer.
+  size_t required = 0;
+  switch (parquet_type) {
+    case Type::BOOLEAN:
+      required = sizeof(bool);
+      break;
+    case Type::INT32:
+    case Type::FLOAT:
+      required = 4;
+      break;
+    case Type::INT64:
+    case Type::DOUBLE:
+      required = 8;
+      break;
+    case Type::INT96:
+      required = 3 * sizeof(int32_t);
+      break;
+    case Type::BYTE_ARRAY:
+    case Type::FIXED_LEN_BYTE_ARRAY:
+      if (logical_type != nullptr && logical_type->is_float16()) {
+        required = 2;
+      }
+      break;
+    case Type::UNDEFINED:
+    default:
+      break;
+  }
+  if (val.size() < required) {

Review Comment:
   Fair, it's mostly the debug/printer path. The thing is val is taken verbatim from the file's Thrift stats, so a truncated min/max makes the BOOLEAN/INT96/numeric memcpys read past the end of the buffer even there. The guard is just a size check in front of the existing loads, so I tried to keep it minimal. Happy to trim it further if it still feels too heavy.



-- 
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: github-unsubscribe@arrow.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


Re: [PR] GH-50184: [C++][Parquet] Reject too-short statistics values in FormatStatValue [arrow]

Posted by "wgtmac (via GitHub)" <gi...@apache.org>.
wgtmac commented on code in PR #50025:
URL: https://github.com/apache/arrow/pull/50025#discussion_r3417718975


##########
cpp/src/parquet/types.cc:
##########
@@ -184,6 +184,43 @@ std::string FormatFloat16Value(::std::string_view val) {
 
 std::string FormatStatValue(Type::type parquet_type, ::std::string_view val,
                             const std::shared_ptr<const LogicalType>& logical_type) {
+  // Statistics blobs come from the file's Thrift-encoded metadata and may have
+  // arbitrary length under a malicious writer. Reject any value that is shorter
+  // than what the physical (and, for FLOAT16, logical) type requires so the
+  // memcpy/byte loads below cannot run past the buffer.
+  size_t required = 0;
+  switch (parquet_type) {
+    case Type::BOOLEAN:
+      required = sizeof(bool);
+      break;
+    case Type::INT32:
+    case Type::FLOAT:
+      required = 4;
+      break;
+    case Type::INT64:
+    case Type::DOUBLE:
+      required = 8;
+      break;
+    case Type::INT96:
+      required = 3 * sizeof(int32_t);
+      break;
+    case Type::BYTE_ARRAY:
+    case Type::FIXED_LEN_BYTE_ARRAY:
+      if (logical_type != nullptr && logical_type->is_float16()) {
+        required = 2;
+      }
+      break;
+    case Type::UNDEFINED:
+    default:
+      break;
+  }
+  if (val.size() < required) {

Review Comment:
   I admit that it is better than nothing to check types with known sizes. It still looks confusing with this partial support. If we do want to add the check, I think we need to support all types. We can either pass the type instance instead of only the enum or pass the type length to `FormatStatValue`. The challenge is that `FormatStatValue` is a public API so we cannot changing its signature without breaking backward compatibility.



-- 
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: github-unsubscribe@arrow.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


Re: [PR] GH-50184: [C++][Parquet] Reject too-short statistics values in FormatStatValue [arrow]

Posted by "wgtmac (via GitHub)" <gi...@apache.org>.
wgtmac commented on code in PR #50025:
URL: https://github.com/apache/arrow/pull/50025#discussion_r3417721291


##########
cpp/src/parquet/types.cc:
##########
@@ -184,6 +184,43 @@ std::string FormatFloat16Value(::std::string_view val) {
 
 std::string FormatStatValue(Type::type parquet_type, ::std::string_view val,
                             const std::shared_ptr<const LogicalType>& logical_type) {
+  // Statistics blobs come from the file's Thrift-encoded metadata and may have
+  // arbitrary length under a malicious writer. Reject any value that is shorter
+  // than what the physical (and, for FLOAT16, logical) type requires so the
+  // memcpy/byte loads below cannot run past the buffer.
+  size_t required = 0;
+  switch (parquet_type) {
+    case Type::BOOLEAN:
+      required = sizeof(bool);
+      break;
+    case Type::INT32:
+    case Type::FLOAT:
+      required = 4;
+      break;
+    case Type::INT64:
+    case Type::DOUBLE:
+      required = 8;
+      break;
+    case Type::INT96:
+      required = 3 * sizeof(int32_t);
+      break;
+    case Type::BYTE_ARRAY:
+    case Type::FIXED_LEN_BYTE_ARRAY:
+      if (logical_type != nullptr && logical_type->is_float16()) {
+        required = 2;
+      }
+      break;
+    case Type::UNDEFINED:
+    default:
+      break;
+  }
+  if (val.size() < required) {

Review Comment:
   (I thought I have posted the above comment but it was a draft before I posted it just now)



-- 
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: github-unsubscribe@arrow.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


Re: [PR] MINOR: [C++][Parquet] Reject too-short statistics values in FormatStatValue [arrow]

Posted by "wgtmac (via GitHub)" <gi...@apache.org>.
wgtmac commented on code in PR #50025:
URL: https://github.com/apache/arrow/pull/50025#discussion_r3294219441


##########
cpp/src/parquet/types.cc:
##########
@@ -184,6 +184,43 @@ std::string FormatFloat16Value(::std::string_view val) {
 
 std::string FormatStatValue(Type::type parquet_type, ::std::string_view val,
                             const std::shared_ptr<const LogicalType>& logical_type) {
+  // Statistics blobs come from the file's Thrift-encoded metadata and may have
+  // arbitrary length under a malicious writer. Reject any value that is shorter
+  // than what the physical (and, for FLOAT16, logical) type requires so the
+  // memcpy/byte loads below cannot run past the buffer.
+  size_t required = 0;
+  switch (parquet_type) {
+    case Type::BOOLEAN:
+      required = sizeof(bool);
+      break;
+    case Type::INT32:
+    case Type::FLOAT:
+      required = 4;
+      break;
+    case Type::INT64:
+    case Type::DOUBLE:
+      required = 8;
+      break;
+    case Type::INT96:
+      required = 3 * sizeof(int32_t);
+      break;
+    case Type::BYTE_ARRAY:
+    case Type::FIXED_LEN_BYTE_ARRAY:
+      if (logical_type != nullptr && logical_type->is_float16()) {
+        required = 2;
+      }
+      break;
+    case Type::UNDEFINED:
+    default:
+      break;
+  }
+  if (val.size() < required) {

Review Comment:
   I'm a little hesitant to complicate `FormatStatValue` by introducing this check. `FormatStatValue` is usually called in the printer when we want to print some information of a parquet file for debugging purpuse.



##########
cpp/src/parquet/types.cc:
##########
@@ -184,6 +184,43 @@ std::string FormatFloat16Value(::std::string_view val) {
 
 std::string FormatStatValue(Type::type parquet_type, ::std::string_view val,
                             const std::shared_ptr<const LogicalType>& logical_type) {
+  // Statistics blobs come from the file's Thrift-encoded metadata and may have
+  // arbitrary length under a malicious writer. Reject any value that is shorter
+  // than what the physical (and, for FLOAT16, logical) type requires so the
+  // memcpy/byte loads below cannot run past the buffer.
+  size_t required = 0;
+  switch (parquet_type) {
+    case Type::BOOLEAN:
+      required = sizeof(bool);
+      break;
+    case Type::INT32:
+    case Type::FLOAT:
+      required = 4;
+      break;
+    case Type::INT64:
+    case Type::DOUBLE:
+      required = 8;
+      break;
+    case Type::INT96:
+      required = 3 * sizeof(int32_t);
+      break;
+    case Type::BYTE_ARRAY:

Review Comment:
   It is better to put `BYTE_ARRAY` and `UNDEFINED` together since they are skipped. In case you don't know, `BYTE_ARRAY` cannot have `float16` logical type.



##########
cpp/src/parquet/types.cc:
##########
@@ -184,6 +184,43 @@ std::string FormatFloat16Value(::std::string_view val) {
 
 std::string FormatStatValue(Type::type parquet_type, ::std::string_view val,
                             const std::shared_ptr<const LogicalType>& logical_type) {
+  // Statistics blobs come from the file's Thrift-encoded metadata and may have
+  // arbitrary length under a malicious writer. Reject any value that is shorter
+  // than what the physical (and, for FLOAT16, logical) type requires so the
+  // memcpy/byte loads below cannot run past the buffer.
+  size_t required = 0;
+  switch (parquet_type) {
+    case Type::BOOLEAN:
+      required = sizeof(bool);
+      break;
+    case Type::INT32:
+    case Type::FLOAT:
+      required = 4;
+      break;
+    case Type::INT64:
+    case Type::DOUBLE:
+      required = 8;
+      break;
+    case Type::INT96:
+      required = 3 * sizeof(int32_t);
+      break;
+    case Type::BYTE_ARRAY:
+    case Type::FIXED_LEN_BYTE_ARRAY:
+      if (logical_type != nullptr && logical_type->is_float16()) {

Review Comment:
   Why not dealing with the length of `FIXED_LEN_BYTE_ARRAY`?



-- 
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: github-unsubscribe@arrow.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


Re: [PR] GH-50184: [C++][Parquet] Avoid reading past truncated statistics values in FormatStatValue [arrow]

Posted by "conbench-apache-arrow[bot] (via GitHub)" <gi...@apache.org>.
conbench-apache-arrow[bot] commented on PR #50025:
URL: https://github.com/apache/arrow/pull/50025#issuecomment-4732376628

   After merging your PR, Conbench analyzed the 4 benchmarking runs that have been run so far on merge-commit 546d42c71a467c3741df2d6ececad966fc66bf4c.
   
   There was 1 benchmark result indicating a performance regression:
   
   - Commit Run on `test-mac-arm` at [2026-06-17 12:23:48Z](https://conbench.arrow-dev.org/compare/runs/18b473a5ae604c9085560aa7bcc63fbd...8a457e515ef14432a9751ff4f76e2f19/)
     - [`tpch` (R) with engine=arrow, format=native, language=R, memory_map=False, query_id=TPCH-01, scale_factor=1](https://conbench.arrow-dev.org/compare/benchmarks/06a327bb2b8d79e5800068fcc03bfd12...06a329a855177a788000bf2d81553355)
   
   The [full Conbench report](https://github.com/apache/arrow/runs/81937263349) has more details. It also includes information about 31 possible false positives for unstable benchmarks that are known to sometimes produce them.


-- 
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: github-unsubscribe@arrow.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


Re: [PR] GH-50184: [C++][Parquet] Avoid reading past truncated statistics values in FormatStatValue [arrow]

Posted by "jmestwa-coder (via GitHub)" <gi...@apache.org>.
jmestwa-coder commented on PR #50025:
URL: https://github.com/apache/arrow/pull/50025#issuecomment-4720456616

   @pitrou makes sense, truncated stats are spec-legal so throwing was wrong. reworked it to clamp every fixed-width memcpy/Float16 load in FormatStatValue to val.size(), so a short min/max is zero-padded instead of read past the buffer and nothing throws. the variable-length FLBA (decimal/string) and BYTE_ARRAY paths were already size-driven, so they're untouched.
   
   @wgtmac this also drops the partial required-length table you flagged. every read now bounds itself, so there's no half-covered enum check and the public signature stays the same. updated the test and the title/description to match.


-- 
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: github-unsubscribe@arrow.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


Re: [PR] GH-50184: [C++][Parquet] Reject too-short statistics values in FormatStatValue [arrow]

Posted by "wgtmac (via GitHub)" <gi...@apache.org>.
wgtmac commented on code in PR #50025:
URL: https://github.com/apache/arrow/pull/50025#discussion_r3417723957


##########
cpp/src/parquet/types.cc:
##########
@@ -184,6 +184,43 @@ std::string FormatFloat16Value(::std::string_view val) {
 
 std::string FormatStatValue(Type::type parquet_type, ::std::string_view val,
                             const std::shared_ptr<const LogicalType>& logical_type) {
+  // Statistics blobs come from the file's Thrift-encoded metadata and may have
+  // arbitrary length under a malicious writer. Reject any value that is shorter
+  // than what the physical (and, for FLOAT16, logical) type requires so the
+  // memcpy/byte loads below cannot run past the buffer.
+  size_t required = 0;
+  switch (parquet_type) {
+    case Type::BOOLEAN:
+      required = sizeof(bool);
+      break;
+    case Type::INT32:
+    case Type::FLOAT:
+      required = 4;
+      break;
+    case Type::INT64:
+    case Type::DOUBLE:
+      required = 8;
+      break;
+    case Type::INT96:
+      required = 3 * sizeof(int32_t);
+      break;
+    case Type::BYTE_ARRAY:
+    case Type::FIXED_LEN_BYTE_ARRAY:
+      if (logical_type != nullptr && logical_type->is_float16()) {
+        required = 2;
+      }
+      break;
+    case Type::UNDEFINED:
+    default:
+      break;
+  }
+  if (val.size() < required) {

Review Comment:
   @pitrou Do you have any suggestion?



-- 
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: github-unsubscribe@arrow.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


Re: [PR] GH-50184: [C++][Parquet] Reject too-short statistics values in FormatStatValue [arrow]

Posted by "pitrou (via GitHub)" <gi...@apache.org>.
pitrou commented on PR #50025:
URL: https://github.com/apache/arrow/pull/50025#issuecomment-4716687178

   The Parquet spec allows for truncated statistics, so raising an exception sounds wrong here. Just make sure that we're not copying too many bytes from the `std::string_view` .
   


-- 
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: github-unsubscribe@arrow.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


Re: [PR] GH-50184: [C++][Parquet] Reject too-short statistics values in FormatStatValue [arrow]

Posted by "jmestwa-coder (via GitHub)" <gi...@apache.org>.
jmestwa-coder commented on code in PR #50025:
URL: https://github.com/apache/arrow/pull/50025#discussion_r3415850270


##########
cpp/src/parquet/types.cc:
##########
@@ -184,6 +184,43 @@ std::string FormatFloat16Value(::std::string_view val) {
 
 std::string FormatStatValue(Type::type parquet_type, ::std::string_view val,
                             const std::shared_ptr<const LogicalType>& logical_type) {
+  // Statistics blobs come from the file's Thrift-encoded metadata and may have
+  // arbitrary length under a malicious writer. Reject any value that is shorter
+  // than what the physical (and, for FLOAT16, logical) type requires so the
+  // memcpy/byte loads below cannot run past the buffer.
+  size_t required = 0;
+  switch (parquet_type) {
+    case Type::BOOLEAN:
+      required = sizeof(bool);
+      break;
+    case Type::INT32:
+    case Type::FLOAT:
+      required = 4;
+      break;
+    case Type::INT64:
+    case Type::DOUBLE:
+      required = 8;
+      break;
+    case Type::INT96:
+      required = 3 * sizeof(int32_t);
+      break;
+    case Type::BYTE_ARRAY:
+    case Type::FIXED_LEN_BYTE_ARRAY:
+      if (logical_type != nullptr && logical_type->is_float16()) {

Review Comment:
   Fair. Full per-length validation needs the column type_length, and since FormatStatValue is public I left the signature alone, so the guard only covers the types that do an unconditional fixed-width load (BOOLEAN/INT32/INT64/INT96/FLOAT/DOUBLE and the float16 FLBA), which are the ones that actually over-read. The variable-length FLBA (decimal/string) and BYTE_ARRAY paths are already size-driven and stay in bounds. If you'd rather thread the type_length through a new overload to cover everything, I'm happy to go that way.



-- 
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: github-unsubscribe@arrow.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


Re: [PR] GH-50184: [C++][Parquet] Reject too-short statistics values in FormatStatValue [arrow]

Posted by "jmestwa-coder (via GitHub)" <gi...@apache.org>.
jmestwa-coder commented on PR #50025:
URL: https://github.com/apache/arrow/pull/50025#issuecomment-4711346175

   Filed #50184 for this and retitled the PR to reference it. Also reworked the description into the template sections.


-- 
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: github-unsubscribe@arrow.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


Re: [PR] GH-50184: [C++][Parquet] Reject too-short statistics values in FormatStatValue [arrow]

Posted by "github-actions[bot] (via GitHub)" <gi...@apache.org>.
github-actions[bot] commented on PR #50025:
URL: https://github.com/apache/arrow/pull/50025#issuecomment-4711339301

   :warning: GitHub issue #50184 **has been automatically assigned in GitHub** to PR creator.


-- 
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: github-unsubscribe@arrow.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


Re: [PR] GH-50184: [C++][Parquet] Avoid reading past truncated statistics values in FormatStatValue [arrow]

Posted by "pitrou (via GitHub)" <gi...@apache.org>.
pitrou merged PR #50025:
URL: https://github.com/apache/arrow/pull/50025


-- 
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: github-unsubscribe@arrow.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org