Print this page
uts: Allow for address space randomisation.
Randomise the base addresses of shared objects, non-fixed mappings, the
stack and the heap. Introduce a service, svc:/system/process-security,
and a tool psecflags(1) to control and observe it
Split |
Close |
Expand all |
Collapse all |
--- old/usr/src/uts/common/os/cred.c
+++ new/usr/src/uts/common/os/cred.c
1 1 /*
2 2 * CDDL HEADER START
3 3 *
4 4 * The contents of this file are subject to the terms of the
5 5 * Common Development and Distribution License (the "License").
6 6 * You may not use this file except in compliance with the License.
7 7 *
8 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 9 * or http://www.opensolaris.org/os/licensing.
10 10 * See the License for the specific language governing permissions
11 11 * and limitations under the License.
12 12 *
13 13 * When distributing Covered Code, include this CDDL HEADER in each
14 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 15 * If applicable, add the following below this CDDL HEADER, with the
16 16 * fields enclosed by brackets "[]" replaced with your own identifying
17 17 * information: Portions Copyright [yyyy] [name of copyright owner]
18 18 *
19 19 * CDDL HEADER END
20 20 */
21 21 /*
22 22 * Copyright (c) 2013, Ira Cooper. All rights reserved.
23 23 */
24 24 /*
25 25 * Copyright (c) 1989, 2010, Oracle and/or its affiliates. All rights reserved.
26 26 */
27 27
28 28 /* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */
29 29 /* All Rights Reserved */
30 30
31 31 /*
32 32 * University Copyright- Copyright (c) 1982, 1986, 1988
33 33 * The Regents of the University of California
34 34 * All Rights Reserved
35 35 *
36 36 * University Acknowledgment- Portions of this document are derived from
37 37 * software developed by the University of California, Berkeley, and its
38 38 * contributors.
39 39 */
40 40
41 41 #include <sys/types.h>
42 42 #include <sys/sysmacros.h>
43 43 #include <sys/param.h>
44 44 #include <sys/systm.h>
45 45 #include <sys/cred_impl.h>
46 46 #include <sys/policy.h>
47 47 #include <sys/vnode.h>
48 48 #include <sys/errno.h>
49 49 #include <sys/kmem.h>
50 50 #include <sys/user.h>
51 51 #include <sys/proc.h>
52 52 #include <sys/syscall.h>
53 53 #include <sys/debug.h>
54 54 #include <sys/atomic.h>
55 55 #include <sys/ucred.h>
56 56 #include <sys/prsystm.h>
57 57 #include <sys/modctl.h>
58 58 #include <sys/avl.h>
59 59 #include <sys/door.h>
60 60 #include <c2/audit.h>
61 61 #include <sys/zone.h>
62 62 #include <sys/tsol/label.h>
63 63 #include <sys/sid.h>
64 64 #include <sys/idmap.h>
65 65 #include <sys/klpd.h>
66 66 #include <sys/varargs.h>
67 67 #include <sys/sysconf.h>
68 68 #include <util/qsort.h>
69 69
70 70
71 71 /* Ephemeral IDs Zones specific data */
72 72 typedef struct ephemeral_zsd {
73 73 uid_t min_uid;
74 74 uid_t last_uid;
75 75 gid_t min_gid;
76 76 gid_t last_gid;
77 77 kmutex_t eph_lock;
78 78 cred_t *eph_nobody;
79 79 } ephemeral_zsd_t;
80 80
81 81 static void crgrphold(credgrp_t *);
82 82
83 83 #define CREDGRPSZ(ngrp) (sizeof (credgrp_t) + ((ngrp - 1) * sizeof (gid_t)))
84 84
85 85 static kmutex_t ephemeral_zone_mutex;
86 86 static zone_key_t ephemeral_zone_key;
87 87
88 88 static struct kmem_cache *cred_cache;
89 89 static size_t crsize = 0;
90 90 static int audoff = 0;
91 91 uint32_t ucredsize;
92 92 cred_t *kcred;
93 93 static cred_t *dummycr;
94 94
95 95 int rstlink; /* link(2) restricted to files owned by user? */
96 96
97 97 static int get_c2audit_load(void);
98 98
99 99 #define CR_AUINFO(c) (auditinfo_addr_t *)((audoff == 0) ? NULL : \
100 100 ((char *)(c)) + audoff)
101 101
102 102 #define REMOTE_PEER_CRED(c) ((c)->cr_gid == -1)
103 103
104 104 #define BIN_GROUP_SEARCH_CUTOFF 16
105 105
106 106 static boolean_t hasephids = B_FALSE;
107 107
108 108 static ephemeral_zsd_t *
109 109 get_ephemeral_zsd(zone_t *zone)
110 110 {
111 111 ephemeral_zsd_t *eph_zsd;
112 112
113 113 eph_zsd = zone_getspecific(ephemeral_zone_key, zone);
114 114 if (eph_zsd != NULL) {
115 115 return (eph_zsd);
116 116 }
117 117
118 118 mutex_enter(&ephemeral_zone_mutex);
119 119 eph_zsd = zone_getspecific(ephemeral_zone_key, zone);
120 120 if (eph_zsd == NULL) {
121 121 eph_zsd = kmem_zalloc(sizeof (ephemeral_zsd_t), KM_SLEEP);
122 122 eph_zsd->min_uid = MAXUID;
123 123 eph_zsd->last_uid = IDMAP_WK__MAX_UID;
124 124 eph_zsd->min_gid = MAXUID;
125 125 eph_zsd->last_gid = IDMAP_WK__MAX_GID;
126 126 mutex_init(&eph_zsd->eph_lock, NULL, MUTEX_DEFAULT, NULL);
127 127
128 128 /*
129 129 * nobody is used to map SID containing CRs.
130 130 */
131 131 eph_zsd->eph_nobody = crdup(zone->zone_kcred);
132 132 (void) crsetugid(eph_zsd->eph_nobody, UID_NOBODY, GID_NOBODY);
133 133 CR_FLAGS(eph_zsd->eph_nobody) = 0;
134 134 eph_zsd->eph_nobody->cr_zone = zone;
135 135
136 136 (void) zone_setspecific(ephemeral_zone_key, zone, eph_zsd);
137 137 }
138 138 mutex_exit(&ephemeral_zone_mutex);
139 139 return (eph_zsd);
140 140 }
141 141
142 142 static cred_t *crdup_flags(const cred_t *, int);
143 143 static cred_t *cralloc_flags(int);
144 144
145 145 /*
146 146 * This function is called when a zone is destroyed
147 147 */
148 148 static void
149 149 /* ARGSUSED */
150 150 destroy_ephemeral_zsd(zoneid_t zone_id, void *arg)
151 151 {
152 152 ephemeral_zsd_t *eph_zsd = arg;
153 153 if (eph_zsd != NULL) {
154 154 mutex_destroy(&eph_zsd->eph_lock);
155 155 crfree(eph_zsd->eph_nobody);
156 156 kmem_free(eph_zsd, sizeof (ephemeral_zsd_t));
157 157 }
158 158 }
159 159
160 160
161 161
162 162 /*
163 163 * Initialize credentials data structures.
164 164 */
165 165
166 166 void
167 167 cred_init(void)
168 168 {
169 169 priv_init();
170 170
171 171 crsize = sizeof (cred_t);
172 172
173 173 if (get_c2audit_load() > 0) {
174 174 #ifdef _LP64
175 175 /* assure audit context is 64-bit aligned */
176 176 audoff = (crsize +
177 177 sizeof (int64_t) - 1) & ~(sizeof (int64_t) - 1);
178 178 #else /* _LP64 */
179 179 audoff = crsize;
180 180 #endif /* _LP64 */
181 181 crsize = audoff + sizeof (auditinfo_addr_t);
182 182 crsize = (crsize + sizeof (int) - 1) & ~(sizeof (int) - 1);
183 183 }
184 184
185 185 cred_cache = kmem_cache_create("cred_cache", crsize, 0,
186 186 NULL, NULL, NULL, NULL, NULL, 0);
187 187
188 188 /*
189 189 * dummycr is used to copy initial state for creds.
190 190 */
191 191 dummycr = cralloc();
192 192 bzero(dummycr, crsize);
193 193 dummycr->cr_ref = 1;
194 194 dummycr->cr_uid = (uid_t)-1;
195 195 dummycr->cr_gid = (gid_t)-1;
196 196 dummycr->cr_ruid = (uid_t)-1;
197 197 dummycr->cr_rgid = (gid_t)-1;
198 198 dummycr->cr_suid = (uid_t)-1;
199 199 dummycr->cr_sgid = (gid_t)-1;
200 200
201 201
202 202 /*
203 203 * kcred is used by anything that needs all privileges; it's
204 204 * also the template used for crget as it has all the compatible
205 205 * sets filled in.
206 206 */
207 207 kcred = cralloc();
↓ open down ↓ |
207 lines elided |
↑ open up ↑ |
208 208
209 209 bzero(kcred, crsize);
210 210 kcred->cr_ref = 1;
211 211
212 212 /* kcred is never freed, so we don't need zone_cred_hold here */
213 213 kcred->cr_zone = &zone0;
214 214
215 215 priv_fillset(&CR_LPRIV(kcred));
216 216 CR_IPRIV(kcred) = *priv_basic;
217 217
218 + priv_addset(&CR_IPRIV(kcred), PRIV_PROC_SECFLAGS);
219 +
218 220 /* Not a basic privilege, if chown is not restricted add it to I0 */
219 221 if (!rstchown)
220 222 priv_addset(&CR_IPRIV(kcred), PRIV_FILE_CHOWN_SELF);
221 223
222 224 /* Basic privilege, if link is restricted remove it from I0 */
223 225 if (rstlink)
224 226 priv_delset(&CR_IPRIV(kcred), PRIV_FILE_LINK_ANY);
225 227
226 228 CR_EPRIV(kcred) = CR_PPRIV(kcred) = CR_IPRIV(kcred);
227 229
228 230 CR_FLAGS(kcred) = NET_MAC_AWARE;
229 231
230 232 /*
231 233 * Set up credentials of p0.
232 234 */
233 235 ttoproc(curthread)->p_cred = kcred;
234 236 curthread->t_cred = kcred;
235 237
236 238 ucredsize = UCRED_SIZE;
237 239
238 240 mutex_init(&ephemeral_zone_mutex, NULL, MUTEX_DEFAULT, NULL);
239 241 zone_key_create(&ephemeral_zone_key, NULL, NULL, destroy_ephemeral_zsd);
240 242 }
241 243
242 244 /*
243 245 * Allocate (nearly) uninitialized cred_t.
244 246 */
245 247 static cred_t *
246 248 cralloc_flags(int flgs)
247 249 {
248 250 cred_t *cr = kmem_cache_alloc(cred_cache, flgs);
249 251
250 252 if (cr == NULL)
251 253 return (NULL);
252 254
253 255 cr->cr_ref = 1; /* So we can crfree() */
254 256 cr->cr_zone = NULL;
255 257 cr->cr_label = NULL;
256 258 cr->cr_ksid = NULL;
257 259 cr->cr_klpd = NULL;
258 260 cr->cr_grps = NULL;
259 261 return (cr);
260 262 }
261 263
262 264 cred_t *
263 265 cralloc(void)
264 266 {
265 267 return (cralloc_flags(KM_SLEEP));
266 268 }
267 269
268 270 /*
269 271 * As cralloc but prepared for ksid change (if appropriate).
270 272 */
271 273 cred_t *
272 274 cralloc_ksid(void)
273 275 {
274 276 cred_t *cr = cralloc();
275 277 if (hasephids)
276 278 cr->cr_ksid = kcrsid_alloc();
277 279 return (cr);
278 280 }
279 281
280 282 /*
281 283 * Allocate a initialized cred structure and crhold() it.
282 284 * Initialized means: all ids 0, group count 0, L=Full, E=P=I=I0
283 285 */
284 286 cred_t *
285 287 crget(void)
286 288 {
287 289 cred_t *cr = kmem_cache_alloc(cred_cache, KM_SLEEP);
288 290
289 291 bcopy(kcred, cr, crsize);
290 292 cr->cr_ref = 1;
291 293 zone_cred_hold(cr->cr_zone);
292 294 if (cr->cr_label)
293 295 label_hold(cr->cr_label);
294 296 ASSERT(cr->cr_klpd == NULL);
295 297 ASSERT(cr->cr_grps == NULL);
296 298 return (cr);
297 299 }
298 300
299 301 /*
300 302 * Broadcast the cred to all the threads in the process.
301 303 * The current thread's credentials can be set right away, but other
302 304 * threads must wait until the start of the next system call or trap.
303 305 * This avoids changing the cred in the middle of a system call.
304 306 *
305 307 * The cred has already been held for the process and the thread (2 holds),
306 308 * and p->p_cred set.
307 309 *
308 310 * p->p_crlock shouldn't be held here, since p_lock must be acquired.
309 311 */
310 312 void
311 313 crset(proc_t *p, cred_t *cr)
312 314 {
313 315 kthread_id_t t;
314 316 kthread_id_t first;
315 317 cred_t *oldcr;
316 318
317 319 ASSERT(p == curproc); /* assumes p_lwpcnt can't change */
318 320
319 321 /*
320 322 * DTrace accesses t_cred in probe context. t_cred must always be
321 323 * either NULL, or point to a valid, allocated cred structure.
322 324 */
323 325 t = curthread;
324 326 oldcr = t->t_cred;
325 327 t->t_cred = cr; /* the cred is held by caller for this thread */
326 328 crfree(oldcr); /* free the old cred for the thread */
327 329
328 330 /*
329 331 * Broadcast to other threads, if any.
330 332 */
331 333 if (p->p_lwpcnt > 1) {
332 334 mutex_enter(&p->p_lock); /* to keep thread list safe */
333 335 first = curthread;
334 336 for (t = first->t_forw; t != first; t = t->t_forw)
335 337 t->t_pre_sys = 1; /* so syscall will get new cred */
336 338 mutex_exit(&p->p_lock);
337 339 }
338 340 }
339 341
340 342 /*
341 343 * Put a hold on a cred structure.
342 344 */
343 345 void
344 346 crhold(cred_t *cr)
345 347 {
346 348 ASSERT(cr->cr_ref != 0xdeadbeef && cr->cr_ref != 0);
347 349 atomic_inc_32(&cr->cr_ref);
348 350 }
349 351
350 352 /*
351 353 * Release previous hold on a cred structure. Free it if refcnt == 0.
352 354 * If cred uses label different from zone label, free it.
353 355 */
354 356 void
355 357 crfree(cred_t *cr)
356 358 {
357 359 ASSERT(cr->cr_ref != 0xdeadbeef && cr->cr_ref != 0);
358 360 if (atomic_dec_32_nv(&cr->cr_ref) == 0) {
359 361 ASSERT(cr != kcred);
360 362 if (cr->cr_label)
361 363 label_rele(cr->cr_label);
362 364 if (cr->cr_klpd)
363 365 crklpd_rele(cr->cr_klpd);
364 366 if (cr->cr_zone)
365 367 zone_cred_rele(cr->cr_zone);
366 368 if (cr->cr_ksid)
367 369 kcrsid_rele(cr->cr_ksid);
368 370 if (cr->cr_grps)
369 371 crgrprele(cr->cr_grps);
370 372
371 373 kmem_cache_free(cred_cache, cr);
372 374 }
373 375 }
374 376
375 377 /*
376 378 * Copy a cred structure to a new one and free the old one.
377 379 * The new cred will have two references. One for the calling process,
378 380 * and one for the thread.
379 381 */
380 382 cred_t *
381 383 crcopy(cred_t *cr)
382 384 {
383 385 cred_t *newcr;
384 386
385 387 newcr = cralloc();
386 388 bcopy(cr, newcr, crsize);
387 389 if (newcr->cr_zone)
388 390 zone_cred_hold(newcr->cr_zone);
389 391 if (newcr->cr_label)
390 392 label_hold(newcr->cr_label);
391 393 if (newcr->cr_ksid)
392 394 kcrsid_hold(newcr->cr_ksid);
393 395 if (newcr->cr_klpd)
394 396 crklpd_hold(newcr->cr_klpd);
395 397 if (newcr->cr_grps)
396 398 crgrphold(newcr->cr_grps);
397 399 crfree(cr);
398 400 newcr->cr_ref = 2; /* caller gets two references */
399 401 return (newcr);
400 402 }
401 403
402 404 /*
403 405 * Copy a cred structure to a new one and free the old one.
404 406 * The new cred will have two references. One for the calling process,
405 407 * and one for the thread.
406 408 * This variation on crcopy uses a pre-allocated structure for the
407 409 * "new" cred.
408 410 */
409 411 void
410 412 crcopy_to(cred_t *oldcr, cred_t *newcr)
411 413 {
412 414 credsid_t *nkcr = newcr->cr_ksid;
413 415
414 416 bcopy(oldcr, newcr, crsize);
415 417 if (newcr->cr_zone)
416 418 zone_cred_hold(newcr->cr_zone);
417 419 if (newcr->cr_label)
418 420 label_hold(newcr->cr_label);
419 421 if (newcr->cr_klpd)
420 422 crklpd_hold(newcr->cr_klpd);
421 423 if (newcr->cr_grps)
422 424 crgrphold(newcr->cr_grps);
423 425 if (nkcr) {
424 426 newcr->cr_ksid = nkcr;
425 427 kcrsidcopy_to(oldcr->cr_ksid, newcr->cr_ksid);
426 428 } else if (newcr->cr_ksid)
427 429 kcrsid_hold(newcr->cr_ksid);
428 430 crfree(oldcr);
429 431 newcr->cr_ref = 2; /* caller gets two references */
430 432 }
431 433
432 434 /*
433 435 * Dup a cred struct to a new held one.
434 436 * The old cred is not freed.
435 437 */
436 438 static cred_t *
437 439 crdup_flags(const cred_t *cr, int flgs)
438 440 {
439 441 cred_t *newcr;
440 442
441 443 newcr = cralloc_flags(flgs);
442 444
443 445 if (newcr == NULL)
444 446 return (NULL);
445 447
446 448 bcopy(cr, newcr, crsize);
447 449 if (newcr->cr_zone)
448 450 zone_cred_hold(newcr->cr_zone);
449 451 if (newcr->cr_label)
450 452 label_hold(newcr->cr_label);
451 453 if (newcr->cr_klpd)
452 454 crklpd_hold(newcr->cr_klpd);
453 455 if (newcr->cr_ksid)
454 456 kcrsid_hold(newcr->cr_ksid);
455 457 if (newcr->cr_grps)
456 458 crgrphold(newcr->cr_grps);
457 459 newcr->cr_ref = 1;
458 460 return (newcr);
459 461 }
460 462
461 463 cred_t *
462 464 crdup(cred_t *cr)
463 465 {
464 466 return (crdup_flags(cr, KM_SLEEP));
465 467 }
466 468
467 469 /*
468 470 * Dup a cred struct to a new held one.
469 471 * The old cred is not freed.
470 472 * This variation on crdup uses a pre-allocated structure for the
471 473 * "new" cred.
472 474 */
473 475 void
474 476 crdup_to(cred_t *oldcr, cred_t *newcr)
475 477 {
476 478 credsid_t *nkcr = newcr->cr_ksid;
477 479
478 480 bcopy(oldcr, newcr, crsize);
479 481 if (newcr->cr_zone)
480 482 zone_cred_hold(newcr->cr_zone);
481 483 if (newcr->cr_label)
482 484 label_hold(newcr->cr_label);
483 485 if (newcr->cr_klpd)
484 486 crklpd_hold(newcr->cr_klpd);
485 487 if (newcr->cr_grps)
486 488 crgrphold(newcr->cr_grps);
487 489 if (nkcr) {
488 490 newcr->cr_ksid = nkcr;
489 491 kcrsidcopy_to(oldcr->cr_ksid, newcr->cr_ksid);
490 492 } else if (newcr->cr_ksid)
491 493 kcrsid_hold(newcr->cr_ksid);
492 494 newcr->cr_ref = 1;
493 495 }
494 496
495 497 /*
496 498 * Return the (held) credentials for the current running process.
497 499 */
498 500 cred_t *
499 501 crgetcred(void)
500 502 {
501 503 cred_t *cr;
502 504 proc_t *p;
503 505
504 506 p = ttoproc(curthread);
505 507 mutex_enter(&p->p_crlock);
506 508 crhold(cr = p->p_cred);
507 509 mutex_exit(&p->p_crlock);
508 510 return (cr);
509 511 }
510 512
511 513 /*
512 514 * Backward compatibility check for suser().
513 515 * Accounting flag is now set in the policy functions; auditing is
514 516 * done through use of privilege in the audit trail.
515 517 */
516 518 int
517 519 suser(cred_t *cr)
518 520 {
519 521 return (PRIV_POLICY(cr, PRIV_SYS_SUSER_COMPAT, B_FALSE, EPERM, NULL)
520 522 == 0);
521 523 }
522 524
523 525 /*
524 526 * Determine whether the supplied group id is a member of the group
525 527 * described by the supplied credentials.
526 528 */
527 529 int
528 530 groupmember(gid_t gid, const cred_t *cr)
529 531 {
530 532 if (gid == cr->cr_gid)
531 533 return (1);
532 534 return (supgroupmember(gid, cr));
533 535 }
534 536
535 537 /*
536 538 * As groupmember but only check against the supplemental groups.
537 539 */
538 540 int
539 541 supgroupmember(gid_t gid, const cred_t *cr)
540 542 {
541 543 int hi, lo;
542 544 credgrp_t *grps = cr->cr_grps;
543 545 const gid_t *gp, *endgp;
544 546
545 547 if (grps == NULL)
546 548 return (0);
547 549
548 550 /* For a small number of groups, use sequentials search. */
549 551 if (grps->crg_ngroups <= BIN_GROUP_SEARCH_CUTOFF) {
550 552 endgp = &grps->crg_groups[grps->crg_ngroups];
551 553 for (gp = grps->crg_groups; gp < endgp; gp++)
552 554 if (*gp == gid)
553 555 return (1);
554 556 return (0);
555 557 }
556 558
557 559 /* We use binary search when we have many groups. */
558 560 lo = 0;
559 561 hi = grps->crg_ngroups - 1;
560 562 gp = grps->crg_groups;
561 563
562 564 do {
563 565 int m = (lo + hi) / 2;
564 566
565 567 if (gid > gp[m])
566 568 lo = m + 1;
567 569 else if (gid < gp[m])
568 570 hi = m - 1;
569 571 else
570 572 return (1);
571 573 } while (lo <= hi);
572 574
573 575 return (0);
574 576 }
575 577
576 578 /*
577 579 * This function is called to check whether the credentials set
578 580 * "scrp" has permission to act on credentials set "tcrp". It enforces the
579 581 * permission requirements needed to send a signal to a process.
580 582 * The same requirements are imposed by other system calls, however.
581 583 *
582 584 * The rules are:
583 585 * (1) if the credentials are the same, the check succeeds
584 586 * (2) if the zone ids don't match, and scrp is not in the global zone or
585 587 * does not have the PRIV_PROC_ZONE privilege, the check fails
586 588 * (3) if the real or effective user id of scrp matches the real or saved
587 589 * user id of tcrp or scrp has the PRIV_PROC_OWNER privilege, the check
588 590 * succeeds
589 591 * (4) otherwise, the check fails
590 592 */
591 593 int
592 594 hasprocperm(const cred_t *tcrp, const cred_t *scrp)
593 595 {
594 596 if (scrp == tcrp)
595 597 return (1);
596 598 if (scrp->cr_zone != tcrp->cr_zone &&
597 599 (scrp->cr_zone != global_zone ||
598 600 secpolicy_proc_zone(scrp) != 0))
599 601 return (0);
600 602 if (scrp->cr_uid == tcrp->cr_ruid ||
601 603 scrp->cr_ruid == tcrp->cr_ruid ||
602 604 scrp->cr_uid == tcrp->cr_suid ||
603 605 scrp->cr_ruid == tcrp->cr_suid ||
604 606 !PRIV_POLICY(scrp, PRIV_PROC_OWNER, B_FALSE, EPERM, "hasprocperm"))
605 607 return (1);
606 608 return (0);
607 609 }
608 610
609 611 /*
610 612 * This interface replaces hasprocperm; it works like hasprocperm but
611 613 * additionally returns success if the proc_t's match
612 614 * It is the preferred interface for most uses.
613 615 * And it will acquire p_crlock itself, so it assert's that it shouldn't
614 616 * be held.
615 617 */
616 618 int
617 619 prochasprocperm(proc_t *tp, proc_t *sp, const cred_t *scrp)
618 620 {
619 621 int rets;
620 622 cred_t *tcrp;
621 623
622 624 ASSERT(MUTEX_NOT_HELD(&tp->p_crlock));
623 625
624 626 if (tp == sp)
625 627 return (1);
626 628
627 629 if (tp->p_sessp != sp->p_sessp && secpolicy_basic_proc(scrp) != 0)
628 630 return (0);
629 631
630 632 mutex_enter(&tp->p_crlock);
631 633 crhold(tcrp = tp->p_cred);
632 634 mutex_exit(&tp->p_crlock);
633 635 rets = hasprocperm(tcrp, scrp);
634 636 crfree(tcrp);
635 637
636 638 return (rets);
637 639 }
638 640
639 641 /*
640 642 * This routine is used to compare two credentials to determine if
641 643 * they refer to the same "user". If the pointers are equal, then
642 644 * they must refer to the same user. Otherwise, the contents of
643 645 * the credentials are compared to see whether they are equivalent.
644 646 *
645 647 * This routine returns 0 if the credentials refer to the same user,
646 648 * 1 if they do not.
647 649 */
648 650 int
649 651 crcmp(const cred_t *cr1, const cred_t *cr2)
650 652 {
651 653 credgrp_t *grp1, *grp2;
652 654
653 655 if (cr1 == cr2)
654 656 return (0);
655 657
656 658 if (cr1->cr_uid == cr2->cr_uid &&
657 659 cr1->cr_gid == cr2->cr_gid &&
658 660 cr1->cr_ruid == cr2->cr_ruid &&
659 661 cr1->cr_rgid == cr2->cr_rgid &&
660 662 cr1->cr_zone == cr2->cr_zone &&
661 663 ((grp1 = cr1->cr_grps) == (grp2 = cr2->cr_grps) ||
662 664 (grp1 != NULL && grp2 != NULL &&
663 665 grp1->crg_ngroups == grp2->crg_ngroups &&
664 666 bcmp(grp1->crg_groups, grp2->crg_groups,
665 667 grp1->crg_ngroups * sizeof (gid_t)) == 0))) {
666 668 return (!priv_isequalset(&CR_OEPRIV(cr1), &CR_OEPRIV(cr2)));
667 669 }
668 670 return (1);
669 671 }
670 672
671 673 /*
672 674 * Read access functions to cred_t.
673 675 */
674 676 uid_t
675 677 crgetuid(const cred_t *cr)
676 678 {
677 679 return (cr->cr_uid);
678 680 }
679 681
680 682 uid_t
681 683 crgetruid(const cred_t *cr)
682 684 {
683 685 return (cr->cr_ruid);
684 686 }
685 687
686 688 uid_t
687 689 crgetsuid(const cred_t *cr)
688 690 {
689 691 return (cr->cr_suid);
690 692 }
691 693
692 694 gid_t
693 695 crgetgid(const cred_t *cr)
694 696 {
695 697 return (cr->cr_gid);
696 698 }
697 699
698 700 gid_t
699 701 crgetrgid(const cred_t *cr)
700 702 {
701 703 return (cr->cr_rgid);
702 704 }
703 705
704 706 gid_t
705 707 crgetsgid(const cred_t *cr)
706 708 {
707 709 return (cr->cr_sgid);
708 710 }
709 711
710 712 const auditinfo_addr_t *
711 713 crgetauinfo(const cred_t *cr)
712 714 {
713 715 return ((const auditinfo_addr_t *)CR_AUINFO(cr));
714 716 }
715 717
716 718 auditinfo_addr_t *
717 719 crgetauinfo_modifiable(cred_t *cr)
718 720 {
719 721 return (CR_AUINFO(cr));
720 722 }
721 723
722 724 zoneid_t
723 725 crgetzoneid(const cred_t *cr)
724 726 {
725 727 return (cr->cr_zone == NULL ?
726 728 (cr->cr_uid == -1 ? (zoneid_t)-1 : GLOBAL_ZONEID) :
727 729 cr->cr_zone->zone_id);
728 730 }
729 731
730 732 projid_t
731 733 crgetprojid(const cred_t *cr)
732 734 {
733 735 return (cr->cr_projid);
734 736 }
735 737
736 738 zone_t *
737 739 crgetzone(const cred_t *cr)
738 740 {
739 741 return (cr->cr_zone);
740 742 }
741 743
742 744 struct ts_label_s *
743 745 crgetlabel(const cred_t *cr)
744 746 {
745 747 return (cr->cr_label ?
746 748 cr->cr_label :
747 749 (cr->cr_zone ? cr->cr_zone->zone_slabel : NULL));
748 750 }
749 751
750 752 boolean_t
751 753 crisremote(const cred_t *cr)
752 754 {
753 755 return (REMOTE_PEER_CRED(cr));
754 756 }
755 757
756 758 #define BADUID(x, zn) ((x) != -1 && !VALID_UID((x), (zn)))
757 759 #define BADGID(x, zn) ((x) != -1 && !VALID_GID((x), (zn)))
758 760
759 761 int
760 762 crsetresuid(cred_t *cr, uid_t r, uid_t e, uid_t s)
761 763 {
762 764 zone_t *zone = crgetzone(cr);
763 765
764 766 ASSERT(cr->cr_ref <= 2);
765 767
766 768 if (BADUID(r, zone) || BADUID(e, zone) || BADUID(s, zone))
767 769 return (-1);
768 770
769 771 if (r != -1)
770 772 cr->cr_ruid = r;
771 773 if (e != -1)
772 774 cr->cr_uid = e;
773 775 if (s != -1)
774 776 cr->cr_suid = s;
775 777
776 778 return (0);
777 779 }
778 780
779 781 int
780 782 crsetresgid(cred_t *cr, gid_t r, gid_t e, gid_t s)
781 783 {
782 784 zone_t *zone = crgetzone(cr);
783 785
784 786 ASSERT(cr->cr_ref <= 2);
785 787
786 788 if (BADGID(r, zone) || BADGID(e, zone) || BADGID(s, zone))
787 789 return (-1);
788 790
789 791 if (r != -1)
790 792 cr->cr_rgid = r;
791 793 if (e != -1)
792 794 cr->cr_gid = e;
793 795 if (s != -1)
794 796 cr->cr_sgid = s;
795 797
796 798 return (0);
797 799 }
798 800
799 801 int
800 802 crsetugid(cred_t *cr, uid_t uid, gid_t gid)
801 803 {
802 804 zone_t *zone = crgetzone(cr);
803 805
804 806 ASSERT(cr->cr_ref <= 2);
805 807
806 808 if (!VALID_UID(uid, zone) || !VALID_GID(gid, zone))
807 809 return (-1);
808 810
809 811 cr->cr_uid = cr->cr_ruid = cr->cr_suid = uid;
810 812 cr->cr_gid = cr->cr_rgid = cr->cr_sgid = gid;
811 813
812 814 return (0);
813 815 }
814 816
815 817 static int
816 818 gidcmp(const void *v1, const void *v2)
817 819 {
818 820 gid_t g1 = *(gid_t *)v1;
819 821 gid_t g2 = *(gid_t *)v2;
820 822
821 823 if (g1 < g2)
822 824 return (-1);
823 825 else if (g1 > g2)
824 826 return (1);
825 827 else
826 828 return (0);
827 829 }
828 830
829 831 int
830 832 crsetgroups(cred_t *cr, int n, gid_t *grp)
831 833 {
832 834 ASSERT(cr->cr_ref <= 2);
833 835
834 836 if (n > ngroups_max || n < 0)
835 837 return (-1);
836 838
837 839 if (cr->cr_grps != NULL)
838 840 crgrprele(cr->cr_grps);
839 841
840 842 if (n > 0) {
841 843 cr->cr_grps = kmem_alloc(CREDGRPSZ(n), KM_SLEEP);
842 844 bcopy(grp, cr->cr_grps->crg_groups, n * sizeof (gid_t));
843 845 cr->cr_grps->crg_ref = 1;
844 846 cr->cr_grps->crg_ngroups = n;
845 847 qsort(cr->cr_grps->crg_groups, n, sizeof (gid_t), gidcmp);
846 848 } else {
847 849 cr->cr_grps = NULL;
848 850 }
849 851
850 852 return (0);
851 853 }
852 854
853 855 void
854 856 crsetprojid(cred_t *cr, projid_t projid)
855 857 {
856 858 ASSERT(projid >= 0 && projid <= MAXPROJID);
857 859 cr->cr_projid = projid;
858 860 }
859 861
860 862 /*
861 863 * This routine returns the pointer to the first element of the crg_groups
862 864 * array. It can move around in an implementation defined way.
863 865 * Note that when we have no grouplist, we return one element but the
864 866 * caller should never reference it.
865 867 */
866 868 const gid_t *
867 869 crgetgroups(const cred_t *cr)
868 870 {
869 871 return (cr->cr_grps == NULL ? &cr->cr_gid : cr->cr_grps->crg_groups);
870 872 }
871 873
872 874 int
873 875 crgetngroups(const cred_t *cr)
874 876 {
875 877 return (cr->cr_grps == NULL ? 0 : cr->cr_grps->crg_ngroups);
876 878 }
877 879
878 880 void
879 881 cred2prcred(const cred_t *cr, prcred_t *pcrp)
880 882 {
881 883 pcrp->pr_euid = cr->cr_uid;
882 884 pcrp->pr_ruid = cr->cr_ruid;
883 885 pcrp->pr_suid = cr->cr_suid;
884 886 pcrp->pr_egid = cr->cr_gid;
885 887 pcrp->pr_rgid = cr->cr_rgid;
886 888 pcrp->pr_sgid = cr->cr_sgid;
887 889 pcrp->pr_groups[0] = 0; /* in case ngroups == 0 */
888 890 pcrp->pr_ngroups = cr->cr_grps == NULL ? 0 : cr->cr_grps->crg_ngroups;
889 891
890 892 if (pcrp->pr_ngroups != 0)
891 893 bcopy(cr->cr_grps->crg_groups, pcrp->pr_groups,
892 894 sizeof (gid_t) * pcrp->pr_ngroups);
893 895 }
894 896
895 897 static int
896 898 cred2ucaud(const cred_t *cr, auditinfo64_addr_t *ainfo, const cred_t *rcr)
897 899 {
898 900 auditinfo_addr_t *ai;
899 901 au_tid_addr_t tid;
900 902
901 903 if (secpolicy_audit_getattr(rcr, B_TRUE) != 0)
902 904 return (-1);
903 905
904 906 ai = CR_AUINFO(cr); /* caller makes sure this is non-NULL */
905 907 tid = ai->ai_termid;
906 908
907 909 ainfo->ai_auid = ai->ai_auid;
908 910 ainfo->ai_mask = ai->ai_mask;
909 911 ainfo->ai_asid = ai->ai_asid;
910 912
911 913 ainfo->ai_termid.at_type = tid.at_type;
912 914 bcopy(&tid.at_addr, &ainfo->ai_termid.at_addr, 4 * sizeof (uint_t));
913 915
914 916 ainfo->ai_termid.at_port.at_major = (uint32_t)getmajor(tid.at_port);
915 917 ainfo->ai_termid.at_port.at_minor = (uint32_t)getminor(tid.at_port);
916 918
917 919 return (0);
918 920 }
919 921
920 922 void
921 923 cred2uclabel(const cred_t *cr, bslabel_t *labelp)
922 924 {
923 925 ts_label_t *tslp;
924 926
925 927 if ((tslp = crgetlabel(cr)) != NULL)
926 928 bcopy(&tslp->tsl_label, labelp, sizeof (bslabel_t));
927 929 }
928 930
929 931 /*
930 932 * Convert a credential into a "ucred". Allow the caller to specify
931 933 * and aligned buffer, e.g., in an mblk, so we don't have to allocate
932 934 * memory and copy it twice.
933 935 *
934 936 * This function may call cred2ucaud(), which calls CRED(). Since this
935 937 * can be called from an interrupt thread, receiver's cred (rcr) is needed
936 938 * to determine whether audit info should be included.
937 939 */
938 940 struct ucred_s *
939 941 cred2ucred(const cred_t *cr, pid_t pid, void *buf, const cred_t *rcr)
940 942 {
941 943 struct ucred_s *uc;
942 944 uint32_t realsz = ucredminsize(cr);
943 945 ts_label_t *tslp = is_system_labeled() ? crgetlabel(cr) : NULL;
944 946
945 947 /* The structure isn't always completely filled in, so zero it */
946 948 if (buf == NULL) {
947 949 uc = kmem_zalloc(realsz, KM_SLEEP);
948 950 } else {
949 951 bzero(buf, realsz);
950 952 uc = buf;
951 953 }
952 954 uc->uc_size = realsz;
953 955 uc->uc_pid = pid;
954 956 uc->uc_projid = cr->cr_projid;
955 957 uc->uc_zoneid = crgetzoneid(cr);
956 958
957 959 if (REMOTE_PEER_CRED(cr)) {
958 960 /*
959 961 * Other than label, the rest of cred info about a
960 962 * remote peer isn't available. Copy the label directly
961 963 * after the header where we generally copy the prcred.
962 964 * That's why we use sizeof (struct ucred_s). The other
963 965 * offset fields are initialized to 0.
964 966 */
965 967 uc->uc_labeloff = tslp == NULL ? 0 : sizeof (struct ucred_s);
966 968 } else {
967 969 uc->uc_credoff = UCRED_CRED_OFF;
968 970 uc->uc_privoff = UCRED_PRIV_OFF;
969 971 uc->uc_audoff = UCRED_AUD_OFF;
970 972 uc->uc_labeloff = tslp == NULL ? 0 : UCRED_LABEL_OFF;
971 973
972 974 cred2prcred(cr, UCCRED(uc));
973 975 cred2prpriv(cr, UCPRIV(uc));
974 976
975 977 if (audoff == 0 || cred2ucaud(cr, UCAUD(uc), rcr) != 0)
976 978 uc->uc_audoff = 0;
977 979 }
978 980 if (tslp != NULL)
979 981 bcopy(&tslp->tsl_label, UCLABEL(uc), sizeof (bslabel_t));
980 982
981 983 return (uc);
982 984 }
983 985
984 986 /*
985 987 * Don't allocate the non-needed group entries. Note: this function
986 988 * must match the code in cred2ucred; they must agree about the
987 989 * minimal size of the ucred.
988 990 */
989 991 uint32_t
990 992 ucredminsize(const cred_t *cr)
991 993 {
992 994 int ndiff;
993 995
994 996 if (cr == NULL)
995 997 return (ucredsize);
996 998
997 999 if (REMOTE_PEER_CRED(cr)) {
998 1000 if (is_system_labeled())
999 1001 return (sizeof (struct ucred_s) + sizeof (bslabel_t));
1000 1002 else
1001 1003 return (sizeof (struct ucred_s));
1002 1004 }
1003 1005
1004 1006 if (cr->cr_grps == NULL)
1005 1007 ndiff = ngroups_max - 1; /* Needs one for prcred_t */
1006 1008 else
1007 1009 ndiff = ngroups_max - cr->cr_grps->crg_ngroups;
1008 1010
1009 1011 return (ucredsize - ndiff * sizeof (gid_t));
1010 1012 }
1011 1013
1012 1014 /*
1013 1015 * Get the "ucred" of a process.
1014 1016 */
1015 1017 struct ucred_s *
1016 1018 pgetucred(proc_t *p)
1017 1019 {
1018 1020 cred_t *cr;
1019 1021 struct ucred_s *uc;
1020 1022
1021 1023 mutex_enter(&p->p_crlock);
1022 1024 cr = p->p_cred;
1023 1025 crhold(cr);
1024 1026 mutex_exit(&p->p_crlock);
1025 1027
1026 1028 uc = cred2ucred(cr, p->p_pid, NULL, CRED());
1027 1029 crfree(cr);
1028 1030
1029 1031 return (uc);
1030 1032 }
1031 1033
1032 1034 /*
1033 1035 * If the reply status is NFSERR_EACCES, it may be because we are
1034 1036 * root (no root net access). Check the real uid, if it isn't root
1035 1037 * make that the uid instead and retry the call.
1036 1038 * Private interface for NFS.
1037 1039 */
1038 1040 cred_t *
1039 1041 crnetadjust(cred_t *cr)
1040 1042 {
1041 1043 if (cr->cr_uid == 0 && cr->cr_ruid != 0) {
1042 1044 cr = crdup(cr);
1043 1045 cr->cr_uid = cr->cr_ruid;
1044 1046 return (cr);
1045 1047 }
1046 1048 return (NULL);
1047 1049 }
1048 1050
1049 1051 /*
1050 1052 * The reference count is of interest when you want to check
1051 1053 * whether it is ok to modify the credential in place.
1052 1054 */
1053 1055 uint_t
1054 1056 crgetref(const cred_t *cr)
1055 1057 {
1056 1058 return (cr->cr_ref);
1057 1059 }
1058 1060
1059 1061 static int
1060 1062 get_c2audit_load(void)
1061 1063 {
1062 1064 static int gotit = 0;
1063 1065 static int c2audit_load;
1064 1066
1065 1067 if (gotit)
1066 1068 return (c2audit_load);
1067 1069 c2audit_load = 1; /* set default value once */
1068 1070 if (mod_sysctl(SYS_CHECK_EXCLUDE, "c2audit") != 0)
1069 1071 c2audit_load = 0;
1070 1072 gotit++;
1071 1073
1072 1074 return (c2audit_load);
1073 1075 }
1074 1076
1075 1077 int
1076 1078 get_audit_ucrsize(void)
1077 1079 {
1078 1080 return (get_c2audit_load() ? sizeof (auditinfo64_addr_t) : 0);
1079 1081 }
1080 1082
1081 1083 /*
1082 1084 * Set zone pointer in credential to indicated value. First adds a
1083 1085 * hold for the new zone, then drops the hold on previous zone (if any).
1084 1086 * This is done in this order in case the old and new zones are the
1085 1087 * same.
1086 1088 */
1087 1089 void
1088 1090 crsetzone(cred_t *cr, zone_t *zptr)
1089 1091 {
1090 1092 zone_t *oldzptr = cr->cr_zone;
1091 1093
1092 1094 ASSERT(cr != kcred);
1093 1095 ASSERT(cr->cr_ref <= 2);
1094 1096 cr->cr_zone = zptr;
1095 1097 zone_cred_hold(zptr);
1096 1098 if (oldzptr)
1097 1099 zone_cred_rele(oldzptr);
1098 1100 }
1099 1101
1100 1102 /*
1101 1103 * Create a new cred based on the supplied label
1102 1104 */
1103 1105 cred_t *
1104 1106 newcred_from_bslabel(bslabel_t *blabel, uint32_t doi, int flags)
1105 1107 {
1106 1108 ts_label_t *lbl = labelalloc(blabel, doi, flags);
1107 1109 cred_t *cr = NULL;
1108 1110
1109 1111 if (lbl != NULL) {
1110 1112 if ((cr = crdup_flags(dummycr, flags)) != NULL) {
1111 1113 cr->cr_label = lbl;
1112 1114 } else {
1113 1115 label_rele(lbl);
1114 1116 }
1115 1117 }
1116 1118
1117 1119 return (cr);
1118 1120 }
1119 1121
1120 1122 /*
1121 1123 * Derive a new cred from the existing cred, but with a different label.
1122 1124 * To be used when a cred is being shared, but the label needs to be changed
1123 1125 * by a caller without affecting other users
1124 1126 */
1125 1127 cred_t *
1126 1128 copycred_from_tslabel(const cred_t *cr, ts_label_t *label, int flags)
1127 1129 {
1128 1130 cred_t *newcr = NULL;
1129 1131
1130 1132 if ((newcr = crdup_flags(cr, flags)) != NULL) {
1131 1133 if (newcr->cr_label != NULL)
1132 1134 label_rele(newcr->cr_label);
1133 1135 label_hold(label);
1134 1136 newcr->cr_label = label;
1135 1137 }
1136 1138
1137 1139 return (newcr);
1138 1140 }
1139 1141
1140 1142 /*
1141 1143 * Derive a new cred from the existing cred, but with a different label.
1142 1144 */
1143 1145 cred_t *
1144 1146 copycred_from_bslabel(const cred_t *cr, bslabel_t *blabel,
1145 1147 uint32_t doi, int flags)
1146 1148 {
1147 1149 ts_label_t *lbl = labelalloc(blabel, doi, flags);
1148 1150 cred_t *newcr = NULL;
1149 1151
1150 1152 if (lbl != NULL) {
1151 1153 newcr = copycred_from_tslabel(cr, lbl, flags);
1152 1154 label_rele(lbl);
1153 1155 }
1154 1156
1155 1157 return (newcr);
1156 1158 }
1157 1159
1158 1160 /*
1159 1161 * This function returns a pointer to the kcred-equivalent in the current zone.
1160 1162 */
1161 1163 cred_t *
1162 1164 zone_kcred(void)
1163 1165 {
1164 1166 zone_t *zone;
1165 1167
1166 1168 if ((zone = CRED()->cr_zone) != NULL)
1167 1169 return (zone->zone_kcred);
1168 1170 else
1169 1171 return (kcred);
1170 1172 }
1171 1173
1172 1174 boolean_t
1173 1175 valid_ephemeral_uid(zone_t *zone, uid_t id)
1174 1176 {
1175 1177 ephemeral_zsd_t *eph_zsd;
1176 1178 if (id <= IDMAP_WK__MAX_UID)
1177 1179 return (B_TRUE);
1178 1180
1179 1181 eph_zsd = get_ephemeral_zsd(zone);
1180 1182 ASSERT(eph_zsd != NULL);
1181 1183 membar_consumer();
1182 1184 return (id > eph_zsd->min_uid && id <= eph_zsd->last_uid);
1183 1185 }
1184 1186
1185 1187 boolean_t
1186 1188 valid_ephemeral_gid(zone_t *zone, gid_t id)
1187 1189 {
1188 1190 ephemeral_zsd_t *eph_zsd;
1189 1191 if (id <= IDMAP_WK__MAX_GID)
1190 1192 return (B_TRUE);
1191 1193
1192 1194 eph_zsd = get_ephemeral_zsd(zone);
1193 1195 ASSERT(eph_zsd != NULL);
1194 1196 membar_consumer();
1195 1197 return (id > eph_zsd->min_gid && id <= eph_zsd->last_gid);
1196 1198 }
1197 1199
1198 1200 int
1199 1201 eph_uid_alloc(zone_t *zone, int flags, uid_t *start, int count)
1200 1202 {
1201 1203 ephemeral_zsd_t *eph_zsd = get_ephemeral_zsd(zone);
1202 1204
1203 1205 ASSERT(eph_zsd != NULL);
1204 1206
1205 1207 mutex_enter(&eph_zsd->eph_lock);
1206 1208
1207 1209 /* Test for unsigned integer wrap around */
1208 1210 if (eph_zsd->last_uid + count < eph_zsd->last_uid) {
1209 1211 mutex_exit(&eph_zsd->eph_lock);
1210 1212 return (-1);
1211 1213 }
1212 1214
1213 1215 /* first call or idmap crashed and state corrupted */
1214 1216 if (flags != 0)
1215 1217 eph_zsd->min_uid = eph_zsd->last_uid;
1216 1218
1217 1219 hasephids = B_TRUE;
1218 1220 *start = eph_zsd->last_uid + 1;
1219 1221 atomic_add_32(&eph_zsd->last_uid, count);
1220 1222 mutex_exit(&eph_zsd->eph_lock);
1221 1223 return (0);
1222 1224 }
1223 1225
1224 1226 int
1225 1227 eph_gid_alloc(zone_t *zone, int flags, gid_t *start, int count)
1226 1228 {
1227 1229 ephemeral_zsd_t *eph_zsd = get_ephemeral_zsd(zone);
1228 1230
1229 1231 ASSERT(eph_zsd != NULL);
1230 1232
1231 1233 mutex_enter(&eph_zsd->eph_lock);
1232 1234
1233 1235 /* Test for unsigned integer wrap around */
1234 1236 if (eph_zsd->last_gid + count < eph_zsd->last_gid) {
1235 1237 mutex_exit(&eph_zsd->eph_lock);
1236 1238 return (-1);
1237 1239 }
1238 1240
1239 1241 /* first call or idmap crashed and state corrupted */
1240 1242 if (flags != 0)
1241 1243 eph_zsd->min_gid = eph_zsd->last_gid;
1242 1244
1243 1245 hasephids = B_TRUE;
1244 1246 *start = eph_zsd->last_gid + 1;
1245 1247 atomic_add_32(&eph_zsd->last_gid, count);
1246 1248 mutex_exit(&eph_zsd->eph_lock);
1247 1249 return (0);
1248 1250 }
1249 1251
1250 1252 /*
1251 1253 * IMPORTANT.The two functions get_ephemeral_data() and set_ephemeral_data()
1252 1254 * are project private functions that are for use of the test system only and
1253 1255 * are not to be used for other purposes.
1254 1256 */
1255 1257
1256 1258 void
1257 1259 get_ephemeral_data(zone_t *zone, uid_t *min_uid, uid_t *last_uid,
1258 1260 gid_t *min_gid, gid_t *last_gid)
1259 1261 {
1260 1262 ephemeral_zsd_t *eph_zsd = get_ephemeral_zsd(zone);
1261 1263
1262 1264 ASSERT(eph_zsd != NULL);
1263 1265
1264 1266 mutex_enter(&eph_zsd->eph_lock);
1265 1267
1266 1268 *min_uid = eph_zsd->min_uid;
1267 1269 *last_uid = eph_zsd->last_uid;
1268 1270 *min_gid = eph_zsd->min_gid;
1269 1271 *last_gid = eph_zsd->last_gid;
1270 1272
1271 1273 mutex_exit(&eph_zsd->eph_lock);
1272 1274 }
1273 1275
1274 1276
1275 1277 void
1276 1278 set_ephemeral_data(zone_t *zone, uid_t min_uid, uid_t last_uid,
1277 1279 gid_t min_gid, gid_t last_gid)
1278 1280 {
1279 1281 ephemeral_zsd_t *eph_zsd = get_ephemeral_zsd(zone);
1280 1282
1281 1283 ASSERT(eph_zsd != NULL);
1282 1284
1283 1285 mutex_enter(&eph_zsd->eph_lock);
1284 1286
1285 1287 if (min_uid != 0)
1286 1288 eph_zsd->min_uid = min_uid;
1287 1289 if (last_uid != 0)
1288 1290 eph_zsd->last_uid = last_uid;
1289 1291 if (min_gid != 0)
1290 1292 eph_zsd->min_gid = min_gid;
1291 1293 if (last_gid != 0)
1292 1294 eph_zsd->last_gid = last_gid;
1293 1295
1294 1296 mutex_exit(&eph_zsd->eph_lock);
1295 1297 }
1296 1298
1297 1299 /*
1298 1300 * If the credential user SID or group SID is mapped to an ephemeral
1299 1301 * ID, map the credential to nobody.
1300 1302 */
1301 1303 cred_t *
1302 1304 crgetmapped(const cred_t *cr)
1303 1305 {
1304 1306 ephemeral_zsd_t *eph_zsd;
1305 1307 /*
1306 1308 * Someone incorrectly passed a NULL cred to a vnode operation
1307 1309 * either on purpose or by calling CRED() in interrupt context.
1308 1310 */
1309 1311 if (cr == NULL)
1310 1312 return (NULL);
1311 1313
1312 1314 if (cr->cr_ksid != NULL) {
1313 1315 if (cr->cr_ksid->kr_sidx[KSID_USER].ks_id > MAXUID) {
1314 1316 eph_zsd = get_ephemeral_zsd(crgetzone(cr));
1315 1317 return (eph_zsd->eph_nobody);
1316 1318 }
1317 1319
1318 1320 if (cr->cr_ksid->kr_sidx[KSID_GROUP].ks_id > MAXUID) {
1319 1321 eph_zsd = get_ephemeral_zsd(crgetzone(cr));
1320 1322 return (eph_zsd->eph_nobody);
1321 1323 }
1322 1324 }
1323 1325
1324 1326 return ((cred_t *)cr);
1325 1327 }
1326 1328
1327 1329 /* index should be in range for a ksidindex_t */
1328 1330 void
1329 1331 crsetsid(cred_t *cr, ksid_t *ksp, int index)
1330 1332 {
1331 1333 ASSERT(cr->cr_ref <= 2);
1332 1334 ASSERT(index >= 0 && index < KSID_COUNT);
1333 1335 if (cr->cr_ksid == NULL && ksp == NULL)
1334 1336 return;
1335 1337 cr->cr_ksid = kcrsid_setsid(cr->cr_ksid, ksp, index);
1336 1338 }
1337 1339
1338 1340 void
1339 1341 crsetsidlist(cred_t *cr, ksidlist_t *ksl)
1340 1342 {
1341 1343 ASSERT(cr->cr_ref <= 2);
1342 1344 if (cr->cr_ksid == NULL && ksl == NULL)
1343 1345 return;
1344 1346 cr->cr_ksid = kcrsid_setsidlist(cr->cr_ksid, ksl);
1345 1347 }
1346 1348
1347 1349 ksid_t *
1348 1350 crgetsid(const cred_t *cr, int i)
1349 1351 {
1350 1352 ASSERT(i >= 0 && i < KSID_COUNT);
1351 1353 if (cr->cr_ksid != NULL && cr->cr_ksid->kr_sidx[i].ks_domain)
1352 1354 return ((ksid_t *)&cr->cr_ksid->kr_sidx[i]);
1353 1355 return (NULL);
1354 1356 }
1355 1357
1356 1358 ksidlist_t *
1357 1359 crgetsidlist(const cred_t *cr)
1358 1360 {
1359 1361 if (cr->cr_ksid != NULL)
1360 1362 return (cr->cr_ksid->kr_sidlist);
1361 1363 return (NULL);
1362 1364 }
1363 1365
1364 1366 /*
1365 1367 * Interface to set the effective and permitted privileges for
1366 1368 * a credential; this interface does no security checks and is
1367 1369 * intended for kernel (file)servers creating credentials with
1368 1370 * specific privileges.
1369 1371 */
1370 1372 int
1371 1373 crsetpriv(cred_t *cr, ...)
1372 1374 {
1373 1375 va_list ap;
1374 1376 const char *privnm;
1375 1377
1376 1378 ASSERT(cr->cr_ref <= 2);
1377 1379
1378 1380 priv_set_PA(cr);
1379 1381
1380 1382 va_start(ap, cr);
1381 1383
1382 1384 while ((privnm = va_arg(ap, const char *)) != NULL) {
1383 1385 int priv = priv_getbyname(privnm, 0);
1384 1386 if (priv < 0)
1385 1387 return (-1);
1386 1388
1387 1389 priv_addset(&CR_PPRIV(cr), priv);
1388 1390 priv_addset(&CR_EPRIV(cr), priv);
1389 1391 }
1390 1392 priv_adjust_PA(cr);
1391 1393 va_end(ap);
1392 1394 return (0);
1393 1395 }
1394 1396
1395 1397 /*
1396 1398 * Interface to effectively set the PRIV_ALL for
1397 1399 * a credential; this interface does no security checks and is
1398 1400 * intended for kernel (file)servers to extend the user credentials
1399 1401 * to be ALL, like either kcred or zcred.
1400 1402 */
1401 1403 void
1402 1404 crset_zone_privall(cred_t *cr)
1403 1405 {
1404 1406 zone_t *zone = crgetzone(cr);
1405 1407
1406 1408 priv_fillset(&CR_LPRIV(cr));
1407 1409 CR_EPRIV(cr) = CR_PPRIV(cr) = CR_IPRIV(cr) = CR_LPRIV(cr);
1408 1410 priv_intersect(zone->zone_privset, &CR_LPRIV(cr));
1409 1411 priv_intersect(zone->zone_privset, &CR_EPRIV(cr));
1410 1412 priv_intersect(zone->zone_privset, &CR_IPRIV(cr));
1411 1413 priv_intersect(zone->zone_privset, &CR_PPRIV(cr));
1412 1414 }
1413 1415
1414 1416 struct credklpd *
1415 1417 crgetcrklpd(const cred_t *cr)
1416 1418 {
1417 1419 return (cr->cr_klpd);
1418 1420 }
1419 1421
1420 1422 void
1421 1423 crsetcrklpd(cred_t *cr, struct credklpd *crklpd)
1422 1424 {
1423 1425 ASSERT(cr->cr_ref <= 2);
1424 1426
1425 1427 if (cr->cr_klpd != NULL)
1426 1428 crklpd_rele(cr->cr_klpd);
1427 1429 cr->cr_klpd = crklpd;
1428 1430 }
1429 1431
1430 1432 credgrp_t *
1431 1433 crgrpcopyin(int n, gid_t *gidset)
1432 1434 {
1433 1435 credgrp_t *mem;
1434 1436 size_t sz = CREDGRPSZ(n);
1435 1437
1436 1438 ASSERT(n > 0);
1437 1439
1438 1440 mem = kmem_alloc(sz, KM_SLEEP);
1439 1441
1440 1442 if (copyin(gidset, mem->crg_groups, sizeof (gid_t) * n)) {
1441 1443 kmem_free(mem, sz);
1442 1444 return (NULL);
1443 1445 }
1444 1446 mem->crg_ref = 1;
1445 1447 mem->crg_ngroups = n;
1446 1448 qsort(mem->crg_groups, n, sizeof (gid_t), gidcmp);
1447 1449 return (mem);
1448 1450 }
1449 1451
1450 1452 const gid_t *
1451 1453 crgetggroups(const credgrp_t *grps)
1452 1454 {
1453 1455 return (grps->crg_groups);
1454 1456 }
1455 1457
1456 1458 void
1457 1459 crsetcredgrp(cred_t *cr, credgrp_t *grps)
1458 1460 {
1459 1461 ASSERT(cr->cr_ref <= 2);
1460 1462
1461 1463 if (cr->cr_grps != NULL)
1462 1464 crgrprele(cr->cr_grps);
1463 1465
1464 1466 cr->cr_grps = grps;
1465 1467 }
1466 1468
1467 1469 void
1468 1470 crgrprele(credgrp_t *grps)
1469 1471 {
1470 1472 if (atomic_dec_32_nv(&grps->crg_ref) == 0)
1471 1473 kmem_free(grps, CREDGRPSZ(grps->crg_ngroups));
1472 1474 }
1473 1475
1474 1476 static void
1475 1477 crgrphold(credgrp_t *grps)
1476 1478 {
1477 1479 atomic_inc_32(&grps->crg_ref);
1478 1480 }
↓ open down ↓ |
1251 lines elided |
↑ open up ↑ |
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX