Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

slab: Avoid race on slab->obj_exts in alloc_slab_obj_exts

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: f7381b911640 ("slab: mark slab->obj_exts allocation failures unconditionally")
Cc: <stable@vger.kernel.org>
Suggested-by: Suren Baghdasaryan <surenb@google.com>
Signed-off-by: Hao Ge <gehao@kylinos.cn>
Reviewed-by: Harry Yoo <harry.yoo@oracle.com>
Reviewed-by: Suren Baghdasaryan <surenb@google.com>
Link: https://patch.msgid.link/20251021010353.1187193-1-hao.ge@linux.dev
Signed-off-by: Vlastimil Babka <vbabka@suse.cz>

authored by

Hao Ge and committed by
Vlastimil Babka
6ed8bfd2 86f54f9b

+6 -3
+6 -3
mm/slub.c
··· 2054 2054 2055 2055 static inline void mark_failed_objexts_alloc(struct slab *slab) 2056 2056 { 2057 - slab->obj_exts = OBJEXTS_ALLOC_FAIL; 2057 + cmpxchg(&slab->obj_exts, 0, OBJEXTS_ALLOC_FAIL); 2058 2058 } 2059 2059 2060 2060 static inline void handle_failed_objexts_alloc(unsigned long obj_exts, ··· 2136 2136 #ifdef CONFIG_MEMCG 2137 2137 new_exts |= MEMCG_DATA_OBJEXTS; 2138 2138 #endif 2139 + retry: 2139 2140 old_exts = READ_ONCE(slab->obj_exts); 2140 2141 handle_failed_objexts_alloc(old_exts, vec, objects); 2141 2142 if (new_slab) { ··· 2146 2145 * be simply assigned. 2147 2146 */ 2148 2147 slab->obj_exts = new_exts; 2149 - } else if ((old_exts & ~OBJEXTS_FLAGS_MASK) || 2150 - cmpxchg(&slab->obj_exts, old_exts, new_exts) != old_exts) { 2148 + } else if (old_exts & ~OBJEXTS_FLAGS_MASK) { 2151 2149 /* 2152 2150 * If the slab is already in use, somebody can allocate and 2153 2151 * assign slabobj_exts in parallel. In this case the existing ··· 2158 2158 else 2159 2159 kfree(vec); 2160 2160 return 0; 2161 + } else if (cmpxchg(&slab->obj_exts, old_exts, new_exts) != old_exts) { 2162 + /* Retry if a racing thread changed slab->obj_exts from under us. */ 2163 + goto retry; 2161 2164 } 2162 2165 2163 2166 if (allow_spin)