1*bbb1b6f9SApple OSS Distributions /*
2*bbb1b6f9SApple OSS Distributions * Copyright (c) 2025 Apple Inc. All rights reserved.
3*bbb1b6f9SApple OSS Distributions *
4*bbb1b6f9SApple OSS Distributions * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
5*bbb1b6f9SApple OSS Distributions *
6*bbb1b6f9SApple OSS Distributions * This file contains Original Code and/or Modifications of Original Code
7*bbb1b6f9SApple OSS Distributions * as defined in and that are subject to the Apple Public Source License
8*bbb1b6f9SApple OSS Distributions * Version 2.0 (the 'License'). You may not use this file except in
9*bbb1b6f9SApple OSS Distributions * compliance with the License. The rights granted to you under the License
10*bbb1b6f9SApple OSS Distributions * may not be used to create, or enable the creation or redistribution of,
11*bbb1b6f9SApple OSS Distributions * unlawful or unlicensed copies of an Apple operating system, or to
12*bbb1b6f9SApple OSS Distributions * circumvent, violate, or enable the circumvention or violation of, any
13*bbb1b6f9SApple OSS Distributions * terms of an Apple operating system software license agreement.
14*bbb1b6f9SApple OSS Distributions *
15*bbb1b6f9SApple OSS Distributions * Please obtain a copy of the License at
16*bbb1b6f9SApple OSS Distributions * http://www.opensource.apple.com/apsl/ and read it before using this file.
17*bbb1b6f9SApple OSS Distributions *
18*bbb1b6f9SApple OSS Distributions * The Original Code and all software distributed under the License are
19*bbb1b6f9SApple OSS Distributions * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
20*bbb1b6f9SApple OSS Distributions * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
21*bbb1b6f9SApple OSS Distributions * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
22*bbb1b6f9SApple OSS Distributions * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
23*bbb1b6f9SApple OSS Distributions * Please see the License for the specific language governing rights and
24*bbb1b6f9SApple OSS Distributions * limitations under the License.
25*bbb1b6f9SApple OSS Distributions *
26*bbb1b6f9SApple OSS Distributions * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
27*bbb1b6f9SApple OSS Distributions */
28*bbb1b6f9SApple OSS Distributions
29*bbb1b6f9SApple OSS Distributions /* test that the header doesn't implicitly depend on others */
30*bbb1b6f9SApple OSS Distributions #include <sys/resource_private.h>
31*bbb1b6f9SApple OSS Distributions #include <sys/resource.h>
32*bbb1b6f9SApple OSS Distributions
33*bbb1b6f9SApple OSS Distributions #include <libproc.h>
34*bbb1b6f9SApple OSS Distributions
35*bbb1b6f9SApple OSS Distributions #include <sys/types.h>
36*bbb1b6f9SApple OSS Distributions #include <unistd.h>
37*bbb1b6f9SApple OSS Distributions
38*bbb1b6f9SApple OSS Distributions #include <mach/task.h>
39*bbb1b6f9SApple OSS Distributions #include <mach/task_policy.h>
40*bbb1b6f9SApple OSS Distributions #include <mach/mach.h>
41*bbb1b6f9SApple OSS Distributions
42*bbb1b6f9SApple OSS Distributions #include <darwintest.h>
43*bbb1b6f9SApple OSS Distributions #include <darwintest_utils.h>
44*bbb1b6f9SApple OSS Distributions
45*bbb1b6f9SApple OSS Distributions #include <sys/sfi.h>
46*bbb1b6f9SApple OSS Distributions #include <Kernel/kern/ledger.h> /* TODO: this should be installed for userspace */
47*bbb1b6f9SApple OSS Distributions extern int ledger(int cmd, caddr_t arg1, caddr_t arg2, caddr_t arg3);
48*bbb1b6f9SApple OSS Distributions
49*bbb1b6f9SApple OSS Distributions #include <kern/debug.h>
50*bbb1b6f9SApple OSS Distributions extern int __microstackshot(char *tracebuf, uint32_t tracebuf_size, uint32_t flags);
51*bbb1b6f9SApple OSS Distributions
52*bbb1b6f9SApple OSS Distributions
53*bbb1b6f9SApple OSS Distributions T_GLOBAL_META(T_META_NAMESPACE("xnu.scheduler"),
54*bbb1b6f9SApple OSS Distributions T_META_RADAR_COMPONENT_NAME("xnu"),
55*bbb1b6f9SApple OSS Distributions T_META_RADAR_COMPONENT_VERSION("scheduler"),
56*bbb1b6f9SApple OSS Distributions T_META_OWNER("chimene"),
57*bbb1b6f9SApple OSS Distributions T_META_RUN_CONCURRENTLY(false), /* because of messing with global SFI */
58*bbb1b6f9SApple OSS Distributions T_META_ASROOT(true), /* for TASK_POLICY_STATE, and setting SFI */
59*bbb1b6f9SApple OSS Distributions T_META_TAG_VM_PREFERRED);
60*bbb1b6f9SApple OSS Distributions
61*bbb1b6f9SApple OSS Distributions static void
check_is_bg(bool wants_bg)62*bbb1b6f9SApple OSS Distributions check_is_bg(bool wants_bg)
63*bbb1b6f9SApple OSS Distributions {
64*bbb1b6f9SApple OSS Distributions kern_return_t kr;
65*bbb1b6f9SApple OSS Distributions struct task_policy_state policy_state;
66*bbb1b6f9SApple OSS Distributions
67*bbb1b6f9SApple OSS Distributions mach_msg_type_number_t count = TASK_POLICY_STATE_COUNT;
68*bbb1b6f9SApple OSS Distributions boolean_t get_default = FALSE;
69*bbb1b6f9SApple OSS Distributions
70*bbb1b6f9SApple OSS Distributions kr = task_policy_get(mach_task_self(), TASK_POLICY_STATE,
71*bbb1b6f9SApple OSS Distributions (task_policy_t)&policy_state, &count, &get_default);
72*bbb1b6f9SApple OSS Distributions
73*bbb1b6f9SApple OSS Distributions T_QUIET; T_ASSERT_MACH_SUCCESS(kr, "task_policy_get(TASK_POLICY_STATE)");
74*bbb1b6f9SApple OSS Distributions
75*bbb1b6f9SApple OSS Distributions /*
76*bbb1b6f9SApple OSS Distributions * A test reporting type=APPLICATION should have the live donor bit set.
77*bbb1b6f9SApple OSS Distributions * If this fails, the test may have been launched as a daemon instead.
78*bbb1b6f9SApple OSS Distributions */
79*bbb1b6f9SApple OSS Distributions T_QUIET; T_ASSERT_BITS_SET(policy_state.flags, TASK_IMP_LIVE_DONOR, "test should be live donor enabled");
80*bbb1b6f9SApple OSS Distributions
81*bbb1b6f9SApple OSS Distributions /*
82*bbb1b6f9SApple OSS Distributions * The BG bit is updated via task_policy_update_internal_locked,
83*bbb1b6f9SApple OSS Distributions * checking this proves that the first phase update ran on this task.
84*bbb1b6f9SApple OSS Distributions */
85*bbb1b6f9SApple OSS Distributions if (wants_bg) {
86*bbb1b6f9SApple OSS Distributions T_ASSERT_BITS_SET(policy_state.effective, POLICY_EFF_DARWIN_BG, "%d: is BG", getpid());
87*bbb1b6f9SApple OSS Distributions } else {
88*bbb1b6f9SApple OSS Distributions T_ASSERT_BITS_NOTSET(policy_state.effective, POLICY_EFF_DARWIN_BG, "%d: is not BG", getpid());
89*bbb1b6f9SApple OSS Distributions }
90*bbb1b6f9SApple OSS Distributions
91*bbb1b6f9SApple OSS Distributions /*
92*bbb1b6f9SApple OSS Distributions * The live donor bit is updated via task_policy_update_complete_unlocked,
93*bbb1b6f9SApple OSS Distributions * checking this proves that the second phase update ran on this task.
94*bbb1b6f9SApple OSS Distributions */
95*bbb1b6f9SApple OSS Distributions if (wants_bg) {
96*bbb1b6f9SApple OSS Distributions T_ASSERT_BITS_NOTSET(policy_state.flags, TASK_IMP_DONOR, "%d: is not live donor", getpid());
97*bbb1b6f9SApple OSS Distributions } else {
98*bbb1b6f9SApple OSS Distributions T_ASSERT_BITS_SET(policy_state.flags, TASK_IMP_DONOR, "%d: is live donor", getpid());
99*bbb1b6f9SApple OSS Distributions }
100*bbb1b6f9SApple OSS Distributions }
101*bbb1b6f9SApple OSS Distributions
102*bbb1b6f9SApple OSS Distributions static void
check_runaway_mode(bool expected_mode)103*bbb1b6f9SApple OSS Distributions check_runaway_mode(bool expected_mode)
104*bbb1b6f9SApple OSS Distributions {
105*bbb1b6f9SApple OSS Distributions int runaway_mode = getpriority(PRIO_DARWIN_RUNAWAY_MITIGATION, 0);
106*bbb1b6f9SApple OSS Distributions
107*bbb1b6f9SApple OSS Distributions T_QUIET;
108*bbb1b6f9SApple OSS Distributions T_ASSERT_POSIX_SUCCESS(runaway_mode, "getpriority(PRIO_DARWIN_RUNAWAY_MITIGATION)");
109*bbb1b6f9SApple OSS Distributions
110*bbb1b6f9SApple OSS Distributions T_LOG("pid %d: runaway mitigation mode is: %d", getpid(), runaway_mode);
111*bbb1b6f9SApple OSS Distributions
112*bbb1b6f9SApple OSS Distributions if (expected_mode) {
113*bbb1b6f9SApple OSS Distributions T_QUIET;
114*bbb1b6f9SApple OSS Distributions T_ASSERT_EQ(runaway_mode, PRIO_DARWIN_RUNAWAY_MITIGATION_ON, "should be on");
115*bbb1b6f9SApple OSS Distributions check_is_bg(true);
116*bbb1b6f9SApple OSS Distributions } else {
117*bbb1b6f9SApple OSS Distributions T_QUIET;
118*bbb1b6f9SApple OSS Distributions T_ASSERT_EQ(runaway_mode, PRIO_DARWIN_RUNAWAY_MITIGATION_OFF, "should be off");
119*bbb1b6f9SApple OSS Distributions check_is_bg(false);
120*bbb1b6f9SApple OSS Distributions }
121*bbb1b6f9SApple OSS Distributions }
122*bbb1b6f9SApple OSS Distributions
123*bbb1b6f9SApple OSS Distributions T_DECL(entitled_runaway_mode, "runaway mitigation mode should be settable while entitled")
124*bbb1b6f9SApple OSS Distributions {
125*bbb1b6f9SApple OSS Distributions T_LOG("uid: %d", getuid());
126*bbb1b6f9SApple OSS Distributions
127*bbb1b6f9SApple OSS Distributions check_runaway_mode(false);
128*bbb1b6f9SApple OSS Distributions
129*bbb1b6f9SApple OSS Distributions T_ASSERT_POSIX_SUCCESS(setpriority(PRIO_DARWIN_RUNAWAY_MITIGATION, 0, PRIO_DARWIN_RUNAWAY_MITIGATION_ON),
130*bbb1b6f9SApple OSS Distributions "setpriority(PRIO_DARWIN_RUNAWAY_MITIGATION, 0, PRIO_DARWIN_RUNAWAY_MITIGATION_ON)");
131*bbb1b6f9SApple OSS Distributions
132*bbb1b6f9SApple OSS Distributions check_runaway_mode(true);
133*bbb1b6f9SApple OSS Distributions
134*bbb1b6f9SApple OSS Distributions T_ASSERT_POSIX_SUCCESS(setpriority(PRIO_DARWIN_RUNAWAY_MITIGATION, 0, PRIO_DARWIN_RUNAWAY_MITIGATION_OFF),
135*bbb1b6f9SApple OSS Distributions "setpriority(PRIO_DARWIN_RUNAWAY_MITIGATION, 0, PRIO_DARWIN_RUNAWAY_MITIGATION_OFF)");
136*bbb1b6f9SApple OSS Distributions
137*bbb1b6f9SApple OSS Distributions check_runaway_mode(false);
138*bbb1b6f9SApple OSS Distributions }
139*bbb1b6f9SApple OSS Distributions
140*bbb1b6f9SApple OSS Distributions T_DECL(entitled_runaway_mode_read_root, "runaway mitigation mode should be readable as root",
141*bbb1b6f9SApple OSS Distributions T_META_ASROOT(true))
142*bbb1b6f9SApple OSS Distributions {
143*bbb1b6f9SApple OSS Distributions T_LOG("uid: %d", getuid());
144*bbb1b6f9SApple OSS Distributions
145*bbb1b6f9SApple OSS Distributions check_runaway_mode(false);
146*bbb1b6f9SApple OSS Distributions }
147*bbb1b6f9SApple OSS Distributions
148*bbb1b6f9SApple OSS Distributions T_DECL(entitled_runaway_mode_read_notroot, "runaway mitigation mode should be readable as not root but entitled",
149*bbb1b6f9SApple OSS Distributions T_META_ASROOT(false))
150*bbb1b6f9SApple OSS Distributions {
151*bbb1b6f9SApple OSS Distributions T_LOG("uid: %d", getuid());
152*bbb1b6f9SApple OSS Distributions
153*bbb1b6f9SApple OSS Distributions int runaway_mode = getpriority(PRIO_DARWIN_RUNAWAY_MITIGATION, getpid());
154*bbb1b6f9SApple OSS Distributions
155*bbb1b6f9SApple OSS Distributions T_QUIET;
156*bbb1b6f9SApple OSS Distributions T_ASSERT_POSIX_SUCCESS(runaway_mode, "getpriority(PRIO_DARWIN_RUNAWAY_MITIGATION)");
157*bbb1b6f9SApple OSS Distributions
158*bbb1b6f9SApple OSS Distributions T_ASSERT_EQ(runaway_mode, PRIO_DARWIN_RUNAWAY_MITIGATION_OFF, "should be off");
159*bbb1b6f9SApple OSS Distributions }
160*bbb1b6f9SApple OSS Distributions
161*bbb1b6f9SApple OSS Distributions T_DECL(runaway_mode_child_exit, "runaway mitigation mode should disappear when child exits")
162*bbb1b6f9SApple OSS Distributions {
163*bbb1b6f9SApple OSS Distributions T_LOG("uid: %d", getuid());
164*bbb1b6f9SApple OSS Distributions
165*bbb1b6f9SApple OSS Distributions check_runaway_mode(false);
166*bbb1b6f9SApple OSS Distributions
167*bbb1b6f9SApple OSS Distributions T_LOG("Spawning child");
168*bbb1b6f9SApple OSS Distributions
169*bbb1b6f9SApple OSS Distributions pid_t child_pid = fork();
170*bbb1b6f9SApple OSS Distributions
171*bbb1b6f9SApple OSS Distributions if (child_pid == 0) {
172*bbb1b6f9SApple OSS Distributions /* child process */
173*bbb1b6f9SApple OSS Distributions
174*bbb1b6f9SApple OSS Distributions check_runaway_mode(false);
175*bbb1b6f9SApple OSS Distributions
176*bbb1b6f9SApple OSS Distributions T_ASSERT_POSIX_SUCCESS(setpriority(PRIO_DARWIN_RUNAWAY_MITIGATION, 0, PRIO_DARWIN_RUNAWAY_MITIGATION_ON),
177*bbb1b6f9SApple OSS Distributions "setpriority(PRIO_DARWIN_RUNAWAY_MITIGATION, 0, PRIO_DARWIN_RUNAWAY_MITIGATION_ON)");
178*bbb1b6f9SApple OSS Distributions
179*bbb1b6f9SApple OSS Distributions check_runaway_mode(true);
180*bbb1b6f9SApple OSS Distributions
181*bbb1b6f9SApple OSS Distributions T_LOG("Exit pid %d with runaway mitigation mode on", getpid());
182*bbb1b6f9SApple OSS Distributions
183*bbb1b6f9SApple OSS Distributions exit(0);
184*bbb1b6f9SApple OSS Distributions } else {
185*bbb1b6f9SApple OSS Distributions T_ASSERT_POSIX_SUCCESS(child_pid, "fork, pid %d", child_pid);
186*bbb1b6f9SApple OSS Distributions
187*bbb1b6f9SApple OSS Distributions /* wait for child process to exit */
188*bbb1b6f9SApple OSS Distributions int exit_status = 0, signum = 0;
189*bbb1b6f9SApple OSS Distributions
190*bbb1b6f9SApple OSS Distributions T_ASSERT_TRUE(dt_waitpid(child_pid, &exit_status, &signum, 5),
191*bbb1b6f9SApple OSS Distributions "wait for child (%d) complete", child_pid);
192*bbb1b6f9SApple OSS Distributions
193*bbb1b6f9SApple OSS Distributions T_QUIET; T_ASSERT_EQ(exit_status, 0, "dt_waitpid: exit_status");
194*bbb1b6f9SApple OSS Distributions T_QUIET; T_ASSERT_EQ(signum, 0, "dt_waitpid: signum");
195*bbb1b6f9SApple OSS Distributions }
196*bbb1b6f9SApple OSS Distributions
197*bbb1b6f9SApple OSS Distributions check_runaway_mode(false);
198*bbb1b6f9SApple OSS Distributions }
199*bbb1b6f9SApple OSS Distributions
200*bbb1b6f9SApple OSS Distributions T_DECL(runaway_mode_child_set, "runaway mitigation mode should be settable on child pid")
201*bbb1b6f9SApple OSS Distributions {
202*bbb1b6f9SApple OSS Distributions T_LOG("uid: %d", getuid());
203*bbb1b6f9SApple OSS Distributions
204*bbb1b6f9SApple OSS Distributions check_runaway_mode(false);
205*bbb1b6f9SApple OSS Distributions
206*bbb1b6f9SApple OSS Distributions int fd[2];
207*bbb1b6f9SApple OSS Distributions
208*bbb1b6f9SApple OSS Distributions T_QUIET; T_ASSERT_POSIX_SUCCESS(pipe(fd), "pipe()");
209*bbb1b6f9SApple OSS Distributions
210*bbb1b6f9SApple OSS Distributions T_LOG("Spawning child");
211*bbb1b6f9SApple OSS Distributions
212*bbb1b6f9SApple OSS Distributions pid_t child_pid = fork();
213*bbb1b6f9SApple OSS Distributions
214*bbb1b6f9SApple OSS Distributions if (child_pid == 0) {
215*bbb1b6f9SApple OSS Distributions char buf[10];
216*bbb1b6f9SApple OSS Distributions
217*bbb1b6f9SApple OSS Distributions /* child process */
218*bbb1b6f9SApple OSS Distributions T_ASSERT_POSIX_SUCCESS(child_pid, "fork, in child with pid %d", getpid());
219*bbb1b6f9SApple OSS Distributions
220*bbb1b6f9SApple OSS Distributions T_ASSERT_POSIX_SUCCESS(close(fd[1]), "close(fd[1])");
221*bbb1b6f9SApple OSS Distributions
222*bbb1b6f9SApple OSS Distributions T_ASSERT_POSIX_SUCCESS(read(fd[0], buf, sizeof(buf)), "read(fd[0], buf, sizeof(buf)");
223*bbb1b6f9SApple OSS Distributions
224*bbb1b6f9SApple OSS Distributions T_ASSERT_POSIX_SUCCESS(close(fd[0]), "close(fd[0])");
225*bbb1b6f9SApple OSS Distributions
226*bbb1b6f9SApple OSS Distributions check_runaway_mode(true);
227*bbb1b6f9SApple OSS Distributions
228*bbb1b6f9SApple OSS Distributions T_LOG("Exit pid %d with runaway mitigation mode on", getpid());
229*bbb1b6f9SApple OSS Distributions
230*bbb1b6f9SApple OSS Distributions exit(0);
231*bbb1b6f9SApple OSS Distributions } else {
232*bbb1b6f9SApple OSS Distributions T_ASSERT_POSIX_SUCCESS(child_pid, "fork parent: child pid %d", child_pid);
233*bbb1b6f9SApple OSS Distributions
234*bbb1b6f9SApple OSS Distributions T_ASSERT_POSIX_SUCCESS(setpriority(PRIO_DARWIN_RUNAWAY_MITIGATION, child_pid, PRIO_DARWIN_RUNAWAY_MITIGATION_ON),
235*bbb1b6f9SApple OSS Distributions "setpriority(PRIO_DARWIN_RUNAWAY_MITIGATION, child_pid, PRIO_DARWIN_RUNAWAY_MITIGATION_ON)");
236*bbb1b6f9SApple OSS Distributions
237*bbb1b6f9SApple OSS Distributions int runaway_mode = getpriority(PRIO_DARWIN_RUNAWAY_MITIGATION, child_pid);
238*bbb1b6f9SApple OSS Distributions
239*bbb1b6f9SApple OSS Distributions T_QUIET;
240*bbb1b6f9SApple OSS Distributions T_ASSERT_POSIX_SUCCESS(runaway_mode, "getpriority(PRIO_DARWIN_RUNAWAY_MITIGATION)");
241*bbb1b6f9SApple OSS Distributions
242*bbb1b6f9SApple OSS Distributions T_ASSERT_EQ(runaway_mode, PRIO_DARWIN_RUNAWAY_MITIGATION_ON, "should be on");
243*bbb1b6f9SApple OSS Distributions
244*bbb1b6f9SApple OSS Distributions T_QUIET; T_LOG("Signalling child to continue");
245*bbb1b6f9SApple OSS Distributions T_ASSERT_POSIX_SUCCESS(close(fd[1]), "close(fd[1])");
246*bbb1b6f9SApple OSS Distributions
247*bbb1b6f9SApple OSS Distributions /* wait for child process to exit */
248*bbb1b6f9SApple OSS Distributions int exit_status = 0, signum = 0;
249*bbb1b6f9SApple OSS Distributions
250*bbb1b6f9SApple OSS Distributions T_ASSERT_TRUE(dt_waitpid(child_pid, &exit_status, &signum, 5),
251*bbb1b6f9SApple OSS Distributions "wait for child (%d) complete", child_pid);
252*bbb1b6f9SApple OSS Distributions
253*bbb1b6f9SApple OSS Distributions T_QUIET; T_ASSERT_EQ(exit_status, 0, "dt_waitpid: exit_status");
254*bbb1b6f9SApple OSS Distributions T_QUIET; T_ASSERT_EQ(signum, 0, "dt_waitpid: signum");
255*bbb1b6f9SApple OSS Distributions }
256*bbb1b6f9SApple OSS Distributions
257*bbb1b6f9SApple OSS Distributions check_runaway_mode(false);
258*bbb1b6f9SApple OSS Distributions }
259*bbb1b6f9SApple OSS Distributions
260*bbb1b6f9SApple OSS Distributions
261*bbb1b6f9SApple OSS Distributions /*
262*bbb1b6f9SApple OSS Distributions * TODO: This should be in a test utils library,
263*bbb1b6f9SApple OSS Distributions * but it requires including Kernel.framework header kern/ledger.h, which is Bad
264*bbb1b6f9SApple OSS Distributions */
265*bbb1b6f9SApple OSS Distributions static size_t
ledger_index_for_string(size_t * num_entries,char * string)266*bbb1b6f9SApple OSS Distributions ledger_index_for_string(size_t *num_entries, char* string)
267*bbb1b6f9SApple OSS Distributions {
268*bbb1b6f9SApple OSS Distributions struct ledger_info li;
269*bbb1b6f9SApple OSS Distributions struct ledger_template_info *templateInfo = NULL;
270*bbb1b6f9SApple OSS Distributions int ret;
271*bbb1b6f9SApple OSS Distributions size_t i, footprint_index;
272*bbb1b6f9SApple OSS Distributions bool found = false;
273*bbb1b6f9SApple OSS Distributions
274*bbb1b6f9SApple OSS Distributions ret = ledger(LEDGER_INFO, (caddr_t)(uintptr_t)getpid(), (caddr_t)&li, NULL);
275*bbb1b6f9SApple OSS Distributions T_QUIET; T_ASSERT_POSIX_SUCCESS(ret, "ledger(LEDGER_INFO)");
276*bbb1b6f9SApple OSS Distributions
277*bbb1b6f9SApple OSS Distributions T_QUIET; T_ASSERT_GT(li.li_entries, (int64_t) 0, "num ledger entries is valid");
278*bbb1b6f9SApple OSS Distributions *num_entries = (size_t) li.li_entries;
279*bbb1b6f9SApple OSS Distributions templateInfo = malloc((size_t)li.li_entries * sizeof(struct ledger_template_info));
280*bbb1b6f9SApple OSS Distributions T_QUIET; T_ASSERT_NOTNULL(templateInfo, "malloc entries");
281*bbb1b6f9SApple OSS Distributions
282*bbb1b6f9SApple OSS Distributions footprint_index = 0;
283*bbb1b6f9SApple OSS Distributions ret = ledger(LEDGER_TEMPLATE_INFO, (caddr_t) templateInfo, (caddr_t) num_entries, NULL);
284*bbb1b6f9SApple OSS Distributions T_QUIET; T_ASSERT_POSIX_SUCCESS(ret, "ledger(LEDGER_TEMPLATE_INFO)");
285*bbb1b6f9SApple OSS Distributions for (i = 0; i < *num_entries; i++) {
286*bbb1b6f9SApple OSS Distributions if (strcmp(templateInfo[i].lti_name, string) == 0) {
287*bbb1b6f9SApple OSS Distributions footprint_index = i;
288*bbb1b6f9SApple OSS Distributions found = true;
289*bbb1b6f9SApple OSS Distributions }
290*bbb1b6f9SApple OSS Distributions }
291*bbb1b6f9SApple OSS Distributions free(templateInfo);
292*bbb1b6f9SApple OSS Distributions T_QUIET; T_ASSERT_TRUE(found, "found %s in ledger", string);
293*bbb1b6f9SApple OSS Distributions return footprint_index;
294*bbb1b6f9SApple OSS Distributions }
295*bbb1b6f9SApple OSS Distributions
296*bbb1b6f9SApple OSS Distributions /*
297*bbb1b6f9SApple OSS Distributions * sadly there's no 'get just this one ledger index' syscall,
298*bbb1b6f9SApple OSS Distributions * we have to read all ledgers and filter for the one we want
299*bbb1b6f9SApple OSS Distributions */
300*bbb1b6f9SApple OSS Distributions static int64_t
get_ledger_entry_for_pid(pid_t pid,size_t index,size_t num_entries)301*bbb1b6f9SApple OSS Distributions get_ledger_entry_for_pid(pid_t pid, size_t index, size_t num_entries)
302*bbb1b6f9SApple OSS Distributions {
303*bbb1b6f9SApple OSS Distributions int ret;
304*bbb1b6f9SApple OSS Distributions int64_t value;
305*bbb1b6f9SApple OSS Distributions struct ledger_entry_info *lei = NULL;
306*bbb1b6f9SApple OSS Distributions
307*bbb1b6f9SApple OSS Distributions lei = malloc(num_entries * sizeof(*lei));
308*bbb1b6f9SApple OSS Distributions ret = ledger(LEDGER_ENTRY_INFO, (caddr_t) (uintptr_t) pid, (caddr_t) lei, (caddr_t) &num_entries);
309*bbb1b6f9SApple OSS Distributions T_QUIET; T_ASSERT_POSIX_SUCCESS(ret, "ledger(LEDGER_ENTRY_INFO)");
310*bbb1b6f9SApple OSS Distributions value = lei[index].lei_balance;
311*bbb1b6f9SApple OSS Distributions free(lei);
312*bbb1b6f9SApple OSS Distributions return value;
313*bbb1b6f9SApple OSS Distributions }
314*bbb1b6f9SApple OSS Distributions
315*bbb1b6f9SApple OSS Distributions
316*bbb1b6f9SApple OSS Distributions uint64_t initial_sfi_window = 0, initial_class_offtime = 0;
317*bbb1b6f9SApple OSS Distributions
318*bbb1b6f9SApple OSS Distributions static void
restore_sfi_state(void)319*bbb1b6f9SApple OSS Distributions restore_sfi_state(void)
320*bbb1b6f9SApple OSS Distributions {
321*bbb1b6f9SApple OSS Distributions T_LOG("Restoring initial system SFI window %lld, SFI_CLASS_RUNAWAY_MITIGATION class offtime %lld",
322*bbb1b6f9SApple OSS Distributions initial_sfi_window, initial_class_offtime);
323*bbb1b6f9SApple OSS Distributions
324*bbb1b6f9SApple OSS Distributions /*
325*bbb1b6f9SApple OSS Distributions * Setting window will fail if there is a larger offtime set, and
326*bbb1b6f9SApple OSS Distributions * setting class will fail if the window is smaller.
327*bbb1b6f9SApple OSS Distributions * To avoid this, disable the window, configure new values, then finally
328*bbb1b6f9SApple OSS Distributions * re-enable the window.
329*bbb1b6f9SApple OSS Distributions */
330*bbb1b6f9SApple OSS Distributions
331*bbb1b6f9SApple OSS Distributions T_QUIET; T_ASSERT_POSIX_SUCCESS(system_set_sfi_window(0),
332*bbb1b6f9SApple OSS Distributions "system_set_sfi_window(0)");
333*bbb1b6f9SApple OSS Distributions
334*bbb1b6f9SApple OSS Distributions T_QUIET; T_ASSERT_POSIX_SUCCESS(sfi_set_class_offtime(SFI_CLASS_RUNAWAY_MITIGATION, initial_class_offtime),
335*bbb1b6f9SApple OSS Distributions "system_set_sfi_window(%lld)", initial_class_offtime);
336*bbb1b6f9SApple OSS Distributions T_QUIET; T_ASSERT_POSIX_SUCCESS(system_set_sfi_window(initial_sfi_window),
337*bbb1b6f9SApple OSS Distributions "system_set_sfi_window(%lld)", initial_sfi_window);
338*bbb1b6f9SApple OSS Distributions }
339*bbb1b6f9SApple OSS Distributions
340*bbb1b6f9SApple OSS Distributions const int spin_seconds = 1;
341*bbb1b6f9SApple OSS Distributions
342*bbb1b6f9SApple OSS Distributions
343*bbb1b6f9SApple OSS Distributions static void *
spin_thread(void * arg)344*bbb1b6f9SApple OSS Distributions spin_thread(void *arg)
345*bbb1b6f9SApple OSS Distributions {
346*bbb1b6f9SApple OSS Distributions static mach_timebase_info_data_t timebase_info;
347*bbb1b6f9SApple OSS Distributions mach_timebase_info(&timebase_info);
348*bbb1b6f9SApple OSS Distributions
349*bbb1b6f9SApple OSS Distributions uint64_t duration = spin_seconds * NSEC_PER_SEC * timebase_info.denom / timebase_info.numer;
350*bbb1b6f9SApple OSS Distributions uint64_t deadline = mach_absolute_time() + duration;
351*bbb1b6f9SApple OSS Distributions
352*bbb1b6f9SApple OSS Distributions while (mach_absolute_time() < deadline) {
353*bbb1b6f9SApple OSS Distributions ;
354*bbb1b6f9SApple OSS Distributions }
355*bbb1b6f9SApple OSS Distributions
356*bbb1b6f9SApple OSS Distributions return NULL;
357*bbb1b6f9SApple OSS Distributions }
358*bbb1b6f9SApple OSS Distributions
359*bbb1b6f9SApple OSS Distributions T_DECL(runaway_mode_child_sfi, "runaway mitigation mode should cause SFI")
360*bbb1b6f9SApple OSS Distributions {
361*bbb1b6f9SApple OSS Distributions T_LOG("uid: %d", getuid());
362*bbb1b6f9SApple OSS Distributions
363*bbb1b6f9SApple OSS Distributions check_runaway_mode(false);
364*bbb1b6f9SApple OSS Distributions
365*bbb1b6f9SApple OSS Distributions T_QUIET; T_ASSERT_POSIX_SUCCESS(system_get_sfi_window(&initial_sfi_window),
366*bbb1b6f9SApple OSS Distributions "system_get_sfi_window(&initial_sfi_window)");
367*bbb1b6f9SApple OSS Distributions
368*bbb1b6f9SApple OSS Distributions T_QUIET; T_ASSERT_POSIX_SUCCESS(sfi_get_class_offtime(SFI_CLASS_RUNAWAY_MITIGATION, &initial_class_offtime),
369*bbb1b6f9SApple OSS Distributions "sfi_get_class_offtime(SFI_CLASS_RUNAWAY_MITIGATION, &initial_class_offtime)");
370*bbb1b6f9SApple OSS Distributions
371*bbb1b6f9SApple OSS Distributions T_LOG("Initial System SFI window %lld, SFI_CLASS_RUNAWAY_MITIGATION class offtime %lld\n", initial_sfi_window, initial_class_offtime);
372*bbb1b6f9SApple OSS Distributions
373*bbb1b6f9SApple OSS Distributions size_t num_ledger_entries = 0;
374*bbb1b6f9SApple OSS Distributions size_t ledger_index = ledger_index_for_string(&num_ledger_entries, "SFI_CLASS_RUNAWAY_MITIGATION");
375*bbb1b6f9SApple OSS Distributions uint64_t sfi_time_before = get_ledger_entry_for_pid(getpid(), ledger_index, num_ledger_entries);
376*bbb1b6f9SApple OSS Distributions
377*bbb1b6f9SApple OSS Distributions T_LOG("SFI_CLASS_RUNAWAY_MITIGATION ledger index: %zu out of %zu\n", ledger_index, num_ledger_entries);
378*bbb1b6f9SApple OSS Distributions
379*bbb1b6f9SApple OSS Distributions T_LOG("Initial accumulated SFI time: %lld\n", sfi_time_before);
380*bbb1b6f9SApple OSS Distributions
381*bbb1b6f9SApple OSS Distributions T_ATEND(restore_sfi_state);
382*bbb1b6f9SApple OSS Distributions
383*bbb1b6f9SApple OSS Distributions uint64_t custom_sfi_window = 100000; /* microseconds */
384*bbb1b6f9SApple OSS Distributions uint64_t custom_class_offtime = 50000;
385*bbb1b6f9SApple OSS Distributions
386*bbb1b6f9SApple OSS Distributions T_LOG("Setting custom system SFI window %lld, SFI_CLASS_RUNAWAY_MITIGATION class offtime %lld",
387*bbb1b6f9SApple OSS Distributions custom_sfi_window, custom_class_offtime);
388*bbb1b6f9SApple OSS Distributions
389*bbb1b6f9SApple OSS Distributions T_QUIET; T_ASSERT_POSIX_SUCCESS(system_set_sfi_window(0),
390*bbb1b6f9SApple OSS Distributions "system_set_sfi_window(0)");
391*bbb1b6f9SApple OSS Distributions T_ASSERT_POSIX_SUCCESS(sfi_set_class_offtime(SFI_CLASS_RUNAWAY_MITIGATION, custom_class_offtime),
392*bbb1b6f9SApple OSS Distributions "sfi_set_class_offtime(SFI_CLASS_RUNAWAY_MITIGATION, %lld)", custom_class_offtime);
393*bbb1b6f9SApple OSS Distributions T_ASSERT_POSIX_SUCCESS(system_set_sfi_window(custom_sfi_window),
394*bbb1b6f9SApple OSS Distributions "system_set_sfi_window(%lld)", custom_sfi_window);
395*bbb1b6f9SApple OSS Distributions
396*bbb1b6f9SApple OSS Distributions pthread_t thread;
397*bbb1b6f9SApple OSS Distributions
398*bbb1b6f9SApple OSS Distributions T_LOG("Spawning thread to spin for %d seconds\n", spin_seconds);
399*bbb1b6f9SApple OSS Distributions
400*bbb1b6f9SApple OSS Distributions int rv = pthread_create(&thread, NULL, spin_thread, NULL);
401*bbb1b6f9SApple OSS Distributions T_QUIET; T_ASSERT_POSIX_SUCCESS(rv, "pthread_create");
402*bbb1b6f9SApple OSS Distributions
403*bbb1b6f9SApple OSS Distributions T_LOG("Enable mitigation mode\n");
404*bbb1b6f9SApple OSS Distributions
405*bbb1b6f9SApple OSS Distributions T_ASSERT_POSIX_SUCCESS(setpriority(PRIO_DARWIN_RUNAWAY_MITIGATION, 0, PRIO_DARWIN_RUNAWAY_MITIGATION_ON),
406*bbb1b6f9SApple OSS Distributions "setpriority(PRIO_DARWIN_RUNAWAY_MITIGATION, 0, PRIO_DARWIN_RUNAWAY_MITIGATION_ON)");
407*bbb1b6f9SApple OSS Distributions
408*bbb1b6f9SApple OSS Distributions check_runaway_mode(true);
409*bbb1b6f9SApple OSS Distributions
410*bbb1b6f9SApple OSS Distributions T_LOG("Wait %d seconds for spin to finish\n", spin_seconds);
411*bbb1b6f9SApple OSS Distributions
412*bbb1b6f9SApple OSS Distributions rv = pthread_join(thread, NULL);
413*bbb1b6f9SApple OSS Distributions T_QUIET; T_ASSERT_POSIX_SUCCESS(rv, "pthread_join");
414*bbb1b6f9SApple OSS Distributions
415*bbb1b6f9SApple OSS Distributions T_LOG("Thread joined, disable mitigation mode\n");
416*bbb1b6f9SApple OSS Distributions
417*bbb1b6f9SApple OSS Distributions T_ASSERT_POSIX_SUCCESS(setpriority(PRIO_DARWIN_RUNAWAY_MITIGATION, 0, PRIO_DARWIN_RUNAWAY_MITIGATION_OFF),
418*bbb1b6f9SApple OSS Distributions "setpriority(PRIO_DARWIN_RUNAWAY_MITIGATION, 0, PRIO_DARWIN_RUNAWAY_MITIGATION_OFF)");
419*bbb1b6f9SApple OSS Distributions
420*bbb1b6f9SApple OSS Distributions uint64_t sfi_time_after = get_ledger_entry_for_pid(getpid(), ledger_index, num_ledger_entries);
421*bbb1b6f9SApple OSS Distributions
422*bbb1b6f9SApple OSS Distributions T_LOG("Ending accumulated SFI time: %lld\n", sfi_time_after);
423*bbb1b6f9SApple OSS Distributions
424*bbb1b6f9SApple OSS Distributions T_ASSERT_LT(sfi_time_before, sfi_time_after, "SFI_CLASS_RUNAWAY_MITIGATION SFI time must have increased");
425*bbb1b6f9SApple OSS Distributions
426*bbb1b6f9SApple OSS Distributions check_runaway_mode(false);
427*bbb1b6f9SApple OSS Distributions
428*bbb1b6f9SApple OSS Distributions uint64_t final_sfi_window = 0, final_class_offtime = 0;
429*bbb1b6f9SApple OSS Distributions
430*bbb1b6f9SApple OSS Distributions T_QUIET; T_ASSERT_POSIX_SUCCESS(system_get_sfi_window(&final_sfi_window),
431*bbb1b6f9SApple OSS Distributions "system_get_sfi_window(&final_sfi_window)");
432*bbb1b6f9SApple OSS Distributions
433*bbb1b6f9SApple OSS Distributions T_QUIET; T_ASSERT_POSIX_SUCCESS(sfi_get_class_offtime(SFI_CLASS_RUNAWAY_MITIGATION, &final_class_offtime),
434*bbb1b6f9SApple OSS Distributions "sfi_get_class_offtime(SFI_CLASS_RUNAWAY_MITIGATION, &final_class_offtime)");
435*bbb1b6f9SApple OSS Distributions
436*bbb1b6f9SApple OSS Distributions /*
437*bbb1b6f9SApple OSS Distributions * If the System SFI configuration was changed out from under us during the test, either us or them will be confused.
438*bbb1b6f9SApple OSS Distributions */
439*bbb1b6f9SApple OSS Distributions T_QUIET; T_ASSERT_EQ(custom_sfi_window, final_sfi_window, "System SFI window should not unexpectedly change during the test");
440*bbb1b6f9SApple OSS Distributions T_QUIET; T_ASSERT_EQ(custom_class_offtime, final_class_offtime, "System SFI offtime should not unexpectedly change during the test");
441*bbb1b6f9SApple OSS Distributions }
442*bbb1b6f9SApple OSS Distributions
443*bbb1b6f9SApple OSS Distributions #if defined(__arm64__)
444*bbb1b6f9SApple OSS Distributions
445*bbb1b6f9SApple OSS Distributions static bool found_flag = false;
446*bbb1b6f9SApple OSS Distributions static bool found_self = false;
447*bbb1b6f9SApple OSS Distributions
448*bbb1b6f9SApple OSS Distributions static const size_t microstackshot_buf_size = 16 * 1024;
449*bbb1b6f9SApple OSS Distributions
450*bbb1b6f9SApple OSS Distributions static bool
search_for_self_microstackshot(bool log_details)451*bbb1b6f9SApple OSS Distributions search_for_self_microstackshot(bool log_details)
452*bbb1b6f9SApple OSS Distributions {
453*bbb1b6f9SApple OSS Distributions void *buf = calloc(microstackshot_buf_size, 1);
454*bbb1b6f9SApple OSS Distributions T_QUIET; T_ASSERT_NOTNULL(buf, "allocate buffer");
455*bbb1b6f9SApple OSS Distributions
456*bbb1b6f9SApple OSS Distributions int ret = __microstackshot(buf, microstackshot_buf_size, STACKSHOT_GET_MICROSTACKSHOT);
457*bbb1b6f9SApple OSS Distributions T_QUIET; T_ASSERT_POSIX_SUCCESS(ret, "microstackshot");
458*bbb1b6f9SApple OSS Distributions
459*bbb1b6f9SApple OSS Distributions if (!log_details) {
460*bbb1b6f9SApple OSS Distributions T_QUIET;
461*bbb1b6f9SApple OSS Distributions }
462*bbb1b6f9SApple OSS Distributions T_EXPECT_EQ(*(uint32_t *)buf,
463*bbb1b6f9SApple OSS Distributions (uint32_t)STACKSHOT_MICRO_SNAPSHOT_MAGIC,
464*bbb1b6f9SApple OSS Distributions "magic value for microstackshot matches");
465*bbb1b6f9SApple OSS Distributions
466*bbb1b6f9SApple OSS Distributions uint32_t magic = STACKSHOT_TASK_SNAPSHOT_MAGIC;
467*bbb1b6f9SApple OSS Distributions
468*bbb1b6f9SApple OSS Distributions void* next_tsnap = memmem(buf, microstackshot_buf_size, &magic, sizeof(magic));
469*bbb1b6f9SApple OSS Distributions
470*bbb1b6f9SApple OSS Distributions void* buf_end = buf + microstackshot_buf_size;
471*bbb1b6f9SApple OSS Distributions
472*bbb1b6f9SApple OSS Distributions while (next_tsnap != NULL && next_tsnap + sizeof(struct task_snapshot) < buf_end) {
473*bbb1b6f9SApple OSS Distributions struct task_snapshot *tsnap = (struct task_snapshot *)next_tsnap;
474*bbb1b6f9SApple OSS Distributions unsigned int offset = next_tsnap - buf;
475*bbb1b6f9SApple OSS Distributions
476*bbb1b6f9SApple OSS Distributions if (log_details) {
477*bbb1b6f9SApple OSS Distributions T_LOG("%6d: found snap pid %d name %s\n", offset, tsnap->pid, (char*)&tsnap->p_comm);
478*bbb1b6f9SApple OSS Distributions }
479*bbb1b6f9SApple OSS Distributions
480*bbb1b6f9SApple OSS Distributions if (tsnap->pid == getpid()) {
481*bbb1b6f9SApple OSS Distributions if (log_details) {
482*bbb1b6f9SApple OSS Distributions T_LOG("%6d: found self snap: flags 0x%x 0x%llx\n", offset, tsnap->ss_flags, tsnap->disk_reads_count);
483*bbb1b6f9SApple OSS Distributions }
484*bbb1b6f9SApple OSS Distributions found_self = true;
485*bbb1b6f9SApple OSS Distributions
486*bbb1b6f9SApple OSS Distributions if (tsnap->disk_reads_count & kTaskRunawayMitigation) {
487*bbb1b6f9SApple OSS Distributions T_LOG("%6d: found runaway flag: pid %d, name %s, flags: 0x%x 0x%llx, \n",
488*bbb1b6f9SApple OSS Distributions offset, tsnap->pid, (char*)&tsnap->p_comm, tsnap->ss_flags, tsnap->disk_reads_count);
489*bbb1b6f9SApple OSS Distributions found_flag = true;
490*bbb1b6f9SApple OSS Distributions }
491*bbb1b6f9SApple OSS Distributions }
492*bbb1b6f9SApple OSS Distributions
493*bbb1b6f9SApple OSS Distributions void* search_start = next_tsnap + sizeof(struct task_snapshot);
494*bbb1b6f9SApple OSS Distributions size_t remaining_size = buf_end - search_start;
495*bbb1b6f9SApple OSS Distributions next_tsnap = memmem(search_start, remaining_size, &magic, sizeof(magic));
496*bbb1b6f9SApple OSS Distributions }
497*bbb1b6f9SApple OSS Distributions
498*bbb1b6f9SApple OSS Distributions free(buf);
499*bbb1b6f9SApple OSS Distributions
500*bbb1b6f9SApple OSS Distributions return found_flag;
501*bbb1b6f9SApple OSS Distributions }
502*bbb1b6f9SApple OSS Distributions
503*bbb1b6f9SApple OSS Distributions T_DECL(runaway_mode_microstackshot_flag,
504*bbb1b6f9SApple OSS Distributions "check that mitigated processes show up in microstackshot",
505*bbb1b6f9SApple OSS Distributions T_META_REQUIRES_SYSCTL_EQ("kern.monotonic.supported", 1),
506*bbb1b6f9SApple OSS Distributions T_META_TAG_VM_NOT_ELIGIBLE, T_META_TIMEOUT(120))
507*bbb1b6f9SApple OSS Distributions {
508*bbb1b6f9SApple OSS Distributions unsigned int pmi_counter;
509*bbb1b6f9SApple OSS Distributions size_t sysctl_size = sizeof(pmi_counter);
510*bbb1b6f9SApple OSS Distributions int ret = sysctlbyname(
511*bbb1b6f9SApple OSS Distributions "kern.microstackshot.pmi_sample_counter",
512*bbb1b6f9SApple OSS Distributions &pmi_counter, &sysctl_size, NULL, 0);
513*bbb1b6f9SApple OSS Distributions if (ret == -1 && errno == ENOENT) {
514*bbb1b6f9SApple OSS Distributions T_SKIP("no PMI support");
515*bbb1b6f9SApple OSS Distributions } else {
516*bbb1b6f9SApple OSS Distributions T_QUIET; T_ASSERT_POSIX_SUCCESS(ret, "query PMI counter");
517*bbb1b6f9SApple OSS Distributions }
518*bbb1b6f9SApple OSS Distributions uint64_t pmi_period;
519*bbb1b6f9SApple OSS Distributions sysctl_size = sizeof(pmi_period);
520*bbb1b6f9SApple OSS Distributions T_QUIET;
521*bbb1b6f9SApple OSS Distributions T_ASSERT_POSIX_SUCCESS(sysctlbyname(
522*bbb1b6f9SApple OSS Distributions "kern.microstackshot.pmi_sample_period",
523*bbb1b6f9SApple OSS Distributions &pmi_period, &sysctl_size, NULL, 0),
524*bbb1b6f9SApple OSS Distributions "query PMI period");
525*bbb1b6f9SApple OSS Distributions
526*bbb1b6f9SApple OSS Distributions T_LOG("PMI counter: %u", pmi_counter);
527*bbb1b6f9SApple OSS Distributions T_LOG("PMI period: %llu", pmi_period);
528*bbb1b6f9SApple OSS Distributions
529*bbb1b6f9SApple OSS Distributions if (pmi_period == 0) {
530*bbb1b6f9SApple OSS Distributions T_SKIP("PMI microstackshots not enabled");
531*bbb1b6f9SApple OSS Distributions }
532*bbb1b6f9SApple OSS Distributions
533*bbb1b6f9SApple OSS Distributions T_LOG("Enable mitigation mode on self\n");
534*bbb1b6f9SApple OSS Distributions
535*bbb1b6f9SApple OSS Distributions T_EXPECT_POSIX_SUCCESS(setpriority(PRIO_DARWIN_RUNAWAY_MITIGATION,
536*bbb1b6f9SApple OSS Distributions 0, PRIO_DARWIN_RUNAWAY_MITIGATION_ON),
537*bbb1b6f9SApple OSS Distributions "setpriority(PRIO_DARWIN_RUNAWAY_MITIGATION, 0, PRIO_DARWIN_RUNAWAY_MITIGATION_ON)");
538*bbb1b6f9SApple OSS Distributions
539*bbb1b6f9SApple OSS Distributions uint32_t iterations = 100;
540*bbb1b6f9SApple OSS Distributions
541*bbb1b6f9SApple OSS Distributions /* Over-spin to make it likely we get sampled at least once before failing */
542*bbb1b6f9SApple OSS Distributions uint32_t multiplier = 10;
543*bbb1b6f9SApple OSS Distributions uint64_t target_cycles = multiplier * pmi_period;
544*bbb1b6f9SApple OSS Distributions
545*bbb1b6f9SApple OSS Distributions T_LOG("Spinning for %d iterations or %lld*%d cycles or until self-sample is found\n",
546*bbb1b6f9SApple OSS Distributions iterations, pmi_period, multiplier);
547*bbb1b6f9SApple OSS Distributions
548*bbb1b6f9SApple OSS Distributions struct rusage_info_v6 ru = {};
549*bbb1b6f9SApple OSS Distributions
550*bbb1b6f9SApple OSS Distributions for (int i = 0; i < iterations; i++) {
551*bbb1b6f9SApple OSS Distributions spin_thread(NULL);
552*bbb1b6f9SApple OSS Distributions
553*bbb1b6f9SApple OSS Distributions int rv = proc_pid_rusage(getpid(), RUSAGE_INFO_V6, (rusage_info_t *)&ru);
554*bbb1b6f9SApple OSS Distributions T_QUIET; T_ASSERT_POSIX_SUCCESS(rv, "proc_pid_rusage");
555*bbb1b6f9SApple OSS Distributions
556*bbb1b6f9SApple OSS Distributions T_LOG("iteration %3d: %14lld / %14lld cycles executed (%.2f%%)\n", i,
557*bbb1b6f9SApple OSS Distributions ru.ri_cycles, target_cycles,
558*bbb1b6f9SApple OSS Distributions ((double)ru.ri_cycles) * 100.0 / (double)target_cycles);
559*bbb1b6f9SApple OSS Distributions
560*bbb1b6f9SApple OSS Distributions T_QUIET; T_ASSERT_NE(ru.ri_cycles, (uint64_t)0,
561*bbb1b6f9SApple OSS Distributions "should be able to measure cycles with proc_pid_rusage");
562*bbb1b6f9SApple OSS Distributions
563*bbb1b6f9SApple OSS Distributions bool found = search_for_self_microstackshot(false);
564*bbb1b6f9SApple OSS Distributions if (ru.ri_cycles > target_cycles || found) {
565*bbb1b6f9SApple OSS Distributions break;
566*bbb1b6f9SApple OSS Distributions }
567*bbb1b6f9SApple OSS Distributions }
568*bbb1b6f9SApple OSS Distributions
569*bbb1b6f9SApple OSS Distributions T_LOG("Complete, executed %lld cycles. Disable mitigation mode.\n", ru.ri_cycles);
570*bbb1b6f9SApple OSS Distributions
571*bbb1b6f9SApple OSS Distributions T_EXPECT_POSIX_SUCCESS(setpriority(PRIO_DARWIN_RUNAWAY_MITIGATION,
572*bbb1b6f9SApple OSS Distributions 0, PRIO_DARWIN_RUNAWAY_MITIGATION_OFF),
573*bbb1b6f9SApple OSS Distributions "setpriority(PRIO_DARWIN_RUNAWAY_MITIGATION, 0, PRIO_DARWIN_RUNAWAY_MITIGATION_OFF)");
574*bbb1b6f9SApple OSS Distributions
575*bbb1b6f9SApple OSS Distributions search_for_self_microstackshot(true);
576*bbb1b6f9SApple OSS Distributions
577*bbb1b6f9SApple OSS Distributions T_EXPECT_EQ(found_self, true,
578*bbb1b6f9SApple OSS Distributions "Should have found self in microstackshot buffer");
579*bbb1b6f9SApple OSS Distributions T_EXPECT_EQ(found_flag, true,
580*bbb1b6f9SApple OSS Distributions "Should have found kTaskRunawayMitigation flag in microstackshot buffer");
581*bbb1b6f9SApple OSS Distributions }
582*bbb1b6f9SApple OSS Distributions #endif // defined(__arm64__)
583