2022-06-08 01:17:59

by Vincenzo Frascino

[permalink] [raw]
Subject: [PATCH] mte: Initialize tag storage to KASAN_TAG_INVALID

When the kernel is entered on aarch64, the MTE allocation tags are in an
UNKNOWN state.

With MTE enabled, the tags are initialized:
- When a page is allocated and the user maps it with PROT_MTE.
- On allocation, with in-kernel MTE enabled (KHWASAN).

If the tag pool is zeroed by the hardware at reset, it makes it
difficult to track potential places where the initialization of the
tags was missed.

This can be observed under QEMU for aarch64, which initializes the MTE
allocation tags to zero.

Initialize to tag storage to KASAN_TAG_INVALID to catch potential
places where the initialization of the tags was missed.

This is done introducing a new kernel command line parameter
"mte.tags_init" that enables the debug option.

Note: The proposed solution should be considered a debug option because
it might have performance impact on large machines at boot.

Cc: Catalin Marinas <[email protected]>
Cc: Will Deacon <[email protected]>
Signed-off-by: Vincenzo Frascino <[email protected]>
---
arch/arm64/kernel/mte.c | 47 +++++++++++++++++++++++++++++++++++++++++
1 file changed, 47 insertions(+)

diff --git a/arch/arm64/kernel/mte.c b/arch/arm64/kernel/mte.c
index 57b30bcf9f21..259a826363f1 100644
--- a/arch/arm64/kernel/mte.c
+++ b/arch/arm64/kernel/mte.c
@@ -6,6 +6,7 @@
#include <linux/bitops.h>
#include <linux/cpu.h>
#include <linux/kernel.h>
+#include <linux/memblock.h>
#include <linux/mm.h>
#include <linux/prctl.h>
#include <linux/sched.h>
@@ -35,6 +36,8 @@ DEFINE_STATIC_KEY_FALSE(mte_async_or_asymm_mode);
EXPORT_SYMBOL_GPL(mte_async_or_asymm_mode);
#endif

+static bool mte_tags_init __ro_after_init;
+
static void mte_sync_page_tags(struct page *page, pte_t old_pte,
bool check_swap, bool pte_is_tagged)
{
@@ -107,6 +110,48 @@ int memcmp_pages(struct page *page1, struct page *page2)
return ret;
}

+/* mte.tags_init=off/on */
+static int __init early_mte_tags_init(char *arg)
+{
+ if (!arg)
+ return -EINVAL;
+
+ if (!strcmp(arg, "off"))
+ mte_tags_init = false;
+ else if (!strcmp(arg, "on"))
+ mte_tags_init = true;
+ else
+ return -EINVAL;
+
+ return 0;
+}
+early_param("mte.tags_init", early_mte_tags_init);
+
+static inline void __mte_tag_storage_init(void)
+{
+ static bool mte_tags_uninitialized = true;
+ phys_addr_t pa_start, pa_end;
+ u64 index;
+
+ if (mte_tags_init && !mte_tags_uninitialized)
+ return;
+
+ for_each_mem_range(index, &pa_start, &pa_end) {
+ void *va_start = (void *)__phys_to_virt(pa_start);
+ void *va_end = (void *)__phys_to_virt(pa_end);
+ size_t va_size = (u64)va_end - (u64)va_start;
+
+ if (va_start >= va_end)
+ break;
+
+ mte_set_mem_tag_range(va_start, va_size, KASAN_TAG_INVALID, false);
+ }
+
+ /* Tags are now initialized to KASAN_TAG_INVALID */
+ mte_tags_uninitialized = false;
+ pr_info("MTE: Tag Storage Initialized\n");
+}
+
static inline void __mte_enable_kernel(const char *mode, unsigned long tcf)
{
/* Enable MTE Sync Mode for EL1. */
@@ -114,6 +159,8 @@ static inline void __mte_enable_kernel(const char *mode, unsigned long tcf)
SYS_FIELD_PREP(SCTLR_EL1, TCF, tcf));
isb();

+ __mte_tag_storage_init();
+
pr_info_once("MTE: enabled in %s mode at EL1\n", mode);
}

--
2.36.1


2022-06-09 18:51:47

by Andrey Konovalov

[permalink] [raw]
Subject: Re: [PATCH] mte: Initialize tag storage to KASAN_TAG_INVALID

On Tue, Jun 7, 2022 at 1:32 PM Vincenzo Frascino
<[email protected]> wrote:
>
> When the kernel is entered on aarch64, the MTE allocation tags are in an
> UNKNOWN state.
>
> With MTE enabled, the tags are initialized:
> - When a page is allocated and the user maps it with PROT_MTE.
> - On allocation, with in-kernel MTE enabled (KHWASAN).

Hi Vincenzo,

I think we should move away from the KHWASAN name - it was used during
the early prototyping days for SW_TAGS KASAN. What you mean here is
HW_TAGS KASAN.

Thanks!


