diff options
author | Mark Wielaard <mark@klomp.org> | 2019-02-19 16:27:40 +0100 |
---|---|---|
committer | Mark Wielaard <mark@klomp.org> | 2019-02-19 16:27:40 +0100 |
commit | ff7fe986679b0811591ef6e40cf485fa9f037e07 (patch) | |
tree | 035299f3a4b0867825c3c92a19ea5e75580e8423 /libelf | |
parent | 1e52d4ce3aa2093d12901d32fe07aae70211fe2a (diff) | |
download | elfutils-ff7fe986679b0811591ef6e40cf485fa9f037e07.tar.gz |
libelf: Handle zero size decompressed data.
This is a corner case that will most likely never occur in practice,
but we have several testcases that compress and decompress zero sized
data. In that case during decompression we might malloc a buffer of
size zero. It is allowed for malloc to return NULL in that case. But
we do need a non-NULL buffer to return and set as result. So make sure
to always at least allocate one byte. Also make sure that we don't
allocate a zero sized conversion buffer for the data.
https://sourceware.org/bugzilla/show_bug.cgi?id=24000
Signed-off-by: Mark Wielaard <mark@klomp.org>
Diffstat (limited to 'libelf')
-rw-r--r-- | libelf/ChangeLog | 10 | ||||
-rw-r--r-- | libelf/elf_compress.c | 31 |
2 files changed, 28 insertions, 13 deletions
diff --git a/libelf/ChangeLog b/libelf/ChangeLog index d8e8fdc8..e4d39d3f 100644 --- a/libelf/ChangeLog +++ b/libelf/ChangeLog @@ -1,3 +1,13 @@ +2019-02-19 Mark Wielaard <mark@klomp.org> + + * elf_compress.c (do_deflate_cleanup): Remove ei_data argument, + check cdatap is not NULL before calling free. + (deflate_cleanup): Add cdata as argument. + (__libelf_compress): Also check whether the d_size is not zero + before converting data. Call deflate_cleanup with an extra + argument depending on whether there is converted data to free. + Always allocate allocate at least one byte for buf_out. + 2019-02-14 Mark Wielaard <mark@klomp.org> * elf_begin.c (read_long_names): Make sure ar_size is properly diff --git a/libelf/elf_compress.c b/libelf/elf_compress.c index be9eeaba..874054ac 100644 --- a/libelf/elf_compress.c +++ b/libelf/elf_compress.c @@ -44,17 +44,17 @@ /* Cleanup and return result. Don't leak memory. */ static void * do_deflate_cleanup (void *result, z_stream *z, void *out_buf, - int ei_data, Elf_Data *cdatap) + Elf_Data *cdatap) { deflateEnd (z); free (out_buf); - if (ei_data != MY_ELFDATA) + if (cdatap != NULL) free (cdatap->d_buf); return result; } -#define deflate_cleanup(result) \ - do_deflate_cleanup(result, &z, out_buf, ei_data, &cdata) +#define deflate_cleanup(result, cdata) \ + do_deflate_cleanup(result, &z, out_buf, cdata) /* Given a section, uses the (in-memory) Elf_Data to extract the original data size (including the given header size) and data @@ -127,7 +127,8 @@ __libelf_compress (Elf_Scn *scn, size_t hsize, int ei_data, { /* Convert to raw if different endianess. */ cdata = *data; - if (ei_data != MY_ELFDATA) + bool convert = ei_data != MY_ELFDATA && data->d_size > 0; + if (convert) { /* Don't do this conversion in place, we might want to keep the original data around, caller decides. */ @@ -135,10 +136,10 @@ __libelf_compress (Elf_Scn *scn, size_t hsize, int ei_data, if (cdata.d_buf == NULL) { __libelf_seterrno (ELF_E_NOMEM); - return deflate_cleanup (NULL); + return deflate_cleanup (NULL, NULL); } if (gelf_xlatetof (scn->elf, &cdata, data, ei_data) == NULL) - return deflate_cleanup (NULL); + return deflate_cleanup (NULL, &cdata); } z.avail_in = cdata.d_size; @@ -164,7 +165,7 @@ __libelf_compress (Elf_Scn *scn, size_t hsize, int ei_data, if (zrc == Z_STREAM_ERROR) { __libelf_seterrno (ELF_E_COMPRESS_ERROR); - return deflate_cleanup (NULL); + return deflate_cleanup (NULL, convert ? &cdata : NULL); } used += (out_size - used) - z.avail_out; @@ -172,7 +173,7 @@ __libelf_compress (Elf_Scn *scn, size_t hsize, int ei_data, compression forced and we are using more compressed data than original data. */ if (!force && flush == Z_FINISH && used >= *orig_size) - return deflate_cleanup ((void *) -1); + return deflate_cleanup ((void *) -1, convert ? &cdata : NULL); if (z.avail_out == 0) { @@ -180,7 +181,7 @@ __libelf_compress (Elf_Scn *scn, size_t hsize, int ei_data, if (bigger == NULL) { __libelf_seterrno (ELF_E_NOMEM); - return deflate_cleanup (NULL); + return deflate_cleanup (NULL, convert ? &cdata : NULL); } out_buf = bigger; out_size += block; @@ -188,7 +189,7 @@ __libelf_compress (Elf_Scn *scn, size_t hsize, int ei_data, } while (z.avail_out == 0); /* Need more output buffer. */ - if (ei_data != MY_ELFDATA) + if (convert) { free (cdata.d_buf); cdata.d_buf = NULL; @@ -200,7 +201,7 @@ __libelf_compress (Elf_Scn *scn, size_t hsize, int ei_data, if (zrc != Z_OK) { __libelf_seterrno (ELF_E_COMPRESS_ERROR); - return deflate_cleanup (NULL); + return deflate_cleanup (NULL, NULL); } *new_size = used; @@ -220,7 +221,11 @@ __libelf_decompress (void *buf_in, size_t size_in, size_t size_out) return NULL; } - void *buf_out = malloc (size_out); + /* Malloc might return NULL when requestion zero size. This is highly + unlikely, it would only happen when the compression was forced. + But we do need a non-NULL buffer to return and set as result. + Just make sure to always allocate at least 1 byte. */ + void *buf_out = malloc (size_out ?: 1); if (unlikely (buf_out == NULL)) { __libelf_seterrno (ELF_E_NOMEM); |