1
0
mirror of https://github.com/systemd/systemd synced 2025-10-06 00:13:24 +02:00

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.
This commit is contained in:
Lennart Poettering
2025-09-23 11:46:49 +02:00
parent ab2b430487
commit 7c3a7f925f
9 changed files with 276 additions and 141 deletions

View 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'))

View 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;

View 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);

View 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,

View 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;

View 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;
}

View 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'),

View 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
}

View 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,
],