[Date Prev][Date Next] [Thread Prev][Thread Next] [Date Index] [Thread Index]

Bug#1002703: bullseye-pu: package libarchive/3.4.3-2+deb11u1



On Thu, Dec 30, 2021 at 09:10:34PM +0100, Salvatore Bonaccorso wrote:
> Hi Peter,
> 
> On Mon, Dec 27, 2021 at 10:10:58PM +0200, Peter Pentchev wrote:
> > Package: release.debian.org
> > Severity: normal
> > Tags: bullseye
> > User: release.debian.org@packages.debian.org
> > Usertags: pu
> > X-Debbugs-Cc: roam@ringlet.net
> > 
> > [ Reason ]
> > This is a future unblock request before I upload
> > libarchive-3.4.3-2+deb11u1 to fix a couple of bugs that were
> > fixed in later upstream versions and in unstable. They are all
> > related to setting permissions and ACLs when extracting
> > archive members that represent symbolic and hard links.
> > 
> > [ Impact ]
> > Extracting some (rarely seen) archives may result in files
> > having the wrong access permissions.
> > 
> > [ Tests ]
> > All the added patches are taken from upstream commits that
> > include both the bugfixes and the testsuite additions to
> > check for regressions.
> > 
> > [ Risks ]
> > The code is mostly easy to follow, the fixes are straightforward.
> > 
> > [ Checklist ]
> >   [x] *all* changes are documented in the d/changelog
> >   [x] I reviewed all changes and I approve them
> >   [x] attach debdiff against the package in stable
> >   [x] the issue is verified as fixed in unstable
> > 
> > [ Changes ]
> > - correctly extract a hardlink to a symlink using the linkat(2)
> >   system call
> > - do not change the ACLs on symlinks, since that would affect
> >   the symlink target instead
> > - do not accidentally change the access mode of a symlink target
> >   when a change to the symlink's mode was intended
> > 
> > [ Other info ]
> > Thanks in advance for looking at this, and keep up the great work!
> 
> > diff -Nru libarchive-3.4.3/debian/changelog libarchive-3.4.3/debian/changelog
> > --- libarchive-3.4.3/debian/changelog	2020-08-01 21:46:12.000000000 +0300
> > +++ libarchive-3.4.3/debian/changelog	2021-12-27 18:45:51.000000000 +0200
> > @@ -1,3 +1,12 @@
> > +libarchive (3.4.3-2+deb11u1) bullseye; urgency=medium
> > +
> > +  * Add four upstream fixes for various problems:
> > +    - fix extracting hardlinks to symlinks
> > +    - fix handling of symlink ACLs; Closes: 1001986
> > +    - never follow symlinks when setting file flags; Closes: 1001990
> 
> While at it, can you as well add the CVE references to the
> debian/changelog?

Right... I'm not very smart these days, am I? Thanks a lot for
your patience with me these past few weeks!

Attached is an updated debdiff, the only difference being the CVE
references added to the changelog entry.

G'luck,
Peter

-- 
Peter Pentchev  roam@ringlet.net roam@debian.org pp@storpool.com
PGP key:        http://people.FreeBSD.org/~roam/roam.key.asc
Key fingerprint 2EE7 A7A5 17FC 124C F115  C354 651E EFB0 2527 DF13
diff -Nru libarchive-3.4.3/debian/changelog libarchive-3.4.3/debian/changelog
--- libarchive-3.4.3/debian/changelog	2020-08-01 21:46:12.000000000 +0300
+++ libarchive-3.4.3/debian/changelog	2021-12-27 18:45:51.000000000 +0200
@@ -1,3 +1,13 @@
+libarchive (3.4.3-2+deb11u1) bullseye; urgency=medium
+
+  * Add four upstream fixes for various problems:
+    - fix extracting hardlinks to symlinks
+    - CVE-2021-23177: fix handling of symlink ACLs; Closes: 1001986
+    - CVE-2021-31566: never follow symlinks when setting file flags;
+      Closes: 1001990
+
+ -- Peter Pentchev <roam@debian.org>  Mon, 27 Dec 2021 18:45:51 +0200
+
 libarchive (3.4.3-2) unstable; urgency=medium
 
   * Add some more upstream patches:
