linux/security/keys/user_defined.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0-or-later
   2/* user_defined.c: user defined key type
   3 *
   4 * Copyright (C) 2004 Red Hat, Inc. All Rights Reserved.
   5 * Written by David Howells (dhowells@redhat.com)
   6 */
   7
   8#include <linux/export.h>
   9#include <linux/init.h>
  10#include <linux/slab.h>
  11#include <linux/seq_file.h>
  12#include <linux/err.h>
  13#include <keys/user-type.h>
  14#include <linux/uaccess.h>
  15#include "internal.h"
  16
  17static int logon_vet_description(const char *desc);
  18
  19/*
  20 * user defined keys take an arbitrary string as the description and an
  21 * arbitrary blob of data as the payload
  22 */
  23struct key_type key_type_user = {
  24        .name                   = "user",
  25        .preparse               = user_preparse,
  26        .free_preparse          = user_free_preparse,
  27        .instantiate            = generic_key_instantiate,
  28        .update                 = user_update,
  29        .revoke                 = user_revoke,
  30        .destroy                = user_destroy,
  31        .describe               = user_describe,
  32        .read                   = user_read,
  33};
  34
  35EXPORT_SYMBOL_GPL(key_type_user);
  36
  37/*
  38 * This key type is essentially the same as key_type_user, but it does
  39 * not define a .read op. This is suitable for storing username and
  40 * password pairs in the keyring that you do not want to be readable
  41 * from userspace.
  42 */
  43struct key_type key_type_logon = {
  44        .name                   = "logon",
  45        .preparse               = user_preparse,
  46        .free_preparse          = user_free_preparse,
  47        .instantiate            = generic_key_instantiate,
  48        .update                 = user_update,
  49        .revoke                 = user_revoke,
  50        .destroy                = user_destroy,
  51        .describe               = user_describe,
  52        .vet_description        = logon_vet_description,
  53};
  54EXPORT_SYMBOL_GPL(key_type_logon);
  55
  56/*
  57 * Preparse a user defined key payload
  58 */
  59int user_preparse(struct key_preparsed_payload *prep)
  60{
  61        struct user_key_payload *upayload;
  62        size_t datalen = prep->datalen;
  63
  64        if (datalen <= 0 || datalen > 32767 || !prep->data)
  65                return -EINVAL;
  66
  67        upayload = kmalloc(sizeof(*upayload) + datalen, GFP_KERNEL);
  68        if (!upayload)
  69                return -ENOMEM;
  70
  71        /* attach the data */
  72        prep->quotalen = datalen;
  73        prep->payload.data[0] = upayload;
  74        upayload->datalen = datalen;
  75        memcpy(upayload->data, prep->data, datalen);
  76        return 0;
  77}
  78EXPORT_SYMBOL_GPL(user_preparse);
  79
  80/*
  81 * Free a preparse of a user defined key payload
  82 */
  83void user_free_preparse(struct key_preparsed_payload *prep)
  84{
  85        kzfree(prep->payload.data[0]);
  86}
  87EXPORT_SYMBOL_GPL(user_free_preparse);
  88
  89static void user_free_payload_rcu(struct rcu_head *head)
  90{
  91        struct user_key_payload *payload;
  92
  93        payload = container_of(head, struct user_key_payload, rcu);
  94        kzfree(payload);
  95}
  96
  97/*
  98 * update a user defined key
  99 * - the key's semaphore is write-locked
 100 */
 101int user_update(struct key *key, struct key_preparsed_payload *prep)
 102{
 103        struct user_key_payload *zap = NULL;
 104        int ret;
 105
 106        /* check the quota and attach the new data */
 107        ret = key_payload_reserve(key, prep->datalen);
 108        if (ret < 0)
 109                return ret;
 110
 111        /* attach the new data, displacing the old */
 112        key->expiry = prep->expiry;
 113        if (key_is_positive(key))
 114                zap = dereference_key_locked(key);
 115        rcu_assign_keypointer(key, prep->payload.data[0]);
 116        prep->payload.data[0] = NULL;
 117
 118        if (zap)
 119                call_rcu(&zap->rcu, user_free_payload_rcu);
 120        return ret;
 121}
 122EXPORT_SYMBOL_GPL(user_update);
 123
 124/*
 125 * dispose of the links from a revoked keyring
 126 * - called with the key sem write-locked
 127 */
 128void user_revoke(struct key *key)
 129{
 130        struct user_key_payload *upayload = user_key_payload_locked(key);
 131
 132        /* clear the quota */
 133        key_payload_reserve(key, 0);
 134
 135        if (upayload) {
 136                rcu_assign_keypointer(key, NULL);
 137                call_rcu(&upayload->rcu, user_free_payload_rcu);
 138        }
 139}
 140
 141EXPORT_SYMBOL(user_revoke);
 142
 143/*
 144 * dispose of the data dangling from the corpse of a user key
 145 */
 146void user_destroy(struct key *key)
 147{
 148        struct user_key_payload *upayload = key->payload.data[0];
 149
 150        kzfree(upayload);
 151}
 152
 153EXPORT_SYMBOL_GPL(user_destroy);
 154
 155/*
 156 * describe the user key
 157 */
 158void user_describe(const struct key *key, struct seq_file *m)
 159{
 160        seq_puts(m, key->description);
 161        if (key_is_positive(key))
 162                seq_printf(m, ": %u", key->datalen);
 163}
 164
 165EXPORT_SYMBOL_GPL(user_describe);
 166
 167/*
 168 * read the key data
 169 * - the key's semaphore is read-locked
 170 */
 171long user_read(const struct key *key, char __user *buffer, size_t buflen)
 172{
 173        const struct user_key_payload *upayload;
 174        long ret;
 175
 176        upayload = user_key_payload_locked(key);
 177        ret = upayload->datalen;
 178
 179        /* we can return the data as is */
 180        if (buffer && buflen > 0) {
 181                if (buflen > upayload->datalen)
 182                        buflen = upayload->datalen;
 183
 184                if (copy_to_user(buffer, upayload->data, buflen) != 0)
 185                        ret = -EFAULT;
 186        }
 187
 188        return ret;
 189}
 190
 191EXPORT_SYMBOL_GPL(user_read);
 192
 193/* Vet the description for a "logon" key */
 194static int logon_vet_description(const char *desc)
 195{
 196        char *p;
 197
 198        /* require a "qualified" description string */
 199        p = strchr(desc, ':');
 200        if (!p)
 201                return -EINVAL;
 202
 203        /* also reject description with ':' as first char */
 204        if (p == desc)
 205                return -EINVAL;
 206
 207        return 0;
 208}
 209