Skip to content

Commit e731640

Browse files
committed
mte/kasan: Implementing KASAN memory protection for ARM64 hardware MTE
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]>
1 parent 3457b94 commit e731640

File tree

12 files changed

+307
-14
lines changed

12 files changed

+307
-14
lines changed

arch/arm64/include/mte.h

+58
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
/****************************************************************************
2+
* arch/arm64/include/mte.h
3+
*
4+
* SPDX-License-Identifier: Apache-2.0
5+
*
6+
* Licensed to the Apache Software Foundation (ASF) under one or more
7+
* contributor license agreements. See the NOTICE file distributed with
8+
* this work for additional information regarding copyright ownership. The
9+
* ASF licenses this file to you under the Apache License, Version 2.0 (the
10+
* "License"); you may not use this file except in compliance with the
11+
* License. You may obtain a copy of the License at
12+
*
13+
* http://www.apache.org/licenses/LICENSE-2.0
14+
*
15+
* Unless required by applicable law or agreed to in writing, software
16+
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
17+
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
18+
* License for the specific language governing permissions and limitations
19+
* under the License.
20+
*
21+
****************************************************************************/
22+
23+
#ifndef ___ARCH_ARM64_SRC_COMMON_ARM64_MTE_H
24+
#define ___ARCH_ARM64_SRC_COMMON_ARM64_MTE_H
25+
26+
/****************************************************************************
27+
* Public Function Prototypes
28+
****************************************************************************/
29+
30+
/* Initialize MTE settings and enable memory tagging */
31+
32+
void arm64_mte_init(void);
33+
34+
/* Enable MTE by setting the TCF1 bit in SCTLR_EL1 */
35+
36+
void arm64_mte_enable(void);
37+
38+
/* Disable MTE by clearing the TCF1 bit in SCTLR_EL1 */
39+
40+
void arm64_mte_disable(void);
41+
42+
/* Set memory tags for a given memory range */
43+
44+
void arm64_mte_set_tag(const void *addr, size_t size);
45+
46+
/* Get a random label based on the address through the mte register */
47+
48+
uint8_t arm64_mte_get_random_tag(const void *addr);
49+
50+
/* Get the address without label */
51+
52+
FAR void *arm64_mte_get_untagged_addr(const void *addr);
53+
54+
/* Get the address with label */
55+
56+
FAR void *arm64_mte_get_tagged_addr(const void *addr, uint8_t tag);
57+
58+
#endif /* ___ARCH_ARM64_SRC_COMMON_ARM64_MTE_H */

arch/arm64/src/common/arm64_arch.h

-6
Original file line numberDiff line numberDiff line change
@@ -506,12 +506,6 @@ uint64_t arm64_get_mpid(int cpu);
506506
int arm64_get_cpuid(uint64_t mpid);
507507
#endif
508508

509-
#ifdef CONFIG_ARM64_MTE
510-
void arm64_enable_mte(void);
511-
#else
512-
#define arm64_enable_mte()
513-
#endif
514-
515509
#endif /* __ASSEMBLY__ */
516510

517511
#endif /* ___ARCH_ARM64_SRC_COMMON_ARM64_ARCH_H */

arch/arm64/src/common/arm64_mmu.h

+4-2
Original file line numberDiff line numberDiff line change
@@ -170,8 +170,10 @@
170170
* in the address range [59:55] = 0b00000 are unchecked accesses.
171171
*/
172172

173-
#define TCR_TCMA0 (1ULL << 57)
174-
#define TCR_TCMA1 (1ULL << 58)
173+
#define TCR_TCMA1 BIT(56)
174+
#define TCR_TCMA0 BIT(57)
175+
#define TCR_MTX0_SHIFT BIT(60)
176+
#define TCR_MTX1_SHIFT BIT(61)
175177

176178
#define TCR_PS_BITS_4GB 0x0ULL
177179
#define TCR_PS_BITS_64GB 0x1ULL

arch/arm64/src/common/arm64_mte.c

+89-3
Original file line numberDiff line numberDiff line change
@@ -29,18 +29,25 @@
2929
#include <stdio.h>
3030

3131
#include "arm64_arch.h"
32+
#include "arm64_mmu.h"
3233

3334
/****************************************************************************
3435
* Pre-processor Definitions
3536
****************************************************************************/
3637

3738
#define GCR_EL1_VAL 0x10001
3839

40+
/* The alignment length of the MTE must be a multiple of sixteen */
41+
42+
#define MTE_MM_AILGN 16
43+
44+
#define MTE_TAG_SHIFT 56
45+
3946
/****************************************************************************
4047
* Private Functions
4148
****************************************************************************/
4249

43-
static int arm64_mte_is_support(void)
50+
static int mte_is_support(void)
4451
{
4552
int supported;
4653
__asm__ volatile (
@@ -53,15 +60,86 @@ static int arm64_mte_is_support(void)
5360
return supported != 0;
5461
}
5562

63+
static void mte_set_tcf(bool enable)
64+
{
65+
uint64_t val = read_sysreg(sctlr_el1);
66+
67+
if (enable)
68+
{
69+
val |= SCTLR_TCF1_BIT;
70+
}
71+
else
72+
{
73+
val &= ~SCTLR_TCF1_BIT;
74+
}
75+
76+
write_sysreg(val, sctlr_el1);
77+
}
78+
79+
static inline uint8_t mte_get_ptr_tag(const void *ptr)
80+
{
81+
return 0xf0 | (uint8_t)(((uint64_t)(ptr)) >> MTE_TAG_SHIFT);
82+
}
83+
5684
/****************************************************************************
5785
* Public Functions
5886
****************************************************************************/
5987

60-
void arm64_enable_mte(void)
88+
uint8_t arm64_mte_get_random_tag(const void *addr)
89+
{
90+
asm("irg %0, %0" : "=r" (addr));
91+
92+
return mte_get_ptr_tag(addr);
93+
}
94+
95+
FAR void *arm64_mte_get_untagged_addr(const void *addr)
96+
{
97+
return (FAR void *)
98+
(((uint64_t)(addr)) & ~((uint64_t)0xff << MTE_TAG_SHIFT));
99+
}
100+
101+
FAR void *arm64_mte_get_tagged_addr(const void *addr, uint8_t tag)
102+
{
103+
return (FAR void *)
104+
(((uint64_t)(addr)) | ((uint64_t)tag << MTE_TAG_SHIFT));
105+
}
106+
107+
/* Disable MTE by clearing the TCF1 bit in SCTLR_EL1 */
108+
109+
void arm64_mte_disable(void)
110+
{
111+
mte_set_tcf(false);
112+
}
113+
114+
/* Enable MTE by setting the TCF1 bit in SCTLR_EL1 */
115+
116+
void arm64_mte_enable(void)
117+
{
118+
mte_set_tcf(true);
119+
}
120+
121+
/* Set memory tags for a given memory range */
122+
123+
void arm64_mte_set_tag(const void *addr, size_t size)
124+
{
125+
size_t i;
126+
127+
DEBUGASSERT((uintptr_t)addr % MTE_MM_AILGN == 0);
128+
DEBUGASSERT(size % MTE_MM_AILGN == 0);
129+
130+
for (i = 0; i < size; i += MTE_MM_AILGN)
131+
{
132+
asm("stg %0, [%0]" : : "r"(addr + i));
133+
}
134+
}
135+
136+
/* Initialize MTE settings and enable memory tagging */
137+
138+
void arm64_mte_init(void)
61139
{
62140
uint64_t val;
63141

64-
if (!arm64_mte_is_support())
142+
if (!mte_is_support())
65143
{
66144
return;
67145
}
@@ -78,6 +156,14 @@ void arm64_enable_mte(void)
78156
assert(!(read_sysreg(ttbr0_el1) & TTBR_CNP_BIT));
79157
assert(!(read_sysreg(ttbr1_el1) & TTBR_CNP_BIT));
80158

159+
/* Controls the default value for skipping high bytes */
160+
161+
val = read_sysreg(tcr_el1);
162+
val |= TCR_TCMA1;
163+
write_sysreg(val, tcr_el1);
164+
165+
/* Enable the MTE function */
166+
81167
val = read_sysreg(sctlr_el1);
82168
val |= SCTLR_ATA_BIT | SCTLR_TCF1_BIT;
83169
write_sysreg(val, sctlr_el1);

arch/arm64/src/qemu/qemu_boot.c

+4-1
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@
3636
# include <nuttx/page.h>
3737
#endif
3838

39+
#include <arch/mte.h>
3940
#include <arch/chip/chip.h>
4041

4142
#ifdef CONFIG_SMP
@@ -161,7 +162,9 @@ void arm64_chip_boot(void)
161162

162163
arm64_mmu_init(true);
163164

164-
arm64_enable_mte();
165+
#ifdef CONFIG_ARM64_MTE
166+
arm64_mte_init();
167+
#endif
165168

166169
#ifdef CONFIG_DEVICE_TREE
167170
fdt_register((const char *)0x40000000);

include/nuttx/mm/kasan.h

+19
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,8 @@
4646
# define kasan_stop()
4747
# define kasan_debugpoint(t,a,s) 0
4848
# define kasan_init_early()
49+
# define kasan_hw_open()
50+
# define kasan_hw_close()
4951
#else
5052

5153
# define kasan_init_early() kasan_stop()
@@ -201,6 +203,23 @@ void kasan_stop(void);
201203

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

206+
#ifndef CONFIG_MM_KASAN_MTE_TAGS
207+
# define kasan_hw_open()
208+
# define kasan_hw_close()
209+
#else
210+
/****************************************************************************
211+
* Name: kasan_hw_open
212+
****************************************************************************/
213+
214+
void kasan_hw_open(void);
215+
216+
/****************************************************************************
217+
* Name: kasan_hw_open
218+
****************************************************************************/
219+
220+
void kasan_hw_close(void);
221+
#endif
222+
204223
#undef EXTERN
205224
#ifdef __cplusplus
206225
}

mm/Kconfig

+13
Original file line numberDiff line numberDiff line change
@@ -348,10 +348,22 @@ config MM_KASAN_SW_TAGS
348348
---help---
349349
KAsan based on software tags
350350

351+
config MM_KASAN_MTE_TAGS
352+
bool "KAsan MTE tags"
353+
depends on ARM64_MTE
354+
select MM_KASAN_NO_INSTRUMENT
355+
---help---
356+
KAsan based on hardware tags
357+
351358
endchoice
352359

360+
config MM_KASAN_NO_INSTRUMENT
361+
bool
362+
default n
363+
353364
config MM_KASAN_ALL
354365
bool "Enable KASan for the entire image"
366+
depends on !MM_KASAN_NO_INSTRUMENT
355367
default y
356368
---help---
357369
This option activates address sanitizer for the entire image.
@@ -366,6 +378,7 @@ config MM_KASAN_REGIONS
366378

367379
config MM_KASAN_WATCHPOINT
368380
int "Kasan watchpoint maximum number"
381+
depends on !MM_KASAN_NO_INSTRUMENT
369382
default 0
370383
---help---
371384
The maximum number of watchpoints that can be set by KASan.

mm/kasan/hook.c

+8
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,8 @@
4242
# include "generic.c"
4343
#elif defined(CONFIG_MM_KASAN_SW_TAGS)
4444
# include "sw_tags.c"
45+
#elif defined(CONFIG_MM_KASAN_MTE_TAGS)
46+
# include "mte_tags.c"
4547
#else
4648
# define kasan_is_poisoned(addr, size) false
4749
#endif
@@ -123,6 +125,8 @@ static uint32_t g_region_init;
123125
* Private Functions
124126
****************************************************************************/
125127

128+
#ifndef CONFIG_MM_KASAN_MTE_TAGS
129+
126130
static void kasan_show_memory(FAR const uint8_t *addr, size_t size,
127131
size_t dumpsize)
128132
{
@@ -252,6 +256,10 @@ static inline void kasan_check_report(FAR const void *addr, size_t size,
252256
# endif
253257
#endif
254258
}
259+
#else
260+
#define kasan_check_report(addr, size, is_write, return_address)
261+
#define kasan_report(addr, size, is_write, return_address)
262+
#endif
255263

256264
/****************************************************************************
257265
* Public Functions

0 commit comments

Comments
 (0)