ANDROID: vfs: Add setattr2 for filesystems with per mount permissions
This allows filesystems to use their mount private data to influence the permssions they use in setattr2. It has been separated into a new call to avoid disrupting current setattr users. Change-Id: I19959038309284448f1b7f232d579674ef546385 Signed-off-by: Daniel Rosenberg <drosen@google.com>
This commit is contained in:
committed by
Dmitry Shmidt
parent
29f888e730
commit
2757e9bdf4
@@ -200,7 +200,7 @@ EXPORT_SYMBOL(setattr_copy);
|
|||||||
* the file open for write, as there can be no conflicting delegation in
|
* the file open for write, as there can be no conflicting delegation in
|
||||||
* that case.
|
* that case.
|
||||||
*/
|
*/
|
||||||
int notify_change(struct dentry * dentry, struct iattr * attr, struct inode **delegated_inode)
|
int notify_change2(struct vfsmount *mnt, struct dentry * dentry, struct iattr * attr, struct inode **delegated_inode)
|
||||||
{
|
{
|
||||||
struct inode *inode = dentry->d_inode;
|
struct inode *inode = dentry->d_inode;
|
||||||
umode_t mode = inode->i_mode;
|
umode_t mode = inode->i_mode;
|
||||||
@@ -307,7 +307,9 @@ int notify_change(struct dentry * dentry, struct iattr * attr, struct inode **de
|
|||||||
if (error)
|
if (error)
|
||||||
return error;
|
return error;
|
||||||
|
|
||||||
if (inode->i_op->setattr)
|
if (mnt && inode->i_op->setattr2)
|
||||||
|
error = inode->i_op->setattr2(mnt, dentry, attr);
|
||||||
|
else if (inode->i_op->setattr)
|
||||||
error = inode->i_op->setattr(dentry, attr);
|
error = inode->i_op->setattr(dentry, attr);
|
||||||
else
|
else
|
||||||
error = simple_setattr(dentry, attr);
|
error = simple_setattr(dentry, attr);
|
||||||
@@ -320,4 +322,10 @@ int notify_change(struct dentry * dentry, struct iattr * attr, struct inode **de
|
|||||||
|
|
||||||
return error;
|
return error;
|
||||||
}
|
}
|
||||||
|
EXPORT_SYMBOL(notify_change2);
|
||||||
|
|
||||||
|
int notify_change(struct dentry * dentry, struct iattr * attr, struct inode **delegated_inode)
|
||||||
|
{
|
||||||
|
return notify_change2(NULL, dentry, attr, delegated_inode);
|
||||||
|
}
|
||||||
EXPORT_SYMBOL(notify_change);
|
EXPORT_SYMBOL(notify_change);
|
||||||
|
|||||||
+1
-1
@@ -744,7 +744,7 @@ void do_coredump(const siginfo_t *siginfo)
|
|||||||
goto close_fail;
|
goto close_fail;
|
||||||
if (!(cprm.file->f_mode & FMODE_CAN_WRITE))
|
if (!(cprm.file->f_mode & FMODE_CAN_WRITE))
|
||||||
goto close_fail;
|
goto close_fail;
|
||||||
if (do_truncate(cprm.file->f_path.dentry, 0, 0, cprm.file))
|
if (do_truncate2(cprm.file->f_path.mnt, cprm.file->f_path.dentry, 0, 0, cprm.file))
|
||||||
goto close_fail;
|
goto close_fail;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+3
-3
@@ -1780,7 +1780,7 @@ int dentry_needs_remove_privs(struct dentry *dentry)
|
|||||||
return mask;
|
return mask;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int __remove_privs(struct dentry *dentry, int kill)
|
static int __remove_privs(struct vfsmount *mnt, struct dentry *dentry, int kill)
|
||||||
{
|
{
|
||||||
struct iattr newattrs;
|
struct iattr newattrs;
|
||||||
|
|
||||||
@@ -1789,7 +1789,7 @@ static int __remove_privs(struct dentry *dentry, int kill)
|
|||||||
* Note we call this on write, so notify_change will not
|
* Note we call this on write, so notify_change will not
|
||||||
* encounter any conflicting delegations:
|
* encounter any conflicting delegations:
|
||||||
*/
|
*/
|
||||||
return notify_change(dentry, &newattrs, NULL);
|
return notify_change2(mnt, dentry, &newattrs, NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -1811,7 +1811,7 @@ int file_remove_privs(struct file *file)
|
|||||||
if (kill < 0)
|
if (kill < 0)
|
||||||
return kill;
|
return kill;
|
||||||
if (kill)
|
if (kill)
|
||||||
error = __remove_privs(dentry, kill);
|
error = __remove_privs(file->f_path.mnt, dentry, kill);
|
||||||
if (!error)
|
if (!error)
|
||||||
inode_has_no_xattr(inode);
|
inode_has_no_xattr(inode);
|
||||||
|
|
||||||
|
|||||||
+1
-1
@@ -2957,7 +2957,7 @@ static int handle_truncate(struct file *filp)
|
|||||||
if (!error)
|
if (!error)
|
||||||
error = security_path_truncate(path);
|
error = security_path_truncate(path);
|
||||||
if (!error) {
|
if (!error) {
|
||||||
error = do_truncate(path->dentry, 0,
|
error = do_truncate2(path->mnt, path->dentry, 0,
|
||||||
ATTR_MTIME|ATTR_CTIME|ATTR_OPEN,
|
ATTR_MTIME|ATTR_CTIME|ATTR_OPEN,
|
||||||
filp);
|
filp);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -34,8 +34,8 @@
|
|||||||
|
|
||||||
#include "internal.h"
|
#include "internal.h"
|
||||||
|
|
||||||
int do_truncate(struct dentry *dentry, loff_t length, unsigned int time_attrs,
|
int do_truncate2(struct vfsmount *mnt, struct dentry *dentry, loff_t length,
|
||||||
struct file *filp)
|
unsigned int time_attrs, struct file *filp)
|
||||||
{
|
{
|
||||||
int ret;
|
int ret;
|
||||||
struct iattr newattrs;
|
struct iattr newattrs;
|
||||||
@@ -60,10 +60,15 @@ int do_truncate(struct dentry *dentry, loff_t length, unsigned int time_attrs,
|
|||||||
|
|
||||||
inode_lock(dentry->d_inode);
|
inode_lock(dentry->d_inode);
|
||||||
/* Note any delegations or leases have already been broken: */
|
/* Note any delegations or leases have already been broken: */
|
||||||
ret = notify_change(dentry, &newattrs, NULL);
|
ret = notify_change2(mnt, dentry, &newattrs, NULL);
|
||||||
inode_unlock(dentry->d_inode);
|
inode_unlock(dentry->d_inode);
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
int do_truncate(struct dentry *dentry, loff_t length, unsigned int time_attrs,
|
||||||
|
struct file *filp)
|
||||||
|
{
|
||||||
|
return do_truncate2(NULL, dentry, length, time_attrs, filp);
|
||||||
|
}
|
||||||
|
|
||||||
long vfs_truncate(const struct path *path, loff_t length)
|
long vfs_truncate(const struct path *path, loff_t length)
|
||||||
{
|
{
|
||||||
@@ -117,7 +122,7 @@ long vfs_truncate(const struct path *path, loff_t length)
|
|||||||
if (!error)
|
if (!error)
|
||||||
error = security_path_truncate(path);
|
error = security_path_truncate(path);
|
||||||
if (!error)
|
if (!error)
|
||||||
error = do_truncate(path->dentry, length, 0, NULL);
|
error = do_truncate2(mnt, path->dentry, length, 0, NULL);
|
||||||
|
|
||||||
put_write_and_out:
|
put_write_and_out:
|
||||||
put_write_access(upperdentry->d_inode);
|
put_write_access(upperdentry->d_inode);
|
||||||
@@ -166,6 +171,7 @@ static long do_sys_ftruncate(unsigned int fd, loff_t length, int small)
|
|||||||
{
|
{
|
||||||
struct inode *inode;
|
struct inode *inode;
|
||||||
struct dentry *dentry;
|
struct dentry *dentry;
|
||||||
|
struct vfsmount *mnt;
|
||||||
struct fd f;
|
struct fd f;
|
||||||
int error;
|
int error;
|
||||||
|
|
||||||
@@ -182,6 +188,7 @@ static long do_sys_ftruncate(unsigned int fd, loff_t length, int small)
|
|||||||
small = 0;
|
small = 0;
|
||||||
|
|
||||||
dentry = f.file->f_path.dentry;
|
dentry = f.file->f_path.dentry;
|
||||||
|
mnt = f.file->f_path.mnt;
|
||||||
inode = dentry->d_inode;
|
inode = dentry->d_inode;
|
||||||
error = -EINVAL;
|
error = -EINVAL;
|
||||||
if (!S_ISREG(inode->i_mode) || !(f.file->f_mode & FMODE_WRITE))
|
if (!S_ISREG(inode->i_mode) || !(f.file->f_mode & FMODE_WRITE))
|
||||||
@@ -201,7 +208,7 @@ static long do_sys_ftruncate(unsigned int fd, loff_t length, int small)
|
|||||||
if (!error)
|
if (!error)
|
||||||
error = security_path_truncate(&f.file->f_path);
|
error = security_path_truncate(&f.file->f_path);
|
||||||
if (!error)
|
if (!error)
|
||||||
error = do_truncate(dentry, length, ATTR_MTIME|ATTR_CTIME, f.file);
|
error = do_truncate2(mnt, dentry, length, ATTR_MTIME|ATTR_CTIME, f.file);
|
||||||
sb_end_write(inode->i_sb);
|
sb_end_write(inode->i_sb);
|
||||||
out_putf:
|
out_putf:
|
||||||
fdput(f);
|
fdput(f);
|
||||||
@@ -533,7 +540,7 @@ retry_deleg:
|
|||||||
goto out_unlock;
|
goto out_unlock;
|
||||||
newattrs.ia_mode = (mode & S_IALLUGO) | (inode->i_mode & ~S_IALLUGO);
|
newattrs.ia_mode = (mode & S_IALLUGO) | (inode->i_mode & ~S_IALLUGO);
|
||||||
newattrs.ia_valid = ATTR_MODE | ATTR_CTIME;
|
newattrs.ia_valid = ATTR_MODE | ATTR_CTIME;
|
||||||
error = notify_change(path->dentry, &newattrs, &delegated_inode);
|
error = notify_change2(path->mnt, path->dentry, &newattrs, &delegated_inode);
|
||||||
out_unlock:
|
out_unlock:
|
||||||
inode_unlock(inode);
|
inode_unlock(inode);
|
||||||
if (delegated_inode) {
|
if (delegated_inode) {
|
||||||
@@ -613,7 +620,7 @@ retry_deleg:
|
|||||||
inode_lock(inode);
|
inode_lock(inode);
|
||||||
error = security_path_chown(path, uid, gid);
|
error = security_path_chown(path, uid, gid);
|
||||||
if (!error)
|
if (!error)
|
||||||
error = notify_change(path->dentry, &newattrs, &delegated_inode);
|
error = notify_change2(path->mnt, path->dentry, &newattrs, &delegated_inode);
|
||||||
inode_unlock(inode);
|
inode_unlock(inode);
|
||||||
if (delegated_inode) {
|
if (delegated_inode) {
|
||||||
error = break_deleg_wait(&delegated_inode);
|
error = break_deleg_wait(&delegated_inode);
|
||||||
|
|||||||
+1
-1
@@ -91,7 +91,7 @@ static int utimes_common(struct path *path, struct timespec *times)
|
|||||||
}
|
}
|
||||||
retry_deleg:
|
retry_deleg:
|
||||||
inode_lock(inode);
|
inode_lock(inode);
|
||||||
error = notify_change(path->dentry, &newattrs, &delegated_inode);
|
error = notify_change2(path->mnt, path->dentry, &newattrs, &delegated_inode);
|
||||||
inode_unlock(inode);
|
inode_unlock(inode);
|
||||||
if (delegated_inode) {
|
if (delegated_inode) {
|
||||||
error = break_deleg_wait(&delegated_inode);
|
error = break_deleg_wait(&delegated_inode);
|
||||||
|
|||||||
@@ -1751,6 +1751,7 @@ struct inode_operations {
|
|||||||
int (*rename) (struct inode *, struct dentry *,
|
int (*rename) (struct inode *, struct dentry *,
|
||||||
struct inode *, struct dentry *, unsigned int);
|
struct inode *, struct dentry *, unsigned int);
|
||||||
int (*setattr) (struct dentry *, struct iattr *);
|
int (*setattr) (struct dentry *, struct iattr *);
|
||||||
|
int (*setattr2) (struct vfsmount *, struct dentry *, struct iattr *);
|
||||||
int (*getattr) (struct vfsmount *mnt, struct dentry *, struct kstat *);
|
int (*getattr) (struct vfsmount *mnt, struct dentry *, struct kstat *);
|
||||||
ssize_t (*listxattr) (struct dentry *, char *, size_t);
|
ssize_t (*listxattr) (struct dentry *, char *, size_t);
|
||||||
int (*fiemap)(struct inode *, struct fiemap_extent_info *, u64 start,
|
int (*fiemap)(struct inode *, struct fiemap_extent_info *, u64 start,
|
||||||
@@ -2340,6 +2341,8 @@ struct filename {
|
|||||||
extern long vfs_truncate(const struct path *, loff_t);
|
extern long vfs_truncate(const struct path *, loff_t);
|
||||||
extern int do_truncate(struct dentry *, loff_t start, unsigned int time_attrs,
|
extern int do_truncate(struct dentry *, loff_t start, unsigned int time_attrs,
|
||||||
struct file *filp);
|
struct file *filp);
|
||||||
|
extern int do_truncate2(struct vfsmount *, struct dentry *, loff_t start,
|
||||||
|
unsigned int time_attrs, struct file *filp);
|
||||||
extern int vfs_fallocate(struct file *file, int mode, loff_t offset,
|
extern int vfs_fallocate(struct file *file, int mode, loff_t offset,
|
||||||
loff_t len);
|
loff_t len);
|
||||||
extern long do_sys_open(int dfd, const char __user *filename, int flags,
|
extern long do_sys_open(int dfd, const char __user *filename, int flags,
|
||||||
@@ -2582,6 +2585,7 @@ extern void emergency_remount(void);
|
|||||||
extern sector_t bmap(struct inode *, sector_t);
|
extern sector_t bmap(struct inode *, sector_t);
|
||||||
#endif
|
#endif
|
||||||
extern int notify_change(struct dentry *, struct iattr *, struct inode **);
|
extern int notify_change(struct dentry *, struct iattr *, struct inode **);
|
||||||
|
extern int notify_change2(struct vfsmount *, struct dentry *, struct iattr *, struct inode **);
|
||||||
extern int inode_permission(struct inode *, int);
|
extern int inode_permission(struct inode *, int);
|
||||||
extern int __inode_permission(struct inode *, int);
|
extern int __inode_permission(struct inode *, int);
|
||||||
extern int generic_permission(struct inode *, int);
|
extern int generic_permission(struct inode *, int);
|
||||||
|
|||||||
Reference in New Issue
Block a user