← Documents Documentation/arch/arm64/tagged-address-abi.rst GitHub 원문 ↗

Linux 6.18.37 · Architecture

AArch64 Tagged Address ABI

AArch64 syscall에서 valid tagged pointer를 허용하는 범위, prctl opt-in, 예외와 C 사용 예를 정의합니다.

Source pathDocumentation/arch/arm64/tagged-address-abi.rst
Source versionLinux v6.18.37
TranslationDUJINLABS 전문 번역 + 해설

요약·해설과 원문, 전문 번역을 서로 분리했습니다. API 이름, symbol, source path는 원문 표기를 사용합니다.

1. 요약·해설

원문의 핵심 논리와 kernel programming 관점의 보충 설명입니다. 아래의 전문 번역과는 별도로 작성했습니다.

요약과 해설

tagged-address-abi.rst:1-179

Top-byte-ignore hardware 기능만으로 syscall ABI가 자동 완화되는 것은 아닙니다. Linux는 address 획득 경로와 kernel의 실제 memory 접근 여부를 기준으로 valid pointer를 정의하고, 접근하는 syscall에는 thread별 `prctl()` opt-in과 명시적 예외 목록을 적용합니다.

Tagged pointer syscall 판정
User pointerValid mapping 출처?Kernel이 memory 접근?`PR_TAGGED_ADDR_ENABLE`?예외 syscall 아님?Untagged와 동일 동작

Pointer 출처, kernel 접근, thread opt-in, syscall 예외를 차례로 검사합니다.

ABI 수명과 정책
항목범위규칙
ABI stateThread`clone()`/`fork()` 상속, `exec()` clear
Global gateSystem`abi.tagged_addr_disabled` 기본 0
Invalid pointerSyscall동작 undefined
Valid pointerSyscallUntagged pointer와 동일

상태 범위와 주요 reset 조건입니다.

2. 영어 원문 전체

번역 기준이 된 Linux v6.18.37 원문입니다. 줄 번호는 이 버전의 파일 좌표입니다.

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

3. 한국어 전문 번역

영어 원문의 문단 순서와 의미를 유지한 전체 번역입니다. 코드, 함수명, symbol과 URL은 원문 표기를 유지합니다.

문서 범위와 도입

1-21

저자: Vincenzo Frascino, Catalin Marinas. 작성일: 2019-08-21. 이 문서는 AArch64 Linux Tagged Address ABI의 사용법과 의미를 정의합니다.

AArch64는 기본적으로 `TCR_EL1.TBI0`를 설정하므로 사용자 공간(EL0)은 top byte가 0이 아닌 64-bit pointer로 memory에 접근할 수 있습니다. 이 ABI는 특정 tagged pointer를 kernel syscall에 넘길 수 있도록 syscall ABI를 완화합니다.

AArch64 Tagged Address ABI

22-111

이 문서에서 valid tagged pointer는 top byte가 0이 아닐 수 있고, 다음 경로 중 하나로 얻은 user process address-space의 주소를 가리키는 pointer입니다.

획득 경로유효 조건
`mmap()``MAP_ANONYMOUS`, regular file, `memfd_create()` 결과 또는 `/dev/zero`
`brk()`Process 생성 당시 initial program break와 현재 break 사이 heap
Kernel-created mappingData, bss, stack 등 process 생성 중 kernel이 만든 영역이며 `mmap()`과 같은 제한

Kernel이 user address를 사용하는 방식에 따라 완화가 두 단계로 나뉩니다.

단계Kernel 사용Tagged pointer 정책
1Address-space 관리에만 사용하고 memory에 접근하지 않음`mprotect()`, `madvise()` 등에서 valid pointer 허용, alias·userfaultfd 예외 적용
2Kernel이 user memory에 실제 접근`write()` 등은 기본 disable이며 thread가 `prctl()`로 enable

1단계에서도 기존 user address와 alias할 수 있는 `brk()`, `mmap()`, `mremap()`의 `new_address`는 tagged pointer를 허용하지 않습니다. 이 동작은 v5.6에서 바뀌었으므로 더 오래된 kernel은 잘못 허용할 수 있습니다.

`userfaultfd()` fd에 사용하는 `UFFDIO_*` ioctl의 `range.start`, `start`, `dst`도 예외입니다. 이후 fd에서 읽는 fault address는 untagged이므로 tag를 모르는 program이 혼동할 수 있습니다. 이 동작은 v5.14에서 바뀌었습니다.

prctl동작
`PR_SET_TAGGED_ADDR_CTRL``arg2` bitmask의 `PR_TAGGED_ADDR_ENABLE`로 calling thread ABI enable/disable; `arg3..arg5`는 0
`PR_GET_TAGGED_ADDR_CTRL`Calling thread 상태 조회; `arg2..arg5`는 0

ABI 상태는 thread-scoped이며 `clone()`과 `fork()`에서 상속하고 `exec()`에서 clear합니다. `sysctl abi.tagged_addr_disabled=1`이면 enable prctl은 `-EINVAL`을 반환합니다. Sysctl 기본값은 0입니다.

  • Enable된 thread에서는 3절의 예외를 빼고 모든 syscall이 valid tagged pointer를 받을 수 있습니다.
  • Invalid tagged pointer의 syscall 동작은 undefined이며 error, fatal signal 또는 다른 실패가 가능합니다.
  • Valid tagged pointer의 syscall 동작은 대응하는 untagged pointer와 같습니다.

AArch64 tagged pointer의 의미 자체는 `Documentation/arch/arm64/tagged-pointers.rst`에 정의되어 있습니다.

ABI 완화 예외

112-135

다음 system-call parameter는 ABI를 enable해도 반드시 untagged여야 합니다.

System call/parameter예외 범위
`prctl()`Kernel이 접근할 user data pointer를 직접·간접 전달한 경우를 제외한 pointer
`ioctl()`Kernel이 접근할 user data pointer를 직접·간접 전달한 경우를 제외한 pointer
`shmat()`, `shmdt()`모든 관련 address
`brk()`Kernel v5.6부터
`mmap()`Kernel v5.6부터
`mremap()``new_address`, kernel v5.6부터

이 예외에 non-zero tagged pointer를 사용하면 error code, fatal signal 또는 다른 방식의 실패가 발생할 수 있습니다.

올바른 사용 예

136-179

예제는 `PR_SET_TAGGED_ADDR_CTRL`로 ABI를 enable하고 anonymous page를 `mmap()`한 뒤 bit 63:56에 임의 tag를 넣습니다. Tagged address로 직접 memory에 접근하고 같은 pointer를 `write()` syscall에 전달합니다.

#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/mman.h>
#include <sys/prctl.h>

#define PR_SET_TAGGED_ADDR_CTRL        55
#define PR_TAGGED_ADDR_ENABLE        (1UL << 0)

#define TAG_SHIFT                56

int main(void)
{
        int tbi_enabled = 0;
        unsigned long tag = 0;
        char *ptr;

        /* check/enable the tagged address ABI */
        if (!prctl(PR_SET_TAGGED_ADDR_CTRL, PR_TAGGED_ADDR_ENABLE, 0, 0, 0))
                tbi_enabled = 1;

        /* memory allocation */
        ptr = mmap(NULL, sysconf(_SC_PAGE_SIZE), PROT_READ | PROT_WRITE,
                   MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
        if (ptr == MAP_FAILED)
                return 1;

        /* set a non-zero tag if the ABI is available */
        if (tbi_enabled)
                tag = rand() & 0xff;
        ptr = (char *)((unsigned long)ptr | (tag << TAG_SHIFT));

        /* memory access to a tagged address */
        strcpy(ptr, "tagged pointer\n");

        /* syscall with a tagged pointer */
        write(1, ptr, strlen(ptr));

        return 0;
}