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