]> git.ipfire.org Git - thirdparty/libarchive.git/commitdiff
RAR5 reader: fix SIGSEGV when archive_read_support_format_rar5 is called twice 2893/head
authorGrzegorz Antoniak <ga@anadoxin.org>
Fri, 6 Mar 2026 18:52:22 +0000 (19:52 +0100)
committerGrzegorz Antoniak <ga@anadoxin.org>
Fri, 6 Mar 2026 18:53:36 +0000 (19:53 +0100)
When the same archive_read object registers rar5 format more than once,
__archive_read_register_format returns ARCHIVE_WARN (duplicate bid).
The error path then called rar5_cleanup(ar), which dereferences
a->format to get the rar5 context — but a->format is NULL until
archive_read_open() is called, causing a SIGSEGV. The newly allocated
rar struct was also leaked.

Fix by introducing rar5_deinit() (the inverse of rar5_init) and using
it in both rar5_cleanup() and the registration error path. On failure,
the locally allocated rar is freed directly without going through
a->format. The function now always returns ARCHIVE_OK, consistent with
all other format handlers.

Fixes #1963.

libarchive/archive_read_support_format_rar5.c

index 17e501e02e9f1733c0c2f7abf4c6026db0f898a7..7fddd3c3698a814fff1b8d8360bdeeeb641cd184 100644 (file)
@@ -375,6 +375,7 @@ static int rar5_read_data_skip(struct archive_read *a);
 static int push_data_ready(struct archive_read* a, struct rar5* rar,
        const uint8_t* buf, size_t size, int64_t offset);
 static void clear_data_ready_stack(struct rar5* rar);
+static void rar5_deinit(struct rar5* rar);
 
 /* CDE_xxx = Circular Double Ended (Queue) return values. */
 enum CDE_RETURN_VALUES {
@@ -4328,7 +4329,7 @@ static int rar5_cleanup(struct archive_read *a) {
        free(rar->vol.push_buf);
 
        free_filters(rar);
-       cdeque_free(&rar->cstate.filters);
+       rar5_deinit(rar);
 
        free(rar);
        a->format->data = NULL;
@@ -4353,6 +4354,7 @@ static int rar5_has_encrypted_entries(struct archive_read *_a) {
        return ARCHIVE_READ_FORMAT_ENCRYPTION_DONT_KNOW;
 }
 
+/* Must match deallocations in rar5_deinit */
 static int rar5_init(struct rar5* rar) {
        memset(rar, 0, sizeof(struct rar5));
 
@@ -4368,6 +4370,11 @@ static int rar5_init(struct rar5* rar) {
        return ARCHIVE_OK;
 }
 
+/* Must match allocations in rar5_init */
+static void rar5_deinit(struct rar5* rar) {
+       cdeque_free(&rar->cstate.filters);
+}
+
 int archive_read_support_format_rar5(struct archive *_a) {
        struct archive_read* ar;
        int ret;
@@ -4404,8 +4411,9 @@ int archive_read_support_format_rar5(struct archive *_a) {
            rar5_has_encrypted_entries);
 
        if(ret != ARCHIVE_OK) {
-               (void) rar5_cleanup(ar);
+               rar5_deinit(rar);
+               free(rar);
        }
 
-       return ret;
+       return ARCHIVE_OK;
 }