On 2013/03/13 18:57, Daniel P. Berrange wrote:
On Mon, Mar 11, 2013 at 02:26:48PM +0800, Gao feng wrote:
> This patch introduces new helper function
> virLXCControllerSetupUserns, in this function,
> we set the files uid_map and gid_map of process
> libvirt_lxc.
>
> lxcContainerSetUserns is used for creating cred for
> tasks running in container. Since after setuid/setgid,
> we may be a new user. This patch calls lxcContainerSetUserns
> at first to make sure the new created files belong to
> right user.
>
> Signed-off-by: Gao feng <gaofeng(a)cn.fujitsu.com>
> ---
> src/lxc/lxc_container.c | 55 ++++++++++++++++++++++++++++++----------
> src/lxc/lxc_controller.c | 66 ++++++++++++++++++++++++++++++++++++++++++++++++
> 2 files changed, 107 insertions(+), 14 deletions(-)
>
> diff --git a/src/lxc/lxc_container.c b/src/lxc/lxc_container.c
> index 1d7bc1e..5c66ae3 100644
> --- a/src/lxc/lxc_container.c
> +++ b/src/lxc/lxc_container.c
> @@ -329,6 +329,29 @@ int lxcContainerWaitForContinue(int control)
>
>
> /**
> + * lxcContainerSetUserns:
> + *
> + * This function calls setuid and setgid to create proper
> + * cred for tasks running in container.
> + *
> + * Returns 0 on success or -1 in case of error
> + */
> +static int lxcContainerSetUserns(virDomainDefPtr def)
> +{
> + if (def->os.userns != VIR_DOMAIN_USER_NS_ENABLED)
> + return 0;
> +
> + if (virSetUIDGID(def->os.uidmap.first,
> + def->os.gidmap.first) < 0) {
> + virReportSystemError(errno, "%s",
> + _("setuid or setgid failed"));
> + return -1;
> + }
> +
> + return 0;
> +}
I don't see why we should force the init process to have the first
UID in the map. The init process should always start as uid:gid 0:0
regardless of mapping IMHO. If we want a capability to start the
init process as a different uid:gid, then that should involve separate
XML configuration.
Yes,kernel provides flexible interface.but we can force the [u,g]ser id of
init process to 0:0.
> @@ -2221,6 +2244,24 @@ static int lxcContainerChild(void *data)
> }
> }
>
> + if (!virFileExists(vmDef->os.init)) {
> + virReportSystemError(errno,
> + _("cannot find init path '%s' relative to container
root"),
> + vmDef->os.init);
> + goto cleanup;
> + }
> +
> + /* Wait for interface devices to show up */
> + if (lxcContainerWaitForContinue(argv->monitor) < 0) {
> + virReportSystemError(errno, "%s",
> + _("Failed to read the container continue
message"));
> + goto cleanup;
> + }
> + VIR_DEBUG("Received container continue message");
I don't really see why you're moving these lines - they are unrelated
to user namespaces.
This change ensure the init process has new cred first.
see lxcContainerSetUserns below.
> +
> + if (lxcContainerSetUserns(vmDef) < 0)
> + goto cleanup;
> +
> VIR_DEBUG("Container TTY path: %s", ttyPath);
>
> ttyfd = open(ttyPath, O_RDWR|O_NOCTTY);
> @@ -2236,20 +2277,6 @@ static int lxcContainerChild(void *data)
> argv->securityDriver) < 0)
> goto cleanup;
>
> - if (!virFileExists(vmDef->os.init)) {
> - virReportSystemError(errno,
> - _("cannot find init path '%s' relative to container
root"),
> - vmDef->os.init);
> - goto cleanup;
> - }
> -
> - /* Wait for interface devices to show up */
> - if (lxcContainerWaitForContinue(argv->monitor) < 0) {
> - virReportSystemError(errno, "%s",
> - _("Failed to read the container continue
message"));
> - goto cleanup;
> - }
> - VIR_DEBUG("Received container continue message");
>
> /* rename and enable interfaces */
> if (lxcContainerRenameAndEnableInterfaces(!!(vmDef->features &
> diff --git a/src/lxc/lxc_controller.c b/src/lxc/lxc_controller.c
> index 15aa334..f17142f 100644
> --- a/src/lxc/lxc_controller.c
> +++ b/src/lxc/lxc_controller.c
> @@ -1028,6 +1028,69 @@ cleanup2:
> }
>
>
> +/**
> + * virLXCControllerSetupUserns
> + *
> + * Set proc files for user namespace
> + *
> + * Returns 0 on success or -1 in case of error
> + */
> +static int virLXCControllerSetupUserns(virLXCControllerPtr ctrl)
> +{
> + char *uid_map = NULL;
> + char *gid_map = NULL;
> + char *uidmap_value = NULL;
> + char *gidmap_value = NULL;
> + int ret = -1;
> +
> + if (ctrl->def->os.userns != VIR_DOMAIN_USER_NS_ENABLED)
> + return 0;
> +
> + if (virAsprintf(&uid_map, "/proc/%d/uid_map", ctrl->initpid)
< 0)
> + goto cleanup;
> +
> + if (virAsprintf(&gid_map, "/proc/%d/gid_map", ctrl->initpid)
< 0)
> + goto cleanup;
> +
> + if (virAsprintf(&uidmap_value, "%u %u %u",
> + ctrl->def->os.uidmap.first,
> + ctrl->def->os.uidmap.low_first,
> + ctrl->def->os.uidmap.count) < 0)
> + goto cleanup;
> +
> + if (virAsprintf(&gidmap_value, "%u %u %u",
> + ctrl->def->os.gidmap.first,
> + ctrl->def->os.gidmap.low_first,
> + ctrl->def->os.gidmap.count) < 0)
> + goto cleanup;
> +
> + if (virFileWriteStr(uid_map, uidmap_value, 0) < 0) {
> + if (errno == -ENOENT)
> + virReportSystemError(errno,
> + _("%s doesn't exist, please disable
userns"),
> + uid_map);
> + virReportSystemError(errno, _("unable write to %s"), uid_map);
> + goto cleanup;
> + }
> +
> + if (virFileWriteStr(gid_map, gidmap_value, 0) < 0) {
> + if (errno == -ENOENT)
> + virReportSystemError(errno,
> + _("%s doesn't exist, please disable
userns"),
> + gid_map);
> + virReportSystemError(errno, _("unable write to %s"), gid_map);
> + goto cleanup;
> + }
> +
> + ret = 0;
> +cleanup:
> + VIR_FREE(uidmap_value);
> + VIR_FREE(gidmap_value);
> + VIR_FREE(uid_map);
> + VIR_FREE(gid_map);
> + return ret;
> +}
I think we should have one method can write to either mapping file,
and that should be invoked once to setup UID mapping and once to
setup GID mapping. This would remove all the duplication in this
method. Also we need to be able to write multiple lines to the
mapping files in one go.
sounds reasonable,will do.
Thanks!