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