← Documents Documentation/userspace-api/mseal.rst GitHub 원문 ↗

Linux 6.18.37 · 사용자 공간 API

mseal 메모리 매핑 봉인

가상 메모리 매핑의 권한·수명 변경을 되돌릴 수 없게 봉인하는 mseal 시스템 호출의 계약, 차단 범위, 적용 주의점을 정리합니다.

Source pathDocumentation/userspace-api/mseal.rst
Source versionLinux v6.18.37
TranslationDUJINLABS 전문 번역 + 해설

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

1. 요약·해설

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

요약·해설

mseal.rst:1-209

`mseal`은 메모리 내용 자체를 불변으로 만드는 장치가 아니라 특정 mm 시스템 호출이 매핑 속성과 수명을 바꾸는 일을 차단합니다. 봉인 후 해제할 수 없으므로 보호 가치뿐 아니라 매핑 소유자와 전체 수명을 먼저 확인하는 것이 핵심입니다.

2. 영어 원문 전체

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

원문 전체 펼치기
1 .. SPDX-License-Identifier: GPL-2.0
2
3 =====================
4 Introduction of mseal
5 =====================
6
7 :Author: Jeff Xu <jeffxu@chromium.org>
8
9 Modern CPUs support memory permissions such as RW and NX bits. The memory
10 permission feature improves security stance on memory corruption bugs, i.e.
11 the attacker can’t just write to arbitrary memory and point the code to it,
12 the memory has to be marked with X bit, or else an exception will happen.
13
14 Memory sealing additionally protects the mapping itself against
15 modifications. This is useful to mitigate memory corruption issues where a
16 corrupted pointer is passed to a memory management system. For example,
17 such an attacker primitive can break control-flow integrity guarantees
18 since read-only memory that is supposed to be trusted can become writable
19 or .text pages can get remapped. Memory sealing can automatically be
20 applied by the runtime loader to seal .text and .rodata pages and
21 applications can additionally seal security critical data at runtime.
22
23 A similar feature already exists in the XNU kernel with the
24 VM_FLAGS_PERMANENT flag [1] and on OpenBSD with the mimmutable syscall [2].
25
26 SYSCALL
27 =======
28 mseal syscall signature
29 -----------------------
30 ``int mseal(void *addr, size_t len, unsigned long flags)``
31
32 **addr**/**len**: virtual memory address range.
33 The address range set by **addr**/**len** must meet:
34 - The start address must be in an allocated VMA.
35 - The start address must be page aligned.
36 - The end address (**addr** + **len**) must be in an allocated VMA.
37 - no gap (unallocated memory) between start and end address.
38
39 The ``len`` will be paged aligned implicitly by the kernel.
40
41 **flags**: reserved for future use.
42
43 **Return values**:
44 - **0**: Success.
45 - **-EINVAL**:
46 * Invalid input ``flags``.
47 * The start address (``addr``) is not page aligned.
48 * Address range (``addr`` + ``len``) overflow.
49 - **-ENOMEM**:
50 * The start address (``addr``) is not allocated.
51 * The end address (``addr`` + ``len``) is not allocated.
52 * A gap (unallocated memory) between start and end address.
53 - **-EPERM**:
54 * sealing is supported only on 64-bit CPUs, 32-bit is not supported.
55
56 **Note about error return**:
57 - For above error cases, users can expect the given memory range is
58 unmodified, i.e. no partial update.
59 - There might be other internal errors/cases not listed here, e.g.
60 error during merging/splitting VMAs, or the process reaching the maximum
61 number of supported VMAs. In those cases, partial updates to the given
62 memory range could happen. However, those cases should be rare.
63
64 **Architecture support**:
65 mseal only works on 64-bit CPUs, not 32-bit CPUs.
66
67 **Idempotent**:
68 users can call mseal multiple times. mseal on an already sealed memory
69 is a no-action (not error).
70
71 **no munseal**
72 Once mapping is sealed, it can't be unsealed. The kernel should never
73 have munseal, this is consistent with other sealing feature, e.g.
74 F_SEAL_SEAL for file.
75
76 Blocked mm syscall for sealed mapping
77 -------------------------------------
78 It might be important to note: **once the mapping is sealed, it will
79 stay in the process's memory until the process terminates**.
80
81 Example::
82
83 *ptr = mmap(0, 4096, PROT_READ, MAP_ANONYMOUS | MAP_PRIVATE, 0, 0);
84 rc = mseal(ptr, 4096, 0);
85 /* munmap will fail */
86 rc = munmap(ptr, 4096);
87 assert(rc < 0);
88
89 Blocked mm syscall:
90 - munmap
91 - mmap
92 - mremap
93 - mprotect and pkey_mprotect
94 - some destructive madvise behaviors: MADV_DONTNEED, MADV_FREE,
95 MADV_DONTNEED_LOCKED, MADV_FREE, MADV_DONTFORK, MADV_WIPEONFORK
96
97 The first set of syscalls to block is munmap, mremap, mmap. They can
98 either leave an empty space in the address space, therefore allowing
99 replacement with a new mapping with new set of attributes, or can
100 overwrite the existing mapping with another mapping.
101
102 mprotect and pkey_mprotect are blocked because they changes the
103 protection bits (RWX) of the mapping.
104
105 Certain destructive madvise behaviors, specifically MADV_DONTNEED,
106 MADV_FREE, MADV_DONTNEED_LOCKED, and MADV_WIPEONFORK, can introduce
107 risks when applied to anonymous memory by threads lacking write
108 permissions. Consequently, these operations are prohibited under such
109 conditions. The aforementioned behaviors have the potential to modify
110 region contents by discarding pages, effectively performing a memset(0)
111 operation on the anonymous memory.
112
113 Kernel will return -EPERM for blocked syscalls.
114
115 When blocked syscall return -EPERM due to sealing, the memory regions may
116 or may not be changed, depends on the syscall being blocked:
117
118 - munmap: munmap is atomic. If one of VMAs in the given range is
119 sealed, none of VMAs are updated.
120 - mprotect, pkey_mprotect, madvise: partial update might happen, e.g.
121 when mprotect over multiple VMAs, mprotect might update the beginning
122 VMAs before reaching the sealed VMA and return -EPERM.
123 - mmap and mremap: undefined behavior.
124
125 Use cases
126 =========
127 - glibc:
128 The dynamic linker, during loading ELF executables, can apply sealing to
129 mapping segments.
130
131 - Chrome browser: protect some security sensitive data structures.
132
133 - System mappings:
134 The system mappings are created by the kernel and includes vdso, vvar,
135 vvar_vclock, vectors (arm compat-mode), sigpage (arm compat-mode), uprobes.
136
137 Those system mappings are readonly only or execute only, memory sealing can
138 protect them from ever changing to writable or unmmap/remapped as different
139 attributes. This is useful to mitigate memory corruption issues where a
140 corrupted pointer is passed to a memory management system.
141
142 If supported by an architecture (CONFIG_ARCH_SUPPORTS_MSEAL_SYSTEM_MAPPINGS),
143 the CONFIG_MSEAL_SYSTEM_MAPPINGS seals all system mappings of this
144 architecture.
145
146 The following architectures currently support this feature: x86-64, arm64,
147 loongarch and s390.
148
149 WARNING: This feature breaks programs which rely on relocating
150 or unmapping system mappings. Known broken software at the time
151 of writing includes CHECKPOINT_RESTORE, UML, gVisor, rr. Therefore
152 this config can't be enabled universally.
153
154 When not to use mseal
155 =====================
156 Applications can apply sealing to any virtual memory region from userspace,
157 but it is *crucial to thoroughly analyze the mapping's lifetime* prior to
158 apply the sealing. This is because the sealed mapping *won’t be unmapped*
159 until the process terminates or the exec system call is invoked.
160
161 For example:
162 - aio/shm
163 aio/shm can call mmap and munmap on behalf of userspace, e.g.
164 ksys_shmdt() in shm.c. The lifetimes of those mapping are not tied to
165 the lifetime of the process. If those memories are sealed from userspace,
166 then munmap will fail, causing leaks in VMA address space during the
167 lifetime of the process.
168
169 - ptr allocated by malloc (heap)
170 Don't use mseal on the memory ptr return from malloc().
171 malloc() is implemented by allocator, e.g. by glibc. Heap manager might
172 allocate a ptr from brk or mapping created by mmap.
173 If an app calls mseal on a ptr returned from malloc(), this can affect
174 the heap manager's ability to manage the mappings; the outcome is
175 non-deterministic.
176
177 Example::
178
179 ptr = malloc(size);
180 /* don't call mseal on ptr return from malloc. */
181 mseal(ptr, size);
182 /* free will success, allocator can't shrink heap lower than ptr */
183 free(ptr);
184
185 mseal doesn't block
186 ===================
187 In a nutshell, mseal blocks certain mm syscall from modifying some of VMA's
188 attributes, such as protection bits (RWX). Sealed mappings doesn't mean the
189 memory is immutable.
190
191 As Jann Horn pointed out in [3], there are still a few ways to write
192 to RO memory, which is, in a way, by design. And those could be blocked
193 by different security measures.
194
195 Those cases are:
196
197 - Write to read-only memory through /proc/self/mem interface (FOLL_FORCE).
198 - Write to read-only memory through ptrace (such as PTRACE_POKETEXT).
199 - userfaultfd.
200
201 The idea that inspired this patch comes from Stephen Röttger’s work in V8
202 CFI [4]. Chrome browser in ChromeOS will be the first user of this API.
203
204 Reference
205 =========
206 - [1] https://github.com/apple-oss-distributions/xnu/blob/1031c584a5e37aff177559b9f69dbd3c8c3fd30a/osfmk/mach/vm_statistics.h#L274
207 - [2] https://man.openbsd.org/mimmutable.2
208 - [3] https://lore.kernel.org/lkml/CAG48ez3ShUYey+ZAFsU2i1RpQn0a5eOs2hzQ426FkcgnfUGLvA@mail.gmail.com
209 - [4] https://docs.google.com/document/d/1O2jwK4dxI3nRcOJuPYkonhTkNQfbmwdvxQMyXgeaRHo/edit#heading=h.bvaojj9fu6hc
210

3. 한국어 전문 번역

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

메모리 봉인의 목적

1-25

현대 CPU의 RW 및 NX 권한은 공격자가 임의 메모리에 코드를 쓴 뒤 곧바로 실행하는 일을 어렵게 만듭니다. 코드를 실행하려면 메모리에 X 비트가 있어야 하며, 그렇지 않으면 예외가 발생합니다.

메모리 봉인은 한 단계 더 나아가 매핑 자체가 변경되지 않도록 보호합니다. 손상된 포인터가 메모리 관리 인터페이스에 전달되더라도 신뢰해야 할 읽기 전용 메모리를 쓰기 가능하게 바꾸거나 `.text` 페이지를 다시 매핑하여 제어 흐름 무결성을 깨뜨리는 공격을 줄일 수 있습니다.

런타임 로더는 `.text`와 `.rodata` 페이지를 자동으로 봉인할 수 있고, 애플리케이션은 실행 중 보안상 중요한 데이터를 추가로 봉인할 수 있습니다. 유사한 기능으로 XNU의 `VM_FLAGS_PERMANENT`와 OpenBSD의 `mimmutable` 시스템 호출이 있습니다.

.. SPDX-License-Identifier: GPL-2.0

=====================
Introduction of mseal
=====================

:Author: Jeff Xu <jeffxu@chromium.org>

Modern CPUs support memory permissions such as RW and NX bits. The memory
permission feature improves security stance on memory corruption bugs, i.e.
the attacker can’t just write to arbitrary memory and point the code to it,
the memory has to be marked with X bit, or else an exception will happen.

Memory sealing additionally protects the mapping itself against
modifications. This is useful to mitigate memory corruption issues where a
corrupted pointer is passed to a memory management system. For example,
such an attacker primitive can break control-flow integrity guarantees
since read-only memory that is supposed to be trusted can become writable
or .text pages can get remapped. Memory sealing can automatically be
applied by the runtime loader to seal .text and .rodata pages and
applications can additionally seal security critical data at runtime.

A similar feature already exists in the XNU kernel with the
VM_FLAGS_PERMANENT flag [1] and on OpenBSD with the mimmutable syscall [2].

시스템 호출 계약과 오류

26-75

`mseal(void *addr, size_t len, unsigned long flags)`은 `addr`부터 `len` 길이의 가상 메모리 범위를 봉인합니다. 시작 주소는 할당된 VMA 안에 있고 페이지 경계에 맞아야 하며, 끝 주소도 할당된 VMA 안에 있어야 합니다. 시작과 끝 사이에 할당되지 않은 틈이 있어서는 안 됩니다. `len`은 커널이 암묵적으로 페이지 경계에 맞춥니다.

mseal 반환값
반환조건
`0`성공
`-EINVAL`알 수 없는 flags, 정렬되지 않은 addr, addr + len 오버플로
`-ENOMEM`시작 또는 끝이 미할당이거나 범위 중간에 미할당 틈 존재
`-EPERM`32비트 CPU처럼 sealing을 지원하지 않는 환경

입력 범위와 아키텍처 조건에 따른 결과입니다.

나열된 입력 오류에서는 범위가 부분적으로 바뀌지 않았다고 기대할 수 있습니다. 다만 VMA 병합·분할 오류나 프로세스가 지원 가능한 최대 VMA 수에 도달하는 등의 드문 내부 오류에서는 일부만 갱신될 수 있습니다.

mseal의 지속 속성
속성의미
64비트 전용32비트 CPU에서는 동작하지 않음
멱등성이미 봉인된 메모리를 다시 봉인해도 동작 없음이며 오류가 아님
`munseal` 없음한 번 봉인한 매핑은 해제할 수 없으며 파일의 `F_SEAL_SEAL`과 같은 방향
`flags` 예약현재는 향후 확장을 위해 남겨 둠

호출자가 수명과 되돌릴 수 없음까지 고려해야 하는 계약입니다.

SYSCALL
=======
mseal syscall signature
-----------------------
   ``int mseal(void *addr, size_t len, unsigned long flags)``

   **addr**/**len**: virtual memory address range.
      The address range set by **addr**/**len** must meet:
         - The start address must be in an allocated VMA.
         - The start address must be page aligned.
         - The end address (**addr** + **len**) must be in an allocated VMA.
         - no gap (unallocated memory) between start and end address.

      The ``len`` will be paged aligned implicitly by the kernel.

   **flags**: reserved for future use.

   **Return values**:
      - **0**: Success.
      - **-EINVAL**:
         * Invalid input ``flags``.
         * The start address (``addr``) is not page aligned.
         * Address range (``addr`` + ``len``) overflow.
      - **-ENOMEM**:
         * The start address (``addr``) is not allocated.
         * The end address (``addr`` + ``len``) is not allocated.
         * A gap (unallocated memory) between start and end address.
      - **-EPERM**:
         * sealing is supported only on 64-bit CPUs, 32-bit is not supported.

   **Note about error return**:
      - For above error cases, users can expect the given memory range is
        unmodified, i.e. no partial update.
      - There might be other internal errors/cases not listed here, e.g.
        error during merging/splitting VMAs, or the process reaching the maximum
        number of supported VMAs. In those cases, partial updates to the given
        memory range could happen. However, those cases should be rare.

   **Architecture support**:
      mseal only works on 64-bit CPUs, not 32-bit CPUs.

   **Idempotent**:
      users can call mseal multiple times. mseal on an already sealed memory
      is a no-action (not error).

   **no munseal**
      Once mapping is sealed, it can't be unsealed. The kernel should never
      have munseal, this is consistent with other sealing feature, e.g.
      F_SEAL_SEAL for file.