diff -Nru libarchive-3.4.3/debian/patches/series libarchive-3.4.3/debian/patches/series
--- libarchive-3.4.3/debian/patches/series	2020-08-01 21:46:12.000000000 +0300
+++ libarchive-3.4.3/debian/patches/series	2021-12-27 18:45:51.000000000 +0200
@@ -8,3 +8,7 @@
 upstream-rar-read-format.patch
 upstream-memory-stdlib.patch
 upstream-max-comp-level.patch
+upstream-hardlinks-to-symlinks.patch
+upstream-symlink-acls.patch
+upstream-set-flags-nofollow.patch
+upstream-fixup-nofollow.patch
diff -Nru libarchive-3.4.3/debian/patches/upstream-fixup-nofollow.patch libarchive-3.4.3/debian/patches/upstream-fixup-nofollow.patch
--- libarchive-3.4.3/debian/patches/upstream-fixup-nofollow.patch	1970-01-01 02:00:00.000000000 +0200
+++ libarchive-3.4.3/debian/patches/upstream-fixup-nofollow.patch	2021-12-27 18:45:51.000000000 +0200
@@ -0,0 +1,168 @@
+Description: Do not follow symlinks when processing the fixup list
+ Published as CVE-2021-31566
+Origin: upstream, https://github.com/libarchive/libarchive/commit/b41daecb5ccb4c8e3b2c53fd6147109fc12c3043
+Bug-Debian: https://bugs.debian.org/1001990
+Author: Martin Matuska <martin@matuska.org>
+Last-Update: 2021-12-20
+
+--- a/Makefile.am
++++ b/Makefile.am
+@@ -556,6 +556,7 @@
+ 	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 \
+--- a/libarchive/archive_write_disk_posix.c
++++ b/libarchive/archive_write_disk_posix.c
+@@ -2461,6 +2461,7 @@
+ {
+ 	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 @@
+ 		    (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 @@
+ 				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 @@
+ 		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 @@
+ 	fe->next = a->fixup_list;
+ 	a->fixup_list = fe;
+ 	fe->fixup = 0;
++	fe->mode = 0;
+ 	fe->name = strdup(pathname);
+ 	return (fe);
+ }
+--- a/libarchive/test/CMakeLists.txt
++++ b/libarchive/test/CMakeLists.txt
+@@ -208,6 +208,7 @@
+     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
+--- /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", 0);
++	assertFileMode("victim", 0600);
++}
diff -Nru libarchive-3.4.3/debian/patches/upstream-hardlinks-to-symlinks.patch libarchive-3.4.3/debian/patches/upstream-hardlinks-to-symlinks.patch
--- libarchive-3.4.3/debian/patches/upstream-hardlinks-to-symlinks.patch	1970-01-01 02:00:00.000000000 +0200
+++ libarchive-3.4.3/debian/patches/upstream-hardlinks-to-symlinks.patch	2021-12-27 18:45:51.000000000 +0200
@@ -0,0 +1,214 @@
+Description: Fix extracting hardlinks to symlinks
+Origin: upstream, https://github.com/libarchive/libarchive/commit/5e646b890fb3c59ef6f94221ef8ef9ae62a8a9d6
+Author: Martin Matuska <martin@matuska.org>
+Last-Updated: 2021-12-20
+
+--- a/CMakeLists.txt
++++ b/CMakeLists.txt
+@@ -1352,6 +1352,7 @@
+ CHECK_FUNCTION_EXISTS_GLIBC(lchmod HAVE_LCHMOD)
+ CHECK_FUNCTION_EXISTS_GLIBC(lchown HAVE_LCHOWN)
+ CHECK_FUNCTION_EXISTS_GLIBC(link HAVE_LINK)
++CHECK_FUNCTION_EXISTS_GLIBC(linkat HAVE_LINKAT)
+ CHECK_FUNCTION_EXISTS_GLIBC(localtime_r HAVE_LOCALTIME_R)
+ CHECK_FUNCTION_EXISTS_GLIBC(lstat HAVE_LSTAT)
+ CHECK_FUNCTION_EXISTS_GLIBC(lutimes HAVE_LUTIMES)
+--- a/build/cmake/config.h.in
++++ b/build/cmake/config.h.in
+@@ -743,6 +743,9 @@
+ /* Define to 1 if you have the `link' function. */
+ #cmakedefine HAVE_LINK 1
+ 
++/* Define to 1 if you have the `linkat' function. */
++#cmakedefine HAVE_LINKAT 1
++
+ /* Define to 1 if you have the <linux/fiemap.h> header file. */
+ #cmakedefine HAVE_LINUX_FIEMAP_H 1
+ 
+--- a/configure.ac
++++ b/configure.ac
+@@ -631,7 +631,7 @@
+ AC_CHECK_FUNCS([futimens futimes futimesat])
+ AC_CHECK_FUNCS([geteuid getpid getgrgid_r getgrnam_r])
+ AC_CHECK_FUNCS([getpwnam_r getpwuid_r getvfsbyname gmtime_r])
+-AC_CHECK_FUNCS([lchflags lchmod lchown link localtime_r lstat lutimes])
++AC_CHECK_FUNCS([lchflags lchmod lchown link linkat localtime_r lstat lutimes])
+ AC_CHECK_FUNCS([mbrtowc memmove memset])
+ AC_CHECK_FUNCS([mkdir mkfifo mknod mkstemp])
+ AC_CHECK_FUNCS([nl_langinfo openat pipe poll posix_spawnp readlink readlinkat])
+--- a/libarchive/archive_write_disk_posix.c
++++ b/libarchive/archive_write_disk_posix.c
+@@ -360,7 +360,7 @@
+ static void	fsobj_error(int *, struct archive_string *, int, const char *,
+ 		    const char *);
+ static int	check_symlinks_fsobj(char *, int *, struct archive_string *,
+-		    int);
++		    int, int);
+ static int	check_symlinks(struct archive_write_disk *);
+ static int	create_filesystem_object(struct archive_write_disk *);
+ static struct fixup_entry *current_fixup(struct archive_write_disk *,
+@@ -2263,7 +2263,7 @@
+ 			return (EPERM);
+ 		}
+ 		r = check_symlinks_fsobj(linkname_copy, &error_number,
+-		    &error_string, a->flags);
++		    &error_string, a->flags, 1);
+ 		if (r != ARCHIVE_OK) {
+ 			archive_set_error(&a->archive, error_number, "%s",
+ 			    error_string.s);
+@@ -2284,7 +2284,12 @@
+ 		 */
+ 		if (a->flags & ARCHIVE_EXTRACT_SAFE_WRITES)
+ 			unlink(a->name);
++#ifdef HAVE_LINKAT
++		r = linkat(AT_FDCWD, linkname, AT_FDCWD, a->name,
++		    0) ? errno : 0;
++#else
+ 		r = link(linkname, a->name) ? errno : 0;
++#endif
+ 		/*
+ 		 * New cpio and pax formats allow hardlink entries
+ 		 * to carry data, so we may have to open the file
+@@ -2675,7 +2680,7 @@
+  */
+ static int
+ check_symlinks_fsobj(char *path, int *a_eno, struct archive_string *a_estr,
+-    int flags)
++    int flags, int checking_linkname)
+ {
+ #if !defined(HAVE_LSTAT) && \
+     !(defined(HAVE_OPENAT) && defined(HAVE_FSTATAT) && defined(HAVE_UNLINKAT))
+@@ -2684,6 +2689,7 @@
+ 	(void)error_number; /* UNUSED */
+ 	(void)error_string; /* UNUSED */
+ 	(void)flags; /* UNUSED */
++	(void)checking_linkname; /* UNUSED */
+ 	return (ARCHIVE_OK);
+ #else
+ 	int res = ARCHIVE_OK;
+@@ -2805,6 +2811,28 @@
+ 				head = tail + 1;
+ 			}
+ 		} else if (S_ISLNK(st.st_mode)) {
++			if (last && checking_linkname) {
++#ifdef HAVE_LINKAT
++				/*
++				 * Hardlinks to symlinks are safe to write
++				 * if linkat() is supported as it does not
++				 * follow symlinks.
++				 */
++				res = ARCHIVE_OK;
++#else
++				/*
++				 * We return ARCHIVE_FAILED here as we are
++				 * not able to safely write hardlinks
++				 * to symlinks.
++				 */
++				tail[0] = c;
++				fsobj_error(a_eno, a_estr, errno,
++				    "Cannot write hardlink to symlink ",
++				    path);
++				res = ARCHIVE_FAILED;
++#endif
++				break;
++			} else
+ 			if (last) {
+ 				/*
+ 				 * Last element is symlink; remove it
+@@ -2971,7 +2999,7 @@
+ 	int rc;
+ 	archive_string_init(&error_string);
+ 	rc = check_symlinks_fsobj(a->name, &error_number, &error_string,
+-	    a->flags);
++	    a->flags, 0);
+ 	if (rc != ARCHIVE_OK) {
+ 		archive_set_error(&a->archive, error_number, "%s",
+ 		    error_string.s);
+--- a/libarchive/config_freebsd.h
++++ b/libarchive/config_freebsd.h
+@@ -137,6 +137,7 @@
+ #define HAVE_LIBZ 1
+ #define HAVE_LIMITS_H 1
+ #define HAVE_LINK 1
++#define HAVE_LINKAT 1
+ #define HAVE_LOCALE_H 1
+ #define HAVE_LOCALTIME_R 1
+ #define HAVE_LONG_LONG_INT 1
+--- a/libarchive/test/test_write_disk_hardlink.c
++++ b/libarchive/test/test_write_disk_hardlink.c
+@@ -49,6 +49,9 @@
+ 	static const char data[]="abcdefghijklmnopqrstuvwxyz";
+ 	struct archive *ad;
+ 	struct archive_entry *ae;
++#ifdef HAVE_LINKAT
++	int can_symlink;
++#endif
+ 	int r;
+ 
+ 	/* Force the umask to something predictable. */
+@@ -147,7 +150,7 @@
+ 	archive_entry_free(ae);
+ 
+ 	/*
+-	 * Finally, try a new-cpio-like approach, where the initial
++	 * Third, try a new-cpio-like approach, where the initial
+ 	 * regular file is empty and the hardlink has the data.
+ 	 */
+ 
+@@ -174,6 +177,41 @@
+ 		assertEqualIntA(ad, 0, archive_write_finish_entry(ad));
+ 	}
+ 	archive_entry_free(ae);
++
++#ifdef HAVE_LINKAT
++	/* Finally, try creating a hard link to a dangling symlink */
++	can_symlink = canSymlink();
++	if (can_symlink) {
++		/* Symbolic link: link5a -> foo */
++		assert((ae = archive_entry_new()) != NULL);
++		archive_entry_copy_pathname(ae, "link5a");
++		archive_entry_set_mode(ae, AE_IFLNK | 0642);
++		archive_entry_unset_size(ae);
++		archive_entry_copy_symlink(ae, "foo");
++		assertEqualIntA(ad, 0, r = archive_write_header(ad, ae));
++		if (r >= ARCHIVE_WARN) {
++			assertEqualInt(ARCHIVE_WARN,
++			    archive_write_data(ad, data, sizeof(data)));
++			assertEqualIntA(ad, 0, archive_write_finish_entry(ad));
++		}
++		archive_entry_free(ae);
++
++
++		/* Link.  Size of zero means this doesn't carry data. */
++		assert((ae = archive_entry_new()) != NULL);
++		archive_entry_copy_pathname(ae, "link5b");
++		archive_entry_set_mode(ae, S_IFREG | 0642);
++		archive_entry_set_size(ae, 0);
++		archive_entry_copy_hardlink(ae, "link5a");
++		assertEqualIntA(ad, 0, r = archive_write_header(ad, ae));
++		if (r >= ARCHIVE_WARN) {
++			assertEqualInt(ARCHIVE_WARN,
++			    archive_write_data(ad, data, sizeof(data)));
++			assertEqualIntA(ad, 0, archive_write_finish_entry(ad));
++		}
++		archive_entry_free(ae);
++	}
++#endif
+ 	assertEqualInt(0, archive_write_free(ad));
+ 
+ 	/* Test the entries on disk. */
+@@ -211,5 +249,14 @@
+ 	assertFileNLinks("link4a", 2);
+ 	assertFileSize("link4a", sizeof(data));
+ 	assertIsHardlink("link4a", "link4b");
++
++#ifdef HAVE_LINKAT
++	if (can_symlink) {
++		/* Test #5 */
++		assertIsSymlink("link5a", "foo", 0);
++		assertFileNLinks("link5a", 2);
++		assertIsHardlink("link5a", "link5b");
++	}
++#endif
+ #endif
+ }
diff -Nru libarchive-3.4.3/debian/patches/upstream-set-flags-nofollow.patch libarchive-3.4.3/debian/patches/upstream-set-flags-nofollow.patch
--- libarchive-3.4.3/debian/patches/upstream-set-flags-nofollow.patch	1970-01-01 02:00:00.000000000 +0200
+++ libarchive-3.4.3/debian/patches/upstream-set-flags-nofollow.patch	2021-12-27 18:45:51.000000000 +0200
@@ -0,0 +1,19 @@
+Description: Never follow symlinks when setting file flags on Linux
+ Published as CVE-2021-31566
+Origin: upstream, https://github.com/libarchive/libarchive/commit/e2ad1a2c3064fa9eba6274b3641c4c1beed25c0b
+Bug-Debian: https://bugs.debian.org/1001990
+Author: Martin Matuska <martin@matuska.org>
+Last-Update: 2021-12-20
+
+--- a/libarchive/archive_write_disk_posix.c
++++ b/libarchive/archive_write_disk_posix.c
+@@ -3927,7 +3927,8 @@
+ 
+ 	/* 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)
diff -Nru libarchive-3.4.3/debian/patches/upstream-symlink-acls.patch libarchive-3.4.3/debian/patches/upstream-symlink-acls.patch
--- libarchive-3.4.3/debian/patches/upstream-symlink-acls.patch	1970-01-01 02:00:00.000000000 +0200
+++ libarchive-3.4.3/debian/patches/upstream-symlink-acls.patch	2021-12-27 18:45:51.000000000 +0200
@@ -0,0 +1,179 @@
+Description: Fix handling of symbolic link ACLs
+ Published as CVE-2021-23177
+Origin: upstream, https://github.com/libarchive/libarchive/commit/fba4f123cc456d2b2538f811bb831483bf336bad
+Bug-Debian: https://bugs.debian.org/1001986
+Author: Martin Matuska <martin@matuska.org>
+Last-Updated: 2021-12-20
+
+--- a/libarchive/archive_disk_acl_freebsd.c
++++ b/libarchive/archive_disk_acl_freebsd.c
+@@ -319,7 +319,7 @@
+ 
+ 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 @@
+ 		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 @@
+ 	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_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 @@
+ #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
+--- a/libarchive/archive_disk_acl_linux.c
++++ b/libarchive/archive_disk_acl_linux.c
+@@ -343,6 +343,11 @@
+ 		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 @@
+ #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 @@
+ 		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_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 */
+--- a/libarchive/archive_disk_acl_sunos.c
++++ b/libarchive/archive_disk_acl_sunos.c
+@@ -443,7 +443,7 @@
+ 
+ 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 @@
+ 	if (entries == 0)
+ 		return (ARCHIVE_OK);
+ 
+-
+ 	switch (ae_requested_type) {
+ 	case ARCHIVE_ENTRY_ACL_TYPE_POSIX1E:
+ 		cmd = SETACL;
+@@ -492,6 +491,12 @@
+ 		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 @@
+ 	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 @@
+ #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

Attachment: signature.asc
Description: PGP signature


Reply to: