Skip to content

Commit 9fa3ec8

Browse files
author
Al Viro
committed
allow incomplete imports of filenames
There are two filename-related problems in io_uring and its interplay with audit. Filenames are imported when request is submitted and used when it is processed. Unfortunately, the latter may very well happen in a different thread. In that case the reference to filename is put into the wrong audit_context - that of submitting thread, not the processing one. Audit logics is called by the latter, and it really wants to be able to find the names in audit_context current (== processing) thread. Another related problem is the headache with refcounts - normally all references to given struct filename are visible only to one thread (the one that uses that struct filename). io_uring violates that - an extra reference is stashed in audit_context of submitter. It gets dropped when submitter returns to userland, which can happen simultaneously with processing thread deciding to drop the reference it got. We paper over that by making refcount atomic, but that means pointless headache for everyone. Solution: the notion of partially imported filenames. Namely, already copied from userland, but *not* exposed to audit yet. io_uring can create that in submitter thread, and complete the import (obtaining the usual reference to struct filename) in processing thread. Object: struct delayed_filename. Primitives for working with it: delayed_getname(&delayed_filename, user_string) - copies the name from userland, returning 0 and stashing the address of (still incomplete) struct filename in delayed_filename on success and returning -E... on error. delayed_getname_uflags(&delayed_filename, user_string, atflags) - similar, in the same relation to delayed_getname() as getname_uflags() is to getname() complete_getname(&delayed_filename) - completes the import of filename stashed in delayed_filename and returns struct filename to caller, emptying delayed_filename. CLASS(filename_complete_delayed, name)(&delayed_filename) - variant of CLASS(filename) with complete_getname() for constructor. dismiss_delayed_filename(&delayed_filename) - destructor; drops whatever might be stashed in delayed_filename, emptying it. putname_to_delayed(&delayed_filename, name) - if name is shared, stashes its copy into delayed_filename and drops the reference to name, otherwise stashes the name itself in there. Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
1 parent a9900a2 commit 9fa3ec8

File tree

6 files changed

+157
-95
lines changed

6 files changed

+157
-95
lines changed

fs/namei.c

Lines changed: 61 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -172,8 +172,8 @@ static int getname_long(struct filename *name, const char __user *filename)
172172
return 0;
173173
}
174174

175-
struct filename *
176-
getname_flags(const char __user *filename, int flags)
175+
static struct filename *
176+
do_getname(const char __user *filename, int flags, bool incomplete)
177177
{
178178
struct filename *result;
179179
char *kname;
@@ -214,10 +214,17 @@ getname_flags(const char __user *filename, int flags)
214214
}
215215

216216
initname(result);
217-
audit_getname(result);
217+
if (likely(!incomplete))
218+
audit_getname(result);
218219
return result;
219220
}
220221

222+
struct filename *
223+
getname_flags(const char __user *filename, int flags)
224+
{
225+
return do_getname(filename, flags, false);
226+
}
227+
221228
struct filename *getname_uflags(const char __user *filename, int uflags)
222229
{
223230
int flags = (uflags & AT_EMPTY_PATH) ? LOOKUP_EMPTY : 0;
@@ -242,7 +249,7 @@ struct filename *__getname_maybe_null(const char __user *pathname)
242249
return no_free_ptr(name);
243250
}
244251

245-
struct filename *getname_kernel(const char * filename)
252+
static struct filename *do_getname_kernel(const char *filename, bool incomplete)
246253
{
247254
struct filename *result;
248255
int len = strlen(filename) + 1;
@@ -267,9 +274,15 @@ struct filename *getname_kernel(const char * filename)
267274
}
268275
result->name = p;
269276
initname(result);
270-
audit_getname(result);
277+
if (likely(!incomplete))
278+
audit_getname(result);
271279
return result;
272280
}
281+
282+
struct filename *getname_kernel(const char *filename)
283+
{
284+
return do_getname_kernel(filename, false);
285+
}
273286
EXPORT_SYMBOL(getname_kernel);
274287

