From 2da59394ec858ae5aecf2b26ab8d9fefdae17bb8 Mon Sep 17 00:00:00 2001 From: David Lamparter Date: Tue, 8 Nov 2016 20:46:05 +0100 Subject: [PATCH] lib: add and use set_cloexec() watchquagga is already leaking an open file descriptor on its pid file on fork+exec() invocations; next up is adding vtysh support with even more fds. Mark things CLOEXEC before going there. Signed-off-by: David Lamparter --- lib/network.c | 14 ++++++++++++++ lib/network.h | 2 ++ lib/pid_output.c | 3 +++ lib/vty.c | 8 +++++++- 4 files changed, 26 insertions(+), 1 deletion(-) diff --git a/lib/network.c b/lib/network.c index 5379ecb5a6..506e019136 100644 --- a/lib/network.c +++ b/lib/network.c @@ -94,6 +94,20 @@ set_nonblocking(int fd) return 0; } +int +set_cloexec(int fd) +{ + int flags; + flags = fcntl(fd, F_GETFD, 0); + if (flags == -1) + return -1; + + flags |= FD_CLOEXEC; + if (fcntl(fd, F_SETFD, flags) == -1) + return -1; + return 0; +} + float htonf (float host) { diff --git a/lib/network.h b/lib/network.h index 0fcb575d1c..a9126caf7f 100644 --- a/lib/network.h +++ b/lib/network.h @@ -33,6 +33,8 @@ extern int writen (int, const u_char *, int); -1 on error. */ extern int set_nonblocking(int fd); +extern int set_cloexec(int fd); + /* Does the I/O error indicate that the operation should be retried later? */ #define ERRNO_IO_RETRY(EN) \ (((EN) == EAGAIN) || ((EN) == EWOULDBLOCK) || ((EN) == EINTR)) diff --git a/lib/pid_output.c b/lib/pid_output.c index 5261babc6d..de4c2fba99 100644 --- a/lib/pid_output.c +++ b/lib/pid_output.c @@ -24,6 +24,7 @@ #include #include #include "version.h" +#include "network.h" #define PIDFILE_MASK 0644 #ifndef HAVE_FCNTL @@ -84,6 +85,8 @@ pid_output (const char *path) umask(oldumask); memset (&lock, 0, sizeof(lock)); + set_cloexec(fd); + lock.l_type = F_WRLCK; lock.l_whence = SEEK_SET; diff --git a/lib/vty.c b/lib/vty.c index 171aca1739..10ae99db07 100644 --- a/lib/vty.c +++ b/lib/vty.c @@ -1841,6 +1841,7 @@ vty_accept (struct thread *thread) return -1; } set_nonblocking(vty_sock); + set_cloexec(vty_sock); sockunion2hostprefix (&su, &p); @@ -1939,6 +1940,7 @@ vty_serv_sock_addrinfo (const char *hostname, unsigned short port) sockopt_v6only (ainfo->ai_family, sock); sockopt_reuseaddr (sock); sockopt_reuseport (sock); + set_cloexec (sock); ret = bind (sock, ainfo->ai_addr, ainfo->ai_addrlen); if (ret < 0) @@ -2006,6 +2008,7 @@ vty_serv_sock_family (const char* addr, unsigned short port, int family) /* This is server, so reuse address. */ sockopt_reuseaddr (accept_sock); sockopt_reuseport (accept_sock); + set_cloexec (accept_sock); /* Bind socket to universal address and given port. */ ret = sockunion_bind (accept_sock, &su, port, naddr); @@ -2068,6 +2071,8 @@ vty_serv_un (const char *path) len = sizeof (serv.sun_family) + strlen (serv.sun_path); #endif /* HAVE_STRUCT_SOCKADDR_UN_SUN_LEN */ + set_cloexec (sock); + ret = bind (sock, (struct sockaddr *) &serv, len); if (ret < 0) { @@ -2135,7 +2140,8 @@ vtysh_accept (struct thread *thread) close (sock); return -1; } - + set_cloexec(sock); + #ifdef VTYSH_DEBUG printf ("VTY shell accept\n"); #endif /* VTYSH_DEBUG */