Skip to content

[io] validate decompressed size against point layout in readBodyBinary - #6491

Merged
mvieth merged 2 commits into
PointCloudLibrary:masterfrom
aysha-afrah26:pcd-compressed-size-check
Oct 21, 2026
Merged

mvieth merged 2 commits into
PointCloudLibrary:masterfrom
aysha-afrah26:pcd-compressed-size-check

Conversation

@aysha-afrah26

@aysha-afrah26 aysha-afrah26 commented Oct 14, 2026 •

Copy link
Copy Markdown
Contributor

pcl::PCDReader::readBodyBinary reads the uncompressed size of a binary_compressed PCD straight from the body header and uses it to size the decompression buffer and cloud.data. Nothing enforces that size against the point layout: when it differs from the cloud.data size computed from the header fields, the reader only warns and then resizes cloud.data to the file-supplied value. The planar unpack loop right below walks width * height points with fsize bytes per point, so a file that advertises an uncompressed size smaller than fsize * width * height sends the plane pointers past the end of the decompressed buffer and the copy past the end of cloud.data. I hit it while fuzzing the compressed reader: a 100-point XYZ cloud whose body claims 12 bytes drives the second plane pointer 288 bytes past the 12-byte buffer, which AddressSanitizer flags as a heap-buffer-overflow read, with the matching write landing outside the shrunk cloud.data. A valid writer always stores fsize * width * height here, which is exactly what cloud.data was sized to from the header, so the existing mismatch check now returns -1 instead of warning and resizing. The added test in test/io/test_io.cpp feeds readBodyBinary a short self-consistent compressed block and expects it to return -1 rather than overflow.

@mvieth

mvieth commented Oct 18, 2026

Copy link
Copy Markdown
Member

There is a relatively similar check in line 576:

if (uncompressed_size != cloud.data.size ())

It even triggers in the new test you added:
[pcl::PCDReader::read] The estimated cloud.data size (1200) is different than the saved uncompressed value (12)! Data corruption?
However, that is currently just a warning, and then the code resizes cloud.data. Maybe it should already error-out there? Or do you see any difference between line 576 and the new check you added?

@aysha-afrah26

Copy link
Copy Markdown
Contributor Author

Good point, it's the same condition. readHeader already rejects WIDTH x HEIGHT != POINTS, so cloud.data.size() is point_step * width * height, and the only way that differs from fsize * width * height is a _ padding field in FIELDS. The compressed writer strips those from the header, so for anything PCL writes the two checks are identical, and a compressed file with padding fields would already come out inconsistent today (point_step keeps the padded stride, the unpacked data doesn't).

So I dropped my check and turned the warning at line 576 into an error that returns -1. The new test still passes, it just fails at that earlier point now, and the rest of test_io is green.

@mvieth mvieth left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks!

@mvieth
mvieth merged commit 8af779d into PointCloudLibrary:master Oct 21, 2026
13 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants