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>
This commit is contained in:
Родитель
18e5066102
Коммит
d36a63a943
13
mm/slub.c
13
mm/slub.c
|
@ -249,7 +249,18 @@ static inline void *freelist_ptr(const struct kmem_cache *s, void *ptr,
|
|||
unsigned long ptr_addr)
|
||||
{
|
||||
#ifdef CONFIG_SLAB_FREELIST_HARDENED
|
||||
return (void *)((unsigned long)ptr ^ s->random ^ ptr_addr);
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
return (void *)((unsigned long)ptr ^ s->random ^
|
||||
(unsigned long)kasan_reset_tag((void *)ptr_addr));
|
||||
#else
|
||||
return ptr;
|
||||
#endif
|
||||
|
|
Загрузка…
Ссылка в новой задаче