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 <bogorodskiy@gmail.com> --- 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