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. --- Makefile.am | 7 +++++++ configure.ac | 13 +++++++++++++ man/systemd.exec.xml | 13 +++++++++++++ src/core/build.h | 8 +++++++- src/core/dbus-execute.c | 1 + src/core/execute.c | 30 ++++++++++++++++++++++++++++++ src/core/execute.h | 2 ++ src/core/load-fragment-gperf.gperf.m4 | 3 ++- src/shared/exit-status.c | 3 +++ src/shared/exit-status.h | 3 ++- 10 files changed, 80 insertions(+), 3 deletions(-)
diff --git a/Makefile.am b/Makefile.am index 79c49e6..79d355c 100644 --- a/Makefile.am +++ b/Makefile.am @@ -776,6 +776,13 @@ libsystemd_shared_la_SOURCES += \ src/shared/seccomp-util.c endif +libsystemd_shared_la_CFLAGS = \ + $(AM_CFLAGS) \ + $(APPARMOR_CFLAGS) + +libsystemd_shared_la_LIBADD = \ + $(APPARMOR_LIBS) + # ------------------------------------------------------------------------------ noinst_LTLIBRARIES += \ libsystemd-units.la diff --git a/configure.ac b/configure.ac index 48d63e8..38dfa91 100644 --- a/configure.ac +++ b/configure.ac @@ -382,6 +382,18 @@ if test "x$enable_selinux" != "xno"; then fi AM_CONDITIONAL(HAVE_SELINUX, [test "$have_selinux" = "yes"]) +have_apparmor=no +AC_ARG_ENABLE(apparmor, AS_HELP_STRING([--disable-apparmor], [Disable optional AppArmor support])) +if test "x$enable_apparmor" != "xno"; then + PKG_CHECK_MODULES([APPARMOR], [libapparmor], + [AC_DEFINE(HAVE_APPARMOR, 1, [Define if AppArmor is available]) have_apparmor=yes], have_apparmor=no) + if test "x$have_apparmor" = xno -a "x$enable_apparmor" = xyes; then + AC_MSG_ERROR([*** AppArmor support requested but libraries not found]) + fi +fi +AM_CONDITIONAL(HAVE_APPARMOR, [test "$have_apparmor" = "yes"]) + + AC_ARG_WITH(debug-shell, AS_HELP_STRING([--with-debug-shell=PATH], [Path to debug shell binary]), @@ -1104,6 +1116,7 @@ AC_MSG_RESULT([ PAM: ${have_pam} AUDIT: ${have_audit} IMA: ${have_ima} + AppArmor: ${have_apparmor} SELinux: ${have_selinux} SECCOMP: ${have_seccomp} SMACK: ${have_smack} diff --git a/man/systemd.exec.xml b/man/systemd.exec.xml index 01356e4..262638d 100644 --- a/man/systemd.exec.xml +++ b/man/systemd.exec.xml @@ -968,6 +968,19 @@ </varlistentry> <varlistentry> + <term><varname>AppArmorProfile=</varname></term> + + <listitem><para>Take a profile name as argument. + The process executed by the unit will switch to + this profile when started. Profiles must already + be loaded in the kernel, or the unit will fail. + This result in a non operation if AppArmor is not + enabled. If prefixed by <literal>-</literal>, all errors + will be ignored. + </para></listitem> + </varlistentry> + + <varlistentry> <term><varname>IgnoreSIGPIPE=</varname></term> <listitem><para>Takes a boolean diff --git a/src/core/build.h b/src/core/build.h index f04f03f..3d7cd3e 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 a62f517..286ae7d 100644 --- a/src/core/dbus-execute.c +++ b/src/core/dbus-execute.c @@ -524,6 +524,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", "s", NULL, offsetof(ExecContext, selinux_context), SD_BUS_VTABLE_PROPERTY_CONST), + SD_BUS_PROPERTY("AppArmorProfile", "s", NULL, offsetof(ExecContext, apparmor_profile), 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 06ddd5c..8bf416a 100644 --- a/src/core/execute.c +++ b/src/core/execute.c @@ -54,6 +54,10 @@ #include <seccomp.h> #endif +#ifdef HAVE_APPARMOR +#include <sys/apparmor.h> +#endif + #include "execute.h" #include "strv.h" #include "macro.h" @@ -76,6 +80,7 @@ #include "async.h" #include "selinux-util.h" #include "errno-list.h" +#include "apparmor-util.h" #ifdef HAVE_SECCOMP #include "seccomp-util.h" @@ -1589,6 +1594,23 @@ int exec_spawn(ExecCommand *command, } } #endif + +#ifdef HAVE_APPARMOR + if (context->apparmor_profile && use_apparmor()) { + char* c = context->apparmor_profile; + bool ignore = false; + if (c[0] == '-') { + c++; + ignore = true; + } + + err = aa_change_onexec(context->apparmor_profile); + if (err < 0 && !ignore) { + r = EXIT_APPARMOR; + goto fail_child; + } + } +#endif } err = build_environment(context, n_fds, watchdog_usec, home, username, shell, &our_env); @@ -1750,6 +1772,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; @@ -2182,6 +2207,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\n", + prefix, 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 06b6b3f..b490faf 100644 --- a/src/core/execute.h +++ b/src/core/execute.h @@ -140,6 +140,8 @@ struct ExecContext { char *selinux_context; + 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 c8add14..532d5e2 100644 --- a/src/core/load-fragment-gperf.gperf.m4 +++ b/src/core/load-fragment-gperf.gperf.m4 @@ -83,7 +83,8 @@ $1.TCPWrapName, config_parse_unit_string_printf, 0, $1.PAMName, config_parse_unit_string_printf, 0, offsetof($1, exec_context.pam_name) $1.IgnoreSIGPIPE, config_parse_bool, 0, offsetof($1, exec_context.ignore_sigpipe) $1.UtmpIdentifier, config_parse_unit_string_printf, 0, offsetof($1, exec_context.utmp_id) -$1.SELinuxContext, config_parse_unit_string_printf, 0, offsetof($1, exec_context.selinux_context)' +$1.SELinuxContext, config_parse_unit_string_printf, 0, offsetof($1, exec_context.selinux_context) +$1.AppArmorProfile, config_parse_unit_string_printf, 0, offsetof($1, exec_context.apparmor_profile)' )m4_dnl m4_define(`KILL_CONTEXT_CONFIG_ITEMS', `$1.SendSIGKILL, config_parse_bool, 0, offsetof($1, kill_context.send_sigkill) diff --git a/src/shared/exit-status.c b/src/shared/exit-status.c index 70789f5..2f87779 100644 --- a/src/shared/exit-status.c +++ b/src/shared/exit-status.c @@ -133,6 +133,9 @@ const char* exit_status_to_string(ExitStatus status, ExitStatusLevel level) { case EXIT_SELINUX_CONTEXT: return "SELINUX_CONTEXT"; + + case EXIT_APPARMOR: + return "APPARMOR"; } } diff --git a/src/shared/exit-status.h b/src/shared/exit-status.h index e84bfe3..6ea0236 100644 --- a/src/shared/exit-status.h +++ b/src/shared/exit-status.h @@ -68,7 +68,8 @@ typedef enum ExitStatus { EXIT_NAMESPACE, EXIT_NO_NEW_PRIVILEGES, EXIT_SECCOMP, - EXIT_SELINUX_CONTEXT + EXIT_SELINUX_CONTEXT, + EXIT_APPARMOR /* 230 */ } ExitStatus; typedef enum ExitStatusLevel { -- 1.8.5.3 _______________________________________________ systemd-devel mailing list systemd-devel@lists.freedesktop.org http://lists.freedesktop.org/mailman/listinfo/systemd-devel