1*d4514f0bSApple OSS Distributions /*
2*d4514f0bSApple OSS Distributions * Copyright (c) 2023 Apple Computer, Inc. All rights reserved.
3*d4514f0bSApple OSS Distributions *
4*d4514f0bSApple OSS Distributions * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
5*d4514f0bSApple OSS Distributions *
6*d4514f0bSApple OSS Distributions * This file contains Original Code and/or Modifications of Original Code
7*d4514f0bSApple OSS Distributions * as defined in and that are subject to the Apple Public Source License
8*d4514f0bSApple OSS Distributions * Version 2.0 (the 'License'). You may not use this file except in
9*d4514f0bSApple OSS Distributions * compliance with the License. The rights granted to you under the License
10*d4514f0bSApple OSS Distributions * may not be used to create, or enable the creation or redistribution of,
11*d4514f0bSApple OSS Distributions * unlawful or unlicensed copies of an Apple operating system, or to
12*d4514f0bSApple OSS Distributions * circumvent, violate, or enable the circumvention or violation of, any
13*d4514f0bSApple OSS Distributions * terms of an Apple operating system software license agreement.
14*d4514f0bSApple OSS Distributions *
15*d4514f0bSApple OSS Distributions * Please obtain a copy of the License at
16*d4514f0bSApple OSS Distributions * http://www.opensource.apple.com/apsl/ and read it before using this file.
17*d4514f0bSApple OSS Distributions *
18*d4514f0bSApple OSS Distributions * The Original Code and all software distributed under the License are
19*d4514f0bSApple OSS Distributions * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
20*d4514f0bSApple OSS Distributions * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
21*d4514f0bSApple OSS Distributions * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
22*d4514f0bSApple OSS Distributions * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
23*d4514f0bSApple OSS Distributions * Please see the License for the specific language governing rights and
24*d4514f0bSApple OSS Distributions * limitations under the License.
25*d4514f0bSApple OSS Distributions *
26*d4514f0bSApple OSS Distributions * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
27*d4514f0bSApple OSS Distributions */
28*d4514f0bSApple OSS Distributions
29*d4514f0bSApple OSS Distributions #include <darwintest.h>
30*d4514f0bSApple OSS Distributions #include <stdlib.h>
31*d4514f0bSApple OSS Distributions #include <unistd.h>
32*d4514f0bSApple OSS Distributions #include <mach/exception_types.h>
33*d4514f0bSApple OSS Distributions #include <sys/wait.h>
34*d4514f0bSApple OSS Distributions #include <sys/sysctl.h>
35*d4514f0bSApple OSS Distributions #include <sys/code_signing.h>
36*d4514f0bSApple OSS Distributions
37*d4514f0bSApple OSS Distributions #include "exc_helpers.h"
38*d4514f0bSApple OSS Distributions #include "test_utils.h"
39*d4514f0bSApple OSS Distributions
40*d4514f0bSApple OSS Distributions T_GLOBAL_META(
41*d4514f0bSApple OSS Distributions T_META_NAMESPACE("xnu.arm"),
42*d4514f0bSApple OSS Distributions T_META_RADAR_COMPONENT_NAME("xnu"),
43*d4514f0bSApple OSS Distributions T_META_RADAR_COMPONENT_VERSION("arm"),
44*d4514f0bSApple OSS Distributions T_META_OWNER("ghackmann"),
45*d4514f0bSApple OSS Distributions T_META_REQUIRES_SYSCTL_EQ("hw.optional.ptrauth", 1),
46*d4514f0bSApple OSS Distributions T_META_IGNORECRASHES(".*pac_exception_entitlement.*"),
47*d4514f0bSApple OSS Distributions XNU_T_META_SOC_SPECIFIC
48*d4514f0bSApple OSS Distributions );
49*d4514f0bSApple OSS Distributions
50*d4514f0bSApple OSS Distributions #if __arm64e__
51*d4514f0bSApple OSS Distributions static size_t
exception_handler(mach_port_t task __unused,mach_port_t thread __unused,exception_type_t type __unused,mach_exception_data_t codes __unused)52*d4514f0bSApple OSS Distributions exception_handler(mach_port_t task __unused, mach_port_t thread __unused,
53*d4514f0bSApple OSS Distributions exception_type_t type __unused, mach_exception_data_t codes __unused)
54*d4514f0bSApple OSS Distributions {
55*d4514f0bSApple OSS Distributions T_ASSERT_FAIL("kernel ran exception handler instead of terminating process");
56*d4514f0bSApple OSS Distributions }
57*d4514f0bSApple OSS Distributions
58*d4514f0bSApple OSS Distributions /*
59*d4514f0bSApple OSS Distributions * To trigger PAC failure, we create a validly-signed pointer and then flip an
60*d4514f0bSApple OSS Distributions * arbitrary PAC bit before accessing it. The exact number and location of PAC
61*d4514f0bSApple OSS Distributions * bits depends on the device configuration. For instruction pointers, the PAC
62*d4514f0bSApple OSS Distributions * field always includes bit 63. For data pointers, it may start as low as bit
63*d4514f0bSApple OSS Distributions * 54: bits 63-56 can be carved out for software tagging, and bit 55 is always
64*d4514f0bSApple OSS Distributions * reserved for addressing.
65*d4514f0bSApple OSS Distributions *
66*d4514f0bSApple OSS Distributions * Real-world software should use ptrauth.h when it needs to manually sign or
67*d4514f0bSApple OSS Distributions * auth pointers. But for testing purposes we need clang to emit specific
68*d4514f0bSApple OSS Distributions * ptrauth instructions, so we use inline asm here instead.
69*d4514f0bSApple OSS Distributions *
70*d4514f0bSApple OSS Distributions * Likewise clang would normally combine the "naked" auth and brk testcases as
71*d4514f0bSApple OSS Distributions * part of a sequence like:
72*d4514f0bSApple OSS Distributions *
73*d4514f0bSApple OSS Distributions * output = auth(...);
74*d4514f0bSApple OSS Distributions * if (output is poisoned) {
75*d4514f0bSApple OSS Distributions * brk(PTRAUTH_FAILURE_COMMENT);
76*d4514f0bSApple OSS Distributions * }
77*d4514f0bSApple OSS Distributions *
78*d4514f0bSApple OSS Distributions * On auth failure, CPUs that implement FEAT_FPAC will trap immediately at the
79*d4514f0bSApple OSS Distributions * auth instruction, and CPUs without FEAT_FPAC will trap at the later brk
80*d4514f0bSApple OSS Distributions * instruction. But again, for testing purposes we want these to be two
81*d4514f0bSApple OSS Distributions * discrete cases. (On FPAC-enabled CPUs, the kernel should treat *both* traps
82*d4514f0bSApple OSS Distributions * as ptrauth failure, even if we don't expect the latter to be reachable in
83*d4514f0bSApple OSS Distributions * real-world software.)
84*d4514f0bSApple OSS Distributions */
85*d4514f0bSApple OSS Distributions
86*d4514f0bSApple OSS Distributions static void
naked_auth(void)87*d4514f0bSApple OSS Distributions naked_auth(void)
88*d4514f0bSApple OSS Distributions {
89*d4514f0bSApple OSS Distributions asm volatile (
90*d4514f0bSApple OSS Distributions "mov x0, #0" "\n"
91*d4514f0bSApple OSS Distributions "paciza x0" "\n"
92*d4514f0bSApple OSS Distributions "eor x0, x0, (1 << 63)" "\n"
93*d4514f0bSApple OSS Distributions "autiza x0"
94*d4514f0bSApple OSS Distributions :
95*d4514f0bSApple OSS Distributions :
96*d4514f0bSApple OSS Distributions : "x0"
97*d4514f0bSApple OSS Distributions );
98*d4514f0bSApple OSS Distributions }
99*d4514f0bSApple OSS Distributions
100*d4514f0bSApple OSS Distributions static void
ptrauth_brk(void)101*d4514f0bSApple OSS Distributions ptrauth_brk(void)
102*d4514f0bSApple OSS Distributions {
103*d4514f0bSApple OSS Distributions asm volatile ("brk 0xc470");
104*d4514f0bSApple OSS Distributions }
105*d4514f0bSApple OSS Distributions
106*d4514f0bSApple OSS Distributions static void
combined_branch_auth(void)107*d4514f0bSApple OSS Distributions combined_branch_auth(void)
108*d4514f0bSApple OSS Distributions {
109*d4514f0bSApple OSS Distributions asm volatile (
110*d4514f0bSApple OSS Distributions "adr x0, 1f" "\n"
111*d4514f0bSApple OSS Distributions "paciza x0" "\n"
112*d4514f0bSApple OSS Distributions "eor x0, x0, (1 << 63)" "\n"
113*d4514f0bSApple OSS Distributions "braaz x0" "\n"
114*d4514f0bSApple OSS Distributions "1:"
115*d4514f0bSApple OSS Distributions :
116*d4514f0bSApple OSS Distributions :
117*d4514f0bSApple OSS Distributions : "x0"
118*d4514f0bSApple OSS Distributions );
119*d4514f0bSApple OSS Distributions }
120*d4514f0bSApple OSS Distributions
121*d4514f0bSApple OSS Distributions static void
combined_load_auth(void)122*d4514f0bSApple OSS Distributions combined_load_auth(void)
123*d4514f0bSApple OSS Distributions {
124*d4514f0bSApple OSS Distributions asm volatile (
125*d4514f0bSApple OSS Distributions "mov x0, sp" "\n"
126*d4514f0bSApple OSS Distributions "pacdza x0" "\n"
127*d4514f0bSApple OSS Distributions "eor x0, x0, (1 << 54)" "\n"
128*d4514f0bSApple OSS Distributions "ldraa x0, [x0]" "\n"
129*d4514f0bSApple OSS Distributions :
130*d4514f0bSApple OSS Distributions :
131*d4514f0bSApple OSS Distributions : "x0"
132*d4514f0bSApple OSS Distributions );
133*d4514f0bSApple OSS Distributions }
134*d4514f0bSApple OSS Distributions
135*d4514f0bSApple OSS Distributions static void
run_pac_exception_test(void (* ptrauth_failure_fn)(void))136*d4514f0bSApple OSS Distributions run_pac_exception_test(void (*ptrauth_failure_fn)(void))
137*d4514f0bSApple OSS Distributions {
138*d4514f0bSApple OSS Distributions
139*d4514f0bSApple OSS Distributions pid_t pid = fork();
140*d4514f0bSApple OSS Distributions T_QUIET; T_ASSERT_POSIX_SUCCESS(pid, "fork");
141*d4514f0bSApple OSS Distributions
142*d4514f0bSApple OSS Distributions if (pid == 0) {
143*d4514f0bSApple OSS Distributions mach_port_t exc_port = create_exception_port(EXC_MASK_BAD_ACCESS | EXC_MASK_BREAKPOINT);
144*d4514f0bSApple OSS Distributions run_exception_handler(exc_port, exception_handler);
145*d4514f0bSApple OSS Distributions
146*d4514f0bSApple OSS Distributions ptrauth_failure_fn();
147*d4514f0bSApple OSS Distributions /* ptrauth_failure_fn() should have raised an uncatchable exception */
148*d4514f0bSApple OSS Distributions T_FAIL("child ran to completion");
149*d4514f0bSApple OSS Distributions } else {
150*d4514f0bSApple OSS Distributions int status;
151*d4514f0bSApple OSS Distributions int err = waitpid(pid, &status, 0);
152*d4514f0bSApple OSS Distributions T_QUIET; T_ASSERT_POSIX_SUCCESS(err, "waitpid");
153*d4514f0bSApple OSS Distributions
154*d4514f0bSApple OSS Distributions T_EXPECT_TRUE(WIFSIGNALED(status), "child terminated due to signal");
155*d4514f0bSApple OSS Distributions T_EXPECT_EQ(SIGKILL, WTERMSIG(status), "child terminated due to SIGKILL");
156*d4514f0bSApple OSS Distributions }
157*d4514f0bSApple OSS Distributions }
158*d4514f0bSApple OSS Distributions #endif //__arm64e__
159*d4514f0bSApple OSS Distributions
160*d4514f0bSApple OSS Distributions T_DECL(pac_exception_naked_auth,
161*d4514f0bSApple OSS Distributions "Test the com.apple.private.pac.exception entitlement (naked auth failure)",
162*d4514f0bSApple OSS Distributions T_META_REQUIRES_SYSCTL_EQ("hw.optional.arm.FEAT_FPAC", 1), T_META_TAG_VM_NOT_ELIGIBLE)
163*d4514f0bSApple OSS Distributions {
164*d4514f0bSApple OSS Distributions #if __arm64e__
165*d4514f0bSApple OSS Distributions run_pac_exception_test(naked_auth);
166*d4514f0bSApple OSS Distributions #else
167*d4514f0bSApple OSS Distributions T_SKIP("Running on non-arm64e target, skipping...");
168*d4514f0bSApple OSS Distributions #endif
169*d4514f0bSApple OSS Distributions }
170*d4514f0bSApple OSS Distributions
171*d4514f0bSApple OSS Distributions
172*d4514f0bSApple OSS Distributions T_DECL(pac_exception_ptrauth_brk,
173*d4514f0bSApple OSS Distributions "Test the com.apple.private.pac.exception entitlement (brk with comment indicating ptrauth failure)", T_META_TAG_VM_NOT_ELIGIBLE)
174*d4514f0bSApple OSS Distributions {
175*d4514f0bSApple OSS Distributions #if __arm64e__
176*d4514f0bSApple OSS Distributions run_pac_exception_test(ptrauth_brk);
177*d4514f0bSApple OSS Distributions #else
178*d4514f0bSApple OSS Distributions T_SKIP("Running on non-arm64e target, skipping...");
179*d4514f0bSApple OSS Distributions #endif
180*d4514f0bSApple OSS Distributions }
181*d4514f0bSApple OSS Distributions
182*d4514f0bSApple OSS Distributions T_DECL(pac_exception_combined_branch_auth,
183*d4514f0bSApple OSS Distributions "Test the com.apple.private.pac.exception entitlement (combined branch + auth failure)", T_META_TAG_VM_NOT_ELIGIBLE)
184*d4514f0bSApple OSS Distributions {
185*d4514f0bSApple OSS Distributions #if __arm64e__
186*d4514f0bSApple OSS Distributions run_pac_exception_test(combined_branch_auth);
187*d4514f0bSApple OSS Distributions #else
188*d4514f0bSApple OSS Distributions T_SKIP("Running on non-arm64e target, skipping...");
189*d4514f0bSApple OSS Distributions #endif
190*d4514f0bSApple OSS Distributions }
191*d4514f0bSApple OSS Distributions
192*d4514f0bSApple OSS Distributions T_DECL(pac_exception_combined_load_auth,
193*d4514f0bSApple OSS Distributions "Test the com.apple.private.pac.exception entitlement (combined branch + auth failure)", T_META_TAG_VM_NOT_ELIGIBLE)
194*d4514f0bSApple OSS Distributions {
195*d4514f0bSApple OSS Distributions #if __arm64e__
196*d4514f0bSApple OSS Distributions run_pac_exception_test(combined_load_auth);
197*d4514f0bSApple OSS Distributions #else
198*d4514f0bSApple OSS Distributions T_SKIP("Running on non-arm64e target, skipping...");
199*d4514f0bSApple OSS Distributions #endif
200*d4514f0bSApple OSS Distributions }
201