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