1 /* This test program is part of GDB, the GNU debugger. 2 3 Copyright 2021-2023 Free Software Foundation, Inc. 4 5 This program is free software; you can redistribute it and/or modify 6 it under the terms of the GNU General Public License as published by 7 the Free Software Foundation; either version 3 of the License, or 8 (at your option) any later version. 9 10 This program is distributed in the hope that it will be useful, 11 but WITHOUT ANY WARRANTY; without even the implied warranty of 12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 GNU General Public License for more details. 14 15 You should have received a copy of the GNU General Public License 16 along with this program. If not, see <http://www.gnu.org/licenses/>. */ 17 18 /* Exercise AArch64's Memory Tagging Extension with tagged pointers. */ 19 20 /* This test was based on the documentation for the AArch64 Memory Tagging 21 Extension from the Linux Kernel, found in the sources in 22 Documentation/arm64/memory-tagging-extension.rst. */ 23 24 #include <errno.h> 25 #include <stdio.h> 26 #include <stdlib.h> 27 #include <unistd.h> 28 #include <sys/auxv.h> 29 #include <sys/mman.h> 30 #include <sys/prctl.h> 31 32 /* From arch/arm64/include/uapi/asm/hwcap.h */ 33 #ifndef HWCAP2_MTE 34 #define HWCAP2_MTE (1 << 18) 35 #endif 36 37 /* From arch/arm64/include/uapi/asm/mman.h */ 38 #ifndef PROT_MTE 39 #define PROT_MTE 0x20 40 #endif 41 42 #ifndef PR_SET_TAGGED_ADDR_CTRL 43 #define PR_SET_TAGGED_ADDR_CTRL 55 44 #define PR_TAGGED_ADDR_ENABLE (1UL << 0) 45 #endif 46 47 /* From include/uapi/linux/prctl.h */ 48 #ifndef PR_MTE_TCF_SHIFT 49 #define PR_MTE_TCF_SHIFT 1 50 #define PR_MTE_TCF_SYNC (1UL << PR_MTE_TCF_SHIFT) 51 #define PR_MTE_TCF_ASYNC (2UL << PR_MTE_TCF_SHIFT) 52 #define PR_MTE_TAG_SHIFT 3 53 #endif 54 55 void 56 access_memory (unsigned char *tagged_ptr, unsigned char *untagged_ptr) 57 { 58 tagged_ptr[0] = 'a'; 59 } 60 61 int 62 main (int argc, char **argv) 63 { 64 unsigned char *tagged_ptr; 65 unsigned char *untagged_ptr; 66 unsigned long page_sz = sysconf (_SC_PAGESIZE); 67 unsigned long hwcap2 = getauxval(AT_HWCAP2); 68 69 /* Bail out if MTE is not supported. */ 70 if (!(hwcap2 & HWCAP2_MTE)) 71 return 1; 72 73 /* Enable the tagged address ABI, synchronous MTE tag check faults and 74 allow all non-zero tags in the randomly generated set. */ 75 if (prctl (PR_SET_TAGGED_ADDR_CTRL, 76 PR_TAGGED_ADDR_ENABLE | PR_MTE_TCF_SYNC 77 | (0xfffe << PR_MTE_TAG_SHIFT), 78 0, 0, 0)) 79 { 80 perror ("prctl () failed"); 81 return 1; 82 } 83 84 /* Create a mapping that will have PROT_MTE set. */ 85 tagged_ptr = mmap (0, page_sz, PROT_READ | PROT_WRITE, 86 MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); 87 if (tagged_ptr == MAP_FAILED) 88 { 89 perror ("mmap () failed"); 90 return 1; 91 } 92 93 /* Create another mapping that won't have PROT_MTE set. */ 94 untagged_ptr = mmap (0, page_sz, PROT_READ | PROT_WRITE, 95 MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); 96 if (untagged_ptr == MAP_FAILED) 97 { 98 perror ("mmap () failed"); 99 return 1; 100 } 101 102 /* Enable MTE on the above anonymous mmap. */ 103 if (mprotect (tagged_ptr, page_sz, PROT_READ | PROT_WRITE | PROT_MTE)) 104 { 105 perror ("mprotect () failed"); 106 return 1; 107 } 108 109 access_memory (tagged_ptr, untagged_ptr); 110 111 return 0; 112 } 113