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 :|