summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--NEWS4
-rw-r--r--man/systemd-nspawn.xml18
-rw-r--r--src/nspawn/nspawn.c21
-rw-r--r--src/shared/util.c30
-rw-r--r--src/shared/util.h2
5 files changed, 75 insertions, 0 deletions
diff --git a/NEWS b/NEWS
index b40d369746..c240d11dc7 100644
--- a/NEWS
+++ b/NEWS
@@ -379,6 +379,10 @@ CHANGES WITH 209:
switch then allows assigning the host side of this virtual
Ethernet connection to a bridge device.
+ * systemd-nspawn gained a new --personality= switch for
+ setting the kernel personality for the container. This is
+ useful when running a 32bit container on a 64bit host.
+
* logind will now also track a "Desktop" identifier for each
session which encodes the desktop environment of it. This is
useful for desktop environments that want to identify
diff --git a/man/systemd-nspawn.xml b/man/systemd-nspawn.xml
index b34d38c9b5..6518eb819e 100644
--- a/man/systemd-nspawn.xml
+++ b/man/systemd-nspawn.xml
@@ -555,6 +555,24 @@
session.</para></listitem>
</varlistentry>
+ <varlistentry>
+ <term><option>--personality=</option></term>
+
+ <listitem><para>Control the
+ architecture ("personality") reported
+ by
+ <citerefentry><refentrytitle>uname</refentrytitle><manvolnum>2</manvolnum></citerefentry>
+ in the container. Currently, only
+ <literal>x86</literal> and
+ <literal>x86-64</literal> are
+ supported. This is useful when running
+ a 32bit container on a 64bit
+ host. If this setting is not used
+ the personality reported in the
+ container is the same as the one
+ reported on the
+ host.</para></listitem>
+ </varlistentry>
</variablelist>
</refsect1>
diff --git a/src/nspawn/nspawn.c b/src/nspawn/nspawn.c
index 379ea92355..98e90fe3c9 100644
--- a/src/nspawn/nspawn.c
+++ b/src/nspawn/nspawn.c
@@ -43,6 +43,7 @@
#include <sys/eventfd.h>
#include <net/if.h>
#include <linux/veth.h>
+#include <sys/personality.h>
#ifdef HAVE_SELINUX
#include <selinux/selinux.h>
@@ -138,6 +139,7 @@ static bool arg_keep_unit = false;
static char **arg_network_interfaces = NULL;
static bool arg_network_veth = false;
static char *arg_network_bridge = NULL;
+static unsigned long arg_personality = 0xffffffffLU;
static int help(void) {
@@ -206,6 +208,7 @@ static int parse_argv(int argc, char *argv[]) {
ARG_NETWORK_INTERFACE,
ARG_NETWORK_VETH,
ARG_NETWORK_BRIDGE,
+ ARG_PERSONALITY,
};
static const struct option options[] = {
@@ -234,6 +237,7 @@ static int parse_argv(int argc, char *argv[]) {
{ "network-interface", required_argument, NULL, ARG_NETWORK_INTERFACE },
{ "network-veth", no_argument, NULL, ARG_NETWORK_VETH },
{ "network-bridge", required_argument, NULL, ARG_NETWORK_BRIDGE },
+ { "personality", required_argument, NULL, ARG_PERSONALITY },
{}
};
@@ -474,6 +478,16 @@ static int parse_argv(int argc, char *argv[]) {
arg_keep_unit = true;
break;
+ case ARG_PERSONALITY:
+
+ arg_personality = parse_personality(optarg);
+ if (arg_personality == 0xffffffffLU) {
+ log_error("Unknown or unsupported personality '%s'.", optarg);
+ return -EINVAL;
+ }
+
+ break;
+
case '?':
return -EINVAL;
@@ -1983,6 +1997,13 @@ int main(int argc, char *argv[]) {
setup_hostname();
+ if (arg_personality != 0xffffffffLU) {
+ if (personality(arg_personality) < 0) {
+ log_error("personality() failed: %m");
+ goto child_fail;
+ }
+ }
+
eventfd_read(sync_fd, &x);
close_nointr_nofail(sync_fd);
sync_fd = -1;
diff --git a/src/shared/util.c b/src/shared/util.c
index 72b1e2f3c8..99658f0975 100644
--- a/src/shared/util.c
+++ b/src/shared/util.c
@@ -58,6 +58,7 @@
#include <limits.h>
#include <langinfo.h>
#include <locale.h>
+#include <sys/personality.h>
#include <libgen.h>
#undef basename
@@ -6192,3 +6193,32 @@ int fd_warn_permissions(const char *path, int fd) {
return 0;
}
+
+unsigned long parse_personality(const char *p) {
+
+ /* Parse a personality specifier. We introduce our own
+ * identifiers that indicate specific ABIs, rather than just
+ * hints regarding the register size, since we want to keep
+ * things open for multiple locally supported ABIs for the
+ * same register size. We try to reuse the ABI identifiers
+ * used by libseccomp. */
+
+#if defined(__x86_64__)
+
+ if (streq(p, "x86"))
+ return PER_LINUX32;
+
+ if (streq(p, "x86-64"))
+ return PER_LINUX;
+
+#elif defined(__i386__)
+
+ if (streq(p, "x86"))
+ return PER_LINUX;
+#endif
+
+ /* personality(7) documents that 0xffffffffUL is used for
+ * querying the current personality, hence let's use that here
+ * as error indicator. */
+ return 0xffffffffUL;
+}
diff --git a/src/shared/util.h b/src/shared/util.h
index a41348e32e..e379c30e63 100644
--- a/src/shared/util.h
+++ b/src/shared/util.h
@@ -870,3 +870,5 @@ int mkostemp_safe(char *pattern, int flags);
int open_tmpfile(const char *path, int flags);
int fd_warn_permissions(const char *path, int fd);
+
+unsigned long parse_personality(const char *p);