[systemd-devel] [PATCH] smack: introduce new SmackLabelExec option

WaLyong Cho walyong.cho at samsung.com
Tue Nov 4 00:35:42 PST 2014


In case of systemd has "_" label and run as root, if a service file
has "User=" option and the command line file has a special SMACK label
then systemd will fail to execute the command. Generally, SMACK label
is ignored for the root. But if a service has a "User=" then systemd
will call setresuid() in the child process. After then it no more
root. So it should have some of executable label for the command. To
set the SMACK64EXEC before the uid is changed introduce new
SmackLabelExec option.
---
 man/systemd.exec.xml                  |  9 +++++++
 src/core/dbus-execute.c               | 19 +++++++++++++
 src/core/execute.c                    | 14 ++++++++++
 src/core/execute.h                    |  3 +++
 src/core/load-fragment-gperf.gperf.m4 |  7 +++--
 src/core/load-fragment.c              | 50 +++++++++++++++++++++++++++++++++++
 src/core/load-fragment.h              |  1 +
 src/shared/exit-status.h              |  1 +
 src/shared/smack-util.c               | 26 ++++++++++++++++++
 src/shared/smack-util.h               |  1 +
 10 files changed, 129 insertions(+), 2 deletions(-)

diff --git a/man/systemd.exec.xml b/man/systemd.exec.xml
index e9af4ab..27e6fae 100644
--- a/man/systemd.exec.xml
+++ b/man/systemd.exec.xml
@@ -1138,6 +1138,15 @@
                         </varlistentry>
 
                         <varlistentry>
+                                <term><varname>SmackLabelExec=</varname></term>
+
+                                <listitem><para>Set the SMACK security
+                                label of the executed process. This directive is ignored if SMACK is
+                                disabled. 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/dbus-execute.c b/src/core/dbus-execute.c
index 9276da4..5c56824 100644
--- a/src/core/dbus-execute.c
+++ b/src/core/dbus-execute.c
@@ -508,6 +508,24 @@ static int property_get_apparmor_profile(
         return sd_bus_message_append(reply, "(bs)", c->apparmor_profile_ignore, c->apparmor_profile);
 }
 
+static int property_get_smack_exec_label(
+                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->smack_exec_label_ignore, c->smack_exec_label);
+}
+
 static int property_get_personality(
                 sd_bus *bus,
                 const char *path,
@@ -636,6 +654,7 @@ const sd_bus_vtable bus_exec_vtable[] = {
         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("SmackLabelExec", "(bs)", property_get_smack_exec_label, 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 c41aec2..5222aee 100644
--- a/src/core/execute.c
+++ b/src/core/execute.c
@@ -90,6 +90,10 @@
 #include "seccomp-util.h"
 #endif
 
+#ifdef HAVE_SMACK
+#include "smack-util.h"
+#endif
+
 #define IDLE_TIMEOUT_USEC (5*USEC_PER_SEC)
 #define IDLE_TIMEOUT2_USEC (1*USEC_PER_SEC)
 
@@ -1617,6 +1621,16 @@ static int exec_child(ExecCommand *command,
                         }
                 }
 
+#ifdef HAVE_SMACK
+                if (context->smack_exec_label) {
+                        err = mac_smack_apply_pid(0, context->smack_exec_label);
+                        if (err < 0) {
+                                *error = EXIT_SMACK_LABEL;
+                                return err;
+                        }
+                }
+#endif
+
                 if (context->user) {
                         err = enforce_user(context, uid);
                         if (err < 0) {
diff --git a/src/core/execute.h b/src/core/execute.h
index c45dde5..e6b9122 100644
--- a/src/core/execute.h
+++ b/src/core/execute.h
@@ -142,6 +142,9 @@ struct ExecContext {
         bool apparmor_profile_ignore;
         char *apparmor_profile;
 
+        bool smack_exec_label_ignore;
+        char *smack_exec_label;
+
         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 ca01394..b424ff8 100644
--- a/src/core/load-fragment-gperf.gperf.m4
+++ b/src/core/load-fragment-gperf.gperf.m4
@@ -95,8 +95,11 @@ m4_ifdef(`HAVE_SELINUX',
 `$1.SELinuxContext,              config_parse_exec_selinux_context,  0,                             offsetof($1, exec_context)',
 `$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')'
+`$1.AppArmorProfile,             config_parse_exec_apparmor_profile, 0,                             offsetof($1, exec_context)',
+`$1.AppArmorProfile,             config_parse_warn_compat,           0,                             0')
+m4_ifdef(`HAVE_SMACK',
+`$1.SmackLabelExec,              config_parse_exec_smack_exec_label, 0,                             offsetof($1, exec_context)',
+`$1.SmackLabelExec,              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 e193a67..a58f279 100644
--- a/src/core/load-fragment.c
+++ b/src/core/load-fragment.c
@@ -1313,6 +1313,56 @@ int config_parse_exec_apparmor_profile(
         return 0;
 }
 
+int config_parse_exec_smack_exec_label(
+                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->smack_exec_label);
+                c->smack_exec_label = NULL;
+                c->smack_exec_label_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->smack_exec_label);
+        c->smack_exec_label = k;
+        c->smack_exec_label_ignore = ignore;
+
+        return 0;
+}
+
 int config_parse_timer(const char *unit,
                        const char *filename,
                        unsigned line,
diff --git a/src/core/load-fragment.h b/src/core/load-fragment.h
index 65100c9..deca84a 100644
--- a/src/core/load-fragment.h
+++ b/src/core/load-fragment.h
@@ -94,6 +94,7 @@ int config_parse_job_mode_isolate(const char *unit, const char *filename, unsign
 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);
+int config_parse_exec_smack_exec_label(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_address_families(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_runtime_directory(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_set_status(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);
diff --git a/src/shared/exit-status.h b/src/shared/exit-status.h
index f719580..1f8f9d1 100644
--- a/src/shared/exit-status.h
+++ b/src/shared/exit-status.h
@@ -78,6 +78,7 @@ typedef enum ExitStatus {
         EXIT_MAKE_STARTER,
         EXIT_CHOWN,
         EXIT_BUS_ENDPOINT,
+        EXIT_SMACK_LABEL,
 } ExitStatus;
 
 typedef enum ExitStatusLevel {
diff --git a/src/shared/smack-util.c b/src/shared/smack-util.c
index a8dccd1..7467911 100644
--- a/src/shared/smack-util.c
+++ b/src/shared/smack-util.c
@@ -25,6 +25,7 @@
 
 #include "util.h"
 #include "path-util.h"
+#include "fileio.h"
 #include "smack-util.h"
 
 #define SMACK_FLOOR_LABEL "_"
@@ -123,6 +124,31 @@ int mac_smack_apply_ip_in_fd(int fd, const char *label) {
         return r;
 }
 
+int mac_smack_apply_pid(pid_t pid, const char *label) {
+        int r = 0;
+        _cleanup_free_ char *path = NULL;
+
+        assert(label);
+
+#ifdef HAVE_SMACK
+        if (!mac_smack_use())
+                return 0;
+
+        if (pid)
+                r = asprintf(&path, "/proc/%lu/attr/current", (unsigned long) pid);
+        else
+                r = asprintf(&path, "/proc/self/attr/current");
+        if (r < 0)
+                return -ENOMEM;
+
+        r = write_string_file(path, label);
+        if (r < 0)
+                return -errno;
+#endif
+
+        return r;
+}
+
 int mac_smack_fix(const char *path, bool ignore_enoent, bool ignore_erofs) {
         int r = 0;
 
diff --git a/src/shared/smack-util.h b/src/shared/smack-util.h
index 68778da..50f55b1 100644
--- a/src/shared/smack-util.h
+++ b/src/shared/smack-util.h
@@ -31,5 +31,6 @@ int mac_smack_fix(const char *path, bool ignore_enoent, bool ignore_erofs);
 
 int mac_smack_apply(const char *path, const char *label);
 int mac_smack_apply_fd(int fd, const char *label);
+int mac_smack_apply_pid(pid_t pid, const char *label);
 int mac_smack_apply_ip_in_fd(int fd, const char *label);
 int mac_smack_apply_ip_out_fd(int fd, const char *label);
-- 
1.9.3



More information about the systemd-devel mailing list