LCOV - code coverage report
Current view: top level - lib/keyring - keyring.c (source / functions) Hit Total Coverage
Test: ut_cov_unit.info Lines: 127 253 50.2 %
Date: 2024-12-13 17:41:14 Functions: 15 22 68.2 %

          Line data    Source code
       1             : /* SPDX-License-Identifier: BSD-3-Clause
       2             :  * Copyright (c) 2024 Intel Corporation. All rights reserved.
       3             :  */
       4             : 
       5             : #include "keyring_internal.h"
       6             : #include "spdk/keyring.h"
       7             : #include "spdk/keyring_module.h"
       8             : #include "spdk/log.h"
       9             : #include "spdk/queue.h"
      10             : #include "spdk/string.h"
      11             : 
      12             : struct spdk_key {
      13             :         char                            *name;
      14             :         int                             refcnt;
      15             :         bool                            removed;
      16             :         bool                            probed;
      17             :         struct spdk_keyring_module      *module;
      18             :         TAILQ_ENTRY(spdk_key)           tailq;
      19             : };
      20             : 
      21             : struct spdk_keyring {
      22             :         pthread_mutex_t                         mutex;
      23             :         TAILQ_HEAD(, spdk_keyring_module)       modules;
      24             :         TAILQ_HEAD(, spdk_key)                  keys;
      25             :         TAILQ_HEAD(, spdk_key)                  removed_keys;
      26             : };
      27             : 
      28             : static struct spdk_keyring g_keyring = {
      29             :         .keys = TAILQ_HEAD_INITIALIZER(g_keyring.keys),
      30             :         .removed_keys = TAILQ_HEAD_INITIALIZER(g_keyring.removed_keys),
      31             :         .modules = TAILQ_HEAD_INITIALIZER(g_keyring.modules),
      32             : };
      33             : 
      34             : static const char *
      35          40 : keyring_get_key_name(const char *name)
      36             : {
      37          40 :         const char *keyname;
      38             : 
      39             :         /* Both "key0" and ":key0" refer to "key0" in the global keyring */
      40          40 :         keyname = strstr(name, ":");
      41          40 :         if (keyname == NULL) {
      42          36 :                 return name;
      43             :         }
      44             : 
      45           4 :         return keyname + 1;
      46          40 : }
      47             : 
      48             : static struct spdk_key *
      49          33 : keyring_find_key(const char *name)
      50             : {
      51          33 :         struct spdk_key *key;
      52             : 
      53          33 :         TAILQ_FOREACH(key, &g_keyring.keys, tailq) {
      54          20 :                 if (strcmp(keyring_get_key_name(key->name),
      55          20 :                            keyring_get_key_name(name)) == 0) {
      56          20 :                         return key;
      57             :                 }
      58           0 :         }
      59             : 
      60          13 :         return NULL;
      61          33 : }
      62             : 
      63             : static void
      64           4 : keyring_free_key(struct spdk_key *key)
      65             : {
      66           4 :         assert(key->refcnt == 0);
      67             : 
      68           4 :         free(key->name);
      69           4 :         free(key);
      70           4 : }
      71             : 
      72             : static int
      73          15 : keyring_put_key(struct spdk_key *key)
      74             : {
      75          15 :         assert(key->refcnt > 0);
      76          15 :         key->refcnt--;
      77             : 
      78          15 :         if (key->refcnt == 0) {
      79           3 :                 assert(key->removed);
      80           3 :                 TAILQ_REMOVE(&g_keyring.removed_keys, key, tailq);
      81           3 :                 keyring_free_key(key);
      82             : 
      83           3 :                 return 0;
      84             :         }
      85             : 
      86          12 :         return key->refcnt;
      87          15 : }
      88             : 
      89             : int
      90           7 : spdk_keyring_add_key(const struct spdk_key_opts *opts)
      91             : {
      92           7 :         struct spdk_key *key = NULL;
      93           7 :         struct spdk_keyring_module *module = opts->module;
      94           7 :         const char *keyname;
      95           7 :         int rc = 0;
      96             : 
      97             :         /* For now, only global keyring is supported */
      98           7 :         keyname = strstr(opts->name, ":");
      99           7 :         if (keyname != NULL && keyname != opts->name) {
     100           0 :                 SPDK_ERRLOG("Couldn't add key '%s' to the keyring: keyring doesn't exist\n",
     101             :                             opts->name);
     102           0 :                 return -EINVAL;
     103             :         }
     104             : 
     105           7 :         pthread_mutex_lock(&g_keyring.mutex);
     106           7 :         if (keyring_find_key(opts->name) != NULL) {
     107           2 :                 SPDK_ERRLOG("Key '%s' already exists\n", opts->name);
     108           2 :                 rc = -EEXIST;
     109           2 :                 goto out;
     110             :         }
     111             : 
     112           5 :         key = calloc(1, sizeof(*key) + module->get_ctx_size());
     113           5 :         if (key == NULL) {
     114           0 :                 rc = -ENOMEM;
     115           0 :                 goto out;
     116             :         }
     117             : 
     118           5 :         key->name = strdup(opts->name);
     119           5 :         if (key->name == NULL) {
     120           0 :                 rc = -ENOMEM;
     121           0 :                 goto out;
     122             :         }
     123             : 
     124           5 :         rc = module->add_key(key, opts->ctx);
     125           5 :         if (rc != 0) {
     126           1 :                 SPDK_ERRLOG("Failed to add key '%s' to the keyring\n", opts->name);
     127           1 :                 goto out;
     128             :         }
     129             : 
     130           4 :         key->module = module;
     131           4 :         key->refcnt = 1;
     132           4 :         TAILQ_INSERT_TAIL(&g_keyring.keys, key, tailq);
     133             : out:
     134           7 :         pthread_mutex_unlock(&g_keyring.mutex);
     135           7 :         if (rc != 0 && key != NULL) {
     136           1 :                 keyring_free_key(key);
     137           1 :         }
     138             : 
     139           7 :         return rc;
     140           7 : }
     141             : 
     142             : static void
     143           4 : keyring_remove_key(struct spdk_key *key)
     144             : {
     145           4 :         assert(!key->removed);
     146           4 :         key->removed = true;
     147           4 :         key->module->remove_key(key);
     148           4 :         TAILQ_REMOVE(&g_keyring.keys, key, tailq);
     149           4 :         TAILQ_INSERT_TAIL(&g_keyring.removed_keys, key, tailq);
     150           4 :         keyring_put_key(key);
     151           4 : }
     152             : 
     153             : int
     154           7 : spdk_keyring_remove_key(const char *name, struct spdk_keyring_module *module)
     155             : {
     156           7 :         struct spdk_key *key;
     157           7 :         int rc = 0;
     158             : 
     159           7 :         pthread_mutex_lock(&g_keyring.mutex);
     160           7 :         key = keyring_find_key(name);
     161           7 :         if (key == NULL) {
     162           2 :                 SPDK_ERRLOG("Key '%s' does not exist\n", name);
     163           2 :                 rc = -ENOKEY;
     164           2 :                 goto out;
     165             :         }
     166             : 
     167           5 :         if (key->module != module) {
     168           1 :                 SPDK_ERRLOG("Key '%s' is not owned by module '%s'\n", name, module->name);
     169           1 :                 rc = -EINVAL;
     170           1 :                 goto out;
     171             :         }
     172             : 
     173           4 :         keyring_remove_key(key);
     174             : out:
     175           7 :         pthread_mutex_unlock(&g_keyring.mutex);
     176          14 :         return rc;
     177           7 : }
     178             : 
     179             : static struct spdk_key *
     180           6 : keyring_probe_key(const char *name)
     181             : {
     182           6 :         struct spdk_keyring_module *module;
     183           6 :         struct spdk_key *key = NULL;
     184           6 :         int rc;
     185             : 
     186          12 :         TAILQ_FOREACH(module, &g_keyring.modules, tailq) {
     187           6 :                 if (module->probe_key == NULL) {
     188           6 :                         continue;
     189             :                 }
     190             : 
     191           0 :                 rc = module->probe_key(name);
     192           0 :                 if (rc == 0) {
     193           0 :                         key = keyring_find_key(name);
     194           0 :                         if (key == NULL) {
     195           0 :                                 SPDK_ERRLOG("Successfully probed key '%s' using module '%s', but "
     196             :                                             "the key is unavailable\n", name, module->name);
     197           0 :                                 return NULL;
     198             :                         }
     199             : 
     200           0 :                         key->probed = true;
     201           0 :                         break;
     202           0 :                 } else if (rc != -ENOKEY) {
     203             :                         /* The module is aware of the key but couldn't instantiate it */
     204           0 :                         assert(keyring_find_key(name) == NULL);
     205           0 :                         SPDK_ERRLOG("Failed to probe key '%s' using module '%s': %s\n",
     206             :                                     name, module->name, spdk_strerror(-rc));
     207           0 :                         break;
     208             :                 }
     209           0 :         }
     210             : 
     211           6 :         return key;
     212           6 : }
     213             : 
     214             : struct spdk_key *
     215          19 : spdk_keyring_get_key(const char *name)
     216             : {
     217          19 :         struct spdk_key *key;
     218             : 
     219          19 :         pthread_mutex_lock(&g_keyring.mutex);
     220          19 :         key = keyring_find_key(name);
     221          19 :         if (key == NULL) {
     222           6 :                 key = keyring_probe_key(name);
     223           6 :                 if (key == NULL) {
     224           6 :                         goto out;
     225             :                 }
     226           0 :         }
     227             : 
     228          13 :         key->refcnt++;
     229             : out:
     230          19 :         pthread_mutex_unlock(&g_keyring.mutex);
     231             : 
     232          38 :         return key;
     233          19 : }
     234             : 
     235             : void
     236          11 : spdk_keyring_put_key(struct spdk_key *key)
     237             : {
     238          11 :         int refcnt;
     239             : 
     240          11 :         if (key == NULL) {
     241           0 :                 return;
     242             :         }
     243             : 
     244          11 :         pthread_mutex_lock(&g_keyring.mutex);
     245          11 :         refcnt = keyring_put_key(key);
     246          11 :         if (refcnt == 1 && key->probed && !key->removed) {
     247           0 :                 keyring_remove_key(key);
     248           0 :         }
     249          11 :         pthread_mutex_unlock(&g_keyring.mutex);
     250          11 : }
     251             : 
     252             : struct spdk_key *
     253           0 : spdk_key_dup(struct spdk_key *key)
     254             : {
     255           0 :         pthread_mutex_lock(&g_keyring.mutex);
     256           0 :         key->refcnt++;
     257           0 :         pthread_mutex_unlock(&g_keyring.mutex);
     258             : 
     259           0 :         return key;
     260             : }
     261             : 
     262             : const char *
     263           9 : spdk_key_get_name(struct spdk_key *key)
     264             : {
     265           9 :         return key->name;
     266             : }
     267             : 
     268             : int
     269           3 : spdk_key_get_key(struct spdk_key *key, void *buf, int len)
     270             : {
     271           3 :         struct spdk_keyring_module *module = key->module;
     272             : 
     273           3 :         if (key->removed) {
     274           1 :                 return -ENOKEY;
     275             :         }
     276             : 
     277           2 :         return module->get_key(key, buf, len);
     278           3 : }
     279             : 
     280             : void *
     281          11 : spdk_key_get_ctx(struct spdk_key *key)
     282             : {
     283          11 :         return key + 1;
     284             : }
     285             : 
     286             : 
     287             : struct spdk_keyring_module *
     288           0 : spdk_key_get_module(struct spdk_key *key)
     289             : {
     290           0 :         return key->module;
     291             : }
     292             : 
     293             : void
     294           0 : spdk_keyring_write_config(struct spdk_json_write_ctx *w)
     295             : {
     296           0 :         struct spdk_keyring_module *module;
     297             : 
     298           0 :         TAILQ_FOREACH(module, &g_keyring.modules, tailq) {
     299           0 :                 if (module->write_config != NULL) {
     300           0 :                         module->write_config(w);
     301           0 :                 }
     302           0 :         }
     303           0 : }
     304             : 
     305             : void
     306           0 : spdk_keyring_for_each_key(struct spdk_keyring *keyring,
     307             :                           void *ctx, void (*fn)(void *ctx, struct spdk_key *key), uint32_t flags)
     308             : {
     309           0 :         struct spdk_key *key, *tmp;
     310             : 
     311           0 :         assert(keyring == NULL);
     312           0 :         pthread_mutex_lock(&g_keyring.mutex);
     313           0 :         TAILQ_FOREACH_SAFE(key, &g_keyring.keys, tailq, tmp) {
     314           0 :                 fn(ctx, key);
     315           0 :         }
     316             : 
     317           0 :         if (flags & SPDK_KEYRING_FOR_EACH_ALL) {
     318           0 :                 TAILQ_FOREACH_SAFE(key, &g_keyring.removed_keys, tailq, tmp) {
     319           0 :                         fn(ctx, key);
     320           0 :                 }
     321           0 :         }
     322           0 :         pthread_mutex_unlock(&g_keyring.mutex);
     323           0 : }
     324             : 
     325             : void
     326           1 : spdk_keyring_register_module(struct spdk_keyring_module *module)
     327             : {
     328           1 :         TAILQ_INSERT_TAIL(&g_keyring.modules, module, tailq);
     329           1 : }
     330             : 
     331             : void
     332           0 : keyring_dump_key_info(struct spdk_key *key, struct spdk_json_write_ctx *w)
     333             : {
     334           0 :         struct spdk_keyring_module *module = key->module;
     335             : 
     336           0 :         spdk_json_write_named_string(w, "name", key->name);
     337           0 :         spdk_json_write_named_string(w, "module", module->name);
     338           0 :         spdk_json_write_named_bool(w, "removed", key->removed);
     339           0 :         spdk_json_write_named_bool(w, "probed", key->probed);
     340           0 :         spdk_json_write_named_int32(w, "refcnt", key->refcnt);
     341             : 
     342           0 :         if (!key->removed && module->dump_info != NULL) {
     343           0 :                 module->dump_info(key, w);
     344           0 :         }
     345           0 : }
     346             : 
     347             : int
     348           0 : spdk_keyring_init(void)
     349             : {
     350           0 :         struct spdk_keyring_module *module, *tmp;
     351           0 :         pthread_mutexattr_t attr;
     352           0 :         int rc;
     353             : 
     354           0 :         rc = pthread_mutexattr_init(&attr);
     355           0 :         if (rc != 0) {
     356           0 :                 SPDK_ERRLOG("Failed to initialize mutex attr\n");
     357           0 :                 return -rc;
     358             :         }
     359             : 
     360           0 :         rc = pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE);
     361           0 :         if (rc != 0) {
     362           0 :                 SPDK_ERRLOG("Failed to set mutex attr\n");
     363           0 :                 pthread_mutexattr_destroy(&attr);
     364           0 :                 return -rc;
     365             :         }
     366             : 
     367           0 :         rc = pthread_mutex_init(&g_keyring.mutex, &attr);
     368           0 :         if (rc != 0) {
     369           0 :                 SPDK_ERRLOG("Failed to initialize mutex\n");
     370           0 :                 pthread_mutexattr_destroy(&attr);
     371           0 :                 return -rc;
     372             :         }
     373             : 
     374           0 :         pthread_mutexattr_destroy(&attr);
     375           0 :         TAILQ_FOREACH_SAFE(module, &g_keyring.modules, tailq, tmp) {
     376           0 :                 if (module->init != NULL) {
     377           0 :                         rc = module->init();
     378           0 :                         if (rc != 0) {
     379           0 :                                 if (rc == -ENODEV) {
     380           0 :                                         SPDK_INFOLOG(keyring, "Skipping module %s\n", module->name);
     381           0 :                                         TAILQ_REMOVE(&g_keyring.modules, module, tailq);
     382           0 :                                         rc = 0;
     383           0 :                                         continue;
     384             :                                 }
     385             : 
     386           0 :                                 SPDK_ERRLOG("Failed to initialize module %s: %s\n",
     387             :                                             module->name, spdk_strerror(-rc));
     388           0 :                                 break;
     389             :                         }
     390           0 :                 }
     391             : 
     392           0 :                 SPDK_INFOLOG(keyring, "Initialized module %s\n", module->name);
     393           0 :         }
     394             : 
     395           0 :         if (rc != 0) {
     396           0 :                 TAILQ_FOREACH(tmp, &g_keyring.modules, tailq) {
     397           0 :                         if (tmp == module) {
     398           0 :                                 break;
     399             :                         }
     400           0 :                         if (tmp->cleanup != NULL) {
     401           0 :                                 tmp->cleanup();
     402           0 :                         }
     403           0 :                 }
     404           0 :         }
     405             : 
     406           0 :         return rc;
     407           0 : }
     408             : 
     409             : void
     410           0 : spdk_keyring_cleanup(void)
     411             : {
     412           0 :         struct spdk_keyring_module *module;
     413           0 :         struct spdk_key *key;
     414             : 
     415           0 :         while (!TAILQ_EMPTY(&g_keyring.keys)) {
     416           0 :                 key = TAILQ_FIRST(&g_keyring.keys);
     417           0 :                 keyring_remove_key(key);
     418             :         }
     419             : 
     420           0 :         while (!TAILQ_EMPTY(&g_keyring.removed_keys)) {
     421           0 :                 key = TAILQ_FIRST(&g_keyring.removed_keys);
     422           0 :                 SPDK_WARNLOG("Key '%s' still has %d references\n", key->name, key->refcnt);
     423           0 :                 key->refcnt = 0;
     424           0 :                 TAILQ_REMOVE(&g_keyring.removed_keys, key, tailq);
     425           0 :                 keyring_free_key(key);
     426             :         }
     427             : 
     428           0 :         TAILQ_FOREACH(module, &g_keyring.modules, tailq) {
     429           0 :                 if (module->cleanup != NULL) {
     430           0 :                         module->cleanup();
     431           0 :                 }
     432           0 :         }
     433           0 : }
     434             : 
     435           1 : SPDK_LOG_REGISTER_COMPONENT(keyring)

Generated by: LCOV version 1.15