1 // Copyright 2023 (c) Apple Inc.  All rights reserved.
2 
3 #include <darwintest.h>
4 #include <darwintest_utils.h>
5 #include <dirent.h>
6 #include <kperf/kpc.h>
7 #include <kperfdata/kpep.h>
8 #include <stdarg.h>
9 #include <stdbool.h>
10 #include <string.h>
11 #include <sys/guarded.h>
12 #include <sys/ioctl.h>
13 #include <sys/monotonic.h>
14 
15 #include "test_utils.h"
16 
17 #if __arm64__
18 #define HAS_CPC_SECURITY true
19 #else // __arm64__
20 #define HAS_CPC_SECURITY false
21 #endif // !__arm64__
22 
23 #define _T_META_REQUIRES_CPC_SUPPORT \
24 	T_META_REQUIRES_SYSCTL_EQ("kern.monotonic.supported", 1)
25 
26 T_GLOBAL_META(
27 	T_META_NAMESPACE("xnu.cpc"),
28 	T_META_RADAR_COMPONENT_NAME("xnu"),
29 	T_META_RADAR_COMPONENT_VERSION("cpu counters"),
30 	T_META_OWNER("mwidmann"),
31 	T_META_CHECK_LEAKS(false),
32 	T_META_ASROOT(true),
33 	XNU_T_META_SOC_SPECIFIC,
34 	T_META_ENABLED(HAS_CPC_SECURITY),
35 	_T_META_REQUIRES_CPC_SUPPORT);
36 
37 // Several of these tests have two variants to support running on development and release kernels.
38 // Tests prefixed with `secure_` put the development kernel into a secure CPC mode while tests prefixed with `release_` can run on the RELEASE build variant.
39 
40 // Metadata for running on a development kernel in CPC secure mode.
41 //
42 // This should require kern.development to be 1 with XNU_T_META_REQUIRES_DEVELOPMENT_KERNEL,
43 // but libdarwintest has a bug (rdar://111297938) preventing that.
44 // In the meantime, manually check in the test whether the kernel is DEVELOPMENT.
45 #define _T_META_CPC_SECURE_ON_DEV T_META_SYSCTL_INT("kern.cpc.secure=1")
46 
47 static void
_skip_unless_development(void)48 _skip_unless_development(void)
49 {
50 	unsigned int dev = 0;
51 	size_t dev_size = sizeof(dev);
52 	int ret = sysctlbyname("kern.development", &dev, &dev_size, NULL, 0);
53 	if (ret < 0 || dev) {
54 		T_SKIP("test must run on DEVELOPMENT kernel");
55 	}
56 }
57 
58 static void
_assert_kpep_ok(int kpep_err,const char * fmt,...)59 _assert_kpep_ok(int kpep_err, const char *fmt, ...)
60 {
61 	char msg[1024] = "";
62 	va_list args;
63 	va_start(args, fmt);
64 	vsnprintf(msg, sizeof(msg), fmt, args);
65 	va_end(args);
66 	T_QUIET;
67 	T_ASSERT_EQ(kpep_err, KPEP_ERR_NONE, "%s: %s", msg, kpep_strerror(kpep_err));
68 }
69 
70 static void
_skip_for_db(const char * kind,int kpep_err)71 _skip_for_db(const char *kind, int kpep_err)
72 {
73 	const char * const public_kpep_path = "/usr/share/kpep";
74 	const char * const internal_kpep_path = "/usr/local/share/kpep";
75 	const char * const paths[2] = { public_kpep_path, internal_kpep_path, };
76 	for (int i = 0; i < 2; i++) {
77 		const char * const path = paths[i];
78 		T_LOG("contents of %s:", path);
79 		DIR *dir = opendir(path);
80 		if (dir) {
81 			struct dirent *entry = NULL;
82 			while ((entry = readdir(dir)) != NULL) {
83 				T_LOG("    %s", entry->d_name);
84 			}
85 			(void)closedir(dir);
86 		} else {
87 			T_LOG("failed to open directory: %s", strerror(errno));
88 		}
89 	}
90 	int cpu_family = 0;
91 	size_t family_size = sizeof(cpu_family);
92 	int ret = sysctlbyname("hw.cpufamily", &cpu_family, &family_size, NULL, 0);
93 	if (ret != 0) {
94 		T_LOG("HW CPU family: 0x%8x", cpu_family);
95 	} else {
96 		T_LOG("failed to get hw.cpufamily: %s", strerror(errno));
97 	}
98 	T_SKIP("cannot open %s event database: %s", kind, kpep_strerror(kpep_err));
99 }
100 
101 // Check that a secure kernel disallows restricted events.
102 
103 static void
check_secure_cpmu(void)104 check_secure_cpmu(void)
105 {
106 	kpep_db_t public_db = NULL;
107 	int ret = kpep_db_createx(NULL, KPEP_DB_FLAG_PUBLIC_ONLY, &public_db);
108 	if (ret != KPEP_ERR_NONE) {
109 		_skip_for_db("public", ret);
110 	}
111 	kpep_db_t internal_db = NULL;
112 	ret = kpep_db_createx(NULL, KPEP_DB_FLAG_INTERNAL_ONLY, &internal_db);
113 	if (ret != KPEP_ERR_NONE) {
114 		_skip_for_db("internal", ret);
115 	}
116 	const char *na = NULL;
117 	kpep_db_name(public_db, &na);
118 
119 	size_t internal_event_count = 0;
120 	ret = kpep_db_events_count(internal_db, &internal_event_count);
121 	_assert_kpep_ok(ret, "getting internal event count");
122 
123 	kpep_event_t *internal_events = calloc(internal_event_count,
124 	    sizeof(internal_events[0]));
125 	T_QUIET; T_WITH_ERRNO;
126 	T_ASSERT_NOTNULL(internal_events, "allocate space for internal events");
127 
128 	ret = kpep_db_events(internal_db, internal_events,
129 	    internal_event_count * sizeof(internal_events[0]));
130 	_assert_kpep_ok(ret, "getting internal events");
131 
132 	kpep_config_t config = NULL;
133 	ret = kpep_config_create(internal_db, &config);
134 	_assert_kpep_ok(ret, "creating event configuration");
135 	ret = kpep_config_force_counters(config);
136 	_assert_kpep_ok(ret, "forcing counters with configuration");
137 
138 	unsigned int tested = 0;
139 	unsigned int filtered = 0;
140 	unsigned int public_tested = 0;
141 	for (size_t i = 0; i < internal_event_count; i++) {
142 		kpep_event_t event = internal_events[i];
143 		const char *name = NULL;
144 		ret = kpep_event_alias(event, &name);
145 		if (!name) {
146 			ret = kpep_event_name(event, &name);
147 		}
148 		_assert_kpep_ok(ret, "getting event name");
149 		if (strncmp(name, "FIXED", strlen("FIXED")) == 0) {
150 			T_LOG("skipping non-configurable %s event", name);
151 			continue;
152 		}
153 		bool empty_event = strcmp(name, "NO_EVNT") == 0;
154 		if (empty_event) {
155 			continue;
156 		}
157 
158 		kpep_event_t public_event = NULL;
159 		ret = kpep_db_event(public_db, name, &public_event);
160 		bool internal_only = ret == KPEP_ERR_EVENT_NOT_FOUND;
161 		ret = kpep_config_add_event(config, &event, 0, NULL);
162 		_assert_kpep_ok(ret, "adding event %s to configuration", name);
163 
164 		ret = kpep_config_apply(config);
165 		bool not_permitted = ret == KPEP_ERR_ERRNO && errno == EPERM;
166 		if (not_permitted) {
167 			if (!internal_only) {
168 				T_LOG("failed to configure public event %s", name);
169 			}
170 			filtered++;
171 		} else if (internal_only) {
172 			T_FAIL("configured internal-only event %s with secure CPC", name);
173 		} else {
174 			public_tested++;
175 		}
176 		ret = kpep_config_remove_event(config, 0);
177 		_assert_kpep_ok(ret, "removing event %s from configuration", name);
178 		tested++;
179 	}
180 
181 	T_LOG("tested %u internal/public events", tested);
182 	T_LOG("correctly permitted to configure %u public events", public_tested);
183 	T_LOG("correctly not permitted to configure %u internal-only events",
184 	    filtered);
185 	kpep_config_free(config);
186 	kpep_db_free(public_db);
187 	kpep_db_free(internal_db);
188 }
189 
190 T_DECL(secure_cpmu_event_restrictions, "secured CPMU should be restricted to known events",
191     _T_META_CPC_SECURE_ON_DEV, T_META_TAG_VM_NOT_ELIGIBLE)
192 {
193 	_skip_unless_development();
194 	check_secure_cpmu();
195 }
196 
197 T_DECL(release_cpmu_event_restrictions, "release CPMU should be restricted to known events",
198     XNU_T_META_REQUIRES_RELEASE_KERNEL, T_META_TAG_VM_NOT_ELIGIBLE)
199 {
200 	check_secure_cpmu();
201 }
202 
203 #define UNCORE_DEV_PATH "/dev/monotonic/uncore"
204 #define UPMU_REF_CYCLES 0x02
205 
206 static void
check_secure_upmu(void)207 check_secure_upmu(void)
208 {
209 	guardid_t guard;
210 	int fd;
211 
212 	guard = 0xa5adcafe;
213 
214 	T_SETUPBEGIN;
215 
216 	fd = guarded_open_np(UNCORE_DEV_PATH, &guard,
217 	    GUARD_CLOSE | GUARD_DUP | GUARD_WRITE, O_CLOEXEC | O_EXCL);
218 	if (fd < 0 && errno == ENOENT) {
219 		T_SKIP("uncore counters are unsupported");
220 	}
221 
222 	union monotonic_ctl_add add_ctl = {
223 		.in.config.event = UPMU_REF_CYCLES,
224 		.in.config.allowed_ctr_mask = 0xffff,
225 	};
226 
227 	T_SETUPEND;
228 
229 	int ret = ioctl(fd, MT_IOC_ADD, &add_ctl);
230 	T_EXPECT_POSIX_FAILURE(ret, EPERM,
231 	    "should not be allowed to count any events on UPMU");
232 }
233 
234 T_DECL(secure_upmu_event_restrictions, "secured UPMU should be restricted to no events",
235     _T_META_CPC_SECURE_ON_DEV, T_META_TAG_VM_NOT_ELIGIBLE)
236 {
237 	_skip_unless_development();
238 	check_secure_upmu();
239 }
240 
241 T_DECL(release_upmu_event_restrictions, "release UPMU should be restricted to no events",
242     XNU_T_META_REQUIRES_RELEASE_KERNEL, T_META_TAG_VM_NOT_ELIGIBLE)
243 {
244 	check_secure_upmu();
245 }
246 
247 // Check that events which are exposed publicly are allowed to be configured.
248 
249 static void
check_event_coverage(kpep_db_flags_t flag,const char * kind)250 check_event_coverage(kpep_db_flags_t flag, const char *kind)
251 {
252 	kpep_db_t db = NULL;
253 	int ret = kpep_db_createx(NULL, flag, &db);
254 	_assert_kpep_ok(ret, "creating %s event database", kind);
255 
256 	size_t event_count = 0;
257 	ret = kpep_db_events_count(db, &event_count);
258 	_assert_kpep_ok(ret, "getting %s event count", kind);
259 
260 	kpep_event_t *events = calloc(event_count, sizeof(events[0]));
261 	T_QUIET; T_WITH_ERRNO;
262 	T_ASSERT_NOTNULL(events, "allocate space for events");
263 
264 	ret = kpep_db_events(db, events, event_count * sizeof(events[0]));
265 	_assert_kpep_ok(ret, "getting public events");
266 
267 	kpep_config_t config = NULL;
268 	ret = kpep_config_create(db, &config);
269 	_assert_kpep_ok(ret, "creating event configuration");
270 	ret = kpep_config_force_counters(config);
271 	_assert_kpep_ok(ret, "forcing counters with configuration");
272 
273 	unsigned int tested = 0;
274 	for (size_t i = 0; i < event_count; i++) {
275 		kpep_event_t event = events[i];
276 		const char *name = NULL;
277 		ret = kpep_event_name(event, &name);
278 		_assert_kpep_ok(ret, "getting event name");
279 		if (strncmp(name, "FIXED", strlen("FIXED")) == 0) {
280 			T_LOG("skipping non-configurable %s event", name);
281 			continue;
282 		}
283 
284 		ret = kpep_config_add_event(config, &event, 0, NULL);
285 		_assert_kpep_ok(ret, "adding event %s to configuration", name);
286 
287 		ret = kpep_config_apply(config);
288 		if (ret == KPEP_ERR_ERRNO && errno == EPERM) {
289 			T_FAIL("failed to configure %s event %s with secure CPC", kind, name);
290 		} else {
291 			_assert_kpep_ok(ret, "applying configuration with event %s", name);
292 		}
293 		ret = kpep_config_remove_event(config, 0);
294 		_assert_kpep_ok(ret, "removing event %s from configuration", name);
295 		tested++;
296 	}
297 
298 	T_LOG("successfully configured %u %s events", tested, kind);
299 	kpep_config_free(config);
300 	kpep_db_free(db);
301 }
302 
303 T_DECL(secure_public_event_coverage, "all public events in kpep should be allowed",
304     _T_META_CPC_SECURE_ON_DEV, T_META_TAG_VM_NOT_ELIGIBLE)
305 {
306 	_skip_unless_development();
307 	check_event_coverage(KPEP_DB_FLAG_PUBLIC_ONLY, "public");
308 }
309 
310 T_DECL(release_public_event_coverage, "all public events in kpep should be allowed",
311     XNU_T_META_REQUIRES_RELEASE_KERNEL, T_META_TAG_VM_NOT_ELIGIBLE)
312 {
313 	check_event_coverage(KPEP_DB_FLAG_PUBLIC_ONLY, "public");
314 }
315 
316 // Check for internal development behaviors.
317 T_DECL(insecure_cpmu_unrestricted, "insecure CPMU should be unrestricted",
318     XNU_T_META_REQUIRES_DEVELOPMENT_KERNEL, T_META_SYSCTL_INT("kern.cpc.secure=0"), T_META_TAG_VM_NOT_ELIGIBLE)
319 {
320 	check_event_coverage(KPEP_DB_FLAG_INTERNAL_ONLY, "internal");
321 }
322 
323 T_DECL(secure_kpc_counting_system, "kpc should not allow counting the kernel when secure",
324     _T_META_CPC_SECURE_ON_DEV)
325 {
326 	kpep_db_t db = NULL;
327 	int ret = kpep_db_createx(NULL, KPEP_DB_FLAG_PUBLIC_ONLY, &db);
328 	_assert_kpep_ok(ret, "creating public event database");
329 
330 	size_t event_count = 0;
331 	ret = kpep_db_events_count(db, &event_count);
332 	_assert_kpep_ok(ret, "getting public event count");
333 
334 	kpep_event_t *events = calloc(event_count, sizeof(events[0]));
335 	T_QUIET; T_WITH_ERRNO;
336 	T_ASSERT_NOTNULL(events, "allocate space for events");
337 
338 	ret = kpep_db_events(db, events, event_count * sizeof(events[0]));
339 	_assert_kpep_ok(ret, "getting public events");
340 
341 	kpep_config_t config = NULL;
342 	ret = kpep_config_create(db, &config);
343 	_assert_kpep_ok(ret, "creating event configuration");
344 	ret = kpep_config_force_counters(config);
345 	_assert_kpep_ok(ret, "forcing counters with configuration");
346 
347 
348 	kpep_event_t event = NULL;
349 	const char *name = NULL;
350 	for (size_t i = 0; i < event_count; i++) {
351 		event = events[i];
352 		ret = kpep_event_name(event, &name);
353 		_assert_kpep_ok(ret, "getting event name");
354 		if (strncmp(name, "FIXED", strlen("FIXED")) != 0) {
355 			break;
356 		}
357 		T_LOG("skipping non-configurable %s event", name);
358 	}
359 
360 	ret = kpep_config_add_event(config, &event, KPEP_EVENT_FLAG_KERNEL, NULL);
361 	_assert_kpep_ok(ret, "adding event %s to configuration", name);
362 
363 	ret = kpep_config_apply(config);
364 	_assert_kpep_ok(ret, "applying configuration with event %s", name);
365 
366 	uint32_t config_count = kpc_get_config_count(KPC_CLASS_CONFIGURABLE_MASK);
367 	uint64_t *configs = calloc(config_count, sizeof(configs[0]));
368 	T_QUIET;
369 	T_ASSERT_NOTNULL(configs, "allocated %u * %zu", config_count, sizeof(configs[0]));
370 	ret = kpc_get_config(KPC_CLASS_CONFIGURABLE_MASK, configs);
371 	for (uint32_t i = 0; i < config_count; i++) {
372 		if ((configs[i] & 0x40000)) {
373 			T_FAIL("found configurable counter %u with configuration 0x%llx", i, configs[i]);
374 		}
375 	}
376 	T_LOG("checked %d events for EL2 counting", config_count);
377 
378 	kpep_config_free(config);
379 	kpep_db_free(db);
380 }
381