1e7f57d2cSEric Biggers // SPDX-License-Identifier: GPL-2.0-only 2e7f57d2cSEric Biggers /* 3e7f57d2cSEric Biggers * Copyright 2024 Google LLC 4e7f57d2cSEric Biggers */ 5e7f57d2cSEric Biggers 6e7f57d2cSEric Biggers #include <linux/blk-crypto.h> 7e7f57d2cSEric Biggers #include <linux/ctype.h> 8e7f57d2cSEric Biggers #include <linux/device-mapper.h> 9e7f57d2cSEric Biggers #include <linux/hex.h> 10e7f57d2cSEric Biggers #include <linux/module.h> 11e7f57d2cSEric Biggers #include <keys/user-type.h> 12e7f57d2cSEric Biggers 13e7f57d2cSEric Biggers #define DM_MSG_PREFIX "inlinecrypt" 14e7f57d2cSEric Biggers 15e7f57d2cSEric Biggers static const struct dm_inlinecrypt_cipher { 16e7f57d2cSEric Biggers const char *name; 17e7f57d2cSEric Biggers enum blk_crypto_mode_num mode_num; 18e7f57d2cSEric Biggers } dm_inlinecrypt_ciphers[] = { 19e7f57d2cSEric Biggers { 20e7f57d2cSEric Biggers .name = "aes-xts-plain64", 21e7f57d2cSEric Biggers .mode_num = BLK_ENCRYPTION_MODE_AES_256_XTS, 22e7f57d2cSEric Biggers }, 23e7f57d2cSEric Biggers }; 24e7f57d2cSEric Biggers 25e7f57d2cSEric Biggers /** 26e7f57d2cSEric Biggers * struct inlinecrypt_ctx - private data of an inlinecrypt target 27e7f57d2cSEric Biggers * @dev: the underlying device 28e7f57d2cSEric Biggers * @start: starting sector of the range of @dev which this target actually maps. 29e7f57d2cSEric Biggers * For this purpose a "sector" is 512 bytes. 30e7f57d2cSEric Biggers * @cipher_string: the name of the encryption algorithm being used 31e7f57d2cSEric Biggers * @key_size: size of the encryption key in bytes 32e7f57d2cSEric Biggers * @iv_offset: starting offset for IVs. IVs are generated as if the target were 33e7f57d2cSEric Biggers * preceded by @iv_offset 512-byte sectors. 34e7f57d2cSEric Biggers * @sector_size: crypto sector size in bytes (usually 4096) 35e7f57d2cSEric Biggers * @sector_bits: log2(sector_size) 36*f9f57971SLinlin Zhang * @key_type: type of the key -- either raw or hardware-wrapped 37e7f57d2cSEric Biggers * @key: the encryption key to use 38e7f57d2cSEric Biggers * @max_dun: the maximum DUN that may be used (computed from other params) 39e7f57d2cSEric Biggers */ 40e7f57d2cSEric Biggers struct inlinecrypt_ctx { 41e7f57d2cSEric Biggers struct dm_dev *dev; 42e7f57d2cSEric Biggers sector_t start; 43e7f57d2cSEric Biggers const char *cipher_string; 44e7f57d2cSEric Biggers unsigned int key_size; 45e7f57d2cSEric Biggers u64 iv_offset; 46e7f57d2cSEric Biggers unsigned int sector_size; 47e7f57d2cSEric Biggers unsigned int sector_bits; 48*f9f57971SLinlin Zhang enum blk_crypto_key_type key_type; 49e7f57d2cSEric Biggers struct blk_crypto_key key; 50e7f57d2cSEric Biggers u64 max_dun; 51e7f57d2cSEric Biggers }; 52e7f57d2cSEric Biggers 53e7f57d2cSEric Biggers static const struct dm_inlinecrypt_cipher * 54e7f57d2cSEric Biggers lookup_cipher(const char *cipher_string) 55e7f57d2cSEric Biggers { 56e7f57d2cSEric Biggers int i; 57e7f57d2cSEric Biggers 58e7f57d2cSEric Biggers for (i = 0; i < ARRAY_SIZE(dm_inlinecrypt_ciphers); i++) { 59e7f57d2cSEric Biggers if (strcmp(cipher_string, dm_inlinecrypt_ciphers[i].name) == 0) 60e7f57d2cSEric Biggers return &dm_inlinecrypt_ciphers[i]; 61e7f57d2cSEric Biggers } 62e7f57d2cSEric Biggers return NULL; 63e7f57d2cSEric Biggers } 64e7f57d2cSEric Biggers 65e7f57d2cSEric Biggers static void inlinecrypt_dtr(struct dm_target *ti) 66e7f57d2cSEric Biggers { 67e7f57d2cSEric Biggers struct inlinecrypt_ctx *ctx = ti->private; 68e7f57d2cSEric Biggers 69e7f57d2cSEric Biggers if (ctx->dev) { 70e7f57d2cSEric Biggers if (ctx->key.size) 71e7f57d2cSEric Biggers blk_crypto_evict_key(ctx->dev->bdev, &ctx->key); 72e7f57d2cSEric Biggers dm_put_device(ti, ctx->dev); 73e7f57d2cSEric Biggers } 74e7f57d2cSEric Biggers kfree_sensitive(ctx->cipher_string); 75e7f57d2cSEric Biggers kfree_sensitive(ctx); 76e7f57d2cSEric Biggers } 77e7f57d2cSEric Biggers 78e7f57d2cSEric Biggers #ifdef CONFIG_KEYS 79e7f57d2cSEric Biggers 80e7f57d2cSEric Biggers static bool contains_whitespace(const char *str) 81e7f57d2cSEric Biggers { 82e7f57d2cSEric Biggers while (*str) 83e7f57d2cSEric Biggers if (isspace(*str++)) 84e7f57d2cSEric Biggers return true; 85e7f57d2cSEric Biggers return false; 86e7f57d2cSEric Biggers } 87e7f57d2cSEric Biggers 88*f9f57971SLinlin Zhang static int set_key_user(struct key *key, char *key_bytes, 89*f9f57971SLinlin Zhang const unsigned int key_bytes_size) 90e7f57d2cSEric Biggers { 91e7f57d2cSEric Biggers const struct user_key_payload *ukp; 92e7f57d2cSEric Biggers 93e7f57d2cSEric Biggers ukp = user_key_payload_locked(key); 94e7f57d2cSEric Biggers if (!ukp) 95e7f57d2cSEric Biggers return -EKEYREVOKED; 96e7f57d2cSEric Biggers 97*f9f57971SLinlin Zhang if (key_bytes_size != ukp->datalen) 98e7f57d2cSEric Biggers return -EINVAL; 99e7f57d2cSEric Biggers 100*f9f57971SLinlin Zhang memcpy(key_bytes, ukp->data, key_bytes_size); 101e7f57d2cSEric Biggers 102e7f57d2cSEric Biggers return 0; 103e7f57d2cSEric Biggers } 104e7f57d2cSEric Biggers 105*f9f57971SLinlin Zhang static int inlinecrypt_get_keyring_key(const char *key_string, u8 *key_bytes, 106*f9f57971SLinlin Zhang const unsigned int key_bytes_size) 107e7f57d2cSEric Biggers { 108e7f57d2cSEric Biggers char *key_desc; 109e7f57d2cSEric Biggers int ret; 110e7f57d2cSEric Biggers struct key_type *type; 111e7f57d2cSEric Biggers struct key *key; 112*f9f57971SLinlin Zhang int (*set_key)(struct key *key, char *key_bytes, 113*f9f57971SLinlin Zhang const unsigned int key_bytes_size); 114e7f57d2cSEric Biggers 115e7f57d2cSEric Biggers /* 116e7f57d2cSEric Biggers * Reject key_string with whitespace. dm core currently lacks code for 117e7f57d2cSEric Biggers * proper whitespace escaping in arguments on DM_TABLE_STATUS path. 118e7f57d2cSEric Biggers */ 119e7f57d2cSEric Biggers if (contains_whitespace(key_string)) { 120e7f57d2cSEric Biggers DMERR("whitespace chars not allowed in key string"); 121e7f57d2cSEric Biggers return -EINVAL; 122e7f57d2cSEric Biggers } 123e7f57d2cSEric Biggers 124e7f57d2cSEric Biggers /* look for next ':' separating key_type from key_description */ 125e7f57d2cSEric Biggers key_desc = strchr(key_string, ':'); 126e7f57d2cSEric Biggers if (!key_desc || key_desc == key_string || !strlen(key_desc + 1)) 127e7f57d2cSEric Biggers return -EINVAL; 128e7f57d2cSEric Biggers 129e7f57d2cSEric Biggers if (!strncmp(key_string, "logon:", key_desc - key_string + 1)) { 130e7f57d2cSEric Biggers type = &key_type_logon; 131e7f57d2cSEric Biggers set_key = set_key_user; 132e7f57d2cSEric Biggers } else { 133e7f57d2cSEric Biggers return -EINVAL; 134e7f57d2cSEric Biggers } 135e7f57d2cSEric Biggers 136e7f57d2cSEric Biggers key = request_key(type, key_desc + 1, NULL); 137e7f57d2cSEric Biggers if (IS_ERR(key)) 138e7f57d2cSEric Biggers return PTR_ERR(key); 139e7f57d2cSEric Biggers 140e7f57d2cSEric Biggers down_read(&key->sem); 141e7f57d2cSEric Biggers 142*f9f57971SLinlin Zhang ret = set_key(key, (char *)key_bytes, key_bytes_size); 143e7f57d2cSEric Biggers 144e7f57d2cSEric Biggers up_read(&key->sem); 145e7f57d2cSEric Biggers key_put(key); 146e7f57d2cSEric Biggers 147e7f57d2cSEric Biggers return ret; 148e7f57d2cSEric Biggers } 149e7f57d2cSEric Biggers 150e7f57d2cSEric Biggers static int get_key_size(char **key_string) 151e7f57d2cSEric Biggers { 152e7f57d2cSEric Biggers char *colon, dummy; 153e7f57d2cSEric Biggers int ret; 154e7f57d2cSEric Biggers 155e7f57d2cSEric Biggers if (*key_string[0] != ':') { 156e7f57d2cSEric Biggers ret = strlen(*key_string); 157e7f57d2cSEric Biggers 158e7f57d2cSEric Biggers if (ret > 2 * BLK_CRYPTO_MAX_ANY_KEY_SIZE 159e7f57d2cSEric Biggers || ret % 2 160e7f57d2cSEric Biggers || !ret) { 161e7f57d2cSEric Biggers DMERR("Invalid keysize"); 162e7f57d2cSEric Biggers return -EINVAL; 163e7f57d2cSEric Biggers } 164e7f57d2cSEric Biggers return ret >> 1; 165e7f57d2cSEric Biggers } 166e7f57d2cSEric Biggers 167e7f57d2cSEric Biggers /* look for next ':' in key string */ 168e7f57d2cSEric Biggers colon = strpbrk(*key_string + 1, ":"); 169e7f57d2cSEric Biggers if (!colon) 170e7f57d2cSEric Biggers return -EINVAL; 171e7f57d2cSEric Biggers 172e7f57d2cSEric Biggers if (sscanf(*key_string + 1, "%u%c", &ret, &dummy) != 2 || dummy != ':') 173e7f57d2cSEric Biggers return -EINVAL; 174e7f57d2cSEric Biggers 175e7f57d2cSEric Biggers /* remaining key string should be :<logon|user>:<key_desc> */ 176e7f57d2cSEric Biggers *key_string = colon; 177e7f57d2cSEric Biggers 178e7f57d2cSEric Biggers return ret; 179e7f57d2cSEric Biggers } 180e7f57d2cSEric Biggers 181e7f57d2cSEric Biggers #else 182e7f57d2cSEric Biggers 183*f9f57971SLinlin Zhang static int inlinecrypt_get_keyring_key(const char *key_string, u8 *key_bytes, 184*f9f57971SLinlin Zhang const unsigned int key_bytes_size) 185e7f57d2cSEric Biggers { 186e7f57d2cSEric Biggers return -EINVAL; 187e7f57d2cSEric Biggers } 188e7f57d2cSEric Biggers 189e7f57d2cSEric Biggers static int get_key_size(char **key_string) 190e7f57d2cSEric Biggers { 191e7f57d2cSEric Biggers int key_hex_size = strlen(*key_string); 192e7f57d2cSEric Biggers 193e7f57d2cSEric Biggers if (*key_string[0] == ':') 194e7f57d2cSEric Biggers return -EINVAL; 195e7f57d2cSEric Biggers 196e7f57d2cSEric Biggers if (key_hex_size > 2 * BLK_CRYPTO_MAX_ANY_KEY_SIZE 197e7f57d2cSEric Biggers || key_hex_size % 2 198e7f57d2cSEric Biggers || !key_hex_size) { 199e7f57d2cSEric Biggers DMERR("Invalid keysize"); 200e7f57d2cSEric Biggers return -EINVAL; 201e7f57d2cSEric Biggers } 202e7f57d2cSEric Biggers 203e7f57d2cSEric Biggers return key_hex_size >> 1; 204e7f57d2cSEric Biggers } 205e7f57d2cSEric Biggers 206e7f57d2cSEric Biggers #endif /* CONFIG_KEYS */ 207e7f57d2cSEric Biggers 208e7f57d2cSEric Biggers static int inlinecrypt_get_key(const char *key_string, 209e7f57d2cSEric Biggers u8 key[BLK_CRYPTO_MAX_ANY_KEY_SIZE], 210e7f57d2cSEric Biggers const unsigned int key_size) 211e7f57d2cSEric Biggers { 212e7f57d2cSEric Biggers int ret = 0; 213e7f57d2cSEric Biggers 214e7f57d2cSEric Biggers if (key_size > BLK_CRYPTO_MAX_ANY_KEY_SIZE) { 215e7f57d2cSEric Biggers DMERR("Invalid keysize"); 216e7f57d2cSEric Biggers return -EINVAL; 217e7f57d2cSEric Biggers } 218e7f57d2cSEric Biggers 219e7f57d2cSEric Biggers /* ':' means the key is in kernel keyring, short-circuit normal key processing */ 220e7f57d2cSEric Biggers if (key_string[0] == ':') { 221e7f57d2cSEric Biggers /* key string should be :<logon|user>:<key_desc> */ 222e7f57d2cSEric Biggers ret = inlinecrypt_get_keyring_key(key_string + 1, key, key_size); 223e7f57d2cSEric Biggers goto out; 224e7f57d2cSEric Biggers } 225e7f57d2cSEric Biggers 226e7f57d2cSEric Biggers if (hex2bin(key, key_string, key_size) != 0) 227e7f57d2cSEric Biggers ret = -EINVAL; 228e7f57d2cSEric Biggers 229e7f57d2cSEric Biggers out: 230e7f57d2cSEric Biggers return ret; 231e7f57d2cSEric Biggers } 232e7f57d2cSEric Biggers 233e7f57d2cSEric Biggers static int inlinecrypt_ctr_optional(struct dm_target *ti, 234e7f57d2cSEric Biggers unsigned int argc, char **argv) 235e7f57d2cSEric Biggers { 236e7f57d2cSEric Biggers struct inlinecrypt_ctx *ctx = ti->private; 237e7f57d2cSEric Biggers struct dm_arg_set as; 238e7f57d2cSEric Biggers static const struct dm_arg _args[] = { 239*f9f57971SLinlin Zhang {0, 4, "Invalid number of feature args"}, 240e7f57d2cSEric Biggers }; 241e7f57d2cSEric Biggers unsigned int opt_params; 242e7f57d2cSEric Biggers const char *opt_string; 243e7f57d2cSEric Biggers bool iv_large_sectors = false; 244e7f57d2cSEric Biggers char dummy; 245e7f57d2cSEric Biggers int err; 246e7f57d2cSEric Biggers 247e7f57d2cSEric Biggers as.argc = argc; 248e7f57d2cSEric Biggers as.argv = argv; 249e7f57d2cSEric Biggers 250e7f57d2cSEric Biggers err = dm_read_arg_group(_args, &as, &opt_params, &ti->error); 251e7f57d2cSEric Biggers if (err) 252e7f57d2cSEric Biggers return err; 253e7f57d2cSEric Biggers 254e7f57d2cSEric Biggers while (opt_params--) { 255e7f57d2cSEric Biggers opt_string = dm_shift_arg(&as); 256e7f57d2cSEric Biggers if (!opt_string) { 257e7f57d2cSEric Biggers ti->error = "Not enough feature arguments"; 258e7f57d2cSEric Biggers return -EINVAL; 259e7f57d2cSEric Biggers } 260*f9f57971SLinlin Zhang if (str_has_prefix(opt_string, "keytype:")) { 261*f9f57971SLinlin Zhang const char *val = opt_string + strlen("keytype:"); 262*f9f57971SLinlin Zhang 263*f9f57971SLinlin Zhang if (!*val) { 264*f9f57971SLinlin Zhang ti->error = "Invalid block key type"; 265*f9f57971SLinlin Zhang return -EINVAL; 266*f9f57971SLinlin Zhang } 267*f9f57971SLinlin Zhang 268*f9f57971SLinlin Zhang if (!strcmp(val, "raw")) { 269*f9f57971SLinlin Zhang ctx->key_type = BLK_CRYPTO_KEY_TYPE_RAW; 270*f9f57971SLinlin Zhang } else if (!strcmp(val, "hw-wrapped")) { 271*f9f57971SLinlin Zhang ctx->key_type = BLK_CRYPTO_KEY_TYPE_HW_WRAPPED; 272*f9f57971SLinlin Zhang } else { 273*f9f57971SLinlin Zhang ti->error = "Invalid block key type"; 274*f9f57971SLinlin Zhang return -EINVAL; 275*f9f57971SLinlin Zhang } 276*f9f57971SLinlin Zhang } else if (!strcmp(opt_string, "allow_discards")) { 277e7f57d2cSEric Biggers ti->num_discard_bios = 1; 278e7f57d2cSEric Biggers } else if (sscanf(opt_string, "sector_size:%u%c", 279e7f57d2cSEric Biggers &ctx->sector_size, &dummy) == 1) { 280e7f57d2cSEric Biggers if (ctx->sector_size < SECTOR_SIZE || 281e7f57d2cSEric Biggers ctx->sector_size > 4096 || 282e7f57d2cSEric Biggers !is_power_of_2(ctx->sector_size)) { 283e7f57d2cSEric Biggers ti->error = "Invalid sector_size"; 284e7f57d2cSEric Biggers return -EINVAL; 285e7f57d2cSEric Biggers } 286e7f57d2cSEric Biggers } else if (!strcmp(opt_string, "iv_large_sectors")) { 287e7f57d2cSEric Biggers iv_large_sectors = true; 288e7f57d2cSEric Biggers } else { 289e7f57d2cSEric Biggers ti->error = "Invalid feature arguments"; 290e7f57d2cSEric Biggers return -EINVAL; 291e7f57d2cSEric Biggers } 292e7f57d2cSEric Biggers } 293e7f57d2cSEric Biggers 294e7f57d2cSEric Biggers /* dm-inlinecrypt doesn't implement iv_large_sectors=false. */ 295e7f57d2cSEric Biggers if (ctx->sector_size != SECTOR_SIZE && !iv_large_sectors) { 296e7f57d2cSEric Biggers ti->error = "iv_large_sectors must be specified"; 297e7f57d2cSEric Biggers return -EINVAL; 298e7f57d2cSEric Biggers } 299e7f57d2cSEric Biggers 300e7f57d2cSEric Biggers return 0; 301e7f57d2cSEric Biggers } 302e7f57d2cSEric Biggers 303e7f57d2cSEric Biggers /* 304e7f57d2cSEric Biggers * Construct an inlinecrypt mapping: 305e7f57d2cSEric Biggers * <cipher> [<key>|:<key_size>:<logon>:<key_description>] <iv_offset> <dev_path> <start> 306e7f57d2cSEric Biggers * 307e7f57d2cSEric Biggers * This syntax matches dm-crypt's, but the set of supported functionality has 308e7f57d2cSEric Biggers * been stripped down. 309e7f57d2cSEric Biggers */ 310e7f57d2cSEric Biggers static int inlinecrypt_ctr(struct dm_target *ti, unsigned int argc, char **argv) 311e7f57d2cSEric Biggers { 312e7f57d2cSEric Biggers struct inlinecrypt_ctx *ctx; 313e7f57d2cSEric Biggers const struct dm_inlinecrypt_cipher *cipher; 314*f9f57971SLinlin Zhang u8 key_bytes[BLK_CRYPTO_MAX_ANY_KEY_SIZE]; 315e7f57d2cSEric Biggers unsigned int dun_bytes; 316e7f57d2cSEric Biggers unsigned long long tmpll; 317e7f57d2cSEric Biggers char dummy; 318e7f57d2cSEric Biggers int err; 319e7f57d2cSEric Biggers 320e7f57d2cSEric Biggers if (argc < 5) { 321e7f57d2cSEric Biggers ti->error = "Not enough arguments"; 322e7f57d2cSEric Biggers return -EINVAL; 323e7f57d2cSEric Biggers } 324e7f57d2cSEric Biggers 325e7f57d2cSEric Biggers ctx = kzalloc(sizeof(*ctx), GFP_KERNEL); 326e7f57d2cSEric Biggers if (!ctx) { 327e7f57d2cSEric Biggers ti->error = "Out of memory"; 328e7f57d2cSEric Biggers return -ENOMEM; 329e7f57d2cSEric Biggers } 330e7f57d2cSEric Biggers ti->private = ctx; 331e7f57d2cSEric Biggers 332e7f57d2cSEric Biggers /* <cipher> */ 333e7f57d2cSEric Biggers ctx->cipher_string = kstrdup(argv[0], GFP_KERNEL); 334e7f57d2cSEric Biggers if (!ctx->cipher_string) { 335e7f57d2cSEric Biggers ti->error = "Out of memory"; 336e7f57d2cSEric Biggers err = -ENOMEM; 337e7f57d2cSEric Biggers goto bad; 338e7f57d2cSEric Biggers } 339e7f57d2cSEric Biggers cipher = lookup_cipher(ctx->cipher_string); 340e7f57d2cSEric Biggers if (!cipher) { 341e7f57d2cSEric Biggers ti->error = "Unsupported cipher"; 342e7f57d2cSEric Biggers err = -EINVAL; 343e7f57d2cSEric Biggers goto bad; 344e7f57d2cSEric Biggers } 345e7f57d2cSEric Biggers 346e7f57d2cSEric Biggers /* <key> */ 347e7f57d2cSEric Biggers err = get_key_size(&argv[1]); 348e7f57d2cSEric Biggers if (err < 0) { 349e7f57d2cSEric Biggers ti->error = "Cannot parse key size"; 350e7f57d2cSEric Biggers return -EINVAL; 351e7f57d2cSEric Biggers } 352e7f57d2cSEric Biggers ctx->key_size = err; 353e7f57d2cSEric Biggers 354*f9f57971SLinlin Zhang err = inlinecrypt_get_key(argv[1], key_bytes, ctx->key_size); 355e7f57d2cSEric Biggers if (err) { 356e7f57d2cSEric Biggers ti->error = "Malformed key string"; 357e7f57d2cSEric Biggers goto bad; 358e7f57d2cSEric Biggers } 359e7f57d2cSEric Biggers 360e7f57d2cSEric Biggers /* <iv_offset> */ 361e7f57d2cSEric Biggers if (sscanf(argv[2], "%llu%c", &ctx->iv_offset, &dummy) != 1) { 362e7f57d2cSEric Biggers ti->error = "Invalid iv_offset sector"; 363e7f57d2cSEric Biggers err = -EINVAL; 364e7f57d2cSEric Biggers goto bad; 365e7f57d2cSEric Biggers } 366e7f57d2cSEric Biggers 367e7f57d2cSEric Biggers /* <dev_path> */ 368e7f57d2cSEric Biggers err = dm_get_device(ti, argv[3], dm_table_get_mode(ti->table), 369e7f57d2cSEric Biggers &ctx->dev); 370e7f57d2cSEric Biggers if (err) { 371e7f57d2cSEric Biggers ti->error = "Device lookup failed"; 372e7f57d2cSEric Biggers goto bad; 373e7f57d2cSEric Biggers } 374e7f57d2cSEric Biggers 375e7f57d2cSEric Biggers /* <start> */ 376e7f57d2cSEric Biggers if (sscanf(argv[4], "%llu%c", &tmpll, &dummy) != 1 || 377e7f57d2cSEric Biggers tmpll != (sector_t)tmpll) { 378e7f57d2cSEric Biggers ti->error = "Invalid start sector"; 379e7f57d2cSEric Biggers err = -EINVAL; 380e7f57d2cSEric Biggers goto bad; 381e7f57d2cSEric Biggers } 382e7f57d2cSEric Biggers ctx->start = tmpll; 383e7f57d2cSEric Biggers 384e7f57d2cSEric Biggers /* optional arguments */ 385e7f57d2cSEric Biggers ctx->sector_size = SECTOR_SIZE; 386*f9f57971SLinlin Zhang ctx->key_type = BLK_CRYPTO_KEY_TYPE_RAW; 387e7f57d2cSEric Biggers if (argc > 5) { 388e7f57d2cSEric Biggers err = inlinecrypt_ctr_optional(ti, argc - 5, &argv[5]); 389e7f57d2cSEric Biggers if (err) 390e7f57d2cSEric Biggers goto bad; 391e7f57d2cSEric Biggers } 392e7f57d2cSEric Biggers ctx->sector_bits = ilog2(ctx->sector_size); 393e7f57d2cSEric Biggers if (ti->len & ((ctx->sector_size >> SECTOR_SHIFT) - 1)) { 394e7f57d2cSEric Biggers ti->error = "Device size is not a multiple of sector_size"; 395e7f57d2cSEric Biggers err = -EINVAL; 396e7f57d2cSEric Biggers goto bad; 397e7f57d2cSEric Biggers } 398e7f57d2cSEric Biggers if (ctx->iv_offset & ((ctx->sector_size >> SECTOR_SHIFT) - 1)) { 399e7f57d2cSEric Biggers ti->error = "Wrong alignment of iv_offset sector"; 400e7f57d2cSEric Biggers err = -EINVAL; 401e7f57d2cSEric Biggers } 402e7f57d2cSEric Biggers 403e7f57d2cSEric Biggers ctx->max_dun = (ctx->iv_offset + ti->len - 1) >> 404e7f57d2cSEric Biggers (ctx->sector_bits - SECTOR_SHIFT); 405e7f57d2cSEric Biggers dun_bytes = DIV_ROUND_UP(fls64(ctx->max_dun), 8); 406e7f57d2cSEric Biggers 407*f9f57971SLinlin Zhang err = blk_crypto_init_key(&ctx->key, key_bytes, ctx->key_size, 408*f9f57971SLinlin Zhang ctx->key_type, cipher->mode_num, 409*f9f57971SLinlin Zhang dun_bytes, ctx->sector_size); 410e7f57d2cSEric Biggers if (err) { 411e7f57d2cSEric Biggers ti->error = "Error initializing blk-crypto key"; 412e7f57d2cSEric Biggers goto bad; 413e7f57d2cSEric Biggers } 414e7f57d2cSEric Biggers 415e7f57d2cSEric Biggers err = blk_crypto_start_using_key(ctx->dev->bdev, &ctx->key); 416e7f57d2cSEric Biggers if (err) { 417e7f57d2cSEric Biggers ti->error = "Error starting to use blk-crypto"; 418e7f57d2cSEric Biggers goto bad; 419e7f57d2cSEric Biggers } 420e7f57d2cSEric Biggers 421e7f57d2cSEric Biggers ti->num_flush_bios = 1; 422e7f57d2cSEric Biggers 423e7f57d2cSEric Biggers err = 0; 424e7f57d2cSEric Biggers goto out; 425e7f57d2cSEric Biggers 426e7f57d2cSEric Biggers bad: 427e7f57d2cSEric Biggers inlinecrypt_dtr(ti); 428e7f57d2cSEric Biggers out: 429*f9f57971SLinlin Zhang memzero_explicit(key_bytes, sizeof(key_bytes)); 430e7f57d2cSEric Biggers return err; 431e7f57d2cSEric Biggers } 432e7f57d2cSEric Biggers 433e7f57d2cSEric Biggers static int inlinecrypt_map(struct dm_target *ti, struct bio *bio) 434e7f57d2cSEric Biggers { 435e7f57d2cSEric Biggers const struct inlinecrypt_ctx *ctx = ti->private; 436e7f57d2cSEric Biggers sector_t sector_in_target; 437e7f57d2cSEric Biggers u64 dun[BLK_CRYPTO_DUN_ARRAY_SIZE] = {}; 438e7f57d2cSEric Biggers 439e7f57d2cSEric Biggers bio_set_dev(bio, ctx->dev->bdev); 440e7f57d2cSEric Biggers 441e7f57d2cSEric Biggers /* 442e7f57d2cSEric Biggers * If the bio is a device-level request which doesn't target a specific 443e7f57d2cSEric Biggers * sector, there's nothing more to do. 444e7f57d2cSEric Biggers */ 445e7f57d2cSEric Biggers if (bio_sectors(bio) == 0) 446e7f57d2cSEric Biggers return DM_MAPIO_REMAPPED; 447e7f57d2cSEric Biggers 448e7f57d2cSEric Biggers /* 449e7f57d2cSEric Biggers * The bio should never have an encryption context already, since 450e7f57d2cSEric Biggers * dm-inlinecrypt doesn't pass through any inline encryption 451e7f57d2cSEric Biggers * capabilities to the layer above it. 452e7f57d2cSEric Biggers */ 453e7f57d2cSEric Biggers if (WARN_ON_ONCE(bio_has_crypt_ctx(bio))) 454e7f57d2cSEric Biggers return DM_MAPIO_KILL; 455e7f57d2cSEric Biggers 456e7f57d2cSEric Biggers /* Map the bio's sector to the underlying device. (512-byte sectors) */ 457e7f57d2cSEric Biggers sector_in_target = dm_target_offset(ti, bio->bi_iter.bi_sector); 458e7f57d2cSEric Biggers bio->bi_iter.bi_sector = ctx->start + sector_in_target; 459e7f57d2cSEric Biggers /* 460e7f57d2cSEric Biggers * If the bio doesn't have any data (e.g. if it's a DISCARD request), 461e7f57d2cSEric Biggers * there's nothing more to do. 462e7f57d2cSEric Biggers */ 463e7f57d2cSEric Biggers if (!bio_has_data(bio)) 464e7f57d2cSEric Biggers return DM_MAPIO_REMAPPED; 465e7f57d2cSEric Biggers 466e7f57d2cSEric Biggers /* Calculate the DUN and enforce data-unit (crypto sector) alignment. */ 467e7f57d2cSEric Biggers dun[0] = ctx->iv_offset + sector_in_target; /* 512-byte sectors */ 468e7f57d2cSEric Biggers if (dun[0] & ((ctx->sector_size >> SECTOR_SHIFT) - 1)) 469e7f57d2cSEric Biggers return DM_MAPIO_KILL; 470e7f57d2cSEric Biggers dun[0] >>= ctx->sector_bits - SECTOR_SHIFT; /* crypto sectors */ 471e7f57d2cSEric Biggers 472e7f57d2cSEric Biggers /* 473e7f57d2cSEric Biggers * This check isn't necessary as we should have calculated max_dun 474e7f57d2cSEric Biggers * correctly, but be safe. 475e7f57d2cSEric Biggers */ 476e7f57d2cSEric Biggers if (WARN_ON_ONCE(dun[0] > ctx->max_dun)) 477e7f57d2cSEric Biggers return DM_MAPIO_KILL; 478e7f57d2cSEric Biggers 479e7f57d2cSEric Biggers bio_crypt_set_ctx(bio, &ctx->key, dun, GFP_NOIO); 480e7f57d2cSEric Biggers 481e7f57d2cSEric Biggers /* 482e7f57d2cSEric Biggers * Since we've added an encryption context to the bio and 483e7f57d2cSEric Biggers * blk-crypto-fallback may be needed to process it, it's necessary to 484e7f57d2cSEric Biggers * use the fallback-aware bio submission code rather than 485e7f57d2cSEric Biggers * unconditionally returning DM_MAPIO_REMAPPED. 486e7f57d2cSEric Biggers * 487e7f57d2cSEric Biggers * To get the correct accounting for a dm target in the case where 488e7f57d2cSEric Biggers * __blk_crypto_submit_bio() doesn't take ownership of the bio (returns 489e7f57d2cSEric Biggers * true), call __blk_crypto_submit_bio() directly and return 490e7f57d2cSEric Biggers * DM_MAPIO_REMAPPED in that case, rather than relying on 491e7f57d2cSEric Biggers * blk_crypto_submit_bio() which calls submit_bio() in that case. 492e7f57d2cSEric Biggers * 493e7f57d2cSEric Biggers * TODO: blk-crypto fallback write slow-path currently double-accounts 494e7f57d2cSEric Biggers * IO in vmstat, as encrypted bios are submitted via submit_bio(). 495e7f57d2cSEric Biggers * This does not affect data correctness. Consider fixing this if 496e7f57d2cSEric Biggers * a cleaner accounting model for derived bios is introduced. 497e7f57d2cSEric Biggers */ 498e7f57d2cSEric Biggers if (__blk_crypto_submit_bio(bio)) 499e7f57d2cSEric Biggers return DM_MAPIO_REMAPPED; 500e7f57d2cSEric Biggers return DM_MAPIO_SUBMITTED; 501e7f57d2cSEric Biggers } 502e7f57d2cSEric Biggers 503e7f57d2cSEric Biggers static void inlinecrypt_status(struct dm_target *ti, status_type_t type, 504e7f57d2cSEric Biggers unsigned int status_flags, char *result, 505e7f57d2cSEric Biggers unsigned int maxlen) 506e7f57d2cSEric Biggers { 507e7f57d2cSEric Biggers const struct inlinecrypt_ctx *ctx = ti->private; 508e7f57d2cSEric Biggers unsigned int sz = 0; 509e7f57d2cSEric Biggers int num_feature_args = 0; 510e7f57d2cSEric Biggers 511e7f57d2cSEric Biggers switch (type) { 512e7f57d2cSEric Biggers case STATUSTYPE_INFO: 513e7f57d2cSEric Biggers case STATUSTYPE_IMA: 514e7f57d2cSEric Biggers result[0] = '\0'; 515e7f57d2cSEric Biggers break; 516e7f57d2cSEric Biggers 517e7f57d2cSEric Biggers case STATUSTYPE_TABLE: 518e7f57d2cSEric Biggers /* 519e7f57d2cSEric Biggers * Warning: like dm-crypt, dm-inlinecrypt includes the key in 520e7f57d2cSEric Biggers * the returned table. Userspace is responsible for redacting 521e7f57d2cSEric Biggers * the key when needed. 522e7f57d2cSEric Biggers */ 523*f9f57971SLinlin Zhang DMEMIT("%s %*phN %u %llu %s %llu", ctx->cipher_string, 524*f9f57971SLinlin Zhang ctx->key.size, ctx->key.bytes, 525*f9f57971SLinlin Zhang ctx->key_type, ctx->iv_offset, 526e7f57d2cSEric Biggers ctx->dev->name, ctx->start); 527e7f57d2cSEric Biggers num_feature_args += !!ti->num_discard_bios; 528e7f57d2cSEric Biggers if (ctx->sector_size != SECTOR_SIZE) 529e7f57d2cSEric Biggers num_feature_args += 2; 530e7f57d2cSEric Biggers if (num_feature_args != 0) { 531e7f57d2cSEric Biggers DMEMIT(" %d", num_feature_args); 532e7f57d2cSEric Biggers if (ti->num_discard_bios) 533e7f57d2cSEric Biggers DMEMIT(" allow_discards"); 534e7f57d2cSEric Biggers if (ctx->sector_size != SECTOR_SIZE) { 535e7f57d2cSEric Biggers DMEMIT(" sector_size:%u", ctx->sector_size); 536e7f57d2cSEric Biggers DMEMIT(" iv_large_sectors"); 537e7f57d2cSEric Biggers } 538e7f57d2cSEric Biggers } 539e7f57d2cSEric Biggers break; 540e7f57d2cSEric Biggers } 541e7f57d2cSEric Biggers } 542e7f57d2cSEric Biggers 543e7f57d2cSEric Biggers static int inlinecrypt_prepare_ioctl(struct dm_target *ti, 544e7f57d2cSEric Biggers struct block_device **bdev, unsigned int cmd, 545e7f57d2cSEric Biggers unsigned long arg, bool *forward) 546e7f57d2cSEric Biggers { 547e7f57d2cSEric Biggers const struct inlinecrypt_ctx *ctx = ti->private; 548e7f57d2cSEric Biggers const struct dm_dev *dev = ctx->dev; 549e7f57d2cSEric Biggers 550e7f57d2cSEric Biggers *bdev = dev->bdev; 551e7f57d2cSEric Biggers 552e7f57d2cSEric Biggers /* Only pass ioctls through if the device sizes match exactly. */ 553e7f57d2cSEric Biggers return ctx->start != 0 || ti->len != bdev_nr_sectors(dev->bdev); 554e7f57d2cSEric Biggers } 555e7f57d2cSEric Biggers 556e7f57d2cSEric Biggers static int inlinecrypt_iterate_devices(struct dm_target *ti, 557e7f57d2cSEric Biggers iterate_devices_callout_fn fn, 558e7f57d2cSEric Biggers void *data) 559e7f57d2cSEric Biggers { 560e7f57d2cSEric Biggers const struct inlinecrypt_ctx *ctx = ti->private; 561e7f57d2cSEric Biggers 562e7f57d2cSEric Biggers return fn(ti, ctx->dev, ctx->start, ti->len, data); 563e7f57d2cSEric Biggers } 564e7f57d2cSEric Biggers 565e7f57d2cSEric Biggers #ifdef CONFIG_BLK_DEV_ZONED 566e7f57d2cSEric Biggers static int inlinecrypt_report_zones(struct dm_target *ti, 567e7f57d2cSEric Biggers struct dm_report_zones_args *args, 568e7f57d2cSEric Biggers unsigned int nr_zones) 569e7f57d2cSEric Biggers { 570e7f57d2cSEric Biggers const struct inlinecrypt_ctx *ctx = ti->private; 571e7f57d2cSEric Biggers 572e7f57d2cSEric Biggers return dm_report_zones(ctx->dev->bdev, ctx->start, 573e7f57d2cSEric Biggers ctx->start + dm_target_offset(ti, args->next_sector), 574e7f57d2cSEric Biggers args, nr_zones); 575e7f57d2cSEric Biggers } 576e7f57d2cSEric Biggers #else 577e7f57d2cSEric Biggers #define inlinecrypt_report_zones NULL 578e7f57d2cSEric Biggers #endif 579e7f57d2cSEric Biggers 580e7f57d2cSEric Biggers static void inlinecrypt_io_hints(struct dm_target *ti, 581e7f57d2cSEric Biggers struct queue_limits *limits) 582e7f57d2cSEric Biggers { 583e7f57d2cSEric Biggers const struct inlinecrypt_ctx *ctx = ti->private; 584e7f57d2cSEric Biggers const unsigned int sector_size = ctx->sector_size; 585e7f57d2cSEric Biggers 586e7f57d2cSEric Biggers limits->logical_block_size = 587e7f57d2cSEric Biggers max_t(unsigned int, limits->logical_block_size, sector_size); 588e7f57d2cSEric Biggers limits->physical_block_size = 589e7f57d2cSEric Biggers max_t(unsigned int, limits->physical_block_size, sector_size); 590e7f57d2cSEric Biggers limits->io_min = max_t(unsigned int, limits->io_min, sector_size); 591e7f57d2cSEric Biggers limits->dma_alignment = limits->logical_block_size - 1; 592e7f57d2cSEric Biggers } 593e7f57d2cSEric Biggers 594e7f57d2cSEric Biggers static struct target_type inlinecrypt_target = { 595e7f57d2cSEric Biggers .name = "inlinecrypt", 596e7f57d2cSEric Biggers .version = {1, 0, 0}, 597e7f57d2cSEric Biggers /* 598e7f57d2cSEric Biggers * Do not set DM_TARGET_PASSES_CRYPTO, since dm-inlinecrypt consumes the 599e7f57d2cSEric Biggers * crypto capability itself. 600e7f57d2cSEric Biggers */ 601e7f57d2cSEric Biggers .features = DM_TARGET_ZONED_HM, 602e7f57d2cSEric Biggers .module = THIS_MODULE, 603e7f57d2cSEric Biggers .ctr = inlinecrypt_ctr, 604e7f57d2cSEric Biggers .dtr = inlinecrypt_dtr, 605e7f57d2cSEric Biggers .map = inlinecrypt_map, 606e7f57d2cSEric Biggers .status = inlinecrypt_status, 607e7f57d2cSEric Biggers .prepare_ioctl = inlinecrypt_prepare_ioctl, 608e7f57d2cSEric Biggers .iterate_devices = inlinecrypt_iterate_devices, 609e7f57d2cSEric Biggers .report_zones = inlinecrypt_report_zones, 610e7f57d2cSEric Biggers .io_hints = inlinecrypt_io_hints, 611e7f57d2cSEric Biggers }; 612e7f57d2cSEric Biggers 613e7f57d2cSEric Biggers module_dm(inlinecrypt); 614e7f57d2cSEric Biggers 615e7f57d2cSEric Biggers MODULE_AUTHOR("Eric Biggers <ebiggers@google.com>"); 616e7f57d2cSEric Biggers MODULE_AUTHOR("Linlin Zhang <linlin.zhang@oss.qualcomm.com>"); 617e7f57d2cSEric Biggers MODULE_DESCRIPTION(DM_NAME " target for inline encryption"); 618e7f57d2cSEric Biggers MODULE_LICENSE("GPL"); 619