From 1620d1d7d45e98c1c8b1479a2fde08ea950422d8 Mon Sep 17 00:00:00 2001 From: Daniel Rosenberg Date: Wed, 26 Oct 2016 16:33:11 -0700 Subject: [PATCH] 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 --- fs/attr.c | 11 +++++++++-- fs/open.c | 21 ++++++++++++++------- fs/utimes.c | 2 +- include/linux/fs.h | 4 ++++ 4 files changed, 28 insertions(+), 10 deletions(-) diff --git a/fs/attr.c b/fs/attr.c index 73f69a6ce9ed..61aa4bc2435a 100644 --- a/fs/attr.c +++ b/fs/attr.c @@ -163,7 +163,7 @@ void setattr_copy(struct inode *inode, const struct iattr *attr) } EXPORT_SYMBOL(setattr_copy); -int notify_change(struct dentry * dentry, struct iattr * attr) +int notify_change2(struct vfsmount *mnt, struct dentry * dentry, struct iattr * attr) { struct inode *inode = dentry->d_inode; umode_t mode = inode->i_mode; @@ -233,7 +233,9 @@ int notify_change(struct dentry * dentry, struct iattr * attr) if (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); else error = simple_setattr(dentry, attr); @@ -245,5 +247,10 @@ int notify_change(struct dentry * dentry, struct iattr * attr) return error; } +EXPORT_SYMBOL(notify_change2); +int notify_change(struct dentry * dentry, struct iattr * attr) +{ + return notify_change2(NULL, dentry, attr); +} EXPORT_SYMBOL(notify_change); diff --git a/fs/open.c b/fs/open.c index 83789f65fbb8..26f243e86e8a 100644 --- a/fs/open.c +++ b/fs/open.c @@ -33,8 +33,8 @@ #include "internal.h" -int do_truncate(struct dentry *dentry, loff_t length, unsigned int time_attrs, - struct file *filp) +int do_truncate2(struct vfsmount *mnt, struct dentry *dentry, loff_t length, + unsigned int time_attrs, struct file *filp) { int ret; struct iattr newattrs; @@ -56,10 +56,15 @@ int do_truncate(struct dentry *dentry, loff_t length, unsigned int time_attrs, newattrs.ia_valid |= ret | ATTR_FORCE; mutex_lock(&dentry->d_inode->i_mutex); - ret = notify_change(dentry, &newattrs); + ret = notify_change2(mnt, dentry, &newattrs); mutex_unlock(&dentry->d_inode->i_mutex); 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); +} static long do_sys_truncate(const char __user *pathname, loff_t length) { @@ -115,7 +120,7 @@ static long do_sys_truncate(const char __user *pathname, loff_t length) if (!error) error = security_path_truncate(&path); 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_access(inode); @@ -136,6 +141,7 @@ static long do_sys_ftruncate(unsigned int fd, loff_t length, int small) { struct inode * inode; struct dentry *dentry; + struct vfsmount *mnt; struct file * file; int error; @@ -152,6 +158,7 @@ static long do_sys_ftruncate(unsigned int fd, loff_t length, int small) small = 0; dentry = file->f_path.dentry; + mnt = file->f_path.mnt; inode = dentry->d_inode; error = -EINVAL; if (!S_ISREG(inode->i_mode) || !(file->f_mode & FMODE_WRITE)) @@ -170,7 +177,7 @@ static long do_sys_ftruncate(unsigned int fd, loff_t length, int small) if (!error) error = security_path_truncate(&file->f_path); if (!error) - error = do_truncate(dentry, length, ATTR_MTIME|ATTR_CTIME, file); + error = do_truncate2(mnt, dentry, length, ATTR_MTIME|ATTR_CTIME, file); out_putf: fput(file); out: @@ -467,7 +474,7 @@ static int chmod_common(struct path *path, umode_t mode) goto out_unlock; newattrs.ia_mode = (mode & S_IALLUGO) | (inode->i_mode & ~S_IALLUGO); newattrs.ia_valid = ATTR_MODE | ATTR_CTIME; - error = notify_change(path->dentry, &newattrs); + error = notify_change2(path->mnt, path->dentry, &newattrs); out_unlock: mutex_unlock(&inode->i_mutex); mnt_drop_write(path->mnt); @@ -527,7 +534,7 @@ static int chown_common(struct path *path, uid_t user, gid_t group) mutex_lock(&inode->i_mutex); error = security_path_chown(path, user, group); if (!error) - error = notify_change(path->dentry, &newattrs); + error = notify_change2(path->mnt, path->dentry, &newattrs); mutex_unlock(&inode->i_mutex); return error; diff --git a/fs/utimes.c b/fs/utimes.c index fdbac68120b3..8486d8d6800c 100644 --- a/fs/utimes.c +++ b/fs/utimes.c @@ -102,7 +102,7 @@ static int utimes_common(struct path *path, struct timespec *times) } } mutex_lock(&inode->i_mutex); - error = notify_change(path->dentry, &newattrs); + error = notify_change2(path->mnt, path->dentry, &newattrs); mutex_unlock(&inode->i_mutex); mnt_drop_write_and_out: diff --git a/include/linux/fs.h b/include/linux/fs.h index e19195a39259..c733b3fc64d5 100644 --- a/include/linux/fs.h +++ b/include/linux/fs.h @@ -1698,6 +1698,7 @@ struct inode_operations { struct inode *, struct dentry *); void (*truncate) (struct inode *); int (*setattr) (struct dentry *, struct iattr *); + int (*setattr2) (struct vfsmount *, struct dentry *, struct iattr *); int (*getattr) (struct vfsmount *mnt, struct dentry *, struct kstat *); int (*setxattr) (struct dentry *, const char *,const void *,size_t,int); ssize_t (*getxattr) (struct dentry *, const char *, void *, size_t); @@ -2078,6 +2079,8 @@ static inline int break_lease(struct inode *inode, unsigned int mode) extern int do_truncate(struct dentry *, loff_t start, unsigned int time_attrs, struct file *filp); +extern int do_truncate2(struct vfsmount *, struct dentry *, loff_t start, + unsigned int time_attrs, struct file *filp); extern int do_fallocate(struct file *file, int mode, loff_t offset, loff_t len); extern long do_sys_open(int dfd, const char __user *filename, int flags, @@ -2276,6 +2279,7 @@ extern void emergency_remount(void); extern sector_t bmap(struct inode *, sector_t); #endif extern int notify_change(struct dentry *, struct iattr *); +extern int notify_change2(struct vfsmount *, struct dentry *, struct iattr *); extern int inode_permission(struct inode *, int); extern int inode_permission2(struct vfsmount *, struct inode *, int); extern int generic_permission(struct inode *, int);