1// SPDX-License-Identifier: GPL-2.0
2/*
3 * drivers/hyperhold/hp_device.c
4 *
5 * Copyright (c) 2020-2022 Huawei Technologies Co., Ltd.
6 */
7
8#define pr_fmt(fmt) "[HYPERHOLD]" fmt
9
10#include <linux/random.h>
11#include <linux/blk-crypto.h>
12#include <linux/scatterlist.h>
13#include <linux/version.h>
14
15#include "hp_device.h"
16
17#define HP_CIPHER_MODE BLK_ENCRYPTION_MODE_AES_256_XTS
18#define HP_CIPHER_NAME "xts(aes)"
19#define HP_KEY_SIZE (64)
20#define HP_IV_SIZE (16)
21
22union hp_iv {
23	__le64 index;
24	__le64 dun[BLK_CRYPTO_DUN_ARRAY_SIZE];
25};
26
27void unbind_bdev(struct hp_device *dev)
28{
29	int ret;
30
31	if (!dev->bdev)
32		goto close;
33	if (!dev->old_block_size)
34		goto put;
35	ret = set_blocksize(dev->bdev, dev->old_block_size);
36	if (ret)
37		pr_err("set old block size %d failed, err = %d!\n",
38				dev->old_block_size, ret);
39	dev->old_block_size = 0;
40put:
41	blkdev_put(dev->bdev, FMODE_READ | FMODE_WRITE);
42	dev->bdev = NULL;
43close:
44	if (dev->filp)
45		filp_close(dev->filp, NULL);
46	dev->filp = NULL;
47
48	pr_info("hyperhold bdev unbinded.\n");
49}
50
51bool bind_bdev(struct hp_device *dev, const char *name)
52{
53	struct inode *inode = NULL;
54	int ret;
55
56	dev->filp = filp_open(name, O_RDWR | O_LARGEFILE, 0);
57	if (IS_ERR(dev->filp)) {
58		pr_err("open file %s failed, err = %ld!\n", name, PTR_ERR(dev->filp));
59		dev->filp = NULL;
60		goto err;
61	}
62	inode = dev->filp->f_mapping->host;
63	if (!S_ISBLK(inode->i_mode)) {
64		pr_err("%s is not a block device!\n", name);
65		goto err;
66	}
67#if LINUX_VERSION_CODE >= KERNEL_VERSION(6, 6, 0)
68	dev->bdev = blkdev_get_by_dev(inode->i_rdev, BLK_OPEN_READ | BLK_OPEN_WRITE, dev, NULL);
69#else
70	dev->bdev = blkdev_get_by_dev(inode->i_rdev, FMODE_READ | FMODE_WRITE | FMODE_EXCL, dev);
71#endif
72	if (IS_ERR(dev->bdev)) {
73		ret = PTR_ERR(dev->bdev);
74		dev->bdev = NULL;
75		pr_err("get blkdev %s failed, err = %d!\n", name, ret);
76		goto err;
77	}
78	dev->old_block_size = block_size(dev->bdev);
79	ret = set_blocksize(dev->bdev, PAGE_SIZE);
80	if (ret) {
81		pr_err("set %s block size failed, err = %d!\n", name, ret);
82		goto err;
83	}
84	dev->dev_size = (u64)i_size_read(inode);
85	dev->sec_size = SECTOR_SIZE;
86
87	pr_info("hyperhold bind bdev %s of size %llu / %u succ.\n",
88			name, dev->dev_size, dev->sec_size);
89
90	return true;
91err:
92	unbind_bdev(dev);
93
94	return false;
95}
96
97int soft_crypt_page(struct crypto_skcipher *ctfm, struct page *dst_page,
98		    struct page *src_page, unsigned int op)
99{
100	struct skcipher_request *req = NULL;
101	DECLARE_CRYPTO_WAIT(wait);
102	struct scatterlist dst, src;
103	int ret = 0;
104	union hp_iv iv;
105
106	memset(&iv, 0, sizeof(union hp_iv));
107	iv.index = cpu_to_le64(src_page->index);
108
109	req = skcipher_request_alloc(ctfm, GFP_NOIO);
110	if (!req) {
111		pr_err("alloc skcipher request failed!\n");
112		return -ENOMEM;
113	}
114
115	skcipher_request_set_callback(req, CRYPTO_TFM_REQ_MAY_BACKLOG | CRYPTO_TFM_REQ_MAY_SLEEP,
116			crypto_req_done, &wait);
117	sg_init_table(&dst, 1);
118	sg_set_page(&dst, dst_page, PAGE_SIZE, 0);
119	sg_init_table(&src, 1);
120	sg_set_page(&src, src_page, PAGE_SIZE, 0);
121	skcipher_request_set_crypt(req, &src, &dst, PAGE_SIZE, &iv);
122	if (op == HP_DEV_ENCRYPT)
123		ret = crypto_wait_req(crypto_skcipher_encrypt(req), &wait);
124	else if (op == HP_DEV_DECRYPT)
125		ret = crypto_wait_req(crypto_skcipher_decrypt(req), &wait);
126	else
127		BUG();
128
129	skcipher_request_free(req);
130
131	if (ret)
132		pr_err("%scrypt failed!\n", op == HP_DEV_ENCRYPT ? "en" : "de");
133
134	return ret;
135}
136
137static struct crypto_skcipher *soft_crypto_init(const u8 *key)
138{
139	char *cipher = HP_CIPHER_NAME;
140	u32 key_len = HP_KEY_SIZE;
141	struct crypto_skcipher *ctfm = NULL;
142	int ret;
143
144	ctfm = crypto_alloc_skcipher(cipher, 0, 0);
145	if (IS_ERR(ctfm)) {
146		pr_err("alloc ctfm failed, ret = %ld!\n", PTR_ERR(ctfm));
147		ctfm = NULL;
148		goto err;
149	}
150	crypto_skcipher_clear_flags(ctfm, ~0);
151	crypto_skcipher_set_flags(ctfm, CRYPTO_TFM_REQ_FORBID_WEAK_KEYS);
152	ret = crypto_skcipher_setkey(ctfm, key, key_len);
153	if (ret) {
154		pr_err("ctfm setkey failed, ret = %d!\n", ret);
155		goto err;
156	}
157
158	return ctfm;
159err:
160	if (ctfm)
161		crypto_free_skcipher(ctfm);
162
163	return NULL;
164}
165
166#ifdef CONFIG_BLK_INLINE_ENCRYPTION
167void inline_crypt_bio(struct blk_crypto_key *blk_key, struct bio *bio)
168{
169	union hp_iv iv;
170
171	memset(&iv, 0, sizeof(union hp_iv));
172	iv.index = cpu_to_le64(bio->bi_iter.bi_sector);
173
174	bio_crypt_set_ctx(bio, blk_key, iv.dun, GFP_NOIO);
175}
176
177static struct blk_crypto_key *inline_crypto_init(const u8 *key)
178{
179	struct blk_crypto_key *blk_key = NULL;
180	u32 dun_bytes = HP_IV_SIZE - sizeof(__le64);
181	int ret;
182
183	blk_key = kzalloc(sizeof(struct blk_crypto_key), GFP_KERNEL);
184	if (!blk_key) {
185		pr_err("blk key alloc failed!\n");
186		goto err;
187	}
188	ret = blk_crypto_init_key(blk_key, key, HP_CIPHER_MODE, dun_bytes, PAGE_SIZE);
189	if (ret) {
190		pr_err("blk key init failed, ret = %d!\n", ret);
191		goto err;
192	}
193
194	return blk_key;
195err:
196	if (blk_key)
197		kfree_sensitive(blk_key);
198
199	return NULL;
200}
201#else
202void inline_crypt_bio(struct blk_crypto_key *blk_key, struct bio *bio) {}
203static struct blk_crypto_key *inline_crypto_init(const u8 *key)
204{
205	pr_err("CONFIG_BLK_INLINE_ENCRYPTION is not enabled!\n");
206	return NULL;
207}
208#endif
209
210bool crypto_init(struct hp_device *dev, bool soft)
211{
212	u8 key[HP_KEY_SIZE];
213	bool ret = false;
214
215	get_random_bytes(key, HP_KEY_SIZE);
216	if (soft) {
217		dev->ctfm = soft_crypto_init(key);
218		ret = dev->ctfm;
219	} else {
220		dev->blk_key = inline_crypto_init(key);
221		ret = dev->blk_key;
222		if (ret)
223			pr_warn("soft crypt has been turned off, now apply hard crypt!\n");
224	}
225	memzero_explicit(key, HP_KEY_SIZE);
226
227	return ret;
228}
229
230void crypto_deinit(struct hp_device *dev)
231{
232	if (dev->ctfm) {
233		crypto_free_skcipher(dev->ctfm);
234		dev->ctfm = NULL;
235	}
236	if (dev->blk_key) {
237		kfree_sensitive(dev->blk_key);
238		dev->blk_key = NULL;
239	}
240}
241