xref: /linux/io_uring/xattr.c (revision 0158005aaa3c946ecac9d251c34708a40a85cbe1)
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;
21537c7662SChristian Göttsche 	struct kernel_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 	ix->filename = NULL;
525e2a18d9SJens Axboe 	ix->ctx.kvalue = NULL;
535e2a18d9SJens Axboe 	name = u64_to_user_ptr(READ_ONCE(sqe->addr));
54*0158005aSAl Viro 	ix->ctx.value = u64_to_user_ptr(READ_ONCE(sqe->addr2));
555e2a18d9SJens Axboe 	ix->ctx.size = READ_ONCE(sqe->len);
565e2a18d9SJens Axboe 	ix->ctx.flags = READ_ONCE(sqe->xattr_flags);
575e2a18d9SJens Axboe 
585e2a18d9SJens Axboe 	if (ix->ctx.flags)
595e2a18d9SJens Axboe 		return -EINVAL;
605e2a18d9SJens Axboe 
615e2a18d9SJens Axboe 	ix->ctx.kname = kmalloc(sizeof(*ix->ctx.kname), GFP_KERNEL);
625e2a18d9SJens Axboe 	if (!ix->ctx.kname)
635e2a18d9SJens Axboe 		return -ENOMEM;
645e2a18d9SJens Axboe 
65a10c4c5eSAl Viro 	ret = import_xattr_name(ix->ctx.kname, name);
66a10c4c5eSAl Viro 	if (ret) {
675e2a18d9SJens Axboe 		kfree(ix->ctx.kname);
685e2a18d9SJens Axboe 		return ret;
695e2a18d9SJens Axboe 	}
705e2a18d9SJens Axboe 
715e2a18d9SJens Axboe 	req->flags |= REQ_F_NEED_CLEANUP;
72aebb224fSDylan Yudaken 	req->flags |= REQ_F_FORCE_ASYNC;
735e2a18d9SJens Axboe 	return 0;
745e2a18d9SJens Axboe }
755e2a18d9SJens Axboe 
765e2a18d9SJens Axboe int io_fgetxattr_prep(struct io_kiocb *req, const struct io_uring_sqe *sqe)
775e2a18d9SJens Axboe {
785e2a18d9SJens Axboe 	return __io_getxattr_prep(req, sqe);
795e2a18d9SJens Axboe }
805e2a18d9SJens Axboe 
815e2a18d9SJens Axboe int io_getxattr_prep(struct io_kiocb *req, const struct io_uring_sqe *sqe)
825e2a18d9SJens Axboe {
83f2ccb5aeSStefan Metzmacher 	struct io_xattr *ix = io_kiocb_to_cmd(req, struct io_xattr);
845e2a18d9SJens Axboe 	const char __user *path;
855e2a18d9SJens Axboe 	int ret;
865e2a18d9SJens Axboe 
87dc7e76baSJens Axboe 	if (unlikely(req->flags & REQ_F_FIXED_FILE))
88dc7e76baSJens Axboe 		return -EBADF;
89dc7e76baSJens Axboe 
905e2a18d9SJens Axboe 	ret = __io_getxattr_prep(req, sqe);
915e2a18d9SJens Axboe 	if (ret)
925e2a18d9SJens Axboe 		return ret;
935e2a18d9SJens Axboe 
945e2a18d9SJens Axboe 	path = u64_to_user_ptr(READ_ONCE(sqe->addr3));
955e2a18d9SJens Axboe 
96b8cdd253SAl Viro 	ix->filename = getname(path);
97*0158005aSAl Viro 	if (IS_ERR(ix->filename))
98*0158005aSAl Viro 		return PTR_ERR(ix->filename);
995e2a18d9SJens Axboe 
100*0158005aSAl Viro 	return 0;
1015e2a18d9SJens Axboe }
1025e2a18d9SJens Axboe 
1035e2a18d9SJens Axboe int io_fgetxattr(struct io_kiocb *req, unsigned int issue_flags)
1045e2a18d9SJens Axboe {
105f2ccb5aeSStefan Metzmacher 	struct io_xattr *ix = io_kiocb_to_cmd(req, struct io_xattr);
1065e2a18d9SJens Axboe 	int ret;
1075e2a18d9SJens Axboe 
108aebb224fSDylan Yudaken 	WARN_ON_ONCE(issue_flags & IO_URING_F_NONBLOCK);
1095e2a18d9SJens Axboe 
110*0158005aSAl Viro 	ret = file_getxattr(req->file, &ix->ctx);
1115e2a18d9SJens Axboe 	io_xattr_finish(req, ret);
1125e2a18d9SJens Axboe 	return IOU_OK;
1135e2a18d9SJens Axboe }
1145e2a18d9SJens Axboe 
1155e2a18d9SJens Axboe int io_getxattr(struct io_kiocb *req, unsigned int issue_flags)
1165e2a18d9SJens Axboe {
117f2ccb5aeSStefan Metzmacher 	struct io_xattr *ix = io_kiocb_to_cmd(req, struct io_xattr);
1185e2a18d9SJens Axboe 	int ret;
1195e2a18d9SJens Axboe 
120aebb224fSDylan Yudaken 	WARN_ON_ONCE(issue_flags & IO_URING_F_NONBLOCK);
1215e2a18d9SJens Axboe 
122*0158005aSAl Viro 	ret = filename_getxattr(AT_FDCWD, ix->filename, LOOKUP_FOLLOW, &ix->ctx);
123*0158005aSAl Viro 	ix->filename = NULL;
1245e2a18d9SJens Axboe 	io_xattr_finish(req, ret);
1255e2a18d9SJens Axboe 	return IOU_OK;
1265e2a18d9SJens Axboe }
1275e2a18d9SJens Axboe 
1285e2a18d9SJens Axboe static int __io_setxattr_prep(struct io_kiocb *req,
1295e2a18d9SJens Axboe 			const struct io_uring_sqe *sqe)
1305e2a18d9SJens Axboe {
131f2ccb5aeSStefan Metzmacher 	struct io_xattr *ix = io_kiocb_to_cmd(req, struct io_xattr);
1325e2a18d9SJens Axboe 	const char __user *name;
1335e2a18d9SJens Axboe 	int ret;
1345e2a18d9SJens Axboe 
1355e2a18d9SJens Axboe 	ix->filename = NULL;
1365e2a18d9SJens Axboe 	name = u64_to_user_ptr(READ_ONCE(sqe->addr));
1375e2a18d9SJens Axboe 	ix->ctx.cvalue = u64_to_user_ptr(READ_ONCE(sqe->addr2));
1385e2a18d9SJens Axboe 	ix->ctx.kvalue = NULL;
1395e2a18d9SJens Axboe 	ix->ctx.size = READ_ONCE(sqe->len);
1405e2a18d9SJens Axboe 	ix->ctx.flags = READ_ONCE(sqe->xattr_flags);
1415e2a18d9SJens Axboe 
1425e2a18d9SJens Axboe 	ix->ctx.kname = kmalloc(sizeof(*ix->ctx.kname), GFP_KERNEL);
1435e2a18d9SJens Axboe 	if (!ix->ctx.kname)
1445e2a18d9SJens Axboe 		return -ENOMEM;
1455e2a18d9SJens Axboe 
1465e2a18d9SJens Axboe 	ret = setxattr_copy(name, &ix->ctx);
1475e2a18d9SJens Axboe 	if (ret) {
1485e2a18d9SJens Axboe 		kfree(ix->ctx.kname);
1495e2a18d9SJens Axboe 		return ret;
1505e2a18d9SJens Axboe 	}
1515e2a18d9SJens Axboe 
1525e2a18d9SJens Axboe 	req->flags |= REQ_F_NEED_CLEANUP;
153aebb224fSDylan Yudaken 	req->flags |= REQ_F_FORCE_ASYNC;
1545e2a18d9SJens Axboe 	return 0;
1555e2a18d9SJens Axboe }
1565e2a18d9SJens Axboe 
1575e2a18d9SJens Axboe int io_setxattr_prep(struct io_kiocb *req, const struct io_uring_sqe *sqe)
1585e2a18d9SJens Axboe {
159f2ccb5aeSStefan Metzmacher 	struct io_xattr *ix = io_kiocb_to_cmd(req, struct io_xattr);
1605e2a18d9SJens Axboe 	const char __user *path;
1615e2a18d9SJens Axboe 	int ret;
1625e2a18d9SJens Axboe 
163dc7e76baSJens Axboe 	if (unlikely(req->flags & REQ_F_FIXED_FILE))
164dc7e76baSJens Axboe 		return -EBADF;
165dc7e76baSJens Axboe 
1665e2a18d9SJens Axboe 	ret = __io_setxattr_prep(req, sqe);
1675e2a18d9SJens Axboe 	if (ret)
1685e2a18d9SJens Axboe 		return ret;
1695e2a18d9SJens Axboe 
1705e2a18d9SJens Axboe 	path = u64_to_user_ptr(READ_ONCE(sqe->addr3));
1715e2a18d9SJens Axboe 
172b8cdd253SAl Viro 	ix->filename = getname(path);
17366d7ac6bSAl Viro 	if (IS_ERR(ix->filename))
17466d7ac6bSAl Viro 		return PTR_ERR(ix->filename);
1755e2a18d9SJens Axboe 
17666d7ac6bSAl Viro 	return 0;
1775e2a18d9SJens Axboe }
1785e2a18d9SJens Axboe 
1795e2a18d9SJens Axboe int io_fsetxattr_prep(struct io_kiocb *req, const struct io_uring_sqe *sqe)
1805e2a18d9SJens Axboe {
1815e2a18d9SJens Axboe 	return __io_setxattr_prep(req, sqe);
1825e2a18d9SJens Axboe }
1835e2a18d9SJens Axboe 
18466d7ac6bSAl Viro int io_fsetxattr(struct io_kiocb *req, unsigned int issue_flags)
1855e2a18d9SJens Axboe {
186f2ccb5aeSStefan Metzmacher 	struct io_xattr *ix = io_kiocb_to_cmd(req, struct io_xattr);
1875e2a18d9SJens Axboe 	int ret;
1885e2a18d9SJens Axboe 
189aebb224fSDylan Yudaken 	WARN_ON_ONCE(issue_flags & IO_URING_F_NONBLOCK);
1905e2a18d9SJens Axboe 
19166d7ac6bSAl Viro 	ret = file_setxattr(req->file, &ix->ctx);
1925e2a18d9SJens Axboe 	io_xattr_finish(req, ret);
1935e2a18d9SJens Axboe 	return IOU_OK;
1945e2a18d9SJens Axboe }
1955e2a18d9SJens Axboe 
1965e2a18d9SJens Axboe int io_setxattr(struct io_kiocb *req, unsigned int issue_flags)
1975e2a18d9SJens Axboe {
198f2ccb5aeSStefan Metzmacher 	struct io_xattr *ix = io_kiocb_to_cmd(req, struct io_xattr);
1995e2a18d9SJens Axboe 	int ret;
2005e2a18d9SJens Axboe 
201aebb224fSDylan Yudaken 	WARN_ON_ONCE(issue_flags & IO_URING_F_NONBLOCK);
2025e2a18d9SJens Axboe 
20366d7ac6bSAl Viro 	ret = filename_setxattr(AT_FDCWD, ix->filename, LOOKUP_FOLLOW, &ix->ctx);
20466d7ac6bSAl Viro 	ix->filename = NULL;
2055e2a18d9SJens Axboe 	io_xattr_finish(req, ret);
2065e2a18d9SJens Axboe 	return IOU_OK;
2075e2a18d9SJens Axboe }
208