On Mon, Aug 19, 2019 at 7:26 PM Andrey Ryabinin <aryabinin@xxxxxxxxxxxxx> wrote: > > The code like this: > > ptr = kmalloc(size, GFP_KERNEL); > page = virt_to_page(ptr); > offset = offset_in_page(ptr); > kfree(page_address(page) + offset); > > may produce false-positive invalid-free reports on the kernel with > CONFIG_KASAN_SW_TAGS=y. > > In the example above we loose the original tag assigned to 'ptr', > so kfree() gets the pointer with 0xFF tag. In kfree() we check that > 0xFF tag is different from the tag in shadow hence print false report. > > Instead of just comparing tags, do the following: > 1) Check that shadow doesn't contain KASAN_TAG_INVALID. Otherwise it's > double-free and it doesn't matter what tag the pointer have. > > 2) If pointer tag is different from 0xFF, make sure that tag in the shadow > is the same as in the pointer. > > Fixes: 7f94ffbc4c6a ("kasan: add hooks implementation for tag-based mode") > Signed-off-by: Andrey Ryabinin <aryabinin@xxxxxxxxxxxxx> > Reported-by: Walter Wu <walter-zh.wu@xxxxxxxxxxxx> > Reported-by: Mark Rutland <mark.rutland@xxxxxxx> > Cc: <stable@xxxxxxxxxxxxxxx> Reviewed-by: Andrey Konovalov <andreyknvl@xxxxxxxxxx> > --- > mm/kasan/common.c | 10 ++++++++-- > 1 file changed, 8 insertions(+), 2 deletions(-) > > diff --git a/mm/kasan/common.c b/mm/kasan/common.c > index 895dc5e2b3d5..3b8cde0cb5b2 100644 > --- a/mm/kasan/common.c > +++ b/mm/kasan/common.c > @@ -406,8 +406,14 @@ static inline bool shadow_invalid(u8 tag, s8 shadow_byte) > if (IS_ENABLED(CONFIG_KASAN_GENERIC)) > return shadow_byte < 0 || > shadow_byte >= KASAN_SHADOW_SCALE_SIZE; > - else > - return tag != (u8)shadow_byte; > + > + /* else CONFIG_KASAN_SW_TAGS: */ > + if ((u8)shadow_byte == KASAN_TAG_INVALID) > + return true; > + if ((tag != KASAN_TAG_KERNEL) && (tag != (u8)shadow_byte)) > + return true; > + > + return false; > } > > static bool __kasan_slab_free(struct kmem_cache *cache, void *object, > -- > 2.21.0 >