Skip to content

Commit

Permalink
Fix for HDFFV-11052: h5debug fails on a corrupted file (h5_nrefs_POC)… (
Browse files Browse the repository at this point in the history
HDFGroup#2291) (HDFGroup#2496)

* Fix for HDFFV-11052: h5debug fails on a corrupted file (h5_nrefs_POC) producing a core dump.
When h5debug closes the corrupted file, the library calls H5F__dest() which performs all the
closing operations for the file "f" (H5F_t *) but just keeping note of errors in "ret_value"
all the way till the end of the routine.  The user-provided corrupted file has an illegal
file size causing failure when reading the image during the closing process.
At the end of this routine it sets f->shared to NULL and then frees "f".
This is done whether there is error or not in "ret_value".
Due to the failure in reading the file earlier, the routine then returns error.
The error return from H5F__dest() causes the file object "f" not being removed from the
ID node table.  When the library finally exits, it will try to close the
file objects in the table.  This causes assert failure when H5F_ID_EXISTS(f) or H5F_NREFS(f).
Fix:
a) H5F_dest(): free the f only when there is no error in "ret_value" at the end of the routine.
b) H5VL__native_file_close(): if f->shared is NULL, free "f"; otherwise, perform closing on "f" as before.
c) h5debug.c main(): track error return from H5Fclose().

* Committing clang-format changes

Co-authored-by: vchoi <[email protected]>
Co-authored-by: github-actions <41898282+github-actions[bot]@users.noreply.github.com>
  • Loading branch information
3 people authored Feb 26, 2023
1 parent a7dd645 commit 063a61c
Show file tree
Hide file tree
Showing 7 changed files with 97 additions and 26 deletions.
19 changes: 19 additions & 0 deletions release_docs/RELEASE.txt
Original file line number Diff line number Diff line change
Expand Up @@ -180,6 +180,25 @@ Bug Fixes since HDF5-1.12.1 release
===================================
Library
-------
- Seg fault on file close

h5debug fails at file close with core dump on a file that has an
illegal file size in its cache image. In H5F_dest(), the library
performs all the closing operations for the file and keeps track of
the error encountered when reading the file cache image.
At the end of the routine, it frees the file's file structure and
returns error. Due to the error return, the file object is not removed
from the ID node table. This eventually causes assertion failure in
H5VL__native_file_close() when the library finally exits and tries to
access that file object in the table for closing.

The closing routine, H5F_dest(), will not free the file structure if
there is error, keeping a valid file structure in the ID node table.
It will be freed later in H5VL__native_file_close() when the
library exits and terminates the file package.

(VC - 2022/12/14, HDFFV-11052, CVE-2020-10812)

- Fixed an issue with variable length attributes

Previously, if a variable length attribute was held open while its file
Expand Down
4 changes: 3 additions & 1 deletion src/H5Fint.c
Original file line number Diff line number Diff line change
Expand Up @@ -1648,7 +1648,9 @@ H5F__dest(H5F_t *f, hbool_t flush)
if (H5FO_top_dest(f) < 0)
HDONE_ERROR(H5E_FILE, H5E_CANTINIT, FAIL, "problems closing file")
f->shared = NULL;
f = H5FL_FREE(H5F_t, f);

if (ret_value >= 0)
f = H5FL_FREE(H5F_t, f);

