From: Mike Yuan Date: Tue, 16 Dec 2025 00:47:10 +0000 (+0100) Subject: Revert "acl-util: drop now unused fd_acl_make_writable()" X-Git-Tag: v259~10^2~3 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=4abf7ee02e7642bc6ff0b064a95ab57c906f4302;p=thirdparty%2Fsystemd.git Revert "acl-util: drop now unused fd_acl_make_writable()" This reverts commit 4175cd4f400c2e89028878dc265ccd67ca838edd. It turned out that we still need this. Preparation for later commits. --- diff --git a/src/shared/acl-util.c b/src/shared/acl-util.c index bcac9a9bb80..21bbb01278b 100644 --- a/src/shared/acl-util.c +++ b/src/shared/acl-util.c @@ -738,6 +738,68 @@ maybe_fallback: /* No ACLs? Then just update the regular mode_t */ return fd_acl_make_read_only_fallback(fd); } + +int fd_acl_make_writable(int fd) { + _cleanup_(acl_freep) acl_t acl = NULL; + acl_entry_t i; + int r; + + /* Safely adds the writable bit to the owner's ACL entry of this inode. (And only the owner's! – This + * not the obvious inverse of fd_acl_make_read_only() hence!) */ + + r = dlopen_libacl(); + if (r < 0) + return r; + + acl = sym_acl_get_fd(fd); + if (!acl) { + if (!ERRNO_IS_NOT_SUPPORTED(errno)) + return -errno; + + /* No ACLs? Then just update the regular mode_t */ + return fd_acl_make_writable_fallback(fd); + } + + for (r = sym_acl_get_entry(acl, ACL_FIRST_ENTRY, &i); + r > 0; + r = sym_acl_get_entry(acl, ACL_NEXT_ENTRY, &i)) { + acl_permset_t permset; + acl_tag_t tag; + int b; + + if (sym_acl_get_tag_type(i, &tag) < 0) + return -errno; + + if (tag != ACL_USER_OBJ) + continue; + + if (sym_acl_get_permset(i, &permset) < 0) + return -errno; + + b = sym_acl_get_perm(permset, ACL_WRITE); + if (b < 0) + return -errno; + + if (b) + return 0; /* Already set? Then there's nothing to do. */ + + if (sym_acl_add_perm(permset, ACL_WRITE) < 0) + return -errno; + + break; + } + if (r < 0) + return -errno; + + if (sym_acl_set_fd(fd, acl) < 0) { + if (!ERRNO_IS_NOT_SUPPORTED(errno)) + return -errno; + + return fd_acl_make_writable_fallback(fd); + } + + return 1; +} #endif int fd_acl_make_read_only_fallback(int fd) { @@ -757,6 +819,23 @@ int fd_acl_make_read_only_fallback(int fd) { return 1; } +int fd_acl_make_writable_fallback(int fd) { + struct stat st; + + assert(fd >= 0); + + if (fstat(fd, &st) < 0) + return -errno; + + if ((st.st_mode & 0200) != 0) /* already set */ + return 0; + + if (fchmod(fd, (st.st_mode & 07777) | 0200) < 0) + return -errno; + + return 1; +} + int inode_type_can_acl(mode_t mode) { return IN_SET(mode & S_IFMT, S_IFSOCK, S_IFREG, S_IFBLK, S_IFCHR, S_IFDIR, S_IFIFO); } diff --git a/src/shared/acl-util.h b/src/shared/acl-util.h index d65fe0299fd..33a19f30b41 100644 --- a/src/shared/acl-util.h +++ b/src/shared/acl-util.h @@ -4,6 +4,7 @@ #include "shared-forward.h" int fd_acl_make_read_only_fallback(int fd); +int fd_acl_make_writable_fallback(int fd); #if HAVE_ACL #include /* IWYU pragma: export */ @@ -55,6 +56,7 @@ int acls_for_file(const char *path, acl_type_t type, acl_t acl, acl_t *ret); int fd_add_uid_acl_permission(int fd, uid_t uid, unsigned mask); int fd_acl_make_read_only(int fd); +int fd_acl_make_writable(int fd); /* acl_free() takes multiple argument types. Multiple cleanup functions are necessary. */ DEFINE_TRIVIAL_CLEANUP_FUNC_FULL_RENAME(acl_t, sym_acl_free, acl_freep, NULL); @@ -104,6 +106,10 @@ static inline int fd_add_uid_acl_permission(int fd, uid_t uid, unsigned mask) { static inline int fd_acl_make_read_only(int fd) { return fd_acl_make_read_only_fallback(fd); } + +static inline int fd_acl_make_writable(int fd) { + return fd_acl_make_writable_fallback(fd); +} #endif int inode_type_can_acl(mode_t mode); diff --git a/src/test/test-acl-util.c b/src/test/test-acl-util.c index bf65d38b37f..5967c4b4061 100644 --- a/src/test/test-acl-util.c +++ b/src/test/test-acl-util.c @@ -112,6 +112,30 @@ TEST_RET(fd_acl_make_read_only) { cmd = strjoina("stat ", fn); ASSERT_OK_ZERO_ERRNO(system(cmd)); + log_info("writable"); + ASSERT_OK_POSITIVE(fd_acl_make_writable(fd)); + + ASSERT_OK_ERRNO(fstat(fd, &st)); + ASSERT_EQ(st.st_mode & 0222, 0200u); + + cmd = strjoina("getfacl -p ", fn); + ASSERT_OK_ZERO_ERRNO(system(cmd)); + + cmd = strjoina("stat ", fn); + ASSERT_OK_ZERO_ERRNO(system(cmd)); + + log_info("read-only"); + ASSERT_OK_POSITIVE(fd_acl_make_read_only(fd)); + + ASSERT_OK_ERRNO(fstat(fd, &st)); + ASSERT_EQ(st.st_mode & 0222, 0000u); + + cmd = strjoina("getfacl -p ", fn); + ASSERT_OK_ZERO_ERRNO(system(cmd)); + + cmd = strjoina("stat ", fn); + ASSERT_OK_ZERO_ERRNO(system(cmd)); + return 0; }