Skip to content

Commit 522018a

Browse files
LiBaokun96brauner
authored andcommitted
cachefiles: fix slab-use-after-free in fscache_withdraw_volume()
We got the following issue in our fault injection stress test: ================================================================== BUG: KASAN: slab-use-after-free in fscache_withdraw_volume+0x2e1/0x370 Read of size 4 at addr ffff88810680be08 by task ondemand-04-dae/5798 CPU: 0 PID: 5798 Comm: ondemand-04-dae Not tainted 6.8.0-dirty #565 Call Trace: kasan_check_range+0xf6/0x1b0 fscache_withdraw_volume+0x2e1/0x370 cachefiles_withdraw_volume+0x31/0x50 cachefiles_withdraw_cache+0x3ad/0x900 cachefiles_put_unbind_pincount+0x1f6/0x250 cachefiles_daemon_release+0x13b/0x290 __fput+0x204/0xa00 task_work_run+0x139/0x230 Allocated by task 5820: __kmalloc+0x1df/0x4b0 fscache_alloc_volume+0x70/0x600 __fscache_acquire_volume+0x1c/0x610 erofs_fscache_register_volume+0x96/0x1a0 erofs_fscache_register_fs+0x49a/0x690 erofs_fc_fill_super+0x6c0/0xcc0 vfs_get_super+0xa9/0x140 vfs_get_tree+0x8e/0x300 do_new_mount+0x28c/0x580 [...] Freed by task 5820: kfree+0xf1/0x2c0 fscache_put_volume.part.0+0x5cb/0x9e0 erofs_fscache_unregister_fs+0x157/0x1b0 erofs_kill_sb+0xd9/0x1c0 deactivate_locked_super+0xa3/0x100 vfs_get_super+0x105/0x140 vfs_get_tree+0x8e/0x300 do_new_mount+0x28c/0x580 [...] ================================================================== Following is the process that triggers the issue: mount failed | daemon exit ------------------------------------------------------------ deactivate_locked_super cachefiles_daemon_release erofs_kill_sb erofs_fscache_unregister_fs fscache_relinquish_volume __fscache_relinquish_volume fscache_put_volume(fscache_volume, fscache_volume_put_relinquish) zero = __refcount_dec_and_test(&fscache_volume->ref, &ref); cachefiles_put_unbind_pincount cachefiles_daemon_unbind cachefiles_withdraw_cache cachefiles_withdraw_volumes list_del_init(&volume->cache_link) fscache_free_volume(fscache_volume) cache->ops->free_volume cachefiles_free_volume list_del_init(&cachefiles_volume->cache_link); kfree(fscache_volume) cachefiles_withdraw_volume fscache_withdraw_volume fscache_volume->n_accesses // fscache_volume UAF !!! The fscache_volume in cache->volumes must not have been freed yet, but its reference count may be 0. So use the new fscache_try_get_volume() helper function try to get its reference count. If the reference count of fscache_volume is 0, fscache_put_volume() is freeing it, so wait for it to be removed from cache->volumes. If its reference count is not 0, call cachefiles_withdraw_volume() with reference count protection to avoid the above issue. Fixes: fe2140e ("cachefiles: Implement volume support") Signed-off-by: Baokun Li <[email protected]> Link: https://lore.kernel.org/r/[email protected] Signed-off-by: Christian Brauner <[email protected]>
1 parent 85b08b3 commit 522018a

File tree

2 files changed

+14
-0
lines changed

2 files changed

+14
-0
lines changed

fs/cachefiles/cache.c

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
#include <linux/slab.h>
99
#include <linux/statfs.h>
1010
#include <linux/namei.h>
11+
#include <trace/events/fscache.h>
1112
#include "internal.h"
1213

1314
/*
@@ -319,19 +320,28 @@ static void cachefiles_withdraw_volumes(struct cachefiles_cache *cache)
319320
_enter("");
320321

321322
for (;;) {
323+
struct fscache_volume *vcookie = NULL;
322324
struct cachefiles_volume *volume = NULL;
323325

324326
spin_lock(&cache->object_list_lock);
325327
if (!list_empty(&cache->volumes)) {
326328
volume = list_first_entry(&cache->volumes,
327329
struct cachefiles_volume, cache_link);
330+
vcookie = fscache_try_get_volume(volume->vcookie,
331+
fscache_volume_get_withdraw);
332+
if (!vcookie) {
333+
spin_unlock(&cache->object_list_lock);
334+
cpu_relax();
335+
continue;
336+
}
328337
list_del_init(&volume->cache_link);
329338
}
330339
spin_unlock(&cache->object_list_lock);
331340
if (!volume)
332341
break;
333342

334343
cachefiles_withdraw_volume(volume);
344+
fscache_put_volume(vcookie, fscache_volume_put_withdraw);
335345
}
336346

337347
_leave("");

include/trace/events/fscache.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,12 +35,14 @@ enum fscache_volume_trace {
3535
fscache_volume_get_cookie,
3636
fscache_volume_get_create_work,
3737
fscache_volume_get_hash_collision,
38+
fscache_volume_get_withdraw,
3839
fscache_volume_free,
3940
fscache_volume_new_acquire,
4041
fscache_volume_put_cookie,
4142
fscache_volume_put_create_work,
4243
fscache_volume_put_hash_collision,
4344
fscache_volume_put_relinquish,
45+
fscache_volume_put_withdraw,
4446
fscache_volume_see_create_work,
4547
fscache_volume_see_hash_wake,
4648
fscache_volume_wait_create_work,
@@ -120,12 +122,14 @@ enum fscache_access_trace {
120122
EM(fscache_volume_get_cookie, "GET cook ") \
121123
EM(fscache_volume_get_create_work, "GET creat") \
122124
EM(fscache_volume_get_hash_collision, "GET hcoll") \
125+
EM(fscache_volume_get_withdraw, "GET withd") \
123126
EM(fscache_volume_free, "FREE ") \
124127
EM(fscache_volume_new_acquire, "NEW acq ") \
125128
EM(fscache_volume_put_cookie, "PUT cook ") \
126129
EM(fscache_volume_put_create_work, "PUT creat") \
127130
EM(fscache_volume_put_hash_collision, "PUT hcoll") \
128131
EM(fscache_volume_put_relinquish, "PUT relnq") \
132+
EM(fscache_volume_put_withdraw, "PUT withd") \
129133
EM(fscache_volume_see_create_work, "SEE creat") \
130134
EM(fscache_volume_see_hash_wake, "SEE hwake") \
131135
E_(fscache_volume_wait_create_work, "WAIT crea")

0 commit comments

Comments
 (0)