Print this page
5045 use atomic_{inc,dec}_* instead of atomic_add_*
Split |
Close |
Expand all |
Collapse all |
--- old/usr/src/uts/common/os/devpolicy.c
+++ new/usr/src/uts/common/os/devpolicy.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 2010 Sun Microsystems, Inc. All rights reserved.
23 23 * Use is subject to license terms.
24 24 */
25 25
26 26 /*
27 27 * Device policy implementation.
28 28 *
29 29 * Maintains the device policy table and defines the lookup functions.
30 30 *
31 31 * The table contains one entry for each major device number; each
32 32 * major bucket has a list of minor number specific entries. First
33 33 * match gets it. Not even simple minor names are expanded as that
34 34 * would cause the device to be loaded. Non-wildcard entries are expanded
35 35 * on first match. Wildcard entries are matched each open but the actual
36 36 * policy is cached with the common snode, so the matching code will
37 37 * probably be called infrequently. The trivial wildcard ``*'' does
38 38 * not cause expensive string expansions and matches.
39 39 *
40 40 * When the policy is updated, the the generation count is increased;
41 41 * whenever a cached policy is used, the generation count is compared;
42 42 * if there's no match, the device policy is refreshed.
43 43 *
44 44 * The special policy "nullpolicy" is used to mean "no checking beyond DAC
45 45 * needed". It too will change when the policy is rev'ed to make sure
46 46 * that devices with nullpolicy are also refreshed.
47 47 *
48 48 * The special policy "dfltpolicy" is used for those devices with no
49 49 * matching policy. On boot, it is "all privileges required".
50 50 * This restriction on boot functions as a fail-safe; if no device policy
51 51 * is loaded a "no restriction policy" would lead to security problems that
52 52 * are not immediately noticable.
53 53 */
54 54
55 55 #include <sys/priv_impl.h>
56 56 #include <sys/policy.h>
57 57 #include <sys/atomic.h>
58 58 #include <sys/autoconf.h>
59 59 #include <sys/sysmacros.h>
60 60 #include <sys/systm.h>
61 61 #include <sys/vnode.h>
62 62 #include <sys/devpolicy.h>
63 63 #include <sys/priv.h>
64 64 #include <sys/kmem.h>
65 65 #include <sys/ksynch.h>
66 66 #include <sys/errno.h>
67 67 #include <sys/sunddi.h>
68 68 #include <c2/audit.h>
69 69 #include <sys/fs/dv_node.h>
70 70
71 71 /*
72 72 * Internal data structures definitions.
73 73 */
74 74
75 75 typedef struct devplcyent devplcyent_t;
76 76
77 77 /*
78 78 * The device policy entry; if there is an expression string, the
79 79 * minor numbers are not relevant. This is indicated by dpe_len > 0.
80 80 */
81 81 struct devplcyent {
82 82 devplcyent_t *dpe_next; /* next entry in this list */
83 83 devplcy_t *dpe_plcy; /* policy for this entry */
84 84 char *dpe_expr; /* expression matching minor mode */
85 85 int dpe_len; /* size of allocated mem for expr */
86 86 uint32_t dpe_flags; /* flags */
87 87 minor_t dpe_lomin; /* expanded: low minor number */
88 88 minor_t dpe_himin; /* expanded: high minor number */
89 89 vtype_t dpe_spec; /* expanded: VBLK or VCHR */
90 90 };
91 91
92 92 #define DPE_WILDC 0x01 /* Expression has wildcard */
93 93 #define DPE_ALLMINOR 0x02 /* Matches all minor numbers */
94 94 #define DPE_EXPANDED 0x04 /* Minor numbers expanded */
95 95
96 96 typedef struct tableent {
97 97 devplcyent_t *t_ent; /* list of policies by minor */
98 98 major_t t_major; /* device major number */
99 99 } tableent_t;
100 100
101 101 /*
102 102 * The data store.
103 103 */
104 104
105 105 static int ntabent; /* # of major numbers */
106 106 static int totitems; /* Number of entries in all buckets + dflt */
107 107 static tableent_t *devpolicy; /* The device policy itself */
108 108
109 109 static krwlock_t policyrw; /* protects the table */
110 110 static kmutex_t policymutex; /* allows only one concurrent devpolicy_load */
111 111
112 112 devplcy_t *nullpolicy; /* public because it's used for shortcuts */
113 113 static devplcy_t *dfltpolicy;
114 114 static devplcy_t *netpolicy;
115 115
116 116 /*
117 117 * Device policy generation count; only device policies matching the
118 118 * generation count are still valid.
119 119 */
120 120 volatile uint32_t devplcy_gen;
121 121
122 122 /*
123 123 * Tunable: maximum number of device policy entries to load in
124 124 * a system call. (Protects KM_SLEEP call)
125 125 */
126 126 int maxdevpolicy = MAXDEVPOLICY;
127 127
128 128 /*
129 129 * Initialize the device policy code
130 130 */
131 131 void
132 132 devpolicy_init(void)
133 133 {
134 134 rw_init(&policyrw, NULL, RW_DRIVER, NULL);
135 135 mutex_init(&policymutex, NULL, MUTEX_DRIVER, NULL);
136 136
137 137 /* The mutex is held here in order to satisfy the ASSERT in dpget() */
138 138 mutex_enter(&policymutex);
139 139
140 140 nullpolicy = dpget();
141 141 dfltpolicy = dpget();
142 142 netpolicy = dpget();
143 143
144 144 /*
145 145 * Initially, we refuse access to all devices except
146 146 * to processes with all privileges.
147 147 */
148 148 priv_fillset(&dfltpolicy->dp_rdp);
149 149 priv_fillset(&dfltpolicy->dp_wrp);
150 150
151 151 totitems = 1;
152 152
153 153 devplcy_gen++;
154 154 mutex_exit(&policymutex);
155 155
156 156 /* initialize default network privilege */
157 157 priv_emptyset(&netpolicy->dp_rdp);
158 158 priv_emptyset(&netpolicy->dp_wrp);
159 159 priv_addset(&netpolicy->dp_rdp, PRIV_NET_RAWACCESS);
160 160 priv_addset(&netpolicy->dp_wrp, PRIV_NET_RAWACCESS);
161 161 }
162 162
163 163 /*
164 164 * Devpolicy reference counting/allocation routines.
165 165 * cf. crget()/crhold()/crfree().
166 166 */
167 167 devplcy_t *
168 168 dpget(void)
169 169 {
170 170 devplcy_t *dp = kmem_zalloc(sizeof (*dp), KM_SLEEP);
171 171
172 172 ASSERT(MUTEX_HELD(&policymutex));
173 173
↓ open down ↓ |
173 lines elided |
↑ open up ↑ |
174 174 dp->dp_ref = 1;
175 175 /* New ones belong to the next generation */
176 176 dp->dp_gen = devplcy_gen + 1;
177 177 return (dp);
178 178 }
179 179
180 180 void
181 181 dphold(devplcy_t *dp)
182 182 {
183 183 ASSERT(dp->dp_ref != 0xdeadbeef && dp->dp_ref != 0);
184 - atomic_add_32(&dp->dp_ref, 1);
184 + atomic_inc_32(&dp->dp_ref);
185 185 }
186 186
187 187 void
188 188 dpfree(devplcy_t *dp)
189 189 {
190 190 ASSERT(dp->dp_ref != 0xdeadbeef && dp->dp_ref != 0);
191 - if (atomic_add_32_nv(&dp->dp_ref, -1) == 0)
191 + if (atomic_dec_32_nv(&dp->dp_ref) == 0)
192 192 kmem_free(dp, sizeof (*dp));
193 193 }
194 194
195 195 /*
196 196 * Find the policy that matches this device.
197 197 */
198 198 static devplcy_t *
199 199 match_policy(devplcyent_t *de, dev_t dev, vtype_t spec)
200 200 {
201 201 char *mname = NULL;
202 202 minor_t min = getminor(dev);
203 203
204 204 for (; de != NULL; de = de->dpe_next) {
205 205 if (de->dpe_flags & DPE_ALLMINOR)
206 206 break;
207 207
208 208 if (de->dpe_flags & DPE_EXPANDED) {
209 209 if (min >= de->dpe_lomin && min <= de->dpe_himin &&
210 210 spec == de->dpe_spec) {
211 211 break;
212 212 } else {
213 213 continue;
214 214 }
215 215 }
216 216
217 217 /*
218 218 * We now need the minor name to match string or
219 219 * simle regexp. Could we use csp->s_dip and not
220 220 * allocate a string here?
221 221 */
222 222 if (mname == NULL &&
223 223 ddi_lyr_get_minor_name(dev, spec, &mname) != DDI_SUCCESS)
224 224 /* mname can be set after the function fails */
225 225 return (dfltpolicy);
226 226
227 227 /* Simple wildcard, with only one ``*'' */
228 228 if (de->dpe_flags & DPE_WILDC) {
229 229 int plen = de->dpe_len - 1;
230 230 int slen = strlen(mname);
231 231 char *pp = de->dpe_expr;
232 232 char *sp = mname;
233 233
234 234 /* string must be at least as long as pattern w/o '*' */
235 235 if (slen < plen - 1)
236 236 continue;
237 237
238 238 /* skip prefix */
239 239 while (*pp == *sp && *pp != '\0') {
240 240 pp++;
241 241 sp++;
242 242 }
243 243 /* matched single '*' */
244 244 if (*pp == '\0')
245 245 if (*sp == '\0')
246 246 break;
247 247 else
248 248 continue;
249 249 if (*pp != '*')
250 250 continue;
251 251
252 252 pp++;
253 253 /*
254 254 * skip characters matched by '*': difference of
255 255 * length of s and length of pattern sans '*'
256 256 */
257 257 sp += slen - (plen - 1);
258 258 if (strcmp(pp, sp) == 0) /* match! */
259 259 break;
260 260
261 261 } else if (strcmp(de->dpe_expr, mname) == 0) {
262 262 /* Store minor number, if no contention */
263 263 if (rw_tryupgrade(&policyrw)) {
264 264 de->dpe_lomin = de->dpe_himin = min;
265 265 de->dpe_spec = spec;
266 266 de->dpe_flags |= DPE_EXPANDED;
267 267 }
268 268 break;
269 269 }
270 270
271 271 }
272 272
273 273 if (mname != NULL)
274 274 kmem_free(mname, strlen(mname) + 1);
275 275
276 276 return (de != NULL ? de->dpe_plcy : dfltpolicy);
277 277 }
278 278
279 279 static int
280 280 devpolicyent_bymajor(major_t maj)
281 281 {
282 282 int lo, hi;
283 283
284 284 ASSERT(RW_LOCK_HELD(&policyrw));
285 285
286 286 lo = 0;
287 287 hi = ntabent - 1;
288 288
289 289 /* Binary search for major number */
290 290 while (lo <= hi) {
291 291 int mid = (lo + hi) / 2;
292 292
293 293 if (devpolicy[mid].t_major == maj)
294 294 return (mid);
295 295 else if (maj < devpolicy[mid].t_major)
296 296 hi = mid - 1;
297 297 else
298 298 lo = mid + 1;
299 299 }
300 300 return (-1);
301 301 }
302 302
303 303 /*
304 304 * Returns held device policy for the specific device node.
305 305 * Note devfs_devpolicy returns with a hold on the policy.
306 306 */
307 307 devplcy_t *
308 308 devpolicy_find(vnode_t *vp)
309 309 {
310 310 dev_t dev = vp->v_rdev;
311 311 vtype_t spec = vp->v_type;
312 312 major_t maj = getmajor(dev);
313 313 int i;
314 314 devplcy_t *res;
315 315
316 316 if (maj == clone_major)
317 317 maj = getminor(dev);
318 318
319 319 rw_enter(&policyrw, RW_READER);
320 320
321 321 i = devpolicyent_bymajor(maj);
322 322
323 323 if (i != -1) {
324 324 res = match_policy(devpolicy[i].t_ent, dev, spec);
325 325 dphold(res);
326 326 } else if (devfs_devpolicy(vp, &res) != 0) {
327 327 res = NETWORK_DRV(maj) ? netpolicy : dfltpolicy;
328 328 dphold(res);
329 329 }
330 330
331 331 rw_exit(&policyrw);
332 332
333 333 return (res);
334 334 }
335 335
336 336 static devplcyent_t *
337 337 parse_policy(devplcysys_t *ds, devplcy_t *nullp, devplcy_t *defp)
338 338 {
339 339 devplcyent_t *de = kmem_zalloc(sizeof (*de), KM_SLEEP);
340 340 devplcy_t *np;
341 341
342 342 if (priv_isemptyset(&ds->dps_rdp) && priv_isemptyset(&ds->dps_wrp))
343 343 dphold(np = nullp);
344 344 else if (defp != nullp &&
345 345 priv_isequalset(&ds->dps_rdp, &defp->dp_rdp) &&
346 346 priv_isequalset(&ds->dps_wrp, &defp->dp_wrp))
347 347 dphold(np = defp);
348 348 else {
349 349 np = dpget();
350 350 np->dp_rdp = ds->dps_rdp;
351 351 np->dp_wrp = ds->dps_wrp;
352 352 }
353 353
354 354 if (ds->dps_minornm[0] != '\0') {
355 355 de->dpe_len = strlen(ds->dps_minornm) + 1;
356 356
357 357 if (strchr(ds->dps_minornm, '*') != NULL) {
358 358 if (de->dpe_len == 2) { /* "*\0" */
359 359 de->dpe_flags = DPE_ALLMINOR;
360 360 de->dpe_len = 0;
361 361 } else
362 362 de->dpe_flags = DPE_WILDC;
363 363 }
364 364 if (de->dpe_len != 0) {
365 365 de->dpe_expr = kmem_alloc(de->dpe_len, KM_SLEEP);
366 366 (void) strcpy(de->dpe_expr, ds->dps_minornm);
367 367 }
368 368 } else {
369 369 de->dpe_lomin = ds->dps_lomin;
370 370 de->dpe_himin = ds->dps_himin;
371 371 de->dpe_flags = DPE_EXPANDED;
372 372 de->dpe_spec = ds->dps_isblock ? VBLK : VCHR;
373 373 }
374 374 de->dpe_plcy = np;
375 375
376 376 ASSERT((de->dpe_flags & (DPE_ALLMINOR|DPE_EXPANDED)) ||
377 377 de->dpe_expr != NULL);
378 378
379 379 return (de);
380 380 }
381 381
382 382 static void
383 383 freechain(devplcyent_t *de)
384 384 {
385 385 devplcyent_t *dn;
386 386
387 387 do {
388 388 dn = de->dpe_next;
389 389 dpfree(de->dpe_plcy);
390 390 if (de->dpe_len != 0)
391 391 kmem_free(de->dpe_expr, de->dpe_len);
392 392 kmem_free(de, sizeof (*de));
393 393 de = dn;
394 394 } while (de != NULL);
395 395 }
396 396
397 397 /*
398 398 * Load the device policy.
399 399 * The device policy currently makes nu distinction between the
400 400 * block and characters devices; that is generally not a problem
401 401 * as the names of those devices cannot clash.
402 402 */
403 403 int
404 404 devpolicy_load(int nitems, size_t sz, devplcysys_t *uitmp)
405 405 {
406 406 int i, j;
407 407 int nmaj = 0;
408 408 major_t lastmajor;
409 409 devplcysys_t *items;
410 410 size_t mem;
411 411 major_t curmaj;
412 412 devplcyent_t **last, *de;
413 413
414 414 tableent_t *newpolicy, *oldpolicy;
415 415 devplcy_t *newnull, *newdflt, *oldnull, *olddflt;
416 416 int oldcnt;
417 417 int lastlen;
418 418 int lastwild;
419 419
420 420 #ifdef lint
421 421 /* Lint can't figure out that the "i == 1" test protects all */
422 422 lastlen = 0;
423 423 lastwild = 0;
424 424 lastmajor = 0;
425 425 #endif
426 426 /*
427 427 * The application must agree with the kernel on the size of each
428 428 * item; it must not exceed the maximum number and must be
429 429 * at least 1 item in size.
430 430 */
431 431 if (sz != sizeof (devplcysys_t) || nitems > maxdevpolicy || nitems < 1)
432 432 return (EINVAL);
433 433
434 434 mem = nitems * sz;
435 435
436 436 items = kmem_alloc(mem, KM_SLEEP);
437 437
438 438 if (copyin(uitmp, items, mem)) {
439 439 kmem_free(items, mem);
440 440 return (EFAULT);
441 441 }
442 442
443 443 /* Check for default policy, it must exist and be sorted first */
444 444 if (items[0].dps_maj != DEVPOLICY_DFLT_MAJ) {
445 445 kmem_free(items, mem);
446 446 return (EINVAL);
447 447 }
448 448
449 449 /*
450 450 * Application must deliver entries sorted.
451 451 * Sorted meaning here:
452 452 * In major number order
453 453 * For each major number, we first need to have the explicit
454 454 * entries, then the wild card entries, longest first.
455 455 */
456 456 for (i = 1; i < nitems; i++) {
457 457 int len, wild;
458 458 char *tmp;
459 459
460 460 curmaj = items[i].dps_maj;
461 461 len = strlen(items[i].dps_minornm);
462 462 wild = len > 0 &&
463 463 (tmp = strchr(items[i].dps_minornm, '*')) != NULL;
464 464
465 465 /* Another default major, string too long or too many ``*'' */
466 466 if (curmaj == DEVPOLICY_DFLT_MAJ ||
467 467 len >= sizeof (items[i].dps_minornm) ||
468 468 wild && strchr(tmp + 1, '*') != NULL) {
469 469 kmem_free(items, mem);
470 470 return (EINVAL);
471 471 }
472 472 if (i == 1 || lastmajor < curmaj) {
473 473 lastmajor = curmaj;
474 474 nmaj++;
475 475 } else if (lastmajor > curmaj || lastwild > wild ||
476 476 lastwild && lastlen < len) {
477 477 kmem_free(items, mem);
478 478 return (EINVAL);
479 479 }
480 480 lastlen = len;
481 481 lastwild = wild;
482 482 }
483 483
484 484 if (AU_AUDITING())
485 485 audit_devpolicy(nitems, items);
486 486
487 487 /*
488 488 * Parse the policy. We create an array for all major numbers
489 489 * and in each major number bucket we'll have a linked list of
490 490 * entries. Each item may contain either a lo,hi minor pair
491 491 * or a string/wild card matching a minor node.
492 492 */
493 493 if (nmaj > 0)
494 494 newpolicy = kmem_zalloc(nmaj * sizeof (tableent_t), KM_SLEEP);
495 495
496 496 /*
497 497 * We want to lock out concurrent updates but we don't want to
498 498 * lock out device opens while we still need to allocate memory.
499 499 * As soon as we allocate new devplcy_t's we commit to the next
500 500 * generation number, so we must lock out other updates from here.
501 501 */
502 502 mutex_enter(&policymutex);
503 503
504 504 /* New default and NULL policy */
505 505 newnull = dpget();
506 506
507 507 if (priv_isemptyset(&items[0].dps_rdp) &&
508 508 priv_isemptyset(&items[0].dps_wrp)) {
509 509 newdflt = newnull;
510 510 dphold(newdflt);
511 511 } else {
512 512 newdflt = dpget();
513 513 newdflt->dp_rdp = items[0].dps_rdp;
514 514 newdflt->dp_wrp = items[0].dps_wrp;
515 515 }
516 516
517 517 j = -1;
518 518
519 519 /* Userland made sure sorting was ok */
520 520 for (i = 1; i < nitems; i++) {
521 521 de = parse_policy(&items[i], newnull, newdflt);
522 522
523 523 if (j == -1 || curmaj != items[i].dps_maj) {
524 524 j++;
525 525 newpolicy[j].t_major = curmaj = items[i].dps_maj;
526 526 last = &newpolicy[j].t_ent;
527 527 }
528 528 *last = de;
529 529 last = &de->dpe_next;
530 530 }
531 531
532 532 /* Done parsing, throw away input */
533 533 kmem_free(items, mem);
534 534
535 535 /* Lock out all devpolicy_find()s */
536 536 rw_enter(&policyrw, RW_WRITER);
537 537
538 538 /* Install the new global data */
539 539 oldnull = nullpolicy;
540 540 nullpolicy = newnull;
541 541
542 542 olddflt = dfltpolicy;
543 543 dfltpolicy = newdflt;
544 544
545 545 oldcnt = ntabent;
546 546 ntabent = nmaj;
547 547
548 548 totitems = nitems;
549 549
550 550 oldpolicy = devpolicy;
551 551 devpolicy = newpolicy;
552 552
553 553 /* Force all calls by devpolicy_find() */
554 554 devplcy_gen++;
555 555
556 556 /* Reenable policy finds */
557 557 rw_exit(&policyrw);
558 558 mutex_exit(&policymutex);
559 559
560 560 /* Free old stuff */
561 561 if (oldcnt != 0) {
562 562 for (i = 0; i < oldcnt; i++)
563 563 freechain(oldpolicy[i].t_ent);
564 564 kmem_free(oldpolicy, oldcnt * sizeof (*oldpolicy));
565 565 }
566 566
567 567 dpfree(oldnull);
568 568 dpfree(olddflt);
569 569
570 570 return (0);
571 571 }
572 572
573 573 /*
574 574 * Get device policy: argument one is a pointer to an integer holding
575 575 * the number of items allocated for the 3rd argument; the size argument
576 576 * is a revision check between kernel and userland.
577 577 */
578 578 int
579 579 devpolicy_get(int *nitemp, size_t sz, devplcysys_t *uitmp)
580 580 {
581 581 int i;
582 582 devplcyent_t *de;
583 583 devplcysys_t *itmp;
584 584 int ind;
585 585 int nitems;
586 586 int err = 0;
587 587 size_t alloced;
588 588
589 589 if (sz != sizeof (devplcysys_t))
590 590 return (EINVAL);
591 591
592 592 if (copyin(nitemp, &nitems, sizeof (nitems)))
593 593 return (EFAULT);
594 594
595 595 rw_enter(&policyrw, RW_READER);
596 596
597 597 if (copyout(&totitems, nitemp, sizeof (totitems)))
598 598 err = EFAULT;
599 599 else if (nitems < totitems)
600 600 err = ENOMEM;
601 601
602 602 if (err != 0) {
603 603 rw_exit(&policyrw);
604 604 return (err);
605 605 }
606 606
607 607 alloced = totitems * sizeof (devplcysys_t);
608 608 itmp = kmem_zalloc(alloced, KM_SLEEP);
609 609
610 610 itmp[0].dps_rdp = dfltpolicy->dp_rdp;
611 611 itmp[0].dps_wrp = dfltpolicy->dp_wrp;
612 612 itmp[0].dps_maj = DEVPOLICY_DFLT_MAJ;
613 613
614 614 ind = 1;
615 615
616 616 for (i = 0; i < ntabent; i++) {
617 617 for (de = devpolicy[i].t_ent; de != NULL; de = de->dpe_next) {
618 618 itmp[ind].dps_maj = devpolicy[i].t_major;
619 619 itmp[ind].dps_rdp = de->dpe_plcy->dp_rdp;
620 620 itmp[ind].dps_wrp = de->dpe_plcy->dp_wrp;
621 621 if (de->dpe_len)
622 622 (void) strcpy(itmp[ind].dps_minornm,
623 623 de->dpe_expr);
624 624 else if (de->dpe_flags & DPE_ALLMINOR)
625 625 (void) strcpy(itmp[ind].dps_minornm, "*");
626 626 else {
627 627 itmp[ind].dps_lomin = de->dpe_lomin;
628 628 itmp[ind].dps_himin = de->dpe_himin;
629 629 itmp[ind].dps_isblock = de->dpe_spec == VBLK;
630 630 }
631 631 ind++;
632 632 }
633 633 }
634 634
635 635 rw_exit(&policyrw);
636 636
637 637 if (copyout(itmp, uitmp, alloced))
638 638 err = EFAULT;
639 639
640 640 kmem_free(itmp, alloced);
641 641 return (err);
642 642 }
643 643
644 644 /*
645 645 * Get device policy by device name.
646 646 * This is the implementation of MODGETDEVPOLICYBYNAME
647 647 */
648 648 int
649 649 devpolicy_getbyname(size_t sz, devplcysys_t *uitmp, char *devname)
650 650 {
651 651 devplcysys_t itm;
652 652 devplcy_t *plcy;
653 653 vtype_t spec;
654 654 vnode_t *vp;
655 655
656 656 if (sz != sizeof (devplcysys_t))
657 657 return (EINVAL);
658 658
659 659 if (lookupname(devname, UIO_USERSPACE, FOLLOW,
660 660 NULLVPP, &vp) != 0)
661 661 return (EINVAL);
662 662
663 663 spec = vp->v_type;
664 664 if (spec != VBLK && spec != VCHR) {
665 665 VN_RELE(vp);
666 666 return (EINVAL);
667 667 }
668 668
669 669 plcy = devpolicy_find(vp);
670 670 VN_RELE(vp);
671 671
672 672 bzero(&itm, sizeof (itm));
673 673
674 674 /* These are the only values of interest */
675 675 itm.dps_rdp = plcy->dp_rdp;
676 676 itm.dps_wrp = plcy->dp_wrp;
677 677
678 678 dpfree(plcy);
679 679
680 680 if (copyout(&itm, uitmp, sz))
681 681 return (EFAULT);
682 682 else
683 683 return (0);
684 684 }
685 685
686 686 static void
687 687 priv_str_to_set(const char *priv_name, priv_set_t *priv_set)
688 688 {
689 689 if (priv_name == NULL || strcmp(priv_name, "none") == 0) {
690 690 priv_emptyset(priv_set);
691 691 } else if (strcmp(priv_name, "all") == 0) {
692 692 priv_fillset(priv_set);
693 693 } else {
694 694 int priv;
695 695 priv = priv_getbyname(priv_name, PRIV_ALLOC);
696 696 if (priv < 0) {
697 697 cmn_err(CE_WARN, "fail to allocate privilege: %s",
698 698 priv_name);
699 699 return;
700 700 }
701 701 priv_emptyset(priv_set);
702 702 priv_addset(priv_set, priv);
703 703 }
704 704 }
705 705
706 706 /*
707 707 * Return device privileges by privilege name
708 708 * Called by ddi_create_priv_minor_node()
709 709 */
710 710 devplcy_t *
711 711 devpolicy_priv_by_name(const char *read_priv, const char *write_priv)
712 712 {
713 713 devplcy_t *dp;
714 714 mutex_enter(&policymutex);
715 715 dp = dpget();
716 716 mutex_exit(&policymutex);
717 717 priv_str_to_set(read_priv, &dp->dp_rdp);
718 718 priv_str_to_set(write_priv, &dp->dp_wrp);
719 719
720 720 return (dp);
721 721 }
↓ open down ↓ |
520 lines elided |
↑ open up ↑ |
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX