-
Notifications
You must be signed in to change notification settings - Fork 52
Expand file tree
/
Copy pathboot_config.c
More file actions
149 lines (132 loc) · 6.23 KB
/
Copy pathboot_config.c
File metadata and controls
149 lines (132 loc) · 6.23 KB
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
// This file is part of KASLD - https://github.com/bcoles/kasld
//
// Check kernel config for CONFIG_RELOCATABLE, CONFIG_RANDOMIZE_BASE,
// and CONFIG_PAGE_OFFSET (32-bit vmsplit).
//
// Detection component; on 32-bit vmsplit arches also emits the parsed
// CONFIG_PAGE_OFFSET as the page-offset base.
// Purpose: reads /boot/config-$(uname -r) to determine whether
// CONFIG_RANDOMIZE_BASE is set (KASLR compiled in) and what the
// 32-bit vmsplit (CONFIG_PAGE_OFFSET) is. Readable when /boot is
// accessible (common on most distros).
//
// References:
// https://lwn.net/Articles/444556/
// https://cateee.net/lkddb/web-lkddb/RANDOMIZE_BASE.html
// https://cateee.net/lkddb/web-lkddb/RELOCATABLE.html
// https://cateee.net/lkddb/web-lkddb/PAGE_OFFSET.html
// ---
// <bcoles@gmail.com>
#include "include/kasld/api.h"
#include "include/kasld/bootconfig.h"
#include "include/kasld/cli.h"
#include "include/kconfig.h"
#include "include/text_order.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
KASLD_EXPLAIN(
"Reads /boot/config-$(uname -r) to check whether CONFIG_RANDOMIZE_BASE "
"is set (KASLR compiled in) and determines the 32-bit vmsplit "
"(CONFIG_PAGE_OFFSET). Readable when /boot is accessible.");
KASLD_META("method:detection\n"
"phase:inference\n"
"discloses:virtual\n");
static unsigned long get_kernel_addr_boot_config(FILE *fp) {
if (kconfig_has_kaslr(fp))
return 0;
kasld_info(
"Kernel appears to have been compiled without CONFIG_RANDOMIZE_BASE"
" (KASLR not compiled in)");
return (unsigned long)KERNEL_VIRT_TEXT_DEFAULT;
}
int main(void) {
int is_unkeyed = 0;
FILE *fp = kasld_open_boot_config(&is_unkeyed);
if (!fp) {
if (kasld_boot_config_denied) {
kasld_err("kernel config present but not readable");
return KASLD_EXIT_NOPERM;
}
kasld_err("could not find kernel config");
return KASLD_EXIT_UNAVAILABLE;
}
/* An unkeyed /boot/config carries no binding to the running kernel: it may be
* a leftover from another kernel or a rescue image. Its Kconfig answers drive
* guaranteed pins (the KASLR-disabled C_EQUALS pin, the PHYSICAL_START floor,
* the s390 layout discriminator, ...), so a stale file could exclude the true
* base from the guaranteed window. Demote every fact from that source below
* the guaranteed floor — it then shapes only the likely window. Release-keyed
* paths are bound to the running kernel and stay at CONF_PARSED. */
enum kasld_confidence cfg_conf = is_unkeyed ? CONF_HEURISTIC : CONF_PARSED;
#if PAGE_OFFSET_FROM_CONFIG
/* Detect PAGE_OFFSET (32-bit vmsplit). CONFIG_PAGE_OFFSET equals the runtime
* page_offset only on PAGE_OFFSET_FROM_CONFIG arches (x86_32, arm32, ppc32);
* pinning Q_PAGE_OFFSET to it via page_offset_from_landmark's C_EQUALS would
* exclude the truth on arches whose CONFIG_PAGE_OFFSET differs from the
* running base.
* (The properly gated scalar path is bootconfig_facts ->
* page_offset_from_config.) */
unsigned long virt_page_offset = get_kconfig_page_offset(fp);
if (virt_page_offset) {
kasld_info("CONFIG_PAGE_OFFSET: %#lx", virt_page_offset);
kasld_result_base(KASLD_TYPE_VIRT, REGION_PAGE_OFFSET, virt_page_offset,
NULL, cfg_conf);
}
#endif
/* CONFIG_PHYSICAL_START (x86 LOAD_PHYSICAL_ADDR). The honest-top floors
* for Q_VIRT_IMAGE_BASE / Q_PHYS_IMAGE_BASE are *widened* to the smallest
* practical value (2 MiB, the minimum CONFIG_PHYSICAL_START alignment);
* when the real value is learnable, the physical_start_lower_bound rule
* raises the floor to the precise position at CONF_PARSED. */
unsigned long phys_start = get_kconfig_physical_start(fp);
if (phys_start) {
kasld_info("CONFIG_PHYSICAL_START: %#lx", phys_start);
kasld_emit_scalar(SF_PHYSICAL_START, phys_start, cfg_conf);
}
/* CONFIG_PHYSICAL_ALIGN — KASLR slot granularity on x86. boot_params
* exposes the same value at hdr.kernel_alignment; this is a fallback for
* systems where /sys/kernel/boot_params/data is unreadable. Both sources
* emit the same SF_PHYS_KERNEL_ALIGN scalar; boot_params_kaslr_align raises
* Q_VIRT_KASLR_ALIGN / Q_PHYS_KASLR_ALIGN regardless of source. */
unsigned long phys_align = get_kconfig_physical_align(fp);
if (phys_align) {
kasld_info("CONFIG_PHYSICAL_ALIGN: %#lx", phys_align);
kasld_emit_scalar(SF_PHYS_KERNEL_ALIGN, phys_align, cfg_conf);
}
/* KASLR-off detection. CONFIG_RANDOMIZE_BASE=n means the kernel binary
* was built without KASLR support entirely — both virtual and physical
* placement use compile-time defaults. virt_kaslr_disabled_pin /
* phys_kaslr_disabled_pin each gate by its arch macro
* (KASLR_DISABLED_PINS_VIRT_TEXT / KASLR_DISABLED_PINS_PHYS) + window-
* containment to decide whether to pin. */
if (get_kernel_addr_boot_config(fp)) {
kasld_emit_scalar(SF_VIRT_KASLR_DISABLED, 1, cfg_conf);
kasld_emit_scalar(SF_PHYS_KASLR_DISABLED, 1, cfg_conf);
}
/* CONFIG_KASAN=y forces the direct-map randomization off at runtime
* (kaslr_memory_enabled() = kaslr_enabled() && !IS_ENABLED(CONFIG_KASAN)), so
* page_offset / vmalloc / vmemmap stay at their compile-time defaults even
* with CONFIG_RANDOMIZE_MEMORY=y. Consumed by directmap_kaslr_disabled_pin.
*/
if (is_kconfig_set(fp, "CONFIG_KASAN")) {
kasld_info("CONFIG_KASAN=y");
kasld_emit_scalar(SF_KASAN_ENABLED, 1, cfg_conf);
}
/* Kernel-text function ordering (canonical / static-reorder / FG-KASLR) —
* gates whether a generic System.map can resolve symbols. See text_order.h.
*/
emit_text_order_from_kconfig(fp, cfg_conf);
/* s390 image-base layout discriminator — see proc_config.c. CONFIG_S390=y
* with CONFIG_KERNEL_IMAGE_BASE present (value > 0) selects the modern high
* separate-kernel-mapping layout; absent (value 0) selects the pre-v6.8
* identity-mapped layout. Consumed by s390_image_base_from_config. */
if (is_kconfig_set(fp, "CONFIG_S390")) {
unsigned long s390_image_base = get_kconfig_kernel_image_base(fp);
kasld_info("CONFIG_KERNEL_IMAGE_BASE: %#lx%s", s390_image_base,
s390_image_base ? "" : " (absent: identity-mapped layout)");
kasld_emit_scalar(SF_VIRT_KERNEL_IMAGE_BASE, s390_image_base, cfg_conf);
}
fclose(fp);
return 0;
}