Skip to content

Commit

Permalink
mte/kasan: Implementing KASAN memory protection for ARM64 hardware MTE
Browse files Browse the repository at this point in the history
1. Add mte_tags.c, which will call arm64_mte to implement tagging of memory blocks by operating registers
2. please use arm64/mte, it default enable MM_KASAN_MTE_TAGS, run log:

➜  NX git:(mm) ✗ qemu-system-aarch64 -cpu max -nographic \
        -machine virt,virtualization=on,gic-version=3,mte=on \
        -chardev stdio,id=con,mux=on, -serial chardev:con \
        -mon chardev=con,mode=readline  -kernel ./nuttx/nuttx -s
- Ready to Boot Primary CPU
- Boot from EL2
- Boot from EL1
- Boot to C runtime for OS Initialize
mm_initialize: Heap: name=Umem, start=0x403f2000 size=130080768
mm_addregion: [Umem] Region 1: base=0x403f23a0 size=130079840
mm_malloc: Allocated 0xf8000000403f23e0, size 144
mm_malloc: Allocated 0xfe000000403f2470, size 80
mm_malloc: Allocated 0xfe000000403f24c0, size 64
mm_malloc: Allocated 0xfe000000403f2500, size 96
mm_malloc: Allocated 0xff000000403f2560, size 96
mm_malloc: Allocated 0xf7000000403f25c0, size 96
mm_malloc: Allocated 0xff000000403f2620, size 96
mm_malloc: Allocated 0xfe000000403f2680, size 96
mm_malloc: Allocated 0xfe000000403f26e0, size 64
mm_malloc: Allocated 0xf1000000403f2720, size 64
mm_malloc: Allocated 0xf9000000403f2760, size 336
mm_malloc: Allocated 0xf6000000403f28b0, size 8208
mm_malloc: Allocated 0xf4000000403f48c0, size 1584
mm_malloc: Allocated 0xfa000000403f4ef0, size 64
mm_malloc: Allocated 0xf8000000403f4f30, size 64
mm_malloc: Allocated 0xfe000000403f4f70, size 8208
mm_malloc: Allocated 0xfe000000403f6f80, size 80
mm_malloc: Allocated 0xfe000000403f6fd0, size 96
mm_malloc: Allocated 0xf7000000403f7030, size 96
mm_malloc: Allocated 0xf7000000403f7090, size 336
mm_malloc: Allocated 0xfc000000403f71e0, size 96
mm_malloc: Allocated 0xfd000000403f7240, size 912

NuttShell (NSH)
nsh>
nsh> mtetest
mm_malloc: Allocated 0xf4000000403f75d0, size 1584
mm_malloc: Allocated 0xfd000000403f7c00, size 64
mm_malloc: Allocated 0xff000000403f7c40, size 64
mm_malloc: Allocated 0xfe000000403f7c80, size 8208
Spawning process for test: mtetest1
mm_malloc: Allocated 0xf4000000403f9c90, size 1584
mm_malloc: Allocated 0xfb000000403fa2c0, size 64
mm_malloc: Allocated 0xf5000000403fa300, size 64
mm_malloc: Allocated 0xfd000000403fa340, size 8208
Running test: mtetest1
mm_free: Freeing 0xf5000000403fa300
mm_free: Freeing 0xfb000000403fa2c0
mm_free: Freeing 0xfd000000403fa340
mm_free: Freeing 0xf4000000403f9c90
Test 'mtetest1' completed
Spawning process for test: mtetest2
mm_malloc: Allocated 0xf9000000403f9c90, size 1584
mm_malloc: Allocated 0xfd000000403fa2c0, size 64
mm_malloc: Allocated 0xfd000000403fa300, size 64
mm_malloc: Allocated 0xfb000000403fa340, size 8208
Running test: mtetest2
mm_free: Freeing 0xfd000000403fa300
mm_free: Freeing 0xfd000000403fa2c0
mm_free: Freeing 0xfb000000403fa340
mm_free: Freeing 0xf9000000403f9c90
Test 'mtetest2' completed
Spawning process for test: mtetest3
mm_malloc: Allocated 0xf5000000403f9c90, size 1584
mm_malloc: Allocated 0xf7000000403fa2c0, size 64
mm_malloc: Allocated 0xfd000000403fa300, size 64
mm_malloc: Allocated 0xf4000000403fa340, size 8208
Running test: mtetest3
mm_free: Freeing 0xfd000000403fa300
mm_free: Freeing 0xf7000000403fa2c0
mm_free: Freeing 0xf4000000403fa340
mm_free: Freeing 0xf5000000403f9c90
Test 'mtetest3' completed
Spawning process for test: mtetest4
mm_malloc: Allocated 0xf8000000403f9c90, size 1584
mm_malloc: Allocated 0xfb000000403fa2c0, size 64
mm_malloc: Allocated 0xf4000000403fa300, size 64
mm_malloc: Allocated 0xfe000000403fa340, size 8208
Running test: mtetest4
mm_free: Freeing 0xf4000000403fa300
mm_free: Freeing 0xfb000000403fa2c0
mm_free: Freeing 0xfe000000403fa340
mm_free: Freeing 0xf8000000403f9c90
Test 'mtetest4' completed
Spawning process for test: mtetest5
mm_malloc: Allocated 0xf2000000403f9c90, size 1584
mm_malloc: Allocated 0xf5000000403fa2c0, size 64
mm_malloc: Allocated 0xf8000000403fa300, size 64
mm_malloc: Allocated 0xfb000000403fa340, size 8208
Running test: mtetest5
mm_free: Freeing 0xf8000000403fa300
mm_free: Freeing 0xf5000000403fa2c0
mm_free: Freeing 0xfb000000403fa340
mm_free: Freeing 0xf2000000403f9c90
Test 'mtetest5' completed
Spawning process for test: Thread switch MTE test
mm_malloc: Allocated 0xf4000000403f9c90, size 1584
mm_malloc: Allocated 0xff000000403fa2c0, size 64
mm_malloc: Allocated 0xfe000000403fa300, size 64
mm_malloc: Allocated 0xfb000000403fa340, size 8208
Running test: Thread switch MTE test
mm_malloc: Allocated 0xf2000000403fc350, size 352
mm_malloc: Allocated 0xf4000000403fc4b0, size 8208
mm_malloc: Allocated 0xf4000000403fe4c0, size 352
mm_malloc: Allocated 0xfa000000403fe620, size 8208
Process 1 holding lock
Process 2 holding lock
Process 1 holding lock again
default_fatal_handler: (IFSC/DFSC) for Data/Instruction aborts: synchronous tag check fault
arm64_exception_handler: CurrentEL: MODE_EL1
arm64_exception_handler: ESR_ELn: 0x96000011
arm64_exception_handler: FAR_ELn: 0x6000000403ee2f0
arm64_exception_handler: ELR_ELn: 0x402b3e98
print_ec_cause: DABT (current EL)
print_ec_cause: Data Abort taken without a change in Exception level

Signed-off-by: wangmingrong1 <[email protected]>
  • Loading branch information
W-M-R committed Jan 8, 2025
1 parent 3457b94 commit e731640
Show file tree
Hide file tree
Showing 12 changed files with 307 additions and 14 deletions.
58 changes: 58 additions & 0 deletions arch/arm64/include/mte.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
/****************************************************************************
* arch/arm64/include/mte.h
*
* SPDX-License-Identifier: Apache-2.0
*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership. The
* ASF licenses this file to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance with the
* License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations
* under the License.
*
****************************************************************************/

#ifndef ___ARCH_ARM64_SRC_COMMON_ARM64_MTE_H
#define ___ARCH_ARM64_SRC_COMMON_ARM64_MTE_H

/****************************************************************************
* Public Function Prototypes
****************************************************************************/

/* Initialize MTE settings and enable memory tagging */

void arm64_mte_init(void);

/* Enable MTE by setting the TCF1 bit in SCTLR_EL1 */

void arm64_mte_enable(void);

/* Disable MTE by clearing the TCF1 bit in SCTLR_EL1 */

void arm64_mte_disable(void);

/* Set memory tags for a given memory range */

void arm64_mte_set_tag(const void *addr, size_t size);

/* Get a random label based on the address through the mte register */

uint8_t arm64_mte_get_random_tag(const void *addr);

/* Get the address without label */

FAR void *arm64_mte_get_untagged_addr(const void *addr);

/* Get the address with label */

FAR void *arm64_mte_get_tagged_addr(const void *addr, uint8_t tag);

#endif /* ___ARCH_ARM64_SRC_COMMON_ARM64_MTE_H */
6 changes: 0 additions & 6 deletions arch/arm64/src/common/arm64_arch.h
Original file line number Diff line number Diff line change
Expand Up @@ -506,12 +506,6 @@ uint64_t arm64_get_mpid(int cpu);
int arm64_get_cpuid(uint64_t mpid);
#endif

#ifdef CONFIG_ARM64_MTE
void arm64_enable_mte(void);
#else
#define arm64_enable_mte()
#endif

#endif /* __ASSEMBLY__ */

#endif /* ___ARCH_ARM64_SRC_COMMON_ARM64_ARCH_H */
6 changes: 4 additions & 2 deletions arch/arm64/src/common/arm64_mmu.h
Original file line number Diff line number Diff line change
Expand Up @@ -170,8 +170,10 @@
* in the address range [59:55] = 0b00000 are unchecked accesses.
*/

#define TCR_TCMA0 (1ULL << 57)
#define TCR_TCMA1 (1ULL << 58)
#define TCR_TCMA1 BIT(56)
#define TCR_TCMA0 BIT(57)
#define TCR_MTX0_SHIFT BIT(60)
#define TCR_MTX1_SHIFT BIT(61)

#define TCR_PS_BITS_4GB 0x0ULL
#define TCR_PS_BITS_64GB 0x1ULL
Expand Down
92 changes: 89 additions & 3 deletions arch/arm64/src/common/arm64_mte.c
Original file line number Diff line number Diff line change
Expand Up @@ -29,18 +29,25 @@
#include <stdio.h>

#include "arm64_arch.h"
#include "arm64_mmu.h"

/****************************************************************************
* Pre-processor Definitions
****************************************************************************/

#define GCR_EL1_VAL 0x10001

/* The alignment length of the MTE must be a multiple of sixteen */

#define MTE_MM_AILGN 16

#define MTE_TAG_SHIFT 56

/****************************************************************************
* Private Functions
****************************************************************************/

static int arm64_mte_is_support(void)
static int mte_is_support(void)
{
int supported;
__asm__ volatile (
Expand All @@ -53,15 +60,86 @@ static int arm64_mte_is_support(void)
return supported != 0;
}

static void mte_set_tcf(bool enable)
{
uint64_t val = read_sysreg(sctlr_el1);

if (enable)
{
val |= SCTLR_TCF1_BIT;
}
else
{
val &= ~SCTLR_TCF1_BIT;
}

write_sysreg(val, sctlr_el1);
}

static inline uint8_t mte_get_ptr_tag(const void *ptr)
{
return 0xf0 | (uint8_t)(((uint64_t)(ptr)) >> MTE_TAG_SHIFT);
}

/****************************************************************************
* Public Functions
****************************************************************************/

void arm64_enable_mte(void)
uint8_t arm64_mte_get_random_tag(const void *addr)
{
asm("irg %0, %0" : "=r" (addr));

return mte_get_ptr_tag(addr);
}

FAR void *arm64_mte_get_untagged_addr(const void *addr)
{
return (FAR void *)
(((uint64_t)(addr)) & ~((uint64_t)0xff << MTE_TAG_SHIFT));
}

FAR void *arm64_mte_get_tagged_addr(const void *addr, uint8_t tag)
{
return (FAR void *)
(((uint64_t)(addr)) | ((uint64_t)tag << MTE_TAG_SHIFT));
}

/* Disable MTE by clearing the TCF1 bit in SCTLR_EL1 */

void arm64_mte_disable(void)
{
mte_set_tcf(false);
}

/* Enable MTE by setting the TCF1 bit in SCTLR_EL1 */

void arm64_mte_enable(void)
{
mte_set_tcf(true);
}

/* Set memory tags for a given memory range */

void arm64_mte_set_tag(const void *addr, size_t size)
{
size_t i;

DEBUGASSERT((uintptr_t)addr % MTE_MM_AILGN == 0);
DEBUGASSERT(size % MTE_MM_AILGN == 0);

for (i = 0; i < size; i += MTE_MM_AILGN)
{
asm("stg %0, [%0]" : : "r"(addr + i));
}
}

/* Initialize MTE settings and enable memory tagging */

void arm64_mte_init(void)
{
uint64_t val;

if (!arm64_mte_is_support())
if (!mte_is_support())
{
return;
}
Expand All @@ -78,6 +156,14 @@ void arm64_enable_mte(void)
assert(!(read_sysreg(ttbr0_el1) & TTBR_CNP_BIT));
assert(!(read_sysreg(ttbr1_el1) & TTBR_CNP_BIT));

/* Controls the default value for skipping high bytes */

val = read_sysreg(tcr_el1);
val |= TCR_TCMA1;
write_sysreg(val, tcr_el1);

/* Enable the MTE function */

val = read_sysreg(sctlr_el1);
val |= SCTLR_ATA_BIT | SCTLR_TCF1_BIT;
write_sysreg(val, sctlr_el1);
Expand Down
5 changes: 4 additions & 1 deletion arch/arm64/src/qemu/qemu_boot.c
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@
# include <nuttx/page.h>
#endif

#include <arch/mte.h>
#include <arch/chip/chip.h>

#ifdef CONFIG_SMP
Expand Down Expand Up @@ -161,7 +162,9 @@ void arm64_chip_boot(void)

arm64_mmu_init(true);

arm64_enable_mte();
#ifdef CONFIG_ARM64_MTE
arm64_mte_init();
#endif

#ifdef CONFIG_DEVICE_TREE
fdt_register((const char *)0x40000000);
Expand Down
19 changes: 19 additions & 0 deletions include/nuttx/mm/kasan.h
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,8 @@
# define kasan_stop()
# define kasan_debugpoint(t,a,s) 0
# define kasan_init_early()
# define kasan_hw_open()
# define kasan_hw_close()
#else

# define kasan_init_early() kasan_stop()
Expand Down Expand Up @@ -201,6 +203,23 @@ void kasan_stop(void);

int kasan_debugpoint(int type, FAR void *addr, size_t size);

#ifndef CONFIG_MM_KASAN_MTE_TAGS
# define kasan_hw_open()
# define kasan_hw_close()
#else
/****************************************************************************
* Name: kasan_hw_open
****************************************************************************/

void kasan_hw_open(void);

/****************************************************************************
* Name: kasan_hw_open
****************************************************************************/

void kasan_hw_close(void);
#endif

#undef EXTERN
#ifdef __cplusplus
}
Expand Down
13 changes: 13 additions & 0 deletions mm/Kconfig
Original file line number Diff line number Diff line change
Expand Up @@ -348,10 +348,22 @@ config MM_KASAN_SW_TAGS
---help---
KAsan based on software tags

config MM_KASAN_MTE_TAGS
bool "KAsan MTE tags"
depends on ARM64_MTE
select MM_KASAN_NO_INSTRUMENT
---help---
KAsan based on hardware tags

endchoice

config MM_KASAN_NO_INSTRUMENT
bool
default n

config MM_KASAN_ALL
bool "Enable KASan for the entire image"
depends on !MM_KASAN_NO_INSTRUMENT
default y
---help---
This option activates address sanitizer for the entire image.
Expand All @@ -366,6 +378,7 @@ config MM_KASAN_REGIONS

config MM_KASAN_WATCHPOINT
int "Kasan watchpoint maximum number"
depends on !MM_KASAN_NO_INSTRUMENT
default 0
---help---
The maximum number of watchpoints that can be set by KASan.
Expand Down
8 changes: 8 additions & 0 deletions mm/kasan/hook.c
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,8 @@
# include "generic.c"
#elif defined(CONFIG_MM_KASAN_SW_TAGS)
# include "sw_tags.c"
#elif defined(CONFIG_MM_KASAN_MTE_TAGS)
# include "mte_tags.c"
#else
# define kasan_is_poisoned(addr, size) false
#endif
Expand Down Expand Up @@ -123,6 +125,8 @@ static uint32_t g_region_init;
* Private Functions
****************************************************************************/

#ifndef CONFIG_MM_KASAN_MTE_TAGS

static void kasan_show_memory(FAR const uint8_t *addr, size_t size,
size_t dumpsize)
{
Expand Down Expand Up @@ -252,6 +256,10 @@ static inline void kasan_check_report(FAR const void *addr, size_t size,
# endif
#endif
}
#else
#define kasan_check_report(addr, size, is_write, return_address)
#define kasan_report(addr, size, is_write, return_address)
#endif

/****************************************************************************
* Public Functions
Expand Down
Loading

0 comments on commit e731640

Please sign in to comment.