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:
Daniel Rosenberg 2016-10-26 16:33:11 -07:00
parent 21fc44e40a
commit 1cbf8e31e3
7 changed files with 34 additions and 15 deletions

View file

@ -187,7 +187,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;
@ -262,7 +262,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);
@ -275,4 +277,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);

View file

@ -695,7 +695,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;
} }

View file

@ -1715,7 +1715,7 @@ int dentry_needs_remove_privs(struct dentry *dentry)
} }
EXPORT_SYMBOL(dentry_needs_remove_privs); EXPORT_SYMBOL(dentry_needs_remove_privs);
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;
@ -1724,7 +1724,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);
} }
/* /*
@ -1746,7 +1746,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);

View file

@ -2760,7 +2760,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);
} }

View file

@ -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,
mutex_lock(&dentry->d_inode->i_mutex); mutex_lock(&dentry->d_inode->i_mutex);
/* 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);
mutex_unlock(&dentry->d_inode->i_mutex); mutex_unlock(&dentry->d_inode->i_mutex);
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(struct path *path, loff_t length) long vfs_truncate(struct path *path, loff_t length)
{ {
@ -108,7 +113,7 @@ long vfs_truncate(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(inode); put_write_access(inode);
@ -157,6 +162,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;
@ -173,6 +179,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))
@ -192,7 +199,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);
@ -522,7 +529,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:
mutex_unlock(&inode->i_mutex); mutex_unlock(&inode->i_mutex);
if (delegated_inode) { if (delegated_inode) {
@ -602,7 +609,7 @@ retry_deleg:
mutex_lock(&inode->i_mutex); mutex_lock(&inode->i_mutex);
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);
mutex_unlock(&inode->i_mutex); mutex_unlock(&inode->i_mutex);
if (delegated_inode) { if (delegated_inode) {
error = break_deleg_wait(&delegated_inode); error = break_deleg_wait(&delegated_inode);

View file

@ -104,7 +104,7 @@ static int utimes_common(struct path *path, struct timespec *times)
} }
retry_deleg: retry_deleg:
mutex_lock(&inode->i_mutex); mutex_lock(&inode->i_mutex);
error = notify_change(path->dentry, &newattrs, &delegated_inode); error = notify_change2(path->mnt, path->dentry, &newattrs, &delegated_inode);
mutex_unlock(&inode->i_mutex); mutex_unlock(&inode->i_mutex);
if (delegated_inode) { if (delegated_inode) {
error = break_deleg_wait(&delegated_inode); error = break_deleg_wait(&delegated_inode);

View file

@ -1661,6 +1661,7 @@ struct inode_operations {
int (*rename2) (struct inode *, struct dentry *, int (*rename2) (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 *);
int (*setxattr) (struct dentry *, const char *,const void *,size_t,int); int (*setxattr) (struct dentry *, const char *,const void *,size_t,int);
ssize_t (*getxattr) (struct dentry *, const char *, void *, size_t); ssize_t (*getxattr) (struct dentry *, const char *, void *, size_t);
@ -2226,6 +2227,8 @@ struct filename {
extern long vfs_truncate(struct path *, loff_t); extern long vfs_truncate(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,
@ -2450,6 +2453,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_permission2(struct vfsmount *, struct inode *, int); extern int inode_permission2(struct vfsmount *, struct inode *, int);
extern int __inode_permission(struct inode *, int); extern int __inode_permission(struct inode *, int);