From: Jeff Layton Date: Thu, 18 Oct 2007 10:05:19 +0000 (-0700) Subject: knfsd: only set ATTR_KILL_S*ID if ATTR_MODE isn't being explicitly set X-Git-Tag: v2.6.24-rc1~402 X-Git-Url: https://err.no/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=8a0ce7d99a4d19788e017f3138bc59b9962057ae;p=linux-2.6 knfsd: only set ATTR_KILL_S*ID if ATTR_MODE isn't being explicitly set It's theoretically possible for a single SETATTR call to come in that sets the mode and the uid/gid. In that case, don't set the ATTR_KILL_S*ID bits since that would trip the BUG() in notify_change. Just fix up the mode to have the same effect. Signed-off-by: Jeff Layton Cc: Neil Brown Cc: "J. Bruce Fields" Cc: Christoph Hellwig Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- diff --git a/fs/nfsd/vfs.c b/fs/nfsd/vfs.c index 819545d216..46934c97f8 100644 --- a/fs/nfsd/vfs.c +++ b/fs/nfsd/vfs.c @@ -364,14 +364,23 @@ nfsd_setattr(struct svc_rqst *rqstp, struct svc_fh *fhp, struct iattr *iap, if (iap->ia_valid & ATTR_MODE) { iap->ia_mode &= S_IALLUGO; imode = iap->ia_mode |= (imode & ~S_IALLUGO); + /* if changing uid/gid revoke setuid/setgid in mode */ + if ((iap->ia_valid & ATTR_UID) && iap->ia_uid != inode->i_uid) { + iap->ia_valid |= ATTR_KILL_PRIV; + iap->ia_mode &= ~S_ISUID; + } + if ((iap->ia_valid & ATTR_GID) && iap->ia_gid != inode->i_gid) + iap->ia_mode &= ~S_ISGID; + } else { + /* + * Revoke setuid/setgid bit on chown/chgrp + */ + if ((iap->ia_valid & ATTR_UID) && iap->ia_uid != inode->i_uid) + iap->ia_valid |= ATTR_KILL_SUID | ATTR_KILL_PRIV; + if ((iap->ia_valid & ATTR_GID) && iap->ia_gid != inode->i_gid) + iap->ia_valid |= ATTR_KILL_SGID; } - /* Revoke setuid/setgid bit on chown/chgrp */ - if ((iap->ia_valid & ATTR_UID) && iap->ia_uid != inode->i_uid) - iap->ia_valid |= ATTR_KILL_SUID | ATTR_KILL_PRIV; - if ((iap->ia_valid & ATTR_GID) && iap->ia_gid != inode->i_gid) - iap->ia_valid |= ATTR_KILL_SGID; - /* Change the attributes. */ iap->ia_valid |= ATTR_CTIME;