Skip to content

Commit 7c34fed

Browse files
GeHao01994gregkh
authored andcommitted
slab: Avoid race on slab->obj_exts in alloc_slab_obj_exts
commit 6ed8bfd upstream. If two competing threads enter alloc_slab_obj_exts() and one of them fails to allocate the object extension vector, it might override the valid slab->obj_exts allocated by the other thread with OBJEXTS_ALLOC_FAIL. This will cause the thread that lost this race and expects a valid pointer to dereference a NULL pointer later on. Update slab->obj_exts atomically using cmpxchg() to avoid slab->obj_exts overrides by racing threads. Thanks for Vlastimil and Suren's help with debugging. Fixes: f7381b9 ("slab: mark slab->obj_exts allocation failures unconditionally") Cc: <[email protected]> Suggested-by: Suren Baghdasaryan <[email protected]> Signed-off-by: Hao Ge <[email protected]> Reviewed-by: Harry Yoo <[email protected]> Reviewed-by: Suren Baghdasaryan <[email protected]> Link: https://patch.msgid.link/[email protected] Signed-off-by: Vlastimil Babka <[email protected]> Signed-off-by: Greg Kroah-Hartman <[email protected]>
1 parent 2b55b5b commit 7c34fed

File tree

1 file changed

+6
-3
lines changed

1 file changed

+6
-3
lines changed

mm/slub.c

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1978,7 +1978,7 @@ static inline void mark_objexts_empty(struct slabobj_ext *obj_exts)
19781978

19791979
static inline void mark_failed_objexts_alloc(struct slab *slab)
19801980
{
1981-
slab->obj_exts = OBJEXTS_ALLOC_FAIL;
1981+
cmpxchg(&slab->obj_exts, 0, OBJEXTS_ALLOC_FAIL);
19821982
}
19831983

19841984
static inline void handle_failed_objexts_alloc(unsigned long obj_exts,
@@ -2043,6 +2043,7 @@ int alloc_slab_obj_exts(struct slab *slab, struct kmem_cache *s,
20432043
#ifdef CONFIG_MEMCG
20442044
new_exts |= MEMCG_DATA_OBJEXTS;
20452045
#endif
2046+
retry:
20462047
old_exts = READ_ONCE(slab->obj_exts);
20472048
handle_failed_objexts_alloc(old_exts, vec, objects);
20482049
if (new_slab) {
@@ -2052,8 +2053,7 @@ int alloc_slab_obj_exts(struct slab *slab, struct kmem_cache *s,
20522053
* be simply assigned.
20532054
*/
20542055
slab->obj_exts = new_exts;
2055-
} else if ((old_exts & ~OBJEXTS_FLAGS_MASK) ||
2056-
cmpxchg(&slab->obj_exts, old_exts, new_exts) != old_exts) {
2056+
} else if (old_exts & ~OBJEXTS_FLAGS_MASK) {
20572057
/*
20582058
* If the slab is already in use, somebody can allocate and
20592059
* assign slabobj_exts in parallel. In this case the existing
@@ -2062,6 +2062,9 @@ int alloc_slab_obj_exts(struct slab *slab, struct kmem_cache *s,
20622062
mark_objexts_empty(vec);
20632063
kfree(vec);
20642064
return 0;
2065+
} else if (cmpxchg(&slab->obj_exts, old_exts, new_exts) != old_exts) {
2066+
/* Retry if a racing thread changed slab->obj_exts from under us. */
2067+
goto retry;
20652068
}
20662069

20672070
kmemleak_not_leak(vec);

0 commit comments

Comments
 (0)