Skip to content

Heap-based Buffer Overflow in H5F__accum_free #5380

@sae-as-me

Description

@sae-as-me

Affected Projects

hdf5 v1.14.6 (https://github.com/HDFGroup/hdf5)

Problem Type

CWE-122: Heap-based Buffer Overflow

Description

Summary

A heap-buffer-overflow vulnerability was discovered in the H5F__accum_free function within the HDF5 Library. This issue occurs when processing certain files, leading to an out-of-bounds read and potential application crash.

Details

The vulnerability arises in the H5F__accum_free function defined in src/H5Faccum.c at line 885. The function failed to correctly check the value of overlap_size (which may be a large value) and buffer boundaries, resulting in buffer overflow and read operations exceeding allocated memory when calling function memmove.

herr_t
H5F__accum_free(H5F_shared_t *f_sh, H5FD_mem_t H5_ATTR_UNUSED type, haddr_t addr, hsize_t size)
{
    H5F_meta_accum_t *accum;               /* Alias for file's metadata accumulator */
    H5FD_t           *file;                /* File driver pointer */
    herr_t            ret_value = SUCCEED; /* Return value */

    FUNC_ENTER_PACKAGE

    /* check arguments */
    assert(f_sh);

    /* Set up alias for file's metadata accumulator info */
    accum = &f_sh->accum;

    /* Translate to file driver pointer */
    file = f_sh->lf;

    /* Adjust the metadata accumulator to remove the freed block, if it overlaps */
    if ((f_sh->feature_flags & H5FD_FEAT_ACCUMULATE_METADATA) && H5_addr_defined(accum->loc) &&
        H5_addr_overlap(addr, size, accum->loc, accum->size)) {
        size_t overlap_size; /* Size of overlap with accumulator */

        /* Sanity check */
        /* (The metadata accumulator should not intersect w/raw data */
        assert(H5FD_MEM_DRAW != type);
        assert(H5FD_MEM_GHEAP != type); /* (global heap data is being treated as raw data currently) */

        /* Check for overlapping the beginning of the accumulator */
        if (H5_addr_le(addr, accum->loc)) {
            /* Check for completely overlapping the accumulator */
            if (H5_addr_ge(addr + size, accum->loc + accum->size)) {
                /* Reset the accumulator, but don't free buffer */
                accum->loc   = HADDR_UNDEF;
                accum->size  = 0;
                accum->dirty = false;
            } /* end if */
            /* Block to free must end within the accumulator */
            else {
                size_t new_accum_size; /* Size of new accumulator buffer */

                /* Calculate the size of the overlap with the accumulator, etc. */
                H5_CHECKED_ASSIGN(overlap_size, size_t, (addr + size) - accum->loc, haddr_t);
                new_accum_size = accum->size - overlap_size;

                /* Move the accumulator buffer information to eliminate the freed block */
                memmove(accum->buf, accum->buf + overlap_size, new_accum_size);    //heap-buffer-overflow

                /* Adjust the accumulator information */
                accum->loc += overlap_size;
                accum->size = new_accum_size;

                /* ... other code */
            }         /* end else */
        }             /* end if */
        /* ...other code */
        
    }     /* end if */

done:
    FUNC_LEAVE_NOAPI(ret_value)
} /* end H5F__accum_free() */

Image

PoC

Steps to reproduce:

  1. 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)
  1. 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
  1. Run the fuzzer to trigger the segmentation fault:

H5F__accum_free-hbo.zip

./h5_extended_fuzzer ./H5F__accum_free-hbo

The invalid read access will cause AddressSanitizer to report a segmentation fault during the execution of the post-processing logic.

Report

