hdf5 icon indicating copy to clipboard operation
hdf5 copied to clipboard

[BUG, CVE-2021-46242] Heap use after free in H5AC_unpin_entry()

Open e4t opened this issue 2 years ago • 0 comments

Describe the bug The reproducer of CVE-2021-46242 exposes a heap use after free error on version 1.10.8 which makes the application crash. This crash can no longer be reproduced on 1.13 - presumably due to commit aa688c68c447c. This commit, however, seems to be unrelated to the issue that causes the crash and I believe the analysis below remain valid regardless: The use-after-free occurs in

H5AC_unpin_entry(void *thing)
{
...
    entry_ptr = (H5AC_info_t *)thing;
    cache_ptr = entry_ptr->cache_ptr;
...

    if (cache_ptr != NULL && cache_ptr->log_info != NULL)
        if (cache_ptr->log_info->logging)
-->             if (cache_ptr->log_info->logging)
...
}

called from:

herr_t
H5F__dest(H5F_t *f, hbool_t flush)
{
...
            if (f->shared->drvinfo)
                if (H5AC_unpin_entry(f->shared->drvinfo) < 0)
...
}

Valgrind reveals that f->shared->drvinfo was freed in

H5F__super_read(..)
{
...
   if (ret_value < 0) {
        /* Unpin and discard drvinfo cache entry */
        if (f->shared->drvinfo) {
            if (H5AC_unpin_entry(f->shared->drvinfo) < 0)
                HDONE_ERROR(H5E_FILE, H5E_CANTUNPIN, FAIL, "unable to unpin driver info")

            /* Evict the driver info block from the cache */
-->        if (sblock && H5AC_expunge_entry(f, H5AC_DRVRINFO, sblock->driver_addr, H5AC__NO_FLAGS_SET) < 0)
                HDONE_ERROR(H5E_FILE, H5E_CANTEXPUNGE, FAIL, "unable to expunge driver info block")
        } /* end if */
 ...
  }
...
}

Since H5C_expunge_entry() (called from H5AC_expunge_entry()) sets the H5C__FLUSH_INVALIDATE_FLAG, the entry is destroyed (ie. deallocated). The pointer f->shared->drvinfo is however not NULLed. When H5AC_unpin_entry() is called again from H5F__dest() a use-after-free occurs.

Expected behavior f->shared->drvinfo should be NULLed, after the call to H5AC_expunge_entry(). In the same vein f->shared->sblock should probably also be NULLed after the call to H5AC_expunge_entry(..,H5AC_SUPERBLOCK,..). In other parts of the code, these pointers are checked already. These checks will ensure that these pointers are dereferenced only when initialized.

Platform

  • 1.10.8 and earlier
  • openSUSE Leap 15.4/ SLE 15 SP4 / openSUSE Tumbleweed
  • gcc7
  • Autotools
  • config --enable-fortran --enable-unsupported --enable-hl --enable-shared --enable-threadsafe --enable-build-mode=production --enable-cxx --with-pthread

e4t avatar Nov 11 '22 22:11 e4t