chiark / gitweb /
core: add Personality= option for units to set the personality for spawned processes
authorLennart Poettering <lennart@poettering.net>
Wed, 19 Feb 2014 01:15:24 +0000 (02:15 +0100)
committerLennart Poettering <lennart@poettering.net>
Wed, 19 Feb 2014 02:27:03 +0000 (03:27 +0100)
12 files changed:
man/systemd.exec.xml
src/core/dbus-execute.c
src/core/execute.c
src/core/execute.h
src/core/load-fragment-gperf.gperf.m4
src/core/load-fragment.c
src/core/load-fragment.h
src/nspawn/nspawn.c
src/shared/exit-status.c
src/shared/exit-status.h
src/shared/util.c
src/shared/util.h

index e82e1f5..7f97ca0 100644 (file)
                                 is triggered, instead of terminating
                                 the process immediately. Takes an
                                 error name such as
-                                <literal>EPERM</literal>,
-                                <literal>EACCES</literal> or
-                                <literal>EUCLEAN</literal>. When this
+                                <constant>EPERM</constant>,
+                                <constant>EACCES</constant> or
+                                <constant>EUCLEAN</constant>. When this
                                 setting is not used, or when the empty
                                 string is assigned, the process will be
                                 terminated immediately when the filter
                                 identifiers to include in the system
                                 call filter. The known architecture
                                 identifiers are
-                                <literal>x86</literal>,
-                                <literal>x86-64</literal>,
-                                <literal>x32</literal>,
-                                <literal>arm</literal> as well as the
+                                <constant>x86</constant>,
+                                <constant>x86-64</constant>,
+                                <constant>x32</constant>,
+                                <constant>arm</constant> as well as the
                                 special identifier
-                                <literal>native</literal>. Only system
+                                <constant>native</constant>. Only system
                                 calls of the specified architectures
                                 will be permitted to processes of this
                                 unit. This is an effective way to
                                 example to prohibit execution of
                                 32-bit x86 binaries on 64-bit x86-64
                                 systems. The special
-                                <literal>native</literal> identifier
+                                <constant>native</constant> identifier
                                 implicitly maps to the native
                                 architecture of the system (or more
                                 strictly: to the architecture the
                                 system manager is compiled for). Note
                                 that setting this option to a
                                 non-empty list implies that
-                                <literal>native</literal> is included
+                                <constant>native</constant> is included
                                 too. By default, this option is set to
                                 the empty list, i.e. no architecture
                                 system call filtering is
                                 applied.</para></listitem>
                         </varlistentry>
 
+                        <varlistentry>
+                                <term><varname>Personality=</varname></term>
+
+                                <listitem><para>Controls which
+                                kernel architecture
+                                <citerefentry><refentrytitle>uname</refentrytitle><manvolnum>2</manvolnum></citerefentry>
+                                shall report, when invoked by unit
+                                processes. Takes one of
+                                <constant>x86</constant> and
+                                <constant>x86-64</constant>. This is
+                                useful when running 32bit services on
+                                a 64bit host system. If not specified
+                                the personality is left unmodified and
+                                thus reflects the personality of the
+                                host system's
+                                kernel.</para></listitem>
+                        </varlistentry>
                 </variablelist>
         </refsect1>
 
