From nobody Sat Nov 20 22:58:45 2021 X-Original-To: dev-commits-src-branches@mlmmj.nyi.freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2610:1c1:1:606c::19:1]) by mlmmj.nyi.freebsd.org (Postfix) with ESMTP id 1331E18A5C93; Sat, 20 Nov 2021 22:58:46 +0000 (UTC) (envelope-from git@FreeBSD.org) Received: from mxrelay.nyi.freebsd.org (mxrelay.nyi.freebsd.org [IPv6:2610:1c1:1:606c::19:3]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (4096 bits) server-digest SHA256 client-signature RSA-PSS (4096 bits) client-digest SHA256) (Client CN "mxrelay.nyi.freebsd.org", Issuer "R3" (verified OK)) by mx1.freebsd.org (Postfix) with ESMTPS id 4HxTVF4dCMz3mCH; Sat, 20 Nov 2021 22:58:45 +0000 (UTC) (envelope-from git@FreeBSD.org) Received: from gitrepo.freebsd.org (gitrepo.freebsd.org [IPv6:2610:1c1:1:6068::e6a:5]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (4096 bits) server-digest SHA256) (Client did not present a certificate) by mxrelay.nyi.freebsd.org (Postfix) with ESMTPS id 7B24D2441C; Sat, 20 Nov 2021 22:58:45 +0000 (UTC) (envelope-from git@FreeBSD.org) Received: from gitrepo.freebsd.org ([127.0.1.44]) by gitrepo.freebsd.org (8.16.1/8.16.1) with ESMTP id 1AKMwj8D024956; Sat, 20 Nov 2021 22:58:45 GMT (envelope-from git@gitrepo.freebsd.org) Received: (from git@localhost) by gitrepo.freebsd.org (8.16.1/8.16.1/Submit) id 1AKMwj2R024955; Sat, 20 Nov 2021 22:58:45 GMT (envelope-from git) Date: Sat, 20 Nov 2021 22:58:45 GMT Message-Id: <202111202258.1AKMwj2R024955@gitrepo.freebsd.org> To: src-committers@FreeBSD.org, dev-commits-src-all@FreeBSD.org, dev-commits-src-branches@FreeBSD.org From: Martin Matuska Subject: git: ca2b9574aa42 - stable/13 - libarchive: cherry-pick bugfix from vendor List-Id: Commits to the stable branches of the FreeBSD src repository List-Archive: https://lists.freebsd.org/archives/dev-commits-src-branches List-Help: List-Post: List-Subscribe: List-Unsubscribe: Sender: owner-dev-commits-src-branches@freebsd.org X-BeenThere: dev-commits-src-branches@freebsd.org MIME-Version: 1.0 Content-Type: text/plain; charset=utf-8 Content-Transfer-Encoding: 8bit X-Git-Committer: mm X-Git-Repository: src X-Git-Refname: refs/heads/stable/13 X-Git-Reftype: branch X-Git-Commit: ca2b9574aa42f1bca7a4d611bf32a997a31e2e9a Auto-Submitted: auto-generated X-ThisMailContainsUnwantedMimeParts: N The branch stable/13 has been updated by mm: URL: https://cgit.FreeBSD.org/src/commit/?id=ca2b9574aa42f1bca7a4d611bf32a997a31e2e9a commit ca2b9574aa42f1bca7a4d611bf32a997a31e2e9a Author: Martin Matuska AuthorDate: 2021-11-17 21:21:19 +0000 Commit: Martin Matuska CommitDate: 2021-11-20 22:33:10 +0000 libarchive: cherry-pick bugfix from vendor Vendor commit message (ede459d2e): 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 vendor issue #1617: Immutable flag no longer preserved during tar extraction on FreeBSD Reported by: markjdb Libarchive commit: ede459d2ebb879f5eedb6f7abea203be0b334230 (cherry picked from commit 201d0ebee321fb1a5501e17a4f150aa211020c5c) --- .../libarchive/archive_write_disk_posix.c | 87 +++++++++++++++++++--- 1 file changed, 75 insertions(+), 12 deletions(-) diff --git a/contrib/libarchive/libarchive/archive_write_disk_posix.c b/contrib/libarchive/libarchive/archive_write_disk_posix.c index a554679bfd10..1aa00840bf4c 100644 --- a/contrib/libarchive/libarchive/archive_write_disk_posix.c +++ b/contrib/libarchive/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. */