summaryrefslogtreecommitdiffstats
path: root/sys/kern
diff options
context:
space:
mode:
authordillon <dillon@FreeBSD.org>2001-06-04 04:04:45 +0000
committerdillon <dillon@FreeBSD.org>2001-06-04 04:04:45 +0000
commit7f9e5322905b494d6f28f9afbc36e58c55ddd46a (patch)
treeb6c902473dc382e5e5ad2e1e718fc175a379a436 /sys/kern
parent9471850c148e388bf94d02bb661aa608919ed979 (diff)
downloadFreeBSD-src-7f9e5322905b494d6f28f9afbc36e58c55ddd46a.zip
FreeBSD-src-7f9e5322905b494d6f28f9afbc36e58c55ddd46a.tar.gz
The pipe_write() code was locking the pipe without busying it first in
certain cases, and a close() by another process could potentially rip the pipe out from under the (blocked) locking operation. Reported-by: Alexander Viro <viro@math.psu.edu>
Diffstat (limited to 'sys/kern')
-rw-r--r--sys/kern/sys_pipe.c25
1 files changed, 20 insertions, 5 deletions
diff --git a/sys/kern/sys_pipe.c b/sys/kern/sys_pipe.c
index c347a58..6c0e17e 100644
--- a/sys/kern/sys_pipe.c
+++ b/sys/kern/sys_pipe.c
@@ -777,6 +777,7 @@ pipe_write(fp, uio, cred, flags, p)
if ((wpipe == NULL) || (wpipe->pipe_state & PIPE_EOF)) {
return (EPIPE);
}
+ ++wpipe->pipe_busy;
/*
* If it is advantageous to resize the pipe buffer, do
@@ -792,15 +793,27 @@ pipe_write(fp, uio, cred, flags, p)
if (pipespace(wpipe, BIG_PIPE_SIZE) == 0)
nbigpipe++;
pipeunlock(wpipe);
- } else {
- return (error);
}
}
+
+ /*
+ * If an early error occured unbusy and return, waking up any pending
+ * readers.
+ */
+ if (error) {
+ --wpipe->pipe_busy;
+ if ((wpipe->pipe_busy == 0) &&
+ (wpipe->pipe_state & PIPE_WANT)) {
+ wpipe->pipe_state &= ~(PIPE_WANT | PIPE_WANTR);
+ wakeup(wpipe);
+ }
+ return(error);
+ }
KASSERT(wpipe->pipe_buffer.buffer != NULL, ("pipe buffer gone"));
- ++wpipe->pipe_busy;
orig_resid = uio->uio_resid;
+
while (uio->uio_resid) {
int space;
@@ -977,6 +990,7 @@ pipe_write(fp, uio, cred, flags, p)
}
--wpipe->pipe_busy;
+
if ((wpipe->pipe_busy == 0) && (wpipe->pipe_state & PIPE_WANT)) {
wpipe->pipe_state &= ~(PIPE_WANT | PIPE_WANTR);
wakeup(wpipe);
@@ -995,9 +1009,10 @@ pipe_write(fp, uio, cred, flags, p)
* Don't return EPIPE if I/O was successful
*/
if ((wpipe->pipe_buffer.cnt == 0) &&
- (uio->uio_resid == 0) &&
- (error == EPIPE))
+ (uio->uio_resid == 0) &&
+ (error == EPIPE)) {
error = 0;
+ }
if (error == 0)
vfs_timestamp(&wpipe->pipe_mtime);
OpenPOWER on IntegriCloud