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