mirror of
https://github.com/torvalds/linux.git
synced 2026-03-08 01:04:41 +01:00
struct filename series
[mostly] sanitize struct filename hanling
Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
-----BEGIN PGP SIGNATURE-----
iHUEABYKAB0WIQQqUNBr3gm4hGXdBJlZ7Krx/gZQ6wUCaYlcJgAKCRBZ7Krx/gZQ
6xlKAP9c9J13sJ/mcobsj1Ov7nSHISNbnYqvRRCu09Wq3UQvJgEApNQYOEdLtpff
zUnWOAQ0nOKY7w9VMLkRRustXpuGjAc=
=Fld4
-----END PGP SIGNATURE-----
Merge tag 'pull-filename' of git://git.kernel.org/pub/scm/linux/kernel/git/viro/vfs
Pull vfs 'struct filename' updates from Al Viro:
"[Mostly] sanitize struct filename handling"
* tag 'pull-filename' of git://git.kernel.org/pub/scm/linux/kernel/git/viro/vfs: (68 commits)
sysfs(2): fs_index() argument is _not_ a pathname
alpha: switch osf_mount() to strndup_user()
ksmbd: use CLASS(filename_kernel)
mqueue: switch to CLASS(filename)
user_statfs(): switch to CLASS(filename)
statx: switch to CLASS(filename_maybe_null)
quotactl_block(): switch to CLASS(filename)
chroot(2): switch to CLASS(filename)
move_mount(2): switch to CLASS(filename_maybe_null)
namei.c: switch user pathname imports to CLASS(filename{,_flags})
namei.c: convert getname_kernel() callers to CLASS(filename_kernel)
do_f{chmod,chown,access}at(): use CLASS(filename_uflags)
do_readlinkat(): switch to CLASS(filename_flags)
do_sys_truncate(): switch to CLASS(filename)
do_utimes_path(): switch to CLASS(filename_uflags)
chdir(2): unspaghettify a bit...
do_fchownat(): unspaghettify a bit...
fspick(2): use CLASS(filename_flags)
name_to_handle_at(): use CLASS(filename_uflags)
vfs_open_tree(): use CLASS(filename_uflags)
...
This commit is contained in:
commit
26c9342bb7
37 changed files with 564 additions and 828 deletions
|
|
@ -1340,3 +1340,14 @@ The ->setlease() file_operation must now be explicitly set in order to provide
|
|||
support for leases. When set to NULL, the kernel will now return -EINVAL to
|
||||
attempts to set a lease. Filesystems that wish to use the kernel-internal lease
|
||||
implementation should set it to generic_setlease().
|
||||
|
||||
---
|
||||
|
||||
**mandatory**
|
||||
|
||||
fs/namei.c primitives that consume filesystem references (do_renameat2(),
|
||||
do_linkat(), do_symlinkat(), do_mkdirat(), do_mknodat(), do_unlinkat()
|
||||
and do_rmdir()) are gone; they are replaced with non-consuming analogues
|
||||
(filename_renameat2(), etc.)
|
||||
Callers are adjusted - responsibility for dropping the filenames belongs
|
||||
to them now.
|
||||
|
|
|
|||
|
|
@ -454,42 +454,30 @@ static int
|
|||
osf_ufs_mount(const char __user *dirname,
|
||||
struct ufs_args __user *args, int flags)
|
||||
{
|
||||
int retval;
|
||||
struct cdfs_args tmp;
|
||||
struct filename *devname;
|
||||
struct ufs_args tmp;
|
||||
char *devname __free(kfree) = NULL;
|
||||
|
||||
retval = -EFAULT;
|
||||
if (copy_from_user(&tmp, args, sizeof(tmp)))
|
||||
goto out;
|
||||
devname = getname(tmp.devname);
|
||||
retval = PTR_ERR(devname);
|
||||
return -EFAULT;
|
||||
devname = strndup_user(tmp.devname, PATH_MAX);
|
||||
if (IS_ERR(devname))
|
||||
goto out;
|
||||
retval = do_mount(devname->name, dirname, "ext2", flags, NULL);
|
||||
putname(devname);
|
||||
out:
|
||||
return retval;
|
||||
return PTR_ERR(devname);
|
||||
return do_mount(devname, dirname, "ext2", flags, NULL);
|
||||
}
|
||||
|
||||
static int
|
||||
osf_cdfs_mount(const char __user *dirname,
|
||||
struct cdfs_args __user *args, int flags)
|
||||
{
|
||||
int retval;
|
||||
struct cdfs_args tmp;
|
||||
struct filename *devname;
|
||||
char *devname __free(kfree) = NULL;
|
||||
|
||||
retval = -EFAULT;
|
||||
if (copy_from_user(&tmp, args, sizeof(tmp)))
|
||||
goto out;
|
||||
devname = getname(tmp.devname);
|
||||
retval = PTR_ERR(devname);
|
||||
return -EFAULT;
|
||||
devname = strndup_user(tmp.devname, PATH_MAX);
|
||||
if (IS_ERR(devname))
|
||||
goto out;
|
||||
retval = do_mount(devname->name, dirname, "iso9660", flags, NULL);
|
||||
putname(devname);
|
||||
out:
|
||||
return retval;
|
||||
return PTR_ERR(devname);
|
||||
return do_mount(devname, dirname, "iso9660", flags, NULL);
|
||||
}
|
||||
|
||||
static int
|
||||
|
|
|
|||
|
|
@ -895,11 +895,12 @@ static bool coredump_file(struct core_name *cn, struct coredump_params *cprm,
|
|||
* privs and don't want to unlink another user's coredump.
|
||||
*/
|
||||
if (!coredump_force_suid_safe(cprm)) {
|
||||
CLASS(filename_kernel, name)(cn->corename);
|
||||
/*
|
||||
* If it doesn't exist, that's fine. If there's some
|
||||
* other problem, we'll catch it at the filp_open().
|
||||
*/
|
||||
do_unlinkat(AT_FDCWD, getname_kernel(cn->corename));
|
||||
filename_unlinkat(AT_FDCWD, name);
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
|
|||
|
|
@ -3297,10 +3297,6 @@ static void __init dcache_init(void)
|
|||
runtime_const_init(ptr, dentry_hashtable);
|
||||
}
|
||||
|
||||
/* SLAB cache for __getname() consumers */
|
||||
struct kmem_cache *names_cachep __ro_after_init;
|
||||
EXPORT_SYMBOL(names_cachep);
|
||||
|
||||
void __init vfs_caches_init_early(void)
|
||||
{
|
||||
int i;
|
||||
|
|
@ -3314,9 +3310,7 @@ void __init vfs_caches_init_early(void)
|
|||
|
||||
void __init vfs_caches_init(void)
|
||||
{
|
||||
names_cachep = kmem_cache_create_usercopy("names_cache", PATH_MAX, 0,
|
||||
SLAB_HWCACHE_ALIGN|SLAB_PANIC, 0, PATH_MAX, NULL);
|
||||
|
||||
filename_init();
|
||||
dcache_init();
|
||||
inode_init();
|
||||
files_init();
|
||||
|
|
|
|||
178
fs/exec.c
178
fs/exec.c
|
|
@ -777,10 +777,8 @@ static struct file *do_open_execat(int fd, struct filename *name, int flags)
|
|||
return ERR_PTR(-EINVAL);
|
||||
if (flags & AT_SYMLINK_NOFOLLOW)
|
||||
open_exec_flags.lookup_flags &= ~LOOKUP_FOLLOW;
|
||||
if (flags & AT_EMPTY_PATH)
|
||||
open_exec_flags.lookup_flags |= LOOKUP_EMPTY;
|
||||
|
||||
file = do_filp_open(fd, name, &open_exec_flags);
|
||||
file = do_file_open(fd, name, &open_exec_flags);
|
||||
if (IS_ERR(file))
|
||||
return file;
|
||||
|
||||
|
|
@ -815,14 +813,8 @@ static struct file *do_open_execat(int fd, struct filename *name, int flags)
|
|||
*/
|
||||
struct file *open_exec(const char *name)
|
||||
{
|
||||
struct filename *filename = getname_kernel(name);
|
||||
struct file *f = ERR_CAST(filename);
|
||||
|
||||
if (!IS_ERR(filename)) {
|
||||
f = do_open_execat(AT_FDCWD, filename, 0);
|
||||
putname(filename);
|
||||
}
|
||||
return f;
|
||||
CLASS(filename_kernel, filename)(name);
|
||||
return do_open_execat(AT_FDCWD, filename, 0);
|
||||
}
|
||||
EXPORT_SYMBOL(open_exec);
|
||||
|
||||
|
|
@ -1471,6 +1463,9 @@ out_free:
|
|||
return ERR_PTR(retval);
|
||||
}
|
||||
|
||||
DEFINE_CLASS(bprm, struct linux_binprm *, if (!IS_ERR(_T)) free_bprm(_T),
|
||||
alloc_bprm(fd, name, flags), int fd, struct filename *name, int flags)
|
||||
|
||||
int bprm_change_interp(const char *interp, struct linux_binprm *bprm)
|
||||
{
|
||||
/* If a binfmt changed the interp, free it first. */
|
||||
|
|
@ -1785,12 +1780,8 @@ static int do_execveat_common(int fd, struct filename *filename,
|
|||
struct user_arg_ptr envp,
|
||||
int flags)
|
||||
{
|
||||
struct linux_binprm *bprm;
|
||||
int retval;
|
||||
|
||||
if (IS_ERR(filename))
|
||||
return PTR_ERR(filename);
|
||||
|
||||
/*
|
||||
* We move the actual failure in case of RLIMIT_NPROC excess from
|
||||
* set*uid() to execve() because too many poorly written programs
|
||||
|
|
@ -1798,47 +1789,43 @@ static int do_execveat_common(int fd, struct filename *filename,
|
|||
* whether NPROC limit is still exceeded.
|
||||
*/
|
||||
if ((current->flags & PF_NPROC_EXCEEDED) &&
|
||||
is_rlimit_overlimit(current_ucounts(), UCOUNT_RLIMIT_NPROC, rlimit(RLIMIT_NPROC))) {
|
||||
retval = -EAGAIN;
|
||||
goto out_ret;
|
||||
}
|
||||
is_rlimit_overlimit(current_ucounts(), UCOUNT_RLIMIT_NPROC, rlimit(RLIMIT_NPROC)))
|
||||
return -EAGAIN;
|
||||
|
||||
/* We're below the limit (still or again), so we don't want to make
|
||||
* further execve() calls fail. */
|
||||
current->flags &= ~PF_NPROC_EXCEEDED;
|
||||
|
||||
bprm = alloc_bprm(fd, filename, flags);
|
||||
if (IS_ERR(bprm)) {
|
||||
retval = PTR_ERR(bprm);
|
||||
goto out_ret;
|
||||
}
|
||||
CLASS(bprm, bprm)(fd, filename, flags);
|
||||
if (IS_ERR(bprm))
|
||||
return PTR_ERR(bprm);
|
||||
|
||||
retval = count(argv, MAX_ARG_STRINGS);
|
||||
if (retval < 0)
|
||||
goto out_free;
|
||||
return retval;
|
||||
bprm->argc = retval;
|
||||
|
||||
retval = count(envp, MAX_ARG_STRINGS);
|
||||
if (retval < 0)
|
||||
goto out_free;
|
||||
return retval;
|
||||
bprm->envc = retval;
|
||||
|
||||
retval = bprm_stack_limits(bprm);
|
||||
if (retval < 0)
|
||||
goto out_free;
|
||||
return retval;
|
||||
|
||||
retval = copy_string_kernel(bprm->filename, bprm);
|
||||
if (retval < 0)
|
||||
goto out_free;
|
||||
return retval;
|
||||
bprm->exec = bprm->p;
|
||||
|
||||
retval = copy_strings(bprm->envc, envp, bprm);
|
||||
if (retval < 0)
|
||||
goto out_free;
|
||||
return retval;
|
||||
|
||||
retval = copy_strings(bprm->argc, argv, bprm);
|
||||
if (retval < 0)
|
||||
goto out_free;
|
||||
return retval;
|
||||
|
||||
/*
|
||||
* When argv is empty, add an empty string ("") as argv[0] to
|
||||
|
|
@ -1849,134 +1836,62 @@ static int do_execveat_common(int fd, struct filename *filename,
|
|||
if (bprm->argc == 0) {
|
||||
retval = copy_string_kernel("", bprm);
|
||||
if (retval < 0)
|
||||
goto out_free;
|
||||
return retval;
|
||||
bprm->argc = 1;
|
||||
|
||||
pr_warn_once("process '%s' launched '%s' with NULL argv: empty string added\n",
|
||||
current->comm, bprm->filename);
|
||||
}
|
||||
|
||||
retval = bprm_execve(bprm);
|
||||
out_free:
|
||||
free_bprm(bprm);
|
||||
|
||||
out_ret:
|
||||
putname(filename);
|
||||
return retval;
|
||||
return bprm_execve(bprm);
|
||||
}
|
||||
|
||||
int kernel_execve(const char *kernel_filename,
|
||||
const char *const *argv, const char *const *envp)
|
||||
{
|
||||
struct filename *filename;
|
||||
struct linux_binprm *bprm;
|
||||
int fd = AT_FDCWD;
|
||||
int retval;
|
||||
|
||||
/* It is non-sense for kernel threads to call execve */
|
||||
if (WARN_ON_ONCE(current->flags & PF_KTHREAD))
|
||||
return -EINVAL;
|
||||
|
||||
filename = getname_kernel(kernel_filename);
|
||||
if (IS_ERR(filename))
|
||||
return PTR_ERR(filename);
|
||||
|
||||
bprm = alloc_bprm(fd, filename, 0);
|
||||
if (IS_ERR(bprm)) {
|
||||
retval = PTR_ERR(bprm);
|
||||
goto out_ret;
|
||||
}
|
||||
CLASS(filename_kernel, filename)(kernel_filename);
|
||||
CLASS(bprm, bprm)(AT_FDCWD, filename, 0);
|
||||
if (IS_ERR(bprm))
|
||||
return PTR_ERR(bprm);
|
||||
|
||||
retval = count_strings_kernel(argv);
|
||||
if (WARN_ON_ONCE(retval == 0))
|
||||
retval = -EINVAL;
|
||||
return -EINVAL;
|
||||
if (retval < 0)
|
||||
goto out_free;
|
||||
return retval;
|
||||
bprm->argc = retval;
|
||||
|
||||
retval = count_strings_kernel(envp);
|
||||
if (retval < 0)
|
||||
goto out_free;
|
||||
return retval;
|
||||
bprm->envc = retval;
|
||||
|
||||
retval = bprm_stack_limits(bprm);
|
||||
if (retval < 0)
|
||||
goto out_free;
|
||||
return retval;
|
||||
|
||||
retval = copy_string_kernel(bprm->filename, bprm);
|
||||
if (retval < 0)
|
||||
goto out_free;
|
||||
return retval;
|
||||
bprm->exec = bprm->p;
|
||||
|
||||
retval = copy_strings_kernel(bprm->envc, envp, bprm);
|
||||
if (retval < 0)
|
||||
goto out_free;
|
||||
return retval;
|
||||
|
||||
retval = copy_strings_kernel(bprm->argc, argv, bprm);
|
||||
if (retval < 0)
|
||||
goto out_free;
|
||||
return retval;
|
||||
|
||||
retval = bprm_execve(bprm);
|
||||
out_free:
|
||||
free_bprm(bprm);
|
||||
out_ret:
|
||||
putname(filename);
|
||||
return retval;
|
||||
return bprm_execve(bprm);
|
||||
}
|
||||
|
||||
static int do_execve(struct filename *filename,
|
||||
const char __user *const __user *__argv,
|
||||
const char __user *const __user *__envp)
|
||||
{
|
||||
struct user_arg_ptr argv = { .ptr.native = __argv };
|
||||
struct user_arg_ptr envp = { .ptr.native = __envp };
|
||||
return do_execveat_common(AT_FDCWD, filename, argv, envp, 0);
|
||||
}
|
||||
|
||||
static int do_execveat(int fd, struct filename *filename,
|
||||
const char __user *const __user *__argv,
|
||||
const char __user *const __user *__envp,
|
||||
int flags)
|
||||
{
|
||||
struct user_arg_ptr argv = { .ptr.native = __argv };
|
||||
struct user_arg_ptr envp = { .ptr.native = __envp };
|
||||
|
||||
return do_execveat_common(fd, filename, argv, envp, flags);
|
||||
}
|
||||
|
||||
#ifdef CONFIG_COMPAT
|
||||
static int compat_do_execve(struct filename *filename,
|
||||
const compat_uptr_t __user *__argv,
|
||||
const compat_uptr_t __user *__envp)
|
||||
{
|
||||
struct user_arg_ptr argv = {
|
||||
.is_compat = true,
|
||||
.ptr.compat = __argv,
|
||||
};
|
||||
struct user_arg_ptr envp = {
|
||||
.is_compat = true,
|
||||
.ptr.compat = __envp,
|
||||
};
|
||||
return do_execveat_common(AT_FDCWD, filename, argv, envp, 0);
|
||||
}
|
||||
|
||||
static int compat_do_execveat(int fd, struct filename *filename,
|
||||
const compat_uptr_t __user *__argv,
|
||||
const compat_uptr_t __user *__envp,
|
||||
int flags)
|
||||
{
|
||||
struct user_arg_ptr argv = {
|
||||
.is_compat = true,
|
||||
.ptr.compat = __argv,
|
||||
};
|
||||
struct user_arg_ptr envp = {
|
||||
.is_compat = true,
|
||||
.ptr.compat = __envp,
|
||||
};
|
||||
return do_execveat_common(fd, filename, argv, envp, flags);
|
||||
}
|
||||
#endif
|
||||
|
||||
void set_binfmt(struct linux_binfmt *new)
|
||||
{
|
||||
struct mm_struct *mm = current->mm;
|
||||
|
|
@ -2001,12 +1916,19 @@ void set_dumpable(struct mm_struct *mm, int value)
|
|||
__mm_flags_set_mask_dumpable(mm, value);
|
||||
}
|
||||
|
||||
static inline struct user_arg_ptr native_arg(const char __user *const __user *p)
|
||||
{
|
||||
return (struct user_arg_ptr){.ptr.native = p};
|
||||
}
|
||||
|
||||
SYSCALL_DEFINE3(execve,
|
||||
const char __user *, filename,
|
||||
const char __user *const __user *, argv,
|
||||
const char __user *const __user *, envp)
|
||||
{
|
||||
return do_execve(getname(filename), argv, envp);
|
||||
CLASS(filename, name)(filename);
|
||||
return do_execveat_common(AT_FDCWD, name,
|
||||
native_arg(argv), native_arg(envp), 0);
|
||||
}
|
||||
|
||||
SYSCALL_DEFINE5(execveat,
|
||||
|
|
@ -2015,17 +1937,25 @@ SYSCALL_DEFINE5(execveat,
|
|||
const char __user *const __user *, envp,
|
||||
int, flags)
|
||||
{
|
||||
return do_execveat(fd,
|
||||
getname_uflags(filename, flags),
|
||||
argv, envp, flags);
|
||||
CLASS(filename_uflags, name)(filename, flags);
|
||||
return do_execveat_common(fd, name,
|
||||
native_arg(argv), native_arg(envp), flags);
|
||||
}
|
||||
|
||||
#ifdef CONFIG_COMPAT
|
||||
|
||||
static inline struct user_arg_ptr compat_arg(const compat_uptr_t __user *p)
|
||||
{
|
||||
return (struct user_arg_ptr){.is_compat = true, .ptr.compat = p};
|
||||
}
|
||||
|
||||
COMPAT_SYSCALL_DEFINE3(execve, const char __user *, filename,
|
||||
const compat_uptr_t __user *, argv,
|
||||
const compat_uptr_t __user *, envp)
|
||||
{
|
||||
return compat_do_execve(getname(filename), argv, envp);
|
||||
CLASS(filename, name)(filename);
|
||||
return do_execveat_common(AT_FDCWD, name,
|
||||
compat_arg(argv), compat_arg(envp), 0);
|
||||
}
|
||||
|
||||
COMPAT_SYSCALL_DEFINE5(execveat, int, fd,
|
||||
|
|
@ -2034,9 +1964,9 @@ COMPAT_SYSCALL_DEFINE5(execveat, int, fd,
|
|||
const compat_uptr_t __user *, envp,
|
||||
int, flags)
|
||||
{
|
||||
return compat_do_execveat(fd,
|
||||
getname_uflags(filename, flags),
|
||||
argv, envp, flags);
|
||||
CLASS(filename_uflags, name)(filename, flags);
|
||||
return do_execveat_common(fd, name,
|
||||
compat_arg(argv), compat_arg(envp), flags);
|
||||
}
|
||||
#endif
|
||||
|
||||
|
|
|
|||
|
|
@ -157,9 +157,8 @@ SYSCALL_DEFINE5(name_to_handle_at, int, dfd, const char __user *, name,
|
|||
fh_flags |= EXPORT_FH_CONNECTABLE;
|
||||
|
||||
lookup_flags = (flag & AT_SYMLINK_FOLLOW) ? LOOKUP_FOLLOW : 0;
|
||||
if (flag & AT_EMPTY_PATH)
|
||||
lookup_flags |= LOOKUP_EMPTY;
|
||||
err = user_path_at(dfd, name, lookup_flags, &path);
|
||||
CLASS(filename_uflags, filename)(name, flag);
|
||||
err = filename_lookup(dfd, filename, lookup_flags, &path, NULL);
|
||||
if (!err) {
|
||||
err = do_sys_name_to_handle(&path, handle, mnt_id,
|
||||
flag & AT_HANDLE_MNT_ID_UNIQUE,
|
||||
|
|
|
|||
|
|
@ -374,7 +374,6 @@ SYSCALL_DEFINE5(file_getattr, int, dfd, const char __user *, filename,
|
|||
unsigned int, at_flags)
|
||||
{
|
||||
struct path filepath __free(path_put) = {};
|
||||
struct filename *name __free(putname) = NULL;
|
||||
unsigned int lookup_flags = 0;
|
||||
struct file_attr fattr;
|
||||
struct file_kattr fa;
|
||||
|
|
@ -395,10 +394,7 @@ SYSCALL_DEFINE5(file_getattr, int, dfd, const char __user *, filename,
|
|||
if (usize < FILE_ATTR_SIZE_VER0)
|
||||
return -EINVAL;
|
||||
|
||||
name = getname_maybe_null(filename, at_flags);
|
||||
if (IS_ERR(name))
|
||||
return PTR_ERR(name);
|
||||
|
||||
CLASS(filename_maybe_null, name)(filename, at_flags);
|
||||
if (!name && dfd >= 0) {
|
||||
CLASS(fd, f)(dfd);
|
||||
if (fd_empty(f))
|
||||
|
|
@ -431,7 +427,6 @@ SYSCALL_DEFINE5(file_setattr, int, dfd, const char __user *, filename,
|
|||
unsigned int, at_flags)
|
||||
{
|
||||
struct path filepath __free(path_put) = {};
|
||||
struct filename *name __free(putname) = NULL;
|
||||
unsigned int lookup_flags = 0;
|
||||
struct file_attr fattr;
|
||||
struct file_kattr fa;
|
||||
|
|
@ -461,10 +456,7 @@ SYSCALL_DEFINE5(file_setattr, int, dfd, const char __user *, filename,
|
|||
if (error)
|
||||
return error;
|
||||
|
||||
name = getname_maybe_null(filename, at_flags);
|
||||
if (IS_ERR(name))
|
||||
return PTR_ERR(name);
|
||||
|
||||
CLASS(filename_maybe_null, name)(filename, at_flags);
|
||||
if (!name && dfd >= 0) {
|
||||
CLASS(fd, f)(dfd);
|
||||
if (fd_empty(f))
|
||||
|
|
|
|||
|
|
@ -132,24 +132,21 @@ EXPORT_SYMBOL(unregister_filesystem);
|
|||
static int fs_index(const char __user * __name)
|
||||
{
|
||||
struct file_system_type * tmp;
|
||||
struct filename *name;
|
||||
char *name __free(kfree) = strndup_user(__name, PATH_MAX);
|
||||
int err, index;
|
||||
|
||||
name = getname(__name);
|
||||
err = PTR_ERR(name);
|
||||
if (IS_ERR(name))
|
||||
return err;
|
||||
return PTR_ERR(name);
|
||||
|
||||
err = -EINVAL;
|
||||
read_lock(&file_systems_lock);
|
||||
for (tmp=file_systems, index=0 ; tmp ; tmp=tmp->next, index++) {
|
||||
if (strcmp(tmp->name, name->name) == 0) {
|
||||
if (strcmp(tmp->name, name) == 0) {
|
||||
err = index;
|
||||
break;
|
||||
}
|
||||
}
|
||||
read_unlock(&file_systems_lock);
|
||||
putname(name);
|
||||
return err;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -181,9 +181,9 @@ SYSCALL_DEFINE3(fspick, int, dfd, const char __user *, path, unsigned int, flags
|
|||
lookup_flags &= ~LOOKUP_FOLLOW;
|
||||
if (flags & FSPICK_NO_AUTOMOUNT)
|
||||
lookup_flags &= ~LOOKUP_AUTOMOUNT;
|
||||
if (flags & FSPICK_EMPTY_PATH)
|
||||
lookup_flags |= LOOKUP_EMPTY;
|
||||
ret = user_path_at(dfd, path, lookup_flags, &target);
|
||||
CLASS(filename_flags, filename)(path,
|
||||
(flags & FSPICK_EMPTY_PATH) ? LOOKUP_EMPTY : 0);
|
||||
ret = filename_lookup(dfd, filename, lookup_flags, &target, NULL);
|
||||
if (ret < 0)
|
||||
goto err;
|
||||
|
||||
|
|
|
|||
98
fs/init.c
98
fs/init.c
|
|
@ -157,110 +157,40 @@ int __init init_stat(const char *filename, struct kstat *stat, int flags)
|
|||
|
||||
int __init init_mknod(const char *filename, umode_t mode, unsigned int dev)
|
||||
{
|
||||
struct dentry *dentry;
|
||||
struct path path;
|
||||
int error;
|
||||
|
||||
if (S_ISFIFO(mode) || S_ISSOCK(mode))
|
||||
dev = 0;
|
||||
else if (!(S_ISBLK(mode) || S_ISCHR(mode)))
|
||||
return -EINVAL;
|
||||
|
||||
dentry = start_creating_path(AT_FDCWD, filename, &path, 0);
|
||||
if (IS_ERR(dentry))
|
||||
return PTR_ERR(dentry);
|
||||
|
||||
mode = mode_strip_umask(d_inode(path.dentry), mode);
|
||||
error = security_path_mknod(&path, dentry, mode, dev);
|
||||
if (!error)
|
||||
error = vfs_mknod(mnt_idmap(path.mnt), path.dentry->d_inode,
|
||||
dentry, mode, new_decode_dev(dev), NULL);
|
||||
end_creating_path(&path, dentry);
|
||||
return error;
|
||||
CLASS(filename_kernel, name)(filename);
|
||||
return filename_mknodat(AT_FDCWD, name, mode, dev);
|
||||
}
|
||||
|
||||
int __init init_link(const char *oldname, const char *newname)
|
||||
{
|
||||
struct dentry *new_dentry;
|
||||
struct path old_path, new_path;
|
||||
struct mnt_idmap *idmap;
|
||||
int error;
|
||||
|
||||
error = kern_path(oldname, 0, &old_path);
|
||||
if (error)
|
||||
return error;
|
||||
|
||||
new_dentry = start_creating_path(AT_FDCWD, newname, &new_path, 0);
|
||||
error = PTR_ERR(new_dentry);
|
||||
if (IS_ERR(new_dentry))
|
||||
goto out;
|
||||
|
||||
error = -EXDEV;
|
||||
if (old_path.mnt != new_path.mnt)
|
||||
goto out_dput;
|
||||
idmap = mnt_idmap(new_path.mnt);
|
||||
error = may_linkat(idmap, &old_path);
|
||||
if (unlikely(error))
|
||||
goto out_dput;
|
||||
error = security_path_link(old_path.dentry, &new_path, new_dentry);
|
||||
if (error)
|
||||
goto out_dput;
|
||||
error = vfs_link(old_path.dentry, idmap, new_path.dentry->d_inode,
|
||||
new_dentry, NULL);
|
||||
out_dput:
|
||||
end_creating_path(&new_path, new_dentry);
|
||||
out:
|
||||
path_put(&old_path);
|
||||
return error;
|
||||
CLASS(filename_kernel, old)(oldname);
|
||||
CLASS(filename_kernel, new)(newname);
|
||||
return filename_linkat(AT_FDCWD, old, AT_FDCWD, new, 0);
|
||||
}
|
||||
|
||||
int __init init_symlink(const char *oldname, const char *newname)
|
||||
{
|
||||
struct dentry *dentry;
|
||||
struct path path;
|
||||
int error;
|
||||
|
||||
dentry = start_creating_path(AT_FDCWD, newname, &path, 0);
|
||||
if (IS_ERR(dentry))
|
||||
return PTR_ERR(dentry);
|
||||
error = security_path_symlink(&path, dentry, oldname);
|
||||
if (!error)
|
||||
error = vfs_symlink(mnt_idmap(path.mnt), path.dentry->d_inode,
|
||||
dentry, oldname, NULL);
|
||||
end_creating_path(&path, dentry);
|
||||
return error;
|
||||
CLASS(filename_kernel, old)(oldname);
|
||||
CLASS(filename_kernel, new)(newname);
|
||||
return filename_symlinkat(old, AT_FDCWD, new);
|
||||
}
|
||||
|
||||
int __init init_unlink(const char *pathname)
|
||||
{
|
||||
return do_unlinkat(AT_FDCWD, getname_kernel(pathname));
|
||||
CLASS(filename_kernel, name)(pathname);
|
||||
return filename_unlinkat(AT_FDCWD, name);
|
||||
}
|
||||
|
||||
int __init init_mkdir(const char *pathname, umode_t mode)
|
||||
{
|
||||
struct dentry *dentry;
|
||||
struct path path;
|
||||
int error;
|
||||
|
||||
dentry = start_creating_path(AT_FDCWD, pathname, &path,
|
||||
LOOKUP_DIRECTORY);
|
||||
if (IS_ERR(dentry))
|
||||
return PTR_ERR(dentry);
|
||||
mode = mode_strip_umask(d_inode(path.dentry), mode);
|
||||
error = security_path_mkdir(&path, dentry, mode);
|
||||
if (!error) {
|
||||
dentry = vfs_mkdir(mnt_idmap(path.mnt), path.dentry->d_inode,
|
||||
dentry, mode, NULL);
|
||||
if (IS_ERR(dentry))
|
||||
error = PTR_ERR(dentry);
|
||||
}
|
||||
end_creating_path(&path, dentry);
|
||||
return error;
|
||||
CLASS(filename_kernel, name)(pathname);
|
||||
return filename_mkdirat(AT_FDCWD, name, mode);
|
||||
}
|
||||
|
||||
int __init init_rmdir(const char *pathname)
|
||||
{
|
||||
return do_rmdir(AT_FDCWD, getname_kernel(pathname));
|
||||
CLASS(filename_kernel, name)(pathname);
|
||||
return filename_rmdir(AT_FDCWD, name);
|
||||
}
|
||||
|
||||
int __init init_utimes(char *filename, struct timespec64 *ts)
|
||||
|
|
|
|||
|
|
@ -53,14 +53,15 @@ extern int finish_clean_context(struct fs_context *fc);
|
|||
*/
|
||||
extern int filename_lookup(int dfd, struct filename *name, unsigned flags,
|
||||
struct path *path, const struct path *root);
|
||||
int do_rmdir(int dfd, struct filename *name);
|
||||
int do_unlinkat(int dfd, struct filename *name);
|
||||
int filename_rmdir(int dfd, struct filename *name);
|
||||
int filename_unlinkat(int dfd, struct filename *name);
|
||||
int may_linkat(struct mnt_idmap *idmap, const struct path *link);
|
||||
int do_renameat2(int olddfd, struct filename *oldname, int newdfd,
|
||||
int filename_renameat2(int olddfd, struct filename *oldname, int newdfd,
|
||||
struct filename *newname, unsigned int flags);
|
||||
int do_mkdirat(int dfd, struct filename *name, umode_t mode);
|
||||
int do_symlinkat(struct filename *from, int newdfd, struct filename *to);
|
||||
int do_linkat(int olddfd, struct filename *old, int newdfd,
|
||||
int filename_mkdirat(int dfd, struct filename *name, umode_t mode);
|
||||
int filename_mknodat(int dfd, struct filename *name, umode_t mode, unsigned int dev);
|
||||
int filename_symlinkat(struct filename *from, int newdfd, struct filename *to);
|
||||
int filename_linkat(int olddfd, struct filename *old, int newdfd,
|
||||
struct filename *new, int flags);
|
||||
int vfs_tmpfile(struct mnt_idmap *idmap,
|
||||
const struct path *parentpath,
|
||||
|
|
@ -70,6 +71,8 @@ struct dentry *start_dirop(struct dentry *parent, struct qstr *name,
|
|||
unsigned int lookup_flags);
|
||||
int lookup_noperm_common(struct qstr *qname, struct dentry *base);
|
||||
|
||||
void __init filename_init(void);
|
||||
|
||||
/*
|
||||
* namespace.c
|
||||
*/
|
||||
|
|
@ -187,7 +190,7 @@ struct open_flags {
|
|||
int intent;
|
||||
int lookup_flags;
|
||||
};
|
||||
extern struct file *do_filp_open(int dfd, struct filename *pathname,
|
||||
extern struct file *do_file_open(int dfd, struct filename *pathname,
|
||||
const struct open_flags *op);
|
||||
extern struct file *do_file_open_root(const struct path *,
|
||||
const char *, const struct open_flags *);
|
||||
|
|
|
|||
422
fs/namei.c
422
fs/namei.c
|
|
@ -41,6 +41,8 @@
|
|||
#include <linux/init_task.h>
|
||||
#include <linux/uaccess.h>
|
||||
|
||||
#include <asm/runtime-const.h>
|
||||
|
||||
#include "internal.h"
|
||||
#include "mount.h"
|
||||
|
||||
|
|
@ -123,27 +125,61 @@
|
|||
* PATH_MAX includes the nul terminator --RR.
|
||||
*/
|
||||
|
||||
#define EMBEDDED_NAME_MAX (PATH_MAX - offsetof(struct filename, iname))
|
||||
/* SLAB cache for struct filename instances */
|
||||
static struct kmem_cache *__names_cache __ro_after_init;
|
||||
#define names_cache runtime_const_ptr(__names_cache)
|
||||
|
||||
static inline void initname(struct filename *name, const char __user *uptr)
|
||||
void __init filename_init(void)
|
||||
{
|
||||
name->uptr = uptr;
|
||||
name->aname = NULL;
|
||||
atomic_set(&name->refcnt, 1);
|
||||
__names_cache = kmem_cache_create_usercopy("names_cache", sizeof(struct filename), 0,
|
||||
SLAB_HWCACHE_ALIGN|SLAB_PANIC, offsetof(struct filename, iname),
|
||||
EMBEDDED_NAME_MAX, NULL);
|
||||
runtime_const_init(ptr, __names_cache);
|
||||
}
|
||||
|
||||
struct filename *
|
||||
getname_flags(const char __user *filename, int flags)
|
||||
static inline struct filename *alloc_filename(void)
|
||||
{
|
||||
return kmem_cache_alloc(names_cache, GFP_KERNEL);
|
||||
}
|
||||
|
||||
static inline void free_filename(struct filename *p)
|
||||
{
|
||||
kmem_cache_free(names_cache, p);
|
||||
}
|
||||
|
||||
static inline void initname(struct filename *name)
|
||||
{
|
||||
name->aname = NULL;
|
||||
name->refcnt = 1;
|
||||
}
|
||||
|
||||
static int getname_long(struct filename *name, const char __user *filename)
|
||||
{
|
||||
int len;
|
||||
char *p __free(kfree) = kmalloc(PATH_MAX, GFP_KERNEL);
|
||||
if (unlikely(!p))
|
||||
return -ENOMEM;
|
||||
|
||||
memcpy(p, &name->iname, EMBEDDED_NAME_MAX);
|
||||
len = strncpy_from_user(p + EMBEDDED_NAME_MAX,
|
||||
filename + EMBEDDED_NAME_MAX,
|
||||
PATH_MAX - EMBEDDED_NAME_MAX);
|
||||
if (unlikely(len < 0))
|
||||
return len;
|
||||
if (unlikely(len == PATH_MAX - EMBEDDED_NAME_MAX))
|
||||
return -ENAMETOOLONG;
|
||||
name->name = no_free_ptr(p);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct filename *
|
||||
do_getname(const char __user *filename, int flags, bool incomplete)
|
||||
{
|
||||
struct filename *result;
|
||||
char *kname;
|
||||
int len;
|
||||
|
||||
result = audit_reusename(filename);
|
||||
if (result)
|
||||
return result;
|
||||
|
||||
result = __getname();
|
||||
result = alloc_filename();
|
||||
if (unlikely(!result))
|
||||
return ERR_PTR(-ENOMEM);
|
||||
|
||||
|
|
@ -159,16 +195,9 @@ getname_flags(const char __user *filename, int flags)
|
|||
* Handle both empty path and copy failure in one go.
|
||||
*/
|
||||
if (unlikely(len <= 0)) {
|
||||
if (unlikely(len < 0)) {
|
||||
__putname(result);
|
||||
return ERR_PTR(len);
|
||||
}
|
||||
|
||||
/* The empty path is special. */
|
||||
if (!(flags & LOOKUP_EMPTY)) {
|
||||
__putname(result);
|
||||
return ERR_PTR(-ENOENT);
|
||||
}
|
||||
if (!len && !(flags & LOOKUP_EMPTY))
|
||||
len = -ENOENT;
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
@ -177,44 +206,25 @@ getname_flags(const char __user *filename, int flags)
|
|||
* names_cache allocation for the pathname, and re-do the copy from
|
||||
* userland.
|
||||
*/
|
||||
if (unlikely(len == EMBEDDED_NAME_MAX)) {
|
||||
const size_t size = offsetof(struct filename, iname[1]);
|
||||
kname = (char *)result;
|
||||
|
||||
/*
|
||||
* size is chosen that way we to guarantee that
|
||||
* result->iname[0] is within the same object and that
|
||||
* kname can't be equal to result->iname, no matter what.
|
||||
*/
|
||||
result = kzalloc(size, GFP_KERNEL);
|
||||
if (unlikely(!result)) {
|
||||
__putname(kname);
|
||||
return ERR_PTR(-ENOMEM);
|
||||
}
|
||||
result->name = kname;
|
||||
len = strncpy_from_user(kname, filename, PATH_MAX);
|
||||
if (unlikely(len < 0)) {
|
||||
__putname(kname);
|
||||
kfree(result);
|
||||
return ERR_PTR(len);
|
||||
}
|
||||
/* The empty path is special. */
|
||||
if (unlikely(!len) && !(flags & LOOKUP_EMPTY)) {
|
||||
__putname(kname);
|
||||
kfree(result);
|
||||
return ERR_PTR(-ENOENT);
|
||||
}
|
||||
if (unlikely(len == PATH_MAX)) {
|
||||
__putname(kname);
|
||||
kfree(result);
|
||||
return ERR_PTR(-ENAMETOOLONG);
|
||||
}
|
||||
if (unlikely(len == EMBEDDED_NAME_MAX))
|
||||
len = getname_long(result, filename);
|
||||
if (unlikely(len < 0)) {
|
||||
free_filename(result);
|
||||
return ERR_PTR(len);
|
||||
}
|
||||
initname(result, filename);
|
||||
audit_getname(result);
|
||||
|
||||
initname(result);
|
||||
if (likely(!incomplete))
|
||||
audit_getname(result);
|
||||
return result;
|
||||
}
|
||||
|
||||
struct filename *
|
||||
getname_flags(const char __user *filename, int flags)
|
||||
{
|
||||
return do_getname(filename, flags, false);
|
||||
}
|
||||
|
||||
struct filename *getname_uflags(const char __user *filename, int uflags)
|
||||
{
|
||||
int flags = (uflags & AT_EMPTY_PATH) ? LOOKUP_EMPTY : 0;
|
||||
|
|
@ -224,7 +234,6 @@ struct filename *getname_uflags(const char __user *filename, int uflags)
|
|||
|
||||
struct filename *__getname_maybe_null(const char __user *pathname)
|
||||
{
|
||||
struct filename *name;
|
||||
char c;
|
||||
|
||||
/* try to save on allocations; loss on um, though */
|
||||
|
|
@ -233,45 +242,47 @@ struct filename *__getname_maybe_null(const char __user *pathname)
|
|||
if (!c)
|
||||
return NULL;
|
||||
|
||||
name = getname_flags(pathname, LOOKUP_EMPTY);
|
||||
if (!IS_ERR(name) && !(name->name[0])) {
|
||||
putname(name);
|
||||
name = NULL;
|
||||
}
|
||||
return name;
|
||||
CLASS(filename_flags, name)(pathname, LOOKUP_EMPTY);
|
||||
/* empty pathname translates to NULL */
|
||||
if (!IS_ERR(name) && !(name->name[0]))
|
||||
return NULL;
|
||||
return no_free_ptr(name);
|
||||
}
|
||||
|
||||
struct filename *getname_kernel(const char * filename)
|
||||
static struct filename *do_getname_kernel(const char *filename, bool incomplete)
|
||||
{
|
||||
struct filename *result;
|
||||
int len = strlen(filename) + 1;
|
||||
char *p;
|
||||
|
||||
result = __getname();
|
||||
if (unlikely(len > PATH_MAX))
|
||||
return ERR_PTR(-ENAMETOOLONG);
|
||||
|
||||
result = alloc_filename();
|
||||
if (unlikely(!result))
|
||||
return ERR_PTR(-ENOMEM);
|
||||
|
||||
if (len <= EMBEDDED_NAME_MAX) {
|
||||
result->name = (char *)result->iname;
|
||||
} else if (len <= PATH_MAX) {
|
||||
const size_t size = offsetof(struct filename, iname[1]);
|
||||
struct filename *tmp;
|
||||
|
||||
tmp = kmalloc(size, GFP_KERNEL);
|
||||
if (unlikely(!tmp)) {
|
||||
__putname(result);
|
||||
p = (char *)result->iname;
|
||||
memcpy(p, filename, len);
|
||||
} else {
|
||||
p = kmemdup(filename, len, GFP_KERNEL);
|
||||
if (unlikely(!p)) {
|
||||
free_filename(result);
|
||||
return ERR_PTR(-ENOMEM);
|
||||
}
|
||||
tmp->name = (char *)result;
|
||||
result = tmp;
|
||||
} else {
|
||||
__putname(result);
|
||||
return ERR_PTR(-ENAMETOOLONG);
|
||||
}
|
||||
memcpy((char *)result->name, filename, len);
|
||||
initname(result, NULL);
|
||||
audit_getname(result);
|
||||
result->name = p;
|
||||
initname(result);
|
||||
if (likely(!incomplete))
|
||||
audit_getname(result);
|
||||
return result;
|
||||
}
|
||||
|
||||
struct filename *getname_kernel(const char *filename)
|
||||
{
|
||||
return do_getname_kernel(filename, false);
|
||||
}
|
||||
EXPORT_SYMBOL(getname_kernel);
|
||||
|
||||
void putname(struct filename *name)
|
||||
|
|
@ -281,23 +292,64 @@ void putname(struct filename *name)
|
|||
if (IS_ERR_OR_NULL(name))
|
||||
return;
|
||||
|
||||
refcnt = atomic_read(&name->refcnt);
|
||||
refcnt = name->refcnt;
|
||||
if (unlikely(refcnt != 1)) {
|
||||
if (WARN_ON_ONCE(!refcnt))
|
||||
return;
|
||||
|
||||
if (!atomic_dec_and_test(&name->refcnt))
|
||||
return;
|
||||
name->refcnt--;
|
||||
return;
|
||||
}
|
||||
|
||||
if (unlikely(name->name != name->iname)) {
|
||||
__putname(name->name);
|
||||
kfree(name);
|
||||
} else
|
||||
__putname(name);
|
||||
if (unlikely(name->name != name->iname))
|
||||
kfree(name->name);
|
||||
free_filename(name);
|
||||
}
|
||||
EXPORT_SYMBOL(putname);
|
||||
|
||||
static inline int __delayed_getname(struct delayed_filename *v,
|
||||
const char __user *string, int flags)
|
||||
{
|
||||
v->__incomplete_filename = do_getname(string, flags, true);
|
||||
return PTR_ERR_OR_ZERO(v->__incomplete_filename);
|
||||
}
|
||||
|
||||
int delayed_getname(struct delayed_filename *v, const char __user *string)
|
||||
{
|
||||
return __delayed_getname(v, string, 0);
|
||||
}
|
||||
|
||||
int delayed_getname_uflags(struct delayed_filename *v, const char __user *string,
|
||||
int uflags)
|
||||
{
|
||||
int flags = (uflags & AT_EMPTY_PATH) ? LOOKUP_EMPTY : 0;
|
||||
return __delayed_getname(v, string, flags);
|
||||
}
|
||||
|
||||
int putname_to_delayed(struct delayed_filename *v, struct filename *name)
|
||||
{
|
||||
if (likely(name->refcnt == 1)) {
|
||||
v->__incomplete_filename = name;
|
||||
return 0;
|
||||
}
|
||||
name->refcnt--;
|
||||
v->__incomplete_filename = do_getname_kernel(name->name, true);
|
||||
return PTR_ERR_OR_ZERO(v->__incomplete_filename);
|
||||
}
|
||||
|
||||
void dismiss_delayed_filename(struct delayed_filename *v)
|
||||
{
|
||||
putname(no_free_ptr(v->__incomplete_filename));
|
||||
}
|
||||
|
||||
struct filename *complete_getname(struct delayed_filename *v)
|
||||
{
|
||||
struct filename *res = no_free_ptr(v->__incomplete_filename);
|
||||
if (!IS_ERR(res))
|
||||
audit_getname(res);
|
||||
return res;
|
||||
}
|
||||
|
||||
/**
|
||||
* check_acl - perform ACL permission checking
|
||||
* @idmap: idmap of the mount the inode was found from
|
||||
|
|
@ -2948,7 +3000,7 @@ drop:
|
|||
struct dentry *kern_path_parent(const char *name, struct path *path)
|
||||
{
|
||||
struct path parent_path __free(path_put) = {};
|
||||
struct filename *filename __free(putname) = getname_kernel(name);
|
||||
CLASS(filename_kernel, filename)(name);
|
||||
struct dentry *d;
|
||||
struct qstr last;
|
||||
int type, error;
|
||||
|
|
@ -2969,33 +3021,23 @@ struct dentry *kern_path_parent(const char *name, struct path *path)
|
|||
|
||||
struct dentry *start_removing_path(const char *name, struct path *path)
|
||||
{
|
||||
struct filename *filename = getname_kernel(name);
|
||||
struct dentry *res = __start_removing_path(AT_FDCWD, filename, path);
|
||||
|
||||
putname(filename);
|
||||
return res;
|
||||
CLASS(filename_kernel, filename)(name);
|
||||
return __start_removing_path(AT_FDCWD, filename, path);
|
||||
}
|
||||
|
||||
struct dentry *start_removing_user_path_at(int dfd,
|
||||
const char __user *name,
|
||||
struct path *path)
|
||||
{
|
||||
struct filename *filename = getname(name);
|
||||
struct dentry *res = __start_removing_path(dfd, filename, path);
|
||||
|
||||
putname(filename);
|
||||
return res;
|
||||
CLASS(filename, filename)(name);
|
||||
return __start_removing_path(dfd, filename, path);
|
||||
}
|
||||
EXPORT_SYMBOL(start_removing_user_path_at);
|
||||
|
||||
int kern_path(const char *name, unsigned int flags, struct path *path)
|
||||
{
|
||||
struct filename *filename = getname_kernel(name);
|
||||
int ret = filename_lookup(AT_FDCWD, filename, flags, path, NULL);
|
||||
|
||||
putname(filename);
|
||||
return ret;
|
||||
|
||||
CLASS(filename_kernel, filename)(name);
|
||||
return filename_lookup(AT_FDCWD, filename, flags, path, NULL);
|
||||
}
|
||||
EXPORT_SYMBOL(kern_path);
|
||||
|
||||
|
|
@ -3029,15 +3071,11 @@ int vfs_path_lookup(struct dentry *dentry, struct vfsmount *mnt,
|
|||
const char *name, unsigned int flags,
|
||||
struct path *path)
|
||||
{
|
||||
struct filename *filename;
|
||||
CLASS(filename_kernel, filename)(name);
|
||||
struct path root = {.mnt = mnt, .dentry = dentry};
|
||||
int ret;
|
||||
|
||||
filename = getname_kernel(name);
|
||||
/* the first argument of filename_lookup() is ignored with root */
|
||||
ret = filename_lookup(AT_FDCWD, filename, flags, path, &root);
|
||||
putname(filename);
|
||||
return ret;
|
||||
return filename_lookup(AT_FDCWD, filename, flags, path, &root);
|
||||
}
|
||||
EXPORT_SYMBOL(vfs_path_lookup);
|
||||
|
||||
|
|
@ -3570,11 +3608,8 @@ int path_pts(struct path *path)
|
|||
int user_path_at(int dfd, const char __user *name, unsigned flags,
|
||||
struct path *path)
|
||||
{
|
||||
struct filename *filename = getname_flags(name, flags);
|
||||
int ret = filename_lookup(dfd, filename, flags, path, NULL);
|
||||
|
||||
putname(filename);
|
||||
return ret;
|
||||
CLASS(filename_flags, filename)(name, flags);
|
||||
return filename_lookup(dfd, filename, flags, path, NULL);
|
||||
}
|
||||
EXPORT_SYMBOL(user_path_at);
|
||||
|
||||
|
|
@ -4811,13 +4846,15 @@ static struct file *path_openat(struct nameidata *nd,
|
|||
return ERR_PTR(error);
|
||||
}
|
||||
|
||||
struct file *do_filp_open(int dfd, struct filename *pathname,
|
||||
struct file *do_file_open(int dfd, struct filename *pathname,
|
||||
const struct open_flags *op)
|
||||
{
|
||||
struct nameidata nd;
|
||||
int flags = op->lookup_flags;
|
||||
struct file *filp;
|
||||
|
||||
if (IS_ERR(pathname))
|
||||
return ERR_CAST(pathname);
|
||||
set_nameidata(&nd, dfd, pathname, NULL);
|
||||
filp = path_openat(&nd, op, flags | LOOKUP_RCU);
|
||||
if (unlikely(filp == ERR_PTR(-ECHILD)))
|
||||
|
|
@ -4833,13 +4870,12 @@ struct file *do_file_open_root(const struct path *root,
|
|||
{
|
||||
struct nameidata nd;
|
||||
struct file *file;
|
||||
struct filename *filename;
|
||||
int flags = op->lookup_flags;
|
||||
|
||||
if (d_is_symlink(root->dentry) && op->intent & LOOKUP_OPEN)
|
||||
return ERR_PTR(-ELOOP);
|
||||
|
||||
filename = getname_kernel(name);
|
||||
CLASS(filename_kernel, filename)(name);
|
||||
if (IS_ERR(filename))
|
||||
return ERR_CAST(filename);
|
||||
|
||||
|
|
@ -4850,7 +4886,6 @@ struct file *do_file_open_root(const struct path *root,
|
|||
if (unlikely(file == ERR_PTR(-ESTALE)))
|
||||
file = path_openat(&nd, op, flags | LOOKUP_REVAL);
|
||||
restore_nameidata();
|
||||
putname(filename);
|
||||
return file;
|
||||
}
|
||||
|
||||
|
|
@ -4906,11 +4941,8 @@ out:
|
|||
struct dentry *start_creating_path(int dfd, const char *pathname,
|
||||
struct path *path, unsigned int lookup_flags)
|
||||
{
|
||||
struct filename *filename = getname_kernel(pathname);
|
||||
struct dentry *res = filename_create(dfd, filename, path, lookup_flags);
|
||||
|
||||
putname(filename);
|
||||
return res;
|
||||
CLASS(filename_kernel, filename)(pathname);
|
||||
return filename_create(dfd, filename, path, lookup_flags);
|
||||
}
|
||||
EXPORT_SYMBOL(start_creating_path);
|
||||
|
||||
|
|
@ -4937,11 +4969,8 @@ inline struct dentry *start_creating_user_path(
|
|||
int dfd, const char __user *pathname,
|
||||
struct path *path, unsigned int lookup_flags)
|
||||
{
|
||||
struct filename *filename = getname(pathname);
|
||||
struct dentry *res = filename_create(dfd, filename, path, lookup_flags);
|
||||
|
||||
putname(filename);
|
||||
return res;
|
||||
CLASS(filename, filename)(pathname);
|
||||
return filename_create(dfd, filename, path, lookup_flags);
|
||||
}
|
||||
EXPORT_SYMBOL(start_creating_user_path);
|
||||
|
||||
|
|
@ -5084,8 +5113,8 @@ static int may_mknod(umode_t mode)
|
|||
}
|
||||
}
|
||||
|
||||
static int do_mknodat(int dfd, struct filename *name, umode_t mode,
|
||||
unsigned int dev)
|
||||
int filename_mknodat(int dfd, struct filename *name, umode_t mode,
|
||||
unsigned int dev)
|
||||
{
|
||||
struct delegated_inode di = { };
|
||||
struct mnt_idmap *idmap;
|
||||
|
|
@ -5096,12 +5125,11 @@ static int do_mknodat(int dfd, struct filename *name, umode_t mode,
|
|||
|
||||
error = may_mknod(mode);
|
||||
if (error)
|
||||
goto out1;
|
||||
return error;
|
||||
retry:
|
||||
dentry = filename_create(dfd, name, &path, lookup_flags);
|
||||
error = PTR_ERR(dentry);
|
||||
if (IS_ERR(dentry))
|
||||
goto out1;
|
||||
return PTR_ERR(dentry);
|
||||
|
||||
error = security_path_mknod(&path, dentry,
|
||||
mode_strip_umask(path.dentry->d_inode, mode), dev);
|
||||
|
|
@ -5135,20 +5163,20 @@ out2:
|
|||
lookup_flags |= LOOKUP_REVAL;
|
||||
goto retry;
|
||||
}
|
||||
out1:
|
||||
putname(name);
|
||||
return error;
|
||||
}
|
||||
|
||||
SYSCALL_DEFINE4(mknodat, int, dfd, const char __user *, filename, umode_t, mode,
|
||||
unsigned int, dev)
|
||||
{
|
||||
return do_mknodat(dfd, getname(filename), mode, dev);
|
||||
CLASS(filename, name)(filename);
|
||||
return filename_mknodat(dfd, name, mode, dev);
|
||||
}
|
||||
|
||||
SYSCALL_DEFINE3(mknod, const char __user *, filename, umode_t, mode, unsigned, dev)
|
||||
{
|
||||
return do_mknodat(AT_FDCWD, getname(filename), mode, dev);
|
||||
CLASS(filename, name)(filename);
|
||||
return filename_mknodat(AT_FDCWD, name, mode, dev);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -5219,7 +5247,7 @@ err:
|
|||
}
|
||||
EXPORT_SYMBOL(vfs_mkdir);
|
||||
|
||||
int do_mkdirat(int dfd, struct filename *name, umode_t mode)
|
||||
int filename_mkdirat(int dfd, struct filename *name, umode_t mode)
|
||||
{
|
||||
struct dentry *dentry;
|
||||
struct path path;
|
||||
|
|
@ -5229,9 +5257,8 @@ int do_mkdirat(int dfd, struct filename *name, umode_t mode)
|
|||
|
||||
retry:
|
||||
dentry = filename_create(dfd, name, &path, lookup_flags);
|
||||
error = PTR_ERR(dentry);
|
||||
if (IS_ERR(dentry))
|
||||
goto out_putname;
|
||||
return PTR_ERR(dentry);
|
||||
|
||||
error = security_path_mkdir(&path, dentry,
|
||||
mode_strip_umask(path.dentry->d_inode, mode));
|
||||
|
|
@ -5251,19 +5278,19 @@ retry:
|
|||
lookup_flags |= LOOKUP_REVAL;
|
||||
goto retry;
|
||||
}
|
||||
out_putname:
|
||||
putname(name);
|
||||
return error;
|
||||
}
|
||||
|
||||
SYSCALL_DEFINE3(mkdirat, int, dfd, const char __user *, pathname, umode_t, mode)
|
||||
{
|
||||
return do_mkdirat(dfd, getname(pathname), mode);
|
||||
CLASS(filename, name)(pathname);
|
||||
return filename_mkdirat(dfd, name, mode);
|
||||
}
|
||||
|
||||
SYSCALL_DEFINE2(mkdir, const char __user *, pathname, umode_t, mode)
|
||||
{
|
||||
return do_mkdirat(AT_FDCWD, getname(pathname), mode);
|
||||
CLASS(filename, name)(pathname);
|
||||
return filename_mkdirat(AT_FDCWD, name, mode);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -5326,7 +5353,7 @@ out:
|
|||
}
|
||||
EXPORT_SYMBOL(vfs_rmdir);
|
||||
|
||||
int do_rmdir(int dfd, struct filename *name)
|
||||
int filename_rmdir(int dfd, struct filename *name)
|
||||
{
|
||||
int error;
|
||||
struct dentry *dentry;
|
||||
|
|
@ -5338,7 +5365,7 @@ int do_rmdir(int dfd, struct filename *name)
|
|||
retry:
|
||||
error = filename_parentat(dfd, name, lookup_flags, &path, &last, &type);
|
||||
if (error)
|
||||
goto exit1;
|
||||
return error;
|
||||
|
||||
switch (type) {
|
||||
case LAST_DOTDOT:
|
||||
|
|
@ -5380,14 +5407,13 @@ exit2:
|
|||
lookup_flags |= LOOKUP_REVAL;
|
||||
goto retry;
|
||||
}
|
||||
exit1:
|
||||
putname(name);
|
||||
return error;
|
||||
}
|
||||
|
||||
SYSCALL_DEFINE1(rmdir, const char __user *, pathname)
|
||||
{
|
||||
return do_rmdir(AT_FDCWD, getname(pathname));
|
||||
CLASS(filename, name)(pathname);
|
||||
return filename_rmdir(AT_FDCWD, name);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -5469,7 +5495,7 @@ EXPORT_SYMBOL(vfs_unlink);
|
|||
* writeout happening, and we don't want to prevent access to the directory
|
||||
* while waiting on the I/O.
|
||||
*/
|
||||
int do_unlinkat(int dfd, struct filename *name)
|
||||
int filename_unlinkat(int dfd, struct filename *name)
|
||||
{
|
||||
int error;
|
||||
struct dentry *dentry;
|
||||
|
|
@ -5482,7 +5508,7 @@ int do_unlinkat(int dfd, struct filename *name)
|
|||
retry:
|
||||
error = filename_parentat(dfd, name, lookup_flags, &path, &last, &type);
|
||||
if (error)
|
||||
goto exit_putname;
|
||||
return error;
|
||||
|
||||
error = -EISDIR;
|
||||
if (type != LAST_NORM)
|
||||
|
|
@ -5529,8 +5555,6 @@ exit_path_put:
|
|||
lookup_flags |= LOOKUP_REVAL;
|
||||
goto retry;
|
||||
}
|
||||
exit_putname:
|
||||
putname(name);
|
||||
return error;
|
||||
}
|
||||
|
||||
|
|
@ -5539,14 +5563,16 @@ SYSCALL_DEFINE3(unlinkat, int, dfd, const char __user *, pathname, int, flag)
|
|||
if ((flag & ~AT_REMOVEDIR) != 0)
|
||||
return -EINVAL;
|
||||
|
||||
CLASS(filename, name)(pathname);
|
||||
if (flag & AT_REMOVEDIR)
|
||||
return do_rmdir(dfd, getname(pathname));
|
||||
return do_unlinkat(dfd, getname(pathname));
|
||||
return filename_rmdir(dfd, name);
|
||||
return filename_unlinkat(dfd, name);
|
||||
}
|
||||
|
||||
SYSCALL_DEFINE1(unlink, const char __user *, pathname)
|
||||
{
|
||||
return do_unlinkat(AT_FDCWD, getname(pathname));
|
||||
CLASS(filename, name)(pathname);
|
||||
return filename_unlinkat(AT_FDCWD, name);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -5593,7 +5619,7 @@ int vfs_symlink(struct mnt_idmap *idmap, struct inode *dir,
|
|||
}
|
||||
EXPORT_SYMBOL(vfs_symlink);
|
||||
|
||||
int do_symlinkat(struct filename *from, int newdfd, struct filename *to)
|
||||
int filename_symlinkat(struct filename *from, int newdfd, struct filename *to)
|
||||
{
|
||||
int error;
|
||||
struct dentry *dentry;
|
||||
|
|
@ -5601,15 +5627,13 @@ int do_symlinkat(struct filename *from, int newdfd, struct filename *to)
|
|||
unsigned int lookup_flags = 0;
|
||||
struct delegated_inode delegated_inode = { };
|
||||
|
||||
if (IS_ERR(from)) {
|
||||
error = PTR_ERR(from);
|
||||
goto out_putnames;
|
||||
}
|
||||
if (IS_ERR(from))
|
||||
return PTR_ERR(from);
|
||||
|
||||
retry:
|
||||
dentry = filename_create(newdfd, to, &path, lookup_flags);
|
||||
error = PTR_ERR(dentry);
|
||||
if (IS_ERR(dentry))
|
||||
goto out_putnames;
|
||||
return PTR_ERR(dentry);
|
||||
|
||||
error = security_path_symlink(&path, dentry, from->name);
|
||||
if (!error)
|
||||
|
|
@ -5625,21 +5649,22 @@ retry:
|
|||
lookup_flags |= LOOKUP_REVAL;
|
||||
goto retry;
|
||||
}
|
||||
out_putnames:
|
||||
putname(to);
|
||||
putname(from);
|
||||
return error;
|
||||
}
|
||||
|
||||
SYSCALL_DEFINE3(symlinkat, const char __user *, oldname,
|
||||
int, newdfd, const char __user *, newname)
|
||||
{
|
||||
return do_symlinkat(getname(oldname), newdfd, getname(newname));
|
||||
CLASS(filename, old)(oldname);
|
||||
CLASS(filename, new)(newname);
|
||||
return filename_symlinkat(old, newdfd, new);
|
||||
}
|
||||
|
||||
SYSCALL_DEFINE2(symlink, const char __user *, oldname, const char __user *, newname)
|
||||
{
|
||||
return do_symlinkat(getname(oldname), AT_FDCWD, getname(newname));
|
||||
CLASS(filename, old)(oldname);
|
||||
CLASS(filename, new)(newname);
|
||||
return filename_symlinkat(old, AT_FDCWD, new);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -5741,9 +5766,9 @@ EXPORT_SYMBOL(vfs_link);
|
|||
* We don't follow them on the oldname either to be compatible
|
||||
* with linux 2.0, and to avoid hard-linking to directories
|
||||
* and other special files. --ADM
|
||||
*/
|
||||
int do_linkat(int olddfd, struct filename *old, int newdfd,
|
||||
struct filename *new, int flags)
|
||||
*/
|
||||
int filename_linkat(int olddfd, struct filename *old,
|
||||
int newdfd, struct filename *new, int flags)
|
||||
{
|
||||
struct mnt_idmap *idmap;
|
||||
struct dentry *new_dentry;
|
||||
|
|
@ -5752,10 +5777,8 @@ int do_linkat(int olddfd, struct filename *old, int newdfd,
|
|||
int how = 0;
|
||||
int error;
|
||||
|
||||
if ((flags & ~(AT_SYMLINK_FOLLOW | AT_EMPTY_PATH)) != 0) {
|
||||
error = -EINVAL;
|
||||
goto out_putnames;
|
||||
}
|
||||
if ((flags & ~(AT_SYMLINK_FOLLOW | AT_EMPTY_PATH)) != 0)
|
||||
return -EINVAL;
|
||||
/*
|
||||
* To use null names we require CAP_DAC_READ_SEARCH or
|
||||
* that the open-time creds of the dfd matches current.
|
||||
|
|
@ -5770,7 +5793,7 @@ int do_linkat(int olddfd, struct filename *old, int newdfd,
|
|||
retry:
|
||||
error = filename_lookup(olddfd, old, how, &old_path, NULL);
|
||||
if (error)
|
||||
goto out_putnames;
|
||||
return error;
|
||||
|
||||
new_dentry = filename_create(newdfd, new, &new_path,
|
||||
(how & LOOKUP_REVAL));
|
||||
|
|
@ -5806,23 +5829,22 @@ out_dput:
|
|||
}
|
||||
out_putpath:
|
||||
path_put(&old_path);
|
||||
out_putnames:
|
||||
putname(old);
|
||||
putname(new);
|
||||
|
||||
return error;
|
||||
}
|
||||
|
||||
SYSCALL_DEFINE5(linkat, int, olddfd, const char __user *, oldname,
|
||||
int, newdfd, const char __user *, newname, int, flags)
|
||||
{
|
||||
return do_linkat(olddfd, getname_uflags(oldname, flags),
|
||||
newdfd, getname(newname), flags);
|
||||
CLASS(filename_uflags, old)(oldname, flags);
|
||||
CLASS(filename, new)(newname);
|
||||
return filename_linkat(olddfd, old, newdfd, new, flags);
|
||||
}
|
||||
|
||||
SYSCALL_DEFINE2(link, const char __user *, oldname, const char __user *, newname)
|
||||
{
|
||||
return do_linkat(AT_FDCWD, getname(oldname), AT_FDCWD, getname(newname), 0);
|
||||
CLASS(filename, old)(oldname);
|
||||
CLASS(filename, new)(newname);
|
||||
return filename_linkat(AT_FDCWD, old, AT_FDCWD, new, 0);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -6040,8 +6062,8 @@ out:
|
|||
}
|
||||
EXPORT_SYMBOL(vfs_rename);
|
||||
|
||||
int do_renameat2(int olddfd, struct filename *from, int newdfd,
|
||||
struct filename *to, unsigned int flags)
|
||||
int filename_renameat2(int olddfd, struct filename *from,
|
||||
int newdfd, struct filename *to, unsigned int flags)
|
||||
{
|
||||
struct renamedata rd;
|
||||
struct path old_path, new_path;
|
||||
|
|
@ -6050,20 +6072,20 @@ int do_renameat2(int olddfd, struct filename *from, int newdfd,
|
|||
struct delegated_inode delegated_inode = { };
|
||||
unsigned int lookup_flags = 0;
|
||||
bool should_retry = false;
|
||||
int error = -EINVAL;
|
||||
int error;
|
||||
|
||||
if (flags & ~(RENAME_NOREPLACE | RENAME_EXCHANGE | RENAME_WHITEOUT))
|
||||
goto put_names;
|
||||
return -EINVAL;
|
||||
|
||||
if ((flags & (RENAME_NOREPLACE | RENAME_WHITEOUT)) &&
|
||||
(flags & RENAME_EXCHANGE))
|
||||
goto put_names;
|
||||
return -EINVAL;
|
||||
|
||||
retry:
|
||||
error = filename_parentat(olddfd, from, lookup_flags, &old_path,
|
||||
&old_last, &old_type);
|
||||
if (error)
|
||||
goto put_names;
|
||||
return error;
|
||||
|
||||
error = filename_parentat(newdfd, to, lookup_flags, &new_path, &new_last,
|
||||
&new_type);
|
||||
|
|
@ -6140,30 +6162,30 @@ exit1:
|
|||
lookup_flags |= LOOKUP_REVAL;
|
||||
goto retry;
|
||||
}
|
||||
put_names:
|
||||
putname(from);
|
||||
putname(to);
|
||||
return error;
|
||||
}
|
||||
|
||||
SYSCALL_DEFINE5(renameat2, int, olddfd, const char __user *, oldname,
|
||||
int, newdfd, const char __user *, newname, unsigned int, flags)
|
||||
{
|
||||
return do_renameat2(olddfd, getname(oldname), newdfd, getname(newname),
|
||||
flags);
|
||||
CLASS(filename, old)(oldname);
|
||||
CLASS(filename, new)(newname);
|
||||
return filename_renameat2(olddfd, old, newdfd, new, flags);
|
||||
}
|
||||
|
||||
SYSCALL_DEFINE4(renameat, int, olddfd, const char __user *, oldname,
|
||||
int, newdfd, const char __user *, newname)
|
||||
{
|
||||
return do_renameat2(olddfd, getname(oldname), newdfd, getname(newname),
|
||||
0);
|
||||
CLASS(filename, old)(oldname);
|
||||
CLASS(filename, new)(newname);
|
||||
return filename_renameat2(olddfd, old, newdfd, new, 0);
|
||||
}
|
||||
|
||||
SYSCALL_DEFINE2(rename, const char __user *, oldname, const char __user *, newname)
|
||||
{
|
||||
return do_renameat2(AT_FDCWD, getname(oldname), AT_FDCWD,
|
||||
getname(newname), 0);
|
||||
CLASS(filename, old)(oldname);
|
||||
CLASS(filename, new)(newname);
|
||||
return filename_renameat2(AT_FDCWD, old, AT_FDCWD, new, 0);
|
||||
}
|
||||
|
||||
int readlink_copy(char __user *buffer, int buflen, const char *link, int linklen)
|
||||
|
|
|
|||
|
|
@ -3195,8 +3195,6 @@ static struct file *vfs_open_tree(int dfd, const char __user *filename, unsigned
|
|||
lookup_flags &= ~LOOKUP_AUTOMOUNT;
|
||||
if (flags & AT_SYMLINK_NOFOLLOW)
|
||||
lookup_flags &= ~LOOKUP_FOLLOW;
|
||||
if (flags & AT_EMPTY_PATH)
|
||||
lookup_flags |= LOOKUP_EMPTY;
|
||||
|
||||
/*
|
||||
* If we create a new mount namespace with the cloned mount tree we
|
||||
|
|
@ -3210,7 +3208,8 @@ static struct file *vfs_open_tree(int dfd, const char __user *filename, unsigned
|
|||
if ((flags & OPEN_TREE_CLONE) && !may_mount())
|
||||
return ERR_PTR(-EPERM);
|
||||
|
||||
ret = user_path_at(dfd, filename, lookup_flags, &path);
|
||||
CLASS(filename_uflags, name)(filename, flags);
|
||||
ret = filename_lookup(dfd, name, lookup_flags, &path, NULL);
|
||||
if (unlikely(ret))
|
||||
return ERR_PTR(ret);
|
||||
|
||||
|
|
@ -4528,8 +4527,6 @@ SYSCALL_DEFINE5(move_mount,
|
|||
{
|
||||
struct path to_path __free(path_put) = {};
|
||||
struct path from_path __free(path_put) = {};
|
||||
struct filename *to_name __free(putname) = NULL;
|
||||
struct filename *from_name __free(putname) = NULL;
|
||||
unsigned int lflags, uflags;
|
||||
enum mnt_tree_flags_t mflags = 0;
|
||||
int ret = 0;
|
||||
|
|
@ -4551,10 +4548,7 @@ SYSCALL_DEFINE5(move_mount,
|
|||
if (flags & MOVE_MOUNT_T_EMPTY_PATH)
|
||||
uflags = AT_EMPTY_PATH;
|
||||
|
||||
to_name = getname_maybe_null(to_pathname, uflags);
|
||||
if (IS_ERR(to_name))
|
||||
return PTR_ERR(to_name);
|
||||
|
||||
CLASS(filename_maybe_null,to_name)(to_pathname, uflags);
|
||||
if (!to_name && to_dfd >= 0) {
|
||||
CLASS(fd_raw, f_to)(to_dfd);
|
||||
if (fd_empty(f_to))
|
||||
|
|
@ -4577,10 +4571,7 @@ SYSCALL_DEFINE5(move_mount,
|
|||
if (flags & MOVE_MOUNT_F_EMPTY_PATH)
|
||||
uflags = AT_EMPTY_PATH;
|
||||
|
||||
from_name = getname_maybe_null(from_pathname, uflags);
|
||||
if (IS_ERR(from_name))
|
||||
return PTR_ERR(from_name);
|
||||
|
||||
CLASS(filename_maybe_null,from_name)(from_pathname, uflags);
|
||||
if (!from_name && from_dfd >= 0) {
|
||||
CLASS(fd_raw, f_from)(from_dfd);
|
||||
if (fd_empty(f_from))
|
||||
|
|
@ -5116,8 +5107,6 @@ SYSCALL_DEFINE5(mount_setattr, int, dfd, const char __user *, path,
|
|||
lookup_flags &= ~LOOKUP_AUTOMOUNT;
|
||||
if (flags & AT_SYMLINK_NOFOLLOW)
|
||||
lookup_flags &= ~LOOKUP_FOLLOW;
|
||||
if (flags & AT_EMPTY_PATH)
|
||||
lookup_flags |= LOOKUP_EMPTY;
|
||||
|
||||
kattr = (struct mount_kattr) {
|
||||
.lookup_flags = lookup_flags,
|
||||
|
|
@ -5130,7 +5119,8 @@ SYSCALL_DEFINE5(mount_setattr, int, dfd, const char __user *, path,
|
|||
if (err <= 0)
|
||||
return err;
|
||||
|
||||
err = user_path_at(dfd, path, kattr.lookup_flags, &target);
|
||||
CLASS(filename_uflags, name)(path, flags);
|
||||
err = filename_lookup(dfd, name, kattr.lookup_flags, &target, NULL);
|
||||
if (!err) {
|
||||
err = do_mount_setattr(&target, &kattr);
|
||||
path_put(&target);
|
||||
|
|
|
|||
|
|
@ -424,8 +424,7 @@ static int ntfs_readdir(struct file *file, struct dir_context *ctx)
|
|||
if (!dir_emit_dots(file, ctx))
|
||||
return 0;
|
||||
|
||||
/* Allocate PATH_MAX bytes. */
|
||||
name = __getname();
|
||||
name = kmalloc(PATH_MAX, GFP_KERNEL);
|
||||
if (!name)
|
||||
return -ENOMEM;
|
||||
|
||||
|
|
@ -503,7 +502,7 @@ static int ntfs_readdir(struct file *file, struct dir_context *ctx)
|
|||
|
||||
out:
|
||||
|
||||
__putname(name);
|
||||
kfree(name);
|
||||
put_indx_node(node);
|
||||
|
||||
if (err == 1) {
|
||||
|
|
|
|||
|
|
@ -2627,7 +2627,7 @@ int ntfs_set_label(struct ntfs_sb_info *sbi, u8 *label, int len)
|
|||
u32 uni_bytes;
|
||||
struct ntfs_inode *ni = sbi->volume.ni;
|
||||
/* Allocate PATH_MAX bytes. */
|
||||
struct cpu_str *uni = __getname();
|
||||
struct cpu_str *uni = kmalloc(PATH_MAX, GFP_KERNEL);
|
||||
|
||||
if (!uni)
|
||||
return -ENOMEM;
|
||||
|
|
@ -2671,6 +2671,6 @@ unlock_out:
|
|||
err = _ni_write_inode(&ni->vfs_inode, 0);
|
||||
|
||||
out:
|
||||
__putname(uni);
|
||||
kfree(uni);
|
||||
return err;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1281,7 +1281,7 @@ int ntfs_create_inode(struct mnt_idmap *idmap, struct inode *dir,
|
|||
fa |= FILE_ATTRIBUTE_READONLY;
|
||||
|
||||
/* Allocate PATH_MAX bytes. */
|
||||
new_de = kmem_cache_zalloc(names_cachep, GFP_KERNEL);
|
||||
new_de = kzalloc(PATH_MAX, GFP_KERNEL);
|
||||
if (!new_de) {
|
||||
err = -ENOMEM;
|
||||
goto out1;
|
||||
|
|
@ -1702,7 +1702,7 @@ out3:
|
|||
ntfs_mark_rec_free(sbi, ino, false);
|
||||
|
||||
out2:
|
||||
__putname(new_de);
|
||||
kfree(new_de);
|
||||
kfree(rp);
|
||||
|
||||
out1:
|
||||
|
|
@ -1723,7 +1723,7 @@ int ntfs_link_inode(struct inode *inode, struct dentry *dentry)
|
|||
struct NTFS_DE *de;
|
||||
|
||||
/* Allocate PATH_MAX bytes. */
|
||||
de = kmem_cache_zalloc(names_cachep, GFP_KERNEL);
|
||||
de = kzalloc(PATH_MAX, GFP_KERNEL);
|
||||
if (!de)
|
||||
return -ENOMEM;
|
||||
|
||||
|
|
@ -1737,7 +1737,7 @@ int ntfs_link_inode(struct inode *inode, struct dentry *dentry)
|
|||
|
||||
err = ni_add_name(ntfs_i(d_inode(dentry->d_parent)), ni, de);
|
||||
out:
|
||||
__putname(de);
|
||||
kfree(de);
|
||||
return err;
|
||||
}
|
||||
|
||||
|
|
@ -1760,8 +1760,7 @@ int ntfs_unlink_inode(struct inode *dir, const struct dentry *dentry)
|
|||
if (ntfs_is_meta_file(sbi, ni->mi.rno))
|
||||
return -EINVAL;
|
||||
|
||||
/* Allocate PATH_MAX bytes. */
|
||||
de = kmem_cache_zalloc(names_cachep, GFP_KERNEL);
|
||||
de = kzalloc(PATH_MAX, GFP_KERNEL);
|
||||
if (!de)
|
||||
return -ENOMEM;
|
||||
|
||||
|
|
@ -1797,7 +1796,7 @@ int ntfs_unlink_inode(struct inode *dir, const struct dentry *dentry)
|
|||
|
||||
out:
|
||||
ni_unlock(ni);
|
||||
__putname(de);
|
||||
kfree(de);
|
||||
return err;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -68,7 +68,7 @@ static struct dentry *ntfs_lookup(struct inode *dir, struct dentry *dentry,
|
|||
u32 flags)
|
||||
{
|
||||
struct ntfs_inode *ni = ntfs_i(dir);
|
||||
struct cpu_str *uni = __getname();
|
||||
struct cpu_str *uni = kmalloc(PATH_MAX, GFP_KERNEL);
|
||||
struct inode *inode;
|
||||
int err;
|
||||
|
||||
|
|
@ -85,7 +85,7 @@ static struct dentry *ntfs_lookup(struct inode *dir, struct dentry *dentry,
|
|||
inode = dir_search_u(dir, uni, NULL);
|
||||
ni_unlock(ni);
|
||||
}
|
||||
__putname(uni);
|
||||
kfree(uni);
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
@ -303,8 +303,7 @@ static int ntfs_rename(struct mnt_idmap *idmap, struct inode *dir,
|
|||
return err;
|
||||
}
|
||||
|
||||
/* Allocate PATH_MAX bytes. */
|
||||
de = __getname();
|
||||
de = kmalloc(PATH_MAX, GFP_KERNEL);
|
||||
if (!de)
|
||||
return -ENOMEM;
|
||||
|
||||
|
|
@ -349,7 +348,7 @@ static int ntfs_rename(struct mnt_idmap *idmap, struct inode *dir,
|
|||
ni_unlock(ni);
|
||||
ni_unlock(dir_ni);
|
||||
out:
|
||||
__putname(de);
|
||||
kfree(de);
|
||||
return err;
|
||||
}
|
||||
|
||||
|
|
@ -407,7 +406,7 @@ static int ntfs_d_hash(const struct dentry *dentry, struct qstr *name)
|
|||
/*
|
||||
* Try slow way with current upcase table
|
||||
*/
|
||||
uni = kmem_cache_alloc(names_cachep, GFP_NOWAIT);
|
||||
uni = kmalloc(PATH_MAX, GFP_NOWAIT);
|
||||
if (!uni)
|
||||
return -ENOMEM;
|
||||
|
||||
|
|
@ -429,7 +428,7 @@ static int ntfs_d_hash(const struct dentry *dentry, struct qstr *name)
|
|||
err = 0;
|
||||
|
||||
out:
|
||||
kmem_cache_free(names_cachep, uni);
|
||||
kfree(uni);
|
||||
return err;
|
||||
}
|
||||
|
||||
|
|
@ -468,7 +467,7 @@ static int ntfs_d_compare(const struct dentry *dentry, unsigned int len1,
|
|||
* Try slow way with current upcase table
|
||||
*/
|
||||
sbi = dentry->d_sb->s_fs_info;
|
||||
uni1 = __getname();
|
||||
uni1 = kmalloc(PATH_MAX, GFP_NOWAIT);
|
||||
if (!uni1)
|
||||
return -ENOMEM;
|
||||
|
||||
|
|
@ -498,7 +497,7 @@ static int ntfs_d_compare(const struct dentry *dentry, unsigned int len1,
|
|||
ret = !ntfs_cmp_names_cpu(uni1, uni2, sbi->upcase, false) ? 0 : 1;
|
||||
|
||||
out:
|
||||
__putname(uni1);
|
||||
kfree(uni1);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -556,8 +556,7 @@ struct posix_acl *ntfs_get_acl(struct mnt_idmap *idmap, struct dentry *dentry,
|
|||
if (unlikely(is_bad_ni(ni)))
|
||||
return ERR_PTR(-EINVAL);
|
||||
|
||||
/* Allocate PATH_MAX bytes. */
|
||||
buf = __getname();
|
||||
buf = kmalloc(PATH_MAX, GFP_KERNEL);
|
||||
if (!buf)
|
||||
return ERR_PTR(-ENOMEM);
|
||||
|
||||
|
|
@ -588,7 +587,7 @@ struct posix_acl *ntfs_get_acl(struct mnt_idmap *idmap, struct dentry *dentry,
|
|||
if (!IS_ERR(acl))
|
||||
set_cached_acl(inode, type, acl);
|
||||
|
||||
__putname(buf);
|
||||
kfree(buf);
|
||||
|
||||
return acl;
|
||||
}
|
||||
|
|
|
|||
119
fs/open.c
119
fs/open.c
|
|
@ -135,15 +135,16 @@ int do_sys_truncate(const char __user *pathname, loff_t length)
|
|||
if (length < 0) /* sorry, but loff_t says... */
|
||||
return -EINVAL;
|
||||
|
||||
CLASS(filename, name)(pathname);
|
||||
retry:
|
||||
error = user_path_at(AT_FDCWD, pathname, lookup_flags, &path);
|
||||
error = filename_lookup(AT_FDCWD, name, lookup_flags, &path, NULL);
|
||||
if (!error) {
|
||||
error = vfs_truncate(&path, length);
|
||||
path_put(&path);
|
||||
}
|
||||
if (retry_estale(error, lookup_flags)) {
|
||||
lookup_flags |= LOOKUP_REVAL;
|
||||
goto retry;
|
||||
if (retry_estale(error, lookup_flags)) {
|
||||
lookup_flags |= LOOKUP_REVAL;
|
||||
goto retry;
|
||||
}
|
||||
}
|
||||
return error;
|
||||
}
|
||||
|
|
@ -477,8 +478,6 @@ static int do_faccessat(int dfd, const char __user *filename, int mode, int flag
|
|||
|
||||
if (flags & AT_SYMLINK_NOFOLLOW)
|
||||
lookup_flags &= ~LOOKUP_FOLLOW;
|
||||
if (flags & AT_EMPTY_PATH)
|
||||
lookup_flags |= LOOKUP_EMPTY;
|
||||
|
||||
if (access_need_override_creds(flags)) {
|
||||
old_cred = access_override_creds();
|
||||
|
|
@ -486,8 +485,9 @@ static int do_faccessat(int dfd, const char __user *filename, int mode, int flag
|
|||
return -ENOMEM;
|
||||
}
|
||||
|
||||
CLASS(filename_uflags, name)(filename, flags);
|
||||
retry:
|
||||
res = user_path_at(dfd, filename, lookup_flags, &path);
|
||||
res = filename_lookup(dfd, name, lookup_flags, &path, NULL);
|
||||
if (res)
|
||||
goto out;
|
||||
|
||||
|
|
@ -554,24 +554,19 @@ SYSCALL_DEFINE1(chdir, const char __user *, filename)
|
|||
struct path path;
|
||||
int error;
|
||||
unsigned int lookup_flags = LOOKUP_FOLLOW | LOOKUP_DIRECTORY;
|
||||
CLASS(filename, name)(filename);
|
||||
retry:
|
||||
error = user_path_at(AT_FDCWD, filename, lookup_flags, &path);
|
||||
if (error)
|
||||
goto out;
|
||||
|
||||
error = path_permission(&path, MAY_EXEC | MAY_CHDIR);
|
||||
if (error)
|
||||
goto dput_and_out;
|
||||
|
||||
set_fs_pwd(current->fs, &path);
|
||||
|
||||
dput_and_out:
|
||||
path_put(&path);
|
||||
if (retry_estale(error, lookup_flags)) {
|
||||
lookup_flags |= LOOKUP_REVAL;
|
||||
goto retry;
|
||||
error = filename_lookup(AT_FDCWD, name, lookup_flags, &path, NULL);
|
||||
if (!error) {
|
||||
error = path_permission(&path, MAY_EXEC | MAY_CHDIR);
|
||||
if (!error)
|
||||
set_fs_pwd(current->fs, &path);
|
||||
path_put(&path);
|
||||
if (retry_estale(error, lookup_flags)) {
|
||||
lookup_flags |= LOOKUP_REVAL;
|
||||
goto retry;
|
||||
}
|
||||
}
|
||||
out:
|
||||
return error;
|
||||
}
|
||||
|
||||
|
|
@ -597,10 +592,11 @@ SYSCALL_DEFINE1(chroot, const char __user *, filename)
|
|||
struct path path;
|
||||
int error;
|
||||
unsigned int lookup_flags = LOOKUP_FOLLOW | LOOKUP_DIRECTORY;
|
||||
CLASS(filename, name)(filename);
|
||||
retry:
|
||||
error = user_path_at(AT_FDCWD, filename, lookup_flags, &path);
|
||||
error = filename_lookup(AT_FDCWD, name, lookup_flags, &path, NULL);
|
||||
if (error)
|
||||
goto out;
|
||||
return error;
|
||||
|
||||
error = path_permission(&path, MAY_EXEC | MAY_CHDIR);
|
||||
if (error)
|
||||
|
|
@ -610,18 +606,14 @@ retry:
|
|||
if (!ns_capable(current_user_ns(), CAP_SYS_CHROOT))
|
||||
goto dput_and_out;
|
||||
error = security_path_chroot(&path);
|
||||
if (error)
|
||||
goto dput_and_out;
|
||||
|
||||
set_fs_root(current->fs, &path);
|
||||
error = 0;
|
||||
if (!error)
|
||||
set_fs_root(current->fs, &path);
|
||||
dput_and_out:
|
||||
path_put(&path);
|
||||
if (retry_estale(error, lookup_flags)) {
|
||||
lookup_flags |= LOOKUP_REVAL;
|
||||
goto retry;
|
||||
}
|
||||
out:
|
||||
return error;
|
||||
}
|
||||
|
||||
|
|
@ -685,11 +677,9 @@ static int do_fchmodat(int dfd, const char __user *filename, umode_t mode,
|
|||
return -EINVAL;
|
||||
|
||||
lookup_flags = (flags & AT_SYMLINK_NOFOLLOW) ? 0 : LOOKUP_FOLLOW;
|
||||
if (flags & AT_EMPTY_PATH)
|
||||
lookup_flags |= LOOKUP_EMPTY;
|
||||
|
||||
CLASS(filename_uflags, name)(filename, flags);
|
||||
retry:
|
||||
error = user_path_at(dfd, filename, lookup_flags, &path);
|
||||
error = filename_lookup(dfd, name, lookup_flags, &path, NULL);
|
||||
if (!error) {
|
||||
error = chmod_common(&path, mode);
|
||||
path_put(&path);
|
||||
|
|
@ -800,31 +790,28 @@ int do_fchownat(int dfd, const char __user *filename, uid_t user, gid_t group,
|
|||
int flag)
|
||||
{
|
||||
struct path path;
|
||||
int error = -EINVAL;
|
||||
int error;
|
||||
int lookup_flags;
|
||||
|
||||
if ((flag & ~(AT_SYMLINK_NOFOLLOW | AT_EMPTY_PATH)) != 0)
|
||||
goto out;
|
||||
return -EINVAL;
|
||||
|
||||
lookup_flags = (flag & AT_SYMLINK_NOFOLLOW) ? 0 : LOOKUP_FOLLOW;
|
||||
if (flag & AT_EMPTY_PATH)
|
||||
lookup_flags |= LOOKUP_EMPTY;
|
||||
CLASS(filename_uflags, name)(filename, flag);
|
||||
retry:
|
||||
error = user_path_at(dfd, filename, lookup_flags, &path);
|
||||
if (error)
|
||||
goto out;
|
||||
error = mnt_want_write(path.mnt);
|
||||
if (error)
|
||||
goto out_release;
|
||||
error = chown_common(&path, user, group);
|
||||
mnt_drop_write(path.mnt);
|
||||
out_release:
|
||||
path_put(&path);
|
||||
if (retry_estale(error, lookup_flags)) {
|
||||
lookup_flags |= LOOKUP_REVAL;
|
||||
goto retry;
|
||||
error = filename_lookup(dfd, name, lookup_flags, &path, NULL);
|
||||
if (!error) {
|
||||
error = mnt_want_write(path.mnt);
|
||||
if (!error) {
|
||||
error = chown_common(&path, user, group);
|
||||
mnt_drop_write(path.mnt);
|
||||
}
|
||||
path_put(&path);
|
||||
if (retry_estale(error, lookup_flags)) {
|
||||
lookup_flags |= LOOKUP_REVAL;
|
||||
goto retry;
|
||||
}
|
||||
}
|
||||
out:
|
||||
return error;
|
||||
}
|
||||
|
||||
|
|
@ -1334,7 +1321,7 @@ struct file *file_open_name(struct filename *name, int flags, umode_t mode)
|
|||
int err = build_open_flags(&how, &op);
|
||||
if (err)
|
||||
return ERR_PTR(err);
|
||||
return do_filp_open(AT_FDCWD, name, &op);
|
||||
return do_file_open(AT_FDCWD, name, &op);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -1350,14 +1337,8 @@ struct file *file_open_name(struct filename *name, int flags, umode_t mode)
|
|||
*/
|
||||
struct file *filp_open(const char *filename, int flags, umode_t mode)
|
||||
{
|
||||
struct filename *name = getname_kernel(filename);
|
||||
struct file *file = ERR_CAST(name);
|
||||
|
||||
if (!IS_ERR(name)) {
|
||||
file = file_open_name(name, flags, mode);
|
||||
putname(name);
|
||||
}
|
||||
return file;
|
||||
CLASS(filename_kernel, name)(filename);
|
||||
return file_open_name(name, flags, mode);
|
||||
}
|
||||
EXPORT_SYMBOL(filp_open);
|
||||
|
||||
|
|
@ -1377,18 +1358,12 @@ static int do_sys_openat2(int dfd, const char __user *filename,
|
|||
struct open_how *how)
|
||||
{
|
||||
struct open_flags op;
|
||||
struct filename *tmp __free(putname) = NULL;
|
||||
int err;
|
||||
|
||||
err = build_open_flags(how, &op);
|
||||
int err = build_open_flags(how, &op);
|
||||
if (unlikely(err))
|
||||
return err;
|
||||
|
||||
tmp = getname(filename);
|
||||
if (IS_ERR(tmp))
|
||||
return PTR_ERR(tmp);
|
||||
|
||||
return FD_ADD(how->flags, do_filp_open(dfd, tmp, &op));
|
||||
CLASS(filename, name)(filename);
|
||||
return FD_ADD(how->flags, do_file_open(dfd, name, &op));
|
||||
}
|
||||
|
||||
int do_sys_open(int dfd, const char __user *filename, int flags, umode_t mode)
|
||||
|
|
|
|||
|
|
@ -867,7 +867,7 @@ static struct super_block *quotactl_block(const char __user *special, int cmd)
|
|||
{
|
||||
#ifdef CONFIG_BLOCK
|
||||
struct super_block *sb;
|
||||
struct filename *tmp = getname(special);
|
||||
CLASS(filename, tmp)(special);
|
||||
bool excl = false, thawed = false;
|
||||
int error;
|
||||
dev_t dev;
|
||||
|
|
@ -875,7 +875,6 @@ static struct super_block *quotactl_block(const char __user *special, int cmd)
|
|||
if (IS_ERR(tmp))
|
||||
return ERR_CAST(tmp);
|
||||
error = lookup_bdev(tmp->name, &dev);
|
||||
putname(tmp);
|
||||
if (error)
|
||||
return ERR_PTR(error);
|
||||
|
||||
|
|
|
|||
|
|
@ -54,7 +54,6 @@ static int ksmbd_vfs_path_lookup(struct ksmbd_share_config *share_conf,
|
|||
struct path *path, bool for_remove)
|
||||
{
|
||||
struct qstr last;
|
||||
struct filename *filename __free(putname) = NULL;
|
||||
const struct path *root_share_path = &share_conf->vfs_path;
|
||||
int err, type;
|
||||
struct dentry *d;
|
||||
|
|
@ -66,10 +65,7 @@ static int ksmbd_vfs_path_lookup(struct ksmbd_share_config *share_conf,
|
|||
flags |= LOOKUP_BENEATH;
|
||||
}
|
||||
|
||||
filename = getname_kernel(pathname);
|
||||
if (IS_ERR(filename))
|
||||
return PTR_ERR(filename);
|
||||
|
||||
CLASS(filename_kernel, filename)(pathname);
|
||||
err = vfs_path_parent_lookup(filename, flags,
|
||||
path, &last, &type,
|
||||
root_share_path);
|
||||
|
|
@ -667,7 +663,6 @@ int ksmbd_vfs_rename(struct ksmbd_work *work, const struct path *old_path,
|
|||
struct path new_path;
|
||||
struct qstr new_last;
|
||||
struct renamedata rd;
|
||||
struct filename *to;
|
||||
struct ksmbd_share_config *share_conf = work->tcon->share_conf;
|
||||
struct ksmbd_file *parent_fp;
|
||||
int new_type;
|
||||
|
|
@ -676,11 +671,7 @@ int ksmbd_vfs_rename(struct ksmbd_work *work, const struct path *old_path,
|
|||
if (ksmbd_override_fsids(work))
|
||||
return -ENOMEM;
|
||||
|
||||
to = getname_kernel(newname);
|
||||
if (IS_ERR(to)) {
|
||||
err = PTR_ERR(to);
|
||||
goto revert_fsids;
|
||||
}
|
||||
CLASS(filename_kernel, to)(newname);
|
||||
|
||||
retry:
|
||||
err = vfs_path_parent_lookup(to, lookup_flags | LOOKUP_BENEATH,
|
||||
|
|
@ -739,8 +730,6 @@ out2:
|
|||
goto retry;
|
||||
}
|
||||
out1:
|
||||
putname(to);
|
||||
revert_fsids:
|
||||
ksmbd_revert_fsids(work);
|
||||
return err;
|
||||
}
|
||||
|
|
|
|||
28
fs/stat.c
28
fs/stat.c
|
|
@ -365,17 +365,13 @@ retry:
|
|||
int vfs_fstatat(int dfd, const char __user *filename,
|
||||
struct kstat *stat, int flags)
|
||||
{
|
||||
int ret;
|
||||
int statx_flags = flags | AT_NO_AUTOMOUNT;
|
||||
struct filename *name = getname_maybe_null(filename, flags);
|
||||
CLASS(filename_maybe_null, name)(filename, flags);
|
||||
|
||||
if (!name && dfd >= 0)
|
||||
return vfs_fstat(dfd, stat);
|
||||
|
||||
ret = vfs_statx(dfd, name, statx_flags, stat, STATX_BASIC_STATS);
|
||||
putname(name);
|
||||
|
||||
return ret;
|
||||
return vfs_statx(dfd, name, flags | AT_NO_AUTOMOUNT,
|
||||
stat, STATX_BASIC_STATS);
|
||||
}
|
||||
|
||||
#ifdef __ARCH_WANT_OLD_STAT
|
||||
|
|
@ -564,20 +560,17 @@ static int do_readlinkat(int dfd, const char __user *pathname,
|
|||
char __user *buf, int bufsiz)
|
||||
{
|
||||
struct path path;
|
||||
struct filename *name;
|
||||
int error;
|
||||
unsigned int lookup_flags = LOOKUP_EMPTY;
|
||||
unsigned int lookup_flags = 0;
|
||||
|
||||
if (bufsiz <= 0)
|
||||
return -EINVAL;
|
||||
|
||||
CLASS(filename_flags, name)(pathname, LOOKUP_EMPTY);
|
||||
retry:
|
||||
name = getname_flags(pathname, lookup_flags);
|
||||
error = filename_lookup(dfd, name, lookup_flags, &path, NULL);
|
||||
if (unlikely(error)) {
|
||||
putname(name);
|
||||
if (unlikely(error))
|
||||
return error;
|
||||
}
|
||||
|
||||
/*
|
||||
* AFS mountpoints allow readlink(2) but are not symlinks
|
||||
|
|
@ -593,7 +586,6 @@ retry:
|
|||
error = (name->name[0] == '\0') ? -ENOENT : -EINVAL;
|
||||
}
|
||||
path_put(&path);
|
||||
putname(name);
|
||||
if (retry_estale(error, lookup_flags)) {
|
||||
lookup_flags |= LOOKUP_REVAL;
|
||||
goto retry;
|
||||
|
|
@ -814,16 +806,12 @@ SYSCALL_DEFINE5(statx,
|
|||
unsigned int, mask,
|
||||
struct statx __user *, buffer)
|
||||
{
|
||||
int ret;
|
||||
struct filename *name = getname_maybe_null(filename, flags);
|
||||
CLASS(filename_maybe_null, name)(filename, flags);
|
||||
|
||||
if (!name && dfd >= 0)
|
||||
return do_statx_fd(dfd, flags & ~AT_NO_AUTOMOUNT, mask, buffer);
|
||||
|
||||
ret = do_statx(dfd, name, flags, mask, buffer);
|
||||
putname(name);
|
||||
|
||||
return ret;
|
||||
return do_statx(dfd, name, flags, mask, buffer);
|
||||
}
|
||||
|
||||
#if defined(CONFIG_COMPAT) && defined(__ARCH_WANT_COMPAT_STAT)
|
||||
|
|
|
|||
|
|
@ -99,8 +99,9 @@ int user_statfs(const char __user *pathname, struct kstatfs *st)
|
|||
struct path path;
|
||||
int error;
|
||||
unsigned int lookup_flags = LOOKUP_FOLLOW|LOOKUP_AUTOMOUNT;
|
||||
CLASS(filename, name)(pathname);
|
||||
retry:
|
||||
error = user_path_at(AT_FDCWD, pathname, lookup_flags, &path);
|
||||
error = filename_lookup(AT_FDCWD, name, lookup_flags, &path, NULL);
|
||||
if (!error) {
|
||||
error = vfs_statfs(&path, st);
|
||||
path_put(&path);
|
||||
|
|
|
|||
|
|
@ -8,6 +8,7 @@
|
|||
#include <linux/compat.h>
|
||||
#include <asm/unistd.h>
|
||||
#include <linux/filelock.h>
|
||||
#include "internal.h"
|
||||
|
||||
static bool nsec_valid(long nsec)
|
||||
{
|
||||
|
|
@ -89,21 +90,18 @@ static int do_utimes_path(int dfd, const char __user *filename,
|
|||
|
||||
if (!(flags & AT_SYMLINK_NOFOLLOW))
|
||||
lookup_flags |= LOOKUP_FOLLOW;
|
||||
if (flags & AT_EMPTY_PATH)
|
||||
lookup_flags |= LOOKUP_EMPTY;
|
||||
|
||||
CLASS(filename_uflags, name)(filename, flags);
|
||||
retry:
|
||||
error = user_path_at(dfd, filename, lookup_flags, &path);
|
||||
error = filename_lookup(dfd, name, lookup_flags, &path, NULL);
|
||||
if (error)
|
||||
return error;
|
||||
|
||||
error = vfs_utimes(&path, times);
|
||||
path_put(&path);
|
||||
if (retry_estale(error, lookup_flags)) {
|
||||
lookup_flags |= LOOKUP_REVAL;
|
||||
goto retry;
|
||||
}
|
||||
|
||||
return error;
|
||||
}
|
||||
|
||||
|
|
|
|||
33
fs/xattr.c
33
fs/xattr.c
|
|
@ -649,7 +649,6 @@ int file_setxattr(struct file *f, struct kernel_xattr_ctx *ctx)
|
|||
return error;
|
||||
}
|
||||
|
||||
/* unconditionally consumes filename */
|
||||
int filename_setxattr(int dfd, struct filename *filename,
|
||||
unsigned int lookup_flags, struct kernel_xattr_ctx *ctx)
|
||||
{
|
||||
|
|
@ -659,7 +658,7 @@ int filename_setxattr(int dfd, struct filename *filename,
|
|||
retry:
|
||||
error = filename_lookup(dfd, filename, lookup_flags, &path, NULL);
|
||||
if (error)
|
||||
goto out;
|
||||
return error;
|
||||
error = mnt_want_write(path.mnt);
|
||||
if (!error) {
|
||||
error = do_setxattr(mnt_idmap(path.mnt), path.dentry, ctx);
|
||||
|
|
@ -670,9 +669,6 @@ retry:
|
|||
lookup_flags |= LOOKUP_REVAL;
|
||||
goto retry;
|
||||
}
|
||||
|
||||
out:
|
||||
putname(filename);
|
||||
return error;
|
||||
}
|
||||
|
||||
|
|
@ -688,7 +684,6 @@ static int path_setxattrat(int dfd, const char __user *pathname,
|
|||
.kname = &kname,
|
||||
.flags = flags,
|
||||
};
|
||||
struct filename *filename;
|
||||
unsigned int lookup_flags = 0;
|
||||
int error;
|
||||
|
||||
|
|
@ -702,7 +697,7 @@ static int path_setxattrat(int dfd, const char __user *pathname,
|
|||
if (error)
|
||||
return error;
|
||||
|
||||
filename = getname_maybe_null(pathname, at_flags);
|
||||
CLASS(filename_maybe_null, filename)(pathname, at_flags);
|
||||
if (!filename && dfd >= 0) {
|
||||
CLASS(fd, f)(dfd);
|
||||
if (fd_empty(f))
|
||||
|
|
@ -804,7 +799,6 @@ ssize_t file_getxattr(struct file *f, struct kernel_xattr_ctx *ctx)
|
|||
return do_getxattr(file_mnt_idmap(f), f->f_path.dentry, ctx);
|
||||
}
|
||||
|
||||
/* unconditionally consumes filename */
|
||||
ssize_t filename_getxattr(int dfd, struct filename *filename,
|
||||
unsigned int lookup_flags, struct kernel_xattr_ctx *ctx)
|
||||
{
|
||||
|
|
@ -813,15 +807,13 @@ ssize_t filename_getxattr(int dfd, struct filename *filename,
|
|||
retry:
|
||||
error = filename_lookup(dfd, filename, lookup_flags, &path, NULL);
|
||||
if (error)
|
||||
goto out;
|
||||
return error;
|
||||
error = do_getxattr(mnt_idmap(path.mnt), path.dentry, ctx);
|
||||
path_put(&path);
|
||||
if (retry_estale(error, lookup_flags)) {
|
||||
lookup_flags |= LOOKUP_REVAL;
|
||||
goto retry;
|
||||
}
|
||||
out:
|
||||
putname(filename);
|
||||
return error;
|
||||
}
|
||||
|
||||
|
|
@ -836,7 +828,6 @@ static ssize_t path_getxattrat(int dfd, const char __user *pathname,
|
|||
.kname = &kname,
|
||||
.flags = 0,
|
||||
};
|
||||
struct filename *filename;
|
||||
ssize_t error;
|
||||
|
||||
if ((at_flags & ~(AT_SYMLINK_NOFOLLOW | AT_EMPTY_PATH)) != 0)
|
||||
|
|
@ -846,7 +837,7 @@ static ssize_t path_getxattrat(int dfd, const char __user *pathname,
|
|||
if (error)
|
||||
return error;
|
||||
|
||||
filename = getname_maybe_null(pathname, at_flags);
|
||||
CLASS(filename_maybe_null, filename)(pathname, at_flags);
|
||||
if (!filename && dfd >= 0) {
|
||||
CLASS(fd, f)(dfd);
|
||||
if (fd_empty(f))
|
||||
|
|
@ -943,7 +934,6 @@ ssize_t file_listxattr(struct file *f, char __user *list, size_t size)
|
|||
return listxattr(f->f_path.dentry, list, size);
|
||||
}
|
||||
|
||||
/* unconditionally consumes filename */
|
||||
static
|
||||
ssize_t filename_listxattr(int dfd, struct filename *filename,
|
||||
unsigned int lookup_flags,
|
||||
|
|
@ -954,15 +944,13 @@ ssize_t filename_listxattr(int dfd, struct filename *filename,
|
|||
retry:
|
||||
error = filename_lookup(dfd, filename, lookup_flags, &path, NULL);
|
||||
if (error)
|
||||
goto out;
|
||||
return error;
|
||||
error = listxattr(path.dentry, list, size);
|
||||
path_put(&path);
|
||||
if (retry_estale(error, lookup_flags)) {
|
||||
lookup_flags |= LOOKUP_REVAL;
|
||||
goto retry;
|
||||
}
|
||||
out:
|
||||
putname(filename);
|
||||
return error;
|
||||
}
|
||||
|
||||
|
|
@ -970,13 +958,12 @@ static ssize_t path_listxattrat(int dfd, const char __user *pathname,
|
|||
unsigned int at_flags, char __user *list,
|
||||
size_t size)
|
||||
{
|
||||
struct filename *filename;
|
||||
int lookup_flags;
|
||||
|
||||
if ((at_flags & ~(AT_SYMLINK_NOFOLLOW | AT_EMPTY_PATH)) != 0)
|
||||
return -EINVAL;
|
||||
|
||||
filename = getname_maybe_null(pathname, at_flags);
|
||||
CLASS(filename_maybe_null, filename)(pathname, at_flags);
|
||||
if (!filename) {
|
||||
CLASS(fd, f)(dfd);
|
||||
if (fd_empty(f))
|
||||
|
|
@ -1036,7 +1023,6 @@ static int file_removexattr(struct file *f, struct xattr_name *kname)
|
|||
return error;
|
||||
}
|
||||
|
||||
/* unconditionally consumes filename */
|
||||
static int filename_removexattr(int dfd, struct filename *filename,
|
||||
unsigned int lookup_flags, struct xattr_name *kname)
|
||||
{
|
||||
|
|
@ -1046,7 +1032,7 @@ static int filename_removexattr(int dfd, struct filename *filename,
|
|||
retry:
|
||||
error = filename_lookup(dfd, filename, lookup_flags, &path, NULL);
|
||||
if (error)
|
||||
goto out;
|
||||
return error;
|
||||
error = mnt_want_write(path.mnt);
|
||||
if (!error) {
|
||||
error = removexattr(mnt_idmap(path.mnt), path.dentry, kname->name);
|
||||
|
|
@ -1057,8 +1043,6 @@ retry:
|
|||
lookup_flags |= LOOKUP_REVAL;
|
||||
goto retry;
|
||||
}
|
||||
out:
|
||||
putname(filename);
|
||||
return error;
|
||||
}
|
||||
|
||||
|
|
@ -1066,7 +1050,6 @@ static int path_removexattrat(int dfd, const char __user *pathname,
|
|||
unsigned int at_flags, const char __user *name)
|
||||
{
|
||||
struct xattr_name kname;
|
||||
struct filename *filename;
|
||||
unsigned int lookup_flags;
|
||||
int error;
|
||||
|
||||
|
|
@ -1077,7 +1060,7 @@ static int path_removexattrat(int dfd, const char __user *pathname,
|
|||
if (error)
|
||||
return error;
|
||||
|
||||
filename = getname_maybe_null(pathname, at_flags);
|
||||
CLASS(filename_maybe_null, filename)(pathname, at_flags);
|
||||
if (!filename) {
|
||||
CLASS(fd, f)(dfd);
|
||||
if (fd_empty(f))
|
||||
|
|
|
|||
|
|
@ -972,7 +972,8 @@
|
|||
#define RUNTIME_CONST_VARIABLES \
|
||||
RUNTIME_CONST(shift, d_hash_shift) \
|
||||
RUNTIME_CONST(ptr, dentry_hashtable) \
|
||||
RUNTIME_CONST(ptr, __dentry_cache)
|
||||
RUNTIME_CONST(ptr, __dentry_cache) \
|
||||
RUNTIME_CONST(ptr, __names_cache)
|
||||
|
||||
/* Alignment must be consistent with (kunit_suite *) in include/kunit/test.h */
|
||||
#define KUNIT_TABLE() \
|
||||
|
|
|
|||
|
|
@ -318,7 +318,6 @@ extern void __audit_uring_exit(int success, long code);
|
|||
extern void __audit_syscall_entry(int major, unsigned long a0, unsigned long a1,
|
||||
unsigned long a2, unsigned long a3);
|
||||
extern void __audit_syscall_exit(int ret_success, long ret_value);
|
||||
extern struct filename *__audit_reusename(const __user char *uptr);
|
||||
extern void __audit_getname(struct filename *name);
|
||||
extern void __audit_inode(struct filename *name, const struct dentry *dentry,
|
||||
unsigned int flags);
|
||||
|
|
@ -382,12 +381,6 @@ static inline void audit_syscall_exit(void *pt_regs)
|
|||
__audit_syscall_exit(success, return_code);
|
||||
}
|
||||
}
|
||||
static inline struct filename *audit_reusename(const __user char *name)
|
||||
{
|
||||
if (unlikely(!audit_dummy_context()))
|
||||
return __audit_reusename(name);
|
||||
return NULL;
|
||||
}
|
||||
static inline void audit_getname(struct filename *name)
|
||||
{
|
||||
if (unlikely(!audit_dummy_context()))
|
||||
|
|
@ -626,10 +619,6 @@ static inline struct audit_context *audit_context(void)
|
|||
{
|
||||
return NULL;
|
||||
}
|
||||
static inline struct filename *audit_reusename(const __user char *name)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
static inline void audit_getname(struct filename *name)
|
||||
{ }
|
||||
static inline void audit_inode(struct filename *name,
|
||||
|
|
|
|||
|
|
@ -2418,14 +2418,19 @@ extern struct kobject *fs_kobj;
|
|||
|
||||
/* fs/open.c */
|
||||
struct audit_names;
|
||||
struct filename {
|
||||
|
||||
struct __filename_head {
|
||||
const char *name; /* pointer to actual string */
|
||||
const __user char *uptr; /* original userland pointer */
|
||||
atomic_t refcnt;
|
||||
int refcnt;
|
||||
struct audit_names *aname;
|
||||
const char iname[];
|
||||
};
|
||||
#define EMBEDDED_NAME_MAX (192 - sizeof(struct __filename_head))
|
||||
struct filename {
|
||||
struct __filename_head;
|
||||
const char iname[EMBEDDED_NAME_MAX];
|
||||
};
|
||||
static_assert(offsetof(struct filename, iname) % sizeof(long) == 0);
|
||||
static_assert(sizeof(struct filename) % 64 == 0);
|
||||
|
||||
static inline struct mnt_idmap *file_mnt_idmap(const struct file *file)
|
||||
{
|
||||
|
|
@ -2520,11 +2525,23 @@ static inline struct filename *getname_maybe_null(const char __user *name, int f
|
|||
extern void putname(struct filename *name);
|
||||
DEFINE_FREE(putname, struct filename *, if (!IS_ERR_OR_NULL(_T)) putname(_T))
|
||||
|
||||
static inline struct filename *refname(struct filename *name)
|
||||
{
|
||||
atomic_inc(&name->refcnt);
|
||||
return name;
|
||||
}
|
||||
struct delayed_filename {
|
||||
struct filename *__incomplete_filename; // don't touch
|
||||
};
|
||||
#define INIT_DELAYED_FILENAME(ptr) \
|
||||
((void)(*(ptr) = (struct delayed_filename){}))
|
||||
int delayed_getname(struct delayed_filename *, const char __user *);
|
||||
int delayed_getname_uflags(struct delayed_filename *v, const char __user *, int);
|
||||
void dismiss_delayed_filename(struct delayed_filename *);
|
||||
int putname_to_delayed(struct delayed_filename *, struct filename *);
|
||||
struct filename *complete_getname(struct delayed_filename *);
|
||||
|
||||
DEFINE_CLASS(filename, struct filename *, putname(_T), getname(p), const char __user *p)
|
||||
EXTEND_CLASS(filename, _kernel, getname_kernel(p), const char *p)
|
||||
EXTEND_CLASS(filename, _flags, getname_flags(p, f), const char __user *p, unsigned int f)
|
||||
EXTEND_CLASS(filename, _uflags, getname_uflags(p, f), const char __user *p, unsigned int f)
|
||||
EXTEND_CLASS(filename, _maybe_null, getname_maybe_null(p, f), const char __user *p, unsigned int f)
|
||||
EXTEND_CLASS(filename, _complete_delayed, complete_getname(p), struct delayed_filename *p)
|
||||
|
||||
extern int finish_open(struct file *file, struct dentry *dentry,
|
||||
int (*open)(struct inode *, struct file *));
|
||||
|
|
@ -2543,10 +2560,8 @@ static inline int finish_open_simple(struct file *file, int error)
|
|||
extern void __init vfs_caches_init_early(void);
|
||||
extern void __init vfs_caches_init(void);
|
||||
|
||||
extern struct kmem_cache *names_cachep;
|
||||
|
||||
#define __getname() kmem_cache_alloc(names_cachep, GFP_KERNEL)
|
||||
#define __putname(name) kmem_cache_free(names_cachep, (void *)(name))
|
||||
#define __getname() kmalloc(PATH_MAX, GFP_KERNEL)
|
||||
#define __putname(name) kfree(name)
|
||||
|
||||
void emergency_thaw_all(void);
|
||||
extern int sync_filesystem(struct super_block *);
|
||||
|
|
|
|||
106
io_uring/fs.c
106
io_uring/fs.c
|
|
@ -19,8 +19,8 @@ struct io_rename {
|
|||
struct file *file;
|
||||
int old_dfd;
|
||||
int new_dfd;
|
||||
struct filename *oldpath;
|
||||
struct filename *newpath;
|
||||
struct delayed_filename oldpath;
|
||||
struct delayed_filename newpath;
|
||||
int flags;
|
||||
};
|
||||
|
||||
|
|
@ -28,22 +28,22 @@ struct io_unlink {
|
|||
struct file *file;
|
||||
int dfd;
|
||||
int flags;
|
||||
struct filename *filename;
|
||||
struct delayed_filename filename;
|
||||
};
|
||||
|
||||
struct io_mkdir {
|
||||
struct file *file;
|
||||
int dfd;
|
||||
umode_t mode;
|
||||
struct filename *filename;
|
||||
struct delayed_filename filename;
|
||||
};
|
||||
|
||||
struct io_link {
|
||||
struct file *file;
|
||||
int old_dfd;
|
||||
int new_dfd;
|
||||
struct filename *oldpath;
|
||||
struct filename *newpath;
|
||||
struct delayed_filename oldpath;
|
||||
struct delayed_filename newpath;
|
||||
int flags;
|
||||
};
|
||||
|
||||
|
|
@ -51,6 +51,7 @@ int io_renameat_prep(struct io_kiocb *req, const struct io_uring_sqe *sqe)
|
|||
{
|
||||
struct io_rename *ren = io_kiocb_to_cmd(req, struct io_rename);
|
||||
const char __user *oldf, *newf;
|
||||
int err;
|
||||
|
||||
if (sqe->buf_index || sqe->splice_fd_in)
|
||||
return -EINVAL;
|
||||
|
|
@ -63,14 +64,14 @@ int io_renameat_prep(struct io_kiocb *req, const struct io_uring_sqe *sqe)
|
|||
ren->new_dfd = READ_ONCE(sqe->len);
|
||||
ren->flags = READ_ONCE(sqe->rename_flags);
|
||||
|
||||
ren->oldpath = getname(oldf);
|
||||
if (IS_ERR(ren->oldpath))
|
||||
return PTR_ERR(ren->oldpath);
|
||||
err = delayed_getname(&ren->oldpath, oldf);
|
||||
if (unlikely(err))
|
||||
return err;
|
||||
|
||||
ren->newpath = getname(newf);
|
||||
if (IS_ERR(ren->newpath)) {
|
||||
putname(ren->oldpath);
|
||||
return PTR_ERR(ren->newpath);
|
||||
err = delayed_getname(&ren->newpath, newf);
|
||||
if (unlikely(err)) {
|
||||
dismiss_delayed_filename(&ren->oldpath);
|
||||
return err;
|
||||
}
|
||||
|
||||
req->flags |= REQ_F_NEED_CLEANUP;
|
||||
|
|
@ -81,12 +82,14 @@ int io_renameat_prep(struct io_kiocb *req, const struct io_uring_sqe *sqe)
|
|||
int io_renameat(struct io_kiocb *req, unsigned int issue_flags)
|
||||
{
|
||||
struct io_rename *ren = io_kiocb_to_cmd(req, struct io_rename);
|
||||
CLASS(filename_complete_delayed, old)(&ren->oldpath);
|
||||
CLASS(filename_complete_delayed, new)(&ren->newpath);
|
||||
int ret;
|
||||
|
||||
WARN_ON_ONCE(issue_flags & IO_URING_F_NONBLOCK);
|
||||
|
||||
ret = do_renameat2(ren->old_dfd, ren->oldpath, ren->new_dfd,
|
||||
ren->newpath, ren->flags);
|
||||
ret = filename_renameat2(ren->old_dfd, old,
|
||||
ren->new_dfd, new, ren->flags);
|
||||
|
||||
req->flags &= ~REQ_F_NEED_CLEANUP;
|
||||
io_req_set_res(req, ret, 0);
|
||||
|
|
@ -97,14 +100,15 @@ void io_renameat_cleanup(struct io_kiocb *req)
|
|||
{
|
||||
struct io_rename *ren = io_kiocb_to_cmd(req, struct io_rename);
|
||||
|
||||
putname(ren->oldpath);
|
||||
putname(ren->newpath);
|
||||
dismiss_delayed_filename(&ren->oldpath);
|
||||
dismiss_delayed_filename(&ren->newpath);
|
||||
}
|
||||
|
||||
int io_unlinkat_prep(struct io_kiocb *req, const struct io_uring_sqe *sqe)
|
||||
{
|
||||
struct io_unlink *un = io_kiocb_to_cmd(req, struct io_unlink);
|
||||
const char __user *fname;
|
||||
int err;
|
||||
|
||||
if (sqe->off || sqe->len || sqe->buf_index || sqe->splice_fd_in)
|
||||
return -EINVAL;
|
||||
|
|
@ -118,9 +122,9 @@ int io_unlinkat_prep(struct io_kiocb *req, const struct io_uring_sqe *sqe)
|
|||
return -EINVAL;
|
||||
|
||||
fname = u64_to_user_ptr(READ_ONCE(sqe->addr));
|
||||
un->filename = getname(fname);
|
||||
if (IS_ERR(un->filename))
|
||||
return PTR_ERR(un->filename);
|
||||
err = delayed_getname(&un->filename, fname);
|
||||
if (unlikely(err))
|
||||
return err;
|
||||
|
||||
req->flags |= REQ_F_NEED_CLEANUP;
|
||||
req->flags |= REQ_F_FORCE_ASYNC;
|
||||
|
|
@ -130,14 +134,15 @@ int io_unlinkat_prep(struct io_kiocb *req, const struct io_uring_sqe *sqe)
|
|||
int io_unlinkat(struct io_kiocb *req, unsigned int issue_flags)
|
||||
{
|
||||
struct io_unlink *un = io_kiocb_to_cmd(req, struct io_unlink);
|
||||
CLASS(filename_complete_delayed, name)(&un->filename);
|
||||
int ret;
|
||||
|
||||
WARN_ON_ONCE(issue_flags & IO_URING_F_NONBLOCK);
|
||||
|
||||
if (un->flags & AT_REMOVEDIR)
|
||||
ret = do_rmdir(un->dfd, un->filename);
|
||||
ret = filename_rmdir(un->dfd, name);
|
||||
else
|
||||
ret = do_unlinkat(un->dfd, un->filename);
|
||||
ret = filename_unlinkat(un->dfd, name);
|
||||
|
||||
req->flags &= ~REQ_F_NEED_CLEANUP;
|
||||
io_req_set_res(req, ret, 0);
|
||||
|
|
@ -148,13 +153,14 @@ void io_unlinkat_cleanup(struct io_kiocb *req)
|
|||
{
|
||||
struct io_unlink *ul = io_kiocb_to_cmd(req, struct io_unlink);
|
||||
|
||||
putname(ul->filename);
|
||||
dismiss_delayed_filename(&ul->filename);
|
||||
}
|
||||
|
||||
int io_mkdirat_prep(struct io_kiocb *req, const struct io_uring_sqe *sqe)
|
||||
{
|
||||
struct io_mkdir *mkd = io_kiocb_to_cmd(req, struct io_mkdir);
|
||||
const char __user *fname;
|
||||
int err;
|
||||
|
||||
if (sqe->off || sqe->rw_flags || sqe->buf_index || sqe->splice_fd_in)
|
||||
return -EINVAL;
|
||||
|
|
@ -165,9 +171,9 @@ int io_mkdirat_prep(struct io_kiocb *req, const struct io_uring_sqe *sqe)
|
|||
mkd->mode = READ_ONCE(sqe->len);
|
||||
|
||||
fname = u64_to_user_ptr(READ_ONCE(sqe->addr));
|
||||
mkd->filename = getname(fname);
|
||||
if (IS_ERR(mkd->filename))
|
||||
return PTR_ERR(mkd->filename);
|
||||
err = delayed_getname(&mkd->filename, fname);
|
||||
if (unlikely(err))
|
||||
return err;
|
||||
|
||||
req->flags |= REQ_F_NEED_CLEANUP;
|
||||
req->flags |= REQ_F_FORCE_ASYNC;
|
||||
|
|
@ -177,11 +183,12 @@ int io_mkdirat_prep(struct io_kiocb *req, const struct io_uring_sqe *sqe)
|
|||
int io_mkdirat(struct io_kiocb *req, unsigned int issue_flags)
|
||||
{
|
||||
struct io_mkdir *mkd = io_kiocb_to_cmd(req, struct io_mkdir);
|
||||
CLASS(filename_complete_delayed, name)(&mkd->filename);
|
||||
int ret;
|
||||
|
||||
WARN_ON_ONCE(issue_flags & IO_URING_F_NONBLOCK);
|
||||
|
||||
ret = do_mkdirat(mkd->dfd, mkd->filename, mkd->mode);
|
||||
ret = filename_mkdirat(mkd->dfd, name, mkd->mode);
|
||||
|
||||
req->flags &= ~REQ_F_NEED_CLEANUP;
|
||||
io_req_set_res(req, ret, 0);
|
||||
|
|
@ -192,13 +199,14 @@ void io_mkdirat_cleanup(struct io_kiocb *req)
|
|||
{
|
||||
struct io_mkdir *md = io_kiocb_to_cmd(req, struct io_mkdir);
|
||||
|
||||
putname(md->filename);
|
||||
dismiss_delayed_filename(&md->filename);
|
||||
}
|
||||
|
||||
int io_symlinkat_prep(struct io_kiocb *req, const struct io_uring_sqe *sqe)
|
||||
{
|
||||
struct io_link *sl = io_kiocb_to_cmd(req, struct io_link);
|
||||
const char __user *oldpath, *newpath;
|
||||
int err;
|
||||
|
||||
if (sqe->len || sqe->rw_flags || sqe->buf_index || sqe->splice_fd_in)
|
||||
return -EINVAL;
|
||||
|
|
@ -209,14 +217,14 @@ int io_symlinkat_prep(struct io_kiocb *req, const struct io_uring_sqe *sqe)
|
|||
oldpath = u64_to_user_ptr(READ_ONCE(sqe->addr));
|
||||
newpath = u64_to_user_ptr(READ_ONCE(sqe->addr2));
|
||||
|
||||
sl->oldpath = getname(oldpath);
|
||||
if (IS_ERR(sl->oldpath))
|
||||
return PTR_ERR(sl->oldpath);
|
||||
err = delayed_getname(&sl->oldpath, oldpath);
|
||||
if (unlikely(err))
|
||||
return err;
|
||||
|
||||
sl->newpath = getname(newpath);
|
||||
if (IS_ERR(sl->newpath)) {
|
||||
putname(sl->oldpath);
|
||||
return PTR_ERR(sl->newpath);
|
||||
err = delayed_getname(&sl->newpath, newpath);
|
||||
if (unlikely(err)) {
|
||||
dismiss_delayed_filename(&sl->oldpath);
|
||||
return err;
|
||||
}
|
||||
|
||||
req->flags |= REQ_F_NEED_CLEANUP;
|
||||
|
|
@ -227,11 +235,13 @@ int io_symlinkat_prep(struct io_kiocb *req, const struct io_uring_sqe *sqe)
|
|||
int io_symlinkat(struct io_kiocb *req, unsigned int issue_flags)
|
||||
{
|
||||
struct io_link *sl = io_kiocb_to_cmd(req, struct io_link);
|
||||
CLASS(filename_complete_delayed, old)(&sl->oldpath);
|
||||
CLASS(filename_complete_delayed, new)(&sl->newpath);
|
||||
int ret;
|
||||
|
||||
WARN_ON_ONCE(issue_flags & IO_URING_F_NONBLOCK);
|
||||
|
||||
ret = do_symlinkat(sl->oldpath, sl->new_dfd, sl->newpath);
|
||||
ret = filename_symlinkat(old, sl->new_dfd, new);
|
||||
|
||||
req->flags &= ~REQ_F_NEED_CLEANUP;
|
||||
io_req_set_res(req, ret, 0);
|
||||
|
|
@ -242,6 +252,7 @@ int io_linkat_prep(struct io_kiocb *req, const struct io_uring_sqe *sqe)
|
|||
{
|
||||
struct io_link *lnk = io_kiocb_to_cmd(req, struct io_link);
|
||||
const char __user *oldf, *newf;
|
||||
int err;
|
||||
|
||||
if (sqe->buf_index || sqe->splice_fd_in)
|
||||
return -EINVAL;
|
||||
|
|
@ -254,14 +265,14 @@ int io_linkat_prep(struct io_kiocb *req, const struct io_uring_sqe *sqe)
|
|||
newf = u64_to_user_ptr(READ_ONCE(sqe->addr2));
|
||||
lnk->flags = READ_ONCE(sqe->hardlink_flags);
|
||||
|
||||
lnk->oldpath = getname_uflags(oldf, lnk->flags);
|
||||
if (IS_ERR(lnk->oldpath))
|
||||
return PTR_ERR(lnk->oldpath);
|
||||
err = delayed_getname_uflags(&lnk->oldpath, oldf, lnk->flags);
|
||||
if (unlikely(err))
|
||||
return err;
|
||||
|
||||
lnk->newpath = getname(newf);
|
||||
if (IS_ERR(lnk->newpath)) {
|
||||
putname(lnk->oldpath);
|
||||
return PTR_ERR(lnk->newpath);
|
||||
err = delayed_getname(&lnk->newpath, newf);
|
||||
if (unlikely(err)) {
|
||||
dismiss_delayed_filename(&lnk->oldpath);
|
||||
return err;
|
||||
}
|
||||
|
||||
req->flags |= REQ_F_NEED_CLEANUP;
|
||||
|
|
@ -272,12 +283,13 @@ int io_linkat_prep(struct io_kiocb *req, const struct io_uring_sqe *sqe)
|
|||
int io_linkat(struct io_kiocb *req, unsigned int issue_flags)
|
||||
{
|
||||
struct io_link *lnk = io_kiocb_to_cmd(req, struct io_link);
|
||||
CLASS(filename_complete_delayed, old)(&lnk->oldpath);
|
||||
CLASS(filename_complete_delayed, new)(&lnk->newpath);
|
||||
int ret;
|
||||
|
||||
WARN_ON_ONCE(issue_flags & IO_URING_F_NONBLOCK);
|
||||
|
||||
ret = do_linkat(lnk->old_dfd, lnk->oldpath, lnk->new_dfd,
|
||||
lnk->newpath, lnk->flags);
|
||||
ret = filename_linkat(lnk->old_dfd, old, lnk->new_dfd, new, lnk->flags);
|
||||
|
||||
req->flags &= ~REQ_F_NEED_CLEANUP;
|
||||
io_req_set_res(req, ret, 0);
|
||||
|
|
@ -288,6 +300,6 @@ void io_link_cleanup(struct io_kiocb *req)
|
|||
{
|
||||
struct io_link *sl = io_kiocb_to_cmd(req, struct io_link);
|
||||
|
||||
putname(sl->oldpath);
|
||||
putname(sl->newpath);
|
||||
dismiss_delayed_filename(&sl->oldpath);
|
||||
dismiss_delayed_filename(&sl->newpath);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -23,7 +23,7 @@ struct io_open {
|
|||
struct file *file;
|
||||
int dfd;
|
||||
u32 file_slot;
|
||||
struct filename *filename;
|
||||
struct delayed_filename filename;
|
||||
struct open_how how;
|
||||
unsigned long nofile;
|
||||
};
|
||||
|
|
@ -67,12 +67,9 @@ static int __io_openat_prep(struct io_kiocb *req, const struct io_uring_sqe *sqe
|
|||
|
||||
open->dfd = READ_ONCE(sqe->fd);
|
||||
fname = u64_to_user_ptr(READ_ONCE(sqe->addr));
|
||||
open->filename = getname(fname);
|
||||
if (IS_ERR(open->filename)) {
|
||||
ret = PTR_ERR(open->filename);
|
||||
open->filename = NULL;
|
||||
ret = delayed_getname(&open->filename, fname);
|
||||
if (unlikely(ret))
|
||||
return ret;
|
||||
}
|
||||
req->flags |= REQ_F_NEED_CLEANUP;
|
||||
|
||||
open->file_slot = READ_ONCE(sqe->file_index);
|
||||
|
|
@ -121,6 +118,7 @@ int io_openat2(struct io_kiocb *req, unsigned int issue_flags)
|
|||
struct file *file;
|
||||
bool resolve_nonblock, nonblock_set;
|
||||
bool fixed = !!open->file_slot;
|
||||
CLASS(filename_complete_delayed, name)(&open->filename);
|
||||
int ret;
|
||||
|
||||
ret = build_open_flags(&open->how, &op);
|
||||
|
|
@ -140,7 +138,7 @@ int io_openat2(struct io_kiocb *req, unsigned int issue_flags)
|
|||
goto err;
|
||||
}
|
||||
|
||||
file = do_filp_open(open->dfd, open->filename, &op);
|
||||
file = do_file_open(open->dfd, name, &op);
|
||||
if (IS_ERR(file)) {
|
||||
/*
|
||||
* We could hang on to this 'fd' on retrying, but seems like
|
||||
|
|
@ -152,9 +150,13 @@ int io_openat2(struct io_kiocb *req, unsigned int issue_flags)
|
|||
|
||||
ret = PTR_ERR(file);
|
||||
/* only retry if RESOLVE_CACHED wasn't already set by application */
|
||||
if (ret == -EAGAIN &&
|
||||
(!resolve_nonblock && (issue_flags & IO_URING_F_NONBLOCK)))
|
||||
return -EAGAIN;
|
||||
if (ret == -EAGAIN && !resolve_nonblock &&
|
||||
(issue_flags & IO_URING_F_NONBLOCK)) {
|
||||
ret = putname_to_delayed(&open->filename,
|
||||
no_free_ptr(name));
|
||||
if (likely(!ret))
|
||||
return -EAGAIN;
|
||||
}
|
||||
goto err;
|
||||
}
|
||||
|
||||
|
|
@ -167,7 +169,6 @@ int io_openat2(struct io_kiocb *req, unsigned int issue_flags)
|
|||
ret = io_fixed_fd_install(req, issue_flags, file,
|
||||
open->file_slot);
|
||||
err:
|
||||
putname(open->filename);
|
||||
req->flags &= ~REQ_F_NEED_CLEANUP;
|
||||
if (ret < 0)
|
||||
req_set_fail(req);
|
||||
|
|
@ -184,8 +185,7 @@ void io_open_cleanup(struct io_kiocb *req)
|
|||
{
|
||||
struct io_open *open = io_kiocb_to_cmd(req, struct io_open);
|
||||
|
||||
if (open->filename)
|
||||
putname(open->filename);
|
||||
dismiss_delayed_filename(&open->filename);
|
||||
}
|
||||
|
||||
int __io_close_fixed(struct io_ring_ctx *ctx, unsigned int issue_flags,
|
||||
|
|
|
|||
|
|
@ -16,7 +16,7 @@ struct io_statx {
|
|||
int dfd;
|
||||
unsigned int mask;
|
||||
unsigned int flags;
|
||||
struct filename *filename;
|
||||
struct delayed_filename filename;
|
||||
struct statx __user *buffer;
|
||||
};
|
||||
|
||||
|
|
@ -24,6 +24,7 @@ int io_statx_prep(struct io_kiocb *req, const struct io_uring_sqe *sqe)
|
|||
{
|
||||
struct io_statx *sx = io_kiocb_to_cmd(req, struct io_statx);
|
||||
const char __user *path;
|
||||
int ret;
|
||||
|
||||
if (sqe->buf_index || sqe->splice_fd_in)
|
||||
return -EINVAL;
|
||||
|
|
@ -36,14 +37,10 @@ int io_statx_prep(struct io_kiocb *req, const struct io_uring_sqe *sqe)
|
|||
sx->buffer = u64_to_user_ptr(READ_ONCE(sqe->addr2));
|
||||
sx->flags = READ_ONCE(sqe->statx_flags);
|
||||
|
||||
sx->filename = getname_uflags(path, sx->flags);
|
||||
ret = delayed_getname_uflags(&sx->filename, path, sx->flags);
|
||||
|
||||
if (IS_ERR(sx->filename)) {
|
||||
int ret = PTR_ERR(sx->filename);
|
||||
|
||||
sx->filename = NULL;
|
||||
if (unlikely(ret))
|
||||
return ret;
|
||||
}
|
||||
|
||||
req->flags |= REQ_F_NEED_CLEANUP;
|
||||
req->flags |= REQ_F_FORCE_ASYNC;
|
||||
|
|
@ -53,11 +50,12 @@ int io_statx_prep(struct io_kiocb *req, const struct io_uring_sqe *sqe)
|
|||
int io_statx(struct io_kiocb *req, unsigned int issue_flags)
|
||||
{
|
||||
struct io_statx *sx = io_kiocb_to_cmd(req, struct io_statx);
|
||||
CLASS(filename_complete_delayed, name)(&sx->filename);
|
||||
int ret;
|
||||
|
||||
WARN_ON_ONCE(issue_flags & IO_URING_F_NONBLOCK);
|
||||
|
||||
ret = do_statx(sx->dfd, sx->filename, sx->flags, sx->mask, sx->buffer);
|
||||
ret = do_statx(sx->dfd, name, sx->flags, sx->mask, sx->buffer);
|
||||
io_req_set_res(req, ret, 0);
|
||||
return IOU_COMPLETE;
|
||||
}
|
||||
|
|
@ -66,6 +64,5 @@ void io_statx_cleanup(struct io_kiocb *req)
|
|||
{
|
||||
struct io_statx *sx = io_kiocb_to_cmd(req, struct io_statx);
|
||||
|
||||
if (sx->filename)
|
||||
putname(sx->filename);
|
||||
dismiss_delayed_filename(&sx->filename);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -19,16 +19,14 @@
|
|||
struct io_xattr {
|
||||
struct file *file;
|
||||
struct kernel_xattr_ctx ctx;
|
||||
struct filename *filename;
|
||||
struct delayed_filename filename;
|
||||
};
|
||||
|
||||
void io_xattr_cleanup(struct io_kiocb *req)
|
||||
{
|
||||
struct io_xattr *ix = io_kiocb_to_cmd(req, struct io_xattr);
|
||||
|
||||
if (ix->filename)
|
||||
putname(ix->filename);
|
||||
|
||||
dismiss_delayed_filename(&ix->filename);
|
||||
kfree(ix->ctx.kname);
|
||||
kvfree(ix->ctx.kvalue);
|
||||
}
|
||||
|
|
@ -48,7 +46,7 @@ static int __io_getxattr_prep(struct io_kiocb *req,
|
|||
const char __user *name;
|
||||
int ret;
|
||||
|
||||
ix->filename = NULL;
|
||||
INIT_DELAYED_FILENAME(&ix->filename);
|
||||
ix->ctx.kvalue = NULL;
|
||||
name = u64_to_user_ptr(READ_ONCE(sqe->addr));
|
||||
ix->ctx.value = u64_to_user_ptr(READ_ONCE(sqe->addr2));
|
||||
|
|
@ -93,11 +91,7 @@ int io_getxattr_prep(struct io_kiocb *req, const struct io_uring_sqe *sqe)
|
|||
|
||||
path = u64_to_user_ptr(READ_ONCE(sqe->addr3));
|
||||
|
||||
ix->filename = getname(path);
|
||||
if (IS_ERR(ix->filename))
|
||||
return PTR_ERR(ix->filename);
|
||||
|
||||
return 0;
|
||||
return delayed_getname(&ix->filename, path);
|
||||
}
|
||||
|
||||
int io_fgetxattr(struct io_kiocb *req, unsigned int issue_flags)
|
||||
|
|
@ -115,12 +109,12 @@ int io_fgetxattr(struct io_kiocb *req, unsigned int issue_flags)
|
|||
int io_getxattr(struct io_kiocb *req, unsigned int issue_flags)
|
||||
{
|
||||
struct io_xattr *ix = io_kiocb_to_cmd(req, struct io_xattr);
|
||||
CLASS(filename_complete_delayed, name)(&ix->filename);
|
||||
int ret;
|
||||
|
||||
WARN_ON_ONCE(issue_flags & IO_URING_F_NONBLOCK);
|
||||
|
||||
ret = filename_getxattr(AT_FDCWD, ix->filename, LOOKUP_FOLLOW, &ix->ctx);
|
||||
ix->filename = NULL;
|
||||
ret = filename_getxattr(AT_FDCWD, name, LOOKUP_FOLLOW, &ix->ctx);
|
||||
io_xattr_finish(req, ret);
|
||||
return IOU_COMPLETE;
|
||||
}
|
||||
|
|
@ -132,7 +126,7 @@ static int __io_setxattr_prep(struct io_kiocb *req,
|
|||
const char __user *name;
|
||||
int ret;
|
||||
|
||||
ix->filename = NULL;
|
||||
INIT_DELAYED_FILENAME(&ix->filename);
|
||||
name = u64_to_user_ptr(READ_ONCE(sqe->addr));
|
||||
ix->ctx.cvalue = u64_to_user_ptr(READ_ONCE(sqe->addr2));
|
||||
ix->ctx.kvalue = NULL;
|
||||
|
|
@ -169,11 +163,7 @@ int io_setxattr_prep(struct io_kiocb *req, const struct io_uring_sqe *sqe)
|
|||
|
||||
path = u64_to_user_ptr(READ_ONCE(sqe->addr3));
|
||||
|
||||
ix->filename = getname(path);
|
||||
if (IS_ERR(ix->filename))
|
||||
return PTR_ERR(ix->filename);
|
||||
|
||||
return 0;
|
||||
return delayed_getname(&ix->filename, path);
|
||||
}
|
||||
|
||||
int io_fsetxattr_prep(struct io_kiocb *req, const struct io_uring_sqe *sqe)
|
||||
|
|
@ -196,12 +186,12 @@ int io_fsetxattr(struct io_kiocb *req, unsigned int issue_flags)
|
|||
int io_setxattr(struct io_kiocb *req, unsigned int issue_flags)
|
||||
{
|
||||
struct io_xattr *ix = io_kiocb_to_cmd(req, struct io_xattr);
|
||||
CLASS(filename_complete_delayed, name)(&ix->filename);
|
||||
int ret;
|
||||
|
||||
WARN_ON_ONCE(issue_flags & IO_URING_F_NONBLOCK);
|
||||
|
||||
ret = filename_setxattr(AT_FDCWD, ix->filename, LOOKUP_FOLLOW, &ix->ctx);
|
||||
ix->filename = NULL;
|
||||
ret = filename_setxattr(AT_FDCWD, name, LOOKUP_FOLLOW, &ix->ctx);
|
||||
io_xattr_finish(req, ret);
|
||||
return IOU_COMPLETE;
|
||||
}
|
||||
|
|
|
|||
11
ipc/mqueue.c
11
ipc/mqueue.c
|
|
@ -912,13 +912,12 @@ static struct file *mqueue_file_open(struct filename *name,
|
|||
static int do_mq_open(const char __user *u_name, int oflag, umode_t mode,
|
||||
struct mq_attr *attr)
|
||||
{
|
||||
struct filename *name __free(putname) = NULL;;
|
||||
struct vfsmount *mnt = current->nsproxy->ipc_ns->mq_mnt;
|
||||
int fd, ro;
|
||||
|
||||
audit_mq_open(oflag, mode, attr);
|
||||
|
||||
name = getname(u_name);
|
||||
CLASS(filename, name)(u_name);
|
||||
if (IS_ERR(name))
|
||||
return PTR_ERR(name);
|
||||
|
||||
|
|
@ -942,20 +941,19 @@ SYSCALL_DEFINE4(mq_open, const char __user *, u_name, int, oflag, umode_t, mode,
|
|||
SYSCALL_DEFINE1(mq_unlink, const char __user *, u_name)
|
||||
{
|
||||
int err;
|
||||
struct filename *name;
|
||||
struct dentry *dentry;
|
||||
struct inode *inode;
|
||||
struct ipc_namespace *ipc_ns = current->nsproxy->ipc_ns;
|
||||
struct vfsmount *mnt = ipc_ns->mq_mnt;
|
||||
CLASS(filename, name)(u_name);
|
||||
|
||||
name = getname(u_name);
|
||||
if (IS_ERR(name))
|
||||
return PTR_ERR(name);
|
||||
|
||||
audit_inode_parent_hidden(name, mnt->mnt_root);
|
||||
err = mnt_want_write(mnt);
|
||||
if (err)
|
||||
goto out_name;
|
||||
return err;
|
||||
dentry = start_removing_noperm(mnt->mnt_root, &QSTR(name->name));
|
||||
if (IS_ERR(dentry)) {
|
||||
err = PTR_ERR(dentry);
|
||||
|
|
@ -971,9 +969,6 @@ SYSCALL_DEFINE1(mq_unlink, const char __user *, u_name)
|
|||
|
||||
out_drop_write:
|
||||
mnt_drop_write(mnt);
|
||||
out_name:
|
||||
putname(name);
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -218,7 +218,6 @@ static int acct_on(const char __user *name)
|
|||
/* Difference from BSD - they don't do O_APPEND */
|
||||
const int open_flags = O_WRONLY|O_APPEND|O_LARGEFILE;
|
||||
struct pid_namespace *ns = task_active_pid_ns(current);
|
||||
struct filename *pathname __free(putname) = getname(name);
|
||||
struct file *original_file __free(fput) = NULL; // in that order
|
||||
struct path internal __free(path_put) = {}; // in that order
|
||||
struct file *file __free(fput_sync) = NULL; // in that order
|
||||
|
|
@ -226,8 +225,7 @@ static int acct_on(const char __user *name)
|
|||
struct vfsmount *mnt;
|
||||
struct fs_pin *old;
|
||||
|
||||
if (IS_ERR(pathname))
|
||||
return PTR_ERR(pathname);
|
||||
CLASS(filename, pathname)(name);
|
||||
original_file = file_open_name(pathname, open_flags, 0);
|
||||
if (IS_ERR(original_file))
|
||||
return PTR_ERR(original_file);
|
||||
|
|
|
|||
|
|
@ -2169,29 +2169,6 @@ static struct audit_names *audit_alloc_name(struct audit_context *context,
|
|||
return aname;
|
||||
}
|
||||
|
||||
/**
|
||||
* __audit_reusename - fill out filename with info from existing entry
|
||||
* @uptr: userland ptr to pathname
|
||||
*
|
||||
* Search the audit_names list for the current audit context. If there is an
|
||||
* existing entry with a matching "uptr" then return the filename
|
||||
* associated with that audit_name. If not, return NULL.
|
||||
*/
|
||||
struct filename *
|
||||
__audit_reusename(const __user char *uptr)
|
||||
{
|
||||
struct audit_context *context = audit_context();
|
||||
struct audit_names *n;
|
||||
|
||||
list_for_each_entry(n, &context->names_list, list) {
|
||||
if (!n->name)
|
||||
continue;
|
||||
if (n->name->uptr == uptr)
|
||||
return refname(n->name);
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
* __audit_getname - add a name to the list
|
||||
* @name: name to add
|
||||
|
|
@ -2214,7 +2191,7 @@ void __audit_getname(struct filename *name)
|
|||
n->name = name;
|
||||
n->name_len = AUDIT_NAME_FULL;
|
||||
name->aname = n;
|
||||
refname(name);
|
||||
name->refcnt++;
|
||||
}
|
||||
|
||||
static inline int audit_copy_fcaps(struct audit_names *name,
|
||||
|
|
@ -2346,7 +2323,7 @@ out_alloc:
|
|||
return;
|
||||
if (name) {
|
||||
n->name = name;
|
||||
refname(name);
|
||||
name->refcnt++;
|
||||
}
|
||||
|
||||
out:
|
||||
|
|
@ -2468,7 +2445,7 @@ void __audit_inode_child(struct inode *parent,
|
|||
if (found_parent) {
|
||||
found_child->name = found_parent->name;
|
||||
found_child->name_len = AUDIT_NAME_FULL;
|
||||
refname(found_child->name);
|
||||
found_child->name->refcnt++;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -4692,23 +4692,18 @@ static int split_huge_pages_in_file(const char *file_path, pgoff_t off_start,
|
|||
pgoff_t off_end, unsigned int new_order,
|
||||
long in_folio_offset)
|
||||
{
|
||||
struct filename *file;
|
||||
struct file *candidate;
|
||||
struct address_space *mapping;
|
||||
int ret = -EINVAL;
|
||||
pgoff_t index;
|
||||
int nr_pages = 1;
|
||||
unsigned long total = 0, split = 0;
|
||||
unsigned int min_order;
|
||||
unsigned int target_order;
|
||||
|
||||
file = getname_kernel(file_path);
|
||||
if (IS_ERR(file))
|
||||
return ret;
|
||||
|
||||
CLASS(filename_kernel, file)(file_path);
|
||||
candidate = file_open_name(file, O_RDONLY, 0);
|
||||
if (IS_ERR(candidate))
|
||||
goto out;
|
||||
return -EINVAL;
|
||||
|
||||
pr_debug("split file-backed THPs in file: %s, page offset: [0x%lx - 0x%lx], new_order: %u, in_folio_offset: %ld\n",
|
||||
file_path, off_start, off_end, new_order, in_folio_offset);
|
||||
|
|
@ -4757,12 +4752,8 @@ next:
|
|||
}
|
||||
|
||||
filp_close(candidate, NULL);
|
||||
ret = 0;
|
||||
|
||||
pr_debug("%lu of %lu file-backed THP split\n", split, total);
|
||||
out:
|
||||
putname(file);
|
||||
return ret;
|
||||
return 0;
|
||||
}
|
||||
|
||||
#define MAX_INPUT_BUF_SZ 255
|
||||
|
|
|
|||
|
|
@ -2831,7 +2831,6 @@ SYSCALL_DEFINE1(swapoff, const char __user *, specialfile)
|
|||
struct file *swap_file, *victim;
|
||||
struct address_space *mapping;
|
||||
struct inode *inode;
|
||||
struct filename *pathname;
|
||||
unsigned int maxpages;
|
||||
int err, found = 0;
|
||||
|
||||
|
|
@ -2840,14 +2839,10 @@ SYSCALL_DEFINE1(swapoff, const char __user *, specialfile)
|
|||
|
||||
BUG_ON(!current->mm);
|
||||
|
||||
pathname = getname(specialfile);
|
||||
if (IS_ERR(pathname))
|
||||
return PTR_ERR(pathname);
|
||||
|
||||
CLASS(filename, pathname)(specialfile);
|
||||
victim = file_open_name(pathname, O_RDWR|O_LARGEFILE, 0);
|
||||
err = PTR_ERR(victim);
|
||||
if (IS_ERR(victim))
|
||||
goto out;
|
||||
return PTR_ERR(victim);
|
||||
|
||||
mapping = victim->f_mapping;
|
||||
spin_lock(&swap_lock);
|
||||
|
|
@ -2964,8 +2959,6 @@ SYSCALL_DEFINE1(swapoff, const char __user *, specialfile)
|
|||
|
||||
out_dput:
|
||||
filp_close(victim, NULL);
|
||||
out:
|
||||
putname(pathname);
|
||||
return err;
|
||||
}
|
||||
|
||||
|
|
@ -3392,7 +3385,6 @@ err:
|
|||
SYSCALL_DEFINE2(swapon, const char __user *, specialfile, int, swap_flags)
|
||||
{
|
||||
struct swap_info_struct *si;
|
||||
struct filename *name;
|
||||
struct file *swap_file = NULL;
|
||||
struct address_space *mapping;
|
||||
struct dentry *dentry;
|
||||
|
|
@ -3422,12 +3414,7 @@ SYSCALL_DEFINE2(swapon, const char __user *, specialfile, int, swap_flags)
|
|||
INIT_WORK(&si->discard_work, swap_discard_work);
|
||||
INIT_WORK(&si->reclaim_work, swap_reclaim_work);
|
||||
|
||||
name = getname(specialfile);
|
||||
if (IS_ERR(name)) {
|
||||
error = PTR_ERR(name);
|
||||
name = NULL;
|
||||
goto bad_swap;
|
||||
}
|
||||
CLASS(filename, name)(specialfile);
|
||||
swap_file = file_open_name(name, O_RDWR | O_LARGEFILE | O_EXCL, 0);
|
||||
if (IS_ERR(swap_file)) {
|
||||
error = PTR_ERR(swap_file);
|
||||
|
|
@ -3635,8 +3622,6 @@ bad_swap:
|
|||
out:
|
||||
if (!IS_ERR_OR_NULL(folio))
|
||||
folio_release_kmap(folio, swap_header);
|
||||
if (name)
|
||||
putname(name);
|
||||
if (inode)
|
||||
inode_unlock(inode);
|
||||
return error;
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue