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)
36f9f57971SLinlin 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;
48f9f57971SLinlin 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 *
lookup_cipher(const char * cipher_string)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
inlinecrypt_dtr(struct dm_target * ti)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
contains_whitespace(const char * str)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
set_key_user(struct key * key,char * key_bytes,const unsigned int key_bytes_size)88f9f57971SLinlin Zhang static int set_key_user(struct key *key, char *key_bytes,
89f9f57971SLinlin 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
97f9f57971SLinlin Zhang if (key_bytes_size != ukp->datalen)
98e7f57d2cSEric Biggers return -EINVAL;
99e7f57d2cSEric Biggers
100f9f57971SLinlin Zhang memcpy(key_bytes, ukp->data, key_bytes_size);
101e7f57d2cSEric Biggers
102e7f57d2cSEric Biggers return 0;
103e7f57d2cSEric Biggers }
104e7f57d2cSEric Biggers
inlinecrypt_get_keyring_key(const char * key_string,u8 * key_bytes,const unsigned int key_bytes_size)105f9f57971SLinlin Zhang static int inlinecrypt_get_keyring_key(const char *key_string, u8 *key_bytes,
106f9f57971SLinlin 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;
112f9f57971SLinlin Zhang int (*set_key)(struct key *key, char *key_bytes,
113f9f57971SLinlin 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
142f9f57971SLinlin 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
get_key_size(char ** key_string)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
inlinecrypt_get_keyring_key(const char * key_string,u8 * key_bytes,const unsigned int key_bytes_size)183f9f57971SLinlin Zhang static int inlinecrypt_get_keyring_key(const char *key_string, u8 *key_bytes,
184f9f57971SLinlin Zhang const unsigned int key_bytes_size)
185e7f57d2cSEric Biggers {
186e7f57d2cSEric Biggers return -EINVAL;
187e7f57d2cSEric Biggers }
188e7f57d2cSEric Biggers
get_key_size(char ** key_string)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
inlinecrypt_get_key(const char * key_string,u8 key[BLK_CRYPTO_MAX_ANY_KEY_SIZE],const unsigned int key_size)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
inlinecrypt_ctr_optional(struct dm_target * ti,unsigned int argc,char ** argv)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[] = {
239f9f57971SLinlin 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 }
260f9f57971SLinlin Zhang if (str_has_prefix(opt_string, "keytype:")) {
261f9f57971SLinlin Zhang const char *val = opt_string + strlen("keytype:");
262f9f57971SLinlin Zhang
263f9f57971SLinlin Zhang if (!*val) {
264f9f57971SLinlin Zhang ti->error = "Invalid block key type";
265f9f57971SLinlin Zhang return -EINVAL;
266f9f57971SLinlin Zhang }
267f9f57971SLinlin Zhang
268f9f57971SLinlin Zhang if (!strcmp(val, "raw")) {
269f9f57971SLinlin Zhang ctx->key_type = BLK_CRYPTO_KEY_TYPE_RAW;
270f9f57971SLinlin Zhang } else if (!strcmp(val, "hw-wrapped")) {
271f9f57971SLinlin Zhang ctx->key_type = BLK_CRYPTO_KEY_TYPE_HW_WRAPPED;
272f9f57971SLinlin Zhang } else {
273f9f57971SLinlin Zhang ti->error = "Invalid block key type";
274f9f57971SLinlin Zhang return -EINVAL;
275f9f57971SLinlin Zhang }
276f9f57971SLinlin 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 */
inlinecrypt_ctr(struct dm_target * ti,unsigned int argc,char ** argv)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;
314f9f57971SLinlin 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";
350*da991cbdSChristophe JAILLET goto bad;
351*da991cbdSChristophe JAILLET }
352e7f57d2cSEric Biggers ctx->key_size = err;
353e7f57d2cSEric Biggers
354e7f57d2cSEric Biggers err = inlinecrypt_get_key(argv[1], key_bytes, ctx->key_size);
355f9f57971SLinlin Zhang 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;
386e7f57d2cSEric Biggers ctx->key_type = BLK_CRYPTO_KEY_TYPE_RAW;
387f9f57971SLinlin Zhang 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 goto bad;
402*da991cbdSChristophe JAILLET }
403e7f57d2cSEric Biggers
404e7f57d2cSEric Biggers ctx->max_dun = (ctx->iv_offset + ti->len - 1) >>
405e7f57d2cSEric Biggers (ctx->sector_bits - SECTOR_SHIFT);
406e7f57d2cSEric Biggers dun_bytes = DIV_ROUND_UP(fls64(ctx->max_dun), 8);
407e7f57d2cSEric Biggers
408e7f57d2cSEric Biggers err = blk_crypto_init_key(&ctx->key, key_bytes, ctx->key_size,
409f9f57971SLinlin Zhang ctx->key_type, cipher->mode_num,
410f9f57971SLinlin Zhang dun_bytes, ctx->sector_size,
411f9f57971SLinlin Zhang BLK_CRYPTO_CFG_ALLOW_HW);
412e7f57d2cSEric Biggers if (err) {
413e7f57d2cSEric Biggers ti->error = "Error initializing blk-crypto key";
414e7f57d2cSEric Biggers goto bad;
415e7f57d2cSEric Biggers }
416e7f57d2cSEric Biggers
417e7f57d2cSEric Biggers err = blk_crypto_start_using_key(ctx->dev->bdev, &ctx->key);
418e7f57d2cSEric Biggers if (err) {
419e7f57d2cSEric Biggers ti->error = "Error starting to use blk-crypto";
420e7f57d2cSEric Biggers goto bad;
421e7f57d2cSEric Biggers }
422e7f57d2cSEric Biggers
423e7f57d2cSEric Biggers ti->num_flush_bios = 1;
424e7f57d2cSEric Biggers
425e7f57d2cSEric Biggers err = 0;
426e7f57d2cSEric Biggers goto out;
427e7f57d2cSEric Biggers
428e7f57d2cSEric Biggers bad:
429e7f57d2cSEric Biggers inlinecrypt_dtr(ti);
430e7f57d2cSEric Biggers out:
431f9f57971SLinlin Zhang memzero_explicit(key_bytes, sizeof(key_bytes));
432e7f57d2cSEric Biggers return err;
433e7f57d2cSEric Biggers }
434e7f57d2cSEric Biggers
inlinecrypt_map(struct dm_target * ti,struct bio * bio)435e7f57d2cSEric Biggers static int inlinecrypt_map(struct dm_target *ti, struct bio *bio)
436e7f57d2cSEric Biggers {
437e7f57d2cSEric Biggers const struct inlinecrypt_ctx *ctx = ti->private;
438e7f57d2cSEric Biggers sector_t sector_in_target;
439e7f57d2cSEric Biggers u64 dun[BLK_CRYPTO_DUN_ARRAY_SIZE] = {};
440e7f57d2cSEric Biggers
441e7f57d2cSEric Biggers bio_set_dev(bio, ctx->dev->bdev);
442e7f57d2cSEric Biggers
443e7f57d2cSEric Biggers /*
444e7f57d2cSEric Biggers * If the bio is a device-level request which doesn't target a specific
445e7f57d2cSEric Biggers * sector, there's nothing more to do.
446e7f57d2cSEric Biggers */
447e7f57d2cSEric Biggers if (bio_sectors(bio) == 0)
448e7f57d2cSEric Biggers return DM_MAPIO_REMAPPED;
449e7f57d2cSEric Biggers
450e7f57d2cSEric Biggers /*
451e7f57d2cSEric Biggers * The bio should never have an encryption context already, since
452e7f57d2cSEric Biggers * dm-inlinecrypt doesn't pass through any inline encryption
453e7f57d2cSEric Biggers * capabilities to the layer above it.
454e7f57d2cSEric Biggers */
455e7f57d2cSEric Biggers if (WARN_ON_ONCE(bio_has_crypt_ctx(bio)))
456e7f57d2cSEric Biggers return DM_MAPIO_KILL;
457e7f57d2cSEric Biggers
458e7f57d2cSEric Biggers /* Map the bio's sector to the underlying device. (512-byte sectors) */
459e7f57d2cSEric Biggers sector_in_target = dm_target_offset(ti, bio->bi_iter.bi_sector);
460e7f57d2cSEric Biggers bio->bi_iter.bi_sector = ctx->start + sector_in_target;
461e7f57d2cSEric Biggers /*
462e7f57d2cSEric Biggers * If the bio doesn't have any data (e.g. if it's a DISCARD request),
463e7f57d2cSEric Biggers * there's nothing more to do.
464e7f57d2cSEric Biggers */
465e7f57d2cSEric Biggers if (!bio_has_data(bio))
466e7f57d2cSEric Biggers return DM_MAPIO_REMAPPED;
467e7f57d2cSEric Biggers
468e7f57d2cSEric Biggers /* Calculate the DUN and enforce data-unit (crypto sector) alignment. */
469e7f57d2cSEric Biggers dun[0] = ctx->iv_offset + sector_in_target; /* 512-byte sectors */
470e7f57d2cSEric Biggers if (dun[0] & ((ctx->sector_size >> SECTOR_SHIFT) - 1))
471e7f57d2cSEric Biggers return DM_MAPIO_KILL;
472e7f57d2cSEric Biggers dun[0] >>= ctx->sector_bits - SECTOR_SHIFT; /* crypto sectors */
473e7f57d2cSEric Biggers
474e7f57d2cSEric Biggers /*
475e7f57d2cSEric Biggers * This check isn't necessary as we should have calculated max_dun
476e7f57d2cSEric Biggers * correctly, but be safe.
477e7f57d2cSEric Biggers */
478e7f57d2cSEric Biggers if (WARN_ON_ONCE(dun[0] > ctx->max_dun))
479e7f57d2cSEric Biggers return DM_MAPIO_KILL;
480e7f57d2cSEric Biggers
481e7f57d2cSEric Biggers bio_crypt_set_ctx(bio, &ctx->key, dun, GFP_NOIO);
482e7f57d2cSEric Biggers
483e7f57d2cSEric Biggers /*
484e7f57d2cSEric Biggers * Since we've added an encryption context to the bio and
485e7f57d2cSEric Biggers * blk-crypto-fallback may be needed to process it, it's necessary to
486e7f57d2cSEric Biggers * use the fallback-aware bio submission code rather than
487e7f57d2cSEric Biggers * unconditionally returning DM_MAPIO_REMAPPED.
488e7f57d2cSEric Biggers *
489e7f57d2cSEric Biggers * To get the correct accounting for a dm target in the case where
490e7f57d2cSEric Biggers * __blk_crypto_submit_bio() doesn't take ownership of the bio (returns
491e7f57d2cSEric Biggers * true), call __blk_crypto_submit_bio() directly and return
492e7f57d2cSEric Biggers * DM_MAPIO_REMAPPED in that case, rather than relying on
493e7f57d2cSEric Biggers * blk_crypto_submit_bio() which calls submit_bio() in that case.
494e7f57d2cSEric Biggers *
495e7f57d2cSEric Biggers * TODO: blk-crypto fallback write slow-path currently double-accounts
496e7f57d2cSEric Biggers * IO in vmstat, as encrypted bios are submitted via submit_bio().
497e7f57d2cSEric Biggers * This does not affect data correctness. Consider fixing this if
498e7f57d2cSEric Biggers * a cleaner accounting model for derived bios is introduced.
499e7f57d2cSEric Biggers */
500e7f57d2cSEric Biggers if (__blk_crypto_submit_bio(bio))
501e7f57d2cSEric Biggers return DM_MAPIO_REMAPPED;
502e7f57d2cSEric Biggers return DM_MAPIO_SUBMITTED;
503e7f57d2cSEric Biggers }
504e7f57d2cSEric Biggers
inlinecrypt_status(struct dm_target * ti,status_type_t type,unsigned int status_flags,char * result,unsigned int maxlen)505e7f57d2cSEric Biggers static void inlinecrypt_status(struct dm_target *ti, status_type_t type,
506e7f57d2cSEric Biggers unsigned int status_flags, char *result,
507e7f57d2cSEric Biggers unsigned int maxlen)
508e7f57d2cSEric Biggers {
509e7f57d2cSEric Biggers const struct inlinecrypt_ctx *ctx = ti->private;
510e7f57d2cSEric Biggers unsigned int sz = 0;
511e7f57d2cSEric Biggers int num_feature_args = 0;
512e7f57d2cSEric Biggers
513e7f57d2cSEric Biggers switch (type) {
514e7f57d2cSEric Biggers case STATUSTYPE_INFO:
515e7f57d2cSEric Biggers case STATUSTYPE_IMA:
516e7f57d2cSEric Biggers result[0] = '\0';
517e7f57d2cSEric Biggers break;
518e7f57d2cSEric Biggers
519e7f57d2cSEric Biggers case STATUSTYPE_TABLE:
520e7f57d2cSEric Biggers /*
521e7f57d2cSEric Biggers * Warning: like dm-crypt, dm-inlinecrypt includes the key in
522e7f57d2cSEric Biggers * the returned table. Userspace is responsible for redacting
523e7f57d2cSEric Biggers * the key when needed.
524e7f57d2cSEric Biggers */
525f9f57971SLinlin Zhang DMEMIT("%s %*phN %u %llu %s %llu", ctx->cipher_string,
526f9f57971SLinlin Zhang ctx->key.size, ctx->key.bytes,
527f9f57971SLinlin Zhang ctx->key_type, ctx->iv_offset,
528e7f57d2cSEric Biggers ctx->dev->name, ctx->start);
529e7f57d2cSEric Biggers num_feature_args += !!ti->num_discard_bios;
530e7f57d2cSEric Biggers if (ctx->sector_size != SECTOR_SIZE)
531e7f57d2cSEric Biggers num_feature_args += 2;
532e7f57d2cSEric Biggers if (num_feature_args != 0) {
533e7f57d2cSEric Biggers DMEMIT(" %d", num_feature_args);
534e7f57d2cSEric Biggers if (ti->num_discard_bios)
535e7f57d2cSEric Biggers DMEMIT(" allow_discards");
536e7f57d2cSEric Biggers if (ctx->sector_size != SECTOR_SIZE) {
537e7f57d2cSEric Biggers DMEMIT(" sector_size:%u", ctx->sector_size);
538e7f57d2cSEric Biggers DMEMIT(" iv_large_sectors");
539e7f57d2cSEric Biggers }
540e7f57d2cSEric Biggers }
541e7f57d2cSEric Biggers break;
542e7f57d2cSEric Biggers }
543e7f57d2cSEric Biggers }
544e7f57d2cSEric Biggers
inlinecrypt_prepare_ioctl(struct dm_target * ti,struct block_device ** bdev,unsigned int cmd,unsigned long arg,bool * forward)545e7f57d2cSEric Biggers static int inlinecrypt_prepare_ioctl(struct dm_target *ti,
546e7f57d2cSEric Biggers struct block_device **bdev, unsigned int cmd,
547e7f57d2cSEric Biggers unsigned long arg, bool *forward)
548e7f57d2cSEric Biggers {
549e7f57d2cSEric Biggers const struct inlinecrypt_ctx *ctx = ti->private;
550e7f57d2cSEric Biggers const struct dm_dev *dev = ctx->dev;
551e7f57d2cSEric Biggers
552e7f57d2cSEric Biggers *bdev = dev->bdev;
553e7f57d2cSEric Biggers
554e7f57d2cSEric Biggers /* Only pass ioctls through if the device sizes match exactly. */
555e7f57d2cSEric Biggers return ctx->start != 0 || ti->len != bdev_nr_sectors(dev->bdev);
556e7f57d2cSEric Biggers }
557e7f57d2cSEric Biggers
inlinecrypt_iterate_devices(struct dm_target * ti,iterate_devices_callout_fn fn,void * data)558e7f57d2cSEric Biggers static int inlinecrypt_iterate_devices(struct dm_target *ti,
559e7f57d2cSEric Biggers iterate_devices_callout_fn fn,
560e7f57d2cSEric Biggers void *data)
561e7f57d2cSEric Biggers {
562e7f57d2cSEric Biggers const struct inlinecrypt_ctx *ctx = ti->private;
563e7f57d2cSEric Biggers
564e7f57d2cSEric Biggers return fn(ti, ctx->dev, ctx->start, ti->len, data);
565e7f57d2cSEric Biggers }
566e7f57d2cSEric Biggers
567e7f57d2cSEric Biggers #ifdef CONFIG_BLK_DEV_ZONED
inlinecrypt_report_zones(struct dm_target * ti,struct dm_report_zones_args * args,unsigned int nr_zones)568e7f57d2cSEric Biggers static int inlinecrypt_report_zones(struct dm_target *ti,
569e7f57d2cSEric Biggers struct dm_report_zones_args *args,
570e7f57d2cSEric Biggers unsigned int nr_zones)
571e7f57d2cSEric Biggers {
572e7f57d2cSEric Biggers const struct inlinecrypt_ctx *ctx = ti->private;
573e7f57d2cSEric Biggers
574e7f57d2cSEric Biggers return dm_report_zones(ctx->dev->bdev, ctx->start,
575e7f57d2cSEric Biggers ctx->start + dm_target_offset(ti, args->next_sector),
576e7f57d2cSEric Biggers args, nr_zones);
577e7f57d2cSEric Biggers }
578e7f57d2cSEric Biggers #else
579e7f57d2cSEric Biggers #define inlinecrypt_report_zones NULL
580e7f57d2cSEric Biggers #endif
581e7f57d2cSEric Biggers
inlinecrypt_io_hints(struct dm_target * ti,struct queue_limits * limits)582e7f57d2cSEric Biggers static void inlinecrypt_io_hints(struct dm_target *ti,
583e7f57d2cSEric Biggers struct queue_limits *limits)
584e7f57d2cSEric Biggers {
585e7f57d2cSEric Biggers const struct inlinecrypt_ctx *ctx = ti->private;
586e7f57d2cSEric Biggers const unsigned int sector_size = ctx->sector_size;
587e7f57d2cSEric Biggers
588e7f57d2cSEric Biggers limits->logical_block_size =
589e7f57d2cSEric Biggers max_t(unsigned int, limits->logical_block_size, sector_size);
590e7f57d2cSEric Biggers limits->physical_block_size =
591e7f57d2cSEric Biggers max_t(unsigned int, limits->physical_block_size, sector_size);
592e7f57d2cSEric Biggers limits->io_min = max_t(unsigned int, limits->io_min, sector_size);
593e7f57d2cSEric Biggers limits->dma_alignment = limits->logical_block_size - 1;
594e7f57d2cSEric Biggers }
595e7f57d2cSEric Biggers
596e7f57d2cSEric Biggers static struct target_type inlinecrypt_target = {
597e7f57d2cSEric Biggers .name = "inlinecrypt",
598e7f57d2cSEric Biggers .version = {1, 0, 0},
599e7f57d2cSEric Biggers /*
600e7f57d2cSEric Biggers * Do not set DM_TARGET_PASSES_CRYPTO, since dm-inlinecrypt consumes the
601e7f57d2cSEric Biggers * crypto capability itself.
602e7f57d2cSEric Biggers */
603e7f57d2cSEric Biggers .features = DM_TARGET_ZONED_HM,
604e7f57d2cSEric Biggers .module = THIS_MODULE,
605e7f57d2cSEric Biggers .ctr = inlinecrypt_ctr,
606e7f57d2cSEric Biggers .dtr = inlinecrypt_dtr,
607e7f57d2cSEric Biggers .map = inlinecrypt_map,
608e7f57d2cSEric Biggers .status = inlinecrypt_status,
609e7f57d2cSEric Biggers .prepare_ioctl = inlinecrypt_prepare_ioctl,
610e7f57d2cSEric Biggers .iterate_devices = inlinecrypt_iterate_devices,
611e7f57d2cSEric Biggers .report_zones = inlinecrypt_report_zones,
612e7f57d2cSEric Biggers .io_hints = inlinecrypt_io_hints,
613e7f57d2cSEric Biggers };
614e7f57d2cSEric Biggers
615e7f57d2cSEric Biggers module_dm(inlinecrypt);
616e7f57d2cSEric Biggers
617e7f57d2cSEric Biggers MODULE_AUTHOR("Eric Biggers <ebiggers@google.com>");
618e7f57d2cSEric Biggers MODULE_AUTHOR("Linlin Zhang <linlin.zhang@oss.qualcomm.com>");
619e7f57d2cSEric Biggers MODULE_DESCRIPTION(DM_NAME " target for inline encryption");
620e7f57d2cSEric Biggers MODULE_LICENSE("GPL");
621