From: "Christian Göttsche" <cgzones@googlemail.com>
To: selinux@vger.kernel.org
Subject: [PATCH SYSTEMD 5/7] core: implement the sd-bus generic callback for SELinux
Date: Thu, 5 Aug 2021 16:24:43 +0200 [thread overview]
Message-ID: <20210805142445.61725-6-cgzones@googlemail.com> (raw)
In-Reply-To: <20210805142445.61725-1-cgzones@googlemail.com>
---
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
next prev parent reply other threads:[~2021-08-05 14:26 UTC|newest]
Thread overview: 9+ messages / expand[flat|nested] mbox.gz Atom feed top
2021-08-05 14:24 [PATCH SYSTEMD 0/7] Re-add SELinux checks for unit install operations Christian Göttsche
2021-08-05 14:24 ` [PATCH SYSTEMD 1/7] selinux: add function name to audit data Christian Göttsche
2021-08-05 14:24 ` [PATCH SYSTEMD 2/7] selinux: improve debug log format Christian Göttsche
2021-08-05 14:24 ` [PATCH SYSTEMD 3/7] selinux: mark _mac_selinux_generic_access_check with leading underscore Christian Göttsche
2021-08-05 14:24 ` [PATCH SYSTEMD 4/7] core: add support for MAC checks on unit install operations Christian Göttsche
2021-08-05 14:24 ` Christian Göttsche [this message]
2021-08-05 14:24 ` [PATCH SYSTEMD 6/7] core: avoid bypasses in D-BUS SELinux filter Christian Göttsche
2021-08-05 14:24 ` [PATCH SYSTEMD 7/7] core: tweak job_type_to_access_method SELinux permissions Christian Göttsche
2021-08-05 15:08 ` [PATCH SYSTEMD 0/7] Re-add SELinux checks for unit install operations Dominick Grift
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20210805142445.61725-6-cgzones@googlemail.com \
--to=cgzones@googlemail.com \
--cc=selinux@vger.kernel.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox