Skip to content

Commit 3e35d30

Browse files
mrutland-armctmarinas
authored andcommitted
arm64: module: rework module VA range selection
Currently, the modules region is 128M in size, which is a problem for some large modules. Shanker reports [1] that the NVIDIA GPU driver alone can consume 110M of module space in some configurations. We'd like to make the modules region a full 2G such that we can always make use of a 2G range. It's possible to build kernel images which are larger than 128M in some configurations, such as when many debug options are selected and many drivers are built in. In these configurations, we can't legitimately select a base for a 128M module region, though we currently select a value for which allocation will fail. It would be nicer to have a diagnostic message in this case. Similarly, in theory it's possible to build a kernel image which is larger than 2G and which cannot support modules. While this isn't likely to be the case for any realistic kernel deplyed in the field, it would be nice if we could print a diagnostic in this case. This patch reworks the module VA range selection to use a 2G range, and improves handling of cases where we cannot select legitimate module regions. We now attempt to select a 128M region and a 2G region: * The 128M region is selected such that modules can use direct branches (with JUMP26/CALL26 relocations) to branch to kernel code and other modules, and so that modules can reference data and text (using PREL32 relocations) anywhere in the kernel image and other modules. This region covers the entire kernel image (rather than just the text) to ensure that all PREL32 relocations are in range even when the kernel data section is absurdly large. Where we cannot allocate from this region, we'll fall back to the full 2G region. * The 2G region is selected such that modules can use direct branches with PLTs to branch to kernel code and other modules, and so that modules can use reference data and text (with PREL32 relocations) in the kernel image and other modules. This region covers the entire kernel image, and the 128M region (if one is selected). The two module regions are randomized independently while ensuring the constraints described above. [1] https://lore.kernel.org/linux-arm-kernel/[email protected]/ Signed-off-by: Mark Rutland <[email protected]> Reviewed-by: Ard Biesheuvel <[email protected]> Cc: Shanker Donthineni <[email protected]> Cc: Will Deacon <[email protected]> Tested-by: Shanker Donthineni <[email protected]> Link: https://lore.kernel.org/r/[email protected] Signed-off-by: Catalin Marinas <[email protected]>
1 parent ea3752b commit 3e35d30

File tree

3 files changed

+99
-50
lines changed

3 files changed

+99
-50
lines changed

Documentation/arm64/memory.rst

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -33,8 +33,8 @@ AArch64 Linux memory layout with 4KB pages + 4 levels (48-bit)::
3333
0000000000000000 0000ffffffffffff 256TB user
3434
ffff000000000000 ffff7fffffffffff 128TB kernel logical memory map
3535
[ffff600000000000 ffff7fffffffffff] 32TB [kasan shadow region]
36-
ffff800000000000 ffff800007ffffff 128MB modules
37-
ffff800008000000 fffffbffefffffff 124TB vmalloc
36+
ffff800000000000 ffff80007fffffff 2GB modules
37+
ffff800080000000 fffffbffefffffff 124TB vmalloc
3838
fffffbfff0000000 fffffbfffdffffff 224MB fixed mappings (top down)
3939
fffffbfffe000000 fffffbfffe7fffff 8MB [guard region]
4040
fffffbfffe800000 fffffbffff7fffff 16MB PCI I/O space
@@ -50,8 +50,8 @@ AArch64 Linux memory layout with 64KB pages + 3 levels (52-bit with HW support):
5050
0000000000000000 000fffffffffffff 4PB user
5151
fff0000000000000 ffff7fffffffffff ~4PB kernel logical memory map
5252
[fffd800000000000 ffff7fffffffffff] 512TB [kasan shadow region]
53-
ffff800000000000 ffff800007ffffff 128MB modules
54-
ffff800008000000 fffffbffefffffff 124TB vmalloc
53+
ffff800000000000 ffff80007fffffff 2GB modules
54+
ffff800080000000 fffffbffefffffff 124TB vmalloc
5555
fffffbfff0000000 fffffbfffdffffff 224MB fixed mappings (top down)
5656
fffffbfffe000000 fffffbfffe7fffff 8MB [guard region]
5757
fffffbfffe800000 fffffbffff7fffff 16MB PCI I/O space

