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 2010 Sun Microsystems, Inc. All rights reserved. 23 * Use is subject to license terms. 24 */ 25 26 #include <sys/types.h> 27 #include <sys/systm.h> 28 #include <sys/kmem.h> 29 #include <sys/disp.h> 30 #include <sys/stream.h> 31 #include <sys/strsubr.h> 32 #include <sys/strsun.h> 33 #include <sys/policy.h> 34 #include <sys/tsol/label_macro.h> 35 #include <sys/tsol/tndb.h> 36 #include <sys/tsol/tnet.h> 37 #include <inet/ip.h> 38 #include <inet/ip6.h> 39 #include <inet/tcp.h> 40 #include <inet/ipclassifier.h> 41 #include <inet/ip_ire.h> 42 #include <inet/ip_ftable.h> 43 44 /* 45 * This routine takes a sensitivity label as input and creates a CIPSO 46 * option in the specified buffer. It returns the size of the CIPSO option. 47 * If the sensitivity label is too large for the CIPSO option, then 0 48 * is returned. 49 * 50 * tsol2cipso_tt1 returns 0 for failure and greater than 0 for success 51 * (more accurately, success means a return value between 10 and 40). 52 */ 53 54 static int 55 tsol2cipso_tt1(const bslabel_t *sl, unsigned char *cop, uint32_t doi) 56 { 57 struct cipso_tag_type_1 *tt1; 58 const _bslabel_impl_t *bsl; 59 const uchar_t *ucp; 60 int i; 61 62 if (doi == 0) 63 return (0); 64 65 /* check for Admin High sensitivity label */ 66 if (blequal(sl, label2bslabel(l_admin_high))) 67 return (0); 68 69 /* check whether classification will fit in one octet */ 70 bsl = (const _bslabel_impl_t *)sl; 71 if (LCLASS(bsl) & 0xFF00) 72 return (0); 73 74 /* 75 * Check whether compartments will fit in 30 octets. 76 * Compartments 241 - 256 are not allowed. 77 */ 78 if (ntohl(bsl->compartments.c8) & 0x0000FFFF) 79 return (0); 80 81 /* 82 * Compute option length and tag length. 83 * 'p' points to the last two bytes in the Sensitivity Label's 84 * compartments; these cannot be mapped into CIPSO compartments. 85 */ 86 ucp = (const uchar_t *)&bsl->compartments.c8 + 2; 87 while (--ucp >= (const uchar_t *)&bsl->compartments.c1) 88 if (*ucp != 0) 89 break; 90 91 i = ucp - (const uchar_t *)&bsl->compartments.c1 + 1; 92 93 if (cop == NULL) 94 return (10 + i); 95 96 doi = htonl(doi); 97 ucp = (const uchar_t *)&doi; 98 cop[IPOPT_OPTVAL] = IPOPT_COMSEC; 99 cop[IPOPT_OLEN] = 10 + i; 100 cop[IPOPT_OLEN+1] = ucp[0]; 101 cop[IPOPT_OLEN+2] = ucp[1]; 102 cop[IPOPT_OLEN+3] = ucp[2]; 103 cop[IPOPT_OLEN+4] = ucp[3]; 104 tt1 = (struct cipso_tag_type_1 *)&cop[IPOPT_OLEN + 5]; 105 tt1->tag_type = 1; 106 tt1->tag_align = 0; 107 tt1->tag_sl = LCLASS(bsl); 108 tt1->tag_length = 4 + i; 109 110 bcopy(&bsl->compartments.c1, tt1->tag_cat, i); 111 112 return (cop[IPOPT_OLEN]); 113 } 114 115 /* 116 * The following routine searches for a security label in an IPv4 datagram. 117 * It returns label_type of: 118 * OPT_CIPSO if a CIPSO IP option is found. 119 * OPT_NONE if no security label is found. 120 * 121 * If OPT_CIPSO, a pointer to the CIPSO IP option will be returned in 122 * the buffer parameter. 123 * 124 * The function will return with B_FALSE if an IP format error 125 * is encountered. 126 */ 127 128 boolean_t 129 tsol_get_option_v4(mblk_t *mp, tsol_ip_label_t *label_type, uchar_t **buffer) 130 { 131 ipha_t *ipha; 132 uchar_t *opt; 133 uint32_t totallen; 134 uint32_t optval; 135 uint32_t optlen; 136 137 *label_type = OPT_NONE; 138 139 /* 140 * Get length (in 4 byte octets) of IP header options. 141 * If header doesn't contain options, then return a label_type 142 * of OPT_NONE. 143 */ 144 ipha = (ipha_t *)mp->b_rptr; 145 totallen = ipha->ipha_version_and_hdr_length - 146 (uint8_t)((IP_VERSION << 4)); 147 totallen <<= 2; 148 if (totallen < IP_SIMPLE_HDR_LENGTH || totallen > MBLKL(mp)) 149 return (B_FALSE); 150 totallen -= IP_SIMPLE_HDR_LENGTH; 151 if (totallen == 0) 152 return (B_TRUE); 153 154 /* 155 * Search for CIPSO option. 156 * If no such option is present, then return OPT_NONE. 157 */ 158 opt = (uchar_t *)&ipha[1]; 159 while (totallen != 0) { 160 switch (optval = opt[IPOPT_OPTVAL]) { 161 case IPOPT_EOL: 162 return (B_TRUE); 163 case IPOPT_NOP: 164 optlen = 1; 165 break; 166 default: 167 if (totallen <= IPOPT_OLEN) 168 return (B_FALSE); 169 optlen = opt[IPOPT_OLEN]; 170 if (optlen < 2) 171 return (B_FALSE); 172 } 173 if (optlen > totallen) 174 return (B_FALSE); 175 /* 176 * Copy pointer to option into '*buffer' and 177 * return the option type. 178 */ 179 switch (optval) { 180 case IPOPT_COMSEC: 181 if (TSOL_CIPSO_TAG_OFFSET < optlen && 182 opt[TSOL_CIPSO_TAG_OFFSET] == 1) { 183 *label_type = OPT_CIPSO; 184 *buffer = opt; 185 return (B_TRUE); 186 } 187 return (B_FALSE); 188 } 189 totallen -= optlen; 190 opt += optlen; 191 } 192 return (B_TRUE); 193 } 194 195 /* 196 * The following routine searches for a security label in an IPv6 datagram. 197 * It returns label_type of: 198 * OPT_CIPSO if a CIPSO IP option is found. 199 * OPT_NONE if no security label is found. 200 * 201 * If OPT_CIPSO, a pointer to the IPv4 portion of the CIPSO IP option will 202 * be returned in the buffer parameter. 203 * 204 * The function will return with B_FALSE if an IP format error 205 * or an unexpected label content error is encountered. 206 */ 207 208 boolean_t 209 tsol_get_option_v6(mblk_t *mp, tsol_ip_label_t *label_type, uchar_t **buffer) 210 { 211 uchar_t *opt_ptr = NULL; 212 uchar_t *after_secopt; 213 boolean_t hbh_needed; 214 const uchar_t *ip6hbh; 215 size_t optlen; 216 uint32_t doi; 217 const ip6_t *ip6h; 218 219 *label_type = OPT_NONE; 220 *buffer = NULL; 221 ip6h = (const ip6_t *)mp->b_rptr; 222 if (ip6h->ip6_nxt != IPPROTO_HOPOPTS) 223 return (B_TRUE); 224 ip6hbh = (const uchar_t *)&ip6h[1]; 225 if (ip6hbh + MIN_EHDR_LEN > mp->b_wptr) 226 return (B_FALSE); 227 optlen = (ip6hbh[1] + 1) << 3; 228 if (ip6hbh + optlen > mp->b_wptr) 229 return (B_FALSE); 230 if (!tsol_find_secopt_v6(ip6hbh, optlen, 231 &opt_ptr, &after_secopt, &hbh_needed)) 232 return (B_FALSE); 233 /* tsol_find_secopt_v6 guarantees some sanity */ 234 if (opt_ptr != NULL) { 235 /* 236 * IPv6 Option 237 * opt_ptr[0]: Option type 238 * opt_ptr[1]: Length of option data in bytes 239 * opt_ptr[2]: First byte of option data 240 */ 241 if ((optlen = opt_ptr[1]) < 8) 242 return (B_FALSE); 243 opt_ptr += 2; 244 /* 245 * From "Generalized Labeled Security Option for IPv6" draft 246 * opt_ptr[0] - opt_ptr[4]: DOI = IP6LS_DOI_V4 247 * opt_ptr[4]: Tag type = IP6LS_TT_V4 248 * opt_ptr[5]: Tag length in bytes starting at Tag type field 249 * IPv4 CIPSO Option 250 * opt_ptr[6]: option type 251 * opt_ptr[7]: option length in bytes starting at type field 252 */ 253 bcopy(opt_ptr, &doi, sizeof (doi)); 254 doi = ntohl(doi); 255 if (doi == IP6LS_DOI_V4 && 256 opt_ptr[4] == IP6LS_TT_V4 && 257 opt_ptr[5] <= optlen - 4 && 258 opt_ptr[7] <= optlen - 6 && 259 opt_ptr[7] <= opt_ptr[5] - 2) { 260 opt_ptr += sizeof (doi) + 2; 261 *label_type = OPT_CIPSO; 262 *buffer = opt_ptr; 263 return (B_TRUE); 264 } 265 return (B_FALSE); 266 } 267 return (B_TRUE); 268 } 269 270 /* 271 * tsol_check_dest() 272 * 273 * This routine verifies if a destination is allowed to recieve messages 274 * based on the security label. If any adjustments to the label are needed 275 * due to the connection's MAC mode or the destination's ability 276 * to receive labels, an "effective label" will be returned. 277 * 278 * zone_is_global is set if the actual zoneid is global. That is, it is 279 * not set for an exclusive-IP zone. 280 * 281 * On successful return, effective_tsl will point to the new label needed 282 * or will be NULL if a new label isn't needed. On error, effective_tsl will 283 * point to NULL. 284 * 285 * Returns: 286 * 0 Label (was|is now) correct 287 * EHOSTUNREACH The label failed the remote host accreditation 288 * ENOMEM Memory allocation failure 289 */ 290 int 291 tsol_check_dest(const ts_label_t *tsl, const void *dst, 292 uchar_t version, uint_t mac_mode, boolean_t zone_is_global, 293 ts_label_t **effective_tsl) 294 { 295 ts_label_t *newtsl = NULL; 296 tsol_tpc_t *dst_rhtp; 297 298 if (effective_tsl != NULL) 299 *effective_tsl = NULL; 300 ASSERT(version == IPV4_VERSION || 301 (version == IPV6_VERSION && 302 !IN6_IS_ADDR_V4MAPPED((in6_addr_t *)dst))); 303 304 /* Always pass kernel level communication (NULL label) */ 305 if (tsl == NULL) { 306 DTRACE_PROBE2(tx__tnopt__log__info__labeling__mac__allownull, 307 char *, "destination ip(1) with null label was passed", 308 ipaddr_t, dst); 309 return (0); 310 } 311 312 if (tsl->tsl_flags & TSLF_IMPLICIT_IN) { 313 DTRACE_PROBE3(tx__tnopt__log__info__labeling__unresolved__label, 314 char *, 315 "implicit-in packet to ip(1) reached tsol_check_dest " 316 "with implied security label sl(2)", 317 ipaddr_t, dst, ts_label_t *, tsl); 318 } 319 320 /* Always pass multicast */ 321 if (version == IPV4_VERSION && 322 CLASSD(*(ipaddr_t *)dst)) { 323 DTRACE_PROBE2(tx__tnopt__log__info__labeling__mac__allowmult, 324 char *, "destination ip(1) with multicast dest was passed", 325 ipaddr_t, dst); 326 return (0); 327 } else if (version == IPV6_VERSION && 328 IN6_IS_ADDR_MULTICAST((in6_addr_t *)dst)) { 329 DTRACE_PROBE2(tx__tnopt__log__info__labeling__mac__allowmult_v6, 330 char *, "destination ip(1) with multicast dest was passed", 331 in6_addr_t *, dst); 332 return (0); 333 } 334 335 /* Never pass an undefined destination */ 336 if ((dst_rhtp = find_tpc(dst, version, B_FALSE)) == NULL) { 337 DTRACE_PROBE2(tx__tnopt__log__info__labeling__lookupdst, 338 char *, "destination ip(1) not in tn database.", 339 void *, dst); 340 return (EHOSTUNREACH); 341 } 342 343 switch (dst_rhtp->tpc_tp.host_type) { 344 case UNLABELED: 345 /* 346 * Can talk to unlabeled hosts if 347 * (1) zone's label matches the default label, or 348 * (2) SO_MAC_EXEMPT is on and we 349 * dominate the peer's label, or 350 * (3) SO_MAC_EXEMPT is on and 351 * this is the global zone 352 */ 353 if (dst_rhtp->tpc_tp.tp_doi != tsl->tsl_doi) { 354 DTRACE_PROBE4(tx__tnopt__log__info__labeling__doi, 355 char *, "unlabeled dest ip(1)/tpc(2) doi does " 356 "not match msg label(3) doi.", void *, dst, 357 tsol_tpc_t *, dst_rhtp, ts_label_t *, tsl); 358 TPC_RELE(dst_rhtp); 359 return (EHOSTUNREACH); 360 } 361 if (!blequal(&dst_rhtp->tpc_tp.tp_def_label, 362 &tsl->tsl_label)) { 363 if (mac_mode != CONN_MAC_AWARE || 364 !(zone_is_global || 365 bldominates(&tsl->tsl_label, 366 &dst_rhtp->tpc_tp.tp_def_label))) { 367 DTRACE_PROBE4( 368 tx__tnopt__log__info__labeling__mac, 369 char *, "unlabeled dest ip(1)/tpc(2) does " 370 "not match msg label(3).", void *, dst, 371 tsol_tpc_t *, dst_rhtp, ts_label_t *, tsl); 372 TPC_RELE(dst_rhtp); 373 return (EHOSTUNREACH); 374 } 375 /* 376 * This is a downlabel MAC-exempt exchange. 377 * Use the remote destination's default label 378 * as the label of the message data. 379 */ 380 if ((newtsl = labelalloc(&dst_rhtp->tpc_tp.tp_def_label, 381 dst_rhtp->tpc_tp.tp_doi, KM_NOSLEEP)) == NULL) { 382 TPC_RELE(dst_rhtp); 383 return (ENOMEM); 384 } 385 newtsl->tsl_flags |= TSLF_UNLABELED; 386 387 } else if (!(tsl->tsl_flags & TSLF_UNLABELED)) { 388 /* 389 * The security labels are the same but we need 390 * to flag that the remote node is unlabeled. 391 */ 392 if ((newtsl = labeldup(tsl, KM_NOSLEEP)) == NULL) { 393 TPC_RELE(dst_rhtp); 394 return (ENOMEM); 395 } 396 newtsl->tsl_flags |= TSLF_UNLABELED; 397 } 398 break; 399 400 case SUN_CIPSO: 401 /* 402 * Can talk to labeled hosts if zone's label is within target's 403 * label range or set. 404 */ 405 if (dst_rhtp->tpc_tp.tp_cipso_doi_cipso != tsl->tsl_doi || 406 (!_blinrange(&tsl->tsl_label, 407 &dst_rhtp->tpc_tp.tp_sl_range_cipso) && 408 !blinlset(&tsl->tsl_label, 409 dst_rhtp->tpc_tp.tp_sl_set_cipso))) { 410 DTRACE_PROBE4(tx__tnopt__log__info__labeling__mac, 411 char *, "labeled dest ip(1)/tpc(2) does not " 412 "match msg label(3).", void *, dst, 413 tsol_tpc_t *, dst_rhtp, ts_label_t *, tsl); 414 TPC_RELE(dst_rhtp); 415 return (EHOSTUNREACH); 416 } 417 if ((tsl->tsl_flags & TSLF_UNLABELED) || 418 (mac_mode == CONN_MAC_IMPLICIT)) { 419 /* 420 * Copy label so we can modify the flags 421 */ 422 if ((newtsl = labeldup(tsl, KM_NOSLEEP)) == NULL) { 423 TPC_RELE(dst_rhtp); 424 return (ENOMEM); 425 } 426 /* 427 * The security label is a match but we need to 428 * clear the unlabeled flag for this remote node. 429 */ 430 newtsl->tsl_flags &= ~TSLF_UNLABELED; 431 if (mac_mode == CONN_MAC_IMPLICIT) 432 newtsl->tsl_flags |= TSLF_IMPLICIT_OUT; 433 } 434 break; 435 436 default: 437 TPC_RELE(dst_rhtp); 438 return (EHOSTUNREACH); 439 } 440 441 /* 442 * Return the new label. 443 */ 444 if (newtsl != NULL) { 445 if (effective_tsl != NULL) 446 *effective_tsl = newtsl; 447 else 448 label_rele(newtsl); 449 } 450 TPC_RELE(dst_rhtp); 451 return (0); 452 } 453 454 /* 455 * tsol_compute_label_v4() 456 * 457 * This routine computes the IP label that should be on a packet based on the 458 * connection and destination information. 459 * 460 * The zoneid is the IP zoneid (i.e., GLOBAL_ZONEID for exlusive-IP zones). 461 * 462 * Returns: 463 * 0 Fetched label 464 * EHOSTUNREACH No route to destination 465 * EINVAL Label cannot be computed 466 */ 467 int 468 tsol_compute_label_v4(const ts_label_t *tsl, zoneid_t zoneid, ipaddr_t dst, 469 uchar_t *opt_storage, ip_stack_t *ipst) 470 { 471 uint_t sec_opt_len; 472 ire_t *ire; 473 tsol_ire_gw_secattr_t *attrp = NULL; 474 475 if (opt_storage != NULL) 476 opt_storage[IPOPT_OLEN] = 0; 477 478 if (tsl == NULL) 479 return (0); 480 481 /* always pass multicast */ 482 if (CLASSD(dst)) 483 return (0); 484 485 if (tsl->tsl_flags & TSLF_IMPLICIT_OUT) 486 return (0); 487 488 if (tsl->tsl_flags & TSLF_UNLABELED) { 489 /* 490 * The destination is unlabeled. Only add a label if the 491 * destination is not a broadcast/local/loopback address, 492 * the destination is not on the same subnet, and the 493 * next-hop gateway is labeled. 494 */ 495 ire = ire_route_recursive_v4(dst, 0, NULL, zoneid, tsl, 496 MATCH_IRE_SECATTR, IRR_ALLOCATE, 0, ipst, NULL, &attrp, 497 NULL); 498 ASSERT(ire != NULL); 499 if (ire->ire_flags & (RTF_REJECT|RTF_BLACKHOLE)) { 500 /* no route to destination */ 501 ire_refrele(ire); 502 DTRACE_PROBE3( 503 tx__tnopt__log__info__labeling__routedst__v4, 504 char *, "No route to unlabeled dest ip(1) with " 505 "with label(2).", ipaddr_t, dst, ts_label_t *, tsl); 506 return (EHOSTUNREACH); 507 } 508 if (ire->ire_type & (IRE_BROADCAST | IRE_LOCAL | IRE_LOOPBACK | 509 IRE_INTERFACE)) { 510 ire_refrele(ire); 511 return (0); 512 } 513 514 /* 515 * ire_route_recursive gives us the first attrp it finds 516 * in the recursive lookup. 517 */ 518 /* 519 * Return now if next hop gateway is unlabeled. There is 520 * no need to generate a CIPSO option for this message. 521 */ 522 if (attrp == NULL || attrp->igsa_rhc == NULL || 523 attrp->igsa_rhc->rhc_tpc->tpc_tp.host_type == UNLABELED) { 524 ire_refrele(ire); 525 return (0); 526 } 527 ire_refrele(ire); 528 } 529 530 /* compute the CIPSO option */ 531 sec_opt_len = tsol2cipso_tt1(&tsl->tsl_label, opt_storage, 532 tsl->tsl_doi); 533 534 if (sec_opt_len == 0) { 535 DTRACE_PROBE3(tx__tnopt__log__error__labeling__lostops__v4, 536 char *, "options lack length for dest ip(1) with label(2).", 537 ipaddr_t, dst, ts_label_t *, tsl); 538 return (EINVAL); 539 } 540 541 return (0); 542 } 543 544 /* 545 * Remove any existing security option (CIPSO) from the given IP 546 * header, move the 'buflen' bytes back to fill the gap, and return the number 547 * of bytes removed (as zero or negative number). Assumes that the headers are 548 * sane. 549 * 550 * Note that tsol_remove_secopt does not adjust ipha_length but 551 * tsol_remove_secopt_v6 does adjust ip6_plen. 552 */ 553 int 554 tsol_remove_secopt(ipha_t *ipha, int buflen) 555 { 556 int remlen, olen, oval, delta; 557 uchar_t *fptr, *tptr; 558 boolean_t noop_keep; 559 560 remlen = IPH_HDR_LENGTH(ipha) - IP_SIMPLE_HDR_LENGTH; 561 fptr = tptr = (uchar_t *)(ipha + 1); 562 noop_keep = B_TRUE; 563 while (remlen > 0) { 564 oval = fptr[IPOPT_OPTVAL]; 565 566 /* terminate on end of list */ 567 if (oval == IPOPT_EOL) 568 break; 569 570 /* 571 * Delete any no-ops following a deleted option, at least up 572 * to a 4 octet alignment; copy others. 573 */ 574 if (oval == IPOPT_NOP) { 575 if (((fptr - (uchar_t *)ipha) & 3) == 0) 576 noop_keep = B_TRUE; 577 if (noop_keep) 578 *tptr++ = oval; 579 fptr++; 580 remlen--; 581 continue; 582 } 583 584 /* stop on corrupted list; just do nothing. */ 585 if (remlen < 2) 586 return (0); 587 olen = fptr[IPOPT_OLEN]; 588 if (olen < 2 || olen > remlen) 589 return (0); 590 591 /* skip over security options to delete them */ 592 if (oval == IPOPT_COMSEC || oval == IPOPT_SECURITY) { 593 noop_keep = B_FALSE; 594 fptr += olen; 595 remlen -= olen; 596 continue; 597 } 598 599 /* copy the rest */ 600 noop_keep = B_TRUE; 601 if (tptr != fptr) 602 ovbcopy(fptr, tptr, olen); 603 fptr += olen; 604 tptr += olen; 605 remlen -= olen; 606 } 607 608 fptr += remlen; 609 610 /* figure how much padding we'll need for header alignment */ 611 olen = (tptr - (uchar_t *)ipha) & 3; 612 if (olen > 0) { 613 olen = 4 - olen; 614 /* pad with end-of-list */ 615 bzero(tptr, olen); 616 tptr += olen; 617 } 618 619 /* slide back the headers that follow and update the IP header */ 620 delta = fptr - tptr; 621 if (delta != 0) { 622 ovbcopy(fptr, tptr, ((uchar_t *)ipha + buflen) - fptr); 623 ipha->ipha_version_and_hdr_length -= delta / 4; 624 } 625 return (-delta); 626 } 627 628 /* 629 * Insert the option in 'optbuf' into the IP header pointed to by 'ipha', and 630 * move the data following the IP header (up to buflen) to accomodate the new 631 * option. Assumes that up to IP_MAX_OPT_LENGTH bytes are available (in total) 632 * for IP options. Returns the number of bytes actually inserted, or -1 if the 633 * option cannot be inserted. (Note that negative return values are possible 634 * when noops must be compressed, and that only -1 indicates error. Successful 635 * return value is always evenly divisible by 4, by definition.) 636 * 637 * Note that tsol_prepend_option does not adjust ipha_length but 638 * tsol_prepend_option_v6 does adjust ip6_plen. 639 */ 640 int 641 tsol_prepend_option(uchar_t *optbuf, ipha_t *ipha, int buflen) 642 { 643 int remlen, padding, lastpad, totlen; 644 int oval, olen; 645 int delta; 646 uchar_t *optr; 647 uchar_t tempopt[IP_MAX_OPT_LENGTH], *toptr; 648 649 if (optbuf[IPOPT_OPTVAL] == IPOPT_EOL || 650 optbuf[IPOPT_OPTVAL] == IPOPT_NOP || 651 optbuf[IPOPT_OLEN] == 0) 652 return (0); 653 654 ASSERT(optbuf[IPOPT_OLEN] >= 2 && 655 optbuf[IPOPT_OLEN] <= IP_MAX_OPT_LENGTH); 656 657 /* first find the real (unpadded) length of the existing options */ 658 remlen = IPH_HDR_LENGTH(ipha) - IP_SIMPLE_HDR_LENGTH; 659 padding = totlen = lastpad = 0; 660 optr = (uchar_t *)(ipha + 1); 661 while (remlen > 0) { 662 oval = optr[IPOPT_OPTVAL]; 663 664 /* stop at end of list */ 665 if (oval == IPOPT_EOL) 666 break; 667 668 /* skip no-ops, noting that length byte isn't present */ 669 if (oval == IPOPT_NOP) { 670 optr++; 671 padding++; 672 lastpad++; 673 totlen++; 674 remlen--; 675 continue; 676 } 677 678 /* give up on a corrupted list; report failure */ 679 if (remlen < 2) 680 return (-1); 681 olen = optr[IPOPT_OLEN]; 682 if (olen < 2 || olen > remlen) 683 return (-1); 684 685 lastpad = 0; 686 optr += olen; 687 totlen += olen; 688 remlen -= olen; 689 } 690 691 /* completely ignore any trailing padding */ 692 totlen -= lastpad; 693 padding -= lastpad; 694 695 /* 696 * If some sort of inter-option alignment was present, try to preserve 697 * that alignment. If alignment pushes us out past the maximum, then 698 * discard it and try to compress to fit. (We just "assume" that any 699 * padding added was attempting to get 32 bit alignment. If that's 700 * wrong, that's just too bad.) 701 */ 702 if (padding > 0) { 703 olen = (optbuf[IPOPT_OLEN] + 3) & ~3; 704 if (olen + totlen > IP_MAX_OPT_LENGTH) { 705 totlen -= padding; 706 if (olen + totlen > IP_MAX_OPT_LENGTH) 707 return (-1); 708 padding = 0; 709 } 710 } 711 712 /* 713 * Since we may need to compress or expand the option list, we write to 714 * a temporary buffer and then copy the results back to the IP header. 715 */ 716 toptr = tempopt; 717 718 /* compute actual option to insert */ 719 olen = optbuf[IPOPT_OLEN]; 720 bcopy(optbuf, toptr, olen); 721 toptr += olen; 722 if (padding > 0) { 723 while ((olen & 3) != 0) { 724 *toptr++ = IPOPT_NOP; 725 olen++; 726 } 727 } 728 729 /* copy over the existing options */ 730 optr = (uchar_t *)(ipha + 1); 731 while (totlen > 0) { 732 oval = optr[IPOPT_OPTVAL]; 733 734 /* totlen doesn't include end-of-list marker */ 735 ASSERT(oval != IPOPT_EOL); 736 737 /* handle no-ops; copy if desired, ignore otherwise */ 738 if (oval == IPOPT_NOP) { 739 if (padding > 0) { 740 /* note: cannot overflow due to checks above */ 741 ASSERT(toptr < tempopt + IP_MAX_OPT_LENGTH); 742 *toptr++ = oval; 743 } 744 optr++; 745 totlen--; 746 continue; 747 } 748 749 /* list cannot be corrupt at this point */ 750 ASSERT(totlen >= 2); 751 olen = optr[IPOPT_OLEN]; 752 ASSERT(olen >= 2 && olen <= totlen); 753 754 /* cannot run out of room due to tests above */ 755 ASSERT(toptr + olen <= tempopt + IP_MAX_OPT_LENGTH); 756 757 bcopy(optr, toptr, olen); 758 optr += olen; 759 toptr += olen; 760 totlen -= olen; 761 } 762 763 /* figure how much padding we'll need for header alignment */ 764 olen = (toptr - tempopt) & 3; 765 if (olen > 0) { 766 olen = 4 - olen; 767 ASSERT(toptr + olen <= tempopt + IP_MAX_OPT_LENGTH); 768 /* pad with end-of-list value */ 769 bzero(toptr, olen); 770 toptr += olen; 771 } 772 773 /* move the headers as needed and update IP header */ 774 olen = (toptr - tempopt) + IP_SIMPLE_HDR_LENGTH; 775 remlen = IPH_HDR_LENGTH(ipha); 776 delta = olen - remlen; 777 if (delta != 0) { 778 ovbcopy((uchar_t *)ipha + remlen, (uchar_t *)ipha + olen, 779 buflen - remlen); 780 ipha->ipha_version_and_hdr_length += delta / 4; 781 } 782 783 /* slap in the new options */ 784 bcopy(tempopt, ipha + 1, olen - IP_SIMPLE_HDR_LENGTH); 785 786 return (delta); 787 } 788 789 /* 790 * tsol_check_label_v4() 791 * 792 * This routine computes the IP label that should be on the packet based on the 793 * connection and destination information. It's called by the IP forwarding 794 * logic and by ip_output_simple. The ULPs generate the labels before calling 795 * conn_ip_output. If any adjustments to 796 * the label are needed due to the connection's MAC-exempt status or 797 * the destination's ability to receive labels, an "effective label" 798 * will be returned. 799 * 800 * The packet's header is clear before entering IPsec's engine. 801 * 802 * The zoneid is the IP zoneid (i.e., GLOBAL_ZONEID for exlusive-IP zones). 803 * zone_is_global is set if the actual zoneid is global. 804 * 805 * On successful return, effective_tslp will point to the new label needed 806 * or will be NULL if a new label isn't needed. On error, effective_tsl will 807 * point to NULL. 808 * 809 * Returns: 810 * 0 Label (was|is now) correct 811 * EACCES The packet failed the remote host accreditation. 812 * ENOMEM Memory allocation failure. 813 * EINVAL Label cannot be computed 814 */ 815 int 816 tsol_check_label_v4(const ts_label_t *tsl, zoneid_t zoneid, mblk_t **mpp, 817 uint_t mac_mode, boolean_t zone_is_global, ip_stack_t *ipst, 818 ts_label_t **effective_tslp) 819 { 820 mblk_t *mp = *mpp; 821 ipha_t *ipha; 822 ts_label_t *effective_tsl = NULL; 823 uchar_t opt_storage[IP_MAX_OPT_LENGTH]; 824 uint_t hlen; 825 uint_t sec_opt_len; 826 uchar_t *optr; 827 int delta_remove = 0, delta_add, adjust; 828 int retv; 829 830 *effective_tslp = NULL; 831 opt_storage[IPOPT_OPTVAL] = 0; 832 833 ipha = (ipha_t *)mp->b_rptr; 834 835 /* 836 * Verify the destination is allowed to receive packets at 837 * the security label of the message data. tsol_check_dest() 838 * may create a new effective label or label flags. 839 */ 840 retv = tsol_check_dest(tsl, &ipha->ipha_dst, IPV4_VERSION, 841 mac_mode, zone_is_global, &effective_tsl); 842 if (retv != 0) 843 return (retv); 844 845 /* 846 * Calculate the security label to be placed in the text 847 * of the message (if any). 848 */ 849 if (effective_tsl != NULL) { 850 if ((retv = tsol_compute_label_v4(effective_tsl, zoneid, 851 ipha->ipha_dst, opt_storage, ipst)) != 0) { 852 label_rele(effective_tsl); 853 return (retv); 854 } 855 *effective_tslp = effective_tsl; 856 } else { 857 if ((retv = tsol_compute_label_v4(tsl, zoneid, 858 ipha->ipha_dst, opt_storage, ipst)) != 0) { 859 return (retv); 860 } 861 } 862 863 optr = (uchar_t *)(ipha + 1); 864 hlen = IPH_HDR_LENGTH(ipha) - IP_SIMPLE_HDR_LENGTH; 865 sec_opt_len = opt_storage[IPOPT_OLEN]; 866 867 if (hlen >= sec_opt_len) { 868 /* If no option is supposed to be there, make sure it's not */ 869 if (sec_opt_len == 0 && hlen > 0 && 870 optr[IPOPT_OPTVAL] != IPOPT_COMSEC && 871 optr[IPOPT_OPTVAL] != IPOPT_SECURITY) 872 return (0); 873 /* if the option is there, it's always first */ 874 if (sec_opt_len != 0 && 875 bcmp(opt_storage, optr, sec_opt_len) == 0) 876 return (0); 877 } 878 879 /* 880 * If there is an option there, then it must be the wrong one; delete. 881 */ 882 if (hlen > 0) { 883 delta_remove = tsol_remove_secopt(ipha, MBLKL(mp)); 884 mp->b_wptr += delta_remove; 885 } 886 887 /* Make sure we have room for the worst-case addition */ 888 hlen = IPH_HDR_LENGTH(ipha) + opt_storage[IPOPT_OLEN]; 889 hlen = (hlen + 3) & ~3; 890 if (hlen > IP_MAX_HDR_LENGTH) 891 hlen = IP_MAX_HDR_LENGTH; 892 hlen -= IPH_HDR_LENGTH(ipha); 893 if (mp->b_wptr + hlen > mp->b_datap->db_lim) { 894 int copylen; 895 mblk_t *new_mp; 896 897 /* allocate enough to be meaningful, but not *too* much */ 898 copylen = MBLKL(mp); 899 if (copylen > 256) 900 copylen = 256; 901 new_mp = allocb_tmpl(hlen + copylen + 902 (mp->b_rptr - mp->b_datap->db_base), mp); 903 if (new_mp == NULL) { 904 if (effective_tsl != NULL) { 905 label_rele(effective_tsl); 906 *effective_tslp = NULL; 907 } 908 return (ENOMEM); 909 } 910 911 /* keep the bias */ 912 new_mp->b_rptr += mp->b_rptr - mp->b_datap->db_base; 913 new_mp->b_wptr = new_mp->b_rptr + copylen; 914 bcopy(mp->b_rptr, new_mp->b_rptr, copylen); 915 new_mp->b_cont = mp; 916 if ((mp->b_rptr += copylen) >= mp->b_wptr) { 917 new_mp->b_cont = mp->b_cont; 918 freeb(mp); 919 } 920 *mpp = mp = new_mp; 921 ipha = (ipha_t *)mp->b_rptr; 922 } 923 924 delta_add = tsol_prepend_option(opt_storage, ipha, MBLKL(mp)); 925 if (delta_add == -1) 926 goto param_prob; 927 928 ASSERT((mp->b_wptr + delta_add) <= DB_LIM(mp)); 929 mp->b_wptr += delta_add; 930 931 adjust = delta_remove + delta_add; 932 adjust += ntohs(ipha->ipha_length); 933 ipha->ipha_length = htons(adjust); 934 935 return (0); 936 937 param_prob: 938 if (effective_tsl != NULL) { 939 label_rele(effective_tsl); 940 *effective_tslp = NULL; 941 } 942 return (EINVAL); 943 } 944 945 /* 946 * IPv6 HopOpt extension header for the label option layout: 947 * - One octet giving the type of the 'next extension header' 948 * - Header extension length in 8-byte words, not including the 949 * 1st 8 bytes, but including any pad bytes at the end. 950 * Eg. A value of 2 means 16 bytes not including the 1st 8 bytes. 951 * - Followed by TLV encoded IPv6 label option. Option layout is 952 * * One octet, IP6OPT_LS 953 * * One octet option length in bytes of the option data following 954 * the length, but not including any pad bytes at the end. 955 * * Four-octet DOI (IP6LS_DOI_V4) 956 * * One octet suboption, IP6LS_TT_V4 957 * * One octet suboption length in bytes of the suboption 958 * following the suboption length, including the suboption 959 * header length, but not including any pad bytes at the end. 960 * - Pad to make the extension header a multiple of 8 bytes. 961 * 962 * This function returns the contents of 'IPv6 option structure' in the above. 963 * i.e starting from the IP6OPT_LS but not including the pad at the end. 964 * The user must prepend two octets (either padding or next header / length) 965 * and append padding out to the next 8 octet boundary. 966 * 967 * The zoneid is the IP zoneid (i.e., GLOBAL_ZONEID for exlusive-IP zones). 968 */ 969 int 970 tsol_compute_label_v6(const ts_label_t *tsl, zoneid_t zoneid, 971 const in6_addr_t *dst, uchar_t *opt_storage, ip_stack_t *ipst) 972 { 973 uint_t sec_opt_len; 974 uint32_t doi; 975 ire_t *ire; 976 tsol_ire_gw_secattr_t *attrp = NULL; 977 978 if (ip6opt_ls == 0) 979 return (EINVAL); 980 981 if (opt_storage != NULL) 982 opt_storage[IPOPT_OLEN] = 0; 983 984 if (tsl == NULL) 985 return (0); 986 987 /* Always pass multicast */ 988 if (IN6_IS_ADDR_MULTICAST(dst)) 989 return (0); 990 991 /* 992 * Fill in a V6 label. If a new format is added here, make certain 993 * that the maximum size of this label is reflected in sys/tsol/tnet.h 994 * as TSOL_MAX_IPV6_OPTION. 995 */ 996 if (tsl->tsl_flags & TSLF_IMPLICIT_OUT) 997 return (0); 998 999 if (tsl->tsl_flags & TSLF_UNLABELED) { 1000 /* 1001 * The destination is unlabeled. Only add a label if the 1002 * destination is not a broadcast/local/loopback address, 1003 * the destination is not on the same subnet, and the 1004 * next-hop gateway is labeled. 1005 */ 1006 ire = ire_route_recursive_v6(dst, 0, NULL, zoneid, tsl, 1007 MATCH_IRE_SECATTR, IRR_ALLOCATE, 0, ipst, NULL, &attrp, 1008 NULL); 1009 ASSERT(ire != NULL); 1010 if (ire->ire_flags & (RTF_REJECT|RTF_BLACKHOLE)) { 1011 /* no route to destination */ 1012 ire_refrele(ire); 1013 DTRACE_PROBE3( 1014 tx__tnopt__log__info__labeling__routedst__v6, 1015 char *, "No route to unlabeled dest ip6(1) with " 1016 "label(2).", in6_addr_t *, dst, ts_label_t *, tsl); 1017 return (EHOSTUNREACH); 1018 } 1019 if (ire->ire_type & (IRE_LOCAL | IRE_LOOPBACK | 1020 IRE_INTERFACE)) { 1021 ire_refrele(ire); 1022 return (0); 1023 } 1024 /* 1025 * ire_route_recursive gives us the first attrp it finds 1026 * in the recursive lookup. 1027 */ 1028 /* 1029 * Return now if next hop gateway is unlabeled. There is 1030 * no need to generate a CIPSO option for this message. 1031 */ 1032 if (attrp == NULL || attrp->igsa_rhc == NULL || 1033 attrp->igsa_rhc->rhc_tpc->tpc_tp.host_type == UNLABELED) { 1034 ire_refrele(ire); 1035 return (0); 1036 } 1037 ire_refrele(ire); 1038 } 1039 1040 /* compute the CIPSO option */ 1041 if (opt_storage != NULL) 1042 opt_storage += 8; 1043 sec_opt_len = tsol2cipso_tt1(&tsl->tsl_label, opt_storage, 1044 tsl->tsl_doi); 1045 1046 if (sec_opt_len == 0) { 1047 DTRACE_PROBE3(tx__tnopt__log__error__labeling__lostops__v6, 1048 char *, "options lack length for dest ip6(1) with " 1049 "label(2).", in6_addr_t *, dst, ts_label_t *, tsl); 1050 return (EINVAL); 1051 } 1052 1053 if (opt_storage == NULL) 1054 return (0); 1055 1056 if (sec_opt_len < IP_MAX_OPT_LENGTH) 1057 opt_storage[sec_opt_len] = IPOPT_EOL; 1058 1059 /* 1060 * Just in case the option length is odd, round it up to the next even 1061 * multiple. The IPv6 option definition doesn't like odd numbers for 1062 * some reason. 1063 * 1064 * Length in the overall option header (IP6OPT_LS) does not include the 1065 * option header itself, but the length in the suboption does include 1066 * the suboption header. Thus, when there's just one suboption, the 1067 * length in the option header is the suboption length plus 4 (for the 1068 * DOI value). 1069 */ 1070 opt_storage[-2] = IP6LS_TT_V4; 1071 opt_storage[-1] = (sec_opt_len + 2 + 1) & ~1; 1072 opt_storage[-8] = ip6opt_ls; 1073 opt_storage[-7] = opt_storage[-1] + 4; 1074 doi = htons(IP6LS_DOI_V4); 1075 bcopy(&doi, opt_storage - 6, 4); 1076 1077 return (0); 1078 } 1079 1080 /* 1081 * Locate the start of the IP6OPT_LS label option and return it. 1082 * Also return the start of the next non-pad option in after_secoptp. 1083 * Usually the label option is the first option at least when packets 1084 * are generated, but for generality we don't assume that on received packets. 1085 * 1086 * The function will return with B_FALSE if an IP format error 1087 * or an unexpected label content error is encountered. 1088 */ 1089 boolean_t 1090 tsol_find_secopt_v6( 1091 const uchar_t *ip6hbh, /* Start of the hop-by-hop extension header */ 1092 uint_t hbhlen, /* Length of the hop-by-hop extension header */ 1093 uchar_t **secoptp, /* Location of IP6OPT_LS label option */ 1094 uchar_t **after_secoptp, /* Non-pad option following the label option */ 1095 boolean_t *hbh_needed) /* Is hop-by-hop hdr needed w/o label */ 1096 { 1097 uint_t optlen; 1098 uint_t optused; 1099 const uchar_t *optptr; 1100 uchar_t opt_type; 1101 1102 *secoptp = NULL; 1103 *hbh_needed = B_FALSE; 1104 *after_secoptp = NULL; 1105 optlen = hbhlen - 2; 1106 optptr = ip6hbh + 2; 1107 while (optlen != 0) { 1108 opt_type = *optptr; 1109 if (opt_type == IP6OPT_PAD1) { 1110 optptr++; 1111 optlen--; 1112 continue; 1113 } 1114 if (optlen == 1) 1115 return (B_FALSE); 1116 optused = 2 + optptr[1]; 1117 if (optused > optlen) 1118 return (B_FALSE); 1119 /* 1120 * if we get here, ip6opt_ls can 1121 * not be 0 because it will always 1122 * match the IP6OPT_PAD1 above. 1123 * Therefore ip6opt_ls == 0 forces 1124 * this test to always fail here. 1125 */ 1126 if (opt_type == ip6opt_ls) { 1127 if (*secoptp != NULL) 1128 /* More than one security option found */ 1129 return (B_FALSE); 1130 *secoptp = (uchar_t *)optptr; 1131 } else switch (opt_type) { 1132 case IP6OPT_PADN: 1133 break; 1134 default: 1135 /* 1136 * There is at least 1 option other than 1137 * the label option. So the hop-by-hop header is needed 1138 */ 1139 *hbh_needed = B_TRUE; 1140 if (*secoptp != NULL) { 1141 *after_secoptp = (uchar_t *)optptr; 1142 return (B_TRUE); 1143 } 1144 break; 1145 } 1146 optlen -= optused; 1147 optptr += optused; 1148 } 1149 return (B_TRUE); 1150 } 1151 1152 /* 1153 * Remove the label option from the hop-by-hop options header if it exists. 1154 * 'buflen' is the total length of the packet typically b_wptr - b_rptr. 1155 * Header and data following the label option that is deleted are copied 1156 * (i.e. slid backward) to the right position, and returns the number 1157 * of bytes removed (as zero or negative number.) 1158 * 1159 * Note that tsol_remove_secopt does not adjust ipha_length but 1160 * tsol_remove_secopt_v6 does adjust ip6_plen. 1161 */ 1162 int 1163 tsol_remove_secopt_v6(ip6_t *ip6h, int buflen) 1164 { 1165 uchar_t *ip6hbh; /* hop-by-hop header */ 1166 uint_t hbhlen; /* hop-by-hop extension header length */ 1167 uchar_t *secopt = NULL; 1168 uchar_t *after_secopt; 1169 uint_t pad; 1170 uint_t delta; 1171 boolean_t hbh_needed; 1172 1173 /* 1174 * hop-by-hop extension header must appear first, if it does not 1175 * exist, there is no label option. 1176 */ 1177 if (ip6h->ip6_nxt != IPPROTO_HOPOPTS) 1178 return (0); 1179 1180 ip6hbh = (uchar_t *)&ip6h[1]; 1181 hbhlen = (ip6hbh[1] + 1) << 3; 1182 /* 1183 * Locate the start of the label option if it exists and the end 1184 * of the label option including pads if any. 1185 */ 1186 if (!tsol_find_secopt_v6(ip6hbh, hbhlen, &secopt, &after_secopt, 1187 &hbh_needed)) { 1188 /* 1189 * This function should not see invalid messages. 1190 * If one occurs, it would indicate either an 1191 * option previously verified in the forwarding 1192 * path has been corrupted or an option was 1193 * incorrectly generated locally. 1194 */ 1195 ASSERT(0); 1196 return (0); 1197 } 1198 if (secopt == NULL) 1199 return (0); 1200 if (!hbh_needed) { 1201 uchar_t next_hdr; 1202 /* 1203 * The label option was the only option in the hop-by-hop 1204 * header. We don't need the hop-by-hop header itself any 1205 * longer. 1206 */ 1207 next_hdr = ip6hbh[0]; 1208 ovbcopy(ip6hbh + hbhlen, ip6hbh, 1209 buflen - (IPV6_HDR_LEN + hbhlen)); 1210 ip6h->ip6_plen = htons(ntohs(ip6h->ip6_plen) - hbhlen); 1211 ip6h->ip6_nxt = next_hdr; 1212 return (-hbhlen); 1213 } 1214 1215 if (after_secopt == NULL) { 1216 /* There is no option following the label option */ 1217 after_secopt = ip6hbh + hbhlen; 1218 } 1219 1220 /* 1221 * After deleting the label option, we need to slide the headers 1222 * and data back, while still maintaining the same alignment (module 8) 1223 * for the other options. So we slide the headers and data back only 1224 * by an integral multiple of 8 bytes, and fill the remaining bytes 1225 * with pads. 1226 */ 1227 delta = after_secopt - secopt; 1228 pad = delta % 8; 1229 if (pad == 1) { 1230 secopt[0] = IP6OPT_PAD1; 1231 } else if (pad > 1) { 1232 secopt[0] = IP6OPT_PADN; 1233 secopt[1] = pad - 2; 1234 if (pad > 2) 1235 bzero(&secopt[2], pad - 2); 1236 } 1237 secopt += pad; 1238 delta -= pad; 1239 ovbcopy(after_secopt, secopt, 1240 (uchar_t *)ip6h + buflen - after_secopt); 1241 ip6hbh[1] -= delta/8; 1242 ip6h->ip6_plen = htons(ntohs(ip6h->ip6_plen) - delta); 1243 1244 return (-delta); 1245 } 1246 1247 /* 1248 * 'optbuf' contains a CIPSO label embedded in an IPv6 hop-by-hop option, 1249 * starting with the IP6OPT_LS option type. The format of this hop-by-hop 1250 * option is described in the block comment above tsol_compute_label_v6. 1251 * This function prepends this hop-by-hop option before any other hop-by-hop 1252 * options in the hop-by-hop header if one already exists, else a new 1253 * hop-by-hop header is created and stuffed into the packet following 1254 * the IPv6 header. 'buflen' is the total length of the packet i.e. 1255 * b_wptr - b_rptr. The caller ensures that there is enough space for the 1256 * extra option being added. Header and data following the position where 1257 * the label option is inserted are copied (i.e. slid forward) to the right 1258 * position. 1259 * 1260 * Note that tsol_prepend_option does not adjust ipha_length but 1261 * tsol_prepend_option_v6 does adjust ip6_plen. 1262 */ 1263 int 1264 tsol_prepend_option_v6(uchar_t *optbuf, ip6_t *ip6h, int buflen) 1265 { 1266 /* 1267 * rawlen is the length of the label option in bytes, not including 1268 * any pads, starting from the IP6OPT_LS (option type) byte. 1269 */ 1270 uint_t rawlen; 1271 1272 uint_t optlen; /* rawlen rounded to an 8 byte multiple */ 1273 uchar_t *ip6hbh; /* start of the hop-by-hop extension header */ 1274 uint_t hbhlen; /* Length of the hop-by-hop extension header */ 1275 uint_t pad_len; 1276 uchar_t *pad_position; 1277 int delta; /* Actual number of bytes inserted */ 1278 1279 rawlen = optbuf[1] + 2; /* Add 2 for the option type, option length */ 1280 ip6hbh = (uchar_t *)&ip6h[1]; 1281 if (ip6h->ip6_nxt == IPPROTO_HOPOPTS) { 1282 /* 1283 * There is a hop-by-hop header present already. In order to 1284 * preserve the alignment of the other options at the existing 1285 * value (modulo 8) we need to pad the label option to a 1286 * multiple of 8 bytes before prepending it to the other 1287 * options. Slide the extension headers and data forward to 1288 * accomodate the label option at the start of the hop-by-hop 1289 * header 1290 */ 1291 delta = optlen = (rawlen + 7) & ~7; 1292 pad_len = optlen - rawlen; 1293 pad_position = ip6hbh + 2 + rawlen; 1294 ovbcopy(ip6hbh + 2, ip6hbh + 2 + optlen, 1295 buflen - (IPV6_HDR_LEN + 2)); 1296 /* 1297 * Bump up the hop-by-hop extension header length by 1298 * the number of 8-byte words added 1299 */ 1300 optlen >>= 3; 1301 if (ip6hbh[1] + optlen > 255) 1302 return (-1); 1303 ip6hbh[1] += optlen; 1304 } else { 1305 /* 1306 * There is no hop-by-hop header in the packet. Construct a 1307 * new Hop-by-hop extension header (a multiple of 8 bytes). 1308 * Slide any other extension headers and data forward to 1309 * accomodate this hop-by-hop header 1310 */ 1311 delta = hbhlen = (2 + rawlen + 7) & ~7; /* +2 for nxthdr, len */ 1312 pad_len = hbhlen - (2 + rawlen); 1313 pad_position = ip6hbh + 2 + rawlen; 1314 ovbcopy(ip6hbh, ip6hbh + hbhlen, buflen - IPV6_HDR_LEN); 1315 ip6hbh[0] = ip6h->ip6_nxt; 1316 /* 1317 * hop-by-hop extension header length in 8-byte words, not 1318 * including the 1st 8 bytes of the hop-by-hop header. 1319 */ 1320 ip6hbh[1] = (hbhlen >> 3) - 1; 1321 ip6h->ip6_nxt = IPPROTO_HOPOPTS; 1322 } 1323 /* 1324 * Copy the label option into the hop-by-hop header and insert any 1325 * needed pads 1326 */ 1327 bcopy(optbuf, ip6hbh + 2, rawlen); 1328 if (pad_len == 1) { 1329 pad_position[0] = IP6OPT_PAD1; 1330 } else if (pad_len > 1) { 1331 pad_position[0] = IP6OPT_PADN; 1332 pad_position[1] = pad_len - 2; 1333 if (pad_len > 2) 1334 bzero(pad_position + 2, pad_len - 2); 1335 } 1336 ip6h->ip6_plen = htons(ntohs(ip6h->ip6_plen) + delta); 1337 return (delta); 1338 } 1339 1340 /* 1341 * tsol_check_label_v6() 1342 * 1343 * This routine computes the IP label that should be on the packet based on the 1344 * connection and destination information. It's called by the IP forwarding 1345 * logic and by ip_output_simple. The ULPs generate the labels before calling 1346 * conn_ip_output. If any adjustments to 1347 * the label are needed due to the connection's MAC-exempt status or 1348 * the destination's ability to receive labels, an "effective label" 1349 * will be returned. 1350 * 1351 * The packet's header is clear before entering IPsec's engine. 1352 * 1353 * The zoneid is the IP zoneid (i.e., GLOBAL_ZONEID for exlusive-IP zones). 1354 * zone_is_global is set if the actual zoneid is global. 1355 * 1356 * On successful return, effective_tslp will point to the new label needed 1357 * or will be NULL if a new label isn't needed. On error, effective_tsl will 1358 * point to NULL. 1359 * 1360 * Returns: 1361 * 0 Label (was|is now) correct 1362 * EACCES The packet failed the remote host accreditation. 1363 * ENOMEM Memory allocation failure. 1364 * EINVAL Label cannot be computed 1365 */ 1366 int 1367 tsol_check_label_v6(const ts_label_t *tsl, zoneid_t zoneid, mblk_t **mpp, 1368 uint_t mac_mode, boolean_t zone_is_global, ip_stack_t *ipst, 1369 ts_label_t **effective_tslp) 1370 { 1371 mblk_t *mp = *mpp; 1372 ip6_t *ip6h; 1373 ts_label_t *effective_tsl = NULL; 1374 /* 1375 * Label option length is limited to IP_MAX_OPT_LENGTH for 1376 * symmetry with IPv4. Can be relaxed if needed 1377 */ 1378 uchar_t opt_storage[TSOL_MAX_IPV6_OPTION]; 1379 uint_t hlen; 1380 uint_t sec_opt_len; /* label option length not including type, len */ 1381 int delta_remove = 0, delta_add; 1382 int retv; 1383 uchar_t *after_secopt; 1384 uchar_t *secopt = NULL; 1385 uchar_t *ip6hbh; 1386 uint_t hbhlen; 1387 boolean_t hbh_needed; 1388 1389 *effective_tslp = NULL; 1390 1391 /* 1392 * Verify the destination is allowed to receive packets at 1393 * the security label of the message data. tsol_check_dest() 1394 * may create a new effective label or label flags. 1395 */ 1396 ip6h = (ip6_t *)mp->b_rptr; 1397 retv = tsol_check_dest(tsl, &ip6h->ip6_dst, IPV6_VERSION, 1398 mac_mode, zone_is_global, &effective_tsl); 1399 if (retv != 0) 1400 return (retv); 1401 1402 /* 1403 * Calculate the security label to be placed in the text 1404 * of the message (if any). 1405 */ 1406 if (effective_tsl != NULL) { 1407 if ((retv = tsol_compute_label_v6(effective_tsl, zoneid, 1408 &ip6h->ip6_dst, opt_storage, ipst)) != 0) { 1409 label_rele(effective_tsl); 1410 return (retv); 1411 } 1412 *effective_tslp = effective_tsl; 1413 } else { 1414 if ((retv = tsol_compute_label_v6(tsl, zoneid, 1415 &ip6h->ip6_dst, opt_storage, ipst)) != 0) 1416 return (retv); 1417 } 1418 1419 sec_opt_len = opt_storage[1]; 1420 1421 if (ip6h->ip6_nxt == IPPROTO_HOPOPTS) { 1422 ip6hbh = (uchar_t *)&ip6h[1]; 1423 hbhlen = (ip6hbh[1] + 1) << 3; 1424 if (!tsol_find_secopt_v6(ip6hbh, hbhlen, &secopt, 1425 &after_secopt, &hbh_needed)) { 1426 /* 1427 * This function should not see invalid messages. 1428 * If one occurs, it would indicate either an 1429 * option previously verified in the forwarding 1430 * path has been corrupted or an option was 1431 * incorrectly generated locally. 1432 */ 1433 ASSERT(0); 1434 return (EACCES); 1435 } 1436 } 1437 1438 if (sec_opt_len == 0 && secopt == NULL) { 1439 /* 1440 * The packet is not supposed to have a label, and it 1441 * does not have one currently 1442 */ 1443 return (0); 1444 } 1445 1446 if (secopt != NULL && sec_opt_len != 0 && 1447 (bcmp(opt_storage, secopt, sec_opt_len + 2) == 0)) { 1448 /* The packet has the correct label already */ 1449 return (0); 1450 } 1451 1452 /* 1453 * If there is an option there, then it must be the wrong one; delete. 1454 */ 1455 if (secopt != NULL) { 1456 delta_remove = tsol_remove_secopt_v6(ip6h, MBLKL(mp)); 1457 mp->b_wptr += delta_remove; 1458 } 1459 1460 /* 1461 * Make sure we have room for the worst-case addition. Add 2 bytes for 1462 * the hop-by-hop ext header's next header and length fields. Add 1463 * another 2 bytes for the label option type, len and then round 1464 * up to the next 8-byte multiple. 1465 */ 1466 hlen = (4 + sec_opt_len + 7) & ~7; 1467 if (mp->b_wptr + hlen > mp->b_datap->db_lim) { 1468 int copylen; 1469 mblk_t *new_mp; 1470 uint16_t hdr_len; 1471 1472 hdr_len = ip_hdr_length_v6(mp, ip6h); 1473 /* 1474 * Allocate enough to be meaningful, but not *too* much. 1475 * Also all the IPv6 extension headers must be in the same mblk 1476 */ 1477 copylen = MBLKL(mp); 1478 if (copylen > 256) 1479 copylen = 256; 1480 if (copylen < hdr_len) 1481 copylen = hdr_len; 1482 new_mp = allocb_tmpl(hlen + copylen + 1483 (mp->b_rptr - mp->b_datap->db_base), mp); 1484 if (new_mp == NULL) { 1485 if (effective_tsl != NULL) { 1486 label_rele(effective_tsl); 1487 *effective_tslp = NULL; 1488 } 1489 return (ENOMEM); 1490 } 1491 1492 /* keep the bias */ 1493 new_mp->b_rptr += mp->b_rptr - mp->b_datap->db_base; 1494 new_mp->b_wptr = new_mp->b_rptr + copylen; 1495 bcopy(mp->b_rptr, new_mp->b_rptr, copylen); 1496 new_mp->b_cont = mp; 1497 if ((mp->b_rptr += copylen) >= mp->b_wptr) { 1498 new_mp->b_cont = mp->b_cont; 1499 freeb(mp); 1500 } 1501 *mpp = mp = new_mp; 1502 ip6h = (ip6_t *)mp->b_rptr; 1503 } 1504 1505 delta_add = tsol_prepend_option_v6(opt_storage, ip6h, MBLKL(mp)); 1506 if (delta_add == -1) 1507 goto param_prob; 1508 1509 ASSERT(mp->b_wptr + delta_add <= DB_LIM(mp)); 1510 mp->b_wptr += delta_add; 1511 1512 /* tsol_prepend_option_v6 has adjusted ip6_plen */ 1513 return (0); 1514 1515 param_prob: 1516 if (effective_tsl != NULL) { 1517 label_rele(effective_tsl); 1518 *effective_tslp = NULL; 1519 } 1520 return (EINVAL); 1521 } 1522