Allow lookup flags to be passed to filename_*() so callers can pass LOOUP_IN_INIT to explicitly opt-into to performing lookups in init's filesystem state. Signed-off-by: Christian Brauner --- fs/coredump.c | 2 +- fs/init.c | 12 ++++++------ fs/internal.h | 18 ++++++++++++------ fs/namei.c | 52 +++++++++++++++++++++++++++------------------------- io_uring/fs.c | 10 +++++----- 5 files changed, 51 insertions(+), 43 deletions(-) diff --git a/fs/coredump.c b/fs/coredump.c index 29df8aa19e2e..550a1553f6cb 100644 --- a/fs/coredump.c +++ b/fs/coredump.c @@ -900,7 +900,7 @@ static bool coredump_file(struct core_name *cn, struct coredump_params *cprm, * If it doesn't exist, that's fine. If there's some * other problem, we'll catch it at the filp_open(). */ - filename_unlinkat(AT_FDCWD, name); + filename_unlinkat(AT_FDCWD, name, 0); } /* diff --git a/fs/init.c b/fs/init.c index 33e312d74f58..a79872d5af3b 100644 --- a/fs/init.c +++ b/fs/init.c @@ -158,39 +158,39 @@ 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) { CLASS(filename_kernel, name)(filename); - return filename_mknodat(AT_FDCWD, name, mode, dev); + return filename_mknodat(AT_FDCWD, name, mode, dev, 0); } int __init init_link(const char *oldname, const char *newname) { CLASS(filename_kernel, old)(oldname); CLASS(filename_kernel, new)(newname); - return filename_linkat(AT_FDCWD, old, AT_FDCWD, new, 0); + return filename_linkat(AT_FDCWD, old, AT_FDCWD, new, 0, 0); } int __init init_symlink(const char *oldname, const char *newname) { CLASS(filename_kernel, old)(oldname); CLASS(filename_kernel, new)(newname); - return filename_symlinkat(old, AT_FDCWD, new); + return filename_symlinkat(old, AT_FDCWD, new, 0); } int __init init_unlink(const char *pathname) { CLASS(filename_kernel, name)(pathname); - return filename_unlinkat(AT_FDCWD, name); + return filename_unlinkat(AT_FDCWD, name, 0); } int __init init_mkdir(const char *pathname, umode_t mode) { CLASS(filename_kernel, name)(pathname); - return filename_mkdirat(AT_FDCWD, name, mode); + return filename_mkdirat(AT_FDCWD, name, mode, 0); } int __init init_rmdir(const char *pathname) { CLASS(filename_kernel, name)(pathname); - return filename_rmdir(AT_FDCWD, name); + return filename_rmdir(AT_FDCWD, name, 0); } int __init init_utimes(char *filename, struct timespec64 *ts) diff --git a/fs/internal.h b/fs/internal.h index cbc384a1aa09..7302badcae69 100644 --- a/fs/internal.h +++ b/fs/internal.h @@ -53,16 +53,22 @@ 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 filename_rmdir(int dfd, struct filename *name); -int filename_unlinkat(int dfd, struct filename *name); +int filename_rmdir(int dfd, struct filename *name, + unsigned int lookup_flags); +int filename_unlinkat(int dfd, struct filename *name, + unsigned int lookup_flags); int may_linkat(struct mnt_idmap *idmap, const struct path *link); int filename_renameat2(int olddfd, struct filename *oldname, int newdfd, struct filename *newname, unsigned int flags); -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_mkdirat(int dfd, struct filename *name, umode_t mode, + unsigned int lookup_flags); +int filename_mknodat(int dfd, struct filename *name, umode_t mode, + unsigned int dev, unsigned int lookup_flags); +int filename_symlinkat(struct filename *from, int newdfd, struct filename *to, + unsigned int lookup_flags); int filename_linkat(int olddfd, struct filename *old, int newdfd, - struct filename *new, int flags); + struct filename *new, int flags, + unsigned int lookup_flags); int vfs_tmpfile(struct mnt_idmap *idmap, const struct path *parentpath, struct file *file, umode_t mode); diff --git a/fs/namei.c b/fs/namei.c index dd2710d5f5df..5cf407aad5b3 100644 --- a/fs/namei.c +++ b/fs/namei.c @@ -5125,14 +5125,13 @@ static int may_mknod(umode_t mode) } int filename_mknodat(int dfd, struct filename *name, umode_t mode, - unsigned int dev) + unsigned int dev, unsigned int lookup_flags) { struct delegated_inode di = { }; struct mnt_idmap *idmap; struct dentry *dentry; struct path path; int error; - unsigned int lookup_flags = 0; error = may_mknod(mode); if (error) @@ -5181,13 +5180,13 @@ SYSCALL_DEFINE4(mknodat, int, dfd, const char __user *, filename, umode_t, mode, unsigned int, dev) { CLASS(filename, name)(filename); - return filename_mknodat(dfd, name, mode, dev); + return filename_mknodat(dfd, name, mode, dev, 0); } SYSCALL_DEFINE3(mknod, const char __user *, filename, umode_t, mode, unsigned, dev) { CLASS(filename, name)(filename); - return filename_mknodat(AT_FDCWD, name, mode, dev); + return filename_mknodat(AT_FDCWD, name, mode, dev, 0); } /** @@ -5258,14 +5257,16 @@ struct dentry *vfs_mkdir(struct mnt_idmap *idmap, struct inode *dir, } EXPORT_SYMBOL(vfs_mkdir); -int filename_mkdirat(int dfd, struct filename *name, umode_t mode) +int filename_mkdirat(int dfd, struct filename *name, umode_t mode, + unsigned int lookup_flags) { struct dentry *dentry; struct path path; int error; - unsigned int lookup_flags = LOOKUP_DIRECTORY; struct delegated_inode delegated_inode = { }; + lookup_flags |= LOOKUP_DIRECTORY; + retry: dentry = filename_create(dfd, name, &path, lookup_flags); if (IS_ERR(dentry)) @@ -5295,13 +5296,13 @@ int filename_mkdirat(int dfd, struct filename *name, umode_t mode) SYSCALL_DEFINE3(mkdirat, int, dfd, const char __user *, pathname, umode_t, mode) { CLASS(filename, name)(pathname); - return filename_mkdirat(dfd, name, mode); + return filename_mkdirat(dfd, name, mode, 0); } SYSCALL_DEFINE2(mkdir, const char __user *, pathname, umode_t, mode) { CLASS(filename, name)(pathname); - return filename_mkdirat(AT_FDCWD, name, mode); + return filename_mkdirat(AT_FDCWD, name, mode, 0); } /** @@ -5364,14 +5365,14 @@ int vfs_rmdir(struct mnt_idmap *idmap, struct inode *dir, } EXPORT_SYMBOL(vfs_rmdir); -int filename_rmdir(int dfd, struct filename *name) +int filename_rmdir(int dfd, struct filename *name, + unsigned int lookup_flags) { int error; struct dentry *dentry; struct path path; struct qstr last; int type; - unsigned int lookup_flags = 0; struct delegated_inode delegated_inode = { }; retry: error = filename_parentat(dfd, name, lookup_flags, &path, &last, &type); @@ -5424,7 +5425,7 @@ int filename_rmdir(int dfd, struct filename *name) SYSCALL_DEFINE1(rmdir, const char __user *, pathname) { CLASS(filename, name)(pathname); - return filename_rmdir(AT_FDCWD, name); + return filename_rmdir(AT_FDCWD, name, 0); } /** @@ -5506,7 +5507,8 @@ EXPORT_SYMBOL(vfs_unlink); * writeout happening, and we don't want to prevent access to the directory * while waiting on the I/O. */ -int filename_unlinkat(int dfd, struct filename *name) +int filename_unlinkat(int dfd, struct filename *name, + unsigned int lookup_flags) { int error; struct dentry *dentry; @@ -5515,7 +5517,6 @@ int filename_unlinkat(int dfd, struct filename *name) int type; struct inode *inode; struct delegated_inode delegated_inode = { }; - unsigned int lookup_flags = 0; retry: error = filename_parentat(dfd, name, lookup_flags, &path, &last, &type); if (error) @@ -5576,14 +5577,14 @@ SYSCALL_DEFINE3(unlinkat, int, dfd, const char __user *, pathname, int, flag) CLASS(filename, name)(pathname); if (flag & AT_REMOVEDIR) - return filename_rmdir(dfd, name); - return filename_unlinkat(dfd, name); + return filename_rmdir(dfd, name, 0); + return filename_unlinkat(dfd, name, 0); } SYSCALL_DEFINE1(unlink, const char __user *, pathname) { CLASS(filename, name)(pathname); - return filename_unlinkat(AT_FDCWD, name); + return filename_unlinkat(AT_FDCWD, name, 0); } /** @@ -5630,12 +5631,12 @@ int vfs_symlink(struct mnt_idmap *idmap, struct inode *dir, } EXPORT_SYMBOL(vfs_symlink); -int filename_symlinkat(struct filename *from, int newdfd, struct filename *to) +int filename_symlinkat(struct filename *from, int newdfd, struct filename *to, + unsigned int lookup_flags) { int error; struct dentry *dentry; struct path path; - unsigned int lookup_flags = 0; struct delegated_inode delegated_inode = { }; if (IS_ERR(from)) @@ -5668,14 +5669,14 @@ SYSCALL_DEFINE3(symlinkat, const char __user *, oldname, { CLASS(filename, old)(oldname); CLASS(filename, new)(newname); - return filename_symlinkat(old, newdfd, new); + return filename_symlinkat(old, newdfd, new, 0); } SYSCALL_DEFINE2(symlink, const char __user *, oldname, const char __user *, newname) { CLASS(filename, old)(oldname); CLASS(filename, new)(newname); - return filename_symlinkat(old, AT_FDCWD, new); + return filename_symlinkat(old, AT_FDCWD, new, 0); } /** @@ -5779,13 +5780,14 @@ EXPORT_SYMBOL(vfs_link); * and other special files. --ADM */ int filename_linkat(int olddfd, struct filename *old, - int newdfd, struct filename *new, int flags) + int newdfd, struct filename *new, int flags, + unsigned int lookup_flags) { struct mnt_idmap *idmap; struct dentry *new_dentry; struct path old_path, new_path; struct delegated_inode delegated_inode = { }; - int how = 0; + int how = lookup_flags; int error; if ((flags & ~(AT_SYMLINK_FOLLOW | AT_EMPTY_PATH)) != 0) @@ -5807,7 +5809,7 @@ int filename_linkat(int olddfd, struct filename *old, return error; new_dentry = filename_create(newdfd, new, &new_path, - (how & LOOKUP_REVAL)); + (how & (LOOKUP_REVAL | LOOKUP_IN_INIT))); error = PTR_ERR(new_dentry); if (IS_ERR(new_dentry)) goto out_putpath; @@ -5848,14 +5850,14 @@ SYSCALL_DEFINE5(linkat, int, olddfd, const char __user *, oldname, { CLASS(filename_uflags, old)(oldname, flags); CLASS(filename, new)(newname); - return filename_linkat(olddfd, old, newdfd, new, flags); + return filename_linkat(olddfd, old, newdfd, new, flags, 0); } SYSCALL_DEFINE2(link, const char __user *, oldname, const char __user *, newname) { CLASS(filename, old)(oldname); CLASS(filename, new)(newname); - return filename_linkat(AT_FDCWD, old, AT_FDCWD, new, 0); + return filename_linkat(AT_FDCWD, old, AT_FDCWD, new, 0, 0); } /** diff --git a/io_uring/fs.c b/io_uring/fs.c index d0580c754bf8..1d9b2939f5ae 100644 --- a/io_uring/fs.c +++ b/io_uring/fs.c @@ -140,9 +140,9 @@ int io_unlinkat(struct io_kiocb *req, unsigned int issue_flags) WARN_ON_ONCE(issue_flags & IO_URING_F_NONBLOCK); if (un->flags & AT_REMOVEDIR) - ret = filename_rmdir(un->dfd, name); + ret = filename_rmdir(un->dfd, name, 0); else - ret = filename_unlinkat(un->dfd, name); + ret = filename_unlinkat(un->dfd, name, 0); req->flags &= ~REQ_F_NEED_CLEANUP; io_req_set_res(req, ret, 0); @@ -188,7 +188,7 @@ int io_mkdirat(struct io_kiocb *req, unsigned int issue_flags) WARN_ON_ONCE(issue_flags & IO_URING_F_NONBLOCK); - ret = filename_mkdirat(mkd->dfd, name, mkd->mode); + ret = filename_mkdirat(mkd->dfd, name, mkd->mode, 0); req->flags &= ~REQ_F_NEED_CLEANUP; io_req_set_res(req, ret, 0); @@ -241,7 +241,7 @@ int io_symlinkat(struct io_kiocb *req, unsigned int issue_flags) WARN_ON_ONCE(issue_flags & IO_URING_F_NONBLOCK); - ret = filename_symlinkat(old, sl->new_dfd, new); + ret = filename_symlinkat(old, sl->new_dfd, new, 0); req->flags &= ~REQ_F_NEED_CLEANUP; io_req_set_res(req, ret, 0); @@ -289,7 +289,7 @@ int io_linkat(struct io_kiocb *req, unsigned int issue_flags) WARN_ON_ONCE(issue_flags & IO_URING_F_NONBLOCK); - ret = filename_linkat(lnk->old_dfd, old, lnk->new_dfd, new, lnk->flags); + ret = filename_linkat(lnk->old_dfd, old, lnk->new_dfd, new, lnk->flags, 0); req->flags &= ~REQ_F_NEED_CLEANUP; io_req_set_res(req, ret, 0); -- 2.47.3