KEYS: Add new function key_create()
authorThomas Weißschuh <linux@weissschuh.net>
Mon, 9 Jan 2023 23:59:42 +0000 (23:59 +0000)
committerJarkko Sakkinen <jarkko@kernel.org>
Mon, 13 Feb 2023 08:11:20 +0000 (10:11 +0200)
key_create() works like key_create_or_update() but does not allow
updating an existing key, instead returning ERR_PTR(-EEXIST).

key_create() will be used by the blacklist keyring which should not
create duplicate entries or update existing entries.
Instead a dedicated message with appropriate severity will be logged.

Signed-off-by: Thomas Weißschuh <linux@weissschuh.net>
Signed-off-by: Jarkko Sakkinen <jarkko@kernel.org>
include/linux/key.h
security/keys/key.c

index d27477faf00d7d837bdf1dd39d7ff58ec44b3535..8dc7f7c3088b9eede68c6eda026ff43b0b20b9ab 100644 (file)
@@ -386,6 +386,14 @@ extern int wait_for_key_construction(struct key *key, bool intr);
 
 extern int key_validate(const struct key *key);
 
+extern key_ref_t key_create(key_ref_t keyring,
+                           const char *type,
+                           const char *description,
+                           const void *payload,
+                           size_t plen,
+                           key_perm_t perm,
+                           unsigned long flags);
+
 extern key_ref_t key_create_or_update(key_ref_t keyring,
                                      const char *type,
                                      const char *description,
index c45afdd1dfbb4fa3dfa01ff927707671186e4b30..5c0c7df833f8a90ff27ef52e889300be1ef954c0 100644 (file)
@@ -788,38 +788,18 @@ error:
        goto out;
 }
 
-/**
- * key_create_or_update - Update or create and instantiate a key.
- * @keyring_ref: A pointer to the destination keyring with possession flag.
- * @type: The type of key.
- * @description: The searchable description for the key.
- * @payload: The data to use to instantiate or update the key.
- * @plen: The length of @payload.
- * @perm: The permissions mask for a new key.
- * @flags: The quota flags for a new key.
- *
- * Search the destination keyring for a key of the same description and if one
- * is found, update it, otherwise create and instantiate a new one and create a
- * link to it from that keyring.
- *
- * If perm is KEY_PERM_UNDEF then an appropriate key permissions mask will be
- * concocted.
- *
- * Returns a pointer to the new key if successful, -ENODEV if the key type
- * wasn't available, -ENOTDIR if the keyring wasn't a keyring, -EACCES if the
- * caller isn't permitted to modify the keyring or the LSM did not permit
- * creation of the key.
- *
- * On success, the possession flag from the keyring ref will be tacked on to
- * the key ref before it is returned.
+/*
+ * Create or potentially update a key. The combined logic behind
+ * key_create_or_update() and key_create()
  */
-key_ref_t key_create_or_update(key_ref_t keyring_ref,
-                              const char *type,
-                              const char *description,
-                              const void *payload,
-                              size_t plen,
-                              key_perm_t perm,
-                              unsigned long flags)
+static key_ref_t __key_create_or_update(key_ref_t keyring_ref,
+                                       const char *type,
+                                       const char *description,
+                                       const void *payload,
+                                       size_t plen,
+                                       key_perm_t perm,
+                                       unsigned long flags,
+                                       bool allow_update)
 {
        struct keyring_index_key index_key = {
                .description    = description,
@@ -906,14 +886,23 @@ key_ref_t key_create_or_update(key_ref_t keyring_ref,
                goto error_link_end;
        }
 
-       /* if it's possible to update this type of key, search for an existing
-        * key of the same type and description in the destination keyring and
-        * update that instead if possible
+       /* if it's requested and possible to update this type of key, search
+        * for an existing key of the same type and description in the
+        * destination keyring and update that instead if possible
         */
-       if (index_key.type->update) {
+       if (allow_update) {
+               if (index_key.type->update) {
+                       key_ref = find_key_to_update(keyring_ref, &index_key);
+                       if (key_ref)
+                               goto found_matching_key;
+               }
+       } else {
                key_ref = find_key_to_update(keyring_ref, &index_key);
-               if (key_ref)
-                       goto found_matching_key;
+               if (key_ref) {
+                       key_ref_put(key_ref);
+                       key_ref = ERR_PTR(-EEXIST);
+                       goto error_link_end;
+               }
        }
 
        /* if the client doesn't provide, decide on the permissions we want */
@@ -985,8 +974,82 @@ error:
 
        goto error_free_prep;
 }
+
+/**
+ * key_create_or_update - Update or create and instantiate a key.
+ * @keyring_ref: A pointer to the destination keyring with possession flag.
+ * @type: The type of key.
+ * @description: The searchable description for the key.
+ * @payload: The data to use to instantiate or update the key.
+ * @plen: The length of @payload.
+ * @perm: The permissions mask for a new key.
+ * @flags: The quota flags for a new key.
+ *
+ * Search the destination keyring for a key of the same description and if one
+ * is found, update it, otherwise create and instantiate a new one and create a
+ * link to it from that keyring.
+ *
+ * If perm is KEY_PERM_UNDEF then an appropriate key permissions mask will be
+ * concocted.
+ *
+ * Returns a pointer to the new key if successful, -ENODEV if the key type
+ * wasn't available, -ENOTDIR if the keyring wasn't a keyring, -EACCES if the
+ * caller isn't permitted to modify the keyring or the LSM did not permit
+ * creation of the key.
+ *
+ * On success, the possession flag from the keyring ref will be tacked on to
+ * the key ref before it is returned.
+ */
+key_ref_t key_create_or_update(key_ref_t keyring_ref,
+                              const char *type,
+                              const char *description,
+                              const void *payload,
+                              size_t plen,
+                              key_perm_t perm,
+                              unsigned long flags)
+{
+       return __key_create_or_update(keyring_ref, type, description, payload,
+                                     plen, perm, flags, true);
+}
 EXPORT_SYMBOL(key_create_or_update);
 
+/**
+ * key_create - Create and instantiate a key.
+ * @keyring_ref: A pointer to the destination keyring with possession flag.
+ * @type: The type of key.
+ * @description: The searchable description for the key.
+ * @payload: The data to use to instantiate or update the key.
+ * @plen: The length of @payload.
+ * @perm: The permissions mask for a new key.
+ * @flags: The quota flags for a new key.
+ *
+ * Create and instantiate a new key and link to it from the destination keyring.
+ *
+ * If perm is KEY_PERM_UNDEF then an appropriate key permissions mask will be
+ * concocted.
+ *
+ * Returns a pointer to the new key if successful, -EEXIST if a key with the
+ * same description already exists, -ENODEV if the key type wasn't available,
+ * -ENOTDIR if the keyring wasn't a keyring, -EACCES if the caller isn't
+ * permitted to modify the keyring or the LSM did not permit creation of the
+ * key.
+ *
+ * On success, the possession flag from the keyring ref will be tacked on to
+ * the key ref before it is returned.
+ */
+key_ref_t key_create(key_ref_t keyring_ref,
+                    const char *type,
+                    const char *description,
+                    const void *payload,
+                    size_t plen,
+                    key_perm_t perm,
+                    unsigned long flags)
+{
+       return __key_create_or_update(keyring_ref, type, description, payload,
+                                     plen, perm, flags, false);
+}
+EXPORT_SYMBOL(key_create);
+
 /**
  * key_update - Update a key's contents.
  * @key_ref: The pointer (plus possession flag) to the key.