Package: release.debian.org
Severity: normal
Tags: bullseye
User: release.debian....@packages.debian.org
Usertags: pu
X-Debbugs-Cc: r...@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
+
+ -- Peter Pentchev <r...@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:27:13.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:26:12.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 <mar...@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:26:12.000000000 +0200
@@ -0,0 +1,214 @@
+Description: Fix extracting hardlinks to symlinks
+Origin: upstream, 
https://github.com/libarchive/libarchive/commit/5e646b890fb3c59ef6f94221ef8ef9ae62a8a9d6
+Author: Martin Matuska <mar...@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:26:12.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 <mar...@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:26:12.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 <mar...@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 via email to