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 2006 Sun Microsystems, Inc. All rights reserved.
23 * Use is subject to license terms.
26 #pragma ident "%Z%%M% %I% %E% SMI"
28 #include <sys/systm.h>
29 #include <sys/types.h>
30 #include <sys/stream.h>
32 #include <sys/strsubr.h>
33 #include <sys/cmn_err.h>
34 #include <sys/debug.h>
35 #include <sys/param.h>
36 #include <sys/model.h>
37 #include <sys/errno.h>
38 #include <sys/modhash.h>
40 #include <sys/policy.h>
41 #include <sys/tsol/label.h>
42 #include <sys/tsol/tsyscall.h>
43 #include <sys/tsol/tndb.h>
44 #include <sys/tsol/tnet.h>
51 static mod_hash_t
*tpc_name_hash
; /* hash of cache entries by name */
52 static kmutex_t tpc_lock
;
54 static tsol_tpc_t
*tpc_unlab
;
57 * tnrhc_table and tnrhc_table_v6 are similar to the IP forwarding tables
58 * in organization and search. The tnrhc_table[_v6] is an array of 33/129
59 * pointers to the 33/129 tnrhc tables indexed by the prefix length.
60 * A largest prefix match search is done by find_rhc and it walks the
61 * tables from the most specific to the least specific table. Table 0
62 * corresponds to the single entry for 0.0.0.0/0 or ::0/0.
64 tnrhc_hash_t
*tnrhc_table
[TSOL_MASK_TABLE_SIZE
];
65 tnrhc_hash_t
*tnrhc_table_v6
[TSOL_MASK_TABLE_SIZE_V6
];
66 kmutex_t tnrhc_g_lock
;
68 static void tsol_create_i_tmpls(void);
70 static void tsol_create_i_tnrh(const tnaddr_t
*);
72 /* List of MLPs on valid on shared addresses */
73 static tsol_mlp_list_t shared_mlps
;
76 * Convert length for a mask to the mask.
79 tsol_plen_to_mask(uint_t masklen
)
81 return (masklen
== 0 ? 0 : htonl(IP_HOST_MASK
<< (IP_ABITS
- masklen
)));
85 * Convert a prefix length to the mask for that prefix.
86 * Returns the argument bitmask.
89 tsol_plen_to_mask_v6(uint_t plen
, in6_addr_t
*bitmask
)
93 ASSERT(plen
<= IPV6_ABITS
);
95 ptr
= (uint32_t *)bitmask
;
101 *ptr
++ = htonl(0xffffffff << (32 - plen
));
102 while (ptr
< (uint32_t *)(bitmask
+ 1))
107 tnrhc_init_table(tnrhc_hash_t
*table
[], short prefix_len
, int kmflag
)
111 mutex_enter(&tnrhc_g_lock
);
113 if (table
[prefix_len
] == NULL
) {
114 table
[prefix_len
] = (tnrhc_hash_t
*)
115 kmem_zalloc(TNRHC_SIZE
* sizeof (tnrhc_hash_t
), kmflag
);
116 if (table
[prefix_len
] == NULL
) {
117 mutex_exit(&tnrhc_g_lock
);
120 for (i
= 0; i
< TNRHC_SIZE
; i
++) {
121 mutex_init(&table
[prefix_len
][i
].tnrh_lock
,
122 NULL
, MUTEX_DEFAULT
, 0);
125 mutex_exit(&tnrhc_g_lock
);
135 * Note: unable to use mod_hash_create_strhash here, since it's
136 * assymetric. It assumes that the user has allocated exactly
137 * strlen(key) + 1 bytes for the key when inserted, and attempts to
138 * kmem_free that memory on a delete.
140 tpc_name_hash
= mod_hash_create_extended("tnrhtpc_by_name", 256,
141 mod_hash_null_keydtor
, mod_hash_null_valdtor
, mod_hash_bystr
,
142 NULL
, mod_hash_strkey_cmp
, KM_SLEEP
);
143 mutex_init(&tpc_lock
, NULL
, MUTEX_DEFAULT
, NULL
);
145 mutex_init(&tnrhc_g_lock
, NULL
, MUTEX_DEFAULT
, NULL
);
147 /* label_init always called before tcache_init */
148 ASSERT(l_admin_low
!= NULL
&& l_admin_high
!= NULL
);
150 /* Initialize the zeroth table prior to loading the 0.0.0.0 entry */
151 (void) tnrhc_init_table(tnrhc_table
, 0, KM_SLEEP
);
152 (void) tnrhc_init_table(tnrhc_table_v6
, 0, KM_SLEEP
);
154 * create an internal host template called "_unlab"
156 tsol_create_i_tmpls();
159 * create a host entry, 0.0.0.0 = _unlab
161 bzero(&address
, sizeof (tnaddr_t
));
162 address
.ta_family
= AF_INET
;
163 tsol_create_i_tnrh(&address
);
166 * create a host entry, ::0 = _unlab
168 address
.ta_family
= AF_INET6
;
169 tsol_create_i_tnrh(&address
);
171 rw_init(&shared_mlps
.mlpl_rwlock
, NULL
, RW_DEFAULT
, NULL
);
174 /* Called only by the TNRHC_RELE macro when the refcount goes to zero. */
176 tnrhc_free(tsol_tnrhc_t
*tnrhc
)
179 * We assert rhc_invalid here to make sure that no new thread could
180 * possibly end up finding this entry. If it could, then the
181 * mutex_destroy would panic.
183 DTRACE_PROBE1(tx__tndb__l3__tnrhcfree
, tsol_tnrhc_t
*, tnrhc
);
184 ASSERT(tnrhc
->rhc_next
== NULL
&& tnrhc
->rhc_invalid
);
185 mutex_exit(&tnrhc
->rhc_lock
);
186 mutex_destroy(&tnrhc
->rhc_lock
);
187 if (tnrhc
->rhc_tpc
!= NULL
)
188 TPC_RELE(tnrhc
->rhc_tpc
);
189 kmem_free(tnrhc
, sizeof (*tnrhc
));
192 /* Called only by the TPC_RELE macro when the refcount goes to zero. */
194 tpc_free(tsol_tpc_t
*tpc
)
196 DTRACE_PROBE1(tx__tndb__l3__tpcfree
, tsol_tpc_t
*, tpc
);
197 ASSERT(tpc
->tpc_invalid
);
198 mutex_exit(&tpc
->tpc_lock
);
199 mutex_destroy(&tpc
->tpc_lock
);
200 kmem_free(tpc
, sizeof (*tpc
));
204 * Find and hold a reference to a template entry by name. Ignores entries that
208 tnrhtp_find(const char *name
, mod_hash_t
*hash
)
211 tsol_tpc_t
*tpc
= NULL
;
213 mutex_enter(&tpc_lock
);
214 if (mod_hash_find(hash
, (mod_hash_key_t
)name
, &hv
) == 0) {
215 tpc
= (tsol_tpc_t
*)hv
;
216 if (tpc
->tpc_invalid
)
221 mutex_exit(&tpc_lock
);
226 tnrh_delete(const tsol_rhent_t
*rhent
)
228 tsol_tnrhc_t
*current
;
229 tsol_tnrhc_t
**prevp
;
231 in6_addr_t tmpmask_v6
;
232 tnrhc_hash_t
*tnrhc_hash
;
234 if (rhent
->rh_address
.ta_family
== AF_INET
) {
235 if (rhent
->rh_prefix
< 0 || rhent
->rh_prefix
> IP_ABITS
)
237 if (tnrhc_table
[rhent
->rh_prefix
] == NULL
)
239 tmpmask
= tsol_plen_to_mask(rhent
->rh_prefix
);
240 tnrhc_hash
= &tnrhc_table
[rhent
->rh_prefix
][
241 TSOL_ADDR_HASH(rhent
->rh_address
.ta_addr_v4
.s_addr
&
242 tmpmask
, TNRHC_SIZE
)];
243 } else if (rhent
->rh_address
.ta_family
== AF_INET6
) {
244 if (rhent
->rh_prefix
< 0 || rhent
->rh_prefix
> IPV6_ABITS
)
246 if (tnrhc_table_v6
[rhent
->rh_prefix
] == NULL
)
248 tsol_plen_to_mask_v6(rhent
->rh_prefix
, &tmpmask_v6
);
249 tnrhc_hash
= &tnrhc_table_v6
[rhent
->rh_prefix
][
250 TSOL_ADDR_MASK_HASH_V6(rhent
->rh_address
.ta_addr_v6
,
251 tmpmask_v6
, TNRHC_SIZE
)];
253 return (EAFNOSUPPORT
);
256 /* search for existing entry */
257 mutex_enter(&tnrhc_hash
->tnrh_lock
);
258 prevp
= &tnrhc_hash
->tnrh_list
;
259 while ((current
= *prevp
) != NULL
) {
260 if (TNADDR_EQ(&rhent
->rh_address
, ¤t
->rhc_host
))
262 prevp
= ¤t
->rhc_next
;
265 if (current
!= NULL
) {
266 DTRACE_PROBE(tx__tndb__l2__tnrhdelete_existingrhentry
);
267 *prevp
= current
->rhc_next
;
268 mutex_enter(¤t
->rhc_lock
);
269 current
->rhc_next
= NULL
;
270 current
->rhc_invalid
= 1;
271 mutex_exit(¤t
->rhc_lock
);
274 mutex_exit(&tnrhc_hash
->tnrh_lock
);
275 return (current
== NULL
? ENOENT
: 0);
279 * Flush all remote host entries from the database.
281 * Note that the htable arrays themselves do not have reference counters, so,
282 * unlike the remote host entries, they cannot be freed.
285 flush_rh_table(tnrhc_hash_t
**htable
, int nbits
)
287 tnrhc_hash_t
*hent
, *hend
;
288 tsol_tnrhc_t
*rhc
, *rhnext
;
290 while (--nbits
>= 0) {
291 if ((hent
= htable
[nbits
]) == NULL
)
293 hend
= hent
+ TNRHC_SIZE
;
294 while (hent
< hend
) {
296 * List walkers hold this lock during the walk. It
297 * protects tnrh_list and rhc_next.
299 mutex_enter(&hent
->tnrh_lock
);
300 rhnext
= hent
->tnrh_list
;
301 hent
->tnrh_list
= NULL
;
302 mutex_exit(&hent
->tnrh_lock
);
304 * There may still be users of the rhcs at this point,
305 * but not of the list or its next pointer. Thus, the
306 * only thing that would need to be done under a lock
307 * is setting the invalid bit, but that's atomic
308 * anyway, so no locks needed here.
310 while ((rhc
= rhnext
) != NULL
) {
311 rhnext
= rhc
->rhc_next
;
312 rhc
->rhc_next
= NULL
;
313 rhc
->rhc_invalid
= 1;
322 * Load a remote host entry into kernel cache. Create a new one if a matching
323 * entry isn't found, otherwise replace the contents of the previous one by
324 * deleting it and recreating it. (Delete and recreate is used to avoid
325 * allowing other threads to see an unstable data structure.)
327 * A "matching" entry is the one whose address matches that of the one
330 * Return 0 for success, error code for failure.
333 tnrh_hash_add(tsol_tnrhc_t
*new, short prefix
)
338 in6_addr_t tmpmask_v6
;
339 tnrhc_hash_t
*tnrhc_hash
;
341 /* Find the existing entry, if any, leaving the hash locked */
342 if (new->rhc_host
.ta_family
== AF_INET
) {
343 if (prefix
< 0 || prefix
> IP_ABITS
)
345 if (tnrhc_table
[prefix
] == NULL
&&
346 !tnrhc_init_table(tnrhc_table
, prefix
,
349 tmpmask
= tsol_plen_to_mask(prefix
);
350 tnrhc_hash
= &tnrhc_table
[prefix
][
351 TSOL_ADDR_HASH(new->rhc_host
.ta_addr_v4
.s_addr
&
352 tmpmask
, TNRHC_SIZE
)];
353 mutex_enter(&tnrhc_hash
->tnrh_lock
);
354 for (rhp
= &tnrhc_hash
->tnrh_list
; (rh
= *rhp
) != NULL
;
355 rhp
= &rh
->rhc_next
) {
356 ASSERT(rh
->rhc_host
.ta_family
== AF_INET
);
357 if (((rh
->rhc_host
.ta_addr_v4
.s_addr
^
358 new->rhc_host
.ta_addr_v4
.s_addr
) & tmpmask
) ==
362 } else if (new->rhc_host
.ta_family
== AF_INET6
) {
363 if (prefix
< 0 || prefix
> IPV6_ABITS
)
365 if (tnrhc_table_v6
[prefix
] == NULL
&&
366 !tnrhc_init_table(tnrhc_table_v6
, prefix
,
369 tsol_plen_to_mask_v6(prefix
, &tmpmask_v6
);
370 tnrhc_hash
= &tnrhc_table_v6
[prefix
][
371 TSOL_ADDR_MASK_HASH_V6(new->rhc_host
.ta_addr_v6
,
372 tmpmask_v6
, TNRHC_SIZE
)];
373 mutex_enter(&tnrhc_hash
->tnrh_lock
);
374 for (rhp
= &tnrhc_hash
->tnrh_list
; (rh
= *rhp
) != NULL
;
375 rhp
= &rh
->rhc_next
) {
376 ASSERT(rh
->rhc_host
.ta_family
== AF_INET6
);
377 if (V6_MASK_EQ_2(rh
->rhc_host
.ta_addr_v6
, tmpmask_v6
,
378 new->rhc_host
.ta_addr_v6
))
382 return (EAFNOSUPPORT
);
385 /* Clobber the old remote host entry. */
387 ASSERT(!rh
->rhc_invalid
);
391 DTRACE_PROBE1(tx__tndb__l2__tnrhhashadd__invalidaterh
,
397 new->rhc_next
= tnrhc_hash
->tnrh_list
;
398 tnrhc_hash
->tnrh_list
= new;
399 DTRACE_PROBE1(tx__tndb__l2__tnrhhashadd__addedrh
, tsol_tnrhc_t
*, new);
400 mutex_exit(&tnrhc_hash
->tnrh_lock
);
406 * Load a remote host entry into kernel cache.
408 * Return 0 for success, error code for failure.
411 tnrh_load(const tsol_rhent_t
*rhent
)
417 /* Find and bump the reference count on the named template */
418 if ((tpc
= tnrhtp_find(rhent
->rh_template
, tpc_name_hash
)) == NULL
) {
421 ASSERT(tpc
->tpc_tp
.host_type
== UNLABELED
||
422 tpc
->tpc_tp
.host_type
== SUN_CIPSO
);
424 if ((new = kmem_zalloc(sizeof (*new), KM_NOSLEEP
)) == NULL
) {
429 /* Initialize the new entry. */
430 mutex_init(&new->rhc_lock
, NULL
, MUTEX_DEFAULT
, NULL
);
431 new->rhc_host
= rhent
->rh_address
;
433 /* The rhc now owns this tpc reference, so no TPC_RELE past here */
437 * tnrh_hash_add handles the tnrh entry ref count for hash
438 * table inclusion. The ref count is incremented and decremented
439 * here to trigger deletion of the new hash table entry in the
440 * event that tnrh_hash_add fails.
443 status
= tnrh_hash_add(new, rhent
->rh_prefix
);
450 tnrh_get(tsol_rhent_t
*rhent
)
454 switch (rhent
->rh_address
.ta_family
) {
456 tpc
= find_tpc(&rhent
->rh_address
.ta_addr_v4
, IPV4_VERSION
,
461 tpc
= find_tpc(&rhent
->rh_address
.ta_addr_v6
, IPV6_VERSION
,
471 DTRACE_PROBE2(tx__tndb__l4__tnrhget__foundtpc
, tsol_rhent_t
*,
472 rhent
, tsol_tpc_t
*, tpc
);
473 bcopy(tpc
->tpc_tp
.name
, rhent
->rh_template
,
474 sizeof (rhent
->rh_template
));
480 template_name_ok(const char *name
)
482 const char *name_end
= name
+ TNTNAMSIZ
;
484 while (name
< name_end
) {
489 return (name
< name_end
);
493 tnrh(int cmd
, void *buf
)
498 /* Make sure user has sufficient privilege */
499 if (cmd
!= TNDB_GET
&&
500 (retv
= secpolicy_net_config(CRED(), B_FALSE
)) != 0)
501 return (set_errno(retv
));
506 if (cmd
!= TNDB_FLUSH
&&
507 copyin(buf
, &rhent
, sizeof (rhent
)) != 0) {
508 DTRACE_PROBE(tx__tndb__l0__tnrhdelete__copyin
);
509 return (set_errno(EFAULT
));
514 DTRACE_PROBE(tx__tndb__l2__tnrhdelete__tndbload
);
515 if (!template_name_ok(rhent
.rh_template
)) {
518 retv
= tnrh_load(&rhent
);
523 DTRACE_PROBE(tx__tndb__l2__tnrhdelete__tndbdelete
);
524 retv
= tnrh_delete(&rhent
);
528 DTRACE_PROBE(tx__tndb__l4__tnrhdelete__tndbget
);
529 if (!template_name_ok(rhent
.rh_template
)) {
534 retv
= tnrh_get(&rhent
);
541 if (copyout(&rhent
, buf
, sizeof (rhent
)) != 0) {
542 DTRACE_PROBE(tx__tndb__l0__tnrhdelete__copyout
);
548 DTRACE_PROBE(tx__tndb__l2__tnrhdelete__flush
);
549 flush_rh_table(tnrhc_table
, TSOL_MASK_TABLE_SIZE
);
550 flush_rh_table(tnrhc_table_v6
, TSOL_MASK_TABLE_SIZE_V6
);
554 DTRACE_PROBE1(tx__tndb__l0__tnrhdelete__unknowncmd
,
561 return (set_errno(retv
));
567 tnrhtp_create(const tsol_tpent_t
*tpent
, int kmflags
)
573 * We intentionally allocate a new entry before taking the lock on the
576 if ((tpc
= kmem_zalloc(sizeof (*tpc
), kmflags
)) == NULL
)
579 mutex_enter(&tpc_lock
);
580 if (mod_hash_find(tpc_name_hash
, (mod_hash_key_t
)tpent
->name
,
582 tsol_tpc_t
*found_tpc
= (tsol_tpc_t
*)hv
;
584 found_tpc
->tpc_invalid
= 1;
585 (void) mod_hash_destroy(tpc_name_hash
,
586 (mod_hash_key_t
)tpent
->name
);
590 mutex_init(&tpc
->tpc_lock
, NULL
, MUTEX_DEFAULT
, NULL
);
591 /* tsol_tpent_t is the same on LP64 and ILP32 */
592 bcopy(tpent
, &tpc
->tpc_tp
, sizeof (tpc
->tpc_tp
));
593 (void) mod_hash_insert(tpc_name_hash
, (mod_hash_key_t
)tpc
->tpc_tp
.name
,
594 (mod_hash_val_t
)tpc
);
596 mutex_exit(&tpc_lock
);
602 tnrhtp_delete(const char *tname
)
608 mutex_enter(&tpc_lock
);
609 if (mod_hash_find(tpc_name_hash
, (mod_hash_key_t
)tname
, &hv
) == 0) {
610 tpc
= (tsol_tpc_t
*)hv
;
611 ASSERT(!tpc
->tpc_invalid
);
612 tpc
->tpc_invalid
= 1;
613 (void) mod_hash_destroy(tpc_name_hash
,
614 (mod_hash_key_t
)tpc
->tpc_tp
.name
);
618 mutex_exit(&tpc_lock
);
624 tpc_delete(mod_hash_key_t key
, mod_hash_val_t
*val
, void *arg
)
626 tsol_tpc_t
*tpc
= (tsol_tpc_t
*)val
;
628 ASSERT(!tpc
->tpc_invalid
);
629 tpc
->tpc_invalid
= 1;
631 return (MH_WALK_CONTINUE
);
637 mutex_enter(&tpc_lock
);
638 mod_hash_walk(tpc_name_hash
, tpc_delete
, NULL
);
639 mod_hash_clear(tpc_name_hash
);
640 mutex_exit(&tpc_lock
);
644 tnrhtp(int cmd
, void *buf
)
648 tsol_tpent_t rhtpent
;
651 /* Make sure user has sufficient privilege */
652 if (cmd
!= TNDB_GET
&&
653 (retv
= secpolicy_net_config(CRED(), B_FALSE
)) != 0)
654 return (set_errno(retv
));
657 * Get argument. Note that tsol_tpent_t is the same on LP64 and ILP32,
658 * so no special handling is required.
660 if (cmd
!= TNDB_FLUSH
) {
661 if (copyin(buf
, &rhtpent
, sizeof (rhtpent
)) != 0) {
662 DTRACE_PROBE(tx__tndb__l0__tnrhtp__copyin
);
663 return (set_errno(EFAULT
));
667 * Don't let the user give us a bogus (unterminated) template
670 if (!template_name_ok(rhtpent
.name
))
671 return (set_errno(EINVAL
));
676 DTRACE_PROBE1(tx__tndb__l2__tnrhtp__tndbload
, char *,
678 type
= rhtpent
.host_type
;
679 if (type
!= UNLABELED
&& type
!= SUN_CIPSO
) {
684 if (tnrhtp_create(&rhtpent
, KM_NOSLEEP
) == NULL
)
691 DTRACE_PROBE1(tx__tndb__l4__tnrhtp__tndbget
, char *,
693 tpc
= tnrhtp_find(rhtpent
.name
, tpc_name_hash
);
699 /* Copy out result */
700 if (copyout(&tpc
->tpc_tp
, buf
, sizeof (tpc
->tpc_tp
)) != 0) {
701 DTRACE_PROBE(tx__tndb__l0__tnrhtp__copyout
);
710 DTRACE_PROBE1(tx__tndb__l4__tnrhtp__tndbdelete
, char *,
712 retv
= tnrhtp_delete(rhtpent
.name
);
716 DTRACE_PROBE(tx__tndb__l4__tnrhtp__flush
);
722 DTRACE_PROBE1(tx__tndb__l0__tnrhtp__unknowncmd
, int,
729 return (set_errno(retv
));
735 * MLP entry ordering logic
737 * There are two loops in this routine. The first loop finds the entry that
738 * either logically follows the new entry to be inserted, or is the entry that
739 * precedes and overlaps the new entry, or is NULL to mean end-of-list. This
740 * is 'tme.' The second loop scans ahead from that point to find any overlap
741 * on the front or back of this new entry.
743 * For the first loop, we can have the following cases in the list (note that
744 * the port-portmax range is inclusive):
748 * 1: +------+ ................... precedes; skip to next
749 * 2: +------+ ............. overlaps; stop here if same protocol
750 * 3: +------+ ......... overlaps; stop if same or higher protocol
751 * 4: +-------+ .... overlaps or succeeds; stop here
753 * For the second loop, we can have the following cases (note that we need not
754 * care about other protocol entries at this point, because we're only looking
755 * for overlap, not an insertion point):
759 * 5: +------+ ............. overlaps; stop if same protocol
760 * 6: +------+ ......... overlaps; stop if same protocol
761 * 7: +-------+ .... overlaps; stop if same protocol
762 * 8: +---+ . follows; search is done
764 * In other words, this second search needs to consider only whether the entry
765 * has a starting port number that's greater than the end point of the new
766 * entry. All others are overlaps.
769 mlp_add_del(tsol_mlp_list_t
*mlpl
, zoneid_t zoneid
, uint8_t proto
,
770 uint16_t port
, uint16_t portmax
, boolean_t addflag
)
773 tsol_mlp_entry_t
*tme
, *tme2
, *newent
;
776 if ((newent
= kmem_zalloc(sizeof (*newent
), KM_NOSLEEP
)) ==
782 rw_enter(&mlpl
->mlpl_rwlock
, RW_WRITER
);
785 * First loop: find logical insertion point or overlap. Table is kept
786 * in order of port number first, and then, within that, by protocol
789 for (tme
= mlpl
->mlpl_first
; tme
!= NULL
; tme
= tme
->mlpe_next
) {
790 /* logically next (case 4) */
791 if (tme
->mlpe_mlp
.mlp_port
> port
)
793 /* if this is logically next or overlap, then stop (case 3) */
794 if (tme
->mlpe_mlp
.mlp_port
== port
&&
795 tme
->mlpe_mlp
.mlp_ipp
>= proto
)
797 /* earlier or same port sequence; check for overlap (case 2) */
798 if (tme
->mlpe_mlp
.mlp_ipp
== proto
&&
799 tme
->mlpe_mlp
.mlp_port_upper
>= port
)
801 /* otherwise, loop again (case 1) */
804 /* Second loop: scan ahead for overlap */
805 for (tme2
= tme
; tme2
!= NULL
; tme2
= tme2
->mlpe_next
) {
806 /* check if entry follows; no overlap (case 8) */
807 if (tme2
->mlpe_mlp
.mlp_port
> portmax
) {
811 /* only exact protocol matches at this point (cases 5-7) */
812 if (tme2
->mlpe_mlp
.mlp_ipp
== proto
)
821 newent
->mlpe_zoneid
= zoneid
;
822 newent
->mlpe_mlp
.mlp_ipp
= proto
;
823 newent
->mlpe_mlp
.mlp_port
= port
;
824 newent
->mlpe_mlp
.mlp_port_upper
= portmax
;
825 newent
->mlpe_next
= tme
;
827 tme2
= mlpl
->mlpl_last
;
828 mlpl
->mlpl_last
= newent
;
830 tme2
= tme
->mlpe_prev
;
831 tme
->mlpe_prev
= newent
;
833 newent
->mlpe_prev
= tme2
;
835 mlpl
->mlpl_first
= newent
;
837 tme2
->mlpe_next
= newent
;
841 if (tme2
== NULL
|| tme2
->mlpe_mlp
.mlp_port
!= port
||
842 tme2
->mlpe_mlp
.mlp_port_upper
!= portmax
) {
845 if ((tme2
= tme
->mlpe_prev
) == NULL
)
846 mlpl
->mlpl_first
= tme
->mlpe_next
;
848 tme2
->mlpe_next
= tme
->mlpe_next
;
849 if ((tme2
= tme
->mlpe_next
) == NULL
)
850 mlpl
->mlpl_last
= tme
->mlpe_prev
;
852 tme2
->mlpe_prev
= tme
->mlpe_prev
;
856 rw_exit(&mlpl
->mlpl_rwlock
);
859 kmem_free(newent
, sizeof (*newent
));
865 * Add or remove an MLP entry from the database so that the classifier can find
868 * Note: port number is in host byte order.
871 tsol_mlp_anon(zone_t
*zone
, mlp_type_t mlptype
, uchar_t proto
, uint16_t port
,
876 if (mlptype
== mlptBoth
|| mlptype
== mlptPrivate
)
877 retv
= mlp_add_del(&zone
->zone_mlps
, zone
->zone_id
, proto
,
878 port
, port
, addflag
);
879 if ((retv
== 0 || !addflag
) &&
880 (mlptype
== mlptBoth
|| mlptype
== mlptShared
)) {
881 retv
= mlp_add_del(&shared_mlps
, zone
->zone_id
, proto
, port
,
883 if (retv
!= 0 && addflag
)
884 (void) mlp_add_del(&zone
->zone_mlps
, zone
->zone_id
,
885 proto
, port
, port
, B_FALSE
);
891 mlp_flush(tsol_mlp_list_t
*mlpl
, zoneid_t zoneid
)
893 tsol_mlp_entry_t
*tme
, *tme2
, *tmnext
;
895 rw_enter(&mlpl
->mlpl_rwlock
, RW_WRITER
);
896 for (tme
= mlpl
->mlpl_first
; tme
!= NULL
; tme
= tmnext
) {
897 tmnext
= tme
->mlpe_next
;
898 if (zoneid
== ALL_ZONES
|| tme
->mlpe_zoneid
== zoneid
) {
899 if ((tme2
= tme
->mlpe_prev
) == NULL
)
900 mlpl
->mlpl_first
= tmnext
;
902 tme2
->mlpe_next
= tmnext
;
904 mlpl
->mlpl_last
= tme2
;
906 tmnext
->mlpe_prev
= tme2
;
907 kmem_free(tme
, sizeof (*tme
));
910 rw_exit(&mlpl
->mlpl_rwlock
);
914 * Note: user supplies port numbers in host byte order.
917 tnmlp(int cmd
, void *buf
)
922 tsol_mlp_list_t
*mlpl
;
923 tsol_mlp_entry_t
*tme
;
925 /* Make sure user has sufficient privilege */
926 if (cmd
!= TNDB_GET
&&
927 (retv
= secpolicy_net_config(CRED(), B_FALSE
)) != 0)
928 return (set_errno(retv
));
931 * Get argument. Note that tsol_mlpent_t is the same on LP64 and
932 * ILP32, so no special handling is required.
934 if (copyin(buf
, &tsme
, sizeof (tsme
)) != 0) {
935 DTRACE_PROBE(tx__tndb__l0__tnmlp__copyin
);
936 return (set_errno(EFAULT
));
939 /* MLPs on shared IP addresses */
940 if (tsme
.tsme_flags
& TSOL_MEF_SHARED
) {
944 zone
= zone_find_by_id(tsme
.tsme_zoneid
);
946 return (set_errno(EINVAL
));
947 mlpl
= &zone
->zone_mlps
;
949 if (tsme
.tsme_mlp
.mlp_port_upper
== 0)
950 tsme
.tsme_mlp
.mlp_port_upper
= tsme
.tsme_mlp
.mlp_port
;
954 DTRACE_PROBE1(tx__tndb__l2__tnmlp__tndbload
,
955 tsol_mlpent_t
*, &tsme
);
956 if (tsme
.tsme_mlp
.mlp_ipp
== 0 || tsme
.tsme_mlp
.mlp_port
== 0 ||
957 tsme
.tsme_mlp
.mlp_port
> tsme
.tsme_mlp
.mlp_port_upper
) {
961 retv
= mlp_add_del(mlpl
, tsme
.tsme_zoneid
,
962 tsme
.tsme_mlp
.mlp_ipp
, tsme
.tsme_mlp
.mlp_port
,
963 tsme
.tsme_mlp
.mlp_port_upper
, B_TRUE
);
967 DTRACE_PROBE1(tx__tndb__l2__tnmlp__tndbget
,
968 tsol_mlpent_t
*, &tsme
);
971 * Search for the requested element or, failing that, the one
972 * that's logically next in the sequence.
974 rw_enter(&mlpl
->mlpl_rwlock
, RW_READER
);
975 for (tme
= mlpl
->mlpl_first
; tme
!= NULL
;
976 tme
= tme
->mlpe_next
) {
977 if (tsme
.tsme_zoneid
!= ALL_ZONES
&&
978 tme
->mlpe_zoneid
!= tsme
.tsme_zoneid
)
980 if (tme
->mlpe_mlp
.mlp_ipp
>= tsme
.tsme_mlp
.mlp_ipp
&&
981 tme
->mlpe_mlp
.mlp_port
== tsme
.tsme_mlp
.mlp_port
)
983 if (tme
->mlpe_mlp
.mlp_port
> tsme
.tsme_mlp
.mlp_port
)
989 tsme
.tsme_zoneid
= tme
->mlpe_zoneid
;
990 tsme
.tsme_mlp
= tme
->mlpe_mlp
;
993 rw_exit(&mlpl
->mlpl_rwlock
);
997 DTRACE_PROBE1(tx__tndb__l4__tnmlp__tndbdelete
,
998 tsol_mlpent_t
*, &tsme
);
999 retv
= mlp_add_del(mlpl
, tsme
.tsme_zoneid
,
1000 tsme
.tsme_mlp
.mlp_ipp
, tsme
.tsme_mlp
.mlp_port
,
1001 tsme
.tsme_mlp
.mlp_port_upper
, B_FALSE
);
1005 DTRACE_PROBE1(tx__tndb__l4__tnmlp__tndbflush
,
1006 tsol_mlpent_t
*, &tsme
);
1007 mlp_flush(mlpl
, ALL_ZONES
);
1008 mlp_flush(&shared_mlps
, tsme
.tsme_zoneid
);
1013 DTRACE_PROBE1(tx__tndb__l0__tnmlp__unknowncmd
, int,
1022 if (cmd
== TNDB_GET
&& retv
== 0) {
1023 /* Copy out result */
1024 if (copyout(&tsme
, buf
, sizeof (tsme
)) != 0) {
1025 DTRACE_PROBE(tx__tndb__l0__tnmlp__copyout
);
1031 return (set_errno(retv
));
1037 * Returns a tnrhc matching the addr address.
1038 * The returned rhc's refcnt is incremented.
1041 find_rhc(const void *addr
, uchar_t version
, boolean_t staleok
)
1043 tsol_tnrhc_t
*rh
= NULL
;
1046 tnrhc_hash_t
*tnrhc_hash
;
1048 in_addr_t
*in4
= (in_addr_t
*)addr
;
1049 in6_addr_t
*in6
= (in6_addr_t
*)addr
;
1051 in6_addr_t tmpmask6
;
1056 * An IPv4-mapped IPv6 address is really an IPv4 address
1059 if (version
== IPV6_VERSION
&&
1060 IN6_IS_ADDR_V4MAPPED(in6
)) {
1061 IN6_V4MAPPED_TO_IPADDR(in6
, tmpin4
);
1062 version
= IPV4_VERSION
;
1067 * Search the tnrh hash table for each prefix length,
1068 * starting at longest prefix length, until a matching
1069 * rhc entry is found.
1071 if (version
== IPV4_VERSION
) {
1072 for (i
= (TSOL_MASK_TABLE_SIZE
- 1); i
>= 0; i
--) {
1074 if ((tnrhc_table
[i
]) == NULL
)
1077 tmpmask
= tsol_plen_to_mask(i
);
1078 tnrhc_hash
= &tnrhc_table
[i
][
1079 TSOL_ADDR_HASH(*in4
& tmpmask
, TNRHC_SIZE
)];
1081 mutex_enter(&tnrhc_hash
->tnrh_lock
);
1082 for (rh
= tnrhc_hash
->tnrh_list
; rh
!= NULL
;
1083 rh
= rh
->rhc_next
) {
1084 if ((rh
->rhc_host
.ta_family
== AF_INET
) &&
1085 ((rh
->rhc_host
.ta_addr_v4
.s_addr
&
1086 tmpmask
) == (*in4
& tmpmask
))) {
1092 mutex_exit(&tnrhc_hash
->tnrh_lock
);
1097 DTRACE_PROBE1(tx__tndb__l1__findrhc__norhv4ent
,
1100 for (i
= (TSOL_MASK_TABLE_SIZE_V6
- 1); i
>= 0; i
--) {
1101 if ((tnrhc_table_v6
[i
]) == NULL
)
1104 tsol_plen_to_mask_v6(i
, &tmpmask6
);
1105 tnrhc_hash
= &tnrhc_table_v6
[i
][
1106 TSOL_ADDR_MASK_HASH_V6(*in6
, tmpmask6
, TNRHC_SIZE
)];
1108 mutex_enter(&tnrhc_hash
->tnrh_lock
);
1109 for (rh
= tnrhc_hash
->tnrh_list
; rh
!= NULL
;
1110 rh
= rh
->rhc_next
) {
1111 if ((rh
->rhc_host
.ta_family
== AF_INET6
) &&
1112 V6_MASK_EQ_2(rh
->rhc_host
.ta_addr_v6
,
1119 mutex_exit(&tnrhc_hash
->tnrh_lock
);
1124 DTRACE_PROBE1(tx__tndb__l1__findrhc__norhv6ent
,
1129 * Does the tnrh entry point to a stale template?
1130 * This can happen any time the user deletes or modifies
1131 * a template that has existing tnrh entries pointing
1132 * to it. Try to find a new version of the template.
1133 * If there is no template, then just give up.
1134 * If the template exists, reload the tnrh entry.
1136 if (rh
!= NULL
&& rh
->rhc_tpc
->tpc_invalid
) {
1137 tpc
= tnrhtp_find(rh
->rhc_tpc
->tpc_tp
.name
, tpc_name_hash
);
1140 DTRACE_PROBE2(tx__tndb__l1__findrhc__staletpc
,
1141 tsol_tnrhc_t
*, rh
, tsol_tpc_t
*,
1147 ASSERT(tpc
->tpc_tp
.host_type
== UNLABELED
||
1148 tpc
->tpc_tp
.host_type
== SUN_CIPSO
);
1150 if ((new = kmem_zalloc(sizeof (*new),
1151 KM_NOSLEEP
)) == NULL
) {
1152 DTRACE_PROBE(tx__tndb__l1__findrhc__nomem
);
1158 mutex_init(&new->rhc_lock
, NULL
, MUTEX_DEFAULT
, NULL
);
1159 new->rhc_host
= rh
->rhc_host
;
1161 new->rhc_isbcast
= rh
->rhc_isbcast
;
1162 new->rhc_local
= rh
->rhc_local
;
1167 * This function increments the tnrh entry ref count
1168 * for the pointer returned to the caller.
1169 * tnrh_hash_add increments the tnrh entry ref count
1170 * for the pointer in the hash table.
1173 if (tnrh_hash_add(new, prefix
) != 0) {
1183 find_tpc(const void *addr
, uchar_t version
, boolean_t staleok
)
1188 if ((rhc
= find_rhc(addr
, version
, staleok
)) == NULL
)
1198 * create an internal template called "_unlab":
1201 * host_type = unlabeled;\
1202 * def_label = ADMIN_LOW[ADMIN_LOW];\
1203 * min_sl = ADMIN_LOW;\
1204 * max_sl = ADMIN_HIGH;
1207 tsol_create_i_tmpls(void)
1209 tsol_tpent_t rhtpent
;
1211 bzero(&rhtpent
, sizeof (rhtpent
));
1214 (void) strcpy(rhtpent
.name
, "_unlab");
1216 rhtpent
.host_type
= UNLABELED
;
1217 rhtpent
.tp_mask_unl
= TSOL_MSK_DEF_LABEL
| TSOL_MSK_DEF_CL
|
1218 TSOL_MSK_SL_RANGE_TSOL
;
1220 rhtpent
.tp_gw_sl_range
.lower_bound
= *label2bslabel(l_admin_low
);
1221 rhtpent
.tp_def_label
= rhtpent
.tp_gw_sl_range
.lower_bound
;
1222 rhtpent
.tp_gw_sl_range
.upper_bound
= *label2bslabel(l_admin_high
);
1223 rhtpent
.tp_cipso_doi_unl
= default_doi
;
1224 tpc_unlab
= tnrhtp_create(&rhtpent
, KM_SLEEP
);
1228 * set up internal host template, called from kernel only.
1231 tsol_create_i_tnrh(const tnaddr_t
*sa
)
1233 tsol_tnrhc_t
*rh
, *new;
1234 tnrhc_hash_t
*tnrhc_hash
;
1236 /* Allocate a new entry before taking the lock */
1237 new = kmem_zalloc(sizeof (*new), KM_SLEEP
);
1239 tnrhc_hash
= (sa
->ta_family
== AF_INET
) ? &tnrhc_table
[0][0] :
1240 &tnrhc_table_v6
[0][0];
1242 mutex_enter(&tnrhc_hash
->tnrh_lock
);
1243 rh
= tnrhc_hash
->tnrh_list
;
1246 /* We're keeping the new entry. */
1250 mutex_init(&rh
->rhc_lock
, NULL
, MUTEX_DEFAULT
, NULL
);
1252 tnrhc_hash
->tnrh_list
= rh
;
1256 * Link the entry to internal_unlab
1258 if (rh
->rhc_tpc
!= tpc_unlab
) {
1259 if (rh
->rhc_tpc
!= NULL
)
1260 TPC_RELE(rh
->rhc_tpc
);
1261 rh
->rhc_tpc
= tpc_unlab
;
1262 TPC_HOLD(tpc_unlab
);
1264 mutex_exit(&tnrhc_hash
->tnrh_lock
);
1266 kmem_free(new, sizeof (*new));
1270 * Returns 0 if the port is known to be SLP. Returns next possible port number
1271 * (wrapping through 1) if port is MLP on shared or global. Administrator
1272 * should not make all ports MLP. If that's done, then we'll just pretend
1273 * everything is SLP to avoid looping forever.
1275 * Note: port is in host byte order.
1278 tsol_next_port(zone_t
*zone
, in_port_t port
, int proto
, boolean_t upward
)
1281 tsol_mlp_entry_t
*tme
;
1286 if (zone
!= NULL
&& zone
->zone_mlps
.mlpl_first
!= NULL
) {
1287 rw_enter(&zone
->zone_mlps
.mlpl_rwlock
, RW_READER
);
1288 for (tme
= zone
->zone_mlps
.mlpl_first
; tme
!= NULL
;
1289 tme
= tme
->mlpe_next
) {
1290 if (proto
== tme
->mlpe_mlp
.mlp_ipp
&&
1291 newport
>= tme
->mlpe_mlp
.mlp_port
&&
1292 newport
<= tme
->mlpe_mlp
.mlp_port_upper
)
1294 tme
->mlpe_mlp
.mlp_port_upper
+ 1 :
1295 tme
->mlpe_mlp
.mlp_port
- 1;
1297 rw_exit(&zone
->zone_mlps
.mlpl_rwlock
);
1299 if (shared_mlps
.mlpl_first
!= NULL
) {
1300 rw_enter(&shared_mlps
.mlpl_rwlock
, RW_READER
);
1301 for (tme
= shared_mlps
.mlpl_first
; tme
!= NULL
;
1302 tme
= tme
->mlpe_next
) {
1303 if (proto
== tme
->mlpe_mlp
.mlp_ipp
&&
1304 newport
>= tme
->mlpe_mlp
.mlp_port
&&
1305 newport
<= tme
->mlpe_mlp
.mlp_port_upper
)
1307 tme
->mlpe_mlp
.mlp_port_upper
+ 1 :
1308 tme
->mlpe_mlp
.mlp_port
- 1;
1310 rw_exit(&shared_mlps
.mlpl_rwlock
);
1312 if (newport
<= 65535 && newport
> 0)
1317 newport
= upward
? 1 : 65535;
1319 return (newport
== port
? 0 : newport
);
1323 * tsol_mlp_port_type will check if the given (zone, proto, port) is a
1324 * multilevel port. If it is, return the type (shared, private, or both), or
1325 * indicate that it's single-level.
1327 * Note: port is given in host byte order, not network byte order.
1330 tsol_mlp_port_type(zone_t
*zone
, uchar_t proto
, uint16_t port
,
1333 tsol_mlp_entry_t
*tme
;
1335 if (mlptype
== mlptBoth
|| mlptype
== mlptPrivate
) {
1337 if (zone
->zone_mlps
.mlpl_first
!= NULL
) {
1338 rw_enter(&zone
->zone_mlps
.mlpl_rwlock
, RW_READER
);
1339 for (tme
= zone
->zone_mlps
.mlpl_first
; tme
!= NULL
;
1340 tme
= tme
->mlpe_next
) {
1341 if (proto
== tme
->mlpe_mlp
.mlp_ipp
&&
1342 port
>= tme
->mlpe_mlp
.mlp_port
&&
1343 port
<= tme
->mlpe_mlp
.mlp_port_upper
)
1346 rw_exit(&zone
->zone_mlps
.mlpl_rwlock
);
1349 if (mlptype
== mlptBoth
)
1350 mlptype
= mlptShared
;
1351 else if (mlptype
== mlptPrivate
)
1352 mlptype
= mlptSingle
;
1355 if (mlptype
== mlptBoth
|| mlptype
== mlptShared
) {
1357 if (shared_mlps
.mlpl_first
!= NULL
) {
1358 rw_enter(&shared_mlps
.mlpl_rwlock
, RW_READER
);
1359 for (tme
= shared_mlps
.mlpl_first
; tme
!= NULL
;
1360 tme
= tme
->mlpe_next
) {
1361 if (proto
== tme
->mlpe_mlp
.mlp_ipp
&&
1362 port
>= tme
->mlpe_mlp
.mlp_port
&&
1363 port
<= tme
->mlpe_mlp
.mlp_port_upper
)
1366 rw_exit(&shared_mlps
.mlpl_rwlock
);
1369 if (mlptype
== mlptBoth
)
1370 mlptype
= mlptPrivate
;
1371 else if (mlptype
== mlptShared
)
1372 mlptype
= mlptSingle
;
1379 * tsol_mlp_findzone will check if the given (proto, port) is a multilevel port
1380 * on a shared address. If it is, return the owning zone.
1382 * Note: lport is in network byte order, unlike the other MLP functions,
1383 * because the callers of this function are all dealing with packets off the
1387 tsol_mlp_findzone(uchar_t proto
, uint16_t lport
)
1389 tsol_mlp_entry_t
*tme
;
1393 if (shared_mlps
.mlpl_first
== NULL
)
1395 port
= ntohs(lport
);
1396 rw_enter(&shared_mlps
.mlpl_rwlock
, RW_READER
);
1397 for (tme
= shared_mlps
.mlpl_first
; tme
!= NULL
; tme
= tme
->mlpe_next
) {
1398 if (proto
== tme
->mlpe_mlp
.mlp_ipp
&&
1399 port
>= tme
->mlpe_mlp
.mlp_port
&&
1400 port
<= tme
->mlpe_mlp
.mlp_port_upper
)
1403 zoneid
= tme
== NULL
? ALL_ZONES
: tme
->mlpe_zoneid
;
1404 rw_exit(&shared_mlps
.mlpl_rwlock
);
1410 tsol_print_label(const blevel_t
*blev
, const char *name
)
1412 const _blevel_impl_t
*bli
= (const _blevel_impl_t
*)blev
;
1414 /* We really support only sensitivity labels */
1415 cmn_err(CE_NOTE
, "%s %x:%x:%08x%08x%08x%08x%08x%08x%08x%08x",
1416 name
, bli
->id
, LCLASS(bli
), ntohl(bli
->_comps
.c1
),
1417 ntohl(bli
->_comps
.c2
), ntohl(bli
->_comps
.c3
), ntohl(bli
->_comps
.c4
),
1418 ntohl(bli
->_comps
.c5
), ntohl(bli
->_comps
.c6
), ntohl(bli
->_comps
.c7
),
1419 ntohl(bli
->_comps
.c8
));
1425 * Normal: Routes TSOL syscalls.
1427 * Output: As defined for each TSOL syscall.
1428 * Returns ENOSYS for unrecognized calls.
1432 labelsys(int op
, void *a1
, void *a2
, void *a3
, void *a4
, void *a5
)
1435 case TSOL_SYSLABELING
:
1436 return (sys_labeling
);
1438 return (tnrh((int)(uintptr_t)a1
, a2
));
1440 return (tnrhtp((int)(uintptr_t)a1
, a2
));
1442 return (tnmlp((int)(uintptr_t)a1
, a2
));
1444 return (getlabel((char *)a1
, (bslabel_t
*)a2
));
1445 case TSOL_FGETLABEL
:
1446 return (fgetlabel((int)(uintptr_t)a1
, (bslabel_t
*)a2
));
1448 return (set_errno(ENOSYS
));