diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..29b3ada --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +/libarchive-3.3.3.tar.gz diff --git a/EMPTY b/EMPTY deleted file mode 100644 index 0519ecb..0000000 --- a/EMPTY +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/fix-few-obvious-resource-leaks-covscan.patch b/fix-few-obvious-resource-leaks-covscan.patch new file mode 100644 index 0000000..a503633 --- /dev/null +++ b/fix-few-obvious-resource-leaks-covscan.patch @@ -0,0 +1,146 @@ +From 9d178fe573818764a2d15e0a39691f5eb4e300f6 Mon Sep 17 00:00:00 2001 +From: Ondrej Dubaj +Date: Mon, 27 May 2019 10:52:51 +0200 +Subject: [PATCH] Fix a few obvious resource leaks and strcpy() misuses + +Per Coverity report. +--- + cpio/cpio.c | 4 +++- + libarchive/archive_acl.c | 8 ++++++-- + libarchive/archive_write_set_format_iso9660.c | 4 ++-- + libarchive/archive_write_set_format_mtree.c | 4 ++-- + libarchive/archive_write_set_format_pax.c | 6 ++++-- + libarchive/archive_write_set_format_xar.c | 10 ++++++---- + 6 files changed, 23 insertions(+), 13 deletions(-) + +diff --git a/cpio/cpio.c b/cpio/cpio.c +index 5beedd0..6696bb5 100644 +--- a/cpio/cpio.c ++++ b/cpio/cpio.c +@@ -744,8 +744,10 @@ file_to_archive(struct cpio *cpio, const char *srcpath) + } + if (cpio->option_rename) + destpath = cpio_rename(destpath); +- if (destpath == NULL) ++ if (destpath == NULL) { ++ archive_entry_free(entry); + return (0); ++ } + archive_entry_copy_pathname(entry, destpath); + + /* +diff --git a/libarchive/archive_acl.c b/libarchive/archive_acl.c +index b8b6b63..503f379 100644 +--- a/libarchive/archive_acl.c ++++ b/libarchive/archive_acl.c +@@ -753,8 +753,10 @@ archive_acl_to_text_w(struct archive_acl *acl, ssize_t *text_len, int flags, + append_entry_w(&wp, prefix, ap->type, ap->tag, flags, + wname, ap->permset, id); + count++; +- } else if (r < 0 && errno == ENOMEM) ++ } else if (r < 0 && errno == ENOMEM) { ++ free(ws); + return (NULL); ++ } + } + + /* Add terminating character */ +@@ -975,8 +977,10 @@ archive_acl_to_text_l(struct archive_acl *acl, ssize_t *text_len, int flags, + prefix = NULL; + r = archive_mstring_get_mbs_l( + &ap->name, &name, &len, sc); +- if (r != 0) ++ if (r != 0) { ++ free(s); + return (NULL); ++ } + if (count > 0) + *p++ = separator; + if (name == NULL || +diff --git a/libarchive/archive_write_set_format_iso9660.c b/libarchive/archive_write_set_format_iso9660.c +index c0ca435..badc88b 100644 +--- a/libarchive/archive_write_set_format_iso9660.c ++++ b/libarchive/archive_write_set_format_iso9660.c +@@ -4899,10 +4899,10 @@ isofile_gen_utility_names(struct archive_write *a, struct isofile *file) + if (p[0] == '/') { + if (p[1] == '/') + /* Convert '//' --> '/' */ +- strcpy(p, p+1); ++ memmove(p, p+1, strlen(p+1) + 1); + else if (p[1] == '.' && p[2] == '/') + /* Convert '/./' --> '/' */ +- strcpy(p, p+2); ++ memmove(p, p+2, strlen(p+2) + 1); + else if (p[1] == '.' && p[2] == '.' && p[3] == '/') { + /* Convert 'dir/dir1/../dir2/' + * --> 'dir/dir2/' +diff --git a/libarchive/archive_write_set_format_mtree.c b/libarchive/archive_write_set_format_mtree.c +index 493d473..0f2431e 100644 +--- a/libarchive/archive_write_set_format_mtree.c ++++ b/libarchive/archive_write_set_format_mtree.c +@@ -1810,10 +1810,10 @@ mtree_entry_setup_filenames(struct archive_write *a, struct mtree_entry *file, + if (p[0] == '/') { + if (p[1] == '/') + /* Convert '//' --> '/' */ +- strcpy(p, p+1); ++ memmove(p, p+1, strlen(p+1) + 1); + else if (p[1] == '.' && p[2] == '/') + /* Convert '/./' --> '/' */ +- strcpy(p, p+2); ++ memmove(p, p+2, strlen(p+2) + 1); + else if (p[1] == '.' && p[2] == '.' && p[3] == '/') { + /* Convert 'dir/dir1/../dir2/' + * --> 'dir/dir2/' +diff --git a/libarchive/archive_write_set_format_pax.c b/libarchive/archive_write_set_format_pax.c +index 0eaf733..4863e46 100644 +--- a/libarchive/archive_write_set_format_pax.c ++++ b/libarchive/archive_write_set_format_pax.c +@@ -522,11 +522,13 @@ add_pax_acl(struct archive_write *a, + ARCHIVE_ERRNO_FILE_FORMAT, "%s %s %s", + "Can't translate ", attr, " to UTF-8"); + return(ARCHIVE_WARN); +- } else if (*p != '\0') { ++ } ++ ++ if (*p != '\0') { + add_pax_attr(&(pax->pax_header), + attr, p); +- free(p); + } ++ free(p); + return(ARCHIVE_OK); + } + +diff --git a/libarchive/archive_write_set_format_xar.c b/libarchive/archive_write_set_format_xar.c +index 495f0d4..56cd33c 100644 +--- a/libarchive/archive_write_set_format_xar.c ++++ b/libarchive/archive_write_set_format_xar.c +@@ -2120,10 +2120,10 @@ file_gen_utility_names(struct archive_write *a, struct file *file) + if (p[0] == '/') { + if (p[1] == '/') + /* Convert '//' --> '/' */ +- strcpy(p, p+1); ++ memmove(p, p+1, strlen(p+1) + 1); + else if (p[1] == '.' && p[2] == '/') + /* Convert '/./' --> '/' */ +- strcpy(p, p+2); ++ memmove(p, p+2, strlen(p+2) + 1); + else if (p[1] == '.' && p[2] == '.' && p[3] == '/') { + /* Convert 'dir/dir1/../dir2/' + * --> 'dir/dir2/' +@@ -3169,8 +3169,10 @@ save_xattrs(struct archive_write *a, struct file *file) + checksum_update(&(xar->a_sumwrk), + xar->wbuff, size); + if (write_to_temp(a, xar->wbuff, size) +- != ARCHIVE_OK) +- return (ARCHIVE_FATAL); ++ != ARCHIVE_OK) { ++ free(heap); ++ return (ARCHIVE_FATAL); ++ } + if (r == ARCHIVE_OK) { + xar->stream.next_out = xar->wbuff; + xar->stream.avail_out = sizeof(xar->wbuff); +-- +2.17.1 + diff --git a/fix-use-after-free-in-delayed-newc.patch b/fix-use-after-free-in-delayed-newc.patch new file mode 100644 index 0000000..2534d32 --- /dev/null +++ b/fix-use-after-free-in-delayed-newc.patch @@ -0,0 +1,78 @@ +From 6a71cce7ed735f83f9a6a6bad8beaa47f8d14734 Mon Sep 17 00:00:00 2001 +From: Ondrej Dubaj +Date: Mon, 27 May 2019 10:06:14 +0200 +Subject: [PATCH 1/2] Fix use-after-free in delayed link processing (newc + format) + +During archiving, if some of the "delayed" hard link entries +happened to disappear on filesystem (or become unreadable) for +some reason (most probably race), the old code free()d the 'entry' +and continued with the loop; the next loop though dereferenced +'entry' and crashed the archiver. + +Per report from Coverity. +--- + tar/write.c | 9 ++++----- + 1 file changed, 4 insertions(+), 5 deletions(-) + +diff --git a/tar/write.c b/tar/write.c +index 9c24566..3970de2 100644 +--- a/tar/write.c ++++ b/tar/write.c +@@ -540,8 +540,7 @@ write_archive(struct archive *a, struct bsdtar *bsdtar) + lafe_warnc(archive_errno(disk), + "%s", archive_error_string(disk)); + bsdtar->return_value = 1; +- archive_entry_free(entry); +- continue; ++ goto next_entry; + } + + /* +@@ -559,13 +558,13 @@ write_archive(struct archive *a, struct bsdtar *bsdtar) + bsdtar->return_value = 1; + else + archive_read_close(disk); +- archive_entry_free(entry); +- continue; ++ goto next_entry; + } + + write_file(bsdtar, a, entry); +- archive_entry_free(entry); + archive_read_close(disk); ++next_entry: ++ archive_entry_free(entry); + entry = NULL; + archive_entry_linkify(bsdtar->resolver, &entry, &sparse_entry); + } +-- +2.17.1 + + +From a999ca882aeb8fce4f4f2ee1317f528984b47e8e Mon Sep 17 00:00:00 2001 +From: Ondrej Dubaj +Date: Mon, 27 May 2019 10:34:48 +0200 +Subject: [PATCH 2/2] call missing archive_read_close() in write_archive() + +--- + tar/write.c | 3 +-- + 1 file changed, 1 insertion(+), 2 deletions(-) + +diff --git a/tar/write.c b/tar/write.c +index 3970de2..63c619c 100644 +--- a/tar/write.c ++++ b/tar/write.c +@@ -556,8 +556,7 @@ write_archive(struct archive *a, struct bsdtar *bsdtar) + "%s", archive_error_string(disk)); + if (r == ARCHIVE_FATAL) + bsdtar->return_value = 1; +- else +- archive_read_close(disk); ++ archive_read_close(disk); + goto next_entry; + } + +-- +2.17.1 + diff --git a/libarchive-3.1.2-CVE-2019-1000019.patch b/libarchive-3.1.2-CVE-2019-1000019.patch new file mode 100644 index 0000000..f05595e --- /dev/null +++ b/libarchive-3.1.2-CVE-2019-1000019.patch @@ -0,0 +1,58 @@ +From 65a23f5dbee4497064e9bb467f81138a62b0dae1 Mon Sep 17 00:00:00 2001 +From: Daniel Axtens +Date: Tue, 1 Jan 2019 16:01:40 +1100 +Subject: [PATCH 2/2] 7zip: fix crash when parsing certain archives + +Fuzzing with CRCs disabled revealed that a call to get_uncompressed_data() +would sometimes fail to return at least 'minimum' bytes. This can cause +the crc32() invocation in header_bytes to read off into invalid memory. + +A specially crafted archive can use this to cause a crash. + +An ASAN trace is below, but ASAN is not required - an uninstrumented +binary will also crash. + +==7719==ERROR: AddressSanitizer: SEGV on unknown address 0x631000040000 (pc 0x7fbdb3b3ec1d bp 0x7ffe77a51310 sp 0x7ffe77a51150 T0) +==7719==The signal is caused by a READ memory access. + #0 0x7fbdb3b3ec1c in crc32_z (/lib/x86_64-linux-gnu/libz.so.1+0x2c1c) + #1 0x84f5eb in header_bytes (/tmp/libarchive/bsdtar+0x84f5eb) + #2 0x856156 in read_Header (/tmp/libarchive/bsdtar+0x856156) + #3 0x84e134 in slurp_central_directory (/tmp/libarchive/bsdtar+0x84e134) + #4 0x849690 in archive_read_format_7zip_read_header (/tmp/libarchive/bsdtar+0x849690) + #5 0x5713b7 in _archive_read_next_header2 (/tmp/libarchive/bsdtar+0x5713b7) + #6 0x570e63 in _archive_read_next_header (/tmp/libarchive/bsdtar+0x570e63) + #7 0x6f08bd in archive_read_next_header (/tmp/libarchive/bsdtar+0x6f08bd) + #8 0x52373f in read_archive (/tmp/libarchive/bsdtar+0x52373f) + #9 0x5257be in tar_mode_x (/tmp/libarchive/bsdtar+0x5257be) + #10 0x51daeb in main (/tmp/libarchive/bsdtar+0x51daeb) + #11 0x7fbdb27cab96 in __libc_start_main /build/glibc-OTsEL5/glibc-2.27/csu/../csu/libc-start.c:310 + #12 0x41dd09 in _start (/tmp/libarchive/bsdtar+0x41dd09) + +This was primarly done with afl and FairFuzz. Some early corpus entries +may have been generated by qsym. +--- + libarchive/archive_read_support_format_7zip.c | 8 +------- + 1 file changed, 1 insertion(+), 7 deletions(-) + +diff --git a/libarchive/archive_read_support_format_7zip.c b/libarchive/archive_read_support_format_7zip.c +index bccbf896..b6d1505d 100644 +--- a/libarchive/archive_read_support_format_7zip.c ++++ b/libarchive/archive_read_support_format_7zip.c +@@ -2964,13 +2964,7 @@ get_uncompressed_data(struct archive_read *a, const void **buff, size_t size, + if (zip->codec == _7Z_COPY && zip->codec2 == (unsigned long)-1) { + /* Copy mode. */ + +- /* +- * Note: '1' here is a performance optimization. +- * Recall that the decompression layer returns a count of +- * available bytes; asking for more than that forces the +- * decompressor to combine reads by copying data. +- */ +- *buff = __archive_read_ahead(a, 1, &bytes_avail); ++ *buff = __archive_read_ahead(a, minimum, &bytes_avail); + if (bytes_avail <= 0) { + archive_set_error(&a->archive, + ARCHIVE_ERRNO_FILE_FORMAT, +-- +2.20.1 + diff --git a/libarchive-3.1.2-CVE-2019-1000020.patch b/libarchive-3.1.2-CVE-2019-1000020.patch new file mode 100644 index 0000000..b314520 --- /dev/null +++ b/libarchive-3.1.2-CVE-2019-1000020.patch @@ -0,0 +1,59 @@ +From 8312eaa576014cd9b965012af51bc1f967b12423 Mon Sep 17 00:00:00 2001 +From: Daniel Axtens +Date: Tue, 1 Jan 2019 17:10:49 +1100 +Subject: [PATCH 1/2] iso9660: Fail when expected Rockridge extensions is + missing + +A corrupted or malicious ISO9660 image can cause read_CE() to loop +forever. + +read_CE() calls parse_rockridge(), expecting a Rockridge extension +to be read. However, parse_rockridge() is structured as a while +loop starting with a sanity check, and if the sanity check fails +before the loop has run, the function returns ARCHIVE_OK without +advancing the position in the file. This causes read_CE() to retry +indefinitely. + +Make parse_rockridge() return ARCHIVE_WARN if it didn't read an +extension. As someone with no real knowledge of the format, this +seems more apt than ARCHIVE_FATAL, but both the call-sites escalate +it to a fatal error immediately anyway. + +Found with a combination of AFL, afl-rb (FairFuzz) and qsym. +--- + libarchive/archive_read_support_format_iso9660.c | 11 ++++++++++- + 1 file changed, 10 insertions(+), 1 deletion(-) + +diff --git a/libarchive/archive_read_support_format_iso9660.c b/libarchive/archive_read_support_format_iso9660.c +index 28acfefb..bad8f1df 100644 +--- a/libarchive/archive_read_support_format_iso9660.c ++++ b/libarchive/archive_read_support_format_iso9660.c +@@ -2102,6 +2102,7 @@ parse_rockridge(struct archive_read *a, struct file_info *file, + const unsigned char *p, const unsigned char *end) + { + struct iso9660 *iso9660; ++ int entry_seen = 0; + + iso9660 = (struct iso9660 *)(a->format->data); + +@@ -2257,8 +2258,16 @@ parse_rockridge(struct archive_read *a, struct file_info *file, + } + + p += p[2]; ++ entry_seen = 1; ++ } ++ ++ if (entry_seen) ++ return (ARCHIVE_OK); ++ else { ++ archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT, ++ "Tried to parse Rockridge extensions, but none found"); ++ return (ARCHIVE_WARN); + } +- return (ARCHIVE_OK); + } + + static int +-- +2.20.1 + diff --git a/libarchive-3.3.2-CVE-2018-1000877.patch b/libarchive-3.3.2-CVE-2018-1000877.patch new file mode 100644 index 0000000..e980aa6 --- /dev/null +++ b/libarchive-3.3.2-CVE-2018-1000877.patch @@ -0,0 +1,34 @@ +From 88311f46cdfc719d26bb99d3b47944eb92ceae02 Mon Sep 17 00:00:00 2001 +From: Ondrej Dubaj +Date: Tue, 30 Apr 2019 11:50:33 +0200 +Subject: [PATCH] Avoid a double-free when a window size of 0 is specified + +new_size can be 0 with a malicious or corrupted RAR archive. + +realloc(area, 0) is equivalent to free(area), so the region would +be free()d here and the free()d again in the cleanup function. + +Found with a setup running AFL, afl-rb, and qsym. +--- + libarchive/archive_read_support_format_rar.c | 5 +++++ + 1 file changed, 5 insertions(+) + +diff --git a/libarchive/archive_read_support_format_rar.c b/libarchive/archive_read_support_format_rar.c +index c4a8278..3f88eef 100644 +--- a/libarchive/archive_read_support_format_rar.c ++++ b/libarchive/archive_read_support_format_rar.c +@@ -2317,6 +2317,11 @@ parse_codes(struct archive_read *a) + new_size = DICTIONARY_MAX_SIZE; + else + new_size = rar_fls((unsigned int)rar->unp_size) << 1; ++ if (new_size == 0) { ++ archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT, ++ "Zero window size is invalid."); ++ return (ARCHIVE_FATAL); ++ } + new_window = realloc(rar->lzss.window, new_size); + if (new_window == NULL) { + archive_set_error(&a->archive, ENOMEM, +-- +2.17.1 + diff --git a/libarchive-3.3.2-CVE-2018-1000878.patch b/libarchive-3.3.2-CVE-2018-1000878.patch new file mode 100644 index 0000000..2736827 --- /dev/null +++ b/libarchive-3.3.2-CVE-2018-1000878.patch @@ -0,0 +1,75 @@ +From d00ccaf8c20efbd009964e3e2697d26907d14163 Mon Sep 17 00:00:00 2001 +From: Ondrej Dubaj +Date: Tue, 30 Apr 2019 11:36:08 +0200 +Subject: [PATCH] rar: file split across multi-part archives must match + +Fuzzing uncovered some UAF and memory overrun bugs where a file in a +single file archive reported that it was split across multiple +volumes. This was caused by ppmd7 operations calling +rar_br_fillup. This would invoke rar_read_ahead, which would in some +situations invoke archive_read_format_rar_read_header. That would +check the new file name against the old file name, and if they didn't +match up it would free the ppmd7 buffer and allocate a new +one. However, because the ppmd7 decoder wasn't actually done with the +buffer, it would continue to used the freed buffer. Both reads and +writes to the freed region can be observed. + +This is quite tricky to solve: once the buffer has been freed it is +too late, as the ppmd7 decoder functions almost universally assume +success - there's no way for ppmd_read to signal error, nor are there +good ways for functions like Range_Normalise to propagate them. So we +can't detect after the fact that we're in an invalid state - e.g. by +checking rar->cursor, we have to prevent ourselves from ever ending up +there. So, when we are in the dangerous part or rar_read_ahead that +assumes a valid split, we set a flag force read_header to either go +down the path for split files or bail. This means that the ppmd7 +decoder keeps a valid buffer and just runs out of data. + +Found with a combination of AFL, afl-rb and qsym. +--- + libarchive/archive_read_support_format_rar.c | 9 +++++++++ + 1 file changed, 9 insertions(+) + +diff --git a/libarchive/archive_read_support_format_rar.c b/libarchive/archive_read_support_format_rar.c +index cbb14c3..c4a8278 100644 +--- a/libarchive/archive_read_support_format_rar.c ++++ b/libarchive/archive_read_support_format_rar.c +@@ -258,6 +258,7 @@ struct rar + struct data_block_offsets *dbo; + unsigned int cursor; + unsigned int nodes; ++ char filename_must_match; + + /* LZSS members */ + struct huffman_code maincode; +@@ -1570,6 +1571,12 @@ read_header(struct archive_read *a, struct archive_entry *entry, + } + return ret; + } ++ else if (rar->filename_must_match) ++ { ++ archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT, ++ "Mismatch of file parts split across multi-volume archive"); ++ return (ARCHIVE_FATAL); ++ } + + rar->filename_save = (char*)realloc(rar->filename_save, + filename_size + 1); +@@ -2938,12 +2945,14 @@ rar_read_ahead(struct archive_read *a, size_t min, ssize_t *avail) + else if (*avail == 0 && rar->main_flags & MHD_VOLUME && + rar->file_flags & FHD_SPLIT_AFTER) + { ++ rar->filename_must_match = 1; + ret = archive_read_format_rar_read_header(a, a->entry); + if (ret == (ARCHIVE_EOF)) + { + rar->has_endarc_header = 1; + ret = archive_read_format_rar_read_header(a, a->entry); + } ++ rar->filename_must_match = 0; + if (ret != (ARCHIVE_OK)) + return NULL; + return rar_read_ahead(a, min, avail); +-- +2.17.1 + diff --git a/libarchive-3.3.2-CVE-2019-18408.patch b/libarchive-3.3.2-CVE-2019-18408.patch new file mode 100644 index 0000000..854322c --- /dev/null +++ b/libarchive-3.3.2-CVE-2019-18408.patch @@ -0,0 +1,31 @@ +From 1abcbf1af5209631ccf4fca4ddcab3c863294c85 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Patrik=20Novotn=C3=BD?= +Date: Wed, 15 Jan 2020 16:10:04 +0100 +Subject: [PATCH] RAR reader: fix use after free + +If read_data_compressed() returns ARCHIVE_FAILED, the caller is allowed +to continue with next archive headers. We need to set rar->start_new_table +after the ppmd7_context got freed, otherwise it won't be allocated again. +--- + libarchive/archive_read_support_format_rar.c | 4 +++- + 1 file changed, 3 insertions(+), 1 deletion(-) + +diff --git a/libarchive/archive_read_support_format_rar.c b/libarchive/archive_read_support_format_rar.c +index cbb14c32..9c26ef97 100644 +--- a/libarchive/archive_read_support_format_rar.c ++++ b/libarchive/archive_read_support_format_rar.c +@@ -1037,8 +1037,10 @@ archive_read_format_rar_read_data(struct archive_read *a, const void **buff, + case COMPRESS_METHOD_GOOD: + case COMPRESS_METHOD_BEST: + ret = read_data_compressed(a, buff, size, offset); +- if (ret != ARCHIVE_OK && ret != ARCHIVE_WARN) ++ if (ret != ARCHIVE_OK && ret != ARCHIVE_WARN) { + __archive_ppmd7_functions.Ppmd7_Free(&rar->ppmd7_context); ++ rar->start_new_table = 1; ++ } + break; + + default: +-- +2.24.1 + diff --git a/libarchive-3.3.2-CVE-2019-19221.patch b/libarchive-3.3.2-CVE-2019-19221.patch new file mode 100644 index 0000000..86279ad --- /dev/null +++ b/libarchive-3.3.2-CVE-2019-19221.patch @@ -0,0 +1,98 @@ +From 72085b30bf30867360c4aa77bd43de5e1788d875 Mon Sep 17 00:00:00 2001 +From: Ondrej Dubaj +Date: Tue, 24 Mar 2020 09:22:47 +0100 +Subject: [PATCH] Bugfix and optimize archive_wstring_append_from_mbs() + +The cal to mbrtowc() or mbtowc() should read up to mbs_length +bytes and not wcs_length. This avoids out-of-bounds reads. + +mbrtowc() and mbtowc() return (size_t)-1 wit errno EILSEQ when +they encounter an invalid multibyte character and (size_t)-2 when +they they encounter an incomplete multibyte character. As we return +failure and all our callers error out it makes no sense to continue +parsing mbs. + +As we allocate `len` wchars at the beginning and each wchar has +at least one byte, there will never be need to grow the buffer, +so the code can be left out. On the other hand, we are always +allocatng more memory than we need. + +As long as wcs_length == mbs_length == len we can omit wcs_length. +We keep the old code commented if we decide to save memory and +use autoexpanding wcs_length in the future. +--- + libarchive/archive_string.c | 28 +++++++++++++++++----------- + 1 file changed, 17 insertions(+), 11 deletions(-) + +diff --git a/libarchive/archive_string.c b/libarchive/archive_string.c +index 5ae09b6..d7541dc 100644 +--- a/libarchive/archive_string.c ++++ b/libarchive/archive_string.c +@@ -590,7 +590,7 @@ archive_wstring_append_from_mbs(struct archive_wstring *dest, + * No single byte will be more than one wide character, + * so this length estimate will always be big enough. + */ +- size_t wcs_length = len; ++ //size_t wcs_length = len; + size_t mbs_length = len; + const char *mbs = p; + wchar_t *wcs; +@@ -599,7 +599,11 @@ archive_wstring_append_from_mbs(struct archive_wstring *dest, + + memset(&shift_state, 0, sizeof(shift_state)); + #endif +- if (NULL == archive_wstring_ensure(dest, dest->length + wcs_length + 1)) ++ /* ++ * As we decided to have wcs_length == mbs_length == len ++ * we can use len here instead of wcs_length ++ */ ++ if (NULL == archive_wstring_ensure(dest, dest->length + len + 1)) + return (-1); + wcs = dest->s + dest->length; + /* +@@ -608,6 +612,12 @@ archive_wstring_append_from_mbs(struct archive_wstring *dest, + * multi bytes. + */ + while (*mbs && mbs_length > 0) { ++ /* ++ * The buffer we allocated is always big enough. ++ * Keep this code path in a comment if we decide to choose ++ * smaller wcs_length in the future ++ */ ++/* + if (wcs_length == 0) { + dest->length = wcs - dest->s; + dest->s[dest->length] = L'\0'; +@@ -617,24 +627,20 @@ archive_wstring_append_from_mbs(struct archive_wstring *dest, + return (-1); + wcs = dest->s + dest->length; + } ++*/ + #if HAVE_MBRTOWC +- r = mbrtowc(wcs, mbs, wcs_length, &shift_state); ++ r = mbrtowc(wcs, mbs, mbs_length, &shift_state); + #else +- r = mbtowc(wcs, mbs, wcs_length); ++ r = mbtowc(wcs, mbs, mbs_length); + #endif + if (r == (size_t)-1 || r == (size_t)-2) { + ret_val = -1; +- if (errno == EILSEQ) { +- ++mbs; +- --mbs_length; +- continue; +- } else +- break; ++ break; + } + if (r == 0 || r > mbs_length) + break; + wcs++; +- wcs_length--; ++ //wcs_length--; + mbs += r; + mbs_length -= r; + } +-- +2.24.1 + diff --git a/libarchive-3.3.3-CVE-2021-23177.patch b/libarchive-3.3.3-CVE-2021-23177.patch new file mode 100644 index 0000000..09babb5 --- /dev/null +++ b/libarchive-3.3.3-CVE-2021-23177.patch @@ -0,0 +1,199 @@ +From fba4f123cc456d2b2538f811bb831483bf336bad Mon Sep 17 00:00:00 2001 +From: Martin Matuska +Date: Sat, 21 Aug 2021 20:51:07 +0200 +Subject: [PATCH 1/2] Fix handling of symbolic link ACLs + +On Linux ACLs on symbolic links are not supported. +We must avoid calling acl_set_file() on symbolic links as their +targets are modified instead. + +While here, do not try to set default ACLs on non-directories. + +Fixes #1565 +--- + libarchive/archive_disk_acl_freebsd.c | 20 +++++++++++++++----- + libarchive/archive_disk_acl_linux.c | 23 ++++++++++++++++++++--- + libarchive/archive_disk_acl_sunos.c | 13 +++++++++---- + 3 files changed, 44 insertions(+), 12 deletions(-) + +diff --git a/libarchive/archive_disk_acl_freebsd.c b/libarchive/archive_disk_acl_freebsd.c +index aba41e5d..ed4e7a78 100644 +--- a/libarchive/archive_disk_acl_freebsd.c ++++ b/libarchive/archive_disk_acl_freebsd.c +@@ -319,7 +319,7 @@ translate_acl(struct archive_read_disk *a, + + static int + set_acl(struct archive *a, int fd, const char *name, +- struct archive_acl *abstract_acl, ++ struct archive_acl *abstract_acl, __LA_MODE_T mode, + int ae_requested_type, const char *tname) + { + int acl_type = 0; +@@ -364,6 +364,13 @@ set_acl(struct archive *a, int fd, const char *name, + return (ARCHIVE_FAILED); + } + ++ if (acl_type == ACL_TYPE_DEFAULT && !S_ISDIR(mode)) { ++ errno = EINVAL; ++ archive_set_error(a, errno, ++ "Cannot set default ACL on non-directory"); ++ return (ARCHIVE_WARN); ++ } ++ + acl = acl_init(entries); + if (acl == (acl_t)NULL) { + archive_set_error(a, errno, +@@ -542,7 +549,10 @@ set_acl(struct archive *a, int fd, const char *name, + else if (acl_set_link_np(name, acl_type, acl) != 0) + #else + /* FreeBSD older than 8.0 */ +- else if (acl_set_file(name, acl_type, acl) != 0) ++ else if (S_ISLNK(mode)) { ++ /* acl_set_file() follows symbolic links, skip */ ++ ret = ARCHIVE_OK; ++ } else if (acl_set_file(name, acl_type, acl) != 0) + #endif + { + if (errno == EOPNOTSUPP) { +@@ -677,14 +687,14 @@ archive_write_disk_set_acls(struct archive *a, int fd, const char *name, + & ARCHIVE_ENTRY_ACL_TYPE_POSIX1E) != 0) { + if ((archive_acl_types(abstract_acl) + & ARCHIVE_ENTRY_ACL_TYPE_ACCESS) != 0) { +- ret = set_acl(a, fd, name, abstract_acl, ++ ret = set_acl(a, fd, name, abstract_acl, mode, + ARCHIVE_ENTRY_ACL_TYPE_ACCESS, "access"); + if (ret != ARCHIVE_OK) + return (ret); + } + if ((archive_acl_types(abstract_acl) + & ARCHIVE_ENTRY_ACL_TYPE_DEFAULT) != 0) +- ret = set_acl(a, fd, name, abstract_acl, ++ ret = set_acl(a, fd, name, abstract_acl, mode, + ARCHIVE_ENTRY_ACL_TYPE_DEFAULT, "default"); + + /* Simultaneous POSIX.1e and NFSv4 is not supported */ +@@ -693,7 +703,7 @@ archive_write_disk_set_acls(struct archive *a, int fd, const char *name, + #if ARCHIVE_ACL_FREEBSD_NFS4 + else if ((archive_acl_types(abstract_acl) & + ARCHIVE_ENTRY_ACL_TYPE_NFS4) != 0) { +- ret = set_acl(a, fd, name, abstract_acl, ++ ret = set_acl(a, fd, name, abstract_acl, mode, + ARCHIVE_ENTRY_ACL_TYPE_NFS4, "nfs4"); + } + #endif +diff --git a/libarchive/archive_disk_acl_linux.c b/libarchive/archive_disk_acl_linux.c +index 3928f3d6..31d27053 100644 +--- a/libarchive/archive_disk_acl_linux.c ++++ b/libarchive/archive_disk_acl_linux.c +@@ -343,6 +343,11 @@ set_richacl(struct archive *a, int fd, const char *name, + return (ARCHIVE_FAILED); + } + ++ if (S_ISLNK(mode)) { ++ /* Linux does not support RichACLs on symbolic links */ ++ return (ARCHIVE_OK); ++ } ++ + richacl = richacl_alloc(entries); + if (richacl == NULL) { + archive_set_error(a, errno, +@@ -455,7 +460,7 @@ exit_free: + #if ARCHIVE_ACL_LIBACL + static int + set_acl(struct archive *a, int fd, const char *name, +- struct archive_acl *abstract_acl, ++ struct archive_acl *abstract_acl, __LA_MODE_T mode, + int ae_requested_type, const char *tname) + { + int acl_type = 0; +@@ -488,6 +493,18 @@ set_acl(struct archive *a, int fd, const char *name, + return (ARCHIVE_FAILED); + } + ++ if (S_ISLNK(mode)) { ++ /* Linux does not support ACLs on symbolic links */ ++ return (ARCHIVE_OK); ++ } ++ ++ if (acl_type == ACL_TYPE_DEFAULT && !S_ISDIR(mode)) { ++ errno = EINVAL; ++ archive_set_error(a, errno, ++ "Cannot set default ACL on non-directory"); ++ return (ARCHIVE_WARN); ++ } ++ + acl = acl_init(entries); + if (acl == (acl_t)NULL) { + archive_set_error(a, errno, +@@ -727,14 +744,14 @@ archive_write_disk_set_acls(struct archive *a, int fd, const char *name, + & ARCHIVE_ENTRY_ACL_TYPE_POSIX1E) != 0) { + if ((archive_acl_types(abstract_acl) + & ARCHIVE_ENTRY_ACL_TYPE_ACCESS) != 0) { +- ret = set_acl(a, fd, name, abstract_acl, ++ ret = set_acl(a, fd, name, abstract_acl, mode, + ARCHIVE_ENTRY_ACL_TYPE_ACCESS, "access"); + if (ret != ARCHIVE_OK) + return (ret); + } + if ((archive_acl_types(abstract_acl) + & ARCHIVE_ENTRY_ACL_TYPE_DEFAULT) != 0) +- ret = set_acl(a, fd, name, abstract_acl, ++ ret = set_acl(a, fd, name, abstract_acl, mode, + ARCHIVE_ENTRY_ACL_TYPE_DEFAULT, "default"); + } + #endif /* ARCHIVE_ACL_LIBACL */ +diff --git a/libarchive/archive_disk_acl_sunos.c b/libarchive/archive_disk_acl_sunos.c +index b0f5dfad..0ef3ad52 100644 +--- a/libarchive/archive_disk_acl_sunos.c ++++ b/libarchive/archive_disk_acl_sunos.c +@@ -443,7 +443,7 @@ translate_acl(struct archive_read_disk *a, + + static int + set_acl(struct archive *a, int fd, const char *name, +- struct archive_acl *abstract_acl, ++ struct archive_acl *abstract_acl, __LA_MODE_T mode, + int ae_requested_type, const char *tname) + { + aclent_t *aclent; +@@ -467,7 +467,6 @@ set_acl(struct archive *a, int fd, const char *name, + if (entries == 0) + return (ARCHIVE_OK); + +- + switch (ae_requested_type) { + case ARCHIVE_ENTRY_ACL_TYPE_POSIX1E: + cmd = SETACL; +@@ -492,6 +491,12 @@ set_acl(struct archive *a, int fd, const char *name, + return (ARCHIVE_FAILED); + } + ++ if (S_ISLNK(mode)) { ++ /* Skip ACLs on symbolic links */ ++ ret = ARCHIVE_OK; ++ goto exit_free; ++ } ++ + e = 0; + + while (archive_acl_next(a, abstract_acl, ae_requested_type, &ae_type, +@@ -801,7 +806,7 @@ archive_write_disk_set_acls(struct archive *a, int fd, const char *name, + if ((archive_acl_types(abstract_acl) + & ARCHIVE_ENTRY_ACL_TYPE_POSIX1E) != 0) { + /* Solaris writes POSIX.1e access and default ACLs together */ +- ret = set_acl(a, fd, name, abstract_acl, ++ ret = set_acl(a, fd, name, abstract_acl, mode, + ARCHIVE_ENTRY_ACL_TYPE_POSIX1E, "posix1e"); + + /* Simultaneous POSIX.1e and NFSv4 is not supported */ +@@ -810,7 +815,7 @@ archive_write_disk_set_acls(struct archive *a, int fd, const char *name, + #if ARCHIVE_ACL_SUNOS_NFS4 + else if ((archive_acl_types(abstract_acl) & + ARCHIVE_ENTRY_ACL_TYPE_NFS4) != 0) { +- ret = set_acl(a, fd, name, abstract_acl, ++ ret = set_acl(a, fd, name, abstract_acl, mode, + ARCHIVE_ENTRY_ACL_TYPE_NFS4, "nfs4"); + } + #endif +-- +2.31.1 + diff --git a/libarchive-3.3.3-CVE-2021-31566.patch b/libarchive-3.3.3-CVE-2021-31566.patch new file mode 100644 index 0000000..48adb55 --- /dev/null +++ b/libarchive-3.3.3-CVE-2021-31566.patch @@ -0,0 +1,811 @@ +From b837c72c423b744a2e6c554742877173406dbfa0 Mon Sep 17 00:00:00 2001 +From: Martin Matuska +Date: Sat, 25 May 2019 23:46:59 +0200 +Subject: [PATCH] archive_write_disk_posix: open a fd when processing fixup + entries + +--- + libarchive/archive_write_disk_posix.c | 25 ++++++++++++++++++++----- + 1 file changed, 20 insertions(+), 5 deletions(-) + +diff --git a/libarchive/archive_write_disk_posix.c b/libarchive/archive_write_disk_posix.c +index 70b27b50..0583fbd1 100644 +--- a/libarchive/archive_write_disk_posix.c ++++ b/libarchive/archive_write_disk_posix.c +@@ -182,6 +182,7 @@ struct fixup_entry { + void *mac_metadata; + int fixup; /* bitmask of what needs fixing */ + char *name; ++ int fd; + }; + + /* +@@ -2354,20 +2355,31 @@ _archive_write_disk_close(struct archive *_a) + + while (p != NULL) { + a->pst = NULL; /* Mark stat cache as out-of-date. */ ++ if (p->fd < 0 && p->fixup & ++ (TODO_TIMES | TODO_MODE_BASE | TODO_ACLS | TODO_FFLAGS)) { ++ p->fd = open(p->name, ++ O_WRONLY | O_BINARY | O_NOFOLLOW | O_CLOEXEC); ++ } + if (p->fixup & TODO_TIMES) { +- set_times(a, -1, p->mode, p->name, ++ set_times(a, p->fd, p->mode, p->name, + p->atime, p->atime_nanos, + p->birthtime, p->birthtime_nanos, + p->mtime, p->mtime_nanos, + p->ctime, p->ctime_nanos); + } +- if (p->fixup & TODO_MODE_BASE) ++ if (p->fixup & TODO_MODE_BASE) { ++#ifdef HAVE_FCHMOD ++ if (p->fd >= 0) ++ fchmod(p->fd, p->mode); ++ else ++#endif + chmod(p->name, p->mode); ++ } + if (p->fixup & TODO_ACLS) +- archive_write_disk_set_acls(&a->archive, -1, p->name, +- &p->acl, p->mode); ++ archive_write_disk_set_acls(&a->archive, p->fd, ++ p->name, &p->acl, p->mode); + if (p->fixup & TODO_FFLAGS) +- set_fflags_platform(a, -1, p->name, ++ set_fflags_platform(a, p->fd, p->name, + p->mode, p->fflags_set, 0); + if (p->fixup & TODO_MAC_METADATA) + set_mac_metadata(a, p->name, p->mac_metadata, +@@ -2376,6 +2388,8 @@ _archive_write_disk_close(struct archive *_a) + archive_acl_clear(&p->acl); + free(p->mac_metadata); + free(p->name); ++ if (p->fd >= 0) ++ close(p->fd); + free(p); + p = next; + } +@@ -2510,6 +2524,7 @@ new_fixup(struct archive_write_disk *a, const char *pathname) + a->fixup_list = fe; + fe->fixup = 0; + fe->name = strdup(pathname); ++ fe->fd = -1; + return (fe); + } + +-- +2.31.1 + +From 6d5204058ed51e11588a438737e9033305cfd248 Mon Sep 17 00:00:00 2001 +From: Martin Matuska +Date: Thu, 6 Jun 2019 15:12:11 +0200 +Subject: [PATCH] archive_write_disk_posix changes - private file descriptor in + _archive_write_disk_close() - use la_opendirat() in edit_deep_directories() + +--- + libarchive/archive_write_disk_posix.c | 25 ++++++++++++------------- + 1 file changed, 12 insertions(+), 13 deletions(-) + +diff --git a/libarchive/archive_write_disk_posix.c b/libarchive/archive_write_disk_posix.c +index 89941c64..b1a0bb38 100644 +--- a/libarchive/archive_write_disk_posix.c ++++ b/libarchive/archive_write_disk_posix.c +@@ -186,7 +186,6 @@ struct fixup_entry { + void *mac_metadata; + int fixup; /* bitmask of what needs fixing */ + char *name; +- int fd; + }; + + /* +@@ -1947,7 +1946,7 @@ edit_deep_directories(struct archive_write_disk *a) + return; + + /* Try to record our starting dir. */ +- a->restore_pwd = open(".", O_RDONLY | O_BINARY | O_CLOEXEC); ++ a->restore_pwd = open(".", O_RDONLY | O_BINARY | O_CLOEXEC | O_DIRECTORY); + __archive_ensure_cloexec_flag(a->restore_pwd); + if (a->restore_pwd < 0) + return; +@@ -2380,7 +2379,7 @@ _archive_write_disk_close(struct archive *_a) + { + struct archive_write_disk *a = (struct archive_write_disk *)_a; + struct fixup_entry *next, *p; +- int ret; ++ int fd, ret; + + archive_check_magic(&a->archive, ARCHIVE_WRITE_DISK_MAGIC, + ARCHIVE_STATE_HEADER | ARCHIVE_STATE_DATA, +@@ -2391,14 +2390,15 @@ _archive_write_disk_close(struct archive *_a) + p = sort_dir_list(a->fixup_list); + + while (p != NULL) { ++ fd = -1; + a->pst = NULL; /* Mark stat cache as out-of-date. */ +- if (p->fd < 0 && p->fixup & ++ if (p->fixup & + (TODO_TIMES | TODO_MODE_BASE | TODO_ACLS | TODO_FFLAGS)) { +- p->fd = open(p->name, ++ fd = open(p->name, + O_WRONLY | O_BINARY | O_NOFOLLOW | O_CLOEXEC); + } + if (p->fixup & TODO_TIMES) { +- set_times(a, p->fd, p->mode, p->name, ++ set_times(a, fd, p->mode, p->name, + p->atime, p->atime_nanos, + p->birthtime, p->birthtime_nanos, + p->mtime, p->mtime_nanos, +@@ -2406,17 +2406,17 @@ _archive_write_disk_close(struct archive *_a) + } + if (p->fixup & TODO_MODE_BASE) { + #ifdef HAVE_FCHMOD +- if (p->fd >= 0) +- fchmod(p->fd, p->mode); ++ if (fd >= 0) ++ fchmod(fd, p->mode); + else + #endif + chmod(p->name, p->mode); + } + if (p->fixup & TODO_ACLS) +- archive_write_disk_set_acls(&a->archive, p->fd, ++ archive_write_disk_set_acls(&a->archive, fd, + p->name, &p->acl, p->mode); + if (p->fixup & TODO_FFLAGS) +- set_fflags_platform(a, p->fd, p->name, ++ set_fflags_platform(a, fd, p->name, + p->mode, p->fflags_set, 0); + if (p->fixup & TODO_MAC_METADATA) + set_mac_metadata(a, p->name, p->mac_metadata, +@@ -2425,8 +2425,8 @@ _archive_write_disk_close(struct archive *_a) + archive_acl_clear(&p->acl); + free(p->mac_metadata); + free(p->name); +- if (p->fd >= 0) +- close(p->fd); ++ if (fd >= 0) ++ close(fd); + free(p); + p = next; + } +@@ -2561,7 +2561,6 @@ new_fixup(struct archive_write_disk *a, const char *pathname) + a->fixup_list = fe; + fe->fixup = 0; + fe->name = strdup(pathname); +- fe->fd = -1; + return (fe); + } + +-- +2.31.1 + +From e2ad1a2c3064fa9eba6274b3641c4c1beed25c0b Mon Sep 17 00:00:00 2001 +From: Martin Matuska +Date: Sun, 22 Aug 2021 03:53:28 +0200 +Subject: [PATCH] Never follow symlinks when setting file flags on Linux + +When opening a file descriptor to set file flags on linux, ensure +no symbolic links are followed. This fixes the case when an archive +contains a directory entry followed by a symlink entry with the same +path. The fixup code would modify file flags of the symlink target. +--- + libarchive/archive_write_disk_posix.c | 3 ++- + 1 file changed, 2 insertions(+), 1 deletion(-) + +diff --git a/libarchive/archive_write_disk_posix.c b/libarchive/archive_write_disk_posix.c +index ba4e65df..8474617e 100644 +--- a/libarchive/archive_write_disk_posix.c ++++ b/libarchive/archive_write_disk_posix.c +@@ -3927,7 +3927,8 @@ set_fflags_platform(struct archive_write_disk *a, int fd, const char *name, + + /* If we weren't given an fd, open it ourselves. */ + if (myfd < 0) { +- myfd = open(name, O_RDONLY | O_NONBLOCK | O_BINARY | O_CLOEXEC); ++ myfd = open(name, O_RDONLY | O_NONBLOCK | O_BINARY | ++ O_CLOEXEC | O_NOFOLLOW); + __archive_ensure_cloexec_flag(myfd); + } + if (myfd < 0) +-- +2.31.1 + +From b41daecb5ccb4c8e3b2c53fd6147109fc12c3043 Mon Sep 17 00:00:00 2001 +From: Martin Matuska +Date: Fri, 20 Aug 2021 01:50:27 +0200 +Subject: [PATCH] Do not follow symlinks when processing the fixup list + +Use lchmod() instead of chmod() and tell the remaining functions that the +real file to be modified is a symbolic link. + +Fixes #1566 +--- + Makefile.am | 1 + + libarchive/archive_write_disk_posix.c | 24 +++++++- + libarchive/test/CMakeLists.txt | 1 + + libarchive/test/test_write_disk_fixup.c | 77 +++++++++++++++++++++++++ + 4 files changed, 102 insertions(+), 1 deletion(-) + create mode 100644 libarchive/test/test_write_disk_fixup.c + +diff --git a/Makefile.am b/Makefile.am +index 58edb74e..c93a82e9 100644 +--- a/Makefile.am ++++ b/Makefile.am +@@ -560,6 +560,7 @@ libarchive_test_SOURCES= \ + libarchive/test/test_write_disk.c \ + libarchive/test/test_write_disk_appledouble.c \ + libarchive/test/test_write_disk_failures.c \ ++ libarchive/test/test_write_disk_fixup.c \ + libarchive/test/test_write_disk_hardlink.c \ + libarchive/test/test_write_disk_hfs_compression.c \ + libarchive/test/test_write_disk_lookup.c \ +diff --git a/libarchive/archive_write_disk_posix.c b/libarchive/archive_write_disk_posix.c +index 8474617e..fcd733af 100644 +--- a/libarchive/archive_write_disk_posix.c ++++ b/libarchive/archive_write_disk_posix.c +@@ -2461,6 +2461,7 @@ _archive_write_disk_close(struct archive *_a) + { + struct archive_write_disk *a = (struct archive_write_disk *)_a; + struct fixup_entry *next, *p; ++ struct stat st; + int fd, ret; + + archive_check_magic(&a->archive, ARCHIVE_WRITE_DISK_MAGIC, +@@ -2478,6 +2479,20 @@ _archive_write_disk_close(struct archive *_a) + (TODO_TIMES | TODO_MODE_BASE | TODO_ACLS | TODO_FFLAGS)) { + fd = open(p->name, + O_WRONLY | O_BINARY | O_NOFOLLOW | O_CLOEXEC); ++ if (fd == -1) { ++ /* If we cannot lstat, skip entry */ ++ if (lstat(p->name, &st) != 0) ++ goto skip_fixup_entry; ++ /* ++ * If we deal with a symbolic link, mark ++ * it in the fixup mode to ensure no ++ * modifications are made to its target. ++ */ ++ if (S_ISLNK(st.st_mode)) { ++ p->mode &= ~S_IFMT; ++ p->mode |= S_IFLNK; ++ } ++ } + } + if (p->fixup & TODO_TIMES) { + set_times(a, fd, p->mode, p->name, +@@ -2492,7 +2507,12 @@ _archive_write_disk_close(struct archive *_a) + fchmod(fd, p->mode); + else + #endif +- chmod(p->name, p->mode); ++#ifdef HAVE_LCHMOD ++ lchmod(p->name, p->mode); ++#else ++ if (!S_ISLNK(p->mode)) ++ chmod(p->name, p->mode); ++#endif + } + if (p->fixup & TODO_ACLS) + archive_write_disk_set_acls(&a->archive, fd, +@@ -2503,6 +2523,7 @@ _archive_write_disk_close(struct archive *_a) + if (p->fixup & TODO_MAC_METADATA) + set_mac_metadata(a, p->name, p->mac_metadata, + p->mac_metadata_size); ++skip_fixup_entry: + next = p->next; + archive_acl_clear(&p->acl); + free(p->mac_metadata); +@@ -2643,6 +2664,7 @@ new_fixup(struct archive_write_disk *a, const char *pathname) + fe->next = a->fixup_list; + a->fixup_list = fe; + fe->fixup = 0; ++ fe->mode = 0; + fe->name = strdup(pathname); + return (fe); + } +diff --git a/libarchive/test/CMakeLists.txt b/libarchive/test/CMakeLists.txt +index b26f679c..53cc3e22 100644 +--- a/libarchive/test/CMakeLists.txt ++++ b/libarchive/test/CMakeLists.txt +@@ -209,6 +209,7 @@ IF(ENABLE_TEST) + test_write_disk.c + test_write_disk_appledouble.c + test_write_disk_failures.c ++ test_write_disk_fixup.c + test_write_disk_hardlink.c + test_write_disk_hfs_compression.c + test_write_disk_lookup.c +diff --git a/libarchive/test/test_write_disk_fixup.c b/libarchive/test/test_write_disk_fixup.c +new file mode 100644 +index 00000000..153cc3a9 +--- /dev/null ++++ b/libarchive/test/test_write_disk_fixup.c +@@ -0,0 +1,77 @@ ++/*- ++ * Copyright (c) 2021 Martin Matuska ++ * All rights reserved. ++ * ++ * Redistribution and use in source and binary forms, with or without ++ * modification, are permitted provided that the following conditions ++ * are met: ++ * 1. Redistributions of source code must retain the above copyright ++ * notice, this list of conditions and the following disclaimer. ++ * 2. Redistributions in binary form must reproduce the above copyright ++ * notice, this list of conditions and the following disclaimer in the ++ * documentation and/or other materials provided with the distribution. ++ * ++ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR ++ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES ++ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. ++ * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT, ++ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT ++ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, ++ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY ++ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT ++ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF ++ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ++ */ ++#include "test.h" ++ ++/* ++ * Test fixup entries don't follow symlinks ++ */ ++DEFINE_TEST(test_write_disk_fixup) ++{ ++ struct archive *ad; ++ struct archive_entry *ae; ++ int r; ++ ++ if (!canSymlink()) { ++ skipping("Symlinks not supported"); ++ return; ++ } ++ ++ /* Write entries to disk. */ ++ assert((ad = archive_write_disk_new()) != NULL); ++ ++ /* ++ * Create a file ++ */ ++ assertMakeFile("victim", 0600, "a"); ++ ++ /* ++ * Create a directory and a symlink with the same name ++ */ ++ ++ /* Directory: dir */ ++ assert((ae = archive_entry_new()) != NULL); ++ archive_entry_copy_pathname(ae, "dir"); ++ archive_entry_set_mode(ae, AE_IFDIR | 0606); ++ assertEqualIntA(ad, 0, archive_write_header(ad, ae)); ++ assertEqualIntA(ad, 0, archive_write_finish_entry(ad)); ++ archive_entry_free(ae); ++ ++ /* Symbolic Link: dir -> foo */ ++ assert((ae = archive_entry_new()) != NULL); ++ archive_entry_copy_pathname(ae, "dir"); ++ archive_entry_set_mode(ae, AE_IFLNK | 0777); ++ archive_entry_set_size(ae, 0); ++ archive_entry_copy_symlink(ae, "victim"); ++ assertEqualIntA(ad, 0, r = archive_write_header(ad, ae)); ++ if (r >= ARCHIVE_WARN) ++ assertEqualIntA(ad, 0, archive_write_finish_entry(ad)); ++ archive_entry_free(ae); ++ ++ assertEqualInt(ARCHIVE_OK, archive_write_free(ad)); ++ ++ /* Test the entries on disk. */ ++ assertIsSymlink("dir", "victim"); ++ assertFileMode("victim", 0600); ++} +-- +2.31.1 + +From 8a1bd5c18e896f0411a991240ce0d772bb02c840 Mon Sep 17 00:00:00 2001 +From: Martin Matuska +Date: Fri, 27 Aug 2021 10:56:28 +0200 +Subject: [PATCH] Fix following symlinks when processing the fixup list + +The previous fix in b41daecb5 was incomplete. Fixup entries are +given the original path without calling cleanup_pathname(). +To make sure we don't follow a symlink, we must strip trailing +slashes from the path. + +The fixup entries are always directories. Make sure we try to modify +only directories by providing O_DIRECTORY to open() (if supported) +and if it fails to check directory via lstat(). + +Fixes #1566 +--- + libarchive/archive_write_disk_posix.c | 62 +++++++++++++++++-------- + libarchive/test/test_write_disk_fixup.c | 44 ++++++++++++++---- + 2 files changed, 78 insertions(+), 28 deletions(-) + +diff --git a/libarchive/archive_write_disk_posix.c b/libarchive/archive_write_disk_posix.c +index fcd733af..aadc5871 100644 +--- a/libarchive/archive_write_disk_posix.c ++++ b/libarchive/archive_write_disk_posix.c +@@ -2462,6 +2462,7 @@ _archive_write_disk_close(struct archive *_a) + struct archive_write_disk *a = (struct archive_write_disk *)_a; + struct fixup_entry *next, *p; + struct stat st; ++ char *c; + int fd, ret; + + archive_check_magic(&a->archive, ARCHIVE_WRITE_DISK_MAGIC, +@@ -2475,24 +2476,49 @@ _archive_write_disk_close(struct archive *_a) + while (p != NULL) { + fd = -1; + a->pst = NULL; /* Mark stat cache as out-of-date. */ +- if (p->fixup & +- (TODO_TIMES | TODO_MODE_BASE | TODO_ACLS | TODO_FFLAGS)) { +- fd = open(p->name, +- O_WRONLY | O_BINARY | O_NOFOLLOW | O_CLOEXEC); ++ ++ /* We must strip trailing slashes from the path to avoid ++ dereferencing symbolic links to directories */ ++ c = p->name; ++ while (*c != '\0') ++ c++; ++ while (c != p->name && *(c - 1) == '/') { ++ c--; ++ *c = '\0'; ++ } ++ ++ if (p->fixup == 0) ++ goto skip_fixup_entry; ++ else { ++ fd = open(p->name, O_BINARY | O_NOFOLLOW | O_RDONLY ++#if defined(O_DIRECTORY) ++ | O_DIRECTORY ++#endif ++ | O_CLOEXEC); ++ /* ++ ` * If we don't support O_DIRECTORY, ++ * or open() has failed, we must stat() ++ * to verify that we are opening a directory ++ */ ++#if defined(O_DIRECTORY) + if (fd == -1) { +- /* If we cannot lstat, skip entry */ +- if (lstat(p->name, &st) != 0) ++ if (lstat(p->name, &st) != 0 || ++ !S_ISDIR(st.st_mode)) { + goto skip_fixup_entry; +- /* +- * If we deal with a symbolic link, mark +- * it in the fixup mode to ensure no +- * modifications are made to its target. +- */ +- if (S_ISLNK(st.st_mode)) { +- p->mode &= ~S_IFMT; +- p->mode |= S_IFLNK; + } + } ++#else ++#if HAVE_FSTAT ++ if (fd > 0 && ( ++ fstat(fd, &st) != 0 || !S_ISDIR(st.st_mode))) { ++ goto skip_fixup_entry; ++ } else ++#endif ++ if (lstat(p->name, &st) != 0 || ++ !S_ISDIR(st.st_mode)) { ++ goto skip_fixup_entry; ++ } ++#endif + } + if (p->fixup & TODO_TIMES) { + set_times(a, fd, p->mode, p->name, +@@ -2504,14 +2530,13 @@ _archive_write_disk_close(struct archive *_a) + if (p->fixup & TODO_MODE_BASE) { + #ifdef HAVE_FCHMOD + if (fd >= 0) +- fchmod(fd, p->mode); ++ fchmod(fd, p->mode & 07777); + else + #endif + #ifdef HAVE_LCHMOD +- lchmod(p->name, p->mode); ++ lchmod(p->name, p->mode & 07777); + #else +- if (!S_ISLNK(p->mode)) +- chmod(p->name, p->mode); ++ chmod(p->name, p->mode & 07777); + #endif + } + if (p->fixup & TODO_ACLS) +@@ -2664,7 +2689,6 @@ new_fixup(struct archive_write_disk *a, const char *pathname) + fe->next = a->fixup_list; + a->fixup_list = fe; + fe->fixup = 0; +- fe->mode = 0; + fe->name = strdup(pathname); + return (fe); + } +diff --git a/libarchive/test/test_write_disk_fixup.c b/libarchive/test/test_write_disk_fixup.c +index c399c984..b83b7307 100644 +--- a/libarchive/test/test_write_disk_fixup.c ++++ b/libarchive/test/test_write_disk_fixup.c +@@ -47,26 +47,50 @@ DEFINE_TEST(test_write_disk_fixup) + /* + * Create a file + */ +- assertMakeFile("victim", 0600, "a"); ++ assertMakeFile("file", 0600, "a"); ++ ++ /* ++ * Create a directory ++ */ ++ assertMakeDir("dir", 0700); + + /* + * Create a directory and a symlink with the same name + */ + +- /* Directory: dir */ ++ /* Directory: dir1 */ ++ assert((ae = archive_entry_new()) != NULL); ++ archive_entry_copy_pathname(ae, "dir1/"); ++ archive_entry_set_mode(ae, AE_IFDIR | 0555); ++ assertEqualIntA(ad, 0, archive_write_header(ad, ae)); ++ assertEqualIntA(ad, 0, archive_write_finish_entry(ad)); ++ archive_entry_free(ae); ++ ++ /* Directory: dir2 */ + assert((ae = archive_entry_new()) != NULL); +- archive_entry_copy_pathname(ae, "dir"); +- archive_entry_set_mode(ae, AE_IFDIR | 0606); ++ archive_entry_copy_pathname(ae, "dir2/"); ++ archive_entry_set_mode(ae, AE_IFDIR | 0555); + assertEqualIntA(ad, 0, archive_write_header(ad, ae)); + assertEqualIntA(ad, 0, archive_write_finish_entry(ad)); + archive_entry_free(ae); + +- /* Symbolic Link: dir -> foo */ ++ /* Symbolic Link: dir1 -> dir */ ++ assert((ae = archive_entry_new()) != NULL); ++ archive_entry_copy_pathname(ae, "dir1"); ++ archive_entry_set_mode(ae, AE_IFLNK | 0777); ++ archive_entry_set_size(ae, 0); ++ archive_entry_copy_symlink(ae, "dir"); ++ assertEqualIntA(ad, 0, r = archive_write_header(ad, ae)); ++ if (r >= ARCHIVE_WARN) ++ assertEqualIntA(ad, 0, archive_write_finish_entry(ad)); ++ archive_entry_free(ae); ++ ++ /* Symbolic Link: dir2 -> file */ + assert((ae = archive_entry_new()) != NULL); +- archive_entry_copy_pathname(ae, "dir"); ++ archive_entry_copy_pathname(ae, "dir2"); + archive_entry_set_mode(ae, AE_IFLNK | 0777); + archive_entry_set_size(ae, 0); +- archive_entry_copy_symlink(ae, "victim"); ++ archive_entry_copy_symlink(ae, "file"); + assertEqualIntA(ad, 0, r = archive_write_header(ad, ae)); + if (r >= ARCHIVE_WARN) + assertEqualIntA(ad, 0, archive_write_finish_entry(ad)); +@@ -75,6 +99,8 @@ DEFINE_TEST(test_write_disk_fixup) + assertEqualInt(ARCHIVE_OK, archive_write_free(ad)); + + /* Test the entries on disk. */ +- assertIsSymlink("dir", "victim"); +- assertFileMode("victim", 0600); ++ assertIsSymlink("dir1", "dir"); ++ assertIsSymlink("dir2", "file"); ++ assertFileMode("dir", 0700); ++ assertFileMode("file", 0600); + } +-- +2.31.1 + +From ede459d2ebb879f5eedb6f7abea203be0b334230 Mon Sep 17 00:00:00 2001 +From: Martin Matuska +Date: Wed, 17 Nov 2021 21:06:00 +0100 +Subject: [PATCH] archive_write_disk_posix: fix writing fflags broken in + 8a1bd5c + +The fixup list was erroneously assumed to be directories only. +Only in the case of critical file flags modification (e.g. SF_IMMUTABLE +on BSD systems), other file types (e.g. regular files or symbolic links) +may be added to the fixup list. We still need to verify that we are writing +to the correct file type, so compare the archive entry file type with +the file type of the file to be modified. + +Fixes #1617 +--- + libarchive/archive_write_disk_posix.c | 87 +++++++++++++++++++++++---- + 1 file changed, 75 insertions(+), 12 deletions(-) + +diff --git a/libarchive/archive_write_disk_posix.c b/libarchive/archive_write_disk_posix.c +index aadc5871..7e57aac2 100644 +--- a/libarchive/archive_write_disk_posix.c ++++ b/libarchive/archive_write_disk_posix.c +@@ -173,6 +173,7 @@ struct fixup_entry { + struct fixup_entry *next; + struct archive_acl acl; + mode_t mode; ++ __LA_MODE_T filetype; + int64_t atime; + int64_t birthtime; + int64_t mtime; +@@ -357,6 +358,7 @@ struct archive_write_disk { + + #define HFS_BLOCKS(s) ((s) >> 12) + ++static int la_verify_filetype(mode_t, __LA_MODE_T); + static void fsobj_error(int *, struct archive_string *, int, const char *, + const char *); + static int check_symlinks_fsobj(char *, int *, struct archive_string *, +@@ -464,6 +466,39 @@ la_opendirat(int fd, const char *path) { + static ssize_t _archive_write_disk_data_block(struct archive *, const void *, + size_t, int64_t); + ++static int ++la_verify_filetype(mode_t mode, __LA_MODE_T filetype) { ++ int ret = 0; ++ ++ switch (filetype) { ++ case AE_IFREG: ++ ret = (S_ISREG(mode)); ++ break; ++ case AE_IFDIR: ++ ret = (S_ISDIR(mode)); ++ break; ++ case AE_IFLNK: ++ ret = (S_ISLNK(mode)); ++ break; ++ case AE_IFSOCK: ++ ret = (S_ISSOCK(mode)); ++ break; ++ case AE_IFCHR: ++ ret = (S_ISCHR(mode)); ++ break; ++ case AE_IFBLK: ++ ret = (S_ISBLK(mode)); ++ break; ++ case AE_IFIFO: ++ ret = (S_ISFIFO(mode)); ++ break; ++ default: ++ break; ++ } ++ ++ return (ret); ++} ++ + static int + lazy_stat(struct archive_write_disk *a) + { +@@ -822,6 +857,7 @@ _archive_write_disk_header(struct archive *_a, struct archive_entry *entry) + fe = current_fixup(a, archive_entry_pathname(entry)); + if (fe == NULL) + return (ARCHIVE_FATAL); ++ fe->filetype = archive_entry_filetype(entry); + fe->fixup |= TODO_MODE_BASE; + fe->mode = a->mode; + } +@@ -832,6 +868,7 @@ _archive_write_disk_header(struct archive *_a, struct archive_entry *entry) + fe = current_fixup(a, archive_entry_pathname(entry)); + if (fe == NULL) + return (ARCHIVE_FATAL); ++ fe->filetype = archive_entry_filetype(entry); + fe->mode = a->mode; + fe->fixup |= TODO_TIMES; + if (archive_entry_atime_is_set(entry)) { +@@ -865,6 +902,7 @@ _archive_write_disk_header(struct archive *_a, struct archive_entry *entry) + fe = current_fixup(a, archive_entry_pathname(entry)); + if (fe == NULL) + return (ARCHIVE_FATAL); ++ fe->filetype = archive_entry_filetype(entry); + fe->fixup |= TODO_ACLS; + archive_acl_copy(&fe->acl, archive_entry_acl(entry)); + } +@@ -877,6 +915,7 @@ _archive_write_disk_header(struct archive *_a, struct archive_entry *entry) + fe = current_fixup(a, archive_entry_pathname(entry)); + if (fe == NULL) + return (ARCHIVE_FATAL); ++ fe->filetype = archive_entry_filetype(entry); + fe->mac_metadata = malloc(metadata_size); + if (fe->mac_metadata != NULL) { + memcpy(fe->mac_metadata, metadata, +@@ -891,6 +930,7 @@ _archive_write_disk_header(struct archive *_a, struct archive_entry *entry) + fe = current_fixup(a, archive_entry_pathname(entry)); + if (fe == NULL) + return (ARCHIVE_FATAL); ++ fe->filetype = archive_entry_filetype(entry); + fe->fixup |= TODO_FFLAGS; + /* TODO: Complete this.. defer fflags from below. */ + } +@@ -2463,7 +2503,7 @@ _archive_write_disk_close(struct archive *_a) + struct fixup_entry *next, *p; + struct stat st; + char *c; +- int fd, ret; ++ int fd, ret, openflags; + + archive_check_magic(&a->archive, ARCHIVE_WRITE_DISK_MAGIC, + ARCHIVE_STATE_HEADER | ARCHIVE_STATE_DATA, +@@ -2490,32 +2530,53 @@ _archive_write_disk_close(struct archive *_a) + if (p->fixup == 0) + goto skip_fixup_entry; + else { +- fd = open(p->name, O_BINARY | O_NOFOLLOW | O_RDONLY ++ /* ++ * We need to verify if the type of the file ++ * we are going to open matches the file type ++ * of the fixup entry. ++ */ ++ openflags = O_BINARY | O_NOFOLLOW | O_RDONLY ++ | O_CLOEXEC; + #if defined(O_DIRECTORY) +- | O_DIRECTORY ++ if (p->filetype == AE_IFDIR) ++ openflags |= O_DIRECTORY; + #endif +- | O_CLOEXEC); ++ fd = open(p->name, openflags); ++ ++#if defined(O_DIRECTORY) + /* +- ` * If we don't support O_DIRECTORY, +- * or open() has failed, we must stat() +- * to verify that we are opening a directory ++ * If we support O_DIRECTORY and open was ++ * successful we can skip the file type check ++ * for directories. For other file types ++ * we need to verify via fstat() or lstat() + */ +-#if defined(O_DIRECTORY) +- if (fd == -1) { ++ if (fd == -1 || p->filetype != AE_IFDIR) { ++#if HAVE_FSTAT ++ if (fd > 0 && ( ++ fstat(fd, &st) != 0 || ++ la_verify_filetype(st.st_mode, ++ p->filetype) == 0)) { ++ goto skip_fixup_entry; ++ } else ++#endif + if (lstat(p->name, &st) != 0 || +- !S_ISDIR(st.st_mode)) { ++ la_verify_filetype(st.st_mode, ++ p->filetype) == 0) { + goto skip_fixup_entry; + } + } + #else + #if HAVE_FSTAT + if (fd > 0 && ( +- fstat(fd, &st) != 0 || !S_ISDIR(st.st_mode))) { ++ fstat(fd, &st) != 0 || ++ la_verify_filetype(st.st_mode, ++ p->filetype) == 0)) { + goto skip_fixup_entry; + } else + #endif + if (lstat(p->name, &st) != 0 || +- !S_ISDIR(st.st_mode)) { ++ la_verify_filetype(st.st_mode, ++ p->filetype) == 0) { + goto skip_fixup_entry; + } + #endif +@@ -2689,6 +2750,7 @@ new_fixup(struct archive_write_disk *a, const char *pathname) + fe->next = a->fixup_list; + a->fixup_list = fe; + fe->fixup = 0; ++ fe->filetype = 0; + fe->name = strdup(pathname); + return (fe); + } +@@ -3811,6 +3873,7 @@ set_fflags(struct archive_write_disk *a) + le = current_fixup(a, a->name); + if (le == NULL) + return (ARCHIVE_FATAL); ++ le->filetype = archive_entry_filetype(a->entry); + le->fixup |= TODO_FFLAGS; + le->fflags_set = set; + /* Store the mode if it's not already there. */ +-- +2.31.1 + diff --git a/libarchive-3.3.3-fixed-zstd_test.patch b/libarchive-3.3.3-fixed-zstd_test.patch new file mode 100644 index 0000000..ea78f9a --- /dev/null +++ b/libarchive-3.3.3-fixed-zstd_test.patch @@ -0,0 +1,114 @@ +From 1bb2ec24b433bf87fed40e207c61c6aa8790e793 Mon Sep 17 00:00:00 2001 +From: Ondrej Dubaj +Date: Mon, 18 Nov 2019 12:41:07 +0100 +Subject: [PATCH] test_write_filter_zstd: size @ lvl=20 < default < lvl=1 + +Raise compression on the second test to level=20, and perform a +third at level=1. Expect the output archive sizes to line up +based on compression level. Reduces test susceptibility to small +output size variations from different libzstd releases. +--- + libarchive/test/test_write_filter_zstd.c | 66 +++++++++++++++++-- + 1 file changed, 60 insertions(+), 6 deletions(-) + +diff --git a/libarchive/test/test_write_filter_zstd.c b/libarchive/test/test_write_filter_zstd.c +index da3c806..13de134 100644 +--- a/libarchive/test/test_write_filter_zstd.c ++++ b/libarchive/test/test_write_filter_zstd.c +@@ -34,7 +34,7 @@ DEFINE_TEST(test_write_filter_zstd) + char *buff, *data; + size_t buffsize, datasize; + char path[16]; +- size_t used1, used2; ++ size_t used1, used2, used3; + int i, r; + + buffsize = 2000000; +@@ -125,7 +125,7 @@ DEFINE_TEST(test_write_filter_zstd) + assertEqualIntA(a, ARCHIVE_OK, + archive_write_set_filter_option(a, NULL, "compression-level", "9")); + assertEqualIntA(a, ARCHIVE_OK, +- archive_write_set_filter_option(a, NULL, "compression-level", "6")); ++ archive_write_set_filter_option(a, NULL, "compression-level", "20")); + assertEqualIntA(a, ARCHIVE_OK, archive_write_open_memory(a, buff, buffsize, &used2)); + for (i = 0; i < 100; i++) { + sprintf(path, "file%03d", i); +@@ -140,10 +140,6 @@ DEFINE_TEST(test_write_filter_zstd) + assertEqualIntA(a, ARCHIVE_OK, archive_write_close(a)); + assertEqualInt(ARCHIVE_OK, archive_write_free(a)); + +- failure("compression-level=6 wrote %d bytes, default wrote %d bytes", +- (int)used2, (int)used1); +- assert(used2 < used1); +- + assert((a = archive_read_new()) != NULL); + assertEqualIntA(a, ARCHIVE_OK, archive_read_support_format_all(a)); + r = archive_read_support_filter_zstd(a); +@@ -167,6 +163,64 @@ DEFINE_TEST(test_write_filter_zstd) + } + assertEqualInt(ARCHIVE_OK, archive_read_free(a)); + ++ /* ++ * One more time at level 1 ++ */ ++ assert((a = archive_write_new()) != NULL); ++ assertEqualIntA(a, ARCHIVE_OK, archive_write_set_format_ustar(a)); ++ assertEqualIntA(a, ARCHIVE_OK, ++ archive_write_set_bytes_per_block(a, 10)); ++ assertEqualIntA(a, ARCHIVE_OK, archive_write_add_filter_zstd(a)); ++ assertEqualIntA(a, ARCHIVE_OK, ++ archive_write_set_filter_option(a, NULL, "compression-level", "1")); ++ assertEqualIntA(a, ARCHIVE_OK, archive_write_open_memory(a, buff, buffsize, &used3)); ++ assert((ae = archive_entry_new()) != NULL); ++ archive_entry_set_filetype(ae, AE_IFREG); ++ archive_entry_set_size(ae, datasize); ++ for (i = 0; i < 100; i++) { ++ sprintf(path, "file%03d", i); ++ archive_entry_copy_pathname(ae, path); ++ assertEqualIntA(a, ARCHIVE_OK, archive_write_header(a, ae)); ++ assertA(datasize == (size_t)archive_write_data(a, data, datasize)); ++ } ++ archive_entry_free(ae); ++ assertEqualIntA(a, ARCHIVE_OK, archive_write_close(a)); ++ assertEqualInt(ARCHIVE_OK, archive_write_free(a)); ++ ++ assert((a = archive_read_new()) != NULL); ++ assertEqualIntA(a, ARCHIVE_OK, archive_read_support_format_all(a)); ++ r = archive_read_support_filter_zstd(a); ++ if (r == ARCHIVE_WARN) { ++ skipping("zstd reading not fully supported on this platform"); ++ } else { ++ assertEqualIntA(a, ARCHIVE_OK, ++ archive_read_support_filter_all(a)); ++ assertEqualIntA(a, ARCHIVE_OK, ++ archive_read_open_memory(a, buff, used3)); ++ for (i = 0; i < 100; i++) { ++ sprintf(path, "file%03d", i); ++ failure("Trying to read %s", path); ++ if (!assertEqualIntA(a, ARCHIVE_OK, ++ archive_read_next_header(a, &ae))) ++ break; ++ assertEqualString(path, archive_entry_pathname(ae)); ++ assertEqualInt((int)datasize, archive_entry_size(ae)); ++ } ++ assertEqualIntA(a, ARCHIVE_OK, archive_read_close(a)); ++ } ++ assertEqualInt(ARCHIVE_OK, archive_read_free(a)); ++ ++ /* ++ * Check output sizes for various compression levels, expectation ++ * is that archive size for level=20 < default < level=1 ++ */ ++ failure("compression-level=20 wrote %d bytes, default wrote %d bytes", ++ (int)used2, (int)used1); ++ assert(used2 < used1); ++ failure("compression-level=1 wrote %d bytes, default wrote %d bytes", ++ (int)used3, (int)used1); ++ assert(used1 < used3); ++ + /* + * Test various premature shutdown scenarios to make sure we + * don't crash or leak memory. +-- +2.19.1 + diff --git a/libarchive.spec b/libarchive.spec new file mode 100644 index 0000000..0ce2924 --- /dev/null +++ b/libarchive.spec @@ -0,0 +1,487 @@ +%bcond_without check + +Name: libarchive +Version: 3.3.3 +Release: 3%{?dist} +Summary: A library for handling streaming archive formats + +License: BSD +URL: http://www.libarchive.org/ +Source0: http://www.libarchive.org/downloads/%{name}-%{version}.tar.gz + +Patch1: libarchive-3.1.2-CVE-2019-1000019.patch +Patch2: libarchive-3.1.2-CVE-2019-1000020.patch +Patch3: libarchive-3.3.2-CVE-2018-1000878.patch +Patch4: libarchive-3.3.2-CVE-2018-1000877.patch +Patch5: fix-use-after-free-in-delayed-newc.patch +Patch6: fix-few-obvious-resource-leaks-covscan.patch +Patch7: libarchive-3.3.2-CVE-2019-18408.patch +Patch8: libarchive-3.3.2-CVE-2019-19221.patch +# upstream reference +# https://github.com/libarchive/libarchive/commit/aaacc8762fd8ced8823350edd8ce2e46b565582b#diff-bc144884a8e634e16f247e0588a266ee +Patch9: libarchive-3.3.3-fixed-zstd_test.patch +Patch10: libarchive-3.3.3-CVE-2021-23177.patch +Patch11: libarchive-3.3.3-CVE-2021-31566.patch + + + +BuildRequires: gcc +BuildRequires: bison +BuildRequires: sharutils +BuildRequires: zlib-devel +BuildRequires: bzip2-devel +BuildRequires: xz-devel +BuildRequires: lzo-devel +BuildRequires: e2fsprogs-devel +BuildRequires: libacl-devel +BuildRequires: libattr-devel +BuildRequires: openssl-devel +BuildRequires: libxml2-devel +BuildRequires: lz4-devel +BuildRequires: automake +BuildRequires: libzstd-devel +BuildRequires: libtool + + +%description +Libarchive is a programming library that can create and read several different +streaming archive formats, including most popular tar variants, several cpio +formats, and both BSD and GNU ar variants. It can also write shar archives and +read ISO9660 CDROM images and ZIP archives. + + +%package devel +Summary: Development files for %{name} +Requires: %{name}%{?_isa} = %{version}-%{release} + +%description devel +The %{name}-devel package contains libraries and header files for +developing applications that use %{name}. + + +%package -n bsdtar +Summary: Manipulate tape archives +Requires: %{name}%{?_isa} = %{version}-%{release} + +%description -n bsdtar +The bsdtar package contains standalone bsdtar utility split off regular +libarchive packages. + + +%package -n bsdcpio +Summary: Copy files to and from archives +Requires: %{name}%{?_isa} = %{version}-%{release} + +%description -n bsdcpio +The bsdcpio package contains standalone bsdcpio utility split off regular +libarchive packages. + + +%package -n bsdcat +Summary: Expand files to standard output +Requires: %{name}%{?_isa} = %{version}-%{release} + +%description -n bsdcat +The bsdcat program typically takes a filename as an argument or reads standard +input when used in a pipe. In both cases decompressed data it written to +standard output. + + +%prep +%autosetup -p1 +bash build/autogen.sh + + +%build +%configure --disable-static --disable-rpath +# remove rpaths +sed -i 's|^hardcode_libdir_flag_spec=.*|hardcode_libdir_flag_spec=""|g' libtool +sed -i 's|^runpath_var=LD_RUN_PATH|runpath_var=DIE_RPATH_DIE|g' libtool + +make %{?_smp_mflags} + + +%install +make install DESTDIR=$RPM_BUILD_ROOT +find $RPM_BUILD_ROOT -name '*.la' -exec rm -f {} ';' + +# rhbz#1294252 +replace () +{ + filename=$1 + file=`basename "$filename"` + binary=${file%%.*} + pattern=${binary##bsd} + + awk " + # replace the topic + /^.Dt ${pattern^^} 1/ { + print \".Dt ${binary^^} 1\"; + next; + } + # replace the first occurence of \"$pattern\" by \"$binary\" + !stop && /^.Nm $pattern/ { + print \".Nm $binary\" ; + stop = 1 ; + next; + } + # print remaining lines + 1; + " "$filename" > "$filename.new" + mv "$filename".new "$filename" +} + +for manpage in bsdtar.1 bsdcpio.1 +do + installed_manpage=`find "$RPM_BUILD_ROOT" -name "$manpage"` + replace "$installed_manpage" +done + + +%check +%if %{with check} +logfiles () +{ + find -name '*_test.log' -or -name test-suite.log +} + +tempdirs () +{ + cat `logfiles` \ + | awk "match(\$0, /[^[:space:]]*`date -I`[^[:space:]]*/) { print substr(\$0, RSTART, RLENGTH); }" \ + | sort | uniq +} + +cat_logs () +{ + for i in `logfiles` + do + echo "=== $i ===" + cat "$i" + done +} + +run_testsuite () +{ + rc=0 + LD_LIBRARY_PATH=`pwd`/.libs make %{?_smp_mflags} check -j1 || { + # error happened - try to extract in koji as much info as possible + cat_logs + + for i in `tempdirs`; do + if test -d "$i" ; then + find $i -printf "%p\n ~> a: %a\n ~> c: %c\n ~> t: %t\n ~> %s B\n" + cat $i/*.log + fi + done + return 1 + } + cat_logs +} + +# On a ppc/ppc64 is some race condition causing 'make check' fail on ppc +# when both 32 and 64 builds are done in parallel on the same machine in +# koji. Try to run once again if failed. +%ifarch ppc +run_testsuite || run_testsuite +%else +run_testsuite +%endif +%endif + + +%files +%{!?_licensedir:%global license %%doc} +%license COPYING +%doc NEWS README.md +%{_libdir}/libarchive.so.13* +%{_mandir}/*/cpio.* +%{_mandir}/*/mtree.* +%{_mandir}/*/tar.* + +%files devel +%{_includedir}/*.h +%{_mandir}/*/archive* +%{_mandir}/*/libarchive* +%{_libdir}/libarchive.so +%{_libdir}/pkgconfig/libarchive.pc + +%files -n bsdtar +%{!?_licensedir:%global license %%doc} +%license COPYING +%doc NEWS README.md +%{_bindir}/bsdtar +%{_mandir}/*/bsdtar* + +%files -n bsdcpio +%{!?_licensedir:%global license %%doc} +%license COPYING +%doc NEWS README.md +%{_bindir}/bsdcpio +%{_mandir}/*/bsdcpio* + +%files -n bsdcat +%{!?_licensedir:%global license %%doc} +%license COPYING +%doc NEWS README.md +%{_bindir}/bsdcat +%{_mandir}/*/bsdcat* + + + +%changelog +* Tue Dec 21 2021 Matej Mužila - 3.3.3-3 +- Do not follow symlinks when processing the fixup list (CVE-2021-31566) + +* Mon Dec 20 2021 Matej Mužila - 3.3.3-2 +- Fix handling of symbolic link ACLs (CVE-2021-23177) + +* Thu Apr 30 2020 Ondrej Dubaj - 3.3.3-1 +- Rebase to version 3.3.3 + +* Tue Mar 24 2020 Ondrej Dubaj - 3.3.2-9 +- Fix out-of-bounds read (CVE-2019-19221) (#1803967) + +* Wed Jan 15 2020 Patrik Novotný - 3.3.2-8 +- Fix CVE-2019-18408: RAR use-after-free + +* Mon May 27 2019 Ondrej Dubaj - 3.3.2-7 +- fix use-after-free in delayed newc link processing (#1602575) +- fix a few obvious resource leaks and strcpy() misuses (#1602575) + +* Tue Apr 30 2019 Ondrej Dubaj - 3.3.2-6 +- fixed use after free in RAR decoder (#1700752) +- fixed double free in RAR decoder (#1700753) + +* Tue Apr 02 2019 Ondrej Dubaj - 3.3.2-5 +- release bump due to gating (#1680768) + +* Fri Feb 22 2019 Pavel Raiskup - 3.3.2-4 +- fix out-of-bounds read within lha_read_data_none() (CVE-2017-14503) +- fix crash on crafted 7zip archives (CVE-2019-1000019) +- fix infinite loop in ISO9660 (CVE-2019-1000020) + +* Wed Jul 18 2018 Pavel Raiskup - 3.3.2-3 +- drop use of %%ldconfig_scriptlets + +* Fri Jul 13 2018 Fedora Release Engineering - 3.3.2-2 +- Rebuilt for https://fedoraproject.org/wiki/Fedora_29_Mass_Rebuild + +* Thu Feb 08 2018 Pavel Raiskup - 3.3.2-1 +- rebase to latest upstream release + +* Wed Feb 07 2018 Fedora Release Engineering - 3.3.1-5 +- Rebuilt for https://fedoraproject.org/wiki/Fedora_28_Mass_Rebuild + +* Sat Feb 03 2018 Igor Gnatenko - 3.3.1-4 +- Switch to %%ldconfig_scriptlets + +* Thu Aug 03 2017 Fedora Release Engineering - 3.3.1-3 +- Rebuilt for https://fedoraproject.org/wiki/Fedora_27_Binutils_Mass_Rebuild + +* Wed Jul 26 2017 Fedora Release Engineering - 3.3.1-2 +- Rebuilt for https://fedoraproject.org/wiki/Fedora_27_Mass_Rebuild + +* Tue Apr 18 2017 Pavel Raiskup - 3.3.1-1 +- the latest release, per release notes: + https://groups.google.com/forum/#!topic/libarchive-discuss/jfc7lBfrvVg + +* Mon Feb 20 2017 Pavel Raiskup - 3.2.2-3 +- temporary work-around for FTBFS (rhbz#1423839) + +* Fri Feb 10 2017 Fedora Release Engineering - 3.2.2-3 +- Rebuilt for https://fedoraproject.org/wiki/Fedora_26_Mass_Rebuild + +* Fri Nov 11 2016 Pavel Raiskup - 3.2.2-2 +- enable lz4 support, rhbz#1394038 + +* Tue Oct 25 2016 Pavel Raiskup - 3.2.2-1 +- minor rebase to 3.2.2 + +* Tue Oct 11 2016 Tomáš Mráz - 3.2.1-5 +- rebuild with OpenSSL 1.1.0 + +* Mon Sep 26 2016 Tomas Repik - 3.2.1-4 +- fix some stack and heap overflows +- resolves (rhbz#1378669, rhbz#1378668, rhbz#1378666) + +* Mon Aug 08 2016 Tomas Repik - 3.2.1-3 +- bump release for upgradepath + +* Mon Jul 18 2016 Pavel Raiskup - 3.2.1-2 +- print more detailed logs for testsuite, even if testsuite succeeded + +* Mon Jun 20 2016 Pavel Raiskup - 3.2.1-1 +- rebase, several security issues fixed (rhbz#1348194) + +* Mon May 16 2016 Pavel Raiskup - 3.2.0-3 +- fix the manual pages for remaining issue (rhbz#1294252) + +* Thu May 12 2016 Pavel Raiskup - 3.2.0-2 +- fix manual pages to mention correctly spelled binary names (rhbz#1294252) + +* Tue May 03 2016 Pavel Raiskup - 3.2.0-1 +- new upstream release 3.2.0 (rhbz#1330345), per release notes: + https://groups.google.com/d/msg/libarchive-discuss/qIzW7doKzxA/MVbUkjlNAAAJ + +* Mon Mar 07 2016 Björn Esser - 3.1.2-16 +- removed %%defattr, BuildRoot and other ancient bits +- added arch'ed bits to all Requires + +* Thu Feb 04 2016 Fedora Release Engineering - 3.1.2-15 +- Rebuilt for https://fedoraproject.org/wiki/Fedora_24_Mass_Rebuild + +* Mon Dec 21 2015 Pavel Raiskup - 3.1.2-14 +- fix 'Out of memory when creating mtree files' error (rhbz#1284162) +- use %%autosetup macro + +* Wed Jun 17 2015 Fedora Release Engineering - 3.1.2-13 +- Rebuilt for https://fedoraproject.org/wiki/Fedora_23_Mass_Rebuild + +* Wed Apr 29 2015 Pavel Raiskup - 3.1.2-12 +- fix libarchive segfault for intentionally broken cpio archives (rhbz#1216892) + +* Sat Feb 21 2015 Till Maas - 3.1.2-11 +- Rebuilt for Fedora 23 Change + https://fedoraproject.org/wiki/Changes/Harden_all_packages_with_position-independent_code + +* Sun Aug 17 2014 Fedora Release Engineering - 3.1.2-10 +- Rebuilt for https://fedoraproject.org/wiki/Fedora_21_22_Mass_Rebuild + +* Thu Jul 17 2014 Tom Callaway - 3.1.2-9 +- fix license handling + +* Sat Jun 07 2014 Fedora Release Engineering - 3.1.2-8 +- Rebuilt for https://fedoraproject.org/wiki/Fedora_21_Mass_Rebuild + +* Thu Aug 08 2013 Jaromir Koncicky - 3.1.2-7 +- Fixed Bug 993048 - added #ifdef ACL_TYPE_NFS4 to code which requires + NFS4 ACL support + +* Sat Aug 03 2013 Fedora Release Engineering - 3.1.2-6 +- Rebuilt for https://fedoraproject.org/wiki/Fedora_20_Mass_Rebuild + +* Mon Jul 22 2013 Pavel Raiskup - 3.1.2-5 +- try to workaround racy testsuite fail + +* Sun Jun 30 2013 Pavel Raiskup - 3.1.2-4 +- enable testsuite in the %%check phase + +* Mon Jun 24 2013 Pavel Raiskup - 3.1.2-3 +- bsdtar/bsdcpio should require versioned libarchive + +* Wed Apr 3 2013 Tomas Bzatek - 3.1.2-2 +- Remove libunistring-devel build require + +* Thu Mar 28 2013 Tomas Bzatek - 3.1.2-1 +- Update to 3.1.2 +- Fix CVE-2013-0211: read buffer overflow on 64-bit systems (#927105) + +* Thu Feb 14 2013 Fedora Release Engineering - 3.1.1-2 +- Rebuilt for https://fedoraproject.org/wiki/Fedora_19_Mass_Rebuild + +* Mon Jan 14 2013 Tomas Bzatek - 3.1.1-1 +- Update to 3.1.1 +- NEWS seems to be valid UTF-8 nowadays + +* Wed Oct 03 2012 Pavel Raiskup - 3.0.4-3 +- better install manual pages for libarchive/bsdtar/bsdcpio (# ... ) +- several fedora-review fixes ...: +- Source0 has moved to github.com +- remove trailing white spaces +- repair summary to better describe bsdtar/cpiotar utilities + +* Thu Jul 19 2012 Fedora Release Engineering - 3.0.4-2 +- Rebuilt for https://fedoraproject.org/wiki/Fedora_18_Mass_Rebuild + +* Mon May 7 2012 Tomas Bzatek - 3.0.4-1 +- Update to 3.0.4 + +* Wed Feb 1 2012 Tomas Bzatek - 3.0.3-2 +- Enable bsdtar and bsdcpio in separate subpackages (#786400) + +* Fri Jan 13 2012 Tomas Bzatek - 3.0.3-1 +- Update to 3.0.3 + +* Fri Jan 13 2012 Fedora Release Engineering - 3.0.0-0.3.a +- Rebuilt for https://fedoraproject.org/wiki/Fedora_17_Mass_Rebuild + +* Tue Nov 15 2011 Rex Dieter 3.0.0-0.2.a +- track files/sonames closer, so abi bumps aren't a surprise +- tighten subpkg deps via %%_isa + +* Mon Nov 14 2011 Tomas Bzatek - 3.0.0-0.1.a +- Update to 3.0.0a (alpha release) + +* Mon Sep 5 2011 Tomas Bzatek - 2.8.5-1 +- Update to 2.8.5 + +* Mon Feb 07 2011 Fedora Release Engineering - 2.8.4-3 +- Rebuilt for https://fedoraproject.org/wiki/Fedora_15_Mass_Rebuild + +* Thu Jan 13 2011 Tomas Bzatek - 2.8.4-2 +- Rebuild for new xz-libs + +* Wed Jun 30 2010 Tomas Bzatek - 2.8.4-1 +- Update to 2.8.4 + +* Fri Jun 25 2010 Tomas Bzatek - 2.8.3-2 +- Fix ISO9660 reader data type mismatches (#597243) + +* Tue Mar 16 2010 Tomas Bzatek - 2.8.3-1 +- Update to 2.8.3 + +* Mon Mar 8 2010 Tomas Bzatek - 2.8.1-1 +- Update to 2.8.1 + +* Fri Feb 5 2010 Tomas Bzatek - 2.8.0-1 +- Update to 2.8.0 + +* Wed Jan 6 2010 Tomas Bzatek - 2.7.902a-1 +- Update to 2.7.902a + +* Fri Aug 21 2009 Tomas Mraz - 2.7.1-2 +- rebuilt with new openssl + +* Fri Aug 7 2009 Tomas Bzatek 2.7.1-1 +- Update to 2.7.1 +- Drop deprecated lzma dependency, libxz handles both formats + +* Mon Jul 27 2009 Tomas Bzatek 2.7.0-3 +- Enable XZ compression format + +* Fri Jul 24 2009 Fedora Release Engineering - 2.7.0-2 +- Rebuilt for https://fedoraproject.org/wiki/Fedora_12_Mass_Rebuild + +* Tue May 12 2009 Tomas Bzatek 2.7.0-1 +- Update to 2.7.0 + +* Fri Mar 6 2009 Tomas Bzatek 2.6.2-1 +- Update to 2.6.2 + +* Wed Feb 25 2009 Fedora Release Engineering - 2.6.1-2 +- Rebuilt for https://fedoraproject.org/wiki/Fedora_11_Mass_Rebuild + +* Mon Feb 16 2009 Tomas Bzatek 2.6.1-1 +- Update to 2.6.1 + +* Thu Jan 8 2009 Tomas Bzatek 2.6.0-1 +- Update to 2.6.0 + +* Mon Dec 15 2008 Tomas Bzatek 2.5.904a-1 +- Update to 2.5.904a + +* Tue Dec 9 2008 Tomas Bzatek 2.5.903a-2 +- Add LZMA support + +* Mon Dec 8 2008 Tomas Bzatek 2.5.903a-1 +- Update to 2.5.903a + +* Tue Jul 22 2008 Tomas Bzatek 2.5.5-1 +- Update to 2.5.5 + +* Wed Apr 2 2008 Tomas Bzatek 2.4.17-1 +- Update to 2.4.17 + +* Wed Mar 19 2008 Tomas Bzatek 2.4.14-1 +- Initial packaging diff --git a/sources b/sources new file mode 100644 index 0000000..b236ed2 --- /dev/null +++ b/sources @@ -0,0 +1 @@ +SHA512 (libarchive-3.3.3.tar.gz) = 9d12b47d6976efa9f98e62c25d8b85fd745d4e9ca7b7e6d36bfe095dfe5c4db017d4e785d110f3758f5938dad6f1a1b009267fd7e82cb7212e93e1aea237bab7