]> git.ipfire.org Git - thirdparty/libarchive.git/commitdiff
Fix overflow in build_ustar_entry (#2588)
authorBrian Campbell <Brian.Campbell@ed.ac.uk>
Sat, 26 Apr 2025 04:11:19 +0000 (05:11 +0100)
committerGitHub <noreply@github.com>
Sat, 26 Apr 2025 04:11:19 +0000 (21:11 -0700)
The calculations for the suffix and prefix can increment the endpoint
for a trailing slash. Hence the limits used should be one lower than the
maximum number of bytes.

Without this patch, when this happens for both the prefix and the
suffix, we end up with 156 + 100 bytes, and the write of the null at the
end will overflow the 256 byte buffer. This can be reproduced by running
```
mkdir -p foo/bar
bsdtar cvf test.tar foo////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////bar
```
when bsdtar is compiled with Address Sanitiser, although I originally
noticed this by accident with a genuine filename on a CHERI capability
system, which faults immediately on the buffer overflow.

libarchive/archive_write_set_format_pax.c

index 0db453446b7c399f543053a77c5e12a9fa8c2004..66e6d75196ec88f01ddf66d032b3af9a99d76de8 100644 (file)
@@ -1571,7 +1571,7 @@ build_ustar_entry_name(char *dest, const char *src, size_t src_length,
        const char *filename, *filename_end;
        char *p;
        int need_slash = 0; /* Was there a trailing slash? */
-       size_t suffix_length = 99;
+       size_t suffix_length = 98; /* 99 - 1 for trailing slash */
        size_t insert_length;
 
        /* Length of additional dir element to be added. */
@@ -1623,7 +1623,7 @@ build_ustar_entry_name(char *dest, const char *src, size_t src_length,
        /* Step 2: Locate the "prefix" section of the dirname, including
         * trailing '/'. */
        prefix = src;
-       prefix_end = prefix + 155;
+       prefix_end = prefix + 154 /* 155 - 1 for trailing / */;
        if (prefix_end > filename)
                prefix_end = filename;
        while (prefix_end > prefix && *prefix_end != '/')