[patch] 2.2.18pre23: user access checking in pipe_read/pipe_write

From: Tim Waugh (tim@cyberelk.demon.co.uk)
Date: Fri Nov 24 2000 - 16:04:00 EST


Here is an untested patch intended to fix the following behaviour:

$ cat a.c
#include <unistd.h>
int main (int argc, char **arghhh)
{
  int fd[2];
  pipe (fd);
  write (fd[1], NULL, 1);
}
$ gcc -o a a.c
$ strace -ewrite ./a
write(4, NULL, 1) = 1
$

Tim.
*/

--- linux-2.2.18pre23/fs/pipe.c.cfu Fri Nov 24 20:55:11 2000
+++ linux-2.2.18pre23/fs/pipe.c Fri Nov 24 21:00:11 2000
@@ -31,7 +31,7 @@
                          size_t count, loff_t *ppos)
 {
         struct inode * inode = filp->f_dentry->d_inode;
- ssize_t chars = 0, size = 0, read = 0;
+ ssize_t chars = 0, size = 0, read = 0, err = 0;
         char *pipebuf;
 
 
@@ -67,11 +67,14 @@
                         chars = size;
                 read += chars;
                 pipebuf = PIPE_BASE(*inode)+PIPE_START(*inode);
+ if (copy_to_user(buf, pipebuf, chars )) {
+ err = -EFAULT;
+ break;
+ }
                 PIPE_START(*inode) += chars;
                 PIPE_START(*inode) &= (PIPE_BUF-1);
                 PIPE_LEN(*inode) -= chars;
                 count -= chars;
- copy_to_user(buf, pipebuf, chars );
                 buf += chars;
         }
         PIPE_LOCK(*inode)--;
@@ -80,9 +83,9 @@
                 UPDATE_ATIME(inode);
                 return read;
         }
- if (PIPE_WRITERS(*inode))
+ if (!err && PIPE_WRITERS(*inode))
                 return -EAGAIN;
- return 0;
+ return err;
 }
         
 static ssize_t pipe_write(struct file * filp, const char * buf,
@@ -109,7 +112,7 @@
                 down(&inode->i_sem);
                 return -ERESTARTSYS;
         }
- while (count>0) {
+ while (count>0 && !err) {
                 while ((PIPE_FREE(*inode) < free) || PIPE_LOCK(*inode)) {
                         if (!PIPE_READERS(*inode)) { /* no readers */
                                 send_sig(SIGPIPE,current,0);
@@ -134,10 +137,13 @@
                         if (chars > free)
                                 chars = free;
                         pipebuf = PIPE_BASE(*inode)+PIPE_END(*inode);
+ if (copy_from_user(pipebuf, buf, chars )) {
+ err = -EFAULT;
+ break;
+ }
                         written += chars;
                         PIPE_LEN(*inode) += chars;
                         count -= chars;
- copy_from_user(pipebuf, buf, chars );
                         buf += chars;
                 }
                 PIPE_LOCK(*inode)--;
-
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@vger.kernel.org
Please read the FAQ at http://www.tux.org/lkml/



This archive was generated by hypermail 2b29 : Thu Nov 30 2000 - 21:00:12 EST