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