From d682b3a7e7c7c2941a4d3e193f1e330dbc9fae89 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Thu, 10 Oct 2013 16:35:44 +0200 Subject: [PATCH] security: rework selinux, smack, ima, apparmor detection logic Always cache the results, and bypass low-level security calls when the respective subsystem is not enabled. --- Makefile.am | 6 ++++- src/core/condition.c | 29 +++++++------------------ src/core/socket.c | 6 ++--- src/journal/journald-native.c | 11 ++++++---- src/journal/journald-server.c | 22 ++++++++++--------- src/journal/journald-stream.c | 7 ++++-- src/journal/journald-syslog.c | 11 ++++++---- src/shared/apparmor-util.c | 41 +++++++++++++++++++++++++++++++++++ src/shared/apparmor-util.h | 26 ++++++++++++++++++++++ src/shared/ima-util.c | 35 ++++++++++++++++++++++++++++++ src/shared/ima-util.h | 26 ++++++++++++++++++++++ src/shared/selinux-util.c | 9 ++++++++ src/shared/smack-util.c | 13 +++++++---- src/udev/udev-node.c | 5 +++-- 14 files changed, 196 insertions(+), 51 deletions(-) create mode 100644 src/shared/apparmor-util.c create mode 100644 src/shared/apparmor-util.h create mode 100644 src/shared/ima-util.c create mode 100644 src/shared/ima-util.h diff --git a/Makefile.am b/Makefile.am index be152e9b8..12c7d7cac 100644 --- a/Makefile.am +++ b/Makefile.am @@ -725,7 +725,11 @@ libsystemd_shared_la_SOURCES = \ src/shared/mkdir.c \ src/shared/mkdir.h \ src/shared/smack-util.c \ - src/shared/smack-util.h + src/shared/smack-util.h \ + src/shared/apparmor-util.c \ + src/shared/apparmor-util.h \ + src/shared/ima-util.c \ + src/shared/ima-util.h #------------------------------------------------------------------------------- noinst_LTLIBRARIES += \ diff --git a/src/core/condition.c b/src/core/condition.c index 6c387450a..c53d40668 100644 --- a/src/core/condition.c +++ b/src/core/condition.c @@ -27,10 +27,6 @@ #include #include -#ifdef HAVE_SELINUX -#include -#endif - #include #include "util.h" #include "condition.h" @@ -38,6 +34,10 @@ #include "path-util.h" #include "fileio.h" #include "unit.h" +#include "smack-util.h" +#include "apparmor-util.h" +#include "ima-util.h" +#include "selinux-util.h" Condition* condition_new(ConditionType type, const char *parameter, bool trigger, bool negate) { Condition *c; @@ -158,28 +158,15 @@ static bool test_virtualization(const char *parameter) { return v > 0 && streq(parameter, id); } -static bool test_apparmor_enabled(void) { - int r; - _cleanup_free_ char *p = NULL; - - r = read_one_line_file("/sys/module/apparmor/parameters/enabled", &p); - if (r < 0) - return false; - - return parse_boolean(p) > 0; -} - static bool test_security(const char *parameter) { -#ifdef HAVE_SELINUX if (streq(parameter, "selinux")) - return is_selinux_enabled() > 0; -#endif + return use_selinux(); if (streq(parameter, "apparmor")) - return test_apparmor_enabled(); + return use_apparmor(); if (streq(parameter, "ima")) - return access("/sys/kernel/security/ima/", F_OK) == 0; + return use_ima(); if (streq(parameter, "smack")) - return access("/sys/fs/smackfs", F_OK) == 0; + return use_smack(); return false; } diff --git a/src/core/socket.c b/src/core/socket.c index 6c0ac1a89..345601f0a 100644 --- a/src/core/socket.c +++ b/src/core/socket.c @@ -775,12 +775,12 @@ static void socket_apply_socket_options(Socket *s, int fd) { } #ifdef HAVE_SMACK - if (s->smack_ip_in) + if (s->smack_ip_in && use_smack()) if (fsetxattr(fd, "security.SMACK64IPIN", s->smack_ip_in, strlen(s->smack_ip_in), 0) < 0) log_error_unit(UNIT(s)->id, "fsetxattr(\"security.SMACK64IPIN\"): %m"); - if (s->smack_ip_out) + if (s->smack_ip_out && use_smack()) if (fsetxattr(fd, "security.SMACK64IPOUT", s->smack_ip_out, strlen(s->smack_ip_out), 0) < 0) log_error_unit(UNIT(s)->id, "fsetxattr(\"security.SMACK64IPOUT\"): %m"); @@ -797,7 +797,7 @@ static void socket_apply_fifo_options(Socket *s, int fd) { "F_SETPIPE_SZ: %m"); #ifdef HAVE_SMACK - if (s->smack) + if (s->smack && use_smack()) if (fsetxattr(fd, "security.SMACK64", s->smack, strlen(s->smack), 0) < 0) log_error_unit(UNIT(s)->id, "fsetxattr(\"security.SMACK64\"): %m"); diff --git a/src/journal/journald-native.c b/src/journal/journald-native.c index c50cf64f5..2c91cba16 100644 --- a/src/journal/journald-native.c +++ b/src/journal/journald-native.c @@ -25,6 +25,7 @@ #include "socket-util.h" #include "path-util.h" +#include "selinux-util.h" #include "journald-server.h" #include "journald-native.h" #include "journald-kmsg.h" @@ -404,10 +405,12 @@ int server_open_native_socket(Server*s) { } #ifdef HAVE_SELINUX - one = 1; - r = setsockopt(s->native_fd, SOL_SOCKET, SO_PASSSEC, &one, sizeof(one)); - if (r < 0) - log_warning("SO_PASSSEC failed: %m"); + if (use_selinux()) { + one = 1; + r = setsockopt(s->native_fd, SOL_SOCKET, SO_PASSSEC, &one, sizeof(one)); + if (r < 0) + log_warning("SO_PASSSEC failed: %m"); + } #endif one = 1; diff --git a/src/journal/journald-server.c b/src/journal/journald-server.c index e03e413ae..9732e1b25 100644 --- a/src/journal/journald-server.c +++ b/src/journal/journald-server.c @@ -629,19 +629,21 @@ static void dispatch_message_real( } #ifdef HAVE_SELINUX - if (label) { - x = alloca(sizeof("_SELINUX_CONTEXT=") + label_len); + if (use_selinux()) { + if (label) { + x = alloca(sizeof("_SELINUX_CONTEXT=") + label_len); - *((char*) mempcpy(stpcpy(x, "_SELINUX_CONTEXT="), label, label_len)) = 0; - IOVEC_SET_STRING(iovec[n++], x); - } else { - security_context_t con; + *((char*) mempcpy(stpcpy(x, "_SELINUX_CONTEXT="), label, label_len)) = 0; + IOVEC_SET_STRING(iovec[n++], x); + } else { + security_context_t con; - if (getpidcon(ucred->pid, &con) >= 0) { - x = strappenda("_SELINUX_CONTEXT=", con); + if (getpidcon(ucred->pid, &con) >= 0) { + x = strappenda("_SELINUX_CONTEXT=", con); - freecon(con); - IOVEC_SET_STRING(iovec[n++], x); + freecon(con); + IOVEC_SET_STRING(iovec[n++], x); + } } } #endif diff --git a/src/journal/journald-stream.c b/src/journal/journald-stream.c index 9c4efec9b..543614aea 100644 --- a/src/journal/journald-stream.c +++ b/src/journal/journald-stream.c @@ -29,6 +29,7 @@ #endif #include "socket-util.h" +#include "selinux-util.h" #include "journald-server.h" #include "journald-stream.h" #include "journald-syslog.h" @@ -381,8 +382,10 @@ int stdout_stream_new(Server *s) { } #ifdef HAVE_SELINUX - if (getpeercon(fd, &stream->security_context) < 0 && errno != ENOPROTOOPT) - log_error("Failed to determine peer security context: %m"); + if (use_selinux()) { + if (getpeercon(fd, &stream->security_context) < 0 && errno != ENOPROTOOPT) + log_error("Failed to determine peer security context: %m"); + } #endif if (shutdown(fd, SHUT_WR) < 0) { diff --git a/src/journal/journald-syslog.c b/src/journal/journald-syslog.c index c2770a53d..dc66ba8c8 100644 --- a/src/journal/journald-syslog.c +++ b/src/journal/journald-syslog.c @@ -25,6 +25,7 @@ #include "systemd/sd-messages.h" #include "socket-util.h" +#include "selinux-util.h" #include "journald-server.h" #include "journald-syslog.h" #include "journald-kmsg.h" @@ -453,10 +454,12 @@ int server_open_syslog_socket(Server *s) { } #ifdef HAVE_SELINUX - one = 1; - r = setsockopt(s->syslog_fd, SOL_SOCKET, SO_PASSSEC, &one, sizeof(one)); - if (r < 0) - log_warning("SO_PASSSEC failed: %m"); + if (use_selinux()) { + one = 1; + r = setsockopt(s->syslog_fd, SOL_SOCKET, SO_PASSSEC, &one, sizeof(one)); + if (r < 0) + log_warning("SO_PASSSEC failed: %m"); + } #endif one = 1; diff --git a/src/shared/apparmor-util.c b/src/shared/apparmor-util.c new file mode 100644 index 000000000..2b85da1e4 --- /dev/null +++ b/src/shared/apparmor-util.c @@ -0,0 +1,41 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +/*** + This file is part of systemd. + + Copyright 2013 Lennart Poettering + + 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 . +***/ + +#include + +#include "util.h" +#include "fileio.h" +#include "apparmor-util.h" + +static int use_apparmor_cached = -1; + +bool use_apparmor(void) { + + if (use_apparmor_cached < 0) { + _cleanup_free_ char *p = NULL; + + use_apparmor_cached = + read_one_line_file("/sys/module/apparmor/parameters/enabled", &p) >= 0 && + parse_boolean(p) > 0; + } + + return use_apparmor_cached; +} diff --git a/src/shared/apparmor-util.h b/src/shared/apparmor-util.h new file mode 100644 index 000000000..4b056a1aa --- /dev/null +++ b/src/shared/apparmor-util.h @@ -0,0 +1,26 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +#pragma once + +/*** + This file is part of systemd. + + Copyright 2013 Lennart Poettering + + 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 . +***/ + +#include + +bool use_apparmor(void); diff --git a/src/shared/ima-util.c b/src/shared/ima-util.c new file mode 100644 index 000000000..f0d3c926a --- /dev/null +++ b/src/shared/ima-util.c @@ -0,0 +1,35 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +/*** + This file is part of systemd. + + Copyright 2013 Lennart Poettering + + 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 . +***/ + +#include + +#include "apparmor-util.h" + + +static int use_ima_cached = -1; + +bool use_ima(void) { + + if (use_ima_cached < 0) + use_ima_cached = access("/sys/kernel/security/ima/", F_OK) >= 0; + + return use_ima_cached; +} diff --git a/src/shared/ima-util.h b/src/shared/ima-util.h new file mode 100644 index 000000000..d38216170 --- /dev/null +++ b/src/shared/ima-util.h @@ -0,0 +1,26 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +#pragma once + +/*** + This file is part of systemd. + + Copyright 2013 Lennart Poettering + + 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 . +***/ + +#include + +bool use_ima(void); diff --git a/src/shared/selinux-util.c b/src/shared/selinux-util.c index ff3375607..026ae5a9e 100644 --- a/src/shared/selinux-util.c +++ b/src/shared/selinux-util.c @@ -39,4 +39,13 @@ void retest_selinux(void) { use_selinux_cached = -1; } +#else + +bool use_selinux(void) { + return false; +} + +void retest_selinux(void) { +} + #endif diff --git a/src/shared/smack-util.c b/src/shared/smack-util.c index a73eaac6d..4e8cf796d 100644 --- a/src/shared/smack-util.c +++ b/src/shared/smack-util.c @@ -21,16 +21,21 @@ along with systemd; If not, see . ***/ -#include "smack-util.h" - #include -static int use_smack_cached = -1; +#include "smack-util.h" bool use_smack(void) { +#ifdef HAVE_SMACK + static int use_smack_cached = -1; + if (use_smack_cached < 0) - use_smack_cached = (access("/sys/fs/smackfs", F_OK) >= 0); + use_smack_cached = access("/sys/fs/smackfs/", F_OK) >= 0; return use_smack_cached; +#else + return false; +#endif + } diff --git a/src/udev/udev-node.c b/src/udev/udev-node.c index 187e24e5b..c5d629d1c 100644 --- a/src/udev/udev-node.c +++ b/src/udev/udev-node.c @@ -32,6 +32,7 @@ #include #endif +#include "smack-util.h" #include "udev.h" static int node_symlink(struct udev_device *dev, const char *node, const char *slink) @@ -311,7 +312,7 @@ static int node_permissions_apply(struct udev_device *dev, bool apply, log_debug("SECLABEL: set SELinux label '%s'", label); #ifdef HAVE_SMACK - } else if (streq(name, "smack")) { + } else if (streq(name, "smack") && use_smack()) { smack = true; if (lsetxattr(devnode, "security.SMACK64", label, strlen(label), 0) < 0) log_error("SECLABEL: failed to set SMACK label '%s'", label); @@ -327,7 +328,7 @@ static int node_permissions_apply(struct udev_device *dev, bool apply, if (!selinux) label_fix(devnode, true, false); #ifdef HAVE_SMACK - if (!smack) + if (!smack && use_smack()) lremovexattr(devnode, "security.SMACK64"); #endif } -- 2.30.2