From f20000dd645ee779e4f56279805b561f08e705bf Mon Sep 17 00:00:00 2001 From: Jeff Layton Date: Thu, 18 Oct 2007 03:05:20 -0700 Subject: [PATCH] --- yaml --- r: 71140 b: refs/heads/master c: 6de0ec00ba8db84d7c452e65e502989455ecb6ea h: refs/heads/master v: v3 --- [refs] | 2 +- trunk/fs/attr.c | 26 ++++++++++++++++---------- 2 files changed, 17 insertions(+), 11 deletions(-) diff --git a/[refs] b/[refs] index daede70ad675..11f8d8775a22 100644 --- a/[refs] +++ b/[refs] @@ -1,2 +1,2 @@ --- -refs/heads/master: cdd6fe6e2f7eb8e940854317613885c33b1fe584 +refs/heads/master: 6de0ec00ba8db84d7c452e65e502989455ecb6ea diff --git a/trunk/fs/attr.c b/trunk/fs/attr.c index ae58bd3f875f..966b73e25f82 100644 --- a/trunk/fs/attr.c +++ b/trunk/fs/attr.c @@ -103,12 +103,11 @@ EXPORT_SYMBOL(inode_setattr); int notify_change(struct dentry * dentry, struct iattr * attr) { struct inode *inode = dentry->d_inode; - mode_t mode; + mode_t mode = inode->i_mode; int error; struct timespec now; unsigned int ia_valid = attr->ia_valid; - mode = inode->i_mode; now = current_fs_time(inode->i_sb); attr->ia_ctime = now; @@ -125,18 +124,25 @@ int notify_change(struct dentry * dentry, struct iattr * attr) if (error) return error; } + + /* + * We now pass ATTR_KILL_S*ID to the lower level setattr function so + * that the function has the ability to reinterpret a mode change + * that's due to these bits. This adds an implicit restriction that + * no function will ever call notify_change with both ATTR_MODE and + * ATTR_KILL_S*ID set. + */ + if ((ia_valid & (ATTR_KILL_SUID|ATTR_KILL_SGID)) && + (ia_valid & ATTR_MODE)) + BUG(); + if (ia_valid & ATTR_KILL_SUID) { - attr->ia_valid &= ~ATTR_KILL_SUID; if (mode & S_ISUID) { - if (!(ia_valid & ATTR_MODE)) { - ia_valid = attr->ia_valid |= ATTR_MODE; - attr->ia_mode = inode->i_mode; - } - attr->ia_mode &= ~S_ISUID; + ia_valid = attr->ia_valid |= ATTR_MODE; + attr->ia_mode = (inode->i_mode & ~S_ISUID); } } if (ia_valid & ATTR_KILL_SGID) { - attr->ia_valid &= ~ ATTR_KILL_SGID; if ((mode & (S_ISGID | S_IXGRP)) == (S_ISGID | S_IXGRP)) { if (!(ia_valid & ATTR_MODE)) { ia_valid = attr->ia_valid |= ATTR_MODE; @@ -145,7 +151,7 @@ int notify_change(struct dentry * dentry, struct iattr * attr) attr->ia_mode &= ~S_ISGID; } } - if (!attr->ia_valid) + if (!(attr->ia_valid & ~(ATTR_KILL_SUID | ATTR_KILL_SGID))) return 0; if (ia_valid & ATTR_SIZE)