Message ID | bf858f26ef32eb7bd24c665755b3aee4bc58d0e4.1550103861.git.andreyknvl@google.com (mailing list archive) |
---|---|
State | New, archived |
Headers | show |
Series | kasan, slub: fix more conflicts with CONFIG_SLAB_FREELIST_HARDENED | expand |
On Thu, Feb 14, 2019 at 1:25 AM Andrey Konovalov <andreyknvl@google.com> wrote: > > 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@google.com> Reported-by: Qian Cai <cai@lca.pw> > --- > 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 >
On 2/13/19 7:27 PM, Andrey Konovalov wrote: > On Thu, Feb 14, 2019 at 1:25 AM Andrey Konovalov <andreyknvl@google.com> wrote: >> >> 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@google.com> > > Reported-by: Qian Cai <cai@lca.pw> Tested-by: Qian Cai <cai@lca.pw>
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
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@google.com> --- mm/slub.c | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-)