Sophie

Sophie

distrib > Scientific%20Linux > 5x > x86_64 > by-pkgid > fc11cd6e1c513a17304da94a5390f3cd > files > 3740

kernel-2.6.18-194.11.1.el5.src.rpm

From: Don Zickus <dzickus@redhat.com>
Subject: Re: [RHEL5] Fwd: Re: [PATCH] splice : Must fully check for fifos
Date: Fri, 15 Dec 2006 13:58:54 -0500
Bugzilla: 214289
Message-Id: <20061215185854.GJ9555@redhat.com>
Changelog: splice : Must fully check for fifos


On Fri, Nov 03, 2006 at 02:36:42PM -0500, Dave Jones wrote:
> As we merged the inode-diet patches in RHEL5, we'll need this (or equivalent)
> to circumvent a trival local DoS.
> 
> 	Dave
> 
Final version of the patch..

Cheers,
Don


commit ddac0d39cf437d02fde9795ae57d9c4b4c146de9
Author: Jens Axboe <jens.axboe@oracle.com>

    [PATCH] splice: fix problem introduced with inode diet
    
    After the inode slimming patch that unionised i_pipe/i_bdev/i_cdev, it's
    no longer enough to check for existance of ->i_pipe to verify that this
    is a pipe.
    
    Original patch from Eric Dumazet <dada1@cosmosbay.com>
    Final solution suggested by Linus.
    
    Signed-off-by: Jens Axboe <jens.axboe@oracle.com>
    Signed-off-by: Linus Torvalds <torvalds@osdl.org>

Index: latest/fs/splice.c
===================================================================
--- latest.orig/fs/splice.c
+++ latest/fs/splice.c
@@ -1042,6 +1042,19 @@ out_release:
 EXPORT_SYMBOL(do_splice_direct);
 
 /*
+ * After the inode slimming patch, i_pipe/i_bdev/i_cdev share the same
+ * location, so checking ->i_pipe is not enough to verify that this is a
+ * pipe.
+ */
+static inline struct pipe_inode_info *pipe_info(struct inode *inode)
+{
+	if (S_ISFIFO(inode->i_mode))
+		return inode->i_pipe;
+
+	return NULL;
+}
+
+/*
  * Determine where to splice to/from.
  */
 static long do_splice(struct file *in, loff_t __user *off_in,
@@ -1052,7 +1065,7 @@ static long do_splice(struct file *in, l
 	loff_t offset, *off;
 	long ret;
 
-	pipe = in->f_dentry->d_inode->i_pipe;
+	pipe = pipe_info(in->f_dentry->d_inode);
 	if (pipe) {
 		if (off_in)
 			return -ESPIPE;
@@ -1073,7 +1086,7 @@ static long do_splice(struct file *in, l
 		return ret;
 	}
 
-	pipe = out->f_dentry->d_inode->i_pipe;
+	pipe = pipe_info(out->f_dentry->d_inode);
 	if (pipe) {
 		if (off_out)
 			return -ESPIPE;
@@ -1231,7 +1244,7 @@ static int get_iovec_page_array(const st
 static long do_vmsplice(struct file *file, const struct iovec __user *iov,
 			unsigned long nr_segs, unsigned int flags)
 {
-	struct pipe_inode_info *pipe = file->f_dentry->d_inode->i_pipe;
+	struct pipe_inode_info *pipe;
 	struct page *pages[PIPE_BUFFERS];
 	struct partial_page partial[PIPE_BUFFERS];
 	struct splice_pipe_desc spd = {
@@ -1241,7 +1254,8 @@ static long do_vmsplice(struct file *fil
 		.ops = &user_page_pipe_buf_ops,
 	};
 
-	if (unlikely(!pipe))
+	pipe = pipe_info(file->f_dentry->d_inode);
+	if (!pipe)
 		return -EBADF;
 	if (unlikely(nr_segs > UIO_MAXIOV))
 		return -EINVAL;
@@ -1475,8 +1489,8 @@ static int link_pipe(struct pipe_inode_i
 static long do_tee(struct file *in, struct file *out, size_t len,
 		   unsigned int flags)
 {
-	struct pipe_inode_info *ipipe = in->f_dentry->d_inode->i_pipe;
-	struct pipe_inode_info *opipe = out->f_dentry->d_inode->i_pipe;
+	struct pipe_inode_info *ipipe = pipe_info(in->f_dentry->d_inode);
+	struct pipe_inode_info *opipe = pipe_info(out->f_dentry->d_inode);
 	int ret = -EINVAL;
 
 	/*