Skip to content

Commit

Permalink
Merge remote-tracking branch 'jk/vfs' into work.misc
Browse files Browse the repository at this point in the history
  • Loading branch information
Al Viro committed Oct 8, 2016
2 parents f334bcd + 030b533 commit e55f1d1
Show file tree
Hide file tree
Showing 76 changed files with 296 additions and 225 deletions.
4 changes: 2 additions & 2 deletions Documentation/filesystems/porting
Original file line number Diff line number Diff line change
Expand Up @@ -287,8 +287,8 @@ implementing on-disk size changes. Start with a copy of the old inode_setattr
and vmtruncate, and the reorder the vmtruncate + foofs_vmtruncate sequence to
be in order of zeroing blocks using block_truncate_page or similar helpers,
size update and on finally on-disk truncation which should not fail.
inode_change_ok now includes the size checks for ATTR_SIZE and must be called
in the beginning of ->setattr unconditionally.
setattr_prepare (which used to be inode_change_ok) now includes the size checks
for ATTR_SIZE and must be called in the beginning of ->setattr unconditionally.

[mandatory]

Expand Down
2 changes: 1 addition & 1 deletion drivers/staging/lustre/lustre/llite/llite_lib.c
Original file line number Diff line number Diff line change
Expand Up @@ -1192,7 +1192,7 @@ int ll_setattr_raw(struct dentry *dentry, struct iattr *attr, bool hsm_import)
attr->ia_valid |= ATTR_MTIME | ATTR_CTIME;
}

/* POSIX: check before ATTR_*TIME_SET set (from inode_change_ok) */
/* POSIX: check before ATTR_*TIME_SET set (from setattr_prepare) */
if (attr->ia_valid & TIMES_SET_FLAGS) {
if ((!uid_eq(current_fsuid(), inode->i_uid)) &&
!capable(CFS_CAP_FOWNER))
Expand Down
40 changes: 17 additions & 23 deletions fs/9p/acl.c
Original file line number Diff line number Diff line change
Expand Up @@ -276,32 +276,26 @@ static int v9fs_xattr_set_acl(const struct xattr_handler *handler,
switch (handler->flags) {
case ACL_TYPE_ACCESS:
if (acl) {
umode_t mode = inode->i_mode;
retval = posix_acl_equiv_mode(acl, &mode);
if (retval < 0)
struct iattr iattr;

retval = posix_acl_update_mode(inode, &iattr.ia_mode, &acl);
if (retval)
goto err_out;
else {
struct iattr iattr;
if (retval == 0) {
/*
* ACL can be represented
* by the mode bits. So don't
* update ACL.
*/
acl = NULL;
value = NULL;
size = 0;
}
/* Updte the mode bits */
iattr.ia_mode = ((mode & S_IALLUGO) |
(inode->i_mode & ~S_IALLUGO));
iattr.ia_valid = ATTR_MODE;
/* FIXME should we update ctime ?
* What is the following setxattr update the
* mode ?
if (!acl) {
/*
* ACL can be represented
* by the mode bits. So don't
* update ACL.
*/
v9fs_vfs_setattr_dotl(dentry, &iattr);
value = NULL;
size = 0;
}
iattr.ia_valid = ATTR_MODE;
/* FIXME should we update ctime ?
* What is the following setxattr update the
* mode ?
*/
v9fs_vfs_setattr_dotl(dentry, &iattr);
}
break;
case ACL_TYPE_DEFAULT:
Expand Down
2 changes: 1 addition & 1 deletion fs/9p/vfs_inode.c
Original file line number Diff line number Diff line change
Expand Up @@ -1094,7 +1094,7 @@ static int v9fs_vfs_setattr(struct dentry *dentry, struct iattr *iattr)
struct p9_wstat wstat;

p9_debug(P9_DEBUG_VFS, "\n");
retval = inode_change_ok(d_inode(dentry), iattr);
retval = setattr_prepare(dentry, iattr);
if (retval)
return retval;

Expand Down
2 changes: 1 addition & 1 deletion fs/9p/vfs_inode_dotl.c
Original file line number Diff line number Diff line change
Expand Up @@ -558,7 +558,7 @@ int v9fs_vfs_setattr_dotl(struct dentry *dentry, struct iattr *iattr)

p9_debug(P9_DEBUG_VFS, "\n");

retval = inode_change_ok(inode, iattr);
retval = setattr_prepare(dentry, iattr);
if (retval)
return retval;

Expand Down
2 changes: 1 addition & 1 deletion fs/adfs/inode.c
Original file line number Diff line number Diff line change
Expand Up @@ -303,7 +303,7 @@ adfs_notify_change(struct dentry *dentry, struct iattr *attr)
unsigned int ia_valid = attr->ia_valid;
int error;

error = inode_change_ok(inode, attr);
error = setattr_prepare(dentry, attr);

/*
* we can't change the UID or GID of any file -
Expand Down
2 changes: 1 addition & 1 deletion fs/affs/inode.c
Original file line number Diff line number Diff line change
Expand Up @@ -219,7 +219,7 @@ affs_notify_change(struct dentry *dentry, struct iattr *attr)

pr_debug("notify_change(%lu,0x%x)\n", inode->i_ino, attr->ia_valid);

error = inode_change_ok(inode,attr);
error = setattr_prepare(dentry, attr);
if (error)
goto out;

Expand Down
35 changes: 23 additions & 12 deletions fs/attr.c
Original file line number Diff line number Diff line change
Expand Up @@ -17,19 +17,22 @@
#include <linux/ima.h>

/**
* inode_change_ok - check if attribute changes to an inode are allowed
* @inode: inode to check
* setattr_prepare - check if attribute changes to a dentry are allowed
* @dentry: dentry to check
* @attr: attributes to change
*
* Check if we are allowed to change the attributes contained in @attr
* in the given inode. This includes the normal unix access permission
* checks, as well as checks for rlimits and others.
* in the given dentry. This includes the normal unix access permission
* checks, as well as checks for rlimits and others. The function also clears
* SGID bit from mode if user is not allowed to set it. Also file capabilities
* and IMA extended attributes are cleared if ATTR_KILL_PRIV is set.
*
* Should be called as the first thing in ->setattr implementations,
* possibly after taking additional locks.
*/
int inode_change_ok(const struct inode *inode, struct iattr *attr)
int setattr_prepare(struct dentry *dentry, struct iattr *attr)
{
struct inode *inode = d_inode(dentry);
unsigned int ia_valid = attr->ia_valid;

/*
Expand All @@ -44,7 +47,7 @@ int inode_change_ok(const struct inode *inode, struct iattr *attr)

/* If force is set do it anyway. */
if (ia_valid & ATTR_FORCE)
return 0;
goto kill_priv;

/* Make sure a caller can chown. */
if ((ia_valid & ATTR_UID) &&
Expand Down Expand Up @@ -77,9 +80,19 @@ int inode_change_ok(const struct inode *inode, struct iattr *attr)
return -EPERM;
}

kill_priv:
/* User has permission for the change */
if (ia_valid & ATTR_KILL_PRIV) {
int error;

error = security_inode_killpriv(dentry);
if (error)
return error;
}

return 0;
}
EXPORT_SYMBOL(inode_change_ok);
EXPORT_SYMBOL(setattr_prepare);

/**
* inode_newsize_ok - may this inode be truncated to a given size
Expand Down Expand Up @@ -232,13 +245,11 @@ int notify_change(struct dentry * dentry, struct iattr * attr, struct inode **de
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)
if (error < 0)
return error;
if (error == 0)
ia_valid = attr->ia_valid &= ~ATTR_KILL_PRIV;
}

/*
Expand Down
6 changes: 2 additions & 4 deletions fs/btrfs/acl.c
Original file line number Diff line number Diff line change
Expand Up @@ -79,11 +79,9 @@ static int __btrfs_set_acl(struct btrfs_trans_handle *trans,
case ACL_TYPE_ACCESS:
name = XATTR_NAME_POSIX_ACL_ACCESS;
if (acl) {
ret = posix_acl_equiv_mode(acl, &inode->i_mode);
if (ret < 0)
ret = posix_acl_update_mode(inode, &inode->i_mode, &acl);
if (ret)
return ret;
if (ret == 0)
acl = NULL;
}
ret = 0;
break;
Expand Down
2 changes: 1 addition & 1 deletion fs/btrfs/inode.c
Original file line number Diff line number Diff line change
Expand Up @@ -5072,7 +5072,7 @@ static int btrfs_setattr(struct dentry *dentry, struct iattr *attr)
if (btrfs_root_readonly(root))
return -EROFS;

err = inode_change_ok(inode, attr);
err = setattr_prepare(dentry, attr);
if (err)
return err;

Expand Down
11 changes: 7 additions & 4 deletions fs/ceph/acl.c
Original file line number Diff line number Diff line change
Expand Up @@ -95,11 +95,9 @@ int ceph_set_acl(struct inode *inode, struct posix_acl *acl, int type)
case ACL_TYPE_ACCESS:
name = XATTR_NAME_POSIX_ACL_ACCESS;
if (acl) {
ret = posix_acl_equiv_mode(acl, &new_mode);
if (ret < 0)
ret = posix_acl_update_mode(inode, &new_mode, &acl);
if (ret)
goto out;
if (ret == 0)
acl = NULL;
}
break;
case ACL_TYPE_DEFAULT:
Expand Down Expand Up @@ -127,6 +125,11 @@ int ceph_set_acl(struct inode *inode, struct posix_acl *acl, int type)
goto out_free;
}

if (ceph_snap(inode) != CEPH_NOSNAP) {
ret = -EROFS;
goto out_free;
}

if (new_mode != old_mode) {
newattrs.ia_mode = new_mode;
newattrs.ia_valid = ATTR_MODE;
Expand Down
19 changes: 11 additions & 8 deletions fs/ceph/inode.c
Original file line number Diff line number Diff line change
Expand Up @@ -1905,13 +1905,6 @@ int __ceph_setattr(struct inode *inode, struct iattr *attr)
int inode_dirty_flags = 0;
bool lock_snap_rwsem = false;

if (ceph_snap(inode) != CEPH_NOSNAP)
return -EROFS;

err = inode_change_ok(inode, attr);
if (err != 0)
return err;

prealloc_cf = ceph_alloc_cap_flush();
if (!prealloc_cf)
return -ENOMEM;
Expand Down Expand Up @@ -2124,7 +2117,17 @@ int __ceph_setattr(struct inode *inode, struct iattr *attr)
*/
int ceph_setattr(struct dentry *dentry, struct iattr *attr)
{
return __ceph_setattr(d_inode(dentry), attr);
struct inode *inode = d_inode(dentry);
int err;

if (ceph_snap(inode) != CEPH_NOSNAP)
return -EROFS;

err = setattr_prepare(dentry, attr);
if (err != 0)
return err;

return __ceph_setattr(inode, attr);
}

/*
Expand Down
4 changes: 2 additions & 2 deletions fs/cifs/inode.c
Original file line number Diff line number Diff line change
Expand Up @@ -2154,7 +2154,7 @@ cifs_setattr_unix(struct dentry *direntry, struct iattr *attrs)
if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NO_PERM)
attrs->ia_valid |= ATTR_FORCE;

rc = inode_change_ok(inode, attrs);
rc = setattr_prepare(direntry, attrs);
if (rc < 0)
goto out;

Expand Down Expand Up @@ -2294,7 +2294,7 @@ cifs_setattr_nounix(struct dentry *direntry, struct iattr *attrs)
if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NO_PERM)
attrs->ia_valid |= ATTR_FORCE;

rc = inode_change_ok(inode, attrs);
rc = setattr_prepare(direntry, attrs);
if (rc < 0) {
free_xid(xid);
return rc;
Expand Down
2 changes: 1 addition & 1 deletion fs/ecryptfs/inode.c
Original file line number Diff line number Diff line change
Expand Up @@ -927,7 +927,7 @@ static int ecryptfs_setattr(struct dentry *dentry, struct iattr *ia)
}
mutex_unlock(&crypt_stat->cs_mutex);

rc = inode_change_ok(inode, ia);
rc = setattr_prepare(dentry, ia);
if (rc)
goto out;
if (ia->ia_valid & ATTR_SIZE) {
Expand Down
2 changes: 1 addition & 1 deletion fs/exofs/inode.c
Original file line number Diff line number Diff line change
Expand Up @@ -1034,7 +1034,7 @@ int exofs_setattr(struct dentry *dentry, struct iattr *iattr)
if (unlikely(error))
return error;

error = inode_change_ok(inode, iattr);
error = setattr_prepare(dentry, iattr);
if (unlikely(error))
return error;

Expand Down
12 changes: 4 additions & 8 deletions fs/ext2/acl.c
Original file line number Diff line number Diff line change
Expand Up @@ -190,15 +190,11 @@ ext2_set_acl(struct inode *inode, struct posix_acl *acl, int type)
case ACL_TYPE_ACCESS:
name_index = EXT2_XATTR_INDEX_POSIX_ACL_ACCESS;
if (acl) {
error = posix_acl_equiv_mode(acl, &inode->i_mode);
if (error < 0)
error = posix_acl_update_mode(inode, &inode->i_mode, &acl);
if (error)
return error;
else {
inode->i_ctime = CURRENT_TIME_SEC;
mark_inode_dirty(inode);
if (error == 0)
acl = NULL;
}
inode->i_ctime = CURRENT_TIME_SEC;
mark_inode_dirty(inode);
}
break;

Expand Down
5 changes: 5 additions & 0 deletions fs/ext2/ialloc.c
Original file line number Diff line number Diff line change
Expand Up @@ -465,6 +465,11 @@ struct inode *ext2_new_inode(struct inode *dir, umode_t mode,

for (i = 0; i < sbi->s_groups_count; i++) {
gdp = ext2_get_group_desc(sb, group, &bh2);
if (!gdp) {
if (++group == sbi->s_groups_count)
group = 0;
continue;
}
brelse(bitmap_bh);
bitmap_bh = read_inode_bitmap(sb, group);
if (!bitmap_bh) {
Expand Down
2 changes: 1 addition & 1 deletion fs/ext2/inode.c
Original file line number Diff line number Diff line change
Expand Up @@ -1580,7 +1580,7 @@ int ext2_setattr(struct dentry *dentry, struct iattr *iattr)
struct inode *inode = d_inode(dentry);
int error;

error = inode_change_ok(inode, iattr);
error = setattr_prepare(dentry, iattr);
if (error)
return error;

Expand Down
12 changes: 4 additions & 8 deletions fs/ext4/acl.c
Original file line number Diff line number Diff line change
Expand Up @@ -193,15 +193,11 @@ __ext4_set_acl(handle_t *handle, struct inode *inode, int type,
case ACL_TYPE_ACCESS:
name_index = EXT4_XATTR_INDEX_POSIX_ACL_ACCESS;
if (acl) {
error = posix_acl_equiv_mode(acl, &inode->i_mode);
if (error < 0)
error = posix_acl_update_mode(inode, &inode->i_mode, &acl);
if (error)
return error;
else {
inode->i_ctime = ext4_current_time(inode);
ext4_mark_inode_dirty(handle, inode);
if (error == 0)
acl = NULL;
}
inode->i_ctime = ext4_current_time(inode);
ext4_mark_inode_dirty(handle, inode);
}
break;

Expand Down
2 changes: 1 addition & 1 deletion fs/ext4/inode.c
Original file line number Diff line number Diff line change
Expand Up @@ -5073,7 +5073,7 @@ int ext4_setattr(struct dentry *dentry, struct iattr *attr)
int orphan = 0;
const unsigned int ia_valid = attr->ia_valid;

error = inode_change_ok(inode, attr);
error = setattr_prepare(dentry, attr);
if (error)
return error;

Expand Down
6 changes: 2 additions & 4 deletions fs/f2fs/acl.c
Original file line number Diff line number Diff line change
Expand Up @@ -210,12 +210,10 @@ static int __f2fs_set_acl(struct inode *inode, int type,
case ACL_TYPE_ACCESS:
name_index = F2FS_XATTR_INDEX_POSIX_ACL_ACCESS;
if (acl) {
error = posix_acl_equiv_mode(acl, &inode->i_mode);
if (error < 0)
error = posix_acl_update_mode(inode, &inode->i_mode, &acl);
if (error)
return error;
set_acl_inode(inode, inode->i_mode);
if (error == 0)
acl = NULL;
}
break;

Expand Down
2 changes: 1 addition & 1 deletion fs/f2fs/file.c
Original file line number Diff line number Diff line change
Expand Up @@ -680,7 +680,7 @@ int f2fs_setattr(struct dentry *dentry, struct iattr *attr)
struct inode *inode = d_inode(dentry);
int err;

err = inode_change_ok(inode, attr);
err = setattr_prepare(dentry, attr);
if (err)
return err;

Expand Down
Loading

0 comments on commit e55f1d1

Please sign in to comment.