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