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

Michal Privoznik mprivozn at redhat.com
Mon Nov 14 17:07:44 UTC 2016


On 14.11.2016 17:55, Daniel P. Berrange wrote:
> 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.

Ah, good point. I will fix this.

Thanks for such quick review.

Michal




More information about the libvir-list mailing list