Print this page
Bayard's initial drop, needs finishing, or at least testing.

Split Close
Expand all
Collapse all
          --- old/usr/src/uts/common/inet/ip/spd.c
          +++ new/usr/src/uts/common/inet/ip/spd.c
↓ open down ↓ 13 lines elided ↑ open up ↑
  14   14   * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
  15   15   * If applicable, add the following below this CDDL HEADER, with the
  16   16   * fields enclosed by brackets "[]" replaced with your own identifying
  17   17   * information: Portions Copyright [yyyy] [name of copyright owner]
  18   18   *
  19   19   * CDDL HEADER END
  20   20   */
  21   21  /*
  22   22   * Copyright 2010 Sun Microsystems, Inc.  All rights reserved.
  23   23   * Use is subject to license terms.
       24 + * Copyright (c) 2012 Nexenta Systems, Inc. All rights reserved.
  24   25   * Copyright (c) 2016 by Delphix. All rights reserved.
       26 + * Copyright (c) 2017, Joyent, Inc.
  25   27   */
  26   28  
  27   29  /*
  28   30   * IPsec Security Policy Database.
  29   31   *
  30   32   * This module maintains the SPD and provides routines used by ip and ip6
  31   33   * to apply IPsec policy to inbound and outbound datagrams.
  32   34   */
  33   35  
  34   36  #include <sys/types.h>
↓ open down ↓ 371 lines elided ↑ open up ↑
 406  408                  ipsec_action_free_table(ipss->ipsec_action_hash[i].hash_head);
 407  409                  ipss->ipsec_action_hash[i].hash_head = NULL;
 408  410                  mutex_destroy(&(ipss->ipsec_action_hash[i].hash_lock));
 409  411          }
 410  412  
 411  413          for (i = 0; i < ipss->ipsec_spd_hashsize; i++) {
 412  414                  ASSERT(ipss->ipsec_sel_hash[i].hash_head == NULL);
 413  415                  mutex_destroy(&(ipss->ipsec_sel_hash[i].hash_lock));
 414  416          }
 415  417  
 416      -        mutex_enter(&ipss->ipsec_alg_lock);
      418 +        rw_enter(&ipss->ipsec_alg_lock, RW_WRITER);
 417  419          for (algtype = 0; algtype < IPSEC_NALGTYPES; algtype ++) {
 418  420                  int nalgs = ipss->ipsec_nalgs[algtype];
 419  421  
 420  422                  for (i = 0; i < nalgs; i++) {
 421  423                          if (ipss->ipsec_alglists[algtype][i] != NULL)
 422  424                                  ipsec_alg_unreg(algtype, i, ns);
 423  425                  }
 424  426          }
 425      -        mutex_exit(&ipss->ipsec_alg_lock);
 426      -        mutex_destroy(&ipss->ipsec_alg_lock);
      427 +        rw_exit(&ipss->ipsec_alg_lock);
      428 +        rw_destroy(&ipss->ipsec_alg_lock);
 427  429  
 428  430          ipsid_gc(ns);
 429  431          ipsid_fini(ns);
 430  432  
 431  433          (void) ipsec_free_tables(ipss);
 432  434          kmem_free(ipss, sizeof (*ipss));
 433  435  }
 434  436  
 435  437  void
 436  438  ipsec_policy_g_destroy(void)
↓ open down ↓ 211 lines elided ↑ open up ↑
 648  650          rw_init(&ipss->ipsec_inactive_policy.iph_lock, NULL, RW_DEFAULT, NULL);
 649  651  
 650  652          for (i = 0; i < IPSEC_ACTION_HASH_SIZE; i++)
 651  653                  mutex_init(&(ipss->ipsec_action_hash[i].hash_lock),
 652  654                      NULL, MUTEX_DEFAULT, NULL);
 653  655  
 654  656          for (i = 0; i < ipss->ipsec_spd_hashsize; i++)
 655  657                  mutex_init(&(ipss->ipsec_sel_hash[i].hash_lock),
 656  658                      NULL, MUTEX_DEFAULT, NULL);
 657  659  
 658      -        mutex_init(&ipss->ipsec_alg_lock, NULL, MUTEX_DEFAULT, NULL);
      660 +        rw_init(&ipss->ipsec_alg_lock, NULL, RW_DEFAULT, NULL);
 659  661          for (i = 0; i < IPSEC_NALGTYPES; i++) {
 660  662                  ipss->ipsec_nalgs[i] = 0;
 661  663          }
 662  664  
 663  665          ip_drop_init(ipss);
 664  666          ip_drop_register(&ipss->ipsec_spd_dropper, "IPsec SPD");
 665  667  
 666  668          /* IP's IPsec code calls the packet dropper */
 667  669          ip_drop_register(&ipss->ipsec_dropper, "IP IPsec processing");
 668  670  
