diff mbox series

[v8,30/43] arm64: kasan: Allow enabling in-kernel MTE

Message ID 5e3c76cac4b161fe39e3fc8ace614400bc2fb5b1.1604531793.git.andreyknvl@google.com (mailing list archive)
State New, archived
Headers show
Series kasan: add hardware tag-based mode for arm64 | expand

Commit Message

Andrey Konovalov Nov. 4, 2020, 11:18 p.m. UTC
Hardware tag-based KASAN relies on Memory Tagging Extension (MTE)
feature and requires it to be enabled. MTE supports

This patch adds a new mte_init_tags() helper, that enables MTE in
Synchronous mode in EL1 and is intended to be called from KASAN runtime
during initialization.

The Tag Checking operation causes a synchronous data abort as
a consequence of a tag check fault when MTE is configured in
synchronous mode.

As part of this change enable match-all tag for EL1 to allow the
kernel to access user pages without faulting. This is required because
the kernel does not have knowledge of the tags set by the user in a
page.

Note: For MTE, the TCF bit field in SCTLR_EL1 affects only EL1 in a
similar way as TCF0 affects EL0.

MTE that is built on top of the Top Byte Ignore (TBI) feature hence we
enable it as part of this patch as well.

Signed-off-by: Vincenzo Frascino <vincenzo.frascino@arm.com>
Co-developed-by: Andrey Konovalov <andreyknvl@google.com>
Signed-off-by: Andrey Konovalov <andreyknvl@google.com>
---
Change-Id: I4d67497268bb7f0c2fc5dcacefa1e273df4af71d
---
 arch/arm64/include/asm/mte-kasan.h |  6 ++++++
 arch/arm64/kernel/mte.c            |  7 +++++++
 arch/arm64/mm/proc.S               | 23 ++++++++++++++++++++---
 3 files changed, 33 insertions(+), 3 deletions(-)

Comments

Vincenzo Frascino Nov. 5, 2020, 11:16 a.m. UTC | #1
Hi Andrey,

On 11/4/20 11:18 PM, Andrey Konovalov wrote:
> Hardware tag-based KASAN relies on Memory Tagging Extension (MTE)
> feature and requires it to be enabled. MTE supports
> 
> This patch adds a new mte_init_tags() helper, that enables MTE in
> Synchronous mode in EL1 and is intended to be called from KASAN runtime
> during initialization.
> 
> The Tag Checking operation causes a synchronous data abort as
> a consequence of a tag check fault when MTE is configured in
> synchronous mode.
> 
> As part of this change enable match-all tag for EL1 to allow the
> kernel to access user pages without faulting. This is required because
> the kernel does not have knowledge of the tags set by the user in a
> page.
> 
> Note: For MTE, the TCF bit field in SCTLR_EL1 affects only EL1 in a
> similar way as TCF0 affects EL0.
> 
> MTE that is built on top of the Top Byte Ignore (TBI) feature hence we
> enable it as part of this patch as well.
> 

seems that in this patch you dropped me as author. Would you mind to clarify the
reason?

> Signed-off-by: Vincenzo Frascino <vincenzo.frascino@arm.com>
> Co-developed-by: Andrey Konovalov <andreyknvl@google.com>
> Signed-off-by: Andrey Konovalov <andreyknvl@google.com>
> ---
> Change-Id: I4d67497268bb7f0c2fc5dcacefa1e273df4af71d
> ---
>  arch/arm64/include/asm/mte-kasan.h |  6 ++++++
>  arch/arm64/kernel/mte.c            |  7 +++++++
>  arch/arm64/mm/proc.S               | 23 ++++++++++++++++++++---
>  3 files changed, 33 insertions(+), 3 deletions(-)
> 
> diff --git a/arch/arm64/include/asm/mte-kasan.h b/arch/arm64/include/asm/mte-kasan.h
> index 3a70fb1807fd..ae75feaea2d4 100644
> --- a/arch/arm64/include/asm/mte-kasan.h
> +++ b/arch/arm64/include/asm/mte-kasan.h
> @@ -29,6 +29,8 @@ u8 mte_get_mem_tag(void *addr);
>  u8 mte_get_random_tag(void);
>  void *mte_set_mem_tag_range(void *addr, size_t size, u8 tag);
>  
> +void __init mte_init_tags(u64 max_tag);
> +
>  #else /* CONFIG_ARM64_MTE */
>  
>  static inline u8 mte_get_ptr_tag(void *ptr)
> @@ -49,6 +51,10 @@ static inline void *mte_set_mem_tag_range(void *addr, size_t size, u8 tag)
>  	return addr;
>  }
>  
> +static inline void mte_init_tags(u64 max_tag)
> +{
> +}
> +
>  #endif /* CONFIG_ARM64_MTE */
>  
>  #endif /* __ASSEMBLY__ */
> diff --git a/arch/arm64/kernel/mte.c b/arch/arm64/kernel/mte.c
> index 06ba6c923ab7..fcfbefcc3174 100644
> --- a/arch/arm64/kernel/mte.c
> +++ b/arch/arm64/kernel/mte.c
> @@ -121,6 +121,13 @@ void *mte_set_mem_tag_range(void *addr, size_t size, u8 tag)
>  	return ptr;
>  }
>  
> +void __init mte_init_tags(u64 max_tag)
> +{
> +	/* Enable MTE Sync Mode for EL1. */
> +	sysreg_clear_set(sctlr_el1, SCTLR_ELx_TCF_MASK, SCTLR_ELx_TCF_SYNC);
> +	isb();

I am fine with the approach of letting cpu_enable_mte() call directly
kasan_init_tags(), but how does it work of the other 2 implementation of KASAN?
Is it still called in arch_setup()?

I would prefer to keep the code that initializes the sync mode in
cpu_enable_mte() (calling kasan_init_tags() before then that) or in a separate
function since setting the mode has nothing to do with initializing the tags.
The second approach probably would come handy when we introduce async mode.

> +}
> +
>  static void update_sctlr_el1_tcf0(u64 tcf0)
>  {
>  	/* ISB required for the kernel uaccess routines */
> diff --git a/arch/arm64/mm/proc.S b/arch/arm64/mm/proc.S
> index 23c326a06b2d..7c3304fb15d9 100644
> --- a/arch/arm64/mm/proc.S
> +++ b/arch/arm64/mm/proc.S
> @@ -40,9 +40,15 @@
>  #define TCR_CACHE_FLAGS	TCR_IRGN_WBWA | TCR_ORGN_WBWA
>  
>  #ifdef CONFIG_KASAN_SW_TAGS
> -#define TCR_KASAN_FLAGS TCR_TBI1
> +#define TCR_KASAN_SW_FLAGS TCR_TBI1
>  #else
> -#define TCR_KASAN_FLAGS 0
> +#define TCR_KASAN_SW_FLAGS 0
> +#endif
> +
> +#ifdef CONFIG_KASAN_HW_TAGS
> +#define TCR_KASAN_HW_FLAGS SYS_TCR_EL1_TCMA1 | TCR_TBI1
> +#else
> +#define TCR_KASAN_HW_FLAGS 0
>  #endif
>  
>  /*
> @@ -427,6 +433,10 @@ SYM_FUNC_START(__cpu_setup)
>  	 */
>  	mov_q	x5, MAIR_EL1_SET
>  #ifdef CONFIG_ARM64_MTE
> +	mte_tcr	.req	x20
> +
> +	mov	mte_tcr, #0
> +
>  	/*
>  	 * Update MAIR_EL1, GCR_EL1 and TFSR*_EL1 if MTE is supported
>  	 * (ID_AA64PFR1_EL1[11:8] > 1).
> @@ -447,6 +457,9 @@ SYM_FUNC_START(__cpu_setup)
>  	/* clear any pending tag check faults in TFSR*_EL1 */
>  	msr_s	SYS_TFSR_EL1, xzr
>  	msr_s	SYS_TFSRE0_EL1, xzr
> +
> +	/* set the TCR_EL1 bits */
> +	mov_q	mte_tcr, TCR_KASAN_HW_FLAGS
>  1:
>  #endif
>  	msr	mair_el1, x5
> @@ -456,7 +469,11 @@ SYM_FUNC_START(__cpu_setup)
>  	 */
>  	mov_q	x10, TCR_TxSZ(VA_BITS) | TCR_CACHE_FLAGS | TCR_SMP_FLAGS | \
>  			TCR_TG_FLAGS | TCR_KASLR_FLAGS | TCR_ASID16 | \
> -			TCR_TBI0 | TCR_A1 | TCR_KASAN_FLAGS
> +			TCR_TBI0 | TCR_A1 | TCR_KASAN_SW_FLAGS
> +#ifdef CONFIG_ARM64_MTE
> +	orr	x10, x10, mte_tcr
> +	.unreq	mte_tcr
> +#endif
>  	tcr_clear_errata_bits x10, x9, x5
>  
>  #ifdef CONFIG_ARM64_VA_BITS_52
>
Andrey Konovalov Nov. 5, 2020, 11:35 a.m. UTC | #2
On Thu, Nov 5, 2020 at 12:13 PM Vincenzo Frascino
<vincenzo.frascino@arm.com> wrote:
>
> Hi Andrey,
>
> On 11/4/20 11:18 PM, Andrey Konovalov wrote:
> > Hardware tag-based KASAN relies on Memory Tagging Extension (MTE)
> > feature and requires it to be enabled. MTE supports
> >
> > This patch adds a new mte_init_tags() helper, that enables MTE in
> > Synchronous mode in EL1 and is intended to be called from KASAN runtime
> > during initialization.
> >
> > The Tag Checking operation causes a synchronous data abort as
> > a consequence of a tag check fault when MTE is configured in
> > synchronous mode.
> >
> > As part of this change enable match-all tag for EL1 to allow the
> > kernel to access user pages without faulting. This is required because
> > the kernel does not have knowledge of the tags set by the user in a
> > page.
> >
> > Note: For MTE, the TCF bit field in SCTLR_EL1 affects only EL1 in a
> > similar way as TCF0 affects EL0.
> >
> > MTE that is built on top of the Top Byte Ignore (TBI) feature hence we
> > enable it as part of this patch as well.
> >
>
> seems that in this patch you dropped me as author. Would you mind to clarify the
> reason?

Sorry, a mistake while squashing/rebasing, will fix in the next version.

>
> > Signed-off-by: Vincenzo Frascino <vincenzo.frascino@arm.com>
> > Co-developed-by: Andrey Konovalov <andreyknvl@google.com>
> > Signed-off-by: Andrey Konovalov <andreyknvl@google.com>
> > ---
> > Change-Id: I4d67497268bb7f0c2fc5dcacefa1e273df4af71d
> > ---
> >  arch/arm64/include/asm/mte-kasan.h |  6 ++++++
> >  arch/arm64/kernel/mte.c            |  7 +++++++
> >  arch/arm64/mm/proc.S               | 23 ++++++++++++++++++++---
> >  3 files changed, 33 insertions(+), 3 deletions(-)
> >
> > diff --git a/arch/arm64/include/asm/mte-kasan.h b/arch/arm64/include/asm/mte-kasan.h
> > index 3a70fb1807fd..ae75feaea2d4 100644
> > --- a/arch/arm64/include/asm/mte-kasan.h
> > +++ b/arch/arm64/include/asm/mte-kasan.h
> > @@ -29,6 +29,8 @@ u8 mte_get_mem_tag(void *addr);
> >  u8 mte_get_random_tag(void);
> >  void *mte_set_mem_tag_range(void *addr, size_t size, u8 tag);
> >
> > +void __init mte_init_tags(u64 max_tag);
> > +
> >  #else /* CONFIG_ARM64_MTE */
> >
> >  static inline u8 mte_get_ptr_tag(void *ptr)
> > @@ -49,6 +51,10 @@ static inline void *mte_set_mem_tag_range(void *addr, size_t size, u8 tag)
> >       return addr;
> >  }
> >
> > +static inline void mte_init_tags(u64 max_tag)
> > +{
> > +}
> > +
> >  #endif /* CONFIG_ARM64_MTE */
> >
> >  #endif /* __ASSEMBLY__ */
> > diff --git a/arch/arm64/kernel/mte.c b/arch/arm64/kernel/mte.c
> > index 06ba6c923ab7..fcfbefcc3174 100644
> > --- a/arch/arm64/kernel/mte.c
> > +++ b/arch/arm64/kernel/mte.c
> > @@ -121,6 +121,13 @@ void *mte_set_mem_tag_range(void *addr, size_t size, u8 tag)
> >       return ptr;
> >  }
> >
> > +void __init mte_init_tags(u64 max_tag)
> > +{
> > +     /* Enable MTE Sync Mode for EL1. */
> > +     sysreg_clear_set(sctlr_el1, SCTLR_ELx_TCF_MASK, SCTLR_ELx_TCF_SYNC);
> > +     isb();
>
> I am fine with the approach of letting cpu_enable_mte() call directly
> kasan_init_tags(), but how does it work of the other 2 implementation of KASAN?
> Is it still called in arch_setup()?

Yes, the other 2 modes are initialized in setup_arch().

> I would prefer to keep the code that initializes the sync mode in
> cpu_enable_mte() (calling kasan_init_tags() before then that)

This won't work, we'll later need to make the decision about whether
to turn on MTE at all in KASAN runtime based on KASAN boot flags.

> or in a separate
> function since setting the mode has nothing to do with initializing the tags.

This will work. Any preference on the name of this function?

Alternatively we can rename mte_init_tags() to something else and let
it handle both RRND and sync/async.

Thanks!
Vincenzo Frascino Nov. 5, 2020, 11:42 a.m. UTC | #3
On 11/5/20 11:35 AM, Andrey Konovalov wrote:
> This will work. Any preference on the name of this function?
>

I called it in my current iteration mte_enable(), and calling it from
cpu_enable_mte().

> Alternatively we can rename mte_init_tags() to something else and let
> it handle both RRND and sync/async.

This is an option but then you need to change the name of kasan_init_tags and
the init_tags indirection name as well. I would go for the simpler and just
splitting the function as per above.

What do you think?
Andrey Konovalov Nov. 5, 2020, 12:14 p.m. UTC | #4
On Thu, Nov 5, 2020 at 12:39 PM Vincenzo Frascino
<vincenzo.frascino@arm.com> wrote:
>
> On 11/5/20 11:35 AM, Andrey Konovalov wrote:
> > This will work. Any preference on the name of this function?
> >
>
> I called it in my current iteration mte_enable(), and calling it from
> cpu_enable_mte().
>
> > Alternatively we can rename mte_init_tags() to something else and let
> > it handle both RRND and sync/async.
>
> This is an option but then you need to change the name of kasan_init_tags and
> the init_tags indirection name as well. I would go for the simpler and just
> splitting the function as per above.
>
> What do you think?

OK, let's split. mte_enable() as a name sounds good to me. Both
functions will still be called one right after another from
kasan_init_hw_tags (as it's now called) though. I think the name
works, as it means initializing the hw_tags mode, not just the tags.

Will do in v9.
Vincenzo Frascino Nov. 5, 2020, 2:17 p.m. UTC | #5
On 11/5/20 12:14 PM, Andrey Konovalov wrote:
> On Thu, Nov 5, 2020 at 12:39 PM Vincenzo Frascino
> <vincenzo.frascino@arm.com> wrote:
>>
>> On 11/5/20 11:35 AM, Andrey Konovalov wrote:
>>> This will work. Any preference on the name of this function?
>>>
>>
>> I called it in my current iteration mte_enable(), and calling it from
>> cpu_enable_mte().
>>
>>> Alternatively we can rename mte_init_tags() to something else and let
>>> it handle both RRND and sync/async.
>>
>> This is an option but then you need to change the name of kasan_init_tags and
>> the init_tags indirection name as well. I would go for the simpler and just
>> splitting the function as per above.
>>
>> What do you think?
> 
> OK, let's split. mte_enable() as a name sounds good to me. Both
> functions will still be called one right after another from
> kasan_init_hw_tags (as it's now called) though. I think the name
> works, as it means initializing the hw_tags mode, not just the tags.
> 

I agree. When you finish with v9, could you please provide a tree with both the
sets on top similar to [1]? I would like to repeat the tests (ltp + kselftests)
and even to rebase my async code on top of it since we are aligning with the
development.

[1] https://github.com/xairy/linux/tree/up-boot-mte-v1

> Will do in v9.
>
Catalin Marinas Nov. 5, 2020, 5:25 p.m. UTC | #6
On Thu, Nov 05, 2020 at 12:18:45AM +0100, Andrey Konovalov wrote:
> diff --git a/arch/arm64/kernel/mte.c b/arch/arm64/kernel/mte.c
> index 06ba6c923ab7..fcfbefcc3174 100644
> --- a/arch/arm64/kernel/mte.c
> +++ b/arch/arm64/kernel/mte.c
> @@ -121,6 +121,13 @@ void *mte_set_mem_tag_range(void *addr, size_t size, u8 tag)
>  	return ptr;
>  }
>  
> +void __init mte_init_tags(u64 max_tag)
> +{
> +	/* Enable MTE Sync Mode for EL1. */
> +	sysreg_clear_set(sctlr_el1, SCTLR_ELx_TCF_MASK, SCTLR_ELx_TCF_SYNC);
> +	isb();
> +}

Is this going to be called on each CPU? I quickly went through the rest
of the patches and couldn't see how.
Andrey Konovalov Nov. 5, 2020, 5:27 p.m. UTC | #7
On Thu, Nov 5, 2020 at 3:14 PM Vincenzo Frascino
<vincenzo.frascino@arm.com> wrote:
>
>
>
> On 11/5/20 12:14 PM, Andrey Konovalov wrote:
> > On Thu, Nov 5, 2020 at 12:39 PM Vincenzo Frascino
> > <vincenzo.frascino@arm.com> wrote:
> >>
> >> On 11/5/20 11:35 AM, Andrey Konovalov wrote:
> >>> This will work. Any preference on the name of this function?
> >>>
> >>
> >> I called it in my current iteration mte_enable(), and calling it from
> >> cpu_enable_mte().
> >>
> >>> Alternatively we can rename mte_init_tags() to something else and let
> >>> it handle both RRND and sync/async.
> >>
> >> This is an option but then you need to change the name of kasan_init_tags and
> >> the init_tags indirection name as well. I would go for the simpler and just
> >> splitting the function as per above.
> >>
> >> What do you think?
> >
> > OK, let's split. mte_enable() as a name sounds good to me. Both
> > functions will still be called one right after another from
> > kasan_init_hw_tags (as it's now called) though. I think the name
> > works, as it means initializing the hw_tags mode, not just the tags.
> >
>
> I agree. When you finish with v9, could you please provide a tree with both the
> sets on top similar to [1]? I would like to repeat the tests (ltp + kselftests)
> and even to rebase my async code on top of it since we are aligning with the
> development.
>
> [1] https://github.com/xairy/linux/tree/up-boot-mte-v1

Sure, will share the trees, probably later today.
Andrey Konovalov Nov. 5, 2020, 5:29 p.m. UTC | #8
On Thu, Nov 5, 2020 at 6:26 PM Catalin Marinas <catalin.marinas@arm.com> wrote:
>
> On Thu, Nov 05, 2020 at 12:18:45AM +0100, Andrey Konovalov wrote:
> > diff --git a/arch/arm64/kernel/mte.c b/arch/arm64/kernel/mte.c
> > index 06ba6c923ab7..fcfbefcc3174 100644
> > --- a/arch/arm64/kernel/mte.c
> > +++ b/arch/arm64/kernel/mte.c
> > @@ -121,6 +121,13 @@ void *mte_set_mem_tag_range(void *addr, size_t size, u8 tag)
> >       return ptr;
> >  }
> >
> > +void __init mte_init_tags(u64 max_tag)
> > +{
> > +     /* Enable MTE Sync Mode for EL1. */
> > +     sysreg_clear_set(sctlr_el1, SCTLR_ELx_TCF_MASK, SCTLR_ELx_TCF_SYNC);
> > +     isb();
> > +}
>
> Is this going to be called on each CPU? I quickly went through the rest
> of the patches and couldn't see how.

Yes, on each CPU. This is done via kasan_init_hw_tags() that is called
from cpu_enable_mte(). This change is added in the "kasan, arm64:
implement HW_TAGS runtime". Would it make sense to put it into a
separate patch?
Catalin Marinas Nov. 5, 2020, 5:39 p.m. UTC | #9
On Thu, Nov 05, 2020 at 06:29:17PM +0100, Andrey Konovalov wrote:
> On Thu, Nov 5, 2020 at 6:26 PM Catalin Marinas <catalin.marinas@arm.com> wrote:
> >
> > On Thu, Nov 05, 2020 at 12:18:45AM +0100, Andrey Konovalov wrote:
> > > diff --git a/arch/arm64/kernel/mte.c b/arch/arm64/kernel/mte.c
> > > index 06ba6c923ab7..fcfbefcc3174 100644
> > > --- a/arch/arm64/kernel/mte.c
> > > +++ b/arch/arm64/kernel/mte.c
> > > @@ -121,6 +121,13 @@ void *mte_set_mem_tag_range(void *addr, size_t size, u8 tag)
> > >       return ptr;
> > >  }
> > >
> > > +void __init mte_init_tags(u64 max_tag)
> > > +{
> > > +     /* Enable MTE Sync Mode for EL1. */
> > > +     sysreg_clear_set(sctlr_el1, SCTLR_ELx_TCF_MASK, SCTLR_ELx_TCF_SYNC);
> > > +     isb();
> > > +}
> >
> > Is this going to be called on each CPU? I quickly went through the rest
> > of the patches and couldn't see how.
> 
> Yes, on each CPU. This is done via kasan_init_hw_tags() that is called
> from cpu_enable_mte(). This change is added in the "kasan, arm64:
> implement HW_TAGS runtime".

Ah, I got there eventually in patch 38. Too many indirections ;) (I'm
sure we could have trimmed them down a bit, hw_init_tags ==
arch_init_tags == mte_init_tags).

