From 7c3a7f925f83bd05a49e8b1f09726cccc26977f7 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Tue, 23 Sep 2025 11:46:49 +0200 Subject: [PATCH] acl: turn libacl dep into a dlopen() one I initially didn't think it would be worth doing this, but I changed my mind. People out there quite successfully build systemd without ACL support, and that suggests life without it is quite possible. Moreover we only use it as very specific places: 1. in udev/logind for "uaccess" mgmt 2. in tmpfiles to implement explicitly configured acl changes 3. in journald/coredump/pstore to manage access to unpriv users 4. in pid1 to manage access to credential files 5. when shifting UIDs of container trees I specific container environments it should be entirely fine to live without all of these, hence let's pull this in on demand only. --- meson.build | 1 + src/shared/acl-util.c | 258 +++++++++++++++++++++++++------------- src/shared/acl-util.h | 49 ++++++-- src/shared/meson.build | 2 +- src/shared/shift-uid.c | 43 ++++--- src/test/test-dlopen-so.c | 2 + src/tmpfiles/meson.build | 4 +- src/tmpfiles/tmpfiles.c | 54 ++++---- src/udev/meson.build | 4 +- 9 files changed, 276 insertions(+), 141 deletions(-) diff --git a/meson.build b/meson.build index 15e1d3821ed..afd2342488f 100644 --- a/meson.build +++ b/meson.build @@ -1183,6 +1183,7 @@ conf.set10('ENABLE_POLKIT', install_polkit) libacl = dependency('libacl', required : get_option('acl')) conf.set10('HAVE_ACL', libacl.found()) +libacl_cflags = libacl.partial_dependency(includes: true, compile_args: true) libaudit = dependency('audit', required : get_option('audit')) diff --git a/src/shared/acl-util.c b/src/shared/acl-util.c index 0a5c8c9f921..554d4738213 100644 --- a/src/shared/acl-util.c +++ b/src/shared/acl-util.c @@ -7,11 +7,74 @@ #include "errno-util.h" #include "extract-word.h" #include "fd-util.h" +#include "log.h" #include "string-util.h" #include "strv.h" #include "user-util.h" #if HAVE_ACL +static void *libacl_dl = NULL; + +DLSYM_PROTOTYPE(acl_add_perm); +DLSYM_PROTOTYPE(acl_calc_mask); +DLSYM_PROTOTYPE(acl_copy_entry); +DLSYM_PROTOTYPE(acl_create_entry); +DLSYM_PROTOTYPE(acl_delete_entry); +DLSYM_PROTOTYPE(acl_delete_perm); +DLSYM_PROTOTYPE(acl_dup); +DLSYM_PROTOTYPE(acl_entries); +DLSYM_PROTOTYPE(acl_free); +DLSYM_PROTOTYPE(acl_from_mode); +DLSYM_PROTOTYPE(acl_from_text); +DLSYM_PROTOTYPE(acl_get_entry); +DLSYM_PROTOTYPE(acl_get_fd); +DLSYM_PROTOTYPE(acl_get_file); +DLSYM_PROTOTYPE(acl_get_perm); +DLSYM_PROTOTYPE(acl_get_permset); +DLSYM_PROTOTYPE(acl_get_qualifier); +DLSYM_PROTOTYPE(acl_get_tag_type); +DLSYM_PROTOTYPE(acl_init); +DLSYM_PROTOTYPE(acl_set_fd); +DLSYM_PROTOTYPE(acl_set_file); +DLSYM_PROTOTYPE(acl_set_qualifier); +DLSYM_PROTOTYPE(acl_set_tag_type); +DLSYM_PROTOTYPE(acl_to_any_text); + +int dlopen_libacl(void) { + ELF_NOTE_DLOPEN("acl", + "Support for file Access Control Lists (ACLs)", + ELF_NOTE_DLOPEN_PRIORITY_RECOMMENDED, + "libacl.so.1"); + + return dlopen_many_sym_or_warn( + &libacl_dl, + "libacl.so.1", + LOG_DEBUG, + DLSYM_ARG(acl_add_perm), + DLSYM_ARG(acl_calc_mask), + DLSYM_ARG(acl_copy_entry), + DLSYM_ARG(acl_create_entry), + DLSYM_ARG(acl_delete_entry), + DLSYM_ARG(acl_delete_perm), + DLSYM_ARG(acl_dup), + DLSYM_ARG(acl_entries), + DLSYM_ARG(acl_free), + DLSYM_ARG(acl_from_mode), + DLSYM_ARG(acl_from_text), + DLSYM_ARG(acl_get_entry), + DLSYM_ARG(acl_get_fd), + DLSYM_ARG(acl_get_file), + DLSYM_ARG(acl_get_perm), + DLSYM_ARG(acl_get_permset), + DLSYM_ARG(acl_get_qualifier), + DLSYM_ARG(acl_get_tag_type), + DLSYM_ARG(acl_init), + DLSYM_ARG(acl_set_fd), + DLSYM_ARG(acl_set_file), + DLSYM_ARG(acl_set_qualifier), + DLSYM_ARG(acl_set_tag_type), + DLSYM_ARG(acl_to_any_text)); +} int devnode_acl(int fd, uid_t uid) { bool changed = false, found = false; @@ -19,43 +82,47 @@ int devnode_acl(int fd, uid_t uid) { assert(fd >= 0); + r = dlopen_libacl(); + if (r < 0) + return r; + _cleanup_(acl_freep) acl_t acl = NULL; - acl = acl_get_file(FORMAT_PROC_FD_PATH(fd), ACL_TYPE_ACCESS); + acl = sym_acl_get_file(FORMAT_PROC_FD_PATH(fd), ACL_TYPE_ACCESS); if (!acl) return -errno; acl_entry_t entry; - for (r = acl_get_entry(acl, ACL_FIRST_ENTRY, &entry); + for (r = sym_acl_get_entry(acl, ACL_FIRST_ENTRY, &entry); r > 0; - r = acl_get_entry(acl, ACL_NEXT_ENTRY, &entry)) { + r = sym_acl_get_entry(acl, ACL_NEXT_ENTRY, &entry)) { acl_tag_t tag; - if (acl_get_tag_type(entry, &tag) < 0) + if (sym_acl_get_tag_type(entry, &tag) < 0) return -errno; if (tag != ACL_USER) continue; if (uid > 0) { - uid_t *u = acl_get_qualifier(entry); + uid_t *u = sym_acl_get_qualifier(entry); if (!u) return -errno; if (*u == uid) { acl_permset_t permset; - if (acl_get_permset(entry, &permset) < 0) + if (sym_acl_get_permset(entry, &permset) < 0) return -errno; - int rd = acl_get_perm(permset, ACL_READ); + int rd = sym_acl_get_perm(permset, ACL_READ); if (rd < 0) return -errno; - int wt = acl_get_perm(permset, ACL_WRITE); + int wt = sym_acl_get_perm(permset, ACL_WRITE); if (wt < 0) return -errno; if (!rd || !wt) { - if (acl_add_perm(permset, ACL_READ|ACL_WRITE) < 0) + if (sym_acl_add_perm(permset, ACL_READ|ACL_WRITE) < 0) return -errno; changed = true; @@ -66,7 +133,7 @@ int devnode_acl(int fd, uid_t uid) { } } - if (acl_delete_entry(acl, entry) < 0) + if (sym_acl_delete_entry(acl, entry) < 0) return -errno; changed = true; @@ -75,20 +142,20 @@ int devnode_acl(int fd, uid_t uid) { return -errno; if (!found && uid > 0) { - if (acl_create_entry(&acl, &entry) < 0) + if (sym_acl_create_entry(&acl, &entry) < 0) return -errno; - if (acl_set_tag_type(entry, ACL_USER) < 0) + if (sym_acl_set_tag_type(entry, ACL_USER) < 0) return -errno; - if (acl_set_qualifier(entry, &uid) < 0) + if (sym_acl_set_qualifier(entry, &uid) < 0) return -errno; acl_permset_t permset; - if (acl_get_permset(entry, &permset) < 0) + if (sym_acl_get_permset(entry, &permset) < 0) return -errno; - if (acl_add_perm(permset, ACL_READ|ACL_WRITE) < 0) + if (sym_acl_add_perm(permset, ACL_READ|ACL_WRITE) < 0) return -errno; changed = true; @@ -97,10 +164,10 @@ int devnode_acl(int fd, uid_t uid) { if (!changed) return 0; - if (acl_calc_mask(&acl) < 0) + if (sym_acl_calc_mask(&acl) < 0) return -errno; - if (acl_set_file(FORMAT_PROC_FD_PATH(fd), ACL_TYPE_ACCESS, acl) < 0) + if (sym_acl_set_file(FORMAT_PROC_FD_PATH(fd), ACL_TYPE_ACCESS, acl) < 0) return -errno; return 0; @@ -114,27 +181,25 @@ static int acl_find_uid(acl_t acl, uid_t uid, acl_entry_t *ret_entry) { assert(uid_is_valid(uid)); assert(ret_entry); - for (r = acl_get_entry(acl, ACL_FIRST_ENTRY, &i); + for (r = sym_acl_get_entry(acl, ACL_FIRST_ENTRY, &i); r > 0; - r = acl_get_entry(acl, ACL_NEXT_ENTRY, &i)) { + r = sym_acl_get_entry(acl, ACL_NEXT_ENTRY, &i)) { acl_tag_t tag; - uid_t *u; bool b; - if (acl_get_tag_type(i, &tag) < 0) + if (sym_acl_get_tag_type(i, &tag) < 0) return -errno; if (tag != ACL_USER) continue; - u = acl_get_qualifier(i); + _cleanup_(acl_free_uid_tpp) uid_t *u = NULL; + u = sym_acl_get_qualifier(i); if (!u) return -errno; b = *u == uid; - acl_free(u); - if (b) { *ret_entry = i; return 1; @@ -154,12 +219,12 @@ int calc_acl_mask_if_needed(acl_t *acl_p) { assert(acl_p); - for (r = acl_get_entry(*acl_p, ACL_FIRST_ENTRY, &i); + for (r = sym_acl_get_entry(*acl_p, ACL_FIRST_ENTRY, &i); r > 0; - r = acl_get_entry(*acl_p, ACL_NEXT_ENTRY, &i)) { + r = sym_acl_get_entry(*acl_p, ACL_NEXT_ENTRY, &i)) { acl_tag_t tag; - if (acl_get_tag_type(i, &tag) < 0) + if (sym_acl_get_tag_type(i, &tag) < 0) return -errno; if (tag == ACL_MASK) @@ -171,7 +236,7 @@ int calc_acl_mask_if_needed(acl_t *acl_p) { if (r < 0) return -errno; - if (need && acl_calc_mask(acl_p) < 0) + if (need && sym_acl_calc_mask(acl_p) < 0) return -errno; return need; @@ -187,12 +252,12 @@ int add_base_acls_if_needed(acl_t *acl_p, const char *path) { assert(acl_p); assert(path); - for (r = acl_get_entry(*acl_p, ACL_FIRST_ENTRY, &i); + for (r = sym_acl_get_entry(*acl_p, ACL_FIRST_ENTRY, &i); r > 0; - r = acl_get_entry(*acl_p, ACL_NEXT_ENTRY, &i)) { + r = sym_acl_get_entry(*acl_p, ACL_NEXT_ENTRY, &i)) { acl_tag_t tag; - if (acl_get_tag_type(i, &tag) < 0) + if (sym_acl_get_tag_type(i, &tag) < 0) return -errno; if (tag == ACL_USER_OBJ) @@ -207,21 +272,20 @@ int add_base_acls_if_needed(acl_t *acl_p, const char *path) { if (r < 0) return -errno; - r = stat(path, &st); - if (r < 0) + if (stat(path, &st) < 0) return -errno; - basic = acl_from_mode(st.st_mode); + basic = sym_acl_from_mode(st.st_mode); if (!basic) return -errno; - for (r = acl_get_entry(basic, ACL_FIRST_ENTRY, &i); + for (r = sym_acl_get_entry(basic, ACL_FIRST_ENTRY, &i); r > 0; - r = acl_get_entry(basic, ACL_NEXT_ENTRY, &i)) { + r = sym_acl_get_entry(basic, ACL_NEXT_ENTRY, &i)) { acl_tag_t tag; acl_entry_t dst; - if (acl_get_tag_type(i, &tag) < 0) + if (sym_acl_get_tag_type(i, &tag) < 0) return -errno; if ((tag == ACL_USER_OBJ && have_user_obj) || @@ -229,11 +293,11 @@ int add_base_acls_if_needed(acl_t *acl_p, const char *path) { (tag == ACL_OTHER && have_other)) continue; - r = acl_create_entry(acl_p, &dst); + r = sym_acl_create_entry(acl_p, &dst); if (r < 0) return -errno; - r = acl_copy_entry(dst, i); + r = sym_acl_copy_entry(dst, i); if (r < 0) return -errno; } @@ -251,11 +315,15 @@ int acl_search_groups(const char *path, char ***ret_groups) { assert(path); - acl = acl_get_file(path, ACL_TYPE_DEFAULT); + r = dlopen_libacl(); + if (r < 0) + return r; + + acl = sym_acl_get_file(path, ACL_TYPE_DEFAULT); if (!acl) return -errno; - r = acl_get_entry(acl, ACL_FIRST_ENTRY, &entry); + r = sym_acl_get_entry(acl, ACL_FIRST_ENTRY, &entry); for (;;) { _cleanup_(acl_free_gid_tpp) gid_t *gid = NULL; acl_tag_t tag; @@ -265,13 +333,13 @@ int acl_search_groups(const char *path, char ***ret_groups) { if (r == 0) break; - if (acl_get_tag_type(entry, &tag) < 0) + if (sym_acl_get_tag_type(entry, &tag) < 0) return -errno; if (tag != ACL_GROUP) goto next; - gid = acl_get_qualifier(entry); + gid = sym_acl_get_qualifier(entry); if (!gid) return -errno; @@ -295,7 +363,7 @@ int acl_search_groups(const char *path, char ***ret_groups) { } next: - r = acl_get_entry(acl, ACL_NEXT_ENTRY, &entry); + r = sym_acl_get_entry(acl, ACL_NEXT_ENTRY, &entry); } if (ret_groups) @@ -324,6 +392,10 @@ int parse_acl( if (!split) return -ENOMEM; + r = dlopen_libacl(); + if (r < 0) + return r; + STRV_FOREACH(entry, split) { _cleanup_strv_free_ char **entry_split = NULL; _cleanup_free_ char *entry_join = NULL; @@ -368,7 +440,7 @@ int parse_acl( if (!join) return -ENOMEM; - a_acl = acl_from_text(join); + a_acl = sym_acl_from_text(join); if (!a_acl) return -errno; @@ -386,7 +458,7 @@ int parse_acl( if (!join) return -ENOMEM; - e_acl = acl_from_text(join); + e_acl = sym_acl_from_text(join); if (!e_acl) return -errno; @@ -400,7 +472,7 @@ int parse_acl( if (!join) return -ENOMEM; - d_acl = acl_from_text(join); + d_acl = sym_acl_from_text(join); if (!d_acl) return -errno; @@ -421,10 +493,10 @@ int parse_acl( static int acl_entry_equal(acl_entry_t a, acl_entry_t b) { acl_tag_t tag_a, tag_b; - if (acl_get_tag_type(a, &tag_a) < 0) + if (sym_acl_get_tag_type(a, &tag_a) < 0) return -errno; - if (acl_get_tag_type(b, &tag_b) < 0) + if (sym_acl_get_tag_type(b, &tag_b) < 0) return -errno; if (tag_a != tag_b) @@ -440,11 +512,11 @@ static int acl_entry_equal(acl_entry_t a, acl_entry_t b) { case ACL_USER: { _cleanup_(acl_free_uid_tpp) uid_t *uid_a = NULL, *uid_b = NULL; - uid_a = acl_get_qualifier(a); + uid_a = sym_acl_get_qualifier(a); if (!uid_a) return -errno; - uid_b = acl_get_qualifier(b); + uid_b = sym_acl_get_qualifier(b); if (!uid_b) return -errno; @@ -453,11 +525,11 @@ static int acl_entry_equal(acl_entry_t a, acl_entry_t b) { case ACL_GROUP: { _cleanup_(acl_free_gid_tpp) gid_t *gid_a = NULL, *gid_b = NULL; - gid_a = acl_get_qualifier(a); + gid_a = sym_acl_get_qualifier(a); if (!gid_a) return -errno; - gid_b = acl_get_qualifier(b); + gid_b = sym_acl_get_qualifier(b); if (!gid_b) return -errno; @@ -472,9 +544,9 @@ static int find_acl_entry(acl_t acl, acl_entry_t entry, acl_entry_t *ret) { acl_entry_t i; int r; - for (r = acl_get_entry(acl, ACL_FIRST_ENTRY, &i); + for (r = sym_acl_get_entry(acl, ACL_FIRST_ENTRY, &i); r > 0; - r = acl_get_entry(acl, ACL_NEXT_ENTRY, &i)) { + r = sym_acl_get_entry(acl, ACL_NEXT_ENTRY, &i)) { r = acl_entry_equal(i, entry); if (r < 0) @@ -498,24 +570,28 @@ int acls_for_file(const char *path, acl_type_t type, acl_t acl, acl_t *ret) { assert(path); - applied = acl_get_file(path, type); + r = dlopen_libacl(); + if (r < 0) + return r; + + applied = sym_acl_get_file(path, type); if (!applied) return -errno; - for (r = acl_get_entry(acl, ACL_FIRST_ENTRY, &i); + for (r = sym_acl_get_entry(acl, ACL_FIRST_ENTRY, &i); r > 0; - r = acl_get_entry(acl, ACL_NEXT_ENTRY, &i)) { + r = sym_acl_get_entry(acl, ACL_NEXT_ENTRY, &i)) { acl_entry_t j; r = find_acl_entry(applied, i, &j); if (r == -ENOENT) { - if (acl_create_entry(&applied, &j) < 0) + if (sym_acl_create_entry(&applied, &j) < 0) return -errno; } else if (r < 0) return r; - if (acl_copy_entry(j, i) < 0) + if (sym_acl_copy_entry(j, i) < 0) return -errno; } if (r < 0) @@ -553,33 +629,37 @@ int fd_add_uid_acl_permission( assert(fd >= 0); assert(uid_is_valid(uid)); - acl = acl_get_fd(fd); + r = dlopen_libacl(); + if (r < 0) + return r; + + acl = sym_acl_get_fd(fd); if (!acl) return -errno; r = acl_find_uid(acl, uid, &entry); if (r <= 0) { - if (acl_create_entry(&acl, &entry) < 0 || - acl_set_tag_type(entry, ACL_USER) < 0 || - acl_set_qualifier(entry, &uid) < 0) + if (sym_acl_create_entry(&acl, &entry) < 0 || + sym_acl_set_tag_type(entry, ACL_USER) < 0 || + sym_acl_set_qualifier(entry, &uid) < 0) return -errno; } - if (acl_get_permset(entry, &permset) < 0) + if (sym_acl_get_permset(entry, &permset) < 0) return -errno; - if ((mask & ACL_READ) && acl_add_perm(permset, ACL_READ) < 0) + if ((mask & ACL_READ) && sym_acl_add_perm(permset, ACL_READ) < 0) return -errno; - if ((mask & ACL_WRITE) && acl_add_perm(permset, ACL_WRITE) < 0) + if ((mask & ACL_WRITE) && sym_acl_add_perm(permset, ACL_WRITE) < 0) return -errno; - if ((mask & ACL_EXECUTE) && acl_add_perm(permset, ACL_EXECUTE) < 0) + if ((mask & ACL_EXECUTE) && sym_acl_add_perm(permset, ACL_EXECUTE) < 0) return -errno; r = calc_acl_mask_if_needed(&acl); if (r < 0) return r; - if (acl_set_fd(fd, acl) < 0) + if (sym_acl_set_fd(fd, acl) < 0) return -errno; return 0; @@ -596,7 +676,11 @@ int fd_acl_make_read_only(int fd) { /* Safely drops all W bits from all relevant ACL entries of the file, without changing entries which * are masked by the ACL mask */ - acl = acl_get_fd(fd); + r = dlopen_libacl(); + if (r < 0) + return r; + + acl = sym_acl_get_fd(fd); if (!acl) { if (!ERRNO_IS_NOT_SUPPORTED(errno)) @@ -606,29 +690,29 @@ int fd_acl_make_read_only(int fd) { return fd_acl_make_read_only_fallback(fd); } - for (r = acl_get_entry(acl, ACL_FIRST_ENTRY, &i); + for (r = sym_acl_get_entry(acl, ACL_FIRST_ENTRY, &i); r > 0; - r = acl_get_entry(acl, ACL_NEXT_ENTRY, &i)) { + r = sym_acl_get_entry(acl, ACL_NEXT_ENTRY, &i)) { acl_permset_t permset; acl_tag_t tag; int b; - if (acl_get_tag_type(i, &tag) < 0) + if (sym_acl_get_tag_type(i, &tag) < 0) return -errno; /* These three control the x bits overall (as ACL_MASK affects all remaining tags) */ if (!IN_SET(tag, ACL_USER_OBJ, ACL_MASK, ACL_OTHER)) continue; - if (acl_get_permset(i, &permset) < 0) + if (sym_acl_get_permset(i, &permset) < 0) return -errno; - b = acl_get_perm(permset, ACL_WRITE); + b = sym_acl_get_perm(permset, ACL_WRITE); if (b < 0) return -errno; if (b) { - if (acl_delete_perm(permset, ACL_WRITE) < 0) + if (sym_acl_delete_perm(permset, ACL_WRITE) < 0) return -errno; changed = true; @@ -640,7 +724,7 @@ int fd_acl_make_read_only(int fd) { if (!changed) return 0; - if (acl_set_fd(fd, acl) < 0) { + if (sym_acl_set_fd(fd, acl) < 0) { if (!ERRNO_IS_NOT_SUPPORTED(errno)) return -errno; @@ -658,7 +742,11 @@ int fd_acl_make_writable(int fd) { /* 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!) */ - acl = acl_get_fd(fd); + r = dlopen_libacl(); + if (r < 0) + return r; + + acl = sym_acl_get_fd(fd); if (!acl) { if (!ERRNO_IS_NOT_SUPPORTED(errno)) return -errno; @@ -667,30 +755,30 @@ int fd_acl_make_writable(int fd) { return fd_acl_make_writable_fallback(fd); } - for (r = acl_get_entry(acl, ACL_FIRST_ENTRY, &i); + for (r = sym_acl_get_entry(acl, ACL_FIRST_ENTRY, &i); r > 0; - r = acl_get_entry(acl, ACL_NEXT_ENTRY, &i)) { + r = sym_acl_get_entry(acl, ACL_NEXT_ENTRY, &i)) { acl_permset_t permset; acl_tag_t tag; int b; - if (acl_get_tag_type(i, &tag) < 0) + if (sym_acl_get_tag_type(i, &tag) < 0) return -errno; if (tag != ACL_USER_OBJ) continue; - if (acl_get_permset(i, &permset) < 0) + if (sym_acl_get_permset(i, &permset) < 0) return -errno; - b = acl_get_perm(permset, ACL_WRITE); + 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 (acl_add_perm(permset, ACL_WRITE) < 0) + if (sym_acl_add_perm(permset, ACL_WRITE) < 0) return -errno; break; @@ -698,7 +786,7 @@ int fd_acl_make_writable(int fd) { if (r < 0) return -errno; - if (acl_set_fd(fd, acl) < 0) { + if (sym_acl_set_fd(fd, acl) < 0) { if (!ERRNO_IS_NOT_SUPPORTED(errno)) return -errno; diff --git a/src/shared/acl-util.h b/src/shared/acl-util.h index 3e23fe39385..54eba92f38e 100644 --- a/src/shared/acl-util.h +++ b/src/shared/acl-util.h @@ -10,6 +10,35 @@ int fd_acl_make_writable_fallback(int fd); #include /* IWYU pragma: export */ #include /* IWYU pragma: export */ +#include "dlfcn-util.h" + +extern DLSYM_PROTOTYPE(acl_add_perm); +extern DLSYM_PROTOTYPE(acl_calc_mask); +extern DLSYM_PROTOTYPE(acl_copy_entry); +extern DLSYM_PROTOTYPE(acl_create_entry); +extern DLSYM_PROTOTYPE(acl_delete_entry); +extern DLSYM_PROTOTYPE(acl_delete_perm); +extern DLSYM_PROTOTYPE(acl_dup); +extern DLSYM_PROTOTYPE(acl_entries); +extern DLSYM_PROTOTYPE(acl_free); +extern DLSYM_PROTOTYPE(acl_from_mode); +extern DLSYM_PROTOTYPE(acl_from_text); +extern DLSYM_PROTOTYPE(acl_get_entry); +extern DLSYM_PROTOTYPE(acl_get_fd); +extern DLSYM_PROTOTYPE(acl_get_file); +extern DLSYM_PROTOTYPE(acl_get_perm); +extern DLSYM_PROTOTYPE(acl_get_permset); +extern DLSYM_PROTOTYPE(acl_get_qualifier); +extern DLSYM_PROTOTYPE(acl_get_tag_type); +extern DLSYM_PROTOTYPE(acl_init); +extern DLSYM_PROTOTYPE(acl_set_fd); +extern DLSYM_PROTOTYPE(acl_set_file); +extern DLSYM_PROTOTYPE(acl_set_qualifier); +extern DLSYM_PROTOTYPE(acl_set_tag_type); +extern DLSYM_PROTOTYPE(acl_to_any_text); + +int dlopen_libacl(void); + int devnode_acl(int fd, uid_t uid); int calc_acl_mask_if_needed(acl_t *acl_p); @@ -27,21 +56,22 @@ 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(acl_t, acl_free, NULL); -#define acl_free_charp acl_free -DEFINE_TRIVIAL_CLEANUP_FUNC_FULL(char*, acl_free_charp, NULL); -#define acl_free_uid_tp acl_free -DEFINE_TRIVIAL_CLEANUP_FUNC_FULL(uid_t*, acl_free_uid_tp, NULL); -#define acl_free_gid_tp acl_free -DEFINE_TRIVIAL_CLEANUP_FUNC_FULL(gid_t*, acl_free_gid_tp, NULL); +/* 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); +DEFINE_TRIVIAL_CLEANUP_FUNC_FULL_RENAME(char*, sym_acl_free, acl_free_charpp, NULL); +DEFINE_TRIVIAL_CLEANUP_FUNC_FULL_RENAME(uid_t*, sym_acl_free, acl_free_uid_tpp, NULL); +DEFINE_TRIVIAL_CLEANUP_FUNC_FULL_RENAME(gid_t*, sym_acl_free, acl_free_gid_tpp, NULL); #else + #define ACL_READ 0x04 #define ACL_WRITE 0x02 #define ACL_EXECUTE 0x01 +static inline int dlopen_libacl(void) { + return -EOPNOTSUPP; +} + static inline int devnode_acl(int fd, uid_t uid) { return -EOPNOTSUPP; } @@ -57,7 +87,6 @@ static inline int fd_acl_make_read_only(int 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/shared/meson.build b/src/shared/meson.build index 4b84dd9cea3..a734c868913 100644 --- a/src/shared/meson.build +++ b/src/shared/meson.build @@ -312,7 +312,7 @@ man_page_depends += ethtool_link_mode_xml libshared_name = 'systemd-shared-@0@'.format(shared_lib_tag) libshared_deps = [threads, - libacl, + libacl_cflags, libaudit_cflags, libblkid, libcap, diff --git a/src/shared/shift-uid.c b/src/shared/shift-uid.c index 2f34908fff5..f0353f2391d 100644 --- a/src/shared/shift-uid.c +++ b/src/shared/shift-uid.c @@ -7,6 +7,7 @@ #include "acl-util.h" #include "alloc-util.h" #include "dirent-util.h" +#include "errno-util.h" #include "fd-util.h" #include "fileio.h" #include "fs-util.h" @@ -36,11 +37,11 @@ static int get_acl(int fd, const char *name, acl_type_t type, acl_t *ret) { if (child_fd < 0) return -errno; - acl = acl_get_file(FORMAT_PROC_FD_PATH(child_fd), type); + acl = sym_acl_get_file(FORMAT_PROC_FD_PATH(child_fd), type); } else if (type == ACL_TYPE_ACCESS) - acl = acl_get_fd(fd); + acl = sym_acl_get_fd(fd); else - acl = acl_get_file(FORMAT_PROC_FD_PATH(fd), type); + acl = sym_acl_get_file(FORMAT_PROC_FD_PATH(fd), type); if (!acl) return -errno; @@ -61,11 +62,11 @@ static int set_acl(int fd, const char *name, acl_type_t type, acl_t acl) { if (child_fd < 0) return -errno; - r = acl_set_file(FORMAT_PROC_FD_PATH(child_fd), type, acl); + r = sym_acl_set_file(FORMAT_PROC_FD_PATH(child_fd), type, acl); } else if (type == ACL_TYPE_ACCESS) - r = acl_set_fd(fd, acl); + r = sym_acl_set_fd(fd, acl); else - r = acl_set_file(FORMAT_PROC_FD_PATH(fd), type, acl); + r = sym_acl_set_file(FORMAT_PROC_FD_PATH(fd), type, acl); if (r < 0) return -errno; @@ -80,7 +81,7 @@ static int shift_acl(acl_t acl, uid_t shift, acl_t *ret) { assert(acl); assert(ret); - r = acl_get_entry(acl, ACL_FIRST_ENTRY, &i); + r = sym_acl_get_entry(acl, ACL_FIRST_ENTRY, &i); if (r < 0) return -errno; while (r > 0) { @@ -88,7 +89,7 @@ static int shift_acl(acl_t acl, uid_t shift, acl_t *ret) { bool modify = false; acl_tag_t tag; - if (acl_get_tag_type(i, &tag) < 0) + if (sym_acl_get_tag_type(i, &tag) < 0) return -errno; if (IN_SET(tag, ACL_USER, ACL_GROUP)) { @@ -97,7 +98,7 @@ static int shift_acl(acl_t acl, uid_t shift, acl_t *ret) { * this is actually OK */ assert_cc(sizeof(uid_t) == sizeof(gid_t)); - old_uid = acl_get_qualifier(i); + old_uid = sym_acl_get_qualifier(i); if (!old_uid) return -errno; @@ -112,16 +113,16 @@ static int shift_acl(acl_t acl, uid_t shift, acl_t *ret) { /* There's no copy of the ACL yet? if so, let's create one, and start the loop from the * beginning, so that we copy all entries, starting from the first, this time. */ - n = acl_entries(acl); + n = sym_acl_entries(acl); if (n < 0) return -errno; - copy = acl_init(n); + copy = sym_acl_init(n); if (!copy) return -errno; /* Seek back to the beginning */ - r = acl_get_entry(acl, ACL_FIRST_ENTRY, &i); + r = sym_acl_get_entry(acl, ACL_FIRST_ENTRY, &i); if (r < 0) return -errno; continue; @@ -131,18 +132,18 @@ static int shift_acl(acl_t acl, uid_t shift, acl_t *ret) { if (copy) { acl_entry_t new_entry; - if (acl_create_entry(©, &new_entry) < 0) + if (sym_acl_create_entry(©, &new_entry) < 0) return -errno; - if (acl_copy_entry(new_entry, i) < 0) + if (sym_acl_copy_entry(new_entry, i) < 0) return -errno; if (modify) - if (acl_set_qualifier(new_entry, &new_uid) < 0) + if (sym_acl_set_qualifier(new_entry, &new_uid) < 0) return -errno; } - r = acl_get_entry(acl, ACL_NEXT_ENTRY, &i); + r = sym_acl_get_entry(acl, ACL_NEXT_ENTRY, &i); if (r < 0) return -errno; } @@ -164,6 +165,12 @@ static int patch_acls(int fd, const char *name, const struct stat *st, uid_t shi if (!inode_type_can_acl(st->st_mode)) return 0; + r = dlopen_libacl(); + if (ERRNO_IS_NEG_NOT_SUPPORTED(r)) + return 0; + if (r < 0) + return r; + r = get_acl(fd, name, ACL_TYPE_ACCESS, &acl); if (r == -EOPNOTSUPP) return 0; @@ -182,10 +189,10 @@ static int patch_acls(int fd, const char *name, const struct stat *st, uid_t shi } if (S_ISDIR(st->st_mode)) { - acl_free(acl); + sym_acl_free(acl); if (shifted) - acl_free(shifted); + sym_acl_free(shifted); acl = shifted = NULL; diff --git a/src/test/test-dlopen-so.c b/src/test/test-dlopen-so.c index ada19fdc66d..817ddde202a 100644 --- a/src/test/test-dlopen-so.c +++ b/src/test/test-dlopen-so.c @@ -1,5 +1,6 @@ /* SPDX-License-Identifier: LGPL-2.1-or-later */ +#include "acl-util.h" #include "apparmor-util.h" #include "bpf-dlopen.h" #include "compress.h" @@ -52,6 +53,7 @@ static int run(int argc, char **argv) { ASSERT_DLOPEN(dlopen_libapparmor, HAVE_APPARMOR); ASSERT_DLOPEN(dlopen_libaudit, HAVE_AUDIT); ASSERT_DLOPEN(dlopen_libpam, HAVE_PAM); + ASSERT_DLOPEN(dlopen_libacl, HAVE_ACL); return 0; } diff --git a/src/tmpfiles/meson.build b/src/tmpfiles/meson.build index a973d16f5c2..2e26d7b0dc3 100644 --- a/src/tmpfiles/meson.build +++ b/src/tmpfiles/meson.build @@ -17,7 +17,7 @@ executables += [ 'public' : true, 'sources' : systemd_tmpfiles_sources + systemd_tmpfiles_extract_sources, 'extract' : systemd_tmpfiles_extract_sources, - 'dependencies' : libacl, + 'dependencies' : libacl_cflags, }, executable_template + { 'name' : 'systemd-tmpfiles.standalone', @@ -30,7 +30,7 @@ executables += [ libshared_static, libsystemd_static, ], - 'dependencies' : libacl, + 'dependencies' : libacl_cflags, }, test_template + { 'sources' : files('test-offline-passwd.c'), diff --git a/src/tmpfiles/tmpfiles.c b/src/tmpfiles/tmpfiles.c index 42d67deebf6..981c6a51982 100644 --- a/src/tmpfiles/tmpfiles.c +++ b/src/tmpfiles/tmpfiles.c @@ -1271,22 +1271,26 @@ static int parse_acl_cond_exec( assert(cond_exec); assert(ret); + r = dlopen_libacl(); + if (r < 0) + return r; + if (!S_ISDIR(st->st_mode)) { _cleanup_(acl_freep) acl_t old = NULL; - old = acl_get_file(path, ACL_TYPE_ACCESS); + old = sym_acl_get_file(path, ACL_TYPE_ACCESS); if (!old) return -errno; has_exec = false; - for (r = acl_get_entry(old, ACL_FIRST_ENTRY, &entry); + for (r = sym_acl_get_entry(old, ACL_FIRST_ENTRY, &entry); r > 0; - r = acl_get_entry(old, ACL_NEXT_ENTRY, &entry)) { + r = sym_acl_get_entry(old, ACL_NEXT_ENTRY, &entry)) { acl_tag_t tag; - if (acl_get_tag_type(entry, &tag) < 0) + if (sym_acl_get_tag_type(entry, &tag) < 0) return -errno; if (tag == ACL_MASK) @@ -1296,10 +1300,10 @@ static int parse_acl_cond_exec( if (!append && IN_SET(tag, ACL_USER, ACL_GROUP)) continue; - if (acl_get_permset(entry, &permset) < 0) + if (sym_acl_get_permset(entry, &permset) < 0) return -errno; - r = acl_get_perm(permset, ACL_EXECUTE); + r = sym_acl_get_perm(permset, ACL_EXECUTE); if (r < 0) return -errno; if (r > 0) { @@ -1312,14 +1316,14 @@ static int parse_acl_cond_exec( /* Check if we're about to set the execute bit in acl_access */ if (!has_exec && access) { - for (r = acl_get_entry(access, ACL_FIRST_ENTRY, &entry); + for (r = sym_acl_get_entry(access, ACL_FIRST_ENTRY, &entry); r > 0; - r = acl_get_entry(access, ACL_NEXT_ENTRY, &entry)) { + r = sym_acl_get_entry(access, ACL_NEXT_ENTRY, &entry)) { - if (acl_get_permset(entry, &permset) < 0) + if (sym_acl_get_permset(entry, &permset) < 0) return -errno; - r = acl_get_perm(permset, ACL_EXECUTE); + r = sym_acl_get_perm(permset, ACL_EXECUTE); if (r < 0) return -errno; if (r > 0) { @@ -1333,28 +1337,28 @@ static int parse_acl_cond_exec( } else has_exec = true; - _cleanup_(acl_freep) acl_t parsed = access ? acl_dup(access) : acl_init(0); + _cleanup_(acl_freep) acl_t parsed = access ? sym_acl_dup(access) : sym_acl_init(0); if (!parsed) return -errno; - for (r = acl_get_entry(cond_exec, ACL_FIRST_ENTRY, &entry); + for (r = sym_acl_get_entry(cond_exec, ACL_FIRST_ENTRY, &entry); r > 0; - r = acl_get_entry(cond_exec, ACL_NEXT_ENTRY, &entry)) { + r = sym_acl_get_entry(cond_exec, ACL_NEXT_ENTRY, &entry)) { acl_entry_t parsed_entry; - if (acl_create_entry(&parsed, &parsed_entry) < 0) + if (sym_acl_create_entry(&parsed, &parsed_entry) < 0) return -errno; - if (acl_copy_entry(parsed_entry, entry) < 0) + if (sym_acl_copy_entry(parsed_entry, entry) < 0) return -errno; /* We substituted 'X' with 'x' in parse_acl(), so drop execute bit here if not applicable. */ if (!has_exec) { - if (acl_get_permset(parsed_entry, &permset) < 0) + if (sym_acl_get_permset(parsed_entry, &permset) < 0) return -errno; - if (acl_delete_perm(permset, ACL_EXECUTE) < 0) + if (sym_acl_delete_perm(permset, ACL_EXECUTE) < 0) return -errno; } } @@ -1386,6 +1390,10 @@ static int path_set_acl( assert(c); + r = dlopen_libacl(); + if (r < 0) + return r; + /* Returns 0 for success, positive error if already warned, negative error otherwise. */ if (modify) { @@ -1397,7 +1405,7 @@ static int path_set_acl( if (r < 0) return r; } else { - dup = acl_dup(acl); + dup = sym_acl_dup(acl); if (!dup) return -errno; @@ -1408,14 +1416,14 @@ static int path_set_acl( if (r < 0) return r; - t = acl_to_any_text(dup, NULL, ',', TEXT_ABBREVIATE); + t = sym_acl_to_any_text(dup, NULL, ',', TEXT_ABBREVIATE); log_action("Would set", "Setting", "%s %s ACL %s on %s", type == ACL_TYPE_ACCESS ? "access" : "default", strna(t), pretty); if (!arg_dry_run && - acl_set_file(path, type, dup) < 0) { + sym_acl_set_file(path, type, dup) < 0) { if (ERRNO_IS_NOT_SUPPORTED(errno)) /* No error if filesystem doesn't support ACLs. Return negative. */ return -errno; @@ -3295,13 +3303,13 @@ static void item_free_contents(Item *i) { #if HAVE_ACL if (i->acl_access) - acl_free(i->acl_access); + sym_acl_free(i->acl_access); if (i->acl_access_exec) - acl_free(i->acl_access_exec); + sym_acl_free(i->acl_access_exec); if (i->acl_default) - acl_free(i->acl_default); + sym_acl_free(i->acl_default); #endif } diff --git a/src/udev/meson.build b/src/udev/meson.build index 908bec8b1d3..b13b5d89792 100644 --- a/src/udev/meson.build +++ b/src/udev/meson.build @@ -114,7 +114,7 @@ endif ############################################################ udev_dependencies = [ - libacl, + libacl_cflags, libblkid, libkmod, threads, @@ -131,7 +131,7 @@ udev_plugin_template = executable_template + { udev_common_template = { 'objects' : ['udevadm'], 'dependencies' : [ - libacl, + libacl_cflags, libblkid, threads, ], -- 2.47.3