From: Michal Privoznik <[email protected]>
There are several types of virtual network interfaces that
libvirt creates (TUN, TAP, MACVLAN, MACVTAP, VETH). After these
are created (e.g. on domain startup or device hotplug), libvirt
often opens their /dev/XXX representation (e.g. /dev/tapNN) in
order to pass FDs to the hypervisor. Well, if creation an open()
happen in very quick succession, then host's udev might not have
had enough time and depending on system's SELinux even we might
see open() fail, with AVC message logged.
Signs of us trying to mitigate this problem are still to be found
in virNetDevMacVLanTapOpen() where upon failed open() a very
short g_usleep() is called.
Alternatively, in linked gitlab issue, the user reports seeing
the following message:
type=AVC msg=audit(1774535384.365:1238): avc: denied { open } for pid=6765
comm="rpc-virtqemud" path="/dev/tap33" dev="devtmpfs" ino=805
scontext=system_u:system_r:virtqemud_t:s0
tcontext=system_u:object_r:device_t:s0 tclass=chr_file permissive=1
(For full reasoning why /dev/tap33 is of device_t type see linked
issue).
Long story short, /dev/tapNN devices are created initially with
device_t SELinux type and udev later changes that to
tun_tap_device_t. This device_t type is viewed as generic type
that only an yet unlabelled device has. Hence missing rule in
SELinux policy for virtqemud to open it.
Therefore, to avoid this problem, wait for udev to settle by
calling virWaitForDevices() (which under the hood spawns "udevadm
settle". This may be a bit too heavy hammer though because the
function is called basically once per (almost) each <interface/>.
If we find that to be a performance drawback then we need to
redesign how tun/tap/... devices are created (well, opened).
Resolves: https://gitlab.com/libvirt/libvirt/-/work_items/866
Signed-off-by: Michal Privoznik <[email protected]>
---
src/util/virnetdevmacvlan.c | 4 ++++
src/util/virnetdevtap.c | 6 ++++++
src/util/virnetdevveth.c | 4 ++++
3 files changed, 14 insertions(+)
diff --git a/src/util/virnetdevmacvlan.c b/src/util/virnetdevmacvlan.c
index cde9d70eef..347148542d 100644
--- a/src/util/virnetdevmacvlan.c
+++ b/src/util/virnetdevmacvlan.c
@@ -24,6 +24,7 @@
#include "virnetdevmacvlan.h"
#include "virmacaddr.h"
#include "virerror.h"
+#include "virutil.h"
#define VIR_FROM_THIS VIR_FROM_NET
@@ -119,6 +120,9 @@ virNetDevMacVLanCreate(const char *ifname,
return -1;
}
+ /* Allow udev to process newly created mactap/macvlan. */
+ virWaitForDevices();
+
VIR_INFO("created device: '%s'", ifname);
return 0;
}
diff --git a/src/util/virnetdevtap.c b/src/util/virnetdevtap.c
index e3a6209642..38f50e959e 100644
--- a/src/util/virnetdevtap.c
+++ b/src/util/virnetdevtap.c
@@ -29,6 +29,7 @@
#include "viralloc.h"
#include "virlog.h"
#include "virstring.h"
+#include "virutil.h"
#include <unistd.h>
#include <sys/types.h>
@@ -265,6 +266,9 @@ int virNetDevTapCreate(char **ifname,
tapfd[i] = fd;
}
+ /* Allow udev to process newly created TUN/TAP. */
+ virWaitForDevices();
+
VIR_INFO("created device: '%s'", *ifname);
ret = 0;
@@ -375,6 +379,8 @@ int virNetDevTapCreate(char **ifname,
if (virNetDevSetName(ifr.ifr_name, *ifname) == -1)
goto cleanup;
+ /* Allow udev to process newly created TUN/TAP. */
+ virWaitForDevices();
ret = 0;
cleanup:
diff --git a/src/util/virnetdevveth.c b/src/util/virnetdevveth.c
index 4365345664..77b017427a 100644
--- a/src/util/virnetdevveth.c
+++ b/src/util/virnetdevveth.c
@@ -26,6 +26,7 @@
#include "virerror.h"
#include "virnetdev.h"
#include "virnetlink.h"
+#include "virutil.h"
#define VIR_FROM_THIS VIR_FROM_NONE
@@ -127,6 +128,9 @@ int virNetDevVethCreate(char **veth1, char **veth2)
if (virNetDevVethCreateInternal(*veth1, *veth2) < 0)
goto cleanup;
+ /* Allow udev to process newly created veth. */
+ virWaitForDevices();
+
VIR_DEBUG("Create Host: %s guest: %s", *veth1, *veth2);
return 0;
--
2.52.0