차단되는 메모리 관리 작업

76-124

봉인된 매핑은 프로세스가 종료될 때까지 메모리에 남습니다. 예제처럼 `mmap()`으로 만든 범위를 `mseal()`한 뒤 `munmap()`하면 해제 호출은 실패합니다.

봉인된 매핑에서 차단되는 작업
분류호출 또는 동작차단 이유
매핑 제거·교체`munmap`, `mmap`, `mremap`빈 공간 생성이나 다른 속성의 새 매핑으로 덮어쓰기 방지
권한 변경`mprotect`, `pkey_mprotect`매핑의 RWX 보호 비트 변경 방지
파괴적 조언`MADV_DONTNEED`, `MADV_FREE`, `MADV_DONTNEED_LOCKED`, `MADV_DONTFORK`, `MADV_WIPEONFORK`페이지 폐기로 익명 메모리 내용이 사실상 0으로 바뀌는 효과 방지

주소 공간의 교체, 권한 변경, 내용 파괴를 막습니다.

차단된 호출은 `-EPERM`을 반환합니다. 그러나 반환 시 전체 범위의 원자성은 호출마다 다르므로, 실패했다는 사실만으로 모든 VMA가 원래 상태라고 가정하면 안 됩니다.

-EPERM 시 변경 원자성
호출결과
`munmap`원자적. 범위 안에 봉인된 VMA가 하나라도 있으면 어떤 VMA도 갱신하지 않음
`mprotect`, `pkey_mprotect`, `madvise`부분 갱신 가능. 봉인된 VMA에 닿기 전의 VMA가 먼저 바뀔 수 있음
`mmap`, `mremap`동작이 정의되지 않음

봉인된 VMA를 만났을 때 앞부분이 이미 바뀌었을 가능성을 구분합니다.

Blocked mm syscall for sealed mapping
-------------------------------------
   It might be important to note: **once the mapping is sealed, it will
   stay in the process's memory until the process terminates**.

   Example::

         *ptr = mmap(0, 4096, PROT_READ, MAP_ANONYMOUS | MAP_PRIVATE, 0, 0);
         rc = mseal(ptr, 4096, 0);
         /* munmap will fail */
         rc = munmap(ptr, 4096);
         assert(rc < 0);

   Blocked mm syscall:
      - munmap
      - mmap
      - mremap
      - mprotect and pkey_mprotect
      - some destructive madvise behaviors: MADV_DONTNEED, MADV_FREE,
        MADV_DONTNEED_LOCKED, MADV_FREE, MADV_DONTFORK, MADV_WIPEONFORK

   The first set of syscalls to block is munmap, mremap, mmap. They can
   either leave an empty space in the address space, therefore allowing
   replacement with a new mapping with new set of attributes, or can
   overwrite the existing mapping with another mapping.

   mprotect and pkey_mprotect are blocked because they changes the
   protection bits (RWX) of the mapping.

   Certain destructive madvise behaviors, specifically MADV_DONTNEED,
   MADV_FREE, MADV_DONTNEED_LOCKED, and MADV_WIPEONFORK, can introduce
   risks when applied to anonymous memory by threads lacking write
   permissions. Consequently, these operations are prohibited under such
   conditions. The aforementioned behaviors have the potential to modify
   region contents by discarding pages, effectively performing a memset(0)
   operation on the anonymous memory.

   Kernel will return -EPERM for blocked syscalls.

   When blocked syscall return -EPERM due to sealing, the memory regions may
   or may not be changed, depends on the syscall being blocked:

      - munmap: munmap is atomic. If one of VMAs in the given range is
        sealed, none of VMAs are updated.
      - mprotect, pkey_mprotect, madvise: partial update might happen, e.g.
        when mprotect over multiple VMAs, mprotect might update the beginning
        VMAs before reaching the sealed VMA and return -EPERM.
      - mmap and mremap: undefined behavior.

사용 사례와 시스템 매핑

125-153

glibc 동적 링커는 ELF 실행 파일을 적재할 때 매핑 세그먼트를 봉인할 수 있고, Chrome 브라우저는 보안에 민감한 데이터 구조를 보호할 수 있습니다.

커널이 만드는 시스템 매핑에는 `vdso`, `vvar`, `vvar_vclock`, ARM 호환 모드의 `vectors`와 `sigpage`, `uprobes`가 포함됩니다. 읽기 전용 또는 실행 전용인 이 매핑을 봉인하면 쓰기 가능 상태로 바꾸거나 다른 속성으로 해제·재매핑하는 일을 막을 수 있습니다.

시스템 매핑 봉인 구성
구성역할
`CONFIG_ARCH_SUPPORTS_MSEAL_SYSTEM_MAPPINGS`아키텍처가 시스템 매핑 봉인을 지원함을 표시
`CONFIG_MSEAL_SYSTEM_MAPPINGS`해당 아키텍처의 모든 시스템 매핑을 봉인
현재 지원 아키텍처x86-64, arm64, loongarch, s390

아키텍처 지원과 실제 활성화를 구분합니다.

이 설정은 시스템 매핑을 옮기거나 해제하는 프로그램을 깨뜨립니다. 문서 작성 시점의 알려진 영향 대상은 `CHECKPOINT_RESTORE`, UML, gVisor, rr이므로 모든 구성에서 보편적으로 켤 수 없습니다.

Use cases
=========
- glibc:
  The dynamic linker, during loading ELF executables, can apply sealing to
  mapping segments.

- Chrome browser: protect some security sensitive data structures.

- System mappings:
  The system mappings are created by the kernel and includes vdso, vvar,
  vvar_vclock, vectors (arm compat-mode), sigpage (arm compat-mode), uprobes.

  Those system mappings are readonly only or execute only, memory sealing can
  protect them from ever changing to writable or unmmap/remapped as different
  attributes. This is useful to mitigate memory corruption issues where a
  corrupted pointer is passed to a memory management system.

  If supported by an architecture (CONFIG_ARCH_SUPPORTS_MSEAL_SYSTEM_MAPPINGS),
  the CONFIG_MSEAL_SYSTEM_MAPPINGS seals all system mappings of this
  architecture.

  The following architectures currently support this feature: x86-64, arm64,
  loongarch and s390.

  WARNING: This feature breaks programs which rely on relocating
  or unmapping system mappings. Known broken software at the time
  of writing includes CHECKPOINT_RESTORE, UML, gVisor, rr. Therefore
  this config can't be enabled universally.

mseal을 사용하지 말아야 할 경우

154-184

사용자 공간은 어떤 가상 메모리 영역에도 sealing을 적용할 수 있지만, 먼저 매핑의 수명을 철저히 분석해야 합니다. 봉인된 매핑은 프로세스 종료 또는 `exec` 시스템 호출 전에는 해제되지 않습니다.

부적합한 대상
대상문제
aio/shm 매핑사용자 공간을 대신해 `mmap`과 `munmap`을 호출하며 수명이 프로세스와 묶이지 않음. 봉인하면 `munmap` 실패로 VMA 주소 공간 누수 발생
`malloc()`이 반환한 포인터allocator가 brk 또는 mmap 매핑을 관리하므로 일부 포인터 봉인의 영향이 비결정적

프로세스 수명과 매핑 관리자의 기대를 깨뜨리는 대표 사례입니다.

heap 포인터를 봉인한 뒤 `free()` 자체는 성공할 수 있지만 allocator는 그 포인터보다 아래로 heap을 축소하지 못할 수 있습니다. 따라서 할당기 소유 메모리의 일부 주소만 보고 `mseal()`을 호출해서는 안 됩니다.

When not to use mseal
=====================
Applications can apply sealing to any virtual memory region from userspace,
but it is *crucial to thoroughly analyze the mapping's lifetime* prior to
apply the sealing. This is because the sealed mapping *won’t be unmapped*
until the process terminates or the exec system call is invoked.

For example:
   - aio/shm
     aio/shm can call mmap and  munmap on behalf of userspace, e.g.
     ksys_shmdt() in shm.c. The lifetimes of those mapping are not tied to
     the lifetime of the process. If those memories are sealed from userspace,
     then munmap will fail, causing leaks in VMA address space during the
     lifetime of the process.

   - ptr allocated by malloc (heap)
     Don't use mseal on the memory ptr return from malloc().
     malloc() is implemented by allocator, e.g. by glibc. Heap manager might
     allocate a ptr from brk or mapping created by mmap.
     If an app calls mseal on a ptr returned from malloc(), this can affect
     the heap manager's ability to manage the mappings; the outcome is
     non-deterministic.

     Example::

        ptr = malloc(size);
        /* don't call mseal on ptr return from malloc. */
        mseal(ptr, size);
        /* free will success, allocator can't shrink heap lower than ptr */
        free(ptr);

mseal이 막지 않는 쓰기

185-203

`mseal`은 일부 mm 시스템 호출이 보호 비트 같은 VMA 속성을 바꾸는 것을 막을 뿐이며, 봉인된 메모리가 불변이라는 뜻은 아닙니다. 다른 설계상 경로는 별도의 보안 수단으로 통제해야 합니다.

봉인 뒤에도 가능한 경로
경로세부 사항
`/proc/self/mem``FOLL_FORCE`를 통해 읽기 전용 메모리에 쓰기
`ptrace``PTRACE_POKETEXT` 같은 요청으로 쓰기
`userfaultfd`사용자 공간 페이지 결함 처리 경로

읽기 전용 메모리에 영향을 줄 수 있지만 mseal의 차단 범위 밖에 있습니다.

이 API의 발상은 Stephen Röttger의 V8 CFI 작업에서 왔으며, ChromeOS의 Chrome 브라우저가 첫 사용자가 될 예정이라고 문서는 설명합니다.

mseal doesn't block
===================
In a nutshell, mseal blocks certain mm syscall from modifying some of VMA's
attributes, such as protection bits (RWX). Sealed mappings doesn't mean the
memory is immutable.

As Jann Horn pointed out in [3], there are still a few ways to write
to RO memory, which is, in a way, by design. And those could be blocked
by different security measures.

Those cases are:

   - Write to read-only memory through /proc/self/mem interface (FOLL_FORCE).
   - Write to read-only memory through ptrace (such as PTRACE_POKETEXT).
   - userfaultfd.

The idea that inspired this patch comes from Stephen Röttger’s work in V8
CFI [4]. Chrome browser in ChromeOS will be the first user of this API.

참고 자료

204-209

참고 자료는 XNU의 영구 매핑 플래그, OpenBSD `mimmutable(2)`, 읽기 전용 메모리 쓰기 경로에 관한 LKML 논의, V8 CFI 설계 문서로 이어집니다.

Reference
=========
- [1] https://github.com/apple-oss-distributions/xnu/blob/1031c584a5e37aff177559b9f69dbd3c8c3fd30a/osfmk/mach/vm_statistics.h#L274
- [2] https://man.openbsd.org/mimmutable.2
- [3] https://lore.kernel.org/lkml/CAG48ez3ShUYey+ZAFsU2i1RpQn0a5eOs2hzQ426FkcgnfUGLvA@mail.gmail.com
- [4] https://docs.google.com/document/d/1O2jwK4dxI3nRcOJuPYkonhTkNQfbmwdvxQMyXgeaRHo/edit#heading=h.bvaojj9fu6hc