]> git.ipfire.org Git - thirdparty/systemd.git/commitdiff
acl: turn libacl dep into a dlopen() one 39087/head
authorLennart Poettering <lennart@poettering.net>
Tue, 23 Sep 2025 09:46:49 +0000 (11:46 +0200)
committerLennart Poettering <lennart@poettering.net>
Wed, 24 Sep 2025 07:47:41 +0000 (09:47 +0200)
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
src/shared/acl-util.c
src/shared/acl-util.h
src/shared/meson.build
src/shared/shift-uid.c
src/test/test-dlopen-so.c
src/tmpfiles/meson.build
src/tmpfiles/tmpfiles.c
src/udev/meson.build

index 15e1d3821ed9265fefd57c6fd05cbd6ee66f1830..afd2342488fd0c7a14aa1abda8714a7638a8b577 100644 (file)
@@ -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'))
index 0a5c8c9f921e4da6dd6d81e1e11b67ae5aa4eae6..554d4738213a1c8ba8da6310fd2662e2e604b273 100644 (file)
@@ -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;
 
index 3e23fe393856048242195694218075ac3fc92af4..54eba92f38e76f4166cbec688b96289e2eb9ce9a 100644 (file)
@@ -10,6 +10,35 @@ int fd_acl_make_writable_fallback(int fd);
 #include <acl/libacl.h> /* IWYU pragma: export */
 #include <sys/acl.h>    /* 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);
index 4b84dd9cea3bd392b86b061099ab9f843f2ec594..a734c868913a5644e691823fbf4f2c102aca19c2 100644 (file)
@@ -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,
index 2f34908fff577a0c1762ba461eb80ea5097ed907..f0353f2391db9684632256252ce01f049a6feaf4 100644 (file)
@@ -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(&copy, &new_entry) < 0)
+                        if (sym_acl_create_entry(&copy, &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;
 
index ada19fdc66d6f4527bf1fc80d925578572da6e17..817ddde202a9bae92a2c4141ff25b5279db44bef 100644 (file)
@@ -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;
 }
index a973d16f5c260d5298c176add53fea23997684b7..2e26d7b0dc396be158280efcf95ef66437fb26b9 100644 (file)
@@ -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'),
index 42d67deebf654ca49b4b2823999ce8ba5d19517e..981c6a51982b086821dca425904850d5f5bd2a8e 100644 (file)
@@ -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
 }
 
index 908bec8b1d3293c262c384fe777397ee78a9a8aa..b13b5d897929308532c744a56255513f173da1fd 100644 (file)
@@ -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,
         ],