[libvirt] [PATCH RFC 6/7] qemu: Spawn qemu under mount namespace

Daniel P. Berrange berrange at redhat.com
Mon Nov 14 16:55:45 UTC 2016


On Mon, Nov 14, 2016 at 05:43:30PM +0100, Michal Privoznik wrote:
> Signed-off-by: Michal Privoznik <mprivozn at redhat.com>
> ---
>  src/qemu/qemu_domain.c  | 233 ++++++++++++++++++++++++++++++++++++++++++++++++
>  src/qemu/qemu_domain.h  |   8 ++
>  src/qemu/qemu_process.c |  13 +++
>  3 files changed, 254 insertions(+)
> 
> diff --git a/src/qemu/qemu_domain.c b/src/qemu/qemu_domain.c
> index 8cba755..3a0170c 100644
> --- a/src/qemu/qemu_domain.c
> +++ b/src/qemu/qemu_domain.c
> @@ -55,6 +55,7 @@
>  
>  #include <sys/time.h>
>  #include <fcntl.h>
> +#include <sys/mount.h>
>  
>  #include <libxml/xpathInternals.h>
>  
> @@ -86,6 +87,21 @@ VIR_ENUM_IMPL(qemuDomainAsyncJob, QEMU_ASYNC_JOB_LAST,
>                "start",
>  );
>  
> +#define QEMU_DEV_MAJ_MEMORY  1
> +#define QEMU_DEV_MAJ_TTY     5
> +#define QEMU_DEV_MAJ_KVM     10
> +#define QEMU_DEV_MAJ_PTY     136
> +
> +#define QEMU_DEV_MIN_CONSOLE 1
> +#define QEMU_DEV_MIN_FULL    7
> +#define QEMU_DEV_MIN_FUSE    229
> +#define QEMU_DEV_MIN_KVM     232
> +#define QEMU_DEV_MIN_NULL    3
> +#define QEMU_DEV_MIN_PTMX    2
> +#define QEMU_DEV_MIN_RANDOM  8
> +#define QEMU_DEV_MIN_TTY     0
> +#define QEMU_DEV_MIN_URANDOM 9
> +#define QEMU_DEV_MIN_ZERO    5
>  
>  struct _qemuDomainLogContext {
>      int refs;
> @@ -6658,3 +6674,220 @@ qemuDomainSupportsVideoVga(virDomainVideoDefPtr video,
>  
>      return true;
>  }
> +
> +
> +static int
> +qemuDomainPopulateDevices(virQEMUDriverPtr driver ATTRIBUTE_UNUSED,
> +                          virDomainObjPtr vm ATTRIBUTE_UNUSED,
> +                          const char *path)
> +{
> +    int ret = -1;
> +    virFileDevices devs[] = {
> +        { QEMU_DEV_MAJ_MEMORY, QEMU_DEV_MIN_NULL, 0666, "/null" },
> +        { QEMU_DEV_MAJ_MEMORY, QEMU_DEV_MIN_ZERO, 0666, "/zero" },
> +        { QEMU_DEV_MAJ_MEMORY, QEMU_DEV_MIN_FULL, 0666, "/full" },
> +        { QEMU_DEV_MAJ_KVM,  QEMU_DEV_MIN_KVM, 0660, "/kvm"},
> +        { QEMU_DEV_MAJ_MEMORY, QEMU_DEV_MIN_RANDOM, 0666, "/random" },
> +        { QEMU_DEV_MAJ_MEMORY, QEMU_DEV_MIN_URANDOM, 0666, "/urandom" },
> +        { QEMU_DEV_MAJ_TTY, QEMU_DEV_MIN_TTY, 0666, "/tty" },
> +        { 0, 0, 0, NULL},
> +    };
> +
> +    if (virFilePopulateDevices(path, devs) < 0)
> +        goto cleanup;
> +
> +    ret = 0;
> + cleanup:
> +    return ret;
> +}
> +
> +
> +static int
> +qemuDomainSetupDev(virQEMUDriverPtr driver,
> +                   virDomainObjPtr vm,
> +                   const char *path)
> +{
> +    char *mount_options = NULL;
> +    char *opts = NULL;
> +    int ret = -1;
> +
> +    VIR_DEBUG("Setting up /dev/ for domain %s", vm->def->name);
> +
> +    mount_options = virSecurityManagerGetMountOptions(driver->securityManager,
> +                                                      vm->def);
> +
> +    if (!mount_options &&
> +        VIR_STRDUP(mount_options, "") < 0)
> +        goto cleanup;
> +
> +    /*
> +     * tmpfs is limited to 64kb, since we only have device nodes in there
> +     * and don't want to DOS the entire OS RAM usage
> +     */
> +    if (virAsprintf(&opts,
> +                    "mode=755,size=65536%s", mount_options) < 0)
> +        goto cleanup;
> +
> +    if (virFileSetupDev(path, opts) < 0)
> +        goto cleanup;
> +
> +    if (qemuDomainPopulateDevices(driver, vm, path) < 0)
> +        goto cleanup;
> +
> +    ret = 0;
> + cleanup:
> +    VIR_FREE(opts);
> +    VIR_FREE(mount_options);
> +    return ret;
> +}
> +
> +
> +static int
> +qemuDomainSetupDevPTS(virQEMUDriverPtr driver,
> +                      virDomainObjPtr vm,
> +                      const char *path)
> +{
> +    char *mount_options = NULL;
> +    char *opts = NULL;
> +    int ret = -1;
> +    const gid_t ptsgid = 5;
> +
> +    mount_options = virSecurityManagerGetMountOptions(driver->securityManager,
> +                                                      vm->def);
> +
> +    if (!mount_options &&
> +        VIR_STRDUP(mount_options, "") < 0)
> +        goto cleanup;
> +
> +    if (virAsprintf(&opts, "newinstance,ptmxmode=0666,mode=0620,gid=%u%s",
> +                    ptsgid, (mount_options ? mount_options : "")) < 0)
> +        goto cleanup;
> +
> +    if (virFileSetupDevPTS(path, opts, NULL) < 0)
> +        goto cleanup;
> +
> +    ret = 0;
> + cleanup:
> +    VIR_FREE(opts);
> +    VIR_FREE(mount_options);
> +    return ret;
> +}

This is going to cause problems - the /dev/pts/NNN nodes that
QEMU has open (for its chardev backend) are exposed in the
guest XML and are intended to be accessed by other processes
on the host. By setting up a new /dev/pts mount with newinstance,
the /dev/pts/NNN nodes for chardevs will be invisible to the host
OS.

So while you want to replace /dev completely, you need to keep
the original /dev/pts mount unchanged. Practically speaking
this means that after doing the unshare() you need to use
mount() with MS_MOVE to move /dev/pts somewhere safe, then
unmount the old /dev, mount our new /dev instance and then
finally MS_MOVE the saved /dev/pts back in place.


Regards,
Daniel
-- 
|: http://berrange.com      -o-    http://www.flickr.com/photos/dberrange/ :|
|: http://libvirt.org              -o-             http://virt-manager.org :|
|: http://entangle-photo.org       -o-    http://search.cpan.org/~danberr/ :|




More information about the libvir-list mailing list