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