↓ open down ↓ 42 lines elided ↑ open up ↑
 711  713  alg_insert_sortlist(enum ipsec_algtype at, uint8_t algid, netstack_t *ns)
 712  714  {
 713  715          ipsec_stack_t   *ipss = ns->netstack_ipsec;
 714  716          ipsec_alginfo_t *ai = ipss->ipsec_alglists[at][algid];
 715  717          uint8_t holder, swap;
 716  718          uint_t i;
 717  719          uint_t count = ipss->ipsec_nalgs[at];
 718  720          ASSERT(ai != NULL);
 719  721          ASSERT(algid == ai->alg_id);
 720  722  
 721      -        ASSERT(MUTEX_HELD(&ipss->ipsec_alg_lock));
      723 +        ASSERT(RW_WRITE_HELD(&ipss->ipsec_alg_lock));
 722  724  
 723  725          holder = algid;
 724  726  
 725  727          for (i = 0; i < count - 1; i++) {
 726  728                  ipsec_alginfo_t *alt;
 727  729  
 728  730                  alt = ipss->ipsec_alglists[at][ipss->ipsec_sortlist[at][i]];
 729  731                  /*
 730  732                   * If you want to give precedence to newly added algs,
 731  733                   * add the = in the > comparison.
↓ open down ↓ 16 lines elided ↑ open up ↑
 748  750   * This should be considerably easier, even with complex sorting.
 749  751   */
 750  752  static void
 751  753  alg_remove_sortlist(enum ipsec_algtype at, uint8_t algid, netstack_t *ns)
 752  754  {
 753  755          boolean_t copyback = B_FALSE;
 754  756          int i;
 755  757          ipsec_stack_t   *ipss = ns->netstack_ipsec;
 756  758          int newcount = ipss->ipsec_nalgs[at];
 757  759  
 758      -        ASSERT(MUTEX_HELD(&ipss->ipsec_alg_lock));
      760 +        ASSERT(RW_WRITE_HELD(&ipss->ipsec_alg_lock));
 759  761  
 760  762          for (i = 0; i <= newcount; i++) {
 761  763                  if (copyback) {
 762  764                          ipss->ipsec_sortlist[at][i-1] =
 763  765                              ipss->ipsec_sortlist[at][i];
 764  766                  } else if (ipss->ipsec_sortlist[at][i] == algid) {
 765  767                          copyback = B_TRUE;
 766  768                  }
 767  769          }
 768  770  }
 769  771  
 770  772  /*
 771  773   * Add the specified algorithm to the algorithm tables.
 772  774   * Must be called while holding the algorithm table writer lock.
 773  775   */
 774  776  void
 775  777  ipsec_alg_reg(ipsec_algtype_t algtype, ipsec_alginfo_t *alg, netstack_t *ns)
 776  778  {
 777  779          ipsec_stack_t   *ipss = ns->netstack_ipsec;
 778  780  
 779      -        ASSERT(MUTEX_HELD(&ipss->ipsec_alg_lock));
      781 +        ASSERT(RW_WRITE_HELD(&ipss->ipsec_alg_lock));
 780  782  
 781  783          ASSERT(ipss->ipsec_alglists[algtype][alg->alg_id] == NULL);
 782  784          ipsec_alg_fix_min_max(alg, algtype, ns);
 783  785          ipss->ipsec_alglists[algtype][alg->alg_id] = alg;
 784  786  
 785  787          ipss->ipsec_nalgs[algtype]++;
 786  788          alg_insert_sortlist(algtype, alg->alg_id, ns);
 787  789  }
 788  790  
 789  791  /*
 790  792   * Remove the specified algorithm from the algorithm tables.
 791  793   * Must be called while holding the algorithm table writer lock.
 792  794   */
 793  795  void
 794  796  ipsec_alg_unreg(ipsec_algtype_t algtype, uint8_t algid, netstack_t *ns)
 795  797  {
 796  798          ipsec_stack_t   *ipss = ns->netstack_ipsec;
 797  799  
 798      -        ASSERT(MUTEX_HELD(&ipss->ipsec_alg_lock));
      800 +        ASSERT(RW_WRITE_HELD(&ipss->ipsec_alg_lock));
 799  801  
 800  802          ASSERT(ipss->ipsec_alglists[algtype][algid] != NULL);
 801  803          ipsec_alg_free(ipss->ipsec_alglists[algtype][algid]);
 802  804          ipss->ipsec_alglists[algtype][algid] = NULL;
 803  805  
 804  806          ipss->ipsec_nalgs[algtype]--;
 805  807          alg_remove_sortlist(algtype, algid, ns);
 806  808  }
 807  809  
 808  810  /*
↓ open down ↓ 3871 lines elided ↑ open up ↑
4680 4682          ipsec_stack_t   *ipss = ns->netstack_ipsec;
4681 4683  
4682 4684          for (i = 0; i < IPSID_HASHSIZE; i++) {
4683 4685                  bucket = &ipss->ipsec_ipsid_buckets[i];
4684 4686                  ASSERT(bucket->ipsif_head == NULL);
4685 4687                  mutex_destroy(&bucket->ipsif_lock);
4686 4688          }
4687 4689  }
4688 4690  
4689 4691  /*
4690      - * Update the minimum and maximum supported key sizes for the
4691      - * specified algorithm. Must be called while holding the algorithms lock.
     4692 + * Update the minimum and maximum supported key sizes for the specified
     4693 + * algorithm, which is either a member of a netstack alg array or about to be,
     4694 + * and therefore must be called holding ipsec_alg_lock for write.
4692 4695   */
4693 4696  void
4694 4697  ipsec_alg_fix_min_max(ipsec_alginfo_t *alg, ipsec_algtype_t alg_type,
4695 4698      netstack_t *ns)
4696 4699  {
4697 4700          size_t crypto_min = (size_t)-1, crypto_max = 0;
4698 4701          size_t cur_crypto_min, cur_crypto_max;
4699 4702          boolean_t is_valid;
4700 4703          crypto_mechanism_info_t *mech_infos;
4701 4704          uint_t nmech_infos;
4702 4705          int crypto_rc, i;
4703 4706          crypto_mech_usage_t mask;
4704 4707          ipsec_stack_t   *ipss = ns->netstack_ipsec;
4705 4708  
4706      -        ASSERT(MUTEX_HELD(&ipss->ipsec_alg_lock));
     4709 +        ASSERT(RW_WRITE_HELD(&ipss->ipsec_alg_lock));
4707 4710  
4708 4711          /*
4709 4712           * Compute the min, max, and default key sizes (in number of
4710 4713           * increments to the default key size in bits) as defined
4711 4714           * by the algorithm mappings. This range of key sizes is used
4712 4715           * for policy related operations. The effective key sizes
4713 4716           * supported by the framework could be more limited than
4714 4717           * those defined for an algorithm.
4715 4718           */
4716 4719          alg->alg_default_bits = alg->alg_key_sizes[0];
↓ open down ↓ 332 lines elided ↑ open up ↑
5049 5052  
5050 5053          mechs = crypto_get_mech_list(&mech_count, KM_SLEEP);
5051 5054          if (mechs == NULL)
5052 5055                  return;
5053 5056  
5054 5057          /*
5055 5058           * Walk the list of currently defined IPsec algorithm. Update
5056 5059           * the algorithm valid flag and trigger an update of the
5057 5060           * SAs that depend on that algorithm.
5058 5061           */
5059      -        mutex_enter(&ipss->ipsec_alg_lock);
     5062 +        rw_enter(&ipss->ipsec_alg_lock, RW_WRITER);
5060 5063          for (algtype = 0; algtype < IPSEC_NALGTYPES; algtype++) {
5061 5064                  for (algidx = 0; algidx < ipss->ipsec_nalgs[algtype];
5062 5065                      algidx++) {
5063 5066  
5064 5067                          algid = ipss->ipsec_sortlist[algtype][algidx];
5065 5068                          alg = ipss->ipsec_alglists[algtype][algid];
5066 5069                          ASSERT(alg != NULL);
5067 5070  
5068 5071                          /*
5069 5072                           * Skip the algorithms which do not map to the
↓ open down ↓ 42 lines elided ↑ open up ↑
5112 5115                           * Update the affected SAs if a software provider is
5113 5116                           * being added or removed.
5114 5117                           */
5115 5118                          if (prov_change->ec_provider_type ==
5116 5119                              CRYPTO_SW_PROVIDER)
5117 5120                                  sadb_alg_update(algtype, alg->alg_id,
5118 5121                                      prov_change->ec_change ==
5119 5122                                      CRYPTO_MECH_ADDED, ns);
5120 5123                  }
5121 5124          }
5122      -        mutex_exit(&ipss->ipsec_alg_lock);
     5125 +        rw_exit(&ipss->ipsec_alg_lock);
5123 5126          crypto_free_mech_list(mechs, mech_count);
5124 5127  
5125 5128          if (alg_changed) {
5126 5129                  /*
5127 5130                   * An algorithm has changed, i.e. it became valid or
5128 5131                   * invalid, or its support key sizes have changed.
5129 5132                   * Notify ipsecah and ipsecesp of this change so
5130 5133                   * that they can send a SADB_REGISTER to their consumers.
5131 5134                   */
5132 5135                  ipsecah_algs_changed(ns);
↓ open down ↓ 1779 lines elided ↑ open up ↑
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX