Device names can be manipulated, so it is better to also log the major/minor device number corresponding to the cgroup ACL changes that libvirt made. This required some refactoring of the relatively new qemu cgroup audit code. * src/qemu/qemu_audit.c (qemuDomainCgroupAudit): Drop a parameter. (qemuDomainCgroupAuditMajor, qemuDomainCgroupAuditPath): New functions, to allow listing device major/minor in audit. * src/qemu/qemu_driver.c (qemudDomainSaveFlag): Adjust callers. * src/qemu/qemu_cgroup.c (qemuSetupDiskPathAllow) (qemuSetupChardevCgroup, qemuSetupHostUsbDeviceCgroup) (qemuSetupCgroup, qemuTeardownDiskPathDeny): Likewise. --- src/qemu/qemu_audit.c | 104 +++++++++++++++++++++++++++++++++++++++++------- src/qemu/qemu_audit.h | 14 ++++++- src/qemu/qemu_cgroup.c | 29 +++++++------ src/qemu/qemu_driver.c | 8 ++-- 4 files changed, 120 insertions(+), 35 deletions(-) diff --git a/src/qemu/qemu_audit.c b/src/qemu/qemu_audit.c index 0f954c0..0d85fa7 100644 --- a/src/qemu/qemu_audit.c +++ b/src/qemu/qemu_audit.c @@ -23,6 +23,9 @@ #include <config.h> +#include <sys/stat.h> +#include <sys/types.h> + #include "qemu_audit.h" #include "virtaudit.h" #include "uuid.h" @@ -176,9 +179,10 @@ cleanup: * @vm: domain making the cgroups ACL change * @cgroup: cgroup that manages the devices * @reason: either "allow" or "deny" - * @item: one of "all", "path", or "major" - * @name: NULL for @item of "all", device path for @item of "path", and - * string describing major device type for @item of "major" + * @extra: additional details, in the form "all", + * "major category=xyz maj=nn", or "path path=xyz dev=nn:mm" (the + * latter two are generated by qemuDomainCgroupAuditMajor and + * qemuDomainCgroupAuditPath). * @success: true if the cgroup operation succeeded * * Log an audit message about an attempted cgroup device ACL change. @@ -186,37 +190,107 @@ cleanup: void qemuDomainCgroupAudit(virDomainObjPtr vm, virCgroupPtr cgroup ATTRIBUTE_UNUSED, const char *reason, - const char *item, - const char *name, + const char *extra, bool success) { char uuidstr[VIR_UUID_STRING_BUFLEN]; char *vmname; - char *detail = NULL; virUUIDFormat(vm->def->uuid, uuidstr); if (!(vmname = virAuditEncode("vm", vm->def->name))) { VIR_WARN0("OOM while encoding audit message"); return; } - if (name && - !(detail = virAuditEncode(STREQ(item, "path") ? "path" : "category", - name))) { + + VIR_AUDIT(VIR_AUDIT_RECORD_RESOURCE, success, + "resrc=cgroup reason=%s %s uuid=%s class=%s", + reason, vmname, uuidstr, extra); + + VIR_FREE(vmname); +} + +/** + * qemuDomainCgroupAuditMajor: + * @vm: domain making the cgroups ACL change + * @cgroup: cgroup that manages the devices + * @reason: either "allow" or "deny" + * @maj: the major number of the device category + * @name: a textual name for that device category, alphabetic only + * @success: true if the cgroup operation succeeded + * + * Log an audit message about an attempted cgroup device ACL change. + */ +void qemuDomainCgroupAuditMajor(virDomainObjPtr vm, + virCgroupPtr cgroup, + const char *reason, + int maj, + const char *name, + bool success) +{ + char *extra; + + if (virAsprintf(&extra, "major category=%s maj=%02X", name, maj) < 0) { + VIR_WARN0("OOM while encoding audit message"); + return; + } + + qemuDomainCgroupAudit(vm, cgroup, reason, extra, success); + + VIR_FREE(extra); +} + +/** + * qemuDomainCgroupAuditPath: + * @vm: domain making the cgroups ACL change + * @cgroup: cgroup that manages the devices + * @reason: either "allow" or "deny" + * @path: the device being adjusted + * @success: true if the cgroup operation succeeded + * + * Log an audit message about an attempted cgroup device ACL change to + * a specific device. + */ +void qemuDomainCgroupAuditPath(virDomainObjPtr vm, + virCgroupPtr cgroup, + const char *reason, + const char *path, + bool success) +{ + char *detail; + char *extra; + int rc; + + if (!(detail = virAuditEncode("path", path))) { + VIR_WARN0("OOM while encoding audit message"); + return; + } + +#if defined major && defined minor + struct stat sb; + if (stat(path, &sb) == 0 && + (S_ISCHR(sb.st_mode) || S_ISBLK(sb.st_mode))) { + int maj = major(sb.st_rdev); + int min = minor(sb.st_rdev); + rc = virAsprintf(&extra, "path path=%s rdev=%02X:%02X", + path, maj, min); + } else +#endif + { + rc = virAsprintf(&extra, "path path=%s rdev=?", path); + } + + if (rc < 0) { VIR_WARN0("OOM while encoding audit message"); goto cleanup; } - VIR_AUDIT(VIR_AUDIT_RECORD_RESOURCE, success, - "resrc=cgroup reason=%s %s uuid=%s class=%s%s%s", - reason, vmname, uuidstr, - item, detail ? " " : "", detail ? detail : ""); + qemuDomainCgroupAudit(vm, cgroup, reason, extra, success); cleanup: - VIR_FREE(vmname); + VIR_FREE(extra); VIR_FREE(detail); } - /** * qemuDomainResourceAudit: * @vm: domain making an integer resource change diff --git a/src/qemu/qemu_audit.h b/src/qemu/qemu_audit.h index 247edde..500eb98 100644 --- a/src/qemu/qemu_audit.h +++ b/src/qemu/qemu_audit.h @@ -46,9 +46,19 @@ void qemuDomainHostdevAudit(virDomainObjPtr vm, void qemuDomainCgroupAudit(virDomainObjPtr vm, virCgroupPtr group, const char *reason, - const char *item, - const char *name, + const char *extra, bool success); +void qemuDomainCgroupAuditMajor(virDomainObjPtr vm, + virCgroupPtr group, + const char *reason, + int maj, + const char *name, + bool success); +void qemuDomainCgroupAuditPath(virDomainObjPtr vm, + virCgroupPtr group, + const char *reason, + const char *path, + bool success); void qemuDomainMemoryAudit(virDomainObjPtr vm, unsigned long long oldmem, unsigned long long newmem, diff --git a/src/qemu/qemu_cgroup.c b/src/qemu/qemu_cgroup.c index e71d3fa..b911005 100644 --- a/src/qemu/qemu_cgroup.c +++ b/src/qemu/qemu_cgroup.c @@ -68,8 +68,8 @@ qemuSetupDiskPathAllow(virDomainDiskDefPtr disk ATTRIBUTE_UNUSED, /* XXX RO vs RW */ rc = virCgroupAllowDevicePath(data->cgroup, path); if (rc <= 0) - qemuDomainCgroupAudit(data->vm, data->cgroup, "allow", "path", path, - rc == 0); + qemuDomainCgroupAuditPath(data->vm, data->cgroup, "allow", path, + rc == 0); if (rc < 0) { if (rc == -EACCES) { /* Get this for root squash NFS */ VIR_DEBUG("Ignoring EACCES for %s", path); @@ -111,8 +111,8 @@ qemuTeardownDiskPathDeny(virDomainDiskDefPtr disk ATTRIBUTE_UNUSED, /* XXX RO vs RW */ rc = virCgroupDenyDevicePath(data->cgroup, path); if (rc <= 0) - qemuDomainCgroupAudit(data->vm, data->cgroup, "deny", "path", path, - rc == 0); + qemuDomainCgroupAuditPath(data->vm, data->cgroup, "deny", path, + rc == 0); if (rc < 0) { if (rc == -EACCES) { /* Get this for root squash NFS */ VIR_DEBUG("Ignoring EACCES for %s", path); @@ -156,8 +156,8 @@ qemuSetupChardevCgroup(virDomainDefPtr def, VIR_DEBUG("Process path '%s' for disk", dev->source.data.file.path); rc = virCgroupAllowDevicePath(data->cgroup, dev->source.data.file.path); if (rc < 0) - qemuDomainCgroupAudit(data->vm, data->cgroup, "allow", "path", - dev->source.data.file.path, rc == 0); + qemuDomainCgroupAuditPath(data->vm, data->cgroup, "allow", + dev->source.data.file.path, rc == 0); if (rc < 0) { virReportSystemError(-rc, _("Unable to allow device %s for %s"), @@ -179,8 +179,8 @@ int qemuSetupHostUsbDeviceCgroup(usbDevice *dev ATTRIBUTE_UNUSED, VIR_DEBUG("Process path '%s' for USB device", path); rc = virCgroupAllowDevicePath(data->cgroup, path); if (rc <= 0) - qemuDomainCgroupAudit(data->vm, data->cgroup, "allow", "path", path, - rc == 0); + qemuDomainCgroupAuditPath(data->vm, data->cgroup, "allow", path, + rc == 0); if (rc < 0) { virReportSystemError(-rc, _("Unable to allow device %s"), @@ -216,7 +216,7 @@ int qemuSetupCgroup(struct qemud_driver *driver, if (qemuCgroupControllerActive(driver, VIR_CGROUP_CONTROLLER_DEVICES)) { qemuCgroupData data = { vm, cgroup }; rc = virCgroupDenyAllDevices(cgroup); - qemuDomainCgroupAudit(vm, cgroup, "deny", "all", NULL, rc == 0); + qemuDomainCgroupAudit(vm, cgroup, "deny", "all", rc == 0); if (rc != 0) { if (rc == -EPERM) { VIR_WARN0("Group devices ACL is not accessible, disabling whitelisting"); @@ -234,7 +234,8 @@ int qemuSetupCgroup(struct qemud_driver *driver, } rc = virCgroupAllowDeviceMajor(cgroup, 'c', DEVICE_PTY_MAJOR); - qemuDomainCgroupAudit(vm, cgroup, "allow", "major", "pty", rc == 0); + qemuDomainCgroupAuditMajor(vm, cgroup, "allow", DEVICE_PTY_MAJOR, + "pty", rc == 0); if (rc != 0) { virReportSystemError(-rc, "%s", _("unable to allow /dev/pts/ devices")); @@ -247,8 +248,8 @@ int qemuSetupCgroup(struct qemud_driver *driver, driver->vncAllowHostAudio) || (vm->def->graphics[0]->type == VIR_DOMAIN_GRAPHICS_TYPE_SDL)))) { rc = virCgroupAllowDeviceMajor(cgroup, 'c', DEVICE_SND_MAJOR); - qemuDomainCgroupAudit(vm, cgroup, "allow", "major", "sound", - rc == 0); + qemuDomainCgroupAuditMajor(vm, cgroup, "allow", DEVICE_SND_MAJOR, + "sound", rc == 0); if (rc != 0) { virReportSystemError(-rc, "%s", _("unable to allow /dev/snd/ devices")); @@ -259,8 +260,8 @@ int qemuSetupCgroup(struct qemud_driver *driver, for (i = 0; deviceACL[i] != NULL ; i++) { rc = virCgroupAllowDevicePath(cgroup, deviceACL[i]); - qemuDomainCgroupAudit(vm, cgroup, "allow", "path", - deviceACL[i], rc == 0); + qemuDomainCgroupAuditPath(vm, cgroup, "allow", + deviceACL[i], rc == 0); if (rc < 0 && rc != -ENOENT) { virReportSystemError(-rc, diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c index 0f7cbad..cb5d7ef 100644 --- a/src/qemu/qemu_driver.c +++ b/src/qemu/qemu_driver.c @@ -1965,7 +1965,7 @@ static int qemudDomainSaveFlag(struct qemud_driver *driver, virDomainPtr dom, } rc = virCgroupAllowDevicePath(cgroup, path); if (rc <= 0) - qemuDomainCgroupAudit(vm, cgroup, "allow", "path", path, rc == 0); + qemuDomainCgroupAuditPath(vm, cgroup, "allow", path, rc == 0); if (rc < 0) { virReportSystemError(-rc, _("Unable to allow device %s for %s"), @@ -2016,7 +2016,7 @@ static int qemudDomainSaveFlag(struct qemud_driver *driver, virDomainPtr dom, if (cgroup != NULL) { rc = virCgroupDenyDevicePath(cgroup, path); if (rc <= 0) - qemuDomainCgroupAudit(vm, cgroup, "deny", "path", path, rc == 0); + qemuDomainCgroupAuditPath(vm, cgroup, "deny", path, rc == 0); if (rc < 0) VIR_WARN("Unable to deny device %s for %s %d", path, vm->def->name, rc); @@ -2049,8 +2049,8 @@ endjob: if (cgroup != NULL) { rc = virCgroupDenyDevicePath(cgroup, path); if (rc <= 0) - qemuDomainCgroupAudit(vm, cgroup, "deny", "path", path, - rc == 0); + qemuDomainCgroupAuditPath(vm, cgroup, "deny", path, + rc == 0); if (rc < 0) VIR_WARN("Unable to deny device %s for %s: %d", path, vm->def->name, rc); -- 1.7.4 -- libvir-list mailing list libvir-list@xxxxxxxxxx https://www.redhat.com/mailman/listinfo/libvir-list