/*
* domain_audit.c: Domain audit management
*
* Copyright (C) 2006-2014 Red Hat, Inc.
* Copyright (C) 2006 Daniel P. Berrange
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library. If not, see
* .
*/
#include
#include
#ifdef MAJOR_IN_MKDEV
# include
#elif MAJOR_IN_SYSMACROS
# include
#endif
#include
#include "domain_audit.h"
#include "viraudit.h"
#include "viruuid.h"
#include "virlog.h"
#include "viralloc.h"
#include "virstring.h"
VIR_LOG_INIT("conf.domain_audit");
/* Return nn:mm in hex for block and character devices, and NULL
* for other file types, stat failure, or allocation failure. */
#if defined major && defined minor
static char *
virDomainAuditGetRdev(const char *path)
{
char *ret = NULL;
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);
ignore_value(virAsprintfQuiet(&ret, "%02X:%02X", maj, min));
}
return ret;
}
#else
static char *
virDomainAuditGetRdev(const char *path G_GNUC_UNUSED)
{
return NULL;
}
#endif
static const char *
virDomainAuditGetVirtType(virDomainDefPtr def)
{
const char *virt;
if (!(virt = virDomainVirtTypeToString(def->virtType))) {
VIR_WARN("Unexpected virt type %d while encoding audit message",
def->virtType);
virt = "?";
}
return virt;
}
static void
virDomainAuditGenericDev(virDomainObjPtr vm,
const char *type,
const char *oldsrcpath,
const char *newsrcpath,
const char *reason,
bool success)
{
char *newdev = NULL;
char *olddev = NULL;
char uuidstr[VIR_UUID_STRING_BUFLEN];
char *vmname = NULL;
char *oldsrc = NULL;
char *newsrc = NULL;
const char *virt = virDomainAuditGetVirtType(vm->def);
/* if both new and old source aren't provided don't log anything */
if (!newsrcpath && !oldsrcpath)
return;
if (virAsprintfQuiet(&newdev, "new-%s", type) < 0)
goto no_memory;
if (virAsprintfQuiet(&olddev, "old-%s", type) < 0)
goto no_memory;
virUUIDFormat(vm->def->uuid, uuidstr);
if (!(vmname = virAuditEncode("vm", vm->def->name)))
goto no_memory;
if (!(newsrc = virAuditEncode(newdev, VIR_AUDIT_STR(newsrcpath))))
goto no_memory;
if (!(oldsrc = virAuditEncode(olddev, VIR_AUDIT_STR(oldsrcpath))))
goto no_memory;
VIR_AUDIT(VIR_AUDIT_RECORD_RESOURCE, success,
"virt=%s resrc=%s reason=%s %s uuid=%s %s %s",
virt, type, reason, vmname, uuidstr, oldsrc, newsrc);
cleanup:
VIR_FREE(newdev);
VIR_FREE(olddev);
VIR_FREE(vmname);
VIR_FREE(oldsrc);
VIR_FREE(newsrc);
return;
no_memory:
VIR_WARN("OOM while encoding audit message");
goto cleanup;
}
void
virDomainAuditChardev(virDomainObjPtr vm,
virDomainChrDefPtr oldDef,
virDomainChrDefPtr newDef,
const char *reason,
bool success)
{
virDomainChrSourceDefPtr oldsrc = NULL;
virDomainChrSourceDefPtr newsrc = NULL;
if (oldDef)
oldsrc = oldDef->source;
if (newDef)
newsrc = newDef->source;
virDomainAuditGenericDev(vm, "chardev",
virDomainChrSourceDefGetPath(oldsrc),
virDomainChrSourceDefGetPath(newsrc),
reason, success);
}
static void
virDomainAuditSmartcard(virDomainObjPtr vm,
virDomainSmartcardDefPtr def,
const char *reason,
bool success)
{
const char *database = VIR_DOMAIN_SMARTCARD_DEFAULT_DATABASE;
size_t i;
if (def) {
switch ((virDomainSmartcardType) def->type) {
case VIR_DOMAIN_SMARTCARD_TYPE_HOST:
virDomainAuditGenericDev(vm, "smartcard",
NULL, "nss-smartcard-device",
reason, success);
break;
case VIR_DOMAIN_SMARTCARD_TYPE_HOST_CERTIFICATES:
for (i = 0; i < VIR_DOMAIN_SMARTCARD_NUM_CERTIFICATES; i++) {
virDomainAuditGenericDev(vm, "smartcard", NULL,
def->data.cert.file[i],
reason, success);
}
if (def->data.cert.database)
database = def->data.cert.database;
virDomainAuditGenericDev(vm, "smartcard",
NULL, database,
reason, success);
break;
case VIR_DOMAIN_SMARTCARD_TYPE_PASSTHROUGH:
virDomainAuditGenericDev(vm, "smartcard", NULL,
virDomainChrSourceDefGetPath(def->data.passthru),
reason, success);
break;
case VIR_DOMAIN_SMARTCARD_TYPE_LAST:
break;
}
}
}
void
virDomainAuditDisk(virDomainObjPtr vm,
virStorageSourcePtr oldDef,
virStorageSourcePtr newDef,
const char *reason,
bool success)
{
const char *oldsrc = NULL;
const char *newsrc = NULL;
if (oldDef && virStorageSourceIsLocalStorage(oldDef))
oldsrc = oldDef->path;
if (newDef && virStorageSourceIsLocalStorage(newDef))
newsrc = newDef->path;
virDomainAuditGenericDev(vm, "disk", oldsrc, newsrc, reason, success);
}
void
virDomainAuditRNG(virDomainObjPtr vm,
virDomainRNGDefPtr oldDef, virDomainRNGDefPtr newDef,
const char *reason, bool success)
{
const char *newsrcpath = NULL;
const char *oldsrcpath = NULL;
if (newDef) {
switch ((virDomainRNGBackend) newDef->backend) {
case VIR_DOMAIN_RNG_BACKEND_RANDOM:
newsrcpath = newDef->source.file;
break;
case VIR_DOMAIN_RNG_BACKEND_EGD:
newsrcpath = virDomainChrSourceDefGetPath(newDef->source.chardev);
break;
case VIR_DOMAIN_RNG_BACKEND_LAST:
break;
}
}
if (oldDef) {
switch ((virDomainRNGBackend) oldDef->backend) {
case VIR_DOMAIN_RNG_BACKEND_RANDOM:
oldsrcpath = oldDef->source.file;
break;
case VIR_DOMAIN_RNG_BACKEND_EGD:
oldsrcpath = virDomainChrSourceDefGetPath(oldDef->source.chardev);
break;
case VIR_DOMAIN_RNG_BACKEND_LAST:
break;
}
}
virDomainAuditGenericDev(vm, "rng", oldsrcpath, newsrcpath, reason, success);
}
void
virDomainAuditFS(virDomainObjPtr vm,
virDomainFSDefPtr oldDef, virDomainFSDefPtr newDef,
const char *reason, bool success)
{
virDomainAuditGenericDev(vm, "fs",
oldDef ? oldDef->src->path : NULL,
newDef ? newDef->src->path : NULL,
reason, success);
}
void
virDomainAuditNet(virDomainObjPtr vm,
virDomainNetDefPtr oldDef, virDomainNetDefPtr newDef,
const char *reason, bool success)
{
char newMacstr[VIR_MAC_STRING_BUFLEN];
char oldMacstr[VIR_MAC_STRING_BUFLEN];
if (oldDef)
virMacAddrFormat(&oldDef->mac, oldMacstr);
if (newDef)
virMacAddrFormat(&newDef->mac, newMacstr);
virDomainAuditGenericDev(vm, "net",
oldDef ? oldMacstr : NULL,
newDef ? newMacstr : NULL,
reason, success);
}
/**
* virDomainAuditNetDevice:
* @vmDef: the definition of the VM
* @netDef: details of network device that fd will be tied to
* @device: device being opened (such as /dev/vhost-net,
* /dev/net/tun, /dev/tanN). Note that merely opening a device
* does not mean that virDomain owns it; a followup virDomainAuditNet
* shows whether the fd was passed on.
* @success: true if the device was opened
*
* Log an audit message about an attempted network device open.
*/
void
virDomainAuditNetDevice(virDomainDefPtr vmDef, virDomainNetDefPtr netDef,
const char *device, bool success)
{
char uuidstr[VIR_UUID_STRING_BUFLEN];
char macstr[VIR_MAC_STRING_BUFLEN];
char *vmname;
char *dev_name = NULL;
char *rdev;
const char *virt = virDomainAuditGetVirtType(vmDef);
virUUIDFormat(vmDef->uuid, uuidstr);
virMacAddrFormat(&netDef->mac, macstr);
rdev = virDomainAuditGetRdev(device);
if (!(vmname = virAuditEncode("vm", vmDef->name)) ||
!(dev_name = virAuditEncode("path", device))) {
VIR_WARN("OOM while encoding audit message");
goto cleanup;
}
VIR_AUDIT(VIR_AUDIT_RECORD_RESOURCE, success,
"virt=%s resrc=net reason=open %s uuid=%s net=%s %s rdev=%s",
virt, vmname, uuidstr, macstr, dev_name, VIR_AUDIT_STR(rdev));
cleanup:
VIR_FREE(vmname);
VIR_FREE(dev_name);
VIR_FREE(rdev);
}
/**
* virDomainAuditHostdev:
* @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
virDomainAuditHostdev(virDomainObjPtr vm, virDomainHostdevDefPtr hostdev,
const char *reason, bool success)
{
char uuidstr[VIR_UUID_STRING_BUFLEN];
char *vmname;
char *address = NULL;
char *device = NULL;
const char *virt = virDomainAuditGetVirtType(vm->def);
virDomainHostdevSubsysUSBPtr usbsrc = &hostdev->source.subsys.u.usb;
virDomainHostdevSubsysPCIPtr pcisrc = &hostdev->source.subsys.u.pci;
virDomainHostdevSubsysSCSIPtr scsisrc = &hostdev->source.subsys.u.scsi;
virDomainHostdevSubsysSCSIVHostPtr hostsrc = &hostdev->source.subsys.u.scsi_host;
virDomainHostdevSubsysMediatedDevPtr mdevsrc = &hostdev->source.subsys.u.mdev;
virUUIDFormat(vm->def->uuid, uuidstr);
if (!(vmname = virAuditEncode("vm", vm->def->name))) {
VIR_WARN("OOM while encoding audit message");
return;
}
switch ((virDomainHostdevMode) hostdev->mode) {
case VIR_DOMAIN_HOSTDEV_MODE_SUBSYS:
switch ((virDomainHostdevSubsysType) hostdev->source.subsys.type) {
case VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_PCI:
if (virAsprintfQuiet(&address,
VIR_PCI_DEVICE_ADDRESS_FMT,
pcisrc->addr.domain,
pcisrc->addr.bus,
pcisrc->addr.slot,
pcisrc->addr.function) < 0) {
VIR_WARN("OOM while encoding audit message");
goto cleanup;
}
break;
case VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_USB:
if (virAsprintfQuiet(&address, "%.3d.%.3d",
usbsrc->bus, usbsrc->device) < 0) {
VIR_WARN("OOM while encoding audit message");
goto cleanup;
}
break;
case VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_SCSI: {
if (scsisrc->protocol ==
VIR_DOMAIN_HOSTDEV_SCSI_PROTOCOL_TYPE_ISCSI) {
/* Follow virDomainAuditDisk && virDomainAuditGenericDev
* and don't audit the networked device.
*/
goto cleanup;
} else {
virDomainHostdevSubsysSCSIHostPtr scsihostsrc =
&scsisrc->u.host;
if (virAsprintfQuiet(&address, "%s:%u:%u:%llu",
scsihostsrc->adapter, scsihostsrc->bus,
scsihostsrc->target,
scsihostsrc->unit) < 0) {
VIR_WARN("OOM while encoding audit message");
goto cleanup;
}
}
break;
}
case VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_SCSI_HOST:
address = g_strdup(hostsrc->wwpn);
break;
case VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_MDEV:
address = g_strdup(mdevsrc->uuidstr);
break;
case VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_LAST:
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_WARN("OOM while encoding audit message");
goto cleanup;
}
VIR_AUDIT(VIR_AUDIT_RECORD_RESOURCE, success,
"virt=%s resrc=dev reason=%s %s uuid=%s bus=%s %s",
virt, reason, vmname, uuidstr,
virDomainHostdevSubsysTypeToString(hostdev->source.subsys.type),
device);
break;
case VIR_DOMAIN_HOSTDEV_MODE_CAPABILITIES:
switch (hostdev->source.caps.type) {
case VIR_DOMAIN_HOSTDEV_CAPS_TYPE_STORAGE:
if (!(device = virAuditEncode("disk",
VIR_AUDIT_STR(hostdev->source.caps.u.storage.block)))) {
VIR_WARN("OOM while encoding audit message");
goto cleanup;
}
VIR_AUDIT(VIR_AUDIT_RECORD_RESOURCE, success,
"virt=%s resrc=hostdev reason=%s %s uuid=%s %s",
virt, reason, vmname, uuidstr, device);
break;
case VIR_DOMAIN_HOSTDEV_CAPS_TYPE_MISC:
if (!(device = virAuditEncode("chardev",
VIR_AUDIT_STR(hostdev->source.caps.u.misc.chardev)))) {
VIR_WARN("OOM while encoding audit message");
goto cleanup;
}
VIR_AUDIT(VIR_AUDIT_RECORD_RESOURCE, success,
"virt=%s resrc=hostdev reason=%s %s uuid=%s %s",
virt, reason, vmname, uuidstr, device);
break;
default:
VIR_WARN("Unexpected hostdev type while encoding audit message: %d",
hostdev->source.caps.type);
goto cleanup;
}
break;
case VIR_DOMAIN_HOSTDEV_MODE_LAST:
default:
VIR_WARN("Unexpected hostdev mode while encoding audit message: %d",
hostdev->mode);
goto cleanup;
}
cleanup:
VIR_FREE(vmname);
VIR_FREE(device);
VIR_FREE(address);
}
/**
* virDomainAuditRedirdev:
* @vm: domain making a change in pass-through host device
* @redirdev: 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
virDomainAuditRedirdev(virDomainObjPtr vm, virDomainRedirdevDefPtr redirdev,
const char *reason, bool success)
{
char uuidstr[VIR_UUID_STRING_BUFLEN];
char *vmname;
char *address = NULL;
char *device = NULL;
const char *virt = virDomainAuditGetVirtType(vm->def);
virUUIDFormat(vm->def->uuid, uuidstr);
if (!(vmname = virAuditEncode("vm", vm->def->name))) {
VIR_WARN("OOM while encoding audit message");
return;
}
switch (redirdev->bus) {
case VIR_DOMAIN_REDIRDEV_BUS_USB:
address = g_strdup("USB redirdev");
break;
default:
VIR_WARN("Unexpected redirdev bus while encoding audit message: %d",
redirdev->bus);
goto cleanup;
}
if (!(device = virAuditEncode("device", VIR_AUDIT_STR(address)))) {
VIR_WARN("OOM while encoding audit message");
goto cleanup;
}
VIR_AUDIT(VIR_AUDIT_RECORD_RESOURCE, success,
"virt=%s resrc=dev reason=%s %s uuid=%s bus=%s %s",
virt, reason, vmname, uuidstr,
virDomainRedirdevBusTypeToString(redirdev->bus),
device);
cleanup:
VIR_FREE(vmname);
VIR_FREE(device);
VIR_FREE(address);
}
/**
* virDomainAuditTPM:
* @vm: domain making a change in pass-through host device or emulator
* @tpm: TPM device being attached or removed
* @reason: one of "start", "attach", or "detach"
* @success: true if the device operation succeeded
*
* Log an audit message about an attempted device passthrough or emulator
* change.
*/
static void
virDomainAuditTPM(virDomainObjPtr vm, virDomainTPMDefPtr tpm,
const char *reason, bool success)
{
char uuidstr[VIR_UUID_STRING_BUFLEN];
char *vmname;
char *path = NULL;
char *device = NULL;
const char *virt = virDomainAuditGetVirtType(vm->def);
virUUIDFormat(vm->def->uuid, uuidstr);
if (!(vmname = virAuditEncode("vm", vm->def->name))) {
VIR_WARN("OOM while encoding audit message");
return;
}
switch (tpm->type) {
case VIR_DOMAIN_TPM_TYPE_PASSTHROUGH:
path = tpm->data.passthrough.source.data.file.path;
if (!(device = virAuditEncode("device", VIR_AUDIT_STR(path)))) {
VIR_WARN("OOM while encoding audit message");
goto cleanup;
}
VIR_AUDIT(VIR_AUDIT_RECORD_RESOURCE, success,
"virt=%s resrc=tpm reason=%s %s uuid=%s %s",
virt, reason, vmname, uuidstr, device);
break;
case VIR_DOMAIN_TPM_TYPE_EMULATOR:
path = tpm->data.emulator.source.data.nix.path;
if (!(device = virAuditEncode("device", VIR_AUDIT_STR(path)))) {
VIR_WARN("OOM while encoding audit message");
goto cleanup;
}
VIR_AUDIT(VIR_AUDIT_RECORD_RESOURCE, success,
"virt=%s resrc=tpm-emulator reason=%s %s uuid=%s %s",
virt, reason, vmname, uuidstr, device);
break;
case VIR_DOMAIN_TPM_TYPE_LAST:
default:
break;
}
cleanup:
VIR_FREE(vmname);
VIR_FREE(device);
}
/**
* virDomainAuditCgroup:
* @vm: domain making the cgroups ACL change
* @cgroup: cgroup that manages the devices
* @reason: either "allow" or "deny"
* @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 virDomainAuditCgroupMajor and
* virDomainAuditCgroupPath).
* @success: true if the cgroup operation succeeded
*
* Log an audit message about an attempted cgroup device ACL change.
*/
void
virDomainAuditCgroup(virDomainObjPtr vm, virCgroupPtr cgroup,
const char *reason, const char *extra, bool success)
{
char uuidstr[VIR_UUID_STRING_BUFLEN];
char *vmname;
char *controller = NULL;
char *detail;
const char *virt = virDomainAuditGetVirtType(vm->def);
virUUIDFormat(vm->def->uuid, uuidstr);
if (!(vmname = virAuditEncode("vm", vm->def->name))) {
VIR_WARN("OOM while encoding audit message");
return;
}
ignore_value(virCgroupPathOfController(cgroup,
VIR_CGROUP_CONTROLLER_DEVICES,
NULL, &controller));
detail = virAuditEncode("cgroup", VIR_AUDIT_STR(controller));
VIR_AUDIT(VIR_AUDIT_RECORD_RESOURCE, success,
"virt=%s resrc=cgroup reason=%s %s uuid=%s %s class=%s",
virt, reason, vmname, uuidstr,
detail ? detail : "cgroup=?", extra);
VIR_FREE(vmname);
VIR_FREE(controller);
VIR_FREE(detail);
}
/**
* virDomainAuditCgroupMajor:
* @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
* @perms: string containing "r", "w", and/or "m" as appropriate
* @success: true if the cgroup operation succeeded
*
* Log an audit message about an attempted cgroup device ACL change.
*/
void
virDomainAuditCgroupMajor(virDomainObjPtr vm, virCgroupPtr cgroup,
const char *reason, int maj, const char *name,
const char *perms, bool success)
{
char *extra;
if (virAsprintfQuiet(&extra, "major category=%s maj=%02X acl=%s",
name, maj, perms) < 0) {
VIR_WARN("OOM while encoding audit message");
return;
}
virDomainAuditCgroup(vm, cgroup, reason, extra, success);
VIR_FREE(extra);
}
/**
* virDomainAuditCgroupPath:
* @vm: domain making the cgroups ACL change
* @cgroup: cgroup that manages the devices
* @reason: either "allow" or "deny"
* @path: the device being adjusted
* @perms: string containing "r", "w", and/or "m" as appropriate
* @rc: > 0 if not a device, 0 if success, < 0 if failure
*
* Log an audit message about an attempted cgroup device ACL change to
* a specific device.
*/
void
virDomainAuditCgroupPath(virDomainObjPtr vm, virCgroupPtr cgroup,
const char *reason, const char *path, const char *perms,
int rc)
{
char *detail;
char *rdev;
char *extra = NULL;
/* Nothing to audit for regular files. */
if (rc > 0)
return;
rdev = virDomainAuditGetRdev(path);
if (!(detail = virAuditEncode("path", path)) ||
virAsprintfQuiet(&extra, "path %s rdev=%s acl=%s",
detail, VIR_AUDIT_STR(rdev), perms) < 0) {
VIR_WARN("OOM while encoding audit message");
goto cleanup;
}
virDomainAuditCgroup(vm, cgroup, reason, extra, rc == 0);
cleanup:
VIR_FREE(extra);
VIR_FREE(detail);
VIR_FREE(rdev);
}
/**
* virDomainAuditResource:
* @vm: domain making an integer resource change
* @resource: name of the resource: "mem" or "vcpu"
* @oldval: the old value of the resource
* @newval: the new value of the resource
* @reason: either "start" or "update"
* @success: true if the resource change succeeded
*
* Log an audit message about an attempted resource change.
*/
static void
virDomainAuditResource(virDomainObjPtr vm, const char *resource,
unsigned long long oldval, unsigned long long newval,
const char *reason, bool success)
{
char uuidstr[VIR_UUID_STRING_BUFLEN];
char *vmname;
const char *virt = virDomainAuditGetVirtType(vm->def);
virUUIDFormat(vm->def->uuid, uuidstr);
if (!(vmname = virAuditEncode("vm", vm->def->name))) {
VIR_WARN("OOM while encoding audit message");
return;
}
VIR_AUDIT(VIR_AUDIT_RECORD_RESOURCE, success,
"virt=%s resrc=%s reason=%s %s uuid=%s old-%s=%lld new-%s=%lld",
virt, resource, reason, vmname, uuidstr,
resource, oldval, resource, newval);
VIR_FREE(vmname);
}
void
virDomainAuditMemory(virDomainObjPtr vm,
unsigned long long oldmem, unsigned long long newmem,
const char *reason, bool success)
{
return virDomainAuditResource(vm, "mem", oldmem, newmem, reason, success);
}
void
virDomainAuditVcpu(virDomainObjPtr vm,
unsigned int oldvcpu, unsigned int newvcpu,
const char *reason, bool success)
{
return virDomainAuditResource(vm, "vcpu", oldvcpu, newvcpu, reason, success);
}
void
virDomainAuditIOThread(virDomainObjPtr vm,
unsigned int oldiothread, unsigned int newiothread,
const char *reason, bool success)
{
return virDomainAuditResource(vm, "iothread", oldiothread, newiothread,
reason, success);
}
static void
virDomainAuditLifecycle(virDomainObjPtr vm, const char *op,
const char *reason, bool success)
{
char uuidstr[VIR_UUID_STRING_BUFLEN];
char *vmname;
const char *virt = virDomainAuditGetVirtType(vm->def);
virUUIDFormat(vm->def->uuid, uuidstr);
if (!(vmname = virAuditEncode("vm", vm->def->name))) {
VIR_WARN("OOM while encoding audit message");
return;
}
VIR_AUDIT(VIR_AUDIT_RECORD_MACHINE_CONTROL, success,
"virt=%s op=%s reason=%s %s uuid=%s vm-pid=%lld",
virt, op, reason, vmname, uuidstr, (long long)vm->pid);
VIR_FREE(vmname);
}
void
virDomainAuditStart(virDomainObjPtr vm, const char *reason, bool success)
{
size_t i;
for (i = 0; i < vm->def->ndisks; i++)
virDomainAuditDisk(vm, NULL, vm->def->disks[i]->src, "start", true);
for (i = 0; i < vm->def->nfss; i++) {
virDomainFSDefPtr fs = vm->def->fss[i];
virDomainAuditFS(vm, NULL, fs, "start", true);
}
for (i = 0; i < vm->def->nnets; i++) {
virDomainNetDefPtr net = vm->def->nets[i];
virDomainAuditNet(vm, NULL, net, "start", true);
}
for (i = 0; i < vm->def->nhostdevs; i++) {
virDomainHostdevDefPtr hostdev = vm->def->hostdevs[i];
virDomainAuditHostdev(vm, hostdev, "start", true);
}
for (i = 0; i < vm->def->nredirdevs; i++) {
virDomainRedirdevDefPtr redirdev = vm->def->redirdevs[i];
virDomainAuditRedirdev(vm, redirdev, "start", true);
}
for (i = 0; i < vm->def->nserials; i++)
virDomainAuditChardev(vm, NULL, vm->def->serials[i], "start", true);
for (i = 0; i < vm->def->nparallels; i++)
virDomainAuditChardev(vm, NULL, vm->def->parallels[i], "start", true);
for (i = 0; i < vm->def->nchannels; i++)
virDomainAuditChardev(vm, NULL, vm->def->channels[i], "start", true);
for (i = 0; i < vm->def->nconsoles; i++) {
if (i == 0 &&
(vm->def->consoles[i]->targetType == VIR_DOMAIN_CHR_CONSOLE_TARGET_TYPE_SERIAL ||
vm->def->consoles[i]->targetType == VIR_DOMAIN_CHR_CONSOLE_TARGET_TYPE_NONE) &&
vm->def->os.type == VIR_DOMAIN_OSTYPE_HVM)
continue;
virDomainAuditChardev(vm, NULL, vm->def->consoles[i], "start", true);
}
for (i = 0; i < vm->def->nsmartcards; i++)
virDomainAuditSmartcard(vm, vm->def->smartcards[i], "start", true);
for (i = 0; i < vm->def->nrngs; i++)
virDomainAuditRNG(vm, NULL, vm->def->rngs[i], "start", true);
if (vm->def->tpm)
virDomainAuditTPM(vm, vm->def->tpm, "start", true);
for (i = 0; i < vm->def->nshmems; i++)
virDomainAuditShmem(vm, vm->def->shmems[i], "start", true);
for (i = 0; i < vm->def->ninputs; i++)
virDomainAuditInput(vm, vm->def->inputs[i], "start", true);
virDomainAuditMemory(vm, 0, virDomainDefGetMemoryTotal(vm->def),
"start", true);
virDomainAuditVcpu(vm, 0, virDomainDefGetVcpus(vm->def), "start", true);
if (vm->def->niothreadids)
virDomainAuditIOThread(vm, 0, vm->def->niothreadids, "start", true);
virDomainAuditLifecycle(vm, "start", reason, success);
}
void
virDomainAuditInit(virDomainObjPtr vm,
pid_t initpid,
ino_t pidns)
{
char uuidstr[VIR_UUID_STRING_BUFLEN];
char *vmname;
const char *virt = virDomainAuditGetVirtType(vm->def);
virUUIDFormat(vm->def->uuid, uuidstr);
if (!(vmname = virAuditEncode("vm", vm->def->name))) {
VIR_WARN("OOM while encoding audit message");
return;
}
VIR_AUDIT(VIR_AUDIT_RECORD_MACHINE_CONTROL, true,
"virt=%s op=init %s uuid=%s vm-pid=%lld init-pid=%lld pid-ns=%lld",
virt, vmname, uuidstr, (long long)vm->pid, (long long)initpid,
(long long)pidns);
VIR_FREE(vmname);
}
void
virDomainAuditStop(virDomainObjPtr vm, const char *reason)
{
virDomainAuditLifecycle(vm, "stop", reason, true);
}
void
virDomainAuditSecurityLabel(virDomainObjPtr vm, bool success)
{
char uuidstr[VIR_UUID_STRING_BUFLEN];
char *vmname;
size_t i;
const char *virt = virDomainAuditGetVirtType(vm->def);
virUUIDFormat(vm->def->uuid, uuidstr);
if (!(vmname = virAuditEncode("vm", vm->def->name))) {
VIR_WARN("OOM while encoding audit message");
return;
}
for (i = 0; i < vm->def->nseclabels; i++) {
VIR_AUDIT(VIR_AUDIT_RECORD_MACHINE_ID, success,
"virt=%s %s uuid=%s vm-ctx=%s img-ctx=%s model=%s",
virt, vmname, uuidstr,
VIR_AUDIT_STR(vm->def->seclabels[i]->label),
VIR_AUDIT_STR(vm->def->seclabels[i]->imagelabel),
VIR_AUDIT_STR(vm->def->seclabels[i]->model));
}
VIR_FREE(vmname);
}
void
virDomainAuditShmem(virDomainObjPtr vm,
virDomainShmemDefPtr def,
const char *reason, bool success)
{
char uuidstr[VIR_UUID_STRING_BUFLEN];
char *vmname = virAuditEncode("vm", vm->def->name);
const char *srcpath = virDomainChrSourceDefGetPath(&def->server.chr);
const char *virt = virDomainAuditGetVirtType(vm->def);
char *shmpath = NULL;
virUUIDFormat(vm->def->uuid, uuidstr);
if (!vmname ||
virAsprintfQuiet(&shmpath, "/dev/shm/%s", def->name) < 0) {
VIR_WARN("OOM while encoding audit message");
goto cleanup;
}
if (!virt) {
VIR_WARN("Unexpected virt type %d while encoding audit message",
vm->def->virtType);
virt = "?";
}
if (def->server.enabled) {
VIR_AUDIT(VIR_AUDIT_RECORD_RESOURCE, success,
"virt=%s resrc=ivshmem-socket reason=%s %s uuid=%s path=%s",
virt, reason, vmname, uuidstr, VIR_AUDIT_STR(srcpath));
} else {
VIR_AUDIT(VIR_AUDIT_RECORD_RESOURCE, success,
"virt=%s resrc=shmem reason=%s %s uuid=%s size=%llu path=%s",
virt, reason, vmname, uuidstr, def->size, VIR_AUDIT_STR(shmpath));
}
cleanup:
VIR_FREE(vmname);
VIR_FREE(shmpath);
return;
}
void
virDomainAuditInput(virDomainObjPtr vm,
virDomainInputDefPtr input,
const char *reason,
bool success)
{
char uuidstr[VIR_UUID_STRING_BUFLEN];
char *vmname;
const char *virt = virDomainAuditGetVirtType(vm->def);
virUUIDFormat(vm->def->uuid, uuidstr);
if (!(vmname = virAuditEncode("vm", vm->def->name)))
goto no_memory;
switch ((virDomainInputType) input->type) {
case VIR_DOMAIN_INPUT_TYPE_MOUSE:
case VIR_DOMAIN_INPUT_TYPE_TABLET:
case VIR_DOMAIN_INPUT_TYPE_KBD:
break;
case VIR_DOMAIN_INPUT_TYPE_PASSTHROUGH:
VIR_AUDIT(VIR_AUDIT_RECORD_RESOURCE, success,
"virt=%s resrc=evdev reason=%s %s uuid=%s path=%s",
virt, reason, vmname, uuidstr, VIR_AUDIT_STR(input->source.evdev));
break;
case VIR_DOMAIN_INPUT_TYPE_LAST:
break;
}
cleanup:
VIR_FREE(vmname);
return;
no_memory:
VIR_WARN("OOM while encoding audit message");
goto cleanup;
}