Skip to content

Commit fba4f12

Browse files
committed
Fix handling of symbolic link ACLs
On Linux ACLs on symbolic links are not supported. We must avoid calling acl_set_file() on symbolic links as their targets are modified instead. While here, do not try to set default ACLs on non-directories. Fixes libarchive#1565
1 parent 1302359 commit fba4f12

3 files changed

Lines changed: 44 additions & 12 deletions

File tree

libarchive/archive_disk_acl_freebsd.c

Lines changed: 15 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -319,7 +319,7 @@ translate_acl(struct archive_read_disk *a,
319319

320320
static int
321321
set_acl(struct archive *a, int fd, const char *name,
322-
struct archive_acl *abstract_acl,
322+
struct archive_acl *abstract_acl, __LA_MODE_T mode,
323323
int ae_requested_type, const char *tname)
324324
{
325325
int acl_type = 0;
@@ -364,6 +364,13 @@ set_acl(struct archive *a, int fd, const char *name,
364364
return (ARCHIVE_FAILED);
365365
}
366366

367+
if (acl_type == ACL_TYPE_DEFAULT && !S_ISDIR(mode)) {
368+
errno = EINVAL;
369+
archive_set_error(a, errno,
370+
"Cannot set default ACL on non-directory");
371+
return (ARCHIVE_WARN);
372+
}
373+
367374
acl = acl_init(entries);
368375
if (acl == (acl_t)NULL) {
369376
archive_set_error(a, errno,
@@ -542,7 +549,10 @@ set_acl(struct archive *a, int fd, const char *name,
542549
else if (acl_set_link_np(name, acl_type, acl) != 0)
543550
#else
544551
/* FreeBSD older than 8.0 */
545-
else if (acl_set_file(name, acl_type, acl) != 0)
552+
else if (S_ISLNK(mode)) {
553+
/* acl_set_file() follows symbolic links, skip */
554+
ret = ARCHIVE_OK;
555+
} else if (acl_set_file(name, acl_type, acl) != 0)
546556
#endif
547557
{
548558
if (errno == EOPNOTSUPP) {
@@ -677,14 +687,14 @@ archive_write_disk_set_acls(struct archive *a, int fd, const char *name,
677687
& ARCHIVE_ENTRY_ACL_TYPE_POSIX1E) != 0) {
678688
if ((archive_acl_types(abstract_acl)
679689
& ARCHIVE_ENTRY_ACL_TYPE_ACCESS) != 0) {
680-
ret = set_acl(a, fd, name, abstract_acl,
690+
ret = set_acl(a, fd, name, abstract_acl, mode,
681691
ARCHIVE_ENTRY_ACL_TYPE_ACCESS, "access");
682692
if (ret != ARCHIVE_OK)
683693
return (ret);
684694
}
685695
if ((archive_acl_types(abstract_acl)
686696
& ARCHIVE_ENTRY_ACL_TYPE_DEFAULT) != 0)
687-
ret = set_acl(a, fd, name, abstract_acl,
697+
ret = set_acl(a, fd, name, abstract_acl, mode,
688698
ARCHIVE_ENTRY_ACL_TYPE_DEFAULT, "default");
689699

690700
/* Simultaneous POSIX.1e and NFSv4 is not supported */
@@ -693,7 +703,7 @@ archive_write_disk_set_acls(struct archive *a, int fd, const char *name,
693703
#if ARCHIVE_ACL_FREEBSD_NFS4
694704
else if ((archive_acl_types(abstract_acl) &
695705
ARCHIVE_ENTRY_ACL_TYPE_NFS4) != 0) {
696-
ret = set_acl(a, fd, name, abstract_acl,
706+
ret = set_acl(a, fd, name, abstract_acl, mode,
697707
ARCHIVE_ENTRY_ACL_TYPE_NFS4, "nfs4");
698708
}
699709
#endif

libarchive/archive_disk_acl_linux.c

Lines changed: 20 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -343,6 +343,11 @@ set_richacl(struct archive *a, int fd, const char *name,
343343
return (ARCHIVE_FAILED);
344344
}
345345

346+
if (S_ISLNK(mode)) {
347+
/* Linux does not support RichACLs on symbolic links */
348+
return (ARCHIVE_OK);
349+
}
350+
346351
richacl = richacl_alloc(entries);
347352
if (richacl == NULL) {
348353
archive_set_error(a, errno,
@@ -455,7 +460,7 @@ set_richacl(struct archive *a, int fd, const char *name,
455460
#if ARCHIVE_ACL_LIBACL
456461
static int
457462
set_acl(struct archive *a, int fd, const char *name,
458-
struct archive_acl *abstract_acl,
463+
struct archive_acl *abstract_acl, __LA_MODE_T mode,
459464
int ae_requested_type, const char *tname)
460465
{
461466
int acl_type = 0;
@@ -488,6 +493,18 @@ set_acl(struct archive *a, int fd, const char *name,
488493
return (ARCHIVE_FAILED);
489494
}
490495

496+
if (S_ISLNK(mode)) {
497+
/* Linux does not support ACLs on symbolic links */
498+
return (ARCHIVE_OK);
499+
}
500+
501+
if (acl_type == ACL_TYPE_DEFAULT && !S_ISDIR(mode)) {
502+
errno = EINVAL;
503+
archive_set_error(a, errno,
504+
"Cannot set default ACL on non-directory");
505+
return (ARCHIVE_WARN);
506+
}
507+
491508
acl = acl_init(entries);
492509
if (acl == (acl_t)NULL) {
493510
archive_set_error(a, errno,
@@ -727,14 +744,14 @@ archive_write_disk_set_acls(struct archive *a, int fd, const char *name,
727744
& ARCHIVE_ENTRY_ACL_TYPE_POSIX1E) != 0) {
728745
if ((archive_acl_types(abstract_acl)
729746
& ARCHIVE_ENTRY_ACL_TYPE_ACCESS) != 0) {
730-
ret = set_acl(a, fd, name, abstract_acl,
747+
ret = set_acl(a, fd, name, abstract_acl, mode,
731748
ARCHIVE_ENTRY_ACL_TYPE_ACCESS, "access");
732749
if (ret != ARCHIVE_OK)
733750
return (ret);
734751
}
735752
if ((archive_acl_types(abstract_acl)
736753
& ARCHIVE_ENTRY_ACL_TYPE_DEFAULT) != 0)
737-
ret = set_acl(a, fd, name, abstract_acl,
754+
ret = set_acl(a, fd, name, abstract_acl, mode,
738755
ARCHIVE_ENTRY_ACL_TYPE_DEFAULT, "default");
739756
}
740757
#endif /* ARCHIVE_ACL_LIBACL */

libarchive/archive_disk_acl_sunos.c

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -443,7 +443,7 @@ translate_acl(struct archive_read_disk *a,
443443

444444
static int
445445
set_acl(struct archive *a, int fd, const char *name,
446-
struct archive_acl *abstract_acl,
446+
struct archive_acl *abstract_acl, __LA_MODE_T mode,
447447
int ae_requested_type, const char *tname)
448448
{
449449
aclent_t *aclent;
@@ -467,7 +467,6 @@ set_acl(struct archive *a, int fd, const char *name,
467467
if (entries == 0)
468468
return (ARCHIVE_OK);
469469

470-
471470
switch (ae_requested_type) {
472471
case ARCHIVE_ENTRY_ACL_TYPE_POSIX1E:
473472
cmd = SETACL;
@@ -492,6 +491,12 @@ set_acl(struct archive *a, int fd, const char *name,
492491
return (ARCHIVE_FAILED);
493492
}
494493

494+
if (S_ISLNK(mode)) {
495+
/* Skip ACLs on symbolic links */
496+
ret = ARCHIVE_OK;
497+
goto exit_free;
498+
}
499+
495500
e = 0;
496501

497502
while (archive_acl_next(a, abstract_acl, ae_requested_type, &ae_type,
@@ -801,7 +806,7 @@ archive_write_disk_set_acls(struct archive *a, int fd, const char *name,
801806
if ((archive_acl_types(abstract_acl)
802807
& ARCHIVE_ENTRY_ACL_TYPE_POSIX1E) != 0) {
803808
/* Solaris writes POSIX.1e access and default ACLs together */
804-
ret = set_acl(a, fd, name, abstract_acl,
809+
ret = set_acl(a, fd, name, abstract_acl, mode,
805810
ARCHIVE_ENTRY_ACL_TYPE_POSIX1E, "posix1e");
806811

807812
/* Simultaneous POSIX.1e and NFSv4 is not supported */
@@ -810,7 +815,7 @@ archive_write_disk_set_acls(struct archive *a, int fd, const char *name,
810815
#if ARCHIVE_ACL_SUNOS_NFS4
811816
else if ((archive_acl_types(abstract_acl) &
812817
ARCHIVE_ENTRY_ACL_TYPE_NFS4) != 0) {
813-
ret = set_acl(a, fd, name, abstract_acl,
818+
ret = set_acl(a, fd, name, abstract_acl, mode,
814819
ARCHIVE_ENTRY_ACL_TYPE_NFS4, "nfs4");
815820
}
816821
#endif

0 commit comments

Comments
 (0)