xref: /xnu-10063.121.3/bsd/sys/persona.h (revision 2c2f96dc2b9a4408a43d3150ae9c105355ca3daa)
1 /*
2  * Copyright (c) 2015 Apple Inc. All rights reserved.
3  *
4  * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
5  *
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.
14  *
15  * Please obtain a copy of the License at
16  * http://www.opensource.apple.com/apsl/ and read it before using this file.
17  *
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.
25  *
26  * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
27  */
28 #ifndef _SYS_PERSONA_H_
29 #define _SYS_PERSONA_H_
30 
31 #ifdef PRIVATE
32 #include <sys/param.h>
33 
34 #ifdef KERNEL
35 __enum_decl(persona_type_t, int, {
36 #else /* !KERNEL */
37 enum {
38 #endif /* KERNEL */
39 	PERSONA_INVALID      = 0,
40 	PERSONA_GUEST        = 1,
41 	PERSONA_MANAGED      = 2,
42 	PERSONA_PRIV         = 3,
43 	PERSONA_SYSTEM       = 4,
44 	PERSONA_DEFAULT      = 5,
45 	PERSONA_SYSTEM_PROXY = 6,
46 	PERSONA_SYS_EXT      = 7,
47 	PERSONA_ENTERPRISE   = 8,
48 
49 	PERSONA_TYPE_MAX     = PERSONA_ENTERPRISE,
50 #ifdef KERNEL
51 });
52 #else /* !KERNEL */
53 };
54 #endif /* KERNEL */
55 
56 #define PERSONA_ID_NONE ((uid_t)-1)
57 
58 struct kpersona_info {
59 	/* v1 fields */
60 	uint32_t persona_info_version;
61 
62 	uid_t    persona_id;
63 	int      persona_type;
64 	gid_t    persona_gid; /* unused */
65 	uint32_t persona_ngroups; /* unused */
66 	gid_t    persona_groups[NGROUPS]; /* unused */
67 	uid_t    persona_gmuid; /* unused */
68 	char     persona_name[MAXLOGNAME + 1];
69 
70 	/* v2 fields */
71 	uid_t    persona_uid;
72 } __attribute__((packed));
73 
74 #define PERSONA_INFO_V1       1
75 #define PERSONA_INFO_V2       2
76 
77 // Userspace and the kernel must see the same struct layout. Assert that in
78 // either case sizeof() is equal to the same pre-determined value.
79 _Static_assert(sizeof(struct kpersona_info) == 348, "sizeof(kpersona_info) == 348");
80 
81 #define PERSONA_OP_ALLOC    1
82 #define PERSONA_OP_PALLOC   2
83 #define PERSONA_OP_DEALLOC  3
84 #define PERSONA_OP_GET      4
85 #define PERSONA_OP_INFO     5
86 #define PERSONA_OP_PIDINFO  6
87 #define PERSONA_OP_FIND     7
88 #define PERSONA_OP_GETPATH  8
89 #define PERSONA_OP_FIND_BY_TYPE  9
90 
91 #define PERSONA_MGMT_ENTITLEMENT "com.apple.private.persona-mgmt"
92 
93 #ifndef KERNEL
94 /*
95  * user space persona interface
96  */
97 
98 /*
99  * kpersona_alloc: Allocate a new in-kernel persona
100  *
101  * Parameters:
102  *       info: Pointer to persona info structure describing the
103  *             attributes of the persona to create / allocate.
104  *
105  *         id: output: set to the ID of the created persona
106  *
107  * Note:
108  *      The 'persona_id' field of the 'info' parameter is ignored.
109  *
110  * Return:
111  *        != 0: ERROR
112  *        == 0: Success
113  */
114 int kpersona_alloc(struct kpersona_info *info, uid_t *id);
115 
116 /*
117  * kpersona_palloc: Allocate a new in-kernel persona with a directory
118  *                 pathname
119  *
120  * Parameters:
121  *       info: Pointer to persona info structure describing the
122  *             attributes of the persona to create / allocate.
123  *
124  *       path: Pointer to directory name that stores persona specific
125  *             data. Assumes path buffer length = MAXPATHLEN and is a
126  *             null-terminated string.
127  *
128  *         id: output: set to the ID of the created persona
129  *
130  * Note:
131  *      The 'persona_id' field of the 'info' parameter is ignored.
132  *
133  * Return:
134  *        != 0: ERROR
135  *        == 0: Success
136  */
137 int kpersona_palloc(struct kpersona_info *info, uid_t *id, char path[MAXPATHLEN]);
138 
139 /*
140  * kpersona_dealloc: delete / destroy an in-kernel persona
141  *
142  * Parameters:
143  *         id: the ID of the persona to destroy
144  *
145  * Return:
146  *        < 0: ERROR
147  *          0: Success
148  */
149 int kpersona_dealloc(uid_t id);
150 
151 /*
152  * kpersona_get: retrieve the persona with which the current thread is running
153  *
154  * To find the proc's persona id use kpersona_pidinfo
155  *
156  * Parameters:
157  *         id: output: will be filled with the persona id from the voucher adopted
158  *             on the current thread. If that voucher contains no persona information
159  *             or there is no such voucher, then it defaults to the proc's persona id.
160  *
161  * Return:
162  *        < 0: Thread is not running under any persona
163  *          0: Success (uuid is filled with running persona UUID)
164  */
165 int kpersona_get(uid_t *id);
166 
167 /*
168  * kpersona_get_path: retrieve the given persona's path
169  *
170  * Parameters:
171  *         id: ID of the persona
172  *
173  *         path: output: filled in with path on success.
174  *               Assumes path buffer length = MAXPATHLEN
175  *
176  * Return:
177  *        < 0: Error
178  *          0: Success
179  */
180 int kpersona_getpath(uid_t id, char path[MAXPATHLEN]);
181 
182 /*
183  * kpersona_info: gather info about the given persona
184  *
185  * Parameters:
186  *         id: ID of the persona to investigate
187  *             If set to 0, it uses persona id from the voucher adopted on the current
188  *             thread. If that voucher contains no persona information or there is no
189  *             such voucher, then it defaults to the proc's persona id.
190  *
191  *       info: output: filled in with persona attributes on success.
192  *
193  * Return:
194  *        < 0: ERROR
195  *          0: Success
196  */
197 int kpersona_info(uid_t id, struct kpersona_info *info);
198 
199 /*
200  * kpersona_pidinfo: gather persona info about the given PID
201  *
202  * Parameters:
203  *        pid: PID of the process whose persona info we're to return
204  *
205  *       info: output: filled in with persona attributes on success.
206  *
207  * Return:
208  *        < 0: ERROR
209  *          0: Success
210  */
211 int kpersona_pidinfo(pid_t pid, struct kpersona_info *info);
212 
213 /*
214  * kpersona_find: lookup the kernel's UUID of a persona
215  *
216  * Parameters:
217  *       name: Local login name of the persona.
218  *             Set this to NULL to find personas by 'uid'.
219  *
220  *        uid: UID of the persona.
221  *             Set this to -1 to find personas by 'name'
222  *
223  *         id: output: the ID(s) matching the input parameters
224  *             This can be NULL
225  *
226  *      idlen: input - size of 'id' buffer (in number of IDs)
227  *             output - the total required size of the 'id' buffer
228  *                      (in number of IDs) - may be larger than input size
229  * Note:
230  *      At least one of 'name' or 'uid' must be set.
231  *
232  * Return:
233  *         < 0: ERROR
234  *        >= 0: Output value of idlen - may be larger than input size
235  */
236 int kpersona_find(const char *name, uid_t uid, uid_t *id, size_t *idlen);
237 
238 /*
239  * kpersona_find_by_type: lookup the persona ids by type
240  *
241  * Parameters:
242  *  persona_type: Type of persona id (see enum)
243  *
244  *           id: output: the ID(s) matching the input parameters
245  *               This can be NULL
246  *
247  *        idlen: input - size of 'id' buffer (in number of IDs)
248  *               output - the total required size of the 'id' buffer
249  *                      (in number of IDs) - may be larger than input size
250  * Return:
251  *         < 0: ERROR
252  *        >= 0: Output value of idlen - may be larger than input size
253  */
254 int kpersona_find_by_type(int persona_type, uid_t *id, size_t *idlen);
255 #endif /* !KERNEL */
256 
257 #ifdef KERNEL_PRIVATE
258 /* XNU + kext private interface */
259 #include <sys/cdefs.h>
260 #include <sys/kauth.h>
261 #include <libkern/libkern.h>
262 #include <os/refcnt.h>
263 
264 #ifdef PERSONA_DEBUG
265 #include <os/log.h>
266 #define persona_dbg(fmt, ...) \
267 	os_log(OS_LOG_DEFAULT, "[%4d] %s:  " fmt "\n", \
268 	       current_proc() ? proc_getpid(current_proc()) : -1, \
269 	       __func__, ## __VA_ARGS__)
270 #else
271 #define persona_dbg(fmt, ...) do { } while (0)
272 #endif
273 
274 /*
275  * Persona
276  */
277 #ifdef XNU_KERNEL_PRIVATE
278 /* only XNU proper needs to see the persona structure */
279 struct persona {
280 	os_refcnt_t  pna_refcount;
281 	int32_t      pna_valid;
282 
283 	uid_t        pna_id;
284 	persona_type_t pna_type;
285 	char         pna_login[MAXLOGNAME + 1];
286 	char         *pna_path;
287 	uid_t        pna_uid;
288 
289 	LIST_ENTRY(persona) pna_list;
290 
291 	/* this could go away if we used a coalition */
292 	LIST_HEAD(, proc)   pna_members;
293 
294 	lck_mtx_t    pna_lock;
295 
296 	/*
297 	 * We can add things here such as PID maps, UID maps, etc.
298 	 */
299 #ifdef PERSONA_DEBUG
300 	char         pna_desc[128];
301 #endif
302 };
303 
304 #define persona_lock(persona)     lck_mtx_lock(&(persona)->pna_lock)
305 #define persona_unlock(persona)   lck_mtx_unlock(&(persona)->pna_lock)
306 #define persona_try_lock(persona) lck_mtx_try_lock(&(persona)->pna_lock)
307 
308 #define persona_lock_assert_held(persona) \
309 	LCK_MTX_ASSERT(&(persona)->pna_lock, LCK_MTX_ASSERT_OWNED)
310 
311 #ifdef PERSONA_DEBUG
312 static inline const char *
persona_desc(struct persona * persona,int locked)313 persona_desc(struct persona *persona, int locked)
314 {
315 	if (!persona) {
316 		return "<none>";
317 	}
318 
319 	if (persona->pna_desc[0] != 0) {
320 		return persona->pna_desc;
321 	}
322 
323 	if (!locked) {
324 		persona_lock(persona);
325 	}
326 	if (persona->pna_desc[0] != 0) {
327 		goto out_unlock;
328 	}
329 
330 	char *p = &persona->pna_desc[0];
331 	char *end = p + sizeof(persona->pna_desc) - 1;
332 
333 	*end = 0;
334 	p += scnprintf(p, end - p, "%s/%d",
335 	    persona->pna_login,
336 	    persona->pna_id);
337 
338 	if (p <= end) {
339 		*p = 0;
340 	}
341 out_unlock:
342 	if (!locked) {
343 		persona_unlock(persona);
344 	}
345 
346 	return persona->pna_desc;
347 }
348 #else /* !PERSONA_DEBUG */
349 static inline const char *
persona_desc(struct persona * persona,int locked)350 persona_desc(struct persona *persona, int locked)
351 {
352 	(void)persona;
353 	(void)locked;
354 	return "<persona>";
355 }
356 #endif
357 
358 #else /* !XNU_KERNEL_PRIVATE */
359 /* kexts should only see an opaque persona structure */
360 struct persona;
361 #endif
362 
363 __BEGIN_DECLS
364 
365 #ifndef _KAUTH_CRED_T
366 #define _KAUTH_CRED_T
367 typedef struct ucred *kauth_cred_t;
368 #endif  /* !_KAUTH_CRED_T */
369 
370 /* returns the persona ID for the given pesona structure */
371 uid_t persona_get_id(struct persona *persona);
372 
373 /* returns the persona UID for the given pesona structure */
374 uid_t persona_get_uid(struct persona *persona);
375 
376 /* returns the type of the persona (see enum above: PERSONA_GUEST, etc.) */
377 int persona_get_type(struct persona *persona);
378 
379 /* returns a reference that must be released with persona_put() */
380 struct persona *persona_lookup(uid_t id);
381 
382 /*
383  * Search for personas based on name or uid
384  *
385  * Parameters:
386  *       name: Local login name of the persona.
387  *             Set this to NULL to find personas by 'uid'.
388  *
389  *        uid: UID of the persona.
390  *             Set this to -1 to find personas by 'name'
391  *
392  *    persona: output - array of persona pointers. Each non-NULL value
393  *             must* be released with persona_put. This can be NULL.
394  *
395  *       plen: input - size of 'persona' buffer (in number of pointers)
396  *             output - the total required size of the 'persona' buffer (could be larger than input value)
397  *
398  * Return:
399  *           0: Success
400  *        != 0: failure (BSD errno value ESRCH or EINVAL)
401  */
402 int persona_find(const char *login, uid_t uid,
403     struct persona **persona, size_t *plen);
404 
405 /* returns a reference that must be released with persona_put() */
406 struct persona *persona_proc_get(pid_t pid);
407 
408 /* returns the persona id tied to the current thread (also uses adopted voucher) */
409 uid_t current_persona_get_id(void);
410 
411 /* returns a reference to the persona tied to the current thread (also uses adopted voucher) */
412 struct persona *current_persona_get(void);
413 
414 /* get a reference to a persona structure */
415 struct persona *persona_get(struct persona *persona);
416 
417 /* returns a reference to proc's persona that must be released with persona_put() */
418 struct persona *proc_persona_get(proc_t p);
419 
420 /* release a reference to a persona structure */
421 void persona_put(struct persona *persona);
422 
423 /*
424  * Search for personas of a given type, 'persona_type'.
425  *
426  * Parameters:
427  *   persona_type: Type of persona (see enum)
428  *
429  *        persona: output - array of persona pointers. Each non-NULL value
430  *        must* be released with persona_put. This can be NULL.
431  *
432  *           plen: input - size of 'persona' buffer (in number of pointers)
433  *                 output - the total required size of the 'persona' buffer (could be larger than input value)
434  *
435  * Return:
436  *           0: Success
437  *        != 0: failure (BSD errno value ESRCH or EINVAL)
438  */
439 int persona_find_by_type(persona_type_t persona_type, struct persona **persona,
440     size_t *plen);
441 
442 boolean_t persona_is_adoption_allowed(struct persona *persona);
443 
444 #ifdef XNU_KERNEL_PRIVATE
445 
446 #if CONFIG_PERSONAS
447 #include <sys/proc_internal.h>
448 
449 /*
450  * In-kernel persona API
451  */
452 extern const uint32_t g_max_personas;
453 
454 struct persona *persona_alloc(uid_t id, const char *login,
455     persona_type_t type, char *path, uid_t uid, int *error);
456 
457 int persona_init_begin(struct persona *persona);
458 void persona_init_end(struct persona *persona, int error);
459 
460 struct persona *persona_lookup_and_invalidate(uid_t id);
461 
462 static inline int
proc_has_persona(proc_t p)463 proc_has_persona(proc_t p)
464 {
465 	if (p && p->p_persona) {
466 		return 1;
467 	}
468 	return 0;
469 }
470 
471 static inline uid_t
persona_id_from_proc(proc_t p)472 persona_id_from_proc(proc_t p)
473 {
474 	if (p && p->p_persona) {
475 		return p->p_persona->pna_id;
476 	}
477 	return PERSONA_ID_NONE;
478 }
479 
480 /* consumes persona */
481 int persona_proc_adopt(proc_t p, struct persona *persona, kauth_cred_derive_t fn);
482 
483 int persona_proc_drop(proc_t p);
484 
485 /* returns a reference that must be released with persona_put() */
486 struct persona *persona_proc_get(pid_t pid);
487 
488 int persona_find_all(const char *login, uid_t uid, persona_type_t persona_type,
489     struct persona **persona, size_t *plen);
490 
491 #else /* !CONFIG_PERSONAS */
492 
493 static inline int
proc_has_persona(__unused proc_t p)494 proc_has_persona(__unused proc_t p)
495 {
496 	return 0;
497 }
498 
499 static inline uid_t
persona_id_from_proc(__unused proc_t p)500 persona_id_from_proc(__unused proc_t p)
501 {
502 	return PERSONA_ID_NONE;
503 }
504 
505 #endif /* CONFIG_PERSONAS */
506 #endif /* XNU_KERNEL_PRIVATE */
507 __END_DECLS
508 
509 #endif /* KERNEL_PRIVATE */
510 
511 #endif /* PRIVATE */
512 #endif /* _SYS_PERSONA_H_ */
513