cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

user_defined.c (4734B)


      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	kfree_sensitive(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	kfree_sensitive(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	kfree_sensitive(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 *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		memcpy(buffer, upayload->data, buflen);
    185	}
    186
    187	return ret;
    188}
    189
    190EXPORT_SYMBOL_GPL(user_read);
    191
    192/* Vet the description for a "logon" key */
    193static int logon_vet_description(const char *desc)
    194{
    195	char *p;
    196
    197	/* require a "qualified" description string */
    198	p = strchr(desc, ':');
    199	if (!p)
    200		return -EINVAL;
    201
    202	/* also reject description with ':' as first char */
    203	if (p == desc)
    204		return -EINVAL;
    205
    206	return 0;
    207}