]> git.ipfire.org Git - thirdparty/libarchive.git/commitdiff
Ignore overlong gzip original_filename
authorTim Kientzle <kientzle@acm.org>
Fri, 12 Sep 2025 16:01:13 +0000 (09:01 -0700)
committerTim Kientzle <kientzle@acm.org>
Fri, 12 Sep 2025 16:01:13 +0000 (09:01 -0700)
We reuse the compression buffer to format the gzip header,
but didn't check for an overlong gzip original_filename.
This adds that check.  If the original_filename is
over 32k (or bigger than the buffer in case someone shrinks
the buffer someday), we WARN and ignore the filename.

libarchive/archive_write_add_filter_gzip.c

index 5ef43c1936ed22bb7d80b21d3da26a18ef954ea3..49fbc6380cae92c4bc47f77ca122a75e2c6992ad 100644 (file)
@@ -191,7 +191,8 @@ static int
 archive_compressor_gzip_open(struct archive_write_filter *f)
 {
        struct private_data *data = (struct private_data *)f->data;
-       int ret;
+       int ret = ARCHIVE_OK;
+       int init_success;
 
        if (data->compressed == NULL) {
                size_t bs = 65536, bpb;
@@ -241,24 +242,43 @@ archive_compressor_gzip_open(struct archive_write_filter *f)
        data->stream.avail_out -= 10;
 
        if (data->original_filename != NULL) {
-               strcpy((char*)data->compressed + 10, data->original_filename);
-               data->stream.next_out += strlen(data->original_filename) + 1;
-               data->stream.avail_out -= strlen(data->original_filename) + 1;
+               /* Limit "original filename" to 32k or the
+                * remaining space in the buffer, whichever is smaller.
+                */
+               int ofn_length = strlen(data->original_filename);
+               int ofn_max_length = 32768;
+               int ofn_space_available = data->compressed
+                       + data->compressed_buffer_size
+                       - data->stream.next_out
+                       - 1;
+               if (ofn_max_length > ofn_space_available) {
+                       ofn_max_length = ofn_space_available;
+               }
+               if (ofn_length < ofn_max_length) {
+                       strcpy((char*)data->compressed + 10,
+                              data->original_filename);
+                       data->stream.next_out += ofn_length + 1;
+                       data->stream.avail_out -= ofn_length + 1;
+               } else {
+                       archive_set_error(&a->archive, ENOMEM,
+                                         "Gzip 'Original Filename' ignored because it is too long");
+                       ret = ARCHIVE_WARN;
+               }
        }
 
        f->write = archive_compressor_gzip_write;
 
        /* Initialize compression library. */
-       ret = deflateInit2(&(data->stream),
+       init_success = deflateInit2(&(data->stream),
            data->compression_level,
            Z_DEFLATED,
            -15 /* < 0 to suppress zlib header */,
            8,
            Z_DEFAULT_STRATEGY);
 
-       if (ret == Z_OK) {
+       if (init_success == Z_OK) {
                f->data = data;
-               return (ARCHIVE_OK);
+               return (ret);
        }
 
        /* Library setup failed: clean up. */
@@ -266,7 +286,7 @@ archive_compressor_gzip_open(struct archive_write_filter *f)
            "initializing compression library");
 
        /* Override the error message if we know what really went wrong. */
-       switch (ret) {
+       switch (init_success) {
        case Z_STREAM_ERROR:
                archive_set_error(f->archive, ARCHIVE_ERRNO_MISC,
                    "Internal error initializing "