mirror of https://github.com/xqemu/xqemu.git
sockets: avoid leak of listen file descriptor
If we iterate over the full port range without successfully binding+listening on the socket, we'll try the next address, whereupon we overwrite the slisten file descriptor variable without closing it. Rather than having two places where we open + close socket FDs on different iterations of nested for loops, re-arrange the code to always open+close within the same loop iteration. Reviewed-by: Eric Blake <eblake@redhat.com> Signed-off-by: Daniel P. Berrange <berrange@redhat.com>
This commit is contained in:
parent
5853e92207
commit
10a7b7e6fd
|
@ -207,7 +207,7 @@ static int inet_listen_saddr(InetSocketAddress *saddr,
|
||||||
char uaddr[INET6_ADDRSTRLEN+1];
|
char uaddr[INET6_ADDRSTRLEN+1];
|
||||||
char uport[33];
|
char uport[33];
|
||||||
int rc, port_min, port_max, p;
|
int rc, port_min, port_max, p;
|
||||||
int slisten = 0;
|
int slisten = -1;
|
||||||
int saved_errno = 0;
|
int saved_errno = 0;
|
||||||
bool socket_created = false;
|
bool socket_created = false;
|
||||||
Error *err = NULL;
|
Error *err = NULL;
|
||||||
|
@ -267,31 +267,42 @@ static int inet_listen_saddr(InetSocketAddress *saddr,
|
||||||
uaddr,INET6_ADDRSTRLEN,uport,32,
|
uaddr,INET6_ADDRSTRLEN,uport,32,
|
||||||
NI_NUMERICHOST | NI_NUMERICSERV);
|
NI_NUMERICHOST | NI_NUMERICSERV);
|
||||||
|
|
||||||
slisten = create_fast_reuse_socket(e);
|
|
||||||
if (slisten < 0) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
socket_created = true;
|
|
||||||
port_min = inet_getport(e);
|
port_min = inet_getport(e);
|
||||||
port_max = saddr->has_to ? saddr->to + port_offset : port_min;
|
port_max = saddr->has_to ? saddr->to + port_offset : port_min;
|
||||||
for (p = port_min; p <= port_max; p++) {
|
for (p = port_min; p <= port_max; p++) {
|
||||||
inet_setport(e, p);
|
inet_setport(e, p);
|
||||||
rc = try_bind(slisten, saddr, e);
|
|
||||||
if (rc) {
|
slisten = create_fast_reuse_socket(e);
|
||||||
if (errno == EADDRINUSE) {
|
if (slisten < 0) {
|
||||||
|
/* First time we expect we might fail to create the socket
|
||||||
|
* eg if 'e' has AF_INET6 but ipv6 kmod is not loaded.
|
||||||
|
* Later iterations should always succeed if first iteration
|
||||||
|
* worked though, so treat that as fatal.
|
||||||
|
*/
|
||||||
|
if (p == port_min) {
|
||||||
continue;
|
continue;
|
||||||
} else {
|
} else {
|
||||||
error_setg_errno(errp, errno, "Failed to bind socket");
|
error_setg_errno(errp, errno,
|
||||||
|
"Failed to recreate failed listening socket");
|
||||||
goto listen_failed;
|
goto listen_failed;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (!listen(slisten, 1)) {
|
socket_created = true;
|
||||||
goto listen_ok;
|
|
||||||
}
|
rc = try_bind(slisten, saddr, e);
|
||||||
if (errno != EADDRINUSE) {
|
if (rc < 0) {
|
||||||
error_setg_errno(errp, errno, "Failed to listen on socket");
|
if (errno != EADDRINUSE) {
|
||||||
goto listen_failed;
|
error_setg_errno(errp, errno, "Failed to bind socket");
|
||||||
|
goto listen_failed;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (!listen(slisten, 1)) {
|
||||||
|
goto listen_ok;
|
||||||
|
}
|
||||||
|
if (errno != EADDRINUSE) {
|
||||||
|
error_setg_errno(errp, errno, "Failed to listen on socket");
|
||||||
|
goto listen_failed;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
/* Someone else managed to bind to the same port and beat us
|
/* Someone else managed to bind to the same port and beat us
|
||||||
* to listen on it! Socket semantics does not allow us to
|
* to listen on it! Socket semantics does not allow us to
|
||||||
|
@ -299,12 +310,7 @@ static int inet_listen_saddr(InetSocketAddress *saddr,
|
||||||
* socket to allow bind attempts for subsequent ports:
|
* socket to allow bind attempts for subsequent ports:
|
||||||
*/
|
*/
|
||||||
closesocket(slisten);
|
closesocket(slisten);
|
||||||
slisten = create_fast_reuse_socket(e);
|
slisten = -1;
|
||||||
if (slisten < 0) {
|
|
||||||
error_setg_errno(errp, errno,
|
|
||||||
"Failed to recreate failed listening socket");
|
|
||||||
goto listen_failed;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
error_setg_errno(errp, errno,
|
error_setg_errno(errp, errno,
|
||||||
|
|
Loading…
Reference in New Issue