We're leaking file descriptors to child processes. Set FD_CLOEXEC on file descriptors that don't need to be passed to children to stop this misbehaviour.
Signed-off-by: Kevin Wolf <kw...@redhat.com> --- block/raw-posix.c | 1 + gdbstub.c | 6 ++++++ kvm-all.c | 1 + migration-tcp.c | 6 +++--- migration-unix.c | 6 +++--- net.c | 8 ++++---- osdep.c | 46 ++++++++++++++++++++++++++++++++++++++++++++++ posix-aio-compat.c | 3 +++ qemu-char.c | 7 ++++++- qemu-common.h | 2 ++ qemu-sockets.c | 10 +++++----- qemu_socket.h | 2 ++ slirp/misc.c | 4 ++-- slirp/slirp.h | 4 ++++ slirp/socket.c | 2 +- slirp/tcp_subr.c | 2 +- slirp/udp.c | 4 ++-- vl.c | 9 +++++++++ vnc.c | 2 +- 19 files changed, 102 insertions(+), 23 deletions(-) diff --git a/block/raw-posix.c b/block/raw-posix.c index f558976..5288948 100644 --- a/block/raw-posix.c +++ b/block/raw-posix.c @@ -160,6 +160,7 @@ static int raw_open_common(BlockDriverState *bs, const char *filename, ret = -EACCES; return ret; } + qemu_set_cloexec(fd); s->fd = fd; s->aligned_buf = NULL; diff --git a/gdbstub.c b/gdbstub.c index 055093f..5a4f7d4 100644 --- a/gdbstub.c +++ b/gdbstub.c @@ -2356,6 +2356,9 @@ static void gdb_accept(void) perror("accept"); return; } else if (fd >= 0) { +#ifndef _WIN32 + fcntl(fd, F_SETFD, FD_CLOEXEC); +#endif break; } } @@ -2385,6 +2388,9 @@ static int gdbserver_open(int port) perror("socket"); return -1; } +#ifndef _WIN32 + fcntl(fd, F_SETFD, FD_CLOEXEC); +#endif /* allow fast reuse */ val = 1; diff --git a/kvm-all.c b/kvm-all.c index 1916ec6..e78dd44 100644 --- a/kvm-all.c +++ b/kvm-all.c @@ -420,6 +420,7 @@ int kvm_init(int smp_cpus) ret = -errno; goto err; } + qemu_set_cloexec(s->fd); ret = kvm_ioctl(s, KVM_GET_API_VERSION, 0); if (ret < KVM_API_VERSION) { diff --git a/migration-tcp.c b/migration-tcp.c index 9ed92b4..dc8772c 100644 --- a/migration-tcp.c +++ b/migration-tcp.c @@ -99,7 +99,7 @@ MigrationState *tcp_start_outgoing_migration(const char *host_port, s->state = MIG_STATE_ACTIVE; s->mon_resume = NULL; s->bandwidth_limit = bandwidth_limit; - s->fd = socket(PF_INET, SOCK_STREAM, 0); + s->fd = qemu_socket(PF_INET, SOCK_STREAM, 0); if (s->fd == -1) { qemu_free(s); return NULL; @@ -139,7 +139,7 @@ static void tcp_accept_incoming_migration(void *opaque) int c, ret; do { - c = accept(s, (struct sockaddr *)&addr, &addrlen); + c = qemu_accept(s, (struct sockaddr *)&addr, &addrlen); } while (c == -1 && socket_error() == EINTR); dprintf("accepted migration\n"); @@ -186,7 +186,7 @@ int tcp_start_incoming_migration(const char *host_port) return -EINVAL; } - s = socket(PF_INET, SOCK_STREAM, 0); + s = qemu_socket(PF_INET, SOCK_STREAM, 0); if (s == -1) return -socket_error(); diff --git a/migration-unix.c b/migration-unix.c index a26587a..d3de7ae 100644 --- a/migration-unix.c +++ b/migration-unix.c @@ -98,7 +98,7 @@ MigrationState *unix_start_outgoing_migration(const char *path, s->state = MIG_STATE_ACTIVE; s->mon_resume = NULL; s->bandwidth_limit = bandwidth_limit; - s->fd = socket(PF_UNIX, SOCK_STREAM, 0); + s->fd = qemu_socket(PF_UNIX, SOCK_STREAM, 0); if (s->fd < 0) { dprintf("Unable to open socket"); goto err_after_alloc; @@ -143,7 +143,7 @@ static void unix_accept_incoming_migration(void *opaque) int c, ret; do { - c = accept(s, (struct sockaddr *)&addr, &addrlen); + c = qemu_accept(s, (struct sockaddr *)&addr, &addrlen); } while (c == -1 && socket_error() == EINTR); dprintf("accepted migration\n"); @@ -184,7 +184,7 @@ int unix_start_incoming_migration(const char *path) dprintf("Attempting to start an incoming migration\n"); - sock = socket(PF_UNIX, SOCK_STREAM, 0); + sock = qemu_socket(PF_UNIX, SOCK_STREAM, 0); if (sock < 0) { fprintf(stderr, "Could not open unix socket: %s\n", strerror(errno)); return -EINVAL; diff --git a/net.c b/net.c index 9ea66e3..cff6efd 100644 --- a/net.c +++ b/net.c @@ -1515,7 +1515,7 @@ static int net_socket_mcast_create(struct sockaddr_in *mcastaddr) return -1; } - fd = socket(PF_INET, SOCK_DGRAM, 0); + fd = qemu_socket(PF_INET, SOCK_DGRAM, 0); if (fd < 0) { perror("socket(PF_INET, SOCK_DGRAM)"); return -1; @@ -1693,7 +1693,7 @@ static void net_socket_accept(void *opaque) for(;;) { len = sizeof(saddr); - fd = accept(s->fd, (struct sockaddr *)&saddr, &len); + fd = qemu_accept(s->fd, (struct sockaddr *)&saddr, &len); if (fd < 0 && errno != EINTR) { return; } else if (fd >= 0) { @@ -1724,7 +1724,7 @@ static int net_socket_listen_init(VLANState *vlan, s = qemu_mallocz(sizeof(NetSocketListenState)); - fd = socket(PF_INET, SOCK_STREAM, 0); + fd = qemu_socket(PF_INET, SOCK_STREAM, 0); if (fd < 0) { perror("socket"); return -1; @@ -1765,7 +1765,7 @@ static int net_socket_connect_init(VLANState *vlan, if (parse_host_port(&saddr, host_str) < 0) return -1; - fd = socket(PF_INET, SOCK_STREAM, 0); + fd = qemu_socket(PF_INET, SOCK_STREAM, 0); if (fd < 0) { perror("socket"); return -1; diff --git a/osdep.c b/osdep.c index fd8bbd7..15c5ff1 100644 --- a/osdep.c +++ b/osdep.c @@ -128,6 +128,8 @@ int qemu_create_pidfile(const char *filename) if (lockf(fd, F_TLOCK, 0) == -1) return -1; + qemu_set_cloexec(fd); + len = snprintf(buffer, sizeof(buffer), "%ld\n", (long)getpid()); if (write(fd, buffer, len) != len) return -1; @@ -201,11 +203,55 @@ int inet_aton(const char *cp, struct in_addr *ia) ia->s_addr = addr; return 1; } + +void qemu_set_cloexec(int fd) +{ +} + #else + void socket_set_nonblock(int fd) { int f; f = fcntl(fd, F_GETFL); fcntl(fd, F_SETFL, f | O_NONBLOCK); } + +void qemu_set_cloexec(int fd) +{ + int f; + f = fcntl(fd, F_GETFD); + fcntl(fd, F_SETFD, f | FD_CLOEXEC); +} + #endif + +/* + * Opens a socket with FD_CLOEXEC set + */ +int qemu_socket(int domain, int type, int protocol) +{ + int ret; + + ret = socket(domain, type, protocol); + if (ret >= 0) { + qemu_set_cloexec(ret); + } + + return ret; +} + +/* + * Accept a connection and set FD_CLOEXEC + */ +int qemu_accept(int s, struct sockaddr *addr, socklen_t *addrlen) +{ + int ret; + + ret = accept(s, addr, addrlen); + if (ret >= 0) { + qemu_set_cloexec(ret); + } + + return ret; +} diff --git a/posix-aio-compat.c b/posix-aio-compat.c index 7f391c9..855763f 100644 --- a/posix-aio-compat.c +++ b/posix-aio-compat.c @@ -630,6 +630,9 @@ int paio_init(void) return -1; } + qemu_set_cloexec(fds[0]); + qemu_set_cloexec(fds[1]); + s->rfd = fds[0]; s->wfd = fds[1]; diff --git a/qemu-char.c b/qemu-char.c index 40bd7e8..6f86459 100644 --- a/qemu-char.c +++ b/qemu-char.c @@ -630,6 +630,7 @@ static CharDriverState *qemu_chr_open_file_out(QemuOpts *opts) O_WRONLY | O_TRUNC | O_CREAT | O_BINARY, 0666)); if (fd_out < 0) return NULL; + qemu_set_cloexec(fd_out); return qemu_chr_open_fd(-1, fd_out); } @@ -657,6 +658,10 @@ static CharDriverState *qemu_chr_open_pipe(QemuOpts *opts) if (fd_in < 0) return NULL; } + + qemu_set_cloexec(fd_in); + qemu_set_cloexec(fd_out); + return qemu_chr_open_fd(fd_in, fd_out); } @@ -2106,7 +2111,7 @@ static void tcp_chr_accept(void *opaque) len = sizeof(saddr); addr = (struct sockaddr *)&saddr; } - fd = accept(s->listen_fd, addr, &len); + fd = qemu_accept(s->listen_fd, addr, &len); if (fd < 0 && errno != EINTR) { return; } else if (fd >= 0) { diff --git a/qemu-common.h b/qemu-common.h index b779cfe..2f6ca1a 100644 --- a/qemu-common.h +++ b/qemu-common.h @@ -159,6 +159,8 @@ void *get_mmap_addr(unsigned long size); void qemu_mutex_lock_iothread(void); void qemu_mutex_unlock_iothread(void); +void qemu_set_cloexec(int fd); + /* Error handling. */ void QEMU_NORETURN hw_error(const char *fmt, ...) diff --git a/qemu-sockets.c b/qemu-sockets.c index 8801453..8850516 100644 --- a/qemu-sockets.c +++ b/qemu-sockets.c @@ -160,7 +160,7 @@ int inet_listen_opts(QemuOpts *opts, int port_offset) getnameinfo((struct sockaddr*)e->ai_addr,e->ai_addrlen, uaddr,INET6_ADDRSTRLEN,uport,32, NI_NUMERICHOST | NI_NUMERICSERV); - slisten = socket(e->ai_family, e->ai_socktype, e->ai_protocol); + slisten = qemu_socket(e->ai_family, e->ai_socktype, e->ai_protocol); if (slisten < 0) { fprintf(stderr,"%s: socket(%s): %s\n", __FUNCTION__, inet_strfamily(e->ai_family), strerror(errno)); @@ -258,7 +258,7 @@ int inet_connect_opts(QemuOpts *opts) fprintf(stderr,"%s: getnameinfo: oops\n", __FUNCTION__); continue; } - sock = socket(e->ai_family, e->ai_socktype, e->ai_protocol); + sock = qemu_socket(e->ai_family, e->ai_socktype, e->ai_protocol); if (sock < 0) { fprintf(stderr,"%s: socket(%s): %s\n", __FUNCTION__, inet_strfamily(e->ai_family), strerror(errno)); @@ -351,7 +351,7 @@ int inet_dgram_opts(QemuOpts *opts) } /* create socket */ - sock = socket(peer->ai_family, peer->ai_socktype, peer->ai_protocol); + sock = qemu_socket(peer->ai_family, peer->ai_socktype, peer->ai_protocol); if (sock < 0) { fprintf(stderr,"%s: socket(%s): %s\n", __FUNCTION__, inet_strfamily(peer->ai_family), strerror(errno)); @@ -505,7 +505,7 @@ int unix_listen_opts(QemuOpts *opts) const char *path = qemu_opt_get(opts, "path"); int sock, fd; - sock = socket(PF_UNIX, SOCK_STREAM, 0); + sock = qemu_socket(PF_UNIX, SOCK_STREAM, 0); if (sock < 0) { perror("socket(unix)"); return -1; @@ -560,7 +560,7 @@ int unix_connect_opts(QemuOpts *opts) return -1; } - sock = socket(PF_UNIX, SOCK_STREAM, 0); + sock = qemu_socket(PF_UNIX, SOCK_STREAM, 0); if (sock < 0) { perror("socket(unix)"); return -1; diff --git a/qemu_socket.h b/qemu_socket.h index c253b32..86bdbf5 100644 --- a/qemu_socket.h +++ b/qemu_socket.h @@ -32,6 +32,8 @@ int inet_aton(const char *cp, struct in_addr *ia); #include "qemu-option.h" /* misc helpers */ +int qemu_socket(int domain, int type, int protocol); +int qemu_accept(int s, struct sockaddr *addr, socklen_t *addrlen); void socket_set_nonblock(int fd); int send_all(int fd, const void *buf, int len1); diff --git a/slirp/misc.c b/slirp/misc.c index e9f08fd..c76ad8f 100644 --- a/slirp/misc.c +++ b/slirp/misc.c @@ -132,7 +132,7 @@ fork_exec(struct socket *so, const char *ex, int do_pty) addr.sin_port = 0; addr.sin_addr.s_addr = INADDR_ANY; - if ((s = socket(AF_INET, SOCK_STREAM, 0)) < 0 || + if ((s = qemu_socket(AF_INET, SOCK_STREAM, 0)) < 0 || bind(s, (struct sockaddr *)&addr, addrlen) < 0 || listen(s, 1) < 0) { lprint("Error: inet socket: %s\n", strerror(errno)); @@ -165,7 +165,7 @@ fork_exec(struct socket *so, const char *ex, int do_pty) * Connect to the socket * XXX If any of these fail, we're in trouble! */ - s = socket(AF_INET, SOCK_STREAM, 0); + s = qemu_socket(AF_INET, SOCK_STREAM, 0); addr.sin_addr = loopback_addr; do { ret = connect(s, (struct sockaddr *)&addr, addrlen); diff --git a/slirp/slirp.h b/slirp/slirp.h index 9ef57ea..98a2644 100644 --- a/slirp/slirp.h +++ b/slirp/slirp.h @@ -197,6 +197,10 @@ int inet_aton(const char *cp, struct in_addr *ia); #include "bootp.h" #include "tftp.h" +/* osdep.c */ +int qemu_socket(int domain, int type, int protocol); + + struct Slirp { QTAILQ_ENTRY(Slirp) entry; diff --git a/slirp/socket.c b/slirp/socket.c index 207109c..cf6e6a9 100644 --- a/slirp/socket.c +++ b/slirp/socket.c @@ -626,7 +626,7 @@ tcp_listen(Slirp *slirp, u_int32_t haddr, u_int hport, u_int32_t laddr, addr.sin_addr.s_addr = haddr; addr.sin_port = hport; - if (((s = socket(AF_INET,SOCK_STREAM,0)) < 0) || + if (((s = qemu_socket(AF_INET,SOCK_STREAM,0)) < 0) || (setsockopt(s,SOL_SOCKET,SO_REUSEADDR,(char *)&opt,sizeof(int)) < 0) || (bind(s,(struct sockaddr *)&addr, sizeof(addr)) < 0) || (listen(s,1) < 0)) { diff --git a/slirp/tcp_subr.c b/slirp/tcp_subr.c index 0417345..7851307 100644 --- a/slirp/tcp_subr.c +++ b/slirp/tcp_subr.c @@ -325,7 +325,7 @@ int tcp_fconnect(struct socket *so) DEBUG_CALL("tcp_fconnect"); DEBUG_ARG("so = %lx", (long )so); - if( (ret=so->s=socket(AF_INET,SOCK_STREAM,0)) >= 0) { + if( (ret = so->s = qemu_socket(AF_INET,SOCK_STREAM,0)) >= 0) { int opt, s=so->s; struct sockaddr_in addr; diff --git a/slirp/udp.c b/slirp/udp.c index a88b645..d6c39b9 100644 --- a/slirp/udp.c +++ b/slirp/udp.c @@ -302,7 +302,7 @@ int udp_output(struct socket *so, struct mbuf *m, int udp_attach(struct socket *so) { - if((so->s = socket(AF_INET,SOCK_DGRAM,0)) != -1) { + if((so->s = qemu_socket(AF_INET,SOCK_DGRAM,0)) != -1) { so->so_expire = curtime + SO_EXPIRE; insque(so, &so->slirp->udb); } @@ -350,7 +350,7 @@ udp_listen(Slirp *slirp, u_int32_t haddr, u_int hport, u_int32_t laddr, if (!so) { return NULL; } - so->s = socket(AF_INET,SOCK_DGRAM,0); + so->s = qemu_socket(AF_INET,SOCK_DGRAM,0); so->so_expire = curtime + SO_EXPIRE; insque(so, &slirp->udb); diff --git a/vl.c b/vl.c index fff8e8d..c84b7fb 100644 --- a/vl.c +++ b/vl.c @@ -1245,6 +1245,7 @@ static int hpet_start_timer(struct qemu_alarm_timer *t) fd = open("/dev/hpet", O_RDONLY); if (fd < 0) return -1; + qemu_set_cloexec(fd); /* Set frequency */ r = ioctl(fd, HPET_IRQFREQ, RTC_FREQ); @@ -1294,6 +1295,7 @@ static int rtc_start_timer(struct qemu_alarm_timer *t) TFR(rtc_fd = open("/dev/rtc", O_RDONLY)); if (rtc_fd < 0) return -1; + qemu_set_cloexec(rtc_fd); ioctl(rtc_fd, RTC_IRQP_READ, ¤t_rtc_freq); if (current_rtc_freq != RTC_FREQ && ioctl(rtc_fd, RTC_IRQP_SET, RTC_FREQ) < 0) { @@ -3305,6 +3307,9 @@ static int qemu_event_init(void) if (err == -1) return -errno; + qemu_set_cloexec(fds[0]); + qemu_set_cloexec(fds[1]); + err = fcntl_setfl(fds[0], O_NONBLOCK); if (err < 0) goto fail; @@ -5461,6 +5466,9 @@ int main(int argc, char **argv, char **envp) } else if (pid < 0) exit(1); + close(fds[0]); + qemu_set_cloexec(fds[1]); + setsid(); pid = fork(); @@ -5862,6 +5870,7 @@ int main(int argc, char **argv, char **envp) chdir("/"); TFR(fd = open("/dev/null", O_RDWR)); + qemu_set_cloexec(fd); if (fd == -1) exit(1); } diff --git a/vnc.c b/vnc.c index 2bb8024..32c4678 100644 --- a/vnc.c +++ b/vnc.c @@ -2247,7 +2247,7 @@ static void vnc_listen_read(void *opaque) /* Catch-up */ vga_hw_update(); - int csock = accept(vs->lsock, (struct sockaddr *)&addr, &addrlen); + int csock = qemu_accept(vs->lsock, (struct sockaddr *)&addr, &addrlen); if (csock != -1) { vnc_connect(vs, csock); } -- 1.6.2.5