mirror of
				https://git.proxmox.com/git/mirror_zfs
				synced 2025-10-31 20:33:04 +00:00 
			
		
		
		
	 1d3ba0bf01
			
		
	
	
		1d3ba0bf01
		
			
		
	
	
	
	
		
			
			The commit replaces all findings of the link: http://www.opensolaris.org/os/licensing with this one: https://opensource.org/licenses/CDDL-1.0 Reviewed-by: Brian Behlendorf <behlendorf1@llnl.gov> Signed-off-by: Tino Reichardt <milky-zfs@mcmilk.de> Closes #13619
		
			
				
	
	
		
			281 lines
		
	
	
		
			8.0 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			281 lines
		
	
	
		
			8.0 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
| /*
 | |
|  * CDDL HEADER START
 | |
|  *
 | |
|  * The contents of this file are subject to the terms of the
 | |
|  * Common Development and Distribution License (the "License").
 | |
|  * You may not use this file except in compliance with the License.
 | |
|  *
 | |
|  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
 | |
|  * or https://opensource.org/licenses/CDDL-1.0.
 | |
|  * See the License for the specific language governing permissions
 | |
|  * and limitations under the License.
 | |
|  *
 | |
|  * When distributing Covered Code, include this CDDL HEADER in each
 | |
|  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
 | |
|  * If applicable, add the following below this CDDL HEADER, with the
 | |
|  * fields enclosed by brackets "[]" replaced with your own identifying
 | |
|  * information: Portions Copyright [yyyy] [name of copyright owner]
 | |
|  *
 | |
|  * CDDL HEADER END
 | |
|  */
 | |
| /*
 | |
|  * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
 | |
|  * Use is subject to license terms.
 | |
|  */
 | |
| 
 | |
| /*
 | |
|  * This file is part of the core Kernel Cryptographic Framework.
 | |
|  * It implements the SPI functions exported to cryptographic
 | |
|  * providers.
 | |
|  */
 | |
| 
 | |
| 
 | |
| #include <sys/zfs_context.h>
 | |
| #include <sys/crypto/common.h>
 | |
| #include <sys/crypto/impl.h>
 | |
| #include <sys/crypto/sched_impl.h>
 | |
| #include <sys/crypto/spi.h>
 | |
| 
 | |
| static int init_prov_mechs(const crypto_provider_info_t *,
 | |
|     kcf_provider_desc_t *);
 | |
| 
 | |
| /*
 | |
|  * This routine is used to add cryptographic providers to the KEF framework.
 | |
|  * Providers pass a crypto_provider_info structure to crypto_register_provider()
 | |
|  * and get back a handle.  The crypto_provider_info structure contains a
 | |
|  * list of mechanisms supported by the provider and an ops vector containing
 | |
|  * provider entry points.  Providers call this routine in their _init() routine.
 | |
|  */
 | |
| int
 | |
| crypto_register_provider(const crypto_provider_info_t *info,
 | |
|     crypto_kcf_provider_handle_t *handle)
 | |
| {
 | |
| 	kcf_provider_desc_t *prov_desc = NULL;
 | |
| 	int ret = CRYPTO_ARGUMENTS_BAD;
 | |
| 
 | |
| 	/*
 | |
| 	 * Allocate and initialize a new provider descriptor. We also
 | |
| 	 * hold it and release it when done.
 | |
| 	 */
 | |
| 	prov_desc = kcf_alloc_provider_desc();
 | |
| 	KCF_PROV_REFHOLD(prov_desc);
 | |
| 
 | |
| 	/* copy provider description string */
 | |
| 	prov_desc->pd_description = info->pi_provider_description;
 | |
| 
 | |
| 	/* Change from Illumos: the ops vector is persistent. */
 | |
| 	prov_desc->pd_ops_vector = info->pi_ops_vector;
 | |
| 
 | |
| 	/* process the mechanisms supported by the provider */
 | |
| 	if ((ret = init_prov_mechs(info, prov_desc)) != CRYPTO_SUCCESS)
 | |
| 		goto bail;
 | |
| 
 | |
| 	/*
 | |
| 	 * Add provider to providers tables, also sets the descriptor
 | |
| 	 * pd_prov_id field.
 | |
| 	 */
 | |
| 	if ((ret = kcf_prov_tab_add_provider(prov_desc)) != CRYPTO_SUCCESS) {
 | |
| 		undo_register_provider(prov_desc, B_FALSE);
 | |
| 		goto bail;
 | |
| 	}
 | |
| 
 | |
| 	/*
 | |
| 	 * The global queue is used for providers. We handle ordering
 | |
| 	 * of multi-part requests in the taskq routine. So, it is safe to
 | |
| 	 * have multiple threads for the taskq. We pass TASKQ_PREPOPULATE flag
 | |
| 	 * to keep some entries cached to improve performance.
 | |
| 	 */
 | |
| 
 | |
| 	mutex_enter(&prov_desc->pd_lock);
 | |
| 	prov_desc->pd_state = KCF_PROV_READY;
 | |
| 	mutex_exit(&prov_desc->pd_lock);
 | |
| 
 | |
| 	*handle = prov_desc->pd_kcf_prov_handle;
 | |
| 	ret = CRYPTO_SUCCESS;
 | |
| 
 | |
| bail:
 | |
| 	KCF_PROV_REFRELE(prov_desc);
 | |
| 	return (ret);
 | |
| }
 | |
| 
 | |
| /*
 | |
|  * This routine is used to notify the framework when a provider is being
 | |
|  * removed.  Providers call this routine in their _fini() routine.
 | |
|  */
 | |
| int
 | |
| crypto_unregister_provider(crypto_kcf_provider_handle_t handle)
 | |
| {
 | |
| 	uint_t mech_idx;
 | |
| 	kcf_provider_desc_t *desc;
 | |
| 	kcf_prov_state_t saved_state;
 | |
| 
 | |
| 	/* lookup provider descriptor */
 | |
| 	if ((desc = kcf_prov_tab_lookup((crypto_provider_id_t)handle)) == NULL)
 | |
| 		return (CRYPTO_UNKNOWN_PROVIDER);
 | |
| 
 | |
| 	mutex_enter(&desc->pd_lock);
 | |
| 	/*
 | |
| 	 * Check if any other thread is disabling or removing
 | |
| 	 * this provider. We return if this is the case.
 | |
| 	 */
 | |
| 	if (desc->pd_state >= KCF_PROV_DISABLED) {
 | |
| 		mutex_exit(&desc->pd_lock);
 | |
| 		/* Release reference held by kcf_prov_tab_lookup(). */
 | |
| 		KCF_PROV_REFRELE(desc);
 | |
| 		return (CRYPTO_BUSY);
 | |
| 	}
 | |
| 
 | |
| 	saved_state = desc->pd_state;
 | |
| 	desc->pd_state = KCF_PROV_REMOVED;
 | |
| 
 | |
| 	/*
 | |
| 	 * Check if this provider is currently being used.
 | |
| 	 * pd_irefcnt is the number of holds from the internal
 | |
| 	 * structures. We add one to account for the above lookup.
 | |
| 	 */
 | |
| 	if (desc->pd_refcnt > desc->pd_irefcnt + 1) {
 | |
| 		desc->pd_state = saved_state;
 | |
| 		mutex_exit(&desc->pd_lock);
 | |
| 		/* Release reference held by kcf_prov_tab_lookup(). */
 | |
| 		KCF_PROV_REFRELE(desc);
 | |
| 		/*
 | |
| 		 * The administrator will presumably stop the clients,
 | |
| 		 * thus removing the holds, when they get the busy
 | |
| 		 * return value.  Any retry will succeed then.
 | |
| 		 */
 | |
| 		return (CRYPTO_BUSY);
 | |
| 	}
 | |
| 	mutex_exit(&desc->pd_lock);
 | |
| 
 | |
| 	/* remove the provider from the mechanisms tables */
 | |
| 	for (mech_idx = 0; mech_idx < desc->pd_mech_list_count;
 | |
| 	    mech_idx++) {
 | |
| 		kcf_remove_mech_provider(
 | |
| 		    desc->pd_mechanisms[mech_idx].cm_mech_name, desc);
 | |
| 	}
 | |
| 
 | |
| 	/* remove provider from providers table */
 | |
| 	if (kcf_prov_tab_rem_provider((crypto_provider_id_t)handle) !=
 | |
| 	    CRYPTO_SUCCESS) {
 | |
| 		/* Release reference held by kcf_prov_tab_lookup(). */
 | |
| 		KCF_PROV_REFRELE(desc);
 | |
| 		return (CRYPTO_UNKNOWN_PROVIDER);
 | |
| 	}
 | |
| 
 | |
| 	/* Release reference held by kcf_prov_tab_lookup(). */
 | |
| 	KCF_PROV_REFRELE(desc);
 | |
| 
 | |
| 	/*
 | |
| 	 * Wait till the existing requests complete.
 | |
| 	 */
 | |
| 	mutex_enter(&desc->pd_lock);
 | |
| 	while (desc->pd_state != KCF_PROV_FREED)
 | |
| 		cv_wait(&desc->pd_remove_cv, &desc->pd_lock);
 | |
| 	mutex_exit(&desc->pd_lock);
 | |
| 
 | |
| 	/*
 | |
| 	 * This is the only place where kcf_free_provider_desc()
 | |
| 	 * is called directly. KCF_PROV_REFRELE() should free the
 | |
| 	 * structure in all other places.
 | |
| 	 */
 | |
| 	ASSERT(desc->pd_state == KCF_PROV_FREED &&
 | |
| 	    desc->pd_refcnt == 0);
 | |
| 	kcf_free_provider_desc(desc);
 | |
| 
 | |
| 	return (CRYPTO_SUCCESS);
 | |
| }
 | |
| 
 | |
| /*
 | |
|  * Process the mechanism info structures specified by the provider
 | |
|  * during registration. A NULL crypto_provider_info_t indicates
 | |
|  * an already initialized provider descriptor.
 | |
|  *
 | |
|  * Returns CRYPTO_SUCCESS on success, CRYPTO_ARGUMENTS if one
 | |
|  * of the specified mechanisms was malformed, or CRYPTO_HOST_MEMORY
 | |
|  * if the table of mechanisms is full.
 | |
|  */
 | |
| static int
 | |
| init_prov_mechs(const crypto_provider_info_t *info, kcf_provider_desc_t *desc)
 | |
| {
 | |
| 	uint_t mech_idx;
 | |
| 	uint_t cleanup_idx;
 | |
| 	int err = CRYPTO_SUCCESS;
 | |
| 	kcf_prov_mech_desc_t *pmd;
 | |
| 	int desc_use_count = 0;
 | |
| 
 | |
| 	/*
 | |
| 	 * Copy the mechanism list from the provider info to the provider
 | |
| 	 * descriptor. desc->pd_mechanisms has an extra crypto_mech_info_t
 | |
| 	 * element if the provider has random_ops since we keep an internal
 | |
| 	 * mechanism, SUN_RANDOM, in this case.
 | |
| 	 */
 | |
| 	if (info != NULL) {
 | |
| 		ASSERT(info->pi_mechanisms != NULL);
 | |
| 		desc->pd_mech_list_count = info->pi_mech_list_count;
 | |
| 		desc->pd_mechanisms = info->pi_mechanisms;
 | |
| 	}
 | |
| 
 | |
| 	/*
 | |
| 	 * For each mechanism support by the provider, add the provider
 | |
| 	 * to the corresponding KCF mechanism mech_entry chain.
 | |
| 	 */
 | |
| 	for (mech_idx = 0; mech_idx < desc->pd_mech_list_count; mech_idx++) {
 | |
| 		if ((err = kcf_add_mech_provider(mech_idx, desc, &pmd)) !=
 | |
| 		    KCF_SUCCESS)
 | |
| 			break;
 | |
| 
 | |
| 		if (pmd == NULL)
 | |
| 			continue;
 | |
| 
 | |
| 		/* The provider will be used for this mechanism */
 | |
| 		desc_use_count++;
 | |
| 	}
 | |
| 
 | |
| 	/*
 | |
| 	 * Don't allow multiple providers with disabled mechanisms
 | |
| 	 * to register. Subsequent enabling of mechanisms will result in
 | |
| 	 * an unsupported configuration, i.e. multiple providers
 | |
| 	 * per mechanism.
 | |
| 	 */
 | |
| 	if (desc_use_count == 0)
 | |
| 		return (CRYPTO_ARGUMENTS_BAD);
 | |
| 
 | |
| 	if (err == KCF_SUCCESS)
 | |
| 		return (CRYPTO_SUCCESS);
 | |
| 
 | |
| 	/*
 | |
| 	 * An error occurred while adding the mechanism, cleanup
 | |
| 	 * and bail.
 | |
| 	 */
 | |
| 	for (cleanup_idx = 0; cleanup_idx < mech_idx; cleanup_idx++) {
 | |
| 		kcf_remove_mech_provider(
 | |
| 		    desc->pd_mechanisms[cleanup_idx].cm_mech_name, desc);
 | |
| 	}
 | |
| 
 | |
| 	if (err == KCF_MECH_TAB_FULL)
 | |
| 		return (CRYPTO_HOST_MEMORY);
 | |
| 
 | |
| 	return (CRYPTO_ARGUMENTS_BAD);
 | |
| }
 | |
| 
 | |
| /*
 | |
|  * Utility routine called from failure paths in crypto_register_provider()
 | |
|  * and from crypto_load_soft_disabled().
 | |
|  */
 | |
| void
 | |
| undo_register_provider(kcf_provider_desc_t *desc, boolean_t remove_prov)
 | |
| {
 | |
| 	uint_t mech_idx;
 | |
| 
 | |
| 	/* remove the provider from the mechanisms tables */
 | |
| 	for (mech_idx = 0; mech_idx < desc->pd_mech_list_count;
 | |
| 	    mech_idx++) {
 | |
| 		kcf_remove_mech_provider(
 | |
| 		    desc->pd_mechanisms[mech_idx].cm_mech_name, desc);
 | |
| 	}
 | |
| 
 | |
| 	/* remove provider from providers table */
 | |
| 	if (remove_prov)
 | |
| 		(void) kcf_prov_tab_rem_provider(desc->pd_prov_id);
 | |
| }
 |