arch/arm64/include/asm/memory.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,7 @@
4646
#define KIMAGE_VADDR (MODULES_END)
4747
#define MODULES_END (MODULES_VADDR + MODULES_VSIZE)
4848
#define MODULES_VADDR (_PAGE_END(VA_BITS_MIN))
49-
#define MODULES_VSIZE (SZ_128M)
49+
#define MODULES_VSIZE (SZ_2G)
5050
#define VMEMMAP_START (-(UL(1) << (VA_BITS - VMEMMAP_SHIFT)))
5151
#define VMEMMAP_END (VMEMMAP_START + VMEMMAP_SIZE)
5252
#define PCI_IO_END (VMEMMAP_START - SZ_8M)

arch/arm64/kernel/module.c

Lines changed: 94 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,8 @@
77
* Author: Will Deacon <[email protected]>
88
*/
99

10+
#define pr_fmt(fmt) "Modules: " fmt
11+
1012
#include <linux/bitops.h>
1113
#include <linux/elf.h>
1214
#include <linux/ftrace.h>
@@ -24,72 +26,119 @@
2426
#include <asm/scs.h>
2527
#include <asm/sections.h>
2628

27-
static u64 __ro_after_init module_alloc_base = (u64)_etext - MODULES_VSIZE;
29+
static u64 module_direct_base __ro_after_init = 0;
30+
static u64 module_plt_base __ro_after_init = 0;
2831

