Also keep the SELinux class `service` in `mac_selinux_generic_access_check()` in the case no path is given. Previously this could mainly happen on a mask unit, which is fixed now. Changing the class, but keeping the permission, is unpleasant as the class `system` must otherwise define always all permissions of `service` and a unit operation resulting in a system class-based check is odd. The fallback target context remains the process context of systemd-pid1. --- src/core/dbus-manager.c | 37 +++++++++++++++++++++------------- src/core/manager.c | 7 +++++++ src/core/manager.h | 1 + src/core/selinux-access.c | 42 ++++++++++++++++++++++++++++++++++----- src/core/selinux-access.h | 28 +++++++++++++++++++++++--- src/core/unit.c | 4 +++- src/core/unit.h | 2 +- 7 files changed, 97 insertions(+), 24 deletions(-) diff --git a/src/core/dbus-manager.c b/src/core/dbus-manager.c index b866fd58b6..14085ba1a1 100644 --- a/src/core/dbus-manager.c +++ b/src/core/dbus-manager.c @@ -2063,14 +2063,20 @@ fail: } struct mac_callback_userdata { + struct mac_selinux_callback_userdata selinux; }; static int mac_callback_check(const char *name, void *userdata) { struct mac_callback_userdata *ud = userdata; + int r; assert(name); assert(ud); + r = mac_selinux_callback_check(name, &(ud->selinux)); + if (r < 0) + return r; + return 0; } @@ -2079,6 +2085,7 @@ static int method_enable_unit_files_generic( Manager *m, int (*call)(UnitFileScope scope, UnitFileFlags flags, const char *root_dir, char *files[], UnitFileChange **changes, size_t *n_changes, mac_callback_t mac_check, void *userdata), bool carries_install_info, + const char *mac_selinux_verb, sd_bus_error *error) { _cleanup_strv_free_ char **l = NULL; @@ -2086,7 +2093,7 @@ static int method_enable_unit_files_generic( size_t n_changes = 0; UnitFileFlags flags; int runtime, force, r; - struct mac_callback_userdata mcud = {}; + struct mac_callback_userdata mcud = { .selinux = { m, message, error, mac_selinux_verb } }; assert(message); assert(m); @@ -2115,15 +2122,15 @@ static int method_enable_unit_files_generic( } static int method_enable_unit_files(sd_bus_message *message, void *userdata, sd_bus_error *error) { - return method_enable_unit_files_generic(message, userdata, unit_file_enable, true, error); + return method_enable_unit_files_generic(message, userdata, unit_file_enable, true, MAC_SELINUX_UNIT_PERM_ENABLE, error); } static int method_reenable_unit_files(sd_bus_message *message, void *userdata, sd_bus_error *error) { - return method_enable_unit_files_generic(message, userdata, unit_file_reenable, true, error); + return method_enable_unit_files_generic(message, userdata, unit_file_reenable, true, MAC_SELINUX_UNIT_PERM_REENABLE, error); } static int method_link_unit_files(sd_bus_message *message, void *userdata, sd_bus_error *error) { - return method_enable_unit_files_generic(message, userdata, unit_file_link, false, error); + return method_enable_unit_files_generic(message, userdata, unit_file_link, false, MAC_SELINUX_UNIT_PERM_LINK, error); } static int unit_file_preset_without_mode(UnitFileScope scope, UnitFileFlags flags, const char *root_dir, char **files, UnitFileChange **changes, size_t *n_changes, mac_callback_t mac_check, void *userdata) { @@ -2131,11 +2138,11 @@ static int unit_file_preset_without_mode(UnitFileScope scope, UnitFileFlags flag } static int method_preset_unit_files(sd_bus_message *message, void *userdata, sd_bus_error *error) { - return method_enable_unit_files_generic(message, userdata, unit_file_preset_without_mode, true, error); + return method_enable_unit_files_generic(message, userdata, unit_file_preset_without_mode, true, MAC_SELINUX_UNIT_PERM_PRESET, error); } static int method_mask_unit_files(sd_bus_message *message, void *userdata, sd_bus_error *error) { - return method_enable_unit_files_generic(message, userdata, unit_file_mask, false, error); + return method_enable_unit_files_generic(message, userdata, unit_file_mask, false, MAC_SELINUX_UNIT_PERM_MASK, error); } static int method_preset_unit_files_with_mode(sd_bus_message *message, void *userdata, sd_bus_error *error) { @@ -2148,7 +2155,7 @@ static int method_preset_unit_files_with_mode(sd_bus_message *message, void *use int runtime, force, r; UnitFileFlags flags; const char *mode; - struct mac_callback_userdata mcud = {}; + struct mac_callback_userdata mcud = { .selinux = { m, message, error, MAC_SELINUX_UNIT_PERM_PRESET } }; assert(message); assert(m); @@ -2188,13 +2195,14 @@ static int method_disable_unit_files_generic( sd_bus_message *message, Manager *m, int (*call)(UnitFileScope scope, UnitFileFlags flags, const char *root_dir, char *files[], UnitFileChange **changes, size_t *n_changes, mac_callback_t mac_check, void *userdata), + const char *mac_selinux_verb, sd_bus_error *error) { _cleanup_strv_free_ char **l = NULL; UnitFileChange *changes = NULL; size_t n_changes = 0; int r, runtime; - struct mac_callback_userdata mcud = {}; + struct mac_callback_userdata mcud = { .selinux = { m, message, error, mac_selinux_verb } }; assert(message); assert(m); @@ -2221,11 +2229,11 @@ static int method_disable_unit_files_generic( } static int method_disable_unit_files(sd_bus_message *message, void *userdata, sd_bus_error *error) { - return method_disable_unit_files_generic(message, userdata, unit_file_disable, error); + return method_disable_unit_files_generic(message, userdata, unit_file_disable, MAC_SELINUX_UNIT_PERM_DISABLE, error); } static int method_unmask_unit_files(sd_bus_message *message, void *userdata, sd_bus_error *error) { - return method_disable_unit_files_generic(message, userdata, unit_file_unmask, error); + return method_disable_unit_files_generic(message, userdata, unit_file_unmask, MAC_SELINUX_UNIT_PERM_UNMASK, error); } static int method_revert_unit_files(sd_bus_message *message, void *userdata, sd_bus_error *error) { @@ -2234,7 +2242,7 @@ static int method_revert_unit_files(sd_bus_message *message, void *userdata, sd_ size_t n_changes = 0; Manager *m = userdata; int r; - struct mac_callback_userdata mcud = {}; + struct mac_callback_userdata mcud = { .selinux = { m, message, error, MAC_SELINUX_UNIT_PERM_REVERT } }; assert(message); assert(m); @@ -2295,7 +2303,7 @@ static int method_preset_all_unit_files(sd_bus_message *message, void *userdata, const char *mode; UnitFileFlags flags; int force, runtime, r; - struct mac_callback_userdata mcud = {}; + struct mac_callback_userdata mcud = { .selinux = { m, message, error, MAC_SELINUX_UNIT_PERM_PRESET } }; assert(message); assert(m); @@ -2340,7 +2348,7 @@ static int method_add_dependency_unit_files(sd_bus_message *message, void *userd char *target, *type; UnitDependency dep; UnitFileFlags flags; - struct mac_callback_userdata mcud = {}; + struct mac_callback_userdata mcud = { .selinux = { m, message, error, MAC_SELINUX_UNIT_PERM_ADDDEPENDENCY } }; assert(message); assert(m); @@ -2377,6 +2385,7 @@ static int method_add_dependency_unit_files(sd_bus_message *message, void *userd } static int method_get_unit_file_links(sd_bus_message *message, void *userdata, sd_bus_error *error) { + Manager *m = userdata; _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL; UnitFileChange *changes = NULL; size_t n_changes = 0, i; @@ -2384,7 +2393,7 @@ static int method_get_unit_file_links(sd_bus_message *message, void *userdata, s const char *name; char **p; int runtime, r; - struct mac_callback_userdata mcud = {}; + struct mac_callback_userdata mcud = { .selinux = { m, message, error, MAC_SELINUX_UNIT_PERM_STATUS } }; r = mac_selinux_access_check(message, "status", error); if (r < 0) diff --git a/src/core/manager.c b/src/core/manager.c index 0b6ef09924..0f69ba12fd 100644 --- a/src/core/manager.c +++ b/src/core/manager.c @@ -1868,6 +1868,13 @@ Unit *manager_get_unit(Manager *m, const char *name) { return hashmap_get(m->units, name); } +const char *manager_get_unitpath(Manager *m, const char *name) { + assert(m); + assert(name); + + return hashmap_get(m->unit_id_map, name); +} + static int manager_dispatch_target_deps_queue(Manager *m) { Unit *u; unsigned k; diff --git a/src/core/manager.h b/src/core/manager.h index fb1a29d88c..acd3762744 100644 --- a/src/core/manager.h +++ b/src/core/manager.h @@ -452,6 +452,7 @@ int manager_startup(Manager *m, FILE *serialization, FDSet *fds); Job *manager_get_job(Manager *m, uint32_t id); Unit *manager_get_unit(Manager *m, const char *name); +const char *manager_get_unitpath(Manager *m, const char *name); int manager_get_job_from_dbus_path(Manager *m, const char *s, Job **_j); diff --git a/src/core/selinux-access.c b/src/core/selinux-access.c index 4500e4452f..d3b89c1d7a 100644 --- a/src/core/selinux-access.c +++ b/src/core/selinux-access.c @@ -168,6 +168,33 @@ static int access_init(sd_bus_error *error) { return 1; } +int mac_selinux_callback_check( + const char *name, + struct mac_selinux_callback_userdata *userdata) { + const Unit *u; + const char *path = NULL; + + assert(name); + assert(userdata); + assert(userdata->m); + assert(userdata->message); + assert(userdata->error); + assert(userdata->permission); + + if (!mac_selinux_use()) + return 0; + + u = manager_get_unit(userdata->m, name); + if (u) + path = unit_label_path(u); + + /* maybe the unit is not loaded, e.g. a disabled user session unit */ + if (!path) + path = manager_get_unitpath(userdata->m, name); + + return mac_selinux_generic_access_check(userdata->message, path, MAC_SELINUX_CLASS_UNIT, userdata->permission, userdata->error); +} + /* This function communicates with the kernel to check whether or not it should allow the access. @@ -177,11 +204,12 @@ static int access_init(sd_bus_error *error) { int mac_selinux_generic_access_check( sd_bus_message *message, const char *path, + const char *tclass, const char *permission, sd_bus_error *error) { _cleanup_(sd_bus_creds_unrefp) sd_bus_creds *creds = NULL; - const char *tclass = NULL, *scon = NULL; + const char *scon = NULL; struct audit_info audit_info = {}; _cleanup_free_ char *cl = NULL; char *fcon = NULL; @@ -227,8 +255,6 @@ int mac_selinux_generic_access_check( r = sd_bus_error_setf(error, SD_BUS_ERROR_ACCESS_DENIED, "Failed to get file context on %s.", path); goto finish; } - - tclass = "service"; } else { r = getcon_raw(&fcon); if (r < 0) { @@ -236,8 +262,6 @@ int mac_selinux_generic_access_check( r = sd_bus_error_setf(error, SD_BUS_ERROR_ACCESS_DENIED, "Failed to get current context."); goto finish; } - - tclass = "system"; } sd_bus_creds_get_cmdline(creds, &cmdline); @@ -269,10 +293,18 @@ finish: int mac_selinux_generic_access_check( sd_bus_message *message, const char *path, + const char *tclass, const char *permission, sd_bus_error *error) { return 0; } +int mac_selinux_callback_check( + const char *name, + struct mac_selinux_callback_userdata *userdata) { + + return 0; +} + #endif diff --git a/src/core/selinux-access.h b/src/core/selinux-access.h index 1e75930f57..cfdeded59b 100644 --- a/src/core/selinux-access.h +++ b/src/core/selinux-access.h @@ -6,15 +6,37 @@ #include "bus-util.h" #include "manager.h" -int mac_selinux_generic_access_check(sd_bus_message *message, const char *path, const char *permission, sd_bus_error *error); +#define MAC_SELINUX_CLASS_SYSTEM "system" +#define MAC_SELINUX_CLASS_UNIT "service" + +#define MAC_SELINUX_UNIT_PERM_ADDDEPENDENCY "modify" +#define MAC_SELINUX_UNIT_PERM_DISABLE "disable" +#define MAC_SELINUX_UNIT_PERM_ENABLE "enable" +#define MAC_SELINUX_UNIT_PERM_LINK "enable" +#define MAC_SELINUX_UNIT_PERM_MASK "disable" +#define MAC_SELINUX_UNIT_PERM_PRESET "modify" +#define MAC_SELINUX_UNIT_PERM_REENABLE "enable" +#define MAC_SELINUX_UNIT_PERM_REVERT "modify" +#define MAC_SELINUX_UNIT_PERM_STATUS "status" +#define MAC_SELINUX_UNIT_PERM_UNMASK "enable" + +struct mac_selinux_callback_userdata { + Manager *m; + sd_bus_message *message; + sd_bus_error *error; + const char *permission; +}; +int mac_selinux_callback_check(const char *name, struct mac_selinux_callback_userdata *userdata); + +int mac_selinux_generic_access_check(sd_bus_message *message, const char *path, const char *tclass, const char *permission, sd_bus_error *error); #if HAVE_SELINUX #define mac_selinux_access_check(message, permission, error) \ - mac_selinux_generic_access_check((message), NULL, (permission), (error)) + mac_selinux_generic_access_check((message), NULL, MAC_SELINUX_CLASS_SYSTEM, (permission), (error)) #define mac_selinux_unit_access_check(unit, message, permission, error) \ - mac_selinux_generic_access_check((message), unit_label_path(unit), (permission), (error)) + mac_selinux_generic_access_check((message), unit_label_path(unit), MAC_SELINUX_CLASS_UNIT, (permission), (error)) #else diff --git a/src/core/unit.c b/src/core/unit.c index f9b299c8a4..1d5c702020 100644 --- a/src/core/unit.c +++ b/src/core/unit.c @@ -5703,9 +5703,11 @@ bool unit_needs_console(Unit *u) { return exec_context_may_touch_console(ec); } -const char *unit_label_path(Unit *u) { +const char *unit_label_path(const Unit *u) { const char *p; + assert(u); + /* Returns the file system path to use for MAC access decisions, i.e. the file to read the SELinux label off * when validating access checks. */ diff --git a/src/core/unit.h b/src/core/unit.h index 5dac251d74..821c7b3c84 100644 --- a/src/core/unit.h +++ b/src/core/unit.h @@ -839,7 +839,7 @@ int unit_warn_leftover_processes(Unit *u); bool unit_needs_console(Unit *u); -const char *unit_label_path(Unit *u); +const char *unit_label_path(const Unit *u); int unit_pid_attachable(Unit *unit, pid_t pid, sd_bus_error *error); -- 2.24.1