blob: ca50de11b6d0181383352781b55b92b34e2a75b3 [file] [log] [blame]
Eric Biggers57d8e332017-04-12 11:09:25 -07001/*
2 * Copyright (C) 2017 Google, Inc.
3 *
4 * This software is licensed under the terms of the GNU General Public
5 * License version 2, as published by the Free Software Foundation, and
6 * may be copied, distributed, and modified under those terms.
7 *
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
12 */
13
14#include <linux/device-mapper.h>
15#include <linux/module.h>
16#include <linux/pfk.h>
17
18#define DM_MSG_PREFIX "default-key"
19
20struct default_key_c {
21 struct dm_dev *dev;
22 sector_t start;
23 struct blk_encryption_key key;
24};
25
26static void default_key_dtr(struct dm_target *ti)
27{
28 struct default_key_c *dkc = ti->private;
29
30 if (dkc->dev)
31 dm_put_device(ti, dkc->dev);
32 kzfree(dkc);
33}
34
35/*
36 * Construct a default-key mapping: <mode> <key> <dev_path> <start>
37 */
38static int default_key_ctr(struct dm_target *ti, unsigned int argc, char **argv)
39{
40 struct default_key_c *dkc;
41 size_t key_size;
42 unsigned long long tmp;
43 char dummy;
44 int err;
45
46 if (argc != 4) {
47 ti->error = "Invalid argument count";
48 return -EINVAL;
49 }
50
51 dkc = kzalloc(sizeof(*dkc), GFP_KERNEL);
52 if (!dkc) {
53 ti->error = "Out of memory";
54 return -ENOMEM;
55 }
56 ti->private = dkc;
57
58 if (strcmp(argv[0], "AES-256-XTS") != 0) {
59 ti->error = "Unsupported encryption mode";
60 err = -EINVAL;
61 goto bad;
62 }
63
64 key_size = strlen(argv[1]);
65 if (key_size != 2 * BLK_ENCRYPTION_KEY_SIZE_AES_256_XTS) {
66 ti->error = "Unsupported key size";
67 err = -EINVAL;
68 goto bad;
69 }
70 key_size /= 2;
71
72 if (hex2bin(dkc->key.raw, argv[1], key_size) != 0) {
73 ti->error = "Malformed key string";
74 err = -EINVAL;
75 goto bad;
76 }
77
78 err = dm_get_device(ti, argv[2], dm_table_get_mode(ti->table),
79 &dkc->dev);
80 if (err) {
81 ti->error = "Device lookup failed";
82 goto bad;
83 }
84
85 if (sscanf(argv[3], "%llu%c", &tmp, &dummy) != 1) {
86 ti->error = "Invalid start sector";
87 err = -EINVAL;
88 goto bad;
89 }
90 dkc->start = tmp;
91
92 if (!blk_queue_inlinecrypt(bdev_get_queue(dkc->dev->bdev))) {
93 ti->error = "Device does not support inline encryption";
94 err = -EINVAL;
95 goto bad;
96 }
97
98 /* Pass flush requests through to the underlying device. */
99 ti->num_flush_bios = 1;
100
101 /*
102 * We pass discard requests through to the underlying device, although
103 * the discarded blocks will be zeroed, which leaks information about
104 * unused blocks. It's also impossible for dm-default-key to know not
105 * to decrypt discarded blocks, so they will not be read back as zeroes
106 * and we must set discard_zeroes_data_unsupported.
107 */
108 ti->num_discard_bios = 1;
109
110 /*
111 * It's unclear whether WRITE_SAME would work with inline encryption; it
112 * would depend on whether the hardware duplicates the data before or
113 * after encryption. But since the internal storage in some devices
114 * (MSM8998-based) doesn't claim to support WRITE_SAME anyway, we don't
115 * currently have a way to test it. Leave it disabled it for now.
116 */
117 /*ti->num_write_same_bios = 1;*/
118
119 return 0;
120
121bad:
122 default_key_dtr(ti);
123 return err;
124}
125
126static int default_key_map(struct dm_target *ti, struct bio *bio)
127{
128 const struct default_key_c *dkc = ti->private;
129
130 bio->bi_bdev = dkc->dev->bdev;
131 if (bio_sectors(bio)) {
132 bio->bi_iter.bi_sector = dkc->start +
133 dm_target_offset(ti, bio->bi_iter.bi_sector);
134 }
135
Jaegeuk Kim20bd93b2018-04-20 19:26:09 -0700136 if (!bio->bi_crypt_key && !bio->bi_crypt_skip)
Eric Biggers57d8e332017-04-12 11:09:25 -0700137 bio->bi_crypt_key = &dkc->key;
138
139 return DM_MAPIO_REMAPPED;
140}
141
142static void default_key_status(struct dm_target *ti, status_type_t type,
143 unsigned int status_flags, char *result,
144 unsigned int maxlen)
145{
146 const struct default_key_c *dkc = ti->private;
147 unsigned int sz = 0;
148
149 switch (type) {
150 case STATUSTYPE_INFO:
151 result[0] = '\0';
152 break;
153
154 case STATUSTYPE_TABLE:
155
156 /* encryption mode */
157 DMEMIT("AES-256-XTS");
158
159 /* reserved for key; dm-crypt shows it, but we don't for now */
160 DMEMIT(" -");
161
162 /* name of underlying device, and the start sector in it */
163 DMEMIT(" %s %llu", dkc->dev->name,
164 (unsigned long long)dkc->start);
165 break;
166 }
167}
168
169static int default_key_prepare_ioctl(struct dm_target *ti,
170 struct block_device **bdev, fmode_t *mode)
171{
172 struct default_key_c *dkc = ti->private;
173 struct dm_dev *dev = dkc->dev;
174
175 *bdev = dev->bdev;
176
177 /*
178 * Only pass ioctls through if the device sizes match exactly.
179 */
180 if (dkc->start ||
181 ti->len != i_size_read(dev->bdev->bd_inode) >> SECTOR_SHIFT)
182 return 1;
183 return 0;
184}
185
186static int default_key_iterate_devices(struct dm_target *ti,
187 iterate_devices_callout_fn fn,
188 void *data)
189{
190 struct default_key_c *dkc = ti->private;
191
192 return fn(ti, dkc->dev, dkc->start, ti->len, data);
193}
194
195static struct target_type default_key_target = {
196 .name = "default-key",
197 .version = {1, 0, 0},
198 .module = THIS_MODULE,
199 .ctr = default_key_ctr,
200 .dtr = default_key_dtr,
201 .map = default_key_map,
202 .status = default_key_status,
203 .prepare_ioctl = default_key_prepare_ioctl,
204 .iterate_devices = default_key_iterate_devices,
205};
206
207static int __init dm_default_key_init(void)
208{
209 return dm_register_target(&default_key_target);
210}
211
212static void __exit dm_default_key_exit(void)
213{
214 dm_unregister_target(&default_key_target);
215}
216
217module_init(dm_default_key_init);
218module_exit(dm_default_key_exit);
219
220MODULE_AUTHOR("Paul Lawrence <paullawrence@google.com>");
221MODULE_AUTHOR("Paul Crowley <paulcrowley@google.com>");
222MODULE_AUTHOR("Eric Biggers <ebiggers@google.com>");
223MODULE_DESCRIPTION(DM_NAME " target for encrypting filesystem metadata");
224MODULE_LICENSE("GPL v2");