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

From: Robin Murphy
Date: Mon Aug 19 2019 - 10:35:22 EST


On 19/08/2019 15:22, Will Deacon wrote:
On Mon, Aug 19, 2019 at 04:05:22PM +0200, Andrey Konovalov wrote:
On Mon, Aug 19, 2019 at 3:34 PM Will Deacon <will@xxxxxxxxxx> 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?

If we end up having to check the KASAN shadow for *_to_virt(), then why
do we need to store anything in the page flags at all? Andrey?

As per 2813b9c0 ("kasan, mm, arm64: tag non slab memory allocated via
pagealloc") we should only save a non-0xff tag in page flags for non
slab pages.

Thanks, that makes sense. Hopefully the patch from Andrey R will solve
both of the reported splats, since I'd not realised they were both on the
kfree() path.

Could you share your .config so I can reproduce this?

This is in the iopgtable code, so it's probably pretty tricky to trigger
at runtime unless you have the write IOMMU hardware, unfortunately.

If simply freeing any entry from the l2_tables cache is sufficient, then the short-descriptor selftest should do the job, and that ought to run on anything (modulo insane RAM layouts).

Robin.