1*d4514f0bSApple OSS Distributions #include <darwintest.h>
2*d4514f0bSApple OSS Distributions #include <darwintest_multiprocess.h>
3*d4514f0bSApple OSS Distributions
4*d4514f0bSApple OSS Distributions #include <bank/bank_types.h>
5*d4514f0bSApple OSS Distributions #include <libproc.h>
6*d4514f0bSApple OSS Distributions #include <mach/mach.h>
7*d4514f0bSApple OSS Distributions #include <mach/mach_voucher.h>
8*d4514f0bSApple OSS Distributions #include <mach/mach_voucher_types.h>
9*d4514f0bSApple OSS Distributions #include <os/voucher_private.h>
10*d4514f0bSApple OSS Distributions #include <sys/kauth.h>
11*d4514f0bSApple OSS Distributions #include <sys/persona.h>
12*d4514f0bSApple OSS Distributions #include <sys/proc_info.h>
13*d4514f0bSApple OSS Distributions #include <unistd.h>
14*d4514f0bSApple OSS Distributions #include <uuid/uuid.h>
15*d4514f0bSApple OSS Distributions
16*d4514f0bSApple OSS Distributions T_GLOBAL_META(
17*d4514f0bSApple OSS Distributions T_META_NAMESPACE("xnu.persona_adoption"),
18*d4514f0bSApple OSS Distributions T_META_CHECK_LEAKS(false),
19*d4514f0bSApple OSS Distributions T_META_RUN_CONCURRENTLY(true),
20*d4514f0bSApple OSS Distributions T_META_ENABLED(!TARGET_OS_WATCH) // rdar://81809878
21*d4514f0bSApple OSS Distributions );
22*d4514f0bSApple OSS Distributions
23*d4514f0bSApple OSS Distributions static uid_t
_persona_create(int persona_type,uid_t persona_uid)24*d4514f0bSApple OSS Distributions _persona_create(int persona_type, uid_t persona_uid)
25*d4514f0bSApple OSS Distributions {
26*d4514f0bSApple OSS Distributions struct kpersona_info pinfo = {
27*d4514f0bSApple OSS Distributions .persona_info_version = PERSONA_INFO_V2,
28*d4514f0bSApple OSS Distributions .persona_type = persona_type,
29*d4514f0bSApple OSS Distributions .persona_uid = persona_uid,
30*d4514f0bSApple OSS Distributions };
31*d4514f0bSApple OSS Distributions
32*d4514f0bSApple OSS Distributions uuid_t uuid;
33*d4514f0bSApple OSS Distributions uuid_generate(uuid);
34*d4514f0bSApple OSS Distributions uuid_string_t uuid_string;
35*d4514f0bSApple OSS Distributions uuid_unparse(uuid, uuid_string);
36*d4514f0bSApple OSS Distributions snprintf(pinfo.persona_name, MAXLOGNAME, "persona_adoption_test.%s", uuid_string);
37*d4514f0bSApple OSS Distributions
38*d4514f0bSApple OSS Distributions uid_t persona_id = 0;
39*d4514f0bSApple OSS Distributions int ret = kpersona_alloc(&pinfo, &persona_id);
40*d4514f0bSApple OSS Distributions T_WITH_ERRNO; T_ASSERT_EQ(ret, 0, NULL);
41*d4514f0bSApple OSS Distributions T_ASSERT_GT(persona_id, 0, NULL);
42*d4514f0bSApple OSS Distributions
43*d4514f0bSApple OSS Distributions return persona_id;
44*d4514f0bSApple OSS Distributions }
45*d4514f0bSApple OSS Distributions
46*d4514f0bSApple OSS Distributions static kern_return_t
_persona_try_adopting(uid_t persona_id)47*d4514f0bSApple OSS Distributions _persona_try_adopting(uid_t persona_id)
48*d4514f0bSApple OSS Distributions {
49*d4514f0bSApple OSS Distributions struct proc_uniqidentifierinfo uniqidinfo;
50*d4514f0bSApple OSS Distributions int error = proc_pidinfo(getpid(), PROC_PIDUNIQIDENTIFIERINFO, 0, &uniqidinfo, sizeof(uniqidinfo));
51*d4514f0bSApple OSS Distributions T_ASSERT_GT(error, 0, NULL);
52*d4514f0bSApple OSS Distributions
53*d4514f0bSApple OSS Distributions struct persona_modify_info pmi = {
54*d4514f0bSApple OSS Distributions .persona_id = persona_id,
55*d4514f0bSApple OSS Distributions .unique_pid = uniqidinfo.p_uniqueid,
56*d4514f0bSApple OSS Distributions };
57*d4514f0bSApple OSS Distributions
58*d4514f0bSApple OSS Distributions mach_voucher_t current_voucher = MACH_VOUCHER_NULL;
59*d4514f0bSApple OSS Distributions kern_return_t kr = mach_voucher_persona_self(¤t_voucher);
60*d4514f0bSApple OSS Distributions T_ASSERT_EQ(kr, 0, NULL);
61*d4514f0bSApple OSS Distributions T_ASSERT_NE(current_voucher, MACH_VOUCHER_NULL, NULL);
62*d4514f0bSApple OSS Distributions
63*d4514f0bSApple OSS Distributions char voucher_buf[sizeof(mach_voucher_attr_recipe_data_t) + sizeof(pmi)];
64*d4514f0bSApple OSS Distributions
65*d4514f0bSApple OSS Distributions mach_voucher_attr_recipe_t recipe = (mach_voucher_attr_recipe_t)&voucher_buf[0];
66*d4514f0bSApple OSS Distributions recipe->key = MACH_VOUCHER_ATTR_KEY_BANK;
67*d4514f0bSApple OSS Distributions recipe->command = MACH_VOUCHER_ATTR_BANK_MODIFY_PERSONA;
68*d4514f0bSApple OSS Distributions recipe->content_size = sizeof(pmi);
69*d4514f0bSApple OSS Distributions recipe->previous_voucher = current_voucher;
70*d4514f0bSApple OSS Distributions memcpy(recipe->content, (void *)&pmi, sizeof(pmi));
71*d4514f0bSApple OSS Distributions
72*d4514f0bSApple OSS Distributions mach_voucher_attr_raw_recipe_size_t recipe_size = sizeof(mach_voucher_attr_recipe_data_t) + recipe->content_size;
73*d4514f0bSApple OSS Distributions mach_voucher_attr_raw_recipe_array_t recipes = (mach_voucher_attr_raw_recipe_array_t)&voucher_buf[0];
74*d4514f0bSApple OSS Distributions mach_voucher_t mach_voucher = MACH_VOUCHER_NULL;
75*d4514f0bSApple OSS Distributions kr = host_create_mach_voucher(mach_host_self(), recipes, recipe_size, &mach_voucher);
76*d4514f0bSApple OSS Distributions if (kr != 0) {
77*d4514f0bSApple OSS Distributions return kr;
78*d4514f0bSApple OSS Distributions }
79*d4514f0bSApple OSS Distributions T_ASSERT_NE(mach_voucher, MACH_VOUCHER_NULL, NULL);
80*d4514f0bSApple OSS Distributions
81*d4514f0bSApple OSS Distributions /* Verify that persona is set on the voucher */
82*d4514f0bSApple OSS Distributions uint32_t voucher_persona;
83*d4514f0bSApple OSS Distributions mach_voucher_attr_content_t content_out = (mach_voucher_attr_content_t)&voucher_persona;
84*d4514f0bSApple OSS Distributions mach_voucher_attr_content_size_t content_out_size = sizeof(voucher_persona);
85*d4514f0bSApple OSS Distributions kr = mach_voucher_attr_command(mach_voucher, MACH_VOUCHER_ATTR_KEY_BANK, BANK_PERSONA_ID, NULL, 0, content_out, &content_out_size);
86*d4514f0bSApple OSS Distributions if (kr != 0) {
87*d4514f0bSApple OSS Distributions return kr;
88*d4514f0bSApple OSS Distributions }
89*d4514f0bSApple OSS Distributions T_ASSERT_EQ(voucher_persona, persona_id, NULL);
90*d4514f0bSApple OSS Distributions
91*d4514f0bSApple OSS Distributions kr = thread_set_mach_voucher(mach_thread_self(), mach_voucher);
92*d4514f0bSApple OSS Distributions return kr;
93*d4514f0bSApple OSS Distributions }
94*d4514f0bSApple OSS Distributions
95*d4514f0bSApple OSS Distributions T_DECL(persona_with_matching_uid_can_be_adopted,
96*d4514f0bSApple OSS Distributions "persona with UID matching at-spawn value can be adopted", T_META_TAG_VM_PREFERRED)
97*d4514f0bSApple OSS Distributions {
98*d4514f0bSApple OSS Distributions struct kpersona_info info = {
99*d4514f0bSApple OSS Distributions .persona_info_version = PERSONA_INFO_V2,
100*d4514f0bSApple OSS Distributions };
101*d4514f0bSApple OSS Distributions int error = kpersona_info(0, &info);
102*d4514f0bSApple OSS Distributions if (error != 0) {
103*d4514f0bSApple OSS Distributions T_SKIP("Test requrires to be running in a persona, skipping");
104*d4514f0bSApple OSS Distributions }
105*d4514f0bSApple OSS Distributions
106*d4514f0bSApple OSS Distributions uid_t created_persona = _persona_create(PERSONA_MANAGED, info.persona_uid);
107*d4514f0bSApple OSS Distributions kern_return_t kr = _persona_try_adopting(created_persona);
108*d4514f0bSApple OSS Distributions T_ASSERT_EQ(kr, 0, NULL);
109*d4514f0bSApple OSS Distributions
110*d4514f0bSApple OSS Distributions uid_t current_persona = PERSONA_ID_NONE;
111*d4514f0bSApple OSS Distributions T_ASSERT_EQ(kpersona_get(¤t_persona), 0, NULL);
112*d4514f0bSApple OSS Distributions T_ASSERT_EQ(current_persona, created_persona, NULL);
113*d4514f0bSApple OSS Distributions
114*d4514f0bSApple OSS Distributions T_ASSERT_EQ(kpersona_dealloc(created_persona), 0, NULL);
115*d4514f0bSApple OSS Distributions }
116*d4514f0bSApple OSS Distributions
117*d4514f0bSApple OSS Distributions T_DECL(persona_with_mismatched_uid_cannot_be_adopted,
118*d4514f0bSApple OSS Distributions "persona with UID that doesn't match at-spawn value cannot be adopted", T_META_TAG_VM_PREFERRED)
119*d4514f0bSApple OSS Distributions {
120*d4514f0bSApple OSS Distributions struct kpersona_info info = {
121*d4514f0bSApple OSS Distributions .persona_info_version = PERSONA_INFO_V2,
122*d4514f0bSApple OSS Distributions };
123*d4514f0bSApple OSS Distributions int error = kpersona_info(0, &info);
124*d4514f0bSApple OSS Distributions if (error != 0) {
125*d4514f0bSApple OSS Distributions T_SKIP("Test requrires to be running in a persona, skipping");
126*d4514f0bSApple OSS Distributions }
127*d4514f0bSApple OSS Distributions
128*d4514f0bSApple OSS Distributions uid_t mismatched_uid = info.persona_uid + 1;
129*d4514f0bSApple OSS Distributions uid_t created_persona = _persona_create(PERSONA_MANAGED, mismatched_uid);
130*d4514f0bSApple OSS Distributions kern_return_t kr = _persona_try_adopting(created_persona);
131*d4514f0bSApple OSS Distributions T_ASSERT_NE(kr, 0, NULL);
132*d4514f0bSApple OSS Distributions
133*d4514f0bSApple OSS Distributions uid_t current_persona = PERSONA_ID_NONE;
134*d4514f0bSApple OSS Distributions T_ASSERT_EQ(kpersona_get(¤t_persona), 0, NULL);
135*d4514f0bSApple OSS Distributions T_ASSERT_EQ(current_persona, info.persona_id, NULL);
136*d4514f0bSApple OSS Distributions
137*d4514f0bSApple OSS Distributions T_ASSERT_EQ(kpersona_dealloc(created_persona), 0, NULL);
138*d4514f0bSApple OSS Distributions }
139*d4514f0bSApple OSS Distributions
140*d4514f0bSApple OSS Distributions #if !TARGET_OS_BRIDGE // PersonaEnterprise is not supported on bridgeOS
141*d4514f0bSApple OSS Distributions
142*d4514f0bSApple OSS Distributions static uid_t _helper_persona = PERSONA_ID_NONE;
143*d4514f0bSApple OSS Distributions
144*d4514f0bSApple OSS Distributions static void
_run_helper_in_persona_cleanup(void)145*d4514f0bSApple OSS Distributions _run_helper_in_persona_cleanup(void)
146*d4514f0bSApple OSS Distributions {
147*d4514f0bSApple OSS Distributions kpersona_dealloc(_helper_persona);
148*d4514f0bSApple OSS Distributions }
149*d4514f0bSApple OSS Distributions
150*d4514f0bSApple OSS Distributions static void __attribute__((noreturn))
_run_helper_in_persona(const char * helper_name,int persona_type)151*d4514f0bSApple OSS Distributions _run_helper_in_persona(const char *helper_name, int persona_type)
152*d4514f0bSApple OSS Distributions {
153*d4514f0bSApple OSS Distributions struct kpersona_info info = {
154*d4514f0bSApple OSS Distributions .persona_info_version = PERSONA_INFO_V2,
155*d4514f0bSApple OSS Distributions };
156*d4514f0bSApple OSS Distributions int error = kpersona_info(0, &info);
157*d4514f0bSApple OSS Distributions uid_t persona_uid = (error == 0) ? info.persona_uid : geteuid();
158*d4514f0bSApple OSS Distributions _helper_persona = _persona_create(persona_type, persona_uid);
159*d4514f0bSApple OSS Distributions T_ATEND(_run_helper_in_persona_cleanup);
160*d4514f0bSApple OSS Distributions
161*d4514f0bSApple OSS Distributions xpc_object_t plist = xpc_dictionary_create_empty();
162*d4514f0bSApple OSS Distributions xpc_dictionary_set_bool(plist, "RunAtLoad", true);
163*d4514f0bSApple OSS Distributions xpc_dictionary_set_int64(plist, "PersonaEnterprise", _helper_persona);
164*d4514f0bSApple OSS Distributions dt_helper_t helper = dt_launchd_helper_plist(plist, helper_name, LAUNCH_SYSTEM_DOMAIN, NULL, NULL);
165*d4514f0bSApple OSS Distributions
166*d4514f0bSApple OSS Distributions dt_run_helpers(&helper, 1, 300);
167*d4514f0bSApple OSS Distributions }
168*d4514f0bSApple OSS Distributions
169*d4514f0bSApple OSS Distributions T_HELPER_DECL(own_persona_can_be_adopted_impl,
170*d4514f0bSApple OSS Distributions "own_persona_can_be_adopted helper spawned into persona type that prohibits adoption")
171*d4514f0bSApple OSS Distributions {
172*d4514f0bSApple OSS Distributions struct kpersona_info info = {
173*d4514f0bSApple OSS Distributions .persona_info_version = PERSONA_INFO_V2,
174*d4514f0bSApple OSS Distributions };
175*d4514f0bSApple OSS Distributions int error = kpersona_info(0, &info);
176*d4514f0bSApple OSS Distributions T_ASSERT_EQ(error, 0, NULL);
177*d4514f0bSApple OSS Distributions
178*d4514f0bSApple OSS Distributions kern_return_t kr = _persona_try_adopting(info.persona_id);
179*d4514f0bSApple OSS Distributions T_ASSERT_EQ(kr, 0, NULL);
180*d4514f0bSApple OSS Distributions }
181*d4514f0bSApple OSS Distributions
182*d4514f0bSApple OSS Distributions T_DECL(own_persona_can_be_adopted,
183*d4514f0bSApple OSS Distributions "process spawned into a persona type that prohibits adoption can adopt own persona", T_META_TAG_VM_PREFERRED)
184*d4514f0bSApple OSS Distributions {
185*d4514f0bSApple OSS Distributions _run_helper_in_persona("own_persona_can_be_adopted_impl", PERSONA_MANAGED);
186*d4514f0bSApple OSS Distributions }
187*d4514f0bSApple OSS Distributions
188*d4514f0bSApple OSS Distributions #endif // TARGET_OS_BRIDGE
189