Print this page
8381 Convert ipsec_alg_lock from mutex to rwlock

Split Close
Expand all
Collapse all
          --- old/usr/src/uts/common/inet/ip/sadb.c
          +++ new/usr/src/uts/common/inet/ip/sadb.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/strsubr.h>
  30   31  #include <sys/errno.h>
  31   32  #include <sys/ddi.h>
  32   33  #include <sys/debug.h>
  33   34  #include <sys/cmn_err.h>
↓ open down ↓ 3157 lines elided ↑ open up ↑
3191 3192                  bzero(akey + 1, newbie->ipsa_authkeylen);
3192 3193  
3193 3194                  /*
3194 3195                   * Pre-initialize the kernel crypto framework key
3195 3196                   * structure.
3196 3197                   */
3197 3198                  newbie->ipsa_kcfauthkey.ck_format = CRYPTO_KEY_RAW;
3198 3199                  newbie->ipsa_kcfauthkey.ck_length = newbie->ipsa_authkeybits;
3199 3200                  newbie->ipsa_kcfauthkey.ck_data = newbie->ipsa_authkey;
3200 3201  
3201      -                mutex_enter(&ipss->ipsec_alg_lock);
     3202 +                rw_enter(&ipss->ipsec_alg_lock, RW_READER);
3202 3203                  alg = ipss->ipsec_alglists[IPSEC_ALG_AUTH]
3203 3204                      [newbie->ipsa_auth_alg];
3204 3205                  if (alg != NULL && ALG_VALID(alg)) {
3205 3206                          newbie->ipsa_amech.cm_type = alg->alg_mech_type;
3206 3207                          newbie->ipsa_amech.cm_param =
3207 3208                              (char *)&newbie->ipsa_mac_len;
3208 3209                          newbie->ipsa_amech.cm_param_len = sizeof (size_t);
3209 3210                          newbie->ipsa_mac_len = (size_t)alg->alg_datalen;
3210 3211                  } else {
3211 3212                          newbie->ipsa_amech.cm_type = CRYPTO_MECHANISM_INVALID;
3212 3213                  }
3213 3214                  error = ipsec_create_ctx_tmpl(newbie, IPSEC_ALG_AUTH);
3214      -                mutex_exit(&ipss->ipsec_alg_lock);
     3215 +                rw_exit(&ipss->ipsec_alg_lock);
3215 3216                  if (error != 0) {
3216 3217                          mutex_exit(&newbie->ipsa_lock);
3217 3218                          /*
3218 3219                           * An error here indicates that alg is the wrong type
3219 3220                           * (IE: not authentication) or its not in the alg tables
3220 3221                           * created by ipsecalgs(1m), or Kcf does not like the
3221 3222                           * parameters passed in with this algorithm, which is
3222 3223                           * probably a coding error!
3223 3224                           */
3224 3225                          *diagnostic = SADB_X_DIAGNOSTIC_BAD_CTX;
3225 3226  
3226 3227                          goto error;
3227 3228                  }
3228 3229          }
3229 3230  
3230 3231          if (ekey != NULL) {
3231      -                mutex_enter(&ipss->ipsec_alg_lock);
     3232 +                rw_enter(&ipss->ipsec_alg_lock, RW_READER);
3232 3233                  async = async || (ipss->ipsec_algs_exec_mode[IPSEC_ALG_ENCR] ==
3233 3234                      IPSEC_ALGS_EXEC_ASYNC);
3234 3235                  alg = ipss->ipsec_alglists[IPSEC_ALG_ENCR]
3235 3236                      [newbie->ipsa_encr_alg];
3236 3237  
3237 3238                  if (alg != NULL && ALG_VALID(alg)) {
3238 3239                          newbie->ipsa_emech.cm_type = alg->alg_mech_type;
3239 3240                          newbie->ipsa_datalen = alg->alg_datalen;
3240 3241                          if (alg->alg_flags & ALG_FLAG_COUNTERMODE)
3241 3242                                  newbie->ipsa_flags |= IPSA_F_COUNTERMODE;
↓ open down ↓ 12 lines elided ↑ open up ↑
3254 3255                          newbie->ipsa_saltlen = alg->alg_saltlen;
3255 3256                          newbie->ipsa_saltbits = SADB_8TO1(newbie->ipsa_saltlen);
3256 3257                          newbie->ipsa_iv_len = alg->alg_ivlen;
3257 3258                          newbie->ipsa_nonce_len = newbie->ipsa_saltlen +
3258 3259                              newbie->ipsa_iv_len;
3259 3260                          newbie->ipsa_emech.cm_param = NULL;
3260 3261                          newbie->ipsa_emech.cm_param_len = 0;
3261 3262                  } else {
3262 3263                          newbie->ipsa_emech.cm_type = CRYPTO_MECHANISM_INVALID;
3263 3264                  }
3264      -                mutex_exit(&ipss->ipsec_alg_lock);
     3265 +                rw_exit(&ipss->ipsec_alg_lock);
3265 3266  
3266 3267                  /*
3267 3268                   * The byte stream following the sadb_key_t is made up of:
3268 3269                   * key bytes, [salt bytes], [IV initial value]
3269 3270                   * All of these have variable length. The IV is typically
3270 3271                   * randomly generated by this function and not passed in.
3271 3272                   * By supporting the injection of a known IV, the whole
3272 3273                   * IPsec subsystem and the underlying crypto subsystem
3273 3274                   * can be tested with known test vectors.
3274 3275                   *
↓ open down ↓ 91 lines elided ↑ open up ↑
3366 3367                  bzero((ekey + 1), SADB_1TO8(ekey->sadb_key_bits));
3367 3368  
3368 3369                  /*
3369 3370                   * Pre-initialize the kernel crypto framework key
3370 3371                   * structure.
3371 3372                   */
3372 3373                  newbie->ipsa_kcfencrkey.ck_format = CRYPTO_KEY_RAW;
3373 3374                  newbie->ipsa_kcfencrkey.ck_length = newbie->ipsa_encrkeybits;
3374 3375                  newbie->ipsa_kcfencrkey.ck_data = newbie->ipsa_encrkey;
3375 3376  
3376      -                mutex_enter(&ipss->ipsec_alg_lock);
     3377 +                rw_enter(&ipss->ipsec_alg_lock, RW_READER);
3377 3378                  error = ipsec_create_ctx_tmpl(newbie, IPSEC_ALG_ENCR);
3378      -                mutex_exit(&ipss->ipsec_alg_lock);
     3379 +                rw_exit(&ipss->ipsec_alg_lock);
3379 3380                  if (error != 0) {
3380 3381                          mutex_exit(&newbie->ipsa_lock);
3381 3382                          /* See above for error explanation. */
3382 3383                          *diagnostic = SADB_X_DIAGNOSTIC_BAD_CTX;
3383 3384                          goto error;
3384 3385                  }
3385 3386          }
3386 3387  
3387 3388          if (async)
3388 3389                  newbie->ipsa_flags |= IPSA_F_ASYNC;
↓ open down ↓ 1885 lines elided ↑ open up ↑
5274 5275          if (cur >= limit)
5275 5276                  return (NULL);
5276 5277  
5277 5278          ecomb->sadb_x_ecomb_numalgs++;
5278 5279  
5279 5280          /*
5280 5281           * Normalize vs. crypto framework's limits.  This way, you can specify
5281 5282           * a stronger policy, and when the framework loads a stronger version,
5282 5283           * you can just keep plowing w/o rewhacking your SPD.
5283 5284           */
5284      -        mutex_enter(&ipss->ipsec_alg_lock);
     5285 +        rw_enter(&ipss->ipsec_alg_lock, RW_READER);
5285 5286          algp = ipss->ipsec_alglists[(algtype == SADB_X_ALGTYPE_AUTH) ?
5286 5287              IPSEC_ALG_AUTH : IPSEC_ALG_ENCR][alg];
5287 5288          if (algp == NULL) {
5288      -                mutex_exit(&ipss->ipsec_alg_lock);
     5289 +                rw_exit(&ipss->ipsec_alg_lock);
5289 5290                  return (NULL);  /* Algorithm doesn't exist.  Fail gracefully. */
5290 5291          }
5291 5292          if (minbits < algp->alg_ef_minbits)
5292 5293                  minbits = algp->alg_ef_minbits;
5293 5294          if (maxbits > algp->alg_ef_maxbits)
5294 5295                  maxbits = algp->alg_ef_maxbits;
5295      -        mutex_exit(&ipss->ipsec_alg_lock);
     5296 +        rw_exit(&ipss->ipsec_alg_lock);
5296 5297  
5297 5298          algdesc->sadb_x_algdesc_reserved = SADB_8TO1(algp->alg_saltlen);
5298 5299          algdesc->sadb_x_algdesc_satype = satype;
5299 5300          algdesc->sadb_x_algdesc_algtype = algtype;
5300 5301          algdesc->sadb_x_algdesc_alg = alg;
5301 5302          algdesc->sadb_x_algdesc_minbits = minbits;
5302 5303          algdesc->sadb_x_algdesc_maxbits = maxbits;
5303 5304  
5304 5305          return (cur);
5305 5306  }
↓ open down ↓ 461 lines elided ↑ open up ↑
5767 5768  
5768 5769          /*
5769 5770           * First, allocate a basic ACQUIRE message
5770 5771           */
5771 5772          allocsize = sizeof (sadb_msg_t) + sizeof (sadb_address_t) +
5772 5773              sizeof (sadb_address_t) + sizeof (sadb_prop_t);
5773 5774  
5774 5775          /* Make sure there's enough to cover both AF_INET and AF_INET6. */
5775 5776          allocsize += 2 * sizeof (struct sockaddr_in6);
5776 5777  
5777      -        mutex_enter(&ipss->ipsec_alg_lock);
     5778 +        rw_enter(&ipss->ipsec_alg_lock, RW_READER);
5778 5779          /* NOTE:  The lock is now held through to this function's return. */
5779 5780          allocsize += ipss->ipsec_nalgs[IPSEC_ALG_AUTH] *
5780 5781              ipss->ipsec_nalgs[IPSEC_ALG_ENCR] * sizeof (sadb_comb_t);
5781 5782  
5782 5783          if (tunnel_mode) {
5783 5784                  /* Tunnel mode! */
5784 5785                  allocsize += 2 * sizeof (sadb_address_t);
5785 5786                  /* Enough to cover both AF_INET and AF_INET6. */
5786 5787                  allocsize += 2 * sizeof (struct sockaddr_in6);
5787 5788          }
5788 5789  
5789 5790          msgmp = allocb(allocsize, BPRI_HI);
5790 5791          if (msgmp == NULL) {
5791 5792                  freeb(pfkeymp);
5792      -                mutex_exit(&ipss->ipsec_alg_lock);
     5793 +                rw_exit(&ipss->ipsec_alg_lock);
5793 5794                  return (NULL);
5794 5795          }
5795 5796  
5796 5797          pfkeymp->b_cont = msgmp;
5797 5798          cur = msgmp->b_rptr;
5798 5799          end = cur + allocsize;
5799 5800          samsg = (sadb_msg_t *)cur;
5800 5801          cur += sizeof (sadb_msg_t);
5801 5802  
5802 5803          af = acqrec->ipsacq_addrfam;
↓ open down ↓ 2 lines elided ↑ open up ↑
5805 5806                  check_proto = IPPROTO_ICMP;
5806 5807                  break;
5807 5808          case AF_INET6:
5808 5809                  check_proto = IPPROTO_ICMPV6;
5809 5810                  break;
5810 5811          default:
5811 5812                  /* This should never happen unless we have kernel bugs. */
5812 5813                  cmn_err(CE_WARN,
5813 5814                      "sadb_setup_acquire:  corrupt ACQUIRE record.\n");
5814 5815                  ASSERT(0);
5815      -                mutex_exit(&ipss->ipsec_alg_lock);
     5816 +                rw_exit(&ipss->ipsec_alg_lock);
5816 5817                  return (NULL);
5817 5818          }
5818 5819  
5819 5820          samsg->sadb_msg_version = PF_KEY_V2;
5820 5821          samsg->sadb_msg_type = SADB_ACQUIRE;
5821 5822          samsg->sadb_msg_satype = satype;
5822 5823          samsg->sadb_msg_errno = 0;
5823 5824          samsg->sadb_msg_pid = 0;
5824 5825          samsg->sadb_msg_reserved = 0;
5825 5826          samsg->sadb_msg_seq = acqrec->ipsacq_seq;
↓ open down ↓ 26 lines elided ↑ open up ↑
5852 5853                      acqrec->ipsacq_innerdstpfx);
5853 5854          }
5854 5855  
5855 5856          /* XXX Insert identity information here. */
5856 5857  
5857 5858          /* XXXMLS Insert sensitivity information here. */
5858 5859  
5859 5860          if (cur != NULL)
5860 5861                  samsg->sadb_msg_len = SADB_8TO64(cur - msgmp->b_rptr);
5861 5862          else
5862      -                mutex_exit(&ipss->ipsec_alg_lock);
     5863 +                rw_exit(&ipss->ipsec_alg_lock);
5863 5864  
5864 5865          return (pfkeymp);
5865 5866  }
5866 5867  
5867 5868  /*
5868 5869   * Given an SADB_GETSPI message, find an appropriately ranged SA and
5869 5870   * allocate an SA.  If there are message improprieties, return (ipsa_t *)-1.
5870 5871   * If there was a memory allocation error, return NULL.  (Assume NULL !=
5871 5872   * (ipsa_t *)-1).
5872 5873   *
↓ open down ↓ 1310 lines elided ↑ open up ↑
7183 7184  int
7184 7185  ipsec_create_ctx_tmpl(ipsa_t *sa, ipsec_algtype_t alg_type)
7185 7186  {
7186 7187          ipsec_alginfo_t *alg;
7187 7188          crypto_mechanism_t mech;
7188 7189          crypto_key_t *key;
7189 7190          crypto_ctx_template_t *sa_tmpl;
7190 7191          int rv;
7191 7192          ipsec_stack_t   *ipss = sa->ipsa_netstack->netstack_ipsec;
7192 7193  
7193      -        ASSERT(MUTEX_HELD(&ipss->ipsec_alg_lock));
     7194 +        ASSERT(RW_READ_HELD(&ipss->ipsec_alg_lock));
7194 7195          ASSERT(MUTEX_HELD(&sa->ipsa_lock));
7195 7196  
7196 7197          /* get pointers to the algorithm info, context template, and key */
7197 7198          switch (alg_type) {
7198 7199          case IPSEC_ALG_AUTH:
7199 7200                  key = &sa->ipsa_kcfauthkey;
7200 7201                  sa_tmpl = &sa->ipsa_authtmpl;
7201 7202                  alg = ipss->ipsec_alglists[alg_type][sa->ipsa_auth_alg];
7202 7203                  break;
7203 7204          case IPSEC_ALG_ENCR:
↓ open down ↓ 644 lines elided ↑ open up ↑
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX