--- src/core/dbus-callbackdata.h | 10 ++++++ src/core/dbus-manager.c | 45 +++++++++++++++++---------- src/core/manager.c | 7 +++++ src/core/manager.h | 1 + src/core/selinux-access.c | 53 ++++++++++++++++++++++++++++++- src/core/selinux-access.h | 7 +++++ src/shared/install.c | 60 ++++++++++++++++++++++++++++++++++++ src/shared/install.h | 2 ++ 8 files changed, 168 insertions(+), 17 deletions(-) diff --git a/src/core/dbus-callbackdata.h b/src/core/dbus-callbackdata.h index 7dedb680c0..400c3bc481 100644 --- a/src/core/dbus-callbackdata.h +++ b/src/core/dbus-callbackdata.h @@ -1,5 +1,15 @@ /* SPDX-License-Identifier: LGPL-2.1-or-later */ #pragma once +#include "sd-bus.h" + +#include "manager.h" + typedef struct MacUnitCallbackUserdata { + Manager *manager; + sd_bus_message *message; + sd_bus_error *error; + const char *func; + + const char *selinux_permission; } MacUnitCallbackUserdata; diff --git a/src/core/dbus-manager.c b/src/core/dbus-manager.c index eec358cb6b..66cc276f8f 100644 --- a/src/core/dbus-manager.c +++ b/src/core/dbus-manager.c @@ -2187,10 +2187,15 @@ fail: static int mac_unit_callback_check(const char *unit_name, void *userdata) { MacUnitCallbackUserdata *ud = userdata; + int r; assert(unit_name); assert(ud); + r = mac_selinux_unit_callback_check(unit_name, ud); + if (r < 0) + return r; + return 0; } @@ -2199,6 +2204,8 @@ 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_permission, + const char *func, sd_bus_error *error) { _cleanup_strv_free_ char **l = NULL; @@ -2206,7 +2213,7 @@ static int method_enable_unit_files_generic( size_t n_changes = 0; UnitFileFlags flags; int r; - MacUnitCallbackUserdata mcud = {}; + MacUnitCallbackUserdata mcud = { m, message, error, func, mac_selinux_permission }; assert(message); assert(m); @@ -2247,19 +2254,19 @@ static int method_enable_unit_files_generic( } static int method_enable_unit_files_with_flags(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, "enable", __func__, error); } 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, "enable", __func__, 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, "enable", __func__, 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, "enable", __func__, 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) { @@ -2267,11 +2274,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, "reload", __func__, 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, "disable", __func__, error); } static int method_preset_unit_files_with_mode(sd_bus_message *message, void *userdata, sd_bus_error *error) { @@ -2284,7 +2291,7 @@ static int method_preset_unit_files_with_mode(sd_bus_message *message, void *use int runtime, force, r; UnitFileFlags flags; const char *mode; - MacUnitCallbackUserdata mcud = {}; + MacUnitCallbackUserdata mcud = { m, message, error, __func__, "reload" }; assert(message); assert(m); @@ -2324,6 +2331,8 @@ 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_permissions, + const char *func, sd_bus_error *error) { _cleanup_strv_free_ char **l = NULL; @@ -2331,7 +2340,7 @@ static int method_disable_unit_files_generic( UnitFileFlags flags; size_t n_changes = 0; int r; - MacUnitCallbackUserdata mcud = {}; + MacUnitCallbackUserdata mcud = { m, message, error, func, mac_selinux_permissions }; assert(message); assert(m); @@ -2373,15 +2382,15 @@ static int method_disable_unit_files_generic( } static int method_disable_unit_files_with_flags(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, "disable", __func__, error); } 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, "disable", __func__, 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, "enable", __func__, error); } static int method_revert_unit_files(sd_bus_message *message, void *userdata, sd_bus_error *error) { @@ -2390,7 +2399,7 @@ static int method_revert_unit_files(sd_bus_message *message, void *userdata, sd_ size_t n_changes = 0; Manager *m = userdata; int r; - MacUnitCallbackUserdata mcud = {}; + MacUnitCallbackUserdata mcud = { m, message, error, __func__, "reload" }; assert(message); assert(m); @@ -2451,7 +2460,7 @@ static int method_preset_all_unit_files(sd_bus_message *message, void *userdata, const char *mode; UnitFileFlags flags; int force, runtime, r; - MacUnitCallbackUserdata mcud = {}; + MacUnitCallbackUserdata mcud = { m, message, error, __func__, "reload" }; assert(message); assert(m); @@ -2496,7 +2505,7 @@ static int method_add_dependency_unit_files(sd_bus_message *message, void *userd char *target, *type; UnitDependency dep; UnitFileFlags flags; - MacUnitCallbackUserdata mcud = {}; + MacUnitCallbackUserdata mcud = { m, message, error, __func__, "reload" }; assert(message); assert(m); @@ -2529,6 +2538,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; @@ -2536,7 +2546,10 @@ static int method_get_unit_file_links(sd_bus_message *message, void *userdata, s const char *name; char **p; int runtime, r; - MacUnitCallbackUserdata mcud = {}; + MacUnitCallbackUserdata mcud = { m, message, error, __func__, "status" }; + + assert(message); + assert(m); r = sd_bus_message_read(message, "sb", &name, &runtime); if (r < 0) diff --git a/src/core/manager.c b/src/core/manager.c index 952bc57036..f9bd2636fa 100644 --- a/src/core/manager.c +++ b/src/core/manager.c @@ -1977,6 +1977,13 @@ Unit *manager_get_unit(Manager *m, const char *name) { return hashmap_get(m->units, name); } +const char *manager_lookup_unit_label_path(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; int r = 0; diff --git a/src/core/manager.h b/src/core/manager.h index 284ea42a9d..42a345c9a7 100644 --- a/src/core/manager.h +++ b/src/core/manager.h @@ -474,6 +474,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_lookup_unit_label_path(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 180fe22773..82a0feffb4 100644 --- a/src/core/selinux-access.c +++ b/src/core/selinux-access.c @@ -16,11 +16,14 @@ #include "alloc-util.h" #include "audit-fd.h" #include "bus-util.h" +#include "dbus-callbackdata.h" #include "errno-util.h" #include "format-util.h" +#include "install.h" #include "log.h" #include "path-util.h" #include "selinux-util.h" +#include "stat-util.h" #include "stdio-util.h" #include "strv.h" #include "util.h" @@ -284,6 +287,47 @@ int _mac_selinux_generic_access_check( return enforce ? r : 0; } +int mac_selinux_unit_callback_check( + const char *unit_name, + const MacUnitCallbackUserdata *userdata) { + + const Unit *u; + const char *path = NULL; + _cleanup_free_ char *path_lookup = NULL; + + assert(unit_name); + assert(userdata); + assert(userdata->manager); + assert(userdata->message); + assert(userdata->error); + assert(userdata->func); + + if (!mac_selinux_use()) + return 0; + + if (!userdata->selinux_permission) + return 0; + + u = manager_get_unit(userdata->manager, unit_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_lookup_unit_label_path(userdata->manager, unit_name); + + /* try to search for a unit path and do not base the check on a masked path, e.g. /dev/null */ + if (!path || null_or_empty_path(path) > 0) + (void) unit_file_label_path(userdata->manager->unit_file_scope, NULL, unit_name, &path_lookup); + + return _mac_selinux_generic_access_check( + userdata->message, + path_lookup ?: path, + userdata->selinux_permission, + userdata->error, + userdata->func); +} + #else /* HAVE_SELINUX */ int _mac_selinux_generic_access_check( @@ -296,4 +340,11 @@ int _mac_selinux_generic_access_check( return 0; } -#endif /* HAVE_SELINUX */ +int mac_selinux_unit_callback_check( + const char *unit_name, + const MacUnitCallbackUserdata *userdata) { + + return 0; +} + +#endif diff --git a/src/core/selinux-access.h b/src/core/selinux-access.h index 8a5582997a..65eb643462 100644 --- a/src/core/selinux-access.h +++ b/src/core/selinux-access.h @@ -5,6 +5,9 @@ #include "manager.h" +/* forward declaration */ +typedef struct MacUnitCallbackUserdata MacUnitCallbackUserdata; + int _mac_selinux_generic_access_check(sd_bus_message *message, const char *path, const char *permission, @@ -16,3 +19,7 @@ int _mac_selinux_generic_access_check(sd_bus_message *message, #define mac_selinux_unit_access_check(unit, message, permission, error) \ _mac_selinux_generic_access_check((message), unit_label_path(unit), (permission), (error), __func__) + +int mac_selinux_unit_callback_check( + const char *unit_name, + const MacUnitCallbackUserdata *userdata); diff --git a/src/shared/install.c b/src/shared/install.c index f1e603fecf..0eab706724 100644 --- a/src/shared/install.c +++ b/src/shared/install.c @@ -3559,6 +3559,66 @@ int unit_file_get_list( return 0; } +int unit_file_label_path( + UnitFileScope scope, + const char *root_dir, + const char *name, + char **ret_path) { + + _cleanup_(lookup_paths_free) LookupPaths paths = {}; + char **dirname; + int r; + + assert(scope >= 0); + assert(scope < _UNIT_FILE_SCOPE_MAX); + assert(name); + assert_return(unit_name_is_valid(name, UNIT_NAME_ANY), -EINVAL); + assert(ret_path); + + r = lookup_paths_init(&paths, scope, 0, root_dir); + if (r < 0) + return r; + + STRV_FOREACH(dirname, paths.search_path) { + _cleanup_closedir_ DIR *d = NULL; + const struct dirent *de; + + d = opendir(*dirname); + if (!d) { + if (errno == ENOENT) + continue; + if (IN_SET(errno, ENOTDIR, EACCES)) { + log_debug_errno(errno, "Failed to open \"%s\": %m", *dirname); + continue; + } + + return -errno; + } + + FOREACH_DIRENT(de, d, return -errno) { + _cleanup_free_ char *p = NULL; + + if (!IN_SET(de->d_type, DT_LNK, DT_REG)) + continue; + + if (!streq(de->d_name, name)) + continue; + + p = path_join(*dirname, de->d_name); + if (!p) + return -ENOMEM; + + if (null_or_empty_path(p)) + continue; + + *ret_path = TAKE_PTR(p); + return 0; + } + } + + return -ENOENT; +} + static const char* const unit_file_state_table[_UNIT_FILE_STATE_MAX] = { [UNIT_FILE_ENABLED] = "enabled", [UNIT_FILE_ENABLED_RUNTIME] = "enabled-runtime", diff --git a/src/shared/install.h b/src/shared/install.h index 96896f0548..e03422c65a 100644 --- a/src/shared/install.h +++ b/src/shared/install.h @@ -208,6 +208,8 @@ int unit_file_lookup_state( int unit_file_get_state(UnitFileScope scope, const char *root_dir, const char *filename, UnitFileState *ret); int unit_file_exists(UnitFileScope scope, const LookupPaths *paths, const char *name); +int unit_file_label_path(UnitFileScope scope, const char *root_dir, const char *name, char **ret_path); + int unit_file_get_list(UnitFileScope scope, const char *root_dir, Hashmap *h, char **states, char **patterns); Hashmap* unit_file_list_free(Hashmap *h); -- 2.32.0