This patch is more focused on access control. CGroups has a controller that enforces ACLs on device nodes. This allows us to restrict exactly what block/character devices a guest is allowed to access. So in the absence of something like SELinux sVirt, you can get a degree of isolation between VMs on block device backed disks. This sets up an initial deny-all policy, and then iterates over all the disks defined for a VM, allowing each one in turn. Finally it allows a handy of common nodes like /dev/null, /dev/random, /dev/ptmx and friends, which all processes need to use. Daniel diff --git a/src/cgroup.c b/src/cgroup.c --- a/src/cgroup.c +++ b/src/cgroup.c @@ -788,6 +788,23 @@ int virCgroupAllowDeviceMajor(virCgroupP return rc; } +int virCgroupAllowDevicePath(virCgroupPtr group, + const char *path) +{ + struct stat sb; + + if (stat(path, &sb) < 0) + return -errno; + + if (!S_ISCHR(sb.st_mode) && !S_ISBLK(sb.st_mode)) + return -EINVAL; + + return virCgroupAllowDevice(group, + S_ISCHR(sb.st_mode) ? 'c' : 'b', + major(sb.st_rdev), + minor(sb.st_rdev)); +} + int virCgroupSetCpuShares(virCgroupPtr group, unsigned long shares) { return virCgroupSetValueU64(group, "cpu.shares", (uint64_t)shares); diff --git a/src/cgroup.h b/src/cgroup.h --- a/src/cgroup.h +++ b/src/cgroup.h @@ -38,6 +38,8 @@ int virCgroupAllowDevice(virCgroupPtr gr int virCgroupAllowDeviceMajor(virCgroupPtr group, char type, int major); +int virCgroupAllowDevicePath(virCgroupPtr group, + const char *path); int virCgroupSetCpuShares(virCgroupPtr group, unsigned long shares); int virCgroupGetCpuShares(virCgroupPtr group, unsigned long *shares); diff --git a/src/qemu_driver.c b/src/qemu_driver.c --- a/src/qemu_driver.c +++ b/src/qemu_driver.c @@ -1135,11 +1135,18 @@ static int qemudNextFreeVNCPort(struct q static virDomainPtr qemudDomainLookupByName(virConnectPtr conn, const char *name); +static const char *const devs[] = { + "/dev/null", "/dev/full", "/dev/zero", + "/dev/random", "/dev/urandom", + "/dev/ptmx", "/dev/kvm", "/dev/kqemu", +}; + static int qemuSetupCgroup(virConnectPtr conn, struct qemud_driver *driver ATTRIBUTE_UNUSED, virDomainObjPtr vm) { virCgroupPtr cgroup = NULL; + unsigned int i; if (virCgroupHaveSupport() != 0) return 0; /* Not supported, so claim success */ @@ -1151,6 +1158,41 @@ static int qemuSetupCgroup(virConnectPtr goto cleanup; } + if (virCgroupDenyAllDevices(cgroup) != 0) + goto cleanup; + + for (i = 0; i < vm->def->ndisks ; i++) { + if (vm->def->disks[i]->type != VIR_DOMAIN_DISK_TYPE_BLOCK) + continue; + + if (virCgroupAllowDevicePath(cgroup, + vm->def->disks[i]->src) < 0) { + qemudReportError(conn, NULL, NULL, VIR_ERR_INTERNAL_ERROR, + _("unable to allow device %s"), + vm->def->disks[i]->src); + goto cleanup; + } + } + + if (virCgroupAllowDeviceMajor(cgroup, 'c', 136) < 0) { + qemudReportError(conn, NULL, NULL, VIR_ERR_INTERNAL_ERROR, + _("unable to allow device %s"), + devs[i]); + goto cleanup; + } + + for (i = 0; i < ARRAY_CARDINALITY(devs) ; i++) { + int rc; + if ((rc = virCgroupAllowDevicePath(cgroup, + devs[i])) < 0 && + rc != -ENOENT) { + qemudReportError(conn, NULL, NULL, VIR_ERR_INTERNAL_ERROR, + _("unable to allow device %s"), + devs[i]); + goto cleanup; + } + } + virCgroupFree(&cgroup); return 0; -- |: Red Hat, Engineering, London -o- http://people.redhat.com/berrange/ :| |: http://libvirt.org -o- http://virt-manager.org -o- http://ovirt.org :| |: http://autobuild.org -o- http://search.cpan.org/~danberr/ :| |: GnuPG: 7D3B9505 -o- F3C9 553F A1DA 4AC2 5648 23C1 B3DF F742 7D3B 9505 :| -- Libvir-list mailing list Libvir-list@xxxxxxxxxx https://www.redhat.com/mailman/listinfo/libvir-list