162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later 262306a36Sopenharmony_ci/* user_defined.c: user defined key type 362306a36Sopenharmony_ci * 462306a36Sopenharmony_ci * Copyright (C) 2004 Red Hat, Inc. All Rights Reserved. 562306a36Sopenharmony_ci * Written by David Howells (dhowells@redhat.com) 662306a36Sopenharmony_ci */ 762306a36Sopenharmony_ci 862306a36Sopenharmony_ci#include <linux/export.h> 962306a36Sopenharmony_ci#include <linux/init.h> 1062306a36Sopenharmony_ci#include <linux/slab.h> 1162306a36Sopenharmony_ci#include <linux/seq_file.h> 1262306a36Sopenharmony_ci#include <linux/err.h> 1362306a36Sopenharmony_ci#include <keys/user-type.h> 1462306a36Sopenharmony_ci#include <linux/uaccess.h> 1562306a36Sopenharmony_ci#include "internal.h" 1662306a36Sopenharmony_ci 1762306a36Sopenharmony_cistatic int logon_vet_description(const char *desc); 1862306a36Sopenharmony_ci 1962306a36Sopenharmony_ci/* 2062306a36Sopenharmony_ci * user defined keys take an arbitrary string as the description and an 2162306a36Sopenharmony_ci * arbitrary blob of data as the payload 2262306a36Sopenharmony_ci */ 2362306a36Sopenharmony_cistruct key_type key_type_user = { 2462306a36Sopenharmony_ci .name = "user", 2562306a36Sopenharmony_ci .preparse = user_preparse, 2662306a36Sopenharmony_ci .free_preparse = user_free_preparse, 2762306a36Sopenharmony_ci .instantiate = generic_key_instantiate, 2862306a36Sopenharmony_ci .update = user_update, 2962306a36Sopenharmony_ci .revoke = user_revoke, 3062306a36Sopenharmony_ci .destroy = user_destroy, 3162306a36Sopenharmony_ci .describe = user_describe, 3262306a36Sopenharmony_ci .read = user_read, 3362306a36Sopenharmony_ci}; 3462306a36Sopenharmony_ci 3562306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(key_type_user); 3662306a36Sopenharmony_ci 3762306a36Sopenharmony_ci/* 3862306a36Sopenharmony_ci * This key type is essentially the same as key_type_user, but it does 3962306a36Sopenharmony_ci * not define a .read op. This is suitable for storing username and 4062306a36Sopenharmony_ci * password pairs in the keyring that you do not want to be readable 4162306a36Sopenharmony_ci * from userspace. 4262306a36Sopenharmony_ci */ 4362306a36Sopenharmony_cistruct key_type key_type_logon = { 4462306a36Sopenharmony_ci .name = "logon", 4562306a36Sopenharmony_ci .preparse = user_preparse, 4662306a36Sopenharmony_ci .free_preparse = user_free_preparse, 4762306a36Sopenharmony_ci .instantiate = generic_key_instantiate, 4862306a36Sopenharmony_ci .update = user_update, 4962306a36Sopenharmony_ci .revoke = user_revoke, 5062306a36Sopenharmony_ci .destroy = user_destroy, 5162306a36Sopenharmony_ci .describe = user_describe, 5262306a36Sopenharmony_ci .vet_description = logon_vet_description, 5362306a36Sopenharmony_ci}; 5462306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(key_type_logon); 5562306a36Sopenharmony_ci 5662306a36Sopenharmony_ci/* 5762306a36Sopenharmony_ci * Preparse a user defined key payload 5862306a36Sopenharmony_ci */ 5962306a36Sopenharmony_ciint user_preparse(struct key_preparsed_payload *prep) 6062306a36Sopenharmony_ci{ 6162306a36Sopenharmony_ci struct user_key_payload *upayload; 6262306a36Sopenharmony_ci size_t datalen = prep->datalen; 6362306a36Sopenharmony_ci 6462306a36Sopenharmony_ci if (datalen <= 0 || datalen > 32767 || !prep->data) 6562306a36Sopenharmony_ci return -EINVAL; 6662306a36Sopenharmony_ci 6762306a36Sopenharmony_ci upayload = kmalloc(sizeof(*upayload) + datalen, GFP_KERNEL); 6862306a36Sopenharmony_ci if (!upayload) 6962306a36Sopenharmony_ci return -ENOMEM; 7062306a36Sopenharmony_ci 7162306a36Sopenharmony_ci /* attach the data */ 7262306a36Sopenharmony_ci prep->quotalen = datalen; 7362306a36Sopenharmony_ci prep->payload.data[0] = upayload; 7462306a36Sopenharmony_ci upayload->datalen = datalen; 7562306a36Sopenharmony_ci memcpy(upayload->data, prep->data, datalen); 7662306a36Sopenharmony_ci return 0; 7762306a36Sopenharmony_ci} 7862306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(user_preparse); 7962306a36Sopenharmony_ci 8062306a36Sopenharmony_ci/* 8162306a36Sopenharmony_ci * Free a preparse of a user defined key payload 8262306a36Sopenharmony_ci */ 8362306a36Sopenharmony_civoid user_free_preparse(struct key_preparsed_payload *prep) 8462306a36Sopenharmony_ci{ 8562306a36Sopenharmony_ci kfree_sensitive(prep->payload.data[0]); 8662306a36Sopenharmony_ci} 8762306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(user_free_preparse); 8862306a36Sopenharmony_ci 8962306a36Sopenharmony_cistatic void user_free_payload_rcu(struct rcu_head *head) 9062306a36Sopenharmony_ci{ 9162306a36Sopenharmony_ci struct user_key_payload *payload; 9262306a36Sopenharmony_ci 9362306a36Sopenharmony_ci payload = container_of(head, struct user_key_payload, rcu); 9462306a36Sopenharmony_ci kfree_sensitive(payload); 9562306a36Sopenharmony_ci} 9662306a36Sopenharmony_ci 9762306a36Sopenharmony_ci/* 9862306a36Sopenharmony_ci * update a user defined key 9962306a36Sopenharmony_ci * - the key's semaphore is write-locked 10062306a36Sopenharmony_ci */ 10162306a36Sopenharmony_ciint user_update(struct key *key, struct key_preparsed_payload *prep) 10262306a36Sopenharmony_ci{ 10362306a36Sopenharmony_ci struct user_key_payload *zap = NULL; 10462306a36Sopenharmony_ci int ret; 10562306a36Sopenharmony_ci 10662306a36Sopenharmony_ci /* check the quota and attach the new data */ 10762306a36Sopenharmony_ci ret = key_payload_reserve(key, prep->datalen); 10862306a36Sopenharmony_ci if (ret < 0) 10962306a36Sopenharmony_ci return ret; 11062306a36Sopenharmony_ci 11162306a36Sopenharmony_ci /* attach the new data, displacing the old */ 11262306a36Sopenharmony_ci key->expiry = prep->expiry; 11362306a36Sopenharmony_ci if (key_is_positive(key)) 11462306a36Sopenharmony_ci zap = dereference_key_locked(key); 11562306a36Sopenharmony_ci rcu_assign_keypointer(key, prep->payload.data[0]); 11662306a36Sopenharmony_ci prep->payload.data[0] = NULL; 11762306a36Sopenharmony_ci 11862306a36Sopenharmony_ci if (zap) 11962306a36Sopenharmony_ci call_rcu(&zap->rcu, user_free_payload_rcu); 12062306a36Sopenharmony_ci return ret; 12162306a36Sopenharmony_ci} 12262306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(user_update); 12362306a36Sopenharmony_ci 12462306a36Sopenharmony_ci/* 12562306a36Sopenharmony_ci * dispose of the links from a revoked keyring 12662306a36Sopenharmony_ci * - called with the key sem write-locked 12762306a36Sopenharmony_ci */ 12862306a36Sopenharmony_civoid user_revoke(struct key *key) 12962306a36Sopenharmony_ci{ 13062306a36Sopenharmony_ci struct user_key_payload *upayload = user_key_payload_locked(key); 13162306a36Sopenharmony_ci 13262306a36Sopenharmony_ci /* clear the quota */ 13362306a36Sopenharmony_ci key_payload_reserve(key, 0); 13462306a36Sopenharmony_ci 13562306a36Sopenharmony_ci if (upayload) { 13662306a36Sopenharmony_ci rcu_assign_keypointer(key, NULL); 13762306a36Sopenharmony_ci call_rcu(&upayload->rcu, user_free_payload_rcu); 13862306a36Sopenharmony_ci } 13962306a36Sopenharmony_ci} 14062306a36Sopenharmony_ci 14162306a36Sopenharmony_ciEXPORT_SYMBOL(user_revoke); 14262306a36Sopenharmony_ci 14362306a36Sopenharmony_ci/* 14462306a36Sopenharmony_ci * dispose of the data dangling from the corpse of a user key 14562306a36Sopenharmony_ci */ 14662306a36Sopenharmony_civoid user_destroy(struct key *key) 14762306a36Sopenharmony_ci{ 14862306a36Sopenharmony_ci struct user_key_payload *upayload = key->payload.data[0]; 14962306a36Sopenharmony_ci 15062306a36Sopenharmony_ci kfree_sensitive(upayload); 15162306a36Sopenharmony_ci} 15262306a36Sopenharmony_ci 15362306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(user_destroy); 15462306a36Sopenharmony_ci 15562306a36Sopenharmony_ci/* 15662306a36Sopenharmony_ci * describe the user key 15762306a36Sopenharmony_ci */ 15862306a36Sopenharmony_civoid user_describe(const struct key *key, struct seq_file *m) 15962306a36Sopenharmony_ci{ 16062306a36Sopenharmony_ci seq_puts(m, key->description); 16162306a36Sopenharmony_ci if (key_is_positive(key)) 16262306a36Sopenharmony_ci seq_printf(m, ": %u", key->datalen); 16362306a36Sopenharmony_ci} 16462306a36Sopenharmony_ci 16562306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(user_describe); 16662306a36Sopenharmony_ci 16762306a36Sopenharmony_ci/* 16862306a36Sopenharmony_ci * read the key data 16962306a36Sopenharmony_ci * - the key's semaphore is read-locked 17062306a36Sopenharmony_ci */ 17162306a36Sopenharmony_cilong user_read(const struct key *key, char *buffer, size_t buflen) 17262306a36Sopenharmony_ci{ 17362306a36Sopenharmony_ci const struct user_key_payload *upayload; 17462306a36Sopenharmony_ci long ret; 17562306a36Sopenharmony_ci 17662306a36Sopenharmony_ci upayload = user_key_payload_locked(key); 17762306a36Sopenharmony_ci ret = upayload->datalen; 17862306a36Sopenharmony_ci 17962306a36Sopenharmony_ci /* we can return the data as is */ 18062306a36Sopenharmony_ci if (buffer && buflen > 0) { 18162306a36Sopenharmony_ci if (buflen > upayload->datalen) 18262306a36Sopenharmony_ci buflen = upayload->datalen; 18362306a36Sopenharmony_ci 18462306a36Sopenharmony_ci memcpy(buffer, upayload->data, buflen); 18562306a36Sopenharmony_ci } 18662306a36Sopenharmony_ci 18762306a36Sopenharmony_ci return ret; 18862306a36Sopenharmony_ci} 18962306a36Sopenharmony_ci 19062306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(user_read); 19162306a36Sopenharmony_ci 19262306a36Sopenharmony_ci/* Vet the description for a "logon" key */ 19362306a36Sopenharmony_cistatic int logon_vet_description(const char *desc) 19462306a36Sopenharmony_ci{ 19562306a36Sopenharmony_ci char *p; 19662306a36Sopenharmony_ci 19762306a36Sopenharmony_ci /* require a "qualified" description string */ 19862306a36Sopenharmony_ci p = strchr(desc, ':'); 19962306a36Sopenharmony_ci if (!p) 20062306a36Sopenharmony_ci return -EINVAL; 20162306a36Sopenharmony_ci 20262306a36Sopenharmony_ci /* also reject description with ':' as first char */ 20362306a36Sopenharmony_ci if (p == desc) 20462306a36Sopenharmony_ci return -EINVAL; 20562306a36Sopenharmony_ci 20662306a36Sopenharmony_ci return 0; 20762306a36Sopenharmony_ci} 208