X-Git-Url: http://git.samba.org/samba.git/?a=blobdiff_plain;f=fs%2Fattr.c;h=966b73e25f82e06f69ad0eca22a3f6fe268c4cd0;hb=2b752acd91ecee926483b5f64a8f8bfe06e081fb;hp=97de946708781df074388be1da5e4f811872766a;hpb=fb7ffeb11bb7e9e75dc83ff67a4925c270e0fa3c;p=sfrench%2Fcifs-2.6.git diff --git a/fs/attr.c b/fs/attr.c index 97de94670878..966b73e25f82 100644 --- a/fs/attr.c +++ b/fs/attr.c @@ -9,7 +9,6 @@ #include #include #include -#include #include #include #include @@ -43,7 +42,7 @@ int inode_change_ok(struct inode *inode, struct iattr *attr) /* Make sure a caller can chmod. */ if (ia_valid & ATTR_MODE) { - if ((current->fsuid != inode->i_uid) && !capable(CAP_FOWNER)) + if (!is_owner_or_cap(inode)) goto error; /* Also check the setgid bit! */ if (!in_group_p((ia_valid & ATTR_GID) ? attr->ia_gid : @@ -53,7 +52,7 @@ int inode_change_ok(struct inode *inode, struct iattr *attr) /* Check for setting the inode time. */ if (ia_valid & (ATTR_MTIME_SET | ATTR_ATIME_SET)) { - if (current->fsuid != inode->i_uid && !capable(CAP_FOWNER)) + if (!is_owner_or_cap(inode)) goto error; } fine: @@ -104,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; @@ -117,18 +115,34 @@ int notify_change(struct dentry * dentry, struct iattr * attr) attr->ia_atime = now; if (!(ia_valid & ATTR_MTIME_SET)) attr->ia_mtime = now; + if (ia_valid & ATTR_KILL_PRIV) { + attr->ia_valid &= ~ATTR_KILL_PRIV; + ia_valid &= ~ATTR_KILL_PRIV; + error = security_inode_need_killpriv(dentry); + if (error > 0) + error = security_inode_killpriv(dentry); + 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; @@ -137,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)