]>
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 <libkern/libkern.h>
40 static int kpersona_copyin(user_addr_t infop
, struct kpersona_info
*kinfo
)
45 error
= copyin(infop
, &info_v
, sizeof(info_v
));
49 /* only support a single version of the struct for now */
50 if (info_v
!= PERSONA_INFO_V1
)
53 error
= copyin(infop
, kinfo
, sizeof(*kinfo
));
55 /* enforce NULL termination on strings */
56 kinfo
->persona_name
[MAXLOGNAME
] = 0;
61 static int kpersona_copyout(struct kpersona_info
*kinfo
, user_addr_t infop
)
66 error
= copyin(infop
, &info_v
, sizeof(info_v
));
70 /* only support a single version of the struct for now */
71 /* TODO: in the future compare info_v to kinfo->persona_info_version */
72 if (info_v
!= PERSONA_INFO_V1
)
75 error
= copyout(kinfo
, infop
, sizeof(*kinfo
));
80 static int kpersona_alloc_syscall(user_addr_t infop
, user_addr_t idp
)
83 struct kpersona_info kinfo
;
84 struct persona
*persona
;
85 uid_t id
= PERSONA_ID_NONE
;
89 * TODO: rdar://problem/19981151
90 * Add entitlement check!
92 if (!kauth_cred_issuser(kauth_cred_get()))
95 error
= kpersona_copyin(infop
, &kinfo
);
99 login
= kinfo
.persona_name
[0] ? kinfo
.persona_name
: NULL
;
100 if (kinfo
.persona_id
!= PERSONA_ID_NONE
&& kinfo
.persona_id
!= (uid_t
)0)
101 id
= kinfo
.persona_id
;
104 persona
= persona_alloc(id
, login
, kinfo
.persona_type
, &error
);
108 if (kinfo
.persona_gid
) {
109 error
= persona_set_gid(persona
, kinfo
.persona_gid
);
114 if (kinfo
.persona_ngroups
> 0) {
115 /* force gmuid 0 to *opt-out* of memberd */
116 if (kinfo
.persona_gmuid
== 0)
117 kinfo
.persona_gmuid
= KAUTH_UID_NONE
;
119 error
= persona_set_groups(persona
, kinfo
.persona_groups
,
120 kinfo
.persona_ngroups
,
121 kinfo
.persona_gmuid
);
126 error
= copyout(&persona
->pna_id
, idp
, sizeof(persona
->pna_id
));
129 error
= kpersona_copyout(&kinfo
, infop
);
132 * On success, we have a persona structure in the global list with a
133 * single reference count on it. The corresponding _dealloc() call
134 * will release this reference.
139 printf("%s: ERROR:%d\n", __func__
, error
);
141 persona_put(persona
);
145 static int kpersona_dealloc_syscall(user_addr_t idp
)
149 struct persona
*persona
;
151 if (!kauth_cred_issuser(kauth_cred_get()))
154 error
= copyin(idp
, &persona_id
, sizeof(persona_id
));
158 /* invalidate the persona (deny subsequent spawn/fork) */
159 persona
= persona_lookup_and_invalidate(persona_id
);
164 /* one reference from the _lookup() */
165 persona_put(persona
);
167 /* one reference from the _alloc() */
168 persona_put(persona
);
173 static int kpersona_get_syscall(user_addr_t idp
)
176 struct persona
*persona
= current_persona_get();
181 error
= copyout(&persona
->pna_id
, idp
, sizeof(persona
->pna_id
));
182 persona_put(persona
);
187 static int kpersona_info_syscall(user_addr_t idp
, user_addr_t infop
)
191 struct persona
*persona
;
192 struct kpersona_info kinfo
;
194 error
= copyin(idp
, &persona_id
, sizeof(persona_id
));
199 * TODO: rdar://problem/19981151
200 * Add entitlement check!
203 persona
= persona_lookup(persona_id
);
207 persona_dbg("FOUND: persona:%p, id:%d, gid:%d, login:\"%s\"",
208 persona
, persona
->pna_id
, persona_get_gid(persona
),
211 memset(&kinfo
, 0, sizeof(kinfo
));
212 kinfo
.persona_info_version
= PERSONA_INFO_V1
;
213 kinfo
.persona_id
= persona
->pna_id
;
214 kinfo
.persona_type
= persona
->pna_type
;
215 kinfo
.persona_gid
= persona_get_gid(persona
);
216 unsigned ngroups
= 0;
217 persona_get_groups(persona
, &ngroups
, kinfo
.persona_groups
, NGROUPS
);
218 kinfo
.persona_ngroups
= ngroups
;
219 kinfo
.persona_gmuid
= persona_get_gmuid(persona
);
222 * NULL termination is assured b/c persona_name is
223 * exactly MAXLOGNAME + 1 bytes (and has been memset to 0)
225 strncpy(kinfo
.persona_name
, persona
->pna_login
, MAXLOGNAME
);
227 persona_put(persona
);
229 error
= kpersona_copyout(&kinfo
, infop
);
234 static int kpersona_pidinfo_syscall(user_addr_t idp
, user_addr_t infop
)
238 struct persona
*persona
;
239 struct kpersona_info kinfo
;
241 error
= copyin(idp
, &pid
, sizeof(pid
));
245 if (!kauth_cred_issuser(kauth_cred_get())
246 && (pid
!= current_proc()->p_pid
))
249 persona
= persona_proc_get(pid
);
253 memset(&kinfo
, 0, sizeof(kinfo
));
254 kinfo
.persona_info_version
= PERSONA_INFO_V1
;
255 kinfo
.persona_id
= persona
->pna_id
;
256 kinfo
.persona_type
= persona
->pna_type
;
257 kinfo
.persona_gid
= persona_get_gid(persona
);
258 unsigned ngroups
= 0;
259 persona_get_groups(persona
, &ngroups
, kinfo
.persona_groups
, NGROUPS
);
260 kinfo
.persona_ngroups
= ngroups
;
261 kinfo
.persona_gmuid
= persona_get_gmuid(persona
);
263 strncpy(kinfo
.persona_name
, persona
->pna_login
, MAXLOGNAME
);
265 persona_put(persona
);
267 error
= kpersona_copyout(&kinfo
, infop
);
272 static int kpersona_find_syscall(user_addr_t infop
, user_addr_t idp
, user_addr_t idlenp
)
275 struct kpersona_info kinfo
;
277 size_t u_idlen
, k_idlen
= 0;
278 struct persona
**persona
= NULL
;
280 error
= copyin(idlenp
, &u_idlen
, sizeof(u_idlen
));
284 if (u_idlen
> g_max_personas
)
285 u_idlen
= g_max_personas
;
287 error
= kpersona_copyin(infop
, &kinfo
);
291 login
= kinfo
.persona_name
[0] ? kinfo
.persona_name
: NULL
;
294 MALLOC(persona
, struct persona
**, sizeof(*persona
) * u_idlen
,
295 M_TEMP
, M_WAITOK
|M_ZERO
);
303 error
= persona_find(login
, kinfo
.persona_id
, persona
, &k_idlen
);
307 /* copyout all the IDs of each persona we found */
308 for (size_t i
= 0; i
< k_idlen
; i
++) {
311 error
= copyout(&persona
[i
]->pna_id
,
312 idp
+ (i
* sizeof(persona
[i
]->pna_id
)),
313 sizeof(persona
[i
]->pna_id
));
320 for (size_t i
= 0; i
< u_idlen
; i
++)
321 persona_put(persona
[i
]);
322 FREE(persona
, M_TEMP
);
325 (void)copyout(&k_idlen
, idlenp
, sizeof(u_idlen
));
332 * Syscall entry point / demux.
334 int persona(__unused proc_t p
, struct persona_args
*pargs
, __unused
int32_t *retval
)
337 uint32_t op
= pargs
->operation
;
338 /* uint32_t flags = pargs->flags; */
339 user_addr_t infop
= pargs
->info
;
340 user_addr_t idp
= pargs
->id
;
343 case PERSONA_OP_ALLOC
:
344 error
= kpersona_alloc_syscall(infop
, idp
);
346 case PERSONA_OP_DEALLOC
:
347 error
= kpersona_dealloc_syscall(idp
);
350 error
= kpersona_get_syscall(idp
);
352 case PERSONA_OP_INFO
:
353 error
= kpersona_info_syscall(idp
, infop
);
355 case PERSONA_OP_PIDINFO
:
356 error
= kpersona_pidinfo_syscall(idp
, infop
);
358 case PERSONA_OP_FIND
:
359 error
= kpersona_find_syscall(infop
, idp
, pargs
->idlen
);