Skip to content

Commit d16716f

Browse files
LiBaokun96intel-lab-lkp
authored andcommitted
cachefiles: fix slab-use-after-free in cachefiles_ondemand_get_fd()
We got the following issue in a fuzz test of randomly issuing the restore command: ================================================================== BUG: KASAN: slab-use-after-free in cachefiles_ondemand_daemon_read+0x609/0xab0 Write of size 4 at addr ffff888109164a80 by task ondemand-04-dae/4962 CPU: 11 PID: 4962 Comm: ondemand-04-dae Not tainted 6.8.0-rc7-dirty torvalds#542 Call Trace: kasan_report+0x94/0xc0 cachefiles_ondemand_daemon_read+0x609/0xab0 vfs_read+0x169/0xb50 ksys_read+0xf5/0x1e0 Allocated by task 626: __kmalloc+0x1df/0x4b0 cachefiles_ondemand_send_req+0x24d/0x690 cachefiles_create_tmpfile+0x249/0xb30 cachefiles_create_file+0x6f/0x140 cachefiles_look_up_object+0x29c/0xa60 cachefiles_lookup_cookie+0x37d/0xca0 fscache_cookie_state_machine+0x43c/0x1230 [...] Freed by task 626: kfree+0xf1/0x2c0 cachefiles_ondemand_send_req+0x568/0x690 cachefiles_create_tmpfile+0x249/0xb30 cachefiles_create_file+0x6f/0x140 cachefiles_look_up_object+0x29c/0xa60 cachefiles_lookup_cookie+0x37d/0xca0 fscache_cookie_state_machine+0x43c/0x1230 [...] ================================================================== Following is the process that triggers the issue: mount | daemon_thread1 | daemon_thread2 ------------------------------------------------------------ cachefiles_ondemand_init_object cachefiles_ondemand_send_req REQ_A = kzalloc(sizeof(*req) + data_len) wait_for_completion(&REQ_A->done) cachefiles_daemon_read cachefiles_ondemand_daemon_read REQ_A = cachefiles_ondemand_select_req cachefiles_ondemand_get_fd copy_to_user(_buffer, msg, n) process_open_req(REQ_A) ------ restore ------ cachefiles_ondemand_restore xas_for_each(&xas, req, ULONG_MAX) xas_set_mark(&xas, CACHEFILES_REQ_NEW); cachefiles_daemon_read cachefiles_ondemand_daemon_read REQ_A = cachefiles_ondemand_select_req write(devfd, ("copen %u,%llu", msg->msg_id, size)); cachefiles_ondemand_copen xa_erase(&cache->reqs, id) complete(&REQ_A->done) kfree(REQ_A) cachefiles_ondemand_get_fd(REQ_A) fd = get_unused_fd_flags file = anon_inode_getfile fd_install(fd, file) load = (void *)REQ_A->msg.data; load->fd = fd; // load UAF !!! This issue is caused by issuing a restore command when the daemon is still alive, which results in a request being processed multiple times thus triggering a UAF. So to avoid this problem, add an additional reference count to cachefiles_req, which is held while waiting and reading, and then released when the waiting and reading is over. Note that since there is only one reference count for waiting, we need to avoid the same request being completed multiple times, so we can only complete the request if it is successfully removed from the xarray. Fixes: e73fa11 ("cachefiles: add restore command to recover inflight ondemand read requests") Suggested-by: Hou Tao <[email protected]> Signed-off-by: Baokun Li <[email protected]> Reviewed-by: Jia Zhu <[email protected]>
1 parent c81c552 commit d16716f

File tree

2 files changed

+25
-20
lines changed

2 files changed

+25
-20
lines changed

fs/cachefiles/internal.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -138,6 +138,7 @@ static inline bool cachefiles_in_ondemand_mode(struct cachefiles_cache *cache)
138138
struct cachefiles_req {
139139
struct cachefiles_object *object;
140140
struct completion done;
141+
refcount_t ref;
141142
int error;
142143
struct cachefiles_msg msg;
143144
};

fs/cachefiles/ondemand.c

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

7+
static inline void cachefiles_req_put(struct cachefiles_req *req)
8+
{
9+
if (refcount_dec_and_test(&req->ref))
10+
kfree(req);
11+
}
12+
713
static int cachefiles_ondemand_fd_release(struct inode *inode,
814
struct file *file)
915
{
@@ -299,7 +305,6 @@ ssize_t cachefiles_ondemand_daemon_read(struct cachefiles_cache *cache,
299305
{
300306
struct cachefiles_req *req;
301307
struct cachefiles_msg *msg;
302-
unsigned long id = 0;
303308
size_t n;
304309
int ret = 0;
305310
XA_STATE(xas, &cache->reqs, cache->req_id_next);
@@ -330,41 +335,39 @@ ssize_t cachefiles_ondemand_daemon_read(struct cachefiles_cache *cache,
330335

331336
xas_clear_mark(&xas, CACHEFILES_REQ_NEW);
332337
cache->req_id_next = xas.xa_index + 1;
338+
refcount_inc(&req->ref);
333339
xa_unlock(&cache->reqs);
334340

335-
id = xas.xa_index;
336-
337341
if (msg->opcode == CACHEFILES_OP_OPEN) {
338342
ret = cachefiles_ondemand_get_fd(req);
339343
if (ret) {
340344
cachefiles_ondemand_set_object_close(req->object);
341-
goto error;
345+
goto out;
342346
}
343347
}
344348

345-
msg->msg_id = id;
349+
msg->msg_id = xas.xa_index;
346350
msg->object_id = req->object->ondemand->ondemand_id;
347351

348352
if (copy_to_user(_buffer, msg, n) != 0) {
349353
ret = -EFAULT;
350354
if (msg->opcode == CACHEFILES_OP_OPEN)
351355
close_fd(((struct cachefiles_open *)msg->data)->fd);
352-
goto error;
353356
}
354-
355-
/* CLOSE request has no reply */
356-
if (msg->opcode == CACHEFILES_OP_CLOSE) {
357-
xa_erase(&cache->reqs, id);
358-
complete(&req->done);
357+
out:
358+
/* Remove error request and CLOSE request has no reply */
359+
if (ret || msg->opcode == CACHEFILES_OP_CLOSE) {
360+
xas_reset(&xas);
361+
xas_lock(&xas);
362+
if (xas_load(&xas) == req) {
363+
req->error = ret;
364+
complete(&req->done);
365+
xas_store(&xas, NULL);
366+
}
367+
xas_unlock(&xas);
359368
}
360-
361-
return n;
362-
363-
error:
364-
xa_erase(&cache->reqs, id);
365-
req->error = ret;
366-
complete(&req->done);
367-
return ret;
369+
cachefiles_req_put(req);
370+
return ret ? ret : n;
368371
}
369372

370373
typedef int (*init_req_fn)(struct cachefiles_req *req, void *private);
@@ -394,6 +397,7 @@ static int cachefiles_ondemand_send_req(struct cachefiles_object *object,
394397
goto out;
395398
}
396399

400+
refcount_set(&req->ref, 1);
397401
req->object = object;
398402
init_completion(&req->done);
399403
req->msg.opcode = opcode;
@@ -455,7 +459,7 @@ static int cachefiles_ondemand_send_req(struct cachefiles_object *object,
455459
wake_up_all(&cache->daemon_pollwq);
456460
wait_for_completion(&req->done);
457461
ret = req->error;
458-
kfree(req);
462+
cachefiles_req_put(req);
459463
return ret;
460464
out:
461465
/* Reset the object to close state in error handling path.

0 commit comments

Comments
 (0)