virCapsPtr virQEMUDriverCreateCapabilities(virQEMUDriverPtr driver) { size_t i, j; virCapsPtr caps; virSecurityManagerPtr *sec_managers = NULL; /* Security driver data */ const char *doi, *model, *lbl, *type; virQEMUDriverConfigPtr cfg = virQEMUDriverGetConfig(driver); const int virtTypes[] = {VIR_DOMAIN_VIRT_KVM, VIR_DOMAIN_VIRT_QEMU,}; /* Basic host arch / guest machine capabilities */ if (!(caps = virQEMUCapsInit(driver->qemuCapsCache))) goto error; if (virGetHostUUID(caps->host.host_uuid)) { virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("cannot get the host uuid")); goto error; } /* access sec drivers and create a sec model for each one */ if (!(sec_managers = virSecurityManagerGetNested(driver->securityManager))) goto error; /* calculate length */ for (i = 0; sec_managers[i]; i++) ; caps->host.nsecModels = i; if (VIR_ALLOC_N(caps->host.secModels, caps->host.nsecModels) < 0) goto error; for (i = 0; sec_managers[i]; i++) { virCapsHostSecModelPtr sm = &caps->host.secModels[i]; doi = virSecurityManagerGetDOI(sec_managers[i]); model = virSecurityManagerGetModel(sec_managers[i]); if (VIR_STRDUP(sm->model, model) < 0 || VIR_STRDUP(sm->doi, doi) < 0) goto error; for (j = 0; j < ARRAY_CARDINALITY(virtTypes); j++) { lbl = virSecurityManagerGetBaseLabel(sec_managers[i], virtTypes[j]); type = virDomainVirtTypeToString(virtTypes[j]); if (lbl && virCapabilitiesHostSecModelAddBaseLabel(sm, type, lbl) < 0) goto error; } VIR_DEBUG("Initialized caps for security driver \"%s\" with " "DOI \"%s\"", model, doi); } VIR_FREE(sec_managers); virObjectUnref(cfg); return caps; error: VIR_FREE(sec_managers); virObjectUnref(caps); virObjectUnref(cfg); return NULL; }
static int qemuSetupDevicesCgroup(virQEMUDriverPtr driver, virDomainObjPtr vm) { qemuDomainObjPrivatePtr priv = vm->privateData; virQEMUDriverConfigPtr cfg = NULL; const char *const *deviceACL = NULL; int rv = -1; int ret = -1; size_t i; if (!virCgroupHasController(priv->cgroup, VIR_CGROUP_CONTROLLER_DEVICES)) return 0; rv = virCgroupDenyAllDevices(priv->cgroup); virDomainAuditCgroup(vm, priv->cgroup, "deny", "all", rv == 0); if (rv < 0) { if (virLastErrorIsSystemErrno(EPERM)) { virResetLastError(); VIR_WARN("Group devices ACL is not accessible, disabling whitelisting"); return 0; } goto cleanup; } for (i = 0; i < vm->def->ndisks; i++) { if (qemuSetupDiskCgroup(vm, vm->def->disks[i]) < 0) goto cleanup; } rv = virCgroupAllowDeviceMajor(priv->cgroup, 'c', DEVICE_PTY_MAJOR, VIR_CGROUP_DEVICE_RW); virDomainAuditCgroupMajor(vm, priv->cgroup, "allow", DEVICE_PTY_MAJOR, "pty", "rw", rv == 0); if (rv < 0) goto cleanup; cfg = virQEMUDriverGetConfig(driver); deviceACL = cfg->cgroupDeviceACL ? (const char *const *)cfg->cgroupDeviceACL : defaultDeviceACL; if (vm->def->nsounds && ((!vm->def->ngraphics && cfg->nogfxAllowHostAudio) || (vm->def->graphics && ((vm->def->graphics[0]->type == VIR_DOMAIN_GRAPHICS_TYPE_VNC && cfg->vncAllowHostAudio) || (vm->def->graphics[0]->type == VIR_DOMAIN_GRAPHICS_TYPE_SDL))))) { rv = virCgroupAllowDeviceMajor(priv->cgroup, 'c', DEVICE_SND_MAJOR, VIR_CGROUP_DEVICE_RW); virDomainAuditCgroupMajor(vm, priv->cgroup, "allow", DEVICE_SND_MAJOR, "sound", "rw", rv == 0); if (rv < 0) goto cleanup; } for (i = 0; deviceACL[i] != NULL; i++) { if (!virFileExists(deviceACL[i])) { VIR_DEBUG("Ignoring non-existent device %s", deviceACL[i]); continue; } rv = virCgroupAllowDevicePath(priv->cgroup, deviceACL[i], VIR_CGROUP_DEVICE_RW); virDomainAuditCgroupPath(vm, priv->cgroup, "allow", deviceACL[i], "rw", rv == 0); if (rv < 0 && !virLastErrorIsSystemErrno(ENOENT)) goto cleanup; } if (virDomainChrDefForeach(vm->def, true, qemuSetupChardevCgroup, vm) < 0) goto cleanup; if (vm->def->tpm && (qemuSetupTPMCgroup(vm->def, vm->def->tpm, vm) < 0)) goto cleanup; for (i = 0; i < vm->def->nhostdevs; i++) { if (qemuSetupHostdevCGroup(vm, vm->def->hostdevs[i]) < 0) goto cleanup; } for (i = 0; i < vm->def->nrngs; i++) { if (vm->def->rngs[i]->backend == VIR_DOMAIN_RNG_BACKEND_RANDOM) { VIR_DEBUG("Setting Cgroup ACL for RNG device"); rv = virCgroupAllowDevicePath(priv->cgroup, vm->def->rngs[i]->source.file, VIR_CGROUP_DEVICE_RW); virDomainAuditCgroupPath(vm, priv->cgroup, "allow", vm->def->rngs[i]->source.file, "rw", rv == 0); if (rv < 0 && !virLastErrorIsSystemErrno(ENOENT)) goto cleanup; } } ret = 0; cleanup: virObjectUnref(cfg); return ret; }
static int qemuInitCgroup(virQEMUDriverPtr driver, virDomainObjPtr vm, size_t nnicindexes, int *nicindexes) { int ret = -1; qemuDomainObjPrivatePtr priv = vm->privateData; virQEMUDriverConfigPtr cfg = virQEMUDriverGetConfig(driver); if (!virQEMUDriverIsPrivileged(driver)) goto done; if (!virCgroupAvailable()) goto done; virCgroupFree(&priv->cgroup); if (!vm->def->resource) { virDomainResourceDefPtr res; if (VIR_ALLOC(res) < 0) goto cleanup; if (VIR_STRDUP(res->partition, "/machine") < 0) { VIR_FREE(res); goto cleanup; } vm->def->resource = res; } if (vm->def->resource->partition[0] != '/') { virReportError(VIR_ERR_CONFIG_UNSUPPORTED, _("Resource partition '%s' must start with '/'"), vm->def->resource->partition); goto cleanup; } /* * We need to do this because of systemd-machined, because * CreateMachine requires the name to be a valid hostname. */ priv->machineName = virSystemdMakeMachineName("qemu", vm->def->id, vm->def->name, virQEMUDriverIsPrivileged(driver)); if (!priv->machineName) goto cleanup; if (virCgroupNewMachine(priv->machineName, "qemu", vm->def->uuid, NULL, vm->pid, false, nnicindexes, nicindexes, vm->def->resource->partition, cfg->cgroupControllers, &priv->cgroup) < 0) { if (virCgroupNewIgnoreError()) goto done; goto cleanup; } done: ret = 0; cleanup: virObjectUnref(cfg); return ret; }