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