diff --git a/configure.in b/configure.in index ccb9d6d..5ff3aa1 100644 --- a/configure.in +++ b/configure.in @@ -768,20 +768,37 @@ AC_CACHE_CHECK([for epoll support], [apr_cv_epoll], int main() { return epoll_create(5) == -1; }], [apr_cv_epoll=yes], [apr_cv_epoll=no], [apr_cv_epoll=no])]) 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) + +AC_CACHE_CHECK([for SOCK_CLOEXEC support], [apr_cv_sock_cloexec], +[AC_TRY_RUN([ +#include +#include + +int main() +{ + return socket(AF_INET, SOCK_STREAM|SOCK_CLOEXEC, 0) == -1; +}], [apr_cv_sock_cloexec=yes], [apr_cv_sock_cloexec=no], [apr_cv_sock_cloexec=no])]) + +if test "$apr_cv_sock_cloexec" = "yes"; then + AC_DEFINE([HAVE_SOCK_CLOEXEC], 1, [Define if the SOCK_CLOEXEC flag is supported]) +fi + dnl ----------------------------- Checking for missing POSIX thread functions AC_CHECK_FUNCS([getpwnam_r getpwuid_r getgrnam_r getgrgid_r]) dnl ----------------------------- Checking for Shared Memory Support echo "${nl}Checking for Shared Memory Support..." # The real-time POSIX extensions (e.g. shm_*, sem_*) may only # be available if linking against librt. AC_SEARCH_LIBS(shm_open, rt) diff --git a/file_io/netware/mktemp.c b/file_io/netware/mktemp.c index 2a71af7..6dc68ca 100644 --- a/file_io/netware/mktemp.c +++ b/file_io/netware/mktemp.c @@ -12,20 +12,21 @@ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include "apr_private.h" #include "apr_file_io.h" /* prototype of apr_mkstemp() */ #include "apr_strings.h" /* prototype of apr_mkstemp() */ #include "apr_arch_file_io.h" /* prototype of apr_mkstemp() */ #include "apr_portable.h" /* for apr_os_file_put() */ +#include "apr_arch_inherit.h" #include /* for mkstemp() - Single Unix */ APR_DECLARE(apr_status_t) apr_file_mktemp(apr_file_t **fp, char *template, apr_int32_t flags, apr_pool_t *p) { int fd; apr_status_t rv; flags = (!flags) ? APR_CREATE | APR_READ | APR_WRITE | APR_DELONCLOSE : flags & ~APR_EXCL; @@ -36,19 +37,20 @@ APR_DECLARE(apr_status_t) apr_file_mktemp(apr_file_t **fp, char *template, apr_i } /* We need to reopen the file to get rid of the o_excl flag. * Otherwise file locking will not allow the file to be shared. */ close(fd); if ((rv = apr_file_open(fp, template, flags|APR_FILE_NOCLEANUP, APR_UREAD | APR_UWRITE, p)) == APR_SUCCESS) { if (!(flags & APR_FILE_NOCLEANUP)) { + APR_SET_FD_CLOEXEC((*fp)->filedes); apr_pool_cleanup_register((*fp)->pool, (void *)(*fp), apr_unix_file_cleanup, apr_unix_child_file_cleanup); } } return rv; } diff --git a/file_io/unix/filedup.c b/file_io/unix/filedup.c index adecbb7..9bb98e7 100644 --- a/file_io/unix/filedup.c +++ b/file_io/unix/filedup.c @@ -17,28 +17,39 @@ #include "apr_arch_file_io.h" #include "apr_strings.h" #include "apr_portable.h" #include "apr_thread_mutex.h" #include "apr_arch_inherit.h" 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)) { + if (rv == -1) + return errno; + APR_SET_FD_CLOEXEC((*new_file)->filedes); + } +#endif } else { rv = dup(old_file->filedes); } if (rv == -1) return errno; if (which_dup == 1) { (*new_file) = (apr_file_t *)apr_pcalloc(p, sizeof(apr_file_t)); (*new_file)->pool = p; diff --git a/file_io/unix/mktemp.c b/file_io/unix/mktemp.c index 22e0bd5..7bb5f8d 100644 --- a/file_io/unix/mktemp.c +++ b/file_io/unix/mktemp.c @@ -44,20 +44,21 @@ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #include "apr_private.h" #include "apr_file_io.h" /* prototype of apr_mkstemp() */ #include "apr_strings.h" /* prototype of apr_mkstemp() */ #include "apr_arch_file_io.h" /* prototype of apr_mkstemp() */ #include "apr_portable.h" /* for apr_os_file_put() */ +#include "apr_arch_inherit.h" #ifndef HAVE_MKSTEMP #if defined(SVR4) || defined(WIN32) || defined(NETWARE) #ifdef SVR4 #if HAVE_INTTYPES_H #include #endif #endif #define arc4random() rand() @@ -196,18 +197,19 @@ APR_DECLARE(apr_status_t) apr_file_mktemp(apr_file_t **fp, char *template, apr_i * mkstemp didn't subscribe to our preference flags. * * We either have to unset the flags, or fix up the fd and other * xthread and inherit bits appropriately. Since gettemp() above * calls apr_file_open, our flags are respected in that code path. */ apr_os_file_put(fp, &fd, flags, p); (*fp)->fname = apr_pstrdup(p, template); if (!(flags & APR_FILE_NOCLEANUP)) { + APR_SET_FD_CLOEXEC(fd); apr_pool_cleanup_register((*fp)->pool, (void *)(*fp), apr_unix_file_cleanup, apr_unix_child_file_cleanup); } #endif return APR_SUCCESS; } diff --git a/file_io/unix/open.c b/file_io/unix/open.c index a4dce36..84ebe3f 100644 --- a/file_io/unix/open.c +++ b/file_io/unix/open.c @@ -120,21 +120,29 @@ APR_DECLARE(apr_status_t) apr_file_open(apr_file_t **new, oflags |= O_APPEND; } if (flag & APR_TRUNCATE) { oflags |= O_TRUNC; } #ifdef O_BINARY if (flag & APR_BINARY) { 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) if (flag & APR_LARGEFILE) { oflags |= O_LARGEFILE; } #endif #if APR_HAS_THREADS if ((flag & APR_BUFFERED) && (flag & APR_XTHREAD)) { @@ -148,20 +156,23 @@ APR_DECLARE(apr_status_t) apr_file_open(apr_file_t **new, if (perm == APR_OS_DEFAULT) { fd = open(fname, oflags, 0666); } else { fd = open(fname, oflags, apr_unix_perms2mode(perm)); } if (fd < 0) { return errno; } + if (!(flag & APR_FILE_NOCLEANUP)) { + APR_SET_FD_CLOEXEC(fd); + } (*new) = (apr_file_t *)apr_pcalloc(pool, sizeof(apr_file_t)); (*new)->pool = pool; (*new)->flags = flag; (*new)->filedes = fd; (*new)->fname = apr_pstrdup(pool, fname); (*new)->blocking = BLK_ON; (*new)->buffered = (flag & APR_BUFFERED) > 0; @@ -330,20 +341,21 @@ 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) { + APR_SET_FD_CLOEXEC(thefile->filedes); 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_POOL_IMPLEMENT_ACCESSOR(file) diff --git a/include/arch/unix/apr_arch_inherit.h b/include/arch/unix/apr_arch_inherit.h index 9a6bdbc..f1a5cdd 100644 --- a/include/arch/unix/apr_arch_inherit.h +++ b/include/arch/unix/apr_arch_inherit.h @@ -20,33 +20,50 @@ #include "apr_inherit.h" #define APR_INHERIT (1 << 24) /* Must not conflict with other bits */ #define APR_IMPLEMENT_INHERIT_SET(name, flag, pool, cleanup) \ 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; \ } +#define APR_SET_FD_CLOEXEC(fd) \ +do { \ + int flags; \ + if ((flags = fcntl(fd, F_GETFD)) == -1) \ + return errno; \ + flags |= FD_CLOEXEC; \ + if (fcntl(fd, F_SETFD, flags) == -1) \ + return errno; \ +} while (0) + #define APR_IMPLEMENT_INHERIT_UNSET(name, flag, pool, cleanup) \ 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) { \ + APR_SET_FD_CLOEXEC(the##name->name##des); \ the##name->flag &= ~APR_INHERIT; \ apr_pool_child_cleanup_set(the##name->pool, \ (void *)the##name, \ cleanup, cleanup); \ } \ return APR_SUCCESS; \ } #endif /* ! INHERIT_H */ diff --git a/network_io/unix/sockets.c b/network_io/unix/sockets.c index bcf6cdd..a46b6a4 100644 --- a/network_io/unix/sockets.c +++ b/network_io/unix/sockets.c @@ -101,72 +101,80 @@ static void alloc_socket(apr_socket_t **new, apr_pool_t *p) apr_status_t apr_socket_protocol_get(apr_socket_t *sock, int *protocol) { *protocol = sock->protocol; return APR_SUCCESS; } 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 HAVE_SOCK_CLOEXEC + flags |= SOCK_CLOEXEC; +#endif + if (family == APR_UNSPEC) { #if APR_HAVE_IPV6 family = APR_INET6; #else family = APR_INET; #endif } #if APR_HAVE_SOCKADDR_UN if (family == APR_UNIX) { protocol = 0; } #endif 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: errno = EPROTONOSUPPORT; (*new)->socketdes = -1; break; } #endif /* BEOS_R5 */ #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 if ((*new)->socketdes < 0) { return errno; } set_socket_vars(*new, family, type, oprotocol); +#ifndef HAVE_SOCK_CLOEXEC + APR_SET_FD_CLOEXEC((*new)->socketdes); +#endif + (*new)->timeout = -1; (*new)->inherit = 0; apr_pool_cleanup_register((*new)->pool, (void *)(*new), socket_cleanup, socket_child_cleanup); return APR_SUCCESS; } apr_status_t apr_socket_shutdown(apr_socket_t *thesocket, apr_shutdown_how_e how) @@ -211,21 +219,25 @@ 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; 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; } #ifdef TPF if (s == 0) { /* 0 is an invalid socket for TPF */ return APR_EINTR; } #endif @@ -293,20 +305,24 @@ apr_status_t apr_socket_accept(apr_socket_t **new, apr_socket_t *sock, sock->local_addr->ipaddr_len)) { /* If the interface address inside the listening socket's local_addr wasn't * up-to-date, we don't know local interface of the connected socket either. * * If the listening socket was not bound to a specific interface, we * don't know the local_addr of the connected socket. */ (*new)->local_interface_unknown = 1; } +#ifndef HAVE_ACCEPT4 + APR_SET_FD_CLOEXEC((*new)->socketdes); +#endif + (*new)->inherit = 0; apr_pool_cleanup_register((*new)->pool, (void *)(*new), socket_cleanup, socket_cleanup); return APR_SUCCESS; } apr_status_t apr_socket_connect(apr_socket_t *sock, apr_sockaddr_t *sa) { int rc; diff --git a/poll/unix/epoll.c b/poll/unix/epoll.c index b695107..d483a37 100644 --- a/poll/unix/epoll.c +++ b/poll/unix/epoll.c @@ -14,20 +14,21 @@ * limitations under the License. */ #include "apr.h" #include "apr_poll.h" #include "apr_time.h" #include "apr_portable.h" #include "apr_arch_file_io.h" #include "apr_arch_networkio.h" #include "apr_arch_poll_private.h" +#include "apr_arch_inherit.h" #if defined(HAVE_EPOLL) static apr_int16_t get_epoll_event(apr_int16_t event) { apr_int16_t rv = 0; if (event & APR_POLLIN) rv |= EPOLLIN; if (event & APR_POLLPRI) @@ -88,26 +89,34 @@ static apr_status_t impl_pollset_cleanup(apr_pollset_t *pollset) static apr_status_t impl_pollset_create(apr_pollset_t *pollset, apr_uint32_t size, apr_pool_t *p, apr_uint32_t flags) { apr_status_t rv; int fd; +#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 + APR_SET_FD_CLOEXEC(fd); +#endif + pollset->p = apr_palloc(p, sizeof(apr_pollset_private_t)); #if APR_HAS_THREADS if ((flags & APR_POLLSET_THREADSAFE) && !(flags & APR_POLLSET_NOCOPY) && ((rv = apr_thread_mutex_create(&pollset->p->ring_lock, APR_THREAD_MUTEX_DEFAULT, p)) != APR_SUCCESS)) { pollset->p = NULL; return rv; } @@ -312,29 +321,37 @@ static apr_status_t cb_cleanup(void *p_) return APR_SUCCESS; } static apr_status_t impl_pollcb_create(apr_pollcb_t *pollcb, apr_uint32_t size, apr_pool_t *p, apr_uint32_t flags) { int fd; +#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 + APR_SET_FD_CLOEXEC(fd); +#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; } static apr_status_t impl_pollcb_add(apr_pollcb_t *pollcb, apr_pollfd_t *descriptor) { struct epoll_event ev; int ret; diff --git a/poll/unix/kqueue.c b/poll/unix/kqueue.c index d7b6780..13d20bb 100644 --- a/poll/unix/kqueue.c +++ b/poll/unix/kqueue.c @@ -14,20 +14,21 @@ * limitations under the License. */ #include "apr.h" #include "apr_poll.h" #include "apr_time.h" #include "apr_portable.h" #include "apr_arch_file_io.h" #include "apr_arch_networkio.h" #include "apr_arch_poll_private.h" +#include "apr_arch_inherit.h" #ifdef HAVE_KQUEUE static apr_int16_t get_kqueue_revent(apr_int16_t event, apr_int16_t flags) { apr_int16_t rv = 0; if (event == EVFILT_READ) rv |= APR_POLLIN; if (event == EVFILT_WRITE) @@ -91,20 +92,22 @@ static apr_status_t impl_pollset_create(apr_pollset_t *pollset, (struct kevent *) apr_palloc(p, size * sizeof(struct kevent)); memset(pollset->p->ke_set, 0, size * sizeof(struct kevent)); pollset->p->kqueue_fd = kqueue(); if (pollset->p->kqueue_fd == -1) { return apr_get_netos_error(); } + APR_SET_FD_CLOEXEC(pollset->p->kqueue_fd); + pollset->p->result_set = apr_palloc(p, size * sizeof(apr_pollfd_t)); APR_RING_INIT(&pollset->p->query_ring, pfd_elem_t, link); APR_RING_INIT(&pollset->p->free_ring, pfd_elem_t, link); APR_RING_INIT(&pollset->p->dead_ring, pfd_elem_t, link); return rv; } static apr_status_t impl_pollset_add(apr_pollset_t *pollset, @@ -305,24 +308,26 @@ static apr_status_t impl_pollcb_create(apr_pollcb_t *pollcb, apr_uint32_t size, apr_pool_t *p, apr_uint32_t flags) { int fd; fd = kqueue(); if (fd < 0) { return apr_get_netos_error(); } - + + APR_SET_FD_CLOEXEC(fd); + 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; } static apr_status_t impl_pollcb_add(apr_pollcb_t *pollcb, apr_pollfd_t *descriptor) { apr_os_sock_t fd; struct kevent ev; apr_status_t rv = APR_SUCCESS; diff --git a/poll/unix/pollset.c b/poll/unix/pollset.c index d3ad33b..07f788a 100644 --- a/poll/unix/pollset.c +++ b/poll/unix/pollset.c @@ -19,20 +19,21 @@ #define FD_SETSIZE 1024 #endif #include "apr.h" #include "apr_poll.h" #include "apr_time.h" #include "apr_portable.h" #include "apr_arch_file_io.h" #include "apr_arch_networkio.h" #include "apr_arch_poll_private.h" +#include "apr_arch_inherit.h" static apr_pollset_method_e pollset_default_method = POLLSET_DEFAULT_METHOD; #if !APR_FILES_AS_SOCKETS #if defined (WIN32) extern apr_status_t apr_file_socket_pipe_create(apr_file_t **in, apr_file_t **out, apr_pool_t *p); @@ -80,20 +81,24 @@ static apr_status_t create_wakeup_pipe(apr_pollset_t *pollset) apr_status_t rv; apr_pollfd_t fd; if ((rv = apr_file_pipe_create(&pollset->wakeup_pipe[0], &pollset->wakeup_pipe[1], pollset->pool)) != APR_SUCCESS) return rv; fd.reqevents = APR_POLLIN; fd.desc_type = APR_POLL_FILE; fd.desc.f = pollset->wakeup_pipe[0]; + + APR_SET_FD_CLOEXEC(pollset->wakeup_pipe[0]->filedes); + APR_SET_FD_CLOEXEC(pollset->wakeup_pipe[1]->filedes); + /* Add the pipe to the pollset */ return apr_pollset_add(pollset, &fd); } #endif /* !APR_FILES_AS_SOCKETS */ /* Read and discard what's ever in the wakeup pipe. */ void apr_pollset_drain_wakeup_pipe(apr_pollset_t *pollset) { diff --git a/poll/unix/port.c b/poll/unix/port.c index 7ff0fb6..7171a00 100644 --- a/poll/unix/port.c +++ b/poll/unix/port.c @@ -15,20 +15,21 @@ */ #include "apr.h" #include "apr_poll.h" #include "apr_time.h" #include "apr_portable.h" #include "apr_atomic.h" #include "apr_arch_file_io.h" #include "apr_arch_networkio.h" #include "apr_arch_poll_private.h" +#include "apr_arch_inherit.h" #if defined(HAVE_PORT_CREATE) static apr_int16_t get_event(apr_int16_t event) { apr_int16_t rv = 0; if (event & APR_POLLIN) rv |= POLLIN; if (event & APR_POLLPRI) @@ -118,20 +119,22 @@ static apr_status_t impl_pollset_create(apr_pollset_t *pollset, pollset->p->port_set = apr_palloc(p, size * sizeof(port_event_t)); pollset->p->port_fd = port_create(); if (pollset->p->port_fd < 0) { pollset->p = NULL; return APR_ENOMEM; } + APR_SET_FD_CLOEXEC(pollset->p->port_fd); + pollset->p->result_set = apr_palloc(p, size * sizeof(apr_pollfd_t)); APR_RING_INIT(&pollset->p->query_ring, pfd_elem_t, link); APR_RING_INIT(&pollset->p->add_ring, pfd_elem_t, link); APR_RING_INIT(&pollset->p->free_ring, pfd_elem_t, link); APR_RING_INIT(&pollset->p->dead_ring, pfd_elem_t, link); return rv; } @@ -388,22 +391,24 @@ static apr_status_t impl_pollcb_create(apr_pollcb_t *pollcb, apr_uint32_t size, apr_pool_t *p, apr_uint32_t flags) { pollcb->fd = port_create(); if (pollcb->fd < 0) { return apr_get_netos_error(); } + APR_SET_FD_CLOEXEC(fd); + 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_pool_cleanup_null); return APR_SUCCESS; } static apr_status_t impl_pollcb_add(apr_pollcb_t *pollcb, apr_pollfd_t *descriptor) { int ret, fd; if (descriptor->desc_type == APR_POLL_SOCKET) {