Skip to content

Conversation

glennsong09
Copy link
Collaborator

This PR fixes issue #5380, which has a heap based buffer overflow after H5MF_xfree is called on an address of 0 (file superblock). This PR changes an assert making sure addr isn't 0 to an if check.

The bug was first reproduced using the fuzzer and the POC file from #5380. With this change, the heap based buffer overflow no longer occurs.

Copy link

@greptile-apps greptile-apps bot left a comment

Choose a reason for hiding this comment

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

Greptile Summary

This PR fixes a critical security vulnerability (CVE-2025-2915) in the HDF5 library by addressing a heap-based buffer overflow in the H5MF_xfree function. The issue occurred when the function was called with an address of 0, which represents the file superblock that should never be freed.

The core change replaces a debug-time assertion with proper runtime error handling. The original code used assert(addr != 0) to check that the superblock wasn't being freed, but assertions are typically disabled in release builds, leaving the vulnerability exposed when processing malicious or corrupted HDF5 files. The fix converts this to a runtime check if (addr <= 0) that returns an appropriate error instead of allowing the invalid operation to proceed.

This change fits into HDF5's memory management subsystem (H5MF - Memory File management) which handles allocation and deallocation of file space. The fix ensures that the fundamental invariant of never freeing the superblock is enforced at runtime, not just during development testing. The condition was also strengthened from != 0 to <= 0 to catch any non-positive addresses, providing more comprehensive protection against similar vulnerabilities.

Important Files Changed

Files Changed
Filename Score Overview
src/H5MF.c 5/5 Replaced debug assertion with runtime error check to prevent heap buffer overflow when freeing superblock address

1 file reviewed, no comments

Edit Code Review Bot Settings | Greptile

qkoziol
qkoziol previously approved these changes Aug 29, 2025
@fortnern fortnern self-assigned this Aug 29, 2025
src/H5MF.c Outdated
assert(addr != 0); /* Can't deallocate the superblock :-) */

if (addr <= 0)
HGOTO_ERROR(H5E_RESOURCE, H5E_BADRANGE, FAIL, "attempting to free file superblock");
Copy link
Collaborator

Choose a reason for hiding this comment

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

I know the original assert didn't have, but should addr also be checked for upper bound, not going pass the end of the file?

@jhendersonHDF jhendersonHDF linked an issue Sep 15, 2025 that may be closed by this pull request
mattjala
mattjala previously approved these changes Sep 16, 2025
Copy link
Member

@fortnern fortnern left a comment

Choose a reason for hiding this comment

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

This appears to be related to #5202 (possibly the same issue). I have essentially the same comment here. The logic in H5F__accum_free should prevent this buffer overlfow, even if addr is 0, as long as accum->size <= accum->alloc_size. We should figure out how that assumption came to be violated.

It is perhaps appropriate to make sure addr cannot be 0, but ideally we should catch it sooner. Do you know where the 0 address came from?

@nbagha1 nbagha1 moved this from To be triaged to Scheduled/On-Deck in HDF5 - TRIAGE & TRACK Sep 22, 2025
Copy link
Member

@fortnern fortnern left a comment

Choose a reason for hiding this comment

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

See previous comment

@github-project-automation github-project-automation bot moved this from Scheduled/On-Deck to In progress in HDF5 - TRIAGE & TRACK Sep 23, 2025
@glennsong09 glennsong09 dismissed stale reviews from mattjala and qkoziol via b092ee3 September 24, 2025 18:28
src/H5Faccum.c Outdated

/* Calculate the size of the overlap with the accumulator, etc. */
H5_CHECKED_ASSIGN(overlap_size, size_t, (addr + size) - accum->loc, haddr_t);
if (overlap_size > accum->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'm still not sure we've found the root of the problem. The condition to get into this block is effectively addr+size < accum->loc + accum->size. Therefore overlap_size, which is addr+size-accum->loc should be less than accum->size undern normal conditions. Is one of the quantities involved (addr, size, accum->loc, accum->size) very large and causing wraparound? If so, is there a real reason it should be this way, or can we detect an impossibly large value when it's loaded from disk? We should also add H5_CHECK_OVERFLOW and similar checks as appropriate.

HGOTO_ERROR(H5E_OHDR, H5E_OVERFLOW, NULL, "address plus size overflows");
if (mesg->addr == HADDR_UNDEF)
HGOTO_ERROR(H5E_OHDR, H5E_OVERFLOW, NULL, "address is undefined");
if ((mesg->addr + mesg->size) > H5F_get_eoa(f, H5FD_MEM_DEFAULT))
Copy link
Member

Choose a reason for hiding this comment

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

Have you tried using H5FD_MEM_SUPER for the type?

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Yes, I swear I used H5FD_MEM_SUPER, I'm not sure when I changed it back to H5FD_MEM_DEFAULT.

HGOTO_ERROR(H5E_OHDR, H5E_OVERFLOW, NULL, "ran off end of input buffer while decoding");
H5F_DECODE_LENGTH(f, p, mesg->size);

if (mesg->addr >= (HADDR_UNDEF - mesg->size))
Copy link
Member

Choose a reason for hiding this comment

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

Clever!

Co-authored-by: Neil Fortner <fortnern@gmail.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

Status: In progress

Development

Successfully merging this pull request may close these issues.

Heap-based Buffer Overflow in H5F__accum_free

6 participants