--- a/configure.in +++ a/configure.in @@ -782,6 +782,9 @@ if test "$apr_cv_epoll" = "yes"; then AC_DEFINE([HAVE_EPOLL], 1, [Define if the epoll interface is supported]) fi +dnl ----------------------------- Checking for extended file descriptor handling +AC_CHECK_FUNCS(dup3 accept4 epoll_create1) + dnl ----------------------------- Checking for missing POSIX thread functions AC_CHECK_FUNCS([getpwnam_r getpwuid_r getgrnam_r getgrgid_r]) --- a/file_io/netware/mktemp.c +++ a/file_io/netware/mktemp.c @@ -43,9 +43,12 @@ APR_DECLARE(apr_status_t) apr_file_mktemp(apr_file_t **fp, char *template, apr_i if (!(flags & APR_FILE_NOCLEANUP)) { + int fdflags = fcntl(fd, F_GETFD); + fdflags |= FD_CLOEXEC; + fcntl(fd, F_SETFD, fdflags); apr_pool_cleanup_register((*fp)->pool, (void *)(*fp), apr_unix_file_cleanup, - apr_unix_child_file_cleanup); + apr_pool_cleanup_null); } } --- a/file_io/unix/filedup.c +++ a/file_io/unix/filedup.c @@ -24,14 +24,28 @@ static apr_status_t file_dup(apr_file_t **new_file, apr_file_t *old_file, apr_pool_t *p, int which_dup) { - int rv; + int rv, flags = 0; if (which_dup == 2) { if ((*new_file) == NULL) { /* We can't dup2 unless we have a valid new_file */ return APR_EINVAL; } +#ifdef HAVE_DUP3 + if (!(old_file->flags & APR_INHERIT)) + flags |= O_CLOEXEC; + rv = dup3(old_file->filedes, (*new_file)->filedes, flags); +#else rv = dup2(old_file->filedes, (*new_file)->filedes); + if (!(old_file->flags & APR_INHERIT)) { + flags = fcntl((*new_file)->filedes, F_GETFD); + if (flags == -1) + return errno; + flags |= FD_CLOEXEC; + if (fcntl((*new_file)->filedes, F_SETFD, flags) == -1) + return errno; + } +#endif } else { rv = dup(old_file->filedes); } @@ -78,9 +92,8 @@ static apr_status_t file_dup(apr_file_t **new_file, * already closed with apr_file_close, because the expected * cleanup was already killed. */ - if (which_dup == 2) { + if (which_dup == 2) return APR_SUCCESS; - } /* apr_file_dup() retains all old_file flags with the exceptions * of APR_INHERIT and APR_FILE_NOCLEANUP. @@ -92,7 +105,7 @@ static apr_status_t file_dup(apr_file_t **new_file, apr_pool_cleanup_register((*new_file)->pool, (void *)(*new_file), apr_unix_file_cleanup, - apr_unix_child_file_cleanup); + apr_pool_cleanup_null); #ifndef WAITIO_USES_POLL /* Start out with no pollset. apr_wait_for_io_or_timeout() will * initialize the pollset if needed. @@ -144,9 +157,7 @@ APR_DECLARE(apr_status_t) apr_file_setaside(apr_file_t **new_file, if (!(old_file->flags & APR_FILE_NOCLEANUP)) { apr_pool_cleanup_register(p, (void *)(*new_file), apr_unix_file_cleanup, - ((*new_file)->flags & APR_INHERIT) - ? apr_pool_cleanup_null - : apr_unix_child_file_cleanup); + apr_pool_cleanup_null); } old_file->filedes = -1; --- a/file_io/unix/mktemp.c +++ a/file_io/unix/mktemp.c @@ -203,9 +203,12 @@ APR_DECLARE(apr_status_t) apr_file_mktemp(apr_file_t **fp, char *template, apr_i (*fp)->fname = apr_pstrdup(p, template); if (!(flags & APR_FILE_NOCLEANUP)) { + int fdflags = fcntl(fd, F_GETFD); + fdflags |= FD_CLOEXEC; + fcntl(fd, F_SETFD, fdflags); apr_pool_cleanup_register((*fp)->pool, (void *)(*fp), apr_unix_file_cleanup, - apr_unix_child_file_cleanup); + apr_pool_cleanup_null); } #endif return APR_SUCCESS; --- a/file_io/unix/open.c +++ a/file_io/unix/open.c @@ -127,7 +127,15 @@ APR_DECLARE(apr_status_t) apr_file_open(apr_file_t **new, oflags |= O_BINARY; } #endif - + +#ifdef O_CLOEXEC + /* Introduced in Linux 2.6.23. Silently ignored on earlier Linux kernels. + */ + if (!(flag & APR_FILE_NOCLEANUP)) { + oflags |= O_CLOEXEC; +} +#endif + #if APR_HAS_LARGE_FILES && defined(_LARGEFILE64_SOURCE) oflags |= O_LARGEFILE; #elif defined(O_LARGEFILE) @@ -155,6 +163,11 @@ APR_DECLARE(apr_status_t) apr_file_open(apr_file_t **new, if (fd < 0) { return errno; } + if (!(flag & APR_FILE_NOCLEANUP)) { + int fdflags = fcntl(fd, F_GETFD); + fdflags |= FD_CLOEXEC; + fcntl(fd, F_SETFD, fdflags); + } (*new) = (apr_file_t *)apr_pcalloc(pool, sizeof(apr_file_t)); (*new)->pool = pool; @@ -196,7 +209,7 @@ APR_DECLARE(apr_status_t) apr_file_open(apr_file_t **new, if (!(flag & APR_FILE_NOCLEANUP)) { apr_pool_cleanup_register((*new)->pool, (void *)(*new), apr_unix_file_cleanup, - apr_unix_child_file_cleanup); + apr_pool_cleanup_null); } return APR_SUCCESS; } @@ -327,24 +340,7 @@ APR_DECLARE(apr_status_t) apr_file_open_stdin(apr_file_t **thefile, } APR_IMPLEMENT_INHERIT_SET(file, flags, pool, apr_unix_file_cleanup) - -/* We need to do this by hand instead of using APR_IMPLEMENT_INHERIT_UNSET - * because the macro sets both cleanups to the same function, which is not - * suitable on Unix (see PR 41119). */ -APR_DECLARE(apr_status_t) apr_file_inherit_unset(apr_file_t *thefile) -{ - if (thefile->flags & APR_FILE_NOCLEANUP) { - return APR_EINVAL; - } - if (thefile->flags & APR_INHERIT) { - thefile->flags &= ~APR_INHERIT; - apr_pool_child_cleanup_set(thefile->pool, - (void *)thefile, - apr_unix_file_cleanup, - apr_unix_child_file_cleanup); - } - return APR_SUCCESS; -} +APR_IMPLEMENT_INHERIT_UNSET(file, flags, pool, apr_unix_file_cleanup) APR_POOL_IMPLEMENT_ACCESSOR(file) --- a/include/arch/unix/apr_arch_inherit.h +++ a/include/arch/unix/apr_arch_inherit.h @@ -27,10 +27,13 @@ apr_status_t apr_##name##_inherit_set(apr_##name##_t *the##name) \ if (the##name->flag & APR_FILE_NOCLEANUP) \ return APR_EINVAL; \ if (!(the##name->flag & APR_INHERIT)) { \ + int flags = fcntl(the##name->name##des, F_GETFD); \ + if (flags == -1) \ + return errno; \ + flags &= ~(FD_CLOEXEC); \ + if (fcntl(the##name->name##des, F_SETFD, flags) == -1) \ + return errno; \ the##name->flag |= APR_INHERIT; \ - apr_pool_child_cleanup_set(the##name->pool, \ - (void *)the##name, \ - cleanup, apr_pool_cleanup_null); \ } \ return APR_SUCCESS; \ } @@ -41,10 +44,13 @@ apr_status_t apr_##name##_inherit_unset(apr_##name##_t *the##name) \ if (the##name->flag & APR_FILE_NOCLEANUP) \ return APR_EINVAL; \ if (the##name->flag & APR_INHERIT) { \ + int flags = fcntl(the##name->name##des, F_GETFD); \ + if (flags == -1) \ + return errno; \ + flags |= FD_CLOEXEC; \ + if (fcntl(the##name->name##des, F_SETFD, flags) == -1) \ + return errno; \ the##name->flag &= ~APR_INHERIT; \ - apr_pool_child_cleanup_set(the##name->pool, \ - (void *)the##name, \ - cleanup, cleanup); \ } \ return APR_SUCCESS; \ } --- a/network_io/unix/sockets.c +++ a/network_io/unix/sockets.c @@ -108,9 +108,13 @@ apr_status_t apr_socket_protocol_get(apr_socket_t *sock, int *protocol) apr_status_t apr_socket_create(apr_socket_t **new, int ofamily, int type, int protocol, apr_pool_t *cont) { - int family = ofamily; + int family = ofamily, flags = 0; int oprotocol = protocol; +#ifdef SOCK_CLOEXEC + flags |= SOCK_CLOEXEC; +#endif + if (family == APR_UNSPEC) { #if APR_HAVE_IPV6 family = APR_INET6; @@ -126,19 +130,19 @@ apr_status_t apr_socket_create(apr_socket_t **new, int ofamily, int type, alloc_socket(new, cont); #ifndef BEOS_R5 - (*new)->socketdes = socket(family, type, protocol); + (*new)->socketdes = socket(family, type|flags, protocol); #else /* For some reason BeOS R5 has an unconventional protocol numbering, * so we need to translate here. */ switch (protocol) { case 0: - (*new)->socketdes = socket(family, type, 0); + (*new)->socketdes = socket(family, type|flags, 0); break; case APR_PROTO_TCP: - (*new)->socketdes = socket(family, type, IPPROTO_TCP); + (*new)->socketdes = socket(family, type|flags, IPPROTO_TCP); break; case APR_PROTO_UDP: - (*new)->socketdes = socket(family, type, IPPROTO_UDP); + (*new)->socketdes = socket(family, type|flags, IPPROTO_UDP); break; case APR_PROTO_SCTP: default: @@ -151,7 +155,7 @@ apr_status_t apr_socket_create(apr_socket_t **new, int ofamily, int type, #if APR_HAVE_IPV6 if ((*new)->socketdes < 0 && ofamily == APR_UNSPEC) { family = APR_INET; - (*new)->socketdes = socket(family, type, protocol); + (*new)->socketdes = socket(family, type|flags, protocol); } #endif @@ -160,6 +164,13 @@ apr_status_t apr_socket_create(apr_socket_t **new, int ofamily, int type, } set_socket_vars(*new, family, type, oprotocol); + flags = fcntl((*new)->socketdes, F_GETFD); + if (flags == -1) + return errno; + flags |= FD_CLOEXEC; + if (fcntl((*new)->socketdes, F_SETFD, flags) == -1) + return errno; + (*new)->timeout = -1; (*new)->inherit = 0; apr_pool_cleanup_register((*new)->pool, (void *)(*new), socket_cleanup, @@ -213,12 +224,16 @@ apr_status_t apr_socket_listen(apr_socket_t *sock, apr_int32_t backlog) apr_status_t apr_socket_accept(apr_socket_t **new, apr_socket_t *sock, apr_pool_t *connection_context) { - int s; + int s, flags; apr_sockaddr_t sa; sa.salen = sizeof(sa.sa); +#ifdef HAVE_ACCEPT4 + s = accept4(sock->socketdes, (struct sockaddr *)&sa.sa, &sa.salen, SOCK_CLOEXEC); +#else s = accept(sock->socketdes, (struct sockaddr *)&sa.sa, &sa.salen); +#endif if (s < 0) { return errno; @@ -300,6 +315,15 @@ apr_status_t apr_socket_accept(apr_socket_t **new, apr_socket_t *sock, (*new)->local_interface_unknown = 1; } +#ifndef HAVE_ACCEPT4 + flags = fcntl((*new)->socketdes, F_GETFD); + if (flags == -1) + return errno; + flags |= FD_CLOEXEC; + if (fcntl((*new)->socketdes, F_SETFD, flags) == -1) + return errno; +#endif + (*new)->inherit = 0; apr_pool_cleanup_register((*new)->pool, (void *)(*new), socket_cleanup, socket_cleanup); --- a/poll/unix/epoll.c +++ a/poll/unix/epoll.c @@ -93,14 +93,24 @@ static apr_status_t impl_pollset_create(apr_pollset_t *pollset, apr_uint32_t flags) { apr_status_t rv; - int fd; + int fd, fdflags; +#ifdef HAVE_EPOLL_CREATE1 + fd = epoll_create1(EPOLL_CLOEXEC); +#else fd = epoll_create(size); +#endif if (fd < 0) { pollset->p = NULL; return apr_get_netos_error(); } +#ifndef HAVE_EPOLL_CREATE1 + fdflags = fcntl(fd, F_GETFD); + fdflags |= FD_CLOEXEC; + fcntl(fd, F_SETFD, fdflags); +#endif + pollset->p = apr_palloc(p, sizeof(apr_pollset_private_t)); #if APR_HAS_THREADS if ((flags & APR_POLLSET_THREADSAFE) && @@ -317,17 +327,27 @@ static apr_status_t impl_pollcb_create(apr_pollcb_t *pollcb, apr_pool_t *p, apr_uint32_t flags) { - int fd; + int fd, fdflags; +#ifdef HAVE_EPOLL_CREATE1 + fd = epoll_create1(EPOLL_CLOEXEC); +#else fd = epoll_create(size); +#endif if (fd < 0) { return apr_get_netos_error(); } + +#ifndef HAVE_EPOLL_CREATE1 + fdflags = fcntl(fd, F_GETFD); + fdflags |= FD_CLOEXEC; + fcntl(fd, F_SETFD, fdflags); +#endif pollcb->fd = fd; pollcb->pollset.epoll = apr_palloc(p, size * sizeof(struct epoll_event)); - apr_pool_cleanup_register(p, pollcb, cb_cleanup, cb_cleanup); + apr_pool_cleanup_register(p, pollcb, cb_cleanup, apr_pool_cleanup_null); return APR_SUCCESS; } --- a/poll/unix/kqueue.c +++ a/poll/unix/kqueue.c @@ -71,6 +71,7 @@ static apr_status_t impl_pollset_create(apr_pollset_t *pollset, apr_uint32_t flags) { apr_status_t rv = APR_SUCCESS; + int fdflags; pollset->p = apr_palloc(p, sizeof(apr_pollset_private_t)); #if APR_HAS_THREADS if (flags & APR_POLLSET_THREADSAFE && @@ -98,6 +99,10 @@ static apr_status_t impl_pollset_create(apr_pollset_t *pollset, return apr_get_netos_error(); } + fdflags = fcntl((*pollset)->kqueue_fd, F_GETFD); + fdflags |= FD_CLOEXEC; + fcntl((*pollset)->kqueue_fd, F_SETFD, fdflags); + pollset->p->result_set = apr_palloc(p, size * sizeof(apr_pollfd_t)); APR_RING_INIT(&pollset->p->query_ring, pfd_elem_t, link); @@ -306,16 +311,20 @@ static apr_status_t impl_pollcb_create(apr_pollcb_t *pollcb, apr_pool_t *p, apr_uint32_t flags) { - int fd; + int fd, fdflags; fd = kqueue(); if (fd < 0) { return apr_get_netos_error(); } + + fdflags = fcntl(fd, F_GETFD); + fdflags |= FD_CLOEXEC; + fcntl(fd, F_SETFD, fdflags); pollcb->fd = fd; pollcb->pollset.ke = (struct kevent *)apr_pcalloc(p, size * sizeof(struct kevent)); - apr_pool_cleanup_register(p, pollcb, cb_cleanup, cb_cleanup); + apr_pool_cleanup_register(p, pollcb, cb_cleanup, apr_pool_cleanup_null); return APR_SUCCESS; } --- a/poll/unix/pollset.c +++ a/poll/unix/pollset.c @@ -79,6 +79,7 @@ static apr_status_t create_wakeup_pipe(apr_pollset_t *pollset) { apr_status_t rv; apr_pollfd_t fd; + int fdflags; if ((rv = apr_file_pipe_create(&pollset->wakeup_pipe[0], &pollset->wakeup_pipe[1], @@ -87,6 +88,15 @@ static apr_status_t create_wakeup_pipe(apr_pollset_t *pollset) fd.reqevents = APR_POLLIN; fd.desc_type = APR_POLL_FILE; fd.desc.f = pollset->wakeup_pipe[0]; + + fdflags = fcntl(pollset->wakeup_pipe[0]->filedes, F_GETFD); + fdflags |= FD_CLOEXEC; + fcntl(pollset->wakeup_pipe[0]->filedes, F_SETFD, fdflags); + + fdflags = fcntl(pollset->wakeup_pipe[1]->filedes, F_GETFD); + fdflags |= FD_CLOEXEC; + fcntl(pollset->wakeup_pipe[1]->filedes, F_SETFD, fdflags); + /* Add the pipe to the pollset */ return apr_pollset_add(pollset, &fd); --- a/poll/unix/port.c +++ a/poll/unix/port.c @@ -100,6 +100,7 @@ static apr_status_t impl_pollset_create(apr_pollset_t **pollset, { apr_status_t rv = APR_SUCCESS; pollset->p = apr_palloc(p, sizeof(apr_pollset_private_t)); + int fdflags; #if APR_HAS_THREADS if (flags & APR_POLLSET_THREADSAFE && ((rv = apr_thread_mutex_create(&pollset->p->ring_lock, @@ -125,6 +126,10 @@ static apr_status_t impl_pollset_create(apr_pollset_t **pollset, return APR_ENOMEM; } + fdflags = fcntl(fd, F_GETFD); + fdflags |= FD_CLOEXEC; + fcntl(fd, F_SETFD, fdflags); + pollset->p->result_set = apr_palloc(p, size * sizeof(apr_pollfd_t)); APR_RING_INIT(&pollset->p->query_ring, pfd_elem_t, link); @@ -389,14 +394,19 @@ static apr_status_t impl_pollcb_create(apr_pollcb_t *pollcb, apr_pool_t *p, apr_uint32_t flags) { + int fdflags; pollcb->fd = port_create(); if (pollcb->fd < 0) { return apr_get_netos_error(); } + fdflags = fcntl(fd, F_GETFD); + fdflags |= FD_CLOEXEC; + fcntl(fd, F_SETFD, fdflags); + pollcb->pollset.port = apr_palloc(p, size * sizeof(port_event_t)); - apr_pool_cleanup_register(p, pollcb, cb_cleanup, cb_cleanup); + apr_pool_cleanup_register(p, pollcb, cb_cleanup, apr_cleanup_null); return APR_SUCCESS; }