[PATCH] kasan, slub: fix more conflicts with CONFIG_SLAB_FREELIST_HARDENED

From: Andrey Konovalov
Date: Wed Feb 13 2019 - 19:25:56 EST


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.

Signed-off-by: Andrey Konovalov <andreyknvl@xxxxxxxxxx>
---
mm/slub.c | 13 ++++++++++++-
1 file changed, 12 insertions(+), 1 deletion(-)

diff --git a/mm/slub.c b/mm/slub.c
index 80da3a40b74d..c80e6699357c 100644
--- a/mm/slub.c
+++ b/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
--
2.20.1.791.gb4d0f1c61a-goog