]>
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 pna_path
= zalloc_flags(ZV_NAMEI
, Z_WAITOK
| Z_ZERO
);
123 error
= copyinstr(path
, (void *)pna_path
, MAXPATHLEN
, &pathlen
);
125 zfree(ZV_NAMEI
, pna_path
);
131 persona
= persona_alloc(id
, login
, kinfo
.persona_type
, pna_path
, &error
);
133 if (pna_path
!= NULL
) {
134 zfree(ZV_NAMEI
, pna_path
);
139 /* persona struct contains a reference to pna_path */
142 error
= persona_init_begin(persona
);
144 goto out_persona_err
;
147 if (kinfo
.persona_gid
) {
148 error
= persona_set_gid(persona
, kinfo
.persona_gid
);
150 goto out_persona_err
;
154 if (kinfo
.persona_ngroups
> 0) {
155 /* force gmuid 0 to *opt-out* of memberd */
156 if (kinfo
.persona_gmuid
== 0) {
157 kinfo
.persona_gmuid
= KAUTH_UID_NONE
;
160 error
= persona_set_groups(persona
, kinfo
.persona_groups
,
161 kinfo
.persona_ngroups
,
162 kinfo
.persona_gmuid
);
164 goto out_persona_err
;
168 error
= copyout(&persona
->pna_id
, idp
, sizeof(persona
->pna_id
));
170 goto out_persona_err
;
173 kinfo
.persona_id
= persona
->pna_id
;
174 error
= kpersona_copyout(&kinfo
, infop
);
176 goto out_persona_err
;
179 error
= persona_verify_and_set_uniqueness(persona
);
181 goto out_persona_err
;
184 persona_init_end(persona
, error
);
187 * On success, we have a persona structure in the global list with a
188 * single reference count on it. The corresponding _dealloc() call
189 * will release this reference.
195 persona_init_end(persona
, error
);
198 printf("%s: ERROR:%d\n", __func__
, error
);
201 persona_put(persona
);
207 kpersona_dealloc_syscall(user_addr_t idp
)
211 struct persona
*persona
;
213 if (!IOTaskHasEntitlement(current_task(), PERSONA_MGMT_ENTITLEMENT
)) {
217 error
= copyin(idp
, &persona_id
, sizeof(persona_id
));
222 /* invalidate the persona (deny subsequent spawn/fork) */
223 persona
= persona_lookup_and_invalidate(persona_id
);
229 /* one reference from the _lookup() */
230 persona_put(persona
);
232 /* one reference from the _alloc() */
233 persona_put(persona
);
239 kpersona_get_syscall(user_addr_t idp
)
242 struct persona
*persona
;
244 persona
= current_persona_get();
250 error
= copyout(&persona
->pna_id
, idp
, sizeof(persona
->pna_id
));
251 persona_put(persona
);
257 kpersona_getpath_syscall(user_addr_t idp
, user_addr_t path
)
261 struct persona
*persona
;
263 uid_t current_persona_id
= PERSONA_ID_NONE
;
269 error
= copyin(idp
, &persona_id
, sizeof(persona_id
));
274 /* Get current thread's persona id to compare if the
275 * input persona_id matches the current persona id
277 persona
= current_persona_get();
279 current_persona_id
= persona
->pna_id
;
282 if (persona_id
&& persona_id
!= current_persona_id
) {
283 /* Release the reference on the current persona id's persona */
284 persona_put(persona
);
285 if (!kauth_cred_issuser(kauth_cred_get()) &&
286 !IOTaskHasEntitlement(current_task(), PERSONA_MGMT_ENTITLEMENT
)) {
289 persona
= persona_lookup(persona_id
);
296 if (persona
->pna_path
) {
297 error
= copyoutstr((void *)persona
->pna_path
, path
, MAXPATHLEN
, &pathlen
);
300 persona_put(persona
);
306 kpersona_info_syscall(user_addr_t idp
, user_addr_t infop
)
309 uid_t current_persona_id
= PERSONA_ID_NONE
;
311 struct persona
*persona
;
312 struct kpersona_info kinfo
;
314 error
= copyin(idp
, &persona_id
, sizeof(persona_id
));
319 /* Get current thread's persona id to compare if the
320 * input persona_id matches the current persona id
322 persona
= current_persona_get();
324 current_persona_id
= persona
->pna_id
;
327 if (persona_id
&& persona_id
!= current_persona_id
) {
328 /* Release the reference on the current persona id's persona */
329 persona_put(persona
);
330 if (!kauth_cred_issuser(kauth_cred_get()) &&
331 !IOTaskHasEntitlement(current_task(), PERSONA_MGMT_ENTITLEMENT
)) {
334 persona
= persona_lookup(persona_id
);
341 persona_dbg("FOUND: persona: id:%d, gid:%d, login:\"%s\"",
342 persona
->pna_id
, persona_get_gid(persona
),
345 memset(&kinfo
, 0, sizeof(kinfo
));
346 kinfo
.persona_info_version
= PERSONA_INFO_V1
;
347 kinfo
.persona_id
= persona
->pna_id
;
348 kinfo
.persona_type
= persona
->pna_type
;
349 kinfo
.persona_gid
= persona_get_gid(persona
);
351 persona_get_groups(persona
, &ngroups
, kinfo
.persona_groups
, NGROUPS
);
352 kinfo
.persona_ngroups
= (uint32_t)ngroups
;
353 kinfo
.persona_gmuid
= persona_get_gmuid(persona
);
356 * NULL termination is assured b/c persona_name is
357 * exactly MAXLOGNAME + 1 bytes (and has been memset to 0)
359 strncpy(kinfo
.persona_name
, persona
->pna_login
, MAXLOGNAME
);
361 persona_put(persona
);
363 error
= kpersona_copyout(&kinfo
, infop
);
369 kpersona_pidinfo_syscall(user_addr_t idp
, user_addr_t infop
)
373 struct persona
*persona
;
374 struct kpersona_info kinfo
;
376 error
= copyin(idp
, &pid
, sizeof(pid
));
381 if (!kauth_cred_issuser(kauth_cred_get())
382 && (pid
!= current_proc()->p_pid
)) {
386 persona
= persona_proc_get(pid
);
391 memset(&kinfo
, 0, sizeof(kinfo
));
392 kinfo
.persona_info_version
= PERSONA_INFO_V1
;
393 kinfo
.persona_id
= persona
->pna_id
;
394 kinfo
.persona_type
= persona
->pna_type
;
395 kinfo
.persona_gid
= persona_get_gid(persona
);
397 persona_get_groups(persona
, &ngroups
, kinfo
.persona_groups
, NGROUPS
);
398 kinfo
.persona_ngroups
= (uint32_t)ngroups
;
399 kinfo
.persona_gmuid
= persona_get_gmuid(persona
);
401 strncpy(kinfo
.persona_name
, persona
->pna_login
, MAXLOGNAME
);
403 persona_put(persona
);
405 error
= kpersona_copyout(&kinfo
, infop
);
411 kpersona_find_syscall(user_addr_t infop
, user_addr_t idp
, user_addr_t idlenp
)
414 struct kpersona_info kinfo
;
416 size_t u_idlen
, k_idlen
= 0;
417 struct persona
**persona
= NULL
;
419 error
= copyin(idlenp
, &u_idlen
, sizeof(u_idlen
));
424 if (u_idlen
> g_max_personas
) {
425 u_idlen
= g_max_personas
;
428 error
= kpersona_copyin(infop
, &kinfo
);
433 login
= kinfo
.persona_name
[0] ? kinfo
.persona_name
: NULL
;
436 persona
= kheap_alloc(KHEAP_TEMP
, sizeof(*persona
) * u_idlen
,
445 error
= persona_find_all(login
, kinfo
.persona_id
, (persona_type_t
)kinfo
.persona_type
, persona
, &k_idlen
);
450 /* copyout all the IDs of each persona we found */
451 for (size_t i
= 0; i
< k_idlen
; i
++) {
455 error
= copyout(&persona
[i
]->pna_id
,
456 idp
+ (i
* sizeof(persona
[i
]->pna_id
)),
457 sizeof(persona
[i
]->pna_id
));
465 for (size_t i
= 0; i
< u_idlen
; i
++) {
466 persona_put(persona
[i
]);
468 kheap_free(KHEAP_TEMP
, persona
, sizeof(*persona
) * u_idlen
);
471 (void)copyout(&k_idlen
, idlenp
, sizeof(u_idlen
));
477 * Syscall entry point / demux.
480 persona(__unused proc_t p
, struct persona_args
*pargs
, __unused
int32_t *retval
)
483 uint32_t op
= pargs
->operation
;
484 /* uint32_t flags = pargs->flags; */
485 user_addr_t infop
= pargs
->info
;
486 user_addr_t idp
= pargs
->id
;
487 user_addr_t path
= pargs
->path
;
490 case PERSONA_OP_ALLOC
:
491 error
= kpersona_alloc_syscall(infop
, idp
, USER_ADDR_NULL
);
493 case PERSONA_OP_PALLOC
:
494 error
= kpersona_alloc_syscall(infop
, idp
, path
);
496 case PERSONA_OP_DEALLOC
:
497 error
= kpersona_dealloc_syscall(idp
);
500 error
= kpersona_get_syscall(idp
);
502 case PERSONA_OP_GETPATH
:
503 error
= kpersona_getpath_syscall(idp
, path
);
505 case PERSONA_OP_INFO
:
506 error
= kpersona_info_syscall(idp
, infop
);
508 case PERSONA_OP_PIDINFO
:
509 error
= kpersona_pidinfo_syscall(idp
, infop
);
511 case PERSONA_OP_FIND
:
512 case PERSONA_OP_FIND_BY_TYPE
:
513 error
= kpersona_find_syscall(infop
, idp
, pargs
->idlen
);