[PATCH] arm64: kasan: fix phys_to_virt() false positive on tag-based kasan

Andrey Ryabinin aryabinin at virtuozzo.com
Mon Aug 19 07:06:33 PDT 2019

On 8/19/19 4:34 PM, Will Deacon wrote:
> On Mon, Aug 19, 2019 at 02:23:48PM +0100, Mark Rutland wrote:
>> On Mon, Aug 19, 2019 at 01:56:26PM +0100, Will Deacon wrote:
>>> On Mon, Aug 19, 2019 at 07:44:20PM +0800, Walter Wu wrote:
>>>> __arm_v7s_unmap() call iopte_deref() to translate pyh_to_virt address,
>>>> but it will modify pointer tag into 0xff, so there is a false positive.
>>>> When enable tag-based kasan, phys_to_virt() function need to rewrite
>>>> its original pointer tag in order to avoid kasan report an incorrect
>>>> memory corruption.
>>> Hmm. Which tree did you see this on? We've recently queued a load of fixes
>>> in this area, but I /thought/ they were only needed after the support for
>>> 52-bit virtual addressing in the kernel.
>> I'm seeing similar issues in the virtio blk code (splat below), atop of
>> the arm64 for-next/core branch. I think this is a latent issue, and
>> people are only just starting to test with KASAN_SW_TAGS.
>> It looks like the virtio blk code will round-trip a SLUB-allocated pointer from
>> virt->page->virt, losing the per-object tag in the process.
>> Our page_to_virt() seems to get a per-page tag, but this only makes
>> sense if you're dealing with the page allocator, rather than something
>> like SLUB which carves a page into smaller objects giving each object a
>> distinct tag.
>> Any round-trip of a pointer from SLUB is going to lose the per-object
>> tag.
> Urgh, I wonder how this is supposed to work?

We supposed to ignore pointers with 0xff tags. We do ignore them when memory access checked,
but not in kfree() path.
This untested patch should fix the issue:

 mm/kasan/common.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/mm/kasan/common.c b/mm/kasan/common.c
index 895dc5e2b3d5..0a81cc328049 100644
--- a/mm/kasan/common.c
+++ b/mm/kasan/common.c
@@ -407,7 +407,7 @@ static inline bool shadow_invalid(u8 tag, s8 shadow_byte)
 		return shadow_byte < 0 ||
 			shadow_byte >= KASAN_SHADOW_SCALE_SIZE;
-		return tag != (u8)shadow_byte;
+		return (tag != KASAN_TAG_KERNEL) && (tag != (u8)shadow_byte);
 static bool __kasan_slab_free(struct kmem_cache *cache, void *object,

More information about the Linux-mediatek mailing list