| From bippy-5f407fcff5a0 Mon Sep 17 00:00:00 2001 |
| From: Greg Kroah-Hartman <gregkh@linuxfoundation.org> |
| To: <linux-cve-announce@vger.kernel.org> |
| Reply-to: <cve@kernel.org>, <linux-kernel@vger.kernel.org> |
| Subject: CVE-2022-49700: mm/slub: add missing TID updates on slab deactivation |
| |
| Description |
| =========== |
| |
| In the Linux kernel, the following vulnerability has been resolved: |
| |
| mm/slub: add missing TID updates on slab deactivation |
| |
| The fastpath in slab_alloc_node() assumes that c->slab is stable as long as |
| the TID stays the same. However, two places in __slab_alloc() currently |
| don't update the TID when deactivating the CPU slab. |
| |
| If multiple operations race the right way, this could lead to an object |
| getting lost; or, in an even more unlikely situation, it could even lead to |
| an object being freed onto the wrong slab's freelist, messing up the |
| `inuse` counter and eventually causing a page to be freed to the page |
| allocator while it still contains slab objects. |
| |
| (I haven't actually tested these cases though, this is just based on |
| looking at the code. Writing testcases for this stuff seems like it'd be |
| a pain...) |
| |
| The race leading to state inconsistency is (all operations on the same CPU |
| and kmem_cache): |
| |
| - task A: begin do_slab_free(): |
| - read TID |
| - read pcpu freelist (==NULL) |
| - check `slab == c->slab` (true) |
| - [PREEMPT A->B] |
| - task B: begin slab_alloc_node(): |
| - fastpath fails (`c->freelist` is NULL) |
| - enter __slab_alloc() |
| - slub_get_cpu_ptr() (disables preemption) |
| - enter ___slab_alloc() |
| - take local_lock_irqsave() |
| - read c->freelist as NULL |
| - get_freelist() returns NULL |
| - write `c->slab = NULL` |
| - drop local_unlock_irqrestore() |
| - goto new_slab |
| - slub_percpu_partial() is NULL |
| - get_partial() returns NULL |
| - slub_put_cpu_ptr() (enables preemption) |
| - [PREEMPT B->A] |
| - task A: finish do_slab_free(): |
| - this_cpu_cmpxchg_double() succeeds() |
| - [CORRUPT STATE: c->slab==NULL, c->freelist!=NULL] |
| |
| From there, the object on c->freelist will get lost if task B is allowed to |
| continue from here: It will proceed to the retry_load_slab label, |
| set c->slab, then jump to load_freelist, which clobbers c->freelist. |
| |
| But if we instead continue as follows, we get worse corruption: |
| |
| - task A: run __slab_free() on object from other struct slab: |
| - CPU_PARTIAL_FREE case (slab was on no list, is now on pcpu partial) |
| - task A: run slab_alloc_node() with NUMA node constraint: |
| - fastpath fails (c->slab is NULL) |
| - call __slab_alloc() |
| - slub_get_cpu_ptr() (disables preemption) |
| - enter ___slab_alloc() |
| - c->slab is NULL: goto new_slab |
| - slub_percpu_partial() is non-NULL |
| - set c->slab to slub_percpu_partial(c) |
| - [CORRUPT STATE: c->slab points to slab-1, c->freelist has objects |
| from slab-2] |
| - goto redo |
| - node_match() fails |
| - goto deactivate_slab |
| - existing c->freelist is passed into deactivate_slab() |
| - inuse count of slab-1 is decremented to account for object from |
| slab-2 |
| |
| At this point, the inuse count of slab-1 is 1 lower than it should be. |
| This means that if we free all allocated objects in slab-1 except for one, |
| SLUB will think that slab-1 is completely unused, and may free its page, |
| leading to use-after-free. |
| |
| The Linux kernel CVE team has assigned CVE-2022-49700 to this issue. |
| |
| |
| Affected and fixed versions |
| =========================== |
| |
| Issue introduced in 3.1 with commit 03e404af26dc2ea0d278d7a342de0aab394793ce and fixed in 4.9.323 with commit 308c6d0e1f200fd26c71270c6e6bfcf0fc6ff082 |
| Issue introduced in 3.1 with commit 03e404af26dc2ea0d278d7a342de0aab394793ce and fixed in 4.14.288 with commit d6a597450e686d4c6388bd3cdcb17224b4dae7f0 |
| Issue introduced in 3.1 with commit 03e404af26dc2ea0d278d7a342de0aab394793ce and fixed in 4.19.252 with commit e2b2f0e2e34d71ae6c2a1114fd3c525930e84bc7 |
| Issue introduced in 3.1 with commit 03e404af26dc2ea0d278d7a342de0aab394793ce and fixed in 5.4.205 with commit e7e3e90d671078455a3a08189f89d85b3da2de9e |
| Issue introduced in 3.1 with commit 03e404af26dc2ea0d278d7a342de0aab394793ce and fixed in 5.10.130 with commit 6c32496964da0dc230cea763a0e934b2e02dabd5 |
| Issue introduced in 3.1 with commit 03e404af26dc2ea0d278d7a342de0aab394793ce and fixed in 5.15.54 with commit 0515cc9b6b24877f59b222ade704bfaa42caa2a6 |
| Issue introduced in 3.1 with commit 03e404af26dc2ea0d278d7a342de0aab394793ce and fixed in 5.18.8 with commit 197e257da473c725dfe47759c3ee02f2398d8ea5 |
| Issue introduced in 3.1 with commit 03e404af26dc2ea0d278d7a342de0aab394793ce and fixed in 5.19 with commit eeaa345e128515135ccb864c04482180c08e3259 |
| |
| Please see https://www.kernel.org for a full list of currently supported |
| kernel versions by the kernel community. |
| |
| Unaffected versions might change over time as fixes are backported to |
| older supported kernel versions. The official CVE entry at |
| https://cve.org/CVERecord/?id=CVE-2022-49700 |
| will be updated if fixes are backported, please check that for the most |
| up to date information about this issue. |
| |
| |
| Affected files |
| ============== |
| |
| The file(s) affected by this issue are: |
| mm/slub.c |
| |
| |
| Mitigation |
| ========== |
| |
| The Linux kernel CVE team recommends that you update to the latest |
| stable kernel version for this, and many other bugfixes. Individual |
| changes are never tested alone, but rather are part of a larger kernel |
| release. Cherry-picking individual commits is not recommended or |
| supported by the Linux kernel community at all. If however, updating to |
| the latest release is impossible, the individual changes to resolve this |
| issue can be found at these commits: |
| https://git.kernel.org/stable/c/308c6d0e1f200fd26c71270c6e6bfcf0fc6ff082 |
| https://git.kernel.org/stable/c/d6a597450e686d4c6388bd3cdcb17224b4dae7f0 |
| https://git.kernel.org/stable/c/e2b2f0e2e34d71ae6c2a1114fd3c525930e84bc7 |
| https://git.kernel.org/stable/c/e7e3e90d671078455a3a08189f89d85b3da2de9e |
| https://git.kernel.org/stable/c/6c32496964da0dc230cea763a0e934b2e02dabd5 |
| https://git.kernel.org/stable/c/0515cc9b6b24877f59b222ade704bfaa42caa2a6 |
| https://git.kernel.org/stable/c/197e257da473c725dfe47759c3ee02f2398d8ea5 |
| https://git.kernel.org/stable/c/eeaa345e128515135ccb864c04482180c08e3259 |