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/ipsecah.c
          +++ new/usr/src/uts/common/inet/ip/ipsecah.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   */
  25   26  
  26   27  #include <sys/types.h>
  27   28  #include <sys/stream.h>
  28   29  #include <sys/stropts.h>
  29   30  #include <sys/errno.h>
  30   31  #include <sys/strlog.h>
  31   32  #include <sys/tihdr.h>
  32   33  #include <sys/socket.h>
  33   34  #include <sys/ddi.h>
↓ open down ↓ 54 lines elided ↑ open up ↑
  88   89          { 1,    1800,                   90,     "ipsecah_larval_timeout"},
  89   90          /* Default lifetime values for ACQUIRE messages. */
  90   91          { 0,    0xffffffffU,            0,      "ipsecah_default_soft_bytes"},
  91   92          { 0,    0xffffffffU,            0,      "ipsecah_default_hard_bytes"},
  92   93          { 0,    0xffffffffU,            24000,  "ipsecah_default_soft_addtime"},
  93   94          { 0,    0xffffffffU,            28800,  "ipsecah_default_hard_addtime"},
  94   95          { 0,    0xffffffffU,            0,      "ipsecah_default_soft_usetime"},
  95   96          { 0,    0xffffffffU,            0,      "ipsecah_default_hard_usetime"},
  96   97          { 0,    1,                      0,      "ipsecah_log_unknown_spi"},
  97   98  };
  98      -#define ipsecah_debug                   ipsecah_params[0].ipsecah_param_value
  99      -#define ipsecah_age_interval            ipsecah_params[1].ipsecah_param_value
 100      -#define ipsecah_age_int_max             ipsecah_params[1].ipsecah_param_max
 101      -#define ipsecah_reap_delay              ipsecah_params[2].ipsecah_param_value
 102      -#define ipsecah_replay_size             ipsecah_params[3].ipsecah_param_value
 103      -#define ipsecah_acquire_timeout         ipsecah_params[4].ipsecah_param_value
 104      -#define ipsecah_larval_timeout          ipsecah_params[5].ipsecah_param_value
 105      -#define ipsecah_default_soft_bytes      ipsecah_params[6].ipsecah_param_value
 106      -#define ipsecah_default_hard_bytes      ipsecah_params[7].ipsecah_param_value
 107      -#define ipsecah_default_soft_addtime    ipsecah_params[8].ipsecah_param_value
 108      -#define ipsecah_default_hard_addtime    ipsecah_params[9].ipsecah_param_value
 109      -#define ipsecah_default_soft_usetime    ipsecah_params[10].ipsecah_param_value
 110      -#define ipsecah_default_hard_usetime    ipsecah_params[11].ipsecah_param_value
 111      -#define ipsecah_log_unknown_spi         ipsecah_params[12].ipsecah_param_value
 112   99  
 113  100  #define ah0dbg(a)       printf a
 114  101  /* NOTE:  != 0 instead of > 0 so lint doesn't complain. */
 115  102  #define ah1dbg(ahstack, a)      if (ahstack->ipsecah_debug != 0) printf a
 116  103  #define ah2dbg(ahstack, a)      if (ahstack->ipsecah_debug > 1) printf a
 117  104  #define ah3dbg(ahstack, a)      if (ahstack->ipsecah_debug > 2) printf a
 118  105  
 119  106  /*
 120  107   * XXX This is broken. Padding should be determined dynamically
 121  108   * depending on the ICV size and IP version number so that the
↓ open down ↓ 19 lines elided ↑ open up ↑
 141  128      boolean_t, ipsecah_stack_t *);
 142  129  static void ah_getspi(mblk_t *, keysock_in_t *, ipsecah_stack_t *);
 143  130  static void ah_inbound_restart(mblk_t *, ip_recv_attr_t *);
 144  131  
 145  132  static mblk_t *ah_outbound(mblk_t *, ip_xmit_attr_t *);
 146  133  static void ah_outbound_finish(mblk_t *, ip_xmit_attr_t *);
 147  134  
 148  135  static int ipsecah_open(queue_t *, dev_t *, int, int, cred_t *);
 149  136  static int ipsecah_close(queue_t *);
 150  137  static void ipsecah_wput(queue_t *, mblk_t *);
 151      -static void ah_send_acquire(ipsacq_t *, mblk_t *, netstack_t *);
 152  138  static boolean_t ah_register_out(uint32_t, uint32_t, uint_t, ipsecah_stack_t *,
 153  139      cred_t *);
 154  140  static void     *ipsecah_stack_init(netstackid_t stackid, netstack_t *ns);
 155  141  static void     ipsecah_stack_fini(netstackid_t stackid, void *arg);
 156  142  
 157  143  /* Setable in /etc/system */
 158  144  uint32_t ah_hash_size = IPSEC_DEFAULT_HASH_SIZE;
 159  145  
 160  146  static taskq_t *ah_taskq;
 161  147  
