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
22 union hp_iv {
23 __le64 index;
24 __le64 dun[BLK_CRYPTO_DUN_ARRAY_SIZE];
25 };
26
unbind_bdev(struct hp_device *dev)27 void 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;
40 put:
41 blkdev_put(dev->bdev, FMODE_READ | FMODE_WRITE);
42 dev->bdev = NULL;
43 close:
44 if (dev->filp)
45 filp_close(dev->filp, NULL);
46 dev->filp = NULL;
47
48 pr_info("hyperhold bdev unbinded.\n");
49 }
50
bind_bdev(struct hp_device *dev, const char *name)51 bool 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;
91 err:
92 unbind_bdev(dev);
93
94 return false;
95 }
96
soft_crypt_page(struct crypto_skcipher *ctfm, struct page *dst_page, struct page *src_page, unsigned int op)97 int 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
soft_crypto_init(const u8 *key)137 static 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;
159 err:
160 if (ctfm)
161 crypto_free_skcipher(ctfm);
162
163 return NULL;
164 }
165
166 #ifdef CONFIG_BLK_INLINE_ENCRYPTION
inline_crypt_bio(struct blk_crypto_key *blk_key, struct bio *bio)167 void 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
inline_crypto_init(const u8 *key)177 static 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;
195 err:
196 if (blk_key)
197 kfree_sensitive(blk_key);
198
199 return NULL;
200 }
201 #else
inline_crypt_bio(struct blk_crypto_key *blk_key, struct bio *bio)202 void inline_crypt_bio(struct blk_crypto_key *blk_key, struct bio *bio) {}
inline_crypto_init(const u8 *key)203 static 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
crypto_init(struct hp_device *dev, bool soft)210 bool 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
crypto_deinit(struct hp_device *dev)230 void 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