aboutsummaryrefslogtreecommitdiff
path: root/src/liblzma/common
diff options
context:
space:
mode:
authorLasse Collin <lasse.collin@tukaani.org>2022-09-09 13:51:57 +0300
committerLasse Collin <lasse.collin@tukaani.org>2022-09-17 00:22:11 +0300
commitf94da15120c3d3c363ca12c2262ac6cb9f321f4f (patch)
tree01750d0525bb53361270dc98e8827961fb6d3a57 /src/liblzma/common
parentTests: Add a test file for lzma_index_append() integer overflow bug. (diff)
downloadxz-f94da15120c3d3c363ca12c2262ac6cb9f321f4f.tar.xz
liblzma: lzma_filters_copy: Keep dest[] unmodified if an error occurs.
lzma_stream_encoder() and lzma_stream_encoder_mt() always assumed this. Before this patch, failing lzma_filters_copy() could result in free(invalid_pointer) or invalid memory reads in stream_encoder.c or stream_encoder_mt.c. To trigger this, allocating memory for a filter options structure has to fail. These are tiny allocations so in practice they very rarely fail. Certain badness in the filter chain array could also make lzma_filters_copy() fail but both stream_encoder.c and stream_encoder_mt.c validate the filter chain before trying to copy it, so the crash cannot occur this way.
Diffstat (limited to 'src/liblzma/common')
-rw-r--r--src/liblzma/common/filter_common.c18
1 files changed, 12 insertions, 6 deletions
diff --git a/src/liblzma/common/filter_common.c b/src/liblzma/common/filter_common.c
index 9ad5d5d8..590be730 100644
--- a/src/liblzma/common/filter_common.c
+++ b/src/liblzma/common/filter_common.c
@@ -122,12 +122,16 @@ static const struct {
extern LZMA_API(lzma_ret)
-lzma_filters_copy(const lzma_filter *src, lzma_filter *dest,
+lzma_filters_copy(const lzma_filter *src, lzma_filter *real_dest,
const lzma_allocator *allocator)
{
- if (src == NULL || dest == NULL)
+ if (src == NULL || real_dest == NULL)
return LZMA_PROG_ERROR;
+ // Use a temporary destination so that the real destination
+ // will never be modied if an error occurs.
+ lzma_filter dest[LZMA_FILTERS_MAX + 1];
+
lzma_ret ret;
size_t i;
for (i = 0; src[i].id != LZMA_VLI_UNKNOWN; ++i) {
@@ -173,18 +177,20 @@ lzma_filters_copy(const lzma_filter *src, lzma_filter *dest,
}
// Terminate the filter array.
- assert(i <= LZMA_FILTERS_MAX + 1);
+ assert(i < LZMA_FILTERS_MAX + 1);
dest[i].id = LZMA_VLI_UNKNOWN;
dest[i].options = NULL;
+ // Copy it to the caller-supplied array now that we know that
+ // no errors occurred.
+ memcpy(real_dest, dest, (i + 1) * sizeof(lzma_filter));
+
return LZMA_OK;
error:
// Free the options which we have already allocated.
- while (i-- > 0) {
+ while (i-- > 0)
lzma_free(dest[i].options, allocator);
- dest[i].options = NULL;
- }
return ret;
}