From: Eric Sandeen <sandeen@redhat.com> Date: Thu, 2 Oct 2008 14:46:52 -0500 Subject: [fs] remove SUID when splicing into an inode Message-id: 48E5252C.8010003@redhat.com O-Subject: [RHEL5.3 PATCH] Remove SUID when splicing into an inode Bugzilla: 464452 RH-Acked-by: Peter Staubach <staubach@redhat.com> RH-Acked-by: Alan Cox <alan@redhat.com> RH-Acked-by: Eugene Teo <eteo@redhat.com> This is for Bug 464452 - kernel: remove SUID when splicing into an inode [rhel-5.3] (I'm not sure how Eugene is handling this, it may be part of CVE CVE-2008-4210?) (Note also that this depends on Eugene's earlier patch, BZ#463687 kernel: open() call allows setgid bit when user is not in new file's group [v2], which provides should_remove_suid()) Without this change, one can use splice to create a binary which has the effective group id of the sgid directory it is created in: (see https://bugzilla.redhat.com/show_bug.cgi?id=464450#c3) [fsgqa@inode setgid_dir]$ ./splice_copy /bin/sh sh copied /bin/sh to sh via splice [fsgqa@inode setgid_dir]$ ls -l sh -rwxr-s--- 1 fsgqa root 801504 Oct 2 13:12 sh [fsgqa@inode setgid_dir]$ ./sh -p sh-3.2$ id uid=500(fsgqa) gid=500(fsgqa) egid=0(root) groups=500(fsgqa) This is a backport of: From: Jens Axboe <jens.axboe@oracle.com> Date: Tue, 17 Oct 2006 17:43:22 +0000 (+0200) Subject: [PATCH] Remove SUID when splicing into an inode X-Git-Tag: v2.6.19-rc3~32^2 X-Git-Url: http://git.kernel.org/?p=linux%2Fkernel%2Fgit%2Ftorvalds%2Flinux-2.6.git;a=commitdiff_plain;h=8c34e2d63231d4bf4852bac8521883944d770fe3 [PATCH] Remove SUID when splicing into an inode Originally from Mark Fasheh <mark.fasheh@oracle.com> generic_file_splice_write() does not remove S_ISUID or S_ISGID. This is inconsistent with the way we generally write to files. Signed-off-by: Mark Fasheh <mark.fasheh@oracle.com> Signed-off-by: Jens Axboe <jens.axboe@oracle.com> diff --git a/fs/splice.c b/fs/splice.c index cee12d8..32e0cc1 100644 --- a/fs/splice.c +++ b/fs/splice.c @@ -827,12 +827,21 @@ generic_file_splice_write(struct pipe_inode_info *pipe, struct file *out, loff_t *ppos, size_t len, unsigned int flags) { struct address_space *mapping = out->f_mapping; + struct inode *inode = mapping->host; ssize_t ret; + int err; + + err = should_remove_suid(out->f_dentry); + if (unlikely(err)) { + mutex_lock(&inode->i_mutex); + err = __remove_suid(out->f_dentry, err); + mutex_unlock(&inode->i_mutex); + if (err) + return err; + } ret = splice_from_pipe(pipe, out, ppos, len, flags, pipe_to_file); if (ret > 0) { - struct inode *inode = mapping->host; - *ppos += ret; /* @@ -840,8 +849,6 @@ generic_file_splice_write(struct pipe_inode_info *pipe, struct file *out, * sync it. */ if (unlikely((out->f_flags & O_SYNC) || IS_SYNC(inode))) { - int err; - mutex_lock(&inode->i_mutex); err = generic_osync_inode(inode, mapping, OSYNC_METADATA|OSYNC_DATA);