diff options
author | Michael Scherer <misc@zarb.org> | 2014-02-20 16:19:44 +0100 |
---|---|---|
committer | Lennart Poettering <lennart@poettering.net> | 2014-02-21 03:44:20 +0100 |
commit | eef65bf3ee6f73afa4a5de23ae3a794a279f30c0 (patch) | |
tree | 366b91cc8b993595fec85469317e1351c98d8ee7 /src | |
parent | 37f78db2f4a33474fc349f406b0a0a48e9c573a2 (diff) |
core: Add AppArmor profile switching
This permit to switch to a specific apparmor profile when starting a daemon. This
will result in a non operation if apparmor is disabled.
It also add a new build requirement on libapparmor for using this feature.
Diffstat (limited to 'src')
-rw-r--r-- | src/core/build.h | 8 | ||||
-rw-r--r-- | src/core/dbus-execute.c | 19 | ||||
-rw-r--r-- | src/core/execute.c | 23 | ||||
-rw-r--r-- | src/core/execute.h | 3 | ||||
-rw-r--r-- | src/core/load-fragment-gperf.gperf.m4 | 5 | ||||
-rw-r--r-- | src/core/load-fragment.c | 53 | ||||
-rw-r--r-- | src/core/load-fragment.h | 1 | ||||
-rw-r--r-- | src/shared/exit-status.c | 3 | ||||
-rw-r--r-- | src/shared/exit-status.h | 3 |
9 files changed, 113 insertions, 5 deletions
diff --git a/src/core/build.h b/src/core/build.h index c8117edff3..3d7cd3ea39 100644 --- a/src/core/build.h +++ b/src/core/build.h @@ -45,6 +45,12 @@ #define _SELINUX_FEATURE_ "-SELINUX" #endif +#ifdef HAVE_APPARMOR +#define _APPARMOR_FEATURE_ "+APPARMOR" +#else +#define _APPARMOR_FEATURE_ "-APPARMOR" +#endif + #ifdef HAVE_IMA #define _IMA_FEATURE_ "+IMA" #else @@ -87,4 +93,4 @@ #define _SECCOMP_FEATURE_ "-SECCOMP" #endif -#define SYSTEMD_FEATURES _PAM_FEATURE_ " " _LIBWRAP_FEATURE_ " " _AUDIT_FEATURE_ " " _SELINUX_FEATURE_ " " _IMA_FEATURE_ " " _SYSVINIT_FEATURE_ " " _LIBCRYPTSETUP_FEATURE_ " " _GCRYPT_FEATURE_ " " _ACL_FEATURE_ " " _XZ_FEATURE_ " " _SECCOMP_FEATURE_ +#define SYSTEMD_FEATURES _PAM_FEATURE_ " " _LIBWRAP_FEATURE_ " " _AUDIT_FEATURE_ " " _SELINUX_FEATURE_ " " _IMA_FEATURE_ " " _SYSVINIT_FEATURE_ " " _LIBCRYPTSETUP_FEATURE_ " " _GCRYPT_FEATURE_ " " _ACL_FEATURE_ " " _XZ_FEATURE_ " " _SECCOMP_FEATURE_ " " _APPARMOR_FEATURE_ diff --git a/src/core/dbus-execute.c b/src/core/dbus-execute.c index 41dbbab904..935c62bdf2 100644 --- a/src/core/dbus-execute.c +++ b/src/core/dbus-execute.c @@ -482,6 +482,24 @@ static int property_get_selinux_context( return sd_bus_message_append(reply, "(bs)", c->selinux_context_ignore, c->selinux_context); } +static int property_get_apparmor_profile( + sd_bus *bus, + const char *path, + const char *interface, + const char *property, + sd_bus_message *reply, + void *userdata, + sd_bus_error *error) { + + ExecContext *c = userdata; + + assert(bus); + assert(reply); + assert(c); + + return sd_bus_message_append(reply, "(bs)", c->apparmor_profile_ignore, c->apparmor_profile); +} + static int property_get_personality( sd_bus *bus, const char *path, @@ -560,6 +578,7 @@ const sd_bus_vtable bus_exec_vtable[] = { SD_BUS_PROPERTY("SameProcessGroup", "b", bus_property_get_bool, offsetof(ExecContext, same_pgrp), SD_BUS_VTABLE_PROPERTY_CONST), SD_BUS_PROPERTY("UtmpIdentifier", "s", NULL, offsetof(ExecContext, utmp_id), SD_BUS_VTABLE_PROPERTY_CONST), SD_BUS_PROPERTY("SELinuxContext", "(bs)", property_get_selinux_context, 0, SD_BUS_VTABLE_PROPERTY_CONST), + SD_BUS_PROPERTY("AppArmorProfile", "(bs)", property_get_apparmor_profile, 0, SD_BUS_VTABLE_PROPERTY_CONST), SD_BUS_PROPERTY("IgnoreSIGPIPE", "b", bus_property_get_bool, offsetof(ExecContext, ignore_sigpipe), SD_BUS_VTABLE_PROPERTY_CONST), SD_BUS_PROPERTY("NoNewPrivileges", "b", bus_property_get_bool, offsetof(ExecContext, no_new_privileges), SD_BUS_VTABLE_PROPERTY_CONST), SD_BUS_PROPERTY("SystemCallFilter", "(bas)", property_get_syscall_filter, 0, SD_BUS_VTABLE_PROPERTY_CONST), diff --git a/src/core/execute.c b/src/core/execute.c index f8b7521ff9..a328fc265f 100644 --- a/src/core/execute.c +++ b/src/core/execute.c @@ -55,6 +55,10 @@ #include <seccomp.h> #endif +#ifdef HAVE_APPARMOR +#include <sys/apparmor.h> +#endif + #include "execute.h" #include "strv.h" #include "macro.h" @@ -77,6 +81,7 @@ #include "async.h" #include "selinux-util.h" #include "errno-list.h" +#include "apparmor-util.h" #ifdef HAVE_SECCOMP #include "seccomp-util.h" @@ -1597,6 +1602,16 @@ int exec_spawn(ExecCommand *command, } } #endif + +#ifdef HAVE_APPARMOR + if (context->apparmor_profile && use_apparmor()) { + err = aa_change_onexec(context->apparmor_profile); + if (err < 0 && !context->apparmor_profile_ignore) { + r = EXIT_APPARMOR_PROFILE; + goto fail_child; + } + } +#endif } err = build_environment(context, n_fds, watchdog_usec, home, username, shell, &our_env); @@ -1759,6 +1774,9 @@ void exec_context_done(ExecContext *c) { free(c->selinux_context); c->selinux_context = NULL; + free(c->apparmor_profile); + c->apparmor_profile = NULL; + #ifdef HAVE_SECCOMP set_free(c->syscall_filter); c->syscall_filter = NULL; @@ -2188,6 +2206,11 @@ void exec_context_dump(ExecContext *c, FILE* f, const char *prefix) { fprintf(f, "%sSystemCallErrorNumber: %s\n", prefix, strna(errno_to_name(c->syscall_errno))); + + if (c->apparmor_profile) + fprintf(f, + "%sAppArmorProfile: %s%s\n", + prefix, c->apparmor_profile_ignore ? "-" : "", c->apparmor_profile); } void exec_status_start(ExecStatus *s, pid_t pid) { diff --git a/src/core/execute.h b/src/core/execute.h index 5c4c0b4abe..2bfe227145 100644 --- a/src/core/execute.h +++ b/src/core/execute.h @@ -141,6 +141,9 @@ struct ExecContext { bool selinux_context_ignore; char *selinux_context; + bool apparmor_profile_ignore; + char *apparmor_profile; + char **read_write_dirs, **read_only_dirs, **inaccessible_dirs; unsigned long mount_flags; diff --git a/src/core/load-fragment-gperf.gperf.m4 b/src/core/load-fragment-gperf.gperf.m4 index e9995bf0c7..e1bab7a264 100644 --- a/src/core/load-fragment-gperf.gperf.m4 +++ b/src/core/load-fragment-gperf.gperf.m4 @@ -90,7 +90,10 @@ $1.IgnoreSIGPIPE, config_parse_bool, 0, $1.UtmpIdentifier, config_parse_unit_string_printf, 0, offsetof($1, exec_context.utmp_id) m4_ifdef(`HAVE_SELINUX', `$1.SELinuxContext, config_parse_exec_selinux_context, 0, offsetof($1, exec_context)', -`$1.SELinuxContext, config_parse_warn_compat, 0, 0')' +`$1.SELinuxContext, config_parse_warn_compat, 0, 0') +m4_ifdef(`HAVE_APPARMOR', +`$1.AppArmorProfile, config_parse_exec_apparmor_profile,0, offsetof($1, exec_context)', +`$1.AppArmorProfile, config_parse_warn_compat, 0, 0')' )m4_dnl m4_define(`KILL_CONTEXT_CONFIG_ITEMS', `$1.SendSIGKILL, config_parse_bool, 0, offsetof($1, kill_context.send_sigkill) diff --git a/src/core/load-fragment.c b/src/core/load-fragment.c index 27666b937c..e74a790e25 100644 --- a/src/core/load-fragment.c +++ b/src/core/load-fragment.c @@ -61,7 +61,7 @@ #include "seccomp-util.h" #endif -#if !defined(HAVE_SYSV_COMPAT) || !defined(HAVE_SECCOMP) || !defined(HAVE_LIBWRAP) || !defined(HAVE_PAM) || !defined(HAVE_SELINUX) || !defined(HAVE_SMACK) +#if !defined(HAVE_SYSV_COMPAT) || !defined(HAVE_SECCOMP) || !defined(HAVE_LIBWRAP) || !defined(HAVE_PAM) || !defined(HAVE_SELINUX) || !defined(HAVE_SMACK) || !defined(HAVE_APPARMOR) int config_parse_warn_compat( const char *unit, const char *filename, @@ -1192,6 +1192,55 @@ int config_parse_exec_selinux_context( return 0; } +int config_parse_exec_apparmor_profile( + const char *unit, + const char *filename, + unsigned line, + const char *section, + unsigned section_line, + const char *lvalue, + int ltype, + const char *rvalue, + void *data, + void *userdata) { + + ExecContext *c = data; + Unit *u = userdata; + bool ignore; + char *k; + int r; + + assert(filename); + assert(lvalue); + assert(rvalue); + assert(data); + + if (isempty(rvalue)) { + free(c->apparmor_profile); + c->apparmor_profile = NULL; + c->apparmor_profile_ignore = false; + return 0; + } + + if (rvalue[0] == '-') { + ignore = true; + rvalue++; + } else + ignore = false; + + r = unit_name_printf(u, rvalue, &k); + if (r < 0) { + log_syntax(unit, LOG_ERR, filename, line, -r, "Failed to resolve specifiers, ignoring: %s", strerror(-r)); + return 0; + } + + free(c->apparmor_profile); + c->apparmor_profile = k; + c->apparmor_profile_ignore = ignore; + + return 0; +} + int config_parse_timer(const char *unit, const char *filename, unsigned line, @@ -2910,7 +2959,7 @@ void unit_dump_config_items(FILE *f) { const ConfigParserCallback callback; const char *rvalue; } table[] = { -#if !defined(HAVE_SYSV_COMPAT) || !defined(HAVE_SECCOMP) || !defined(HAVE_LIBWRAP) || !defined(HAVE_PAM) || !defined(HAVE_SELINUX) || !defined(HAVE_SMACK) +#if !defined(HAVE_SYSV_COMPAT) || !defined(HAVE_SECCOMP) || !defined(HAVE_LIBWRAP) || !defined(HAVE_PAM) || !defined(HAVE_SELINUX) || !defined(HAVE_SMACK) || !defined(HAVE_APPARMOR) { config_parse_warn_compat, "NOTSUPPORTED" }, #endif { config_parse_int, "INTEGER" }, diff --git a/src/core/load-fragment.h b/src/core/load-fragment.h index 83ecea5da1..4a5ec35cbe 100644 --- a/src/core/load-fragment.h +++ b/src/core/load-fragment.h @@ -89,6 +89,7 @@ int config_parse_job_mode(const char *unit, const char *filename, unsigned line, int config_parse_job_mode_isolate(const char *unit, const char *filename, unsigned line, const char *section, unsigned section_line, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata); int config_parse_exec_selinux_context(const char *unit, const char *filename, unsigned line, const char *section, unsigned section_line, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata); int config_parse_personality(const char *unit, const char *filename, unsigned line, const char *section, unsigned section_line, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata); +int config_parse_exec_apparmor_profile(const char *unit, const char *filename, unsigned line, const char *section, unsigned section_line, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata); /* gperf prototypes */ const struct ConfigPerfItem* load_fragment_gperf_lookup(const char *key, unsigned length); diff --git a/src/shared/exit-status.c b/src/shared/exit-status.c index 8b096da7e1..902f55ac65 100644 --- a/src/shared/exit-status.c +++ b/src/shared/exit-status.c @@ -136,6 +136,9 @@ const char* exit_status_to_string(ExitStatus status, ExitStatusLevel level) { case EXIT_PERSONALITY: return "PERSONALITY"; + + case EXIT_APPARMOR_PROFILE: + return "APPARMOR"; } } diff --git a/src/shared/exit-status.h b/src/shared/exit-status.h index dde5bdda8b..de379f1aa0 100644 --- a/src/shared/exit-status.h +++ b/src/shared/exit-status.h @@ -69,7 +69,8 @@ typedef enum ExitStatus { EXIT_NO_NEW_PRIVILEGES, EXIT_SECCOMP, EXIT_SELINUX_CONTEXT, - EXIT_PERSONALITY /* 230 */ + EXIT_PERSONALITY, /* 230 */ + EXIT_APPARMOR_PROFILE } ExitStatus; typedef enum ExitStatusLevel { |