aboutsummaryrefslogtreecommitdiffstats
path: root/fs/nfsd/vfs.c
diff options
context:
space:
mode:
Diffstat (limited to 'fs/nfsd/vfs.c')
-rw-r--r--fs/nfsd/vfs.c27
1 files changed, 14 insertions, 13 deletions
diff --git a/fs/nfsd/vfs.c b/fs/nfsd/vfs.c
index 1d0406c31a44..a3a291f771f4 100644
--- a/fs/nfsd/vfs.c
+++ b/fs/nfsd/vfs.c
@@ -359,24 +359,25 @@ nfsd_setattr(struct svc_rqst *rqstp, struct svc_fh *fhp, struct iattr *iap,
359 DQUOT_INIT(inode); 359 DQUOT_INIT(inode);
360 } 360 }
361 361
362 /* sanitize the mode change */
362 if (iap->ia_valid & ATTR_MODE) { 363 if (iap->ia_valid & ATTR_MODE) {
363 iap->ia_mode &= S_IALLUGO; 364 iap->ia_mode &= S_IALLUGO;
364 iap->ia_mode |= (inode->i_mode & ~S_IALLUGO); 365 iap->ia_mode |= (inode->i_mode & ~S_IALLUGO);
365 /* if changing uid/gid revoke setuid/setgid in mode */ 366 }
366 if ((iap->ia_valid & ATTR_UID) && iap->ia_uid != inode->i_uid) { 367
367 iap->ia_valid |= ATTR_KILL_PRIV; 368 /* Revoke setuid/setgid on chown */
369 if (((iap->ia_valid & ATTR_UID) && iap->ia_uid != inode->i_uid) ||
370 ((iap->ia_valid & ATTR_GID) && iap->ia_gid != inode->i_gid)) {
371 iap->ia_valid |= ATTR_KILL_PRIV;
372 if (iap->ia_valid & ATTR_MODE) {
373 /* we're setting mode too, just clear the s*id bits */
368 iap->ia_mode &= ~S_ISUID; 374 iap->ia_mode &= ~S_ISUID;
375 if (iap->ia_mode & S_IXGRP)
376 iap->ia_mode &= ~S_ISGID;
377 } else {
378 /* set ATTR_KILL_* bits and let VFS handle it */
379 iap->ia_valid |= (ATTR_KILL_SUID | ATTR_KILL_SGID);
369 } 380 }
370 if ((iap->ia_valid & ATTR_GID) && iap->ia_gid != inode->i_gid)
371 iap->ia_mode &= ~S_ISGID;
372 } else {
373 /*
374 * Revoke setuid/setgid bit on chown/chgrp
375 */
376 if ((iap->ia_valid & ATTR_UID) && iap->ia_uid != inode->i_uid)
377 iap->ia_valid |= ATTR_KILL_SUID | ATTR_KILL_PRIV;
378 if ((iap->ia_valid & ATTR_GID) && iap->ia_gid != inode->i_gid)
379 iap->ia_valid |= ATTR_KILL_SGID;
380 } 381 }
381 382
382 /* Change the attributes. */ 383 /* Change the attributes. */