]> git.ipfire.org Git - thirdparty/libarchive.git/commitdiff
Close filters before freeing
authorMartin Matuska <martin@matuska.org>
Wed, 7 Dec 2016 11:14:25 +0000 (12:14 +0100)
committerMartin Matuska <martin@matuska.org>
Wed, 7 Dec 2016 11:53:23 +0000 (12:53 +0100)
Plugs memory leak of allocated filter buffers if archive_read_free()
is called and archive state is ARCHIVE_STATE_FATAL.

Reported-by: OSS-Fuzz issue 227, 230, 239
libarchive/archive_read.c
libarchive/archive_read_append_filter.c
libarchive/archive_read_private.h

index 0bbacc8f185bb7f305a12d06b177f1c27e33deb8..d490d7b41e82cbb70b648504920e329070a30b94 100644 (file)
@@ -57,6 +57,7 @@ __FBSDID("$FreeBSD: head/lib/libarchive/archive_read.c 201157 2009-12-29 05:30:2
 
 static int     choose_filters(struct archive_read *);
 static int     choose_format(struct archive_read *);
+static int     close_filters(struct archive_read *);
 static struct archive_vtable *archive_read_vtable(void);
 static int64_t _archive_filter_bytes(struct archive *, int);
 static int     _archive_filter_code(struct archive *, int);
@@ -528,7 +529,7 @@ archive_read_open1(struct archive *_a)
        {
                slot = choose_format(a);
                if (slot < 0) {
-                       __archive_read_close_filters(a);
+                       close_filters(a);
                        a->archive.state = ARCHIVE_STATE_FATAL;
                        return (ARCHIVE_FATAL);
                }
@@ -582,7 +583,6 @@ choose_filters(struct archive_read *a)
                        /* Verify the filter by asking it for some data. */
                        __archive_read_filter_ahead(a->filter, 1, &avail);
                        if (avail < 0) {
-                               __archive_read_close_filters(a);
                                __archive_read_free_filters(a);
                                return (ARCHIVE_FATAL);
                        }
@@ -601,7 +601,6 @@ choose_filters(struct archive_read *a)
                a->filter = filter;
                r = (best_bidder->init)(a->filter);
                if (r != ARCHIVE_OK) {
-                       __archive_read_close_filters(a);
                        __archive_read_free_filters(a);
                        return (ARCHIVE_FATAL);
                }
@@ -986,8 +985,8 @@ _archive_read_data_block(struct archive *_a,
        return (a->format->read_data)(a, buff, size, offset);
 }
 
-int
-__archive_read_close_filters(struct archive_read *a)
+static int
+close_filters(struct archive_read *a)
 {
        struct archive_read_filter *f = a->filter;
        int r = ARCHIVE_OK;
@@ -1010,6 +1009,9 @@ __archive_read_close_filters(struct archive_read *a)
 void
 __archive_read_free_filters(struct archive_read *a)
 {
+       /* Make sure filters are closed and their buffers are freed */
+       close_filters(a);
+
        while (a->filter != NULL) {
                struct archive_read_filter *t = a->filter->upstream;
                free(a->filter);
@@ -1052,7 +1054,7 @@ _archive_read_close(struct archive *_a)
        /* TODO: Clean up the formatters. */
 
        /* Release the filter objects. */
-       r1 = __archive_read_close_filters(a);
+       r1 = close_filters(a);
        if (r1 < r)
                r = r1;
 
index 3a0d4d68d89a6a4fd8659825b3417ea5ea555b6c..5e4d163079872c31858bad38dc34c504c8b02e35 100644 (file)
@@ -133,7 +133,6 @@ archive_read_append_filter(struct archive *_a, int code)
     a->filter = filter;
     r2 = (bidder->init)(a->filter);
     if (r2 != ARCHIVE_OK) {
-      __archive_read_close_filters(a);
       __archive_read_free_filters(a);
       return (ARCHIVE_FATAL);
     }
@@ -191,7 +190,6 @@ archive_read_append_filter_program_signature(struct archive *_a,
   a->filter = filter;
   r = (bidder->init)(a->filter);
   if (r != ARCHIVE_OK) {
-    __archive_read_close_filters(a);
     __archive_read_free_filters(a);
     return (ARCHIVE_FATAL);
   }
index 8eb5435bdc801c867eaa17b139a9704d2bb55595..78546dca34aac1dbb2dd02bc32510ab7cb04eb7b 100644 (file)
@@ -252,7 +252,6 @@ int64_t     __archive_read_consume(struct archive_read *, int64_t);
 int64_t        __archive_read_filter_consume(struct archive_read_filter *, int64_t);
 int __archive_read_program(struct archive_read_filter *, const char *);
 void __archive_read_free_filters(struct archive_read *);
-int  __archive_read_close_filters(struct archive_read *);
 struct archive_read_extract *__archive_read_get_extract(struct archive_read *);