Skip to content

Conversation

bmribler
Copy link
Collaborator

@bmribler bmribler commented Sep 3, 2025

The size of an mtime message was decoded as 0, which later caused the buffer to small resulting in a heap-buffer-overflow.

This PR fixed the issue by detecting the invalid message size and reporting the error, preventing the continuation of the code.

GH issue #5549


Important

Fixes CVE-2025-6750 by adding a buffer overflow check in H5O__chunk_deserialize() to prevent heap-buffer-overflow.

This description was created by Ellipsis for ddf0d35. You can customize this summary. It will automatically update as commits are pushed.

The size of an mtime message was decoded as 0, which later caused the buffer to small
resulting in a heap-buffer-overflow.

This PR fixed the issue by detecting the invalid message size and reporting the
error, preventing the continuation of the code.

GH issue #5549
qkoziol
qkoziol previously approved these changes Sep 3, 2025
@bmribler bmribler marked this pull request as draft September 3, 2025 23:01
src/H5Ocache.c Outdated
@@ -1268,6 +1268,11 @@ H5O__chunk_deserialize(H5O_t *oh, haddr_t addr, size_t chunk_size, const uint8_t
UINT16DECODE(chunk_image, mesg_size);
if (mesg_size != H5O_ALIGN_OH(oh, mesg_size))
HGOTO_ERROR(H5E_OHDR, H5E_CANTLOAD, FAIL, "message not aligned");
if (mesg_size > (size_t)(p_end - chunk_image))
HGOTO_ERROR(H5E_OHDR, H5E_BADVALUE, FAIL, "message size exceed buffer end");
if (id == H5O_MTIME_NEW_ID) /* validate mtime message size */
Copy link

Choose a reason for hiding this comment

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

Good fix: explicitly validating that mtime messages have a non‐zero size prevents the overflow. Consider adding braces to the nested if for clarity.

@bmribler bmribler marked this pull request as ready for review September 4, 2025 04:19
bmribler and others added 2 commits September 4, 2025 00:20
Co-authored-by: ellipsis-dev[bot] <65095814+ellipsis-dev[bot]@users.noreply.github.com>
Co-authored-by: ellipsis-dev[bot] <65095814+ellipsis-dev[bot]@users.noreply.github.com>
glennsong09
glennsong09 previously approved these changes Sep 4, 2025
qkoziol
qkoziol previously approved these changes Sep 7, 2025
src/H5Ocache.c Outdated
@@ -1268,6 +1268,11 @@ H5O__chunk_deserialize(H5O_t *oh, haddr_t addr, size_t chunk_size, const uint8_t
UINT16DECODE(chunk_image, mesg_size);
if (mesg_size != H5O_ALIGN_OH(oh, mesg_size))
HGOTO_ERROR(H5E_OHDR, H5E_CANTLOAD, FAIL, "message not aligned");
if (mesg_size > (size_t)(p_end - chunk_image))
Copy link
Collaborator

@jhendersonHDF jhendersonHDF Sep 9, 2025

Choose a reason for hiding this comment

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

It may make more sense to use the H5_IS_BUFFER_OVERFLOW macro here, as in:

if (H5_IS_BUFFER_OVERFLOW(chunk_image, mesg_size, p_end))
    error;

as it does the same thing and accounts for the fact that you need p_end - chunk_image + 1. (Consider if mesg_size is 1 and p_end == chunk_image)

src/H5Ocache.c Outdated
@@ -1268,6 +1268,11 @@ H5O__chunk_deserialize(H5O_t *oh, haddr_t addr, size_t chunk_size, const uint8_t
UINT16DECODE(chunk_image, mesg_size);
if (mesg_size != H5O_ALIGN_OH(oh, mesg_size))
HGOTO_ERROR(H5E_OHDR, H5E_CANTLOAD, FAIL, "message not aligned");
if (mesg_size > (size_t)(p_end - chunk_image))
HGOTO_ERROR(H5E_OHDR, H5E_BADVALUE, FAIL, "message size exceeds buffer end");
if (id == H5O_MTIME_NEW_ID) /* validate mtime message size */
Copy link
Member

Choose a reason for hiding this comment

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

I don't think there should be a specific case for mtime messages here. IF we really want to detect invalid messages we should create a callback for checking them, though I'm not sure we'll be able to detect all problems without fully decoding them, potentially adding unnecessary overhead.

There is a check for buffer overflow in H5O__mtime_new_decode(), why does this not catch the problem before an invalid access?

Copy link
Collaborator Author

@bmribler bmribler Sep 9, 2025

Choose a reason for hiding this comment

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

@fortnern The H5O__mtime_new_decode() has the buffer overflow checks but the H5O__mtime_new_encode() doesn't and the issue #5549 is in the encoding. Would you like me to add buffer overflow checks in the encoder? I haven't seen an encoder in the library doing that although I didn't look thoroughly. The reason I added the check here is that's where the decoding of mtime is. Didn't we agree that we'll try validate the inputs where they are decoded? All that aside, just let me know what I should do now for this release. Your call.

Copy link
Member

@fortnern fortnern Sep 10, 2025

Choose a reason for hiding this comment

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

The actual message is decoded in H5O__mtime_new_decode(). The higher level obejct header code just reads the raw bytes for the messages. The message must have been decoded at some point right? Why did it not trip the error condition when it was originally decoded?

Copy link
Member

Choose a reason for hiding this comment

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

It seems likely that the problem was with the off by one error in the check I mentioned in the other comment. I suspect things will work fine if you remove this one (if (id == H5O_MTIME_NEW_ID)), remove the one I mentioned (Try to detect invalidly formatted object header message that extends past end of chunk.), and implement Jordan's suggestions for the last one.

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

I removed the "Try to..." and replaced "if (mesg_size > (size_t)(p_end - chunk_image))" with if H5_IS_BUFFER_OVERFLOW.
Next, I removed the check if (mesg_size == 0) as you suggested, the program crashed again with

WRITE of size 1 at 0x604000001d00 thread T0

in H5O__mtime_new_encode() because the buffer going into H5O__mtime_new_encode() has size 0. Understandably, the buffer overflow check serves when mesg_size is larger than expected but it doesn't help when the mesg_size is 0. That means mesg_size=0 has to be detected somewhere, right?

So, either I have to check for non-zero size in H5O__mtime_new_encode() or here
if (id == H5O_MTIME_NEW_ID) /* validate mtime message size */
if (mesg_size == 0)
HGOTO_ERROR(H5E_OHDR, H5E_BADVALUE, FAIL, "invalid size for mtime message");
Am I missing something?

Copy link
Member

Choose a reason for hiding this comment

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

Yes, please try to figure out why the check in H5O__mtime_new_decode() isn't catching it.

Copy link
Member

Choose a reason for hiding this comment

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

Checking for size==0 isn't a real fix because it would still fail if the size is nonzero but too small. Also the same problem could happen with other message types, each of which have their own size requirements. There should never be a decoded message in memory where the size allocated in the object header (if any) is inconsistent with the size requirements of the message.

Copy link
Member

Choose a reason for hiding this comment

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

It would make sense to add an assert to H5O__mtime_encode that p_size is large enough

src/H5Ocache.c Outdated
@@ -1268,6 +1268,11 @@ H5O__chunk_deserialize(H5O_t *oh, haddr_t addr, size_t chunk_size, const uint8_t
UINT16DECODE(chunk_image, mesg_size);
if (mesg_size != H5O_ALIGN_OH(oh, mesg_size))
HGOTO_ERROR(H5E_OHDR, H5E_CANTLOAD, FAIL, "message not aligned");
if (mesg_size > (size_t)(p_end - chunk_image))
Copy link
Member

Choose a reason for hiding this comment

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

I believe the later check for "Try to detect invalidly formatted object header message that extends past end of chunk." is now obsolete (and it had an off by one error that may have caused the problem in the first place) and can be deleted. I also think having both p_end and eom_ptr doing almost the same thing is confusing and redundant but it doesn't need to be fixed now.

bmribler and others added 2 commits September 11, 2025 23:36
Fixed typo

Co-authored-by: ellipsis-dev[bot] <65095814+ellipsis-dev[bot]@users.noreply.github.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
Status: To be triaged
Development

Successfully merging this pull request may close these issues.

5 participants