FILE
crypto.c
File preview with syntax highlighting.
linux-6.19.14/net/ceph/crypto.c
1// SPDX-License-Identifier: GPL-2.0 2 3#include <linux/ceph/ceph_debug.h> 4 5#include <linux/err.h> 6#include <linux/scatterlist.h> 7#include <linux/sched.h> 8#include <linux/slab.h> 9#include <crypto/aes.h> 10#include <crypto/skcipher.h> 11#include <linux/key-type.h> 12#include <linux/sched/mm.h> 13 14#include <keys/ceph-type.h> 15#include <keys/user-type.h> 16#include <linux/ceph/decode.h> 17#include "crypto.h" 18 19/* 20 * Set ->key and ->tfm. The rest of the key should be filled in before 21 * this function is called. 22 */ 23static int set_secret(struct ceph_crypto_key *key, void *buf) 24{ 25 unsigned int noio_flag; 26 int ret; 27 28 key->key = NULL; 29 key->tfm = NULL; 30 31 switch (key->type) { 32 case CEPH_CRYPTO_NONE: 33 return 0; /* nothing to do */ 34 case CEPH_CRYPTO_AES: 35 break; 36 default: 37 return -ENOTSUPP; 38 } 39 40 key->key = kmemdup(buf, key->len, GFP_NOIO); 41 if (!key->key) { 42 ret = -ENOMEM; 43 goto fail; 44 } 45 46 /* crypto_alloc_sync_skcipher() allocates with GFP_KERNEL */ 47 noio_flag = memalloc_noio_save(); 48 key->tfm = crypto_alloc_sync_skcipher("cbc(aes)", 0, 0); 49 memalloc_noio_restore(noio_flag); 50 if (IS_ERR(key->tfm)) { 51 ret = PTR_ERR(key->tfm); 52 key->tfm = NULL; 53 goto fail; 54 } 55 56 ret = crypto_sync_skcipher_setkey(key->tfm, key->key, key->len); 57 if (ret) 58 goto fail; 59 60 return 0; 61 62fail: 63 ceph_crypto_key_destroy(key); 64 return ret; 65} 66 67int ceph_crypto_key_clone(struct ceph_crypto_key *dst, 68 const struct ceph_crypto_key *src) 69{ 70 memcpy(dst, src, sizeof(struct ceph_crypto_key)); 71 return set_secret(dst, src->key); 72} 73 74int ceph_crypto_key_decode(struct ceph_crypto_key *key, void **p, void *end) 75{ 76 int ret; 77 78 ceph_decode_need(p, end, 2*sizeof(u16) + sizeof(key->created), bad); 79 key->type = ceph_decode_16(p); 80 ceph_decode_copy(p, &key->created, sizeof(key->created)); 81 key->len = ceph_decode_16(p); 82 ceph_decode_need(p, end, key->len, bad); 83 if (key->len > CEPH_MAX_KEY_LEN) { 84 pr_err("secret too big %d\n", key->len); 85 return -EINVAL; 86 } 87 88 ret = set_secret(key, *p); 89 memzero_explicit(*p, key->len); 90 *p += key->len; 91 return ret; 92 93bad: 94 dout("failed to decode crypto key\n"); 95 return -EINVAL; 96} 97 98int ceph_crypto_key_unarmor(struct ceph_crypto_key *key, const char *inkey) 99{ 100 int inlen = strlen(inkey); 101 int blen = inlen * 3 / 4; 102 void *buf, *p; 103 int ret; 104 105 dout("crypto_key_unarmor %s\n", inkey); 106 buf = kmalloc(blen, GFP_NOFS); 107 if (!buf) 108 return -ENOMEM; 109 blen = ceph_unarmor(buf, inkey, inkey+inlen); 110 if (blen < 0) { 111 kfree(buf); 112 return blen; 113 } 114 115 p = buf; 116 ret = ceph_crypto_key_decode(key, &p, p + blen); 117 kfree(buf); 118 if (ret) 119 return ret; 120 dout("crypto_key_unarmor key %p type %d len %d\n", key, 121 key->type, key->len); 122 return 0; 123} 124 125void ceph_crypto_key_destroy(struct ceph_crypto_key *key) 126{ 127 if (key) { 128 kfree_sensitive(key->key); 129 key->key = NULL; 130 if (key->tfm) { 131 crypto_free_sync_skcipher(key->tfm); 132 key->tfm = NULL; 133 } 134 } 135} 136 137static const u8 *aes_iv = (u8 *)CEPH_AES_IV; 138 139/* 140 * Should be used for buffers allocated with kvmalloc(). 141 * Currently these are encrypt out-buffer (ceph_buffer) and decrypt 142 * in-buffer (msg front). 143 * 144 * Dispose of @sgt with teardown_sgtable(). 145 * 146 * @prealloc_sg is to avoid memory allocation inside sg_alloc_table() 147 * in cases where a single sg is sufficient. No attempt to reduce the 148 * number of sgs by squeezing physically contiguous pages together is 149 * made though, for simplicity. 150 */ 151static int setup_sgtable(struct sg_table *sgt, struct scatterlist *prealloc_sg, 152 const void *buf, unsigned int buf_len) 153{ 154 struct scatterlist *sg; 155 const bool is_vmalloc = is_vmalloc_addr(buf); 156 unsigned int off = offset_in_page(buf); 157 unsigned int chunk_cnt = 1; 158 unsigned int chunk_len = PAGE_ALIGN(off + buf_len); 159 int i; 160 int ret; 161 162 if (buf_len == 0) { 163 memset(sgt, 0, sizeof(*sgt)); 164 return -EINVAL; 165 } 166 167 if (is_vmalloc) { 168 chunk_cnt = chunk_len >> PAGE_SHIFT; 169 chunk_len = PAGE_SIZE; 170 } 171 172 if (chunk_cnt > 1) { 173 ret = sg_alloc_table(sgt, chunk_cnt, GFP_NOFS); 174 if (ret) 175 return ret; 176 } else { 177 WARN_ON(chunk_cnt != 1); 178 sg_init_table(prealloc_sg, 1); 179 sgt->sgl = prealloc_sg; 180 sgt->nents = sgt->orig_nents = 1; 181 } 182 183 for_each_sg(sgt->sgl, sg, sgt->orig_nents, i) { 184 struct page *page; 185 unsigned int len = min(chunk_len - off, buf_len); 186 187 if (is_vmalloc) 188 page = vmalloc_to_page(buf); 189 else 190 page = virt_to_page(buf); 191 192 sg_set_page(sg, page, len, off); 193 194 off = 0; 195 buf += len; 196 buf_len -= len; 197 } 198 WARN_ON(buf_len != 0); 199 200 return 0; 201} 202 203static void teardown_sgtable(struct sg_table *sgt) 204{ 205 if (sgt->orig_nents > 1) 206 sg_free_table(sgt); 207} 208 209static int ceph_aes_crypt(const struct ceph_crypto_key *key, bool encrypt, 210 void *buf, int buf_len, int in_len, int *pout_len) 211{ 212 SYNC_SKCIPHER_REQUEST_ON_STACK(req, key->tfm); 213 struct sg_table sgt; 214 struct scatterlist prealloc_sg; 215 char iv[AES_BLOCK_SIZE] __aligned(8); 216 int pad_byte = AES_BLOCK_SIZE - (in_len & (AES_BLOCK_SIZE - 1)); 217 int crypt_len = encrypt ? in_len + pad_byte : in_len; 218 int ret; 219 220 WARN_ON(crypt_len > buf_len); 221 if (encrypt) 222 memset(buf + in_len, pad_byte, pad_byte); 223 ret = setup_sgtable(&sgt, &prealloc_sg, buf, crypt_len); 224 if (ret) 225 return ret; 226 227 memcpy(iv, aes_iv, AES_BLOCK_SIZE); 228 skcipher_request_set_sync_tfm(req, key->tfm); 229 skcipher_request_set_callback(req, 0, NULL, NULL); 230 skcipher_request_set_crypt(req, sgt.sgl, sgt.sgl, crypt_len, iv); 231 232 /* 233 print_hex_dump(KERN_ERR, "key: ", DUMP_PREFIX_NONE, 16, 1, 234 key->key, key->len, 1); 235 print_hex_dump(KERN_ERR, " in: ", DUMP_PREFIX_NONE, 16, 1, 236 buf, crypt_len, 1); 237 */ 238 if (encrypt) 239 ret = crypto_skcipher_encrypt(req); 240 else 241 ret = crypto_skcipher_decrypt(req); 242 skcipher_request_zero(req); 243 if (ret) { 244 pr_err("%s %scrypt failed: %d\n", __func__, 245 encrypt ? "en" : "de", ret); 246 goto out_sgt; 247 } 248 /* 249 print_hex_dump(KERN_ERR, "out: ", DUMP_PREFIX_NONE, 16, 1, 250 buf, crypt_len, 1); 251 */ 252 253 if (encrypt) { 254 *pout_len = crypt_len; 255 } else { 256 pad_byte = *(char *)(buf + in_len - 1); 257 if (pad_byte > 0 && pad_byte <= AES_BLOCK_SIZE && 258 in_len >= pad_byte) { 259 *pout_len = in_len - pad_byte; 260 } else { 261 pr_err("%s got bad padding %d on in_len %d\n", 262 __func__, pad_byte, in_len); 263 ret = -EPERM; 264 goto out_sgt; 265 } 266 } 267 268out_sgt: 269 teardown_sgtable(&sgt); 270 return ret; 271} 272 273int ceph_crypt(const struct ceph_crypto_key *key, bool encrypt, 274 void *buf, int buf_len, int in_len, int *pout_len) 275{ 276 switch (key->type) { 277 case CEPH_CRYPTO_NONE: 278 *pout_len = in_len; 279 return 0; 280 case CEPH_CRYPTO_AES: 281 return ceph_aes_crypt(key, encrypt, buf, buf_len, in_len, 282 pout_len); 283 default: 284 return -ENOTSUPP; 285 } 286} 287 288static int ceph_key_preparse(struct key_preparsed_payload *prep) 289{ 290 struct ceph_crypto_key *ckey; 291 size_t datalen = prep->datalen; 292 int ret; 293 void *p; 294 295 ret = -EINVAL; 296 if (datalen <= 0 || datalen > 32767 || !prep->data) 297 goto err; 298 299 ret = -ENOMEM; 300 ckey = kmalloc(sizeof(*ckey), GFP_KERNEL); 301 if (!ckey) 302 goto err; 303 304 /* TODO ceph_crypto_key_decode should really take const input */ 305 p = (void *)prep->data; 306 ret = ceph_crypto_key_decode(ckey, &p, (char*)prep->data+datalen); 307 if (ret < 0) 308 goto err_ckey; 309 310 prep->payload.data[0] = ckey; 311 prep->quotalen = datalen; 312 return 0; 313 314err_ckey: 315 kfree(ckey); 316err: 317 return ret; 318} 319 320static void ceph_key_free_preparse(struct key_preparsed_payload *prep) 321{ 322 struct ceph_crypto_key *ckey = prep->payload.data[0]; 323 ceph_crypto_key_destroy(ckey); 324 kfree(ckey); 325} 326 327static void ceph_key_destroy(struct key *key) 328{ 329 struct ceph_crypto_key *ckey = key->payload.data[0]; 330 331 ceph_crypto_key_destroy(ckey); 332 kfree(ckey); 333} 334 335struct key_type key_type_ceph = { 336 .name = "ceph", 337 .preparse = ceph_key_preparse, 338 .free_preparse = ceph_key_free_preparse, 339 .instantiate = generic_key_instantiate, 340 .destroy = ceph_key_destroy, 341}; 342 343int __init ceph_crypto_init(void) 344{ 345 return register_key_type(&key_type_ceph); 346} 347 348void ceph_crypto_shutdown(void) 349{ 350 unregister_key_type(&key_type_ceph); 351}
~/
Read-only file preview.