Commit 588d6141 authored by Andrew Morton's avatar Andrew Morton Committed by Linus Torvalds

[PATCH] remove_suid() fix

From: viro@parcelfarce.linux.theplanet.co.uk

bernhard_heibler@gmx.de has discovered that NFS is very slow when writing to
a file which has execute permissions.  See

	http://bugme.osdl.org/show_bug.cgi?id=1936

This patch fixes remove_suid() to not try to modify the inode mode on every
write to such a file.
parent fea7cfba
...@@ -1495,22 +1495,35 @@ __grab_cache_page(struct address_space *mapping, unsigned long index, ...@@ -1495,22 +1495,35 @@ __grab_cache_page(struct address_space *mapping, unsigned long index,
return page; return page;
} }
/*
* The logic we want is
*
* if suid or (sgid and xgrp)
* remove privs
*/
void remove_suid(struct dentry *dentry) void remove_suid(struct dentry *dentry)
{ {
struct iattr newattrs; mode_t mode = dentry->d_inode->i_mode;
struct inode *inode = dentry->d_inode; int kill = 0;
unsigned int mode = inode->i_mode & (S_ISUID|S_ISGID|S_IXGRP);
/* suid always must be killed */
if (unlikely(mode & S_ISUID))
kill = ATTR_KILL_SUID;
if (!(mode & S_IXGRP)) /*
mode &= S_ISUID; * sgid without any exec bits is just a mandatory locking mark; leave
* it alone. If some exec bits are set, it's a real sgid; kill it.
*/
if (unlikely((mode & S_ISGID) && (mode & S_IXGRP)))
kill |= ATTR_KILL_SGID;
/* were any of the uid bits set? */ if (unlikely(kill && !capable(CAP_FSETID))) {
if (mode && !capable(CAP_FSETID)) { struct iattr newattrs;
newattrs.ia_valid = ATTR_KILL_SUID|ATTR_KILL_SGID|ATTR_FORCE;
newattrs.ia_valid = ATTR_FORCE | kill;
notify_change(dentry, &newattrs); notify_change(dentry, &newattrs);
} }
} }
EXPORT_SYMBOL(remove_suid); EXPORT_SYMBOL(remove_suid);
/* /*
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment