Skip to content

Conversation

@jhendersonHDF
Copy link
Collaborator

@jhendersonHDF jhendersonHDF commented Oct 23, 2025

Fixes several crashes/assertion failures related to CVE-2025-7067


Important

Fixes CVE-2025-7067 issues by updating H5FS_sect_add to handle section merging/shrinking and improving error handling.

  • Functionality:
    • H5FS_sect_add in H5FSsection.c now accepts an additional bool *merged_or_shrunk parameter to track if sections are merged or shrunk.
    • Updates to H5MF__add_sect in H5MF.c to handle merged_or_shrunk parameter.
  • Error Handling:
    • Improved error handling in H5FS_vfd_alloc_hdr_and_section_info_if_needed in H5MF.c to manage allocation failures.
  • Tests:
    • Updated test cases in freespace.c and mf.c to include the new parameter in H5FS_sect_add calls.

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

herr_t
H5FS_sect_add(H5F_t *f, H5FS_t *fspace, H5FS_section_info_t *sect, unsigned flags, void *op_data)
H5FS_sect_add(H5F_t *f, H5FS_t *fspace, H5FS_section_info_t *sect, unsigned flags, void *op_data,
bool *merged_or_shrunk)
Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Callers of this function need to know whether the free space section passed in was merged or shrunk away, even on failure. Otherwise, calling code can incorrectly assume that it needs to free the passed in section if it was allocated by the calling code and H5FS_sect_add() failed. In some cases, the passed in section will have already been freed, eventually resulting in a double free situation when the calling code frees the section.

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

An alternative approach would be to pass in a H5FS_section_info_t **, but that seemed uglier and prone to the caller accidentally losing a pointer.

} /* end if */

done:
if (ret_value < 0) {
Copy link
Collaborator Author

Choose a reason for hiding this comment

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

When this function fails, remove everything that was previously inserted into the metadata cache. Otherwise, crashes or assertion failures can occur later on when trying to flush out half-initialized entries that were inserted.

if (H5MF__add_sect(f, alloc_type, f->shared->fs_man[fs_type], node) < 0)
if (H5MF__add_sect(f, alloc_type, f->shared->fs_man[fs_type], node, &section_merged_or_shunk) < 0) {
if (section_merged_or_shunk)
node = NULL;
Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Avoid double-freeing this section that was allocated above in case H5MF__add_sect() already freed it.

if (H5MF__add_sect(f, alloc_type, fspace, node) < 0)
if (H5MF__add_sect(f, alloc_type, fspace, node, NULL) < 0) {
node->sect_info.addr -= size;
node->sect_info.size += size;
Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Reverse the modifications made above on failure.


assert(!H5_addr_defined(f->shared->fs_addr[sm_fshdr_fs_type]));
assert(!H5_addr_defined(f->shared->fs_addr[sm_fssinfo_fs_type]));
if (H5_addr_defined(f->shared->fs_addr[sm_fshdr_fs_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.

These assertions can be triggered by a file space info message in the file's superblock extension that was specifically crafted. Throwing an error here causes the library to fail to be able to settle the MDFSM, which eventually leads to issues closing the library and leaked memory due to the metadata cache not being able to be flushed and destroyed. In Debug builds this still results in an assertion failure when specifically-crafted files are opened, but addressing that will require significant changes to the metadata cache shutdown process.

An alternative is to simply wipe out these addresses to HADDR_UNDEF and let the following logic take over, but this could end up dropping free space on the floor and also causes far more problems when given a specifically crafted file.

Copy link
Member

Choose a reason for hiding this comment

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

Could this be detected when the file space info message is decoded?

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

In theory yes, however there was no obvious documentation or information I could find on which of the free space managers are and aren't allowed to have a defined address right after decoding and after asking around the opinion seemed to be that any of the managers could be defined. In this specific case however it seems the assumption is that these particular ones won't have a defined address.

assert(sect1);
assert(sect2);
assert(sect1->sect_info.type == sect2->sect_info.type); /* Checks "MERGE_SYM" flag */
assert(H5_addr_lt(sect1->sect_info.addr, sect2->sect_info.addr));
Copy link
Collaborator Author

Choose a reason for hiding this comment

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

With the file given in #5577, an attempt is made to place an overlapping section of file free space into the free space manager. That eventually causes this assertion to trigger. While a true fix would likely involve detecting this situation earlier on, this is probably a non-trivial effort. Since these functions are only checking whether two free space sections can be merged and not actually doing the merging, removing these assertions and just letting them return false seemed appropriate.

Copy link
Member

Choose a reason for hiding this comment

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

We should leave open an issue to add the correct fix, and note that these assertions should be re enabled at that point

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Will do. Should I instead comment these out for now then?

Copy link
Member

Choose a reason for hiding this comment

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

That sounds good

@jhendersonHDF jhendersonHDF moved this from To be triaged to In progress in HDF5 - TRIAGE & TRACK Oct 23, 2025
@jhendersonHDF jhendersonHDF marked this pull request as ready for review October 23, 2025 18:09
* Avoid expunging the entry, as the information needs to be kept around
* until we finish trying to settle the metadata free space manager(s).
*/
if (inserted_section || allocated_section) {
Copy link
Member

Choose a reason for hiding this comment

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

Why do we need this line?

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 believe these checks are actually redundant and can be removed at this point. Previously I was removing the cache entries with expunge_entry and the "free file space" flag, in which case I had two branches with different logic where I didn't want to double free the file space with the call to H5MF_xfree followed by expunge_entry. That caused some problems and needed a switch to remove_entry instead, so I think this line and the other line are no longer relevant.

* Avoid expunging the entry, as the information needs to be kept around
* until we finish trying to settle the metadata free space manager(s).
*/
if (inserted_header || allocated_header) {
Copy link
Member

Choose a reason for hiding this comment

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

Same here, is this one just for the assertion?

@fortnern
Copy link
Member

Finished reviewing, 2 questions as comments, 2 as replies

@nbagha1 nbagha1 added this to the Release 2.0.0 milestone Oct 29, 2025
@jhendersonHDF jhendersonHDF removed this from the Release 2.0.0 milestone Oct 29, 2025
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.

5 participants