On FreeBSD, virNetDevTapCreate() creates a generic tap(4)
device and then renames to a desired value (typically vnetN).

However, it does not delete the tap(4) device on errors,
so it leaks the device when rename fails.

Fix by attempting to remove the device in "cleanup:"
if it was created. It's also closed before that because FreeBSD will not
delete an opened device.

Error handling is slightly updated:

 - For the unsupported "tapfdSize > 1" case return immediately,
   nothing to clean there
 - Also return when device creation fails. We have to duplicate
   VIR_FORCE_CLOSE(), but then in "cleanup" we are sure
   that "ifr" is initialized.

Signed-off-by: Roman Bogorodskiy <[email protected]>
---
 src/util/virnetdevtap.c | 20 ++++++++++++++++++--
 1 file changed, 18 insertions(+), 2 deletions(-)

diff --git a/src/util/virnetdevtap.c b/src/util/virnetdevtap.c
index e3a6209642..aa0907dd0c 100644
--- a/src/util/virnetdevtap.c
+++ b/src/util/virnetdevtap.c
@@ -334,11 +334,12 @@ int virNetDevTapCreate(char **ifname,
     int s;
     struct ifreq ifr;
     int ret = -1;
+    bool created = false;
 
     if (tapfdSize > 1) {
         virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
                        _("Multiqueue devices are not supported on this 
system"));
-        goto cleanup;
+        return -1;
     }
 
     /* auto-generate an unused name for the new device (this
@@ -357,9 +358,12 @@ int virNetDevTapCreate(char **ifname,
     if (ioctl(s, SIOCIFCREATE2, &ifr) < 0) {
         virReportSystemError(errno, "%s",
                              _("Unable to create tap device"));
-        goto cleanup;
+        VIR_FORCE_CLOSE(s);
+        return -1;
     }
 
+    created = true;
+
     if (tapfd) {
         g_autofree char *dev_path = NULL;
         dev_path = g_strdup_printf("/dev/%s", ifr.ifr_name);
@@ -378,6 +382,18 @@ int virNetDevTapCreate(char **ifname,
 
     ret = 0;
  cleanup:
+    if (ret < 0 && created) {
+        virErrorPtr err;
+
+        virErrorPreserveLast(&err);
+
+        if (tapfd)
+            VIR_FORCE_CLOSE(*tapfd);
+
+        ignore_value(virNetDevTapDelete(ifr.ifr_name, NULL));
+        virErrorRestore(&err);
+    }
+
     VIR_FORCE_CLOSE(s);
 
     return ret;
-- 
2.55.0

Reply via email to