In the Linux kernel, the following vulnerability has been resolved:
nfsd: release svcexpkey/svcexport with rcu_work
The last reference for cache_head
can be reduced to zero in c_show
and e_show
(using rcu_read_lock
and rcu_read_unlock
). Consequently,
svc_export_put
and expkey_put
will be invoked, leading to two
issues:
The svc_export_put
will directly free ex_uuid. However,
e_show
/c_show
will access ex_uuid
after cache_put
, which can
trigger a use-after-free issue, shown below.
================================================================== BUG: KASAN: slab-use-after-free in svcexportshow+0x362/0x430 [nfsd] Read of size 1 at addr ff11000010fdc120 by task cat/870
CPU: 1 UID: 0 PID: 870 Comm: cat Not tainted 6.12.0-rc3+ #1 Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), BIOS 1.16.1-2.fc37 04/01/2014 Call Trace: <TASK> dumpstacklvl+0x53/0x70 printaddressdescription.constprop.0+0x2c/0x3a0 printreport+0xb9/0x280 kasanreport+0xae/0xe0 svcexportshow+0x362/0x430 [nfsd] cshow+0x161/0x390 [sunrpc] seqreaditer+0x589/0x770 seqread+0x1e5/0x270 procregread+0xe1/0x140 vfsread+0x125/0x530 ksysread+0xc1/0x160 dosyscall64+0x5f/0x170 entrySYSCALL64afterhwframe+0x76/0x7e
Allocated by task 830: kasansavestack+0x20/0x40 kasansavetrack+0x14/0x30 _kasankmalloc+0x8f/0xa0 _kmallocnodetrackcallernoprof+0x1bc/0x400 kmemdupnoprof+0x22/0x50 svcexportparse+0x8a9/0xb80 [nfsd] cachedodowncall+0x71/0xa0 [sunrpc] cachewriteprocfs+0x8e/0xd0 [sunrpc] procregwrite+0xe1/0x140 vfswrite+0x1a5/0x6d0 ksyswrite+0xc1/0x160 dosyscall64+0x5f/0x170 entrySYSCALL64afterhwframe+0x76/0x7e
Freed by task 868: kasansavestack+0x20/0x40 kasansavetrack+0x14/0x30 kasansavefreeinfo+0x3b/0x60 _kasanslabfree+0x37/0x50 kfree+0xf3/0x3e0 svcexportput+0x87/0xb0 [nfsd] cachepurge+0x17f/0x1f0 [sunrpc] nfsddestroyserv+0x226/0x2d0 [nfsd] nfsdsvc+0x125/0x1e0 [nfsd] writethreads+0x16a/0x2a0 [nfsd] nfsctltransactionwrite+0x74/0xa0 [nfsd] vfswrite+0x1a5/0x6d0 ksyswrite+0xc1/0x160 dosyscall64+0x5f/0x170 entrySYSCALL64after_hwframe+0x76/0x7e
We cannot sleep while using rcu_read_lock
/rcu_read_unlock
.
However, svc_export_put
/expkey_put
will call path_put, which
subsequently triggers a sleeping operation due to the following
dput
.
============================= WARNING: suspicious RCU usage 5.10.0-dirty #141 Not tainted
... Call Trace: dumpstack+0x9a/0xd0 _mightsleep+0x231/0x240 dput+0x39/0x600 pathput+0x1b/0x30 svcexportput+0x17/0x80 eshow+0x1c9/0x200 seqreaditer+0x63f/0x7c0 seqread+0x226/0x2d0 vfsread+0x113/0x2c0 ksysread+0xc9/0x170 dosyscall64+0x33/0x40 entrySYSCALL64after_hwframe+0x67/0xd1
Fix these issues by using rcu_work
to help release
svc_expkey
/svc_export
. This approach allows for an asynchronous
context to invoke path_put
and also facilitates the freeing of
uuid/exp/key
after an RCU grace period.