1*5e3eaea3SApple OSS Distributions /* Copyright (c) 2020 Apple Computer, Inc. All rights reserved. */
2*5e3eaea3SApple OSS Distributions
3*5e3eaea3SApple OSS Distributions #include <CoreSymbolication/CoreSymbolication.h>
4*5e3eaea3SApple OSS Distributions #include <CoreSymbolication/CoreSymbolicationPrivate.h>
5*5e3eaea3SApple OSS Distributions #include <darwintest.h>
6*5e3eaea3SApple OSS Distributions #include <dispatch/dispatch.h>
7*5e3eaea3SApple OSS Distributions
8*5e3eaea3SApple OSS Distributions #include <mach-o/loader.h>
9*5e3eaea3SApple OSS Distributions
10*5e3eaea3SApple OSS Distributions #include <sys/kas_info.h>
11*5e3eaea3SApple OSS Distributions
12*5e3eaea3SApple OSS Distributions #include <sys/mman.h>
13*5e3eaea3SApple OSS Distributions #include <sys/stat.h>
14*5e3eaea3SApple OSS Distributions #include <sys/sysctl.h>
15*5e3eaea3SApple OSS Distributions #include <sys/types.h>
16*5e3eaea3SApple OSS Distributions
17*5e3eaea3SApple OSS Distributions #include <fcntl.h>
18*5e3eaea3SApple OSS Distributions
19*5e3eaea3SApple OSS Distributions #include <stdint.h>
20*5e3eaea3SApple OSS Distributions
21*5e3eaea3SApple OSS Distributions T_GLOBAL_META(
22*5e3eaea3SApple OSS Distributions T_META_NAMESPACE("xnu.kas_info"),
23*5e3eaea3SApple OSS Distributions T_META_CHECK_LEAKS(false),
24*5e3eaea3SApple OSS Distributions T_META_ASROOT(true));
25*5e3eaea3SApple OSS Distributions
26*5e3eaea3SApple OSS Distributions static bool
slide_enabled(void)27*5e3eaea3SApple OSS Distributions slide_enabled(void)
28*5e3eaea3SApple OSS Distributions {
29*5e3eaea3SApple OSS Distributions int slide_enabled, err;
30*5e3eaea3SApple OSS Distributions size_t size = sizeof(slide_enabled);
31*5e3eaea3SApple OSS Distributions err = sysctlbyname("kern.slide", &slide_enabled, &size, NULL, 0);
32*5e3eaea3SApple OSS Distributions T_ASSERT_POSIX_SUCCESS(err, "sysctl(\"kern.slide\");");
33*5e3eaea3SApple OSS Distributions return slide_enabled != 0;
34*5e3eaea3SApple OSS Distributions }
35*5e3eaea3SApple OSS Distributions
36*5e3eaea3SApple OSS Distributions static uint64_t
kernel_slide(int selector)37*5e3eaea3SApple OSS Distributions kernel_slide(int selector)
38*5e3eaea3SApple OSS Distributions {
39*5e3eaea3SApple OSS Distributions uint64_t slide;
40*5e3eaea3SApple OSS Distributions size_t size = sizeof(slide);
41*5e3eaea3SApple OSS Distributions int err = kas_info(selector, &slide, &size);
42*5e3eaea3SApple OSS Distributions if (err && errno == ENOTSUP) {
43*5e3eaea3SApple OSS Distributions T_SKIP("Running on kernel without kas_info");
44*5e3eaea3SApple OSS Distributions }
45*5e3eaea3SApple OSS Distributions
46*5e3eaea3SApple OSS Distributions T_ASSERT_POSIX_SUCCESS(errno, "kas_info with selector %d", selector);
47*5e3eaea3SApple OSS Distributions T_ASSERT_EQ(size, sizeof(slide), "returned size is valid");
48*5e3eaea3SApple OSS Distributions
49*5e3eaea3SApple OSS Distributions return slide;
50*5e3eaea3SApple OSS Distributions }
51*5e3eaea3SApple OSS Distributions
52*5e3eaea3SApple OSS Distributions T_DECL(kernel_text_slide,
53*5e3eaea3SApple OSS Distributions "ensures that kas_info can return the kernel text slide")
54*5e3eaea3SApple OSS Distributions {
55*5e3eaea3SApple OSS Distributions if (!slide_enabled()) {
56*5e3eaea3SApple OSS Distributions T_SKIP("KASLR is not enabled");
57*5e3eaea3SApple OSS Distributions __builtin_unreachable();
58*5e3eaea3SApple OSS Distributions }
59*5e3eaea3SApple OSS Distributions
60*5e3eaea3SApple OSS Distributions uint64_t slide = kernel_slide(KAS_INFO_KERNEL_TEXT_SLIDE_SELECTOR);
61*5e3eaea3SApple OSS Distributions
62*5e3eaea3SApple OSS Distributions T_ASSERT_GT_ULLONG(slide, 0ULL, "kernel slide is non-zero");
63*5e3eaea3SApple OSS Distributions }
64*5e3eaea3SApple OSS Distributions
65*5e3eaea3SApple OSS Distributions static void
test_kas_info_invalid_args(int selector)66*5e3eaea3SApple OSS Distributions test_kas_info_invalid_args(int selector)
67*5e3eaea3SApple OSS Distributions {
68*5e3eaea3SApple OSS Distributions uint64_t slide;
69*5e3eaea3SApple OSS Distributions size_t size = 0;
70*5e3eaea3SApple OSS Distributions int err;
71*5e3eaea3SApple OSS Distributions
72*5e3eaea3SApple OSS Distributions err = kas_info(selector, &slide, NULL);
73*5e3eaea3SApple OSS Distributions if (errno == ENOTSUP) {
74*5e3eaea3SApple OSS Distributions T_SKIP("Running on kernel without kas_info %d", selector);
75*5e3eaea3SApple OSS Distributions }
76*5e3eaea3SApple OSS Distributions T_ASSERT_POSIX_FAILURE(err, EFAULT, "kas_info %d with NULL size", selector);
77*5e3eaea3SApple OSS Distributions
78*5e3eaea3SApple OSS Distributions size = sizeof(uint64_t);
79*5e3eaea3SApple OSS Distributions err = kas_info(selector, NULL, &size);
80*5e3eaea3SApple OSS Distributions T_ASSERT_POSIX_FAILURE(err, EFAULT, "kas_info %d with NULL slide", selector);
81*5e3eaea3SApple OSS Distributions
82*5e3eaea3SApple OSS Distributions size = sizeof(uint32_t);
83*5e3eaea3SApple OSS Distributions err = kas_info(selector, &slide, &size);
84*5e3eaea3SApple OSS Distributions T_ASSERT_POSIX_FAILURE(err, EINVAL, "kas_info %d with invalid size", selector);
85*5e3eaea3SApple OSS Distributions }
86*5e3eaea3SApple OSS Distributions
87*5e3eaea3SApple OSS Distributions T_DECL(kernel_text_slide_invalid,
88*5e3eaea3SApple OSS Distributions "ensures that kas_info handles invalid input to KERNEL_TEXT_SLIDE_SELECTOR")
89*5e3eaea3SApple OSS Distributions {
90*5e3eaea3SApple OSS Distributions test_kas_info_invalid_args(KAS_INFO_KERNEL_TEXT_SLIDE_SELECTOR);
91*5e3eaea3SApple OSS Distributions }
92*5e3eaea3SApple OSS Distributions
93*5e3eaea3SApple OSS Distributions
94*5e3eaea3SApple OSS Distributions static char const*
kernel_path(void)95*5e3eaea3SApple OSS Distributions kernel_path(void)
96*5e3eaea3SApple OSS Distributions {
97*5e3eaea3SApple OSS Distributions static CSSymbolicatorRef symbolicator;
98*5e3eaea3SApple OSS Distributions static char const* path;
99*5e3eaea3SApple OSS Distributions static dispatch_once_t once;
100*5e3eaea3SApple OSS Distributions dispatch_once(&once, ^{
101*5e3eaea3SApple OSS Distributions uint32_t flags = kCSSymbolicatorDefaultCreateFlags;
102*5e3eaea3SApple OSS Distributions symbolicator = CSSymbolicatorCreateWithMachKernelFlagsAndNotification(flags, NULL);
103*5e3eaea3SApple OSS Distributions T_QUIET; T_ASSERT_TRUE(!CSIsNull(symbolicator), "CSSymbolicatorCreateWithMachKernelFlagsAndNotification");
104*5e3eaea3SApple OSS Distributions path = CSSymbolOwnerGetPath(CSSymbolicatorGetAOutSymbolOwner(symbolicator));
105*5e3eaea3SApple OSS Distributions if (!path) {
106*5e3eaea3SApple OSS Distributions path = CSSymbolOwnerGetPath(CSSymbolicatorGetSymbolOwner(symbolicator));
107*5e3eaea3SApple OSS Distributions }
108*5e3eaea3SApple OSS Distributions T_QUIET; T_ASSERT_NOTNULL(path, "CSSymbolOwnerGetPath/CSSymbolicatorGetSymbolOwner");
109*5e3eaea3SApple OSS Distributions });
110*5e3eaea3SApple OSS Distributions return path;
111*5e3eaea3SApple OSS Distributions }
112*5e3eaea3SApple OSS Distributions
113*5e3eaea3SApple OSS Distributions static void
disk_kernel_segments(uint64_t ** segs_out,size_t * nsegs_out)114*5e3eaea3SApple OSS Distributions disk_kernel_segments(uint64_t **segs_out, size_t *nsegs_out)
115*5e3eaea3SApple OSS Distributions {
116*5e3eaea3SApple OSS Distributions char const* path = kernel_path();
117*5e3eaea3SApple OSS Distributions int fd = open(path, O_RDONLY);
118*5e3eaea3SApple OSS Distributions int err;
119*5e3eaea3SApple OSS Distributions struct stat sb;
120*5e3eaea3SApple OSS Distributions size_t nsegs = 0;
121*5e3eaea3SApple OSS Distributions uint64_t *segs = NULL;
122*5e3eaea3SApple OSS Distributions void *data;
123*5e3eaea3SApple OSS Distributions
124*5e3eaea3SApple OSS Distributions T_LOG("Kernel file is %s", path);
125*5e3eaea3SApple OSS Distributions T_QUIET; T_ASSERT_POSIX_SUCCESS(fd, "open kernel file");
126*5e3eaea3SApple OSS Distributions
127*5e3eaea3SApple OSS Distributions err = fstat(fd, &sb);
128*5e3eaea3SApple OSS Distributions T_ASSERT_POSIX_SUCCESS(err, "fstat kernel file");
129*5e3eaea3SApple OSS Distributions
130*5e3eaea3SApple OSS Distributions data = mmap(NULL, (size_t)sb.st_size, PROT_READ, MAP_SHARED, fd, 0);
131*5e3eaea3SApple OSS Distributions T_ASSERT_NE(data, MAP_FAILED, "mmap kernel file");
132*5e3eaea3SApple OSS Distributions
133*5e3eaea3SApple OSS Distributions /*
134*5e3eaea3SApple OSS Distributions * TODO: If we bring back FAT kernel binaries
135*5e3eaea3SApple OSS Distributions * this will need to be fixed to handle them properly
136*5e3eaea3SApple OSS Distributions */
137*5e3eaea3SApple OSS Distributions uint32_t magic = *(uint32_t*)data;
138*5e3eaea3SApple OSS Distributions struct load_command *cmd = NULL;
139*5e3eaea3SApple OSS Distributions
140*5e3eaea3SApple OSS Distributions switch (magic) {
141*5e3eaea3SApple OSS Distributions case MH_MAGIC: OS_FALLTHROUGH;
142*5e3eaea3SApple OSS Distributions case MH_CIGAM: {
143*5e3eaea3SApple OSS Distributions struct mach_header *mh = (struct mach_header *)data;
144*5e3eaea3SApple OSS Distributions cmd = (struct load_command *)(&(mh[1]));
145*5e3eaea3SApple OSS Distributions nsegs = mh->ncmds;
146*5e3eaea3SApple OSS Distributions }
147*5e3eaea3SApple OSS Distributions break;
148*5e3eaea3SApple OSS Distributions case MH_MAGIC_64: OS_FALLTHROUGH;
149*5e3eaea3SApple OSS Distributions case MH_CIGAM_64: {
150*5e3eaea3SApple OSS Distributions struct mach_header_64 *mh = (struct mach_header_64 *)data;
151*5e3eaea3SApple OSS Distributions cmd = (struct load_command *)(&(mh[1]));
152*5e3eaea3SApple OSS Distributions nsegs = mh->ncmds;
153*5e3eaea3SApple OSS Distributions }
154*5e3eaea3SApple OSS Distributions break;
155*5e3eaea3SApple OSS Distributions default:
156*5e3eaea3SApple OSS Distributions T_FAIL("kernel file is not a Mach-O file, magic is %x", magic);
157*5e3eaea3SApple OSS Distributions }
158*5e3eaea3SApple OSS Distributions
159*5e3eaea3SApple OSS Distributions /* Adjust for the LC_UUID && LC_BUILD_VERSION commands in front of
160*5e3eaea3SApple OSS Distributions * load commands for dSYMs
161*5e3eaea3SApple OSS Distributions */
162*5e3eaea3SApple OSS Distributions while (cmd->cmd != LC_SEGMENT && cmd->cmd != LC_SEGMENT_64) {
163*5e3eaea3SApple OSS Distributions cmd = (struct load_command *) ((uintptr_t) cmd + cmd->cmdsize);
164*5e3eaea3SApple OSS Distributions nsegs--;
165*5e3eaea3SApple OSS Distributions }
166*5e3eaea3SApple OSS Distributions
167*5e3eaea3SApple OSS Distributions segs = calloc(nsegs, sizeof(*segs));
168*5e3eaea3SApple OSS Distributions T_ASSERT_NOTNULL(segs, "calloc disk segment array");
169*5e3eaea3SApple OSS Distributions
170*5e3eaea3SApple OSS Distributions for (uint8_t i = 0; i < nsegs; i++) {
171*5e3eaea3SApple OSS Distributions if (cmd->cmd == LC_SEGMENT) {
172*5e3eaea3SApple OSS Distributions struct segment_command *sg = (struct segment_command *) cmd;
173*5e3eaea3SApple OSS Distributions if (sg->vmsize > 0) {
174*5e3eaea3SApple OSS Distributions segs[i] = sg->vmaddr;
175*5e3eaea3SApple OSS Distributions }
176*5e3eaea3SApple OSS Distributions } else if (cmd->cmd == LC_SEGMENT_64) {
177*5e3eaea3SApple OSS Distributions struct segment_command_64 *sg = (struct segment_command_64 *) cmd;
178*5e3eaea3SApple OSS Distributions if (sg->vmsize > 0) {
179*5e3eaea3SApple OSS Distributions segs[i] = sg->vmaddr;
180*5e3eaea3SApple OSS Distributions }
181*5e3eaea3SApple OSS Distributions }
182*5e3eaea3SApple OSS Distributions cmd = (struct load_command *) ((uintptr_t) cmd + cmd->cmdsize);
183*5e3eaea3SApple OSS Distributions }
184*5e3eaea3SApple OSS Distributions
185*5e3eaea3SApple OSS Distributions *segs_out = segs;
186*5e3eaea3SApple OSS Distributions *nsegs_out = nsegs;
187*5e3eaea3SApple OSS Distributions
188*5e3eaea3SApple OSS Distributions err = munmap(data, (size_t)sb.st_size);
189*5e3eaea3SApple OSS Distributions
190*5e3eaea3SApple OSS Distributions err = close(fd);
191*5e3eaea3SApple OSS Distributions T_ASSERT_POSIX_SUCCESS(err, "close kernel fd");
192*5e3eaea3SApple OSS Distributions }
193*5e3eaea3SApple OSS Distributions
194*5e3eaea3SApple OSS Distributions static bool
is_fileset_kc(void)195*5e3eaea3SApple OSS Distributions is_fileset_kc(void)
196*5e3eaea3SApple OSS Distributions {
197*5e3eaea3SApple OSS Distributions char uuid[1024];
198*5e3eaea3SApple OSS Distributions int err;
199*5e3eaea3SApple OSS Distributions size_t size = sizeof(uuid);
200*5e3eaea3SApple OSS Distributions err = sysctlbyname("kern.filesetuuid", uuid, &size, NULL, 0);
201*5e3eaea3SApple OSS Distributions return err == 0;
202*5e3eaea3SApple OSS Distributions }
203*5e3eaea3SApple OSS Distributions
204*5e3eaea3SApple OSS Distributions #define KAS_INFO_KERNEL_SEGMENT_LOCATION_SELECTOR 1
205*5e3eaea3SApple OSS Distributions
206*5e3eaea3SApple OSS Distributions T_DECL(kernel_segment_location,
207*5e3eaea3SApple OSS Distributions "ensures that KAS_INFO_KERNEL_SEGMENT_LOCATION returns correct segment locations")
208*5e3eaea3SApple OSS Distributions {
209*5e3eaea3SApple OSS Distributions int err;
210*5e3eaea3SApple OSS Distributions
211*5e3eaea3SApple OSS Distributions if (!slide_enabled()) {
212*5e3eaea3SApple OSS Distributions T_SKIP("KASLR is not enabled");
213*5e3eaea3SApple OSS Distributions __builtin_unreachable();
214*5e3eaea3SApple OSS Distributions }
215*5e3eaea3SApple OSS Distributions
216*5e3eaea3SApple OSS Distributions uint64_t *disk_segs;
217*5e3eaea3SApple OSS Distributions size_t disk_nsegs;
218*5e3eaea3SApple OSS Distributions disk_kernel_segments(&disk_segs, &disk_nsegs);
219*5e3eaea3SApple OSS Distributions
220*5e3eaea3SApple OSS Distributions size_t size = 0;
221*5e3eaea3SApple OSS Distributions
222*5e3eaea3SApple OSS Distributions err = kas_info(KAS_INFO_KERNEL_SEGMENT_VMADDR_SELECTOR, NULL, &size);
223*5e3eaea3SApple OSS Distributions if (errno == ENOTSUP) {
224*5e3eaea3SApple OSS Distributions T_SKIP("KAS_INFO_KERNEL_SEGMENT_VMADDR_SELECTOR not supported");
225*5e3eaea3SApple OSS Distributions }
226*5e3eaea3SApple OSS Distributions T_ASSERT_POSIX_SUCCESS(err, "kas_info KAS_INFO_KERNEL_SEGMENT_VMADDR_SELECTOR for size");
227*5e3eaea3SApple OSS Distributions
228*5e3eaea3SApple OSS Distributions uint64_t mem_nsegs = size / sizeof(uint64_t);
229*5e3eaea3SApple OSS Distributions uint64_t *mem_segs = calloc(mem_nsegs, sizeof(*disk_segs));
230*5e3eaea3SApple OSS Distributions
231*5e3eaea3SApple OSS Distributions err = kas_info(KAS_INFO_KERNEL_SEGMENT_VMADDR_SELECTOR, mem_segs, &size);
232*5e3eaea3SApple OSS Distributions if (errno == ENOTSUP) {
233*5e3eaea3SApple OSS Distributions T_SKIP("KAS_INFO_KERNEL_SEGMENT_VMADDR_SELECTOR not supported");
234*5e3eaea3SApple OSS Distributions }
235*5e3eaea3SApple OSS Distributions
236*5e3eaea3SApple OSS Distributions T_ASSERT_POSIX_SUCCESS(err, "kas_info KAS_INFO_KERNEL_SEGMENT_VMADDR_SELECTOR for data");
237*5e3eaea3SApple OSS Distributions
238*5e3eaea3SApple OSS Distributions T_LOG("Kernel has %zu segments on disk, %zu in memory:", disk_nsegs, mem_nsegs);
239*5e3eaea3SApple OSS Distributions for (size_t i = 0; i < disk_nsegs; i++) {
240*5e3eaea3SApple OSS Distributions T_LOG("%zu %llx %llx", i, disk_segs[i], mem_segs[i]);
241*5e3eaea3SApple OSS Distributions }
242*5e3eaea3SApple OSS Distributions
243*5e3eaea3SApple OSS Distributions /*
244*5e3eaea3SApple OSS Distributions * If the kernel is not a fileset, verify that all
245*5e3eaea3SApple OSS Distributions * the segments in memory are the segment on disk
246*5e3eaea3SApple OSS Distributions * + the kaslr slide
247*5e3eaea3SApple OSS Distributions */
248*5e3eaea3SApple OSS Distributions if (!is_fileset_kc()) {
249*5e3eaea3SApple OSS Distributions T_LOG("Kernelcache is not a fileset kernelcache");
250*5e3eaea3SApple OSS Distributions
251*5e3eaea3SApple OSS Distributions uint64_t slide = kernel_slide(KAS_INFO_KERNEL_TEXT_SLIDE_SELECTOR);
252*5e3eaea3SApple OSS Distributions for (size_t i = 0; i < disk_nsegs; i++) {
253*5e3eaea3SApple OSS Distributions if (disk_segs[i] == 0 || mem_segs[i] == 0) {
254*5e3eaea3SApple OSS Distributions continue;
255*5e3eaea3SApple OSS Distributions }
256*5e3eaea3SApple OSS Distributions T_ASSERT_EQ(disk_segs[i] + slide, mem_segs[i], "segment %zu is slid", i);
257*5e3eaea3SApple OSS Distributions }
258*5e3eaea3SApple OSS Distributions }
259*5e3eaea3SApple OSS Distributions
260*5e3eaea3SApple OSS Distributions free(disk_segs);
261*5e3eaea3SApple OSS Distributions free(mem_segs);
262*5e3eaea3SApple OSS Distributions }
263