> Would it make sense to put it into a separate patch?

I think that's fine. I had the impression that kasan_init_hw_tags()
should only be called once.
Andrey Konovalov Nov. 5, 2020, 6:09 p.m. UTC | #10
On Thu, Nov 5, 2020 at 6:39 PM Catalin Marinas <catalin.marinas@arm.com> wrote:
>
> On Thu, Nov 05, 2020 at 06:29:17PM +0100, Andrey Konovalov wrote:
> > On Thu, Nov 5, 2020 at 6:26 PM Catalin Marinas <catalin.marinas@arm.com> wrote:
> > >
> > > On Thu, Nov 05, 2020 at 12:18:45AM +0100, Andrey Konovalov wrote:
> > > > diff --git a/arch/arm64/kernel/mte.c b/arch/arm64/kernel/mte.c
> > > > index 06ba6c923ab7..fcfbefcc3174 100644
> > > > --- a/arch/arm64/kernel/mte.c
> > > > +++ b/arch/arm64/kernel/mte.c
> > > > @@ -121,6 +121,13 @@ void *mte_set_mem_tag_range(void *addr, size_t size, u8 tag)
> > > >       return ptr;
> > > >  }
> > > >
> > > > +void __init mte_init_tags(u64 max_tag)
> > > > +{
> > > > +     /* Enable MTE Sync Mode for EL1. */
> > > > +     sysreg_clear_set(sctlr_el1, SCTLR_ELx_TCF_MASK, SCTLR_ELx_TCF_SYNC);
> > > > +     isb();
> > > > +}
> > >
> > > Is this going to be called on each CPU? I quickly went through the rest
> > > of the patches and couldn't see how.
> >
> > Yes, on each CPU. This is done via kasan_init_hw_tags() that is called
> > from cpu_enable_mte(). This change is added in the "kasan, arm64:
> > implement HW_TAGS runtime".
>
> Ah, I got there eventually in patch 38. Too many indirections ;) (I'm
> sure we could have trimmed them down a bit, hw_init_tags ==
> arch_init_tags == mte_init_tags).

