From a291821ece28a53463c2b45168217ca9b3fb63b5 Mon Sep 17 00:00:00 2001 From: vchoi Date: Mon, 12 Dec 2022 15:32:48 -0600 Subject: [PATCH 1/7] 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(). --- src/H5Fint.c | 4 ++- src/H5VLnative_file.c | 53 +++++++++++++++++++++++----------------- tools/src/misc/h5debug.c | 8 ++++-- 3 files changed, 39 insertions(+), 26 deletions(-) diff --git a/src/H5Fint.c b/src/H5Fint.c index 2c1b4b2c3c0..069b78b77e3 100644 --- a/src/H5Fint.c +++ b/src/H5Fint.c @@ -1615,7 +1615,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() */ diff --git a/src/H5VLnative_file.c b/src/H5VLnative_file.c index 907a12dedce..660749dabac 100644 --- a/src/H5VLnative_file.c +++ b/src/H5VLnative_file.c @@ -753,29 +753,36 @@ 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_ID, H5E_CANTGET, FAIL, "invalid ID") - - /* Get the number of references outstanding for this file ID */ - if ((nref = H5I_get_ref(file_id, FALSE)) < 0) - HGOTO_ERROR(H5E_ID, H5E_CANTGET, FAIL, "can't get ID ref count") - if (nref == 1) - if (H5F__flush(f) < 0) - HGOTO_ERROR(H5E_FILE, 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_ID, H5E_CANTGET, FAIL, "invalid ID") + + /* Get the number of references outstanding for this file ID */ + if ((nref = H5I_get_ref(file_id, FALSE)) < 0) + HGOTO_ERROR(H5E_ID, H5E_CANTGET, FAIL, "can't get ID ref count") + if (nref == 1) + if (H5F__flush(f) < 0) + HGOTO_ERROR(H5E_FILE, 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) diff --git a/tools/src/misc/h5debug.c b/tools/src/misc/h5debug.c index 05d37b84362..b15ae09a888 100644 --- a/tools/src/misc/h5debug.c +++ b/tools/src/misc/h5debug.c @@ -815,8 +815,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) From cbe13d9bfe75e51db7ab45e6f3d2c08ac0d05884 Mon Sep 17 00:00:00 2001 From: github-actions <41898282+github-actions[bot]@users.noreply.github.com> Date: Mon, 12 Dec 2022 21:36:23 +0000 Subject: [PATCH 2/7] Committing clang-format changes --- src/H5Fint.c | 2 +- src/H5VLnative_file.c | 3 +-- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/src/H5Fint.c b/src/H5Fint.c index 069b78b77e3..7ad35fc552d 100644 --- a/src/H5Fint.c +++ b/src/H5Fint.c @@ -1616,7 +1616,7 @@ H5F__dest(H5F_t *f, hbool_t flush) HDONE_ERROR(H5E_FILE, H5E_CANTINIT, FAIL, "problems closing file") f->shared = NULL; - if(ret_value >= 0) + if (ret_value >= 0) f = H5FL_FREE(H5F_t, f); FUNC_LEAVE_NOAPI(ret_value) diff --git a/src/H5VLnative_file.c b/src/H5VLnative_file.c index 660749dabac..f2f0ea7d19e 100644 --- a/src/H5VLnative_file.c +++ b/src/H5VLnative_file.c @@ -755,7 +755,7 @@ H5VL__native_file_close(void *file, hid_t H5_ATTR_UNUSED dxpl_id, void H5_ATTR_U /* This routine should only be called when a file ID's ref count drops to zero */ HDassert(f->shared == NULL || H5F_ID_EXISTS(f)); - if(f->shared == NULL) + if (f->shared == NULL) f = H5FL_FREE(H5F_t, f); else { @@ -781,7 +781,6 @@ H5VL__native_file_close(void *file, hid_t H5_ATTR_UNUSED dxpl_id, void H5_ATTR_U /* Close the file */ if (H5F__close(f) < 0) HGOTO_ERROR(H5E_FILE, H5E_CANTDEC, FAIL, "can't close file") - } done: From c0d0c390a3c2532e36b853945cca46227af634ed Mon Sep 17 00:00:00 2001 From: vchoi Date: Wed, 14 Dec 2022 19:54:20 -0600 Subject: [PATCH 3/7] Add test and release note info for fix to HDFFV-11052 which is merged via PR#2291. --- release_docs/RELEASE.txt | 19 +++++++++++++++++++ test/cve_2020_10812.h5 | Bin 0 -> 2565 bytes test/tmisc.c | 39 +++++++++++++++++++++++++++++++++++++++ 3 files changed, 58 insertions(+) create mode 100755 test/cve_2020_10812.h5 diff --git a/release_docs/RELEASE.txt b/release_docs/RELEASE.txt index 682addd6de8..a1117a0c9df 100644 --- a/release_docs/RELEASE.txt +++ b/release_docs/RELEASE.txt @@ -171,6 +171,25 @@ Bug Fixes since HDF5-1.13.3 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) + - Fix CVE-2018-13867 / GHSA-j8jr-chrh-qfrf Validate location (offset) of the accumulated metadata when comparing. diff --git a/test/cve_2020_10812.h5 b/test/cve_2020_10812.h5 new file mode 100755 index 0000000000000000000000000000000000000000..a20369da0db50a0d12400e9f886f2a431fbdfe6e GIT binary patch literal 2565 zcmeD5aB<`1lHy|G;9!6O11N))3&J=7<-f7G)6K{Lf(#5DP%#OH1_l!_n-L@o1_BU@ zi(vvMgaxDj(+B`_7|ufp*`h{i7i;8UmvsK Date: Thu, 15 Dec 2022 02:19:47 +0000 Subject: [PATCH 4/7] Committing clang-format changes --- test/tmisc.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/test/tmisc.c b/test/tmisc.c index 8bd9db5e707..8a70a2921e8 100644 --- a/test/tmisc.c +++ b/test/tmisc.c @@ -6051,7 +6051,7 @@ test_misc36(void) /**************************************************************** ** -** test_misc37(): +** test_misc37(): ** 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. @@ -6061,14 +6061,14 @@ static void test_misc37(void) { const char *fname; - hid_t fid; - herr_t ret; + 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); + fid = H5Fopen(fname, H5F_ACC_RDONLY, H5P_DEFAULT); CHECK(fid, FAIL, "H5Fopen"); /* This should fail due to the illegal file size. From 58fec30c50ffe415dd3706acd0f48e2a9693767e Mon Sep 17 00:00:00 2001 From: vchoi Date: Wed, 14 Dec 2022 21:44:08 -0600 Subject: [PATCH 5/7] Add the test file to Cmake. --- test/CMakeTests.cmake | 1 + 1 file changed, 1 insertion(+) diff --git a/test/CMakeTests.cmake b/test/CMakeTests.cmake index 74f63f43aed..508619430cc 100644 --- a/test/CMakeTests.cmake +++ b/test/CMakeTests.cmake @@ -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-000000.h5 family_v16-000001.h5 From cb0de48198b4fa788cfc461ac80035bee5b80205 Mon Sep 17 00:00:00 2001 From: vchoi Date: Fri, 16 Dec 2022 13:04:42 -0600 Subject: [PATCH 6/7] Skip test_misc37() for drivers that is not default compatible as it is using a pre-generated file. --- test/tmisc.c | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/test/tmisc.c b/test/tmisc.c index 8a70a2921e8..ec7a715190b 100644 --- a/test/tmisc.c +++ b/test/tmisc.c @@ -6060,15 +6060,23 @@ test_misc36(void) static void test_misc37(void) { - const char *fname; + const char *testfile = H5_get_srcdir_filename(CVE_2020_10812_FILENAME); + hbool_t driver_is_default_compatible; 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); + ret = h5_driver_is_default_vfd_compatible(H5P_DEFAULT, &driver_is_default_compatible); + CHECK(ret, FAIL, "h5_driver_is_default_vfd_compatible"); + + if (!driver_is_default_compatible) { + HDprintf("-- SKIPPED --\n"); + return; + } + + fid = H5Fopen(testfile, H5F_ACC_RDONLY, H5P_DEFAULT); CHECK(fid, FAIL, "H5Fopen"); /* This should fail due to the illegal file size. From 9d13a1df73e5c15e442aeadc80c7c910cbb4e703 Mon Sep 17 00:00:00 2001 From: github-actions <41898282+github-actions[bot]@users.noreply.github.com> Date: Fri, 16 Dec 2022 19:10:04 +0000 Subject: [PATCH 7/7] Committing clang-format changes --- test/tmisc.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/tmisc.c b/test/tmisc.c index ec7a715190b..5fb44d46fa5 100644 --- a/test/tmisc.c +++ b/test/tmisc.c @@ -6076,7 +6076,7 @@ test_misc37(void) return; } - fid = H5Fopen(testfile, H5F_ACC_RDONLY, H5P_DEFAULT); + fid = H5Fopen(testfile, H5F_ACC_RDONLY, H5P_DEFAULT); CHECK(fid, FAIL, "H5Fopen"); /* This should fail due to the illegal file size.