diff options
author | Kurt Miller <kurt@cvs.openbsd.org> | 2008-02-02 21:45:00 +0000 |
---|---|---|
committer | Kurt Miller <kurt@cvs.openbsd.org> | 2008-02-02 21:45:00 +0000 |
commit | 24acbd4bae386d4bb0412f75da88ca664af7eabf (patch) | |
tree | 576db3c71b6cb461dc605b76268dbb1454d3a321 | |
parent | faf40ddc62daa87bacf418ff2f1a3270facbb83b (diff) |
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@
-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); |