The idea with these indirections was to make hw_tags.c to not directly
call MTE stuff and abstract away the underlying memory tagging
implementation. We won't know for sure how fitting these abstractions
are before we add another memory tagging implementation though :)

> > Would it make sense to put it into a separate patch?
>
> I think that's fine. I had the impression that kasan_init_hw_tags()
> should only be called once.

This was the case before, but not anymore. I've also added a comment
before the kasan_init_hw_tags() definition.
Vincenzo Frascino Nov. 6, 2020, 11:11 a.m. UTC | #11
Hi Catalin,

On 11/5/20 6:09 PM, Andrey Konovalov wrote:
>> Ah, I got there eventually in patch 38. Too many indirections ;) (I'm
>> sure we could have trimmed them down a bit, hw_init_tags ==
>> arch_init_tags == mte_init_tags).
> The idea with these indirections was to make hw_tags.c to not directly
> call MTE stuff and abstract away the underlying memory tagging
> implementation. We won't know for sure how fitting these abstractions
> are before we add another memory tagging implementation though :)
> 

I agree with Andrey, because in future the sparc architecture might want to
support HW KASAN hence keeping a generic infrastructure adds some value.
diff mbox series

Patch

diff --git a/arch/arm64/include/asm/mte-kasan.h b/arch/arm64/include/asm/mte-kasan.h
index 3a70fb1807fd..ae75feaea2d4 100644
--- a/arch/arm64/include/asm/mte-kasan.h
+++ b/arch/arm64/include/asm/mte-kasan.h
@@ -29,6 +29,8 @@  u8 mte_get_mem_tag(void *addr);
 u8 mte_get_random_tag(void);
 void *mte_set_mem_tag_range(void *addr, size_t size, u8 tag);
 
