1 /* user_defined.c: user defined key type 2 * 3 * Copyright (C) 2004 Red Hat, Inc. All Rights Reserved. 4 * Written by David Howells (dhowells@redhat.com) 5 * 6 * This program is free software; you can redistribute it and/or 7 * modify it under the terms of the GNU General Public License 8 * as published by the Free Software Foundation; either version 9 * 2 of the License, or (at your option) any later version. 10 */ 11 12 #include <linux/module.h> 13 #include <linux/init.h> 14 #include <linux/sched.h> 15 #include <linux/slab.h> 16 #include <linux/seq_file.h> 17 #include <linux/err.h> 18 #include <asm/uaccess.h> 19 #include "internal.h" 20 21 static int user_instantiate(struct key *key, const void *data, size_t datalen); 22 static int user_duplicate(struct key *key, const struct key *source); 23 static int user_update(struct key *key, const void *data, size_t datalen); 24 static int user_match(const struct key *key, const void *criterion); 25 static void user_destroy(struct key *key); 26 static void user_describe(const struct key *user, struct seq_file *m); 27 static long user_read(const struct key *key, 28 char __user *buffer, size_t buflen); 29 30 /* 31 * user defined keys take an arbitrary string as the description and an 32 * arbitrary blob of data as the payload 33 */ 34 struct key_type key_type_user = { 35 .name = "user", 36 .instantiate = user_instantiate, 37 .duplicate = user_duplicate, 38 .update = user_update, 39 .match = user_match, 40 .destroy = user_destroy, 41 .describe = user_describe, 42 .read = user_read, 43 }; 44 45 struct user_key_payload { 46 struct rcu_head rcu; /* RCU destructor */ 47 unsigned short datalen; /* length of this data */ 48 char data[0]; /* actual data */ 49 }; 50 51 EXPORT_SYMBOL_GPL(key_type_user); 52 53 /*****************************************************************************/ 54 /* 55 * instantiate a user defined key 56 */ 57 static int user_instantiate(struct key *key, const void *data, size_t datalen) 58 { 59 struct user_key_payload *upayload; 60 int ret; 61 62 ret = -EINVAL; 63 if (datalen <= 0 || datalen > 32767 || !data) 64 goto error; 65 66 ret = key_payload_reserve(key, datalen); 67 if (ret < 0) 68 goto error; 69 70 ret = -ENOMEM; 71 upayload = kmalloc(sizeof(*upayload) + datalen, GFP_KERNEL); 72 if (!upayload) 73 goto error; 74 75 /* attach the data */ 76 upayload->datalen = datalen; 77 memcpy(upayload->data, data, datalen); 78 rcu_assign_pointer(key->payload.data, upayload); 79 ret = 0; 80 81 error: 82 return ret; 83 84 } /* end user_instantiate() */ 85 86 /*****************************************************************************/ 87 /* 88 * duplicate a user defined key 89 * - both keys' semaphores are locked against further modification 90 * - the new key cannot yet be accessed 91 */ 92 static int user_duplicate(struct key *key, const struct key *source) 93 { 94 struct user_key_payload *upayload, *spayload; 95 int ret; 96 97 /* just copy the payload */ 98 ret = -ENOMEM; 99 upayload = kmalloc(sizeof(*upayload) + source->datalen, GFP_KERNEL); 100 if (upayload) { 101 spayload = rcu_dereference(source->payload.data); 102 BUG_ON(source->datalen != spayload->datalen); 103 104 upayload->datalen = key->datalen = spayload->datalen; 105 memcpy(upayload->data, spayload->data, key->datalen); 106 107 key->payload.data = upayload; 108 ret = 0; 109 } 110 111 return ret; 112 113 } /* end user_duplicate() */ 114 115 /*****************************************************************************/ 116 /* 117 * dispose of the old data from an updated user defined key 118 */ 119 static void user_update_rcu_disposal(struct rcu_head *rcu) 120 { 121 struct user_key_payload *upayload; 122 123 upayload = container_of(rcu, struct user_key_payload, rcu); 124 125 kfree(upayload); 126 127 } /* end user_update_rcu_disposal() */ 128 129 /*****************************************************************************/ 130 /* 131 * update a user defined key 132 * - the key's semaphore is write-locked 133 */ 134 static int user_update(struct key *key, const void *data, size_t datalen) 135 { 136 struct user_key_payload *upayload, *zap; 137 int ret; 138 139 ret = -EINVAL; 140 if (datalen <= 0 || datalen > 32767 || !data) 141 goto error; 142 143 /* construct a replacement payload */ 144 ret = -ENOMEM; 145 upayload = kmalloc(sizeof(*upayload) + datalen, GFP_KERNEL); 146 if (!upayload) 147 goto error; 148 149 upayload->datalen = datalen; 150 memcpy(upayload->data, data, datalen); 151 152 /* check the quota and attach the new data */ 153 zap = upayload; 154 155 ret = key_payload_reserve(key, datalen); 156 157 if (ret == 0) { 158 /* attach the new data, displacing the old */ 159 zap = key->payload.data; 160 rcu_assign_pointer(key->payload.data, upayload); 161 key->expiry = 0; 162 } 163 164 call_rcu(&zap->rcu, user_update_rcu_disposal); 165 166 error: 167 return ret; 168 169 } /* end user_update() */ 170 171 /*****************************************************************************/ 172 /* 173 * match users on their name 174 */ 175 static int user_match(const struct key *key, const void *description) 176 { 177 return strcmp(key->description, description) == 0; 178 179 } /* end user_match() */ 180 181 /*****************************************************************************/ 182 /* 183 * dispose of the data dangling from the corpse of a user 184 */ 185 static void user_destroy(struct key *key) 186 { 187 struct user_key_payload *upayload = key->payload.data; 188 189 kfree(upayload); 190 191 } /* end user_destroy() */ 192 193 /*****************************************************************************/ 194 /* 195 * describe the user key 196 */ 197 static void user_describe(const struct key *key, struct seq_file *m) 198 { 199 seq_puts(m, key->description); 200 201 seq_printf(m, ": %u", key->datalen); 202 203 } /* end user_describe() */ 204 205 /*****************************************************************************/ 206 /* 207 * read the key data 208 * - the key's semaphore is read-locked 209 */ 210 static long user_read(const struct key *key, 211 char __user *buffer, size_t buflen) 212 { 213 struct user_key_payload *upayload; 214 long ret; 215 216 upayload = rcu_dereference(key->payload.data); 217 ret = upayload->datalen; 218 219 /* we can return the data as is */ 220 if (buffer && buflen > 0) { 221 if (buflen > upayload->datalen) 222 buflen = upayload->datalen; 223 224 if (copy_to_user(buffer, upayload->data, buflen) != 0) 225 ret = -EFAULT; 226 } 227 228 return ret; 229 230 } /* end user_read() */ 231