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 2006 Sun Microsystems, Inc. All rights reserved. 23 * Use is subject to license terms. 24 */ 25 26 #pragma ident "%Z%%M% %I% %E% SMI" 27 28 #include <sys/systm.h> 29 #include <sys/types.h> 30 #include <sys/stream.h> 31 #include <sys/kmem.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> 39 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> 45 #include <sys/disp.h> 46 47 #include <inet/ip.h> 48 #include <inet/ip6.h> 49 #include <sys/sdt.h> 50 51 static mod_hash_t *tpc_name_hash; /* hash of cache entries by name */ 52 static kmutex_t tpc_lock; 53 54 static tsol_tpc_t *tpc_unlab; 55 56 /* 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_v[46] 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. 63 */ 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; 67 68 static void tsol_create_i_tmpls(void); 69 70 static void tsol_create_i_tnrh(const tnaddr_t *); 71 72 /* List of MLPs on valid on shared addresses */ 73 static tsol_mlp_list_t shared_mlps; 74 75 /* 76 * Convert length for a mask to the mask. 77 */ 78 static ipaddr_t 79 tsol_plen_to_mask(uint_t masklen) 80 { 81 return (masklen == 0 ? 0 : htonl(IP_HOST_MASK << (IP_ABITS - masklen))); 82 } 83 84 /* 85 * Convert a prefix length to the mask for that prefix. 86 * Returns the argument bitmask. 87 */ 88 static void 89 tsol_plen_to_mask_v6(uint_t plen, in6_addr_t *bitmask) 90 { 91 uint32_t *ptr; 92 93 ASSERT(plen <= IPV6_ABITS); 94 95 ptr = (uint32_t *)bitmask; 96 while (plen >= 32) { 97 *ptr++ = 0xffffffffU; 98 plen -= 32; 99 } 100 if (plen > 0) 101 *ptr++ = htonl(0xffffffff << (32 - plen)); 102 while (ptr < (uint32_t *)(bitmask + 1)) 103 *ptr++ = 0; 104 } 105 106 boolean_t 107 tnrhc_init_table(tnrhc_hash_t *table[], short prefix_len, int kmflag) 108 { 109 int i; 110 111 mutex_enter(&tnrhc_g_lock); 112 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); 118 return (B_FALSE); 119 } 120 for (i = 0; i < TNRHC_SIZE; i++) { 121 mutex_init(&table[prefix_len][i].tnrh_lock, 122 NULL, MUTEX_DEFAULT, 0); 123 } 124 } 125 mutex_exit(&tnrhc_g_lock); 126 return (B_TRUE); 127 } 128 129 void 130 tcache_init(void) 131 { 132 tnaddr_t address; 133 134 /* 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. 139 */ 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); 144 145 mutex_init(&tnrhc_g_lock, NULL, MUTEX_DEFAULT, NULL); 146 147 /* label_init always called before tcache_init */ 148 ASSERT(l_admin_low != NULL && l_admin_high != NULL); 149 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); 153 /* 154 * create an internal host template called "_unlab" 155 */ 156 tsol_create_i_tmpls(); 157 158 /* 159 * create a host entry, 0.0.0.0 = _unlab 160 */ 161 bzero(&address, sizeof (tnaddr_t)); 162 address.ta_family = AF_INET; 163 tsol_create_i_tnrh(&address); 164 165 /* 166 * create a host entry, ::0 = _unlab 167 */ 168 address.ta_family = AF_INET6; 169 tsol_create_i_tnrh(&address); 170 171 rw_init(&shared_mlps.mlpl_rwlock, NULL, RW_DEFAULT, NULL); 172 } 173 174 /* Called only by the TNRHC_RELE macro when the refcount goes to zero. */ 175 void 176 tnrhc_free(tsol_tnrhc_t *tnrhc) 177 { 178 /* 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. 182 */ 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)); 190 } 191 192 /* Called only by the TPC_RELE macro when the refcount goes to zero. */ 193 void 194 tpc_free(tsol_tpc_t *tpc) 195 { 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)); 201 } 202 203 /* 204 * Find and hold a reference to a template entry by name. Ignores entries that 205 * are being deleted. 206 */ 207 static tsol_tpc_t * 208 tnrhtp_find(const char *name, mod_hash_t *hash) 209 { 210 mod_hash_val_t hv; 211 tsol_tpc_t *tpc = NULL; 212 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) 217 tpc = NULL; 218 else 219 TPC_HOLD(tpc); 220 } 221 mutex_exit(&tpc_lock); 222 return (tpc); 223 } 224 225 static int 226 tnrh_delete(const tsol_rhent_t *rhent) 227 { 228 tsol_tnrhc_t *current; 229 tsol_tnrhc_t **prevp; 230 ipaddr_t tmpmask; 231 in6_addr_t tmpmask_v6; 232 tnrhc_hash_t *tnrhc_hash; 233 234 if (rhent->rh_address.ta_family == AF_INET) { 235 if (rhent->rh_prefix < 0 || rhent->rh_prefix > IP_ABITS) 236 return (EINVAL); 237 if (tnrhc_table[rhent->rh_prefix] == NULL) 238 return (ENOENT); 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) 245 return (EINVAL); 246 if (tnrhc_table_v6[rhent->rh_prefix] == NULL) 247 return (ENOENT); 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)]; 252 } else { 253 return (EAFNOSUPPORT); 254 } 255 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)) 261 break; 262 prevp = ¤t->rhc_next; 263 } 264 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); 272 TNRHC_RELE(current); 273 } 274 mutex_exit(&tnrhc_hash->tnrh_lock); 275 return (current == NULL ? ENOENT : 0); 276 } 277 278 /* 279 * Flush all remote host entries from the database. 280 * 281 * Note that the htable arrays themselves do not have reference counters, so, 282 * unlike the remote host entries, they cannot be freed. 283 */ 284 static void 285 flush_rh_table(tnrhc_hash_t **htable, int nbits) 286 { 287 tnrhc_hash_t *hent, *hend; 288 tsol_tnrhc_t *rhc, *rhnext; 289 290 while (--nbits >= 0) { 291 if ((hent = htable[nbits]) == NULL) 292 continue; 293 hend = hent + TNRHC_SIZE; 294 while (hent < hend) { 295 /* 296 * List walkers hold this lock during the walk. It 297 * protects tnrh_list and rhc_next. 298 */ 299 mutex_enter(&hent->tnrh_lock); 300 rhnext = hent->tnrh_list; 301 hent->tnrh_list = NULL; 302 mutex_exit(&hent->tnrh_lock); 303 /* 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. 309 */ 310 while ((rhc = rhnext) != NULL) { 311 rhnext = rhc->rhc_next; 312 rhc->rhc_next = NULL; 313 rhc->rhc_invalid = 1; 314 TNRHC_RELE(rhc); 315 } 316 hent++; 317 } 318 } 319 } 320 321 /* 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.) 326 * 327 * A "matching" entry is the one whose address matches that of the one 328 * being loaded. 329 * 330 * Return 0 for success, error code for failure. 331 */ 332 int 333 tnrh_load(const tsol_rhent_t *rhent) 334 { 335 tsol_tnrhc_t **rhp; 336 tsol_tnrhc_t *rh, *new; 337 tsol_tpc_t *tpc; 338 ipaddr_t tmpmask; 339 in6_addr_t tmpmask_v6; 340 tnrhc_hash_t *tnrhc_hash; 341 342 /* Find the existing entry, if any, leaving the hash locked */ 343 if (rhent->rh_address.ta_family == AF_INET) { 344 if (rhent->rh_prefix < 0 || rhent->rh_prefix > IP_ABITS) 345 return (EINVAL); 346 if (tnrhc_table[rhent->rh_prefix] == NULL && 347 !tnrhc_init_table(tnrhc_table, rhent->rh_prefix, 348 KM_NOSLEEP)) 349 return (ENOMEM); 350 tmpmask = tsol_plen_to_mask(rhent->rh_prefix); 351 tnrhc_hash = &tnrhc_table[rhent->rh_prefix][ 352 TSOL_ADDR_HASH(rhent->rh_address.ta_addr_v4.s_addr & 353 tmpmask, TNRHC_SIZE)]; 354 mutex_enter(&tnrhc_hash->tnrh_lock); 355 for (rhp = &tnrhc_hash->tnrh_list; (rh = *rhp) != NULL; 356 rhp = &rh->rhc_next) { 357 ASSERT(rh->rhc_host.ta_family == AF_INET); 358 if (((rh->rhc_host.ta_addr_v4.s_addr ^ 359 rhent->rh_address.ta_addr_v4.s_addr) & tmpmask) == 360 0) 361 break; 362 } 363 } else if (rhent->rh_address.ta_family == AF_INET6) { 364 if (rhent->rh_prefix < 0 || rhent->rh_prefix > IPV6_ABITS) 365 return (EINVAL); 366 if (tnrhc_table_v6[rhent->rh_prefix] == NULL && 367 !tnrhc_init_table(tnrhc_table_v6, rhent->rh_prefix, 368 KM_NOSLEEP)) 369 return (ENOMEM); 370 tsol_plen_to_mask_v6(rhent->rh_prefix, &tmpmask_v6); 371 tnrhc_hash = &tnrhc_table_v6[rhent->rh_prefix][ 372 TSOL_ADDR_MASK_HASH_V6(rhent->rh_address.ta_addr_v6, 373 tmpmask_v6, TNRHC_SIZE)]; 374 mutex_enter(&tnrhc_hash->tnrh_lock); 375 for (rhp = &tnrhc_hash->tnrh_list; (rh = *rhp) != NULL; 376 rhp = &rh->rhc_next) { 377 ASSERT(rh->rhc_host.ta_family == AF_INET6); 378 if (V6_MASK_EQ_2(rh->rhc_host.ta_addr_v6, tmpmask_v6, 379 rhent->rh_address.ta_addr_v6)) 380 break; 381 } 382 } else { 383 return (EAFNOSUPPORT); 384 } 385 386 if ((new = kmem_zalloc(sizeof (*new), KM_NOSLEEP)) == NULL) { 387 mutex_exit(&tnrhc_hash->tnrh_lock); 388 return (ENOMEM); 389 } 390 391 /* Find and bump the reference count on the named template */ 392 if ((tpc = tnrhtp_find(rhent->rh_template, tpc_name_hash)) == NULL) { 393 mutex_exit(&tnrhc_hash->tnrh_lock); 394 kmem_free(new, sizeof (*new)); 395 return (EINVAL); 396 } 397 398 /* Clobber the old remote host entry. */ 399 if (rh != NULL) { 400 ASSERT(!rh->rhc_invalid); 401 rh->rhc_invalid = 1; 402 *rhp = rh->rhc_next; 403 rh->rhc_next = NULL; 404 TNRHC_RELE(rh); 405 } 406 407 /* Initialize the new entry. */ 408 mutex_init(&new->rhc_lock, NULL, MUTEX_DEFAULT, NULL); 409 new->rhc_host = rhent->rh_address; 410 411 /* The rhc now owns this tpc reference, so no TPC_RELE past here */ 412 new->rhc_tpc = tpc; 413 414 ASSERT(tpc->tpc_tp.host_type == UNLABELED || 415 tpc->tpc_tp.host_type == SUN_CIPSO); 416 417 TNRHC_HOLD(new); 418 new->rhc_next = tnrhc_hash->tnrh_list; 419 tnrhc_hash->tnrh_list = new; 420 DTRACE_PROBE(tx__tndb__l2__tnrhload__addedrh); 421 mutex_exit(&tnrhc_hash->tnrh_lock); 422 423 return (0); 424 } 425 426 static int 427 tnrh_get(tsol_rhent_t *rhent) 428 { 429 tsol_tpc_t *tpc; 430 431 switch (rhent->rh_address.ta_family) { 432 case AF_INET: 433 tpc = find_tpc(&rhent->rh_address.ta_addr_v4, IPV4_VERSION, 434 B_TRUE); 435 break; 436 437 case AF_INET6: 438 tpc = find_tpc(&rhent->rh_address.ta_addr_v6, IPV6_VERSION, 439 B_TRUE); 440 break; 441 442 default: 443 return (EINVAL); 444 } 445 if (tpc == NULL) 446 return (ENOENT); 447 448 DTRACE_PROBE2(tx__tndb__l4__tnrhget__foundtpc, tsol_rhent_t *, 449 rhent, tsol_tpc_t *, tpc); 450 bcopy(tpc->tpc_tp.name, rhent->rh_template, 451 sizeof (rhent->rh_template)); 452 TPC_RELE(tpc); 453 return (0); 454 } 455 456 static boolean_t 457 template_name_ok(const char *name) 458 { 459 const char *name_end = name + TNTNAMSIZ; 460 461 while (name < name_end) { 462 if (*name == '\0') 463 break; 464 name++; 465 } 466 return (name < name_end); 467 } 468 469 static int 470 tnrh(int cmd, void *buf) 471 { 472 int retv; 473 tsol_rhent_t rhent; 474 475 /* Make sure user has sufficient privilege */ 476 if (cmd != TNDB_GET && 477 (retv = secpolicy_net_config(CRED(), B_FALSE)) != 0) 478 return (set_errno(retv)); 479 480 /* 481 * Get arguments 482 */ 483 if (cmd != TNDB_FLUSH && 484 copyin(buf, &rhent, sizeof (rhent)) != 0) { 485 DTRACE_PROBE(tx__tndb__l0__tnrhdelete__copyin); 486 return (set_errno(EFAULT)); 487 } 488 489 switch (cmd) { 490 case TNDB_LOAD: 491 DTRACE_PROBE(tx__tndb__l2__tnrhdelete__tndbload); 492 if (!template_name_ok(rhent.rh_template)) { 493 retv = EINVAL; 494 } else { 495 retv = tnrh_load(&rhent); 496 } 497 break; 498 499 case TNDB_DELETE: 500 DTRACE_PROBE(tx__tndb__l2__tnrhdelete__tndbdelete); 501 retv = tnrh_delete(&rhent); 502 break; 503 504 case TNDB_GET: 505 DTRACE_PROBE(tx__tndb__l4__tnrhdelete__tndbget); 506 if (!template_name_ok(rhent.rh_template)) { 507 retv = EINVAL; 508 break; 509 } 510 511 retv = tnrh_get(&rhent); 512 if (retv != 0) 513 break; 514 515 /* 516 * Copy out result 517 */ 518 if (copyout(&rhent, buf, sizeof (rhent)) != 0) { 519 DTRACE_PROBE(tx__tndb__l0__tnrhdelete__copyout); 520 retv = EFAULT; 521 } 522 break; 523 524 case TNDB_FLUSH: 525 DTRACE_PROBE(tx__tndb__l2__tnrhdelete__flush); 526 flush_rh_table(tnrhc_table, TSOL_MASK_TABLE_SIZE); 527 flush_rh_table(tnrhc_table_v6, TSOL_MASK_TABLE_SIZE_V6); 528 break; 529 530 default: 531 DTRACE_PROBE1(tx__tndb__l0__tnrhdelete__unknowncmd, 532 int, cmd); 533 retv = EOPNOTSUPP; 534 break; 535 } 536 537 if (retv != 0) 538 return (set_errno(retv)); 539 else 540 return (retv); 541 } 542 543 static tsol_tpc_t * 544 tnrhtp_create(const tsol_tpent_t *tpent, int kmflags) 545 { 546 tsol_tpc_t *tpc; 547 mod_hash_val_t hv; 548 549 /* 550 * We intentionally allocate a new entry before taking the lock on the 551 * entire database. 552 */ 553 if ((tpc = kmem_zalloc(sizeof (*tpc), kmflags)) == NULL) 554 return (NULL); 555 556 mutex_enter(&tpc_lock); 557 if (mod_hash_find(tpc_name_hash, (mod_hash_key_t)tpent->name, 558 &hv) == 0) { 559 tsol_tpc_t *found_tpc = (tsol_tpc_t *)hv; 560 561 found_tpc->tpc_invalid = 1; 562 (void) mod_hash_destroy(tpc_name_hash, 563 (mod_hash_key_t)tpent->name); 564 TPC_RELE(found_tpc); 565 } 566 567 mutex_init(&tpc->tpc_lock, NULL, MUTEX_DEFAULT, NULL); 568 /* tsol_tpent_t is the same on LP64 and ILP32 */ 569 bcopy(tpent, &tpc->tpc_tp, sizeof (tpc->tpc_tp)); 570 (void) mod_hash_insert(tpc_name_hash, (mod_hash_key_t)tpc->tpc_tp.name, 571 (mod_hash_val_t)tpc); 572 TPC_HOLD(tpc); 573 mutex_exit(&tpc_lock); 574 575 return (tpc); 576 } 577 578 static int 579 tnrhtp_delete(const char *tname) 580 { 581 tsol_tpc_t *tpc; 582 mod_hash_val_t hv; 583 int retv = ENOENT; 584 585 mutex_enter(&tpc_lock); 586 if (mod_hash_find(tpc_name_hash, (mod_hash_key_t)tname, &hv) == 0) { 587 tpc = (tsol_tpc_t *)hv; 588 ASSERT(!tpc->tpc_invalid); 589 tpc->tpc_invalid = 1; 590 (void) mod_hash_destroy(tpc_name_hash, 591 (mod_hash_key_t)tpc->tpc_tp.name); 592 TPC_RELE(tpc); 593 retv = 0; 594 } 595 mutex_exit(&tpc_lock); 596 return (retv); 597 } 598 599 /* ARGSUSED */ 600 static uint_t 601 tpc_delete(mod_hash_key_t key, mod_hash_val_t *val, void *arg) 602 { 603 tsol_tpc_t *tpc = (tsol_tpc_t *)val; 604 605 ASSERT(!tpc->tpc_invalid); 606 tpc->tpc_invalid = 1; 607 TPC_RELE(tpc); 608 return (MH_WALK_CONTINUE); 609 } 610 611 static void 612 tnrhtp_flush(void) 613 { 614 mutex_enter(&tpc_lock); 615 mod_hash_walk(tpc_name_hash, tpc_delete, NULL); 616 mod_hash_clear(tpc_name_hash); 617 mutex_exit(&tpc_lock); 618 } 619 620 static int 621 tnrhtp(int cmd, void *buf) 622 { 623 int retv; 624 int type; 625 tsol_tpent_t rhtpent; 626 tsol_tpc_t *tpc; 627 628 /* Make sure user has sufficient privilege */ 629 if (cmd != TNDB_GET && 630 (retv = secpolicy_net_config(CRED(), B_FALSE)) != 0) 631 return (set_errno(retv)); 632 633 /* 634 * Get argument. Note that tsol_tpent_t is the same on LP64 and ILP32, 635 * so no special handling is required. 636 */ 637 if (cmd != TNDB_FLUSH) { 638 if (copyin(buf, &rhtpent, sizeof (rhtpent)) != 0) { 639 DTRACE_PROBE(tx__tndb__l0__tnrhtp__copyin); 640 return (set_errno(EFAULT)); 641 } 642 643 /* 644 * Don't let the user give us a bogus (unterminated) template 645 * name. 646 */ 647 if (!template_name_ok(rhtpent.name)) 648 return (set_errno(EINVAL)); 649 } 650 651 switch (cmd) { 652 case TNDB_LOAD: 653 DTRACE_PROBE1(tx__tndb__l2__tnrhtp__tndbload, char *, 654 rhtpent.name); 655 type = rhtpent.host_type; 656 if (type != UNLABELED && type != SUN_CIPSO) { 657 retv = EINVAL; 658 break; 659 } 660 661 if (tnrhtp_create(&rhtpent, KM_NOSLEEP) == NULL) 662 retv = ENOMEM; 663 else 664 retv = 0; 665 break; 666 667 case TNDB_GET: 668 DTRACE_PROBE1(tx__tndb__l4__tnrhtp__tndbget, char *, 669 rhtpent.name); 670 tpc = tnrhtp_find(rhtpent.name, tpc_name_hash); 671 if (tpc == NULL) { 672 retv = ENOENT; 673 break; 674 } 675 676 /* Copy out result */ 677 if (copyout(&tpc->tpc_tp, buf, sizeof (tpc->tpc_tp)) != 0) { 678 DTRACE_PROBE(tx__tndb__l0__tnrhtp__copyout); 679 retv = EFAULT; 680 } else { 681 retv = 0; 682 } 683 TPC_RELE(tpc); 684 break; 685 686 case TNDB_DELETE: 687 DTRACE_PROBE1(tx__tndb__l4__tnrhtp__tndbdelete, char *, 688 rhtpent.name); 689 retv = tnrhtp_delete(rhtpent.name); 690 break; 691 692 case TNDB_FLUSH: 693 DTRACE_PROBE(tx__tndb__l4__tnrhtp__flush); 694 tnrhtp_flush(); 695 retv = 0; 696 break; 697 698 default: 699 DTRACE_PROBE1(tx__tndb__l0__tnrhtp__unknowncmd, int, 700 cmd); 701 retv = EOPNOTSUPP; 702 break; 703 } 704 705 if (retv != 0) 706 return (set_errno(retv)); 707 else 708 return (retv); 709 } 710 711 /* 712 * MLP entry ordering logic 713 * 714 * There are two loops in this routine. The first loop finds the entry that 715 * either logically follows the new entry to be inserted, or is the entry that 716 * precedes and overlaps the new entry, or is NULL to mean end-of-list. This 717 * is 'tme.' The second loop scans ahead from that point to find any overlap 718 * on the front or back of this new entry. 719 * 720 * For the first loop, we can have the following cases in the list (note that 721 * the port-portmax range is inclusive): 722 * 723 * port portmax 724 * +--------+ 725 * 1: +------+ ................... precedes; skip to next 726 * 2: +------+ ............. overlaps; stop here if same protocol 727 * 3: +------+ ......... overlaps; stop if same or higher protocol 728 * 4: +-------+ .... overlaps or succeeds; stop here 729 * 730 * For the second loop, we can have the following cases (note that we need not 731 * care about other protocol entries at this point, because we're only looking 732 * for overlap, not an insertion point): 733 * 734 * port portmax 735 * +--------+ 736 * 5: +------+ ............. overlaps; stop if same protocol 737 * 6: +------+ ......... overlaps; stop if same protocol 738 * 7: +-------+ .... overlaps; stop if same protocol 739 * 8: +---+ . follows; search is done 740 * 741 * In other words, this second search needs to consider only whether the entry 742 * has a starting port number that's greater than the end point of the new 743 * entry. All others are overlaps. 744 */ 745 static int 746 mlp_add_del(tsol_mlp_list_t *mlpl, zoneid_t zoneid, uint8_t proto, 747 uint16_t port, uint16_t portmax, boolean_t addflag) 748 { 749 int retv; 750 tsol_mlp_entry_t *tme, *tme2, *newent; 751 752 if (addflag) { 753 if ((newent = kmem_zalloc(sizeof (*newent), KM_NOSLEEP)) == 754 NULL) 755 return (ENOMEM); 756 } else { 757 newent = NULL; 758 } 759 rw_enter(&mlpl->mlpl_rwlock, RW_WRITER); 760 761 /* 762 * First loop: find logical insertion point or overlap. Table is kept 763 * in order of port number first, and then, within that, by protocol 764 * number. 765 */ 766 for (tme = mlpl->mlpl_first; tme != NULL; tme = tme->mlpe_next) { 767 /* logically next (case 4) */ 768 if (tme->mlpe_mlp.mlp_port > port) 769 break; 770 /* if this is logically next or overlap, then stop (case 3) */ 771 if (tme->mlpe_mlp.mlp_port == port && 772 tme->mlpe_mlp.mlp_ipp >= proto) 773 break; 774 /* earlier or same port sequence; check for overlap (case 2) */ 775 if (tme->mlpe_mlp.mlp_ipp == proto && 776 tme->mlpe_mlp.mlp_port_upper >= port) 777 break; 778 /* otherwise, loop again (case 1) */ 779 } 780 781 /* Second loop: scan ahead for overlap */ 782 for (tme2 = tme; tme2 != NULL; tme2 = tme2->mlpe_next) { 783 /* check if entry follows; no overlap (case 8) */ 784 if (tme2->mlpe_mlp.mlp_port > portmax) { 785 tme2 = NULL; 786 break; 787 } 788 /* only exact protocol matches at this point (cases 5-7) */ 789 if (tme2->mlpe_mlp.mlp_ipp == proto) 790 break; 791 } 792 793 retv = 0; 794 if (addflag) { 795 if (tme2 != NULL) { 796 retv = EEXIST; 797 } else { 798 newent->mlpe_zoneid = zoneid; 799 newent->mlpe_mlp.mlp_ipp = proto; 800 newent->mlpe_mlp.mlp_port = port; 801 newent->mlpe_mlp.mlp_port_upper = portmax; 802 newent->mlpe_next = tme; 803 if (tme == NULL) { 804 tme2 = mlpl->mlpl_last; 805 mlpl->mlpl_last = newent; 806 } else { 807 tme2 = tme->mlpe_prev; 808 tme->mlpe_prev = newent; 809 } 810 newent->mlpe_prev = tme2; 811 if (tme2 == NULL) 812 mlpl->mlpl_first = newent; 813 else 814 tme2->mlpe_next = newent; 815 newent = NULL; 816 } 817 } else { 818 if (tme2 == NULL || tme2->mlpe_mlp.mlp_port != port || 819 tme2->mlpe_mlp.mlp_port_upper != portmax) { 820 retv = ENOENT; 821 } else { 822 if ((tme2 = tme->mlpe_prev) == NULL) 823 mlpl->mlpl_first = tme->mlpe_next; 824 else 825 tme2->mlpe_next = tme->mlpe_next; 826 if ((tme2 = tme->mlpe_next) == NULL) 827 mlpl->mlpl_last = tme->mlpe_prev; 828 else 829 tme2->mlpe_prev = tme->mlpe_prev; 830 newent = tme; 831 } 832 } 833 rw_exit(&mlpl->mlpl_rwlock); 834 835 if (newent != NULL) 836 kmem_free(newent, sizeof (*newent)); 837 838 return (retv); 839 } 840 841 /* 842 * Add or remove an MLP entry from the database so that the classifier can find 843 * it. 844 * 845 * Note: port number is in host byte order. 846 */ 847 int 848 tsol_mlp_anon(zone_t *zone, mlp_type_t mlptype, uchar_t proto, uint16_t port, 849 boolean_t addflag) 850 { 851 int retv = 0; 852 853 if (mlptype == mlptBoth || mlptype == mlptPrivate) 854 retv = mlp_add_del(&zone->zone_mlps, zone->zone_id, proto, 855 port, port, addflag); 856 if ((retv == 0 || !addflag) && 857 (mlptype == mlptBoth || mlptype == mlptShared)) { 858 retv = mlp_add_del(&shared_mlps, zone->zone_id, proto, port, 859 port, addflag); 860 if (retv != 0 && addflag) 861 (void) mlp_add_del(&zone->zone_mlps, zone->zone_id, 862 proto, port, port, B_FALSE); 863 } 864 return (retv); 865 } 866 867 static void 868 mlp_flush(tsol_mlp_list_t *mlpl, zoneid_t zoneid) 869 { 870 tsol_mlp_entry_t *tme, *tme2, *tmnext; 871 872 rw_enter(&mlpl->mlpl_rwlock, RW_WRITER); 873 for (tme = mlpl->mlpl_first; tme != NULL; tme = tmnext) { 874 tmnext = tme->mlpe_next; 875 if (zoneid == ALL_ZONES || tme->mlpe_zoneid == zoneid) { 876 if ((tme2 = tme->mlpe_prev) == NULL) 877 mlpl->mlpl_first = tmnext; 878 else 879 tme2->mlpe_next = tmnext; 880 if (tmnext == NULL) 881 mlpl->mlpl_last = tme2; 882 else 883 tmnext->mlpe_prev = tme2; 884 kmem_free(tme, sizeof (*tme)); 885 } 886 } 887 rw_exit(&mlpl->mlpl_rwlock); 888 } 889 890 /* 891 * Note: user supplies port numbers in host byte order. 892 */ 893 static int 894 tnmlp(int cmd, void *buf) 895 { 896 int retv; 897 tsol_mlpent_t tsme; 898 zone_t *zone; 899 tsol_mlp_list_t *mlpl; 900 tsol_mlp_entry_t *tme; 901 902 /* Make sure user has sufficient privilege */ 903 if (cmd != TNDB_GET && 904 (retv = secpolicy_net_config(CRED(), B_FALSE)) != 0) 905 return (set_errno(retv)); 906 907 /* 908 * Get argument. Note that tsol_mlpent_t is the same on LP64 and 909 * ILP32, so no special handling is required. 910 */ 911 if (copyin(buf, &tsme, sizeof (tsme)) != 0) { 912 DTRACE_PROBE(tx__tndb__l0__tnmlp__copyin); 913 return (set_errno(EFAULT)); 914 } 915 916 /* MLPs on shared IP addresses */ 917 if (tsme.tsme_flags & TSOL_MEF_SHARED) { 918 zone = NULL; 919 mlpl = &shared_mlps; 920 } else { 921 zone = zone_find_by_id(tsme.tsme_zoneid); 922 if (zone == NULL) 923 return (set_errno(EINVAL)); 924 mlpl = &zone->zone_mlps; 925 } 926 if (tsme.tsme_mlp.mlp_port_upper == 0) 927 tsme.tsme_mlp.mlp_port_upper = tsme.tsme_mlp.mlp_port; 928 929 switch (cmd) { 930 case TNDB_LOAD: 931 DTRACE_PROBE1(tx__tndb__l2__tnmlp__tndbload, 932 tsol_mlpent_t *, &tsme); 933 if (tsme.tsme_mlp.mlp_ipp == 0 || tsme.tsme_mlp.mlp_port == 0 || 934 tsme.tsme_mlp.mlp_port > tsme.tsme_mlp.mlp_port_upper) { 935 retv = EINVAL; 936 break; 937 } 938 retv = mlp_add_del(mlpl, tsme.tsme_zoneid, 939 tsme.tsme_mlp.mlp_ipp, tsme.tsme_mlp.mlp_port, 940 tsme.tsme_mlp.mlp_port_upper, B_TRUE); 941 break; 942 943 case TNDB_GET: 944 DTRACE_PROBE1(tx__tndb__l2__tnmlp__tndbget, 945 tsol_mlpent_t *, &tsme); 946 947 /* 948 * Search for the requested element or, failing that, the one 949 * that's logically next in the sequence. 950 */ 951 rw_enter(&mlpl->mlpl_rwlock, RW_READER); 952 for (tme = mlpl->mlpl_first; tme != NULL; 953 tme = tme->mlpe_next) { 954 if (tsme.tsme_zoneid != ALL_ZONES && 955 tme->mlpe_zoneid != tsme.tsme_zoneid) 956 continue; 957 if (tme->mlpe_mlp.mlp_ipp >= tsme.tsme_mlp.mlp_ipp && 958 tme->mlpe_mlp.mlp_port == tsme.tsme_mlp.mlp_port) 959 break; 960 if (tme->mlpe_mlp.mlp_port > tsme.tsme_mlp.mlp_port) 961 break; 962 } 963 if (tme == NULL) { 964 retv = ENOENT; 965 } else { 966 tsme.tsme_zoneid = tme->mlpe_zoneid; 967 tsme.tsme_mlp = tme->mlpe_mlp; 968 retv = 0; 969 } 970 rw_exit(&mlpl->mlpl_rwlock); 971 break; 972 973 case TNDB_DELETE: 974 DTRACE_PROBE1(tx__tndb__l4__tnmlp__tndbdelete, 975 tsol_mlpent_t *, &tsme); 976 retv = mlp_add_del(mlpl, tsme.tsme_zoneid, 977 tsme.tsme_mlp.mlp_ipp, tsme.tsme_mlp.mlp_port, 978 tsme.tsme_mlp.mlp_port_upper, B_FALSE); 979 break; 980 981 case TNDB_FLUSH: 982 DTRACE_PROBE1(tx__tndb__l4__tnmlp__tndbflush, 983 tsol_mlpent_t *, &tsme); 984 mlp_flush(mlpl, ALL_ZONES); 985 mlp_flush(&shared_mlps, tsme.tsme_zoneid); 986 retv = 0; 987 break; 988 989 default: 990 DTRACE_PROBE1(tx__tndb__l0__tnmlp__unknowncmd, int, 991 cmd); 992 retv = EOPNOTSUPP; 993 break; 994 } 995 996 if (zone != NULL) 997 zone_rele(zone); 998 999 if (cmd == TNDB_GET && retv == 0) { 1000 /* Copy out result */ 1001 if (copyout(&tsme, buf, sizeof (tsme)) != 0) { 1002 DTRACE_PROBE(tx__tndb__l0__tnmlp__copyout); 1003 retv = EFAULT; 1004 } 1005 } 1006 1007 if (retv != 0) 1008 return (set_errno(retv)); 1009 else 1010 return (retv); 1011 } 1012 1013 /* 1014 * Returns a tnrhc matching the addr address. 1015 * The returned rhc's refcnt is incremented. 1016 */ 1017 tsol_tnrhc_t * 1018 find_rhc_v4(const in_addr_t *in4) 1019 { 1020 tsol_tnrhc_t *rh = NULL; 1021 tnrhc_hash_t *tnrhc_hash; 1022 ipaddr_t tmpmask; 1023 int i; 1024 1025 for (i = (TSOL_MASK_TABLE_SIZE - 1); i >= 0; i--) { 1026 1027 if ((tnrhc_table[i]) == NULL) 1028 continue; 1029 1030 tmpmask = tsol_plen_to_mask(i); 1031 tnrhc_hash = &tnrhc_table[i][ 1032 TSOL_ADDR_HASH(*in4 & tmpmask, TNRHC_SIZE)]; 1033 1034 mutex_enter(&tnrhc_hash->tnrh_lock); 1035 for (rh = tnrhc_hash->tnrh_list; rh != NULL; 1036 rh = rh->rhc_next) { 1037 if ((rh->rhc_host.ta_family == AF_INET) && 1038 ((rh->rhc_host.ta_addr_v4.s_addr & tmpmask) == 1039 (*in4 & tmpmask))) { 1040 TNRHC_HOLD(rh); 1041 mutex_exit(&tnrhc_hash->tnrh_lock); 1042 return (rh); 1043 } 1044 } 1045 mutex_exit(&tnrhc_hash->tnrh_lock); 1046 } 1047 1048 return (NULL); 1049 } 1050 1051 /* 1052 * Returns a tnrhc matching the addr address. 1053 * The returned rhc's refcnt is incremented. 1054 */ 1055 tsol_tnrhc_t * 1056 find_rhc_v6(const in6_addr_t *in6) 1057 { 1058 tsol_tnrhc_t *rh = NULL; 1059 tnrhc_hash_t *tnrhc_hash; 1060 in6_addr_t tmpmask; 1061 int i; 1062 1063 if (IN6_IS_ADDR_V4MAPPED(in6)) { 1064 in_addr_t in4; 1065 1066 IN6_V4MAPPED_TO_IPADDR(in6, in4); 1067 return (find_rhc_v4(&in4)); 1068 } 1069 1070 for (i = (TSOL_MASK_TABLE_SIZE_V6 - 1); i >= 0; i--) { 1071 if ((tnrhc_table_v6[i]) == NULL) 1072 continue; 1073 1074 tsol_plen_to_mask_v6(i, &tmpmask); 1075 tnrhc_hash = &tnrhc_table_v6[i][ 1076 TSOL_ADDR_MASK_HASH_V6(*in6, tmpmask, TNRHC_SIZE)]; 1077 1078 mutex_enter(&tnrhc_hash->tnrh_lock); 1079 for (rh = tnrhc_hash->tnrh_list; rh != NULL; 1080 rh = rh->rhc_next) { 1081 if ((rh->rhc_host.ta_family == AF_INET6) && 1082 V6_MASK_EQ_2(rh->rhc_host.ta_addr_v6, tmpmask, 1083 *in6)) { 1084 TNRHC_HOLD(rh); 1085 mutex_exit(&tnrhc_hash->tnrh_lock); 1086 return (rh); 1087 } 1088 } 1089 mutex_exit(&tnrhc_hash->tnrh_lock); 1090 } 1091 1092 return (NULL); 1093 } 1094 1095 tsol_tpc_t * 1096 find_tpc(const void *addr, uchar_t version, boolean_t staleok) 1097 { 1098 tsol_tpc_t *tpc; 1099 tsol_tnrhc_t *rhc; 1100 1101 if (version == IPV4_VERSION) 1102 rhc = find_rhc_v4(addr); 1103 else 1104 rhc = find_rhc_v6(addr); 1105 1106 if (rhc != NULL) { 1107 tpc = rhc->rhc_tpc; 1108 if (!staleok && tpc->tpc_invalid) { 1109 /* 1110 * This should not happen unless the user deletes 1111 * templates without recreating them. Try to find the 1112 * new version of template. If there is none, then 1113 * just give up. 1114 */ 1115 tpc = tnrhtp_find(tpc->tpc_tp.name, tpc_name_hash); 1116 if (tpc != NULL) { 1117 TPC_RELE(rhc->rhc_tpc); 1118 rhc->rhc_tpc = tpc; 1119 } 1120 } 1121 if (tpc != NULL) 1122 TPC_HOLD(tpc); 1123 TNRHC_RELE(rhc); 1124 return (tpc); 1125 } 1126 DTRACE_PROBE(tx__tndb__l1__findtpc__notemplate); 1127 return (NULL); 1128 } 1129 1130 /* 1131 * create an internal template called "_unlab": 1132 * 1133 * _unlab;\ 1134 * host_type = unlabeled;\ 1135 * def_label = ADMIN_LOW[ADMIN_LOW];\ 1136 * min_sl = ADMIN_LOW;\ 1137 * max_sl = ADMIN_HIGH; 1138 */ 1139 static void 1140 tsol_create_i_tmpls(void) 1141 { 1142 tsol_tpent_t rhtpent; 1143 1144 bzero(&rhtpent, sizeof (rhtpent)); 1145 1146 /* create _unlab */ 1147 (void) strcpy(rhtpent.name, "_unlab"); 1148 1149 rhtpent.host_type = UNLABELED; 1150 rhtpent.tp_mask_unl = TSOL_MSK_DEF_LABEL | TSOL_MSK_DEF_CL | 1151 TSOL_MSK_SL_RANGE_TSOL; 1152 1153 rhtpent.tp_gw_sl_range.lower_bound = *label2bslabel(l_admin_low); 1154 rhtpent.tp_def_label = rhtpent.tp_gw_sl_range.lower_bound; 1155 rhtpent.tp_gw_sl_range.upper_bound = *label2bslabel(l_admin_high); 1156 rhtpent.tp_cipso_doi_unl = default_doi; 1157 tpc_unlab = tnrhtp_create(&rhtpent, KM_SLEEP); 1158 } 1159 1160 /* 1161 * set up internal host template, called from kernel only. 1162 */ 1163 static void 1164 tsol_create_i_tnrh(const tnaddr_t *sa) 1165 { 1166 tsol_tnrhc_t *rh, *new; 1167 tnrhc_hash_t *tnrhc_hash; 1168 1169 /* Allocate a new entry before taking the lock */ 1170 new = kmem_zalloc(sizeof (*new), KM_SLEEP); 1171 1172 tnrhc_hash = (sa->ta_family == AF_INET) ? &tnrhc_table[0][0] : 1173 &tnrhc_table_v6[0][0]; 1174 1175 mutex_enter(&tnrhc_hash->tnrh_lock); 1176 rh = tnrhc_hash->tnrh_list; 1177 1178 if (rh == NULL) { 1179 /* We're keeping the new entry. */ 1180 rh = new; 1181 new = NULL; 1182 rh->rhc_host = *sa; 1183 mutex_init(&rh->rhc_lock, NULL, MUTEX_DEFAULT, NULL); 1184 TNRHC_HOLD(rh); 1185 tnrhc_hash->tnrh_list = rh; 1186 } 1187 1188 /* 1189 * Link the entry to internal_unlab 1190 */ 1191 if (rh->rhc_tpc != tpc_unlab) { 1192 if (rh->rhc_tpc != NULL) 1193 TPC_RELE(rh->rhc_tpc); 1194 rh->rhc_tpc = tpc_unlab; 1195 TPC_HOLD(tpc_unlab); 1196 } 1197 mutex_exit(&tnrhc_hash->tnrh_lock); 1198 if (new != NULL) 1199 kmem_free(new, sizeof (*new)); 1200 } 1201 1202 /* 1203 * Returns 0 if the port is known to be SLP. Returns next possible port number 1204 * (wrapping through 1) if port is MLP on shared or global. Administrator 1205 * should not make all ports MLP. If that's done, then we'll just pretend 1206 * everything is SLP to avoid looping forever. 1207 * 1208 * Note: port is in host byte order. 1209 */ 1210 in_port_t 1211 tsol_next_port(zone_t *zone, in_port_t port, int proto, boolean_t upward) 1212 { 1213 boolean_t loop; 1214 tsol_mlp_entry_t *tme; 1215 int newport = port; 1216 1217 loop = B_FALSE; 1218 for (;;) { 1219 if (zone != NULL && zone->zone_mlps.mlpl_first != NULL) { 1220 rw_enter(&zone->zone_mlps.mlpl_rwlock, RW_READER); 1221 for (tme = zone->zone_mlps.mlpl_first; tme != NULL; 1222 tme = tme->mlpe_next) { 1223 if (proto == tme->mlpe_mlp.mlp_ipp && 1224 newport >= tme->mlpe_mlp.mlp_port && 1225 newport <= tme->mlpe_mlp.mlp_port_upper) 1226 newport = upward ? 1227 tme->mlpe_mlp.mlp_port_upper + 1 : 1228 tme->mlpe_mlp.mlp_port - 1; 1229 } 1230 rw_exit(&zone->zone_mlps.mlpl_rwlock); 1231 } 1232 if (shared_mlps.mlpl_first != NULL) { 1233 rw_enter(&shared_mlps.mlpl_rwlock, RW_READER); 1234 for (tme = shared_mlps.mlpl_first; tme != NULL; 1235 tme = tme->mlpe_next) { 1236 if (proto == tme->mlpe_mlp.mlp_ipp && 1237 newport >= tme->mlpe_mlp.mlp_port && 1238 newport <= tme->mlpe_mlp.mlp_port_upper) 1239 newport = upward ? 1240 tme->mlpe_mlp.mlp_port_upper + 1 : 1241 tme->mlpe_mlp.mlp_port - 1; 1242 } 1243 rw_exit(&shared_mlps.mlpl_rwlock); 1244 } 1245 if (newport <= 65535 && newport > 0) 1246 break; 1247 if (loop) 1248 return (0); 1249 loop = B_TRUE; 1250 newport = upward ? 1 : 65535; 1251 } 1252 return (newport == port ? 0 : newport); 1253 } 1254 1255 /* 1256 * tsol_mlp_port_type will check if the given (zone, proto, port) is a 1257 * multilevel port. If it is, return the type (shared, private, or both), or 1258 * indicate that it's single-level. 1259 * 1260 * Note: port is given in host byte order, not network byte order. 1261 */ 1262 mlp_type_t 1263 tsol_mlp_port_type(zone_t *zone, uchar_t proto, uint16_t port, 1264 mlp_type_t mlptype) 1265 { 1266 tsol_mlp_entry_t *tme; 1267 1268 if (mlptype == mlptBoth || mlptype == mlptPrivate) { 1269 tme = NULL; 1270 if (zone->zone_mlps.mlpl_first != NULL) { 1271 rw_enter(&zone->zone_mlps.mlpl_rwlock, RW_READER); 1272 for (tme = zone->zone_mlps.mlpl_first; tme != NULL; 1273 tme = tme->mlpe_next) { 1274 if (proto == tme->mlpe_mlp.mlp_ipp && 1275 port >= tme->mlpe_mlp.mlp_port && 1276 port <= tme->mlpe_mlp.mlp_port_upper) 1277 break; 1278 } 1279 rw_exit(&zone->zone_mlps.mlpl_rwlock); 1280 } 1281 if (tme == NULL) { 1282 if (mlptype == mlptBoth) 1283 mlptype = mlptShared; 1284 else if (mlptype == mlptPrivate) 1285 mlptype = mlptSingle; 1286 } 1287 } 1288 if (mlptype == mlptBoth || mlptype == mlptShared) { 1289 tme = NULL; 1290 if (shared_mlps.mlpl_first != NULL) { 1291 rw_enter(&shared_mlps.mlpl_rwlock, RW_READER); 1292 for (tme = shared_mlps.mlpl_first; tme != NULL; 1293 tme = tme->mlpe_next) { 1294 if (proto == tme->mlpe_mlp.mlp_ipp && 1295 port >= tme->mlpe_mlp.mlp_port && 1296 port <= tme->mlpe_mlp.mlp_port_upper) 1297 break; 1298 } 1299 rw_exit(&shared_mlps.mlpl_rwlock); 1300 } 1301 if (tme == NULL) { 1302 if (mlptype == mlptBoth) 1303 mlptype = mlptPrivate; 1304 else if (mlptype == mlptShared) 1305 mlptype = mlptSingle; 1306 } 1307 } 1308 return (mlptype); 1309 } 1310 1311 /* 1312 * tsol_mlp_findzone will check if the given (proto, port) is a multilevel port 1313 * on a shared address. If it is, return the owning zone. 1314 * 1315 * Note: lport is in network byte order, unlike the other MLP functions, 1316 * because the callers of this function are all dealing with packets off the 1317 * wire. 1318 */ 1319 zoneid_t 1320 tsol_mlp_findzone(uchar_t proto, uint16_t lport) 1321 { 1322 tsol_mlp_entry_t *tme; 1323 zoneid_t zoneid; 1324 uint16_t port; 1325 1326 if (shared_mlps.mlpl_first == NULL) 1327 return (ALL_ZONES); 1328 port = ntohs(lport); 1329 rw_enter(&shared_mlps.mlpl_rwlock, RW_READER); 1330 for (tme = shared_mlps.mlpl_first; tme != NULL; tme = tme->mlpe_next) { 1331 if (proto == tme->mlpe_mlp.mlp_ipp && 1332 port >= tme->mlpe_mlp.mlp_port && 1333 port <= tme->mlpe_mlp.mlp_port_upper) 1334 break; 1335 } 1336 zoneid = tme == NULL ? ALL_ZONES : tme->mlpe_zoneid; 1337 rw_exit(&shared_mlps.mlpl_rwlock); 1338 return (zoneid); 1339 } 1340 1341 /* Debug routine */ 1342 void 1343 tsol_print_label(const blevel_t *blev, const char *name) 1344 { 1345 const _blevel_impl_t *bli = (const _blevel_impl_t *)blev; 1346 1347 /* We really support only sensitivity labels */ 1348 cmn_err(CE_NOTE, "%s %x:%x:%08x%08x%08x%08x%08x%08x%08x%08x", 1349 name, bli->id, LCLASS(bli), ntohl(bli->_comps.c1), 1350 ntohl(bli->_comps.c2), ntohl(bli->_comps.c3), ntohl(bli->_comps.c4), 1351 ntohl(bli->_comps.c5), ntohl(bli->_comps.c6), ntohl(bli->_comps.c7), 1352 ntohl(bli->_comps.c8)); 1353 } 1354 1355 /* 1356 * Name: labelsys() 1357 * 1358 * Normal: Routes TSOL syscalls. 1359 * 1360 * Output: As defined for each TSOL syscall. 1361 * Returns ENOSYS for unrecognized calls. 1362 */ 1363 /* ARGSUSED */ 1364 int 1365 labelsys(int op, void *a1, void *a2, void *a3, void *a4, void *a5) 1366 { 1367 switch (op) { 1368 case TSOL_SYSLABELING: 1369 return (sys_labeling); 1370 case TSOL_TNRH: 1371 return (tnrh((int)(uintptr_t)a1, a2)); 1372 case TSOL_TNRHTP: 1373 return (tnrhtp((int)(uintptr_t)a1, a2)); 1374 case TSOL_TNMLP: 1375 return (tnmlp((int)(uintptr_t)a1, a2)); 1376 case TSOL_GETLABEL: 1377 return (getlabel((char *)a1, (bslabel_t *)a2)); 1378 case TSOL_FGETLABEL: 1379 return (fgetlabel((int)(uintptr_t)a1, (bslabel_t *)a2)); 1380 default: 1381 return (set_errno(ENOSYS)); 1382 } 1383 /* NOTREACHED */ 1384 } 1385