1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
|
.. SPDX-License-Identifier: GPL-2.0
==================
Kernel Page Tables
==================
Introduction
============
The kernel page tables are created early during boot and, unlike the page
tables of user processes, most of them remain static throughout the system
lifetime.
Every architecture has a direct map (also called linear map) that maps the
physical memory at a fixed offset, so that a physical address can be
translated to a kernel virtual address with simple arithmetic. On most
architectures the direct map is a part of the kernel page tables, with a few
exceptions described in the `Direct map`_ section below.
On 32-bit systems with high memory the direct map covers only a part of the
physical memory, see Documentation/mm/highmem.rst.
The vmalloc area, present on every architecture with an MMU, is used for
allocations of virtually contiguous memory whose backing pages are not
necessarily physically contiguous, and for mapping of the device memory. Its
page tables are created and torn down at runtime, see
Documentation/mm/vmalloc.rst.
Architectures that use the `SPARSEMEM_VMEMMAP` memory model reserve a range of
kernel address space for the memory map, so that `struct page` objects appear
as a virtually contiguous array indexed by the page frame number, see
Documentation/mm/memory-model.rst.
Besides these, the kernel image may be mapped in a dedicated part of the
kernel address space rather than accessed through the direct map. In that
case its mapping is an alias of the direct map of the physical memory the
image occupies.
The rest of the kernel address space is architecture specific. For instance,
x86 has a region for the EFI runtime services and s390 has a region for the
code that has to run in the 31-bit addressing mode.
Direct map
==========
On most architectures the direct map is an ordinary part of the kernel page
tables. It is created early during boot with the largest pages the hardware
and the kernel configuration allow.
Several architectures are different.
MIPS
----
MIPS does not map the physical memory with page tables at all. Instead, a
part of the kernel virtual address space is a window into the physical
address space: the hardware translates the addresses that fall into that
window by a fixed transformation of the address bits, without walking the
page tables and without using the TLB. The memory attributes, such as
cacheability and the privilege level required to access the memory, are a
property of the window rather than of an individual page.
There are no page table entries describing the direct map, so its properties
cannot be changed for an individual page. On 32-bit systems the window covers
only 512 MiB of the physical memory, so everything above that is high memory.
LoongArch
---------
Like MIPS, LoongArch maps the physical memory with a hardware window. The
window covers 256 TiB of the physical address space on 64-bit and 512 MiB on
32-bit systems, and everything above that is high memory.
The window occupies the lower part of the kernel address space. The upper
part, which includes the vmalloc area, is mapped with kernel page tables.
PowerPC with the hash MMU
-------------------------
On 64-bit PowerPC systems with the hash MMU the direct map does not exist in
the Linux page tables. It is installed into the hardware hash page table early
during boot.
Modifying such mappings requires updating the hash page table directly, and
the hash MMU code implements this only for the kernel image permissions,
`debug_pagealloc` and KFENCE.
With the radix MMU the direct map is a part of the ordinary kernel page
tables.
Modifying the kernel page tables
================================
Except for the vmalloc area, the kernel page tables are mostly static. Still,
there are cases when the permissions of existing kernel mappings have to be
updated, for instance when a module is loaded and its text becomes read-only
and executable, or when a page is temporarily removed from the direct map to
reduce its exposure.
There are two families of functions for this, both declared in
`include/linux/set_memory.h`:
* `set_memory_*()` change permissions of an arbitrary kernel mapping. They
take a kernel virtual address and the number of pages.
* `set_direct_map_*()` change permissions of the direct mapping for the range
of page frames starting at the page represented by a `struct page`. They take
a `struct page` pointer and the number of pages.
Architectures that implement `set_memory()` select `CONFIG_ARCH_HAS_SET_MEMORY`
Architectures that implement `set_direct_map()` select
`CONFIG_ARCH_HAS_SET_DIRECT_MAP`.
Common semantics
----------------
Ranges
~~~~~~
The `set_memory()` functions expect a range described by a start address and a
number of pages. The address must be page aligned and the entire range must be
covered by page table entries the architecture knows how to update.
The entries may be marked as not present, set_memory_p() and set_memory_valid()
exist exactly to bring such a mapping back.
When a range does not qualify, an architecture will usually say so by returning
an error and sometimes by a WARN()ing as well, unless it prefers to keep it to
itself and return success, see `Architecture specific differences`_.
The `set_direct_map()` functions expect a range described by the first
`struct page` and a number of pages, and they update the direct map starting
at that page.
The pages that follow the first one are updated regardless of what they are, so
the caller has to make sure that the range does not extend beyond the memory it
owns.
Some architectures cannot split a large mapping, and they reject a range that
is a part of one, see `Architecture specific differences`_.
Calling `set_memory()` with the number of pages set to zero is a no-op that
returns success, except on arm64, where doing nothing to the wrong address is
still an error.
Aliases
~~~~~~~
A physical page may be mapped several times, for instance in the direct map
and in the vmalloc area, and the permissions of these mappings may differ.
Whether the direct map alias is updated by a `set_memory()` call, and
which permission bits make it there, is entirely up to the architecture, and
there is not much agreement between them, see
`Architecture specific differences`_.
Relying on that is a gamble; code that needs the direct map alias to change
should say so with the `set_direct_map()` APIs.
Failures and partial updates
~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Both families of functions return 0 on success and a negative error code on
failure. The most common failures are `-EINVAL` for a range that cannot be
handled and `-ENOMEM` when splitting a large mapping fails to allocate a page
table.
Some of the range checks happen upfront, so their failure leaves the page
tables unchanged.
**The update is not atomic and there is no rollback.**
The architecture implementations walk the range and update the page tables as
they go, and they stop at the first entry that cannot be updated. When an error
is returned, an arbitrary prefix of the range may have been updated already,
and the same is true for the direct map alias when the architecture updates it.
For example, when a range spans two large mappings and splitting the second
one fails because there is no memory for a page table, the first one is
already split and updated by the time the error is returned.
None of the APIs inform the caller where in the range they failed, so reverting
such a partial update is possible in principle but unreliable in practice.
The caller may try to restore the original permissions over the entire range,
but that revert goes through the very code that has just failed, which does
not inspire much confidence.
The callers should therefore be prepared to give up on the memory in question:
leak it or panic, but never return it to the allocator before the permissions
are restored and never assume that the requested permissions are in effect.
Neither option is appealing, but both beat handing out a page whose
permissions nobody knows.
TLB flushing
~~~~~~~~~~~~
The `set_memory()` functions flush the TLB for the affected range before
they return, so that the new permissions are in effect for every CPU.
The `set_direct_map()` functions have `_noflush` in their names because when
they were first introduced on x86, the intention was that the TLB flushing
could be optimized by letting the caller handle it.
For example, vfree() batches the TLB flushes for the areas allocated with
`VM_FLUSH_RESET_PERMS`, folding the flush of the direct map into the flush it
has to do for the vmalloc mapping anyway.
Some architectures flush the TLB in the `_noflush` functions anyway, so the
name is best read as a suggestion. It does not make the flush by the caller
unnecessary, it only makes it more expensive.
A caller that changes the permissions to more restrictive ones must flush the
TLB itself.
Context
~~~~~~~
Architectures use different locking mechanisms to synchronize kernel page table
updates, and both families of functions may sleep, for instance when they
allocate memory to split a large mapping.
The caller cannot presume it is safe to call these APIs from an atomic context.
The `set_direct_map()` functions must not be called for high memory pages,
which have no direct map alias to update.
Unimplemented APIs silently succeed
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
When an architecture does not implement these APIs, the generic stubs in
`include/linux/set_memory.h` return 0, that is, they report success for work
they have no intention of doing.
The same happens inside several architecture implementations. The arm64
`set_direct_map()` functions return 0 when can_set_direct_map() is false, and
the LoongArch `set_memory()` functions return 0 for the addresses in its
windowed direct mapping, which is not backed by page tables at all.
Returning success without actually updating the page tables is a deliberate
trade-off that keeps the callers free of `#ifdef`\ s, but they have to realize:
**a return value of 0 does not imply that the permissions were actually
changed.**
For best-effort hardening that is good enough. When correctness or security
depends on the permissions, the caller has to make sure the architecture
really implements what it needs. For instance, secretmem depends on
`CONFIG_ARCH_HAS_SET_DIRECT_MAP` and calls can_set_direct_map() at runtime.
Architecture specific differences
=================================
The APIs are implemented by seven architectures and, beyond the common
semantics described above, their behaviour differs in several respects.
Which of the APIs are implemented:
========= ===================== =========================
Arch `ARCH_HAS_SET_MEMORY` `ARCH_HAS_SET_DIRECT_MAP`
========= ===================== =========================
arm yes no
arm64 yes yes
loongarch yes yes
powerpc yes no
riscv yes (MMU only) yes (MMU only)
s390 yes yes
x86 yes yes
========= ===================== =========================
Only set_memory_ro(), set_memory_rw(), set_memory_x() and set_memory_nx() are
available everywhere, and even these are not universal: some architectures
restrict the ranges that can be modified, for instance arm64 rejects direct map
addresses and accepts only addresses in vmalloc space. The architectures that
may run on hardware without an execute permission bit, like x86 and s390,
silently skip the update of the executable bit.
set_memory_rox() has a generic implementation that calls set_memory_ro() and
set_memory_x() in turn; PowerPC, s390 and x86 override it with a single-pass
version.
Several architectures define additional APIs. Some of those may have identical
semantics but different names. For example, making a mapping present or not
present is spelled differently: set_memory_p() and set_memory_np() on x86 and
PowerPC, set_memory_valid() on arm and arm64.
The direct map and the kernel image are normally mapped with the largest
possible pages, and changing the permissions of a single page inside such a
mapping requires splitting it, which not every architecture can do.
arm
---
* Does not implement `set_direct_map()`.
* Provides set_memory_valid().
* set_memory_ro(), set_memory_rw(), set_memory_x() and set_memory_nx() accept
only vmalloc and module addresses.
* set_memory_valid() accepts any address.
* Does not update mapping aliases.
arm64
-----
* Provides set_memory_valid().
* Provides the memory encryption helpers, which are effective only when the
kernel runs as a confidential guest.
* set_memory_ro(), set_memory_rw(), set_memory_x() and set_memory_nx() accept
only vmalloc and module addresses:
- the range must fit in the VM area that contains its start
- the VM area must have `VM_ALLOC` set and `VM_ALLOW_HUGE_VMAP` clear
* set_memory_valid() accepts any address.
* The encryption helpers accept only direct map addresses.
* The `set_memory()` functions propagate the read-only and the read-write
changes to the direct map alias when `rodata=full` is in effect.
* Splits leaf mappings before the update on the hardware that supports it.
The split itself may be partial when it fails midway, but the permissions are
left untouched in that case.
Without support for splitting large mappings, a range that covers a leaf
entry only partially fails with a WARN()ing and `-EINVAL`.
If a range spans one or more full leaf entries and a partial leaf entry, the
permissions of the full leaf entries are updated before the failure.
* The `set_direct_map()` functions return 0 without doing anything when the
direct map cannot be modified, see can_set_direct_map().
* Skips the TLB flush in `set_memory()` when the update only turns an invalid
mapping into a valid one.
* Does not flush TLB in `set_direct_map()`.
LoongArch
---------
* Accepts only the addresses above the hardware window and silently returns
success for the rest, see `Direct map`_.
* Does not update mapping aliases.
* Does not split anything: a leaf entry is updated as a whole, which changes
the permissions of the entire large mapping.
* Flushes the TLB in `set_direct_map()`.
PowerPC
-------
* Does not implement `set_direct_map()`.
* Provides set_memory_np() and set_memory_p().
* Rejects huge vmalloc mappings.
* With the hash MMU on 64-bit systems accepts nothing but the vmalloc and the
I/O regions.
* With the radix MMU accepts direct map addresses, but still cannot split a
large mapping.
* Does not update mapping aliases.
riscv
-----
* Implements both APIs only when the MMU is enabled.
* Provides set_memory_rw_nx().
* The `set_memory()` functions accept any mapped kernel address, including the
direct map, but a vmalloc range must have the `pages` array of its VM area
populated, which rules out vmap() and ioremap() mappings.
* On 64-bit systems the `set_memory()` functions update the direct map alias of
a vmalloc range, including the executable bit.
* Does not split vmalloc ranges: a leaf entry is updated as a whole, which
changes the permissions of the entire large mapping.
* Splits the direct map on 64-bit systems.
* Flushes the TLB in `set_direct_map()`.
s390
----
* Provides set_memory_4k(), set_memory_rwnx() and the
`__set_memory_*(start, end)` variants that take a range rather than a page
count.
* The `set_memory()` functions accept any mapped kernel address, including the
direct map.
* Skips the update of the executable bit when the hardware has no support for
it.
* The `set_memory()` functions propagate only the read-only and read-write
changes to the direct map alias of a `VM_ALLOC` area, and deliberately not
the executable bit.
* Splits leaf PUD and PMD entries when the range is not aligned to them or when
set_memory_4k() is requested.
* Updates the page table entries with instructions that invalidate the
corresponding TLB entries, so no separate flush is needed anywhere.
x86
---
* Provides the largest set of operations on top of the common ones:
- the cache attribute helpers: set_memory_uc(), set_memory_wc(),
set_memory_wb()
- presence control: set_memory_np() and set_memory_p()
- set_memory_4k()
- set_memory_global() and set_memory_nonglobal()
- the array variants that operate on `struct page` arrays or arrays of
virtual addresses
- memory encryption: set_memory_encrypted() and set_memory_decrypted()
* The `set_memory()` functions accept any mapped kernel address, including the
direct map, and silently succeed for the unmapped holes inside it.
* Does nothing in set_memory_x() and set_memory_nx() when the CPU has no
execute permission bit.
* The `set_memory()` functions apply the change to the direct map alias and,
for the kernel image, to the high kernel mapping. The NX bit is never
propagated, so that the direct map stays non-executable.
* Splits large mappings on demand and can collapse them back when the
permissions become uniform again.
* Does not flush the TLB in `set_direct_map()`, but splitting a large
mapping flushes it anyway.
|