In the Linux kernel, the following vulnerability has been resolved:
bpf, sockmap: Fix race between element replace and close()
Element replace (with a socket different from the one stored) may race with socket's close() link popping & unlinking. _sockmap_delete() unconditionally unrefs the (wrong) element:
// set map[0] = s0 mapupdateelem(map, 0, s0)
// drop fd of s0 close(s0) sockmapclose() locksock(sk) (s0!) sockmapremovelinks(sk) link = skpsocklinkpop() sockmapunlink(sk, link) sockmapdeletefromlink // replace map[0] with s1 mapupdateelem(map, 0, s1) sockmapupdateelem (s1!) locksock(sk) sockmapupdatecommon psock = skpsock(sk) spinlock(&stab->lock) osk = stab->sks[idx] sockmapaddlink(..., &stab->sks[idx]) sockmapunref(osk, &stab->sks[idx]) psock = skpsock(osk) skpsockput(sk, psock) if (refcountdecandtest(&psock)) skpsockdrop(sk, psock) spinunlock(&stab->lock) unlocksock(sk) _sockmapdelete spinlock(&stab->lock) sk = *psk // s1 replaced s0; sk == s1 if (!sktest || sktest == sk) // sktest (s0) != sk (s1); no branch sk = xchg(psk, NULL) if (sk) sockmapunref(sk, psk) // unref s1; sks[idx] will dangle psock = skpsock(sk) skpsockput(sk, psock) if (refcountdecandtest()) skpsockdrop(sk, psock) spinunlock(&stab->lock) releasesock(sk)
Then close(map) enqueues bpfmapfreedeferred, which finally calls sockmapfree(). This results in some refcountt warnings along with a KASAN splat [1].
Fix _sockmapdelete(), do not allow sockmap_unref() on elements that may have been replaced.
Write of size 4 at addr ffff88811f5b9100 by task kworker/u64:12/1063
CPU: 14 UID: 0 PID: 1063 Comm: kworker/u64:12 Not tainted 6.12.0+ #125 Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), BIOS Arch Linux 1.16.3-1-1 04/01/2014 Workqueue: eventsunbound bpfmapfreedeferred Call Trace: <TASK> dumpstacklvl+0x68/0x90 printreport+0x174/0x4f6 kasanreport+0xb9/0x190 kasancheckrange+0x10f/0x1e0 sockmapfree+0x10e/0x330 bpfmapfreedeferred+0x173/0x320 processonework+0x846/0x1420 workerthread+0x5b3/0xf80 kthread+0x29e/0x360 retfromfork+0x2d/0x70 retfromfork_asm+0x1a/0x30 </TASK>
Allocated by task 1202: kasansavestack+0x1e/0x40 kasansavetrack+0x10/0x30 _kasanslaballoc+0x85/0x90 kmemcacheallocnoprof+0x131/0x450 skprotalloc+0x5b/0x220 skalloc+0x2c/0x870 unixcreate1+0x88/0x8a0 unixcreate+0xc5/0x180 _sockcreate+0x241/0x650 _syssocketpair+0x1ce/0x420 _x64syssocketpair+0x92/0x100 dosyscall64+0x93/0x180 entrySYSCALL64afterhwframe+0x76/0x7e
Freed by task 46: kasansavestack+0x1e/0x40 kasansavetrack+0x10/0x30 kasansavefreeinfo+0x37/0x60 _kasanslabfree+0x4b/0x70 kmemcachefree+0x1a1/0x590 _skdestruct+0x388/0x5a0 skpsockdestroy+0x73e/0xa50 processonework+0x846/0x1420 workerthread+0x5b3/0xf80 kthread+0x29e/0x360 retfromfork+0x2d/0x70 retfromforkasm+0x1a/0x30
The bu ---truncated---
[
{
"signature_type": "Function",
"deprecated": false,
"target": {
"file": "net/core/sock_map.c",
"function": "__sock_map_delete"
},
"digest": {
"length": 336.0,
"function_hash": "34679678572678843180978853196840482387"
},
"source": "https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git@bf2318e288f636a882eea39f7e1015623629f168",
"signature_version": "v1",
"id": "CVE-2024-56664-3f16602a"
},
{
"signature_type": "Line",
"deprecated": false,
"target": {
"file": "net/core/sock_map.c"
},
"digest": {
"line_hashes": [
"95180705289908824923673873350782881447",
"318919811043199200300827682055258945125",
"18072462441344506787349905394294938908",
"72907990672945074088511432350399965994",
"48167334349908533506800112087564649893",
"171630536704768750698560955055215343350",
"274705971106116972295952283747575100811",
"196103919473935205515475631784885582076"
],
"threshold": 0.9
},
"source": "https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git@bf2318e288f636a882eea39f7e1015623629f168",
"signature_version": "v1",
"id": "CVE-2024-56664-54ddd325"
},
{
"signature_type": "Line",
"deprecated": false,
"target": {
"file": "net/core/sock_map.c"
},
"digest": {
"line_hashes": [
"95180705289908824923673873350782881447",
"318919811043199200300827682055258945125",
"175225203589748768825801771661946826757",
"117641566697424408686505493081598006603",
"234068474520533433071468333338471087705",
"263094312756827269468520521624970759798",
"470976049014868199023561994431603947",
"9960045100121545686328367723511783935",
"274705971106116972295952283747575100811",
"196103919473935205515475631784885582076"
],
"threshold": 0.9
},
"source": "https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git@b79a0d1e9a374d1b376933a354c4fcd01fce0365",
"signature_version": "v1",
"id": "CVE-2024-56664-7be6508c"
},
{
"signature_type": "Function",
"deprecated": false,
"target": {
"file": "net/core/sock_map.c",
"function": "__sock_map_delete"
},
"digest": {
"length": 378.0,
"function_hash": "192819561537467546269348689353285465392"
},
"source": "https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git@b79a0d1e9a374d1b376933a354c4fcd01fce0365",
"signature_version": "v1",
"id": "CVE-2024-56664-9f8e86f2"
},
{
"signature_type": "Line",
"deprecated": false,
"target": {
"file": "net/core/sock_map.c"
},
"digest": {
"line_hashes": [
"95180705289908824923673873350782881447",
"318919811043199200300827682055258945125",
"18072462441344506787349905394294938908",
"72907990672945074088511432350399965994",
"48167334349908533506800112087564649893",
"171630536704768750698560955055215343350",
"274705971106116972295952283747575100811",
"196103919473935205515475631784885582076"
],
"threshold": 0.9
},
"source": "https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git@b015f19fedd2e12283a8450dd0aefce49ec57015",
"signature_version": "v1",
"id": "CVE-2024-56664-c6ba2603"
},
{
"signature_type": "Function",
"deprecated": false,
"target": {
"file": "net/core/sock_map.c",
"function": "__sock_map_delete"
},
"digest": {
"length": 336.0,
"function_hash": "34679678572678843180978853196840482387"
},
"source": "https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git@b015f19fedd2e12283a8450dd0aefce49ec57015",
"signature_version": "v1",
"id": "CVE-2024-56664-ebaa2451"
}
]