From f19861d9aca2f1a6970c6a8a6093b70d92d2c060 Mon Sep 17 00:00:00 2001 From: Yu Watanabe Date: Tue, 8 Sep 2026 15:00:28 +0900 Subject: [PATCH 1/4] tar-util: use the same table for converting acl tag Note, ACL_UNDEFINED_TAG == _ARCHIVE_ENTRY_ACL_UNDEFINED, hence this does not change any behavior. --- src/shared/tar-util.c | 64 +++++++++++++++++++++++-------------------- 1 file changed, 34 insertions(+), 30 deletions(-) diff --git a/src/shared/tar-util.c b/src/shared/tar-util.c index 70eefdec31..ae9788755c 100644 --- a/src/shared/tar-util.c +++ b/src/shared/tar-util.c @@ -206,6 +206,38 @@ static int open_inode_finalize_many(OpenInode **array, size_t *n) { return r; } +static const struct { + int libarchive; + acl_tag_t libacl; +} acl_tag_map[] = { + { ARCHIVE_ENTRY_ACL_USER, ACL_USER }, + { ARCHIVE_ENTRY_ACL_GROUP, ACL_GROUP }, + { ARCHIVE_ENTRY_ACL_USER_OBJ, ACL_USER_OBJ }, + { ARCHIVE_ENTRY_ACL_GROUP_OBJ, ACL_GROUP_OBJ }, + { ARCHIVE_ENTRY_ACL_MASK, ACL_MASK }, + { ARCHIVE_ENTRY_ACL_OTHER, ACL_OTHER }, +}; + +static acl_tag_t libarchive_acl_tag_to_libacl_tag(int libarchive_tag) { + FOREACH_ELEMENT(t, acl_tag_map) + if (t->libarchive == libarchive_tag) + return t->libacl; + + return ACL_UNDEFINED_TAG; +} + +#if HAVE_ACL +#define _ARCHIVE_ENTRY_ACL_UNDEFINED 0 + +static int libacl_tag_to_libarchive_acl_tag(acl_tag_t libacl_tag) { + FOREACH_ELEMENT(t, acl_tag_map) + if (t->libacl == libacl_tag) + return t->libarchive; + + return _ARCHIVE_ENTRY_ACL_UNDEFINED; +} +#endif + static int archive_unpack_regular( struct archive *a, struct archive_entry *entry, @@ -541,24 +573,7 @@ static int archive_entry_read_acl( assert(rtype == type); - static const struct { - int libarchive; - acl_tag_t libacl; - } tag_map[] = { - { ARCHIVE_ENTRY_ACL_USER, ACL_USER }, - { ARCHIVE_ENTRY_ACL_GROUP, ACL_GROUP }, - { ARCHIVE_ENTRY_ACL_USER_OBJ, ACL_USER_OBJ }, - { ARCHIVE_ENTRY_ACL_GROUP_OBJ, ACL_GROUP_OBJ }, - { ARCHIVE_ENTRY_ACL_MASK, ACL_MASK }, - { ARCHIVE_ENTRY_ACL_OTHER, ACL_OTHER }, - }; - - acl_tag_t ntag = ACL_UNDEFINED_TAG; - FOREACH_ELEMENT(t, tag_map) - if (t->libarchive == tag) { - ntag = t->libacl; - break; - } + acl_tag_t ntag = libarchive_acl_tag_to_libacl_tag(tag); if (ntag == ACL_UNDEFINED_TAG) continue; @@ -1330,18 +1345,7 @@ static int archive_write_acl( if (sym_acl_get_tag_type(e, &ntag) < 0) return log_error_errno(errno, "Failed to get ACL entry tag: %m"); - static const int tag_map[] = { - [ACL_USER] = ARCHIVE_ENTRY_ACL_USER, - [ACL_GROUP] = ARCHIVE_ENTRY_ACL_GROUP, - [ACL_USER_OBJ] = ARCHIVE_ENTRY_ACL_USER_OBJ, - [ACL_GROUP_OBJ] = ARCHIVE_ENTRY_ACL_GROUP_OBJ, - [ACL_MASK] = ARCHIVE_ENTRY_ACL_MASK, - [ACL_OTHER] = ARCHIVE_ENTRY_ACL_OTHER, - }; - assert_cc(ACL_UNDEFINED_TAG == 0); /* safety check, we assume that holes are filled with ACL_UNDEFINED_TAG */ - assert_cc(ELEMENTSOF(tag_map) <= 64); /* safety check, we assume that the tag ids are all packed and low */ - - int tag = ntag >= 0 && ntag < (acl_tag_t) ELEMENTSOF(tag_map) ? tag_map[ntag] : ACL_UNDEFINED_TAG; + int tag = libacl_tag_to_libarchive_acl_tag(ntag); bool skip = false; id_t qualifier = UID_INVALID; From fc77a3c1a6629ba730e3de387aa4e57ba7b94c3c Mon Sep 17 00:00:00 2001 From: Yu Watanabe Date: Tue, 8 Sep 2026 15:06:48 +0900 Subject: [PATCH 2/4] tar-util: drop boolean 'skip' flag No functional change, just refactoring. --- src/shared/tar-util.c | 53 ++++++++++++++++++++----------------------- 1 file changed, 25 insertions(+), 28 deletions(-) diff --git a/src/shared/tar-util.c b/src/shared/tar-util.c index ae9788755c..f64643d11f 100644 --- a/src/shared/tar-util.c +++ b/src/shared/tar-util.c @@ -1334,8 +1334,9 @@ static int archive_write_acl( return log_error_errno(SYNTHETIC_ERRNO(EOPNOTSUPP), "Unexpected ACL type"); acl_entry_t e; - r = sym_acl_get_entry(acl, ACL_FIRST_ENTRY, &e); - for (;;) { + for (r = sym_acl_get_entry(acl, ACL_FIRST_ENTRY, &e); + ; + r = sym_acl_get_entry(acl, ACL_NEXT_ENTRY, &e)) { if (r < 0) return log_error_errno(errno, "Failed to get ACL entry: %m"); if (r == 0) @@ -1347,7 +1348,6 @@ static int archive_write_acl( int tag = libacl_tag_to_libarchive_acl_tag(ntag); - bool skip = false; id_t qualifier = UID_INVALID; if (IN_SET(ntag, ACL_USER, ACL_GROUP)) { id_t *q = sym_acl_get_qualifier(e); @@ -1358,37 +1358,34 @@ static int archive_write_acl( sym_acl_free(q); /* Suppress invalid UIDs or those that shall be squashed */ - skip = !(uid_is_valid(qualifier) && - (!FLAGS_SET(flags, TAR_SQUASH_UIDS_ABOVE_64K) || qualifier < NSRESOURCE_UIDS_64K)); + if (!(uid_is_valid(qualifier) && + (!FLAGS_SET(flags, TAR_SQUASH_UIDS_ABOVE_64K) || qualifier < NSRESOURCE_UIDS_64K))) + continue; } - if (!skip) { - acl_permset_t p; - if (sym_acl_get_permset(e, &p) < 0) - return log_error_errno(errno, "Failed to get ACL entry permission set: %m"); + acl_permset_t p; + if (sym_acl_get_permset(e, &p) < 0) + return log_error_errno(errno, "Failed to get ACL entry permission set: %m"); - int permset = 0; - r = sym_acl_get_perm(p, ACL_READ); - if (r < 0) - return log_error_errno(errno, "Failed to get ACL entry read bit: %m"); - SET_FLAG(permset, ARCHIVE_ENTRY_ACL_READ, r); + int permset = 0; + r = sym_acl_get_perm(p, ACL_READ); + if (r < 0) + return log_error_errno(errno, "Failed to get ACL entry read bit: %m"); + SET_FLAG(permset, ARCHIVE_ENTRY_ACL_READ, r); - r = sym_acl_get_perm(p, ACL_WRITE); - if (r < 0) - return log_error_errno(errno, "Failed to get ACL entry write bit: %m"); - SET_FLAG(permset, ARCHIVE_ENTRY_ACL_WRITE, r); + r = sym_acl_get_perm(p, ACL_WRITE); + if (r < 0) + return log_error_errno(errno, "Failed to get ACL entry write bit: %m"); + SET_FLAG(permset, ARCHIVE_ENTRY_ACL_WRITE, r); - r = sym_acl_get_perm(p, ACL_EXECUTE); - if (r < 0) - return log_error_errno(errno, "Failed to get ACL entry execute bit: %m"); - SET_FLAG(permset, ARCHIVE_ENTRY_ACL_EXECUTE, r); + r = sym_acl_get_perm(p, ACL_EXECUTE); + if (r < 0) + return log_error_errno(errno, "Failed to get ACL entry execute bit: %m"); + SET_FLAG(permset, ARCHIVE_ENTRY_ACL_EXECUTE, r); - r = sym_archive_entry_acl_add_entry(entry, type, permset, tag, qualifier, /* name= */ NULL); - if (r != ARCHIVE_OK) - return log_error_errno(SYNTHETIC_ERRNO(ENOTRECOVERABLE), "Failed to add ACL entry."); - } - - r = sym_acl_get_entry(acl, ACL_NEXT_ENTRY, &e); + r = sym_archive_entry_acl_add_entry(entry, type, permset, tag, qualifier, /* name= */ NULL); + if (r != ARCHIVE_OK) + return log_error_errno(SYNTHETIC_ERRNO(ENOTRECOVERABLE), "Failed to add ACL entry."); } return 0; From fa7d15b33112020847d4a237af1e5c4e4dea80a8 Mon Sep 17 00:00:00 2001 From: Yu Watanabe Date: Tue, 8 Sep 2026 15:09:23 +0900 Subject: [PATCH 3/4] tar-util: simplify condition No functional change, just refactoring. --- src/shared/tar-util.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/shared/tar-util.c b/src/shared/tar-util.c index f64643d11f..c1afe5bf27 100644 --- a/src/shared/tar-util.c +++ b/src/shared/tar-util.c @@ -1358,8 +1358,8 @@ static int archive_write_acl( sym_acl_free(q); /* Suppress invalid UIDs or those that shall be squashed */ - if (!(uid_is_valid(qualifier) && - (!FLAGS_SET(flags, TAR_SQUASH_UIDS_ABOVE_64K) || qualifier < NSRESOURCE_UIDS_64K))) + if (!uid_is_valid(qualifier) || + (FLAGS_SET(flags, TAR_SQUASH_UIDS_ABOVE_64K) && qualifier >= NSRESOURCE_UIDS_64K)) continue; } From 28e7ae95afa7fbdb68b77dcf441ba7f949afc39a Mon Sep 17 00:00:00 2001 From: Yu Watanabe Date: Tue, 8 Sep 2026 15:15:29 +0900 Subject: [PATCH 4/4] tar-util: do not fail by adding an unknown acl tag archive_entry_acl_add_entry() will fail when an unknown tag is set. --- src/shared/tar-util.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/shared/tar-util.c b/src/shared/tar-util.c index c1afe5bf27..8d6306a20d 100644 --- a/src/shared/tar-util.c +++ b/src/shared/tar-util.c @@ -1347,6 +1347,8 @@ static int archive_write_acl( return log_error_errno(errno, "Failed to get ACL entry tag: %m"); int tag = libacl_tag_to_libarchive_acl_tag(ntag); + if (tag == _ARCHIVE_ENTRY_ACL_UNDEFINED) + continue; id_t qualifier = UID_INVALID; if (IN_SET(ntag, ACL_USER, ACL_GROUP)) {