4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
22 * Copyright 2010 Sun Microsystems, Inc. All rights reserved.
23 * Use is subject to license terms.
27 * Device policy implementation.
29 * Maintains the device policy table and defines the lookup functions.
31 * The table contains one entry for each major device number; each
32 * major bucket has a list of minor number specific entries. First
33 * match gets it. Not even simple minor names are expanded as that
34 * would cause the device to be loaded. Non-wildcard entries are expanded
35 * on first match. Wildcard entries are matched each open but the actual
36 * policy is cached with the common snode, so the matching code will
37 * probably be called infrequently. The trivial wildcard ``*'' does
38 * not cause expensive string expansions and matches.
40 * When the policy is updated, the the generation count is increased;
41 * whenever a cached policy is used, the generation count is compared;
42 * if there's no match, the device policy is refreshed.
44 * The special policy "nullpolicy" is used to mean "no checking beyond DAC
45 * needed". It too will change when the policy is rev'ed to make sure
46 * that devices with nullpolicy are also refreshed.
48 * The special policy "dfltpolicy" is used for those devices with no
49 * matching policy. On boot, it is "all privileges required".
50 * This restriction on boot functions as a fail-safe; if no device policy
51 * is loaded a "no restriction policy" would lead to security problems that
52 * are not immediately noticable.
55 #include <sys/priv_impl.h>
56 #include <sys/policy.h>
57 #include <sys/atomic.h>
58 #include <sys/autoconf.h>
59 #include <sys/sysmacros.h>
60 #include <sys/systm.h>
61 #include <sys/vnode.h>
62 #include <sys/devpolicy.h>
65 #include <sys/ksynch.h>
66 #include <sys/errno.h>
67 #include <sys/sunddi.h>
69 #include <sys/fs/dv_node.h>
72 * Internal data structures definitions.
75 typedef struct devplcyent devplcyent_t
;
78 * The device policy entry; if there is an expression string, the
79 * minor numbers are not relevant. This is indicated by dpe_len > 0.
82 devplcyent_t
*dpe_next
; /* next entry in this list */
83 devplcy_t
*dpe_plcy
; /* policy for this entry */
84 char *dpe_expr
; /* expression matching minor mode */
85 int dpe_len
; /* size of allocated mem for expr */
86 uint32_t dpe_flags
; /* flags */
87 minor_t dpe_lomin
; /* expanded: low minor number */
88 minor_t dpe_himin
; /* expanded: high minor number */
89 vtype_t dpe_spec
; /* expanded: VBLK or VCHR */
92 #define DPE_WILDC 0x01 /* Expression has wildcard */
93 #define DPE_ALLMINOR 0x02 /* Matches all minor numbers */
94 #define DPE_EXPANDED 0x04 /* Minor numbers expanded */
96 typedef struct tableent
{
97 devplcyent_t
*t_ent
; /* list of policies by minor */
98 major_t t_major
; /* device major number */
105 static int ntabent
; /* # of major numbers */
106 static int totitems
; /* Number of entries in all buckets + dflt */
107 static tableent_t
*devpolicy
; /* The device policy itself */
109 static krwlock_t policyrw
; /* protects the table */
110 static kmutex_t policymutex
; /* allows only one concurrent devpolicy_load */
112 devplcy_t
*nullpolicy
; /* public because it's used for shortcuts */
113 static devplcy_t
*dfltpolicy
;
114 static devplcy_t
*netpolicy
;
117 * Device policy generation count; only device policies matching the
118 * generation count are still valid.
120 volatile uint32_t devplcy_gen
;
123 * Tunable: maximum number of device policy entries to load in
124 * a system call. (Protects KM_SLEEP call)
126 int maxdevpolicy
= MAXDEVPOLICY
;
129 * Initialize the device policy code
134 rw_init(&policyrw
, NULL
, RW_DRIVER
, NULL
);
135 mutex_init(&policymutex
, NULL
, MUTEX_DRIVER
, NULL
);
137 /* The mutex is held here in order to satisfy the ASSERT in dpget() */
138 mutex_enter(&policymutex
);
140 nullpolicy
= dpget();
141 dfltpolicy
= dpget();
145 * Initially, we refuse access to all devices except
146 * to processes with all privileges.
148 priv_fillset(&dfltpolicy
->dp_rdp
);
149 priv_fillset(&dfltpolicy
->dp_wrp
);
154 mutex_exit(&policymutex
);
156 /* initialize default network privilege */
157 priv_emptyset(&netpolicy
->dp_rdp
);
158 priv_emptyset(&netpolicy
->dp_wrp
);
159 priv_addset(&netpolicy
->dp_rdp
, PRIV_NET_RAWACCESS
);
160 priv_addset(&netpolicy
->dp_wrp
, PRIV_NET_RAWACCESS
);
164 * Devpolicy reference counting/allocation routines.
165 * cf. crget()/crhold()/crfree().
170 devplcy_t
*dp
= kmem_zalloc(sizeof (*dp
), KM_SLEEP
);
172 ASSERT(MUTEX_HELD(&policymutex
));
175 /* New ones belong to the next generation */
176 dp
->dp_gen
= devplcy_gen
+ 1;
181 dphold(devplcy_t
*dp
)
183 ASSERT(dp
->dp_ref
!= 0xdeadbeef && dp
->dp_ref
!= 0);
184 atomic_inc_32(&dp
->dp_ref
);
188 dpfree(devplcy_t
*dp
)
190 ASSERT(dp
->dp_ref
!= 0xdeadbeef && dp
->dp_ref
!= 0);
191 if (atomic_dec_32_nv(&dp
->dp_ref
) == 0)
192 kmem_free(dp
, sizeof (*dp
));
196 * Find the policy that matches this device.
199 match_policy(devplcyent_t
*de
, dev_t dev
, vtype_t spec
)
202 minor_t min
= getminor(dev
);
204 for (; de
!= NULL
; de
= de
->dpe_next
) {
205 if (de
->dpe_flags
& DPE_ALLMINOR
)
208 if (de
->dpe_flags
& DPE_EXPANDED
) {
209 if (min
>= de
->dpe_lomin
&& min
<= de
->dpe_himin
&&
210 spec
== de
->dpe_spec
) {
218 * We now need the minor name to match string or
219 * simle regexp. Could we use csp->s_dip and not
220 * allocate a string here?
223 ddi_lyr_get_minor_name(dev
, spec
, &mname
) != DDI_SUCCESS
)
224 /* mname can be set after the function fails */
227 /* Simple wildcard, with only one ``*'' */
228 if (de
->dpe_flags
& DPE_WILDC
) {
229 int plen
= de
->dpe_len
- 1;
230 int slen
= strlen(mname
);
231 char *pp
= de
->dpe_expr
;
234 /* string must be at least as long as pattern w/o '*' */
239 while (*pp
== *sp
&& *pp
!= '\0') {
243 /* matched single '*' */
254 * skip characters matched by '*': difference of
255 * length of s and length of pattern sans '*'
257 sp
+= slen
- (plen
- 1);
258 if (strcmp(pp
, sp
) == 0) /* match! */
261 } else if (strcmp(de
->dpe_expr
, mname
) == 0) {
262 /* Store minor number, if no contention */
263 if (rw_tryupgrade(&policyrw
)) {
264 de
->dpe_lomin
= de
->dpe_himin
= min
;
266 de
->dpe_flags
|= DPE_EXPANDED
;
274 kmem_free(mname
, strlen(mname
) + 1);
276 return (de
!= NULL
? de
->dpe_plcy
: dfltpolicy
);
280 devpolicyent_bymajor(major_t maj
)
284 ASSERT(RW_LOCK_HELD(&policyrw
));
289 /* Binary search for major number */
291 int mid
= (lo
+ hi
) / 2;
293 if (devpolicy
[mid
].t_major
== maj
)
295 else if (maj
< devpolicy
[mid
].t_major
)
304 * Returns held device policy for the specific device node.
305 * Note devfs_devpolicy returns with a hold on the policy.
308 devpolicy_find(vnode_t
*vp
)
310 dev_t dev
= vp
->v_rdev
;
311 vtype_t spec
= vp
->v_type
;
312 major_t maj
= getmajor(dev
);
316 if (maj
== clone_major
)
319 rw_enter(&policyrw
, RW_READER
);
321 i
= devpolicyent_bymajor(maj
);
324 res
= match_policy(devpolicy
[i
].t_ent
, dev
, spec
);
326 } else if (devfs_devpolicy(vp
, &res
) != 0) {
327 res
= NETWORK_DRV(maj
) ? netpolicy
: dfltpolicy
;
336 static devplcyent_t
*
337 parse_policy(devplcysys_t
*ds
, devplcy_t
*nullp
, devplcy_t
*defp
)
339 devplcyent_t
*de
= kmem_zalloc(sizeof (*de
), KM_SLEEP
);
342 if (priv_isemptyset(&ds
->dps_rdp
) && priv_isemptyset(&ds
->dps_wrp
))
344 else if (defp
!= nullp
&&
345 priv_isequalset(&ds
->dps_rdp
, &defp
->dp_rdp
) &&
346 priv_isequalset(&ds
->dps_wrp
, &defp
->dp_wrp
))
350 np
->dp_rdp
= ds
->dps_rdp
;
351 np
->dp_wrp
= ds
->dps_wrp
;
354 if (ds
->dps_minornm
[0] != '\0') {
355 de
->dpe_len
= strlen(ds
->dps_minornm
) + 1;
357 if (strchr(ds
->dps_minornm
, '*') != NULL
) {
358 if (de
->dpe_len
== 2) { /* "*\0" */
359 de
->dpe_flags
= DPE_ALLMINOR
;
362 de
->dpe_flags
= DPE_WILDC
;
364 if (de
->dpe_len
!= 0) {
365 de
->dpe_expr
= kmem_alloc(de
->dpe_len
, KM_SLEEP
);
366 (void) strcpy(de
->dpe_expr
, ds
->dps_minornm
);
369 de
->dpe_lomin
= ds
->dps_lomin
;
370 de
->dpe_himin
= ds
->dps_himin
;
371 de
->dpe_flags
= DPE_EXPANDED
;
372 de
->dpe_spec
= ds
->dps_isblock
? VBLK
: VCHR
;
376 ASSERT((de
->dpe_flags
& (DPE_ALLMINOR
|DPE_EXPANDED
)) ||
377 de
->dpe_expr
!= NULL
);
383 freechain(devplcyent_t
*de
)
389 dpfree(de
->dpe_plcy
);
390 if (de
->dpe_len
!= 0)
391 kmem_free(de
->dpe_expr
, de
->dpe_len
);
392 kmem_free(de
, sizeof (*de
));
394 } while (de
!= NULL
);
398 * Load the device policy.
399 * The device policy currently makes nu distinction between the
400 * block and characters devices; that is generally not a problem
401 * as the names of those devices cannot clash.
404 devpolicy_load(int nitems
, size_t sz
, devplcysys_t
*uitmp
)
412 devplcyent_t
**last
, *de
;
414 tableent_t
*newpolicy
, *oldpolicy
;
415 devplcy_t
*newnull
, *newdflt
, *oldnull
, *olddflt
;
421 * The application must agree with the kernel on the size of each
422 * item; it must not exceed the maximum number and must be
423 * at least 1 item in size.
425 if (sz
!= sizeof (devplcysys_t
) || nitems
> maxdevpolicy
|| nitems
< 1)
430 items
= kmem_alloc(mem
, KM_SLEEP
);
432 if (copyin(uitmp
, items
, mem
)) {
433 kmem_free(items
, mem
);
437 /* Check for default policy, it must exist and be sorted first */
438 if (items
[0].dps_maj
!= DEVPOLICY_DFLT_MAJ
) {
439 kmem_free(items
, mem
);
444 * Application must deliver entries sorted.
445 * Sorted meaning here:
446 * In major number order
447 * For each major number, we first need to have the explicit
448 * entries, then the wild card entries, longest first.
450 for (i
= 1; i
< nitems
; i
++) {
454 curmaj
= items
[i
].dps_maj
;
455 len
= strlen(items
[i
].dps_minornm
);
457 (tmp
= strchr(items
[i
].dps_minornm
, '*')) != NULL
;
459 /* Another default major, string too long or too many ``*'' */
460 if (curmaj
== DEVPOLICY_DFLT_MAJ
||
461 len
>= sizeof (items
[i
].dps_minornm
) ||
462 wild
&& strchr(tmp
+ 1, '*') != NULL
) {
463 kmem_free(items
, mem
);
466 if (i
== 1 || lastmajor
< curmaj
) {
469 } else if (lastmajor
> curmaj
|| lastwild
> wild
||
470 lastwild
&& lastlen
< len
) {
471 kmem_free(items
, mem
);
479 audit_devpolicy(nitems
, items
);
482 * Parse the policy. We create an array for all major numbers
483 * and in each major number bucket we'll have a linked list of
484 * entries. Each item may contain either a lo,hi minor pair
485 * or a string/wild card matching a minor node.
488 newpolicy
= kmem_zalloc(nmaj
* sizeof (tableent_t
), KM_SLEEP
);
491 * We want to lock out concurrent updates but we don't want to
492 * lock out device opens while we still need to allocate memory.
493 * As soon as we allocate new devplcy_t's we commit to the next
494 * generation number, so we must lock out other updates from here.
496 mutex_enter(&policymutex
);
498 /* New default and NULL policy */
501 if (priv_isemptyset(&items
[0].dps_rdp
) &&
502 priv_isemptyset(&items
[0].dps_wrp
)) {
507 newdflt
->dp_rdp
= items
[0].dps_rdp
;
508 newdflt
->dp_wrp
= items
[0].dps_wrp
;
513 /* Userland made sure sorting was ok */
514 for (i
= 1; i
< nitems
; i
++) {
515 de
= parse_policy(&items
[i
], newnull
, newdflt
);
517 if (j
== -1 || curmaj
!= items
[i
].dps_maj
) {
519 newpolicy
[j
].t_major
= curmaj
= items
[i
].dps_maj
;
520 last
= &newpolicy
[j
].t_ent
;
523 last
= &de
->dpe_next
;
526 /* Done parsing, throw away input */
527 kmem_free(items
, mem
);
529 /* Lock out all devpolicy_find()s */
530 rw_enter(&policyrw
, RW_WRITER
);
532 /* Install the new global data */
533 oldnull
= nullpolicy
;
534 nullpolicy
= newnull
;
536 olddflt
= dfltpolicy
;
537 dfltpolicy
= newdflt
;
544 oldpolicy
= devpolicy
;
545 devpolicy
= newpolicy
;
547 /* Force all calls by devpolicy_find() */
550 /* Reenable policy finds */
552 mutex_exit(&policymutex
);
556 for (i
= 0; i
< oldcnt
; i
++)
557 freechain(oldpolicy
[i
].t_ent
);
558 kmem_free(oldpolicy
, oldcnt
* sizeof (*oldpolicy
));
568 * Get device policy: argument one is a pointer to an integer holding
569 * the number of items allocated for the 3rd argument; the size argument
570 * is a revision check between kernel and userland.
573 devpolicy_get(int *nitemp
, size_t sz
, devplcysys_t
*uitmp
)
583 if (sz
!= sizeof (devplcysys_t
))
586 if (copyin(nitemp
, &nitems
, sizeof (nitems
)))
589 rw_enter(&policyrw
, RW_READER
);
591 if (copyout(&totitems
, nitemp
, sizeof (totitems
)))
593 else if (nitems
< totitems
)
601 alloced
= totitems
* sizeof (devplcysys_t
);
602 itmp
= kmem_zalloc(alloced
, KM_SLEEP
);
604 itmp
[0].dps_rdp
= dfltpolicy
->dp_rdp
;
605 itmp
[0].dps_wrp
= dfltpolicy
->dp_wrp
;
606 itmp
[0].dps_maj
= DEVPOLICY_DFLT_MAJ
;
610 for (i
= 0; i
< ntabent
; i
++) {
611 for (de
= devpolicy
[i
].t_ent
; de
!= NULL
; de
= de
->dpe_next
) {
612 itmp
[ind
].dps_maj
= devpolicy
[i
].t_major
;
613 itmp
[ind
].dps_rdp
= de
->dpe_plcy
->dp_rdp
;
614 itmp
[ind
].dps_wrp
= de
->dpe_plcy
->dp_wrp
;
616 (void) strcpy(itmp
[ind
].dps_minornm
,
618 else if (de
->dpe_flags
& DPE_ALLMINOR
)
619 (void) strcpy(itmp
[ind
].dps_minornm
, "*");
621 itmp
[ind
].dps_lomin
= de
->dpe_lomin
;
622 itmp
[ind
].dps_himin
= de
->dpe_himin
;
623 itmp
[ind
].dps_isblock
= de
->dpe_spec
== VBLK
;
631 if (copyout(itmp
, uitmp
, alloced
))
634 kmem_free(itmp
, alloced
);
639 * Get device policy by device name.
640 * This is the implementation of MODGETDEVPOLICYBYNAME
643 devpolicy_getbyname(size_t sz
, devplcysys_t
*uitmp
, char *devname
)
650 if (sz
!= sizeof (devplcysys_t
))
653 if (lookupname(devname
, UIO_USERSPACE
, FOLLOW
,
658 if (spec
!= VBLK
&& spec
!= VCHR
) {
663 plcy
= devpolicy_find(vp
);
666 bzero(&itm
, sizeof (itm
));
668 /* These are the only values of interest */
669 itm
.dps_rdp
= plcy
->dp_rdp
;
670 itm
.dps_wrp
= plcy
->dp_wrp
;
674 if (copyout(&itm
, uitmp
, sz
))
681 priv_str_to_set(const char *priv_name
, priv_set_t
*priv_set
)
683 if (priv_name
== NULL
|| strcmp(priv_name
, "none") == 0) {
684 priv_emptyset(priv_set
);
685 } else if (strcmp(priv_name
, "all") == 0) {
686 priv_fillset(priv_set
);
689 priv
= priv_getbyname(priv_name
, PRIV_ALLOC
);
691 cmn_err(CE_WARN
, "fail to allocate privilege: %s",
695 priv_emptyset(priv_set
);
696 priv_addset(priv_set
, priv
);
701 * Return device privileges by privilege name
702 * Called by ddi_create_priv_minor_node()
705 devpolicy_priv_by_name(const char *read_priv
, const char *write_priv
)
708 mutex_enter(&policymutex
);
710 mutex_exit(&policymutex
);
711 priv_str_to_set(read_priv
, &dp
->dp_rdp
);
712 priv_str_to_set(write_priv
, &dp
->dp_wrp
);