Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix memory leaks and aborts in H5O EFL decode #2708

Merged
merged 1 commit into from
Apr 13, 2023
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
109 changes: 61 additions & 48 deletions src/H5Oefl.c
Original file line number Diff line number Diff line change
Expand Up @@ -67,108 +67,121 @@ const H5O_msg_class_t H5O_MSG_EFL[1] = {{
* Purpose: Decode an external file list message and return a pointer to
* the message (and some other data).
*
* Return: Success: Ptr to a new message struct.
* We allow zero dimension size starting from the 1.8.7 release.
* The dataset size of external storage can be zero.
*
* Return: Success: Pointer to a new message struct
* Failure: NULL
*
* Programmer: Robb Matzke
* Tuesday, November 25, 1997
*
* Modification:
* Raymond Lu
* 11 April 2011
* We allow zero dimension size starting from the 1.8.7 release.
* The dataset size of external storage can be zero.
*-------------------------------------------------------------------------
*/
static void *
H5O_efl_decode(H5F_t *f, H5O_t H5_ATTR_UNUSED *open_oh, unsigned H5_ATTR_UNUSED mesg_flags,
unsigned H5_ATTR_UNUSED *ioflags, size_t H5_ATTR_UNUSED p_size, const uint8_t *p)
unsigned H5_ATTR_UNUSED *ioflags, size_t p_size, const uint8_t *p)
{
H5O_efl_t *mesg = NULL;
int version;
const char *s = NULL;
H5HL_t *heap;
size_t u; /* Local index variable */
void *ret_value = NULL; /* Return value */
H5O_efl_t *mesg = NULL;
int version;
const uint8_t *p_end = p + p_size - 1; /* pointer to last byte in p */
const char *s = NULL;
H5HL_t *heap = NULL;
void *ret_value = NULL; /* Return value */

FUNC_ENTER_NOAPI_NOINIT

/* Check args */
HDassert(f);
HDassert(p);
HDassert(p_size > 0);

if (NULL == (mesg = (H5O_efl_t *)H5MM_calloc(sizeof(H5O_efl_t))))
HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, NULL, "memory allocation failed")
HGOTO_ERROR(H5E_OHDR, H5E_NOSPACE, NULL, "memory allocation failed")

/* Version */
/* Version (1 byte) */
if ((p + 1 - 1) > p_end)
HGOTO_ERROR(H5E_OHDR, H5E_NOSPACE, NULL, "ran off end of input buffer while decoding")
version = *p++;
if (version != H5O_EFL_VERSION)
HGOTO_ERROR(H5E_OHDR, H5E_CANTLOAD, NULL, "bad version number for external file list message")

/* Reserved */
/* Reserved (3 bytes) */
if ((p + 3 - 1) > p_end)
HGOTO_ERROR(H5E_OHDR, H5E_NOSPACE, NULL, "ran off end of input buffer while decoding")
p += 3;

/* Number of slots */
/* Number of slots (2x 2 bytes) */
if ((p + 4 - 1) > p_end)
HGOTO_ERROR(H5E_OHDR, H5E_NOSPACE, NULL, "ran off end of input buffer while decoding")
UINT16DECODE(p, mesg->nalloc);
HDassert(mesg->nalloc > 0);
if (mesg->nalloc <= 0)
HGOTO_ERROR(H5E_OHDR, H5E_CANTLOAD, NULL, "bad number of allocated slots when parsing efl msg")
UINT16DECODE(p, mesg->nused);
HDassert(mesg->nused <= mesg->nalloc);
if (mesg->nused > mesg->nalloc)
HGOTO_ERROR(H5E_OHDR, H5E_CANTLOAD, NULL, "bad number of in-use slots when parsing efl msg")

/* Heap address */
if ((p + H5F_SIZEOF_ADDR(f) - 1) > p_end)
HGOTO_ERROR(H5E_OHDR, H5E_NOSPACE, NULL, "ran off end of input buffer while decoding")
H5F_addr_decode(f, &p, &(mesg->heap_addr));
if (H5F_addr_defined(mesg->heap_addr) == FALSE)
HGOTO_ERROR(H5E_OHDR, H5E_CANTLOAD, NULL, "bad local heap address when parsing efl msg")

#ifndef NDEBUG
HDassert(H5F_addr_defined(mesg->heap_addr));
/* Decode the file list */
mesg->slot = (H5O_efl_entry_t *)H5MM_calloc(mesg->nalloc * sizeof(H5O_efl_entry_t));
if (NULL == mesg->slot)
HGOTO_ERROR(H5E_OHDR, H5E_NOSPACE, NULL, "memory allocation failed")

if (NULL == (heap = H5HL_protect(f, mesg->heap_addr, H5AC__READ_ONLY_FLAG)))
HGOTO_ERROR(H5E_SYM, H5E_NOTFOUND, NULL, "unable to read protect link value")
HGOTO_ERROR(H5E_OHDR, H5E_CANTPROTECT, NULL, "unable to protect local heap")

#ifdef H5O_DEBUG
/* Verify that the name at offset 0 in the local heap is the empty string */
s = (const char *)H5HL_offset_into(heap, 0);

HDassert(s && !*s);

if (H5HL_unprotect(heap) < 0)
HGOTO_ERROR(H5E_SYM, H5E_NOTFOUND, NULL, "unable to read unprotect link value")
heap = NULL;
if (s == NULL)
HGOTO_ERROR(H5E_OHDR, H5E_CANTGET, NULL, "could not obtain pointer into local heap")
if (*s != '\0')
HGOTO_ERROR(H5E_OHDR, H5E_CANTGET, NULL, "entry at offset 0 in local heap not an empty string")
#endif

/* Decode the file list */
mesg->slot = (H5O_efl_entry_t *)H5MM_calloc(mesg->nalloc * sizeof(H5O_efl_entry_t));
if (NULL == mesg->slot)
HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, NULL, "memory allocation failed")

