From 579ff6922089cbbbd179619e40e622e279bd719f Mon Sep 17 00:00:00 2001 From: Martijn van Beurden Date: Wed, 3 Aug 2022 13:52:19 +0200 Subject: [PATCH] flac: Add and use _nofree variants of safe_realloc functions Parts of the code use realloc like x = safe_realloc(x, somesize); when this is the case, the safe_realloc variant used must free the old memory block in case it fails, otherwise it will leak. However, there are also instances in the code where handling is different: if (0 == (x = safe_realloc(y, somesize))) return false in this case, y should not be freed, as y is not set to NULL we could encounter double frees. Here the safe_realloc_nofree functions are used. Upstream-Status: Backport [https://github.com/xiph/flac/commit/21fe95ee828b0b9b944f6aa0bb02d24fbb981815] CVE: CVE-2020-22219 Signed-off-by: Meenali Gupta --- include/share/alloc.h | 41 +++++++++++++++++++++++++++++++---- src/flac/encode.c | 4 ++-- src/flac/foreign_metadata.c | 2 +- src/libFLAC/bitwriter.c | 2 +- src/libFLAC/metadata_object.c | 2 +- src/plugin_common/tags.c | 2 +- src/share/utf8/iconvert.c | 2 +- 7 files changed, 44 insertions(+), 11 deletions(-) diff --git a/include/share/alloc.h b/include/share/alloc.h index 914de9b..55bdd1d 100644 --- a/include/share/alloc.h +++ b/include/share/alloc.h @@ -161,17 +161,30 @@ static inline void *safe_realloc_(void *ptr, size_t size) free(oldptr); return newptr; } -static inline void *safe_realloc_add_2op_(void *ptr, size_t size1, size_t size2) +static inline void *safe_realloc_nofree_add_2op_(void *ptr, size_t size1, size_t size2) +{ + size2 += size1; + if(size2 < size1) + return 0; + return realloc(ptr, size2); +} + +static inline void *safe_realloc_add_3op_(void *ptr, size_t size1, size_t size2, size_t size3) { size2 += size1; if(size2 < size1) { free(ptr); return 0; } - return realloc(ptr, size2); + size3 += size2; + if(size3 < size2) { + free(ptr); + return 0; + } + return safe_realloc_(ptr, size3); } -static inline void *safe_realloc_add_3op_(void *ptr, size_t size1, size_t size2, size_t size3) +static inline void *safe_realloc_nofree_add_3op_(void *ptr, size_t size1, size_t size2, size_t size3) { size2 += size1; if(size2 < size1) @@ -182,7 +195,7 @@ static inline void *safe_realloc_add_3op_(void *ptr, size_t size1, size_t size2, return realloc(ptr, size3); } -static inline void *safe_realloc_add_4op_(void *ptr, size_t size1, size_t size2, size_t size3, size_t size4) +static inline void *safe_realloc_nofree_add_4op_(void *ptr, size_t size1, size_t size2, size_t size3, size_t size4) { size2 += size1; if(size2 < size1) @@ -205,6 +218,15 @@ static inline void *safe_realloc_mul_2op_(void *ptr, size_t size1, size_t size2) return safe_realloc_(ptr, size1*size2); } +static inline void *safe_realloc_nofree_mul_2op_(void *ptr, size_t size1, size_t size2) +{ + if(!size1 || !size2) + return realloc(ptr, 0); /* preserve POSIX realloc(ptr, 0) semantics */ + if(size1 > SIZE_MAX / size2) + return 0; + return realloc(ptr, size1*size2); +} + /* size1 * (size2 + size3) */ static inline void *safe_realloc_muladd2_(void *ptr, size_t size1, size_t size2, size_t size3) { @@ -216,4 +238,15 @@ static inline void *safe_realloc_muladd2_(void *ptr, size_t size1, size_t size2, return safe_realloc_mul_2op_(ptr, size1, size2); } +/* size1 * (size2 + size3) */ +static inline void *safe_realloc_nofree_muladd2_(void *ptr, size_t size1, size_t size2, size_t size3) +{ + if(!size1 || (!size2 && !size3)) + return realloc(ptr, 0); /* preserve POSIX realloc(ptr, 0) semantics */ + size2 += size3; + if(size2 < size3) + return 0; + return safe_realloc_nofree_mul_2op_(ptr, size1, size2); +} + #endif diff --git a/src/flac/encode.c b/src/flac/encode.c index a9b907f..f87250c 100644 --- a/src/flac/encode.c +++ b/src/flac/encode.c @@ -1743,10 +1743,10 @@ static void static_metadata_clear(static_metadata_t *m) static FLAC__bool static_metadata_append(static_metadata_t *m, FLAC__StreamMetadata *d, FLAC__bool needs_delete) { void *x; - if(0 == (x = safe_realloc_muladd2_(m->metadata, sizeof(*m->metadata), /*times (*/m->num_metadata, /*+*/1/*)*/))) + if(0 == (x = safe_realloc_nofree_muladd2_(m->metadata, sizeof(*m->metadata), /*times (*/m->num_metadata, /*+*/1/*)*/))) return false; m->metadata = (FLAC__StreamMetadata**)x; - if(0 == (x = safe_realloc_muladd2_(m->needs_delete, sizeof(*m->needs_delete), /*times (*/m->num_metadata, /*+*/1/*)*/))) + if(0 == (x = safe_realloc_nofree_muladd2_(m->needs_delete, sizeof(*m->needs_delete), /*times (*/m->num_metadata, /*+*/1/*)*/))) return false; m->needs_delete = (FLAC__bool*)x; m->metadata[m->num_metadata] = d; diff --git a/src/flac/foreign_metadata.c b/src/flac/foreign_metadata.c index 9ad9c18..fdfb3cf 100644 --- a/src/flac/foreign_metadata.c +++ b/src/flac/foreign_metadata.c @@ -75,7 +75,7 @@ static FLAC__bool copy_data_(FILE *fin, FILE *fout, size_t size, const char **er static FLAC__bool append_block_(foreign_metadata_t *fm, FLAC__off_t offset, FLAC__uint32 size, const char **error) { - foreign_block_t *fb = safe_realloc_muladd2_(fm->blocks, sizeof(foreign_block_t), /*times (*/fm->num_blocks, /*+*/1/*)*/); + foreign_block_t *fb = safe_realloc_nofree_muladd2_(fm->blocks, sizeof(foreign_block_t), /*times (*/fm->num_blocks, /*+*/1/*)*/); if(fb) { fb[fm->num_blocks].offset = offset; fb[fm->num_blocks].size = size; diff --git a/src/libFLAC/bitwriter.c b/src/libFLAC/bitwriter.c index 6e86585..a510b0d 100644 --- a/src/libFLAC/bitwriter.c +++ b/src/libFLAC/bitwriter.c @@ -124,7 +124,7 @@ FLAC__bool bitwriter_grow_(FLAC__BitWriter *bw, uint32_t bits_to_add) FLAC__ASSERT(new_capacity > bw->capacity); FLAC__ASSERT(new_capacity >= bw->words + ((bw->bits + bits_to_add + FLAC__BITS_PER_WORD - 1) / FLAC__BITS_PER_WORD)); - new_buffer = safe_realloc_mul_2op_(bw->buffer, sizeof(bwword), /*times*/new_capacity); + new_buffer = safe_realloc_nofree_mul_2op_(bw->buffer, sizeof(bwword), /*times*/new_capacity); if(new_buffer == 0) return false; bw->buffer = new_buffer; diff --git a/src/libFLAC/metadata_object.c b/src/libFLAC/metadata_object.c index de8e513..aef65be 100644 --- a/src/libFLAC/metadata_object.c +++ b/src/libFLAC/metadata_object.c @@ -98,7 +98,7 @@ static FLAC__bool free_copy_bytes_(FLAC__byte **to, const FLAC__byte *from, uint /* realloc() failure leaves entry unchanged */ static FLAC__bool ensure_null_terminated_(FLAC__byte **entry, uint32_t length) { - FLAC__byte *x = safe_realloc_add_2op_(*entry, length, /*+*/1); + FLAC__byte *x = safe_realloc_nofree_add_2op_(*entry, length, /*+*/1); if (x != NULL) { x[length] = '\0'; *entry = x; diff --git a/src/plugin_common/tags.c b/src/plugin_common/tags.c index ae440c5..dfa10d3 100644 --- a/src/plugin_common/tags.c +++ b/src/plugin_common/tags.c @@ -317,7 +317,7 @@ FLAC__bool FLAC_plugin__tags_add_tag_utf8(FLAC__StreamMetadata *tags, const char const size_t value_len = strlen(value); const size_t separator_len = strlen(separator); FLAC__byte *new_entry; - if(0 == (new_entry = safe_realloc_add_4op_(entry->entry, entry->length, /*+*/value_len, /*+*/separator_len, /*+*/1))) + if(0 == (new_entry = safe_realloc_nofree_add_4op_(entry->entry, entry->length, /*+*/value_len, /*+*/separator_len, /*+*/1))) return false; memcpy(new_entry+entry->length, separator, separator_len); entry->length += separator_len; diff --git a/src/share/utf8/iconvert.c b/src/share/utf8/iconvert.c index 8ab53c1..876c06e 100644 --- a/src/share/utf8/iconvert.c +++ b/src/share/utf8/iconvert.c @@ -149,7 +149,7 @@ int iconvert(const char *fromcode, const char *tocode, iconv_close(cd1); return ret; } - newbuf = safe_realloc_add_2op_(utfbuf, (ob - utfbuf), /*+*/1); + newbuf = safe_realloc_nofree_add_2op_(utfbuf, (ob - utfbuf), /*+*/1); if (!newbuf) goto fail; ob = (ob - utfbuf) + newbuf; -- 2.40.0