LCOV - code coverage report
Current view: top level - lib/keyring - keyring.c (source / functions) Hit Total Coverage
Test: ut_cov_unit.info Lines: 105 207 50.7 %
Date: 2024-07-15 11:46:25 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          34 : keyring_get_key_name(const char *name)
      36             : {
      37             :         const char *keyname;
      38             : 
      39             :         /* Both "key0" and ":key0" refer to "key0" in the global keyring */
      40          34 :         keyname = strstr(name, ":");
      41          34 :         if (keyname == NULL) {
      42          31 :                 return name;
      43             :         }
      44             : 
      45           3 :         return keyname + 1;
      46             : }
      47             : 
      48             : static struct spdk_key *
      49          30 : keyring_find_key(const char *name)
      50             : {
      51             :         struct spdk_key *key;
      52             : 
      53          30 :         TAILQ_FOREACH(key, &g_keyring.keys, tailq) {
      54          17 :                 if (strcmp(keyring_get_key_name(key->name),
      55             :                            keyring_get_key_name(name)) == 0) {
      56          17 :                         return key;
      57             :                 }
      58             :         }
      59             : 
      60          13 :         return NULL;
      61             : }
      62             : 
      63             : static void
      64           5 : keyring_free_key(struct spdk_key *key)
      65             : {
      66           5 :         assert(key->refcnt == 0);
      67             : 
      68           5 :         free(key->name);
      69           5 :         free(key);
      70           5 : }
      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           4 :                 assert(key->removed);
      80           4 :                 TAILQ_REMOVE(&g_keyring.removed_keys, key, tailq);
      81           4 :                 keyring_free_key(key);
      82             : 
      83           4 :                 return 0;
      84             :         }
      85             : 
      86          11 :         return key->refcnt;
      87             : }
      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             :         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           7 : out:
     134           7 :         pthread_mutex_unlock(&g_keyring.mutex);
     135           7 :         if (rc != 0 && key != NULL) {
     136           1 :                 keyring_free_key(key);
     137             :         }
     138             : 
     139           7 :         return rc;
     140             : }
     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             : void
     154           6 : spdk_keyring_remove_key(const char *name)
     155             : {
     156             :         struct spdk_key *key;
     157             : 
     158           6 :         pthread_mutex_lock(&g_keyring.mutex);
     159           6 :         key = keyring_find_key(name);
     160           6 :         if (key == NULL) {
     161           2 :                 SPDK_WARNLOG("Key '%s' does not exist\n", name);
     162           2 :                 goto out;
     163             :         }
     164             : 
     165           4 :         keyring_remove_key(key);
     166           6 : out:
     167           6 :         pthread_mutex_unlock(&g_keyring.mutex);
     168           6 : }
     169             : 
     170             : static struct spdk_key *
     171           6 : keyring_probe_key(const char *name)
     172             : {
     173             :         struct spdk_keyring_module *module;
     174           6 :         struct spdk_key *key = NULL;
     175             :         int rc;
     176             : 
     177          12 :         TAILQ_FOREACH(module, &g_keyring.modules, tailq) {
     178           6 :                 if (module->probe_key == NULL) {
     179           6 :                         continue;
     180             :                 }
     181             : 
     182           0 :                 rc = module->probe_key(name);
     183           0 :                 if (rc == 0) {
     184           0 :                         key = keyring_find_key(name);
     185           0 :                         if (key == NULL) {
     186           0 :                                 SPDK_ERRLOG("Successfully probed key '%s' using module '%s', but "
     187             :                                             "the key is unavailable\n", name, module->name);
     188           0 :                                 return NULL;
     189             :                         }
     190             : 
     191           0 :                         key->probed = true;
     192           0 :                         break;
     193           0 :                 } else if (rc != -ENOKEY) {
     194             :                         /* The module is aware of the key but couldn't instantiate it */
     195           0 :                         assert(keyring_find_key(name) == NULL);
     196           0 :                         SPDK_ERRLOG("Failed to probe key '%s' using module '%s': %s\n",
     197             :                                     name, module->name, spdk_strerror(-rc));
     198           0 :                         break;
     199             :                 }
     200             :         }
     201             : 
     202           6 :         return key;
     203             : }
     204             : 
     205             : struct spdk_key *
     206          17 : spdk_keyring_get_key(const char *name)
     207             : {
     208             :         struct spdk_key *key;
     209             : 
     210          17 :         pthread_mutex_lock(&g_keyring.mutex);
     211          17 :         key = keyring_find_key(name);
     212          17 :         if (key == NULL) {
     213           6 :                 key = keyring_probe_key(name);
     214           6 :                 if (key == NULL) {
     215           6 :                         goto out;
     216             :                 }
     217             :         }
     218             : 
     219          11 :         key->refcnt++;
     220          17 : out:
     221          17 :         pthread_mutex_unlock(&g_keyring.mutex);
     222             : 
     223          17 :         return key;
     224             : }
     225             : 
     226             : void
     227          11 : spdk_keyring_put_key(struct spdk_key *key)
     228             : {
     229             :         int refcnt;
     230             : 
     231          11 :         if (key == NULL) {
     232           0 :                 return;
     233             :         }
     234             : 
     235          11 :         pthread_mutex_lock(&g_keyring.mutex);
     236          11 :         refcnt = keyring_put_key(key);
     237          11 :         if (refcnt == 1 && key->probed && !key->removed) {
     238           0 :                 keyring_remove_key(key);
     239             :         }
     240          11 :         pthread_mutex_unlock(&g_keyring.mutex);
     241             : }
     242             : 
     243             : struct spdk_key *
     244           0 : spdk_key_dup(struct spdk_key *key)
     245             : {
     246           0 :         pthread_mutex_lock(&g_keyring.mutex);
     247           0 :         key->refcnt++;
     248           0 :         pthread_mutex_unlock(&g_keyring.mutex);
     249             : 
     250           0 :         return key;
     251             : }
     252             : 
     253             : const char *
     254           9 : spdk_key_get_name(struct spdk_key *key)
     255             : {
     256           9 :         return key->name;
     257             : }
     258             : 
     259             : int
     260           3 : spdk_key_get_key(struct spdk_key *key, void *buf, int len)
     261             : {
     262           3 :         struct spdk_keyring_module *module = key->module;
     263             : 
     264           3 :         if (key->removed) {
     265           1 :                 return -ENOKEY;
     266             :         }
     267             : 
     268           2 :         return module->get_key(key, buf, len);
     269             : }
     270             : 
     271             : void *
     272          11 : spdk_key_get_ctx(struct spdk_key *key)
     273             : {
     274          11 :         return key + 1;
     275             : }
     276             : 
     277             : 
     278             : struct spdk_keyring_module *
     279           0 : spdk_key_get_module(struct spdk_key *key)
     280             : {
     281           0 :         return key->module;
     282             : }
     283             : 
     284             : void
     285           0 : spdk_keyring_write_config(struct spdk_json_write_ctx *w)
     286             : {
     287             :         struct spdk_keyring_module *module;
     288             : 
     289           0 :         TAILQ_FOREACH(module, &g_keyring.modules, tailq) {
     290           0 :                 if (module->write_config != NULL) {
     291           0 :                         module->write_config(w);
     292             :                 }
     293             :         }
     294           0 : }
     295             : 
     296             : void
     297           0 : spdk_keyring_for_each_key(struct spdk_keyring *keyring,
     298             :                           void *ctx, void (*fn)(void *ctx, struct spdk_key *key), uint32_t flags)
     299             : {
     300             :         struct spdk_key *key, *tmp;
     301             : 
     302           0 :         assert(keyring == NULL);
     303           0 :         pthread_mutex_lock(&g_keyring.mutex);
     304           0 :         TAILQ_FOREACH_SAFE(key, &g_keyring.keys, tailq, tmp) {
     305           0 :                 fn(ctx, key);
     306             :         }
     307             : 
     308           0 :         if (flags & SPDK_KEYRING_FOR_EACH_ALL) {
     309           0 :                 TAILQ_FOREACH_SAFE(key, &g_keyring.removed_keys, tailq, tmp) {
     310           0 :                         fn(ctx, key);
     311             :                 }
     312             :         }
     313           0 :         pthread_mutex_unlock(&g_keyring.mutex);
     314           0 : }
     315             : 
     316             : void
     317           1 : spdk_keyring_register_module(struct spdk_keyring_module *module)
     318             : {
     319           1 :         TAILQ_INSERT_TAIL(&g_keyring.modules, module, tailq);
     320           1 : }
     321             : 
     322             : void
     323           0 : keyring_dump_key_info(struct spdk_key *key, struct spdk_json_write_ctx *w)
     324             : {
     325           0 :         struct spdk_keyring_module *module = key->module;
     326             : 
     327           0 :         spdk_json_write_named_string(w, "name", key->name);
     328           0 :         spdk_json_write_named_string(w, "module", module->name);
     329           0 :         spdk_json_write_named_bool(w, "removed", key->removed);
     330           0 :         spdk_json_write_named_bool(w, "probed", key->probed);
     331           0 :         spdk_json_write_named_int32(w, "refcnt", key->refcnt);
     332             : 
     333           0 :         if (!key->removed && module->dump_info != NULL) {
     334           0 :                 module->dump_info(key, w);
     335             :         }
     336           0 : }
     337             : 
     338             : int
     339           0 : spdk_keyring_init(void)
     340             : {
     341             :         struct spdk_keyring_module *module, *tmp;
     342           0 :         pthread_mutexattr_t attr;
     343             :         int rc;
     344             : 
     345           0 :         rc = pthread_mutexattr_init(&attr);
     346           0 :         if (rc != 0) {
     347           0 :                 SPDK_ERRLOG("Failed to initialize mutex attr\n");
     348           0 :                 return -rc;
     349             :         }
     350             : 
     351           0 :         rc = pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE);
     352           0 :         if (rc != 0) {
     353           0 :                 SPDK_ERRLOG("Failed to set mutex attr\n");
     354           0 :                 pthread_mutexattr_destroy(&attr);
     355           0 :                 return -rc;
     356             :         }
     357             : 
     358           0 :         rc = pthread_mutex_init(&g_keyring.mutex, &attr);
     359           0 :         if (rc != 0) {
     360           0 :                 SPDK_ERRLOG("Failed to initialize mutex\n");
     361           0 :                 pthread_mutexattr_destroy(&attr);
     362           0 :                 return -rc;
     363             :         }
     364             : 
     365           0 :         pthread_mutexattr_destroy(&attr);
     366           0 :         TAILQ_FOREACH_SAFE(module, &g_keyring.modules, tailq, tmp) {
     367           0 :                 if (module->init != NULL) {
     368           0 :                         rc = module->init();
     369           0 :                         if (rc != 0) {
     370           0 :                                 if (rc == -ENODEV) {
     371           0 :                                         SPDK_INFOLOG(keyring, "Skipping module %s\n", module->name);
     372           0 :                                         TAILQ_REMOVE(&g_keyring.modules, module, tailq);
     373           0 :                                         rc = 0;
     374           0 :                                         continue;
     375             :                                 }
     376             : 
     377           0 :                                 SPDK_ERRLOG("Failed to initialize module %s: %s\n",
     378             :                                             module->name, spdk_strerror(-rc));
     379           0 :                                 break;
     380             :                         }
     381             :                 }
     382             : 
     383           0 :                 SPDK_INFOLOG(keyring, "Initialized module %s\n", module->name);
     384             :         }
     385             : 
     386           0 :         if (rc != 0) {
     387           0 :                 TAILQ_FOREACH(tmp, &g_keyring.modules, tailq) {
     388           0 :                         if (tmp == module) {
     389           0 :                                 break;
     390             :                         }
     391           0 :                         if (tmp->cleanup != NULL) {
     392           0 :                                 tmp->cleanup();
     393             :                         }
     394             :                 }
     395             :         }
     396             : 
     397           0 :         return rc;
     398             : }
     399             : 
     400             : void
     401           0 : spdk_keyring_cleanup(void)
     402             : {
     403             :         struct spdk_keyring_module *module;
     404             :         struct spdk_key *key;
     405             : 
     406           0 :         while (!TAILQ_EMPTY(&g_keyring.keys)) {
     407           0 :                 key = TAILQ_FIRST(&g_keyring.keys);
     408           0 :                 keyring_remove_key(key);
     409             :         }
     410             : 
     411           0 :         while (!TAILQ_EMPTY(&g_keyring.removed_keys)) {
     412           0 :                 key = TAILQ_FIRST(&g_keyring.removed_keys);
     413           0 :                 SPDK_WARNLOG("Key '%s' still has %d references\n", key->name, key->refcnt);
     414           0 :                 key->refcnt = 0;
     415           0 :                 TAILQ_REMOVE(&g_keyring.removed_keys, key, tailq);
     416           0 :                 keyring_free_key(key);
     417             :         }
     418             : 
     419           0 :         TAILQ_FOREACH(module, &g_keyring.modules, tailq) {
     420           0 :                 if (module->cleanup != NULL) {
     421           0 :                         module->cleanup();
     422             :                 }
     423             :         }
     424           0 : }
     425             : 
     426           1 : SPDK_LOG_REGISTER_COMPONENT(keyring)

Generated by: LCOV version 1.15