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