Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

calipso: Set the calipso socket label to match the secattr.

CALIPSO is a hop-by-hop IPv6 option. A lot of this patch is based on
the equivalent CISPO code. The main difference is due to manipulating
the options in the hop-by-hop header.

Signed-off-by: Huw Davies <huw@codeweavers.com>
Signed-off-by: Paul Moore <paul@paul-moore.com>

authored by

Huw Davies and committed by
Paul Moore
ceba1832 3faa8f98

+728 -10
+2
include/net/ipv6.h
··· 319 319 320 320 bool ipv6_opt_accepted(const struct sock *sk, const struct sk_buff *skb, 321 321 const struct inet6_skb_parm *opt); 322 + struct ipv6_txoptions *ipv6_update_options(struct sock *sk, 323 + struct ipv6_txoptions *opt); 322 324 323 325 static inline bool ipv6_accept_ra(struct inet6_dev *idev) 324 326 {
+9
include/net/netlabel.h
··· 226 226 * @doi_getdef: returns a reference to a DOI 227 227 * @doi_putdef: releases a reference of a DOI 228 228 * @doi_walk: enumerate the DOI list 229 + * @sock_getattr: retrieve the socket's attr 230 + * @sock_setattr: set the socket's attr 231 + * @sock_delattr: remove the socket's attr 229 232 * 230 233 * Description: 231 234 * This structure is filled out by the CALIPSO engine and passed ··· 246 243 int (*doi_walk)(u32 *skip_cnt, 247 244 int (*callback)(struct calipso_doi *doi_def, void *arg), 248 245 void *cb_arg); 246 + int (*sock_getattr)(struct sock *sk, 247 + struct netlbl_lsm_secattr *secattr); 248 + int (*sock_setattr)(struct sock *sk, 249 + const struct calipso_doi *doi_def, 250 + const struct netlbl_lsm_secattr *secattr); 251 + void (*sock_delattr)(struct sock *sk); 249 252 }; 250 253 251 254 /*
+1
include/uapi/linux/in6.h
··· 143 143 #define IPV6_TLV_PAD1 0 144 144 #define IPV6_TLV_PADN 1 145 145 #define IPV6_TLV_ROUTERALERT 5 146 + #define IPV6_TLV_CALIPSO 7 /* RFC 5570 */ 146 147 #define IPV6_TLV_JUMBO 194 147 148 #define IPV6_TLV_HAO 201 /* home address option */ 148 149
+595
net/ipv6/calipso.c
··· 44 44 #include <linux/atomic.h> 45 45 #include <linux/bug.h> 46 46 #include <asm/unaligned.h> 47 + #include <linux/crc-ccitt.h> 48 + 49 + /* Maximium size of the calipso option including 50 + * the two-byte TLV header. 51 + */ 52 + #define CALIPSO_OPT_LEN_MAX (2 + 252) 53 + 54 + /* Size of the minimum calipso option including 55 + * the two-byte TLV header. 56 + */ 57 + #define CALIPSO_HDR_LEN (2 + 8) 58 + 59 + /* Maximium size of the calipso option including 60 + * the two-byte TLV header and upto 3 bytes of 61 + * leading pad and 7 bytes of trailing pad. 62 + */ 63 + #define CALIPSO_OPT_LEN_MAX_WITH_PAD (3 + CALIPSO_OPT_LEN_MAX + 7) 64 + 47 65 48 66 /* List of available DOI definitions */ 49 67 static DEFINE_SPINLOCK(calipso_doi_list_lock); ··· 315 297 return ret_val; 316 298 } 317 299 300 + /** 301 + * calipso_map_cat_hton - Perform a category mapping from host to network 302 + * @doi_def: the DOI definition 303 + * @secattr: the security attributes 304 + * @net_cat: the zero'd out category bitmap in network/CALIPSO format 305 + * @net_cat_len: the length of the CALIPSO bitmap in bytes 306 + * 307 + * Description: 308 + * Perform a label mapping to translate a local MLS category bitmap to the 309 + * correct CALIPSO bitmap using the given DOI definition. Returns the minimum 310 + * size in bytes of the network bitmap on success, negative values otherwise. 311 + * 312 + */ 313 + static int calipso_map_cat_hton(const struct calipso_doi *doi_def, 314 + const struct netlbl_lsm_secattr *secattr, 315 + unsigned char *net_cat, 316 + u32 net_cat_len) 317 + { 318 + int spot = -1; 319 + u32 net_spot_max = 0; 320 + u32 net_clen_bits = net_cat_len * 8; 321 + 322 + for (;;) { 323 + spot = netlbl_catmap_walk(secattr->attr.mls.cat, 324 + spot + 1); 325 + if (spot < 0) 326 + break; 327 + if (spot >= net_clen_bits) 328 + return -ENOSPC; 329 + netlbl_bitmap_setbit(net_cat, spot, 1); 330 + 331 + if (spot > net_spot_max) 332 + net_spot_max = spot; 333 + } 334 + 335 + return (net_spot_max / 32 + 1) * 4; 336 + } 337 + 338 + /** 339 + * calipso_map_cat_ntoh - Perform a category mapping from network to host 340 + * @doi_def: the DOI definition 341 + * @net_cat: the category bitmap in network/CALIPSO format 342 + * @net_cat_len: the length of the CALIPSO bitmap in bytes 343 + * @secattr: the security attributes 344 + * 345 + * Description: 346 + * Perform a label mapping to translate a CALIPSO bitmap to the correct local 347 + * MLS category bitmap using the given DOI definition. Returns zero on 348 + * success, negative values on failure. 349 + * 350 + */ 351 + static int calipso_map_cat_ntoh(const struct calipso_doi *doi_def, 352 + const unsigned char *net_cat, 353 + u32 net_cat_len, 354 + struct netlbl_lsm_secattr *secattr) 355 + { 356 + int ret_val; 357 + int spot = -1; 358 + u32 net_clen_bits = net_cat_len * 8; 359 + 360 + for (;;) { 361 + spot = netlbl_bitmap_walk(net_cat, 362 + net_clen_bits, 363 + spot + 1, 364 + 1); 365 + if (spot < 0) { 366 + if (spot == -2) 367 + return -EFAULT; 368 + return 0; 369 + } 370 + 371 + ret_val = netlbl_catmap_setbit(&secattr->attr.mls.cat, 372 + spot, 373 + GFP_ATOMIC); 374 + if (ret_val != 0) 375 + return ret_val; 376 + } 377 + 378 + return -EINVAL; 379 + } 380 + 381 + /** 382 + * calipso_pad_write - Writes pad bytes in TLV format 383 + * @buf: the buffer 384 + * @offset: offset from start of buffer to write padding 385 + * @count: number of pad bytes to write 386 + * 387 + * Description: 388 + * Write @count bytes of TLV padding into @buffer starting at offset @offset. 389 + * @count should be less than 8 - see RFC 4942. 390 + * 391 + */ 392 + static int calipso_pad_write(unsigned char *buf, unsigned int offset, 393 + unsigned int count) 394 + { 395 + if (WARN_ON_ONCE(count >= 8)) 396 + return -EINVAL; 397 + 398 + switch (count) { 399 + case 0: 400 + break; 401 + case 1: 402 + buf[offset] = IPV6_TLV_PAD1; 403 + break; 404 + default: 405 + buf[offset] = IPV6_TLV_PADN; 406 + buf[offset + 1] = count - 2; 407 + if (count > 2) 408 + memset(buf + offset + 2, 0, count - 2); 409 + break; 410 + } 411 + return 0; 412 + } 413 + 414 + /** 415 + * calipso_genopt - Generate a CALIPSO option 416 + * @buf: the option buffer 417 + * @start: offset from which to write 418 + * @buf_len: the size of opt_buf 419 + * @doi_def: the CALIPSO DOI to use 420 + * @secattr: the security attributes 421 + * 422 + * Description: 423 + * Generate a CALIPSO option using the DOI definition and security attributes 424 + * passed to the function. This also generates upto three bytes of leading 425 + * padding that ensures that the option is 4n + 2 aligned. It returns the 426 + * number of bytes written (including any initial padding). 427 + */ 428 + static int calipso_genopt(unsigned char *buf, u32 start, u32 buf_len, 429 + const struct calipso_doi *doi_def, 430 + const struct netlbl_lsm_secattr *secattr) 431 + { 432 + int ret_val; 433 + u32 len, pad; 434 + u16 crc; 435 + static const unsigned char padding[4] = {2, 1, 0, 3}; 436 + unsigned char *calipso; 437 + 438 + /* CALIPSO has 4n + 2 alignment */ 439 + pad = padding[start & 3]; 440 + if (buf_len <= start + pad + CALIPSO_HDR_LEN) 441 + return -ENOSPC; 442 + 443 + if ((secattr->flags & NETLBL_SECATTR_MLS_LVL) == 0) 444 + return -EPERM; 445 + 446 + len = CALIPSO_HDR_LEN; 447 + 448 + if (secattr->flags & NETLBL_SECATTR_MLS_CAT) { 449 + ret_val = calipso_map_cat_hton(doi_def, 450 + secattr, 451 + buf + start + pad + len, 452 + buf_len - start - pad - len); 453 + if (ret_val < 0) 454 + return ret_val; 455 + len += ret_val; 456 + } 457 + 458 + calipso_pad_write(buf, start, pad); 459 + calipso = buf + start + pad; 460 + 461 + calipso[0] = IPV6_TLV_CALIPSO; 462 + calipso[1] = len - 2; 463 + *(__be32 *)(calipso + 2) = htonl(doi_def->doi); 464 + calipso[6] = (len - CALIPSO_HDR_LEN) / 4; 465 + calipso[7] = secattr->attr.mls.lvl, 466 + crc = ~crc_ccitt(0xffff, calipso, len); 467 + calipso[8] = crc & 0xff; 468 + calipso[9] = (crc >> 8) & 0xff; 469 + return pad + len; 470 + } 471 + 472 + /* Hop-by-hop hdr helper functions 473 + */ 474 + 475 + /** 476 + * calipso_opt_update - Replaces socket's hop options with a new set 477 + * @sk: the socket 478 + * @hop: new hop options 479 + * 480 + * Description: 481 + * Replaces @sk's hop options with @hop. @hop may be NULL to leave 482 + * the socket with no hop options. 483 + * 484 + */ 485 + static int calipso_opt_update(struct sock *sk, struct ipv6_opt_hdr *hop) 486 + { 487 + struct ipv6_txoptions *old = txopt_get(inet6_sk(sk)), *txopts; 488 + 489 + txopts = ipv6_renew_options_kern(sk, old, IPV6_HOPOPTS, 490 + hop, hop ? ipv6_optlen(hop) : 0); 491 + txopt_put(old); 492 + if (IS_ERR(txopts)) 493 + return PTR_ERR(txopts); 494 + 495 + txopts = ipv6_update_options(sk, txopts); 496 + if (txopts) { 497 + atomic_sub(txopts->tot_len, &sk->sk_omem_alloc); 498 + txopt_put(txopts); 499 + } 500 + 501 + return 0; 502 + } 503 + 504 + /** 505 + * calipso_tlv_len - Returns the length of the TLV 506 + * @opt: the option header 507 + * @offset: offset of the TLV within the header 508 + * 509 + * Description: 510 + * Returns the length of the TLV option at offset @offset within 511 + * the option header @opt. Checks that the entire TLV fits inside 512 + * the option header, returns a negative value if this is not the case. 513 + */ 514 + static int calipso_tlv_len(struct ipv6_opt_hdr *opt, unsigned int offset) 515 + { 516 + unsigned char *tlv = (unsigned char *)opt; 517 + unsigned int opt_len = ipv6_optlen(opt), tlv_len; 518 + 519 + if (offset < sizeof(*opt) || offset >= opt_len) 520 + return -EINVAL; 521 + if (tlv[offset] == IPV6_TLV_PAD1) 522 + return 1; 523 + if (offset + 1 >= opt_len) 524 + return -EINVAL; 525 + tlv_len = tlv[offset + 1] + 2; 526 + if (offset + tlv_len > opt_len) 527 + return -EINVAL; 528 + return tlv_len; 529 + } 530 + 531 + /** 532 + * calipso_opt_find - Finds the CALIPSO option in an IPv6 hop options header 533 + * @hop: the hop options header 534 + * @start: on return holds the offset of any leading padding 535 + * @end: on return holds the offset of the first non-pad TLV after CALIPSO 536 + * 537 + * Description: 538 + * Finds the space occupied by a CALIPSO option (including any leading and 539 + * trailing padding). 540 + * 541 + * If a CALIPSO option exists set @start and @end to the 542 + * offsets within @hop of the start of padding before the first 543 + * CALIPSO option and the end of padding after the first CALIPSO 544 + * option. In this case the function returns 0. 545 + * 546 + * In the absence of a CALIPSO option, @start and @end will be 547 + * set to the start and end of any trailing padding in the header. 548 + * This is useful when appending a new option, as the caller may want 549 + * to overwrite some of this padding. In this case the function will 550 + * return -ENOENT. 551 + */ 552 + static int calipso_opt_find(struct ipv6_opt_hdr *hop, unsigned int *start, 553 + unsigned int *end) 554 + { 555 + int ret_val = -ENOENT, tlv_len; 556 + unsigned int opt_len, offset, offset_s = 0, offset_e = 0; 557 + unsigned char *opt = (unsigned char *)hop; 558 + 559 + opt_len = ipv6_optlen(hop); 560 + offset = sizeof(*hop); 561 + 562 + while (offset < opt_len) { 563 + tlv_len = calipso_tlv_len(hop, offset); 564 + if (tlv_len < 0) 565 + return tlv_len; 566 + 567 + switch (opt[offset]) { 568 + case IPV6_TLV_PAD1: 569 + case IPV6_TLV_PADN: 570 + if (offset_e) 571 + offset_e = offset; 572 + break; 573 + case IPV6_TLV_CALIPSO: 574 + ret_val = 0; 575 + offset_e = offset; 576 + break; 577 + default: 578 + if (offset_e == 0) 579 + offset_s = offset; 580 + else 581 + goto out; 582 + } 583 + offset += tlv_len; 584 + } 585 + 586 + out: 587 + if (offset_s) 588 + *start = offset_s + calipso_tlv_len(hop, offset_s); 589 + else 590 + *start = sizeof(*hop); 591 + if (offset_e) 592 + *end = offset_e + calipso_tlv_len(hop, offset_e); 593 + else 594 + *end = opt_len; 595 + 596 + return ret_val; 597 + } 598 + 599 + /** 600 + * calipso_opt_insert - Inserts a CALIPSO option into an IPv6 hop opt hdr 601 + * @hop: the original hop options header 602 + * @doi_def: the CALIPSO DOI to use 603 + * @secattr: the specific security attributes of the socket 604 + * 605 + * Description: 606 + * Creates a new hop options header based on @hop with a 607 + * CALIPSO option added to it. If @hop already contains a CALIPSO 608 + * option this is overwritten, otherwise the new option is appended 609 + * after any existing options. If @hop is NULL then the new header 610 + * will contain just the CALIPSO option and any needed padding. 611 + * 612 + */ 613 + static struct ipv6_opt_hdr * 614 + calipso_opt_insert(struct ipv6_opt_hdr *hop, 615 + const struct calipso_doi *doi_def, 616 + const struct netlbl_lsm_secattr *secattr) 617 + { 618 + unsigned int start, end, buf_len, pad, hop_len; 619 + struct ipv6_opt_hdr *new; 620 + int ret_val; 621 + 622 + if (hop) { 623 + hop_len = ipv6_optlen(hop); 624 + ret_val = calipso_opt_find(hop, &start, &end); 625 + if (ret_val && ret_val != -ENOENT) 626 + return ERR_PTR(ret_val); 627 + } else { 628 + hop_len = 0; 629 + start = sizeof(*hop); 630 + end = 0; 631 + } 632 + 633 + buf_len = hop_len + start - end + CALIPSO_OPT_LEN_MAX_WITH_PAD; 634 + new = kzalloc(buf_len, GFP_ATOMIC); 635 + if (!new) 636 + return ERR_PTR(-ENOMEM); 637 + 638 + if (start > sizeof(*hop)) 639 + memcpy(new, hop, start); 640 + ret_val = calipso_genopt((unsigned char *)new, start, buf_len, doi_def, 641 + secattr); 642 + if (ret_val < 0) 643 + return ERR_PTR(ret_val); 644 + 645 + buf_len = start + ret_val; 646 + /* At this point buf_len aligns to 4n, so (buf_len & 4) pads to 8n */ 647 + pad = ((buf_len & 4) + (end & 7)) & 7; 648 + calipso_pad_write((unsigned char *)new, buf_len, pad); 649 + buf_len += pad; 650 + 651 + if (end != hop_len) { 652 + memcpy((char *)new + buf_len, (char *)hop + end, hop_len - end); 653 + buf_len += hop_len - end; 654 + } 655 + new->nexthdr = 0; 656 + new->hdrlen = buf_len / 8 - 1; 657 + 658 + return new; 659 + } 660 + 661 + /** 662 + * calipso_opt_del - Removes the CALIPSO option from an option header 663 + * @hop: the original header 664 + * @new: the new header 665 + * 666 + * Description: 667 + * Creates a new header based on @hop without any CALIPSO option. If @hop 668 + * doesn't contain a CALIPSO option it returns -ENOENT. If @hop contains 669 + * no other non-padding options, it returns zero with @new set to NULL. 670 + * Otherwise it returns zero, creates a new header without the CALIPSO 671 + * option (and removing as much padding as possible) and returns with 672 + * @new set to that header. 673 + * 674 + */ 675 + static int calipso_opt_del(struct ipv6_opt_hdr *hop, 676 + struct ipv6_opt_hdr **new) 677 + { 678 + int ret_val; 679 + unsigned int start, end, delta, pad, hop_len; 680 + 681 + ret_val = calipso_opt_find(hop, &start, &end); 682 + if (ret_val) 683 + return ret_val; 684 + 685 + hop_len = ipv6_optlen(hop); 686 + if (start == sizeof(*hop) && end == hop_len) { 687 + /* There's no other option in the header so return NULL */ 688 + *new = NULL; 689 + return 0; 690 + } 691 + 692 + delta = (end - start) & ~7; 693 + *new = kzalloc(hop_len - delta, GFP_ATOMIC); 694 + if (!*new) 695 + return -ENOMEM; 696 + 697 + memcpy(*new, hop, start); 698 + (*new)->hdrlen -= delta / 8; 699 + pad = (end - start) & 7; 700 + calipso_pad_write((unsigned char *)*new, start, pad); 701 + if (end != hop_len) 702 + memcpy((char *)*new + start + pad, (char *)hop + end, 703 + hop_len - end); 704 + 705 + return 0; 706 + } 707 + 708 + /** 709 + * calipso_opt_getattr - Get the security attributes from a memory block 710 + * @calipso: the CALIPSO option 711 + * @secattr: the security attributes 712 + * 713 + * Description: 714 + * Inspect @calipso and return the security attributes in @secattr. 715 + * Returns zero on success and negative values on failure. 716 + * 717 + */ 718 + static int calipso_opt_getattr(const unsigned char *calipso, 719 + struct netlbl_lsm_secattr *secattr) 720 + { 721 + int ret_val = -ENOMSG; 722 + u32 doi, len = calipso[1], cat_len = calipso[6] * 4; 723 + struct calipso_doi *doi_def; 724 + 725 + if (cat_len + 8 > len) 726 + return -EINVAL; 727 + 728 + doi = get_unaligned_be32(calipso + 2); 729 + rcu_read_lock(); 730 + doi_def = calipso_doi_search(doi); 731 + if (!doi_def) 732 + goto getattr_return; 733 + 734 + secattr->attr.mls.lvl = calipso[7]; 735 + secattr->flags |= NETLBL_SECATTR_MLS_LVL; 736 + 737 + if (cat_len) { 738 + ret_val = calipso_map_cat_ntoh(doi_def, 739 + calipso + 10, 740 + cat_len, 741 + secattr); 742 + if (ret_val != 0) { 743 + netlbl_catmap_free(secattr->attr.mls.cat); 744 + goto getattr_return; 745 + } 746 + 747 + secattr->flags |= NETLBL_SECATTR_MLS_CAT; 748 + } 749 + 750 + secattr->type = NETLBL_NLTYPE_CALIPSO; 751 + 752 + getattr_return: 753 + rcu_read_unlock(); 754 + return ret_val; 755 + } 756 + 757 + /* sock functions. 758 + */ 759 + 760 + /** 761 + * calipso_sock_getattr - Get the security attributes from a sock 762 + * @sk: the sock 763 + * @secattr: the security attributes 764 + * 765 + * Description: 766 + * Query @sk to see if there is a CALIPSO option attached to the sock and if 767 + * there is return the CALIPSO security attributes in @secattr. This function 768 + * requires that @sk be locked, or privately held, but it does not do any 769 + * locking itself. Returns zero on success and negative values on failure. 770 + * 771 + */ 772 + static int calipso_sock_getattr(struct sock *sk, 773 + struct netlbl_lsm_secattr *secattr) 774 + { 775 + struct ipv6_opt_hdr *hop; 776 + int opt_len, len, ret_val = -ENOMSG, offset; 777 + unsigned char *opt; 778 + struct ipv6_txoptions *txopts = txopt_get(inet6_sk(sk)); 779 + 780 + if (!txopts || !txopts->hopopt) 781 + goto done; 782 + 783 + hop = txopts->hopopt; 784 + opt = (unsigned char *)hop; 785 + opt_len = ipv6_optlen(hop); 786 + offset = sizeof(*hop); 787 + while (offset < opt_len) { 788 + len = calipso_tlv_len(hop, offset); 789 + if (len < 0) { 790 + ret_val = len; 791 + goto done; 792 + } 793 + switch (opt[offset]) { 794 + case IPV6_TLV_CALIPSO: 795 + if (len < CALIPSO_HDR_LEN) 796 + ret_val = -EINVAL; 797 + else 798 + ret_val = calipso_opt_getattr(&opt[offset], 799 + secattr); 800 + goto done; 801 + default: 802 + offset += len; 803 + break; 804 + } 805 + } 806 + done: 807 + txopt_put(txopts); 808 + return ret_val; 809 + } 810 + 811 + /** 812 + * calipso_sock_setattr - Add a CALIPSO option to a socket 813 + * @sk: the socket 814 + * @doi_def: the CALIPSO DOI to use 815 + * @secattr: the specific security attributes of the socket 816 + * 817 + * Description: 818 + * Set the CALIPSO option on the given socket using the DOI definition and 819 + * security attributes passed to the function. This function requires 820 + * exclusive access to @sk, which means it either needs to be in the 821 + * process of being created or locked. Returns zero on success and negative 822 + * values on failure. 823 + * 824 + */ 825 + static int calipso_sock_setattr(struct sock *sk, 826 + const struct calipso_doi *doi_def, 827 + const struct netlbl_lsm_secattr *secattr) 828 + { 829 + int ret_val; 830 + struct ipv6_opt_hdr *old, *new; 831 + struct ipv6_txoptions *txopts = txopt_get(inet6_sk(sk)); 832 + 833 + old = NULL; 834 + if (txopts) 835 + old = txopts->hopopt; 836 + 837 + new = calipso_opt_insert(old, doi_def, secattr); 838 + txopt_put(txopts); 839 + if (IS_ERR(new)) 840 + return PTR_ERR(new); 841 + 842 + ret_val = calipso_opt_update(sk, new); 843 + 844 + kfree(new); 845 + return ret_val; 846 + } 847 + 848 + /** 849 + * calipso_sock_delattr - Delete the CALIPSO option from a socket 850 + * @sk: the socket 851 + * 852 + * Description: 853 + * Removes the CALIPSO option from a socket, if present. 854 + * 855 + */ 856 + static void calipso_sock_delattr(struct sock *sk) 857 + { 858 + struct ipv6_opt_hdr *new_hop; 859 + struct ipv6_txoptions *txopts = txopt_get(inet6_sk(sk)); 860 + 861 + if (!txopts || !txopts->hopopt) 862 + goto done; 863 + 864 + if (calipso_opt_del(txopts->hopopt, &new_hop)) 865 + goto done; 866 + 867 + calipso_opt_update(sk, new_hop); 868 + kfree(new_hop); 869 + 870 + done: 871 + txopt_put(txopts); 872 + } 873 + 318 874 static const struct netlbl_calipso_ops ops = { 319 875 .doi_add = calipso_doi_add, 320 876 .doi_free = calipso_doi_free, ··· 896 304 .doi_getdef = calipso_doi_getdef, 897 305 .doi_putdef = calipso_doi_putdef, 898 306 .doi_walk = calipso_doi_walk, 307 + .sock_getattr = calipso_sock_getattr, 308 + .sock_setattr = calipso_sock_setattr, 309 + .sock_delattr = calipso_sock_delattr, 899 310 }; 900 311 901 312 /**
-1
net/ipv6/ipv6_sockglue.c
··· 98 98 return 0; 99 99 } 100 100 101 - static 102 101 struct ipv6_txoptions *ipv6_update_options(struct sock *sk, 103 102 struct ipv6_txoptions *opt) 104 103 {
+1
net/netlabel/Kconfig
··· 5 5 config NETLABEL 6 6 bool "NetLabel subsystem support" 7 7 depends on SECURITY 8 + select CRC_CCITT if IPV6 8 9 default n 9 10 ---help--- 10 11 NetLabel provides support for explicit network packet labeling
+64
net/netlabel/netlabel_calipso.c
··· 514 514 ret_val = ops->doi_walk(skip_cnt, callback, cb_arg); 515 515 return ret_val; 516 516 } 517 + 518 + /** 519 + * calipso_sock_getattr - Get the security attributes from a sock 520 + * @sk: the sock 521 + * @secattr: the security attributes 522 + * 523 + * Description: 524 + * Query @sk to see if there is a CALIPSO option attached to the sock and if 525 + * there is return the CALIPSO security attributes in @secattr. This function 526 + * requires that @sk be locked, or privately held, but it does not do any 527 + * locking itself. Returns zero on success and negative values on failure. 528 + * 529 + */ 530 + int calipso_sock_getattr(struct sock *sk, struct netlbl_lsm_secattr *secattr) 531 + { 532 + int ret_val = -ENOMSG; 533 + const struct netlbl_calipso_ops *ops = netlbl_calipso_ops_get(); 534 + 535 + if (ops) 536 + ret_val = ops->sock_getattr(sk, secattr); 537 + return ret_val; 538 + } 539 + 540 + /** 541 + * calipso_sock_setattr - Add a CALIPSO option to a socket 542 + * @sk: the socket 543 + * @doi_def: the CALIPSO DOI to use 544 + * @secattr: the specific security attributes of the socket 545 + * 546 + * Description: 547 + * Set the CALIPSO option on the given socket using the DOI definition and 548 + * security attributes passed to the function. This function requires 549 + * exclusive access to @sk, which means it either needs to be in the 550 + * process of being created or locked. Returns zero on success and negative 551 + * values on failure. 552 + * 553 + */ 554 + int calipso_sock_setattr(struct sock *sk, 555 + const struct calipso_doi *doi_def, 556 + const struct netlbl_lsm_secattr *secattr) 557 + { 558 + int ret_val = -ENOMSG; 559 + const struct netlbl_calipso_ops *ops = netlbl_calipso_ops_get(); 560 + 561 + if (ops) 562 + ret_val = ops->sock_setattr(sk, doi_def, secattr); 563 + return ret_val; 564 + } 565 + 566 + /** 567 + * calipso_sock_delattr - Delete the CALIPSO option from a socket 568 + * @sk: the socket 569 + * 570 + * Description: 571 + * Removes the CALIPSO option from a socket, if present. 572 + * 573 + */ 574 + void calipso_sock_delattr(struct sock *sk) 575 + { 576 + const struct netlbl_calipso_ops *ops = netlbl_calipso_ops_get(); 577 + 578 + if (ops) 579 + ops->sock_delattr(sk); 580 + }
+5
net/netlabel/netlabel_calipso.h
··· 128 128 int calipso_doi_walk(u32 *skip_cnt, 129 129 int (*callback)(struct calipso_doi *doi_def, void *arg), 130 130 void *cb_arg); 131 + int calipso_sock_getattr(struct sock *sk, struct netlbl_lsm_secattr *secattr); 132 + int calipso_sock_setattr(struct sock *sk, 133 + const struct calipso_doi *doi_def, 134 + const struct netlbl_lsm_secattr *secattr); 135 + void calipso_sock_delattr(struct sock *sk); 131 136 132 137 #endif
+50 -8
net/netlabel/netlabel_kapi.c
··· 37 37 #include <net/ipv6.h> 38 38 #include <net/netlabel.h> 39 39 #include <net/cipso_ipv4.h> 40 + #include <net/calipso.h> 40 41 #include <asm/bug.h> 41 42 #include <linux/atomic.h> 42 43 43 44 #include "netlabel_domainhash.h" 44 45 #include "netlabel_unlabeled.h" 45 46 #include "netlabel_cipso_v4.h" 47 + #include "netlabel_calipso.h" 46 48 #include "netlabel_user.h" 47 49 #include "netlabel_mgmt.h" 48 50 #include "netlabel_addrlist.h" ··· 523 521 524 522 return -ENOENT; 525 523 } 524 + EXPORT_SYMBOL(netlbl_catmap_walk); 526 525 527 526 /** 528 527 * netlbl_catmap_walkrng - Find the end of a string of set bits ··· 659 656 660 657 return 0; 661 658 } 659 + EXPORT_SYMBOL(netlbl_catmap_setbit); 662 660 663 661 /** 664 662 * netlbl_catmap_setrng - Set a range of bits in a LSM secattr catmap ··· 874 870 break; 875 871 #if IS_ENABLED(CONFIG_IPV6) 876 872 case AF_INET6: 877 - /* since we don't support any IPv6 labeling protocols right 878 - * now we can optimize everything away until we do */ 879 - ret_val = 0; 873 + switch (dom_entry->def.type) { 874 + case NETLBL_NLTYPE_ADDRSELECT: 875 + ret_val = -EDESTADDRREQ; 876 + break; 877 + case NETLBL_NLTYPE_CALIPSO: 878 + ret_val = calipso_sock_setattr(sk, 879 + dom_entry->def.calipso, 880 + secattr); 881 + break; 882 + case NETLBL_NLTYPE_UNLABELED: 883 + ret_val = 0; 884 + break; 885 + default: 886 + ret_val = -ENOENT; 887 + } 880 888 break; 881 889 #endif /* IPv6 */ 882 890 default: ··· 915 899 case AF_INET: 916 900 cipso_v4_sock_delattr(sk); 917 901 break; 902 + #if IS_ENABLED(CONFIG_IPV6) 903 + case AF_INET6: 904 + calipso_sock_delattr(sk); 905 + break; 906 + #endif /* IPv6 */ 918 907 } 919 908 } 920 909 ··· 946 925 break; 947 926 #if IS_ENABLED(CONFIG_IPV6) 948 927 case AF_INET6: 949 - ret_val = -ENOMSG; 928 + ret_val = calipso_sock_getattr(sk, secattr); 950 929 break; 951 930 #endif /* IPv6 */ 952 931 default: ··· 974 953 { 975 954 int ret_val; 976 955 struct sockaddr_in *addr4; 956 + #if IS_ENABLED(CONFIG_IPV6) 957 + struct sockaddr_in6 *addr6; 958 + #endif 977 959 struct netlbl_dommap_def *entry; 978 960 979 961 rcu_read_lock(); ··· 997 973 case NETLBL_NLTYPE_UNLABELED: 998 974 /* just delete the protocols we support for right now 999 975 * but we could remove other protocols if needed */ 1000 - cipso_v4_sock_delattr(sk); 976 + netlbl_sock_delattr(sk); 1001 977 ret_val = 0; 1002 978 break; 1003 979 default: ··· 1006 982 break; 1007 983 #if IS_ENABLED(CONFIG_IPV6) 1008 984 case AF_INET6: 1009 - /* since we don't support any IPv6 labeling protocols right 1010 - * now we can optimize everything away until we do */ 1011 - ret_val = 0; 985 + addr6 = (struct sockaddr_in6 *)addr; 986 + entry = netlbl_domhsh_getentry_af6(secattr->domain, 987 + &addr6->sin6_addr); 988 + if (entry == NULL) { 989 + ret_val = -ENOENT; 990 + goto conn_setattr_return; 991 + } 992 + switch (entry->type) { 993 + case NETLBL_NLTYPE_CALIPSO: 994 + ret_val = calipso_sock_setattr(sk, 995 + entry->calipso, secattr); 996 + break; 997 + case NETLBL_NLTYPE_UNLABELED: 998 + /* just delete the protocols we support for right now 999 + * but we could remove other protocols if needed */ 1000 + netlbl_sock_delattr(sk); 1001 + ret_val = 0; 1002 + break; 1003 + default: 1004 + ret_val = -ENOENT; 1005 + } 1012 1006 break; 1013 1007 #endif /* IPv6 */ 1014 1008 default:
+1 -1
security/selinux/netlabel.c
··· 333 333 struct sk_security_struct *sksec = sk->sk_security; 334 334 struct netlbl_lsm_secattr *secattr; 335 335 336 - if (family != PF_INET) 336 + if (family != PF_INET && family != PF_INET6) 337 337 return 0; 338 338 339 339 secattr = selinux_netlbl_sock_genattr(sk);