mirror of
https://github.com/rd-stuffs/msm-4.14.git
synced 2025-02-20 11:45:48 +08:00
ANDROID: vfs: Add permission2 for filesystems with per mount permissions
This allows filesystems to use their mount private data to influence the permssions they return in permission2. It has been separated into a new call to avoid disrupting current permission users. Change-Id: I9d416e3b8b6eca84ef3e336bd2af89ddd51df6ca Signed-off-by: Daniel Rosenberg <drosen@google.com>
This commit is contained in:
parent
06b4c45094
commit
571be17396
@ -226,7 +226,7 @@ int notify_change2(struct vfsmount *mnt, struct dentry * dentry, struct iattr *
|
||||
return -EPERM;
|
||||
|
||||
if (!inode_owner_or_capable(inode)) {
|
||||
error = inode_permission(inode, MAY_WRITE);
|
||||
error = inode_permission2(mnt, inode, MAY_WRITE);
|
||||
if (error)
|
||||
return error;
|
||||
}
|
||||
|
@ -1304,7 +1304,7 @@ EXPORT_SYMBOL(flush_old_exec);
|
||||
void would_dump(struct linux_binprm *bprm, struct file *file)
|
||||
{
|
||||
struct inode *inode = file_inode(file);
|
||||
if (inode_permission(inode, MAY_READ) < 0) {
|
||||
if (inode_permission2(file->f_path.mnt, inode, MAY_READ) < 0) {
|
||||
struct user_namespace *old, *user_ns;
|
||||
bprm->interp_flags |= BINPRM_FLAGS_ENFORCE_NONDUMP;
|
||||
|
||||
|
170
fs/namei.c
170
fs/namei.c
@ -376,9 +376,11 @@ EXPORT_SYMBOL(generic_permission);
|
||||
* flag in inode->i_opflags, that says "this has not special
|
||||
* permission function, use the fast case".
|
||||
*/
|
||||
static inline int do_inode_permission(struct inode *inode, int mask)
|
||||
static inline int do_inode_permission(struct vfsmount *mnt, struct inode *inode, int mask)
|
||||
{
|
||||
if (unlikely(!(inode->i_opflags & IOP_FASTPERM))) {
|
||||
if (likely(mnt && inode->i_op->permission2))
|
||||
return inode->i_op->permission2(mnt, inode, mask);
|
||||
if (likely(inode->i_op->permission))
|
||||
return inode->i_op->permission(inode, mask);
|
||||
|
||||
@ -402,7 +404,7 @@ static inline int do_inode_permission(struct inode *inode, int mask)
|
||||
* This does not check for a read-only file system. You probably want
|
||||
* inode_permission().
|
||||
*/
|
||||
int __inode_permission(struct inode *inode, int mask)
|
||||
int __inode_permission2(struct vfsmount *mnt, struct inode *inode, int mask)
|
||||
{
|
||||
int retval;
|
||||
|
||||
@ -422,7 +424,7 @@ int __inode_permission(struct inode *inode, int mask)
|
||||
return -EACCES;
|
||||
}
|
||||
|
||||
retval = do_inode_permission(inode, mask);
|
||||
retval = do_inode_permission(mnt, inode, mask);
|
||||
if (retval)
|
||||
return retval;
|
||||
|
||||
@ -430,7 +432,14 @@ int __inode_permission(struct inode *inode, int mask)
|
||||
if (retval)
|
||||
return retval;
|
||||
|
||||
return security_inode_permission(inode, mask);
|
||||
retval = security_inode_permission(inode, mask);
|
||||
return retval;
|
||||
}
|
||||
EXPORT_SYMBOL(__inode_permission2);
|
||||
|
||||
int __inode_permission(struct inode *inode, int mask)
|
||||
{
|
||||
return __inode_permission2(NULL, inode, mask);
|
||||
}
|
||||
EXPORT_SYMBOL(__inode_permission);
|
||||
|
||||
@ -465,14 +474,20 @@ static int sb_permission(struct super_block *sb, struct inode *inode, int mask)
|
||||
*
|
||||
* When checking for MAY_APPEND, MAY_WRITE must also be set in @mask.
|
||||
*/
|
||||
int inode_permission(struct inode *inode, int mask)
|
||||
int inode_permission2(struct vfsmount *mnt, struct inode *inode, int mask)
|
||||
{
|
||||
int retval;
|
||||
|
||||
retval = sb_permission(inode->i_sb, inode, mask);
|
||||
if (retval)
|
||||
return retval;
|
||||
return __inode_permission(inode, mask);
|
||||
return __inode_permission2(mnt, inode, mask);
|
||||
}
|
||||
EXPORT_SYMBOL(inode_permission2);
|
||||
|
||||
int inode_permission(struct inode *inode, int mask)
|
||||
{
|
||||
return inode_permission2(NULL, inode, mask);
|
||||
}
|
||||
EXPORT_SYMBOL(inode_permission);
|
||||
|
||||
@ -1667,13 +1682,13 @@ out:
|
||||
static inline int may_lookup(struct nameidata *nd)
|
||||
{
|
||||
if (nd->flags & LOOKUP_RCU) {
|
||||
int err = inode_permission(nd->inode, MAY_EXEC|MAY_NOT_BLOCK);
|
||||
int err = inode_permission2(nd->path.mnt, nd->inode, MAY_EXEC|MAY_NOT_BLOCK);
|
||||
if (err != -ECHILD)
|
||||
return err;
|
||||
if (unlazy_walk(nd))
|
||||
return -ECHILD;
|
||||
}
|
||||
return inode_permission(nd->inode, MAY_EXEC);
|
||||
return inode_permission2(nd->path.mnt, nd->inode, MAY_EXEC);
|
||||
}
|
||||
|
||||
static inline int handle_dots(struct nameidata *nd, int type)
|
||||
@ -2449,6 +2464,7 @@ EXPORT_SYMBOL(vfs_path_lookup);
|
||||
/**
|
||||
* lookup_one_len - filesystem helper to lookup single pathname component
|
||||
* @name: pathname component to lookup
|
||||
* @mnt: mount we are looking up on
|
||||
* @base: base directory to lookup from
|
||||
* @len: maximum length @len should be interpreted to
|
||||
*
|
||||
@ -2457,7 +2473,7 @@ EXPORT_SYMBOL(vfs_path_lookup);
|
||||
*
|
||||
* The caller must hold base->i_mutex.
|
||||
*/
|
||||
struct dentry *lookup_one_len(const char *name, struct dentry *base, int len)
|
||||
struct dentry *lookup_one_len2(const char *name, struct vfsmount *mnt, struct dentry *base, int len)
|
||||
{
|
||||
struct qstr this;
|
||||
unsigned int c;
|
||||
@ -2491,12 +2507,18 @@ struct dentry *lookup_one_len(const char *name, struct dentry *base, int len)
|
||||
return ERR_PTR(err);
|
||||
}
|
||||
|
||||
err = inode_permission(base->d_inode, MAY_EXEC);
|
||||
err = inode_permission2(mnt, base->d_inode, MAY_EXEC);
|
||||
if (err)
|
||||
return ERR_PTR(err);
|
||||
|
||||
return __lookup_hash(&this, base, 0);
|
||||
}
|
||||
EXPORT_SYMBOL(lookup_one_len2);
|
||||
|
||||
struct dentry *lookup_one_len(const char *name, struct dentry *base, int len)
|
||||
{
|
||||
return lookup_one_len2(name, NULL, base, len);
|
||||
}
|
||||
EXPORT_SYMBOL(lookup_one_len);
|
||||
|
||||
/**
|
||||
@ -2774,7 +2796,7 @@ EXPORT_SYMBOL(__check_sticky);
|
||||
* 11. We don't allow removal of NFS sillyrenamed files; it's handled by
|
||||
* nfs_async_unlink().
|
||||
*/
|
||||
static int may_delete(struct inode *dir, struct dentry *victim, bool isdir)
|
||||
static int may_delete(struct vfsmount *mnt, struct inode *dir, struct dentry *victim, bool isdir)
|
||||
{
|
||||
struct inode *inode = d_backing_inode(victim);
|
||||
int error;
|
||||
@ -2786,7 +2808,7 @@ static int may_delete(struct inode *dir, struct dentry *victim, bool isdir)
|
||||
BUG_ON(victim->d_parent->d_inode != dir);
|
||||
audit_inode_child(dir, victim, AUDIT_TYPE_CHILD_DELETE);
|
||||
|
||||
error = inode_permission(dir, MAY_WRITE | MAY_EXEC);
|
||||
error = inode_permission2(mnt, dir, MAY_WRITE | MAY_EXEC);
|
||||
if (error)
|
||||
return error;
|
||||
if (IS_APPEND(dir))
|
||||
@ -2818,7 +2840,7 @@ static int may_delete(struct inode *dir, struct dentry *victim, bool isdir)
|
||||
* 4. We should have write and exec permissions on dir
|
||||
* 5. We can't do it if dir is immutable (done in permission())
|
||||
*/
|
||||
static inline int may_create(struct inode *dir, struct dentry *child)
|
||||
static inline int may_create(struct vfsmount *mnt, struct inode *dir, struct dentry *child)
|
||||
{
|
||||
struct user_namespace *s_user_ns;
|
||||
audit_inode_child(dir, child, AUDIT_TYPE_CHILD_CREATE);
|
||||
@ -2830,7 +2852,7 @@ static inline int may_create(struct inode *dir, struct dentry *child)
|
||||
if (!kuid_has_mapping(s_user_ns, current_fsuid()) ||
|
||||
!kgid_has_mapping(s_user_ns, current_fsgid()))
|
||||
return -EOVERFLOW;
|
||||
return inode_permission(dir, MAY_WRITE | MAY_EXEC);
|
||||
return inode_permission2(mnt, dir, MAY_WRITE | MAY_EXEC);
|
||||
}
|
||||
|
||||
/*
|
||||
@ -2877,10 +2899,10 @@ void unlock_rename(struct dentry *p1, struct dentry *p2)
|
||||
}
|
||||
EXPORT_SYMBOL(unlock_rename);
|
||||
|
||||
int vfs_create(struct inode *dir, struct dentry *dentry, umode_t mode,
|
||||
bool want_excl)
|
||||
int vfs_create2(struct vfsmount *mnt, struct inode *dir, struct dentry *dentry,
|
||||
umode_t mode, bool want_excl)
|
||||
{
|
||||
int error = may_create(dir, dentry);
|
||||
int error = may_create(mnt, dir, dentry);
|
||||
if (error)
|
||||
return error;
|
||||
|
||||
@ -2896,6 +2918,13 @@ int vfs_create(struct inode *dir, struct dentry *dentry, umode_t mode,
|
||||
fsnotify_create(dir, dentry);
|
||||
return error;
|
||||
}
|
||||
EXPORT_SYMBOL(vfs_create2);
|
||||
|
||||
int vfs_create(struct inode *dir, struct dentry *dentry, umode_t mode,
|
||||
bool want_excl)
|
||||
{
|
||||
return vfs_create2(NULL, dir, dentry, mode, want_excl);
|
||||
}
|
||||
EXPORT_SYMBOL(vfs_create);
|
||||
|
||||
bool may_open_dev(const struct path *path)
|
||||
@ -2907,6 +2936,7 @@ bool may_open_dev(const struct path *path)
|
||||
static int may_open(const struct path *path, int acc_mode, int flag)
|
||||
{
|
||||
struct dentry *dentry = path->dentry;
|
||||
struct vfsmount *mnt = path->mnt;
|
||||
struct inode *inode = dentry->d_inode;
|
||||
int error;
|
||||
|
||||
@ -2931,7 +2961,7 @@ static int may_open(const struct path *path, int acc_mode, int flag)
|
||||
break;
|
||||
}
|
||||
|
||||
error = inode_permission(inode, MAY_OPEN | acc_mode);
|
||||
error = inode_permission2(mnt, inode, MAY_OPEN | acc_mode);
|
||||
if (error)
|
||||
return error;
|
||||
|
||||
@ -2993,7 +3023,7 @@ static int may_o_create(const struct path *dir, struct dentry *dentry, umode_t m
|
||||
!kgid_has_mapping(s_user_ns, current_fsgid()))
|
||||
return -EOVERFLOW;
|
||||
|
||||
error = inode_permission(dir->dentry->d_inode, MAY_WRITE | MAY_EXEC);
|
||||
error = inode_permission2(dir->mnt, dir->dentry->d_inode, MAY_WRITE | MAY_EXEC);
|
||||
if (error)
|
||||
return error;
|
||||
|
||||
@ -3406,7 +3436,8 @@ struct dentry *vfs_tmpfile(struct dentry *dentry, umode_t mode, int open_flag)
|
||||
int error;
|
||||
|
||||
/* we want directory to be writable */
|
||||
error = inode_permission(dir, MAY_WRITE | MAY_EXEC);
|
||||
error = inode_permission2(ERR_PTR(-EOPNOTSUPP), dir,
|
||||
MAY_WRITE | MAY_EXEC);
|
||||
if (error)
|
||||
goto out_err;
|
||||
error = -EOPNOTSUPP;
|
||||
@ -3684,9 +3715,9 @@ inline struct dentry *user_path_create(int dfd, const char __user *pathname,
|
||||
}
|
||||
EXPORT_SYMBOL(user_path_create);
|
||||
|
||||
int vfs_mknod(struct inode *dir, struct dentry *dentry, umode_t mode, dev_t dev)
|
||||
int vfs_mknod2(struct vfsmount *mnt, struct inode *dir, struct dentry *dentry, umode_t mode, dev_t dev)
|
||||
{
|
||||
int error = may_create(dir, dentry);
|
||||
int error = may_create(mnt, dir, dentry);
|
||||
|
||||
if (error)
|
||||
return error;
|
||||
@ -3710,6 +3741,12 @@ int vfs_mknod(struct inode *dir, struct dentry *dentry, umode_t mode, dev_t dev)
|
||||
fsnotify_create(dir, dentry);
|
||||
return error;
|
||||
}
|
||||
EXPORT_SYMBOL(vfs_mknod2);
|
||||
|
||||
int vfs_mknod(struct inode *dir, struct dentry *dentry, umode_t mode, dev_t dev)
|
||||
{
|
||||
return vfs_mknod2(NULL, dir, dentry, mode, dev);
|
||||
}
|
||||
EXPORT_SYMBOL(vfs_mknod);
|
||||
|
||||
static int may_mknod(umode_t mode)
|
||||
@ -3752,12 +3789,12 @@ retry:
|
||||
goto out;
|
||||
switch (mode & S_IFMT) {
|
||||
case 0: case S_IFREG:
|
||||
error = vfs_create(path.dentry->d_inode,dentry,mode,true);
|
||||
error = vfs_create2(path.mnt, path.dentry->d_inode,dentry,mode,true);
|
||||
if (!error)
|
||||
ima_post_path_mknod(dentry);
|
||||
break;
|
||||
case S_IFCHR: case S_IFBLK:
|
||||
error = vfs_mknod(path.dentry->d_inode,dentry,mode,
|
||||
error = vfs_mknod2(path.mnt, path.dentry->d_inode,dentry,mode,
|
||||
new_decode_dev(dev));
|
||||
break;
|
||||
case S_IFIFO: case S_IFSOCK:
|
||||
@ -3778,9 +3815,9 @@ SYSCALL_DEFINE3(mknod, const char __user *, filename, umode_t, mode, unsigned, d
|
||||
return sys_mknodat(AT_FDCWD, filename, mode, dev);
|
||||
}
|
||||
|
||||
int vfs_mkdir(struct inode *dir, struct dentry *dentry, umode_t mode)
|
||||
int vfs_mkdir2(struct vfsmount *mnt, struct inode *dir, struct dentry *dentry, umode_t mode)
|
||||
{
|
||||
int error = may_create(dir, dentry);
|
||||
int error = may_create(mnt, dir, dentry);
|
||||
unsigned max_links = dir->i_sb->s_max_links;
|
||||
|
||||
if (error)
|
||||
@ -3802,6 +3839,12 @@ int vfs_mkdir(struct inode *dir, struct dentry *dentry, umode_t mode)
|
||||
fsnotify_mkdir(dir, dentry);
|
||||
return error;
|
||||
}
|
||||
EXPORT_SYMBOL(vfs_mkdir2);
|
||||
|
||||
int vfs_mkdir(struct inode *dir, struct dentry *dentry, umode_t mode)
|
||||
{
|
||||
return vfs_mkdir2(NULL, dir, dentry, mode);
|
||||
}
|
||||
EXPORT_SYMBOL(vfs_mkdir);
|
||||
|
||||
SYSCALL_DEFINE3(mkdirat, int, dfd, const char __user *, pathname, umode_t, mode)
|
||||
@ -3820,7 +3863,7 @@ retry:
|
||||
mode &= ~current_umask();
|
||||
error = security_path_mkdir(&path, dentry, mode);
|
||||
if (!error)
|
||||
error = vfs_mkdir(path.dentry->d_inode, dentry, mode);
|
||||
error = vfs_mkdir2(path.mnt, path.dentry->d_inode, dentry, mode);
|
||||
done_path_create(&path, dentry);
|
||||
if (retry_estale(error, lookup_flags)) {
|
||||
lookup_flags |= LOOKUP_REVAL;
|
||||
@ -3834,9 +3877,9 @@ SYSCALL_DEFINE2(mkdir, const char __user *, pathname, umode_t, mode)
|
||||
return sys_mkdirat(AT_FDCWD, pathname, mode);
|
||||
}
|
||||
|
||||
int vfs_rmdir(struct inode *dir, struct dentry *dentry)
|
||||
int vfs_rmdir2(struct vfsmount *mnt, struct inode *dir, struct dentry *dentry)
|
||||
{
|
||||
int error = may_delete(dir, dentry, 1);
|
||||
int error = may_delete(mnt, dir, dentry, 1);
|
||||
|
||||
if (error)
|
||||
return error;
|
||||
@ -3871,6 +3914,10 @@ out:
|
||||
d_delete(dentry);
|
||||
return error;
|
||||
}
|
||||
int vfs_rmdir(struct inode *dir, struct dentry *dentry)
|
||||
{
|
||||
return vfs_rmdir2(NULL, dir, dentry);
|
||||
}
|
||||
EXPORT_SYMBOL(vfs_rmdir);
|
||||
|
||||
static long do_rmdir(int dfd, const char __user *pathname)
|
||||
@ -3916,7 +3963,7 @@ retry:
|
||||
error = security_path_rmdir(&path, dentry);
|
||||
if (error)
|
||||
goto exit3;
|
||||
error = vfs_rmdir(path.dentry->d_inode, dentry);
|
||||
error = vfs_rmdir2(path.mnt, path.dentry->d_inode, dentry);
|
||||
exit3:
|
||||
dput(dentry);
|
||||
exit2:
|
||||
@ -3955,10 +4002,10 @@ SYSCALL_DEFINE1(rmdir, const char __user *, pathname)
|
||||
* be appropriate for callers that expect the underlying filesystem not
|
||||
* to be NFS exported.
|
||||
*/
|
||||
int vfs_unlink(struct inode *dir, struct dentry *dentry, struct inode **delegated_inode)
|
||||
int vfs_unlink2(struct vfsmount *mnt, struct inode *dir, struct dentry *dentry, struct inode **delegated_inode)
|
||||
{
|
||||
struct inode *target = dentry->d_inode;
|
||||
int error = may_delete(dir, dentry, 0);
|
||||
int error = may_delete(mnt, dir, dentry, 0);
|
||||
|
||||
if (error)
|
||||
return error;
|
||||
@ -3993,6 +4040,12 @@ out:
|
||||
|
||||
return error;
|
||||
}
|
||||
EXPORT_SYMBOL(vfs_unlink2);
|
||||
|
||||
int vfs_unlink(struct inode *dir, struct dentry *dentry, struct inode **delegated_inode)
|
||||
{
|
||||
return vfs_unlink2(NULL, dir, dentry, delegated_inode);
|
||||
}
|
||||
EXPORT_SYMBOL(vfs_unlink);
|
||||
|
||||
/*
|
||||
@ -4040,7 +4093,7 @@ retry_deleg:
|
||||
error = security_path_unlink(&path, dentry);
|
||||
if (error)
|
||||
goto exit2;
|
||||
error = vfs_unlink(path.dentry->d_inode, dentry, &delegated_inode);
|
||||
error = vfs_unlink2(path.mnt, path.dentry->d_inode, dentry, &delegated_inode);
|
||||
exit2:
|
||||
dput(dentry);
|
||||
}
|
||||
@ -4090,9 +4143,9 @@ SYSCALL_DEFINE1(unlink, const char __user *, pathname)
|
||||
return do_unlinkat(AT_FDCWD, pathname);
|
||||
}
|
||||
|
||||
int vfs_symlink(struct inode *dir, struct dentry *dentry, const char *oldname)
|
||||
int vfs_symlink2(struct vfsmount *mnt, struct inode *dir, struct dentry *dentry, const char *oldname)
|
||||
{
|
||||
int error = may_create(dir, dentry);
|
||||
int error = may_create(mnt, dir, dentry);
|
||||
|
||||
if (error)
|
||||
return error;
|
||||
@ -4109,6 +4162,12 @@ int vfs_symlink(struct inode *dir, struct dentry *dentry, const char *oldname)
|
||||
fsnotify_create(dir, dentry);
|
||||
return error;
|
||||
}
|
||||
EXPORT_SYMBOL(vfs_symlink2);
|
||||
|
||||
int vfs_symlink(struct inode *dir, struct dentry *dentry, const char *oldname)
|
||||
{
|
||||
return vfs_symlink2(NULL, dir, dentry, oldname);
|
||||
}
|
||||
EXPORT_SYMBOL(vfs_symlink);
|
||||
|
||||
SYSCALL_DEFINE3(symlinkat, const char __user *, oldname,
|
||||
@ -4131,7 +4190,7 @@ retry:
|
||||
|
||||
error = security_path_symlink(&path, dentry, from->name);
|
||||
if (!error)
|
||||
error = vfs_symlink(path.dentry->d_inode, dentry, from->name);
|
||||
error = vfs_symlink2(path.mnt, path.dentry->d_inode, dentry, from->name);
|
||||
done_path_create(&path, dentry);
|
||||
if (retry_estale(error, lookup_flags)) {
|
||||
lookup_flags |= LOOKUP_REVAL;
|
||||
@ -4166,7 +4225,7 @@ SYSCALL_DEFINE2(symlink, const char __user *, oldname, const char __user *, newn
|
||||
* be appropriate for callers that expect the underlying filesystem not
|
||||
* to be NFS exported.
|
||||
*/
|
||||
int vfs_link(struct dentry *old_dentry, struct inode *dir, struct dentry *new_dentry, struct inode **delegated_inode)
|
||||
int vfs_link2(struct vfsmount *mnt, struct dentry *old_dentry, struct inode *dir, struct dentry *new_dentry, struct inode **delegated_inode)
|
||||
{
|
||||
struct inode *inode = old_dentry->d_inode;
|
||||
unsigned max_links = dir->i_sb->s_max_links;
|
||||
@ -4175,7 +4234,7 @@ int vfs_link(struct dentry *old_dentry, struct inode *dir, struct dentry *new_de
|
||||
if (!inode)
|
||||
return -ENOENT;
|
||||
|
||||
error = may_create(dir, new_dentry);
|
||||
error = may_create(mnt, dir, new_dentry);
|
||||
if (error)
|
||||
return error;
|
||||
|
||||
@ -4225,6 +4284,12 @@ int vfs_link(struct dentry *old_dentry, struct inode *dir, struct dentry *new_de
|
||||
fsnotify_link(dir, inode, new_dentry);
|
||||
return error;
|
||||
}
|
||||
EXPORT_SYMBOL(vfs_link2);
|
||||
|
||||
int vfs_link(struct dentry *old_dentry, struct inode *dir, struct dentry *new_dentry, struct inode **delegated_inode)
|
||||
{
|
||||
return vfs_link2(NULL, old_dentry, dir, new_dentry, delegated_inode);
|
||||
}
|
||||
EXPORT_SYMBOL(vfs_link);
|
||||
|
||||
/*
|
||||
@ -4280,7 +4345,7 @@ retry:
|
||||
error = security_path_link(old_path.dentry, &new_path, new_dentry);
|
||||
if (error)
|
||||
goto out_dput;
|
||||
error = vfs_link(old_path.dentry, new_path.dentry->d_inode, new_dentry, &delegated_inode);
|
||||
error = vfs_link2(old_path.mnt, old_path.dentry, new_path.dentry->d_inode, new_dentry, &delegated_inode);
|
||||
out_dput:
|
||||
done_path_create(&new_path, new_dentry);
|
||||
if (delegated_inode) {
|
||||
@ -4356,7 +4421,8 @@ SYSCALL_DEFINE2(link, const char __user *, oldname, const char __user *, newname
|
||||
* ->i_mutex on parents, which works but leads to some truly excessive
|
||||
* locking].
|
||||
*/
|
||||
int vfs_rename(struct inode *old_dir, struct dentry *old_dentry,
|
||||
int vfs_rename2(struct vfsmount *mnt,
|
||||
struct inode *old_dir, struct dentry *old_dentry,
|
||||
struct inode *new_dir, struct dentry *new_dentry,
|
||||
struct inode **delegated_inode, unsigned int flags)
|
||||
{
|
||||
@ -4371,19 +4437,19 @@ int vfs_rename(struct inode *old_dir, struct dentry *old_dentry,
|
||||
if (source == target)
|
||||
return 0;
|
||||
|
||||
error = may_delete(old_dir, old_dentry, is_dir);
|
||||
error = may_delete(mnt, old_dir, old_dentry, is_dir);
|
||||
if (error)
|
||||
return error;
|
||||
|
||||
if (!target) {
|
||||
error = may_create(new_dir, new_dentry);
|
||||
error = may_create(mnt, new_dir, new_dentry);
|
||||
} else {
|
||||
new_is_dir = d_is_dir(new_dentry);
|
||||
|
||||
if (!(flags & RENAME_EXCHANGE))
|
||||
error = may_delete(new_dir, new_dentry, is_dir);
|
||||
error = may_delete(mnt, new_dir, new_dentry, is_dir);
|
||||
else
|
||||
error = may_delete(new_dir, new_dentry, new_is_dir);
|
||||
error = may_delete(mnt, new_dir, new_dentry, new_is_dir);
|
||||
}
|
||||
if (error)
|
||||
return error;
|
||||
@ -4397,12 +4463,12 @@ int vfs_rename(struct inode *old_dir, struct dentry *old_dentry,
|
||||
*/
|
||||
if (new_dir != old_dir) {
|
||||
if (is_dir) {
|
||||
error = inode_permission(source, MAY_WRITE);
|
||||
error = inode_permission2(mnt, source, MAY_WRITE);
|
||||
if (error)
|
||||
return error;
|
||||
}
|
||||
if ((flags & RENAME_EXCHANGE) && new_is_dir) {
|
||||
error = inode_permission(target, MAY_WRITE);
|
||||
error = inode_permission2(mnt, target, MAY_WRITE);
|
||||
if (error)
|
||||
return error;
|
||||
}
|
||||
@ -4479,6 +4545,14 @@ out:
|
||||
|
||||
return error;
|
||||
}
|
||||
EXPORT_SYMBOL(vfs_rename2);
|
||||
|
||||
int vfs_rename(struct inode *old_dir, struct dentry *old_dentry,
|
||||
struct inode *new_dir, struct dentry *new_dentry,
|
||||
struct inode **delegated_inode, unsigned int flags)
|
||||
{
|
||||
return vfs_rename2(NULL, old_dir, old_dentry, new_dir, new_dentry, delegated_inode, flags);
|
||||
}
|
||||
EXPORT_SYMBOL(vfs_rename);
|
||||
|
||||
SYSCALL_DEFINE5(renameat2, int, olddfd, const char __user *, oldname,
|
||||
@ -4592,7 +4666,7 @@ retry_deleg:
|
||||
&new_path, new_dentry, flags);
|
||||
if (error)
|
||||
goto exit5;
|
||||
error = vfs_rename(old_path.dentry->d_inode, old_dentry,
|
||||
error = vfs_rename2(old_path.mnt, old_path.dentry->d_inode, old_dentry,
|
||||
new_path.dentry->d_inode, new_dentry,
|
||||
&delegated_inode, flags);
|
||||
exit5:
|
||||
@ -4637,7 +4711,7 @@ SYSCALL_DEFINE2(rename, const char __user *, oldname, const char __user *, newna
|
||||
|
||||
int vfs_whiteout(struct inode *dir, struct dentry *dentry)
|
||||
{
|
||||
int error = may_create(dir, dentry);
|
||||
int error = may_create(NULL, dir, dentry);
|
||||
if (error)
|
||||
return error;
|
||||
|
||||
|
@ -495,7 +495,7 @@ static int fanotify_find_path(int dfd, const char __user *filename,
|
||||
}
|
||||
|
||||
/* you can only watch an inode if you have read permissions on it */
|
||||
ret = inode_permission(path->dentry->d_inode, MAY_READ);
|
||||
ret = inode_permission2(path->mnt, path->dentry->d_inode, MAY_READ);
|
||||
if (ret)
|
||||
path_put(path);
|
||||
out:
|
||||
|
@ -335,7 +335,7 @@ static int inotify_find_inode(const char __user *dirname, struct path *path, uns
|
||||
if (error)
|
||||
return error;
|
||||
/* you can only watch an inode if you have read permissions on it */
|
||||
error = inode_permission(path->dentry->d_inode, MAY_READ);
|
||||
error = inode_permission2(path->mnt, path->dentry->d_inode, MAY_READ);
|
||||
if (error)
|
||||
path_put(path);
|
||||
return error;
|
||||
|
15
fs/open.c
15
fs/open.c
@ -73,10 +73,12 @@ int do_truncate(struct dentry *dentry, loff_t length, unsigned int time_attrs,
|
||||
long vfs_truncate(const struct path *path, loff_t length)
|
||||
{
|
||||
struct inode *inode;
|
||||
struct vfsmount *mnt;
|
||||
struct dentry *upperdentry;
|
||||
long error;
|
||||
|
||||
inode = path->dentry->d_inode;
|
||||
mnt = path->mnt;
|
||||
|
||||
/* For directories it's -EISDIR, for other non-regulars - -EINVAL */
|
||||
if (S_ISDIR(inode->i_mode))
|
||||
@ -88,7 +90,7 @@ long vfs_truncate(const struct path *path, loff_t length)
|
||||
if (error)
|
||||
goto out;
|
||||
|
||||
error = inode_permission(inode, MAY_WRITE);
|
||||
error = inode_permission2(mnt, inode, MAY_WRITE);
|
||||
if (error)
|
||||
goto mnt_drop_write_and_out;
|
||||
|
||||
@ -363,6 +365,7 @@ SYSCALL_DEFINE3(faccessat, int, dfd, const char __user *, filename, int, mode)
|
||||
struct cred *override_cred;
|
||||
struct path path;
|
||||
struct inode *inode;
|
||||
struct vfsmount *mnt;
|
||||
int res;
|
||||
unsigned int lookup_flags = LOOKUP_FOLLOW;
|
||||
|
||||
@ -393,6 +396,7 @@ retry:
|
||||
goto out;
|
||||
|
||||
inode = d_backing_inode(path.dentry);
|
||||
mnt = path.mnt;
|
||||
|
||||
if ((mode & MAY_EXEC) && S_ISREG(inode->i_mode)) {
|
||||
/*
|
||||
@ -404,7 +408,7 @@ retry:
|
||||
goto out_path_release;
|
||||
}
|
||||
|
||||
res = inode_permission(inode, mode | MAY_ACCESS);
|
||||
res = inode_permission2(mnt, inode, mode | MAY_ACCESS);
|
||||
/* SuS v2 requires we report a read only fs too */
|
||||
if (res || !(mode & S_IWOTH) || special_file(inode->i_mode))
|
||||
goto out_path_release;
|
||||
@ -448,7 +452,7 @@ retry:
|
||||
if (error)
|
||||
goto out;
|
||||
|
||||
error = inode_permission(path.dentry->d_inode, MAY_EXEC | MAY_CHDIR);
|
||||
error = inode_permission2(path.mnt, path.dentry->d_inode, MAY_EXEC | MAY_CHDIR);
|
||||
if (error)
|
||||
goto dput_and_out;
|
||||
|
||||
@ -477,7 +481,8 @@ SYSCALL_DEFINE1(fchdir, unsigned int, fd)
|
||||
if (!d_can_lookup(f.file->f_path.dentry))
|
||||
goto out_putf;
|
||||
|
||||
error = inode_permission(file_inode(f.file), MAY_EXEC | MAY_CHDIR);
|
||||
error = inode_permission2(f.file->f_path.mnt, file_inode(f.file),
|
||||
MAY_EXEC | MAY_CHDIR);
|
||||
if (!error)
|
||||
set_fs_pwd(current->fs, &f.file->f_path);
|
||||
out_putf:
|
||||
@ -496,7 +501,7 @@ retry:
|
||||
if (error)
|
||||
goto out;
|
||||
|
||||
error = inode_permission(path.dentry->d_inode, MAY_EXEC | MAY_CHDIR);
|
||||
error = inode_permission2(path.mnt, path.dentry->d_inode, MAY_EXEC | MAY_CHDIR);
|
||||
if (error)
|
||||
goto dput_and_out;
|
||||
|
||||
|
@ -1596,13 +1596,21 @@ extern bool inode_owner_or_capable(const struct inode *inode);
|
||||
* VFS helper functions..
|
||||
*/
|
||||
extern int vfs_create(struct inode *, struct dentry *, umode_t, bool);
|
||||
extern int vfs_create2(struct vfsmount *, struct inode *, struct dentry *, umode_t, bool);
|
||||
extern int vfs_mkdir(struct inode *, struct dentry *, umode_t);
|
||||
extern int vfs_mkdir2(struct vfsmount *, struct inode *, struct dentry *, umode_t);
|
||||
extern int vfs_mknod(struct inode *, struct dentry *, umode_t, dev_t);
|
||||
extern int vfs_mknod2(struct vfsmount *, struct inode *, struct dentry *, umode_t, dev_t);
|
||||
extern int vfs_symlink(struct inode *, struct dentry *, const char *);
|
||||
extern int vfs_symlink2(struct vfsmount *, struct inode *, struct dentry *, const char *);
|
||||
extern int vfs_link(struct dentry *, struct inode *, struct dentry *, struct inode **);
|
||||
extern int vfs_link2(struct vfsmount *, struct dentry *, struct inode *, struct dentry *, struct inode **);
|
||||
extern int vfs_rmdir(struct inode *, struct dentry *);
|
||||
extern int vfs_rmdir2(struct vfsmount *, struct inode *, struct dentry *);
|
||||
extern int vfs_unlink(struct inode *, struct dentry *, struct inode **);
|
||||
extern int vfs_unlink2(struct vfsmount *, struct inode *, struct dentry *, struct inode **);
|
||||
extern int vfs_rename(struct inode *, struct dentry *, struct inode *, struct dentry *, struct inode **, unsigned int);
|
||||
extern int vfs_rename2(struct vfsmount *, struct inode *, struct dentry *, struct inode *, struct dentry *, struct inode **, unsigned int);
|
||||
extern int vfs_whiteout(struct inode *, struct dentry *);
|
||||
|
||||
extern struct dentry *vfs_tmpfile(struct dentry *dentry, umode_t mode,
|
||||
@ -1733,6 +1741,7 @@ struct inode_operations {
|
||||
struct dentry * (*lookup) (struct inode *,struct dentry *, unsigned int);
|
||||
const char * (*get_link) (struct dentry *, struct inode *, struct delayed_call *);
|
||||
int (*permission) (struct inode *, int);
|
||||
int (*permission2) (struct vfsmount *, struct inode *, int);
|
||||
struct posix_acl * (*get_acl)(struct inode *, int);
|
||||
|
||||
int (*readlink) (struct dentry *, char __user *,int);
|
||||
@ -2694,7 +2703,9 @@ extern sector_t bmap(struct inode *, sector_t);
|
||||
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_permission2(struct vfsmount *, struct inode *, int);
|
||||
extern int __inode_permission(struct inode *, int);
|
||||
extern int __inode_permission2(struct vfsmount *, struct inode *, int);
|
||||
extern int generic_permission(struct inode *, int);
|
||||
extern int __check_sticky(struct inode *dir, struct inode *inode);
|
||||
|
||||
|
@ -82,6 +82,7 @@ extern struct dentry *kern_path_locked(const char *, struct path *);
|
||||
extern int kern_path_mountpoint(int, const char *, struct path *, unsigned int);
|
||||
|
||||
extern struct dentry *lookup_one_len(const char *, struct dentry *, int);
|
||||
extern struct dentry *lookup_one_len2(const char *, struct vfsmount *mnt, struct dentry *, int);
|
||||
extern struct dentry *lookup_one_len_unlocked(const char *, struct dentry *, int);
|
||||
|
||||
extern int follow_down_one(struct path *);
|
||||
|
10
ipc/mqueue.c
10
ipc/mqueue.c
@ -747,7 +747,7 @@ static struct file *do_create(struct ipc_namespace *ipc_ns, struct inode *dir,
|
||||
}
|
||||
|
||||
mode &= ~current_umask();
|
||||
ret = vfs_create(dir, path->dentry, mode, true);
|
||||
ret = vfs_create2(path->mnt, dir, path->dentry, mode, true);
|
||||
path->dentry->d_fsdata = NULL;
|
||||
if (ret)
|
||||
return ERR_PTR(ret);
|
||||
@ -763,7 +763,7 @@ static struct file *do_open(struct path *path, int oflag)
|
||||
if ((oflag & O_ACCMODE) == (O_RDWR | O_WRONLY))
|
||||
return ERR_PTR(-EINVAL);
|
||||
acc = oflag2acc[oflag & O_ACCMODE];
|
||||
if (inode_permission(d_inode(path->dentry), acc))
|
||||
if (inode_permission2(path->mnt, d_inode(path->dentry), acc))
|
||||
return ERR_PTR(-EACCES);
|
||||
return dentry_open(path, oflag, current_cred());
|
||||
}
|
||||
@ -792,7 +792,7 @@ static int do_mq_open(const char __user *u_name, int oflag, umode_t mode,
|
||||
ro = mnt_want_write(mnt); /* we'll drop it in any case */
|
||||
error = 0;
|
||||
inode_lock(d_inode(root));
|
||||
path.dentry = lookup_one_len(name->name, root, strlen(name->name));
|
||||
path.dentry = lookup_one_len2(name->name, mnt, root, strlen(name->name));
|
||||
if (IS_ERR(path.dentry)) {
|
||||
error = PTR_ERR(path.dentry);
|
||||
goto out_putfd;
|
||||
@ -872,7 +872,7 @@ SYSCALL_DEFINE1(mq_unlink, const char __user *, u_name)
|
||||
if (err)
|
||||
goto out_name;
|
||||
inode_lock_nested(d_inode(mnt->mnt_root), I_MUTEX_PARENT);
|
||||
dentry = lookup_one_len(name->name, mnt->mnt_root,
|
||||
dentry = lookup_one_len2(name->name, mnt, mnt->mnt_root,
|
||||
strlen(name->name));
|
||||
if (IS_ERR(dentry)) {
|
||||
err = PTR_ERR(dentry);
|
||||
@ -884,7 +884,7 @@ SYSCALL_DEFINE1(mq_unlink, const char __user *, u_name)
|
||||
err = -ENOENT;
|
||||
} else {
|
||||
ihold(inode);
|
||||
err = vfs_unlink(d_inode(dentry->d_parent), dentry, NULL);
|
||||
err = vfs_unlink2(mnt, d_inode(dentry->d_parent), dentry, NULL);
|
||||
}
|
||||
dput(dentry);
|
||||
|
||||
|
@ -122,7 +122,7 @@ static struct dentry *securityfs_create_dentry(const char *name, umode_t mode,
|
||||
dir = d_inode(parent);
|
||||
|
||||
inode_lock(dir);
|
||||
dentry = lookup_one_len(name, parent, strlen(name));
|
||||
dentry = lookup_one_len2(name, mount, parent, strlen(name));
|
||||
if (IS_ERR(dentry))
|
||||
goto out;
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user