Running: ./H5F__accum_free-hbo
HDF5-DIAG: Error detected in HDF5 (2.0.0):
  #000: /fuzz/project/hdf5/src/H5D.c line 401 in H5Dopen2(): unable to synchronously open dataset
    major: Dataset
    minor: Can't open object
  #001: /fuzz/project/hdf5/src/H5D.c line 363 in H5D__open_api_common(): unable to open dataset
    major: Dataset
    minor: Can't open object
  #002: /fuzz/project/hdf5/src/H5VLcallback.c line 2090 in H5VL_dataset_open(): dataset open failed
    major: Virtual Object Layer
    minor: Can't open object
  #003: /fuzz/project/hdf5/src/H5VLcallback.c line 2057 in H5VL__dataset_open(): dataset open failed
    major: Virtual Object Layer
    minor: Can't open object
  #004: /fuzz/project/hdf5/src/H5VLnative_dataset.c line 332 in H5VL__native_dataset_open(): unable to open dataset
    major: Dataset
    minor: Can't open object
  #005: /fuzz/project/hdf5/src/H5Dint.c line 1472 in H5D__open_name(): not found
    major: Dataset
    minor: Object not found
  #006: /fuzz/project/hdf5/src/H5Gloc.c line 424 in H5G_loc_find(): can't find object
    major: Symbol table
    minor: Object not found
  #007: /fuzz/project/hdf5/src/H5Gtraverse.c line 846 in H5G_traverse(): internal path traversal failed
    major: Symbol table
    minor: Object not found
  #008: /fuzz/project/hdf5/src/H5Gtraverse.c line 573 in H5G__traverse_real(): can't look up component
    major: Symbol table
    minor: Object not found
  #009: /fuzz/project/hdf5/src/H5Gobj.c line 1070 in H5G__obj_lookup(): can't check for link info message
    major: Symbol table
    minor: Can't get value
  #010: /fuzz/project/hdf5/src/H5Gobj.c line 310 in H5G__obj_get_linfo(): unable to read object header
    major: Symbol table
    minor: Can't get value
  #011: /fuzz/project/hdf5/src/H5Omessage.c line 788 in H5O_msg_exists(): unable to protect object header
    major: Object header
    minor: Unable to protect metadata
  #012: /fuzz/project/hdf5/src/H5Oint.c line 1015 in H5O_protect(): unable to load object header
    major: Object header
    minor: Unable to protect metadata
  #013: /fuzz/project/hdf5/src/H5AC.c line 1303 in H5AC_protect(): H5C_protect() failed
    major: Object cache
    minor: Unable to protect metadata
  #014: /fuzz/project/hdf5/src/H5Centry.c line 3107 in H5C_protect(): can't load entry
    major: Object cache
    minor: Unable to load metadata into cache
  #015: /fuzz/project/hdf5/src/H5Centry.c line 1181 in H5C__load_entry(): incorrect metadata checksum after all read attempts
    major: Object cache
    minor: Read failed
  #016: /fuzz/project/hdf5/src/H5Ocache.c line 185 in H5O__cache_get_final_load_size(): can't deserialize object header prefix
    major: Object header
    minor: Unable to decode value
  #017: /fuzz/project/hdf5/src/H5Ocache.c line 1100 in H5O__prefix_deserialize(): bad object header version number
    major: Object header
    minor: Wrong version number
=================================================================
==169==ERROR: AddressSanitizer: heap-buffer-overflow on address 0x612000035297 at pc 0x58f8a738a39f bp 0x7ffdd32475c0 sp 0x7ffdd3246d90
READ of size 201 at 0x612000035297 thread T0
    #0 0x58f8a738a39e in __asan_memmove (/fuzz/fuzzers/cs/h5_extended_fuzzer+0x2c839e) (BuildId: 4f0aadfc2da7074efe3c033dd7d4d5301b6fc3b1)
    #1 0x58f8a7ddee05 in H5F__accum_free /fuzz/project/hdf5/src/H5Faccum.c:885:17
    #2 0x58f8a7690e88 in H5MF_xfree /fuzz/project/hdf5/src/H5MF.c:1093:13
    #3 0x58f8a769f6e5 in H5MF__aggr_reset /fuzz/project/hdf5/src/H5MFaggr.c:725:21
    #4 0x58f8a769f6e5 in H5MF_free_aggrs /fuzz/project/hdf5/src/H5MFaggr.c:789:13
    #5 0x58f8a7693b04 in H5MF__close_aggrfs /fuzz/project/hdf5/src/H5MF.c:1725:9
    #6 0x58f8a7693b04 in H5MF_close /fuzz/project/hdf5/src/H5MF.c:1512:26
    #7 0x58f8a753646a in H5F__dest /fuzz/project/hdf5/src/H5Fint.c:1488:21
    #8 0x58f8a7538fc8 in H5F_try_close /fuzz/project/hdf5/src/H5Fint.c:2680:9
    #9 0x58f8a75389a5 in H5F__close /fuzz/project/hdf5/src/H5Fint.c:2482:9
    #10 0x58f8a7cadf8b in H5VL__native_file_close /fuzz/project/hdf5/src/H5VLnative_file.c:777:13
    #11 0x58f8a7c7aa47 in H5VL__file_close /fuzz/project/hdf5/src/H5VLcallback.c:4326:25
    #12 0x58f8a7c7a575 in H5VL_file_close /fuzz/project/hdf5/src/H5VLcallback.c:4360:9
    #13 0x58f8a753fb7d in H5F__close_cb /fuzz/project/hdf5/src/H5Fint.c:249:9
    #14 0x58f8a76806ba in H5I__dec_ref /fuzz/project/hdf5/src/H5Iint.c:1076:30
    #15 0x58f8a7680afc in H5I__dec_app_ref /fuzz/project/hdf5/src/H5Iint.c:1156:22
    #16 0x58f8a76809e9 in H5I_dec_app_ref /fuzz/project/hdf5/src/H5Iint.c:1201:22
    #17 0x58f8a7515c0f in H5Fclose /fuzz/project/hdf5/src/H5F.c:1040:9
    #18 0x58f8a73c81e8 in LLVMFuzzerTestOneInput /fuzz/project/h5_extended_fuzzer.c:39:7
    #19 0x58f8a72ee5a3 in fuzzer::Fuzzer::ExecuteCallback(unsigned char const*, unsigned long) (/fuzz/fuzzers/cs/h5_extended_fuzzer+0x22c5a3) (BuildId: 4f0aadfc2da7074efe3c033dd7d4d5301b6fc3b1)
    #20 0x58f8a72d831f in fuzzer::RunOneTest(fuzzer::Fuzzer*, char const*, unsigned long) (/fuzz/fuzzers/cs/h5_extended_fuzzer+0x21631f) (BuildId: 4f0aadfc2da7074efe3c033dd7d4d5301b6fc3b1)
    #21 0x58f8a72de076 in fuzzer::FuzzerDriver(int*, char***, int (*)(unsigned char const*, unsigned long)) (/fuzz/fuzzers/cs/h5_extended_fuzzer+0x21c076) (BuildId: 4f0aadfc2da7074efe3c033dd7d4d5301b6fc3b1)
    #22 0x58f8a7307e92 in main (/fuzz/fuzzers/cs/h5_extended_fuzzer+0x245e92) (BuildId: 4f0aadfc2da7074efe3c033dd7d4d5301b6fc3b1)
    #23 0x72c74515bd8f in __libc_start_call_main csu/../sysdeps/nptl/libc_start_call_main.h:58:16
    #24 0x72c74515be3f in __libc_start_main csu/../csu/libc-start.c:392:3
    #25 0x58f8a72d2be4 in _start (/fuzz/fuzzers/cs/h5_extended_fuzzer+0x210be4) (BuildId: 4f0aadfc2da7074efe3c033dd7d4d5301b6fc3b1)

