]>
git.saurik.com Git - apple/xnu.git/blob - bsd/kern/sys_persona.c
2 * Copyright (c) 2015 Apple Inc. All rights reserved.
4 * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. The rights granted to you under the License
10 * may not be used to create, or enable the creation or redistribution of,
11 * unlawful or unlicensed copies of an Apple operating system, or to
12 * circumvent, violate, or enable the circumvention or violation of, any
13 * terms of an Apple operating system software license agreement.
15 * Please obtain a copy of the License at
16 * http://www.opensource.apple.com/apsl/ and read it before using this file.
18 * The Original Code and all software distributed under the License are
19 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
20 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
21 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
22 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
23 * Please see the License for the specific language governing rights and
24 * limitations under the License.
26 * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
28 #include <sys/param.h>
29 #include <sys/kernel.h>
30 #include <sys/kernel_types.h>
31 #include <sys/sysproto.h>
33 #include <sys/kauth.h>
34 #include <sys/malloc.h>
35 #include <sys/persona.h>
38 #include <kern/task.h>
39 #include <kern/thread.h>
40 #include <mach/thread_act.h>
41 #include <mach/mach_types.h>
43 #include <libkern/libkern.h>
44 #include <IOKit/IOBSD.h>
46 extern kern_return_t
bank_get_bank_ledger_thread_group_and_persona(void *voucher
,
47 void *bankledger
, void **banktg
, uint32_t *persona_id
);
50 kpersona_copyin(user_addr_t infop
, struct kpersona_info
*kinfo
)
55 error
= copyin(infop
, &info_v
, sizeof(info_v
));
60 /* only support a single version of the struct for now */
61 if (info_v
!= PERSONA_INFO_V1
) {
65 error
= copyin(infop
, kinfo
, sizeof(*kinfo
));
67 /* enforce NULL termination on strings */
68 kinfo
->persona_name
[MAXLOGNAME
] = 0;
74 kpersona_copyout(struct kpersona_info
*kinfo
, user_addr_t infop
)
79 error
= copyin(infop
, &info_v
, sizeof(info_v
));
84 /* only support a single version of the struct for now */
85 /* TODO: in the future compare info_v to kinfo->persona_info_version */
86 if (info_v
!= PERSONA_INFO_V1
) {
90 error
= copyout(kinfo
, infop
, sizeof(*kinfo
));
96 kpersona_alloc_syscall(user_addr_t infop
, user_addr_t idp
, user_addr_t path
)
99 struct kpersona_info kinfo
;
100 struct persona
*persona
= NULL
;
101 uid_t id
= PERSONA_ID_NONE
;
103 char *pna_path
= NULL
;
105 if (!IOTaskHasEntitlement(current_task(), PERSONA_MGMT_ENTITLEMENT
)) {
109 error
= kpersona_copyin(infop
, &kinfo
);
114 login
= kinfo
.persona_name
[0] ? kinfo
.persona_name
: NULL
;
115 if (kinfo
.persona_id
!= PERSONA_ID_NONE
&& kinfo
.persona_id
!= (uid_t
)0) {
116 id
= kinfo
.persona_id
;
120 MALLOC_ZONE(pna_path
, caddr_t
, MAXPATHLEN
, M_NAMEI
, M_WAITOK
| M_ZERO
);
121 if (pna_path
== NULL
) {
125 error
= copyinstr(path
, (void *)pna_path
, MAXPATHLEN
, &pathlen
);
127 FREE_ZONE(pna_path
, MAXPATHLEN
, M_NAMEI
);
133 persona
= persona_alloc(id
, login
, kinfo
.persona_type
, pna_path
, &error
);
135 if (pna_path
!= NULL
) {
136 FREE_ZONE(pna_path
, MAXPATHLEN
, M_NAMEI
);
141 /* persona struct contains a reference to pna_path */
144 error
= persona_init_begin(persona
);
146 goto out_persona_err
;
149 if (kinfo
.persona_gid
) {
150 error
= persona_set_gid(persona
, kinfo
.persona_gid
);
152 goto out_persona_err
;
156 if (kinfo
.persona_ngroups
> 0) {
157 /* force gmuid 0 to *opt-out* of memberd */
158 if (kinfo
.persona_gmuid
== 0) {
159 kinfo
.persona_gmuid
= KAUTH_UID_NONE
;
162 error
= persona_set_groups(persona
, kinfo
.persona_groups
,
163 kinfo
.persona_ngroups
,
164 kinfo
.persona_gmuid
);
166 goto out_persona_err
;
170 error
= copyout(&persona
->pna_id
, idp
, sizeof(persona
->pna_id
));
172 goto out_persona_err
;
175 kinfo
.persona_id
= persona
->pna_id
;
176 error
= kpersona_copyout(&kinfo
, infop
);
178 goto out_persona_err
;
181 error
= persona_verify_and_set_uniqueness(persona
);
183 goto out_persona_err
;
186 persona_init_end(persona
, error
);
189 * On success, we have a persona structure in the global list with a
190 * single reference count on it. The corresponding _dealloc() call
191 * will release this reference.
197 persona_init_end(persona
, error
);
200 printf("%s: ERROR:%d\n", __func__
, error
);
203 persona_put(persona
);
209 kpersona_dealloc_syscall(user_addr_t idp
)
213 struct persona
*persona
;
215 if (!IOTaskHasEntitlement(current_task(), PERSONA_MGMT_ENTITLEMENT
)) {
219 error
= copyin(idp
, &persona_id
, sizeof(persona_id
));
224 /* invalidate the persona (deny subsequent spawn/fork) */
225 persona
= persona_lookup_and_invalidate(persona_id
);
231 /* one reference from the _lookup() */
232 persona_put(persona
);
234 /* one reference from the _alloc() */
235 persona_put(persona
);
241 kpersona_get_syscall(user_addr_t idp
)
244 struct persona
*persona
;
246 persona
= current_persona_get();
252 error
= copyout(&persona
->pna_id
, idp
, sizeof(persona
->pna_id
));
253 persona_put(persona
);
259 kpersona_getpath_syscall(user_addr_t idp
, user_addr_t path
)
263 struct persona
*persona
;
265 uid_t current_persona_id
= PERSONA_ID_NONE
;
271 error
= copyin(idp
, &persona_id
, sizeof(persona_id
));
276 /* Get current thread's persona id to compare if the
277 * input persona_id matches the current persona id
279 persona
= current_persona_get();
281 current_persona_id
= persona
->pna_id
;
284 if (persona_id
&& persona_id
!= current_persona_id
) {
285 /* Release the reference on the current persona id's persona */
286 persona_put(persona
);
287 if (!kauth_cred_issuser(kauth_cred_get()) &&
288 !IOTaskHasEntitlement(current_task(), PERSONA_MGMT_ENTITLEMENT
)) {
291 persona
= persona_lookup(persona_id
);
298 if (persona
->pna_path
) {
299 error
= copyoutstr((void *)persona
->pna_path
, path
, MAXPATHLEN
, &pathlen
);
302 persona_put(persona
);
308 kpersona_info_syscall(user_addr_t idp
, user_addr_t infop
)
311 uid_t current_persona_id
= PERSONA_ID_NONE
;
313 struct persona
*persona
;
314 struct kpersona_info kinfo
;
316 error
= copyin(idp
, &persona_id
, sizeof(persona_id
));
321 /* Get current thread's persona id to compare if the
322 * input persona_id matches the current persona id
324 persona
= current_persona_get();
326 current_persona_id
= persona
->pna_id
;
329 if (persona_id
&& persona_id
!= current_persona_id
) {
330 /* Release the reference on the current persona id's persona */
331 persona_put(persona
);
332 if (!kauth_cred_issuser(kauth_cred_get()) &&
333 !IOTaskHasEntitlement(current_task(), PERSONA_MGMT_ENTITLEMENT
)) {
336 persona
= persona_lookup(persona_id
);
343 persona_dbg("FOUND: persona: id:%d, gid:%d, login:\"%s\"",
344 persona
->pna_id
, persona_get_gid(persona
),
347 memset(&kinfo
, 0, sizeof(kinfo
));
348 kinfo
.persona_info_version
= PERSONA_INFO_V1
;
349 kinfo
.persona_id
= persona
->pna_id
;
350 kinfo
.persona_type
= persona
->pna_type
;
351 kinfo
.persona_gid
= persona_get_gid(persona
);
352 unsigned ngroups
= 0;
353 persona_get_groups(persona
, &ngroups
, kinfo
.persona_groups
, NGROUPS
);
354 kinfo
.persona_ngroups
= ngroups
;
355 kinfo
.persona_gmuid
= persona_get_gmuid(persona
);
358 * NULL termination is assured b/c persona_name is
359 * exactly MAXLOGNAME + 1 bytes (and has been memset to 0)
361 strncpy(kinfo
.persona_name
, persona
->pna_login
, MAXLOGNAME
);
363 persona_put(persona
);
365 error
= kpersona_copyout(&kinfo
, infop
);
371 kpersona_pidinfo_syscall(user_addr_t idp
, user_addr_t infop
)
375 struct persona
*persona
;
376 struct kpersona_info kinfo
;
378 error
= copyin(idp
, &pid
, sizeof(pid
));
383 if (!kauth_cred_issuser(kauth_cred_get())
384 && (pid
!= current_proc()->p_pid
)) {
388 persona
= persona_proc_get(pid
);
393 memset(&kinfo
, 0, sizeof(kinfo
));
394 kinfo
.persona_info_version
= PERSONA_INFO_V1
;
395 kinfo
.persona_id
= persona
->pna_id
;
396 kinfo
.persona_type
= persona
->pna_type
;
397 kinfo
.persona_gid
= persona_get_gid(persona
);
398 unsigned ngroups
= 0;
399 persona_get_groups(persona
, &ngroups
, kinfo
.persona_groups
, NGROUPS
);
400 kinfo
.persona_ngroups
= ngroups
;
401 kinfo
.persona_gmuid
= persona_get_gmuid(persona
);
403 strncpy(kinfo
.persona_name
, persona
->pna_login
, MAXLOGNAME
);
405 persona_put(persona
);
407 error
= kpersona_copyout(&kinfo
, infop
);
413 kpersona_find_syscall(user_addr_t infop
, user_addr_t idp
, user_addr_t idlenp
)
416 struct kpersona_info kinfo
;
418 size_t u_idlen
, k_idlen
= 0;
419 struct persona
**persona
= NULL
;
421 error
= copyin(idlenp
, &u_idlen
, sizeof(u_idlen
));
426 if (u_idlen
> g_max_personas
) {
427 u_idlen
= g_max_personas
;
430 error
= kpersona_copyin(infop
, &kinfo
);
435 login
= kinfo
.persona_name
[0] ? kinfo
.persona_name
: NULL
;
438 MALLOC(persona
, struct persona
**, sizeof(*persona
) * u_idlen
,
439 M_TEMP
, M_WAITOK
| M_ZERO
);
447 error
= persona_find_all(login
, kinfo
.persona_id
, kinfo
.persona_type
, persona
, &k_idlen
);
452 /* copyout all the IDs of each persona we found */
453 for (size_t i
= 0; i
< k_idlen
; i
++) {
457 error
= copyout(&persona
[i
]->pna_id
,
458 idp
+ (i
* sizeof(persona
[i
]->pna_id
)),
459 sizeof(persona
[i
]->pna_id
));
467 for (size_t i
= 0; i
< u_idlen
; i
++) {
468 persona_put(persona
[i
]);
470 FREE(persona
, M_TEMP
);
473 (void)copyout(&k_idlen
, idlenp
, sizeof(u_idlen
));
479 * Syscall entry point / demux.
482 persona(__unused proc_t p
, struct persona_args
*pargs
, __unused
int32_t *retval
)
485 uint32_t op
= pargs
->operation
;
486 /* uint32_t flags = pargs->flags; */
487 user_addr_t infop
= pargs
->info
;
488 user_addr_t idp
= pargs
->id
;
489 user_addr_t path
= pargs
->path
;
492 case PERSONA_OP_ALLOC
:
493 error
= kpersona_alloc_syscall(infop
, idp
, USER_ADDR_NULL
);
495 case PERSONA_OP_PALLOC
:
496 error
= kpersona_alloc_syscall(infop
, idp
, path
);
498 case PERSONA_OP_DEALLOC
:
499 error
= kpersona_dealloc_syscall(idp
);
502 error
= kpersona_get_syscall(idp
);
504 case PERSONA_OP_GETPATH
:
505 error
= kpersona_getpath_syscall(idp
, path
);
507 case PERSONA_OP_INFO
:
508 error
= kpersona_info_syscall(idp
, infop
);
510 case PERSONA_OP_PIDINFO
:
511 error
= kpersona_pidinfo_syscall(idp
, infop
);
513 case PERSONA_OP_FIND
:
514 case PERSONA_OP_FIND_BY_TYPE
:
515 error
= kpersona_find_syscall(infop
, idp
, pargs
->idlen
);