if (NULL == (heap = H5HL_protect(f, mesg->heap_addr, H5AC__READ_ONLY_FLAG)))
HGOTO_ERROR(H5E_SYM, H5E_NOTFOUND, NULL, "unable to read protect link value")
for (u = 0; u < mesg->nused; u++) {
for (size_t u = 0; u < mesg->nused; u++) {
/* Name */
if ((p + H5F_SIZEOF_SIZE(f) - 1) > p_end)
HGOTO_ERROR(H5E_OHDR, H5E_NOSPACE, NULL, "ran off end of input buffer while decoding")
H5F_DECODE_LENGTH(f, p, mesg->slot[u].name_offset);

if ((s = (const char *)H5HL_offset_into(heap, mesg->slot[u].name_offset)) == NULL)
HGOTO_ERROR(H5E_SYM, H5E_CANTGET, NULL, "unable to get external file name")
if (*s == (char)'\0')
HGOTO_ERROR(H5E_SYM, H5E_CANTGET, NULL, "invalid external file name")
HGOTO_ERROR(H5E_OHDR, H5E_CANTGET, NULL, "unable to get external file name")
if (*s == '\0')
HGOTO_ERROR(H5E_OHDR, H5E_CANTGET, NULL, "invalid external file name")
mesg->slot[u].name = H5MM_xstrdup(s);
HDassert(mesg->slot[u].name);
if (mesg->slot[u].name == NULL)
HGOTO_ERROR(H5E_OHDR, H5E_NOSPACE, NULL, "string duplication failed")

/* File offset */
if ((p + H5F_SIZEOF_SIZE(f) - 1) > p_end)
HGOTO_ERROR(H5E_OHDR, H5E_NOSPACE, NULL, "ran off end of input buffer while decoding")
H5F_DECODE_LENGTH(f, p, mesg->slot[u].offset);

/* Size */
if ((p + H5F_SIZEOF_SIZE(f) - 1) > p_end)
HGOTO_ERROR(H5E_OHDR, H5E_NOSPACE, NULL, "ran off end of input buffer while decoding")
H5F_DECODE_LENGTH(f, p, mesg->slot[u].size);
} /* end for */
}

if (H5HL_unprotect(heap) < 0)
HGOTO_ERROR(H5E_SYM, H5E_NOTFOUND, NULL, "unable to read unprotect link value")
heap = NULL;
HGOTO_ERROR(H5E_OHDR, H5E_CANTUNPROTECT, NULL, "unable to unprotect local heap")

/* Set return value */
ret_value = mesg;

done:
if (ret_value == NULL)
if (mesg != NULL)
if (mesg != NULL) {
if (mesg->slot != NULL) {
for (size_t u = 0; u < mesg->nused; u++)
H5MM_xfree(mesg->slot[u].name);
H5MM_xfree(mesg->slot);
}
H5MM_xfree(mesg);
}

FUNC_LEAVE_NOAPI(ret_value)
} /* end H5O_efl_decode() */
Expand Down