summaryrefslogtreecommitdiff
path: root/src/core/selinux-access.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/core/selinux-access.c')
-rw-r--r--src/core/selinux-access.c125
1 files changed, 47 insertions, 78 deletions
diff --git a/src/core/selinux-access.c b/src/core/selinux-access.c
index e9a9a020de..2b96a9551b 100644
--- a/src/core/selinux-access.c
+++ b/src/core/selinux-access.c
@@ -1,5 +1,3 @@
-/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
-
/***
This file is part of systemd.
@@ -23,21 +21,25 @@
#ifdef HAVE_SELINUX
-#include <stdio.h>
#include <errno.h>
-#include <selinux/selinux.h>
#include <selinux/avc.h>
+#include <selinux/selinux.h>
+#include <stdio.h>
#ifdef HAVE_AUDIT
#include <libaudit.h>
#endif
#include "sd-bus.h"
+
+#include "alloc-util.h"
+#include "audit-fd.h"
#include "bus-util.h"
-#include "util.h"
#include "log.h"
+#include "path-util.h"
#include "selinux-util.h"
-#include "audit-fd.h"
+#include "stdio-util.h"
#include "strv.h"
+#include "util.h"
static bool initialized = false;
@@ -108,6 +110,7 @@ static int callback_type_to_priority(int type) {
*/
_printf_(2, 3) static int log_callback(int type, const char *fmt, ...) {
va_list ap;
+ const char *fmt2;
#ifdef HAVE_AUDIT
int fd;
@@ -129,63 +132,47 @@ _printf_(2, 3) static int log_callback(int type, const char *fmt, ...) {
}
#endif
+ fmt2 = strjoina("selinux: ", fmt);
+
va_start(ap, fmt);
- log_internalv(LOG_AUTH | callback_type_to_priority(type),
- 0, __FILE__, __LINE__, __FUNCTION__, fmt, ap);
+ log_internalv(LOG_AUTH | callback_type_to_priority(type), 0, __FILE__, __LINE__, __FUNCTION__, fmt2, ap);
va_end(ap);
return 0;
}
-/*
- Function must be called once to initialize the SELinux AVC environment.
- Sets up callbacks.
- If you want to cleanup memory you should need to call selinux_access_finish.
-*/
-static int access_init(void) {
- int r = 0;
-
- if (avc_open(NULL, 0))
- return log_error_errno(errno, "avc_open() failed: %m");
+static int access_init(sd_bus_error *error) {
- selinux_set_callback(SELINUX_CB_AUDIT, (union selinux_callback) audit_callback);
- selinux_set_callback(SELINUX_CB_LOG, (union selinux_callback) log_callback);
-
- if (security_getenforce() < 0){
- r = -errno;
- avc_destroy();
- }
-
- return r;
-}
-
-static int mac_selinux_access_init(sd_bus_error *error) {
- int r;
+ if (!mac_selinux_use())
+ return 0;
if (initialized)
- return 0;
+ return 1;
- if (!mac_selinux_use())
- return 0;
+ if (avc_open(NULL, 0) != 0) {
+ int enforce, saved_errno = errno;
- r = access_init();
- if (r < 0)
- return sd_bus_error_set(error, SD_BUS_ERROR_ACCESS_DENIED, "Failed to initialize SELinux.");
+ enforce = security_getenforce();
+ log_full_errno(enforce != 0 ? LOG_ERR : LOG_WARNING, saved_errno, "Failed to open the SELinux AVC: %m");
- initialized = true;
- return 0;
-}
-#endif
+ /* If enforcement isn't on, then let's suppress this
+ * error, and just don't do any AVC checks. The
+ * warning we printed is hence all the admin will
+ * see. */
+ if (enforce == 0)
+ return 0;
-void mac_selinux_access_free(void) {
+ /* Return an access denied error, if we couldn't load
+ * the AVC but enforcing mode was on, or we couldn't
+ * determine whether it is one. */
+ return sd_bus_error_setf(error, SD_BUS_ERROR_ACCESS_DENIED, "Failed to open the SELinux AVC: %s", strerror(saved_errno));
+ }
-#ifdef HAVE_SELINUX
- if (!initialized)
- return;
+ selinux_set_callback(SELINUX_CB_AUDIT, (union selinux_callback) audit_callback);
+ selinux_set_callback(SELINUX_CB_LOG, (union selinux_callback) log_callback);
- avc_destroy();
- initialized = false;
-#endif
+ initialized = true;
+ return 1;
}
/*
@@ -200,12 +187,11 @@ int mac_selinux_generic_access_check(
const char *permission,
sd_bus_error *error) {
-#ifdef HAVE_SELINUX
- _cleanup_bus_creds_unref_ sd_bus_creds *creds = NULL;
+ _cleanup_(sd_bus_creds_unrefp) sd_bus_creds *creds = NULL;
const char *tclass = NULL, *scon = NULL;
struct audit_info audit_info = {};
_cleanup_free_ char *cl = NULL;
- security_context_t fcon = NULL;
+ char *fcon = NULL;
char **cmdline = NULL;
int r = 0;
@@ -213,11 +199,8 @@ int mac_selinux_generic_access_check(
assert(permission);
assert(error);
- if (!mac_selinux_use())
- return 0;
-
- r = mac_selinux_access_init(error);
- if (r < 0)
+ r = access_init(error);
+ if (r <= 0)
return r;
r = sd_bus_query_sender_creds(
@@ -245,7 +228,7 @@ int mac_selinux_generic_access_check(
if (path) {
/* Get the file context of the unit file */
- r = getfilecon(path, &fcon);
+ r = getfilecon_raw(path, &fcon);
if (r < 0) {
r = sd_bus_error_setf(error, SD_BUS_ERROR_ACCESS_DENIED, "Failed to get file context on %s.", path);
goto finish;
@@ -253,7 +236,7 @@ int mac_selinux_generic_access_check(
tclass = "service";
} else {
- r = getcon(&fcon);
+ r = getcon_raw(&fcon);
if (r < 0) {
r = sd_bus_error_setf(error, SD_BUS_ERROR_ACCESS_DENIED, "Failed to get current context.");
goto finish;
@@ -284,31 +267,17 @@ finish:
}
return r;
-#else
- return 0;
-#endif
}
-int mac_selinux_unit_access_check_strv(
- char **units,
+#else
+
+int mac_selinux_generic_access_check(
sd_bus_message *message,
- Manager *m,
+ const char *path,
const char *permission,
sd_bus_error *error) {
-#ifdef HAVE_SELINUX
- char **i;
- Unit *u;
- int r;
-
- STRV_FOREACH(i, units) {
- u = manager_get_unit(m, *i);
- if (u) {
- r = mac_selinux_unit_access_check(u, message, permission, error);
- if (r < 0)
- return r;
- }
- }
-#endif
return 0;
}
+
+#endif