Commit 02f92b38 authored by Christian Brauner's avatar Christian Brauner

fs: add file and path permissions helpers

Add two simple helpers to check permissions on a file and path
respectively and convert over some callers. It simplifies quite a few
codepaths and also reduces the churn in later patches quite a bit.
Christoph also correctly points out that this makes codepaths (e.g.
ioctls) way easier to follow that would otherwise have to do more
complex argument passing than necessary.

Link: https://lore.kernel.org/r/20210121131959.646623-4-christian.brauner@ubuntu.com
Cc: David Howells <dhowells@redhat.com>
Cc: Al Viro <viro@zeniv.linux.org.uk>
Cc: linux-fsdevel@vger.kernel.org
Suggested-by: default avatarChristoph Hellwig <hch@lst.de>
Reviewed-by: default avatarChristoph Hellwig <hch@lst.de>
Reviewed-by: default avatarJames Morris <jamorris@linux.microsoft.com>
Signed-off-by: default avatarChristian Brauner <christian.brauner@ubuntu.com>
parent e6c9a714
...@@ -49,7 +49,7 @@ int __init init_chdir(const char *filename) ...@@ -49,7 +49,7 @@ int __init init_chdir(const char *filename)
error = kern_path(filename, LOOKUP_FOLLOW | LOOKUP_DIRECTORY, &path); error = kern_path(filename, LOOKUP_FOLLOW | LOOKUP_DIRECTORY, &path);
if (error) if (error)
return error; return error;
error = inode_permission(path.dentry->d_inode, MAY_EXEC | MAY_CHDIR); error = path_permission(&path, MAY_EXEC | MAY_CHDIR);
if (!error) if (!error)
set_fs_pwd(current->fs, &path); set_fs_pwd(current->fs, &path);
path_put(&path); path_put(&path);
...@@ -64,7 +64,7 @@ int __init init_chroot(const char *filename) ...@@ -64,7 +64,7 @@ int __init init_chroot(const char *filename)
error = kern_path(filename, LOOKUP_FOLLOW | LOOKUP_DIRECTORY, &path); error = kern_path(filename, LOOKUP_FOLLOW | LOOKUP_DIRECTORY, &path);
if (error) if (error)
return error; return error;
error = inode_permission(path.dentry->d_inode, MAY_EXEC | MAY_CHDIR); error = path_permission(&path, MAY_EXEC | MAY_CHDIR);
if (error) if (error)
goto dput_and_out; goto dput_and_out;
error = -EPERM; error = -EPERM;
...@@ -118,7 +118,7 @@ int __init init_eaccess(const char *filename) ...@@ -118,7 +118,7 @@ int __init init_eaccess(const char *filename)
error = kern_path(filename, LOOKUP_FOLLOW, &path); error = kern_path(filename, LOOKUP_FOLLOW, &path);
if (error) if (error)
return error; return error;
error = inode_permission(d_inode(path.dentry), MAY_ACCESS); error = path_permission(&path, MAY_ACCESS);
path_put(&path); path_put(&path);
return error; return error;
} }
......
...@@ -702,7 +702,7 @@ static int fanotify_find_path(int dfd, const char __user *filename, ...@@ -702,7 +702,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 = path_permission(path, MAY_READ);
if (ret) { if (ret) {
path_put(path); path_put(path);
goto out; goto out;
......
...@@ -352,7 +352,7 @@ static int inotify_find_inode(const char __user *dirname, struct path *path, ...@@ -352,7 +352,7 @@ static int inotify_find_inode(const char __user *dirname, struct path *path,
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 = path_permission(path, MAY_READ);
if (error) { if (error) {
path_put(path); path_put(path);
return error; return error;
......
...@@ -492,7 +492,7 @@ SYSCALL_DEFINE1(chdir, const char __user *, filename) ...@@ -492,7 +492,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 = path_permission(&path, MAY_EXEC | MAY_CHDIR);
if (error) if (error)
goto dput_and_out; goto dput_and_out;
...@@ -521,7 +521,7 @@ SYSCALL_DEFINE1(fchdir, unsigned int, fd) ...@@ -521,7 +521,7 @@ SYSCALL_DEFINE1(fchdir, unsigned int, fd)
if (!d_can_lookup(f.file->f_path.dentry)) if (!d_can_lookup(f.file->f_path.dentry))
goto out_putf; goto out_putf;
error = inode_permission(file_inode(f.file), MAY_EXEC | MAY_CHDIR); error = file_permission(f.file, MAY_EXEC | MAY_CHDIR);
if (!error) if (!error)
set_fs_pwd(current->fs, &f.file->f_path); set_fs_pwd(current->fs, &f.file->f_path);
out_putf: out_putf:
...@@ -540,7 +540,7 @@ SYSCALL_DEFINE1(chroot, const char __user *, filename) ...@@ -540,7 +540,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 = path_permission(&path, MAY_EXEC | MAY_CHDIR);
if (error) if (error)
goto dput_and_out; goto dput_and_out;
......
...@@ -183,7 +183,7 @@ long udf_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) ...@@ -183,7 +183,7 @@ long udf_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
long old_block, new_block; long old_block, new_block;
int result; int result;
if (inode_permission(inode, MAY_READ) != 0) { if (file_permission(filp, MAY_READ) != 0) {
udf_debug("no permission to access inode %lu\n", inode->i_ino); udf_debug("no permission to access inode %lu\n", inode->i_ino);
return -EPERM; return -EPERM;
} }
......
...@@ -369,7 +369,7 @@ int fsverity_ioctl_enable(struct file *filp, const void __user *uarg) ...@@ -369,7 +369,7 @@ int fsverity_ioctl_enable(struct file *filp, const void __user *uarg)
* has verity enabled, and to stabilize the data being hashed. * has verity enabled, and to stabilize the data being hashed.
*/ */
err = inode_permission(inode, MAY_WRITE); err = file_permission(filp, MAY_WRITE);
if (err) if (err)
return err; return err;
......
...@@ -2812,6 +2812,14 @@ static inline int bmap(struct inode *inode, sector_t *block) ...@@ -2812,6 +2812,14 @@ static inline int bmap(struct inode *inode, sector_t *block)
extern int notify_change(struct dentry *, struct iattr *, struct inode **); extern int notify_change(struct dentry *, struct iattr *, struct inode **);
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);
static inline int file_permission(struct file *file, int mask)
{
return inode_permission(file_inode(file), mask);
}
static inline int path_permission(const struct path *path, int mask)
{
return inode_permission(d_inode(path->dentry), mask);
}
extern int __check_sticky(struct inode *dir, struct inode *inode); extern int __check_sticky(struct inode *dir, struct inode *inode);
static inline bool execute_ok(struct inode *inode) static inline bool execute_ok(struct inode *inode)
......
...@@ -507,7 +507,7 @@ static void *bpf_obj_do_get(const char __user *pathname, ...@@ -507,7 +507,7 @@ static void *bpf_obj_do_get(const char __user *pathname,
return ERR_PTR(ret); return ERR_PTR(ret);
inode = d_backing_inode(path.dentry); inode = d_backing_inode(path.dentry);
ret = inode_permission(inode, ACC_MODE(flags)); ret = path_permission(&path, ACC_MODE(flags));
if (ret) if (ret)
goto out; goto out;
......
...@@ -1848,7 +1848,7 @@ static int prctl_set_mm_exe_file(struct mm_struct *mm, unsigned int fd) ...@@ -1848,7 +1848,7 @@ static int prctl_set_mm_exe_file(struct mm_struct *mm, unsigned int fd)
if (!S_ISREG(inode->i_mode) || path_noexec(&exe.file->f_path)) if (!S_ISREG(inode->i_mode) || path_noexec(&exe.file->f_path))
goto exit; goto exit;
err = inode_permission(inode, MAY_EXEC); err = file_permission(exe.file, MAY_EXEC);
if (err) if (err)
goto exit; goto exit;
......
...@@ -540,7 +540,7 @@ static inline bool can_do_pageout(struct vm_area_struct *vma) ...@@ -540,7 +540,7 @@ static inline bool can_do_pageout(struct vm_area_struct *vma)
* opens a side channel. * opens a side channel.
*/ */
return inode_owner_or_capable(file_inode(vma->vm_file)) || return inode_owner_or_capable(file_inode(vma->vm_file)) ||
inode_permission(file_inode(vma->vm_file), MAY_WRITE) == 0; file_permission(vma->vm_file, MAY_WRITE) == 0;
} }
static long madvise_pageout(struct vm_area_struct *vma, static long madvise_pageout(struct vm_area_struct *vma,
......
...@@ -4899,7 +4899,7 @@ static ssize_t memcg_write_event_control(struct kernfs_open_file *of, ...@@ -4899,7 +4899,7 @@ static ssize_t memcg_write_event_control(struct kernfs_open_file *of,
/* the process need read permission on control file */ /* the process need read permission on control file */
/* AV: shouldn't we check that it's been opened for read instead? */ /* AV: shouldn't we check that it's been opened for read instead? */
ret = inode_permission(file_inode(cfile.file), MAY_READ); ret = file_permission(cfile.file, MAY_READ);
if (ret < 0) if (ret < 0)
goto out_put_cfile; goto out_put_cfile;
......
...@@ -167,7 +167,7 @@ static inline bool can_do_mincore(struct vm_area_struct *vma) ...@@ -167,7 +167,7 @@ static inline bool can_do_mincore(struct vm_area_struct *vma)
* mappings, which opens a side channel. * mappings, which opens a side channel.
*/ */
return inode_owner_or_capable(file_inode(vma->vm_file)) || return inode_owner_or_capable(file_inode(vma->vm_file)) ||
inode_permission(file_inode(vma->vm_file), MAY_WRITE) == 0; file_permission(vma->vm_file, MAY_WRITE) == 0;
} }
static const struct mm_walk_ops mincore_walk_ops = { static const struct mm_walk_ops mincore_walk_ops = {
......
...@@ -936,7 +936,7 @@ static struct sock *unix_find_other(struct net *net, ...@@ -936,7 +936,7 @@ static struct sock *unix_find_other(struct net *net,
if (err) if (err)
goto fail; goto fail;
inode = d_backing_inode(path.dentry); inode = d_backing_inode(path.dentry);
err = inode_permission(inode, MAY_WRITE); err = path_permission(&path, MAY_WRITE);
if (err) if (err)
goto put_fail; goto put_fail;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment