sockets: avoid leak of listen file descriptor
PATCH 1/1 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.
--- util/qemu-sockets.c | 31 +++++++++++++++++++------------ 1 file changed, 19 insertions(+), 12 deletions(-)
util/qemu-sockets.c +19 -12
@@ -207,7 +207,7 @@ static int inet_listen_saddr(InetSocketAddress *saddr,char uaddr[INET6_ADDRSTRLEN +1 ];char uport[33 ];int rc, port_min, port_max, p; -int slisten =0 ; +int slisten =-1 ;int saved_errno =0 ;bool socket_created = false;Error *err =NULL ;
@@ -267,16 +267,28 @@ static int inet_listen_saddr(InetSocketAddress *saddr, uaddr,INET6_ADDRSTRLEN ,uport,32 , NI_NUMERICHOST | NI_NUMERICSERV); - slisten =create_fast_reuse_socket (e); -if (slisten <0 ) { -continue ; - } - socket_created = true; port_min =inet_getport (e); port_max = saddr->has_to ? saddr->to + port_offset : port_min;for (p = port_min; p <= port_max; p++) {inet_setport (e, p); + + slisten =create_fast_reuse_socket (e); +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 succeeed if first iteration +* worked though, so treat that as fatal. +*/ +if (p == port_min) { +continue ; + }else { +error_setg_errno (errp, errno, +"Failed to recreate failed listening socket" ); + goto listen_failed; + } + } + rc =try_bind (slisten, saddr, e);if (rc) {if (errno ==EADDRINUSE ) {
@@ -299,12 +311,7 @@ static int inet_listen_saddr(InetSocketAddress *saddr,* socket to allow bind attempts for subsequent ports: */ closesocket (slisten); - slisten =create_fast_reuse_socket (e); -if (slisten <0 ) { -error_setg_errno (errp, errno, -"Failed to recreate failed listening socket" ); - goto listen_failed; - } + slisten =-1 ; } } error_setg_errno(errp, errno,
Signature · 1 line
2.13.6
Quoted 4 lines · Daniel P. Berrange
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.
Quoted 8 lines
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.
Signed-off-by Daniel P. Berrange <[email protected]>--- util/qemu-sockets.c | 31 +++++++++++++++++++------------ 1 file changed, 19 insertions(+), 12 deletions(-)
Self-NACK this has a bug too
Regards,
Daniel
Signature · 3 lines
|: https://berrange.com -o- https://www.flickr.com/photos/dberrange :| |: https://libvirt.org -o- https://fstop138.berrange.com :| |: https://entangle-photo.org -o- https://www.instagram.com/dberrange :|
Quoted 9 lines · Daniel P. Berrange
Quoted 8 lines · Daniel P. Berrange
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.
Quoted 6 lines
Quoted 4 lines
Signed-off-by Daniel P. Berrange <[email protected]>--- util/qemu-sockets.c | 31 +++++++++++++++++++------------ 1 file changed, 19 insertions(+), 12 deletions(-)Self-NACK this has a bug too
Missed this...
Darren.
Quoted 9 lines
Regards,
DanielSignature · 3 lines
|: https://berrange.com -o- https://www.flickr.com/photos/dberrange :| |: https://libvirt.org -o- https://fstop138.berrange.com :| |: https://entangle-photo.org -o- https://www.instagram.com/dberrange :|
Hi Daniel,
Quoted 27 lines · Daniel P. Berrange
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.
Signed-off-by Daniel P. Berrange <[email protected]>---
util/qemu-sockets.c| 31 +++++++++++++++++++------------1 file changed, 19 insertions(+), 12 deletions(-)util/qemu-sockets.c +1
-1@@ -207,7 +207,7 @@ static int inet_listen_saddr(InetSocketAddress *saddr,char uaddr[INET6_ADDRSTRLEN +1 ];char uport[33 ];int rc, port_min, port_max, p; -int slisten =0 ; +int slisten =-1 ;int saved_errno =0 ;bool socket_created = false;Error *err =NULL ;
util/qemu-sockets.c static int inet_listen_saddr(InetSocketAddress *saddr, · line 270
Quoted 9 lines
util/qemu-sockets.c +0
-5@@ -267,16 +267,28 @@ static int inet_listen_saddr(InetSocketAddress *saddr, uaddr,INET6_ADDRSTRLEN ,uport,32 , NI_NUMERICHOST | NI_NUMERICSERV); - slisten =create_fast_reuse_socket (e); -if (slisten <0 ) { -continue ; - } - socket_created = true;
Is this setting of socket_created correct now? Maybe it should be moved to before the try_bind() below?
Quoted 28 lines
util/qemu-sockets.c +17
-0port_min =inet_getport (e); port_max = saddr->has_to ? saddr->to + port_offset : port_min;for (p = port_min; p <= port_max; p++) {inet_setport (e, p); + + slisten =create_fast_reuse_socket (e); +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 succeeed if first iteration +* worked though, so treat that as fatal. +*/ +if (p == port_min) { +continue ; + }else { +error_setg_errno (errp, errno, +"Failed to recreate failed listening socket" ); + goto listen_failed; + } + } + rc =try_bind (slisten, saddr, e);if (rc) {if (errno ==EADDRINUSE ) {@@ -299,12 +311,7 @@ static int inet_listen_saddr(InetSocketAddress *saddr,* socket to allow bind attempts for subsequent ports: */ closesocket (slisten);
util/qemu-sockets.c static int inet_listen_saddr(InetSocketAddress *saddr, · line 317
Quoted 10 lines
util/qemu-sockets.c +1
-6- slisten =create_fast_reuse_socket (e); -if (slisten <0 ) { -error_setg_errno (errp, errno, -"Failed to recreate failed listening socket" ); - goto listen_failed; - } + slisten =-1 ; } } error_setg_errno(errp, errno,
Thanks,
Darren.