↓ open down ↓ 78 lines elided ↑ open up ↑
 240  226          ns = netstack_find_by_stackid(stackid);
 241  227          if (ns == NULL)
 242  228                  return (-1);
 243  229          ipss = ns->netstack_ipsec;
 244  230          if (ipss == NULL) {
 245  231                  netstack_rele(ns);
 246  232                  return (-1);
 247  233          }
 248  234          ekp = (ah_kstats_t *)kp->ks_data;
 249  235  
 250      -        mutex_enter(&ipss->ipsec_alg_lock);
      236 +        rw_enter(&ipss->ipsec_alg_lock, RW_READER);
 251  237          ekp->ah_stat_num_aalgs.value.ui64 = ipss->ipsec_nalgs[IPSEC_ALG_AUTH];
 252      -        mutex_exit(&ipss->ipsec_alg_lock);
      238 +        rw_exit(&ipss->ipsec_alg_lock);
 253  239  
 254  240          netstack_rele(ns);
 255  241          return (0);
 256  242  }
 257  243  
 258  244  /*
 259  245   * Don't have to lock ipsec_age_interval, as only one thread will access it at
 260  246   * a time, because I control the one function that does a qtimeout() on
 261  247   * ah_pfkey_q.
 262  248   */
↓ open down ↓ 149 lines elided ↑ open up ↑
 412  398          ahp = (ipsecahparam_t *)kmem_alloc(sizeof (lcl_param_arr), KM_SLEEP);
 413  399          ahstack->ipsecah_params = ahp;
 414  400          bcopy(lcl_param_arr, ahp, sizeof (lcl_param_arr));
 415  401  
 416  402          (void) ipsecah_param_register(&ahstack->ipsecah_g_nd, ahp,
 417  403              A_CNT(lcl_param_arr));
 418  404  
 419  405          (void) ah_kstat_init(ahstack, stackid);
 420  406  
 421  407          ahstack->ah_sadb.s_acquire_timeout = &ahstack->ipsecah_acquire_timeout;
 422      -        ahstack->ah_sadb.s_acqfn = ah_send_acquire;
 423  408          sadbp_init("AH", &ahstack->ah_sadb, SADB_SATYPE_AH, ah_hash_size,
 424  409              ahstack->ipsecah_netstack);
 425  410  
 426  411          mutex_init(&ahstack->ipsecah_param_lock, NULL, MUTEX_DEFAULT, 0);
 427  412  
 428  413          ip_drop_register(&ahstack->ah_dropper, "IPsec AH");
 429  414          return (ahstack);
 430  415  }
 431  416  
 432  417  /*
↓ open down ↓ 10 lines elided ↑ open up ↑
 443  428   * Destroy things for AH for one stack... Never called?
 444  429   */
 445  430  static void
 446  431  ipsecah_stack_fini(netstackid_t stackid, void *arg)
 447  432  {
 448  433          ipsecah_stack_t *ahstack = (ipsecah_stack_t *)arg;
 449  434  
 450  435          if (ahstack->ah_pfkey_q != NULL) {
 451  436                  (void) quntimeout(ahstack->ah_pfkey_q, ahstack->ah_event);
 452  437          }
 453      -        ahstack->ah_sadb.s_acqfn = NULL;
 454  438          ahstack->ah_sadb.s_acquire_timeout = NULL;
 455  439          sadbp_destroy(&ahstack->ah_sadb, ahstack->ipsecah_netstack);
 456  440          ip_drop_unregister(&ahstack->ah_dropper);
 457  441          mutex_destroy(&ahstack->ipsecah_param_lock);
 458  442          nd_free(&ahstack->ipsecah_g_nd);
 459  443  
 460  444          kmem_free(ahstack->ipsecah_params, sizeof (lcl_param_arr));
 461  445          ahstack->ipsecah_params = NULL;
 462  446          kstat_delete_netstack(ahstack->ah_ksp, stackid);
 463  447          ahstack->ah_ksp = NULL;
↓ open down ↓ 102 lines elided ↑ open up ↑
 566  550                          allocsize += sens_len;
 567  551                  }
 568  552          }
 569  553  
 570  554          /*
 571  555           * Allocate the PF_KEY message that follows KEYSOCK_OUT.
 572  556           * The alg reader lock needs to be held while allocating
 573  557           * the variable part (i.e. the algorithms) of the message.
 574  558           */
 575  559  
 576      -        mutex_enter(&ipss->ipsec_alg_lock);
      560 +        rw_enter(&ipss->ipsec_alg_lock, RW_READER);
 577  561  
 578  562          /*
 579  563           * Return only valid algorithms, so the number of algorithms
 580  564           * to send up may be less than the number of algorithm entries
 581  565           * in the table.
 582  566           */
 583  567          authalgs = ipss->ipsec_alglists[IPSEC_ALG_AUTH];
 584  568          for (num_aalgs = 0, i = 0; i < IPSEC_MAX_ALGS; i++)
 585  569                  if (authalgs[i] != NULL && ALG_VALID(authalgs[i]))
 586  570                          num_aalgs++;
↓ open down ↓ 1 lines elided ↑ open up ↑
 588  572          /*
 589  573           * Fill SADB_REGISTER message's algorithm descriptors.  Hold
 590  574           * down the lock while filling it.
 591  575           */
 592  576          if (num_aalgs != 0) {
 593  577                  allocsize += (num_aalgs * sizeof (*saalg));
 594  578                  allocsize += sizeof (*sasupp);
 595  579          }
 596  580          mp->b_cont = allocb(allocsize, BPRI_HI);
 597  581          if (mp->b_cont == NULL) {
 598      -                mutex_exit(&ipss->ipsec_alg_lock);
      582 +                rw_exit(&ipss->ipsec_alg_lock);
 599  583                  freemsg(mp);
 600  584                  return (B_FALSE);
 601  585          }
 602  586  
 603  587          mp->b_cont->b_wptr += allocsize;
 604  588          nextext = (sadb_ext_t *)(mp->b_cont->b_rptr + sizeof (*samsg));
 605  589  
 606  590          if (num_aalgs != 0) {
 607  591  
 608  592                  saalg = (sadb_alg_t *)(((uint8_t *)nextext) + sizeof (*sasupp));
↓ open down ↓ 26 lines elided ↑ open up ↑
 635  619                   * algorithms.
 636  620                   */
 637  621                  for (; i < IPSEC_MAX_ALGS; i++)
 638  622                          if (authalgs[i] != NULL && ALG_VALID(authalgs[i]))
 639  623                                  cmn_err(CE_PANIC,
 640  624                                      "ah_register_out()!  Missed #%d.\n", i);
 641  625  #endif /* DEBUG */
 642  626                  nextext = (sadb_ext_t *)saalg;
 643  627          }
 644  628  
 645      -        mutex_exit(&ipss->ipsec_alg_lock);
      629 +        rw_exit(&ipss->ipsec_alg_lock);
 646  630  
 647  631          if (sens_tsl != NULL) {
 648  632                  sens = (sadb_sens_t *)nextext;
 649  633                  sadb_sens_from_label(sens, SADB_EXT_SENSITIVITY,
 650  634                      sens_tsl, sens_len);
 651  635  
 652  636                  nextext = (sadb_ext_t *)(((uint8_t *)sens) + sens_len);
 653  637          }
 654  638  
 655  639          /* Now fill the restof the SADB_REGISTER message. */
↓ open down ↓ 460 lines elided ↑ open up ↑
1116 1100                  if (!is_system_labeled())
1117 1101                          return (EOPNOTSUPP);
1118 1102          }
1119 1103          /*
1120 1104           * XXX Policy : I'm not checking identities at this time, but
1121 1105           * if I did, I'd do them here, before I sent the weak key
1122 1106           * check up to the algorithm.
1123 1107           */
1124 1108  
1125 1109          /* verify that there is a mapping for the specified algorithm */
1126      -        mutex_enter(&ipss->ipsec_alg_lock);
     1110 +        rw_enter(&ipss->ipsec_alg_lock, RW_READER);
1127 1111          aalg = ipss->ipsec_alglists[IPSEC_ALG_AUTH][assoc->sadb_sa_auth];
1128 1112          if (aalg == NULL || !ALG_VALID(aalg)) {
1129      -                mutex_exit(&ipss->ipsec_alg_lock);
     1113 +                rw_exit(&ipss->ipsec_alg_lock);
1130 1114                  ah1dbg(ahstack, ("Couldn't find auth alg #%d.\n",
1131 1115                      assoc->sadb_sa_auth));
1132 1116                  *diagnostic = SADB_X_DIAGNOSTIC_BAD_AALG;
1133 1117                  return (EINVAL);
1134 1118          }
1135 1119          ASSERT(aalg->alg_mech_type != CRYPTO_MECHANISM_INVALID);
1136 1120  
1137 1121          /* sanity check key sizes */
1138 1122          if (!ipsec_valid_key_size(key->sadb_key_bits, aalg)) {
1139      -                mutex_exit(&ipss->ipsec_alg_lock);
     1123 +                rw_exit(&ipss->ipsec_alg_lock);
1140 1124                  *diagnostic = SADB_X_DIAGNOSTIC_BAD_AKEYBITS;
1141 1125                  return (EINVAL);
1142 1126          }
1143 1127  
1144 1128          /* check key and fix parity if needed */
1145 1129          if (ipsec_check_key(aalg->alg_mech_type, key, B_TRUE,
1146 1130              diagnostic) != 0) {
1147      -                mutex_exit(&ipss->ipsec_alg_lock);
     1131 +                rw_exit(&ipss->ipsec_alg_lock);
1148 1132                  return (EINVAL);
1149 1133          }
1150 1134  
1151      -        mutex_exit(&ipss->ipsec_alg_lock);
     1135 +        rw_exit(&ipss->ipsec_alg_lock);
1152 1136  
1153 1137          return (ah_add_sa_finish(mp, (sadb_msg_t *)mp->b_cont->b_rptr, ksi,
1154 1138              diagnostic, ahstack));
1155 1139  }
1156 1140  
1157 1141  /* Refactor me */
1158 1142  /*
1159 1143   * Update a security association.  Updates come in two varieties.  The first
1160 1144   * is an update of lifetimes on a non-larval SA.  The second is an update of
1161 1145   * a larval SA, which ends up looking a lot more like an add.
↓ open down ↓ 566 lines elided ↑ open up ↑
1728 1712           */
1729 1713          if (inbound) {
1730 1714                  IPSA_REFRELE(outassoc);
1731 1715          } else {
1732 1716                  IPSA_REFRELE(inassoc);
1733 1717          }
1734 1718  
1735 1719          return (inrc && outrc);
1736 1720  }
1737 1721  
1738      -/*
1739      - * Perform the really difficult work of inserting the proposed situation.
1740      - * Called while holding the algorithm lock.
1741      - */
1742      -static void
1743      -ah_insert_prop(sadb_prop_t *prop, ipsacq_t *acqrec, uint_t combs,
1744      -    netstack_t *ns)
1745      -{
1746      -        sadb_comb_t *comb = (sadb_comb_t *)(prop + 1);
1747      -        ipsec_action_t *ap;
1748      -        ipsec_prot_t *prot;
1749      -        ipsecah_stack_t *ahstack = ns->netstack_ipsecah;
1750      -        ipsec_stack_t   *ipss = ns->netstack_ipsec;
1751      -
1752      -        ASSERT(MUTEX_HELD(&ipss->ipsec_alg_lock));
1753      -
1754      -        prop->sadb_prop_exttype = SADB_EXT_PROPOSAL;
1755      -        prop->sadb_prop_len = SADB_8TO64(sizeof (sadb_prop_t));
1756      -        *(uint32_t *)(&prop->sadb_prop_replay) = 0;     /* Quick zero-out! */
1757      -
1758      -        prop->sadb_prop_replay = ahstack->ipsecah_replay_size;
1759      -
1760      -        /*
1761      -         * Based upon algorithm properties, and what-not, prioritize a
1762      -         * proposal, based on the ordering of the AH algorithms in the
1763      -         * alternatives in the policy rule or socket that was placed
1764      -         * in the acquire record.
1765      -         */
1766      -
1767      -        for (ap = acqrec->ipsacq_act; ap != NULL;
1768      -            ap = ap->ipa_next) {
1769      -                ipsec_alginfo_t *aalg;
1770      -
1771      -                if ((ap->ipa_act.ipa_type != IPSEC_POLICY_APPLY) ||
1772      -                    (!ap->ipa_act.ipa_apply.ipp_use_ah))
1773      -                        continue;
1774      -
1775      -                prot = &ap->ipa_act.ipa_apply;
1776      -
1777      -                ASSERT(prot->ipp_auth_alg > 0);
1778      -
1779      -                aalg = ipss->ipsec_alglists[IPSEC_ALG_AUTH]
1780      -                    [prot->ipp_auth_alg];
1781      -                if (aalg == NULL || !ALG_VALID(aalg))
1782      -                        continue;
1783      -
1784      -                /* XXX check aalg for duplicates??.. */
1785      -
1786      -                comb->sadb_comb_flags = 0;
1787      -                comb->sadb_comb_reserved = 0;
1788      -                comb->sadb_comb_encrypt = 0;
1789      -                comb->sadb_comb_encrypt_minbits = 0;
1790      -                comb->sadb_comb_encrypt_maxbits = 0;
1791      -
1792      -                comb->sadb_comb_auth = aalg->alg_id;
1793      -                comb->sadb_comb_auth_minbits =
1794      -                    MAX(prot->ipp_ah_minbits, aalg->alg_ef_minbits);
1795      -                comb->sadb_comb_auth_maxbits =
1796      -                    MIN(prot->ipp_ah_maxbits, aalg->alg_ef_maxbits);
1797      -
1798      -                /*
1799      -                 * The following may be based on algorithm
1800      -                 * properties, but in the meantime, we just pick
1801      -                 * some good, sensible numbers.  Key mgmt. can
1802      -                 * (and perhaps should) be the place to finalize
1803      -                 * such decisions.
1804      -                 */
1805      -
1806      -                /*
1807      -                 * No limits on allocations, since we really don't
1808      -                 * support that concept currently.
1809      -                 */
1810      -                comb->sadb_comb_soft_allocations = 0;
1811      -                comb->sadb_comb_hard_allocations = 0;
1812      -
1813      -                /*
1814      -                 * These may want to come from policy rule..
1815      -                 */
1816      -                comb->sadb_comb_soft_bytes =
1817      -                    ahstack->ipsecah_default_soft_bytes;
1818      -                comb->sadb_comb_hard_bytes =
1819      -                    ahstack->ipsecah_default_hard_bytes;
1820      -                comb->sadb_comb_soft_addtime =
1821      -                    ahstack->ipsecah_default_soft_addtime;
1822      -                comb->sadb_comb_hard_addtime =
1823      -                    ahstack->ipsecah_default_hard_addtime;
1824      -                comb->sadb_comb_soft_usetime =
1825      -                    ahstack->ipsecah_default_soft_usetime;
1826      -                comb->sadb_comb_hard_usetime =
1827      -                    ahstack->ipsecah_default_hard_usetime;
1828      -
1829      -                prop->sadb_prop_len += SADB_8TO64(sizeof (*comb));
1830      -                if (--combs == 0)
1831      -                        return; /* out of space.. */
1832      -                comb++;
1833      -        }
1834      -}
1835      -
1836      -/*
1837      - * Prepare and actually send the SADB_ACQUIRE message to PF_KEY.
1838      - */
1839      -static void
1840      -ah_send_acquire(ipsacq_t *acqrec, mblk_t *extended, netstack_t *ns)
1841      -{
1842      -        uint_t combs;
1843      -        sadb_msg_t *samsg;
1844      -        sadb_prop_t *prop;
1845      -        mblk_t *pfkeymp, *msgmp;
1846      -        ipsecah_stack_t *ahstack = ns->netstack_ipsecah;
1847      -        ipsec_stack_t   *ipss = ns->netstack_ipsec;
1848      -
1849      -        AH_BUMP_STAT(ahstack, acquire_requests);
1850      -
1851      -        if (ahstack->ah_pfkey_q == NULL) {
1852      -                mutex_exit(&acqrec->ipsacq_lock);
1853      -                return;
1854      -        }
1855      -
1856      -        /* Set up ACQUIRE. */
1857      -        pfkeymp = sadb_setup_acquire(acqrec, SADB_SATYPE_AH,
1858      -            ns->netstack_ipsec);
1859      -        if (pfkeymp == NULL) {
1860      -                ah0dbg(("sadb_setup_acquire failed.\n"));
1861      -                mutex_exit(&acqrec->ipsacq_lock);
1862      -                return;
1863      -        }
1864      -        ASSERT(MUTEX_HELD(&ipss->ipsec_alg_lock));
1865      -        combs = ipss->ipsec_nalgs[IPSEC_ALG_AUTH];
1866      -        msgmp = pfkeymp->b_cont;
1867      -        samsg = (sadb_msg_t *)(msgmp->b_rptr);
1868      -
1869      -        /* Insert proposal here. */
1870      -
1871      -        prop = (sadb_prop_t *)(((uint64_t *)samsg) + samsg->sadb_msg_len);
1872      -        ah_insert_prop(prop, acqrec, combs, ns);
1873      -        samsg->sadb_msg_len += prop->sadb_prop_len;
1874      -        msgmp->b_wptr += SADB_64TO8(samsg->sadb_msg_len);
1875      -
1876      -        mutex_exit(&ipss->ipsec_alg_lock);
1877      -
1878      -        /*
1879      -         * Must mutex_exit() before sending PF_KEY message up, in
1880      -         * order to avoid recursive mutex_enter() if there are no registered
1881      -         * listeners.
1882      -         *
1883      -         * Once I've sent the message, I'm cool anyway.
1884      -         */
1885      -        mutex_exit(&acqrec->ipsacq_lock);
1886      -        if (extended != NULL) {
1887      -                putnext(ahstack->ah_pfkey_q, extended);
1888      -        }
1889      -        putnext(ahstack->ah_pfkey_q, pfkeymp);
1890      -}
1891      -
1892 1722  /* Refactor me */
1893 1723  /*
1894 1724   * Handle the SADB_GETSPI message.  Create a larval SA.
1895 1725   */
1896 1726  static void
1897 1727  ah_getspi(mblk_t *mp, keysock_in_t *ksi, ipsecah_stack_t *ahstack)
1898 1728  {
1899 1729          ipsa_t *newbie, *target;
1900 1730          isaf_t *outbound, *inbound;
1901 1731          int rc, diagnostic;
↓ open down ↓ 2111 lines elided ↑ open up ↑
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX