[systemd-devel] [PATCH v3] smack: introduce new SmackProcessLabel option

WaLyong Cho walyong.cho at samsung.com
Mon Nov 24 03:46:20 PST 2014


In service file, if the file has some of special SMACK label in
ExecStart= and systemd has no permission for the special SMACK label
then permission error will occurred. To resolve this, systemd should
be able to set its SMACK label to something accessible of ExecStart=.
So introduce new SmackProcessLabel. If label is specified with
SmackProcessLabel= then the child systemd will set its label to
that. To successfully execute the ExecStart=, accessible label should
be specified with SmackProcessLabel=.
Additionally, by SMACK policy, if the file in ExecStart= has no
SMACK64EXEC then the executed process will have given label by
SmackProcessLabel=. But if the file has SMACK64EXEC then the
SMACK64EXEC label will be overridden.
---
 man/systemd.exec.xml                  | 19 +++++++++++++
 src/core/dbus-execute.c               | 19 +++++++++++++
 src/core/execute.c                    | 11 ++++++++
 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               | 20 ++++++++++++++
 src/shared/smack-util.h               |  1 +
 10 files changed, 130 insertions(+), 2 deletions(-)

diff --git a/man/systemd.exec.xml b/man/systemd.exec.xml
index e9af4ab..ea2130d 100644
--- a/man/systemd.exec.xml
+++ b/man/systemd.exec.xml
@@ -1138,6 +1138,25 @@
                         </varlistentry>
 
                         <varlistentry>
+                                <term><varname>SmackProcessLabel=</varname></term>
+
+                                <listitem><para>Set the SMACK security
+                                label to run given executable file in
+                                <varname>ExecStart=</varname>. The
+                                executable file has no SMACK64EXEC
+                                label then the executed process run
+                                with this label. But if the file has
+                                SMACK64EXEC label then executed
+                                process run with its own SMACK64EXEC
+                                label. If no label set, defaults to
+                                label of systemd by SMACK policy. This
+                                directive is ignored if SMACK is
+                                disabled. If prefixed
+                                by<literal>-</literal>, all
+                                errorswillbe 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..bbcd610 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_process_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_process_label_ignore, c->smack_process_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("SmackProcessLabel", "(bs)", property_get_smack_process_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 5cfd4a1..e6c1999 100644
--- a/src/core/execute.c
+++ b/src/core/execute.c
@@ -83,6 +83,7 @@
 #include "af-list.h"
 #include "mkdir.h"
 #include "apparmor-util.h"
+#include "smack-util.h"
 #include "bus-kernel.h"
 #include "label.h"
 
@@ -1618,6 +1619,16 @@ static int exec_child(ExecCommand *command,
                         }
                 }
 
+#ifdef HAVE_SMACK
+                if (context->smack_process_label) {
+                        err = mac_smack_apply_pid(0, context->smack_process_label);
+                        if (err < 0) {
+                                *error = EXIT_SMACK_PROCESS_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 b16a24d..5ed7505 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_process_label_ignore;
+        char *smack_process_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 1d2debe..a94b805 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.SmackProcessLabel,           config_parse_exec_smack_process_label, 0,                          offsetof($1, exec_context)',
+`$1.SmackProcessLabel,           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 2ee16bd..4309121 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_process_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_process_label);
+                c->smack_process_label = NULL;
+                c->smack_process_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_process_label);
+        c->smack_process_label = k;
+        c->smack_process_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..a799c9a 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_process_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..1d774f2 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_PROCESS_LABEL,
 } ExitStatus;
 
 typedef enum ExitStatusLevel {
diff --git a/src/shared/smack-util.c b/src/shared/smack-util.c
index a8dccd1..b6c9643 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,25 @@ 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;
+        const char *p;
+
+        assert(label);
+
+#ifdef HAVE_SMACK
+        if (!mac_smack_use())
+                return 0;
+
+        p = procfs_file_alloca(pid, "attr/current");
+        r = write_string_file(p, label);
+        if (r < 0)
+                return r;
+#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