-
Notifications
You must be signed in to change notification settings - Fork 52
Expand file tree
/
Copy pathsysfs_nd_region.c
More file actions
167 lines (151 loc) · 5.81 KB
/
Copy pathsysfs_nd_region.c
File metadata and controls
167 lines (151 loc) · 5.81 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
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
// This file is part of KASLD - https://github.com/bcoles/kasld
//
// Read physical start addresses of NVDIMM/PMem regions from the Linux
// libnvdimm sysfs interface.
//
// When a system has NVDIMM or Persistent Memory (PMem) hardware — such as
// Intel Optane DCPMM (Data Center Persistent Memory) or JEDEC NVDIMM-P —
// the libnvdimm driver registers nd_region devices under:
//
// /sys/bus/nd/devices/ndregionN/
//
// Each nd_region's "resource" attribute exposes the physical start address
// of that PMem region:
//
// /sys/bus/nd/devices/ndregionN/resource (0444 — world-readable)
//
// Format: "%#llx\n" (e.g. "0x2080000000\n")
//
// The attribute is created with DEVICE_ATTR_RO (mode 0444):
//
// static DEVICE_ATTR_RO(resource);
//
// The value is nd_region->ndr_start, the physical byte offset of the first
// byte of this interleave set. On Intel Optane systems this is typically a
// persistent-memory range beyond the regular DRAM ceiling (e.g. starting at
// 0x40_0000_0000 / 256 GiB on a 256 GiB DRAM + 256 GiB PMem system).
//
// The attribute is hidden (mode 0) for degenerate regions with no interleave
// mappings (ndr_mappings == 0); it is visible and world-readable for all
// standard PMem regions.
//
// The resource attribute is only populated when the nd_region driver is
// bound to the device; if no driver is bound, read() returns ENXIO.
//
// Leak primitive:
// Data leaked: physical start address of NVDIMM/PMem interleave region
// Kernel subsystem: drivers/nvdimm —
// /sys/bus/nd/devices/ndregionN/resource
// Data structure: struct nd_region → ndr_start
// Address type: physical (persistent memory / DRAM-like)
// Method: parsed (sysfs text attribute)
// Status: unfixed (information exposure by design)
// Access check: none (world-readable via DEVICE_ATTR_RO, 0444)
// Source:
// https://elixir.bootlin.com/linux/v6.12/source/drivers/nvdimm/region_devs.c
//
// Mitigations:
// CONFIG_LIBNVDIMM=n removes the nd bus and all nd_region sysfs entries.
// Requires physical NVDIMM/PMem hardware and the nd_region driver to be
// bound. On x86_64 with CONFIG_RANDOMIZE_MEMORY, physical addresses do not
// directly reveal the virtual text base. The physical address is emitted as
// a fact; where it lands in the linear map is the engine's to decide, from
// the base it resolved rather than from a compile-time constant.
//
// Requires:
// - CONFIG_LIBNVDIMM
// - NVDIMM / Persistent Memory hardware (Intel Optane DCPMM, JEDEC NVDIMM-P)
// - nd_region driver bound to at least one ndregion device
//
// References:
// https://elixir.bootlin.com/linux/v6.12/source/drivers/nvdimm/region_devs.c
// https://www.kernel.org/doc/html/latest/driver-api/nvdimm/nvdimm.html
// https://www.kernel.org/doc/Documentation/ABI/testing/sysfs-bus-nd
// ---
// <bcoles@gmail.com>
#include "include/kasld/api.h"
#include "include/kasld/cli.h"
#include <dirent.h>
#include <errno.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
KASLD_EXPLAIN(
"Reads physical start addresses of NVDIMM/PMem regions from the libnvdimm "
"sysfs interface (/sys/bus/nd/devices/ndregionN/resource). Each region's "
"world-readable 'resource' attribute (0444, DEVICE_ATTR_RO) exposes "
"nd_region->ndr_start - the physical byte address of the first byte of "
"that interleave set. Only present on systems with NVDIMM or Persistent "
"Memory hardware (Intel Optane DCPMM, JEDEC NVDIMM-P) and the nd_region "
"driver bound.");
KASLD_META("method:parsed\n"
"phase:inference\n"
"discloses:physical\n"
"config:CONFIG_LIBNVDIMM\n");
static const char *nd_base = "/sys/bus/nd/devices";
int main(void) {
DIR *d;
struct dirent *ent;
char path[512];
char buf[64];
int count = 0;
kasld_info("trying %s/ndregionN/resource ...", nd_base);
d = kasld_opendir(nd_base);
if (!d) {
int saved_errno = errno;
if (saved_errno == ENOENT || saved_errno == ENODEV)
kasld_err("%s not present (CONFIG_LIBNVDIMM=n or no nd bus)", nd_base);
else
perror("[-] opendir");
return (saved_errno == EACCES || saved_errno == EPERM)
? KASLD_EXIT_NOPERM
: KASLD_EXIT_UNAVAILABLE;
}
while ((ent = readdir(d)) != NULL) {
/* Only process ndregionN devices (not namespace*, bregion*, dax*, etc.) */
if (strncmp(ent->d_name, "ndregion", 8) != 0)
continue;
/* Name must be "ndregion" followed by one or more digits */
const char *suffix = ent->d_name + 8;
int all_digits = (*suffix != '\0');
for (const char *p = suffix; *p; p++) {
if (*p < '0' || *p > '9') {
all_digits = 0;
break;
}
}
if (!all_digits)
continue;
snprintf(path, sizeof(path), "%s/%s/resource", nd_base, ent->d_name);
FILE *f = kasld_fopen(path, "r");
if (!f) {
/* ENXIO = driver not bound; ENOENT = attribute hidden (no mappings) */
if (errno != ENOENT && errno != ENXIO)
kasld_err("failed to open %s: %s", path, strerror(errno));
continue;
}
if (!fgets(buf, sizeof(buf), f)) {
fclose(f);
continue;
}
fclose(f);
/* Format is "0x%llx\n", so base 0 honours the prefix. A pmem region base
* can exceed the word on a 32-bit build; a refusal skips the region rather
* than reporting a truncated one. */
unsigned long addr;
if (!kasld_addr_parse(buf, 0, &addr, NULL) || addr == 0)
continue;
kasld_info("%s resource: 0x%016lx", ent->d_name, addr);
kasld_result_sample(KASLD_TYPE_PHYS, REGION_PMEM, addr, ent->d_name,
CONF_PARSED);
count++;
}
closedir(d);
if (!count) {
kasld_err("no readable ndregion resource attributes found "
"(no NVDIMM hardware or driver not bound)");
return KASLD_EXIT_UNAVAILABLE;
}
return 0;
}