Users may want to run the init command of a container as a special
user / group. Allow doing it using <inituser uid=""/> and <initgroup
gid=""/> elements.
---
docs/formatdomain.html.in | 6 ++++++
docs/schemas/domaincommon.rng | 12 ++++++++++++
src/conf/domain_conf.c | 19 +++++++++++++++++++
src/conf/domain_conf.h | 2 ++
src/lxc/lxc_container.c | 13 +++++++++++++
tests/lxcxml2xmldata/lxc-inituser.xml | 31 +++++++++++++++++++++++++++++++
tests/lxcxml2xmltest.c | 1 +
7 files changed, 84 insertions(+)
create mode 100644 tests/lxcxml2xmldata/lxc-inituser.xml
diff --git a/docs/formatdomain.html.in b/docs/formatdomain.html.in
index 7627fd0d0..85d5f4539 100644
--- a/docs/formatdomain.html.in
+++ b/docs/formatdomain.html.in
@@ -334,6 +334,10 @@
To set a custom work directory for the init, use the
<code>initdir</code>
element.
</p>
+ <p>
+ To run the init command as a given user or group, use the
<code>inituser</code>
+ or <code>initgroup</code> elements respectively.
+ </p>
<pre>
<os>
@@ -343,6 +347,8 @@
<initarg>emergency.service</initarg>
<initenv name='MYENV'>some value</initenv>
<initdir>/my/custom/cwd</initdir>
+ <inituser uid="1000"/>
+ <initgroup gid="1000"/>
</os>
</pre>
diff --git a/docs/schemas/domaincommon.rng b/docs/schemas/domaincommon.rng
index 5a4c4ecf1..385e937e9 100644
--- a/docs/schemas/domaincommon.rng
+++ b/docs/schemas/domaincommon.rng
@@ -400,6 +400,18 @@
<ref name="absFilePath"/>
</element>
</optional>
+ <optional>
+ <element name="inituser">
+ <attribute name="uid">
+ <ref name="unsignedInt"/>
+ </attribute>
+ </element>
+ <element name="initgroup">
+ <attribute name="gid">
+ <ref name="unsignedInt"/>
+ </attribute>
+ </element>
+ </optional>
</interleave>
</element>
</define>
diff --git a/src/conf/domain_conf.c b/src/conf/domain_conf.c
index 3c2a81f52..21bb104a9 100644
--- a/src/conf/domain_conf.c
+++ b/src/conf/domain_conf.c
@@ -16806,6 +16806,18 @@ virDomainDefParseBootOptions(virDomainDefPtr def,
def->os.cmdline = virXPathString("string(./os/cmdline[1])", ctxt);
def->os.initdir = virXPathString("string(./os/initdir[1])", ctxt);
+ if (virXPathUInt("string(./os/inituser[1]/@uid)", ctxt,
&def->os.inituid) == -2) {
+ virReportError(VIR_ERR_XML_ERROR, "%s",
+ _("Failed to parse inituser uid"));
+ goto error;
+ }
+
+ if (virXPathUInt("string(./os/initgroup[1]/@gid)", ctxt,
&def->os.initgid) == -2) {
+ virReportError(VIR_ERR_XML_ERROR, "%s",
+ _("Failed to parse initgroup gid"));
+ goto error;
+ }
+
if ((n = virXPathNodeSet("./os/initarg", ctxt, &nodes)) < 0)
goto error;
@@ -24593,6 +24605,13 @@ virDomainDefFormatInternal(virDomainDefPtr def,
if (def->os.initdir)
virBufferEscapeString(buf, "<initdir>%s</initdir>\n",
def->os.initdir);
+ if (def->os.inituid)
+ virBufferAsprintf(buf, "<inituser uid='%u'/>\n",
+ def->os.inituid);
+ if (def->os.initgid)
+ virBufferAsprintf(buf, "<initgroup gid='%u'/>\n",
+ def->os.initgid);
+
if (def->os.loader)
virDomainLoaderDefFormat(buf, def->os.loader);
virBufferEscapeString(buf, "<kernel>%s</kernel>\n",
diff --git a/src/conf/domain_conf.h b/src/conf/domain_conf.h
index d6b8429c3..6e1997324 100644
--- a/src/conf/domain_conf.h
+++ b/src/conf/domain_conf.h
@@ -1842,6 +1842,8 @@ struct _virDomainOSDef {
char **initargv;
virDomainOSEnvPtr *initenv;
char *initdir;
+ uid_t inituid;
+ gid_t initgid;
char *kernel;
char *initrd;
char *cmdline;
diff --git a/src/lxc/lxc_container.c b/src/lxc/lxc_container.c
index 8d8e1a735..42bcd25c4 100644
--- a/src/lxc/lxc_container.c
+++ b/src/lxc/lxc_container.c
@@ -247,6 +247,10 @@ static virCommandPtr lxcContainerBuildInitCmd(virDomainDefPtr vmDef,
virCommandAddEnvPair(cmd, "LIBVIRT_LXC_CMDLINE",
vmDef->os.cmdline);
if (vmDef->os.initdir)
virCommandSetWorkingDirectory(cmd, vmDef->os.initdir);
+ if (vmDef->os.inituid)
+ virCommandSetUID(cmd, vmDef->os.inituid);
+ if (vmDef->os.initgid)
+ virCommandSetGID(cmd, vmDef->os.initgid);
for (i = 0; vmDef->os.initenv[i]; i++) {
virCommandAddEnvPair(cmd, vmDef->os.initenv[i]->name,
@@ -2192,6 +2196,15 @@ static int lxcContainerChild(void *data)
goto cleanup;
}
+ /* Change the newly created tty owner to the inituid for
+ * shells to have job control */
+ if (vmDef->os.inituid && chown(ttyPath, vmDef->os.inituid, -1) < 0)
{
+ virReportSystemError(errno,
+ _("Failed to change ownership of tty %s"),
+ ttyPath);
+ goto cleanup;
+ }
+
if (lxcContainerResolveAllSymlinks(vmDef) < 0)
goto cleanup;
diff --git a/tests/lxcxml2xmldata/lxc-inituser.xml
b/tests/lxcxml2xmldata/lxc-inituser.xml
new file mode 100644
index 000000000..61b5db4af
--- /dev/null
+++ b/tests/lxcxml2xmldata/lxc-inituser.xml
@@ -0,0 +1,31 @@
+<domain type='lxc'>
+ <name>jessie</name>
+ <uuid>e21987a5-e98e-9c99-0e35-803e4d9ad1fe</uuid>
+ <memory unit='KiB'>1048576</memory>
+ <currentMemory unit='KiB'>1048576</currentMemory>
+ <vcpu placement='static'>1</vcpu>
+ <resource>
+ <partition>/machine</partition>
+ </resource>
+ <os>
+ <type arch='x86_64'>exe</type>
+ <init>/sbin/sh</init>
+ <inituser uid='1000'/>
+ <initgroup gid='1234'/>
+ </os>
+ <clock offset='utc'/>
+ <on_poweroff>destroy</on_poweroff>
+ <on_reboot>restart</on_reboot>
+ <on_crash>restart</on_crash>
+ <devices>
+ <emulator>/usr/libexec/libvirt_lxc</emulator>
+ <filesystem type='mount' accessmode='passthrough'>
+ <source dir='/mach/jessie'/>
+ <target dir='/'/>
+ </filesystem>
+ <console type='pty'>
+ <target type='lxc' port='0'/>
+ </console>
+ </devices>
+ <seclabel type='none'/>
+</domain>
diff --git a/tests/lxcxml2xmltest.c b/tests/lxcxml2xmltest.c
index c81b0eace..9b9314cf8 100644
--- a/tests/lxcxml2xmltest.c
+++ b/tests/lxcxml2xmltest.c
@@ -100,6 +100,7 @@ mymain(void)
VIR_DOMAIN_DEF_PARSE_SKIP_OSTYPE_CHECKS);
DO_TEST("initenv");
DO_TEST("initdir");
+ DO_TEST("inituser");
virObjectUnref(caps);
virObjectUnref(xmlopt);
--
2.12.2