>
> If the tag pool is zeroed by the hardware at reset, it makes it
> difficult to track potential places where the initialization of the
> tags was missed.
>
> This can be observed under QEMU for aarch64, which initializes the MTE
> allocation tags to zero.
>
> Initialize to tag storage to KASAN_TAG_INVALID to catch potential
> places where the initialization of the tags was missed.
>
> This is done introducing a new kernel command line parameter
> "mte.tags_init" that enables the debug option.
>
> Note: The proposed solution should be considered a debug option because
> it might have performance impact on large machines at boot.
>
> Cc: Catalin Marinas <[email protected]>
> Cc: Will Deacon <[email protected]>
> Signed-off-by: Vincenzo Frascino <[email protected]>
> ---
> arch/arm64/kernel/mte.c | 47 +++++++++++++++++++++++++++++++++++++++++
> 1 file changed, 47 insertions(+)
>
> diff --git a/arch/arm64/kernel/mte.c b/arch/arm64/kernel/mte.c
> index 57b30bcf9f21..259a826363f1 100644
> --- a/arch/arm64/kernel/mte.c
> +++ b/arch/arm64/kernel/mte.c
> @@ -6,6 +6,7 @@
> #include <linux/bitops.h>
> #include <linux/cpu.h>
> #include <linux/kernel.h>
> +#include <linux/memblock.h>
> #include <linux/mm.h>
> #include <linux/prctl.h>
> #include <linux/sched.h>
> @@ -35,6 +36,8 @@ DEFINE_STATIC_KEY_FALSE(mte_async_or_asymm_mode);
> EXPORT_SYMBOL_GPL(mte_async_or_asymm_mode);
> #endif
>
> +static bool mte_tags_init __ro_after_init;
> +
> static void mte_sync_page_tags(struct page *page, pte_t old_pte,
> bool check_swap, bool pte_is_tagged)
> {
> @@ -107,6 +110,48 @@ int memcmp_pages(struct page *page1, struct page *page2)
> return ret;
> }
>
> +/* mte.tags_init=off/on */
> +static int __init early_mte_tags_init(char *arg)
> +{
> + if (!arg)
> + return -EINVAL;
> +
> + if (!strcmp(arg, "off"))
> + mte_tags_init = false;
> + else if (!strcmp(arg, "on"))
> + mte_tags_init = true;
> + else
> + return -EINVAL;
> +
> + return 0;
> +}
> +early_param("mte.tags_init", early_mte_tags_init);
> +
> +static inline void __mte_tag_storage_init(void)
> +{
> + static bool mte_tags_uninitialized = true;
> + phys_addr_t pa_start, pa_end;
> + u64 index;
> +
> + if (mte_tags_init && !mte_tags_uninitialized)
> + return;
> +
> + for_each_mem_range(index, &pa_start, &pa_end) {
> + void *va_start = (void *)__phys_to_virt(pa_start);
> + void *va_end = (void *)__phys_to_virt(pa_end);
> + size_t va_size = (u64)va_end - (u64)va_start;
> +
> + if (va_start >= va_end)
> + break;
> +
> + mte_set_mem_tag_range(va_start, va_size, KASAN_TAG_INVALID, false);
> + }
> +
> + /* Tags are now initialized to KASAN_TAG_INVALID */
> + mte_tags_uninitialized = false;
> + pr_info("MTE: Tag Storage Initialized\n");
> +}
> +
> static inline void __mte_enable_kernel(const char *mode, unsigned long tcf)
> {
> /* Enable MTE Sync Mode for EL1. */
> @@ -114,6 +159,8 @@ static inline void __mte_enable_kernel(const char *mode, unsigned long tcf)
> SYS_FIELD_PREP(SCTLR_EL1, TCF, tcf));
> isb();
>
> + __mte_tag_storage_init();
> +
> pr_info_once("MTE: enabled in %s mode at EL1\n", mode);
> }
>
> --
> 2.36.1
>
> --
> You received this message because you are subscribed to the Google Groups "kasan-dev" group.
> To unsubscribe from this group and stop receiving emails from it, send an email to [email protected].
> To view this discussion on the web visit https://groups.google.com/d/msgid/kasan-dev/20220607113150.55140-1-vincenzo.frascino%40arm.com.

2022-06-14 08:15:56

by Vincenzo Frascino

[permalink] [raw]
Subject: Re: [PATCH] mte: Initialize tag storage to KASAN_TAG_INVALID

Hy Andrey,

On 6/9/22 19:34, Andrey Konovalov wrote:
> On Tue, Jun 7, 2022 at 1:32 PM Vincenzo Frascino
> <[email protected]> wrote:
>>
>> When the kernel is entered on aarch64, the MTE allocation tags are in an
>> UNKNOWN state.
>>
>> With MTE enabled, the tags are initialized:
>> - When a page is allocated and the user maps it with PROT_MTE.
>> - On allocation, with in-kernel MTE enabled (KHWASAN).
>
> Hi Vincenzo,
>
> I think we should move away from the KHWASAN name - it was used during
> the early prototyping days for SW_TAGS KASAN. What you mean here is
> HW_TAGS KASAN.
>

