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 e82e1f59f0ec87d6fa4c56849175558c6177aef8..7f97ca035d2be3d049b9466b81142d8f0e060564 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 ff5245a0ebc91e6c105949c9858e4682e5be5331..41dbbab904a6ab7988273137425cc75dba47822a 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 4b1177a7e5eb5eb198ecb333215c1c72c1223d08..8bfe186c8a1d504c3da4631e37cb1ea999ab531e 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 b98ef952e157fcefc5e9db07ca234fadd961a2b9..5c4c0b4abe635393b1d1e8b23b337af5ff16c617 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 d2b06b2e945ef93bf5b2362e6e8d9f74b38a0ff0..1c2c142eeced28e1f181a29ebaedbb82a673edd0 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 7260d205788664167931e6f8b9724074296f605f..27666b937c2fc6a3ff85d0fca0b1aaaa8ddecaea 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 cc77fccf94a825bf6e37d2323decf8c775d994cd..83ecea5da163c1f6b9edfbecc0fc9c7b867a3db6 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 98e90fe3c9207ab51dde3c3ece05bea4aca7a24e..350dc93cf9f873dd934e6a4b4ae6350dc4363873 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 70789f51367e9e7f23852bedc6ac6823d3adea8d..8b096da7e1b275e4f7130ac1a725dd622bb5ffd0 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 8f9bddf0690437a9e987fdac5aa6e4affb95d97e..dde5bdda8b0836faf0e855a1a265224607962a43 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 99658f097571f847db178d1402623bd27fd3031e..55246f5a4d769eeb98206a29deafb80affe24b9b 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 e379c30e6392f7074118a2a15d6a0ccee205fe99..d1230d2b64cd65be71f97d7524cd22f40e41504b 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);