tnet.c revision 10181:c8b6704cb2b3
1/*
2 * CDDL HEADER START
3 *
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.
7 *
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.
12 *
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]
18 *
19 * CDDL HEADER END
20 */
21/*
22 * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
23 * Use is subject to license terms.
24 */
25
26#include <sys/types.h>
27#include <sys/stream.h>
28#include <sys/strsubr.h>
29#include <sys/stropts.h>
30#include <sys/sunddi.h>
31#include <sys/cred.h>
32#include <sys/debug.h>
33#include <sys/kmem.h>
34#include <sys/errno.h>
35#include <sys/disp.h>
36#include <netinet/in.h>
37#include <netinet/in_systm.h>
38#include <netinet/ip.h>
39#include <netinet/ip_icmp.h>
40#include <netinet/tcp.h>
41#include <inet/common.h>
42#include <inet/ipclassifier.h>
43#include <inet/ip.h>
44#include <inet/mib2.h>
45#include <inet/nd.h>
46#include <inet/tcp.h>
47#include <inet/ip_rts.h>
48#include <inet/ip_ire.h>
49#include <inet/ip_if.h>
50#include <sys/modhash.h>
51
52#include <sys/tsol/label.h>
53#include <sys/tsol/label_macro.h>
54#include <sys/tsol/tnet.h>
55#include <sys/tsol/tndb.h>
56#include <sys/strsun.h>
57
58/* tunable for strict error-reply behavior (TCP RST and ICMP Unreachable) */
59int tsol_strict_error;
60
61/*
62 * Some notes on the Trusted Solaris IRE gateway security attributes:
63 *
64 * When running in Trusted mode, the routing subsystem determines whether or
65 * not a packet can be delivered to an off-link host (not directly reachable
66 * through an interface) based on the accreditation checks of the packet's
67 * security attributes against those associated with the next-hop gateway.
68 *
69 * The next-hop gateway's security attributes can be derived from two sources
70 * (in order of preference): route-related and the host database.  A Trusted
71 * system must be configured with at least the host database containing an
72 * entry for the next-hop gateway, or otherwise no accreditation checks can
73 * be performed, which may result in the inability to send packets to any
74 * off-link destination host.
75 *
76 * The major differences between the two sources are the number and type of
77 * security attributes used for accreditation checks.  A host database entry
78 * can contain at most one set of security attributes, specific only to the
79 * next-hop gateway.  On contrast, route-related security attributes are made
80 * up of a collection of security attributes for the distant networks, and
81 * are grouped together per next-hop gateway used to reach those networks.
82 * This is the preferred method, and the routing subsystem will fallback to
83 * the host database entry only if there are no route-related attributes
84 * associated with the next-hop gateway.
85 *
86 * In Trusted mode, all of the IRE entries (except LOCAL/LOOPBACK/BROADCAST/
87 * INTERFACE type) are initialized to contain a placeholder to store this
88 * information.  The ire_gw_secattr structure gets allocated, initialized
89 * and associated with the IRE during the time of the IRE creation.  The
90 * initialization process also includes resolving the host database entry
91 * of the next-hop gateway for fallback purposes.  It does not include any
92 * route-related attribute setup, as that process comes separately as part
93 * of the route requests (add/change) made to the routing subsystem.
94 *
95 * The underlying logic which involves associating IREs with the gateway
96 * security attributes are represented by the following data structures:
97 *
98 * tsol_gcdb_t, or "gcdb"
99 *
100 *	- This is a system-wide collection of records containing the
101 *	  currently used route-related security attributes, which are fed
102 *	  through the routing socket interface, e.g. "route add/change".
103 *
104 * tsol_gc_t, or "gc"
105 *
106 *	- This is the gateway credential structure, and it provides for the
107 *	  only mechanism to access the contents of gcdb.  More than one gc
108 *	  entries may refer to the same gcdb record.  gc's in the system are
109 *	  grouped according to the next-hop gateway address.
110 *
111 * tsol_gcgrp_t, or "gcgrp"
112 *
113 *	- Group of gateway credentials, and is unique per next-hop gateway
114 *	  address.  When the group is not empty, i.e. when gcgrp_count is
115 *	  greater than zero, it contains one or more gc's, each pointing to
116 *	  a gcdb record which indicates the gateway security attributes
117 *	  associated with the next-hop gateway.
118 *
119 * The fields of the tsol_ire_gw_secattr_t used from within the IRE are:
120 *
121 * igsa_lock
122 *
123 *	- Lock that protects all fields within tsol_ire_gw_secattr_t.
124 *
125 * igsa_rhc
126 *
127 *	- Remote host cache database entry of next-hop gateway.  This is
128 *	  used in the case when there are no route-related attributes
129 *	  configured for the IRE.
130 *
131 * igsa_gc
132 *
133 *	- A set of route-related attributes that only get set for prefix
134 *	  IREs.  If this is non-NULL, the prefix IRE has been associated
135 *	  with a set of gateway security attributes by way of route add/
136 *	  change functionality.  This field stays NULL for IRE_CACHEs.
137 *
138 * igsa_gcgrp
139 *
140 *	- Group of gc's which only gets set for IRE_CACHEs.  Each of the gc
141 *	  points to a gcdb record that contains the security attributes
142 *	  used to perform the credential checks of the packet which uses
143 *	  the IRE.  If the group is not empty, the list of gc's can be
144 *	  traversed starting at gcgrp_head.  This field stays NULL for
145 *	  prefix IREs.
146 */
147
148static kmem_cache_t *ire_gw_secattr_cache;
149
150#define	GCDB_HASH_SIZE	101
151#define	GCGRP_HASH_SIZE	101
152
153#define	GCDB_REFRELE(p) {		\
154	mutex_enter(&gcdb_lock);	\
155	ASSERT((p)->gcdb_refcnt > 0);	\
156	if (--((p)->gcdb_refcnt) == 0)	\
157		gcdb_inactive(p);	\
158	ASSERT(MUTEX_HELD(&gcdb_lock));	\
159	mutex_exit(&gcdb_lock);		\
160}
161
162static int gcdb_hash_size = GCDB_HASH_SIZE;
163static int gcgrp_hash_size = GCGRP_HASH_SIZE;
164static mod_hash_t *gcdb_hash;
165static mod_hash_t *gcgrp4_hash;
166static mod_hash_t *gcgrp6_hash;
167
168static kmutex_t gcdb_lock;
169kmutex_t gcgrp_lock;
170
171static uint_t gcdb_hash_by_secattr(void *, mod_hash_key_t);
172static int gcdb_hash_cmp(mod_hash_key_t, mod_hash_key_t);
173static tsol_gcdb_t *gcdb_lookup(struct rtsa_s *, boolean_t);
174static void gcdb_inactive(tsol_gcdb_t *);
175
176static uint_t gcgrp_hash_by_addr(void *, mod_hash_key_t);
177static int gcgrp_hash_cmp(mod_hash_key_t, mod_hash_key_t);
178
179static int ire_gw_secattr_constructor(void *, void *, int);
180static void ire_gw_secattr_destructor(void *, void *);
181
182void
183tnet_init(void)
184{
185	ire_gw_secattr_cache = kmem_cache_create("ire_gw_secattr_cache",
186	    sizeof (tsol_ire_gw_secattr_t), 64, ire_gw_secattr_constructor,
187	    ire_gw_secattr_destructor, NULL, NULL, NULL, 0);
188
189	gcdb_hash = mod_hash_create_extended("gcdb_hash",
190	    gcdb_hash_size, mod_hash_null_keydtor, mod_hash_null_valdtor,
191	    gcdb_hash_by_secattr, NULL, gcdb_hash_cmp, KM_SLEEP);
192
193	gcgrp4_hash = mod_hash_create_extended("gcgrp4_hash",
194	    gcgrp_hash_size, mod_hash_null_keydtor, mod_hash_null_valdtor,
195	    gcgrp_hash_by_addr, NULL, gcgrp_hash_cmp, KM_SLEEP);
196
197	gcgrp6_hash = mod_hash_create_extended("gcgrp6_hash",
198	    gcgrp_hash_size, mod_hash_null_keydtor, mod_hash_null_valdtor,
199	    gcgrp_hash_by_addr, NULL, gcgrp_hash_cmp, KM_SLEEP);
200
201	mutex_init(&gcdb_lock, NULL, MUTEX_DEFAULT, NULL);
202	mutex_init(&gcgrp_lock, NULL, MUTEX_DEFAULT, NULL);
203}
204
205void
206tnet_fini(void)
207{
208	kmem_cache_destroy(ire_gw_secattr_cache);
209	mod_hash_destroy_hash(gcdb_hash);
210	mod_hash_destroy_hash(gcgrp4_hash);
211	mod_hash_destroy_hash(gcgrp6_hash);
212	mutex_destroy(&gcdb_lock);
213	mutex_destroy(&gcgrp_lock);
214}
215
216/* ARGSUSED */
217static int
218ire_gw_secattr_constructor(void *buf, void *cdrarg, int kmflags)
219{
220	tsol_ire_gw_secattr_t *attrp = buf;
221
222	mutex_init(&attrp->igsa_lock, NULL, MUTEX_DEFAULT, NULL);
223
224	attrp->igsa_rhc = NULL;
225	attrp->igsa_gc = NULL;
226	attrp->igsa_gcgrp = NULL;
227
228	return (0);
229}
230
231/* ARGSUSED */
232static void
233ire_gw_secattr_destructor(void *buf, void *cdrarg)
234{
235	tsol_ire_gw_secattr_t *attrp = (tsol_ire_gw_secattr_t *)buf;
236
237	mutex_destroy(&attrp->igsa_lock);
238}
239
240tsol_ire_gw_secattr_t *
241ire_gw_secattr_alloc(int kmflags)
242{
243	return (kmem_cache_alloc(ire_gw_secattr_cache, kmflags));
244}
245
246void
247ire_gw_secattr_free(tsol_ire_gw_secattr_t *attrp)
248{
249	ASSERT(MUTEX_NOT_HELD(&attrp->igsa_lock));
250
251	if (attrp->igsa_rhc != NULL) {
252		TNRHC_RELE(attrp->igsa_rhc);
253		attrp->igsa_rhc = NULL;
254	}
255
256	if (attrp->igsa_gc != NULL) {
257		GC_REFRELE(attrp->igsa_gc);
258		attrp->igsa_gc = NULL;
259	}
260	if (attrp->igsa_gcgrp != NULL) {
261		GCGRP_REFRELE(attrp->igsa_gcgrp);
262		attrp->igsa_gcgrp = NULL;
263	}
264
265	ASSERT(attrp->igsa_rhc == NULL);
266	ASSERT(attrp->igsa_gc == NULL);
267	ASSERT(attrp->igsa_gcgrp == NULL);
268
269	kmem_cache_free(ire_gw_secattr_cache, attrp);
270}
271
272/* ARGSUSED */
273static uint_t
274gcdb_hash_by_secattr(void *hash_data, mod_hash_key_t key)
275{
276	const struct rtsa_s *rp = (struct rtsa_s *)key;
277	const uint32_t *up, *ue;
278	uint_t hash;
279	int i;
280
281	ASSERT(rp != NULL);
282
283	/* See comments in hash_bylabel in zone.c for details */
284	hash = rp->rtsa_doi + (rp->rtsa_doi << 1);
285	up = (const uint32_t *)&rp->rtsa_slrange;
286	ue = up + sizeof (rp->rtsa_slrange) / sizeof (*up);
287	i = 1;
288	while (up < ue) {
289		/* using 2^n + 1, 1 <= n <= 16 as source of many primes */
290		hash += *up + (*up << ((i % 16) + 1));
291		up++;
292		i++;
293	}
294	return (hash);
295}
296
297static int
298gcdb_hash_cmp(mod_hash_key_t key1, mod_hash_key_t key2)
299{
300	struct rtsa_s *rp1 = (struct rtsa_s *)key1;
301	struct rtsa_s *rp2 = (struct rtsa_s *)key2;
302
303	ASSERT(rp1 != NULL && rp2 != NULL);
304
305	if (blequal(&rp1->rtsa_slrange.lower_bound,
306	    &rp2->rtsa_slrange.lower_bound) &&
307	    blequal(&rp1->rtsa_slrange.upper_bound,
308	    &rp2->rtsa_slrange.upper_bound) &&
309	    rp1->rtsa_doi == rp2->rtsa_doi)
310		return (0);
311
312	/* No match; not found */
313	return (-1);
314}
315
316/* ARGSUSED */
317static uint_t
318gcgrp_hash_by_addr(void *hash_data, mod_hash_key_t key)
319{
320	tsol_gcgrp_addr_t *ga = (tsol_gcgrp_addr_t *)key;
321	uint_t		idx = 0;
322	uint32_t	*ap;
323
324	ASSERT(ga != NULL);
325	ASSERT(ga->ga_af == AF_INET || ga->ga_af == AF_INET6);
326
327	ap = (uint32_t *)&ga->ga_addr.s6_addr32[0];
328	idx ^= *ap++;
329	idx ^= *ap++;
330	idx ^= *ap++;
331	idx ^= *ap;
332
333	return (idx);
334}
335
336static int
337gcgrp_hash_cmp(mod_hash_key_t key1, mod_hash_key_t key2)
338{
339	tsol_gcgrp_addr_t *ga1 = (tsol_gcgrp_addr_t *)key1;
340	tsol_gcgrp_addr_t *ga2 = (tsol_gcgrp_addr_t *)key2;
341
342	ASSERT(ga1 != NULL && ga2 != NULL);
343
344	/* Address family must match */
345	if (ga1->ga_af != ga2->ga_af)
346		return (-1);
347
348	if (ga1->ga_addr.s6_addr32[0] == ga2->ga_addr.s6_addr32[0] &&
349	    ga1->ga_addr.s6_addr32[1] == ga2->ga_addr.s6_addr32[1] &&
350	    ga1->ga_addr.s6_addr32[2] == ga2->ga_addr.s6_addr32[2] &&
351	    ga1->ga_addr.s6_addr32[3] == ga2->ga_addr.s6_addr32[3])
352		return (0);
353
354	/* No match; not found */
355	return (-1);
356}
357
358#define	RTSAFLAGS	"\20\11cipso\3doi\2max_sl\1min_sl"
359
360int
361rtsa_validate(const struct rtsa_s *rp)
362{
363	uint32_t mask = rp->rtsa_mask;
364
365	/* RTSA_CIPSO must be set, and DOI must not be zero */
366	if ((mask & RTSA_CIPSO) == 0 || rp->rtsa_doi == 0) {
367		DTRACE_PROBE2(tx__gcdb__log__error__rtsa__validate, char *,
368		    "rtsa(1) lacks flag or has 0 doi.",
369		    rtsa_s *, rp);
370		return (EINVAL);
371	}
372	/*
373	 * SL range must be specified, and it must have its
374	 * upper bound dominating its lower bound.
375	 */
376	if ((mask & RTSA_SLRANGE) != RTSA_SLRANGE ||
377	    !bldominates(&rp->rtsa_slrange.upper_bound,
378	    &rp->rtsa_slrange.lower_bound)) {
379		DTRACE_PROBE2(tx__gcdb__log__error__rtsa__validate, char *,
380		    "rtsa(1) min_sl and max_sl not set or max_sl is "
381		    "not dominating.", rtsa_s *, rp);
382		return (EINVAL);
383	}
384	return (0);
385}
386
387/*
388 * A brief explanation of the reference counting scheme:
389 *
390 * Prefix IREs have a non-NULL igsa_gc and a NULL igsa_gcgrp;
391 * IRE_CACHEs have it vice-versa.
392 *
393 * Apart from dynamic references due to to reference holds done
394 * actively by threads, we have the following references:
395 *
396 * gcdb_refcnt:
397 *	- Every tsol_gc_t pointing to a tsol_gcdb_t contributes a reference
398 *	  to the gcdb_refcnt.
399 *
400 * gc_refcnt:
401 *	- A prefix IRE that points to an igsa_gc contributes a reference
402 *	  to the gc_refcnt.
403 *
404 * gcgrp_refcnt:
405 *	- An IRE_CACHE that points to an igsa_gcgrp contributes a reference
406 *	  to the gcgrp_refcnt of the associated tsol_gcgrp_t.
407 *	- Every tsol_gc_t in the chain headed by tsol_gcgrp_t contributes
408 *	  a reference to the gcgrp_refcnt.
409 */
410static tsol_gcdb_t *
411gcdb_lookup(struct rtsa_s *rp, boolean_t alloc)
412{
413	tsol_gcdb_t *gcdb = NULL;
414
415	if (rtsa_validate(rp) != 0)
416		return (NULL);
417
418	mutex_enter(&gcdb_lock);
419	/* Find a copy in the cache; otherwise, create one and cache it */
420	if (mod_hash_find(gcdb_hash, (mod_hash_key_t)rp,
421	    (mod_hash_val_t *)&gcdb) == 0) {
422		gcdb->gcdb_refcnt++;
423		ASSERT(gcdb->gcdb_refcnt != 0);
424
425		DTRACE_PROBE2(tx__gcdb__log__info__gcdb__lookup, char *,
426		    "gcdb(1) is in gcdb_hash(global)", tsol_gcdb_t *, gcdb);
427	} else if (alloc) {
428		gcdb = kmem_zalloc(sizeof (*gcdb), KM_NOSLEEP);
429		if (gcdb != NULL) {
430			gcdb->gcdb_refcnt = 1;
431			gcdb->gcdb_mask = rp->rtsa_mask;
432			gcdb->gcdb_doi = rp->rtsa_doi;
433			gcdb->gcdb_slrange = rp->rtsa_slrange;
434
435			if (mod_hash_insert(gcdb_hash,
436			    (mod_hash_key_t)&gcdb->gcdb_attr,
437			    (mod_hash_val_t)gcdb) != 0) {
438				mutex_exit(&gcdb_lock);
439				kmem_free(gcdb, sizeof (*gcdb));
440				return (NULL);
441			}
442
443			DTRACE_PROBE2(tx__gcdb__log__info__gcdb__insert, char *,
444			    "gcdb(1) inserted in gcdb_hash(global)",
445			    tsol_gcdb_t *, gcdb);
446		}
447	}
448	mutex_exit(&gcdb_lock);
449	return (gcdb);
450}
451
452static void
453gcdb_inactive(tsol_gcdb_t *gcdb)
454{
455	ASSERT(MUTEX_HELD(&gcdb_lock));
456	ASSERT(gcdb != NULL && gcdb->gcdb_refcnt == 0);
457
458	(void) mod_hash_remove(gcdb_hash, (mod_hash_key_t)&gcdb->gcdb_attr,
459	    (mod_hash_val_t *)&gcdb);
460
461	DTRACE_PROBE2(tx__gcdb__log__info__gcdb__remove, char *,
462	    "gcdb(1) removed from gcdb_hash(global)",
463	    tsol_gcdb_t *, gcdb);
464	kmem_free(gcdb, sizeof (*gcdb));
465}
466
467tsol_gc_t *
468gc_create(struct rtsa_s *rp, tsol_gcgrp_t *gcgrp, boolean_t *gcgrp_xtrarefp)
469{
470	tsol_gc_t *gc;
471	tsol_gcdb_t *gcdb;
472
473	*gcgrp_xtrarefp = B_TRUE;
474
475	rw_enter(&gcgrp->gcgrp_rwlock, RW_WRITER);
476	if ((gcdb = gcdb_lookup(rp, B_TRUE)) == NULL) {
477		rw_exit(&gcgrp->gcgrp_rwlock);
478		return (NULL);
479	}
480
481	for (gc = gcgrp->gcgrp_head; gc != NULL; gc = gc->gc_next) {
482		if (gc->gc_db == gcdb) {
483			ASSERT(gc->gc_grp == gcgrp);
484
485			gc->gc_refcnt++;
486			ASSERT(gc->gc_refcnt != 0);
487
488			GCDB_REFRELE(gcdb);
489
490			DTRACE_PROBE3(tx__gcdb__log__info__gc__create,
491			    char *, "found gc(1) in gcgrp(2)",
492			    tsol_gc_t *, gc, tsol_gcgrp_t *, gcgrp);
493			rw_exit(&gcgrp->gcgrp_rwlock);
494			return (gc);
495		}
496	}
497
498	gc = kmem_zalloc(sizeof (*gc), KM_NOSLEEP);
499	if (gc != NULL) {
500		if (gcgrp->gcgrp_head == NULL) {
501			gcgrp->gcgrp_head = gcgrp->gcgrp_tail = gc;
502		} else {
503			gcgrp->gcgrp_tail->gc_next = gc;
504			gc->gc_prev = gcgrp->gcgrp_tail;
505			gcgrp->gcgrp_tail = gc;
506		}
507		gcgrp->gcgrp_count++;
508		ASSERT(gcgrp->gcgrp_count != 0);
509
510		/* caller has incremented gcgrp reference for us */
511		gc->gc_grp = gcgrp;
512
513		gc->gc_db = gcdb;
514		gc->gc_refcnt = 1;
515
516		DTRACE_PROBE3(tx__gcdb__log__info__gc__create, char *,
517		    "added gc(1) to gcgrp(2)", tsol_gc_t *, gc,
518		    tsol_gcgrp_t *, gcgrp);
519
520		*gcgrp_xtrarefp = B_FALSE;
521	}
522	rw_exit(&gcgrp->gcgrp_rwlock);
523
524	return (gc);
525}
526
527void
528gc_inactive(tsol_gc_t *gc)
529{
530	tsol_gcgrp_t *gcgrp = gc->gc_grp;
531
532	ASSERT(gcgrp != NULL);
533	ASSERT(RW_WRITE_HELD(&gcgrp->gcgrp_rwlock));
534	ASSERT(gc->gc_refcnt == 0);
535
536	if (gc->gc_prev != NULL)
537		gc->gc_prev->gc_next = gc->gc_next;
538	else
539		gcgrp->gcgrp_head = gc->gc_next;
540	if (gc->gc_next != NULL)
541		gc->gc_next->gc_prev = gc->gc_prev;
542	else
543		gcgrp->gcgrp_tail = gc->gc_prev;
544	ASSERT(gcgrp->gcgrp_count > 0);
545	gcgrp->gcgrp_count--;
546
547	/* drop lock before it's destroyed */
548	rw_exit(&gcgrp->gcgrp_rwlock);
549
550	DTRACE_PROBE3(tx__gcdb__log__info__gc__remove, char *,
551	    "removed inactive gc(1) from gcgrp(2)",
552	    tsol_gc_t *, gc, tsol_gcgrp_t *, gcgrp);
553
554	GCGRP_REFRELE(gcgrp);
555
556	gc->gc_grp = NULL;
557	gc->gc_prev = gc->gc_next = NULL;
558
559	if (gc->gc_db != NULL)
560		GCDB_REFRELE(gc->gc_db);
561
562	kmem_free(gc, sizeof (*gc));
563}
564
565tsol_gcgrp_t *
566gcgrp_lookup(tsol_gcgrp_addr_t *ga, boolean_t alloc)
567{
568	tsol_gcgrp_t *gcgrp = NULL;
569	mod_hash_t *hashp;
570
571	ASSERT(ga->ga_af == AF_INET || ga->ga_af == AF_INET6);
572
573	hashp = (ga->ga_af == AF_INET) ? gcgrp4_hash : gcgrp6_hash;
574
575	mutex_enter(&gcgrp_lock);
576	if (mod_hash_find(hashp, (mod_hash_key_t)ga,
577	    (mod_hash_val_t *)&gcgrp) == 0) {
578		gcgrp->gcgrp_refcnt++;
579		ASSERT(gcgrp->gcgrp_refcnt != 0);
580
581		DTRACE_PROBE3(tx__gcdb__log__info__gcgrp__lookup, char *,
582		    "found gcgrp(1) in hash(2)", tsol_gcgrp_t *, gcgrp,
583		    mod_hash_t *, hashp);
584
585	} else if (alloc) {
586		gcgrp = kmem_zalloc(sizeof (*gcgrp), KM_NOSLEEP);
587		if (gcgrp != NULL) {
588			gcgrp->gcgrp_refcnt = 1;
589			rw_init(&gcgrp->gcgrp_rwlock, NULL, RW_DEFAULT, NULL);
590			bcopy(ga, &gcgrp->gcgrp_addr, sizeof (*ga));
591
592			if (mod_hash_insert(hashp,
593			    (mod_hash_key_t)&gcgrp->gcgrp_addr,
594			    (mod_hash_val_t)gcgrp) != 0) {
595				mutex_exit(&gcgrp_lock);
596				kmem_free(gcgrp, sizeof (*gcgrp));
597				return (NULL);
598			}
599
600			DTRACE_PROBE3(tx__gcdb__log__info__gcgrp__insert,
601			    char *, "inserted gcgrp(1) in hash(2)",
602			    tsol_gcgrp_t *, gcgrp, mod_hash_t *, hashp);
603		}
604	}
605	mutex_exit(&gcgrp_lock);
606	return (gcgrp);
607}
608
609void
610gcgrp_inactive(tsol_gcgrp_t *gcgrp)
611{
612	tsol_gcgrp_addr_t *ga;
613	mod_hash_t *hashp;
614
615	ASSERT(MUTEX_HELD(&gcgrp_lock));
616	ASSERT(!RW_LOCK_HELD(&gcgrp->gcgrp_rwlock));
617	ASSERT(gcgrp != NULL && gcgrp->gcgrp_refcnt == 0);
618	ASSERT(gcgrp->gcgrp_head == NULL && gcgrp->gcgrp_count == 0);
619
620	ga = &gcgrp->gcgrp_addr;
621	ASSERT(ga->ga_af == AF_INET || ga->ga_af == AF_INET6);
622
623	hashp = (ga->ga_af == AF_INET) ? gcgrp4_hash : gcgrp6_hash;
624	(void) mod_hash_remove(hashp, (mod_hash_key_t)ga,
625	    (mod_hash_val_t *)&gcgrp);
626	rw_destroy(&gcgrp->gcgrp_rwlock);
627
628	DTRACE_PROBE3(tx__gcdb__log__info__gcgrp__remove, char *,
629	    "removed inactive gcgrp(1) from hash(2)",
630	    tsol_gcgrp_t *, gcgrp, mod_hash_t *, hashp);
631
632	kmem_free(gcgrp, sizeof (*gcgrp));
633}
634
635/*
636 * Converts CIPSO option to sensitivity label.
637 * Validity checks based on restrictions defined in
638 * COMMERCIAL IP SECURITY OPTION (CIPSO 2.2) (draft-ietf-cipso-ipsecurity)
639 */
640static boolean_t
641cipso_to_sl(const uchar_t *option, bslabel_t *sl)
642{
643	const struct cipso_option *co = (const struct cipso_option *)option;
644	const struct cipso_tag_type_1 *tt1;
645
646	tt1 = (struct cipso_tag_type_1 *)&co->cipso_tag_type[0];
647	if (tt1->tag_type != 1 ||
648	    tt1->tag_length < TSOL_TT1_MIN_LENGTH ||
649	    tt1->tag_length > TSOL_TT1_MAX_LENGTH ||
650	    tt1->tag_length + TSOL_CIPSO_TAG_OFFSET > co->cipso_length)
651		return (B_FALSE);
652
653	bsllow(sl);	/* assumed: sets compartments to all zeroes */
654	LCLASS_SET((_bslabel_impl_t *)sl, tt1->tag_sl);
655	bcopy(tt1->tag_cat, &((_bslabel_impl_t *)sl)->compartments,
656	    tt1->tag_length - TSOL_TT1_MIN_LENGTH);
657	return (B_TRUE);
658}
659
660/*
661 * Parse the CIPSO label in the incoming packet and construct a ts_label_t
662 * that reflects the CIPSO label and attach it to the dblk cred. Later as
663 * the mblk flows up through the stack any code that needs to examine the
664 * packet label can inspect the label from the dblk cred. This function is
665 * called right in ip_rput for all packets, i.e. locally destined and
666 * to be forwarded packets. The forwarding path needs to examine the label
667 * to determine how to forward the packet.
668 *
669 * This routine pulls all message text up into the first mblk.
670 * For IPv4, only the first 20 bytes of the IP header are guaranteed
671 * to exist. For IPv6, only the IPv6 header is guaranteed to exist.
672 */
673boolean_t
674tsol_get_pkt_label(mblk_t *mp, int version)
675{
676	tsol_tpc_t	*src_rhtp;
677	uchar_t		*opt_ptr = NULL;
678	const ipha_t	*ipha;
679	bslabel_t	sl;
680	uint32_t	doi;
681	tsol_ip_label_t	label_type;
682	const cipso_option_t *co;
683	const void	*src;
684	const ip6_t	*ip6h;
685	cred_t		*credp;
686	pid_t		cpid;
687
688	ASSERT(DB_TYPE(mp) == M_DATA);
689
690	if (mp->b_cont != NULL && !pullupmsg(mp, -1))
691		return (B_FALSE);
692
693	if (version == IPV4_VERSION) {
694		ASSERT(MBLKL(mp) >= IP_SIMPLE_HDR_LENGTH);
695		ipha = (const ipha_t *)mp->b_rptr;
696		src = &ipha->ipha_src;
697		if (!tsol_get_option_v4(mp, &label_type, &opt_ptr))
698			return (B_FALSE);
699	} else {
700		ASSERT(MBLKL(mp) >= IPV6_HDR_LEN);
701		ip6h = (const ip6_t *)mp->b_rptr;
702		src = &ip6h->ip6_src;
703		if (!tsol_get_option_v6(mp, &label_type, &opt_ptr))
704			return (B_FALSE);
705	}
706
707	switch (label_type) {
708	case OPT_CIPSO:
709		/*
710		 * Convert the CIPSO label to the internal format
711		 * and attach it to the dblk cred.
712		 * Validity checks based on restrictions defined in
713		 * COMMERCIAL IP SECURITY OPTION (CIPSO 2.2)
714		 * (draft-ietf-cipso-ipsecurity)
715		 */
716		if (version == IPV6_VERSION && ip6opt_ls == 0)
717			return (B_FALSE);
718		co = (const struct cipso_option *)opt_ptr;
719		if ((co->cipso_length <
720		    TSOL_CIPSO_TAG_OFFSET + TSOL_TT1_MIN_LENGTH) ||
721		    (co->cipso_length > IP_MAX_OPT_LENGTH))
722			return (B_FALSE);
723		bcopy(co->cipso_doi, &doi, sizeof (doi));
724		doi = ntohl(doi);
725		if (!cipso_to_sl(opt_ptr, &sl))
726			return (B_FALSE);
727		setbltype(&sl, SUN_SL_ID);
728		break;
729
730	case OPT_NONE:
731		/*
732		 * Handle special cases that are not currently labeled, even
733		 * though the sending system may otherwise be configured as
734		 * labeled.
735		 *	- IGMP
736		 *	- IPv4 ICMP Router Discovery
737		 *	- IPv6 Neighbor Discovery
738		 */
739		if (version == IPV4_VERSION) {
740			if (ipha->ipha_protocol == IPPROTO_IGMP)
741				return (B_TRUE);
742			if (ipha->ipha_protocol == IPPROTO_ICMP) {
743				const struct icmp *icmp = (const struct icmp *)
744				    (mp->b_rptr + IPH_HDR_LENGTH(ipha));
745
746				if ((uchar_t *)icmp + ICMP_MINLEN > mp->b_wptr)
747					return (B_FALSE);
748				if (icmp->icmp_type == ICMP_ROUTERADVERT ||
749				    icmp->icmp_type == ICMP_ROUTERSOLICIT)
750					return (B_TRUE);
751			}
752		} else {
753			if (ip6h->ip6_nxt == IPPROTO_ICMPV6) {
754				const icmp6_t *icmp6 = (const icmp6_t *)
755				    (mp->b_rptr + IPV6_HDR_LEN);
756
757				if ((uchar_t *)icmp6 + ICMP6_MINLEN >
758				    mp->b_wptr)
759					return (B_FALSE);
760				if (icmp6->icmp6_type >= MLD_LISTENER_QUERY &&
761				    icmp6->icmp6_type <= ICMP6_MAX_INFO_TYPE)
762					return (B_TRUE);
763			}
764		}
765
766		/*
767		 * Look up the tnrhtp database and get the implicit label
768		 * that is associated with this unlabeled host and attach
769		 * it to the packet.
770		 */
771		if ((src_rhtp = find_tpc(src, version, B_FALSE)) == NULL)
772			return (B_FALSE);
773
774		/* If the sender is labeled, drop the unlabeled packet. */
775		if (src_rhtp->tpc_tp.host_type != UNLABELED) {
776			TPC_RELE(src_rhtp);
777			pr_addr_dbg("unlabeled packet forged from %s\n",
778			    version == IPV4_VERSION ? AF_INET : AF_INET6, src);
779			return (B_FALSE);
780		}
781
782		sl = src_rhtp->tpc_tp.tp_def_label;
783		setbltype(&sl, SUN_SL_ID);
784		doi = src_rhtp->tpc_tp.tp_doi;
785		TPC_RELE(src_rhtp);
786		break;
787
788	default:
789		return (B_FALSE);
790	}
791
792	/* Make sure no other thread is messing with this mblk */
793	ASSERT(DB_REF(mp) == 1);
794	/* Preserve db_cpid */
795	credp = msg_extractcred(mp, &cpid);
796	if (credp == NULL) {
797		credp = newcred_from_bslabel(&sl, doi, KM_NOSLEEP);
798	} else {
799		cred_t	*newcr;
800
801		newcr = copycred_from_bslabel(credp, &sl, doi,
802		    KM_NOSLEEP);
803		crfree(credp);
804		credp = newcr;
805	}
806	if (credp == NULL)
807		return (B_FALSE);
808	mblk_setcred(mp, credp, cpid);
809	crfree(credp);			/* mblk has ref on cred */
810
811	/*
812	 * If the source was unlabeled, then flag as such,
813	 * while remembering that CIPSO routers add headers.
814	 */
815	if (label_type == OPT_NONE) {
816		crgetlabel(credp)->tsl_flags |= TSLF_UNLABELED;
817	} else if (label_type == OPT_CIPSO) {
818		if ((src_rhtp = find_tpc(src, version, B_FALSE)) == NULL)
819			return (B_FALSE);
820		if (src_rhtp->tpc_tp.host_type == UNLABELED)
821			crgetlabel(credp)->tsl_flags |= TSLF_UNLABELED;
822		TPC_RELE(src_rhtp);
823	}
824
825	return (B_TRUE);
826}
827
828/*
829 * This routine determines whether the given packet should be accepted locally.
830 * It does a range/set check on the packet's label by looking up the given
831 * address in the remote host database.
832 */
833boolean_t
834tsol_receive_local(const mblk_t *mp, const void *addr, uchar_t version,
835    boolean_t shared_addr, const conn_t *connp)
836{
837	const cred_t *credp;
838	ts_label_t *plabel, *conn_plabel;
839	tsol_tpc_t *tp;
840	boolean_t retv;
841	const bslabel_t *label, *conn_label;
842
843	/*
844	 * The cases in which this can happen are:
845	 *	- IPv6 Router Alert, where ip_rput_data_v6 deliberately skips
846	 *	  over the label attachment process.
847	 *	- MLD output looped-back to ourselves.
848	 *	- IPv4 Router Discovery, where tsol_get_pkt_label intentionally
849	 *	  avoids the labeling process.
850	 * We trust that all valid paths in the code set the cred pointer when
851	 * needed.
852	 */
853	if ((credp = msg_getcred(mp, NULL)) == NULL)
854		return (B_TRUE);
855
856	/*
857	 * If this packet is from the inside (not a remote host) and has the
858	 * same zoneid as the selected destination, then no checks are
859	 * necessary.  Membership in the zone is enough proof.  This is
860	 * intended to be a hot path through this function.
861	 */
862	if (!crisremote(credp) &&
863	    crgetzone(credp) == crgetzone(connp->conn_cred))
864		return (B_TRUE);
865
866	plabel = crgetlabel(credp);
867	conn_plabel = crgetlabel(connp->conn_cred);
868	ASSERT(plabel != NULL && conn_plabel != NULL);
869
870	label = label2bslabel(plabel);
871	conn_label = label2bslabel(crgetlabel(connp->conn_cred));
872
873	/*
874	 * MLPs are always validated using the range and set of the local
875	 * address, even when the remote host is unlabeled.
876	 */
877	if (connp->conn_mlp_type == mlptBoth ||
878	/* LINTED: no consequent */
879	    connp->conn_mlp_type == (shared_addr ? mlptShared : mlptPrivate)) {
880		;
881
882	/*
883	 * If this is a packet from an unlabeled sender, then we must apply
884	 * different rules.  If the label is equal to the zone's label, then
885	 * it's allowed.  If it's not equal, but the zone is either the global
886	 * zone or the label is dominated by the zone's label, then allow it
887	 * as long as it's in the range configured for the destination.
888	 */
889	} else if (plabel->tsl_flags & TSLF_UNLABELED) {
890		if (plabel->tsl_doi == conn_plabel->tsl_doi &&
891		    blequal(label, conn_label))
892			return (B_TRUE);
893
894		/*
895		 * conn_zoneid is global for an exclusive stack, thus we use
896		 * conn_cred to get the zoneid
897		 */
898		if (!connp->conn_mac_exempt ||
899		    (crgetzoneid(connp->conn_cred) != GLOBAL_ZONEID &&
900		    (plabel->tsl_doi != conn_plabel->tsl_doi ||
901		    !bldominates(conn_label, label)))) {
902			DTRACE_PROBE3(
903			    tx__ip__log__drop__receivelocal__mac_unl,
904			    char *,
905			    "unlabeled packet mp(1) fails mac for conn(2)",
906			    mblk_t *, mp, conn_t *, connp);
907			return (B_FALSE);
908		}
909
910	/*
911	 * If this is a packet from a labeled sender, verify the
912	 * label on the packet matches the connection label.
913	 */
914	} else {
915		if (plabel->tsl_doi != conn_plabel->tsl_doi ||
916		    !blequal(label, conn_label)) {
917			DTRACE_PROBE3(tx__ip__log__drop__receivelocal__mac__slp,
918			    char *,
919			    "packet mp(1) failed label match to SLP conn(2)",
920			    mblk_t *, mp, conn_t *, connp);
921			return (B_FALSE);
922		}
923		/*
924		 * No further checks will be needed if this is a zone-
925		 * specific address because (1) The process for bringing up
926		 * the interface ensures the zone's label is within the zone-
927		 * specific address's valid label range; (2) For cases where
928		 * the conn is bound to the unspecified addresses, ip fanout
929		 * logic ensures conn's zoneid equals the dest addr's zoneid;
930		 * (3) Mac-exempt and mlp logic above already handle all
931		 * cases where the zone label may not be the same as the
932		 * conn label.
933		 */
934		if (!shared_addr)
935			return (B_TRUE);
936	}
937
938	tp = find_tpc(addr, version, B_FALSE);
939	if (tp == NULL) {
940		DTRACE_PROBE3(tx__ip__log__drop__receivelocal__no__tnr,
941		    char *, "dropping mp(1), host(2) lacks entry",
942		    mblk_t *, mp, void *, addr);
943		return (B_FALSE);
944	}
945
946	/*
947	 * The local host address should not be unlabeled at this point.  The
948	 * only way this can happen is that the destination isn't unicast.  We
949	 * assume that the packet should not have had a label, and thus should
950	 * have been handled by the TSLF_UNLABELED logic above.
951	 */
952	if (tp->tpc_tp.host_type == UNLABELED) {
953		retv = B_FALSE;
954		DTRACE_PROBE3(tx__ip__log__drop__receivelocal__flag, char *,
955		    "mp(1) unlabeled source, but tp is not unlabeled.",
956		    mblk_t *, mp, tsol_tpc_t *, tp);
957
958	} else if (tp->tpc_tp.host_type != SUN_CIPSO) {
959		retv = B_FALSE;
960		DTRACE_PROBE3(tx__ip__log__drop__receivelocal__tptype, char *,
961		    "delivering mp(1), found unrecognized tpc(2) type.",
962		    mblk_t *, mp, tsol_tpc_t *, tp);
963
964	} else if (plabel->tsl_doi != tp->tpc_tp.tp_doi) {
965		retv = B_FALSE;
966		DTRACE_PROBE3(tx__ip__log__drop__receivelocal__mac, char *,
967		    "mp(1) could not be delievered to tp(2), doi mismatch",
968		    mblk_t *, mp, tsol_tpc_t *, tp);
969
970	} else if (!_blinrange(label, &tp->tpc_tp.tp_sl_range_cipso) &&
971	    !blinlset(label, tp->tpc_tp.tp_sl_set_cipso)) {
972		retv = B_FALSE;
973		DTRACE_PROBE3(tx__ip__log__drop__receivelocal__mac, char *,
974		    "mp(1) could not be delievered to tp(2), bad mac",
975		    mblk_t *, mp, tsol_tpc_t *, tp);
976	} else {
977		retv = B_TRUE;
978	}
979
980	TPC_RELE(tp);
981
982	return (retv);
983}
984
985boolean_t
986tsol_can_accept_raw(mblk_t *mp, boolean_t check_host)
987{
988	ts_label_t	*plabel = NULL;
989	tsol_tpc_t	*src_rhtp, *dst_rhtp;
990	boolean_t	retv;
991	cred_t		*credp;
992
993	credp = msg_getcred(mp, NULL);
994	if (credp != NULL)
995		plabel = crgetlabel(credp);
996
997	/* We are bootstrapping or the internal template was never deleted */
998	if (plabel == NULL)
999		return (B_TRUE);
1000
1001	if (IPH_HDR_VERSION(mp->b_rptr) == IPV4_VERSION) {
1002		ipha_t *ipha = (ipha_t *)mp->b_rptr;
1003
1004		src_rhtp = find_tpc(&ipha->ipha_src, IPV4_VERSION,
1005		    B_FALSE);
1006		if (src_rhtp == NULL)
1007			return (B_FALSE);
1008		dst_rhtp = find_tpc(&ipha->ipha_dst, IPV4_VERSION,
1009		    B_FALSE);
1010	} else {
1011		ip6_t *ip6h = (ip6_t *)mp->b_rptr;
1012
1013		src_rhtp = find_tpc(&ip6h->ip6_src, IPV6_VERSION,
1014		    B_FALSE);
1015		if (src_rhtp == NULL)
1016			return (B_FALSE);
1017		dst_rhtp = find_tpc(&ip6h->ip6_dst, IPV6_VERSION,
1018		    B_FALSE);
1019	}
1020	if (dst_rhtp == NULL) {
1021		TPC_RELE(src_rhtp);
1022		return (B_FALSE);
1023	}
1024
1025	if (label2doi(plabel) != src_rhtp->tpc_tp.tp_doi) {
1026		retv = B_FALSE;
1027
1028	/*
1029	 * Check that the packet's label is in the correct range for labeled
1030	 * sender, or is equal to the default label for unlabeled sender.
1031	 */
1032	} else if ((src_rhtp->tpc_tp.host_type != UNLABELED &&
1033	    !_blinrange(label2bslabel(plabel),
1034	    &src_rhtp->tpc_tp.tp_sl_range_cipso) &&
1035	    !blinlset(label2bslabel(plabel),
1036	    src_rhtp->tpc_tp.tp_sl_set_cipso)) ||
1037	    (src_rhtp->tpc_tp.host_type == UNLABELED &&
1038	    !blequal(&plabel->tsl_label, &src_rhtp->tpc_tp.tp_def_label))) {
1039		retv = B_FALSE;
1040
1041	} else if (check_host) {
1042		retv = B_TRUE;
1043
1044	/*
1045	 * Until we have SL range in the Zone structure, pass it
1046	 * when our own address lookup returned an internal entry.
1047	 */
1048	} else switch (dst_rhtp->tpc_tp.host_type) {
1049	case UNLABELED:
1050		retv = B_TRUE;
1051		break;
1052
1053	case SUN_CIPSO:
1054		retv = _blinrange(label2bslabel(plabel),
1055		    &dst_rhtp->tpc_tp.tp_sl_range_cipso) ||
1056		    blinlset(label2bslabel(plabel),
1057		    dst_rhtp->tpc_tp.tp_sl_set_cipso);
1058		break;
1059
1060	default:
1061		retv = B_FALSE;
1062	}
1063	TPC_RELE(src_rhtp);
1064	TPC_RELE(dst_rhtp);
1065	return (retv);
1066}
1067
1068/*
1069 * This routine determines whether a response to a failed packet delivery or
1070 * connection should be sent back.  By default, the policy is to allow such
1071 * messages to be sent at all times, as these messages reveal little useful
1072 * information and are healthy parts of TCP/IP networking.
1073 *
1074 * If tsol_strict_error is set, then we do strict tests: if the packet label is
1075 * within the label range/set of this host/zone, return B_TRUE; otherwise
1076 * return B_FALSE, which causes the packet to be dropped silently.
1077 *
1078 * Note that tsol_get_pkt_label will cause the packet to drop if the sender is
1079 * marked as labeled in the remote host database, but the packet lacks a label.
1080 * This means that we don't need to do a lookup on the source; the
1081 * TSLF_UNLABELED flag is sufficient.
1082 */
1083boolean_t
1084tsol_can_reply_error(const mblk_t *mp)
1085{
1086	ts_label_t	*plabel = NULL;
1087	tsol_tpc_t	*rhtp;
1088	const ipha_t	*ipha;
1089	const ip6_t	*ip6h;
1090	boolean_t	retv;
1091	bslabel_t	*pktbs;
1092	cred_t		*credp;
1093
1094	/* Caller must pull up at least the IP header */
1095	ASSERT(MBLKL(mp) >= (IPH_HDR_VERSION(mp->b_rptr) == IPV4_VERSION ?
1096	    sizeof (*ipha) : sizeof (*ip6h)));
1097
1098	if (!tsol_strict_error)
1099		return (B_TRUE);
1100
1101	credp = msg_getcred(mp, NULL);
1102	if (credp != NULL)
1103		plabel = crgetlabel(credp);
1104
1105	/* We are bootstrapping or the internal template was never deleted */
1106	if (plabel == NULL)
1107		return (B_TRUE);
1108
1109	if (IPH_HDR_VERSION(mp->b_rptr) == IPV4_VERSION) {
1110		ipha = (const ipha_t *)mp->b_rptr;
1111		rhtp = find_tpc(&ipha->ipha_dst, IPV4_VERSION, B_FALSE);
1112	} else {
1113		ip6h = (const ip6_t *)mp->b_rptr;
1114		rhtp = find_tpc(&ip6h->ip6_dst, IPV6_VERSION, B_FALSE);
1115	}
1116
1117	if (rhtp == NULL || label2doi(plabel) != rhtp->tpc_tp.tp_doi) {
1118		retv = B_FALSE;
1119	} else {
1120		/*
1121		 * If we're in the midst of forwarding, then the destination
1122		 * address might not be labeled.  In that case, allow unlabeled
1123		 * packets through only if the default label is the same, and
1124		 * labeled ones if they dominate.
1125		 */
1126		pktbs = label2bslabel(plabel);
1127		switch (rhtp->tpc_tp.host_type) {
1128		case UNLABELED:
1129			if (plabel->tsl_flags & TSLF_UNLABELED) {
1130				retv = blequal(pktbs,
1131				    &rhtp->tpc_tp.tp_def_label);
1132			} else {
1133				retv = bldominates(pktbs,
1134				    &rhtp->tpc_tp.tp_def_label);
1135			}
1136			break;
1137
1138		case SUN_CIPSO:
1139			retv = _blinrange(pktbs,
1140			    &rhtp->tpc_tp.tp_sl_range_cipso) ||
1141			    blinlset(pktbs, rhtp->tpc_tp.tp_sl_set_cipso);
1142			break;
1143
1144		default:
1145			retv = B_FALSE;
1146			break;
1147		}
1148	}
1149
1150	if (rhtp != NULL)
1151		TPC_RELE(rhtp);
1152
1153	return (retv);
1154}
1155
1156/*
1157 * Finds the zone associated with the given packet.  Returns GLOBAL_ZONEID if
1158 * the zone cannot be located.
1159 *
1160 * This is used by the classifier when the packet matches an ALL_ZONES IRE, and
1161 * there's no MLP defined.
1162 *
1163 * Note that we assume that this is only invoked in the ALL_ZONES case.
1164 * Handling other cases would require handle exclusive stack zones where either
1165 * this routine or the callers would have to map from
1166 * the zoneid (zone->zone_id) to what IP uses in conn_zoneid etc.
1167 */
1168zoneid_t
1169tsol_packet_to_zoneid(const mblk_t *mp)
1170{
1171	cred_t *cr = msg_getcred(mp, NULL);
1172	zone_t *zone;
1173	ts_label_t *label;
1174
1175	if (cr != NULL) {
1176		if ((label = crgetlabel(cr)) != NULL) {
1177			zone = zone_find_by_label(label);
1178			if (zone != NULL) {
1179				zoneid_t zoneid = zone->zone_id;
1180
1181				zone_rele(zone);
1182				return (zoneid);
1183			}
1184		}
1185	}
1186	return (GLOBAL_ZONEID);
1187}
1188
1189int
1190tsol_ire_match_gwattr(ire_t *ire, const ts_label_t *tsl)
1191{
1192	int		error = 0;
1193	tsol_ire_gw_secattr_t *attrp = NULL;
1194	tsol_tnrhc_t	*gw_rhc = NULL;
1195	tsol_gcgrp_t	*gcgrp = NULL;
1196	tsol_gc_t	*gc = NULL;
1197	in_addr_t	ga_addr4;
1198	void		*paddr = NULL;
1199
1200	/* Not in Trusted mode or IRE is local/loopback/broadcast/interface */
1201	if (!is_system_labeled() ||
1202	    (ire->ire_type & (IRE_LOCAL | IRE_LOOPBACK | IRE_BROADCAST |
1203	    IRE_INTERFACE)))
1204		goto done;
1205
1206	/*
1207	 * If we don't have a label to compare with, or the IRE does not
1208	 * contain any gateway security attributes, there's not much that
1209	 * we can do.  We let the former case pass, and the latter fail,
1210	 * since the IRE doesn't qualify for a match due to the lack of
1211	 * security attributes.
1212	 */
1213	if (tsl == NULL || ire->ire_gw_secattr == NULL) {
1214		if (tsl != NULL) {
1215			DTRACE_PROBE3(tx__ip__log__drop__irematch__nogwsec,
1216			    char *,
1217			    "ire(1) lacks ire_gw_secattr matching label(2)",
1218			    ire_t *, ire, ts_label_t *, tsl);
1219			error = EACCES;
1220		}
1221		goto done;
1222	}
1223
1224	attrp = ire->ire_gw_secattr;
1225
1226	/*
1227	 * The possible lock order scenarios related to the tsol gateway
1228	 * attribute locks are documented at the beginning of ip.c in the
1229	 * lock order scenario section.
1230	 */
1231	mutex_enter(&attrp->igsa_lock);
1232
1233	/*
1234	 * Depending on the IRE type (prefix vs. cache), we seek the group
1235	 * structure which contains all security credentials of the gateway.
1236	 * A prefix IRE is associated with at most one gateway credential,
1237	 * while a cache IRE is associated with every credentials that the
1238	 * gateway has.
1239	 */
1240	if ((gc = attrp->igsa_gc) != NULL) {			/* prefix */
1241		gcgrp = gc->gc_grp;
1242		ASSERT(gcgrp != NULL);
1243		rw_enter(&gcgrp->gcgrp_rwlock, RW_READER);
1244	} else if ((gcgrp = attrp->igsa_gcgrp) != NULL) {	/* cache */
1245		rw_enter(&gcgrp->gcgrp_rwlock, RW_READER);
1246		gc = gcgrp->gcgrp_head;
1247		if (gc == NULL) {
1248			/* gc group is empty, so the drop lock now */
1249			ASSERT(gcgrp->gcgrp_count == 0);
1250			rw_exit(&gcgrp->gcgrp_rwlock);
1251			gcgrp = NULL;
1252		}
1253	}
1254
1255	if (gcgrp != NULL)
1256		GCGRP_REFHOLD(gcgrp);
1257
1258	if ((gw_rhc = attrp->igsa_rhc) != NULL) {
1259		/*
1260		 * If our cached entry has grown stale, then discard it so we
1261		 * can get a new one.
1262		 */
1263		if (gw_rhc->rhc_invalid || gw_rhc->rhc_tpc->tpc_invalid) {
1264			TNRHC_RELE(gw_rhc);
1265			attrp->igsa_rhc = gw_rhc = NULL;
1266		} else {
1267			TNRHC_HOLD(gw_rhc)
1268		}
1269	}
1270
1271	/* Last attempt at loading the template had failed; try again */
1272	if (gw_rhc == NULL) {
1273		if (gcgrp != NULL) {
1274			tsol_gcgrp_addr_t *ga = &gcgrp->gcgrp_addr;
1275
1276			if (ire->ire_ipversion == IPV4_VERSION) {
1277				ASSERT(ga->ga_af == AF_INET);
1278				IN6_V4MAPPED_TO_IPADDR(&ga->ga_addr, ga_addr4);
1279				paddr = &ga_addr4;
1280			} else {
1281				ASSERT(ga->ga_af == AF_INET6);
1282				paddr = &ga->ga_addr;
1283			}
1284		} else if (ire->ire_ipversion == IPV6_VERSION &&
1285		    !IN6_IS_ADDR_UNSPECIFIED(&ire->ire_gateway_addr_v6)) {
1286			paddr = &ire->ire_gateway_addr_v6;
1287		} else if (ire->ire_ipversion == IPV4_VERSION &&
1288		    ire->ire_gateway_addr != INADDR_ANY) {
1289			paddr = &ire->ire_gateway_addr;
1290		}
1291
1292		/* We've found a gateway address to do the template lookup */
1293		if (paddr != NULL) {
1294			ASSERT(gw_rhc == NULL);
1295			gw_rhc = find_rhc(paddr, ire->ire_ipversion, B_FALSE);
1296			if (gw_rhc != NULL) {
1297				/*
1298				 * Note that if the lookup above returned an
1299				 * internal template, we'll use it for the
1300				 * time being, and do another lookup next
1301				 * time around.
1302				 */
1303				/* Another thread has loaded the template? */
1304				if (attrp->igsa_rhc != NULL) {
1305					TNRHC_RELE(gw_rhc)
1306					/* reload, it could be different */
1307					gw_rhc = attrp->igsa_rhc;
1308				} else {
1309					attrp->igsa_rhc = gw_rhc;
1310				}
1311				/*
1312				 * Hold an extra reference just like we did
1313				 * above prior to dropping the igsa_lock.
1314				 */
1315				TNRHC_HOLD(gw_rhc)
1316			}
1317		}
1318	}
1319
1320	mutex_exit(&attrp->igsa_lock);
1321	/* Gateway template not found */
1322	if (gw_rhc == NULL) {
1323		/*
1324		 * If destination address is directly reachable through an
1325		 * interface rather than through a learned route, pass it.
1326		 */
1327		if (paddr != NULL) {
1328			DTRACE_PROBE3(
1329			    tx__ip__log__drop__irematch__nogwtmpl, char *,
1330			    "ire(1), label(2) off-link with no gw_rhc",
1331			    ire_t *, ire, ts_label_t *, tsl);
1332			error = EINVAL;
1333		}
1334		goto done;
1335	}
1336
1337	if (gc != NULL) {
1338		tsol_gcdb_t *gcdb;
1339		/*
1340		 * In the case of IRE_CACHE we've got one or more gateway
1341		 * security credentials to compare against the passed in label.
1342		 * Perform label range comparison against each security
1343		 * credential of the gateway. In the case of a prefix ire
1344		 * we need to match against the security attributes of
1345		 * just the route itself, so the loop is executed only once.
1346		 */
1347		ASSERT(gcgrp != NULL);
1348		do {
1349			gcdb = gc->gc_db;
1350			if (tsl->tsl_doi == gcdb->gcdb_doi &&
1351			    _blinrange(&tsl->tsl_label, &gcdb->gcdb_slrange))
1352				break;
1353			if (ire->ire_type == IRE_CACHE)
1354				gc = gc->gc_next;
1355			else
1356				gc = NULL;
1357		} while (gc != NULL);
1358
1359		if (gc == NULL) {
1360			DTRACE_PROBE3(
1361			    tx__ip__log__drop__irematch__nogcmatched,
1362			    char *, "ire(1), tsl(2): all gc failed match",
1363			    ire_t *, ire, ts_label_t *, tsl);
1364			error = EACCES;
1365		}
1366	} else {
1367		/*
1368		 * We didn't find any gateway credentials in the IRE
1369		 * attributes; fall back to the gateway's template for
1370		 * label range checks, if we are required to do so.
1371		 */
1372		ASSERT(gw_rhc != NULL);
1373		switch (gw_rhc->rhc_tpc->tpc_tp.host_type) {
1374		case SUN_CIPSO:
1375			if (tsl->tsl_doi != gw_rhc->rhc_tpc->tpc_tp.tp_doi ||
1376			    (!_blinrange(&tsl->tsl_label,
1377			    &gw_rhc->rhc_tpc->tpc_tp.tp_sl_range_cipso) &&
1378			    !blinlset(&tsl->tsl_label,
1379			    gw_rhc->rhc_tpc->tpc_tp.tp_sl_set_cipso))) {
1380				error = EACCES;
1381				DTRACE_PROBE4(
1382				    tx__ip__log__drop__irematch__deftmpl,
1383				    char *, "ire(1), tsl(2), gw_rhc(3) "
1384				    "failed match (cipso gw)",
1385				    ire_t *, ire, ts_label_t *, tsl,
1386				    tsol_tnrhc_t *, gw_rhc);
1387			}
1388			break;
1389
1390		case UNLABELED:
1391			if (tsl->tsl_doi != gw_rhc->rhc_tpc->tpc_tp.tp_doi ||
1392			    (!_blinrange(&tsl->tsl_label,
1393			    &gw_rhc->rhc_tpc->tpc_tp.tp_gw_sl_range) &&
1394			    !blinlset(&tsl->tsl_label,
1395			    gw_rhc->rhc_tpc->tpc_tp.tp_gw_sl_set))) {
1396				error = EACCES;
1397				DTRACE_PROBE4(
1398				    tx__ip__log__drop__irematch__deftmpl,
1399				    char *, "ire(1), tsl(2), gw_rhc(3) "
1400				    "failed match (unlabeled gw)",
1401				    ire_t *, ire, ts_label_t *, tsl,
1402				    tsol_tnrhc_t *, gw_rhc);
1403			}
1404			break;
1405		}
1406	}
1407
1408done:
1409
1410	if (gcgrp != NULL) {
1411		rw_exit(&gcgrp->gcgrp_rwlock);
1412		GCGRP_REFRELE(gcgrp);
1413	}
1414
1415	if (gw_rhc != NULL)
1416		TNRHC_RELE(gw_rhc)
1417
1418	return (error);
1419}
1420
1421/*
1422 * Performs label accreditation checks for packet forwarding.
1423 *
1424 * Returns a pointer to the modified mblk if allowed for forwarding,
1425 * or NULL if the packet must be dropped.
1426 */
1427mblk_t *
1428tsol_ip_forward(ire_t *ire, mblk_t *mp)
1429{
1430	tsol_ire_gw_secattr_t *attrp = NULL;
1431	ipha_t		*ipha;
1432	ip6_t		*ip6h;
1433	const void	*pdst;
1434	const void	*psrc;
1435	boolean_t	off_link;
1436	tsol_tpc_t	*dst_rhtp, *gw_rhtp;
1437	tsol_ip_label_t label_type;
1438	uchar_t		*opt_ptr = NULL;
1439	ts_label_t	*tsl;
1440	uint8_t		proto;
1441	int		af, adjust;
1442	uint16_t	iplen;
1443	boolean_t	need_tpc_rele = B_FALSE;
1444	ipaddr_t	*gw;
1445	ip_stack_t	*ipst = ire->ire_ipst;
1446	cred_t		*credp;
1447	pid_t		pid;
1448
1449	ASSERT(ire != NULL && mp != NULL);
1450	ASSERT(ire->ire_stq != NULL);
1451
1452	af = (ire->ire_ipversion == IPV4_VERSION) ? AF_INET : AF_INET6;
1453
1454	if (IPH_HDR_VERSION(mp->b_rptr) == IPV4_VERSION) {
1455		ASSERT(ire->ire_ipversion == IPV4_VERSION);
1456		ipha = (ipha_t *)mp->b_rptr;
1457		psrc = &ipha->ipha_src;
1458		pdst = &ipha->ipha_dst;
1459		proto = ipha->ipha_protocol;
1460
1461		/*
1462		 * off_link is TRUE if destination not directly reachable.
1463		 * Surya note: we avoid creation of per-dst IRE_CACHE entries
1464		 * for forwarded packets, so we set off_link to be TRUE
1465		 * if the packet dst is different from the ire_addr of
1466		 * the ire for the nexthop.
1467		 */
1468		off_link = ((ipha->ipha_dst != ire->ire_addr) ||
1469		    (ire->ire_gateway_addr != INADDR_ANY));
1470		if (!tsol_get_option_v4(mp, &label_type, &opt_ptr))
1471			return (NULL);
1472	} else {
1473		ASSERT(ire->ire_ipversion == IPV6_VERSION);
1474		ip6h = (ip6_t *)mp->b_rptr;
1475		psrc = &ip6h->ip6_src;
1476		pdst = &ip6h->ip6_dst;
1477		proto = ip6h->ip6_nxt;
1478
1479		if (proto != IPPROTO_TCP && proto != IPPROTO_UDP &&
1480		    proto != IPPROTO_ICMPV6) {
1481			uint8_t *nexthdrp;
1482			uint16_t hdr_len;
1483
1484			if (!ip_hdr_length_nexthdr_v6(mp, ip6h, &hdr_len,
1485			    &nexthdrp)) {
1486				/* malformed packet; drop it */
1487				return (NULL);
1488			}
1489			proto = *nexthdrp;
1490		}
1491
1492		/* destination not directly reachable? */
1493		off_link = !IN6_IS_ADDR_UNSPECIFIED(&ire->ire_gateway_addr_v6);
1494		if (!tsol_get_option_v6(mp, &label_type, &opt_ptr))
1495			return (NULL);
1496	}
1497
1498	if ((tsl = msg_getlabel(mp)) == NULL)
1499		return (mp);
1500
1501	ASSERT(psrc != NULL && pdst != NULL);
1502	dst_rhtp = find_tpc(pdst, ire->ire_ipversion, B_FALSE);
1503
1504	if (dst_rhtp == NULL) {
1505		/*
1506		 * Without a template we do not know if forwarding
1507		 * violates MAC
1508		 */
1509		DTRACE_PROBE3(tx__ip__log__drop__forward__nodst, char *,
1510		    "mp(1) dropped, no template for destination ip4|6(2)",
1511		    mblk_t *, mp, void *, pdst);
1512		return (NULL);
1513	}
1514
1515	/*
1516	 * Gateway template must have existed for off-link destinations,
1517	 * since tsol_ire_match_gwattr has ensured such condition.
1518	 */
1519	if (ire->ire_ipversion == IPV4_VERSION && off_link) {
1520		/*
1521		 * Surya note: first check if we can get the gw_rhtp from
1522		 * the ire_gw_secattr->igsa_rhc; if this is null, then
1523		 * do a lookup based on the ire_addr (address of gw)
1524		 */
1525		if (ire->ire_gw_secattr != NULL &&
1526		    ire->ire_gw_secattr->igsa_rhc != NULL) {
1527			attrp = ire->ire_gw_secattr;
1528			gw_rhtp = attrp->igsa_rhc->rhc_tpc;
1529		} else  {
1530			/*
1531			 * use the ire_addr if this is the IRE_CACHE of nexthop
1532			 */
1533			gw = (ire->ire_gateway_addr == NULL? &ire->ire_addr :
1534			    &ire->ire_gateway_addr);
1535			gw_rhtp = find_tpc(gw, ire->ire_ipversion, B_FALSE);
1536			need_tpc_rele = B_TRUE;
1537		}
1538		if (gw_rhtp == NULL) {
1539			DTRACE_PROBE3(tx__ip__log__drop__forward__nogw, char *,
1540			    "mp(1) dropped, no gateway in ire attributes(2)",
1541			    mblk_t *, mp, tsol_ire_gw_secattr_t *, attrp);
1542			mp = NULL;
1543			goto keep_label;
1544		}
1545	}
1546	if (ire->ire_ipversion == IPV6_VERSION &&
1547	    ((attrp = ire->ire_gw_secattr) == NULL || attrp->igsa_rhc == NULL ||
1548	    (gw_rhtp = attrp->igsa_rhc->rhc_tpc) == NULL) && off_link) {
1549		DTRACE_PROBE3(tx__ip__log__drop__forward__nogw, char *,
1550		    "mp(1) dropped, no gateway in ire attributes(2)",
1551		    mblk_t *, mp, tsol_ire_gw_secattr_t *, attrp);
1552		mp = NULL;
1553		goto keep_label;
1554	}
1555
1556	/*
1557	 * Check that the label for the packet is acceptable
1558	 * by destination host; otherwise, drop it.
1559	 */
1560	switch (dst_rhtp->tpc_tp.host_type) {
1561	case SUN_CIPSO:
1562		if (tsl->tsl_doi != dst_rhtp->tpc_tp.tp_doi ||
1563		    (!_blinrange(&tsl->tsl_label,
1564		    &dst_rhtp->tpc_tp.tp_sl_range_cipso) &&
1565		    !blinlset(&tsl->tsl_label,
1566		    dst_rhtp->tpc_tp.tp_sl_set_cipso))) {
1567			DTRACE_PROBE4(tx__ip__log__drop__forward__mac, char *,
1568			    "labeled packet mp(1) dropped, label(2) fails "
1569			    "destination(3) accredation check",
1570			    mblk_t *, mp, ts_label_t *, tsl,
1571			    tsol_tpc_t *, dst_rhtp);
1572			mp = NULL;
1573			goto keep_label;
1574		}
1575		break;
1576
1577
1578	case UNLABELED:
1579		if (tsl->tsl_doi != dst_rhtp->tpc_tp.tp_doi ||
1580		    !blequal(&dst_rhtp->tpc_tp.tp_def_label,
1581		    &tsl->tsl_label)) {
1582			DTRACE_PROBE4(tx__ip__log__drop__forward__mac, char *,
1583			    "unlabeled packet mp(1) dropped, label(2) fails "
1584			    "destination(3) accredation check",
1585			    mblk_t *, mp, ts_label_t *, tsl,
1586			    tsol_tpc_t *, dst_rhtp);
1587			mp = NULL;
1588			goto keep_label;
1589		}
1590		break;
1591	}
1592	if (label_type == OPT_CIPSO) {
1593		/*
1594		 * We keep the label on any of the following cases:
1595		 *
1596		 *   1. The destination is labeled (on/off-link).
1597		 *   2. The unlabeled destination is off-link,
1598		 *	and the next hop gateway is labeled.
1599		 */
1600		if (dst_rhtp->tpc_tp.host_type != UNLABELED ||
1601		    (off_link &&
1602		    gw_rhtp->tpc_tp.host_type != UNLABELED))
1603			goto keep_label;
1604
1605		/*
1606		 * Strip off the CIPSO option from the packet because: the
1607		 * unlabeled destination host is directly reachable through
1608		 * an interface (on-link); or, the unlabeled destination host
1609		 * is not directly reachable (off-link), and the next hop
1610		 * gateway is unlabeled.
1611		 */
1612		adjust = (af == AF_INET) ? tsol_remove_secopt(ipha, MBLKL(mp)) :
1613		    tsol_remove_secopt_v6(ip6h, MBLKL(mp));
1614
1615		ASSERT(adjust <= 0);
1616		if (adjust != 0) {
1617
1618			/* adjust is negative */
1619			ASSERT((mp->b_wptr + adjust) >= mp->b_rptr);
1620			mp->b_wptr += adjust;
1621
1622			if (af == AF_INET) {
1623				ipha = (ipha_t *)mp->b_rptr;
1624				iplen = ntohs(ipha->ipha_length) + adjust;
1625				ipha->ipha_length = htons(iplen);
1626				ipha->ipha_hdr_checksum = 0;
1627				ipha->ipha_hdr_checksum = ip_csum_hdr(ipha);
1628			}
1629			DTRACE_PROBE3(tx__ip__log__info__forward__adjust,
1630			    char *,
1631			    "mp(1) adjusted(2) for CIPSO option removal",
1632			    mblk_t *, mp, int, adjust);
1633		}
1634		goto keep_label;
1635	}
1636
1637	ASSERT(label_type == OPT_NONE);
1638	ASSERT(dst_rhtp != NULL);
1639
1640	/*
1641	 * We need to add CIPSO option if the destination or the next hop
1642	 * gateway is labeled.  Otherwise, pass the packet as is.
1643	 */
1644	if (dst_rhtp->tpc_tp.host_type == UNLABELED &&
1645	    (!off_link || gw_rhtp->tpc_tp.host_type == UNLABELED))
1646		goto keep_label;
1647
1648
1649	credp = msg_getcred(mp, &pid);
1650	if ((af == AF_INET &&
1651	    tsol_check_label(credp, &mp, B_FALSE, ipst, pid) != 0) ||
1652	    (af == AF_INET6 &&
1653	    tsol_check_label_v6(credp, &mp, B_FALSE, ipst, pid) != 0)) {
1654		mp = NULL;
1655		goto keep_label;
1656	}
1657
1658	if (af == AF_INET) {
1659		ipha = (ipha_t *)mp->b_rptr;
1660		ipha->ipha_hdr_checksum = 0;
1661		ipha->ipha_hdr_checksum = ip_csum_hdr(ipha);
1662	}
1663
1664keep_label:
1665	TPC_RELE(dst_rhtp);
1666	if (need_tpc_rele && gw_rhtp != NULL)
1667		TPC_RELE(gw_rhtp);
1668	return (mp);
1669}
1670
1671/*
1672 * Name:	tsol_pmtu_adjust()
1673 *
1674 * Returns the adjusted mtu after removing security option.
1675 * Removes/subtracts the option if the packet's cred indicates an unlabeled
1676 * sender or if pkt_diff indicates this system enlarged the packet.
1677 */
1678uint32_t
1679tsol_pmtu_adjust(mblk_t *mp, uint32_t mtu, int pkt_diff, int af)
1680{
1681	int		label_adj = 0;
1682	uint32_t	min_mtu = IP_MIN_MTU;
1683	tsol_tpc_t	*src_rhtp;
1684	void		*src;
1685
1686	/*
1687	 * Note: label_adj is non-positive, indicating the number of
1688	 * bytes removed by removing the security option from the
1689	 * header.
1690	 */
1691	if (af == AF_INET6) {
1692		ip6_t	*ip6h;
1693
1694		min_mtu = IPV6_MIN_MTU;
1695		ip6h = (ip6_t *)mp->b_rptr;
1696		src = &ip6h->ip6_src;
1697		if ((src_rhtp = find_tpc(src, IPV6_VERSION, B_FALSE)) == NULL)
1698			return (mtu);
1699		if (pkt_diff > 0 || src_rhtp->tpc_tp.host_type == UNLABELED) {
1700			label_adj = tsol_remove_secopt_v6(
1701			    (ip6_t *)mp->b_rptr, MBLKL(mp));
1702		}
1703	} else {
1704		ipha_t    *ipha;
1705
1706		ASSERT(af == AF_INET);
1707		ipha = (ipha_t *)mp->b_rptr;
1708		src = &ipha->ipha_src;
1709		if ((src_rhtp = find_tpc(src, IPV4_VERSION, B_FALSE)) == NULL)
1710			return (mtu);
1711		if (pkt_diff > 0 || src_rhtp->tpc_tp.host_type == UNLABELED)
1712			label_adj = tsol_remove_secopt(
1713			    (ipha_t *)mp->b_rptr, MBLKL(mp));
1714	}
1715	/*
1716	 * Make pkt_diff non-negative and the larger of the bytes
1717	 * previously added (if any) or just removed, since label
1718	 * addition + subtraction may not be completely idempotent.
1719	 */
1720	if (pkt_diff < -label_adj)
1721		pkt_diff = -label_adj;
1722	if (pkt_diff > 0 && pkt_diff < mtu)
1723		mtu -= pkt_diff;
1724
1725	TPC_RELE(src_rhtp);
1726	return (MAX(mtu, min_mtu));
1727}
1728
1729/*
1730 * Name:	tsol_rtsa_init()
1731 *
1732 * Normal:	Sanity checks on the route security attributes provided by
1733 *		user.  Convert it into a route security parameter list to
1734 *		be returned to caller.
1735 *
1736 * Output:	EINVAL if bad security attributes in the routing message
1737 *		ENOMEM if unable to allocate data structures
1738 *		0 otherwise.
1739 *
1740 * Note:	On input, cp must point to the end of any addresses in
1741 *		the rt_msghdr_t structure.
1742 */
1743int
1744tsol_rtsa_init(rt_msghdr_t *rtm, tsol_rtsecattr_t *sp, caddr_t cp)
1745{
1746	uint_t	sacnt;
1747	int	err;
1748	caddr_t	lim;
1749	tsol_rtsecattr_t *tp;
1750
1751	ASSERT((cp >= (caddr_t)&rtm[1]) && sp != NULL);
1752
1753	/*
1754	 * In theory, we could accept as many security attributes configured
1755	 * per route destination.  However, the current design is limited
1756	 * such that at most only one set security attributes is allowed to
1757	 * be associated with a prefix IRE.  We therefore assert for now.
1758	 */
1759	/* LINTED */
1760	ASSERT(TSOL_RTSA_REQUEST_MAX == 1);
1761
1762	sp->rtsa_cnt = 0;
1763	lim = (caddr_t)rtm + rtm->rtm_msglen;
1764	ASSERT(cp <= lim);
1765
1766	if ((lim - cp) < sizeof (rtm_ext_t) ||
1767	    ((rtm_ext_t *)cp)->rtmex_type != RTMEX_GATEWAY_SECATTR)
1768		return (0);
1769
1770	if (((rtm_ext_t *)cp)->rtmex_len < sizeof (tsol_rtsecattr_t))
1771		return (EINVAL);
1772
1773	cp += sizeof (rtm_ext_t);
1774
1775	if ((lim - cp) < sizeof (*tp) ||
1776	    (tp = (tsol_rtsecattr_t *)cp, (sacnt = tp->rtsa_cnt) == 0) ||
1777	    (lim - cp) < TSOL_RTSECATTR_SIZE(sacnt))
1778		return (EINVAL);
1779
1780	/*
1781	 * Trying to add route security attributes when system
1782	 * labeling service is not available, or when user supllies
1783	 * more than the maximum number of security attributes
1784	 * allowed per request.
1785	 */
1786	if ((sacnt > 0 && !is_system_labeled()) ||
1787	    sacnt > TSOL_RTSA_REQUEST_MAX)
1788		return (EINVAL);
1789
1790	/* Ensure valid credentials */
1791	if ((err = rtsa_validate(&((tsol_rtsecattr_t *)cp)->
1792	    rtsa_attr[0])) != 0) {
1793		cp += sizeof (*sp);
1794		return (err);
1795	}
1796
1797	bcopy(cp, sp, sizeof (*sp));
1798	cp += sizeof (*sp);
1799	return (0);
1800}
1801
1802int
1803tsol_ire_init_gwattr(ire_t *ire, uchar_t ipversion, tsol_gc_t *gc,
1804    tsol_gcgrp_t *gcgrp)
1805{
1806	tsol_ire_gw_secattr_t *attrp;
1807	boolean_t exists = B_FALSE;
1808	in_addr_t ga_addr4;
1809	void *paddr = NULL;
1810
1811	ASSERT(ire != NULL);
1812
1813	/*
1814	 * The only time that attrp can be NULL is when this routine is
1815	 * called for the first time during the creation/initialization
1816	 * of the corresponding IRE.  It will only get cleared when the
1817	 * IRE is deleted.
1818	 */
1819	if ((attrp = ire->ire_gw_secattr) == NULL) {
1820		attrp = ire_gw_secattr_alloc(KM_NOSLEEP);
1821		if (attrp == NULL)
1822			return (ENOMEM);
1823		ire->ire_gw_secattr = attrp;
1824	} else {
1825		exists = B_TRUE;
1826		mutex_enter(&attrp->igsa_lock);
1827
1828		if (attrp->igsa_rhc != NULL) {
1829			TNRHC_RELE(attrp->igsa_rhc);
1830			attrp->igsa_rhc = NULL;
1831		}
1832
1833		if (attrp->igsa_gc != NULL)
1834			GC_REFRELE(attrp->igsa_gc);
1835		if (attrp->igsa_gcgrp != NULL)
1836			GCGRP_REFRELE(attrp->igsa_gcgrp);
1837	}
1838	ASSERT(!exists || MUTEX_HELD(&attrp->igsa_lock));
1839
1840	/*
1841	 * References already held by caller and we keep them;
1842	 * note that both gc and gcgrp may be set to NULL to
1843	 * clear out igsa_gc and igsa_gcgrp, respectively.
1844	 */
1845	attrp->igsa_gc = gc;
1846	attrp->igsa_gcgrp = gcgrp;
1847
1848	if (gcgrp == NULL && gc != NULL) {
1849		gcgrp = gc->gc_grp;
1850		ASSERT(gcgrp != NULL);
1851	}
1852
1853	/*
1854	 * Intialize the template for gateway; we use the gateway's
1855	 * address found in either the passed in gateway credential
1856	 * or group pointer, or the ire_gateway_addr{_v6} field.
1857	 */
1858	if (gcgrp != NULL) {
1859		tsol_gcgrp_addr_t *ga = &gcgrp->gcgrp_addr;
1860
1861		/*
1862		 * Caller is holding a reference, and that we don't
1863		 * need to hold any lock to access the address.
1864		 */
1865		if (ipversion == IPV4_VERSION) {
1866			ASSERT(ga->ga_af == AF_INET);
1867			IN6_V4MAPPED_TO_IPADDR(&ga->ga_addr, ga_addr4);
1868			paddr = &ga_addr4;
1869		} else {
1870			ASSERT(ga->ga_af == AF_INET6);
1871			paddr = &ga->ga_addr;
1872		}
1873	} else if (ipversion == IPV6_VERSION &&
1874	    !IN6_IS_ADDR_UNSPECIFIED(&ire->ire_gateway_addr_v6)) {
1875		paddr = &ire->ire_gateway_addr_v6;
1876	} else if (ipversion == IPV4_VERSION &&
1877	    ire->ire_gateway_addr != INADDR_ANY) {
1878		paddr = &ire->ire_gateway_addr;
1879	}
1880
1881	/*
1882	 * Lookup the gateway template; note that we could get an internal
1883	 * template here, which we cache anyway.  During IRE matching, we'll
1884	 * try to update this gateway template cache and hopefully get a
1885	 * real one.
1886	 */
1887	if (paddr != NULL) {
1888		attrp->igsa_rhc = find_rhc(paddr, ipversion, B_FALSE);
1889	}
1890
1891	if (exists)
1892		mutex_exit(&attrp->igsa_lock);
1893
1894	return (0);
1895}
1896
1897/*
1898 * This function figures the type of MLP that we'll be using based on the
1899 * address that the user is binding and the zone.  If the address is
1900 * unspecified, then we're looking at both private and shared.  If it's one
1901 * of the zone's private addresses, then it's private only.  If it's one
1902 * of the global addresses, then it's shared only.
1903 *
1904 * If we can't figure out what it is, then return mlptSingle.  That's actually
1905 * an error case.
1906 *
1907 * The callers are assume to pass in zone->zone_id and not the zoneid that
1908 * is stored in a conn_t (since the latter will be GLOBAL_ZONEID in an
1909 * exclusive stack zone).
1910 */
1911mlp_type_t
1912tsol_mlp_addr_type(zoneid_t zoneid, uchar_t version, const void *addr,
1913    ip_stack_t *ipst)
1914{
1915	in_addr_t in4;
1916	ire_t *ire;
1917	ipif_t *ipif;
1918	zoneid_t addrzone;
1919	zoneid_t ip_zoneid;
1920
1921	ASSERT(addr != NULL);
1922
1923	/*
1924	 * For exclusive stacks we set the zoneid to zero
1925	 * to operate as if in the global zone for IRE and conn_t comparisons.
1926	 */
1927	if (ipst->ips_netstack->netstack_stackid != GLOBAL_NETSTACKID)
1928		ip_zoneid = GLOBAL_ZONEID;
1929	else
1930		ip_zoneid = zoneid;
1931
1932	if (version == IPV6_VERSION &&
1933	    IN6_IS_ADDR_V4MAPPED((const in6_addr_t *)addr)) {
1934		IN6_V4MAPPED_TO_IPADDR((const in6_addr_t *)addr, in4);
1935		addr = &in4;
1936		version = IPV4_VERSION;
1937	}
1938
1939	if (version == IPV4_VERSION) {
1940		in4 = *(const in_addr_t *)addr;
1941		if (in4 == INADDR_ANY) {
1942			return (mlptBoth);
1943		}
1944		ire = ire_cache_lookup(in4, ip_zoneid, NULL, ipst);
1945	} else {
1946		if (IN6_IS_ADDR_UNSPECIFIED((const in6_addr_t *)addr)) {
1947			return (mlptBoth);
1948		}
1949		ire = ire_cache_lookup_v6(addr, ip_zoneid, NULL, ipst);
1950	}
1951	/*
1952	 * If we can't find the IRE, then we have to behave exactly like
1953	 * ip_bind_laddr{,_v6}.  That means looking up the IPIF so that users
1954	 * can bind to addresses on "down" interfaces.
1955	 *
1956	 * If we can't find that either, then the bind is going to fail, so
1957	 * just give up.  Note that there's a miniscule chance that the address
1958	 * is in transition, but we don't bother handling that.
1959	 */
1960	if (ire == NULL) {
1961		if (version == IPV4_VERSION)
1962			ipif = ipif_lookup_addr(*(const in_addr_t *)addr, NULL,
1963			    ip_zoneid, NULL, NULL, NULL, NULL, ipst);
1964		else
1965			ipif = ipif_lookup_addr_v6((const in6_addr_t *)addr,
1966			    NULL, ip_zoneid, NULL, NULL, NULL, NULL, ipst);
1967		if (ipif == NULL) {
1968			return (mlptSingle);
1969		}
1970		addrzone = ipif->ipif_zoneid;
1971		ipif_refrele(ipif);
1972	} else {
1973		addrzone = ire->ire_zoneid;
1974		ire_refrele(ire);
1975	}
1976	return (addrzone == ALL_ZONES ? mlptShared : mlptPrivate);
1977}
1978
1979/*
1980 * Since we are configuring local interfaces, and we know trusted
1981 * extension CDE requires local interfaces to be cipso host type in
1982 * order to function correctly, we'll associate a cipso template
1983 * to each local interface and let the interface come up.  Configuring
1984 * a local interface to be "unlabeled" host type is a configuration error.
1985 * We'll override that error and make the interface host type to be cipso
1986 * here.
1987 *
1988 * The code is optimized for the usual "success" case and unwinds things on
1989 * error.  We don't want to go to the trouble and expense of formatting the
1990 * interface name for the usual case where everything is configured correctly.
1991 */
1992boolean_t
1993tsol_check_interface_address(const ipif_t *ipif)
1994{
1995	tsol_tpc_t *tp;
1996	char addrbuf[INET6_ADDRSTRLEN];
1997	int af;
1998	const void *addr;
1999	zone_t *zone;
2000	ts_label_t *plabel;
2001	const bslabel_t *label;
2002	char ifbuf[LIFNAMSIZ + 10];
2003	const char *ifname;
2004	boolean_t retval;
2005	tsol_rhent_t rhent;
2006	netstack_t *ns = ipif->ipif_ill->ill_ipst->ips_netstack;
2007
2008	if (IN6_IS_ADDR_V4MAPPED(&ipif->ipif_v6lcl_addr)) {
2009		af = AF_INET;
2010		addr = &V4_PART_OF_V6(ipif->ipif_v6lcl_addr);
2011	} else {
2012		af = AF_INET6;
2013		addr = &ipif->ipif_v6lcl_addr;
2014	}
2015
2016	tp = find_tpc(&ipif->ipif_v6lcl_addr, IPV6_VERSION, B_FALSE);
2017
2018	/* assumes that ALL_ZONES implies that there is no exclusive stack */
2019	if (ipif->ipif_zoneid == ALL_ZONES) {
2020		zone = NULL;
2021	} else if (ns->netstack_stackid == GLOBAL_NETSTACKID) {
2022		/* Shared stack case */
2023		zone = zone_find_by_id(ipif->ipif_zoneid);
2024	} else {
2025		/* Exclusive stack case */
2026		zone = zone_find_by_id(crgetzoneid(ipif->ipif_ill->ill_credp));
2027	}
2028	if (zone != NULL) {
2029		plabel = zone->zone_slabel;
2030		ASSERT(plabel != NULL);
2031		label = label2bslabel(plabel);
2032	}
2033
2034	/*
2035	 * If it's CIPSO and an all-zones address, then we're done.
2036	 * If it's a CIPSO zone specific address, the zone's label
2037	 * must be in the range or set specified in the template.
2038	 * When the remote host entry is missing or the template
2039	 * type is incorrect for this interface, we create a
2040	 * CIPSO host entry in kernel and allow the interface to be
2041	 * brought up as CIPSO type.
2042	 */
2043	if (tp != NULL && (
2044	    /* The all-zones case */
2045	    (tp->tpc_tp.host_type == SUN_CIPSO &&
2046	    tp->tpc_tp.tp_doi == default_doi &&
2047	    ipif->ipif_zoneid == ALL_ZONES) ||
2048	    /* The local-zone case */
2049	    (zone != NULL && plabel->tsl_doi == tp->tpc_tp.tp_doi &&
2050	    ((tp->tpc_tp.host_type == SUN_CIPSO &&
2051	    (_blinrange(label, &tp->tpc_tp.tp_sl_range_cipso) ||
2052	    blinlset(label, tp->tpc_tp.tp_sl_set_cipso))))))) {
2053		if (zone != NULL)
2054			zone_rele(zone);
2055		TPC_RELE(tp);
2056		return (B_TRUE);
2057	}
2058
2059	ifname = ipif->ipif_ill->ill_name;
2060	if (ipif->ipif_id != 0) {
2061		(void) snprintf(ifbuf, sizeof (ifbuf), "%s:%u", ifname,
2062		    ipif->ipif_id);
2063		ifname = ifbuf;
2064	}
2065	(void) inet_ntop(af, addr, addrbuf, sizeof (addrbuf));
2066
2067	if (tp == NULL) {
2068		cmn_err(CE_NOTE, "template entry for %s missing. Default to "
2069		    "CIPSO type for %s", ifname, addrbuf);
2070		retval = B_TRUE;
2071	} else if (tp->tpc_tp.host_type == UNLABELED) {
2072		cmn_err(CE_NOTE, "template type for %s incorrectly configured. "
2073		    "Change to CIPSO type for %s", ifname, addrbuf);
2074		retval = B_TRUE;
2075	} else if (ipif->ipif_zoneid == ALL_ZONES) {
2076		if (tp->tpc_tp.host_type != SUN_CIPSO) {
2077			cmn_err(CE_NOTE, "%s failed: %s isn't set to CIPSO for "
2078			    "all-zones. Converted to CIPSO.", ifname, addrbuf);
2079			retval = B_TRUE;
2080		} else {
2081			cmn_err(CE_NOTE, "%s failed: %s has wrong DOI %d "
2082			    "instead of %d", ifname, addrbuf,
2083			    tp->tpc_tp.tp_doi, default_doi);
2084			retval = B_FALSE;
2085		}
2086	} else if (zone == NULL) {
2087		cmn_err(CE_NOTE, "%s failed: zoneid %d unknown",
2088		    ifname, ipif->ipif_zoneid);
2089		retval = B_FALSE;
2090	} else if (plabel->tsl_doi != tp->tpc_tp.tp_doi) {
2091		cmn_err(CE_NOTE, "%s failed: zone %s has DOI %d but %s has "
2092		    "DOI %d", ifname, zone->zone_name, plabel->tsl_doi,
2093		    addrbuf, tp->tpc_tp.tp_doi);
2094		retval = B_FALSE;
2095	} else {
2096		cmn_err(CE_NOTE, "%s failed: zone %s label incompatible with "
2097		    "%s", ifname, zone->zone_name, addrbuf);
2098		tsol_print_label(label, "zone label");
2099		retval = B_FALSE;
2100	}
2101
2102	if (zone != NULL)
2103		zone_rele(zone);
2104	if (tp != NULL)
2105		TPC_RELE(tp);
2106	if (retval) {
2107		/*
2108		 * we've corrected a config error and let the interface
2109		 * come up as cipso. Need to insert an rhent.
2110		 */
2111		if ((rhent.rh_address.ta_family = af) == AF_INET) {
2112			rhent.rh_prefix = 32;
2113			rhent.rh_address.ta_addr_v4 = *(struct in_addr *)addr;
2114		} else {
2115			rhent.rh_prefix = 128;
2116			rhent.rh_address.ta_addr_v6 = *(in6_addr_t *)addr;
2117		}
2118		(void) strcpy(rhent.rh_template, "cipso");
2119		if (tnrh_load(&rhent) != 0) {
2120			cmn_err(CE_NOTE, "%s failed: Cannot insert CIPSO "
2121			    "template for local addr %s", ifname, addrbuf);
2122			retval = B_FALSE;
2123		}
2124	}
2125	return (retval);
2126}
2127