diff --git a/backport-CVE-2021-31566.patch b/backport-CVE-2021-31566.patch new file mode 100644 index 0000000000000000000000000000000000000000..e03099ab0e96dd46f01d605350fba2a048225062 --- /dev/null +++ b/backport-CVE-2021-31566.patch @@ -0,0 +1,212 @@ +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 +Conflict:NA +Reference:https://github.com/libarchive/libarchive/commit/ede459d2ebb879f5eedb6f7abea203be0b334230 +说明:这是CVE-2021-31556的后置补丁,CVE-2021-31556虽然已在基线tar包修复,但我们仍然建议合入该补丁,并且以该CVE号来命名 +--- + 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 aadc58718..7e57aac2e 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 { + + static int la_opendirat(int, const char *); + static int la_mktemp(struct archive_write_disk *); ++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) { + #endif + } + ++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. */ + diff --git a/backport-CVE-2021-36976.patch b/backport-CVE-2021-36976.patch new file mode 100644 index 0000000000000000000000000000000000000000..032d25e1e650716a621f003cf0e089f2a22f5341 --- /dev/null +++ b/backport-CVE-2021-36976.patch @@ -0,0 +1,58 @@ +From a7ce8a6aa7b710986ab918761c8d2ff1b0e9f537 Mon Sep 17 00:00:00 2001 +From: Samanta Navarro +Date: Sat, 28 Aug 2021 11:58:00 +0000 +Subject: [PATCH] Fix size_t cast in read_mac_metadata_blob + +The size_t data type on 32 bit systems is smaller than int64_t. Check +the int64_t value before casting to size_t. If the value is too large +then stop operation instead of continuing operation with truncated +value. + +Conflict:NA +Reference:https://github.com/libarchive/libarchive/commit/a7ce8a6aa7b710986ab918761c8d2ff1b0e9f537 +--- + libarchive/archive_read_support_format_tar.c | 12 +++++++++--- + 1 file changed, 9 insertions(+), 3 deletions(-) + +diff --git a/libarchive/archive_read_support_format_tar.c b/libarchive/archive_read_support_format_tar.c +index 7e8febacf..773796a5d 100644 +--- a/libarchive/archive_read_support_format_tar.c ++++ b/libarchive/archive_read_support_format_tar.c +@@ -1396,6 +1396,7 @@ read_mac_metadata_blob(struct archive_read *a, struct tar *tar, + struct archive_entry *entry, const void *h, size_t *unconsumed) + { + int64_t size; ++ size_t msize; + const void *data; + const char *p, *name; + const wchar_t *wp, *wname; +@@ -1434,6 +1435,11 @@ read_mac_metadata_blob(struct archive_read *a, struct tar *tar, + + /* Read the body as a Mac OS metadata blob. */ + size = archive_entry_size(entry); ++ msize = (size_t)size; ++ if (size < 0 || (uintmax_t)msize != (uintmax_t)size) { ++ *unconsumed = 0; ++ return (ARCHIVE_FATAL); ++ } + + /* + * TODO: Look beyond the body here to peek at the next header. +@@ -1447,13 +1453,13 @@ read_mac_metadata_blob(struct archive_read *a, struct tar *tar, + * Q: Is the above idea really possible? Even + * when there are GNU or pax extension entries? + */ +- data = __archive_read_ahead(a, (size_t)size, NULL); ++ data = __archive_read_ahead(a, msize, NULL); + if (data == NULL) { + *unconsumed = 0; + return (ARCHIVE_FATAL); + } +- archive_entry_copy_mac_metadata(entry, data, (size_t)size); +- *unconsumed = (size_t)((size + 511) & ~ 511); ++ archive_entry_copy_mac_metadata(entry, data, msize); ++ *unconsumed = (msize + 511) & ~ 511; + tar_flush_unconsumed(a, unconsumed); + return (tar_read_header(a, tar, entry, unconsumed)); + } + diff --git a/libarchive-uninitialized-value.patch b/libarchive-uninitialized-value.patch new file mode 100644 index 0000000000000000000000000000000000000000..412a8ebf4540dea8c05a24e0857b8f5b08d3ac69 --- /dev/null +++ b/libarchive-uninitialized-value.patch @@ -0,0 +1,24 @@ +From 1ab606af27d6b3fa07a638b7f04efadbc8ef75b4 Mon Sep 17 00:00:00 2001 +From: zhangnaru +Date: Tue, 28 Jul 2020 15:05:03 +0800 +Subject: [PATCH] there need to add the init of child to solve the +problem in oss-fuzz +--- + libarchive/filter_fork_posix.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/libarchive/filter_fork_posix.c b/libarchive/filter_fork_posix.c +index ac255c4..62085a7 100644 +--- a/libarchive/filter_fork_posix.c ++++ b/libarchive/filter_fork_posix.c +@@ -76,7 +76,7 @@ int + __archive_create_child(const char *cmd, int *child_stdin, int *child_stdout, + pid_t *out_child) + { +- pid_t child; ++ pid_t child = -1; + int stdin_pipe[2], stdout_pipe[2], tmp; + #if HAVE_POSIX_SPAWNP + posix_spawn_file_actions_t actions; +-- +2.23.0 diff --git a/libarchive.spec b/libarchive.spec index 6e56aa1d561bebe2a9c051a2a0d30ce1542298c9..1d796addd2bd0d8eb006ec1ca2b117c2654bda77 100644 --- a/libarchive.spec +++ b/libarchive.spec @@ -2,7 +2,7 @@ Name: libarchive Version: 3.5.2 -Release: 2 +Release: 3 Summary: Multi-format archive and compression library License: BSD @@ -14,6 +14,10 @@ BuildRequires: lzo-devel e2fsprogs-devel libacl-devel libattr-devel BuildRequires: openssl-devel libxml2-devel lz4-devel automake libzstd-devel Patch6000: backport-libarchive-3.5.2-symlink-fix.patch +Patch6001: backport-CVE-2021-36976.patch +Patch6002: backport-CVE-2021-31566.patch + +Patch9000: libarchive-uninitialized-value.patch %description %{name} is an open-source BSD-licensed C programming library that @@ -186,6 +190,9 @@ run_testsuite %{_bindir}/bsdcat %changelog +* Sat Apr 09 2022 wangkerong - 3.5.2-3 +- fix CVE-2021-36976,CVE-2021-31566,fix fuzz test + * Sat Mar 26 2022 wangkerong - 3.5.2-2 - Eanable make check