[systemd-devel] [PATCH] Add AppArmor profile switching

Michael Scherer misc at zarb.org
Fri Feb 14 03:21:23 PST 2014


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



More information about the systemd-devel mailing list