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 Last-Updated: 2021-12-20 CVE: CVE-2021-23177 Upstream-Status: Backport [http://deb.debian.org/debian/pool/main/liba/libarchive/libarchive_3.4.3-2+deb11u1.debian.tar.xz] Signed-off-by: Ranjitsinh Rathod --- 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