mirror of
https://gitlab.com/libvirt/libvirt.git
synced 2025-03-07 17:28:15 +00:00
audit: add qemu hooks for auditing cgroup events
* src/qemu/qemu_audit.h (qemuDomainCgroupAudit): New prototype. * src/qemu/qemu_audit.c (qemuDomainCgroupAudit): Implement it. * src/qemu/qemu_driver.c (qemudDomainSaveFlag): Add audit. * src/qemu/qemu_cgroup.c (qemuSetupDiskPathAllow) (qemuSetupChardevCgroup, qemuSetupHostUsbDeviceCgroup) (qemuSetupCgroup, qemuTeardownDiskPathDeny): Likewise.
This commit is contained in:
parent
b4d3434fc2
commit
6bb98d419f
@ -1,7 +1,7 @@
|
|||||||
/*
|
/*
|
||||||
* qemu_audit.c: QEMU audit management
|
* qemu_audit.c: QEMU audit management
|
||||||
*
|
*
|
||||||
* Copyright (C) 2006-2007, 2009-2010 Red Hat, Inc.
|
* Copyright (C) 2006-2011 Red Hat, Inc.
|
||||||
* Copyright (C) 2006 Daniel P. Berrange
|
* Copyright (C) 2006 Daniel P. Berrange
|
||||||
*
|
*
|
||||||
* This library is free software; you can redistribute it and/or
|
* This library is free software; you can redistribute it and/or
|
||||||
@ -102,6 +102,52 @@ void qemuDomainNetAudit(virDomainObjPtr vm,
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* qemuDomainCgroupAudit:
|
||||||
|
* @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"
|
||||||
|
* @success: true if the cgroup operation succeeded
|
||||||
|
*
|
||||||
|
* Log an audit message about an attempted cgroup device ACL change.
|
||||||
|
*/
|
||||||
|
void qemuDomainCgroupAudit(virDomainObjPtr vm,
|
||||||
|
virCgroupPtr cgroup ATTRIBUTE_UNUSED,
|
||||||
|
const char *reason,
|
||||||
|
const char *item,
|
||||||
|
const char *name,
|
||||||
|
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" : "type",
|
||||||
|
name))) {
|
||||||
|
VIR_WARN0("OOM while encoding audit message");
|
||||||
|
goto cleanup;
|
||||||
|
}
|
||||||
|
|
||||||
|
VIR_AUDIT(VIR_AUDIT_RECORD_RESOURCE, success,
|
||||||
|
"resrc=cgroup reason=%s %s uuid=%s item=%s%s%s",
|
||||||
|
reason, vmname, uuidstr,
|
||||||
|
item, detail ? " " : "", detail ? detail : "");
|
||||||
|
|
||||||
|
cleanup:
|
||||||
|
VIR_FREE(vmname);
|
||||||
|
VIR_FREE(detail);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
static void qemuDomainLifecycleAudit(virDomainObjPtr vm,
|
static void qemuDomainLifecycleAudit(virDomainObjPtr vm,
|
||||||
const char *op,
|
const char *op,
|
||||||
const char *reason,
|
const char *reason,
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
/*
|
/*
|
||||||
* qemu_audit.h: QEMU audit management
|
* qemu_audit.h: QEMU audit management
|
||||||
*
|
*
|
||||||
* Copyright (C) 2006-2007, 2009-2010 Red Hat, Inc.
|
* Copyright (C) 2006-2011 Red Hat, Inc.
|
||||||
* Copyright (C) 2006 Daniel P. Berrange
|
* Copyright (C) 2006 Daniel P. Berrange
|
||||||
*
|
*
|
||||||
* This library is free software; you can redistribute it and/or
|
* This library is free software; you can redistribute it and/or
|
||||||
@ -25,6 +25,7 @@
|
|||||||
# define __QEMU_AUDIT_H__
|
# define __QEMU_AUDIT_H__
|
||||||
|
|
||||||
# include "domain_conf.h"
|
# include "domain_conf.h"
|
||||||
|
# include "cgroup.h"
|
||||||
|
|
||||||
void qemuDomainStartAudit(virDomainObjPtr vm, const char *reason, bool success);
|
void qemuDomainStartAudit(virDomainObjPtr vm, const char *reason, bool success);
|
||||||
void qemuDomainStopAudit(virDomainObjPtr vm, const char *reason);
|
void qemuDomainStopAudit(virDomainObjPtr vm, const char *reason);
|
||||||
@ -38,6 +39,12 @@ void qemuDomainNetAudit(virDomainObjPtr vm,
|
|||||||
virDomainNetDefPtr newDef,
|
virDomainNetDefPtr newDef,
|
||||||
const char *reason,
|
const char *reason,
|
||||||
bool success);
|
bool success);
|
||||||
|
void qemuDomainCgroupAudit(virDomainObjPtr vm,
|
||||||
|
virCgroupPtr group,
|
||||||
|
const char *reason,
|
||||||
|
const char *item,
|
||||||
|
const char *name,
|
||||||
|
bool success);
|
||||||
void qemuDomainSecurityLabelAudit(virDomainObjPtr vm, bool success);
|
void qemuDomainSecurityLabelAudit(virDomainObjPtr vm, bool success);
|
||||||
|
|
||||||
#endif /* __QEMU_AUDIT_H__ */
|
#endif /* __QEMU_AUDIT_H__ */
|
||||||
|
@ -29,6 +29,7 @@
|
|||||||
#include "memory.h"
|
#include "memory.h"
|
||||||
#include "virterror_internal.h"
|
#include "virterror_internal.h"
|
||||||
#include "util.h"
|
#include "util.h"
|
||||||
|
#include "qemu_audit.h"
|
||||||
|
|
||||||
#define VIR_FROM_THIS VIR_FROM_QEMU
|
#define VIR_FROM_THIS VIR_FROM_QEMU
|
||||||
|
|
||||||
@ -66,6 +67,9 @@ qemuSetupDiskPathAllow(virDomainDiskDefPtr disk ATTRIBUTE_UNUSED,
|
|||||||
VIR_DEBUG("Process path %s for disk", path);
|
VIR_DEBUG("Process path %s for disk", path);
|
||||||
/* XXX RO vs RW */
|
/* XXX RO vs RW */
|
||||||
rc = virCgroupAllowDevicePath(data->cgroup, path);
|
rc = virCgroupAllowDevicePath(data->cgroup, path);
|
||||||
|
if (rc <= 0)
|
||||||
|
qemuDomainCgroupAudit(data->vm, data->cgroup, "allow", "path", path,
|
||||||
|
rc == 0);
|
||||||
if (rc < 0) {
|
if (rc < 0) {
|
||||||
if (rc == -EACCES) { /* Get this for root squash NFS */
|
if (rc == -EACCES) { /* Get this for root squash NFS */
|
||||||
VIR_DEBUG("Ignoring EACCES for %s", path);
|
VIR_DEBUG("Ignoring EACCES for %s", path);
|
||||||
@ -106,6 +110,9 @@ qemuTeardownDiskPathDeny(virDomainDiskDefPtr disk ATTRIBUTE_UNUSED,
|
|||||||
VIR_DEBUG("Process path %s for disk", path);
|
VIR_DEBUG("Process path %s for disk", path);
|
||||||
/* XXX RO vs RW */
|
/* XXX RO vs RW */
|
||||||
rc = virCgroupDenyDevicePath(data->cgroup, path);
|
rc = virCgroupDenyDevicePath(data->cgroup, path);
|
||||||
|
if (rc <= 0)
|
||||||
|
qemuDomainCgroupAudit(data->vm, data->cgroup, "deny", "path", path,
|
||||||
|
rc == 0);
|
||||||
if (rc < 0) {
|
if (rc < 0) {
|
||||||
if (rc == -EACCES) { /* Get this for root squash NFS */
|
if (rc == -EACCES) { /* Get this for root squash NFS */
|
||||||
VIR_DEBUG("Ignoring EACCES for %s", path);
|
VIR_DEBUG("Ignoring EACCES for %s", path);
|
||||||
@ -148,6 +155,9 @@ qemuSetupChardevCgroup(virDomainDefPtr def,
|
|||||||
|
|
||||||
VIR_DEBUG("Process path '%s' for disk", dev->source.data.file.path);
|
VIR_DEBUG("Process path '%s' for disk", dev->source.data.file.path);
|
||||||
rc = virCgroupAllowDevicePath(data->cgroup, 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);
|
||||||
if (rc < 0) {
|
if (rc < 0) {
|
||||||
virReportSystemError(-rc,
|
virReportSystemError(-rc,
|
||||||
_("Unable to allow device %s for %s"),
|
_("Unable to allow device %s for %s"),
|
||||||
@ -168,6 +178,9 @@ int qemuSetupHostUsbDeviceCgroup(usbDevice *dev ATTRIBUTE_UNUSED,
|
|||||||
|
|
||||||
VIR_DEBUG("Process path '%s' for USB device", path);
|
VIR_DEBUG("Process path '%s' for USB device", path);
|
||||||
rc = virCgroupAllowDevicePath(data->cgroup, path);
|
rc = virCgroupAllowDevicePath(data->cgroup, path);
|
||||||
|
if (rc <= 0)
|
||||||
|
qemuDomainCgroupAudit(data->vm, data->cgroup, "allow", "path", path,
|
||||||
|
rc == 0);
|
||||||
if (rc < 0) {
|
if (rc < 0) {
|
||||||
virReportSystemError(-rc,
|
virReportSystemError(-rc,
|
||||||
_("Unable to allow device %s"),
|
_("Unable to allow device %s"),
|
||||||
@ -203,6 +216,7 @@ int qemuSetupCgroup(struct qemud_driver *driver,
|
|||||||
if (qemuCgroupControllerActive(driver, VIR_CGROUP_CONTROLLER_DEVICES)) {
|
if (qemuCgroupControllerActive(driver, VIR_CGROUP_CONTROLLER_DEVICES)) {
|
||||||
qemuCgroupData data = { vm, cgroup };
|
qemuCgroupData data = { vm, cgroup };
|
||||||
rc = virCgroupDenyAllDevices(cgroup);
|
rc = virCgroupDenyAllDevices(cgroup);
|
||||||
|
qemuDomainCgroupAudit(vm, cgroup, "deny", "all", NULL, rc == 0);
|
||||||
if (rc != 0) {
|
if (rc != 0) {
|
||||||
if (rc == -EPERM) {
|
if (rc == -EPERM) {
|
||||||
VIR_WARN0("Group devices ACL is not accessible, disabling whitelisting");
|
VIR_WARN0("Group devices ACL is not accessible, disabling whitelisting");
|
||||||
@ -220,6 +234,7 @@ int qemuSetupCgroup(struct qemud_driver *driver,
|
|||||||
}
|
}
|
||||||
|
|
||||||
rc = virCgroupAllowDeviceMajor(cgroup, 'c', DEVICE_PTY_MAJOR);
|
rc = virCgroupAllowDeviceMajor(cgroup, 'c', DEVICE_PTY_MAJOR);
|
||||||
|
qemuDomainCgroupAudit(vm, cgroup, "allow", "major", "pty", rc == 0);
|
||||||
if (rc != 0) {
|
if (rc != 0) {
|
||||||
virReportSystemError(-rc, "%s",
|
virReportSystemError(-rc, "%s",
|
||||||
_("unable to allow /dev/pts/ devices"));
|
_("unable to allow /dev/pts/ devices"));
|
||||||
@ -228,6 +243,8 @@ int qemuSetupCgroup(struct qemud_driver *driver,
|
|||||||
|
|
||||||
if (vm->def->nsounds) {
|
if (vm->def->nsounds) {
|
||||||
rc = virCgroupAllowDeviceMajor(cgroup, 'c', DEVICE_SND_MAJOR);
|
rc = virCgroupAllowDeviceMajor(cgroup, 'c', DEVICE_SND_MAJOR);
|
||||||
|
qemuDomainCgroupAudit(vm, cgroup, "allow", "major", "sound",
|
||||||
|
rc == 0);
|
||||||
if (rc != 0) {
|
if (rc != 0) {
|
||||||
virReportSystemError(-rc, "%s",
|
virReportSystemError(-rc, "%s",
|
||||||
_("unable to allow /dev/snd/ devices"));
|
_("unable to allow /dev/snd/ devices"));
|
||||||
@ -238,6 +255,8 @@ int qemuSetupCgroup(struct qemud_driver *driver,
|
|||||||
for (i = 0; deviceACL[i] != NULL ; i++) {
|
for (i = 0; deviceACL[i] != NULL ; i++) {
|
||||||
rc = virCgroupAllowDevicePath(cgroup,
|
rc = virCgroupAllowDevicePath(cgroup,
|
||||||
deviceACL[i]);
|
deviceACL[i]);
|
||||||
|
qemuDomainCgroupAudit(vm, cgroup, "allow", "path",
|
||||||
|
deviceACL[i], rc == 0);
|
||||||
if (rc < 0 &&
|
if (rc < 0 &&
|
||||||
rc != -ENOENT) {
|
rc != -ENOENT) {
|
||||||
virReportSystemError(-rc,
|
virReportSystemError(-rc,
|
||||||
|
@ -1962,6 +1962,8 @@ static int qemudDomainSaveFlag(struct qemud_driver *driver, virDomainPtr dom,
|
|||||||
goto endjob;
|
goto endjob;
|
||||||
}
|
}
|
||||||
rc = virCgroupAllowDevicePath(cgroup, path);
|
rc = virCgroupAllowDevicePath(cgroup, path);
|
||||||
|
if (rc <= 0)
|
||||||
|
qemuDomainCgroupAudit(vm, cgroup, "allow", "path", path, rc == 0);
|
||||||
if (rc < 0) {
|
if (rc < 0) {
|
||||||
virReportSystemError(-rc,
|
virReportSystemError(-rc,
|
||||||
_("Unable to allow device %s for %s"),
|
_("Unable to allow device %s for %s"),
|
||||||
@ -2011,6 +2013,8 @@ static int qemudDomainSaveFlag(struct qemud_driver *driver, virDomainPtr dom,
|
|||||||
|
|
||||||
if (cgroup != NULL) {
|
if (cgroup != NULL) {
|
||||||
rc = virCgroupDenyDevicePath(cgroup, path);
|
rc = virCgroupDenyDevicePath(cgroup, path);
|
||||||
|
if (rc <= 0)
|
||||||
|
qemuDomainCgroupAudit(vm, cgroup, "deny", "path", path, rc == 0);
|
||||||
if (rc < 0)
|
if (rc < 0)
|
||||||
VIR_WARN("Unable to deny device %s for %s %d",
|
VIR_WARN("Unable to deny device %s for %s %d",
|
||||||
path, vm->def->name, rc);
|
path, vm->def->name, rc);
|
||||||
@ -2042,6 +2046,9 @@ endjob:
|
|||||||
|
|
||||||
if (cgroup != NULL) {
|
if (cgroup != NULL) {
|
||||||
rc = virCgroupDenyDevicePath(cgroup, path);
|
rc = virCgroupDenyDevicePath(cgroup, path);
|
||||||
|
if (rc <= 0)
|
||||||
|
qemuDomainCgroupAudit(vm, cgroup, "deny", "path", path,
|
||||||
|
rc == 0);
|
||||||
if (rc < 0)
|
if (rc < 0)
|
||||||
VIR_WARN("Unable to deny device %s for %s: %d",
|
VIR_WARN("Unable to deny device %s for %s: %d",
|
||||||
path, vm->def->name, rc);
|
path, vm->def->name, rc);
|
||||||
|
Loading…
x
Reference in New Issue
Block a user