summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--man/systemd.exec.xml37
-rw-r--r--src/core/dbus-execute.c19
-rw-r--r--src/core/execute.c14
-rw-r--r--src/core/execute.h2
-rw-r--r--src/core/load-fragment-gperf.gperf.m41
-rw-r--r--src/core/load-fragment.c30
-rw-r--r--src/core/load-fragment.h1
-rw-r--r--src/nspawn/nspawn.c2
-rw-r--r--src/shared/exit-status.c3
-rw-r--r--src/shared/exit-status.h3
-rw-r--r--src/shared/util.c21
-rw-r--r--src/shared/util.h3
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);