+void __init mte_init_tags(u64 max_tag);
+
 #else /* CONFIG_ARM64_MTE */
 
 static inline u8 mte_get_ptr_tag(void *ptr)
@@ -49,6 +51,10 @@  static inline void *mte_set_mem_tag_range(void *addr, size_t size, u8 tag)
 	return addr;
 }
 
+static inline void mte_init_tags(u64 max_tag)
+{
+}
+
 #endif /* CONFIG_ARM64_MTE */
 
 #endif /* __ASSEMBLY__ */
diff --git a/arch/arm64/kernel/mte.c b/arch/arm64/kernel/mte.c
index 06ba6c923ab7..fcfbefcc3174 100644
--- a/arch/arm64/kernel/mte.c
+++ b/arch/arm64/kernel/mte.c
@@ -121,6 +121,13 @@  void *mte_set_mem_tag_range(void *addr, size_t size, u8 tag)
 	return ptr;
 }
 
+void __init mte_init_tags(u64 max_tag)
+{
+	/* Enable MTE Sync Mode for EL1. */
+	sysreg_clear_set(sctlr_el1, SCTLR_ELx_TCF_MASK, SCTLR_ELx_TCF_SYNC);
+	isb();
+}
+
 static void update_sctlr_el1_tcf0(u64 tcf0)
 {
 	/* ISB required for the kernel uaccess routines */
diff --git a/arch/arm64/mm/proc.S b/arch/arm64/mm/proc.S
index 23c326a06b2d..7c3304fb15d9 100644
--- a/arch/arm64/mm/proc.S
+++ b/arch/arm64/mm/proc.S
@@ -40,9 +40,15 @@ 
 #define TCR_CACHE_FLAGS	TCR_IRGN_WBWA | TCR_ORGN_WBWA
 
 #ifdef CONFIG_KASAN_SW_TAGS
-#define TCR_KASAN_FLAGS TCR_TBI1
+#define TCR_KASAN_SW_FLAGS TCR_TBI1
 #else
-#define TCR_KASAN_FLAGS 0
+#define TCR_KASAN_SW_FLAGS 0
+#endif
+
+#ifdef CONFIG_KASAN_HW_TAGS
+#define TCR_KASAN_HW_FLAGS SYS_TCR_EL1_TCMA1 | TCR_TBI1
+#else
+#define TCR_KASAN_HW_FLAGS 0
 #endif
 
 /*
@@ -427,6 +433,10 @@  SYM_FUNC_START(__cpu_setup)
 	 */
 	mov_q	x5, MAIR_EL1_SET
 #ifdef CONFIG_ARM64_MTE
+	mte_tcr	.req	x20
+
+	mov	mte_tcr, #0
+
 	/*
 	 * Update MAIR_EL1, GCR_EL1 and TFSR*_EL1 if MTE is supported
 	 * (ID_AA64PFR1_EL1[11:8] > 1).
@@ -447,6 +457,9 @@  SYM_FUNC_START(__cpu_setup)
 	/* clear any pending tag check faults in TFSR*_EL1 */
 	msr_s	SYS_TFSR_EL1, xzr
 	msr_s	SYS_TFSRE0_EL1, xzr
+
+	/* set the TCR_EL1 bits */
+	mov_q	mte_tcr, TCR_KASAN_HW_FLAGS
 1:
 #endif
 	msr	mair_el1, x5
@@ -456,7 +469,11 @@  SYM_FUNC_START(__cpu_setup)
 	 */
 	mov_q	x10, TCR_TxSZ(VA_BITS) | TCR_CACHE_FLAGS | TCR_SMP_FLAGS | \
 			TCR_TG_FLAGS | TCR_KASLR_FLAGS | TCR_ASID16 | \
-			TCR_TBI0 | TCR_A1 | TCR_KASAN_FLAGS
+			TCR_TBI0 | TCR_A1 | TCR_KASAN_SW_FLAGS
+#ifdef CONFIG_ARM64_MTE
+	orr	x10, x10, mte_tcr
+	.unreq	mte_tcr
+#endif
 	tcr_clear_errata_bits x10, x9, x5
 
 #ifdef CONFIG_ARM64_VA_BITS_52