FUNC_LEAVE_NOAPI(ret_value)
} /* end H5F__dest() */
Expand Down
52 changes: 29 additions & 23 deletions src/H5VLnative_file.c
Original file line number Diff line number Diff line change
Expand Up @@ -813,29 +813,35 @@ H5VL__native_file_close(void *file, hid_t H5_ATTR_UNUSED dxpl_id, void H5_ATTR_U
FUNC_ENTER_PACKAGE

/* This routine should only be called when a file ID's ref count drops to zero */
HDassert(H5F_ID_EXISTS(f));

/* Flush file if this is the last reference to this id and we have write
* intent, unless it will be flushed by the "shared" file being closed.
* This is only necessary to replicate previous behaviour, and could be
* disabled by an option/property to improve performance.
*/
if ((H5F_NREFS(f) > 1) && (H5F_INTENT(f) & H5F_ACC_RDWR)) {
/* Get the file ID corresponding to the H5F_t struct */
if (H5I_find_id(f, H5I_FILE, &file_id) < 0 || H5I_INVALID_HID == file_id)
HGOTO_ERROR(H5E_ATOM, H5E_CANTGET, FAIL, "invalid atom")

/* Get the number of references outstanding for this file ID */
if ((nref = H5I_get_ref(file_id, FALSE)) < 0)
HGOTO_ERROR(H5E_ATOM, H5E_CANTGET, FAIL, "can't get ID ref count")
if (nref == 1)
if (H5F__flush(f) < 0)
HGOTO_ERROR(H5E_CACHE, H5E_CANTFLUSH, FAIL, "unable to flush cache")
} /* end if */

/* Close the file */
if (H5F__close(f) < 0)
HGOTO_ERROR(H5E_FILE, H5E_CANTDEC, FAIL, "can't close file")
HDassert(f->shared == NULL || H5F_ID_EXISTS(f));

if (f->shared == NULL)
f = H5FL_FREE(H5F_t, f);

else {

/* Flush file if this is the last reference to this id and we have write
* intent, unless it will be flushed by the "shared" file being closed.
* This is only necessary to replicate previous behaviour, and could be
* disabled by an option/property to improve performance.
*/
if ((H5F_NREFS(f) > 1) && (H5F_INTENT(f) & H5F_ACC_RDWR)) {
/* Get the file ID corresponding to the H5F_t struct */
if (H5I_find_id(f, H5I_FILE, &file_id) < 0 || H5I_INVALID_HID == file_id)
HGOTO_ERROR(H5E_ATOM, H5E_CANTGET, FAIL, "invalid atom")

/* Get the number of references outstanding for this file ID */
if ((nref = H5I_get_ref(file_id, FALSE)) < 0)
HGOTO_ERROR(H5E_ATOM, H5E_CANTGET, FAIL, "can't get ID ref count")
if (nref == 1)
if (H5F__flush(f) < 0)
HGOTO_ERROR(H5E_CACHE, H5E_CANTFLUSH, FAIL, "unable to flush cache")
} /* end if */

/* Close the file */
if (H5F__close(f) < 0)
HGOTO_ERROR(H5E_FILE, H5E_CANTDEC, FAIL, "can't close file")
}

done:
FUNC_LEAVE_NOAPI(ret_value)
Expand Down
1 change: 1 addition & 0 deletions test/CMakeTests.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -126,6 +126,7 @@ set (HDF5_REFERENCE_TEST_FILES
btree_idx_1_6.h5
btree_idx_1_8.h5
corrupt_stab_msg.h5
cve_2020_10812.h5
deflate.h5
family_v16_00000.h5
family_v16_00001.h5
Expand Down
Binary file added test/cve_2020_10812.h5
Binary file not shown.
39 changes: 39 additions & 0 deletions test/tmisc.c
Original file line number Diff line number Diff line change
Expand Up @@ -330,6 +330,11 @@ typedef struct {
#define MISC35_SPACE_DIM3 13
#define MISC35_NPOINTS 10

/* Definitions for misc. test #36 */
/* The test file is formerly named h5_nrefs_POC.
* See https://nvd.nist.gov/vuln/detail/CVE-2020-10812 */
#define CVE_2020_10812_FILENAME "cve_2020_10812.h5"

/****************************************************************
**
** test_misc1(): test unlinking a dataset from a group and immediately
Expand Down Expand Up @@ -5905,6 +5910,39 @@ test_misc35(void)

} /* end test_misc35() */

/****************************************************************
* **
* ** test_misc36():
* ** Test for seg fault issue when closing the provided test file
* ** which has an illegal file size in its cache image.
* ** See HDFFV-11052/CVE-2020-10812 for details.
* **
* ****************************************************************/
static void
test_misc36(void)
{
const char *fname;
hid_t fid;
herr_t ret;

/* Output message about test being performed */
MESSAGE(5, ("Fix for HDFFV-11052/CVE-2020-10812"));

fname = H5_get_srcdir_filename(CVE_2020_10812_FILENAME);
fid = H5Fopen(fname, H5F_ACC_RDONLY, H5P_DEFAULT);
CHECK(fid, FAIL, "H5Fopen");

/* This should fail due to the illegal file size.
* It should fail gracefully and not seg fault */
H5E_BEGIN_TRY
{
ret = H5Fclose(fid);
}
H5E_END_TRY;
VERIFY(ret, FAIL, "H5Fclose");

} /* end test_misc36() */

/****************************************************************
**
** test_misc(): Main misc. test routine.
Expand Down Expand Up @@ -5956,6 +5994,7 @@ test_misc(void)
test_misc33(); /* Test to verify that H5HL_offset_into() returns error if offset exceeds heap block */
test_misc34(); /* Test behavior of 0 and NULL in H5MM API calls */
test_misc35(); /* Test behavior of free-list & allocation statistics API calls */
test_misc36(); /* Test for seg fault failure at file close */

} /* test_misc() */

Expand Down
8 changes: 6 additions & 2 deletions tools/src/misc/h5debug.c
Original file line number Diff line number Diff line change
Expand Up @@ -816,8 +816,12 @@ main(int argc, char *argv[])
done:
if (fapl > 0)
H5Pclose(fapl);
if (fid > 0)
H5Fclose(fid);
if (fid > 0) {
if (H5Fclose(fid) < 0) {
HDfprintf(stderr, "Error in closing file!\n");
exit_value = 1;
}
}

/* Pop API context */
if (api_ctx_pushed)
Expand Down

0 comments on commit 063a61c

Please sign in to comment.