[libvirt] [PATCHv3 2/2] audit: audit use of /dev/net/tun, /dev/tapN, /dev/vhost-net
Laine Stump
laine at laine.org
Thu Mar 10 16:16:03 UTC 2011
On 03/09/2011 03:42 PM, Eric Blake wrote:
> Opening raw network devices with the intent of passing those fds to
> qemu is worth an audit point. This makes a multi-part audit: first,
> we audit the device(s) that libvirt opens on behalf of the MAC address
> of a to-be-created interface (which can independently succeed or
> fail), then we audit whether qemu actually started the network device
> with the same MAC (so searching backwards for successful audits with
> the same MAC will show which fd(s) qemu is actually using). Note that
> it is possible for the fd to be successfully opened but no attempt
> made to pass the fd to qemu (for example, because intermediate
> nwfilter operations failed) - no interface start audit will occur in
> that case; so the audit for a successful opened fd does not imply
> rights given to qemu unless there is a followup audit about the
> attempt to start a new interface.
>
> Likewise, when a network device is hot-unplugged, there is only one
> audit message about the MAC being discontinued; again, searching back
> to the earlier device open audits will show which fds that qemu quits
> using (and yes, I checked via /proc/<qemu-pid>/fd that qemu _does_
> close out the fds associated with an interface on hot-unplug). The
> code would require much more refactoring to be able to definitively
> state which device(s) were discontinued at that point, since we
> currently don't record anywhere in the XML whether /dev/vhost-net was
> opened for a given interface.
>
> * src/qemu/qemu_audit.h (qemuAuditNetDevice): New prototype.
> * src/qemu/qemu_audit.c (qemuAuditNetDevice): New function.
> * src/qemu/qemu_command.h (qemuNetworkIfaceConnect)
> (qemuPhysIfaceConnect, qemuOpenVhostNet): Adjust prototype.
> * src/qemu/qemu_command.c (qemuNetworkIfaceConnect)
> (qemuPhysIfaceConnect, qemuOpenVhostNet): Add audit points and
> adjust parameters.
> (qemuBuildCommandLine): Adjust caller.
> * src/qemu/qemu_hotplug.c (qemuDomainAttachNetDevice): Likewise.
> ---
> src/qemu/qemu_audit.c | 41 +++++++++++++++++++++++++++++++++++++++++
> src/qemu/qemu_audit.h | 5 +++++
> src/qemu/qemu_command.c | 40 ++++++++++++++++++++--------------------
> src/qemu/qemu_command.h | 12 +++++++-----
> src/qemu/qemu_hotplug.c | 8 ++++----
> 5 files changed, 77 insertions(+), 29 deletions(-)
>
> diff --git a/src/qemu/qemu_audit.c b/src/qemu/qemu_audit.c
> index 5bdf655..40b68ff 100644
> --- a/src/qemu/qemu_audit.c
> +++ b/src/qemu/qemu_audit.c
> @@ -127,6 +127,47 @@ qemuAuditNet(virDomainObjPtr vm,
> VIR_FREE(vmname);
> }
>
> +/**
> + * qemuAuditNetDevice:
> + * @vm: domain opening a network-related device
> + * @def: 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 qemu owns it; a followup qemuAuditNet
> + * 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
> +qemuAuditNetDevice(virDomainDefPtr vmDef, virDomainNetDefPtr netDef,
> + const char *device, bool success)
> +{
> + char uuidstr[VIR_UUID_STRING_BUFLEN];
> + char macstr[VIR_MAC_STRING_BUFLEN];
> + char *vmname;
> + char *devname;
> + char *rdev;
> +
> + virUUIDFormat(vmDef->uuid, uuidstr);
> + virFormatMacAddr(netDef->mac, macstr);
> + rdev = qemuAuditGetRdev(device);
> +
> + if (!(vmname = virAuditEncode("vm", vmDef->name)) ||
> + !(devname = virAuditEncode("path", device))) {
> + VIR_WARN0("OOM while encoding audit message");
> + goto cleanup;
> + }
> +
> + VIR_AUDIT(VIR_AUDIT_RECORD_RESOURCE, success,
> + "resrc=net reason=open %s uuid=%s net='%s' %s rdev=%s",
> + vmname, uuidstr, macstr, devname, VIR_AUDIT_STR(rdev));
> +
> +cleanup:
> + VIR_FREE(vmname);
> + VIR_FREE(devname);
> + VIR_FREE(rdev);
> +}
>
> /**
> * qemuAuditHostdev:
> diff --git a/src/qemu/qemu_audit.h b/src/qemu/qemu_audit.h
> index a2fbe11..14c7da5 100644
> --- a/src/qemu/qemu_audit.h
> +++ b/src/qemu/qemu_audit.h
> @@ -46,6 +46,11 @@ void qemuAuditNet(virDomainObjPtr vm,
> const char *reason,
> bool success)
> ATTRIBUTE_NONNULL(1) ATTRIBUTE_NONNULL(4);
> +void qemuAuditNetDevice(virDomainDefPtr vmDef,
> + virDomainNetDefPtr netDef,
> + const char *device,
> + bool success)
> + ATTRIBUTE_NONNULL(1) ATTRIBUTE_NONNULL(2) ATTRIBUTE_NONNULL(3);
> void qemuAuditHostdev(virDomainObjPtr vm,
> virDomainHostdevDefPtr def,
> const char *reason,
> diff --git a/src/qemu/qemu_command.c b/src/qemu/qemu_command.c
> index 8cf1737..0fc466c 100644
> --- a/src/qemu/qemu_command.c
> +++ b/src/qemu/qemu_command.c
> @@ -35,6 +35,7 @@
> #include "uuid.h"
> #include "c-ctype.h"
> #include "domain_nwfilter.h"
> +#include "qemu_audit.h"
>
> #include<sys/utsname.h>
> #include<sys/stat.h>
> @@ -97,20 +98,20 @@ uname_normalize (struct utsname *ut)
>
> /**
> * qemuPhysIfaceConnect:
> + * @def: the definition of the VM (needed by 802.1Qbh and audit)
> * @conn: pointer to virConnect object
> * @driver: pointer to the qemud_driver
> * @net: pointer to he VM's interface description with direct device type
> * @qemuCaps: flags for qemu
> - * @vmuuid: The UUID of the VM (needed by 802.1Qbh)
> *
> * Returns a filedescriptor on success or -1 in case of error.
> */
> int
> -qemuPhysIfaceConnect(virConnectPtr conn,
> +qemuPhysIfaceConnect(virDomainDefPtr def,
> + virConnectPtr conn,
> struct qemud_driver *driver,
> virDomainNetDefPtr net,
> virBitmapPtr qemuCaps,
> - const unsigned char *vmuuid,
> enum virVMOperationType vmop)
> {
> int rc;
> @@ -124,9 +125,10 @@ qemuPhysIfaceConnect(virConnectPtr conn,
> vnet_hdr = 1;
>
> rc = openMacvtapTap(net->ifname, net->mac, net->data.direct.linkdev,
> - net->data.direct.mode, vnet_hdr, vmuuid,
> + net->data.direct.mode, vnet_hdr, def->uuid,
> &net->data.direct.virtPortProfile,&res_ifname,
> vmop);
> + qemuAuditNetDevice(def, net, res_ifname, rc>= 0);
> if (rc>= 0) {
> VIR_FREE(net->ifname);
> net->ifname = res_ifname;
> @@ -152,11 +154,11 @@ qemuPhysIfaceConnect(virConnectPtr conn,
> }
> }
> #else
> + (void)def;
> (void)conn;
> (void)net;
> (void)qemuCaps;
> (void)driver;
> - (void)vmuuid;
> (void)vmop;
> qemuReportError(VIR_ERR_INTERNAL_ERROR,
> "%s", _("No support for macvtap device"));
> @@ -167,7 +169,8 @@ qemuPhysIfaceConnect(virConnectPtr conn,
>
>
> int
> -qemuNetworkIfaceConnect(virConnectPtr conn,
> +qemuNetworkIfaceConnect(virDomainDefPtr def,
> + virConnectPtr conn,
> struct qemud_driver *driver,
> virDomainNetDefPtr net,
> virBitmapPtr qemuCaps)
> @@ -247,13 +250,10 @@ qemuNetworkIfaceConnect(virConnectPtr conn,
>
> memcpy(tapmac, net->mac, VIR_MAC_BUFLEN);
> tapmac[0] = 0xFE; /* Discourage bridge from using TAP dev MAC */
> - if ((err = brAddTap(driver->brctl,
> - brname,
> -&net->ifname,
> - tapmac,
> - vnet_hdr,
> - true,
> -&tapfd))) {
> + err = brAddTap(driver->brctl, brname,&net->ifname, tapmac,
> + vnet_hdr, true,&tapfd);
> + qemuAuditNetDevice(def, net, "/dev/net/tun", tapfd>= 0);
> + if (err) {
> if (err == ENOTSUP) {
> /* In this particular case, give a better diagnostic. */
> qemuReportError(VIR_ERR_INTERNAL_ERROR,
> @@ -304,7 +304,8 @@ cleanup:
>
>
> int
> -qemuOpenVhostNet(virDomainNetDefPtr net,
> +qemuOpenVhostNet(virDomainDefPtr def,
> + virDomainNetDefPtr net,
> virBitmapPtr qemuCaps,
> int *vhostfd)
> {
> @@ -342,6 +343,7 @@ qemuOpenVhostNet(virDomainNetDefPtr net,
> }
>
> *vhostfd = open("/dev/vhost-net", O_RDWR);
> + qemuAuditNetDevice(def, net, "/dev/vhost-net", *vhostfd>= 0);
>
> /* If the config says explicitly to use vhost and we couldn't open it,
> * report an error.
> @@ -3460,7 +3462,7 @@ qemuBuildCommandLine(virConnectPtr conn,
>
> if (net->type == VIR_DOMAIN_NET_TYPE_NETWORK ||
> net->type == VIR_DOMAIN_NET_TYPE_BRIDGE) {
> - int tapfd = qemuNetworkIfaceConnect(conn, driver, net,
> + int tapfd = qemuNetworkIfaceConnect(def, conn, driver, net,
> qemuCaps);
> if (tapfd< 0)
> goto error;
> @@ -3472,10 +3474,8 @@ qemuBuildCommandLine(virConnectPtr conn,
> tapfd)>= sizeof(tapfd_name))
> goto no_memory;
> } else if (net->type == VIR_DOMAIN_NET_TYPE_DIRECT) {
> - int tapfd = qemuPhysIfaceConnect(conn, driver, net,
> - qemuCaps,
> - def->uuid,
> - vmop);
> + int tapfd = qemuPhysIfaceConnect(def, conn, driver, net,
> + qemuCaps, vmop);
> if (tapfd< 0)
> goto error;
>
> @@ -3494,7 +3494,7 @@ qemuBuildCommandLine(virConnectPtr conn,
> network device */
> int vhostfd;
>
> - if (qemuOpenVhostNet(net, qemuCaps,&vhostfd)< 0)
> + if (qemuOpenVhostNet(def, net, qemuCaps,&vhostfd)< 0)
> goto error;
> if (vhostfd>= 0) {
> virCommandTransferFD(cmd, vhostfd);
> diff --git a/src/qemu/qemu_command.h b/src/qemu/qemu_command.h
> index 2ae364c..528031d 100644
> --- a/src/qemu/qemu_command.h
> +++ b/src/qemu/qemu_command.h
> @@ -116,20 +116,22 @@ char * qemuBuildUSBHostdevDevStr(virDomainHostdevDefPtr dev);
>
>
>
> -int qemuNetworkIfaceConnect(virConnectPtr conn,
> +int qemuNetworkIfaceConnect(virDomainDefPtr def,
> + virConnectPtr conn,
> struct qemud_driver *driver,
> virDomainNetDefPtr net,
> virBitmapPtr qemuCaps)
> - ATTRIBUTE_NONNULL(1);
> + ATTRIBUTE_NONNULL(2);
>
> -int qemuPhysIfaceConnect(virConnectPtr conn,
> +int qemuPhysIfaceConnect(virDomainDefPtr def,
> + virConnectPtr conn,
> struct qemud_driver *driver,
> virDomainNetDefPtr net,
> virBitmapPtr qemuCaps,
> - const unsigned char *vmuuid,
> enum virVMOperationType vmop);
>
> -int qemuOpenVhostNet(virDomainNetDefPtr net,
> +int qemuOpenVhostNet(virDomainDefPtr def,
> + virDomainNetDefPtr net,
> virBitmapPtr qemuCaps,
> int *vhostfd);
>
> diff --git a/src/qemu/qemu_hotplug.c b/src/qemu/qemu_hotplug.c
> index e8567ad..4646fd7 100644
> --- a/src/qemu/qemu_hotplug.c
> +++ b/src/qemu/qemu_hotplug.c
> @@ -576,7 +576,8 @@ int qemuDomainAttachNetDevice(virConnectPtr conn,
> return -1;
> }
>
> - if ((tapfd = qemuNetworkIfaceConnect(conn, driver, net, qemuCaps))< 0)
> + if ((tapfd = qemuNetworkIfaceConnect(vm->def, conn, driver, net,
> + qemuCaps))< 0)
> return -1;
> } else if (net->type == VIR_DOMAIN_NET_TYPE_DIRECT) {
> if (priv->monConfig->type != VIR_DOMAIN_CHR_TYPE_UNIX) {
> @@ -587,9 +588,8 @@ int qemuDomainAttachNetDevice(virConnectPtr conn,
> return -1;
> }
>
> - if ((tapfd = qemuPhysIfaceConnect(conn, driver, net,
> + if ((tapfd = qemuPhysIfaceConnect(vm->def, conn, driver, net,
> qemuCaps,
> - vm->def->uuid,
> VIR_VM_OP_CREATE))< 0)
> return -1;
> }
> @@ -599,7 +599,7 @@ int qemuDomainAttachNetDevice(virConnectPtr conn,
> net->type == VIR_DOMAIN_NET_TYPE_DIRECT) {
> /* Attempt to use vhost-net mode for these types of
> network device */
> - if (qemuOpenVhostNet(net, qemuCaps,&vhostfd)< 0)
> + if (qemuOpenVhostNet(vm->def, net, qemuCaps,&vhostfd)< 0)
> goto cleanup;
>
> if (vhostfd>= 0&&
ACK
More information about the libvir-list
mailing list