From patchwork Mon Nov 16 15:47:00 2009 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Kevin Wolf X-Patchwork-Id: 38509 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Received: from lists.gnu.org (lists.gnu.org [199.232.76.165]) (using TLSv1 with cipher DHE-RSA-AES256-SHA (256/256 bits)) (Client did not present a certificate) by ozlabs.org (Postfix) with ESMTPS id 1CDDD1007D3 for ; Tue, 17 Nov 2009 02:48:50 +1100 (EST) Received: from localhost ([127.0.0.1]:60426 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.43) id 1NA3os-0004bi-GY for incoming@patchwork.ozlabs.org; Mon, 16 Nov 2009 10:48:46 -0500 Received: from mailman by lists.gnu.org with tmda-scanned (Exim 4.43) id 1NA3oK-0004bN-9x for qemu-devel@nongnu.org; Mon, 16 Nov 2009 10:48:12 -0500 Received: from exim by lists.gnu.org with spam-scanned (Exim 4.43) id 1NA3oF-0004ao-GP for qemu-devel@nongnu.org; Mon, 16 Nov 2009 10:48:12 -0500 Received: from [199.232.76.173] (port=50314 helo=monty-python.gnu.org) by lists.gnu.org with esmtp (Exim 4.43) id 1NA3oF-0004al-BT for qemu-devel@nongnu.org; Mon, 16 Nov 2009 10:48:07 -0500 Received: from mx1.redhat.com ([209.132.183.28]:2204) by monty-python.gnu.org with esmtp (Exim 4.60) (envelope-from ) id 1NA3oE-0001Zx-Kx for qemu-devel@nongnu.org; Mon, 16 Nov 2009 10:48:07 -0500 Received: from int-mx02.intmail.prod.int.phx2.redhat.com (int-mx02.intmail.prod.int.phx2.redhat.com [10.5.11.12]) by mx1.redhat.com (8.13.8/8.13.8) with ESMTP id nAGFm5df014063 (version=TLSv1/SSLv3 cipher=DHE-RSA-AES256-SHA bits=256 verify=OK) for ; Mon, 16 Nov 2009 10:48:05 -0500 Received: from localhost.localdomain (dhcp-5-175.str.redhat.com [10.32.5.175]) by int-mx02.intmail.prod.int.phx2.redhat.com (8.13.8/8.13.8) with ESMTP id nAGFm3bh018544; Mon, 16 Nov 2009 10:48:04 -0500 From: Kevin Wolf To: qemu-devel@nongnu.org Date: Mon, 16 Nov 2009 16:47:00 +0100 Message-Id: <1258386420-23294-1-git-send-email-kwolf@redhat.com> X-Scanned-By: MIMEDefang 2.67 on 10.5.11.12 X-detected-operating-system: by monty-python.gnu.org: Genre and OS details not recognized. Cc: Kevin Wolf Subject: [Qemu-devel] [PATCH v2] Don't leak file descriptors X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.5 Precedence: list List-Id: qemu-devel.nongnu.org List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Sender: qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org Errors-To: qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org 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 --- block/raw-posix.c | 2 +- gdbstub.c | 6 +++ kvm-all.c | 2 +- migration-tcp.c | 6 +- migration-unix.c | 6 +- net.c | 8 ++-- osdep.c | 104 +++++++++++++++++++++++++++++++++++++++++++++++++++- posix-aio-compat.c | 2 +- qemu-char.c | 8 ++-- qemu-common.h | 7 +++ 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 | 11 +++-- vnc.c | 2 +- 19 files changed, 158 insertions(+), 34 deletions(-) diff --git a/block/raw-posix.c b/block/raw-posix.c index f558976..0ee8ff7 100644 --- a/block/raw-posix.c +++ b/block/raw-posix.c @@ -153,7 +153,7 @@ static int raw_open_common(BlockDriverState *bs, const char *filename, s->open_flags |= O_DSYNC; s->fd = -1; - fd = open(filename, s->open_flags, 0644); + fd = qemu_open(filename, s->open_flags, 0644); if (fd < 0) { ret = -errno; if (ret == -EROFS) 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..fe6220c 100644 --- a/kvm-all.c +++ b/kvm-all.c @@ -414,7 +414,7 @@ int kvm_init(int smp_cpus) s->slots[i].slot = i; s->vmfd = -1; - s->fd = open("/dev/kvm", O_RDWR); + s->fd = qemu_open("/dev/kvm", O_RDWR); if (s->fd == -1) { fprintf(stderr, "Could not access KVM kernel module: %m\n"); ret = -errno; 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..039065e 100644 --- a/osdep.c +++ b/osdep.c @@ -121,7 +121,7 @@ int qemu_create_pidfile(const char *filename) #ifndef _WIN32 int fd; - fd = open(filename, O_RDWR | O_CREAT, 0600); + fd = qemu_open(filename, O_RDWR | O_CREAT, 0600); if (fd == -1) return -1; @@ -201,11 +201,113 @@ 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 file with FD_CLOEXEC set + */ +int qemu_open(const char *name, int flags, ...) +{ + int ret; + int mode = 0; + + if (flags & O_CREAT) { + va_list ap; + + va_start(ap, flags); + mode = va_arg(ap, int); + va_end(ap); + } + +#ifdef O_CLOEXEC + ret = open(name, flags | O_CLOEXEC, mode); +#else + ret = open(name, flags, mode); + if (ret >= 0) { + qemu_set_cloexec(ret); + } #endif + + return ret; +} + +#ifndef _WIN32 +/* + * Creates a pipe with FD_CLOEXEC set on both file descriptors + */ +int qemu_pipe(int pipefd[2]) +{ + int ret; + +#ifdef O_CLOEXEC + ret = pipe2(pipefd, O_CLOEXEC); +#else + ret = pipe(pipefd); + if (ret == 0) { + qemu_set_cloexec(pipefd[0]); + qemu_set_cloexec(pipefd[1]); + } +#endif + + return ret; +} +#endif + +/* + * Opens a socket with FD_CLOEXEC set + */ +int qemu_socket(int domain, int type, int protocol) +{ + int ret; + +#ifdef SOCK_CLOEXEC + ret = socket(domain, type | SOCK_CLOEXEC, protocol); +#else + ret = socket(domain, type, protocol); + if (ret >= 0) { + qemu_set_cloexec(ret); + } +#endif + + return ret; +} + +/* + * Accept a connection and set FD_CLOEXEC + */ +int qemu_accept(int s, struct sockaddr *addr, socklen_t *addrlen) +{ + int ret; + +#ifdef SOCK_CLOEXEC + ret = accept4(s, addr, addrlen, SOCK_CLOEXEC); +#else + ret = accept(s, addr, addrlen); + if (ret >= 0) { + qemu_set_cloexec(ret); + } +#endif + + return ret; +} diff --git a/posix-aio-compat.c b/posix-aio-compat.c index 7f391c9..ac247e1 100644 --- a/posix-aio-compat.c +++ b/posix-aio-compat.c @@ -625,7 +625,7 @@ int paio_init(void) sigaction(SIGUSR2, &act, NULL); s->first_aio = NULL; - if (pipe(fds) == -1) { + if (qemu_pipe(fds) == -1) { fprintf(stderr, "failed to create pipe\n"); return -1; } diff --git a/qemu-char.c b/qemu-char.c index 40bd7e8..8b5a8bb 100644 --- a/qemu-char.c +++ b/qemu-char.c @@ -626,7 +626,7 @@ static CharDriverState *qemu_chr_open_file_out(QemuOpts *opts) { int fd_out; - TFR(fd_out = open(qemu_opt_get(opts, "path"), + TFR(fd_out = qemu_open(qemu_opt_get(opts, "path"), O_WRONLY | O_TRUNC | O_CREAT | O_BINARY, 0666)); if (fd_out < 0) return NULL; @@ -646,8 +646,8 @@ static CharDriverState *qemu_chr_open_pipe(QemuOpts *opts) snprintf(filename_in, 256, "%s.in", filename); snprintf(filename_out, 256, "%s.out", filename); - TFR(fd_in = open(filename_in, O_RDWR | O_BINARY)); - TFR(fd_out = open(filename_out, O_RDWR | O_BINARY)); + TFR(fd_in = qemu_open(filename_in, O_RDWR | O_BINARY)); + TFR(fd_out = qemu_open(filename_out, O_RDWR | O_BINARY)); if (fd_in < 0 || fd_out < 0) { if (fd_in >= 0) close(fd_in); @@ -2106,7 +2106,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..6975a29 100644 --- a/qemu-common.h +++ b/qemu-common.h @@ -159,6 +159,13 @@ void *get_mmap_addr(unsigned long size); void qemu_mutex_lock_iothread(void); void qemu_mutex_unlock_iothread(void); +int qemu_open(const char *name, int flags, ...); +void qemu_set_cloexec(int fd); + +#ifndef _WIN32 +int qemu_pipe(int pipefd[2]); +#endif + /* 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..94d82e0 100644 --- a/vl.c +++ b/vl.c @@ -1242,7 +1242,7 @@ static int hpet_start_timer(struct qemu_alarm_timer *t) struct hpet_info info; int r, fd; - fd = open("/dev/hpet", O_RDONLY); + fd = qemu_open("/dev/hpet", O_RDONLY); if (fd < 0) return -1; @@ -1291,7 +1291,7 @@ static int rtc_start_timer(struct qemu_alarm_timer *t) int rtc_fd; unsigned long current_rtc_freq = 0; - TFR(rtc_fd = open("/dev/rtc", O_RDONLY)); + TFR(rtc_fd = qemu_open("/dev/rtc", O_RDONLY)); if (rtc_fd < 0) return -1; ioctl(rtc_fd, RTC_IRQP_READ, ¤t_rtc_freq); @@ -3301,7 +3301,7 @@ static int qemu_event_init(void) int err; int fds[2]; - err = pipe(fds); + err = qemu_pipe(fds); if (err == -1) return -errno; @@ -5461,6 +5461,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(); @@ -5861,7 +5864,7 @@ int main(int argc, char **argv, char **envp) exit(1); chdir("/"); - TFR(fd = open("/dev/null", O_RDWR)); + TFR(fd = qemu_open("/dev/null", O_RDWR)); 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); }