0x612000035297 is located 41 bytes to the left of 264-byte region [0x6120000352c0,0x6120000353c8)
allocated by thread T0 here:
    #0 0x58f8a738ac1e in malloc (/fuzz/fuzzers/cs/h5_extended_fuzzer+0x2c8c1e) (BuildId: 4f0aadfc2da7074efe3c033dd7d4d5301b6fc3b1)
    #1 0x58f8a75c028c in H5FL__malloc /fuzz/project/hdf5/src/H5FL.c:211:30
    #2 0x58f8a75c028c in H5FL_blk_malloc /fuzz/project/hdf5/src/H5FL.c:773:48

SUMMARY: AddressSanitizer: heap-buffer-overflow (/fuzz/fuzzers/cs/h5_extended_fuzzer+0x2c839e) (BuildId: 4f0aadfc2da7074efe3c033dd7d4d5301b6fc3b1) in __asan_memmove
Shadow bytes around the buggy address:
  0x0c247fffea00: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
  0x0c247fffea10: 00 00 00 00 00 00 00 00 00 fa fa fa fa fa fa fa
  0x0c247fffea20: fa fa fa fa fa fa fa fa 00 00 00 00 00 00 00 00
  0x0c247fffea30: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
  0x0c247fffea40: 00 00 00 00 00 00 00 00 00 fa fa fa fa fa fa fa
=>0x0c247fffea50: fa fa[fa]fa fa fa fa fa 00 00 00 00 00 00 00 00
  0x0c247fffea60: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
  0x0c247fffea70: 00 00 00 00 00 00 00 00 00 fa fa fa fa fa fa fa
  0x0c247fffea80: fa fa fa fa fa fa fa fa 00 00 00 00 00 00 00 00
  0x0c247fffea90: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
  0x0c247fffeaa0: 00 00 00 00 00 00 00 00 00 00 00 fa fa fa fa fa
Shadow byte legend (one shadow byte represents 8 application bytes):
  Addressable:           00
  Partially addressable: 01 02 03 04 05 06 07 
  Heap left redzone:       fa
  Freed heap region:       fd
  Stack left redzone:      f1
  Stack mid redzone:       f2
  Stack right redzone:     f3
  Stack after return:      f5
  Stack use after scope:   f8
  Global redzone:          f9
  Global init order:       f6
  Poisoned by user:        f7
  Container overflow:      fc
  Array cookie:            ac
  Intra object redzone:    bb
  ASan internal:           fe
  Left alloca redzone:     ca
  Right alloca redzone:    cb
==169==ABORTING

Metadata

Metadata

Assignees

Labels

Component - C LibraryCore C library issues (usually in the src directory)HDFG-internalInternally coded for use by the HDF GroupType - SecuritySecurity issues, including library crashers and memory leaks

Type

Projects

Status

In progress

Milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions