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>
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),
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
};
#include <linux/oom.h>
#include <sys/poll.h>
#include <glob.h>
+#include <sys/personality.h>
#include <libgen.h>
#undef basename
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);
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) {
"%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;
* don't enter a trigger loop. */
bool same_pgrp;
+ unsigned long personality;
+
Set *syscall_filter;
Set *syscall_archs;
int syscall_errno;
$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')
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) {
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);
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;
case EXIT_SELINUX_CONTEXT:
return "SELINUX_CONTEXT";
+
+ case EXIT_PERSONALITY:
+ return "PERSONALITY";
}
}
EXIT_NAMESPACE,
EXIT_NO_NEW_PRIVILEGES,
EXIT_SECCOMP,
- EXIT_SELINUX_CONTEXT
+ EXIT_SELINUX_CONTEXT,
+ EXIT_PERSONALITY /* 230 */
} ExitStatus;
typedef enum ExitStatusLevel {
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
* 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;
+}
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);