Line data Source code
1 : // SPDX-License-Identifier: GPL-2.0
2 : #include <linux/kernel.h>
3 : #include <linux/errno.h>
4 : #include <linux/fs.h>
5 : #include <linux/file.h>
6 : #include <linux/mm.h>
7 : #include <linux/slab.h>
8 : #include <linux/namei.h>
9 : #include <linux/io_uring.h>
10 : #include <linux/xattr.h>
11 :
12 : #include <uapi/linux/io_uring.h>
13 :
14 : #include "../fs/internal.h"
15 :
16 : #include "io_uring.h"
17 : #include "xattr.h"
18 :
19 : struct io_xattr {
20 : struct file *file;
21 : struct xattr_ctx ctx;
22 : struct filename *filename;
23 : };
24 :
25 0 : void io_xattr_cleanup(struct io_kiocb *req)
26 : {
27 0 : struct io_xattr *ix = io_kiocb_to_cmd(req, struct io_xattr);
28 :
29 0 : if (ix->filename)
30 0 : putname(ix->filename);
31 :
32 0 : kfree(ix->ctx.kname);
33 0 : kvfree(ix->ctx.kvalue);
34 0 : }
35 :
36 : static void io_xattr_finish(struct io_kiocb *req, int ret)
37 : {
38 0 : req->flags &= ~REQ_F_NEED_CLEANUP;
39 :
40 0 : io_xattr_cleanup(req);
41 0 : io_req_set_res(req, ret, 0);
42 : }
43 :
44 0 : static int __io_getxattr_prep(struct io_kiocb *req,
45 : const struct io_uring_sqe *sqe)
46 : {
47 0 : struct io_xattr *ix = io_kiocb_to_cmd(req, struct io_xattr);
48 : const char __user *name;
49 : int ret;
50 :
51 0 : if (unlikely(req->flags & REQ_F_FIXED_FILE))
52 : return -EBADF;
53 :
54 0 : ix->filename = NULL;
55 0 : ix->ctx.kvalue = NULL;
56 0 : name = u64_to_user_ptr(READ_ONCE(sqe->addr));
57 0 : ix->ctx.cvalue = u64_to_user_ptr(READ_ONCE(sqe->addr2));
58 0 : ix->ctx.size = READ_ONCE(sqe->len);
59 0 : ix->ctx.flags = READ_ONCE(sqe->xattr_flags);
60 :
61 0 : if (ix->ctx.flags)
62 : return -EINVAL;
63 :
64 0 : ix->ctx.kname = kmalloc(sizeof(*ix->ctx.kname), GFP_KERNEL);
65 0 : if (!ix->ctx.kname)
66 : return -ENOMEM;
67 :
68 0 : ret = strncpy_from_user(ix->ctx.kname->name, name,
69 : sizeof(ix->ctx.kname->name));
70 0 : if (!ret || ret == sizeof(ix->ctx.kname->name))
71 0 : ret = -ERANGE;
72 0 : if (ret < 0) {
73 0 : kfree(ix->ctx.kname);
74 0 : return ret;
75 : }
76 :
77 0 : req->flags |= REQ_F_NEED_CLEANUP;
78 0 : req->flags |= REQ_F_FORCE_ASYNC;
79 0 : return 0;
80 : }
81 :
82 0 : int io_fgetxattr_prep(struct io_kiocb *req, const struct io_uring_sqe *sqe)
83 : {
84 0 : return __io_getxattr_prep(req, sqe);
85 : }
86 :
87 0 : int io_getxattr_prep(struct io_kiocb *req, const struct io_uring_sqe *sqe)
88 : {
89 0 : struct io_xattr *ix = io_kiocb_to_cmd(req, struct io_xattr);
90 : const char __user *path;
91 : int ret;
92 :
93 0 : ret = __io_getxattr_prep(req, sqe);
94 0 : if (ret)
95 : return ret;
96 :
97 0 : path = u64_to_user_ptr(READ_ONCE(sqe->addr3));
98 :
99 0 : ix->filename = getname_flags(path, LOOKUP_FOLLOW, NULL);
100 0 : if (IS_ERR(ix->filename)) {
101 0 : ret = PTR_ERR(ix->filename);
102 0 : ix->filename = NULL;
103 : }
104 :
105 : return ret;
106 : }
107 :
108 0 : int io_fgetxattr(struct io_kiocb *req, unsigned int issue_flags)
109 : {
110 0 : struct io_xattr *ix = io_kiocb_to_cmd(req, struct io_xattr);
111 : int ret;
112 :
113 0 : WARN_ON_ONCE(issue_flags & IO_URING_F_NONBLOCK);
114 :
115 0 : ret = do_getxattr(mnt_idmap(req->file->f_path.mnt),
116 0 : req->file->f_path.dentry,
117 : &ix->ctx);
118 :
119 0 : io_xattr_finish(req, ret);
120 0 : return IOU_OK;
121 : }
122 :
123 0 : int io_getxattr(struct io_kiocb *req, unsigned int issue_flags)
124 : {
125 0 : struct io_xattr *ix = io_kiocb_to_cmd(req, struct io_xattr);
126 0 : unsigned int lookup_flags = LOOKUP_FOLLOW;
127 : struct path path;
128 : int ret;
129 :
130 0 : WARN_ON_ONCE(issue_flags & IO_URING_F_NONBLOCK);
131 :
132 : retry:
133 0 : ret = filename_lookup(AT_FDCWD, ix->filename, lookup_flags, &path, NULL);
134 0 : if (!ret) {
135 0 : ret = do_getxattr(mnt_idmap(path.mnt), path.dentry, &ix->ctx);
136 :
137 0 : path_put(&path);
138 0 : if (retry_estale(ret, lookup_flags)) {
139 : lookup_flags |= LOOKUP_REVAL;
140 : goto retry;
141 : }
142 : }
143 :
144 0 : io_xattr_finish(req, ret);
145 0 : return IOU_OK;
146 : }
147 :
148 0 : static int __io_setxattr_prep(struct io_kiocb *req,
149 : const struct io_uring_sqe *sqe)
150 : {
151 0 : struct io_xattr *ix = io_kiocb_to_cmd(req, struct io_xattr);
152 : const char __user *name;
153 : int ret;
154 :
155 0 : if (unlikely(req->flags & REQ_F_FIXED_FILE))
156 : return -EBADF;
157 :
158 0 : ix->filename = NULL;
159 0 : name = u64_to_user_ptr(READ_ONCE(sqe->addr));
160 0 : ix->ctx.cvalue = u64_to_user_ptr(READ_ONCE(sqe->addr2));
161 0 : ix->ctx.kvalue = NULL;
162 0 : ix->ctx.size = READ_ONCE(sqe->len);
163 0 : ix->ctx.flags = READ_ONCE(sqe->xattr_flags);
164 :
165 0 : ix->ctx.kname = kmalloc(sizeof(*ix->ctx.kname), GFP_KERNEL);
166 0 : if (!ix->ctx.kname)
167 : return -ENOMEM;
168 :
169 0 : ret = setxattr_copy(name, &ix->ctx);
170 0 : if (ret) {
171 0 : kfree(ix->ctx.kname);
172 0 : return ret;
173 : }
174 :
175 0 : req->flags |= REQ_F_NEED_CLEANUP;
176 0 : req->flags |= REQ_F_FORCE_ASYNC;
177 0 : return 0;
178 : }
179 :
180 0 : int io_setxattr_prep(struct io_kiocb *req, const struct io_uring_sqe *sqe)
181 : {
182 0 : struct io_xattr *ix = io_kiocb_to_cmd(req, struct io_xattr);
183 : const char __user *path;
184 : int ret;
185 :
186 0 : ret = __io_setxattr_prep(req, sqe);
187 0 : if (ret)
188 : return ret;
189 :
190 0 : path = u64_to_user_ptr(READ_ONCE(sqe->addr3));
191 :
192 0 : ix->filename = getname_flags(path, LOOKUP_FOLLOW, NULL);
193 0 : if (IS_ERR(ix->filename)) {
194 0 : ret = PTR_ERR(ix->filename);
195 0 : ix->filename = NULL;
196 : }
197 :
198 : return ret;
199 : }
200 :
201 0 : int io_fsetxattr_prep(struct io_kiocb *req, const struct io_uring_sqe *sqe)
202 : {
203 0 : return __io_setxattr_prep(req, sqe);
204 : }
205 :
206 0 : static int __io_setxattr(struct io_kiocb *req, unsigned int issue_flags,
207 : const struct path *path)
208 : {
209 0 : struct io_xattr *ix = io_kiocb_to_cmd(req, struct io_xattr);
210 : int ret;
211 :
212 0 : ret = mnt_want_write(path->mnt);
213 0 : if (!ret) {
214 0 : ret = do_setxattr(mnt_idmap(path->mnt), path->dentry, &ix->ctx);
215 0 : mnt_drop_write(path->mnt);
216 : }
217 :
218 0 : return ret;
219 : }
220 :
221 0 : int io_fsetxattr(struct io_kiocb *req, unsigned int issue_flags)
222 : {
223 : int ret;
224 :
225 0 : WARN_ON_ONCE(issue_flags & IO_URING_F_NONBLOCK);
226 :
227 0 : ret = __io_setxattr(req, issue_flags, &req->file->f_path);
228 0 : io_xattr_finish(req, ret);
229 0 : return IOU_OK;
230 : }
231 :
232 0 : int io_setxattr(struct io_kiocb *req, unsigned int issue_flags)
233 : {
234 0 : struct io_xattr *ix = io_kiocb_to_cmd(req, struct io_xattr);
235 0 : unsigned int lookup_flags = LOOKUP_FOLLOW;
236 : struct path path;
237 : int ret;
238 :
239 0 : WARN_ON_ONCE(issue_flags & IO_URING_F_NONBLOCK);
240 :
241 : retry:
242 0 : ret = filename_lookup(AT_FDCWD, ix->filename, lookup_flags, &path, NULL);
243 0 : if (!ret) {
244 0 : ret = __io_setxattr(req, issue_flags, &path);
245 0 : path_put(&path);
246 0 : if (retry_estale(ret, lookup_flags)) {
247 : lookup_flags |= LOOKUP_REVAL;
248 : goto retry;
249 : }
250 : }
251 :
252 0 : io_xattr_finish(req, ret);
253 0 : return IOU_OK;
254 : }
|