diff options
-rw-r--r-- | man/systemd.exec.xml | 37 | ||||
-rw-r--r-- | src/core/dbus-execute.c | 19 | ||||
-rw-r--r-- | src/core/execute.c | 14 | ||||
-rw-r--r-- | src/core/execute.h | 2 | ||||
-rw-r--r-- | src/core/load-fragment-gperf.gperf.m4 | 1 | ||||
-rw-r--r-- | src/core/load-fragment.c | 30 | ||||
-rw-r--r-- | src/core/load-fragment.h | 1 | ||||
-rw-r--r-- | src/nspawn/nspawn.c | 2 | ||||
-rw-r--r-- | src/shared/exit-status.c | 3 | ||||
-rw-r--r-- | src/shared/exit-status.h | 3 | ||||
-rw-r--r-- | src/shared/util.c | 21 | ||||
-rw-r--r-- | src/shared/util.h | 3 |
12 files changed, 122 insertions, 14 deletions
diff --git a/man/systemd.exec.xml b/man/systemd.exec.xml index e82e1f59f0..7f97ca035d 100644 --- a/man/systemd.exec.xml +++ b/man/systemd.exec.xml @@ -1063,9 +1063,9 @@ 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 @@ -1080,12 +1080,12 @@ 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 @@ -1094,20 +1094,37 @@ 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> diff --git a/src/core/dbus-execute.c b/src/core/dbus-execute.c index ff5245a0eb..41dbbab904 100644 --- a/src/core/dbus-execute.c +++ b/src/core/dbus-execute.c @@ -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 }; diff --git a/src/core/execute.c b/src/core/execute.c index 4b1177a7e5..8bfe186c8a 100644 --- a/src/core/execute.c +++ b/src/core/execute.c @@ -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; diff --git a/src/core/execute.h b/src/core/execute.h index b98ef952e1..5c4c0b4abe 100644 --- a/src/core/execute.h +++ b/src/core/execute.h @@ -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; diff --git a/src/core/load-fragment-gperf.gperf.m4 b/src/core/load-fragment-gperf.gperf.m4 index d2b06b2e94..1c2c142eec 100644 --- a/src/core/load-fragment-gperf.gperf.m4 +++ b/src/core/load-fragment-gperf.gperf.m4 @@ -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') diff --git a/src/core/load-fragment.c b/src/core/load-fragment.c index 7260d20578..27666b937c 100644 --- a/src/core/load-fragment.c +++ b/src/core/load-fragment.c @@ -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) { diff --git a/src/core/load-fragment.h b/src/core/load-fragment.h index cc77fccf94..83ecea5da1 100644 --- a/src/core/load-fragment.h +++ b/src/core/load-fragment.h @@ -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); diff --git a/src/nspawn/nspawn.c b/src/nspawn/nspawn.c index 98e90fe3c9..350dc93cf9 100644 --- a/src/nspawn/nspawn.c +++ b/src/nspawn/nspawn.c @@ -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; diff --git a/src/shared/exit-status.c b/src/shared/exit-status.c index 70789f5136..8b096da7e1 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_PERSONALITY: + return "PERSONALITY"; } } diff --git a/src/shared/exit-status.h b/src/shared/exit-status.h index 8f9bddf069..dde5bdda8b 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_PERSONALITY /* 230 */ } ExitStatus; typedef enum ExitStatusLevel { diff --git a/src/shared/util.c b/src/shared/util.c index 99658f0975..55246f5a4d 100644 --- a/src/shared/util.c +++ b/src/shared/util.c @@ -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; +} diff --git a/src/shared/util.h b/src/shared/util.h index e379c30e63..d1230d2b64 100644 --- a/src/shared/util.h +++ b/src/shared/util.h @@ -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); |