You are right, I will fix this in v2. Before re-posting I will wait and see if
there are more comments.

> Thanks!
>
>
>>
>> If the tag pool is zeroed by the hardware at reset, it makes it
>> difficult to track potential places where the initialization of the
>> tags was missed.
>>
>> This can be observed under QEMU for aarch64, which initializes the MTE
>> allocation tags to zero.
>>
>> Initialize to tag storage to KASAN_TAG_INVALID to catch potential
>> places where the initialization of the tags was missed.
>>
>> This is done introducing a new kernel command line parameter
>> "mte.tags_init" that enables the debug option.
>>
>> Note: The proposed solution should be considered a debug option because
>> it might have performance impact on large machines at boot.
>>
>> Cc: Catalin Marinas <[email protected]>
>> Cc: Will Deacon <[email protected]>
>> Signed-off-by: Vincenzo Frascino <[email protected]>
>> ---
>> arch/arm64/kernel/mte.c | 47 +++++++++++++++++++++++++++++++++++++++++
>> 1 file changed, 47 insertions(+)
>>
>> diff --git a/arch/arm64/kernel/mte.c b/arch/arm64/kernel/mte.c
>> index 57b30bcf9f21..259a826363f1 100644
>> --- a/arch/arm64/kernel/mte.c
>> +++ b/arch/arm64/kernel/mte.c
>> @@ -6,6 +6,7 @@
>> #include <linux/bitops.h>
>> #include <linux/cpu.h>
>> #include <linux/kernel.h>
>> +#include <linux/memblock.h>
>> #include <linux/mm.h>
>> #include <linux/prctl.h>
>> #include <linux/sched.h>
>> @@ -35,6 +36,8 @@ DEFINE_STATIC_KEY_FALSE(mte_async_or_asymm_mode);
>> EXPORT_SYMBOL_GPL(mte_async_or_asymm_mode);
>> #endif
>>
>> +static bool mte_tags_init __ro_after_init;
>> +
>> static void mte_sync_page_tags(struct page *page, pte_t old_pte,
>> bool check_swap, bool pte_is_tagged)
>> {
>> @@ -107,6 +110,48 @@ int memcmp_pages(struct page *page1, struct page *page2)
>> return ret;
>> }
>>
>> +/* mte.tags_init=off/on */
>> +static int __init early_mte_tags_init(char *arg)
>> +{
>> + if (!arg)
>> + return -EINVAL;
>> +
>> + if (!strcmp(arg, "off"))
>> + mte_tags_init = false;
>> + else if (!strcmp(arg, "on"))
>> + mte_tags_init = true;
>> + else
>> + return -EINVAL;
>> +
>> + return 0;
>> +}
>> +early_param("mte.tags_init", early_mte_tags_init);
>> +
>> +static inline void __mte_tag_storage_init(void)
>> +{
>> + static bool mte_tags_uninitialized = true;
>> + phys_addr_t pa_start, pa_end;
>> + u64 index;
>> +
>> + if (mte_tags_init && !mte_tags_uninitialized)
>> + return;
>> +
>> + for_each_mem_range(index, &pa_start, &pa_end) {
>> + void *va_start = (void *)__phys_to_virt(pa_start);
>> + void *va_end = (void *)__phys_to_virt(pa_end);
>> + size_t va_size = (u64)va_end - (u64)va_start;
>> +
>> + if (va_start >= va_end)
>> + break;
>> +
>> + mte_set_mem_tag_range(va_start, va_size, KASAN_TAG_INVALID, false);
>> + }
>> +
>> + /* Tags are now initialized to KASAN_TAG_INVALID */
>> + mte_tags_uninitialized = false;
>> + pr_info("MTE: Tag Storage Initialized\n");
>> +}
>> +
>> static inline void __mte_enable_kernel(const char *mode, unsigned long tcf)
>> {
>> /* Enable MTE Sync Mode for EL1. */
>> @@ -114,6 +159,8 @@ static inline void __mte_enable_kernel(const char *mode, unsigned long tcf)
>> SYS_FIELD_PREP(SCTLR_EL1, TCF, tcf));
>> isb();
>>
>> + __mte_tag_storage_init();
>> +
>> pr_info_once("MTE: enabled in %s mode at EL1\n", mode);
>> }
>>
>> --
>> 2.36.1
>>
>> --
>> You received this message because you are subscribed to the Google Groups "kasan-dev" group.
>> To unsubscribe from this group and stop receiving emails from it, send an email to [email protected].
>> To view this discussion on the web visit https://groups.google.com/d/msgid/kasan-dev/20220607113150.55140-1-vincenzo.frascino%40arm.com.

--
Regards,
Vincenzo