mirror of
https://github.com/followmsi/android_kernel_google_msm.git
synced 2024-11-06 23:17:41 +00:00
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
2686aceaa7
commit
19a3f7c232
10 changed files with 159 additions and 71 deletions
|
@ -1147,7 +1147,7 @@ EXPORT_SYMBOL(flush_old_exec);
|
||||||
|
|
||||||
void would_dump(struct linux_binprm *bprm, struct file *file)
|
void would_dump(struct linux_binprm *bprm, struct file *file)
|
||||||
{
|
{
|
||||||
if (inode_permission(file->f_path.dentry->d_inode, MAY_READ) < 0)
|
if (inode_permission2(file->f_path.mnt, file->f_path.dentry->d_inode, MAY_READ) < 0)
|
||||||
bprm->interp_flags |= BINPRM_FLAGS_ENFORCE_NONDUMP;
|
bprm->interp_flags |= BINPRM_FLAGS_ENFORCE_NONDUMP;
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL(would_dump);
|
EXPORT_SYMBOL(would_dump);
|
||||||
|
|
183
fs/namei.c
183
fs/namei.c
|
@ -313,9 +313,11 @@ int generic_permission(struct inode *inode, int mask)
|
||||||
* flag in inode->i_opflags, that says "this has not special
|
* flag in inode->i_opflags, that says "this has not special
|
||||||
* permission function, use the fast case".
|
* 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 (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))
|
if (likely(inode->i_op->permission))
|
||||||
return inode->i_op->permission(inode, mask);
|
return inode->i_op->permission(inode, mask);
|
||||||
|
|
||||||
|
@ -339,7 +341,7 @@ static inline int do_inode_permission(struct inode *inode, int mask)
|
||||||
*
|
*
|
||||||
* When checking for MAY_APPEND, MAY_WRITE must also be set in @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;
|
int retval;
|
||||||
|
|
||||||
|
@ -360,7 +362,7 @@ int inode_permission(struct inode *inode, int mask)
|
||||||
return -EACCES;
|
return -EACCES;
|
||||||
}
|
}
|
||||||
|
|
||||||
retval = do_inode_permission(inode, mask);
|
retval = do_inode_permission(mnt, inode, mask);
|
||||||
if (retval)
|
if (retval)
|
||||||
return retval;
|
return retval;
|
||||||
|
|
||||||
|
@ -370,6 +372,13 @@ int inode_permission(struct inode *inode, int mask)
|
||||||
|
|
||||||
return security_inode_permission(inode, mask);
|
return security_inode_permission(inode, mask);
|
||||||
}
|
}
|
||||||
|
EXPORT_SYMBOL(inode_permission2);
|
||||||
|
|
||||||
|
int inode_permission(struct inode *inode, int mask)
|
||||||
|
{
|
||||||
|
return inode_permission2(NULL, inode, mask);
|
||||||
|
}
|
||||||
|
EXPORT_SYMBOL(inode_permission);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* path_get - get a reference to a path
|
* path_get - get a reference to a path
|
||||||
|
@ -1245,13 +1254,13 @@ need_lookup:
|
||||||
static inline int may_lookup(struct nameidata *nd)
|
static inline int may_lookup(struct nameidata *nd)
|
||||||
{
|
{
|
||||||
if (nd->flags & LOOKUP_RCU) {
|
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)
|
if (err != -ECHILD)
|
||||||
return err;
|
return err;
|
||||||
if (unlazy_walk(nd, NULL))
|
if (unlazy_walk(nd, NULL))
|
||||||
return -ECHILD;
|
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)
|
static inline int handle_dots(struct nameidata *nd, int type)
|
||||||
|
@ -1618,10 +1627,11 @@ static int path_init(int dfd, const char *name, unsigned int flags,
|
||||||
nd->depth = 0;
|
nd->depth = 0;
|
||||||
if (flags & LOOKUP_ROOT) {
|
if (flags & LOOKUP_ROOT) {
|
||||||
struct inode *inode = nd->root.dentry->d_inode;
|
struct inode *inode = nd->root.dentry->d_inode;
|
||||||
|
struct vfsmount *mnt = nd->root.mnt;
|
||||||
if (*name) {
|
if (*name) {
|
||||||
if (!inode->i_op->lookup)
|
if (!inode->i_op->lookup)
|
||||||
return -ENOTDIR;
|
return -ENOTDIR;
|
||||||
retval = inode_permission(inode, MAY_EXEC);
|
retval = inode_permission2(mnt, inode, MAY_EXEC);
|
||||||
if (retval)
|
if (retval)
|
||||||
return retval;
|
return retval;
|
||||||
}
|
}
|
||||||
|
@ -1667,6 +1677,7 @@ static int path_init(int dfd, const char *name, unsigned int flags,
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
struct dentry *dentry;
|
struct dentry *dentry;
|
||||||
|
struct vfsmount *mnt;
|
||||||
|
|
||||||
file = fget_raw_light(dfd, &fput_needed);
|
file = fget_raw_light(dfd, &fput_needed);
|
||||||
retval = -EBADF;
|
retval = -EBADF;
|
||||||
|
@ -1674,13 +1685,14 @@ static int path_init(int dfd, const char *name, unsigned int flags,
|
||||||
goto out_fail;
|
goto out_fail;
|
||||||
|
|
||||||
dentry = file->f_path.dentry;
|
dentry = file->f_path.dentry;
|
||||||
|
mnt = file->f_path.mnt;
|
||||||
|
|
||||||
if (*name) {
|
if (*name) {
|
||||||
retval = -ENOTDIR;
|
retval = -ENOTDIR;
|
||||||
if (!S_ISDIR(dentry->d_inode->i_mode))
|
if (!S_ISDIR(dentry->d_inode->i_mode))
|
||||||
goto fput_fail;
|
goto fput_fail;
|
||||||
|
|
||||||
retval = inode_permission(dentry->d_inode, MAY_EXEC);
|
retval = inode_permission2(mnt, dentry->d_inode, MAY_EXEC);
|
||||||
if (retval)
|
if (retval)
|
||||||
goto fput_fail;
|
goto fput_fail;
|
||||||
}
|
}
|
||||||
|
@ -1877,6 +1889,7 @@ static struct dentry *lookup_hash(struct nameidata *nd)
|
||||||
/**
|
/**
|
||||||
* lookup_one_len - filesystem helper to lookup single pathname component
|
* lookup_one_len - filesystem helper to lookup single pathname component
|
||||||
* @name: pathname component to lookup
|
* @name: pathname component to lookup
|
||||||
|
* @mnt: mount we are looking up on
|
||||||
* @base: base directory to lookup from
|
* @base: base directory to lookup from
|
||||||
* @len: maximum length @len should be interpreted to
|
* @len: maximum length @len should be interpreted to
|
||||||
*
|
*
|
||||||
|
@ -1885,7 +1898,7 @@ static struct dentry *lookup_hash(struct nameidata *nd)
|
||||||
* nameidata argument is passed to the filesystem methods and a filesystem
|
* nameidata argument is passed to the filesystem methods and a filesystem
|
||||||
* using this helper needs to be prepared for that.
|
* using this helper needs to be prepared for that.
|
||||||
*/
|
*/
|
||||||
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;
|
struct qstr this;
|
||||||
unsigned int c;
|
unsigned int c;
|
||||||
|
@ -1914,12 +1927,19 @@ struct dentry *lookup_one_len(const char *name, struct dentry *base, int len)
|
||||||
return ERR_PTR(err);
|
return ERR_PTR(err);
|
||||||
}
|
}
|
||||||
|
|
||||||
err = inode_permission(base->d_inode, MAY_EXEC);
|
err = inode_permission2(mnt, base->d_inode, MAY_EXEC);
|
||||||
if (err)
|
if (err)
|
||||||
return ERR_PTR(err);
|
return ERR_PTR(err);
|
||||||
|
|
||||||
return __lookup_hash(&this, base, NULL);
|
return __lookup_hash(&this, base, NULL);
|
||||||
}
|
}
|
||||||
|
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);
|
||||||
|
|
||||||
int user_path_at_empty(int dfd, const char __user *name, unsigned flags,
|
int user_path_at_empty(int dfd, const char __user *name, unsigned flags,
|
||||||
struct path *path, int *empty)
|
struct path *path, int *empty)
|
||||||
|
@ -2003,7 +2023,7 @@ other_userns:
|
||||||
* 10. We don't allow removal of NFS sillyrenamed files; it's handled by
|
* 10. We don't allow removal of NFS sillyrenamed files; it's handled by
|
||||||
* nfs_async_unlink().
|
* nfs_async_unlink().
|
||||||
*/
|
*/
|
||||||
static int may_delete(struct inode *dir,struct dentry *victim,int isdir)
|
static int may_delete(struct vfsmount *mnt, struct inode *dir,struct dentry *victim,int isdir)
|
||||||
{
|
{
|
||||||
int error;
|
int error;
|
||||||
|
|
||||||
|
@ -2013,7 +2033,7 @@ static int may_delete(struct inode *dir,struct dentry *victim,int isdir)
|
||||||
BUG_ON(victim->d_parent->d_inode != dir);
|
BUG_ON(victim->d_parent->d_inode != dir);
|
||||||
audit_inode_child(victim, dir);
|
audit_inode_child(victim, dir);
|
||||||
|
|
||||||
error = inode_permission(dir, MAY_WRITE | MAY_EXEC);
|
error = inode_permission2(mnt, dir, MAY_WRITE | MAY_EXEC);
|
||||||
if (error)
|
if (error)
|
||||||
return error;
|
return error;
|
||||||
if (IS_APPEND(dir))
|
if (IS_APPEND(dir))
|
||||||
|
@ -2043,13 +2063,13 @@ static int may_delete(struct inode *dir,struct dentry *victim,int isdir)
|
||||||
* 3. We should have write and exec permissions on dir
|
* 3. We should have write and exec permissions on dir
|
||||||
* 4. We can't do it if dir is immutable (done in permission())
|
* 4. 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)
|
||||||
{
|
{
|
||||||
if (child->d_inode)
|
if (child->d_inode)
|
||||||
return -EEXIST;
|
return -EEXIST;
|
||||||
if (IS_DEADDIR(dir))
|
if (IS_DEADDIR(dir))
|
||||||
return -ENOENT;
|
return -ENOENT;
|
||||||
return inode_permission(dir, MAY_WRITE | MAY_EXEC);
|
return inode_permission2(mnt, dir, MAY_WRITE | MAY_EXEC);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -2094,10 +2114,10 @@ void unlock_rename(struct dentry *p1, struct dentry *p2)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
int vfs_create(struct inode *dir, struct dentry *dentry, umode_t mode,
|
int vfs_create2(struct vfsmount *mnt, struct inode *dir, struct dentry *dentry,
|
||||||
struct nameidata *nd)
|
umode_t mode, struct nameidata *nd)
|
||||||
{
|
{
|
||||||
int error = may_create(dir, dentry);
|
int error = may_create(mnt, dir, dentry);
|
||||||
|
|
||||||
if (error)
|
if (error)
|
||||||
return error;
|
return error;
|
||||||
|
@ -2114,10 +2134,19 @@ int vfs_create(struct inode *dir, struct dentry *dentry, umode_t mode,
|
||||||
fsnotify_create(dir, dentry);
|
fsnotify_create(dir, dentry);
|
||||||
return error;
|
return error;
|
||||||
}
|
}
|
||||||
|
EXPORT_SYMBOL(vfs_create2);
|
||||||
|
|
||||||
|
int vfs_create(struct inode *dir, struct dentry *dentry, umode_t mode,
|
||||||
|
struct nameidata *nd)
|
||||||
|
{
|
||||||
|
return vfs_create2(NULL, dir, dentry, mode, nd);
|
||||||
|
}
|
||||||
|
EXPORT_SYMBOL(vfs_create);
|
||||||
|
|
||||||
static int may_open(struct path *path, int acc_mode, int flag)
|
static int may_open(struct path *path, int acc_mode, int flag)
|
||||||
{
|
{
|
||||||
struct dentry *dentry = path->dentry;
|
struct dentry *dentry = path->dentry;
|
||||||
|
struct vfsmount *mnt = path->mnt;
|
||||||
struct inode *inode = dentry->d_inode;
|
struct inode *inode = dentry->d_inode;
|
||||||
int error;
|
int error;
|
||||||
|
|
||||||
|
@ -2146,7 +2175,7 @@ static int may_open(struct path *path, int acc_mode, int flag)
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
error = inode_permission(inode, acc_mode);
|
error = inode_permission2(mnt, inode, acc_mode);
|
||||||
if (error)
|
if (error)
|
||||||
return error;
|
return error;
|
||||||
|
|
||||||
|
@ -2316,7 +2345,7 @@ static struct file *do_last(struct nameidata *nd, struct path *path,
|
||||||
error = security_path_mknod(&nd->path, dentry, mode, 0);
|
error = security_path_mknod(&nd->path, dentry, mode, 0);
|
||||||
if (error)
|
if (error)
|
||||||
goto exit_mutex_unlock;
|
goto exit_mutex_unlock;
|
||||||
error = vfs_create(dir->d_inode, dentry, mode, nd);
|
error = vfs_create2(path->mnt, dir->d_inode, dentry, mode, nd);
|
||||||
if (error)
|
if (error)
|
||||||
goto exit_mutex_unlock;
|
goto exit_mutex_unlock;
|
||||||
mutex_unlock(&dir->d_inode->i_mutex);
|
mutex_unlock(&dir->d_inode->i_mutex);
|
||||||
|
@ -2562,9 +2591,9 @@ struct dentry *user_path_create(int dfd, const char __user *pathname, struct pat
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL(user_path_create);
|
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)
|
if (error)
|
||||||
return error;
|
return error;
|
||||||
|
@ -2589,6 +2618,13 @@ int vfs_mknod(struct inode *dir, struct dentry *dentry, umode_t mode, dev_t dev)
|
||||||
fsnotify_create(dir, dentry);
|
fsnotify_create(dir, dentry);
|
||||||
return error;
|
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)
|
static int may_mknod(umode_t mode)
|
||||||
{
|
{
|
||||||
|
@ -2634,10 +2670,10 @@ SYSCALL_DEFINE4(mknodat, int, dfd, const char __user *, filename, umode_t, mode,
|
||||||
goto out_drop_write;
|
goto out_drop_write;
|
||||||
switch (mode & S_IFMT) {
|
switch (mode & S_IFMT) {
|
||||||
case 0: case S_IFREG:
|
case 0: case S_IFREG:
|
||||||
error = vfs_create(path.dentry->d_inode,dentry,mode,NULL);
|
error = vfs_create2(path.mnt, path.dentry->d_inode,dentry,mode,NULL);
|
||||||
break;
|
break;
|
||||||
case S_IFCHR: case S_IFBLK:
|
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));
|
new_decode_dev(dev));
|
||||||
break;
|
break;
|
||||||
case S_IFIFO: case S_IFSOCK:
|
case S_IFIFO: case S_IFSOCK:
|
||||||
|
@ -2659,9 +2695,9 @@ SYSCALL_DEFINE3(mknod, const char __user *, filename, umode_t, mode, unsigned, d
|
||||||
return sys_mknodat(AT_FDCWD, filename, mode, dev);
|
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;
|
unsigned max_links = dir->i_sb->s_max_links;
|
||||||
|
|
||||||
if (error)
|
if (error)
|
||||||
|
@ -2683,6 +2719,13 @@ int vfs_mkdir(struct inode *dir, struct dentry *dentry, umode_t mode)
|
||||||
fsnotify_mkdir(dir, dentry);
|
fsnotify_mkdir(dir, dentry);
|
||||||
return error;
|
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)
|
SYSCALL_DEFINE3(mkdirat, int, dfd, const char __user *, pathname, umode_t, mode)
|
||||||
{
|
{
|
||||||
|
@ -2702,7 +2745,7 @@ SYSCALL_DEFINE3(mkdirat, int, dfd, const char __user *, pathname, umode_t, mode)
|
||||||
error = security_path_mkdir(&path, dentry, mode);
|
error = security_path_mkdir(&path, dentry, mode);
|
||||||
if (error)
|
if (error)
|
||||||
goto out_drop_write;
|
goto out_drop_write;
|
||||||
error = vfs_mkdir(path.dentry->d_inode, dentry, mode);
|
error = vfs_mkdir2(path.mnt, path.dentry->d_inode, dentry, mode);
|
||||||
out_drop_write:
|
out_drop_write:
|
||||||
mnt_drop_write(path.mnt);
|
mnt_drop_write(path.mnt);
|
||||||
out_dput:
|
out_dput:
|
||||||
|
@ -2741,9 +2784,9 @@ void dentry_unhash(struct dentry *dentry)
|
||||||
spin_unlock(&dentry->d_lock);
|
spin_unlock(&dentry->d_lock);
|
||||||
}
|
}
|
||||||
|
|
||||||
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)
|
if (error)
|
||||||
return error;
|
return error;
|
||||||
|
@ -2777,6 +2820,13 @@ out:
|
||||||
d_delete(dentry);
|
d_delete(dentry);
|
||||||
return error;
|
return error;
|
||||||
}
|
}
|
||||||
|
EXPORT_SYMBOL(vfs_rmdir2);
|
||||||
|
|
||||||
|
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)
|
static long do_rmdir(int dfd, const char __user *pathname)
|
||||||
{
|
{
|
||||||
|
@ -2818,7 +2868,7 @@ static long do_rmdir(int dfd, const char __user *pathname)
|
||||||
error = security_path_rmdir(&nd.path, dentry);
|
error = security_path_rmdir(&nd.path, dentry);
|
||||||
if (error)
|
if (error)
|
||||||
goto exit4;
|
goto exit4;
|
||||||
error = vfs_rmdir(nd.path.dentry->d_inode, dentry);
|
error = vfs_rmdir2(nd.path.mnt, nd.path.dentry->d_inode, dentry);
|
||||||
exit4:
|
exit4:
|
||||||
mnt_drop_write(nd.path.mnt);
|
mnt_drop_write(nd.path.mnt);
|
||||||
exit3:
|
exit3:
|
||||||
|
@ -2836,9 +2886,9 @@ SYSCALL_DEFINE1(rmdir, const char __user *, pathname)
|
||||||
return do_rmdir(AT_FDCWD, pathname);
|
return do_rmdir(AT_FDCWD, pathname);
|
||||||
}
|
}
|
||||||
|
|
||||||
int vfs_unlink(struct inode *dir, struct dentry *dentry)
|
int vfs_unlink2(struct vfsmount *mnt, struct inode *dir, struct dentry *dentry)
|
||||||
{
|
{
|
||||||
int error = may_delete(dir, dentry, 0);
|
int error = may_delete(mnt, dir, dentry, 0);
|
||||||
|
|
||||||
if (error)
|
if (error)
|
||||||
return error;
|
return error;
|
||||||
|
@ -2867,6 +2917,13 @@ int vfs_unlink(struct inode *dir, struct dentry *dentry)
|
||||||
|
|
||||||
return error;
|
return error;
|
||||||
}
|
}
|
||||||
|
EXPORT_SYMBOL(vfs_unlink2);
|
||||||
|
|
||||||
|
int vfs_unlink(struct inode *dir, struct dentry *dentry)
|
||||||
|
{
|
||||||
|
return vfs_unlink2(NULL, dir, dentry);
|
||||||
|
}
|
||||||
|
EXPORT_SYMBOL(vfs_unlink);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Make sure that the actual truncation of the file will occur outside its
|
* Make sure that the actual truncation of the file will occur outside its
|
||||||
|
@ -2909,7 +2966,7 @@ static long do_unlinkat(int dfd, const char __user *pathname)
|
||||||
error = security_path_unlink(&nd.path, dentry);
|
error = security_path_unlink(&nd.path, dentry);
|
||||||
if (error)
|
if (error)
|
||||||
goto exit3;
|
goto exit3;
|
||||||
error = vfs_unlink(nd.path.dentry->d_inode, dentry);
|
error = vfs_unlink2(nd.path.mnt, nd.path.dentry->d_inode, dentry);
|
||||||
exit3:
|
exit3:
|
||||||
mnt_drop_write(nd.path.mnt);
|
mnt_drop_write(nd.path.mnt);
|
||||||
exit2:
|
exit2:
|
||||||
|
@ -2945,9 +3002,9 @@ SYSCALL_DEFINE1(unlink, const char __user *, pathname)
|
||||||
return do_unlinkat(AT_FDCWD, 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)
|
if (error)
|
||||||
return error;
|
return error;
|
||||||
|
@ -2964,6 +3021,13 @@ int vfs_symlink(struct inode *dir, struct dentry *dentry, const char *oldname)
|
||||||
fsnotify_create(dir, dentry);
|
fsnotify_create(dir, dentry);
|
||||||
return error;
|
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,
|
SYSCALL_DEFINE3(symlinkat, const char __user *, oldname,
|
||||||
int, newdfd, const char __user *, newname)
|
int, newdfd, const char __user *, newname)
|
||||||
|
@ -2988,7 +3052,7 @@ SYSCALL_DEFINE3(symlinkat, const char __user *, oldname,
|
||||||
error = security_path_symlink(&path, dentry, from);
|
error = security_path_symlink(&path, dentry, from);
|
||||||
if (error)
|
if (error)
|
||||||
goto out_drop_write;
|
goto out_drop_write;
|
||||||
error = vfs_symlink(path.dentry->d_inode, dentry, from);
|
error = vfs_symlink2(path.mnt, path.dentry->d_inode, dentry, from);
|
||||||
out_drop_write:
|
out_drop_write:
|
||||||
mnt_drop_write(path.mnt);
|
mnt_drop_write(path.mnt);
|
||||||
out_dput:
|
out_dput:
|
||||||
|
@ -3005,7 +3069,7 @@ SYSCALL_DEFINE2(symlink, const char __user *, oldname, const char __user *, newn
|
||||||
return sys_symlinkat(oldname, AT_FDCWD, newname);
|
return sys_symlinkat(oldname, AT_FDCWD, newname);
|
||||||
}
|
}
|
||||||
|
|
||||||
int vfs_link(struct dentry *old_dentry, struct inode *dir, struct dentry *new_dentry)
|
int vfs_link2(struct vfsmount *mnt, struct dentry *old_dentry, struct inode *dir, struct dentry *new_dentry)
|
||||||
{
|
{
|
||||||
struct inode *inode = old_dentry->d_inode;
|
struct inode *inode = old_dentry->d_inode;
|
||||||
unsigned max_links = dir->i_sb->s_max_links;
|
unsigned max_links = dir->i_sb->s_max_links;
|
||||||
|
@ -3014,7 +3078,7 @@ int vfs_link(struct dentry *old_dentry, struct inode *dir, struct dentry *new_de
|
||||||
if (!inode)
|
if (!inode)
|
||||||
return -ENOENT;
|
return -ENOENT;
|
||||||
|
|
||||||
error = may_create(dir, new_dentry);
|
error = may_create(mnt, dir, new_dentry);
|
||||||
if (error)
|
if (error)
|
||||||
return error;
|
return error;
|
||||||
|
|
||||||
|
@ -3048,6 +3112,13 @@ int vfs_link(struct dentry *old_dentry, struct inode *dir, struct dentry *new_de
|
||||||
fsnotify_link(dir, inode, new_dentry);
|
fsnotify_link(dir, inode, new_dentry);
|
||||||
return error;
|
return error;
|
||||||
}
|
}
|
||||||
|
EXPORT_SYMBOL(vfs_link2);
|
||||||
|
|
||||||
|
int vfs_link(struct dentry *old_dentry, struct inode *dir, struct dentry *new_dentry)
|
||||||
|
{
|
||||||
|
return vfs_link2(NULL, old_dentry, dir, new_dentry);
|
||||||
|
}
|
||||||
|
EXPORT_SYMBOL(vfs_link);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Hardlinks are often used in delicate situations. We avoid
|
* Hardlinks are often used in delicate situations. We avoid
|
||||||
|
@ -3100,7 +3171,7 @@ SYSCALL_DEFINE5(linkat, int, olddfd, const char __user *, oldname,
|
||||||
error = security_path_link(old_path.dentry, &new_path, new_dentry);
|
error = security_path_link(old_path.dentry, &new_path, new_dentry);
|
||||||
if (error)
|
if (error)
|
||||||
goto out_drop_write;
|
goto out_drop_write;
|
||||||
error = vfs_link(old_path.dentry, new_path.dentry->d_inode, new_dentry);
|
error = vfs_link2(old_path.mnt, old_path.dentry, new_path.dentry->d_inode, new_dentry);
|
||||||
out_drop_write:
|
out_drop_write:
|
||||||
mnt_drop_write(new_path.mnt);
|
mnt_drop_write(new_path.mnt);
|
||||||
out_dput:
|
out_dput:
|
||||||
|
@ -3145,8 +3216,9 @@ SYSCALL_DEFINE2(link, const char __user *, oldname, const char __user *, newname
|
||||||
* ->i_mutex on parents, which works but leads to some truly excessive
|
* ->i_mutex on parents, which works but leads to some truly excessive
|
||||||
* locking].
|
* locking].
|
||||||
*/
|
*/
|
||||||
static int vfs_rename_dir(struct inode *old_dir, struct dentry *old_dentry,
|
static int vfs_rename_dir(struct vfsmount *mnt,
|
||||||
struct inode *new_dir, struct dentry *new_dentry)
|
struct inode *old_dir, struct dentry *old_dentry,
|
||||||
|
struct inode *new_dir, struct dentry *new_dentry)
|
||||||
{
|
{
|
||||||
int error = 0;
|
int error = 0;
|
||||||
struct inode *target = new_dentry->d_inode;
|
struct inode *target = new_dentry->d_inode;
|
||||||
|
@ -3157,7 +3229,7 @@ static int vfs_rename_dir(struct inode *old_dir, struct dentry *old_dentry,
|
||||||
* we'll need to flip '..'.
|
* we'll need to flip '..'.
|
||||||
*/
|
*/
|
||||||
if (new_dir != old_dir) {
|
if (new_dir != old_dir) {
|
||||||
error = inode_permission(old_dentry->d_inode, MAY_WRITE);
|
error = inode_permission2(mnt, old_dentry->d_inode, MAY_WRITE);
|
||||||
if (error)
|
if (error)
|
||||||
return error;
|
return error;
|
||||||
}
|
}
|
||||||
|
@ -3232,7 +3304,8 @@ out:
|
||||||
return error;
|
return error;
|
||||||
}
|
}
|
||||||
|
|
||||||
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 *new_dir, struct dentry *new_dentry)
|
||||||
{
|
{
|
||||||
int error;
|
int error;
|
||||||
|
@ -3242,14 +3315,14 @@ int vfs_rename(struct inode *old_dir, struct dentry *old_dentry,
|
||||||
if (old_dentry->d_inode == new_dentry->d_inode)
|
if (old_dentry->d_inode == new_dentry->d_inode)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
error = may_delete(old_dir, old_dentry, is_dir);
|
error = may_delete(mnt, old_dir, old_dentry, is_dir);
|
||||||
if (error)
|
if (error)
|
||||||
return error;
|
return error;
|
||||||
|
|
||||||
if (!new_dentry->d_inode)
|
if (!new_dentry->d_inode)
|
||||||
error = may_create(new_dir, new_dentry);
|
error = may_create(mnt, new_dir, new_dentry);
|
||||||
else
|
else
|
||||||
error = may_delete(new_dir, new_dentry, is_dir);
|
error = may_delete(mnt, new_dir, new_dentry, is_dir);
|
||||||
if (error)
|
if (error)
|
||||||
return error;
|
return error;
|
||||||
|
|
||||||
|
@ -3259,7 +3332,7 @@ int vfs_rename(struct inode *old_dir, struct dentry *old_dentry,
|
||||||
old_name = fsnotify_oldname_init(old_dentry->d_name.name);
|
old_name = fsnotify_oldname_init(old_dentry->d_name.name);
|
||||||
|
|
||||||
if (is_dir)
|
if (is_dir)
|
||||||
error = vfs_rename_dir(old_dir,old_dentry,new_dir,new_dentry);
|
error = vfs_rename_dir(mnt, old_dir,old_dentry,new_dir,new_dentry);
|
||||||
else
|
else
|
||||||
error = vfs_rename_other(old_dir,old_dentry,new_dir,new_dentry);
|
error = vfs_rename_other(old_dir,old_dentry,new_dir,new_dentry);
|
||||||
if (!error)
|
if (!error)
|
||||||
|
@ -3269,6 +3342,14 @@ int vfs_rename(struct inode *old_dir, struct dentry *old_dentry,
|
||||||
|
|
||||||
return error;
|
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)
|
||||||
|
{
|
||||||
|
return vfs_rename2(NULL, old_dir, old_dentry, new_dir, new_dentry);
|
||||||
|
}
|
||||||
|
EXPORT_SYMBOL(vfs_rename);
|
||||||
|
|
||||||
SYSCALL_DEFINE4(renameat, int, olddfd, const char __user *, oldname,
|
SYSCALL_DEFINE4(renameat, int, olddfd, const char __user *, oldname,
|
||||||
int, newdfd, const char __user *, newname)
|
int, newdfd, const char __user *, newname)
|
||||||
|
@ -3344,7 +3425,7 @@ SYSCALL_DEFINE4(renameat, int, olddfd, const char __user *, oldname,
|
||||||
&newnd.path, new_dentry);
|
&newnd.path, new_dentry);
|
||||||
if (error)
|
if (error)
|
||||||
goto exit6;
|
goto exit6;
|
||||||
error = vfs_rename(old_dir->d_inode, old_dentry,
|
error = vfs_rename2(oldnd.path.mnt, old_dir->d_inode, old_dentry,
|
||||||
new_dir->d_inode, new_dentry);
|
new_dir->d_inode, new_dentry);
|
||||||
exit6:
|
exit6:
|
||||||
mnt_drop_write(oldnd.path.mnt);
|
mnt_drop_write(oldnd.path.mnt);
|
||||||
|
@ -3513,7 +3594,6 @@ EXPORT_SYMBOL(follow_up);
|
||||||
EXPORT_SYMBOL(get_write_access); /* binfmt_aout */
|
EXPORT_SYMBOL(get_write_access); /* binfmt_aout */
|
||||||
EXPORT_SYMBOL(getname);
|
EXPORT_SYMBOL(getname);
|
||||||
EXPORT_SYMBOL(lock_rename);
|
EXPORT_SYMBOL(lock_rename);
|
||||||
EXPORT_SYMBOL(lookup_one_len);
|
|
||||||
EXPORT_SYMBOL(page_follow_link_light);
|
EXPORT_SYMBOL(page_follow_link_light);
|
||||||
EXPORT_SYMBOL(page_put_link);
|
EXPORT_SYMBOL(page_put_link);
|
||||||
EXPORT_SYMBOL(page_readlink);
|
EXPORT_SYMBOL(page_readlink);
|
||||||
|
@ -3522,18 +3602,9 @@ EXPORT_SYMBOL(page_symlink);
|
||||||
EXPORT_SYMBOL(page_symlink_inode_operations);
|
EXPORT_SYMBOL(page_symlink_inode_operations);
|
||||||
EXPORT_SYMBOL(kern_path);
|
EXPORT_SYMBOL(kern_path);
|
||||||
EXPORT_SYMBOL(vfs_path_lookup);
|
EXPORT_SYMBOL(vfs_path_lookup);
|
||||||
EXPORT_SYMBOL(inode_permission);
|
|
||||||
EXPORT_SYMBOL(unlock_rename);
|
EXPORT_SYMBOL(unlock_rename);
|
||||||
EXPORT_SYMBOL(vfs_create);
|
|
||||||
EXPORT_SYMBOL(vfs_follow_link);
|
EXPORT_SYMBOL(vfs_follow_link);
|
||||||
EXPORT_SYMBOL(vfs_link);
|
|
||||||
EXPORT_SYMBOL(vfs_mkdir);
|
|
||||||
EXPORT_SYMBOL(vfs_mknod);
|
|
||||||
EXPORT_SYMBOL(generic_permission);
|
EXPORT_SYMBOL(generic_permission);
|
||||||
EXPORT_SYMBOL(vfs_readlink);
|
EXPORT_SYMBOL(vfs_readlink);
|
||||||
EXPORT_SYMBOL(vfs_rename);
|
|
||||||
EXPORT_SYMBOL(vfs_rmdir);
|
|
||||||
EXPORT_SYMBOL(vfs_symlink);
|
|
||||||
EXPORT_SYMBOL(vfs_unlink);
|
|
||||||
EXPORT_SYMBOL(dentry_unhash);
|
EXPORT_SYMBOL(dentry_unhash);
|
||||||
EXPORT_SYMBOL(generic_readlink);
|
EXPORT_SYMBOL(generic_readlink);
|
||||||
|
|
|
@ -506,7 +506,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 */
|
/* 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)
|
if (ret)
|
||||||
path_put(path);
|
path_put(path);
|
||||||
out:
|
out:
|
||||||
|
|
|
@ -356,7 +356,7 @@ static int inotify_find_inode(const char __user *dirname, struct path *path, uns
|
||||||
if (error)
|
if (error)
|
||||||
return error;
|
return error;
|
||||||
/* you can only watch an inode if you have read permissions on it */
|
/* 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)
|
if (error)
|
||||||
path_put(path);
|
path_put(path);
|
||||||
return error;
|
return error;
|
||||||
|
|
16
fs/open.c
16
fs/open.c
|
@ -65,6 +65,7 @@ static long do_sys_truncate(const char __user *pathname, loff_t length)
|
||||||
{
|
{
|
||||||
struct path path;
|
struct path path;
|
||||||
struct inode *inode;
|
struct inode *inode;
|
||||||
|
struct vfsmount *mnt;
|
||||||
int error;
|
int error;
|
||||||
|
|
||||||
error = -EINVAL;
|
error = -EINVAL;
|
||||||
|
@ -75,6 +76,7 @@ static long do_sys_truncate(const char __user *pathname, loff_t length)
|
||||||
if (error)
|
if (error)
|
||||||
goto out;
|
goto out;
|
||||||
inode = path.dentry->d_inode;
|
inode = path.dentry->d_inode;
|
||||||
|
mnt = path.mnt;
|
||||||
|
|
||||||
/* For directories it's -EISDIR, for other non-regulars - -EINVAL */
|
/* For directories it's -EISDIR, for other non-regulars - -EINVAL */
|
||||||
error = -EISDIR;
|
error = -EISDIR;
|
||||||
|
@ -89,7 +91,7 @@ static long do_sys_truncate(const char __user *pathname, loff_t length)
|
||||||
if (error)
|
if (error)
|
||||||
goto dput_and_out;
|
goto dput_and_out;
|
||||||
|
|
||||||
error = inode_permission(inode, MAY_WRITE);
|
error = inode_permission2(mnt, inode, MAY_WRITE);
|
||||||
if (error)
|
if (error)
|
||||||
goto mnt_drop_write_and_out;
|
goto mnt_drop_write_and_out;
|
||||||
|
|
||||||
|
@ -302,6 +304,7 @@ SYSCALL_DEFINE3(faccessat, int, dfd, const char __user *, filename, int, mode)
|
||||||
struct cred *override_cred;
|
struct cred *override_cred;
|
||||||
struct path path;
|
struct path path;
|
||||||
struct inode *inode;
|
struct inode *inode;
|
||||||
|
struct vfsmount *mnt;
|
||||||
int res;
|
int res;
|
||||||
|
|
||||||
if (mode & ~S_IRWXO) /* where's F_OK, X_OK, W_OK, R_OK? */
|
if (mode & ~S_IRWXO) /* where's F_OK, X_OK, W_OK, R_OK? */
|
||||||
|
@ -330,6 +333,7 @@ SYSCALL_DEFINE3(faccessat, int, dfd, const char __user *, filename, int, mode)
|
||||||
goto out;
|
goto out;
|
||||||
|
|
||||||
inode = path.dentry->d_inode;
|
inode = path.dentry->d_inode;
|
||||||
|
mnt = path.mnt;
|
||||||
|
|
||||||
if ((mode & MAY_EXEC) && S_ISREG(inode->i_mode)) {
|
if ((mode & MAY_EXEC) && S_ISREG(inode->i_mode)) {
|
||||||
/*
|
/*
|
||||||
|
@ -341,7 +345,7 @@ SYSCALL_DEFINE3(faccessat, int, dfd, const char __user *, filename, int, mode)
|
||||||
goto out_path_release;
|
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 */
|
/* SuS v2 requires we report a read only fs too */
|
||||||
if (res || !(mode & S_IWOTH) || special_file(inode->i_mode))
|
if (res || !(mode & S_IWOTH) || special_file(inode->i_mode))
|
||||||
goto out_path_release;
|
goto out_path_release;
|
||||||
|
@ -380,7 +384,7 @@ SYSCALL_DEFINE1(chdir, const char __user *, filename)
|
||||||
if (error)
|
if (error)
|
||||||
goto out;
|
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)
|
if (error)
|
||||||
goto dput_and_out;
|
goto dput_and_out;
|
||||||
|
|
||||||
|
@ -396,6 +400,7 @@ SYSCALL_DEFINE1(fchdir, unsigned int, fd)
|
||||||
{
|
{
|
||||||
struct file *file;
|
struct file *file;
|
||||||
struct inode *inode;
|
struct inode *inode;
|
||||||
|
struct vfsmount *mnt;
|
||||||
int error;
|
int error;
|
||||||
|
|
||||||
error = -EBADF;
|
error = -EBADF;
|
||||||
|
@ -404,12 +409,13 @@ SYSCALL_DEFINE1(fchdir, unsigned int, fd)
|
||||||
goto out;
|
goto out;
|
||||||
|
|
||||||
inode = file->f_path.dentry->d_inode;
|
inode = file->f_path.dentry->d_inode;
|
||||||
|
mnt = file->f_path.mnt;
|
||||||
|
|
||||||
error = -ENOTDIR;
|
error = -ENOTDIR;
|
||||||
if (!S_ISDIR(inode->i_mode))
|
if (!S_ISDIR(inode->i_mode))
|
||||||
goto out_putf;
|
goto out_putf;
|
||||||
|
|
||||||
error = inode_permission(inode, MAY_EXEC | MAY_CHDIR);
|
error = inode_permission2(mnt, inode, MAY_EXEC | MAY_CHDIR);
|
||||||
if (!error)
|
if (!error)
|
||||||
set_fs_pwd(current->fs, &file->f_path);
|
set_fs_pwd(current->fs, &file->f_path);
|
||||||
out_putf:
|
out_putf:
|
||||||
|
@ -427,7 +433,7 @@ SYSCALL_DEFINE1(chroot, const char __user *, filename)
|
||||||
if (error)
|
if (error)
|
||||||
goto out;
|
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)
|
if (error)
|
||||||
goto dput_and_out;
|
goto dput_and_out;
|
||||||
|
|
||||||
|
|
|
@ -96,7 +96,7 @@ static int utimes_common(struct path *path, struct timespec *times)
|
||||||
goto mnt_drop_write_and_out;
|
goto mnt_drop_write_and_out;
|
||||||
|
|
||||||
if (!inode_owner_or_capable(inode)) {
|
if (!inode_owner_or_capable(inode)) {
|
||||||
error = inode_permission(inode, MAY_WRITE);
|
error = inode_permission2(path->mnt, inode, MAY_WRITE);
|
||||||
if (error)
|
if (error)
|
||||||
goto mnt_drop_write_and_out;
|
goto mnt_drop_write_and_out;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1577,13 +1577,20 @@ extern void unlock_super(struct super_block *);
|
||||||
* VFS helper functions..
|
* VFS helper functions..
|
||||||
*/
|
*/
|
||||||
extern int vfs_create(struct inode *, struct dentry *, umode_t, struct nameidata *);
|
extern int vfs_create(struct inode *, struct dentry *, umode_t, struct nameidata *);
|
||||||
|
extern int vfs_create2(struct vfsmount *, struct inode *, struct dentry *, umode_t, struct nameidata *);
|
||||||
extern int vfs_mkdir(struct inode *, struct dentry *, umode_t);
|
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_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_symlink(struct inode *, struct dentry *, const char *);
|
||||||
extern int vfs_link(struct dentry *, struct inode *, struct dentry *);
|
extern int vfs_link(struct dentry *, struct inode *, struct dentry *);
|
||||||
|
extern int vfs_link2(struct vfsmount *, struct dentry *, struct inode *, struct dentry *);
|
||||||
extern int vfs_rmdir(struct inode *, struct dentry *);
|
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 *);
|
extern int vfs_unlink(struct inode *, struct dentry *);
|
||||||
|
extern int vfs_unlink2(struct vfsmount *, struct inode *, struct dentry *);
|
||||||
extern int vfs_rename(struct inode *, struct dentry *, struct inode *, struct dentry *);
|
extern int vfs_rename(struct inode *, struct dentry *, struct inode *, struct dentry *);
|
||||||
|
extern int vfs_rename2(struct vfsmount *, struct inode *, struct dentry *, struct inode *, struct dentry *);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* VFS dentry helper functions.
|
* VFS dentry helper functions.
|
||||||
|
@ -1674,6 +1681,7 @@ struct inode_operations {
|
||||||
struct dentry * (*lookup) (struct inode *,struct dentry *, struct nameidata *);
|
struct dentry * (*lookup) (struct inode *,struct dentry *, struct nameidata *);
|
||||||
void * (*follow_link) (struct dentry *, struct nameidata *);
|
void * (*follow_link) (struct dentry *, struct nameidata *);
|
||||||
int (*permission) (struct inode *, int);
|
int (*permission) (struct inode *, int);
|
||||||
|
int (*permission2) (struct vfsmount *, struct inode *, int);
|
||||||
struct posix_acl * (*get_acl)(struct inode *, int);
|
struct posix_acl * (*get_acl)(struct inode *, int);
|
||||||
|
|
||||||
int (*readlink) (struct dentry *, char __user *,int);
|
int (*readlink) (struct dentry *, char __user *,int);
|
||||||
|
@ -2269,6 +2277,7 @@ extern sector_t bmap(struct inode *, sector_t);
|
||||||
#endif
|
#endif
|
||||||
extern int notify_change(struct dentry *, struct iattr *);
|
extern int notify_change(struct dentry *, struct iattr *);
|
||||||
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 generic_permission(struct inode *, int);
|
extern int generic_permission(struct inode *, int);
|
||||||
|
|
||||||
static inline bool execute_ok(struct inode *inode)
|
static inline bool execute_ok(struct inode *inode)
|
||||||
|
|
|
@ -86,6 +86,7 @@ extern struct file *lookup_instantiate_filp(struct nameidata *nd, struct dentry
|
||||||
int (*open)(struct inode *, struct file *));
|
int (*open)(struct inode *, struct file *));
|
||||||
|
|
||||||
extern struct dentry *lookup_one_len(const char *, struct dentry *, 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 int follow_down_one(struct path *);
|
extern int follow_down_one(struct path *);
|
||||||
extern int follow_down(struct path *);
|
extern int follow_down(struct path *);
|
||||||
|
|
11
ipc/mqueue.c
11
ipc/mqueue.c
|
@ -624,7 +624,7 @@ static struct file *do_create(struct ipc_namespace *ipc_ns, struct dentry *dir,
|
||||||
ret = mnt_want_write(ipc_ns->mq_mnt);
|
ret = mnt_want_write(ipc_ns->mq_mnt);
|
||||||
if (ret)
|
if (ret)
|
||||||
goto out;
|
goto out;
|
||||||
ret = vfs_create(dir->d_inode, dentry, mode, NULL);
|
ret = vfs_create2(ipc_ns->mq_mnt, dir->d_inode, dentry, mode, NULL);
|
||||||
dentry->d_fsdata = NULL;
|
dentry->d_fsdata = NULL;
|
||||||
if (ret)
|
if (ret)
|
||||||
goto out_drop_write;
|
goto out_drop_write;
|
||||||
|
@ -660,7 +660,7 @@ static struct file *do_open(struct ipc_namespace *ipc_ns,
|
||||||
goto err;
|
goto err;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (inode_permission(dentry->d_inode, oflag2acc[oflag & O_ACCMODE])) {
|
if (inode_permission2(ipc_ns->mq_mnt, dentry->d_inode, oflag2acc[oflag & O_ACCMODE])) {
|
||||||
ret = -EACCES;
|
ret = -EACCES;
|
||||||
goto err;
|
goto err;
|
||||||
}
|
}
|
||||||
|
@ -696,7 +696,7 @@ SYSCALL_DEFINE4(mq_open, const char __user *, u_name, int, oflag, umode_t, mode,
|
||||||
goto out_putname;
|
goto out_putname;
|
||||||
|
|
||||||
mutex_lock(&ipc_ns->mq_mnt->mnt_root->d_inode->i_mutex);
|
mutex_lock(&ipc_ns->mq_mnt->mnt_root->d_inode->i_mutex);
|
||||||
dentry = lookup_one_len(name, ipc_ns->mq_mnt->mnt_root, strlen(name));
|
dentry = lookup_one_len2(name, ipc_ns->mq_mnt, ipc_ns->mq_mnt->mnt_root, strlen(name));
|
||||||
if (IS_ERR(dentry)) {
|
if (IS_ERR(dentry)) {
|
||||||
error = PTR_ERR(dentry);
|
error = PTR_ERR(dentry);
|
||||||
goto out_putfd;
|
goto out_putfd;
|
||||||
|
@ -760,7 +760,8 @@ SYSCALL_DEFINE1(mq_unlink, const char __user *, u_name)
|
||||||
|
|
||||||
mutex_lock_nested(&ipc_ns->mq_mnt->mnt_root->d_inode->i_mutex,
|
mutex_lock_nested(&ipc_ns->mq_mnt->mnt_root->d_inode->i_mutex,
|
||||||
I_MUTEX_PARENT);
|
I_MUTEX_PARENT);
|
||||||
dentry = lookup_one_len(name, ipc_ns->mq_mnt->mnt_root, strlen(name));
|
dentry = lookup_one_len2(name, ipc_ns->mq_mnt, ipc_ns->mq_mnt->mnt_root,
|
||||||
|
strlen(name));
|
||||||
if (IS_ERR(dentry)) {
|
if (IS_ERR(dentry)) {
|
||||||
err = PTR_ERR(dentry);
|
err = PTR_ERR(dentry);
|
||||||
goto out_unlock;
|
goto out_unlock;
|
||||||
|
@ -777,7 +778,7 @@ SYSCALL_DEFINE1(mq_unlink, const char __user *, u_name)
|
||||||
err = mnt_want_write(ipc_ns->mq_mnt);
|
err = mnt_want_write(ipc_ns->mq_mnt);
|
||||||
if (err)
|
if (err)
|
||||||
goto out_err;
|
goto out_err;
|
||||||
err = vfs_unlink(dentry->d_parent->d_inode, dentry);
|
err = vfs_unlink2(ipc_ns->mq_mnt, dentry->d_parent->d_inode, dentry);
|
||||||
mnt_drop_write(ipc_ns->mq_mnt);
|
mnt_drop_write(ipc_ns->mq_mnt);
|
||||||
out_err:
|
out_err:
|
||||||
dput(dentry);
|
dput(dentry);
|
||||||
|
|
|
@ -105,7 +105,7 @@ struct dentry *securityfs_create_file(const char *name, umode_t mode,
|
||||||
dir = parent->d_inode;
|
dir = parent->d_inode;
|
||||||
|
|
||||||
mutex_lock(&dir->i_mutex);
|
mutex_lock(&dir->i_mutex);
|
||||||
dentry = lookup_one_len(name, parent, strlen(name));
|
dentry = lookup_one_len2(name, mount, parent, strlen(name));
|
||||||
if (IS_ERR(dentry))
|
if (IS_ERR(dentry))
|
||||||
goto out;
|
goto out;
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue