Loading...
  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
/*
 * Copyright (c) 2015 Apple Inc. All rights reserved.
 *
 * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
 *
 * This file contains Original Code and/or Modifications of Original Code
 * as defined in and that are subject to the Apple Public Source License
 * Version 2.0 (the 'License'). You may not use this file except in
 * compliance with the License. The rights granted to you under the License
 * may not be used to create, or enable the creation or redistribution of,
 * unlawful or unlicensed copies of an Apple operating system, or to
 * circumvent, violate, or enable the circumvention or violation of, any
 * terms of an Apple operating system software license agreement.
 *
 * Please obtain a copy of the License at
 * http://www.opensource.apple.com/apsl/ and read it before using this file.
 *
 * The Original Code and all software distributed under the License are
 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
 * Please see the License for the specific language governing rights and
 * limitations under the License.
 *
 * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
 */
#ifndef _SYS_PERSONA_H_
#define _SYS_PERSONA_H_

#ifdef PRIVATE
#include <sys/param.h>

enum {
	PERSONA_INVALID      = 0,
	PERSONA_GUEST        = 1,
	PERSONA_MANAGED      = 2,
	PERSONA_PRIV         = 3,
	PERSONA_SYSTEM       = 4,
	PERSONA_DEFAULT      = 5,
	PERSONA_SYSTEM_PROXY = 6,
	PERSONA_SYS_EXT      = 7,
	PERSONA_ENTERPRISE   = 8,

	PERSONA_TYPE_MAX     = PERSONA_ENTERPRISE,
};

#define PERSONA_ID_NONE ((uid_t)-1)

struct kpersona_info {
	uint32_t persona_info_version;

	uid_t    persona_id; /* overlaps with UID */
	int      persona_type;
	gid_t    persona_gid;
	uint32_t persona_ngroups;
	gid_t    persona_groups[NGROUPS];
	uid_t    persona_gmuid;
	char     persona_name[MAXLOGNAME + 1];

	/* TODO: MAC policies?! */
};

#define PERSONA_INFO_V1       1
#define PERSONA_INFO_V1_SIZE  (sizeof(struct kpersona_info))


#define PERSONA_OP_ALLOC    1
#define PERSONA_OP_PALLOC   2
#define PERSONA_OP_DEALLOC  3
#define PERSONA_OP_GET      4
#define PERSONA_OP_INFO     5
#define PERSONA_OP_PIDINFO  6
#define PERSONA_OP_FIND     7
#define PERSONA_OP_GETPATH  8
#define PERSONA_OP_FIND_BY_TYPE  9

#define PERSONA_MGMT_ENTITLEMENT "com.apple.private.persona-mgmt"

#ifndef KERNEL
/*
 * user space persona interface
 */

/*
 * kpersona_alloc: Allocate a new in-kernel persona
 *
 * Parameters:
 *       info: Pointer to persona info structure describing the
 *             attributes of the persona to create / allocate.
 *
 *         id: output: set to the ID of the created persona
 *
 * Note:
 *      The 'persona_id' field of the 'info' parameter is ignored.
 *
 * Return:
 *        != 0: ERROR
 *        == 0: Success
 */
int kpersona_alloc(struct kpersona_info *info, uid_t *id);

/*
 * kpersona_palloc: Allocate a new in-kernel persona with a directory
 *                 pathname
 *
 * Parameters:
 *       info: Pointer to persona info structure describing the
 *             attributes of the persona to create / allocate.
 *
 *       path: Pointer to directory name that stores persona specific
 *             data. Assumes path buffer length = MAXPATHLEN and is a
 *             null-terminated string.
 *
 *         id: output: set to the ID of the created persona
 *
 * Note:
 *      The 'persona_id' field of the 'info' parameter is ignored.
 *
 * Return:
 *        != 0: ERROR
 *        == 0: Success
 */
int kpersona_palloc(struct kpersona_info *info, uid_t *id, char path[MAXPATHLEN]);

/*
 * kpersona_dealloc: delete / destroy an in-kernel persona
 *
 * Parameters:
 *         id: the ID of the persona to destroy
 *
 * Return:
 *        < 0: ERROR
 *          0: Success
 */
int kpersona_dealloc(uid_t id);

/*
 * kpersona_get: retrieve the persona with which the current thread is running
 *
 * To find the proc's persona id use kpersona_pidinfo
 *
 * Parameters:
 *         id: output: will be filled with the persona id from the voucher adopted
 *             on the current thread. If that voucher contains no persona information
 *             or there is no such voucher, then it defaults to the proc's persona id.
 *
 * Return:
 *        < 0: Thread is not running under any persona
 *          0: Success (uuid is filled with running persona UUID)
 */
int kpersona_get(uid_t *id);

/*
 * kpersona_get_path: retrieve the given persona's path
 *
 * Parameters:
 *         id: ID of the persona
 *
 *         path: output: filled in with path on success.
 *               Assumes path buffer length = MAXPATHLEN
 *
 * Return:
 *        < 0: Error
 *          0: Success
 */
int kpersona_getpath(uid_t id, char path[MAXPATHLEN]);

/*
 * kpersona_info: gather info about the given persona
 *
 * Parameters:
 *         id: ID of the persona to investigate
 *             If set to 0, it uses persona id from the voucher adopted on the current
 *             thread. If that voucher contains no persona information or there is no
 *             such voucher, then it defaults to the proc's persona id.
 *
 *       info: output: filled in with persona attributes on success.
 *
 * Return:
 *        < 0: ERROR
 *          0: Success
 */
int kpersona_info(uid_t id, struct kpersona_info *info);

/*
 * kpersona_pidinfo: gather persona info about the given PID
 *
 * Parameters:
 *        pid: PID of the process whose persona info we're to return
 *
 *       info: output: filled in with persona attributes on success.
 *
 * Return:
 *        < 0: ERROR
 *          0: Success
 */
int kpersona_pidinfo(pid_t pid, struct kpersona_info *info);

/*
 * kpersona_find: lookup the kernel's UUID of a persona
 *
 * Parameters:
 *       name: Local login name of the persona.
 *             Set this to NULL to find personas by 'uid'.
 *
 *        uid: UID of the persona.
 *             Set this to -1 to find personas by 'name'
 *
 *         id: output: the ID(s) matching the input parameters
 *             This can be NULL
 *
 *      idlen: input - size of 'id' buffer (in number of IDs)
 *             output - the total required size of the 'id' buffer
 *                      (in number of IDs) - may be larger than input size
 * Note:
 *      At least one of 'name' or 'uid' must be set.
 *
 * Return:
 *         < 0: ERROR
 *        >= 0: The number of IDs found to match the input parameters
 */
int kpersona_find(const char *name, uid_t uid, uid_t *id, size_t *idlen);

/*
 * kpersona_find_by_type: lookup the persona ids by type
 *
 * Parameters:
 *  persona_type: Type of persona id (see enum)
 *
 *           id: output: the ID(s) matching the input parameters
 *               This can be NULL
 *
 *        idlen: input - size of 'id' buffer (in number of IDs)
 *               output - the total required size of the 'id' buffer
 *                      (in number of IDs) - may be larger than input size
 * Return:
 *         < 0: ERROR
 *        >= 0: The number of IDs found to match the input parameters
 */
int kpersona_find_by_type(int persona_type, uid_t *id, size_t *idlen);
#endif /* !KERNEL */

#ifdef KERNEL_PRIVATE
/* XNU + kext private interface */
#include <sys/cdefs.h>
#include <sys/kauth.h>
#include <libkern/libkern.h>
#include <os/refcnt.h>

#ifdef PERSONA_DEBUG
#include <os/log.h>
#define persona_dbg(fmt, ...) \
	os_log(OS_LOG_DEFAULT, "[%4d] %s:  " fmt "\n", \
	       current_proc() ? current_proc()->p_pid : -1, \
	       __func__, ## __VA_ARGS__)
#else
#define persona_dbg(fmt, ...) do { } while (0)
#endif

/*
 * Persona
 */
#ifdef XNU_KERNEL_PRIVATE
/* only XNU proper needs to see the persona structure */
struct persona {
	os_refcnt_t  pna_refcount;
	int32_t      pna_valid;

	uid_t        pna_id;
	int          pna_type;
	char         pna_login[MAXLOGNAME + 1];
	char         *pna_path;

	kauth_cred_t pna_cred;
	uid_t        pna_pgid;

	int          pna_cred_locked; /* set upon first adoption */

	LIST_ENTRY(persona) pna_list;

	/* this could go away if we used a coalition */
	LIST_HEAD(, proc)   pna_members;

	lck_mtx_t    pna_lock;

	/*
	 * We can add things here such as PID maps, UID maps, etc.
	 */
#ifdef PERSONA_DEBUG
	char         pna_desc[128];
#endif
};

#define persona_lock(persona)     lck_mtx_lock(&(persona)->pna_lock)
#define persona_unlock(persona)   lck_mtx_unlock(&(persona)->pna_lock)
#define persona_try_lock(persona) lck_mtx_try_lock(&(persona)->pna_lock)

#define persona_lock_assert_held(persona) \
	LCK_MTX_ASSERT(&(persona)->pna_lock, LCK_MTX_ASSERT_OWNED)

#ifdef PERSONA_DEBUG
static inline const char *
persona_desc(struct persona *persona, int locked)
{
	if (!persona) {
		return "<none>";
	}

	if (persona->pna_desc[0] != 0) {
		return persona->pna_desc;
	}

	if (!locked) {
		persona_lock(persona);
	}
	if (persona->pna_desc[0] != 0) {
		goto out_unlock;
	}

	char *p = &persona->pna_desc[0];
	char *end = p + sizeof(persona->pna_desc) - 1;

	*end = 0;
	p += snprintf(p, end - p, "%s/%d:%d",
	    persona->pna_login,
	    kauth_cred_getuid(persona->pna_cred),
	    kauth_cred_getgid(persona->pna_cred));

	if (p <= end) {
		*p = 0;
	}
out_unlock:
	if (!locked) {
		persona_unlock(persona);
	}

	return persona->pna_desc;
}
#else /* !PERSONA_DEBUG */
static inline const char *
persona_desc(struct persona *persona, int locked)
{
	(void)persona;
	(void)locked;
	return "<persona>";
}
#endif

#else /* !XNU_KERNEL_PRIVATE */
/* kexts should only see an opaque persona structure */
struct persona;
#endif

__BEGIN_DECLS

#ifndef _KAUTH_CRED_T
#define _KAUTH_CRED_T
typedef struct ucred *kauth_cred_t;
#endif  /* !_KAUTH_CRED_T */

/* returns the persona ID for the given pesona structure */
uid_t persona_get_id(struct persona *persona);

/* returns the type of the persona (see enum above: PERSONA_GUEST, etc.) */
int persona_get_type(struct persona *persona);

/* returns ref on kauth_cred_t that must be dropped via kauth_cred_unref() */
kauth_cred_t persona_get_cred(struct persona *persona);

/* returns a reference that must be released with persona_put() */
struct persona *persona_lookup(uid_t id);

/*
 * Search for personas based on name or uid
 *
 * Parameters:
 *       name: Local login name of the persona.
 *             Set this to NULL to find personas by 'uid'.
 *
 *        uid: UID of the persona.
 *             Set this to -1 to find personas by 'name'
 *
 *    persona: output - array of persona pointers. Each non-NULL value
 *             must* be released with persona_put. This can be NULL.
 *
 *       plen: input - size of 'persona' buffer (in number of pointers)
 *             output - the total required size of the 'persona' buffer (could be larger than input value)
 *
 * Return:
 *           0: Success
 *        != 0: failure (BSD errno value ESRCH or EINVAL)
 */
int persona_find(const char *login, uid_t uid,
    struct persona **persona, size_t *plen);

/* returns a reference that must be released with persona_put() */
struct persona *persona_proc_get(pid_t pid);

/* returns a reference to the persona tied to the current thread (also uses adopted voucher) */
struct persona *current_persona_get(void);

/* get a reference to a persona structure */
struct persona *persona_get(struct persona *persona);

/* release a reference to a persona structure */
void persona_put(struct persona *persona);

/*
 * Search for personas of a given type, 'persona_type'.
 *
 * Parameters:
 *   persona_type: Type of persona (see enum)
 *
 *        persona: output - array of persona pointers. Each non-NULL value
 *        must* be released with persona_put. This can be NULL.
 *
 *           plen: input - size of 'persona' buffer (in number of pointers)
 *                 output - the total required size of the 'persona' buffer (could be larger than input value)
 *
 * Return:
 *           0: Success
 *        != 0: failure (BSD errno value ESRCH or EINVAL)
 */
int persona_find_by_type(int persona_type, struct persona **persona,
    size_t *plen);

#ifdef XNU_KERNEL_PRIVATE

#if CONFIG_PERSONAS
#include <sys/proc_internal.h>

/*
 * In-kernel persona API
 */
extern uint32_t g_max_personas;

void personas_bootstrap(void);

struct persona *persona_alloc(uid_t id, const char *login,
    int type, char *path, int *error);

int persona_init_begin(struct persona *persona);
void persona_init_end(struct persona *persona, int error);

struct persona *persona_lookup_and_invalidate(uid_t id);
int persona_verify_and_set_uniqueness(struct persona *persona);
boolean_t persona_is_unique(struct persona *persona);

static inline int
proc_has_persona(proc_t p)
{
	if (p && p->p_persona) {
		return 1;
	}
	return 0;
}

static inline uid_t
persona_id_from_proc(proc_t p)
{
	if (p && p->p_persona) {
		return p->p_persona->pna_id;
	}
	return PERSONA_ID_NONE;
}

int persona_proc_inherit(proc_t child, proc_t parent);

int persona_proc_adopt_id(proc_t p, uid_t id,
    kauth_cred_t auth_override);
int persona_proc_adopt(proc_t p, struct persona *persona,
    kauth_cred_t auth_override);
int persona_proc_drop(proc_t p);

int persona_set_cred(struct persona *persona, kauth_cred_t cred);
int persona_set_cred_from_proc(struct persona *persona, proc_t proc);

uid_t persona_get_uid(struct persona *persona);

int persona_set_gid(struct persona *persona, gid_t gid);
gid_t persona_get_gid(struct persona *persona);

int persona_set_groups(struct persona *persona, gid_t *groups, unsigned ngroups, uid_t gmuid);
int persona_get_groups(struct persona *persona, unsigned *ngroups, gid_t *groups, unsigned groups_sz);

uid_t persona_get_gmuid(struct persona *persona);

int persona_get_login(struct persona *persona, char login[MAXLOGNAME + 1]);

/* returns a reference that must be released with persona_put() */
struct persona *persona_proc_get(pid_t pid);

int persona_find_all(const char *login, uid_t uid, int persona_type,
    struct persona **persona, size_t *plen);

#else /* !CONFIG_PERSONAS */

static inline int
proc_has_persona(__unused proc_t p)
{
	return 0;
}

static inline uid_t
persona_id_from_proc(__unused proc_t p)
{
	return PERSONA_ID_NONE;
}

#endif /* CONFIG_PERSONAS */
#endif /* XNU_KERNEL_PRIVATE */
__END_DECLS

#endif /* KERNEL_PRIVATE */

#endif /* PRIVATE */
#endif /* _SYS_PERSONA_H_ */