diff options
| author | Linus Torvalds <torvalds@linux-foundation.org> | 2026-02-09 16:58:28 -0800 |
|---|---|---|
| committer | Linus Torvalds <torvalds@linux-foundation.org> | 2026-02-09 16:58:28 -0800 |
| commit | 26c9342bb761e463774a64fb6210b4f95f5bc035 (patch) | |
| tree | 486d504cf5dcfe041eba4d9d5eb468a5a7b81566 /io_uring | |
| parent | 8a5203c630c67d578975ff237413f5e0b5000af8 (diff) | |
| parent | 0787a93baa1aab9fd0cb8500105d11d3d3a58f7a (diff) | |
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)
...
Diffstat (limited to 'io_uring')
| -rw-r--r-- | io_uring/fs.c | 106 | ||||
| -rw-r--r-- | io_uring/openclose.c | 26 | ||||
| -rw-r--r-- | io_uring/statx.c | 17 | ||||
| -rw-r--r-- | io_uring/xattr.c | 30 |
4 files changed, 89 insertions, 90 deletions
diff --git a/io_uring/fs.c b/io_uring/fs.c index 37079a414eab..d0580c754bf8 100644 --- a/io_uring/fs.c +++ b/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); } diff --git a/io_uring/openclose.c b/io_uring/openclose.c index 15dde9bd6ff6..c09dd14108ed 100644 --- a/io_uring/openclose.c +++ b/io_uring/openclose.c @@ -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, diff --git a/io_uring/statx.c b/io_uring/statx.c index 5111e9befbfe..7bcae4a6c4a3 100644 --- a/io_uring/statx.c +++ b/io_uring/statx.c @@ -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); - - if (IS_ERR(sx->filename)) { - int ret = PTR_ERR(sx->filename); + ret = delayed_getname_uflags(&sx->filename, path, sx->flags); - 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); } diff --git a/io_uring/xattr.c b/io_uring/xattr.c index 322b94ff9e4b..ba2b98cf13f9 100644 --- a/io_uring/xattr.c +++ b/io_uring/xattr.c @@ -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; } |