29-
#ifdef CONFIG_RANDOMIZE_BASE
30-
static int __init kaslr_module_init(void)
32+
/*
33+
* Choose a random page-aligned base address for a window of 'size' bytes which
34+
* entirely contains the interval [start, end - 1].
35+
*/
36+
static u64 __init random_bounding_box(u64 size, u64 start, u64 end)
3137
{
32-
u64 module_range;
33-
u32 seed;
38+
u64 max_pgoff, pgoff;
3439

35-
if (!kaslr_enabled())
40+
if ((end - start) >= size)
3641
return 0;
3742

38-
seed = get_random_u32();
43+
max_pgoff = (size - (end - start)) / PAGE_SIZE;
44+
pgoff = get_random_u32_inclusive(0, max_pgoff);
3945

40-
if (IS_ENABLED(CONFIG_RANDOMIZE_MODULE_REGION_FULL)) {
41-
/*
42-
* Randomize the module region over a 2 GB window covering the
43-
* kernel. This reduces the risk of modules leaking information
44-
* about the address of the kernel itself, but results in
45-
* branches between modules and the core kernel that are
46-
* resolved via PLTs. (Branches between modules will be
47-
* resolved normally.)
48-
*/
49-
module_range = SZ_2G - (u64)(_end - _stext);
50-
module_alloc_base = max((u64)_end - SZ_2G, (u64)MODULES_VADDR);
46+
return start - pgoff * PAGE_SIZE;
47+
}
48+
49+
/*
50+
* Modules may directly reference data and text anywhere within the kernel
51+
* image and other modules. References using PREL32 relocations have a +/-2G
52+
* range, and so we need to ensure that the entire kernel image and all modules
53+
* fall within a 2G window such that these are always within range.
54+
*
55+
* Modules may directly branch to functions and code within the kernel text,
56+
* and to functions and code within other modules. These branches will use
57+
* CALL26/JUMP26 relocations with a +/-128M range. Without PLTs, we must ensure
58+
* that the entire kernel text and all module text falls within a 128M window
59+
* such that these are always within range. With PLTs, we can expand this to a
60+
* 2G window.
61+
*
62+
* We chose the 128M region to surround the entire kernel image (rather than
63+
* just the text) as using the same bounds for the 128M and 2G regions ensures
64+
* by construction that we never select a 128M region that is not a subset of
65+
* the 2G region. For very large and unusual kernel configurations this means
66+
* we may fall back to PLTs where they could have been avoided, but this keeps
67+
* the logic significantly simpler.
68+
*/
69+
static int __init module_init_limits(void)
70+
{
71+
u64 kernel_end = (u64)_end;
72+
u64 kernel_start = (u64)_text;
73+
u64 kernel_size = kernel_end - kernel_start;
74+
75+
/*
76+
* The default modules region is placed immediately below the kernel
77+
* image, and is large enough to use the full 2G relocation range.
78+
*/
79+
BUILD_BUG_ON(KIMAGE_VADDR != MODULES_END);
80+
BUILD_BUG_ON(MODULES_VSIZE < SZ_2G);
81+
82+
if (!kaslr_enabled()) {
83+
if (kernel_size < SZ_128M)
84+
module_direct_base = kernel_end - SZ_128M;
85+
if (kernel_size < SZ_2G)
86+
module_plt_base = kernel_end - SZ_2G;
5187
} else {
52-
/*
53-
* Randomize the module region by setting module_alloc_base to
54-
* a PAGE_SIZE multiple in the range [_etext - MODULES_VSIZE,
55-
* _stext) . This guarantees that the resulting region still
56-
* covers [_stext, _etext], and that all relative branches can
57-
* be resolved without veneers unless this region is exhausted
58-
* and we fall back to a larger 2GB window in module_alloc()
59-
* when ARM64_MODULE_PLTS is enabled.
60-
*/
61-
module_range = MODULES_VSIZE - (u64)(_etext - _stext);
88+
u64 min = kernel_start;
89+
u64 max = kernel_end;
90+
91+
if (IS_ENABLED(CONFIG_RANDOMIZE_MODULE_REGION_FULL)) {
92+
pr_info("2G module region forced by RANDOMIZE_MODULE_REGION_FULL\n");
93+
} else {
94+
module_direct_base = random_bounding_box(SZ_128M, min, max);
95+
if (module_direct_base) {
96+
min = module_direct_base;
97+
max = module_direct_base + SZ_128M;
98+
}
99+
}
100+
101+
module_plt_base = random_bounding_box(SZ_2G, min, max);
62102
}
63103

64-
/* use the lower 21 bits to randomize the base of the module region */
65-
module_alloc_base += (module_range * (seed & ((1 << 21) - 1))) >> 21;
66-
module_alloc_base &= PAGE_MASK;
104+
pr_info("%llu pages in range for non-PLT usage",
105+
module_direct_base ? (SZ_128M - kernel_size) / PAGE_SIZE : 0);
106+
pr_info("%llu pages in range for PLT usage",
107+
module_plt_base ? (SZ_2G - kernel_size) / PAGE_SIZE : 0);
67108

68109
return 0;
69110
}
70-
subsys_initcall(kaslr_module_init)
71-
#endif
111+
subsys_initcall(module_init_limits);
72112

73113
void *module_alloc(unsigned long size)
74114
{
75-
u64 module_alloc_end = module_alloc_base + MODULES_VSIZE;
76-
void *p;
115+
void *p = NULL;
77116

78117
/*
79118
* Where possible, prefer to allocate within direct branch range of the
80-
* kernel such that no PLTs are necessary. This may fail, so we pass
81-
* __GFP_NOWARN to silence the resulting warning.
119+
* kernel such that no PLTs are necessary.
82120
*/
83-
p = __vmalloc_node_range(size, MODULE_ALIGN, module_alloc_base,
84-
module_alloc_end, GFP_KERNEL | __GFP_NOWARN,
85-
PAGE_KERNEL, 0, NUMA_NO_NODE,
86-
__builtin_return_address(0));
121+
if (module_direct_base) {
122+
p = __vmalloc_node_range(size, MODULE_ALIGN,
123+
module_direct_base,
124+
module_direct_base + SZ_128M,
125+
GFP_KERNEL | __GFP_NOWARN,
126+
PAGE_KERNEL, 0, NUMA_NO_NODE,
127+
__builtin_return_address(0));
128+
}
129+
130+
if (!p && module_plt_base) {
131+
p = __vmalloc_node_range(size, MODULE_ALIGN,
132+
module_plt_base,
133+
module_plt_base + SZ_2G,
134+
GFP_KERNEL | __GFP_NOWARN,
135+
PAGE_KERNEL, 0, NUMA_NO_NODE,
136+
__builtin_return_address(0));
137+
}
87138

88139
if (!p) {
89-
p = __vmalloc_node_range(size, MODULE_ALIGN, module_alloc_base,
90-
module_alloc_base + SZ_2G, GFP_KERNEL,
91-
PAGE_KERNEL, 0, NUMA_NO_NODE,
92-
__builtin_return_address(0));
140+
pr_warn_ratelimited("%s: unable to allocate memory\n",
141+
__func__);
93142
}
94143

95144
if (p && (kasan_alloc_module_shadow(p, size, GFP_KERNEL) < 0)) {

0 commit comments

Comments
 (0)