[RAMEN9610-8702][COMMON] f2fs: support fmp encryption
[GitHub/moto-9609/android_kernel_motorola_exynos9610.git] / crypto / diskcipher.c
CommitLineData
2ad5939e
BK
1/*
2 * Copyright (C) 2017 Samsung Electronics Co., Ltd.
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; either version 2 of the License, or
7 * (at your option) any later version.
8 */
9
10#include <linux/kernel.h>
11#include <linux/blkdev.h>
12#include <linux/errno.h>
13#include <linux/module.h>
14#include <linux/seq_file.h>
15#include <linux/string.h>
16#include <linux/crypto.h>
17#include <crypto/algapi.h>
18#include <crypto/diskcipher.h>
37cd97e0 19#include <linux/delay.h>
2ad5939e
BK
20
21#include "internal.h"
22
37cd97e0
BK
23
24#ifdef CONFIG_CRYPTO_DISKCIPHER_DEBUG
2ad5939e
BK
25#include <crypto/fmp.h>
26#include <linux/mm_types.h>
37cd97e0
BK
27#include <linux/fs.h>
28#include <linux/fscrypt.h>
2ad5939e
BK
29
30#define DUMP_MAX 20
31
2ad5939e
BK
32struct dump_err {
33 struct page *page;
34 struct bio bio;
35 struct fmp_crypto_info ci;
37cd97e0 36 enum diskcipher_dbg api;
2ad5939e
BK
37};
38
39struct diskc_debug_info {
40 struct dump_err dump[DUMP_MAX];
41 int err;
37cd97e0 42 int cnt[DISKC_USER_MAX][2];
2ad5939e
BK
43};
44
45static struct diskc_debug_info diskc_dbg;
46
37cd97e0
BK
47void crypto_diskcipher_debug(enum diskcipher_dbg api, int bi_opf)
48{
49 int idx = 0;
50 struct diskc_debug_info *dbg = &diskc_dbg;
51
52 if (api <= DISKC_API_MAX)
53 dbg->cnt[api][bi_opf]++;
54 else {
55 if (bi_opf & REQ_CRYPT)
56 idx = 1;
57 dbg->cnt[api][idx]++;
58 }
59}
60
2ad5939e
BK
61static void print_err(void)
62{
63 int i, j;
64 struct bio_vec *bv; /* bio page list */
65 struct bio *bio;
66 struct fmp_crypto_info *ci;
67 struct diskc_debug_info *dbg = &diskc_dbg;
68
69 for (j = 0; j < dbg->err; j++) {
70 bio = &dbg->dump[j].bio;
71 ci = &dbg->dump[j].ci;
72
73 if (bio) {
74 pr_info
75 ("%s(%d/%d): bio:%p ci:%p page:%p flag:%x, opf:%x, crypt:%p\n",
76 __func__, j, dbg->err, bio, ci, &dbg->dump[j].page,
77 bio->bi_flags, bio->bi_opf, bio->bi_aux_private);
78 print_hex_dump(KERN_CONT, "bio:", DUMP_PREFIX_OFFSET,
79 16, 1, bio, sizeof(struct bio), false);
80 for (i = 0; i < bio->bi_max_vecs; i++) {
81 bv = &bio->bi_io_vec[i];
82 pr_info("bv[%d] page:%p len:%d offset:%d\n",
83 i, bv->bv_page, bv->bv_len, bv->bv_offset);
84 }
85 }
86
87 if (ci) {
88 pr_info("[ci] key_size:%d algo_mode:%d\n",
89 ci->key_size, ci->algo_mode);
90 print_hex_dump(KERN_CONT, "key:", DUMP_PREFIX_OFFSET,
91 16, 1, ci->key, sizeof(ci->key), false);
92 }
93 }
94}
95
37cd97e0 96static void dump_err(struct crypto_diskcipher *ci, enum diskcipher_dbg api,
2ad5939e
BK
97 struct bio *bio, struct page *page)
98{
99 struct diskc_debug_info *dbg = &diskc_dbg;
100
101 if ((dbg->err < DUMP_MAX) && ci) {
102 struct crypto_tfm *tfm = crypto_diskcipher_tfm(ci);
103
104 dbg->dump[dbg->err].api = api;
105 memcpy(&dbg->dump[dbg->err].ci, crypto_tfm_ctx(tfm),
106 sizeof(struct fmp_crypto_info));
107
108 if (page)
109 dbg->dump[dbg->err].page = page;
110 if (bio)
111 memcpy(&dbg->dump[dbg->err].bio, bio,
112 sizeof(struct bio));
113 }
114 dbg->err++;
115}
116
2ad5939e
BK
117static void disckipher_log_show(struct seq_file *m)
118{
119 int i;
2ad5939e 120 struct diskc_debug_info *dbg = &diskc_dbg;
37cd97e0
BK
121 char name[DISKC_USER_MAX][20]
122 = {"alloc", "free", "freereq", "setkey", "set", "get",
123 "crypt", "clear", "null", "page-io", "readpage", "dio",
124 "blk_write", "zeropage", "bufferhead",
125 "dmcrypt", "merge", "diskc_check_err", "fs_dec_warn",
126 "fs_enc_warn", "diskc_merge_dio", "diskc_freereq_warn",
127 "diskc_freewq_warn", "disk_crypt_warn"};
128
129 for (i = 0; i < DISKC_USER_MAX; i++)
130 if (dbg->cnt[i][0] || dbg->cnt[i][1])
131 seq_printf(m, "%s\t: %6u(err:%u)\n",
132 name[i], dbg->cnt[i][0], dbg->cnt[i][1]);
2ad5939e
BK
133
134 if (dbg->err)
135 print_err();
136}
137
138/* check diskcipher for FBE */
37cd97e0
BK
139#define DISKC_FS_ENCRYPT_DEBUG
140void crypto_diskcipher_check(struct bio *bio)
2ad5939e 141{
37cd97e0 142#ifdef DISKC_FS_ENCRYPT_DEBUG
2ad5939e
BK
143 int ret = 0;
144 struct crypto_diskcipher *ci = NULL;
37cd97e0
BK
145 struct inode *inode = NULL;
146 struct page *page = bio->bi_io_vec[0].bv_page;
2ad5939e
BK
147
148 if (page && !PageAnon(page) && bio)
149 if (page->mapping)
150 if (page->mapping->host)
151 if (page->mapping->host->i_crypt_info) {
37cd97e0
BK
152 inode = page->mapping->host;
153 ci = fscrypt_get_diskcipher(page->mapping->host);
2ad5939e
BK
154 if (ci && (bio->bi_aux_private != ci)
155 && (!(bio->bi_flags & REQ_OP_DISCARD))) {
156 dump_err(ci, DISKC_API_GET, bio, page);
157 ret = 1;
37cd97e0
BK
158 crypto_diskcipher_debug(DISKC_CHECK_ERR, 0);
159 }
160 if (!inode->i_crypt_info || !ci) {
161 ret = 1;
162 crypto_diskcipher_debug(DISKC_CHECK_ERR, 1);
2ad5939e
BK
163 }
164 }
37cd97e0 165 crypto_diskcipher_debug(DISKC_API_GET, ret);
2ad5939e
BK
166#endif
167}
168#else
2ad5939e 169#define disckipher_log_show(a) do { } while (0)
2ad5939e
BK
170#endif
171
2ad5939e
BK
172struct crypto_diskcipher *crypto_diskcipher_get(struct bio *bio)
173{
174 if (!bio || !virt_addr_valid(bio)) {
175 pr_err("%s: Invalid bio:%p\n", __func__, bio);
176 return NULL;
177 }
178 if (bio->bi_opf & REQ_CRYPT)
179 return bio->bi_aux_private;
180 else
181 return NULL;
182}
183
184void crypto_diskcipher_set(struct bio *bio,
37cd97e0 185 struct crypto_diskcipher *tfm)
2ad5939e 186{
37cd97e0 187 if (bio && tfm) {
2ad5939e 188 bio->bi_opf |= (REQ_CRYPT | REQ_AUX_PRIV);
37cd97e0 189 bio->bi_aux_private = tfm;
2ad5939e 190 }
37cd97e0 191 crypto_diskcipher_debug(DISKC_API_SET, 0);
2ad5939e
BK
192}
193
37cd97e0
BK
194/* debug freerq */
195enum diskc_status {
196 DISKC_ST_INIT,
197 DISKC_ST_FREE_REQ,
198 DISKC_ST_FREE,
199};
2ad5939e
BK
200int crypto_diskcipher_setkey(struct crypto_diskcipher *tfm, const char *in_key,
201 unsigned int key_len, bool persistent)
202{
203 struct crypto_tfm *base = crypto_diskcipher_tfm(tfm);
204 struct diskcipher_alg *cra = crypto_diskcipher_alg(base->__crt_alg);
205
206 if (!cra) {
207 pr_err("%s: doesn't exist cra", __func__);
208 return -EINVAL;
209 }
37cd97e0
BK
210
211 crypto_diskcipher_debug(DISKC_API_SETKEY, 0);
2ad5939e
BK
212 return cra->setkey(base, in_key, key_len, persistent);
213}
214
215int crypto_diskcipher_clearkey(struct crypto_diskcipher *tfm)
216{
217 struct crypto_tfm *base = crypto_diskcipher_tfm(tfm);
218 struct diskcipher_alg *cra = crypto_diskcipher_alg(base->__crt_alg);
219
220 if (!cra) {
221 pr_err("%s: doesn't exist cra", __func__);
222 return -EINVAL;
223 }
224 return cra->clearkey(base);
225}
226
227int crypto_diskcipher_set_crypt(struct crypto_diskcipher *tfm, void *req)
228{
229 int ret = 0;
230 struct crypto_tfm *base = crypto_diskcipher_tfm(tfm);
231 struct diskcipher_alg *cra = crypto_diskcipher_alg(base->__crt_alg);
232
233 if (!cra) {
234 pr_err("%s: doesn't exist cra", __func__);
235 ret = EINVAL;
236 goto out;
237 }
238
37cd97e0
BK
239 if (atomic_read(&tfm->status) == DISKC_ST_FREE) {
240 pr_err("%s: tfm is free\n", __func__);
241 crypto_diskcipher_debug(DISKC_CRYPT_WARN, 0);
242 return -EINVAL;
243 }
244
2ad5939e 245 ret = cra->crypt(base, req);
37cd97e0 246
91b23ddd
BK
247#ifdef USE_FREE_REQ
248 if (!list_empty(&cra->freectrl.freelist)) {
249 if (!atomic_read(&cra->freectrl.freewq_active)) {
250 atomic_set(&cra->freectrl.freewq_active, 1);
251 schedule_delayed_work(&cra->freectrl.freewq, 0);
37cd97e0
BK
252 }
253 }
91b23ddd 254#endif
2ad5939e
BK
255out:
256 if (ret)
257 pr_err("%s fails ret:%d, cra:%p\n", __func__, ret, cra);
37cd97e0 258 crypto_diskcipher_debug(DISKC_API_CRYPT, ret);
2ad5939e
BK
259 return ret;
260}
261
262int crypto_diskcipher_clear_crypt(struct crypto_diskcipher *tfm, void *req)
263{
264 int ret = 0;
265 struct crypto_tfm *base = crypto_diskcipher_tfm(tfm);
266 struct diskcipher_alg *cra = crypto_diskcipher_alg(base->__crt_alg);
267
268 if (!cra) {
269 pr_err("%s: doesn't exist cra", __func__);
270 ret = EINVAL;
271 goto out;
272 }
273
274 ret = cra->clear(base, req);
275 if (ret)
276 pr_err("%s fails", __func__);
277
278out:
37cd97e0 279 crypto_diskcipher_debug(DISKC_API_CLEAR, ret);
2ad5939e
BK
280 return ret;
281}
282
283#ifndef CONFIG_CRYPTO_MANAGER_DISABLE_TESTS
284int diskcipher_do_crypt(struct crypto_diskcipher *tfm,
285 struct diskcipher_test_request *req)
286{
287 int ret;
288 struct crypto_tfm *base = crypto_diskcipher_tfm(tfm);
289 struct diskcipher_alg *cra = crypto_diskcipher_alg(base->__crt_alg);
290
291 if (!cra) {
292 pr_err("%s: doesn't exist cra", __func__);
293 ret = EINVAL;
294 goto out;
295 }
296
297 if (cra->do_crypt)
298 ret = cra->do_crypt(base, req);
299 else
300 ret = -EINVAL;
301 if (ret)
302 pr_err("%s fails ret:%d", __func__, ret);
303
304out:
2ad5939e
BK
305 return ret;
306}
307#endif
308
37cd97e0 309static int crypto_diskcipher_init_tfm(struct crypto_tfm *base)
2ad5939e 310{
37cd97e0
BK
311 struct crypto_diskcipher *tfm = __crypto_diskcipher_cast(base);
312
37cd97e0 313 atomic_set(&tfm->status, DISKC_ST_INIT);
2ad5939e
BK
314 return 0;
315}
316
91b23ddd 317#ifdef USE_FREE_REQ
37cd97e0
BK
318static void free_workq_func(struct work_struct *work)
319{
320 struct diskcipher_alg *cra =
321 container_of(work, struct diskcipher_alg, freectrl.freewq.work);
322 struct diskcipher_freectrl *fctrl = &cra->freectrl;
323 struct crypto_diskcipher *_tfm, *tmp;
324 unsigned long cur_jiffies = jiffies;
325 struct list_head poss_free_list;
326 unsigned long flags;
327
328 INIT_LIST_HEAD(&poss_free_list);
329
330 /* pickup freelist */
331 spin_lock_irqsave(&fctrl->freelist_lock, flags);
332 list_for_each_entry_safe(_tfm, tmp, &fctrl->freelist, node) {
333 if (jiffies_to_msecs(cur_jiffies - _tfm->req_jiffies) > fctrl->max_io_ms)
334 list_move_tail(&_tfm->node, &poss_free_list);
335 }
336 spin_unlock_irqrestore(&fctrl->freelist_lock, flags);
337
338 list_for_each_entry_safe(_tfm, tmp, &poss_free_list, node) {
339 if (atomic_read (&_tfm->status) != DISKC_ST_FREE_REQ)
340 crypto_diskcipher_debug(DISKC_FREE_WQ_WARN, 0);
341 crypto_free_diskcipher(_tfm);
342 }
343
344 if (!list_empty(&fctrl->freelist))
345 schedule_delayed_work(&fctrl->freewq, msecs_to_jiffies(fctrl->max_io_ms));
346 else
347 atomic_set(&fctrl->freewq_active, 0);
348}
91b23ddd 349#endif
37cd97e0
BK
350
351void crypto_free_req_diskcipher(struct crypto_diskcipher *tfm)
352{
91b23ddd 353#ifdef USE_FREE_REQ
37cd97e0
BK
354 struct crypto_tfm *base = crypto_diskcipher_tfm(tfm);
355 struct diskcipher_alg *cra = crypto_diskcipher_alg(base->__crt_alg);
356 struct diskcipher_freectrl *fctrl = &cra->freectrl;
357 unsigned long flags;
358
359 if (atomic_read(&tfm->status) != DISKC_ST_INIT) {
360 crypto_diskcipher_debug(DISKC_FREE_REQ_WARN, 0);
361 pr_warn("%s: already submit status:%d\n", __func__, atomic_read(&tfm->status));
362 return;
363 }
364
365 atomic_set(&tfm->status, DISKC_ST_FREE_REQ);
366 INIT_LIST_HEAD(&tfm->node);
367 tfm->req_jiffies = jiffies;
368 spin_lock_irqsave(&fctrl->freelist_lock, flags);
369 list_move_tail(&tfm->node, &fctrl->freelist);
370 spin_unlock_irqrestore(&fctrl->freelist_lock, flags);
371 crypto_diskcipher_debug(DISKC_API_FREEREQ, 0);
91b23ddd
BK
372#else
373 crypto_free_diskcipher(tfm);
374#endif
37cd97e0
BK
375}
376
2ad5939e
BK
377unsigned int crypto_diskcipher_extsize(struct crypto_alg *alg)
378{
379 return alg->cra_ctxsize +
380 (alg->cra_alignmask & ~(crypto_tfm_ctx_alignment() - 1));
381}
382
383static void crypto_diskcipher_show(struct seq_file *m, struct crypto_alg *alg)
384{
385 seq_printf(m, "type : diskcipher\n");
386 disckipher_log_show(m);
387}
388
389static const struct crypto_type crypto_diskcipher_type = {
390 .extsize = crypto_diskcipher_extsize,
391 .init_tfm = crypto_diskcipher_init_tfm,
392#ifdef CONFIG_PROC_FS
393 .show = crypto_diskcipher_show,
394#endif
395 .maskclear = ~CRYPTO_ALG_TYPE_MASK,
396 .maskset = CRYPTO_ALG_TYPE_MASK,
397 .type = CRYPTO_ALG_TYPE_DISKCIPHER,
398 .tfmsize = offsetof(struct crypto_diskcipher, base),
399};
400
37cd97e0
BK
401#define DISKC_NAME "-disk"
402#define DISKC_NAME_SIZE (5)
403#define DISKCIPHER_MAX_IO_MS (1000)
2ad5939e
BK
404struct crypto_diskcipher *crypto_alloc_diskcipher(const char *alg_name,
405 u32 type, u32 mask, bool force)
406{
37cd97e0 407 crypto_diskcipher_debug(DISKC_API_ALLOC, 0);
2ad5939e
BK
408 if (force) {
409 if (strlen(alg_name) + DISKC_NAME_SIZE < CRYPTO_MAX_ALG_NAME) {
410 char diskc_name[CRYPTO_MAX_ALG_NAME];
411
412 strcpy(diskc_name, alg_name);
413 strcat(diskc_name, DISKC_NAME);
414 return crypto_alloc_tfm(diskc_name,
415 &crypto_diskcipher_type, type, mask);
416 }
417 } else {
418 return crypto_alloc_tfm(alg_name, &crypto_diskcipher_type, type, mask);
419 }
2ad5939e
BK
420 return NULL;
421}
422
423void crypto_free_diskcipher(struct crypto_diskcipher *tfm)
424{
37cd97e0
BK
425 crypto_diskcipher_debug(DISKC_API_FREE, 0);
426 atomic_set(&tfm->status, DISKC_ST_FREE);
2ad5939e
BK
427 crypto_destroy_tfm(tfm, crypto_diskcipher_tfm(tfm));
428}
429
430int crypto_register_diskcipher(struct diskcipher_alg *alg)
431{
432 struct crypto_alg *base = &alg->base;
91b23ddd
BK
433
434#ifdef USE_FREE_REQ
37cd97e0 435 struct diskcipher_freectrl *fctrl = &alg->freectrl;
2ad5939e 436
37cd97e0
BK
437 INIT_LIST_HEAD(&fctrl->freelist);
438 INIT_DELAYED_WORK(&fctrl->freewq, free_workq_func);
439 spin_lock_init(&fctrl->freelist_lock);
440 if (!fctrl->max_io_ms)
441 fctrl->max_io_ms = DISKCIPHER_MAX_IO_MS;
91b23ddd 442#endif
2ad5939e
BK
443 base->cra_type = &crypto_diskcipher_type;
444 base->cra_flags = CRYPTO_ALG_TYPE_DISKCIPHER;
445 return crypto_register_alg(base);
446}
447
448void crypto_unregister_diskcipher(struct diskcipher_alg *alg)
449{
450 crypto_unregister_alg(&alg->base);
451}
452
453int crypto_register_diskciphers(struct diskcipher_alg *algs, int count)
454{
455 int i, ret;
456
457 for (i = 0; i < count; i++) {
458 ret = crypto_register_diskcipher(algs + i);
459 if (ret)
460 goto err;
461 }
462 return 0;
463
464err:
465 for (--i; i >= 0; --i)
466 crypto_unregister_diskcipher(algs + i);
467 return ret;
468}
469
470void crypto_unregister_diskciphers(struct diskcipher_alg *algs, int count)
471{
472 int i;
473
474 for (i = count - 1; i >= 0; --i)
475 crypto_unregister_diskcipher(algs + i);
476}