275288
void putname(struct filename *name)
@@ -294,6 +307,49 @@ void putname(struct filename *name)
294307
}
295308
EXPORT_SYMBOL(putname);
296309

310+
static inline int __delayed_getname(struct delayed_filename *v,
311+
const char __user *string, int flags)
312+
{
313+
v->__incomplete_filename = do_getname(string, flags, true);
314+
return PTR_ERR_OR_ZERO(v->__incomplete_filename);
315+
}
316+
317+
int delayed_getname(struct delayed_filename *v, const char __user *string)
318+
{
319+
return __delayed_getname(v, string, 0);
320+
}
321+
322+
int delayed_getname_uflags(struct delayed_filename *v, const char __user *string,
323+
int uflags)
324+
{
325+
int flags = (uflags & AT_EMPTY_PATH) ? LOOKUP_EMPTY : 0;
326+
return __delayed_getname(v, string, flags);
327+
}
328+
329+
int putname_to_delayed(struct delayed_filename *v, struct filename *name)
330+
{
331+
if (likely(atomic_read(&name->refcnt) == 1)) {
332+
v->__incomplete_filename = name;
333+
return 0;
334+
}
335+
v->__incomplete_filename = do_getname_kernel(name->name, true);
336+
putname(name);
337+
return PTR_ERR_OR_ZERO(v->__incomplete_filename);
338+
}
339+
340+
void dismiss_delayed_filename(struct delayed_filename *v)
341+
{
342+
putname(no_free_ptr(v->__incomplete_filename));
343+
}
344+
345+
struct filename *complete_getname(struct delayed_filename *v)
346+
{
347+
struct filename *res = no_free_ptr(v->__incomplete_filename);
348+
if (!IS_ERR(res))
349+
audit_getname(res);
350+
return res;
351+
}
352+
297353
/**
298354
* check_acl - perform ACL permission checking
299355
* @idmap: idmap of the mount the inode was found from

include/linux/fs.h

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2516,6 +2516,17 @@ static inline struct filename *getname_maybe_null(const char __user *name, int f
25162516
extern void putname(struct filename *name);
25172517
DEFINE_FREE(putname, struct filename *, if (!IS_ERR_OR_NULL(_T)) putname(_T))
25182518

2519+
struct delayed_filename {
2520+
struct filename *__incomplete_filename; // don't touch
2521+
};
2522+
#define INIT_DELAYED_FILENAME(ptr) \
2523+
((void)(*(ptr) = (struct delayed_filename){}))
2524+
int delayed_getname(struct delayed_filename *, const char __user *);
2525+
int delayed_getname_uflags(struct delayed_filename *v, const char __user *, int);
2526+
void dismiss_delayed_filename(struct delayed_filename *);
2527+
int putname_to_delayed(struct delayed_filename *, struct filename *);
2528+
struct filename *complete_getname(struct delayed_filename *);
2529+
25192530
static inline struct filename *refname(struct filename *name)
25202531
{
25212532
atomic_inc(&name->refcnt);
@@ -2527,6 +2538,7 @@ EXTEND_CLASS(filename, _kernel, getname_kernel(p), const char *p)
25272538
EXTEND_CLASS(filename, _flags, getname_flags(p, f), const char __user *p, unsigned int f)
25282539
EXTEND_CLASS(filename, _uflags, getname_uflags(p, f), const char __user *p, unsigned int f)
25292540
EXTEND_CLASS(filename, _maybe_null, getname_maybe_null(p, f), const char __user *p, unsigned int f)
2541+
EXTEND_CLASS(filename, _complete_delayed, complete_getname(p), struct delayed_filename *p)
25302542

25312543
extern int finish_open(struct file *file, struct dentry *dentry,
25322544
int (*open)(struct inode *, struct file *));

io_uring/fs.c

Lines changed: 54 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -19,38 +19,39 @@ struct io_rename {
1919
struct file *file;
2020
int old_dfd;
2121
int new_dfd;
22-
struct filename *oldpath;
23-
struct filename *newpath;
22+
struct delayed_filename oldpath;
23+
struct delayed_filename newpath;
2424
int flags;
2525
};
2626

2727
struct io_unlink {
2828
struct file *file;
2929
int dfd;
3030
int flags;
31-
struct filename *filename;
31+
struct delayed_filename filename;
3232
};
3333

3434
struct io_mkdir {
3535
struct file *file;
3636
int dfd;
3737
umode_t mode;
38-
struct filename *filename;
38+
struct delayed_filename filename;
3939
};
4040

4141
struct io_link {
4242
struct file *file;
4343
int old_dfd;
4444
int new_dfd;
45-
struct filename *oldpath;
46-
struct filename *newpath;
45+
struct delayed_filename oldpath;
46+
struct delayed_filename newpath;
4747
int flags;
4848
};
4949

5050
int io_renameat_prep(struct io_kiocb *req, const struct io_uring_sqe *sqe)
5151
{
5252
struct io_rename *ren = io_kiocb_to_cmd(req, struct io_rename);
5353
const char __user *oldf, *newf;
54+
int err;
5455

5556
if (sqe->buf_index || sqe->splice_fd_in)
5657
return -EINVAL;
@@ -63,14 +64,14 @@ int io_renameat_prep(struct io_kiocb *req, const struct io_uring_sqe *sqe)
6364
ren->new_dfd = READ_ONCE(sqe->len);
6465
ren->flags = READ_ONCE(sqe->rename_flags);
6566

66-
ren->oldpath = getname(oldf);
67-
if (IS_ERR(ren->oldpath))
68-
return PTR_ERR(ren->oldpath);
67+
err = delayed_getname(&ren->oldpath, oldf);
68+
if (unlikely(err))
69+
return err;
6970

70-
ren->newpath = getname(newf);
71-
if (IS_ERR(ren->newpath)) {
72-
putname(ren->oldpath);
73-
return PTR_ERR(ren->newpath);
71+
err = delayed_getname(&ren->newpath, newf);
72+
if (unlikely(err)) {
73+
dismiss_delayed_filename(&ren->oldpath);
74+
return err;
7475
}
7576

7677
req->flags |= REQ_F_NEED_CLEANUP;
@@ -85,8 +86,9 @@ int io_renameat(struct io_kiocb *req, unsigned int issue_flags)
8586

8687
WARN_ON_ONCE(issue_flags & IO_URING_F_NONBLOCK);
8788

88-
ret = do_renameat2(ren->old_dfd, ren->oldpath, ren->new_dfd,
89-
ren->newpath, ren->flags);
89+
ret = do_renameat2(ren->old_dfd, complete_getname(&ren->oldpath),
90+
ren->new_dfd, complete_getname(&ren->newpath),
91+
ren->flags);
9092

9193
req->flags &= ~REQ_F_NEED_CLEANUP;
9294
io_req_set_res(req, ret, 0);
@@ -97,14 +99,15 @@ void io_renameat_cleanup(struct io_kiocb *req)
9799
{
98100
struct io_rename *ren = io_kiocb_to_cmd(req, struct io_rename);
99101

100-
putname(ren->oldpath);
101-
putname(ren->newpath);
102+
dismiss_delayed_filename(&ren->oldpath);
103+
dismiss_delayed_filename(&ren->newpath);
102104
}
103105

104106
int io_unlinkat_prep(struct io_kiocb *req, const struct io_uring_sqe *sqe)
105107
{
106108
struct io_unlink *un = io_kiocb_to_cmd(req, struct io_unlink);
107109
const char __user *fname;
110+
int err;
108111

109112
if (sqe->off || sqe->len || sqe->buf_index || sqe->splice_fd_in)
110113
return -EINVAL;
@@ -118,9 +121,9 @@ int io_unlinkat_prep(struct io_kiocb *req, const struct io_uring_sqe *sqe)
118121
return -EINVAL;
119122

120123
fname = u64_to_user_ptr(READ_ONCE(sqe->addr));
121-
un->filename = getname(fname);
122-
if (IS_ERR(un->filename))
123-
return PTR_ERR(un->filename);
124+
err = delayed_getname(&un->filename, fname);
125+
if (unlikely(err))
126+
return err;
124127

125128
req->flags |= REQ_F_NEED_CLEANUP;
126129
req->flags |= REQ_F_FORCE_ASYNC;
@@ -135,9 +138,9 @@ int io_unlinkat(struct io_kiocb *req, unsigned int issue_flags)
135138
WARN_ON_ONCE(issue_flags & IO_URING_F_NONBLOCK);
136139

137140
if (un->flags & AT_REMOVEDIR)
138-
ret = do_rmdir(un->dfd, un->filename);
141+
ret = do_rmdir(un->dfd, complete_getname(&un->filename));
139142
else
140-
ret = do_unlinkat(un->dfd, un->filename);
143+
ret = do_unlinkat(un->dfd, complete_getname(&un->filename));
141144

142145
req->flags &= ~REQ_F_NEED_CLEANUP;
143146
io_req_set_res(req, ret, 0);
@@ -148,13 +151,14 @@ void io_unlinkat_cleanup(struct io_kiocb *req)
148151
{
149152
struct io_unlink *ul = io_kiocb_to_cmd(req, struct io_unlink);
150153

151-
putname(ul->filename);
154+
dismiss_delayed_filename(&ul->filename);
152155
}
153156

154157
int io_mkdirat_prep(struct io_kiocb *req, const struct io_uring_sqe *sqe)
155158
{
156159
struct io_mkdir *mkd = io_kiocb_to_cmd(req, struct io_mkdir);
157160
const char __user *fname;
161+
int err;
158162

159163
if (sqe->off || sqe->rw_flags || sqe->buf_index || sqe->splice_fd_in)
160164
return -EINVAL;
@@ -165,9 +169,9 @@ int io_mkdirat_prep(struct io_kiocb *req, const struct io_uring_sqe *sqe)
165169
mkd->mode = READ_ONCE(sqe->len);
166170

167171
fname = u64_to_user_ptr(READ_ONCE(sqe->addr));
168-
mkd->filename = getname(fname);
169-
if (IS_ERR(mkd->filename))
170-
return PTR_ERR(mkd->filename);
172+
err = delayed_getname(&mkd->filename, fname);
173+
if (unlikely(err))
174+
return err;
171175

172176
req->flags |= REQ_F_NEED_CLEANUP;
173177
req->flags |= REQ_F_FORCE_ASYNC;
@@ -181,7 +185,7 @@ int io_mkdirat(struct io_kiocb *req, unsigned int issue_flags)
181185

182186
WARN_ON_ONCE(issue_flags & IO_URING_F_NONBLOCK);
183187

184-
ret = do_mkdirat(mkd->dfd, mkd->filename, mkd->mode);
188+
ret = do_mkdirat(mkd->dfd, complete_getname(&mkd->filename), mkd->mode);
185189

186190
req->flags &= ~REQ_F_NEED_CLEANUP;
187191
io_req_set_res(req, ret, 0);
@@ -192,13 +196,14 @@ void io_mkdirat_cleanup(struct io_kiocb *req)
192196
{
193197
struct io_mkdir *md = io_kiocb_to_cmd(req, struct io_mkdir);
194198

195-
putname(md->filename);
199+
dismiss_delayed_filename(&md->filename);
196200
}
197201

198202
int io_symlinkat_prep(struct io_kiocb *req, const struct io_uring_sqe *sqe)
199203
{
200204
struct io_link *sl = io_kiocb_to_cmd(req, struct io_link);
201205
const char __user *oldpath, *newpath;
206+
int err;
202207

203208
if (sqe->len || sqe->rw_flags || sqe->buf_index || sqe->splice_fd_in)
204209
return -EINVAL;
@@ -209,14 +214,14 @@ int io_symlinkat_prep(struct io_kiocb *req, const struct io_uring_sqe *sqe)
209214
oldpath = u64_to_user_ptr(READ_ONCE(sqe->addr));
210215
newpath = u64_to_user_ptr(READ_ONCE(sqe->addr2));
211216

212-
sl->oldpath = getname(oldpath);
213-
if (IS_ERR(sl->oldpath))
214-
return PTR_ERR(sl->oldpath);
217+
err = delayed_getname(&sl->oldpath, oldpath);
218+
if (unlikely(err))
219+
return err;
215220

216-
sl->newpath = getname(newpath);
217-
if (IS_ERR(sl->newpath)) {
218-
putname(sl->oldpath);
219-
return PTR_ERR(sl->newpath);
221+
err = delayed_getname(&sl->newpath, newpath);
222+
if (unlikely(err)) {
223+
dismiss_delayed_filename(&sl->oldpath);
224+
return err;
220225
}
221226

222227
req->flags |= REQ_F_NEED_CLEANUP;
@@ -231,7 +236,8 @@ int io_symlinkat(struct io_kiocb *req, unsigned int issue_flags)
231236

232237
WARN_ON_ONCE(issue_flags & IO_URING_F_NONBLOCK);
233238

234-
ret = do_symlinkat(sl->oldpath, sl->new_dfd, sl->newpath);
239+
ret = do_symlinkat(complete_getname(&sl->oldpath), sl->new_dfd,
240+
complete_getname(&sl->newpath));
235241

236242
req->flags &= ~REQ_F_NEED_CLEANUP;
237243
io_req_set_res(req, ret, 0);
@@ -242,6 +248,7 @@ int io_linkat_prep(struct io_kiocb *req, const struct io_uring_sqe *sqe)
242248
{
243249
struct io_link *lnk = io_kiocb_to_cmd(req, struct io_link);
244250
const char __user *oldf, *newf;
251+
int err;
245252

246253
if (sqe->buf_index || sqe->splice_fd_in)
247254
return -EINVAL;
@@ -254,14 +261,14 @@ int io_linkat_prep(struct io_kiocb *req, const struct io_uring_sqe *sqe)
254261
newf = u64_to_user_ptr(READ_ONCE(sqe->addr2));
255262
lnk->flags = READ_ONCE(sqe->hardlink_flags);
256263

257-
lnk->oldpath = getname_uflags(oldf, lnk->flags);
258-
if (IS_ERR(lnk->oldpath))
259-
return PTR_ERR(lnk->oldpath);
264+
err = delayed_getname_uflags(&lnk->oldpath, oldf, lnk->flags);
265+
if (unlikely(err))
266+
return err;
260267

261-
lnk->newpath = getname(newf);
262-
if (IS_ERR(lnk->newpath)) {
263-
putname(lnk->oldpath);
264-
return PTR_ERR(lnk->newpath);
268+
err = delayed_getname(&lnk->newpath, newf);
269+
if (unlikely(err)) {
270+
dismiss_delayed_filename(&lnk->oldpath);
271+
return err;
265272
}
266273

267274
req->flags |= REQ_F_NEED_CLEANUP;
@@ -276,8 +283,8 @@ int io_linkat(struct io_kiocb *req, unsigned int issue_flags)
276283

277284
WARN_ON_ONCE(issue_flags & IO_URING_F_NONBLOCK);
278285

279-
ret = do_linkat(lnk->old_dfd, lnk->oldpath, lnk->new_dfd,
280-
lnk->newpath, lnk->flags);
286+
ret = do_linkat(lnk->old_dfd, complete_getname(&lnk->oldpath),
287+
lnk->new_dfd, complete_getname(&lnk->newpath), lnk->flags);
281288

282289
req->flags &= ~REQ_F_NEED_CLEANUP;
283290
io_req_set_res(req, ret, 0);
@@ -288,6 +295,6 @@ void io_link_cleanup(struct io_kiocb *req)
288295
{
289296
struct io_link *sl = io_kiocb_to_cmd(req, struct io_link);
290297

291-
putname(sl->oldpath);
292-
putname(sl->newpath);
298+
dismiss_delayed_filename(&sl->oldpath);
299+
dismiss_delayed_filename(&sl->newpath);
293300
}

0 commit comments

Comments
 (0)