diff options
author | 2008-02-02 21:44:59 +0000 | |
---|---|---|
committer | 2008-02-02 21:44:59 +0000 | |
commit | 94965f455dc299f1083d6d1ce76bdb18d432be1d (patch) | |
tree | df22af3daebcf5731e9841cbb8c0e546beac79f3 /lib/libpthread | |
parent | Basic CVSROOT/modules bits. (diff) | |
download | wireguard-openbsd-94965f455dc299f1083d6d1ce76bdb18d432be1d.tar.xz wireguard-openbsd-94965f455dc299f1083d6d1ce76bdb18d432be1d.zip |
Relocate internal pipe file descriptor if newfd collides with it. Fixes
bsd_auth(2) issue when compiled with threads. Reported by Joachim Wieland
<joachim.wieland at credativ.de>. okay otto@ marc@
Diffstat (limited to 'lib/libpthread')
-rw-r--r-- | lib/libpthread/uthread/uthread_dup2.c | 39 |
1 files changed, 32 insertions, 7 deletions
diff --git a/lib/libpthread/uthread/uthread_dup2.c b/lib/libpthread/uthread/uthread_dup2.c index 8bd4d5b4bba..f035a4609e2 100644 --- a/lib/libpthread/uthread/uthread_dup2.c +++ b/lib/libpthread/uthread/uthread_dup2.c @@ -1,4 +1,4 @@ -/* $OpenBSD: uthread_dup2.c,v 1.11 2007/04/27 12:59:24 kurt Exp $ */ +/* $OpenBSD: uthread_dup2.c,v 1.12 2008/02/02 21:44:59 kurt Exp $ */ /* PUBLIC DOMAIN <marc@snafu.org> */ #include <errno.h> @@ -10,11 +10,39 @@ int dup2(int fd, int newfd) { - int ret; + int ret = 0; int saved_errno; + int *kern_pipe_fd = NULL; - if (newfd >= 0 && newfd < _thread_max_fdtsize && - newfd != _thread_kern_pipe[0] && newfd != _thread_kern_pipe[1]) { + if (newfd < 0 || newfd >= _thread_max_fdtsize) { + errno = EBADF; + return(-1); + } + + /* + * Defer signals so another thread is not scheduled + * while we're checking and possibly moving the pipe fd. + */ + _thread_kern_sig_defer(); + + /* Check if newfd will collide with our internal pipe. */ + if (newfd == _thread_kern_pipe[0]) + kern_pipe_fd = &_thread_kern_pipe[0]; + else if (newfd == _thread_kern_pipe[1]) + kern_pipe_fd = &_thread_kern_pipe[1]; + + /* if we have a conflict move the internal pipe fd */ + if (kern_pipe_fd != NULL) { + ret = _thread_sys_dup(*kern_pipe_fd); + if (ret != -1) { + *kern_pipe_fd = ret; + ret = 0; + } + } + + _thread_kern_sig_undefer(); + + if (ret == 0) { ret = _FD_LOCK(fd, FD_RDWR, NULL); if (ret == 0) { if ((ret = _FD_LOCK(newfd, FD_RDWR_CLOSE, NULL)) == 0) { @@ -50,9 +78,6 @@ dup2(int fd, int newfd) } _FD_UNLOCK(fd, FD_RDWR); } - } else { - errno = EBADF; - ret = -1; } return (ret); |