15e2a18d9SJens Axboe // SPDX-License-Identifier: GPL-2.0 25e2a18d9SJens Axboe #include <linux/kernel.h> 35e2a18d9SJens Axboe #include <linux/errno.h> 45e2a18d9SJens Axboe #include <linux/fs.h> 55e2a18d9SJens Axboe #include <linux/file.h> 65e2a18d9SJens Axboe #include <linux/mm.h> 75e2a18d9SJens Axboe #include <linux/slab.h> 85e2a18d9SJens Axboe #include <linux/namei.h> 95e2a18d9SJens Axboe #include <linux/io_uring.h> 105e2a18d9SJens Axboe #include <linux/xattr.h> 115e2a18d9SJens Axboe 125e2a18d9SJens Axboe #include <uapi/linux/io_uring.h> 135e2a18d9SJens Axboe 145e2a18d9SJens Axboe #include "../fs/internal.h" 155e2a18d9SJens Axboe 165e2a18d9SJens Axboe #include "io_uring.h" 175e2a18d9SJens Axboe #include "xattr.h" 185e2a18d9SJens Axboe 195e2a18d9SJens Axboe struct io_xattr { 205e2a18d9SJens Axboe struct file *file; 215e2a18d9SJens Axboe struct xattr_ctx ctx; 225e2a18d9SJens Axboe struct filename *filename; 235e2a18d9SJens Axboe }; 245e2a18d9SJens Axboe 255e2a18d9SJens Axboe void io_xattr_cleanup(struct io_kiocb *req) 265e2a18d9SJens Axboe { 27f2ccb5aeSStefan Metzmacher struct io_xattr *ix = io_kiocb_to_cmd(req, struct io_xattr); 285e2a18d9SJens Axboe 295e2a18d9SJens Axboe if (ix->filename) 305e2a18d9SJens Axboe putname(ix->filename); 315e2a18d9SJens Axboe 325e2a18d9SJens Axboe kfree(ix->ctx.kname); 335e2a18d9SJens Axboe kvfree(ix->ctx.kvalue); 345e2a18d9SJens Axboe } 355e2a18d9SJens Axboe 365e2a18d9SJens Axboe static void io_xattr_finish(struct io_kiocb *req, int ret) 375e2a18d9SJens Axboe { 385e2a18d9SJens Axboe req->flags &= ~REQ_F_NEED_CLEANUP; 395e2a18d9SJens Axboe 405e2a18d9SJens Axboe io_xattr_cleanup(req); 415e2a18d9SJens Axboe io_req_set_res(req, ret, 0); 425e2a18d9SJens Axboe } 435e2a18d9SJens Axboe 445e2a18d9SJens Axboe static int __io_getxattr_prep(struct io_kiocb *req, 455e2a18d9SJens Axboe const struct io_uring_sqe *sqe) 465e2a18d9SJens Axboe { 47f2ccb5aeSStefan Metzmacher struct io_xattr *ix = io_kiocb_to_cmd(req, struct io_xattr); 485e2a18d9SJens Axboe const char __user *name; 495e2a18d9SJens Axboe int ret; 505e2a18d9SJens Axboe 515e2a18d9SJens Axboe if (unlikely(req->flags & REQ_F_FIXED_FILE)) 525e2a18d9SJens Axboe return -EBADF; 535e2a18d9SJens Axboe 545e2a18d9SJens Axboe ix->filename = NULL; 555e2a18d9SJens Axboe ix->ctx.kvalue = NULL; 565e2a18d9SJens Axboe name = u64_to_user_ptr(READ_ONCE(sqe->addr)); 575e2a18d9SJens Axboe ix->ctx.cvalue = u64_to_user_ptr(READ_ONCE(sqe->addr2)); 585e2a18d9SJens Axboe ix->ctx.size = READ_ONCE(sqe->len); 595e2a18d9SJens Axboe ix->ctx.flags = READ_ONCE(sqe->xattr_flags); 605e2a18d9SJens Axboe 615e2a18d9SJens Axboe if (ix->ctx.flags) 625e2a18d9SJens Axboe return -EINVAL; 635e2a18d9SJens Axboe 645e2a18d9SJens Axboe ix->ctx.kname = kmalloc(sizeof(*ix->ctx.kname), GFP_KERNEL); 655e2a18d9SJens Axboe if (!ix->ctx.kname) 665e2a18d9SJens Axboe return -ENOMEM; 675e2a18d9SJens Axboe 685e2a18d9SJens Axboe ret = strncpy_from_user(ix->ctx.kname->name, name, 695e2a18d9SJens Axboe sizeof(ix->ctx.kname->name)); 705e2a18d9SJens Axboe if (!ret || ret == sizeof(ix->ctx.kname->name)) 715e2a18d9SJens Axboe ret = -ERANGE; 725e2a18d9SJens Axboe if (ret < 0) { 735e2a18d9SJens Axboe kfree(ix->ctx.kname); 745e2a18d9SJens Axboe return ret; 755e2a18d9SJens Axboe } 765e2a18d9SJens Axboe 775e2a18d9SJens Axboe req->flags |= REQ_F_NEED_CLEANUP; 785e2a18d9SJens Axboe return 0; 795e2a18d9SJens Axboe } 805e2a18d9SJens Axboe 815e2a18d9SJens Axboe int io_fgetxattr_prep(struct io_kiocb *req, const struct io_uring_sqe *sqe) 825e2a18d9SJens Axboe { 835e2a18d9SJens Axboe return __io_getxattr_prep(req, sqe); 845e2a18d9SJens Axboe } 855e2a18d9SJens Axboe 865e2a18d9SJens Axboe int io_getxattr_prep(struct io_kiocb *req, const struct io_uring_sqe *sqe) 875e2a18d9SJens Axboe { 88f2ccb5aeSStefan Metzmacher struct io_xattr *ix = io_kiocb_to_cmd(req, struct io_xattr); 895e2a18d9SJens Axboe const char __user *path; 905e2a18d9SJens Axboe int ret; 915e2a18d9SJens Axboe 925e2a18d9SJens Axboe ret = __io_getxattr_prep(req, sqe); 935e2a18d9SJens Axboe if (ret) 945e2a18d9SJens Axboe return ret; 955e2a18d9SJens Axboe 965e2a18d9SJens Axboe path = u64_to_user_ptr(READ_ONCE(sqe->addr3)); 975e2a18d9SJens Axboe 985e2a18d9SJens Axboe ix->filename = getname_flags(path, LOOKUP_FOLLOW, NULL); 995e2a18d9SJens Axboe if (IS_ERR(ix->filename)) { 1005e2a18d9SJens Axboe ret = PTR_ERR(ix->filename); 1015e2a18d9SJens Axboe ix->filename = NULL; 1025e2a18d9SJens Axboe } 1035e2a18d9SJens Axboe 1045e2a18d9SJens Axboe return ret; 1055e2a18d9SJens Axboe } 1065e2a18d9SJens Axboe 1075e2a18d9SJens Axboe int io_fgetxattr(struct io_kiocb *req, unsigned int issue_flags) 1085e2a18d9SJens Axboe { 109f2ccb5aeSStefan Metzmacher struct io_xattr *ix = io_kiocb_to_cmd(req, struct io_xattr); 1105e2a18d9SJens Axboe int ret; 1115e2a18d9SJens Axboe 1125e2a18d9SJens Axboe if (issue_flags & IO_URING_F_NONBLOCK) 1135e2a18d9SJens Axboe return -EAGAIN; 1145e2a18d9SJens Axboe 1155e2a18d9SJens Axboe ret = do_getxattr(mnt_user_ns(req->file->f_path.mnt), 1165e2a18d9SJens Axboe req->file->f_path.dentry, 1175e2a18d9SJens Axboe &ix->ctx); 1185e2a18d9SJens Axboe 1195e2a18d9SJens Axboe io_xattr_finish(req, ret); 1205e2a18d9SJens Axboe return IOU_OK; 1215e2a18d9SJens Axboe } 1225e2a18d9SJens Axboe 1235e2a18d9SJens Axboe int io_getxattr(struct io_kiocb *req, unsigned int issue_flags) 1245e2a18d9SJens Axboe { 125f2ccb5aeSStefan Metzmacher struct io_xattr *ix = io_kiocb_to_cmd(req, struct io_xattr); 1265e2a18d9SJens Axboe unsigned int lookup_flags = LOOKUP_FOLLOW; 1275e2a18d9SJens Axboe struct path path; 1285e2a18d9SJens Axboe int ret; 1295e2a18d9SJens Axboe 1305e2a18d9SJens Axboe if (issue_flags & IO_URING_F_NONBLOCK) 1315e2a18d9SJens Axboe return -EAGAIN; 1325e2a18d9SJens Axboe 1335e2a18d9SJens Axboe retry: 1345e2a18d9SJens Axboe ret = filename_lookup(AT_FDCWD, ix->filename, lookup_flags, &path, NULL); 1355e2a18d9SJens Axboe if (!ret) { 1365e2a18d9SJens Axboe ret = do_getxattr(mnt_user_ns(path.mnt), 1375e2a18d9SJens Axboe path.dentry, 1385e2a18d9SJens Axboe &ix->ctx); 1395e2a18d9SJens Axboe 1405e2a18d9SJens Axboe path_put(&path); 1415e2a18d9SJens Axboe if (retry_estale(ret, lookup_flags)) { 1425e2a18d9SJens Axboe lookup_flags |= LOOKUP_REVAL; 1435e2a18d9SJens Axboe goto retry; 1445e2a18d9SJens Axboe } 1455e2a18d9SJens Axboe } 1465e2a18d9SJens Axboe 1475e2a18d9SJens Axboe io_xattr_finish(req, ret); 1485e2a18d9SJens Axboe return IOU_OK; 1495e2a18d9SJens Axboe } 1505e2a18d9SJens Axboe 1515e2a18d9SJens Axboe static int __io_setxattr_prep(struct io_kiocb *req, 1525e2a18d9SJens Axboe const struct io_uring_sqe *sqe) 1535e2a18d9SJens Axboe { 154f2ccb5aeSStefan Metzmacher struct io_xattr *ix = io_kiocb_to_cmd(req, struct io_xattr); 1555e2a18d9SJens Axboe const char __user *name; 1565e2a18d9SJens Axboe int ret; 1575e2a18d9SJens Axboe 1585e2a18d9SJens Axboe if (unlikely(req->flags & REQ_F_FIXED_FILE)) 1595e2a18d9SJens Axboe return -EBADF; 1605e2a18d9SJens Axboe 1615e2a18d9SJens Axboe ix->filename = NULL; 1625e2a18d9SJens Axboe name = u64_to_user_ptr(READ_ONCE(sqe->addr)); 1635e2a18d9SJens Axboe ix->ctx.cvalue = u64_to_user_ptr(READ_ONCE(sqe->addr2)); 1645e2a18d9SJens Axboe ix->ctx.kvalue = NULL; 1655e2a18d9SJens Axboe ix->ctx.size = READ_ONCE(sqe->len); 1665e2a18d9SJens Axboe ix->ctx.flags = READ_ONCE(sqe->xattr_flags); 1675e2a18d9SJens Axboe 1685e2a18d9SJens Axboe ix->ctx.kname = kmalloc(sizeof(*ix->ctx.kname), GFP_KERNEL); 1695e2a18d9SJens Axboe if (!ix->ctx.kname) 1705e2a18d9SJens Axboe return -ENOMEM; 1715e2a18d9SJens Axboe 1725e2a18d9SJens Axboe ret = setxattr_copy(name, &ix->ctx); 1735e2a18d9SJens Axboe if (ret) { 1745e2a18d9SJens Axboe kfree(ix->ctx.kname); 1755e2a18d9SJens Axboe return ret; 1765e2a18d9SJens Axboe } 1775e2a18d9SJens Axboe 1785e2a18d9SJens Axboe req->flags |= REQ_F_NEED_CLEANUP; 1795e2a18d9SJens Axboe return 0; 1805e2a18d9SJens Axboe } 1815e2a18d9SJens Axboe 1825e2a18d9SJens Axboe int io_setxattr_prep(struct io_kiocb *req, const struct io_uring_sqe *sqe) 1835e2a18d9SJens Axboe { 184f2ccb5aeSStefan Metzmacher struct io_xattr *ix = io_kiocb_to_cmd(req, struct io_xattr); 1855e2a18d9SJens Axboe const char __user *path; 1865e2a18d9SJens Axboe int ret; 1875e2a18d9SJens Axboe 1885e2a18d9SJens Axboe ret = __io_setxattr_prep(req, sqe); 1895e2a18d9SJens Axboe if (ret) 1905e2a18d9SJens Axboe return ret; 1915e2a18d9SJens Axboe 1925e2a18d9SJens Axboe path = u64_to_user_ptr(READ_ONCE(sqe->addr3)); 1935e2a18d9SJens Axboe 1945e2a18d9SJens Axboe ix->filename = getname_flags(path, LOOKUP_FOLLOW, NULL); 1955e2a18d9SJens Axboe if (IS_ERR(ix->filename)) { 1965e2a18d9SJens Axboe ret = PTR_ERR(ix->filename); 1975e2a18d9SJens Axboe ix->filename = NULL; 1985e2a18d9SJens Axboe } 1995e2a18d9SJens Axboe 2005e2a18d9SJens Axboe return ret; 2015e2a18d9SJens Axboe } 2025e2a18d9SJens Axboe 2035e2a18d9SJens Axboe int io_fsetxattr_prep(struct io_kiocb *req, const struct io_uring_sqe *sqe) 2045e2a18d9SJens Axboe { 2055e2a18d9SJens Axboe return __io_setxattr_prep(req, sqe); 2065e2a18d9SJens Axboe } 2075e2a18d9SJens Axboe 2085e2a18d9SJens Axboe static int __io_setxattr(struct io_kiocb *req, unsigned int issue_flags, 209*e81f574dSAl Viro const struct path *path) 2105e2a18d9SJens Axboe { 211f2ccb5aeSStefan Metzmacher struct io_xattr *ix = io_kiocb_to_cmd(req, struct io_xattr); 2125e2a18d9SJens Axboe int ret; 2135e2a18d9SJens Axboe 2145e2a18d9SJens Axboe ret = mnt_want_write(path->mnt); 2155e2a18d9SJens Axboe if (!ret) { 2165e2a18d9SJens Axboe ret = do_setxattr(mnt_user_ns(path->mnt), path->dentry, &ix->ctx); 2175e2a18d9SJens Axboe mnt_drop_write(path->mnt); 2185e2a18d9SJens Axboe } 2195e2a18d9SJens Axboe 2205e2a18d9SJens Axboe return ret; 2215e2a18d9SJens Axboe } 2225e2a18d9SJens Axboe 2235e2a18d9SJens Axboe int io_fsetxattr(struct io_kiocb *req, unsigned int issue_flags) 2245e2a18d9SJens Axboe { 2255e2a18d9SJens Axboe int ret; 2265e2a18d9SJens Axboe 2275e2a18d9SJens Axboe if (issue_flags & IO_URING_F_NONBLOCK) 2285e2a18d9SJens Axboe return -EAGAIN; 2295e2a18d9SJens Axboe 2305e2a18d9SJens Axboe ret = __io_setxattr(req, issue_flags, &req->file->f_path); 2315e2a18d9SJens Axboe io_xattr_finish(req, ret); 2325e2a18d9SJens Axboe return IOU_OK; 2335e2a18d9SJens Axboe } 2345e2a18d9SJens Axboe 2355e2a18d9SJens Axboe int io_setxattr(struct io_kiocb *req, unsigned int issue_flags) 2365e2a18d9SJens Axboe { 237f2ccb5aeSStefan Metzmacher struct io_xattr *ix = io_kiocb_to_cmd(req, struct io_xattr); 2385e2a18d9SJens Axboe unsigned int lookup_flags = LOOKUP_FOLLOW; 2395e2a18d9SJens Axboe struct path path; 2405e2a18d9SJens Axboe int ret; 2415e2a18d9SJens Axboe 2425e2a18d9SJens Axboe if (issue_flags & IO_URING_F_NONBLOCK) 2435e2a18d9SJens Axboe return -EAGAIN; 2445e2a18d9SJens Axboe 2455e2a18d9SJens Axboe retry: 2465e2a18d9SJens Axboe ret = filename_lookup(AT_FDCWD, ix->filename, lookup_flags, &path, NULL); 2475e2a18d9SJens Axboe if (!ret) { 2485e2a18d9SJens Axboe ret = __io_setxattr(req, issue_flags, &path); 2495e2a18d9SJens Axboe path_put(&path); 2505e2a18d9SJens Axboe if (retry_estale(ret, lookup_flags)) { 2515e2a18d9SJens Axboe lookup_flags |= LOOKUP_REVAL; 2525e2a18d9SJens Axboe goto retry; 2535e2a18d9SJens Axboe } 2545e2a18d9SJens Axboe } 2555e2a18d9SJens Axboe 2565e2a18d9SJens Axboe io_xattr_finish(req, ret); 2575e2a18d9SJens Axboe return IOU_OK; 2585e2a18d9SJens Axboe } 259