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; /*