[9610][ERD] arm64: configs: run savedefconfig
[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);
37cd97e0 232 struct diskcipher_freectrl *fctrl = &cra->freectrl;
2ad5939e
BK
233
234 if (!cra) {
235 pr_err("%s: doesn't exist cra", __func__);
236 ret = EINVAL;
237 goto out;
238 }
239
37cd97e0
BK
240 if (atomic_read(&tfm->status) == DISKC_ST_FREE) {
241 pr_err("%s: tfm is free\n", __func__);
242 crypto_diskcipher_debug(DISKC_CRYPT_WARN, 0);
243 return -EINVAL;
244 }
245
2ad5939e 246 ret = cra->crypt(base, req);
37cd97e0
BK
247
248 if (!list_empty(&fctrl->freelist)) {
249 if (!atomic_read(&fctrl->freewq_active)) {
250 atomic_set(&fctrl->freewq_active, 1);
251 schedule_delayed_work(&fctrl->freewq, 0);
252 }
253 }
2ad5939e
BK
254out:
255 if (ret)
256 pr_err("%s fails ret:%d, cra:%p\n", __func__, ret, cra);
37cd97e0 257 crypto_diskcipher_debug(DISKC_API_CRYPT, ret);
2ad5939e
BK
258 return ret;
259}
260
261int crypto_diskcipher_clear_crypt(struct crypto_diskcipher *tfm, void *req)
262{
263 int ret = 0;
264 struct crypto_tfm *base = crypto_diskcipher_tfm(tfm);
265 struct diskcipher_alg *cra = crypto_diskcipher_alg(base->__crt_alg);
266
267 if (!cra) {
268 pr_err("%s: doesn't exist cra", __func__);
269 ret = EINVAL;
270 goto out;
271 }
272
273 ret = cra->clear(base, req);
274 if (ret)
275 pr_err("%s fails", __func__);
276
277out:
37cd97e0 278 crypto_diskcipher_debug(DISKC_API_CLEAR, ret);
2ad5939e
BK
279 return ret;
280}
281
282#ifndef CONFIG_CRYPTO_MANAGER_DISABLE_TESTS
283int diskcipher_do_crypt(struct crypto_diskcipher *tfm,
284 struct diskcipher_test_request *req)
285{
286 int ret;
287 struct crypto_tfm *base = crypto_diskcipher_tfm(tfm);
288 struct diskcipher_alg *cra = crypto_diskcipher_alg(base->__crt_alg);
289
290 if (!cra) {
291 pr_err("%s: doesn't exist cra", __func__);
292 ret = EINVAL;
293 goto out;
294 }
295
296 if (cra->do_crypt)
297 ret = cra->do_crypt(base, req);
298 else
299 ret = -EINVAL;
300 if (ret)
301 pr_err("%s fails ret:%d", __func__, ret);
302
303out:
2ad5939e
BK
304 return ret;
305}
306#endif
307
37cd97e0 308static int crypto_diskcipher_init_tfm(struct crypto_tfm *base)
2ad5939e 309{
37cd97e0
BK
310 struct crypto_diskcipher *tfm = __crypto_diskcipher_cast(base);
311
312 tfm->req_jiffies = 0;
313 atomic_set(&tfm->status, DISKC_ST_INIT);
2ad5939e
BK
314 return 0;
315}
316
37cd97e0
BK
317static void free_workq_func(struct work_struct *work)
318{
319 struct diskcipher_alg *cra =
320 container_of(work, struct diskcipher_alg, freectrl.freewq.work);
321 struct diskcipher_freectrl *fctrl = &cra->freectrl;
322 struct crypto_diskcipher *_tfm, *tmp;
323 unsigned long cur_jiffies = jiffies;
324 struct list_head poss_free_list;
325 unsigned long flags;
326
327 INIT_LIST_HEAD(&poss_free_list);
328
329 /* pickup freelist */
330 spin_lock_irqsave(&fctrl->freelist_lock, flags);
331 list_for_each_entry_safe(_tfm, tmp, &fctrl->freelist, node) {
332 if (jiffies_to_msecs(cur_jiffies - _tfm->req_jiffies) > fctrl->max_io_ms)
333 list_move_tail(&_tfm->node, &poss_free_list);
334 }
335 spin_unlock_irqrestore(&fctrl->freelist_lock, flags);
336
337 list_for_each_entry_safe(_tfm, tmp, &poss_free_list, node) {
338 if (atomic_read (&_tfm->status) != DISKC_ST_FREE_REQ)
339 crypto_diskcipher_debug(DISKC_FREE_WQ_WARN, 0);
340 crypto_free_diskcipher(_tfm);
341 }
342
343 if (!list_empty(&fctrl->freelist))
344 schedule_delayed_work(&fctrl->freewq, msecs_to_jiffies(fctrl->max_io_ms));
345 else
346 atomic_set(&fctrl->freewq_active, 0);
347}
348
349void crypto_free_req_diskcipher(struct crypto_diskcipher *tfm)
350{
351 struct crypto_tfm *base = crypto_diskcipher_tfm(tfm);
352 struct diskcipher_alg *cra = crypto_diskcipher_alg(base->__crt_alg);
353 struct diskcipher_freectrl *fctrl = &cra->freectrl;
354 unsigned long flags;
355
356 if (atomic_read(&tfm->status) != DISKC_ST_INIT) {
357 crypto_diskcipher_debug(DISKC_FREE_REQ_WARN, 0);
358 pr_warn("%s: already submit status:%d\n", __func__, atomic_read(&tfm->status));
359 return;
360 }
361
362 atomic_set(&tfm->status, DISKC_ST_FREE_REQ);
363 INIT_LIST_HEAD(&tfm->node);
364 tfm->req_jiffies = jiffies;
365 spin_lock_irqsave(&fctrl->freelist_lock, flags);
366 list_move_tail(&tfm->node, &fctrl->freelist);
367 spin_unlock_irqrestore(&fctrl->freelist_lock, flags);
368 crypto_diskcipher_debug(DISKC_API_FREEREQ, 0);
369}
370
2ad5939e
BK
371unsigned int crypto_diskcipher_extsize(struct crypto_alg *alg)
372{
373 return alg->cra_ctxsize +
374 (alg->cra_alignmask & ~(crypto_tfm_ctx_alignment() - 1));
375}
376
377static void crypto_diskcipher_show(struct seq_file *m, struct crypto_alg *alg)
378{
379 seq_printf(m, "type : diskcipher\n");
380 disckipher_log_show(m);
381}
382
383static const struct crypto_type crypto_diskcipher_type = {
384 .extsize = crypto_diskcipher_extsize,
385 .init_tfm = crypto_diskcipher_init_tfm,
386#ifdef CONFIG_PROC_FS
387 .show = crypto_diskcipher_show,
388#endif
389 .maskclear = ~CRYPTO_ALG_TYPE_MASK,
390 .maskset = CRYPTO_ALG_TYPE_MASK,
391 .type = CRYPTO_ALG_TYPE_DISKCIPHER,
392 .tfmsize = offsetof(struct crypto_diskcipher, base),
393};
394
37cd97e0
BK
395#define DISKC_NAME "-disk"
396#define DISKC_NAME_SIZE (5)
397#define DISKCIPHER_MAX_IO_MS (1000)
2ad5939e
BK
398struct crypto_diskcipher *crypto_alloc_diskcipher(const char *alg_name,
399 u32 type, u32 mask, bool force)
400{
37cd97e0 401 crypto_diskcipher_debug(DISKC_API_ALLOC, 0);
2ad5939e
BK
402 if (force) {
403 if (strlen(alg_name) + DISKC_NAME_SIZE < CRYPTO_MAX_ALG_NAME) {
404 char diskc_name[CRYPTO_MAX_ALG_NAME];
405
406 strcpy(diskc_name, alg_name);
407 strcat(diskc_name, DISKC_NAME);
408 return crypto_alloc_tfm(diskc_name,
409 &crypto_diskcipher_type, type, mask);
410 }
411 } else {
412 return crypto_alloc_tfm(alg_name, &crypto_diskcipher_type, type, mask);
413 }
2ad5939e
BK
414 return NULL;
415}
416
417void crypto_free_diskcipher(struct crypto_diskcipher *tfm)
418{
37cd97e0
BK
419 crypto_diskcipher_debug(DISKC_API_FREE, 0);
420 atomic_set(&tfm->status, DISKC_ST_FREE);
2ad5939e
BK
421 crypto_destroy_tfm(tfm, crypto_diskcipher_tfm(tfm));
422}
423
424int crypto_register_diskcipher(struct diskcipher_alg *alg)
425{
426 struct crypto_alg *base = &alg->base;
37cd97e0 427 struct diskcipher_freectrl *fctrl = &alg->freectrl;
2ad5939e 428
37cd97e0
BK
429 INIT_LIST_HEAD(&fctrl->freelist);
430 INIT_DELAYED_WORK(&fctrl->freewq, free_workq_func);
431 spin_lock_init(&fctrl->freelist_lock);
432 if (!fctrl->max_io_ms)
433 fctrl->max_io_ms = DISKCIPHER_MAX_IO_MS;
2ad5939e
BK
434 base->cra_type = &crypto_diskcipher_type;
435 base->cra_flags = CRYPTO_ALG_TYPE_DISKCIPHER;
436 return crypto_register_alg(base);
437}
438
439void crypto_unregister_diskcipher(struct diskcipher_alg *alg)
440{
441 crypto_unregister_alg(&alg->base);
442}
443
444int crypto_register_diskciphers(struct diskcipher_alg *algs, int count)
445{
446 int i, ret;
447
448 for (i = 0; i < count; i++) {
449 ret = crypto_register_diskcipher(algs + i);
450 if (ret)
451 goto err;
452 }
453 return 0;
454
455err:
456 for (--i; i >= 0; --i)
457 crypto_unregister_diskcipher(algs + i);
458 return ret;
459}
460
461void crypto_unregister_diskciphers(struct diskcipher_alg *algs, int count)
462{
463 int i;
464
465 for (i = count - 1; i >= 0; --i)
466 crypto_unregister_diskcipher(algs + i);
467}