The Design and Implementation of the FreeBSD Operating System, Second Edition
Now available: The Design and Implementation of the FreeBSD Operating System (Second Edition)


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]

FreeBSD/Linux Kernel Cross Reference
sys/contrib/openzfs/module/icp/spi/kcf_spi.c

Version: -  FREEBSD  -  FREEBSD-13-STABLE  -  FREEBSD-13-0  -  FREEBSD-12-STABLE  -  FREEBSD-12-0  -  FREEBSD-11-STABLE  -  FREEBSD-11-0  -  FREEBSD-10-STABLE  -  FREEBSD-10-0  -  FREEBSD-9-STABLE  -  FREEBSD-9-0  -  FREEBSD-8-STABLE  -  FREEBSD-8-0  -  FREEBSD-7-STABLE  -  FREEBSD-7-0  -  FREEBSD-6-STABLE  -  FREEBSD-6-0  -  FREEBSD-5-STABLE  -  FREEBSD-5-0  -  FREEBSD-4-STABLE  -  FREEBSD-3-STABLE  -  FREEBSD22  -  l41  -  OPENBSD  -  linux-2.6  -  MK84  -  PLAN9  -  xnu-8792 
SearchContext: -  none  -  3  -  10 

    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 https://opensource.org/licenses/CDDL-1.0.
   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 2008 Sun Microsystems, Inc.  All rights reserved.
   23  * Use is subject to license terms.
   24  */
   25 
   26 /*
   27  * This file is part of the core Kernel Cryptographic Framework.
   28  * It implements the SPI functions exported to cryptographic
   29  * providers.
   30  */
   31 
   32 
   33 #include <sys/zfs_context.h>
   34 #include <sys/crypto/common.h>
   35 #include <sys/crypto/impl.h>
   36 #include <sys/crypto/sched_impl.h>
   37 #include <sys/crypto/spi.h>
   38 
   39 static int init_prov_mechs(const crypto_provider_info_t *,
   40     kcf_provider_desc_t *);
   41 
   42 /*
   43  * This routine is used to add cryptographic providers to the KEF framework.
   44  * Providers pass a crypto_provider_info structure to crypto_register_provider()
   45  * and get back a handle.  The crypto_provider_info structure contains a
   46  * list of mechanisms supported by the provider and an ops vector containing
   47  * provider entry points.  Providers call this routine in their _init() routine.
   48  */
   49 int
   50 crypto_register_provider(const crypto_provider_info_t *info,
   51     crypto_kcf_provider_handle_t *handle)
   52 {
   53         kcf_provider_desc_t *prov_desc = NULL;
   54         int ret = CRYPTO_ARGUMENTS_BAD;
   55 
   56         /*
   57          * Allocate and initialize a new provider descriptor. We also
   58          * hold it and release it when done.
   59          */
   60         prov_desc = kcf_alloc_provider_desc();
   61         KCF_PROV_REFHOLD(prov_desc);
   62 
   63         /* copy provider description string */
   64         prov_desc->pd_description = info->pi_provider_description;
   65 
   66         /* Change from Illumos: the ops vector is persistent. */
   67         prov_desc->pd_ops_vector = info->pi_ops_vector;
   68 
   69         /* process the mechanisms supported by the provider */
   70         if ((ret = init_prov_mechs(info, prov_desc)) != CRYPTO_SUCCESS)
   71                 goto bail;
   72 
   73         /*
   74          * Add provider to providers tables, also sets the descriptor
   75          * pd_prov_id field.
   76          */
   77         if ((ret = kcf_prov_tab_add_provider(prov_desc)) != CRYPTO_SUCCESS) {
   78                 undo_register_provider(prov_desc, B_FALSE);
   79                 goto bail;
   80         }
   81 
   82         /*
   83          * The global queue is used for providers. We handle ordering
   84          * of multi-part requests in the taskq routine. So, it is safe to
   85          * have multiple threads for the taskq. We pass TASKQ_PREPOPULATE flag
   86          * to keep some entries cached to improve performance.
   87          */
   88 
   89         mutex_enter(&prov_desc->pd_lock);
   90         prov_desc->pd_state = KCF_PROV_READY;
   91         mutex_exit(&prov_desc->pd_lock);
   92 
   93         *handle = prov_desc->pd_kcf_prov_handle;
   94         ret = CRYPTO_SUCCESS;
   95 
   96 bail:
   97         KCF_PROV_REFRELE(prov_desc);
   98         return (ret);
   99 }
  100 
  101 /*
  102  * This routine is used to notify the framework when a provider is being
  103  * removed.  Providers call this routine in their _fini() routine.
  104  */
  105 int
  106 crypto_unregister_provider(crypto_kcf_provider_handle_t handle)
  107 {
  108         uint_t mech_idx;
  109         kcf_provider_desc_t *desc;
  110         kcf_prov_state_t saved_state;
  111 
  112         /* lookup provider descriptor */
  113         if ((desc = kcf_prov_tab_lookup((crypto_provider_id_t)handle)) == NULL)
  114                 return (CRYPTO_UNKNOWN_PROVIDER);
  115 
  116         mutex_enter(&desc->pd_lock);
  117         /*
  118          * Check if any other thread is disabling or removing
  119          * this provider. We return if this is the case.
  120          */
  121         if (desc->pd_state >= KCF_PROV_DISABLED) {
  122                 mutex_exit(&desc->pd_lock);
  123                 /* Release reference held by kcf_prov_tab_lookup(). */
  124                 KCF_PROV_REFRELE(desc);
  125                 return (CRYPTO_BUSY);
  126         }
  127 
  128         saved_state = desc->pd_state;
  129         desc->pd_state = KCF_PROV_REMOVED;
  130 
  131         /*
  132          * Check if this provider is currently being used.
  133          * pd_irefcnt is the number of holds from the internal
  134          * structures. We add one to account for the above lookup.
  135          */
  136         if (desc->pd_refcnt > desc->pd_irefcnt + 1) {
  137                 desc->pd_state = saved_state;
  138                 mutex_exit(&desc->pd_lock);
  139                 /* Release reference held by kcf_prov_tab_lookup(). */
  140                 KCF_PROV_REFRELE(desc);
  141                 /*
  142                  * The administrator will presumably stop the clients,
  143                  * thus removing the holds, when they get the busy
  144                  * return value.  Any retry will succeed then.
  145                  */
  146                 return (CRYPTO_BUSY);
  147         }
  148         mutex_exit(&desc->pd_lock);
  149 
  150         /* remove the provider from the mechanisms tables */
  151         for (mech_idx = 0; mech_idx < desc->pd_mech_list_count;
  152             mech_idx++) {
  153                 kcf_remove_mech_provider(
  154                     desc->pd_mechanisms[mech_idx].cm_mech_name, desc);
  155         }
  156 
  157         /* remove provider from providers table */
  158         if (kcf_prov_tab_rem_provider((crypto_provider_id_t)handle) !=
  159             CRYPTO_SUCCESS) {
  160                 /* Release reference held by kcf_prov_tab_lookup(). */
  161                 KCF_PROV_REFRELE(desc);
  162                 return (CRYPTO_UNKNOWN_PROVIDER);
  163         }
  164 
  165         /* Release reference held by kcf_prov_tab_lookup(). */
  166         KCF_PROV_REFRELE(desc);
  167 
  168         /*
  169          * Wait till the existing requests complete.
  170          */
  171         mutex_enter(&desc->pd_lock);
  172         while (desc->pd_state != KCF_PROV_FREED)
  173                 cv_wait(&desc->pd_remove_cv, &desc->pd_lock);
  174         mutex_exit(&desc->pd_lock);
  175 
  176         /*
  177          * This is the only place where kcf_free_provider_desc()
  178          * is called directly. KCF_PROV_REFRELE() should free the
  179          * structure in all other places.
  180          */
  181         ASSERT(desc->pd_state == KCF_PROV_FREED &&
  182             desc->pd_refcnt == 0);
  183         kcf_free_provider_desc(desc);
  184 
  185         return (CRYPTO_SUCCESS);
  186 }
  187 
  188 /*
  189  * Process the mechanism info structures specified by the provider
  190  * during registration. A NULL crypto_provider_info_t indicates
  191  * an already initialized provider descriptor.
  192  *
  193  * Returns CRYPTO_SUCCESS on success, CRYPTO_ARGUMENTS if one
  194  * of the specified mechanisms was malformed, or CRYPTO_HOST_MEMORY
  195  * if the table of mechanisms is full.
  196  */
  197 static int
  198 init_prov_mechs(const crypto_provider_info_t *info, kcf_provider_desc_t *desc)
  199 {
  200         uint_t mech_idx;
  201         uint_t cleanup_idx;
  202         int err = CRYPTO_SUCCESS;
  203         kcf_prov_mech_desc_t *pmd;
  204         int desc_use_count = 0;
  205 
  206         /*
  207          * Copy the mechanism list from the provider info to the provider
  208          * descriptor. desc->pd_mechanisms has an extra crypto_mech_info_t
  209          * element if the provider has random_ops since we keep an internal
  210          * mechanism, SUN_RANDOM, in this case.
  211          */
  212         if (info != NULL) {
  213                 ASSERT(info->pi_mechanisms != NULL);
  214                 desc->pd_mech_list_count = info->pi_mech_list_count;
  215                 desc->pd_mechanisms = info->pi_mechanisms;
  216         }
  217 
  218         /*
  219          * For each mechanism support by the provider, add the provider
  220          * to the corresponding KCF mechanism mech_entry chain.
  221          */
  222         for (mech_idx = 0; mech_idx < desc->pd_mech_list_count; mech_idx++) {
  223                 if ((err = kcf_add_mech_provider(mech_idx, desc, &pmd)) !=
  224                     KCF_SUCCESS)
  225                         break;
  226 
  227                 if (pmd == NULL)
  228                         continue;
  229 
  230                 /* The provider will be used for this mechanism */
  231                 desc_use_count++;
  232         }
  233 
  234         /*
  235          * Don't allow multiple providers with disabled mechanisms
  236          * to register. Subsequent enabling of mechanisms will result in
  237          * an unsupported configuration, i.e. multiple providers
  238          * per mechanism.
  239          */
  240         if (desc_use_count == 0)
  241                 return (CRYPTO_ARGUMENTS_BAD);
  242 
  243         if (err == KCF_SUCCESS)
  244                 return (CRYPTO_SUCCESS);
  245 
  246         /*
  247          * An error occurred while adding the mechanism, cleanup
  248          * and bail.
  249          */
  250         for (cleanup_idx = 0; cleanup_idx < mech_idx; cleanup_idx++) {
  251                 kcf_remove_mech_provider(
  252                     desc->pd_mechanisms[cleanup_idx].cm_mech_name, desc);
  253         }
  254 
  255         if (err == KCF_MECH_TAB_FULL)
  256                 return (CRYPTO_HOST_MEMORY);
  257 
  258         return (CRYPTO_ARGUMENTS_BAD);
  259 }
  260 
  261 /*
  262  * Utility routine called from failure paths in crypto_register_provider()
  263  * and from crypto_load_soft_disabled().
  264  */
  265 void
  266 undo_register_provider(kcf_provider_desc_t *desc, boolean_t remove_prov)
  267 {
  268         uint_t mech_idx;
  269 
  270         /* remove the provider from the mechanisms tables */
  271         for (mech_idx = 0; mech_idx < desc->pd_mech_list_count;
  272             mech_idx++) {
  273                 kcf_remove_mech_provider(
  274                     desc->pd_mechanisms[mech_idx].cm_mech_name, desc);
  275         }
  276 
  277         /* remove provider from providers table */
  278         if (remove_prov)
  279                 (void) kcf_prov_tab_rem_provider(desc->pd_prov_id);
  280 }

Cache object: 7b3c4217cce6201cb7090a0ca73b07e6


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]


This page is part of the FreeBSD/Linux Linux Kernel Cross-Reference, and was automatically generated using a modified version of the LXR engine.