Commit 290516a8 authored by Konrad Sztyber's avatar Konrad Sztyber Committed by Tomasz Zawadzki
Browse files

keyring: add probe_key



This callback makes it possible to implement keyring modules that
instantiate the keys only once they're requested by the user.  For
instance, a module can check if the key is available in a remote key
server and fetch it over the network.

Since probed keys are added to the keyring implicitly, they're removed
once the last reference to a key is released.  Users can still
explicitly remove such keys while they're still in use - in this case
the references are still valid, but they cannot be used to retrieve the
keying material.

To make it possible to add a key from within the probe_key() callback,
g_keyring.mutex was changed to be recursive.  That's because probe_key()
is called with the mutex held, and spdk_keyring_add_key() takes it
again.

Signed-off-by: default avatarKonrad Sztyber <konrad.sztyber@intel.com>
Change-Id: I4852c8371c076bdf0f6cfce16cd86619ac4b8c7a
Reviewed-on: https://review.spdk.io/gerrit/c/spdk/spdk/+/21758


Reviewed-by: default avatarAleksey Marchuk <alexeymar@nvidia.com>
Community-CI: Mellanox Build Bot
Tested-by: default avatarSPDK CI Jenkins <sys_sgci@intel.com>
Reviewed-by: default avatarJim Harris <jim.harris@samsung.com>
parent ee164e62
Loading
Loading
Loading
Loading
+5 −1
Original line number Diff line number Diff line
@@ -12812,7 +12812,9 @@ Example response:

### keyring_get_keys {#rpc_keyring_get_keys}

Get a list of available keys.
Get a list of available keys.  This RPC will only list keys that are currently attached to a
keyring.  Dynamically loaded keys (via the `probe_key()` callback) will only be included if they're
currently in-use (i.e. with active references obtained via `spdk_keyring_get_key()`).

#### Example

@@ -12836,6 +12838,7 @@ Example response:
      "name": "key0",
      "module": "keyring_file",
      "removed": false,
      "probed": false,
      "refcnt": 1,
      "path": "/path/to/key0"
    },
@@ -12843,6 +12846,7 @@ Example response:
      "name": "key1",
      "module": "keyring_file",
      "removed": false,
      "probed": false,
      "refcnt": 1,
      "path": "/path/to/key1"
    }
+5 −0
Original line number Diff line number Diff line
@@ -49,6 +49,11 @@ struct spdk_keyring_module {
	void (*cleanup)(void);
	/** Write module configuration to JSON */
	void (*write_config)(struct spdk_json_write_ctx *w);
	/**
	 * Probe if a key with a specified name is available.  If it is, the module should add it to
	 * the keyring and return zero.  Otherwise, -ENOKEY should be returned.
	 */
	int (*probe_key)(const char *name);
	/** Add a key to the keyring */
	int (*add_key)(struct spdk_key *key, void *ctx);
	/** Remove a key from the keyring */
+75 −5
Original line number Diff line number Diff line
@@ -13,6 +13,7 @@ struct spdk_key {
	char				*name;
	int				refcnt;
	bool				removed;
	bool				probed;
	struct spdk_keyring_module	*module;
	TAILQ_ENTRY(spdk_key)		tailq;
};
@@ -25,7 +26,6 @@ struct spdk_keyring {
};

static struct spdk_keyring g_keyring = {
	.mutex = PTHREAD_MUTEX_INITIALIZER,
	.keys = TAILQ_HEAD_INITIALIZER(g_keyring.keys),
	.removed_keys = TAILQ_HEAD_INITIALIZER(g_keyring.removed_keys),
	.modules = TAILQ_HEAD_INITIALIZER(g_keyring.modules),
@@ -69,7 +69,7 @@ keyring_free_key(struct spdk_key *key)
	free(key);
}

static void
static int
keyring_put_key(struct spdk_key *key)
{
	assert(key->refcnt > 0);
@@ -79,7 +79,11 @@ keyring_put_key(struct spdk_key *key)
		assert(key->removed);
		TAILQ_REMOVE(&g_keyring.removed_keys, key, tailq);
		keyring_free_key(key);

		return 0;
	}

	return key->refcnt;
}

int
@@ -163,6 +167,41 @@ out:
	pthread_mutex_unlock(&g_keyring.mutex);
}

static struct spdk_key *
keyring_probe_key(const char *name)
{
	struct spdk_keyring_module *module;
	struct spdk_key *key = NULL;
	int rc;

	TAILQ_FOREACH(module, &g_keyring.modules, tailq) {
		if (module->probe_key == NULL) {
			continue;
		}

		rc = module->probe_key(name);
		if (rc == 0) {
			key = keyring_find_key(name);
			if (key == NULL) {
				SPDK_ERRLOG("Successfully probed key '%s' using module '%s', but "
					    "the key is unavailable\n", name, module->name);
				return NULL;
			}

			key->probed = true;
			break;
		} else if (rc != -ENOKEY) {
			/* The module is aware of the key but couldn't instantiate it */
			assert(keyring_find_key(name) == NULL);
			SPDK_ERRLOG("Failed to probe key '%s' using module '%s': %s\n",
				    name, module->name, spdk_strerror(-rc));
			break;
		}
	}

	return key;
}

struct spdk_key *
spdk_keyring_get_key(const char *name)
{
@@ -170,9 +209,12 @@ spdk_keyring_get_key(const char *name)

	pthread_mutex_lock(&g_keyring.mutex);
	key = keyring_find_key(name);
	if (key == NULL) {
		key = keyring_probe_key(name);
		if (key == NULL) {
			goto out;
		}
	}

	key->refcnt++;
out:
@@ -184,12 +226,17 @@ out:
void
spdk_keyring_put_key(struct spdk_key *key)
{
	int refcnt;

	if (key == NULL) {
		return;
	}

	pthread_mutex_lock(&g_keyring.mutex);
	keyring_put_key(key);
	refcnt = keyring_put_key(key);
	if (refcnt == 1 && key->probed && !key->removed) {
		keyring_remove_key(key);
	}
	pthread_mutex_unlock(&g_keyring.mutex);
}

@@ -270,6 +317,7 @@ keyring_dump_key_info(struct spdk_key *key, struct spdk_json_write_ctx *w)
	spdk_json_write_named_string(w, "name", key->name);
	spdk_json_write_named_string(w, "module", module->name);
	spdk_json_write_named_bool(w, "removed", key->removed);
	spdk_json_write_named_bool(w, "probed", key->probed);
	spdk_json_write_named_int32(w, "refcnt", key->refcnt);

	if (!key->removed && module->dump_info != NULL) {
@@ -281,8 +329,30 @@ int
spdk_keyring_init(void)
{
	struct spdk_keyring_module *module, *tmp;
	int rc = 0;
	pthread_mutexattr_t attr;
	int rc;

	rc = pthread_mutexattr_init(&attr);
	if (rc != 0) {
		SPDK_ERRLOG("Failed to initialize mutex attr\n");
		return -rc;
	}

	rc = pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE);
	if (rc != 0) {
		SPDK_ERRLOG("Failed to set mutex attr\n");
		pthread_mutexattr_destroy(&attr);
		return -rc;
	}

	rc = pthread_mutex_init(&g_keyring.mutex, &attr);
	if (rc != 0) {
		SPDK_ERRLOG("Failed to initialize mutex\n");
		pthread_mutexattr_destroy(&attr);
		return -rc;
	}

	pthread_mutexattr_destroy(&attr);
	TAILQ_FOREACH(module, &g_keyring.modules, tailq) {
		if (module->init != NULL) {
			rc = module->init();