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 -- libvir-list mailing list libvir-list@xxxxxxxxxx https://www.redhat.com/mailman/listinfo/libvir-list