Description
Affected Projects
hdf5 v1.14.6 (https://github.com/HDFGroup/hdf5)
Problem Type
CWE-476: NULL Pointer Dereference
Description
Summary
A null pointer read vulnerability was discovered in the H5O__cache_chk_serialize
function within the HDF5 Library. This issue occurs when processing certain files, leading to a potential application crash.
Details
The vulnerability arises in the H5O__cache_chk_serialize
function defined in src/H5Ocache.c
at line 788
.
The reason is that the function H5O__cache_chk_serialize
did not check the validity of chk_proxy->oh->chunk[chk_proxy->chunkno].image
before calling H5MM_memcpy
, resulting in a null pointer dereference read.
static herr_t
H5O__cache_chk_serialize(const H5F_t *f, void *image, size_t len, void *_thing)
{
H5O_chunk_proxy_t *chk_proxy = (H5O_chunk_proxy_t *)_thing; /* Object header chunk to serialize */
herr_t ret_value = SUCCEED;
FUNC_ENTER_PACKAGE
assert(f);
assert(image);
assert(chk_proxy);
assert(chk_proxy->cache_info.type == H5AC_OHDR_CHK);
assert(chk_proxy->oh);
assert(chk_proxy->oh->chunk[chk_proxy->chunkno].size == len);
/* Serialize messages for this chunk */
if (H5O__chunk_serialize(f, chk_proxy->oh, chk_proxy->chunkno) < 0)
HGOTO_ERROR(H5E_OHDR, H5E_CANTSERIALIZE, FAIL,
"unable to serialize object header continuation chunk");
/* copy the chunk into the image -- this is potentially expensive.
* Can we rework things so that the chunk and the cache share a buffer?
*/
/* Ensure len does not exceed the size of the source buffer */
if (len > chk_proxy->oh->chunk[chk_proxy->chunkno].size)
HGOTO_ERROR(H5E_OHDR, H5E_OVERFLOW, FAIL, "buffer overflow detected");
H5MM_memcpy(image, chk_proxy->oh->chunk[chk_proxy->chunkno].image, len); //read null pointer
done:
FUNC_LEAVE_NOAPI(ret_value)
} /* end H5O__cache_chk_serialize() */
PoC
Steps to reproduce:
- Clone the hdf5 repository and build it using the following commands :
export CC='clang'
export CXX='clang++'
export CFLAGS='-fsanitize=address -g'
export CXXFLAGS='-fsanitize=address -g'
export LDFLAGS="${CFLAGS}"
export CMAKE_C_FLAGS="${CC} ${CFLAGS}"
export CMAKE_CXX_FLAGS="${CXX} ${CXXFLAGS}"
mkdir build-dir
cd build-dir
cmake -G "Unix Makefiles" \
-DCMAKE_BUILD_TYPE:STRING=Release \
-DBUILD_SHARED_LIBS:BOOL=OFF \
-DBUILD_TESTING:BOOL=OFF \
-DCMAKE_VERBOSE_MAKEFILES:BOOL=ON \
-DHDF5_BUILD_EXAMPLES:BOOL=OFF \
-DHDF5_BUILD_TOOLS:BOOL=OFF \
-DHDF5_ENABLE_SANITIZERS:BOOL=ON \
-DHDF5_ENABLE_Z_LIB_SUPPORT:BOOL=ON \
..
cmake --build . --verbose --config Release -j$(nproc)
- Compile the fuzzer:
- harness h5_extended_fuzzer.c from oss-fuzz:
#include "hdf5.h"
#include <unistd.h>
extern int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size)
{
char filename[256];
sprintf(filename, "/tmp/libfuzzer.%d", getpid());
FILE *fp = fopen(filename, "wb");
if (!fp) {
return 0;
}
fwrite(data, size, 1, fp);
fclose(fp);
hid_t fuzz_h5_id = H5Fopen(filename, H5F_ACC_RDWR, H5P_DEFAULT);
if (fuzz_h5_id != H5I_INVALID_HID) {
hid_t dataset_id = H5Dopen2(fuzz_h5_id, "dsetname", H5P_DEFAULT);
if (dataset_id != H5I_INVALID_HID) {
hid_t attribute_id = H5Aopen_name(dataset_id, "theattr");
if (attribute_id != H5I_INVALID_HID) {
H5Aclose(attribute_id);
}
H5Dclose(dataset_id);
}
H5Fclose(fuzz_h5_id);
}
return 0;
}
export LIB_FUZZING_ENGINE='-fsanitize=fuzzer'
$CC $CFLAGS -std=c99 -c \
-I$SRC/hdf5/src -I$SRC/hdf5/build-dir/src -I./src/H5FDsubfiling/ \
$SRC/h5_extended_fuzzer.c
$CXX $CXXFLAGS $LIB_FUZZING_ENGINE h5_extended_fuzzer.o ./build-dir/bin/libhdf5.a -lz -o $OUT/h5_extended_fuzzer
- Run the fuzzer to trigger the segmentation fault:
H5O__cache_chk_serialize-npd.zip
./h5_extended_fuzzer ./H5O__cache_chk_serialize-npd
This will cause AddressSanitizer to report a segmentation fault during the execution of the post-processing logic.
ASAN Report
Running: ./H5O__cache_chk_serialize-npd
AddressSanitizer:DEADLYSIGNAL
=================================================================
==443==ERROR: AddressSanitizer: SEGV on unknown address 0x000000000000 (pc 0x7c53e78ca881 bp 0x7ffdcc9df6f0 sp 0x7ffdcc9deeb8 T0)
==443==The signal is caused by a READ memory access.
==443==Hint: address points to the zero page.
#0 0x7c53e78ca881 in memcpy string/../sysdeps/x86_64/multiarch/memmove-vec-unaligned-erms.S:222
#1 0x5fbdc39da031 in __asan_memcpy (/fuzz/fuzzers/cs/h5_extended_fuzzer+0x2c8031) (BuildId: 4f0aadfc2da7074efe3c033dd7d4d5301b6fc3b1)
#2 0x5fbdc3d05736 in H5O__cache_chk_serialize /fuzz/project/hdf5/src/H5Ocache.c:788:5
#3 0x5fbdc3a88e7c in H5C__generate_image /fuzz/project/hdf5/src/H5Centry.c:374:9
#4 0x5fbdc3a856a1 in H5C__flush_single_entry /fuzz/project/hdf5/src/H5Centry.c:553:17
#5 0x5fbdc3aadf41 in H5C__flush_ring /fuzz/project/hdf5/src/H5Cint.c:1748:25
#6 0x5fbdc3a7f3fa in H5C_flush_cache /fuzz/project/hdf5/src/H5C.c:710:17
#7 0x5fbdc3ac18bc in H5C_flush_tagged_entries /fuzz/project/hdf5/src/H5Ctag.c:654:9
#8 0x5fbdc3a476dc in H5AC_flush_tagged_metadata /fuzz/project/hdf5/src/H5AC.c:2208:9
#9 0x5fbdc3b92221 in H5F_flush_tagged_metadata /fuzz/project/hdf5/src/H5Fio.c:421:9
#10 0x5fbdc3b81432 in H5F_open /fuzz/project/hdf5/src/H5Fint.c:2211:17
#11 0x5fbdc42faa5b in H5VL__native_file_open /fuzz/project/hdf5/src/H5VLnative_file.c:127:9
#12 0x5fbdc42c7015 in H5VL__file_open /fuzz/project/hdf5/src/H5VLcallback.c:3714:25
#13 0x5fbdc42c686a in H5VL_file_open /fuzz/project/hdf5/src/H5VLcallback.c:3832:30
#14 0x5fbdc3b63b19 in H5F__open_api_common /fuzz/project/hdf5/src/H5F.c:780:29
#15 0x5fbdc3b6326b in H5Fopen /fuzz/project/hdf5/src/H5F.c:820:22
#16 0x5fbdc3a1817c in LLVMFuzzerTestOneInput /fuzz/project/h5_extended_fuzzer.c:29:24
#17 0x5fbdc393e5a3 in fuzzer::Fuzzer::ExecuteCallback(unsigned char const*, unsigned long) (/fuzz/fuzzers/cs/h5_extended_fuzzer+0x22c5a3) (BuildId: 4f0aadfc2da7074efe3c033dd7d4d5301b6fc3b1)
#18 0x5fbdc392831f in fuzzer::RunOneTest(fuzzer::Fuzzer*, char const*, unsigned long) (/fuzz/fuzzers/cs/h5_extended_fuzzer+0x21631f) (BuildId: 4f0aadfc2da7074efe3c033dd7d4d5301b6fc3b1)
#19 0x5fbdc392e076 in fuzzer::FuzzerDriver(int*, char***, int (*)(unsigned char const*, unsigned long)) (/fuzz/fuzzers/cs/h5_extended_fuzzer+0x21c076) (BuildId: 4f0aadfc2da7074efe3c033dd7d4d5301b6fc3b1)
#20 0x5fbdc3957e92 in main (/fuzz/fuzzers/cs/h5_extended_fuzzer+0x245e92) (BuildId: 4f0aadfc2da7074efe3c033dd7d4d5301b6fc3b1)
#21 0x7c53e782fd8f in __libc_start_call_main csu/../sysdeps/nptl/libc_start_call_main.h:58:16
#22 0x7c53e782fe3f in __libc_start_main csu/../csu/libc-start.c:392:3
#23 0x5fbdc3922be4 in _start (/fuzz/fuzzers/cs/h5_extended_fuzzer+0x210be4) (BuildId: 4f0aadfc2da7074efe3c033dd7d4d5301b6fc3b1)
AddressSanitizer can not provide additional info.
SUMMARY: AddressSanitizer: SEGV string/../sysdeps/x86_64/multiarch/memmove-vec-unaligned-erms.S:222 in memcpy
==443==ABORTING