Skip to content

Commit 4b4391e

Browse files
LiBaokun96brauner
authored andcommitted
cachefiles: defer exposing anon_fd until after copy_to_user() succeeds
After installing the anonymous fd, we can now see it in userland and close it. However, at this point we may not have gotten the reference count of the cache, but we will put it during colse fd, so this may cause a cache UAF. So grab the cache reference count before fd_install(). In addition, by kernel convention, fd is taken over by the user land after fd_install(), and the kernel should not call close_fd() after that, i.e., it should call fd_install() after everything is ready, thus fd_install() is called after copy_to_user() succeeds. Fixes: c838305 ("cachefiles: notify the user daemon when looking up cookie") Suggested-by: Hou Tao <[email protected]> Signed-off-by: Baokun Li <[email protected]> Link: https://lore.kernel.org/r/[email protected] Acked-by: Jeff Layton <[email protected]> Signed-off-by: Christian Brauner <[email protected]>
1 parent 4988e35 commit 4b4391e

File tree

1 file changed

+33
-20
lines changed

1 file changed

+33
-20
lines changed

fs/cachefiles/ondemand.c

Lines changed: 33 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,11 @@
44
#include <linux/uio.h>
55
#include "internal.h"
66

7+
struct ondemand_anon_file {
8+
struct file *file;
9+
int fd;
10+
};
11+
712
static inline void cachefiles_req_put(struct cachefiles_req *req)
813
{
914
if (refcount_dec_and_test(&req->ref))
@@ -263,14 +268,14 @@ int cachefiles_ondemand_restore(struct cachefiles_cache *cache, char *args)
263268
return 0;
264269
}
265270

266-
static int cachefiles_ondemand_get_fd(struct cachefiles_req *req)
271+
static int cachefiles_ondemand_get_fd(struct cachefiles_req *req,
272+
struct ondemand_anon_file *anon_file)
267273
{
268274
struct cachefiles_object *object;
269275
struct cachefiles_cache *cache;
270276
struct cachefiles_open *load;
271-
struct file *file;
272277
u32 object_id;
273-
int ret, fd;
278+
int ret;
274279

275280
object = cachefiles_grab_object(req->object,
276281
cachefiles_obj_get_ondemand_fd);
@@ -282,33 +287,32 @@ static int cachefiles_ondemand_get_fd(struct cachefiles_req *req)
282287
if (ret < 0)
283288
goto err;
284289

285-
fd = get_unused_fd_flags(O_WRONLY);
286-
if (fd < 0) {
287-
ret = fd;
290+
anon_file->fd = get_unused_fd_flags(O_WRONLY);
291+
if (anon_file->fd < 0) {
292+
ret = anon_file->fd;
288293
goto err_free_id;
289294
}
290295

291-
file = anon_inode_getfile("[cachefiles]", &cachefiles_ondemand_fd_fops,
292-
object, O_WRONLY);
293-
if (IS_ERR(file)) {
294-
ret = PTR_ERR(file);
296+
anon_file->file = anon_inode_getfile("[cachefiles]",
297+
&cachefiles_ondemand_fd_fops, object, O_WRONLY);
298+
if (IS_ERR(anon_file->file)) {
299+
ret = PTR_ERR(anon_file->file);
295300
goto err_put_fd;
296301
}
297302

298303
spin_lock(&object->ondemand->lock);
299304
if (object->ondemand->ondemand_id > 0) {
300305
spin_unlock(&object->ondemand->lock);
301306
/* Pair with check in cachefiles_ondemand_fd_release(). */
302-
file->private_data = NULL;
307+
anon_file->file->private_data = NULL;
303308
ret = -EEXIST;
304309
goto err_put_file;
305310
}
306311

307-
file->f_mode |= FMODE_PWRITE | FMODE_LSEEK;
308-
fd_install(fd, file);
312+
anon_file->file->f_mode |= FMODE_PWRITE | FMODE_LSEEK;
309313

310314
load = (void *)req->msg.data;
311-
load->fd = fd;
315+
load->fd = anon_file->fd;
312316
object->ondemand->ondemand_id = object_id;
313317
spin_unlock(&object->ondemand->lock);
314318

@@ -317,9 +321,11 @@ static int cachefiles_ondemand_get_fd(struct cachefiles_req *req)
317321
return 0;
318322

319323
err_put_file:
320-
fput(file);
324+
fput(anon_file->file);
325+
anon_file->file = NULL;
321326
err_put_fd:
322-
put_unused_fd(fd);
327+
put_unused_fd(anon_file->fd);
328+
anon_file->fd = ret;
323329
err_free_id:
324330
xa_erase(&cache->ondemand_ids, object_id);
325331
err:
@@ -376,6 +382,7 @@ ssize_t cachefiles_ondemand_daemon_read(struct cachefiles_cache *cache,
376382
struct cachefiles_msg *msg;
377383
size_t n;
378384
int ret = 0;
385+
struct ondemand_anon_file anon_file;
379386
XA_STATE(xas, &cache->reqs, cache->req_id_next);
380387

381388
xa_lock(&cache->reqs);
@@ -409,18 +416,24 @@ ssize_t cachefiles_ondemand_daemon_read(struct cachefiles_cache *cache,
409416
xa_unlock(&cache->reqs);
410417

411418
if (msg->opcode == CACHEFILES_OP_OPEN) {
412-
ret = cachefiles_ondemand_get_fd(req);
419+
ret = cachefiles_ondemand_get_fd(req, &anon_file);
413420
if (ret)
414421
goto out;
415422
}
416423

417424
msg->msg_id = xas.xa_index;
418425
msg->object_id = req->object->ondemand->ondemand_id;
419426

420-
if (copy_to_user(_buffer, msg, n) != 0) {
427+
if (copy_to_user(_buffer, msg, n) != 0)
421428
ret = -EFAULT;
422-
if (msg->opcode == CACHEFILES_OP_OPEN)
423-
close_fd(((struct cachefiles_open *)msg->data)->fd);
429+
430+
if (msg->opcode == CACHEFILES_OP_OPEN) {
431+
if (ret < 0) {
432+
fput(anon_file.file);
433+
put_unused_fd(anon_file.fd);
434+
goto out;
435+
}
436+
fd_install(anon_file.fd, anon_file.file);
424437
}
425438
out:
426439
cachefiles_put_object(req->object, cachefiles_obj_put_read_req);

0 commit comments

Comments
 (0)