index ff5245a..41dbbab 100644 (file)
@@ -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_personality(
+                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, "s", personality_to_string(c->personality));
+}
+
 const sd_bus_vtable bus_exec_vtable[] = {
         SD_BUS_VTABLE_START(0),
         SD_BUS_PROPERTY("Environment", "as", NULL, offsetof(ExecContext, environment), SD_BUS_VTABLE_PROPERTY_CONST),
@@ -547,6 +565,7 @@ const sd_bus_vtable bus_exec_vtable[] = {
         SD_BUS_PROPERTY("SystemCallFilter", "(bas)", property_get_syscall_filter, 0, SD_BUS_VTABLE_PROPERTY_CONST),
         SD_BUS_PROPERTY("SystemCallArchitectures", "as", property_get_syscall_archs, 0, SD_BUS_VTABLE_PROPERTY_CONST),
         SD_BUS_PROPERTY("SystemCallErrorNumber", "i", property_get_syscall_errno, 0, SD_BUS_VTABLE_PROPERTY_CONST),
+        SD_BUS_PROPERTY("Personality", "s", property_get_personality, 0, SD_BUS_VTABLE_PROPERTY_CONST),
         SD_BUS_VTABLE_END
 };
 
index 4b1177a..8bfe186 100644 (file)
@@ -39,6 +39,7 @@
 #include <linux/oom.h>
 #include <sys/poll.h>
 #include <glob.h>
+#include <sys/personality.h>
 #include <libgen.h>
 #undef basename
 
@@ -1372,6 +1373,13 @@ int exec_spawn(ExecCommand *command,
                                 goto fail_child;
                         }
 
+                if (context->personality != 0xffffffffUL)
+                        if (personality(context->personality) < 0) {
+                                err = -errno;
+                                r = EXIT_PERSONALITY;
+                                goto fail_child;
+                        }
+
                 if (context->utmp_id)
                         utmp_put_init_process(context->utmp_id, getpid(), getsid(0), context->tty_path);
 
@@ -1683,6 +1691,7 @@ void exec_context_init(ExecContext *c) {
         c->syslog_level_prefix = true;
         c->ignore_sigpipe = true;
         c->timer_slack_nsec = (nsec_t) -1;
+        c->personality = 0xffffffffUL;
 }
 
 void exec_context_done(ExecContext *c) {
@@ -2130,6 +2139,11 @@ void exec_context_dump(ExecContext *c, FILE* f, const char *prefix) {
                         "%sSELinuxContext: %s%s\n",
                         prefix, c->selinux_context_ignore ? "-" : "", c->selinux_context);
 
+        if (c->personality != 0xffffffffUL)
+                fprintf(f,
+                        "%sPersonality: %s\n",
+                        prefix, strna(personality_to_string(c->personality)));
+
         if (c->syscall_filter) {
 #ifdef HAVE_SECCOMP
                 Iterator j;
index b98ef95..5c4c0b4 100644 (file)
@@ -168,6 +168,8 @@ struct ExecContext {
          * don't enter a trigger loop. */
         bool same_pgrp;
 
+        unsigned long personality;
+
         Set *syscall_filter;
         Set *syscall_archs;
         int syscall_errno;
index d2b06b2..1c2c142 100644 (file)
@@ -79,6 +79,7 @@ $1.PrivateTmp,                   config_parse_bool,                  0,
 $1.PrivateNetwork,               config_parse_bool,                  0,                             offsetof($1, exec_context.private_network)
 $1.PrivateDevices,               config_parse_bool,                  0,                             offsetof($1, exec_context.private_devices)
 $1.MountFlags,                   config_parse_exec_mount_flags,      0,                             offsetof($1, exec_context)
+$1.Personality,                  config_parse_personality,           0,                             offsetof($1, exec_context.personality)
 m4_ifdef(`HAVE_LIBWRAP',
 `$1.TCPWrapName,                 config_parse_unit_string_printf,    0,                             offsetof($1, exec_context.tcpwrap_name)',
 `$1.TCPWrapName,                 config_parse_warn_compat,           0,                             0')
index 7260d20..27666b9 100644 (file)
@@ -2566,6 +2566,36 @@ int config_parse_job_mode_isolate(
         return 0;
 }
 
+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) {
+
+        unsigned long *personality = data, p;
+
+        assert(filename);
+        assert(lvalue);
+        assert(rvalue);
+        assert(personality);
+
+        p = personality_from_string(rvalue);
+        if (p == 0xffffffffUL) {
+                log_syntax(unit, LOG_ERR, filename, line, EINVAL,
+                           "Failed to parse personality, ignoring: %s", rvalue);
+                return 0;
+        }
+
+        *personality = p;
+        return 0;
+}
+
 #define FOLLOW_MAX 8
 
 static int open_follow(char **filename, FILE **_f, Set *names, char **_final) {
index cc77fcc..83ecea5 100644 (file)
@@ -88,6 +88,7 @@ int config_parse_blockio_bandwidth(const char *unit, const char *filename, unsig
 int config_parse_job_mode(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_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);
 
 /* gperf prototypes */
 const struct ConfigPerfItem* load_fragment_gperf_lookup(const char *key, unsigned length);
index 98e90fe..350dc93 100644 (file)
@@ -480,7 +480,7 @@ static int parse_argv(int argc, char *argv[]) {
 
                 case ARG_PERSONALITY:
 
-                        arg_personality = parse_personality(optarg);
+                        arg_personality = personality_from_string(optarg);
                         if (arg_personality == 0xffffffffLU) {
                                 log_error("Unknown or unsupported personality '%s'.", optarg);
                                 return -EINVAL;
index 70789f5..8b096da 100644 (file)
@@ -133,6 +133,9 @@ const char* exit_status_to_string(ExitStatus status, ExitStatusLevel level) {
 
                 case EXIT_SELINUX_CONTEXT:
                         return "SELINUX_CONTEXT";
+
+                case EXIT_PERSONALITY:
+                        return "PERSONALITY";
                 }
         }
 
index 8f9bddf..dde5bdd 100644 (file)
@@ -68,7 +68,8 @@ typedef enum ExitStatus {
         EXIT_NAMESPACE,
         EXIT_NO_NEW_PRIVILEGES,
         EXIT_SECCOMP,
-        EXIT_SELINUX_CONTEXT
+        EXIT_SELINUX_CONTEXT,
+        EXIT_PERSONALITY  /* 230 */
 } ExitStatus;
 
 typedef enum ExitStatusLevel {
index 99658f0..55246f5 100644 (file)
@@ -6194,7 +6194,7 @@ int fd_warn_permissions(const char *path, int fd) {
         return 0;
 }
 
-unsigned long parse_personality(const char *p) {
+unsigned long personality_from_string(const char *p) {
 
         /* Parse a personality specifier. We introduce our own
          * identifiers that indicate specific ABIs, rather than just
@@ -6222,3 +6222,22 @@ unsigned long parse_personality(const char *p) {
          * as error indicator. */
         return 0xffffffffUL;
 }
+
+const char* personality_to_string(unsigned long p) {
+
+#if defined(__x86_64__)
+
+        if (p == PER_LINUX32)
+                return "x86";
+
+        if (p == PER_LINUX)
+                return "x86-64";
+
+#elif defined(__i386__)
+
+        if (p == PER_LINUX)
+                return "x86";
+#endif
+
+        return NULL;
+}
index e379c30..d1230d2 100644 (file)
@@ -871,4 +871,5 @@ int open_tmpfile(const char *path, int flags);
 
 int fd_warn_permissions(const char *path, int fd);
 
-unsigned long parse_personality(const char *p);
+unsigned long personality_from_string(const char *p);
+const char *personality_to_string(unsigned long);