* src/qemu/qemu_audit.h (qemuDomainHostdevAudit): New prototype.
* src/qemu/qemu_audit.c (qemuDomainHostdevAudit): New function.
(qemuDomainStartAudit): Call as appropriate.
* src/qemu/qemu_hotplug.c (qemuDomainAttachHostPciDevice)
(qemuDomainAttachHostUsbDevice, qemuDomainDetachHostPciDevice)
(qemuDomainDetachHostUsbDevice): Likewise.
---
v2: new patch; covers the case of pci and usb host device passthrough,
worth auditing since this can involve IOMMU mappings to have the guest
manage the device I/O.
src/qemu/qemu_audit.c | 74 +++++++++++++++++++++++++++++++++++++++++++++++
src/qemu/qemu_audit.h | 4 ++
src/qemu/qemu_hotplug.c | 28 +++++++-----------
3 files changed, 89 insertions(+), 17 deletions(-)
diff --git a/src/qemu/qemu_audit.c b/src/qemu/qemu_audit.c
index 6ea31c9..26247a6 100644
--- a/src/qemu/qemu_audit.c
+++ b/src/qemu/qemu_audit.c
@@ -103,6 +103,75 @@ void qemuDomainNetAudit(virDomainObjPtr vm,
/**
+ * qemuDomainHostdevAudit:
+ * @vm: domain making a change in pass-through host device
+ * @hostdev: device being attached or removed
+ * @reason: one of "start, "attach", or "detach"
+ * @success: true if the device passthrough operation succeeded
+ *
+ * Log an audit message about an attempted device passthrough change.
+ */
+void
+qemuDomainHostdevAudit(virDomainObjPtr vm,
+ virDomainHostdevDefPtr hostdev,
+ const char *reason,
+ bool success)
+{
+ char uuidstr[VIR_UUID_STRING_BUFLEN];
+ char *vmname;
+ char *address;
+ char *device;
+
+ virUUIDFormat(vm->def->uuid, uuidstr);
+ if (!(vmname = virAuditEncode("vm", vm->def->name))) {
+ VIR_WARN0("OOM while encoding audit message");
+ return;
+ }
+
+ switch (hostdev->source.subsys.type) {
+ case VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_PCI:
+ if (virAsprintf(&address, "%.4x:%.2x:%.2x.%.1x",
+ hostdev->source.subsys.u.pci.domain,
+ hostdev->source.subsys.u.pci.bus,
+ hostdev->source.subsys.u.pci.slot,
+ hostdev->source.subsys.u.pci.function) < 0) {
+ VIR_WARN0("OOM while encoding audit message");
+ goto cleanup;
+ }
+ break;
+ case VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_USB:
+ if (virAsprintf(&address, "%.3d.%.3d",
+ hostdev->source.subsys.u.usb.bus,
+ hostdev->source.subsys.u.usb.device) < 0) {
+ VIR_WARN0("OOM while encoding audit message");
+ goto cleanup;
+ }
+ break;
+ default:
+ VIR_WARN("Unexpected hostdev type while encoding audit message: %d",
+ hostdev->source.subsys.type);
+ goto cleanup;
+ }
+
+ if (!(device = virAuditEncode("device", VIR_AUDIT_STR(address)))) {
+ VIR_WARN0("OOM while encoding audit message");
+ goto cleanup;
+ }
+
+ VIR_AUDIT(VIR_AUDIT_RECORD_RESOURCE, success,
+ "resrc=dev reason=%s %s uuid=%s type=%s %s",
+ reason, vmname, uuidstr,
+ virDomainHostdevSubsysTypeToString(hostdev->source.subsys.type),
+ device);
+
+cleanup:
+ VIR_FREE(vmname);
+ VIR_FREE(device);
+ VIR_FREE(address);
+}
+
+
+/**
* qemuDomainCgroupAudit:
* @vm: domain making the cgroups ACL change
* @cgroup: cgroup that manages the devices
@@ -238,6 +307,11 @@ void qemuDomainStartAudit(virDomainObjPtr vm, const char *reason,
bool success)
qemuDomainNetAudit(vm, NULL, net, "start", true);
}
+ for (i = 0 ; i < vm->def->nhostdevs ; i++) {
+ virDomainHostdevDefPtr hostdev = vm->def->hostdevs[i];
+ qemuDomainHostdevAudit(vm, hostdev, "start", true);
+ }
+
qemuDomainMemoryAudit(vm, 0, vm->def->mem.cur_balloon, "start",
true);
qemuDomainVcpuAudit(vm, 0, vm->def->vcpus, "start", true);
diff --git a/src/qemu/qemu_audit.h b/src/qemu/qemu_audit.h
index cdbb957..2f901be 100644
--- a/src/qemu/qemu_audit.h
+++ b/src/qemu/qemu_audit.h
@@ -39,6 +39,10 @@ void qemuDomainNetAudit(virDomainObjPtr vm,
virDomainNetDefPtr newDef,
const char *reason,
bool success);
+void qemuDomainHostdevAudit(virDomainObjPtr vm,
+ virDomainHostdevDefPtr def,
+ const char *reason,
+ bool success);
void qemuDomainCgroupAudit(virDomainObjPtr vm,
virCgroupPtr group,
const char *reason,
diff --git a/src/qemu/qemu_hotplug.c b/src/qemu/qemu_hotplug.c
index 8090b90..da07c29 100644
--- a/src/qemu/qemu_hotplug.c
+++ b/src/qemu/qemu_hotplug.c
@@ -842,6 +842,7 @@ int qemuDomainAttachHostPciDevice(struct qemud_driver *driver,
hostdev->info.type = VIR_DOMAIN_DEVICE_ADDRESS_TYPE_PCI;
memcpy(&hostdev->info.addr.pci, &guestAddr, sizeof(guestAddr));
}
+ qemuDomainHostdevAudit(vm, hostdev, "attach", ret == 0);
if (ret < 0)
goto error;
@@ -918,6 +919,7 @@ int qemuDomainAttachHostUsbDevice(struct qemud_driver *driver,
hostdev->source.subsys.u.usb.bus,
hostdev->source.subsys.u.usb.device);
qemuDomainObjExitMonitorWithDriver(driver, vm);
+ qemuDomainHostdevAudit(vm, hostdev, "attach", ret == 0);
if (ret < 0)
goto error;
@@ -1607,20 +1609,14 @@ int qemuDomainDetachHostPciDevice(struct qemud_driver *driver,
qemuDomainObjEnterMonitorWithDriver(driver, vm);
if (qemuCapsGet(qemuCaps, QEMU_CAPS_DEVICE)) {
- if (qemuMonitorDelDevice(priv->mon, detach->info.alias) < 0) {
- qemuDomainObjExitMonitor(vm);
- return -1;
- }
+ ret = qemuMonitorDelDevice(priv->mon, detach->info.alias);
} else {
- if (qemuMonitorRemovePCIDevice(priv->mon,
- &detach->info.addr.pci) < 0) {
- qemuDomainObjExitMonitorWithDriver(driver, vm);
- return -1;
- }
+ ret = qemuMonitorRemovePCIDevice(priv->mon, &detach->info.addr.pci);
}
qemuDomainObjExitMonitorWithDriver(driver, vm);
-
- ret = 0;
+ qemuDomainHostdevAudit(vm, detach, "detach", ret == 0);
+ if (ret < 0)
+ return -1;
pci = pciGetDevice(detach->source.subsys.u.pci.domain,
detach->source.subsys.u.pci.bus,
@@ -1715,13 +1711,11 @@ int qemuDomainDetachHostUsbDevice(struct qemud_driver *driver,
}
qemuDomainObjEnterMonitorWithDriver(driver, vm);
- if (qemuMonitorDelDevice(priv->mon, detach->info.alias) < 0) {
- qemuDomainObjExitMonitorWithDriver(driver, vm);
- return -1;
- }
+ ret = qemuMonitorDelDevice(priv->mon, detach->info.alias);
qemuDomainObjExitMonitorWithDriver(driver, vm);
-
- ret = 0;
+ qemuDomainHostdevAudit(vm, detach, "detach", ret == 0);
+ if (ret < 0)
+ return -1;
if (vm->def->nhostdevs > 1) {
memmove(vm->def->hostdevs + i,
--
1.7.4