diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/basic/selinux-util.c | 20 | ||||
-rw-r--r-- | src/basic/selinux-util.h | 1 | ||||
-rw-r--r-- | src/journal/journald-native.c | 2 | ||||
-rw-r--r-- | src/journal/journald-server.c | 59 | ||||
-rw-r--r-- | src/journal/journald-server.h | 1 | ||||
-rw-r--r-- | src/journal/journald-stream.c | 2 | ||||
-rw-r--r-- | src/journal/journald-syslog.c | 2 | ||||
-rw-r--r-- | src/libsystemd/sd-bus/bus-socket.c | 2 | ||||
-rw-r--r-- | src/shared/acl-util.c | 45 | ||||
-rw-r--r-- | src/shared/acl-util.h | 1 | ||||
-rw-r--r-- | src/shared/condition.c | 2 | ||||
-rw-r--r-- | src/systemd/_sd-common.h | 10 | ||||
-rw-r--r-- | src/test/test-acl-util.c | 85 | ||||
-rw-r--r-- | src/test/test-condition.c | 2 |
14 files changed, 161 insertions, 73 deletions
diff --git a/src/basic/selinux-util.c b/src/basic/selinux-util.c index e8ce5cfd96..7e4ae33efe 100644 --- a/src/basic/selinux-util.c +++ b/src/basic/selinux-util.c @@ -47,7 +47,7 @@ static struct selabel_handle *label_hnd = NULL; #define log_enforcing(...) log_full(security_getenforce() == 1 ? LOG_ERR : LOG_DEBUG, __VA_ARGS__) #endif -bool mac_selinux_use(void) { +bool mac_selinux_have(void) { #ifdef HAVE_SELINUX if (cached_use < 0) cached_use = is_selinux_enabled() > 0; @@ -58,6 +58,16 @@ bool mac_selinux_use(void) { #endif } +bool mac_selinux_use(void) { + if (!mac_selinux_have()) + return false; + + /* Never try to configure SELinux features if we aren't + * root */ + + return getuid() == 0; +} + void mac_selinux_retest(void) { #ifdef HAVE_SELINUX cached_use = -1; @@ -197,7 +207,7 @@ int mac_selinux_get_create_label_from_exe(const char *exe, char **label) { assert(exe); assert(label); - if (!mac_selinux_use()) + if (!mac_selinux_have()) return -EOPNOTSUPP; r = getcon_raw(&mycon); @@ -223,7 +233,7 @@ int mac_selinux_get_our_label(char **label) { assert(label); #ifdef HAVE_SELINUX - if (!mac_selinux_use()) + if (!mac_selinux_have()) return -EOPNOTSUPP; r = getcon_raw(label); @@ -247,7 +257,7 @@ int mac_selinux_get_child_mls_label(int socket_fd, const char *exe, const char * assert(exe); assert(label); - if (!mac_selinux_use()) + if (!mac_selinux_have()) return -EOPNOTSUPP; r = getcon_raw(&mycon); @@ -302,7 +312,7 @@ char* mac_selinux_free(char *label) { if (!label) return NULL; - if (!mac_selinux_use()) + if (!mac_selinux_have()) return NULL; diff --git a/src/basic/selinux-util.h b/src/basic/selinux-util.h index d19984c5fe..95a2fcdbca 100644 --- a/src/basic/selinux-util.h +++ b/src/basic/selinux-util.h @@ -27,6 +27,7 @@ #include "macro.h" bool mac_selinux_use(void); +bool mac_selinux_have(void); void mac_selinux_retest(void); int mac_selinux_init(const char *prefix); diff --git a/src/journal/journald-native.c b/src/journal/journald-native.c index 69a685c06f..371df5b37f 100644 --- a/src/journal/journald-native.c +++ b/src/journal/journald-native.c @@ -480,7 +480,7 @@ int server_open_native_socket(Server*s) { return log_error_errno(errno, "SO_PASSCRED failed: %m"); #ifdef HAVE_SELINUX - if (mac_selinux_use()) { + if (mac_selinux_have()) { r = setsockopt(s->native_fd, SOL_SOCKET, SO_PASSSEC, &one, sizeof(one)); if (r < 0) log_warning_errno(errno, "SO_PASSSEC failed: %m"); diff --git a/src/journal/journald-server.c b/src/journal/journald-server.c index 7d11a568aa..a8a9b72080 100644 --- a/src/journal/journald-server.c +++ b/src/journal/journald-server.c @@ -204,58 +204,19 @@ static int determine_space(Server *s, bool verbose, bool patch_min_use, uint64_t return determine_space_for(s, metrics, path, name, verbose, patch_min_use, available, limit); } -void server_fix_perms(Server *s, JournalFile *f, uid_t uid) { - int r; +static void server_add_acls(JournalFile *f, uid_t uid) { #ifdef HAVE_ACL - _cleanup_(acl_freep) acl_t acl = NULL; - acl_entry_t entry; - acl_permset_t permset; + int r; #endif - assert(f); - r = fchmod(f->fd, 0640); - if (r < 0) - log_warning_errno(errno, "Failed to fix access mode on %s, ignoring: %m", f->path); - #ifdef HAVE_ACL if (uid <= SYSTEM_UID_MAX) return; - acl = acl_get_fd(f->fd); - if (!acl) { - log_warning_errno(errno, "Failed to read ACL on %s, ignoring: %m", f->path); - return; - } - - 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) { - log_warning_errno(errno, "Failed to patch ACL on %s, ignoring: %m", f->path); - return; - } - } - - /* We do not recalculate the mask unconditionally here, - * so that the fchmod() mask above stays intact. */ - if (acl_get_permset(entry, &permset) < 0 || - acl_add_perm(permset, ACL_READ) < 0) { - log_warning_errno(errno, "Failed to patch ACL on %s, ignoring: %m", f->path); - return; - } - - r = calc_acl_mask_if_needed(&acl); - if (r < 0) { - log_warning_errno(r, "Failed to patch ACL on %s, ignoring: %m", f->path); - return; - } - - if (acl_set_fd(f->fd, acl) < 0) - log_warning_errno(errno, "Failed to set ACL on %s, ignoring: %m", f->path); - + r = add_acls_for_user(f->fd, uid); + if (r < 0) + log_warning_errno(r, "Failed to set ACL on %s, ignoring: %m", f->path); #endif } @@ -301,7 +262,7 @@ static JournalFile* find_journal(Server *s, uid_t uid) { if (r < 0) return s->system_journal; - server_fix_perms(s, f, uid); + server_add_acls(f, uid); r = ordered_hashmap_put(s->user_journals, UID_TO_PTR(uid), f); if (r < 0) { @@ -332,7 +293,7 @@ static int do_rotate( else log_error_errno(r, "Failed to create new %s journal: %m", name); else - server_fix_perms(s, *f, uid); + server_add_acls(*f, uid); return r; } @@ -707,7 +668,7 @@ static void dispatch_message_real( } #ifdef HAVE_SELINUX - if (mac_selinux_use()) { + if (mac_selinux_have()) { if (label) { x = alloca(strlen("_SELINUX_CONTEXT=") + label_len + 1); @@ -971,7 +932,7 @@ static int system_journal_open(Server *s, bool flush_requested) { fn = strjoina(fn, "/system.journal"); r = journal_file_open_reliably(fn, O_RDWR|O_CREAT, 0640, s->compress, s->seal, &s->system_metrics, s->mmap, NULL, &s->system_journal); if (r >= 0) { - server_fix_perms(s, s->system_journal, 0); + server_add_acls(s->system_journal, 0); (void) determine_space_for(s, &s->system_metrics, "/var/log/journal/", "System journal", true, true, NULL, NULL); } else if (r < 0) { if (r != -ENOENT && r != -EROFS) @@ -1015,7 +976,7 @@ static int system_journal_open(Server *s, bool flush_requested) { } if (s->runtime_journal) { - server_fix_perms(s, s->runtime_journal, 0); + server_add_acls(s->runtime_journal, 0); (void) determine_space_for(s, &s->runtime_metrics, "/run/log/journal/", "Runtime journal", true, true, NULL, NULL); } } diff --git a/src/journal/journald-server.h b/src/journal/journald-server.h index dcc21bb7c3..1822765228 100644 --- a/src/journal/journald-server.h +++ b/src/journal/journald-server.h @@ -174,7 +174,6 @@ int config_parse_split_mode(const char *unit, const char *filename, unsigned lin const char *split_mode_to_string(SplitMode s) _const_; SplitMode split_mode_from_string(const char *s) _pure_; -void server_fix_perms(Server *s, JournalFile *f, uid_t uid); int server_init(Server *s); void server_done(Server *s); void server_sync(Server *s); diff --git a/src/journal/journald-stream.c b/src/journal/journald-stream.c index 07a0f1bf41..131fcdac42 100644 --- a/src/journal/journald-stream.c +++ b/src/journal/journald-stream.c @@ -493,7 +493,7 @@ static int stdout_stream_install(Server *s, int fd, StdoutStream **ret) { if (r < 0) return log_error_errno(r, "Failed to determine peer credentials: %m"); - if (mac_selinux_use()) { + if (mac_selinux_have()) { r = getpeersec(fd, &stream->label); if (r < 0 && r != -EOPNOTSUPP) (void) log_warning_errno(r, "Failed to determine peer security context: %m"); diff --git a/src/journal/journald-syslog.c b/src/journal/journald-syslog.c index f3ac1a7ae0..cfc50d889b 100644 --- a/src/journal/journald-syslog.c +++ b/src/journal/journald-syslog.c @@ -415,7 +415,7 @@ int server_open_syslog_socket(Server *s) { return log_error_errno(errno, "SO_PASSCRED failed: %m"); #ifdef HAVE_SELINUX - if (mac_selinux_use()) { + if (mac_selinux_have()) { r = setsockopt(s->syslog_fd, SOL_SOCKET, SO_PASSSEC, &one, sizeof(one)); if (r < 0) log_warning_errno(errno, "SO_PASSSEC failed: %m"); diff --git a/src/libsystemd/sd-bus/bus-socket.c b/src/libsystemd/sd-bus/bus-socket.c index 25873dea1e..1df571ac92 100644 --- a/src/libsystemd/sd-bus/bus-socket.c +++ b/src/libsystemd/sd-bus/bus-socket.c @@ -609,7 +609,7 @@ static void bus_get_peercred(sd_bus *b) { b->ucred_valid = getpeercred(b->input_fd, &b->ucred) >= 0; /* Get the SELinux context of the peer */ - if (mac_selinux_use()) { + if (mac_selinux_have()) { r = getpeersec(b->input_fd, &b->label); if (r < 0 && r != -EOPNOTSUPP) log_debug_errno(r, "Failed to determine peer security context: %m"); diff --git a/src/shared/acl-util.c b/src/shared/acl-util.c index 35f2e1b67d..b4028564c2 100644 --- a/src/shared/acl-util.c +++ b/src/shared/acl-util.c @@ -71,6 +71,7 @@ int acl_find_uid(acl_t acl, uid_t uid, acl_entry_t *entry) { int calc_acl_mask_if_needed(acl_t *acl_p) { acl_entry_t i; int r; + bool need = false; assert(acl_p); @@ -85,17 +86,16 @@ int calc_acl_mask_if_needed(acl_t *acl_p) { if (tag == ACL_MASK) return 0; - if (IN_SET(tag, ACL_USER, ACL_GROUP)) { - if (acl_calc_mask(acl_p) < 0) - return -errno; - - return 1; - } + if (IN_SET(tag, ACL_USER, ACL_GROUP)) + need = true; } if (r < 0) return -errno; - return 0; + if (need && acl_calc_mask(acl_p) < 0) + return -errno; + + return need; } int add_base_acls_if_needed(acl_t *acl_p, const char *path) { @@ -398,3 +398,34 @@ int acls_for_file(const char *path, acl_type_t type, acl_t new, acl_t *acl) { old = NULL; return 0; } + +int add_acls_for_user(int fd, uid_t uid) { + _cleanup_(acl_freep) acl_t acl = NULL; + acl_entry_t entry; + acl_permset_t permset; + int r; + + acl = 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) + return -errno; + } + + /* We do not recalculate the mask unconditionally here, + * so that the fchmod() mask above stays intact. */ + if (acl_get_permset(entry, &permset) < 0 || + acl_add_perm(permset, ACL_READ) < 0) + return -errno; + + r = calc_acl_mask_if_needed(&acl); + if (r < 0) + return r; + + return acl_set_fd(fd, acl); +} diff --git a/src/shared/acl-util.h b/src/shared/acl-util.h index 256a6a5900..1d7f45e2a8 100644 --- a/src/shared/acl-util.h +++ b/src/shared/acl-util.h @@ -35,6 +35,7 @@ int add_base_acls_if_needed(acl_t *acl_p, const char *path); int acl_search_groups(const char* path, char ***ret_groups); int parse_acl(const char *text, acl_t *acl_access, acl_t *acl_default, bool want_mask); int acls_for_file(const char *path, acl_type_t type, acl_t new, acl_t *acl); +int add_acls_for_user(int fd, uid_t uid); /* acl_free takes multiple argument types. * Multiple cleanup functions are necessary. */ diff --git a/src/shared/condition.c b/src/shared/condition.c index a69719116c..14d18429b6 100644 --- a/src/shared/condition.c +++ b/src/shared/condition.c @@ -231,7 +231,7 @@ static int condition_test_security(Condition *c) { assert(c->type == CONDITION_SECURITY); if (streq(c->parameter, "selinux")) - return mac_selinux_use(); + return mac_selinux_have(); if (streq(c->parameter, "smack")) return mac_smack_use(); if (streq(c->parameter, "apparmor")) diff --git a/src/systemd/_sd-common.h b/src/systemd/_sd-common.h index 18765bff32..6b5e6c50f9 100644 --- a/src/systemd/_sd-common.h +++ b/src/systemd/_sd-common.h @@ -57,10 +57,10 @@ # ifdef __cplusplus # define _SD_BEGIN_DECLARATIONS \ extern "C" { \ - struct __useless_struct_to_allow_trailing_semicolon__ + struct _sd_useless_struct_to_allow_trailing_semicolon_ # else # define _SD_BEGIN_DECLARATIONS \ - struct __useless_struct_to_allow_trailing_semicolon__ + struct _sd_useless_struct_to_allow_trailing_semicolon_ # endif #endif @@ -68,10 +68,10 @@ # ifdef __cplusplus # define _SD_END_DECLARATIONS \ } \ - struct __useless_struct_to_allow_trailing_semicolon__ + struct _sd_useless_cpp_struct_to_allow_trailing_semicolon_ # else # define _SD_END_DECLARATIONS \ - struct __useless_struct_to_allow_trailing_semicolon__ + struct _sd_useless_struct_to_allow_trailing_semicolon_ # endif #endif @@ -80,6 +80,6 @@ if (*p) \ func(*p); \ } \ - struct __useless_struct_to_allow_trailing_semicolon__ + struct _sd_useless_struct_to_allow_trailing_semicolon_ #endif diff --git a/src/test/test-acl-util.c b/src/test/test-acl-util.c new file mode 100644 index 0000000000..bdea04d7f0 --- /dev/null +++ b/src/test/test-acl-util.c @@ -0,0 +1,85 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +/*** + This file is part of systemd. + + Copyright 2015 Zbigniew Jędrzejewski-Szmek + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see <http://www.gnu.org/licenses/>. +***/ + +#include <fcntl.h> +#include <stdlib.h> +#include <sys/stat.h> +#include <unistd.h> + +#include "acl-util.h" +#include "fd-util.h" +#include "fileio.h" +#include "string-util.h" +#include "user-util.h" + +static void test_add_acls_for_user(void) { + char fn[] = "/tmp/test-empty.XXXXXX"; + _cleanup_close_ int fd = -1; + char *cmd; + uid_t uid; + int r; + + fd = mkostemp_safe(fn, O_RDWR|O_CLOEXEC); + assert_se(fd >= 0); + + /* Use the mode that user journal files use */ + assert(fchmod(fd, 0640) == 0); + + cmd = strjoina("ls -l ", fn); + assert_se(system(cmd) == 0); + + cmd = strjoina("getfacl -p ", fn); + assert_se(system(cmd) == 0); + + if (getuid() == 0) { + const char *nobody = "nobody"; + r = get_user_creds(&nobody, &uid, NULL, NULL, NULL); + if (r < 0) + uid = 0; + } else + uid = getuid(); + + r = add_acls_for_user(fd, uid); + assert_se(r >= 0); + + cmd = strjoina("ls -l ", fn); + assert_se(system(cmd) == 0); + + cmd = strjoina("getfacl -p ", fn); + assert_se(system(cmd) == 0); + + /* set the acls again */ + + r = add_acls_for_user(fd, uid); + assert_se(r >= 0); + + cmd = strjoina("ls -l ", fn); + assert_se(system(cmd) == 0); + + cmd = strjoina("getfacl -p ", fn); + assert_se(system(cmd) == 0); + + unlink(fn); +} + +int main(int argc, char **argv) { + test_add_acls_for_user(); +} diff --git a/src/test/test-condition.c b/src/test/test-condition.c index f224c6cdd8..8903d10db7 100644 --- a/src/test/test-condition.c +++ b/src/test/test-condition.c @@ -203,7 +203,7 @@ static void test_condition_test_security(void) { condition_free(condition); condition = condition_new(CONDITION_SECURITY, "selinux", false, true); - assert_se(condition_test(condition) != mac_selinux_use()); + assert_se(condition_test(condition) != mac_selinux_have()); condition_free(condition); condition = condition_new(CONDITION_SECURITY, "ima", false, false); |