Skip to content

Commit d36a63a

Browse files
xairytorvalds
authored andcommitted
kasan, slub: fix more conflicts with CONFIG_SLAB_FREELIST_HARDENED
When CONFIG_KASAN_SW_TAGS is enabled, ptr_addr might be tagged. Normally, this doesn't cause any issues, as both set_freepointer() and get_freepointer() are called with a pointer with the same tag. However, there are some issues with CONFIG_SLUB_DEBUG code. For example, when __free_slub() iterates over objects in a cache, it passes untagged pointers to check_object(). check_object() in turns calls get_freepointer() with an untagged pointer, which causes the freepointer to be restored incorrectly. Add kasan_reset_tag to freelist_ptr(). Also add a detailed comment. Link: http://lkml.kernel.org/r/bf858f26ef32eb7bd24c665755b3aee4bc58d0e4.1550103861.git.andreyknvl@google.com Signed-off-by: Andrey Konovalov <andreyknvl@google.com> Reported-by: Qian Cai <cai@lca.pw> Tested-by: Qian Cai <cai@lca.pw> Cc: Andrey Ryabinin <aryabinin@virtuozzo.com> Cc: Alexander Potapenko <glider@google.com> Cc: Dmitry Vyukov <dvyukov@google.com> Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
1 parent 18e5066 commit d36a63a

File tree

1 file changed

+12
-1
lines changed

1 file changed

+12
-1
lines changed

mm/slub.c

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -249,7 +249,18 @@ static inline void *freelist_ptr(const struct kmem_cache *s, void *ptr,
249249
unsigned long ptr_addr)
250250
{
251251
#ifdef CONFIG_SLAB_FREELIST_HARDENED
252-
return (void *)((unsigned long)ptr ^ s->random ^ ptr_addr);
252+
/*
253+
* When CONFIG_KASAN_SW_TAGS is enabled, ptr_addr might be tagged.
254+
* Normally, this doesn't cause any issues, as both set_freepointer()
255+
* and get_freepointer() are called with a pointer with the same tag.
256+
* However, there are some issues with CONFIG_SLUB_DEBUG code. For
257+
* example, when __free_slub() iterates over objects in a cache, it
258+
* passes untagged pointers to check_object(). check_object() in turns
259+
* calls get_freepointer() with an untagged pointer, which causes the
260+
* freepointer to be restored incorrectly.
261+
*/
262+
return (void *)((unsigned long)ptr ^ s->random ^
263+
(unsigned long)kasan_reset_tag((void *)ptr_addr));
253264
#else
254265
return ptr;
255266
#endif

0 commit comments

Comments
 (0)