Branch data Line data Source code
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 : : 17 : : static 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 : : */ 23 : : struct 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 : : 35 : : EXPORT_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 : : */ 43 : : struct 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 : : }; 54 : : EXPORT_SYMBOL_GPL(key_type_logon); 55 : : 56 : : /* 57 : : * Preparse a user defined key payload 58 : : */ 59 : 3 : int user_preparse(struct key_preparsed_payload *prep) 60 : : { 61 : : struct user_key_payload *upayload; 62 : 3 : size_t datalen = prep->datalen; 63 : : 64 : 3 : if (datalen <= 0 || datalen > 32767 || !prep->data) 65 : : return -EINVAL; 66 : : 67 : 3 : upayload = kmalloc(sizeof(*upayload) + datalen, GFP_KERNEL); 68 : 3 : if (!upayload) 69 : : return -ENOMEM; 70 : : 71 : : /* attach the data */ 72 : 3 : prep->quotalen = datalen; 73 : 3 : prep->payload.data[0] = upayload; 74 : 3 : upayload->datalen = datalen; 75 : 3 : memcpy(upayload->data, prep->data, datalen); 76 : 3 : return 0; 77 : : } 78 : : EXPORT_SYMBOL_GPL(user_preparse); 79 : : 80 : : /* 81 : : * Free a preparse of a user defined key payload 82 : : */ 83 : 3 : void user_free_preparse(struct key_preparsed_payload *prep) 84 : : { 85 : 3 : kzfree(prep->payload.data[0]); 86 : 3 : } 87 : : EXPORT_SYMBOL_GPL(user_free_preparse); 88 : : 89 : 0 : static 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 : 0 : kzfree(payload); 95 : 0 : } 96 : : 97 : : /* 98 : : * update a user defined key 99 : : * - the key's semaphore is write-locked 100 : : */ 101 : 0 : int 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 : 0 : ret = key_payload_reserve(key, prep->datalen); 108 : 0 : if (ret < 0) 109 : : return ret; 110 : : 111 : : /* attach the new data, displacing the old */ 112 : 0 : key->expiry = prep->expiry; 113 : 0 : if (key_is_positive(key)) 114 : 0 : zap = dereference_key_locked(key); 115 : 0 : rcu_assign_keypointer(key, prep->payload.data[0]); 116 : 0 : prep->payload.data[0] = NULL; 117 : : 118 : 0 : if (zap) 119 : 0 : call_rcu(&zap->rcu, user_free_payload_rcu); 120 : : return ret; 121 : : } 122 : : EXPORT_SYMBOL_GPL(user_update); 123 : : 124 : : /* 125 : : * dispose of the links from a revoked keyring 126 : : * - called with the key sem write-locked 127 : : */ 128 : 0 : void user_revoke(struct key *key) 129 : : { 130 : : struct user_key_payload *upayload = user_key_payload_locked(key); 131 : : 132 : : /* clear the quota */ 133 : 0 : key_payload_reserve(key, 0); 134 : : 135 : 0 : if (upayload) { 136 : : rcu_assign_keypointer(key, NULL); 137 : 0 : call_rcu(&upayload->rcu, user_free_payload_rcu); 138 : : } 139 : 0 : } 140 : : 141 : : EXPORT_SYMBOL(user_revoke); 142 : : 143 : : /* 144 : : * dispose of the data dangling from the corpse of a user key 145 : : */ 146 : 3 : void user_destroy(struct key *key) 147 : : { 148 : 3 : struct user_key_payload *upayload = key->payload.data[0]; 149 : : 150 : 3 : kzfree(upayload); 151 : 3 : } 152 : : 153 : : EXPORT_SYMBOL_GPL(user_destroy); 154 : : 155 : : /* 156 : : * describe the user key 157 : : */ 158 : 0 : void user_describe(const struct key *key, struct seq_file *m) 159 : : { 160 : 0 : seq_puts(m, key->description); 161 : 0 : if (key_is_positive(key)) 162 : 0 : seq_printf(m, ": %u", key->datalen); 163 : 0 : } 164 : : 165 : : EXPORT_SYMBOL_GPL(user_describe); 166 : : 167 : : /* 168 : : * read the key data 169 : : * - the key's semaphore is read-locked 170 : : */ 171 : 0 : long 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 : 0 : ret = upayload->datalen; 178 : : 179 : : /* we can return the data as is */ 180 : 0 : if (buffer && buflen > 0) { 181 : 0 : if (buflen > upayload->datalen) 182 : : buflen = upayload->datalen; 183 : : 184 : 0 : memcpy(buffer, upayload->data, buflen); 185 : : } 186 : : 187 : 0 : return ret; 188 : : } 189 : : 190 : : EXPORT_SYMBOL_GPL(user_read); 191 : : 192 : : /* Vet the description for a "logon" key */ 193 : 0 : static int logon_vet_description(const char *desc) 194 : : { 195 : : char *p; 196 : : 197 : : /* require a "qualified" description string */ 198 : 0 : p = strchr(desc, ':'); 199 : 0 : if (!p) 200 : : return -EINVAL; 201 : : 202 : : /* also reject description with ':' as first char */ 203 : 0 : if (p == desc) 204 : : return -EINVAL; 205 : : 206 : 0 : return 0; 207 : : }