1*e4624435SJonathan Corbet========================== 2*e4624435SJonathan CorbetAArch64 TAGGED ADDRESS ABI 3*e4624435SJonathan Corbet========================== 4*e4624435SJonathan Corbet 5*e4624435SJonathan CorbetAuthors: Vincenzo Frascino <vincenzo.frascino@arm.com> 6*e4624435SJonathan Corbet Catalin Marinas <catalin.marinas@arm.com> 7*e4624435SJonathan Corbet 8*e4624435SJonathan CorbetDate: 21 August 2019 9*e4624435SJonathan Corbet 10*e4624435SJonathan CorbetThis document describes the usage and semantics of the Tagged Address 11*e4624435SJonathan CorbetABI on AArch64 Linux. 12*e4624435SJonathan Corbet 13*e4624435SJonathan Corbet1. Introduction 14*e4624435SJonathan Corbet--------------- 15*e4624435SJonathan Corbet 16*e4624435SJonathan CorbetOn AArch64 the ``TCR_EL1.TBI0`` bit is set by default, allowing 17*e4624435SJonathan Corbetuserspace (EL0) to perform memory accesses through 64-bit pointers with 18*e4624435SJonathan Corbeta non-zero top byte. This document describes the relaxation of the 19*e4624435SJonathan Corbetsyscall ABI that allows userspace to pass certain tagged pointers to 20*e4624435SJonathan Corbetkernel syscalls. 21*e4624435SJonathan Corbet 22*e4624435SJonathan Corbet2. AArch64 Tagged Address ABI 23*e4624435SJonathan Corbet----------------------------- 24*e4624435SJonathan Corbet 25*e4624435SJonathan CorbetFrom the kernel syscall interface perspective and for the purposes of 26*e4624435SJonathan Corbetthis document, a "valid tagged pointer" is a pointer with a potentially 27*e4624435SJonathan Corbetnon-zero top-byte that references an address in the user process address 28*e4624435SJonathan Corbetspace obtained in one of the following ways: 29*e4624435SJonathan Corbet 30*e4624435SJonathan Corbet- ``mmap()`` syscall where either: 31*e4624435SJonathan Corbet 32*e4624435SJonathan Corbet - flags have the ``MAP_ANONYMOUS`` bit set or 33*e4624435SJonathan Corbet - the file descriptor refers to a regular file (including those 34*e4624435SJonathan Corbet returned by ``memfd_create()``) or ``/dev/zero`` 35*e4624435SJonathan Corbet 36*e4624435SJonathan Corbet- ``brk()`` syscall (i.e. the heap area between the initial location of 37*e4624435SJonathan Corbet the program break at process creation and its current location). 38*e4624435SJonathan Corbet 39*e4624435SJonathan Corbet- any memory mapped by the kernel in the address space of the process 40*e4624435SJonathan Corbet during creation and with the same restrictions as for ``mmap()`` above 41*e4624435SJonathan Corbet (e.g. data, bss, stack). 42*e4624435SJonathan Corbet 43*e4624435SJonathan CorbetThe AArch64 Tagged Address ABI has two stages of relaxation depending on 44*e4624435SJonathan Corbethow the user addresses are used by the kernel: 45*e4624435SJonathan Corbet 46*e4624435SJonathan Corbet1. User addresses not accessed by the kernel but used for address space 47*e4624435SJonathan Corbet management (e.g. ``mprotect()``, ``madvise()``). The use of valid 48*e4624435SJonathan Corbet tagged pointers in this context is allowed with these exceptions: 49*e4624435SJonathan Corbet 50*e4624435SJonathan Corbet - ``brk()``, ``mmap()`` and the ``new_address`` argument to 51*e4624435SJonathan Corbet ``mremap()`` as these have the potential to alias with existing 52*e4624435SJonathan Corbet user addresses. 53*e4624435SJonathan Corbet 54*e4624435SJonathan Corbet NOTE: This behaviour changed in v5.6 and so some earlier kernels may 55*e4624435SJonathan Corbet incorrectly accept valid tagged pointers for the ``brk()``, 56*e4624435SJonathan Corbet ``mmap()`` and ``mremap()`` system calls. 57*e4624435SJonathan Corbet 58*e4624435SJonathan Corbet - The ``range.start``, ``start`` and ``dst`` arguments to the 59*e4624435SJonathan Corbet ``UFFDIO_*`` ``ioctl()``s used on a file descriptor obtained from 60*e4624435SJonathan Corbet ``userfaultfd()``, as fault addresses subsequently obtained by reading 61*e4624435SJonathan Corbet the file descriptor will be untagged, which may otherwise confuse 62*e4624435SJonathan Corbet tag-unaware programs. 63*e4624435SJonathan Corbet 64*e4624435SJonathan Corbet NOTE: This behaviour changed in v5.14 and so some earlier kernels may 65*e4624435SJonathan Corbet incorrectly accept valid tagged pointers for this system call. 66*e4624435SJonathan Corbet 67*e4624435SJonathan Corbet2. User addresses accessed by the kernel (e.g. ``write()``). This ABI 68*e4624435SJonathan Corbet relaxation is disabled by default and the application thread needs to 69*e4624435SJonathan Corbet explicitly enable it via ``prctl()`` as follows: 70*e4624435SJonathan Corbet 71*e4624435SJonathan Corbet - ``PR_SET_TAGGED_ADDR_CTRL``: enable or disable the AArch64 Tagged 72*e4624435SJonathan Corbet Address ABI for the calling thread. 73*e4624435SJonathan Corbet 74*e4624435SJonathan Corbet The ``(unsigned int) arg2`` argument is a bit mask describing the 75*e4624435SJonathan Corbet control mode used: 76*e4624435SJonathan Corbet 77*e4624435SJonathan Corbet - ``PR_TAGGED_ADDR_ENABLE``: enable AArch64 Tagged Address ABI. 78*e4624435SJonathan Corbet Default status is disabled. 79*e4624435SJonathan Corbet 80*e4624435SJonathan Corbet Arguments ``arg3``, ``arg4``, and ``arg5`` must be 0. 81*e4624435SJonathan Corbet 82*e4624435SJonathan Corbet - ``PR_GET_TAGGED_ADDR_CTRL``: get the status of the AArch64 Tagged 83*e4624435SJonathan Corbet Address ABI for the calling thread. 84*e4624435SJonathan Corbet 85*e4624435SJonathan Corbet Arguments ``arg2``, ``arg3``, ``arg4``, and ``arg5`` must be 0. 86*e4624435SJonathan Corbet 87*e4624435SJonathan Corbet The ABI properties described above are thread-scoped, inherited on 88*e4624435SJonathan Corbet clone() and fork() and cleared on exec(). 89*e4624435SJonathan Corbet 90*e4624435SJonathan Corbet Calling ``prctl(PR_SET_TAGGED_ADDR_CTRL, PR_TAGGED_ADDR_ENABLE, 0, 0, 0)`` 91*e4624435SJonathan Corbet returns ``-EINVAL`` if the AArch64 Tagged Address ABI is globally 92*e4624435SJonathan Corbet disabled by ``sysctl abi.tagged_addr_disabled=1``. The default 93*e4624435SJonathan Corbet ``sysctl abi.tagged_addr_disabled`` configuration is 0. 94*e4624435SJonathan Corbet 95*e4624435SJonathan CorbetWhen the AArch64 Tagged Address ABI is enabled for a thread, the 96*e4624435SJonathan Corbetfollowing behaviours are guaranteed: 97*e4624435SJonathan Corbet 98*e4624435SJonathan Corbet- All syscalls except the cases mentioned in section 3 can accept any 99*e4624435SJonathan Corbet valid tagged pointer. 100*e4624435SJonathan Corbet 101*e4624435SJonathan Corbet- The syscall behaviour is undefined for invalid tagged pointers: it may 102*e4624435SJonathan Corbet result in an error code being returned, a (fatal) signal being raised, 103*e4624435SJonathan Corbet or other modes of failure. 104*e4624435SJonathan Corbet 105*e4624435SJonathan Corbet- The syscall behaviour for a valid tagged pointer is the same as for 106*e4624435SJonathan Corbet the corresponding untagged pointer. 107*e4624435SJonathan Corbet 108*e4624435SJonathan Corbet 109*e4624435SJonathan CorbetA definition of the meaning of tagged pointers on AArch64 can be found 110*e4624435SJonathan Corbetin Documentation/arch/arm64/tagged-pointers.rst. 111*e4624435SJonathan Corbet 112*e4624435SJonathan Corbet3. AArch64 Tagged Address ABI Exceptions 113*e4624435SJonathan Corbet----------------------------------------- 114*e4624435SJonathan Corbet 115*e4624435SJonathan CorbetThe following system call parameters must be untagged regardless of the 116*e4624435SJonathan CorbetABI relaxation: 117*e4624435SJonathan Corbet 118*e4624435SJonathan Corbet- ``prctl()`` other than pointers to user data either passed directly or 119*e4624435SJonathan Corbet indirectly as arguments to be accessed by the kernel. 120*e4624435SJonathan Corbet 121*e4624435SJonathan Corbet- ``ioctl()`` other than pointers to user data either passed directly or 122*e4624435SJonathan Corbet indirectly as arguments to be accessed by the kernel. 123*e4624435SJonathan Corbet 124*e4624435SJonathan Corbet- ``shmat()`` and ``shmdt()``. 125*e4624435SJonathan Corbet 126*e4624435SJonathan Corbet- ``brk()`` (since kernel v5.6). 127*e4624435SJonathan Corbet 128*e4624435SJonathan Corbet- ``mmap()`` (since kernel v5.6). 129*e4624435SJonathan Corbet 130*e4624435SJonathan Corbet- ``mremap()``, the ``new_address`` argument (since kernel v5.6). 131*e4624435SJonathan Corbet 132*e4624435SJonathan CorbetAny attempt to use non-zero tagged pointers may result in an error code 133*e4624435SJonathan Corbetbeing returned, a (fatal) signal being raised, or other modes of 134*e4624435SJonathan Corbetfailure. 135*e4624435SJonathan Corbet 136*e4624435SJonathan Corbet4. Example of correct usage 137*e4624435SJonathan Corbet--------------------------- 138*e4624435SJonathan Corbet.. code-block:: c 139*e4624435SJonathan Corbet 140*e4624435SJonathan Corbet #include <stdlib.h> 141*e4624435SJonathan Corbet #include <string.h> 142*e4624435SJonathan Corbet #include <unistd.h> 143*e4624435SJonathan Corbet #include <sys/mman.h> 144*e4624435SJonathan Corbet #include <sys/prctl.h> 145*e4624435SJonathan Corbet 146*e4624435SJonathan Corbet #define PR_SET_TAGGED_ADDR_CTRL 55 147*e4624435SJonathan Corbet #define PR_TAGGED_ADDR_ENABLE (1UL << 0) 148*e4624435SJonathan Corbet 149*e4624435SJonathan Corbet #define TAG_SHIFT 56 150*e4624435SJonathan Corbet 151*e4624435SJonathan Corbet int main(void) 152*e4624435SJonathan Corbet { 153*e4624435SJonathan Corbet int tbi_enabled = 0; 154*e4624435SJonathan Corbet unsigned long tag = 0; 155*e4624435SJonathan Corbet char *ptr; 156*e4624435SJonathan Corbet 157*e4624435SJonathan Corbet /* check/enable the tagged address ABI */ 158*e4624435SJonathan Corbet if (!prctl(PR_SET_TAGGED_ADDR_CTRL, PR_TAGGED_ADDR_ENABLE, 0, 0, 0)) 159*e4624435SJonathan Corbet tbi_enabled = 1; 160*e4624435SJonathan Corbet 161*e4624435SJonathan Corbet /* memory allocation */ 162*e4624435SJonathan Corbet ptr = mmap(NULL, sysconf(_SC_PAGE_SIZE), PROT_READ | PROT_WRITE, 163*e4624435SJonathan Corbet MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); 164*e4624435SJonathan Corbet if (ptr == MAP_FAILED) 165*e4624435SJonathan Corbet return 1; 166*e4624435SJonathan Corbet 167*e4624435SJonathan Corbet /* set a non-zero tag if the ABI is available */ 168*e4624435SJonathan Corbet if (tbi_enabled) 169*e4624435SJonathan Corbet tag = rand() & 0xff; 170*e4624435SJonathan Corbet ptr = (char *)((unsigned long)ptr | (tag << TAG_SHIFT)); 171*e4624435SJonathan Corbet 172*e4624435SJonathan Corbet /* memory access to a tagged address */ 173*e4624435SJonathan Corbet strcpy(ptr, "tagged pointer\n"); 174*e4624435SJonathan Corbet 175*e4624435SJonathan Corbet /* syscall with a tagged pointer */ 176*e4624435SJonathan Corbet write(1, ptr, strlen(ptr)); 177*e4624435SJonathan Corbet 178*e4624435SJonathan Corbet return 0; 179*e4624435SJonathan Corbet } 180