Fix memory leak in virNetSocketNewConnectUNIX

==26726==    by 0x673CD67: __vasprintf_chk (vasprintf_chk.c:80)
==26726==    by 0x5673605: UnknownInlinedFun (stdio2.h:210)
==26726==    by 0x5673605: virVasprintfInternal (virstring.c:476)
==26726==    by 0x56736EE: virAsprintfInternal (virstring.c:497)
==26726==    by 0x5680C37: virGetUserRuntimeDirectory (virutil.c:866)
==26726==    by 0x5783A89: virNetSocketNewConnectUNIX (virnetsocket.c:572)
==26726==    by 0x57751AF: virNetClientNewUNIX (virnetclient.c:344)
==26726==    by 0x57689B3: doRemoteOpen (remote_driver.c:895)
==26726==    by 0x5769F8E: remoteConnectOpen (remote_driver.c:1195)
==26726==    by 0x57092DF: do_open (libvirt.c:1189)
==26726==    by 0x570A7BF: virConnectOpenAuth (libvirt.c:1341)

https://bugzilla.redhat.com/show_bug.cgi?id=1215042
Signed-off-by: Jiri Denemark <jdenemar@redhat.com>
This commit is contained in:
Jiri Denemark 2015-04-24 11:56:34 +02:00
parent 7674c0454b
commit da4d7c3069

View File

@ -546,6 +546,7 @@ int virNetSocketNewConnectUNIX(const char *path,
virSocketAddr localAddr; virSocketAddr localAddr;
virSocketAddr remoteAddr; virSocketAddr remoteAddr;
char *rundir = NULL; char *rundir = NULL;
int ret = -1;
memset(&localAddr, 0, sizeof(localAddr)); memset(&localAddr, 0, sizeof(localAddr));
memset(&remoteAddr, 0, sizeof(remoteAddr)); memset(&remoteAddr, 0, sizeof(remoteAddr));
@ -559,50 +560,50 @@ int virNetSocketNewConnectUNIX(const char *path,
virReportError(VIR_ERR_INTERNAL_ERROR, "%s", virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
_("Auto-spawn of daemon requested, " _("Auto-spawn of daemon requested, "
"but no binary specified")); "but no binary specified"));
goto error; goto cleanup;
} }
if (!(binname = last_component(binary)) || binname[0] == '\0') { if (!(binname = last_component(binary)) || binname[0] == '\0') {
virReportError(VIR_ERR_INTERNAL_ERROR, virReportError(VIR_ERR_INTERNAL_ERROR,
_("Cannot determine basename for binary '%s'"), _("Cannot determine basename for binary '%s'"),
binary); binary);
goto error; goto cleanup;
} }
if (!(rundir = virGetUserRuntimeDirectory())) if (!(rundir = virGetUserRuntimeDirectory()))
goto error; goto cleanup;
if (virFileMakePathWithMode(rundir, 0700) < 0) { if (virFileMakePathWithMode(rundir, 0700) < 0) {
virReportSystemError(errno, virReportSystemError(errno,
_("Cannot create user runtime directory '%s'"), _("Cannot create user runtime directory '%s'"),
rundir); rundir);
goto error; goto cleanup;
} }
if (virAsprintf(&lockpath, "%s/%s.lock", rundir, binname) < 0) if (virAsprintf(&lockpath, "%s/%s.lock", rundir, binname) < 0)
goto error; goto cleanup;
if ((lockfd = open(lockpath, O_RDWR | O_CREAT, 0600)) < 0 || if ((lockfd = open(lockpath, O_RDWR | O_CREAT, 0600)) < 0 ||
virSetCloseExec(lockfd) < 0) { virSetCloseExec(lockfd) < 0) {
virReportSystemError(errno, _("Unable to create lock '%s'"), lockpath); virReportSystemError(errno, _("Unable to create lock '%s'"), lockpath);
goto error; goto cleanup;
} }
if (virFileLock(lockfd, false, 0, 1, true) < 0) { if (virFileLock(lockfd, false, 0, 1, true) < 0) {
virReportSystemError(errno, _("Unable to lock '%s'"), lockpath); virReportSystemError(errno, _("Unable to lock '%s'"), lockpath);
goto error; goto cleanup;
} }
} }
if ((fd = socket(PF_UNIX, SOCK_STREAM, 0)) < 0) { if ((fd = socket(PF_UNIX, SOCK_STREAM, 0)) < 0) {
virReportSystemError(errno, "%s", _("Failed to create socket")); virReportSystemError(errno, "%s", _("Failed to create socket"));
goto error; goto cleanup;
} }
remoteAddr.data.un.sun_family = AF_UNIX; remoteAddr.data.un.sun_family = AF_UNIX;
if (virStrcpyStatic(remoteAddr.data.un.sun_path, path) == NULL) { if (virStrcpyStatic(remoteAddr.data.un.sun_path, path) == NULL) {
virReportSystemError(ENOMEM, _("Path %s too long for unix socket"), path); virReportSystemError(ENOMEM, _("Path %s too long for unix socket"), path);
goto error; goto cleanup;
} }
if (remoteAddr.data.un.sun_path[0] == '@') if (remoteAddr.data.un.sun_path[0] == '@')
remoteAddr.data.un.sun_path[0] = '\0'; remoteAddr.data.un.sun_path[0] = '\0';
@ -612,42 +613,39 @@ int virNetSocketNewConnectUNIX(const char *path,
if (!(spawnDaemon && errno == ENOENT)) { if (!(spawnDaemon && errno == ENOENT)) {
virReportSystemError(errno, _("Failed to connect socket to '%s'"), virReportSystemError(errno, _("Failed to connect socket to '%s'"),
path); path);
goto error; goto cleanup;
} }
if (virNetSocketForkDaemon(binary) < 0) if (virNetSocketForkDaemon(binary) < 0)
goto error; goto cleanup;
retries--; retries--;
usleep(5000); usleep(5000);
} }
if (lockfd != -1) {
unlink(lockpath);
VIR_FORCE_CLOSE(lockfd);
VIR_FREE(lockpath);
}
localAddr.len = sizeof(localAddr.data); localAddr.len = sizeof(localAddr.data);
if (getsockname(fd, &localAddr.data.sa, &localAddr.len) < 0) { if (getsockname(fd, &localAddr.data.sa, &localAddr.len) < 0) {
virReportSystemError(errno, "%s", _("Unable to get local socket name")); virReportSystemError(errno, "%s", _("Unable to get local socket name"));
goto error; goto cleanup;
} }
if (!(*retsock = virNetSocketNew(&localAddr, &remoteAddr, true, fd, -1, 0))) if (!(*retsock = virNetSocketNew(&localAddr, &remoteAddr, true, fd, -1, 0)))
goto error; goto cleanup;
return 0; ret = 0;
error: cleanup:
if (lockfd != -1) { if (lockfd != -1) {
unlink(lockpath); unlink(lockpath);
VIR_FORCE_CLOSE(lockfd); VIR_FORCE_CLOSE(lockfd);
} }
VIR_FREE(lockpath); VIR_FREE(lockpath);
VIR_FREE(rundir); VIR_FREE(rundir);
VIR_FORCE_CLOSE(fd);
return -1; if (ret < 0)
VIR_FORCE_CLOSE(fd);
return ret;
} }
#else #else
int virNetSocketNewConnectUNIX(const char *path ATTRIBUTE_UNUSED, int virNetSocketNewConnectUNIX(const char *path ATTRIBUTE_UNUSED,