Sign Up
Log In
Log In
or
Sign Up
Places
All Projects
Status Monitor
Collapse sidebar
SUSE:SLE-15:Update
hdf5
Pass-compact-chunk-size-info-to-ensure-requeste...
Overview
Repositories
Revisions
Requests
Users
Attributes
Meta
File Pass-compact-chunk-size-info-to-ensure-requested-elements-are-within-bounds.patch of Package hdf5
From: Egbert Eich <eich@suse.com> Date: Sat Oct 1 15:13:52 2022 +0200 Subject: Pass compact chunk size info to ensure requested elements are within bounds Patch-mainline: Not yet Git-repo: https://github.com/HDFGroup/hdf5 Git-commit: 0bce664fd82795520bf706a741a183acb69476c3 References: To avoid reading/writing elements out of bounds of a compact chunk, pass size info and check whether all elements are within the size before attempting to read/write these elements. Such accesses can occur when accessing malformed hdf5 files. This fixes CVE-2018-11205 Signed-off-by: Egbert Eich <eich@suse.com> Signed-off-by: Egbert Eich <eich@suse.de> --- src/H5Dchunk.c | 36 ++++++++++++++++++++++++++++-------- src/H5Dcompact.c | 6 ++++++ src/H5Dpkg.h | 1 + 3 files changed, 35 insertions(+), 8 deletions(-) diff --git a/src/H5Dchunk.c b/src/H5Dchunk.c index a727d88602..6c3c69b28d 100644 --- a/src/H5Dchunk.c +++ b/src/H5Dchunk.c @@ -128,6 +128,7 @@ typedef struct H5D_rdcc_ent_t { H5F_block_t chunk_block; /*offset/length of chunk in file */ hsize_t chunk_idx; /*index of chunk in dataset */ uint8_t * chunk; /*the unfiltered chunk data */ + size_t size; /*size of chunk */ unsigned idx; /*index in hash table */ struct H5D_rdcc_ent_t *next; /*next item in doubly-linked list */ struct H5D_rdcc_ent_t *prev; /*previous item in doubly-linked list */ @@ -303,7 +304,7 @@ static herr_t H5D__chunk_cache_evict(const H5D_t *dset, H5D_rdcc_ent_t *ent, h static hbool_t H5D__chunk_is_partial_edge_chunk(unsigned dset_ndims, const uint32_t *chunk_dims, const hsize_t *chunk_scaled, const hsize_t *dset_dims); static void * H5D__chunk_lock(const H5D_io_info_t *io_info, H5D_chunk_ud_t *udata, hbool_t relax, - hbool_t prev_unfilt_chunk); + hbool_t prev_unfilt_chunk, size_t *ret_size); static herr_t H5D__chunk_unlock(const H5D_io_info_t *io_info, const H5D_chunk_ud_t *udata, hbool_t dirty, void *chunk, uint32_t naccessed); static herr_t H5D__chunk_cache_prune(const H5D_t *dset, size_t size); @@ -2455,6 +2456,7 @@ H5D__chunk_read(H5D_io_info_t *io_info, const H5D_type_info_t *type_info, hsize_ uint32_t src_accessed_bytes = 0; /* Total accessed size in a chunk */ hbool_t skip_missing_chunks = FALSE; /* Whether to skip missing chunks */ herr_t ret_value = SUCCEED; /*return value */ + size_t chunk_size = 0; FUNC_ENTER_STATIC @@ -2540,11 +2542,12 @@ H5D__chunk_read(H5D_io_info_t *io_info, const H5D_type_info_t *type_info, hsize_ src_accessed_bytes = chunk_info->chunk_points * (uint32_t)type_info->src_type_size; /* Lock the chunk into the cache */ - if (NULL == (chunk = H5D__chunk_lock(io_info, &udata, FALSE, FALSE))) + if (NULL == (chunk = H5D__chunk_lock(io_info, &udata, FALSE, FALSE, &chunk_size))) HGOTO_ERROR(H5E_IO, H5E_READERROR, FAIL, "unable to read raw data chunk") /* Set up the storage buffer information for this chunk */ cpt_store.compact.buf = chunk; + cpt_store.compact.size = chunk_size; /* Point I/O info at contiguous I/O info for this chunk */ chk_io_info = &cpt_io_info; @@ -2604,6 +2607,7 @@ H5D__chunk_write(H5D_io_info_t *io_info, const H5D_type_info_t *type_info, hsize hbool_t cpt_dirty; /* Temporary placeholder for compact storage "dirty" flag */ uint32_t dst_accessed_bytes = 0; /* Total accessed size in a chunk */ herr_t ret_value = SUCCEED; /* Return value */ + size_t chunk_size; FUNC_ENTER_STATIC @@ -2674,11 +2678,12 @@ H5D__chunk_write(H5D_io_info_t *io_info, const H5D_type_info_t *type_info, hsize entire_chunk = FALSE; /* Lock the chunk into the cache */ - if (NULL == (chunk = H5D__chunk_lock(io_info, &udata, entire_chunk, FALSE))) + if (NULL == (chunk = H5D__chunk_lock(io_info, &udata, entire_chunk, FALSE, &chunk_size))) HGOTO_ERROR(H5E_IO, H5E_READERROR, FAIL, "unable to read raw data chunk") /* Set up the storage buffer information for this chunk */ cpt_store.compact.buf = chunk; + cpt_store.compact.size = chunk_size; /* Point I/O info at main I/O info for this chunk */ chk_io_info = &cpt_io_info; @@ -3674,7 +3679,7 @@ done: *------------------------------------------------------------------------- */ static void * -H5D__chunk_lock(const H5D_io_info_t *io_info, H5D_chunk_ud_t *udata, hbool_t relax, hbool_t prev_unfilt_chunk) +H5D__chunk_lock(const H5D_io_info_t *io_info, H5D_chunk_ud_t *udata, hbool_t relax, hbool_t prev_unfilt_chunk, size_t *ret_size) { const H5D_t * dset = io_info->dset; /* Local pointer to the dataset info */ const H5O_pline_t *pline = @@ -3691,6 +3696,7 @@ H5D__chunk_lock(const H5D_io_info_t *io_info, H5D_chunk_ud_t *udata, hbool_t rel hbool_t disable_filters = FALSE; /* Whether to disable filters (when adding to cache) */ void * chunk = NULL; /*the file chunk */ void * ret_value = NULL; /* Return value */ + size_t chunk_size_ret = 0; FUNC_ENTER_STATIC @@ -3756,6 +3762,7 @@ H5D__chunk_lock(const H5D_io_info_t *io_info, H5D_chunk_ud_t *udata, hbool_t rel ent->chunk = (uint8_t *)H5D__chunk_mem_xfree(ent->chunk, old_pline); ent->chunk = (uint8_t *)chunk; chunk = NULL; + ent->size = chunk_size; /* Mark the chunk as having filters disabled as well as "newly * disabled" so it is inserted on flush */ @@ -3783,6 +3790,7 @@ H5D__chunk_lock(const H5D_io_info_t *io_info, H5D_chunk_ud_t *udata, hbool_t rel ent->chunk = (uint8_t *)H5D__chunk_mem_xfree(ent->chunk, old_pline); ent->chunk = (uint8_t *)chunk; chunk = NULL; + ent->size = chunk_size; /* Mark the chunk as having filters enabled */ ent->edge_chunk_state &= ~(H5D_RDCC_DISABLE_FILTERS | H5D_RDCC_NEWLY_DISABLED_FILTERS); @@ -3862,6 +3870,7 @@ H5D__chunk_lock(const H5D_io_info_t *io_info, H5D_chunk_ud_t *udata, hbool_t rel /* In the case that some dataset functions look through this data, * clear it to all 0s. */ HDmemset(chunk, 0, chunk_size); + chunk_size_ret = chunk_size; } /* end if */ else { /* @@ -3883,6 +3892,7 @@ H5D__chunk_lock(const H5D_io_info_t *io_info, H5D_chunk_ud_t *udata, hbool_t rel if (H5F_block_read(dset->oloc.file, H5FD_MEM_DRAW, chunk_addr, my_chunk_alloc, chunk) < 0) HGOTO_ERROR(H5E_IO, H5E_READERROR, NULL, "unable to read raw data chunk") + chunk_size_ret = my_chunk_alloc; if (old_pline && old_pline->nused) { H5Z_EDC_t err_detect; /* Error detection info */ H5Z_cb_t filter_cb; /* I/O filter callback function */ @@ -3896,6 +3906,7 @@ H5D__chunk_lock(const H5D_io_info_t *io_info, H5D_chunk_ud_t *udata, hbool_t rel if (H5Z_pipeline(old_pline, H5Z_FLAG_REVERSE, &(udata->filter_mask), err_detect, filter_cb, &my_chunk_alloc, &buf_alloc, &chunk) < 0) HGOTO_ERROR(H5E_DATASET, H5E_CANTFILTER, NULL, "data pipeline read failed") + chunk_size_ret = buf_alloc; /* Reallocate chunk if necessary */ if (udata->new_unfilt_chunk) { @@ -3906,6 +3917,8 @@ H5D__chunk_lock(const H5D_io_info_t *io_info, H5D_chunk_ud_t *udata, hbool_t rel HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, NULL, "memory allocation failed for raw data chunk") } /* end if */ + chunk_size_ret = my_chunk_alloc; + /* orly? */ H5MM_memcpy(chunk, tmp_chunk, chunk_size); (void)H5D__chunk_mem_xfree(tmp_chunk, old_pline); } /* end if */ @@ -3926,6 +3939,7 @@ H5D__chunk_lock(const H5D_io_info_t *io_info, H5D_chunk_ud_t *udata, hbool_t rel HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, NULL, "memory allocation failed for raw data chunk") + chunk_size_ret = chunk_size; if (H5P_is_fill_value_defined(fill, &fill_status) < 0) HGOTO_ERROR(H5E_PLIST, H5E_CANTGET, NULL, "can't tell if fill value defined") @@ -3991,6 +4005,7 @@ H5D__chunk_lock(const H5D_io_info_t *io_info, H5D_chunk_ud_t *udata, hbool_t rel H5_CHECKED_ASSIGN(ent->rd_count, uint32_t, chunk_size, size_t); H5_CHECKED_ASSIGN(ent->wr_count, uint32_t, chunk_size, size_t); ent->chunk = (uint8_t *)chunk; + ent->size = chunk_size_ret; /* Add it to the cache */ HDassert(NULL == rdcc->slot[udata->idx_hint]); @@ -4024,6 +4039,7 @@ H5D__chunk_lock(const H5D_io_info_t *io_info, H5D_chunk_ud_t *udata, hbool_t rel HDassert(!ent->locked); ent->locked = TRUE; chunk = ent->chunk; + chunk_size_ret = ent->size; } /* end if */ else /* @@ -4035,6 +4051,8 @@ H5D__chunk_lock(const H5D_io_info_t *io_info, H5D_chunk_ud_t *udata, hbool_t rel /* Set return value */ ret_value = chunk; + if (ret_size != NULL) + *ret_size = chunk_size_ret; done: /* Release the fill buffer info, if it's been initialized */ @@ -4043,9 +4061,11 @@ done: /* Release the chunk allocated, on error */ if (!ret_value) - if (chunk) + if (chunk) { chunk = H5D__chunk_mem_xfree(chunk, pline); - + if (ret_size != NULL) + *ret_size = 0; + } FUNC_LEAVE_NOAPI(ret_value) } /* end H5D__chunk_lock() */ @@ -4836,7 +4856,7 @@ H5D__chunk_update_old_edge_chunks(H5D_t *dset, hsize_t old_dim[]) if (H5F_addr_defined(chk_udata.chunk_block.offset) || (UINT_MAX != chk_udata.idx_hint)) { /* Lock the chunk into cache. H5D__chunk_lock will take care of * updating the chunk to no longer be an edge chunk. */ - if (NULL == (chunk = (void *)H5D__chunk_lock(&chk_io_info, &chk_udata, FALSE, TRUE))) + if (NULL == (chunk = (void *)H5D__chunk_lock(&chk_io_info, &chk_udata, FALSE, TRUE, NULL))) HGOTO_ERROR(H5E_DATASET, H5E_READERROR, FAIL, "unable to lock raw data chunk") /* Unlock the chunk */ @@ -5143,7 +5163,7 @@ H5D__chunk_prune_fill(H5D_chunk_it_ud1_t *udata, hbool_t new_unfilt_chunk) HGOTO_ERROR(H5E_DATASET, H5E_CANTSELECT, FAIL, "unable to select hyperslab") /* Lock the chunk into the cache, to get a pointer to the chunk buffer */ - if (NULL == (chunk = (void *)H5D__chunk_lock(io_info, &chk_udata, FALSE, FALSE))) + if (NULL == (chunk = (void *)H5D__chunk_lock(io_info, &chk_udata, FALSE, FALSE, NULL))) HGOTO_ERROR(H5E_DATASET, H5E_READERROR, FAIL, "unable to lock raw data chunk") /* Fill the selection in the memory buffer */ diff --git a/src/H5Dcompact.c b/src/H5Dcompact.c index 8d823adcea..d0831c019a 100644 --- a/src/H5Dcompact.c +++ b/src/H5Dcompact.c @@ -234,6 +234,7 @@ H5D__compact_io_init(const H5D_io_info_t *io_info, const H5D_type_info_t H5_ATTR FUNC_ENTER_STATIC_NOERR io_info->store->compact.buf = io_info->dset->shared->layout.storage.u.compact.buf; + io_info->store->compact.size = io_info->dset->shared->layout.storage.u.compact.size; io_info->store->compact.dirty = &io_info->dset->shared->layout.storage.u.compact.dirty; FUNC_LEAVE_NOAPI(SUCCEED) @@ -267,6 +268,8 @@ H5D__compact_readvv(const H5D_io_info_t *io_info, size_t dset_max_nseq, size_t * FUNC_ENTER_STATIC HDassert(io_info); + if (io_info->store->compact.size < *(dset_offset_arr + dset_max_nseq - 1) + *(dset_size_arr + dset_max_nseq - 1)) + HGOTO_ERROR(H5E_IO, H5E_WRITEERROR, FAIL, "source size less than requested data") /* Use the vectorized memory copy routine to do actual work */ if ((ret_value = H5VM_memcpyvv(io_info->u.rbuf, mem_max_nseq, mem_curr_seq, mem_size_arr, mem_offset_arr, @@ -309,6 +312,9 @@ H5D__compact_writevv(const H5D_io_info_t *io_info, size_t dset_max_nseq, size_t FUNC_ENTER_STATIC HDassert(io_info); + if (io_info->store->compact.size < *(dset_offset_arr + dset_max_nseq - 1) + *(dset_size_arr + dset_max_nseq - 1)) { + HGOTO_ERROR(H5E_IO, H5E_WRITEERROR, FAIL, "source size less than requested data") + } /* Use the vectorized memory copy routine to do actual work */ if ((ret_value = H5VM_memcpyvv(io_info->store->compact.buf, dset_max_nseq, dset_curr_seq, dset_size_arr, diff --git a/src/H5Dpkg.h b/src/H5Dpkg.h index 16e101c012..ccdd1675a1 100644 --- a/src/H5Dpkg.h +++ b/src/H5Dpkg.h @@ -194,6 +194,7 @@ typedef struct { typedef struct { void * buf; /* Buffer for compact dataset */ hbool_t *dirty; /* Pointer to dirty flag to mark */ + size_t size; /* Buffer size for compact dataset */ } H5D_compact_storage_t; typedef union H5D_storage_t {
Locations
Projects
Search
Status Monitor
Help
OpenBuildService.org
Documentation
API Documentation
Code of Conduct
Contact
Support
@OBShq
Terms
openSUSE Build Service is sponsored by
The Open Build Service is an
openSUSE project
.
Sign Up
Log In
Places
Places
All Projects
Status Monitor