blob: f9491dec3fccd638693d912607f76c7c234304b4 [file] [log] [blame]
Badhri Jagan Sridharan8bb45a52015-12-14 20:09:39 -08001/*
2 * Copyright (C) 2015 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
15#include <linux/buffer_head.h>
Badhri Jagan Sridharand0706bc2016-03-21 10:55:23 -070016#include <linux/debugfs.h>
Badhri Jagan Sridharan8bb45a52015-12-14 20:09:39 -080017#include <linux/delay.h>
18#include <linux/device.h>
19#include <linux/device-mapper.h>
20#include <linux/errno.h>
21#include <linux/fs.h>
22#include <linux/fcntl.h>
23#include <linux/init.h>
24#include <linux/kernel.h>
25#include <linux/key.h>
26#include <linux/module.h>
27#include <linux/mount.h>
28#include <linux/namei.h>
29#include <linux/of.h>
30#include <linux/reboot.h>
31#include <linux/string.h>
32#include <linux/vmalloc.h>
33
34#include <asm/setup.h>
35#include <crypto/hash.h>
Sandeep Patila3c8a092018-07-23 16:31:32 -070036#include <crypto/hash_info.h>
Badhri Jagan Sridharan8bb45a52015-12-14 20:09:39 -080037#include <crypto/public_key.h>
38#include <crypto/sha.h>
39#include <keys/asymmetric-type.h>
40#include <keys/system_keyring.h>
41
42#include "dm-verity.h"
43#include "dm-android-verity.h"
44
45static char verifiedbootstate[VERITY_COMMANDLINE_PARAM_LENGTH];
46static char veritymode[VERITY_COMMANDLINE_PARAM_LENGTH];
Badhri Jagan Sridharanadb82b92016-05-20 16:45:45 -070047static char veritykeyid[VERITY_DEFAULT_KEY_ID_LENGTH];
Badhri Jagan Sridharanc68a6152016-06-17 18:54:35 -070048static char buildvariant[BUILD_VARIANT];
Badhri Jagan Sridharan8bb45a52015-12-14 20:09:39 -080049
Badhri Jagan Sridharand0706bc2016-03-21 10:55:23 -070050static bool target_added;
51static bool verity_enabled = true;
52struct dentry *debug_dir;
53static int android_verity_ctr(struct dm_target *ti, unsigned argc, char **argv);
54
55static struct target_type android_verity_target = {
56 .name = "android-verity",
57 .version = {1, 0, 0},
58 .module = THIS_MODULE,
59 .ctr = android_verity_ctr,
60 .dtr = verity_dtr,
61 .map = verity_map,
62 .status = verity_status,
Badhri Jagan Sridharan424861b2016-08-09 12:47:37 -070063 .prepare_ioctl = verity_prepare_ioctl,
Badhri Jagan Sridharand0706bc2016-03-21 10:55:23 -070064 .iterate_devices = verity_iterate_devices,
65 .io_hints = verity_io_hints,
66};
67
Badhri Jagan Sridharan8bb45a52015-12-14 20:09:39 -080068static int __init verified_boot_state_param(char *line)
69{
70 strlcpy(verifiedbootstate, line, sizeof(verifiedbootstate));
71 return 1;
72}
73
74__setup("androidboot.verifiedbootstate=", verified_boot_state_param);
75
76static int __init verity_mode_param(char *line)
77{
78 strlcpy(veritymode, line, sizeof(veritymode));
79 return 1;
80}
81
82__setup("androidboot.veritymode=", verity_mode_param);
83
Badhri Jagan Sridharanadb82b92016-05-20 16:45:45 -070084static int __init verity_keyid_param(char *line)
85{
86 strlcpy(veritykeyid, line, sizeof(veritykeyid));
87 return 1;
88}
89
90__setup("veritykeyid=", verity_keyid_param);
91
Badhri Jagan Sridharanc68a6152016-06-17 18:54:35 -070092static int __init verity_buildvariant(char *line)
93{
94 strlcpy(buildvariant, line, sizeof(buildvariant));
95 return 1;
96}
97
98__setup("buildvariant=", verity_buildvariant);
99
Badhri Jagan Sridharanadb82b92016-05-20 16:45:45 -0700100static inline bool default_verity_key_id(void)
101{
102 return veritykeyid[0] != '\0';
103}
104
Badhri Jagan Sridharanc68a6152016-06-17 18:54:35 -0700105static inline bool is_eng(void)
106{
107 static const char typeeng[] = "eng";
108
109 return !strncmp(buildvariant, typeeng, sizeof(typeeng));
110}
111
Badhri Jagan Sridharand5943e02016-06-27 16:25:55 -0700112static inline bool is_userdebug(void)
113{
114 static const char typeuserdebug[] = "userdebug";
115
116 return !strncmp(buildvariant, typeuserdebug, sizeof(typeuserdebug));
117}
118
Bowgo Tsai80f190c2017-03-02 18:54:15 +0800119static inline bool is_unlocked(void)
120{
121 static const char unlocked[] = "orange";
122
123 return !strncmp(verifiedbootstate, unlocked, sizeof(unlocked));
124}
Badhri Jagan Sridharand5943e02016-06-27 16:25:55 -0700125
Badhri Jagan Sridharan8bb45a52015-12-14 20:09:39 -0800126static int read_block_dev(struct bio_read *payload, struct block_device *bdev,
127 sector_t offset, int length)
128{
129 struct bio *bio;
130 int err = 0, i;
131
132 payload->number_of_pages = DIV_ROUND_UP(length, PAGE_SIZE);
133
134 bio = bio_alloc(GFP_KERNEL, payload->number_of_pages);
135 if (!bio) {
136 DMERR("Error while allocating bio");
137 return -ENOMEM;
138 }
139
140 bio->bi_bdev = bdev;
Badhri Jagan Sridharan56f6a6b2016-02-08 16:28:43 -0800141 bio->bi_iter.bi_sector = offset;
Sandeep Patila3c8a092018-07-23 16:31:32 -0700142 bio_set_op_attrs(bio, REQ_OP_READ, READ_SYNC);
Badhri Jagan Sridharan8bb45a52015-12-14 20:09:39 -0800143
144 payload->page_io = kzalloc(sizeof(struct page *) *
145 payload->number_of_pages, GFP_KERNEL);
146 if (!payload->page_io) {
147 DMERR("page_io array alloc failed");
148 err = -ENOMEM;
149 goto free_bio;
150 }
151
152 for (i = 0; i < payload->number_of_pages; i++) {
153 payload->page_io[i] = alloc_page(GFP_KERNEL);
154 if (!payload->page_io[i]) {
155 DMERR("alloc_page failed");
156 err = -ENOMEM;
157 goto free_pages;
158 }
159 if (!bio_add_page(bio, payload->page_io[i], PAGE_SIZE, 0)) {
160 DMERR("bio_add_page error");
161 err = -EIO;
162 goto free_pages;
163 }
164 }
165
Sandeep Patila3c8a092018-07-23 16:31:32 -0700166 if (!submit_bio_wait(bio))
Badhri Jagan Sridharan8bb45a52015-12-14 20:09:39 -0800167 /* success */
168 goto free_bio;
169 DMERR("bio read failed");
170 err = -EIO;
171
172free_pages:
173 for (i = 0; i < payload->number_of_pages; i++)
174 if (payload->page_io[i])
175 __free_page(payload->page_io[i]);
176 kfree(payload->page_io);
177free_bio:
178 bio_put(bio);
179 return err;
180}
181
182static inline u64 fec_div_round_up(u64 x, u64 y)
183{
184 u64 remainder;
185
186 return div64_u64_rem(x, y, &remainder) +
187 (remainder > 0 ? 1 : 0);
188}
189
190static inline void populate_fec_metadata(struct fec_header *header,
191 struct fec_ecc_metadata *ecc)
192{
193 ecc->blocks = fec_div_round_up(le64_to_cpu(header->inp_size),
194 FEC_BLOCK_SIZE);
195 ecc->roots = le32_to_cpu(header->roots);
196 ecc->start = le64_to_cpu(header->inp_size);
197}
198
199static inline int validate_fec_header(struct fec_header *header, u64 offset)
200{
201 /* move offset to make the sanity check work for backup header
202 * as well. */
203 offset -= offset % FEC_BLOCK_SIZE;
204 if (le32_to_cpu(header->magic) != FEC_MAGIC ||
205 le32_to_cpu(header->version) != FEC_VERSION ||
206 le32_to_cpu(header->size) != sizeof(struct fec_header) ||
207 le32_to_cpu(header->roots) == 0 ||
Badhri Jagan Sridharan07bec5d2016-09-27 13:48:29 -0700208 le32_to_cpu(header->roots) >= FEC_RSM)
Badhri Jagan Sridharan8bb45a52015-12-14 20:09:39 -0800209 return -EINVAL;
210
211 return 0;
212}
213
214static int extract_fec_header(dev_t dev, struct fec_header *fec,
215 struct fec_ecc_metadata *ecc)
216{
217 u64 device_size;
218 struct bio_read payload;
219 int i, err = 0;
220 struct block_device *bdev;
221
222 bdev = blkdev_get_by_dev(dev, FMODE_READ, NULL);
223
Badhri Jagan Sridharanc68a6152016-06-17 18:54:35 -0700224 if (IS_ERR_OR_NULL(bdev)) {
Badhri Jagan Sridharan8bb45a52015-12-14 20:09:39 -0800225 DMERR("bdev get error");
226 return PTR_ERR(bdev);
227 }
228
229 device_size = i_size_read(bdev->bd_inode);
230
231 /* fec metadata size is a power of 2 and PAGE_SIZE
232 * is a power of 2 as well.
233 */
234 BUG_ON(FEC_BLOCK_SIZE > PAGE_SIZE);
235 /* 512 byte sector alignment */
236 BUG_ON(((device_size - FEC_BLOCK_SIZE) % (1 << SECTOR_SHIFT)) != 0);
237
238 err = read_block_dev(&payload, bdev, (device_size -
239 FEC_BLOCK_SIZE) / (1 << SECTOR_SHIFT), FEC_BLOCK_SIZE);
240 if (err) {
241 DMERR("Error while reading verity metadata");
242 goto error;
243 }
244
245 BUG_ON(sizeof(struct fec_header) > PAGE_SIZE);
246 memcpy(fec, page_address(payload.page_io[0]),
247 sizeof(*fec));
248
249 ecc->valid = true;
250 if (validate_fec_header(fec, device_size - FEC_BLOCK_SIZE)) {
251 /* Try the backup header */
252 memcpy(fec, page_address(payload.page_io[0]) + FEC_BLOCK_SIZE
253 - sizeof(*fec) ,
254 sizeof(*fec));
255 if (validate_fec_header(fec, device_size -
256 sizeof(struct fec_header)))
257 ecc->valid = false;
258 }
259
260 if (ecc->valid)
261 populate_fec_metadata(fec, ecc);
262
263 for (i = 0; i < payload.number_of_pages; i++)
264 __free_page(payload.page_io[i]);
265 kfree(payload.page_io);
266
267error:
268 blkdev_put(bdev, FMODE_READ);
269 return err;
270}
271static void find_metadata_offset(struct fec_header *fec,
272 struct block_device *bdev, u64 *metadata_offset)
273{
274 u64 device_size;
275
276 device_size = i_size_read(bdev->bd_inode);
277
278 if (le32_to_cpu(fec->magic) == FEC_MAGIC)
279 *metadata_offset = le64_to_cpu(fec->inp_size) -
280 VERITY_METADATA_SIZE;
281 else
282 *metadata_offset = device_size - VERITY_METADATA_SIZE;
283}
284
Badhri Jagan Sridharanc68a6152016-06-17 18:54:35 -0700285static int find_size(dev_t dev, u64 *device_size)
286{
287 struct block_device *bdev;
288
289 bdev = blkdev_get_by_dev(dev, FMODE_READ, NULL);
290 if (IS_ERR_OR_NULL(bdev)) {
291 DMERR("blkdev_get_by_dev failed");
292 return PTR_ERR(bdev);
293 }
294
295 *device_size = i_size_read(bdev->bd_inode);
296 *device_size >>= SECTOR_SHIFT;
297
298 DMINFO("blkdev size in sectors: %llu", *device_size);
299 blkdev_put(bdev, FMODE_READ);
300 return 0;
301}
302
Badhri Jagan Sridharan76350642016-07-06 17:16:19 -0700303static int verify_header(struct android_metadata_header *header)
304{
305 int retval = -EINVAL;
306
307 if (is_userdebug() && le32_to_cpu(header->magic_number) ==
308 VERITY_METADATA_MAGIC_DISABLE)
309 return VERITY_STATE_DISABLE;
310
311 if (!(le32_to_cpu(header->magic_number) ==
312 VERITY_METADATA_MAGIC_NUMBER) ||
313 (le32_to_cpu(header->magic_number) ==
314 VERITY_METADATA_MAGIC_DISABLE)) {
315 DMERR("Incorrect magic number");
316 return retval;
317 }
318
319 if (le32_to_cpu(header->protocol_version) !=
320 VERITY_METADATA_VERSION) {
321 DMERR("Unsupported version %u",
322 le32_to_cpu(header->protocol_version));
323 return retval;
324 }
325
326 return 0;
327}
328
329static int extract_metadata(dev_t dev, struct fec_header *fec,
330 struct android_metadata **metadata,
331 bool *verity_enabled)
Badhri Jagan Sridharan8bb45a52015-12-14 20:09:39 -0800332{
333 struct block_device *bdev;
334 struct android_metadata_header *header;
Badhri Jagan Sridharan8bb45a52015-12-14 20:09:39 -0800335 int i;
336 u32 table_length, copy_length, offset;
337 u64 metadata_offset;
338 struct bio_read payload;
339 int err = 0;
340
341 bdev = blkdev_get_by_dev(dev, FMODE_READ, NULL);
342
Badhri Jagan Sridharanc68a6152016-06-17 18:54:35 -0700343 if (IS_ERR_OR_NULL(bdev)) {
Badhri Jagan Sridharan8bb45a52015-12-14 20:09:39 -0800344 DMERR("blkdev_get_by_dev failed");
Badhri Jagan Sridharan76350642016-07-06 17:16:19 -0700345 return -ENODEV;
Badhri Jagan Sridharan8bb45a52015-12-14 20:09:39 -0800346 }
347
348 find_metadata_offset(fec, bdev, &metadata_offset);
349
350 /* Verity metadata size is a power of 2 and PAGE_SIZE
351 * is a power of 2 as well.
352 * PAGE_SIZE is also a multiple of 512 bytes.
353 */
354 if (VERITY_METADATA_SIZE > PAGE_SIZE)
355 BUG_ON(VERITY_METADATA_SIZE % PAGE_SIZE != 0);
356 /* 512 byte sector alignment */
357 BUG_ON(metadata_offset % (1 << SECTOR_SHIFT) != 0);
358
359 err = read_block_dev(&payload, bdev, metadata_offset /
360 (1 << SECTOR_SHIFT), VERITY_METADATA_SIZE);
361 if (err) {
362 DMERR("Error while reading verity metadata");
Badhri Jagan Sridharan8bb45a52015-12-14 20:09:39 -0800363 goto blkdev_release;
364 }
365
366 header = kzalloc(sizeof(*header), GFP_KERNEL);
367 if (!header) {
368 DMERR("kzalloc failed for header");
369 err = -ENOMEM;
370 goto free_payload;
371 }
372
373 memcpy(header, page_address(payload.page_io[0]),
374 sizeof(*header));
375
376 DMINFO("bio magic_number:%u protocol_version:%d table_length:%u",
377 le32_to_cpu(header->magic_number),
378 le32_to_cpu(header->protocol_version),
379 le32_to_cpu(header->table_length));
380
Badhri Jagan Sridharan76350642016-07-06 17:16:19 -0700381 err = verify_header(header);
382
383 if (err == VERITY_STATE_DISABLE) {
384 DMERR("Mounting root with verity disabled");
385 *verity_enabled = false;
386 /* we would still have to read the metadata to figure out
387 * the data blocks size. Or may be could map the entire
388 * partition similar to mounting the device.
389 *
390 * Reset error as well as the verity_enabled flag is changed.
391 */
392 err = 0;
393 } else if (err)
394 goto free_header;
395
396 *metadata = kzalloc(sizeof(**metadata), GFP_KERNEL);
397 if (!*metadata) {
Badhri Jagan Sridharan8bb45a52015-12-14 20:09:39 -0800398 DMERR("kzalloc for metadata failed");
399 err = -ENOMEM;
400 goto free_header;
401 }
402
Badhri Jagan Sridharan76350642016-07-06 17:16:19 -0700403 (*metadata)->header = header;
Badhri Jagan Sridharan8bb45a52015-12-14 20:09:39 -0800404 table_length = le32_to_cpu(header->table_length);
405
406 if (table_length == 0 ||
407 table_length > (VERITY_METADATA_SIZE -
Badhri Jagan Sridharan76350642016-07-06 17:16:19 -0700408 sizeof(struct android_metadata_header))) {
409 DMERR("table_length too long");
410 err = -EINVAL;
Badhri Jagan Sridharan8bb45a52015-12-14 20:09:39 -0800411 goto free_metadata;
Badhri Jagan Sridharan76350642016-07-06 17:16:19 -0700412 }
Badhri Jagan Sridharan8bb45a52015-12-14 20:09:39 -0800413
Badhri Jagan Sridharan76350642016-07-06 17:16:19 -0700414 (*metadata)->verity_table = kzalloc(table_length + 1, GFP_KERNEL);
Badhri Jagan Sridharan8bb45a52015-12-14 20:09:39 -0800415
Badhri Jagan Sridharan76350642016-07-06 17:16:19 -0700416 if (!(*metadata)->verity_table) {
Badhri Jagan Sridharan8bb45a52015-12-14 20:09:39 -0800417 DMERR("kzalloc verity_table failed");
418 err = -ENOMEM;
419 goto free_metadata;
420 }
421
422 if (sizeof(struct android_metadata_header) +
423 table_length <= PAGE_SIZE) {
Badhri Jagan Sridharan76350642016-07-06 17:16:19 -0700424 memcpy((*metadata)->verity_table,
425 page_address(payload.page_io[0])
Badhri Jagan Sridharan8bb45a52015-12-14 20:09:39 -0800426 + sizeof(struct android_metadata_header),
427 table_length);
428 } else {
429 copy_length = PAGE_SIZE -
430 sizeof(struct android_metadata_header);
Badhri Jagan Sridharan76350642016-07-06 17:16:19 -0700431 memcpy((*metadata)->verity_table,
432 page_address(payload.page_io[0])
Badhri Jagan Sridharan8bb45a52015-12-14 20:09:39 -0800433 + sizeof(struct android_metadata_header),
434 copy_length);
435 table_length -= copy_length;
436 offset = copy_length;
437 i = 1;
438 while (table_length != 0) {
439 if (table_length > PAGE_SIZE) {
Badhri Jagan Sridharan76350642016-07-06 17:16:19 -0700440 memcpy((*metadata)->verity_table + offset,
Badhri Jagan Sridharan8bb45a52015-12-14 20:09:39 -0800441 page_address(payload.page_io[i]),
442 PAGE_SIZE);
443 offset += PAGE_SIZE;
444 table_length -= PAGE_SIZE;
445 } else {
Badhri Jagan Sridharan76350642016-07-06 17:16:19 -0700446 memcpy((*metadata)->verity_table + offset,
Badhri Jagan Sridharan8bb45a52015-12-14 20:09:39 -0800447 page_address(payload.page_io[i]),
448 table_length);
449 table_length = 0;
450 }
451 i++;
452 }
453 }
Badhri Jagan Sridharan76350642016-07-06 17:16:19 -0700454 (*metadata)->verity_table[table_length] = '\0';
Badhri Jagan Sridharan8bb45a52015-12-14 20:09:39 -0800455
Badhri Jagan Sridharan76350642016-07-06 17:16:19 -0700456 DMINFO("verity_table: %s", (*metadata)->verity_table);
Badhri Jagan Sridharan8bb45a52015-12-14 20:09:39 -0800457 goto free_payload;
458
459free_metadata:
Badhri Jagan Sridharan76350642016-07-06 17:16:19 -0700460 kfree(*metadata);
Badhri Jagan Sridharan8bb45a52015-12-14 20:09:39 -0800461free_header:
462 kfree(header);
Badhri Jagan Sridharan8bb45a52015-12-14 20:09:39 -0800463free_payload:
464 for (i = 0; i < payload.number_of_pages; i++)
465 if (payload.page_io[i])
466 __free_page(payload.page_io[i]);
467 kfree(payload.page_io);
Badhri Jagan Sridharan8bb45a52015-12-14 20:09:39 -0800468blkdev_release:
469 blkdev_put(bdev, FMODE_READ);
Badhri Jagan Sridharan76350642016-07-06 17:16:19 -0700470 return err;
Badhri Jagan Sridharan8bb45a52015-12-14 20:09:39 -0800471}
472
473/* helper functions to extract properties from dts */
474const char *find_dt_value(const char *name)
475{
476 struct device_node *firmware;
477 const char *value;
478
479 firmware = of_find_node_by_path("/firmware/android");
480 if (!firmware)
481 return NULL;
482 value = of_get_property(firmware, name, NULL);
483 of_node_put(firmware);
484
485 return value;
486}
487
Badhri Jagan Sridharan8bb45a52015-12-14 20:09:39 -0800488static int verity_mode(void)
489{
490 static const char enforcing[] = "enforcing";
491 static const char verified_mode_prop[] = "veritymode";
492 const char *value;
493
494 value = find_dt_value(verified_mode_prop);
495 if (!value)
496 value = veritymode;
497 if (!strncmp(value, enforcing, sizeof(enforcing) - 1))
498 return DM_VERITY_MODE_RESTART;
499
500 return DM_VERITY_MODE_EIO;
501}
502
Badhri Jagan Sridharan8bb45a52015-12-14 20:09:39 -0800503static void handle_error(void)
504{
505 int mode = verity_mode();
506 if (mode == DM_VERITY_MODE_RESTART) {
507 DMERR("triggering restart");
508 kernel_restart("dm-verity device corrupted");
509 } else {
510 DMERR("Mounting verity root failed");
511 }
512}
513
Sandeep Patila3c8a092018-07-23 16:31:32 -0700514static struct public_key_signature *table_make_digest(
515 enum hash_algo hash,
516 const void *table,
517 unsigned long table_len)
518{
519 struct public_key_signature *pks = NULL;
520 struct crypto_shash *tfm;
521 struct shash_desc *desc;
522 size_t digest_size, desc_size;
523 int ret;
524
525 /* Allocate the hashing algorithm we're going to need and find out how
526 * big the hash operational data will be.
527 */
528 tfm = crypto_alloc_shash(hash_algo_name[hash], 0, 0);
529 if (IS_ERR(tfm))
530 return ERR_CAST(tfm);
531
532 desc_size = crypto_shash_descsize(tfm) + sizeof(*desc);
533 digest_size = crypto_shash_digestsize(tfm);
534
535 /* We allocate the hash operational data storage on the end of out
536 * context data and the digest output buffer on the end of that.
537 */
538 ret = -ENOMEM;
539 pks = kzalloc(digest_size + sizeof(*pks) + desc_size, GFP_KERNEL);
540 if (!pks)
541 goto error;
542
543 pks->pkey_algo = "rsa";
544 pks->hash_algo = hash_algo_name[hash];
545 pks->digest = (u8 *)pks + sizeof(*pks) + desc_size;
546 pks->digest_size = digest_size;
547
548 desc = (struct shash_desc *)(pks + 1);
549 desc->tfm = tfm;
550 desc->flags = CRYPTO_TFM_REQ_MAY_SLEEP;
551
552 ret = crypto_shash_init(desc);
553 if (ret < 0)
554 goto error;
555
556 ret = crypto_shash_finup(desc, table, table_len, pks->digest);
557 if (ret < 0)
558 goto error;
559
560 crypto_free_shash(tfm);
561 return pks;
562
563error:
564 kfree(pks);
565 crypto_free_shash(tfm);
566 return ERR_PTR(ret);
567}
568
569
570static int verify_verity_signature(char *key_id,
571 struct android_metadata *metadata)
572{
573 struct public_key_signature *pks = NULL;
574 int retval = -EINVAL;
575
576 if (!key_id)
577 goto error;
578
579 pks = table_make_digest(HASH_ALGO_SHA256,
580 (const void *)metadata->verity_table,
581 le32_to_cpu(metadata->header->table_length));
582 if (IS_ERR(pks)) {
583 DMERR("hashing failed");
584 retval = PTR_ERR(pks);
585 pks = NULL;
586 goto error;
587 }
588
589 pks->s = kmemdup(&metadata->header->signature[0], RSANUMBYTES, GFP_KERNEL);
590 if (!pks->s) {
591 DMERR("Error allocating memory for signature");
592 goto error;
593 }
594 pks->s_size = RSANUMBYTES;
595
596 retval = verify_signature_one(pks, NULL, key_id);
597 kfree(pks->s);
598error:
599 kfree(pks);
600 return retval;
601}
602
Badhri Jagan Sridharan8bb45a52015-12-14 20:09:39 -0800603static inline bool test_mult_overflow(sector_t a, u32 b)
604{
605 sector_t r = (sector_t)~0ULL;
606
607 sector_div(r, b);
608 return a > r;
609}
610
Badhri Jagan Sridharand0706bc2016-03-21 10:55:23 -0700611static int add_as_linear_device(struct dm_target *ti, char *dev)
612{
613 /*Move to linear mapping defines*/
Badhri Jagan Sridharan7e702182016-03-28 14:41:21 -0700614 char *linear_table_args[DM_LINEAR_ARGS] = {dev,
615 DM_LINEAR_TARGET_OFFSET};
Badhri Jagan Sridharand0706bc2016-03-21 10:55:23 -0700616 int err = 0;
617
Badhri Jagan Sridharan67584ff2016-04-05 11:18:16 -0700618 android_verity_target.dtr = dm_linear_dtr,
619 android_verity_target.map = dm_linear_map,
620 android_verity_target.status = dm_linear_status,
Badhri Jagan Sridharan424861b2016-08-09 12:47:37 -0700621 android_verity_target.prepare_ioctl = dm_linear_prepare_ioctl,
Badhri Jagan Sridharan67584ff2016-04-05 11:18:16 -0700622 android_verity_target.iterate_devices = dm_linear_iterate_devices,
Badhri Jagan Sridharanc5b8dcd2017-01-13 11:05:00 -0800623 android_verity_target.direct_access = dm_linear_direct_access,
Badhri Jagan Sridharand0706bc2016-03-21 10:55:23 -0700624 android_verity_target.io_hints = NULL;
625
Badhri Jagan Sridharanc4676ff2016-06-03 13:16:59 -0700626 set_disk_ro(dm_disk(dm_table_get_md(ti->table)), 0);
627
Badhri Jagan Sridharan67584ff2016-04-05 11:18:16 -0700628 err = dm_linear_ctr(ti, DM_LINEAR_ARGS, linear_table_args);
Badhri Jagan Sridharand0706bc2016-03-21 10:55:23 -0700629
630 if (!err) {
631 DMINFO("Added android-verity as a linear target");
632 target_added = true;
633 } else
634 DMERR("Failed to add android-verity as linear target");
635
636 return err;
637}
638
Bowgo Tsai80f190c2017-03-02 18:54:15 +0800639static int create_linear_device(struct dm_target *ti, dev_t dev,
640 char *target_device)
641{
642 u64 device_size = 0;
643 int err = find_size(dev, &device_size);
644
645 if (err) {
646 DMERR("error finding bdev size");
647 handle_error();
648 return err;
649 }
650
651 ti->len = device_size;
652 err = add_as_linear_device(ti, target_device);
653 if (err) {
654 handle_error();
655 return err;
656 }
657 verity_enabled = false;
658 return 0;
659}
660
Badhri Jagan Sridharan8bb45a52015-12-14 20:09:39 -0800661/*
662 * Target parameters:
663 * <key id> Key id of the public key in the system keyring.
664 * Verity metadata's signature would be verified against
665 * this. If the key id contains spaces, replace them
666 * with '#'.
667 * <block device> The block device for which dm-verity is being setup.
668 */
669static int android_verity_ctr(struct dm_target *ti, unsigned argc, char **argv)
670{
671 dev_t uninitialized_var(dev);
Badhri Jagan Sridharan76350642016-07-06 17:16:19 -0700672 struct android_metadata *metadata = NULL;
Badhri Jagan Sridharan8bb45a52015-12-14 20:09:39 -0800673 int err = 0, i, mode;
Sandeep Patila3c8a092018-07-23 16:31:32 -0700674 char *key_id = NULL, *table_ptr, dummy, *target_device;
675 char *verity_table_args[VERITY_TABLE_ARGS + 2 + VERITY_TABLE_OPT_FEC_ARGS];
Badhri Jagan Sridharan8bb45a52015-12-14 20:09:39 -0800676 /* One for specifying number of opt args and one for mode */
677 sector_t data_sectors;
678 u32 data_block_size;
Jeremy Compostella0b768a42016-04-15 13:32:54 +0200679 unsigned int no_of_args = VERITY_TABLE_ARGS + 2 + VERITY_TABLE_OPT_FEC_ARGS;
Badhri Jagan Sridharan56f6a6b2016-02-08 16:28:43 -0800680 struct fec_header uninitialized_var(fec);
Badhri Jagan Sridharan8bb45a52015-12-14 20:09:39 -0800681 struct fec_ecc_metadata uninitialized_var(ecc);
682 char buf[FEC_ARG_LENGTH], *buf_ptr;
683 unsigned long long tmpll;
684
Badhri Jagan Sridharanadb82b92016-05-20 16:45:45 -0700685 if (argc == 1) {
686 /* Use the default keyid */
687 if (default_verity_key_id())
688 key_id = veritykeyid;
Badhri Jagan Sridharanc68a6152016-06-17 18:54:35 -0700689 else if (!is_eng()) {
Badhri Jagan Sridharanadb82b92016-05-20 16:45:45 -0700690 DMERR("veritykeyid= is not set");
691 handle_error();
692 return -EINVAL;
693 }
Sandeep Patiled62e1e52018-07-24 16:59:40 -0700694 target_device = argv[0];
695 } else if (argc == 2) {
696 key_id = argv[0];
697 target_device = argv[1];
698 } else {
Badhri Jagan Sridharan8bb45a52015-12-14 20:09:39 -0800699 DMERR("Incorrect number of arguments");
700 handle_error();
701 return -EINVAL;
702 }
703
Badhri Jagan Sridharanadb82b92016-05-20 16:45:45 -0700704 dev = name_to_dev_t(target_device);
Jeremy Compostella0b768a42016-04-15 13:32:54 +0200705 if (!dev) {
Badhri Jagan Sridharanadb82b92016-05-20 16:45:45 -0700706 DMERR("no dev found for %s", target_device);
Jeremy Compostella0b768a42016-04-15 13:32:54 +0200707 handle_error();
708 return -EINVAL;
Badhri Jagan Sridharan8bb45a52015-12-14 20:09:39 -0800709 }
710
Bowgo Tsai80f190c2017-03-02 18:54:15 +0800711 if (is_eng())
712 return create_linear_device(ti, dev, target_device);
Badhri Jagan Sridharanc68a6152016-06-17 18:54:35 -0700713
714 strreplace(key_id, '#', ' ');
715
Badhri Jagan Sridharanadb82b92016-05-20 16:45:45 -0700716 DMINFO("key:%s dev:%s", key_id, target_device);
Badhri Jagan Sridharan8bb45a52015-12-14 20:09:39 -0800717
718 if (extract_fec_header(dev, &fec, &ecc)) {
719 DMERR("Error while extracting fec header");
720 handle_error();
721 return -EINVAL;
722 }
723
Badhri Jagan Sridharan76350642016-07-06 17:16:19 -0700724 err = extract_metadata(dev, &fec, &metadata, &verity_enabled);
Badhri Jagan Sridharan8bb45a52015-12-14 20:09:39 -0800725
Badhri Jagan Sridharan76350642016-07-06 17:16:19 -0700726 if (err) {
Bowgo Tsai80f190c2017-03-02 18:54:15 +0800727 /* Allow invalid metadata when the device is unlocked */
728 if (is_unlocked()) {
729 DMWARN("Allow invalid metadata when unlocked");
730 return create_linear_device(ti, dev, target_device);
731 }
Badhri Jagan Sridharan8bb45a52015-12-14 20:09:39 -0800732 DMERR("Error while extracting metadata");
733 handle_error();
Badhri Jagan Sridharan8bb45a52015-12-14 20:09:39 -0800734 goto free_metadata;
735 }
736
Badhri Jagan Sridharane96affa2016-05-20 16:44:19 -0700737 if (verity_enabled) {
Badhri Jagan Sridharand0706bc2016-03-21 10:55:23 -0700738 err = verify_verity_signature(key_id, metadata);
Badhri Jagan Sridharan8bb45a52015-12-14 20:09:39 -0800739
Badhri Jagan Sridharand0706bc2016-03-21 10:55:23 -0700740 if (err) {
741 DMERR("Signature verification failed");
742 handle_error();
743 goto free_metadata;
744 } else
745 DMINFO("Signature verification success");
746 }
Badhri Jagan Sridharan8bb45a52015-12-14 20:09:39 -0800747
748 table_ptr = metadata->verity_table;
749
750 for (i = 0; i < VERITY_TABLE_ARGS; i++) {
751 verity_table_args[i] = strsep(&table_ptr, " ");
752 if (verity_table_args[i] == NULL)
753 break;
754 }
755
756 if (i != VERITY_TABLE_ARGS) {
757 DMERR("Verity table not in the expected format");
758 err = -EINVAL;
759 handle_error();
760 goto free_metadata;
761 }
762
763 if (sscanf(verity_table_args[5], "%llu%c", &tmpll, &dummy)
764 != 1) {
765 DMERR("Verity table not in the expected format");
766 handle_error();
767 err = -EINVAL;
768 goto free_metadata;
769 }
770
771 if (tmpll > ULONG_MAX) {
772 DMERR("<num_data_blocks> too large. Forgot to turn on CONFIG_LBDAF?");
773 handle_error();
774 err = -EINVAL;
775 goto free_metadata;
776 }
777
778 data_sectors = tmpll;
779
780 if (sscanf(verity_table_args[3], "%u%c", &data_block_size, &dummy)
781 != 1) {
782 DMERR("Verity table not in the expected format");
783 handle_error();
784 err = -EINVAL;
785 goto free_metadata;
786 }
787
788 if (test_mult_overflow(data_sectors, data_block_size >>
789 SECTOR_SHIFT)) {
790 DMERR("data_sectors too large");
791 handle_error();
792 err = -EOVERFLOW;
793 goto free_metadata;
794 }
795
796 data_sectors *= data_block_size >> SECTOR_SHIFT;
797 DMINFO("Data sectors %llu", (unsigned long long)data_sectors);
798
799 /* update target length */
800 ti->len = data_sectors;
801
Badhri Jagan Sridharand0706bc2016-03-21 10:55:23 -0700802 /* Setup linear target and free */
803 if (!verity_enabled) {
Badhri Jagan Sridharanadb82b92016-05-20 16:45:45 -0700804 err = add_as_linear_device(ti, target_device);
Badhri Jagan Sridharand0706bc2016-03-21 10:55:23 -0700805 goto free_metadata;
806 }
807
Badhri Jagan Sridharan8bb45a52015-12-14 20:09:39 -0800808 /*substitute data_dev and hash_dev*/
Badhri Jagan Sridharanadb82b92016-05-20 16:45:45 -0700809 verity_table_args[1] = target_device;
810 verity_table_args[2] = target_device;
Badhri Jagan Sridharan8bb45a52015-12-14 20:09:39 -0800811
812 mode = verity_mode();
813
814 if (ecc.valid && IS_BUILTIN(CONFIG_DM_VERITY_FEC)) {
815 if (mode) {
816 err = snprintf(buf, FEC_ARG_LENGTH,
Badhri Jagan Sridharanadb82b92016-05-20 16:45:45 -0700817 "%u %s " VERITY_TABLE_OPT_FEC_FORMAT,
818 1 + VERITY_TABLE_OPT_FEC_ARGS,
819 mode == DM_VERITY_MODE_RESTART ?
820 VERITY_TABLE_OPT_RESTART :
821 VERITY_TABLE_OPT_LOGGING,
822 target_device,
823 ecc.start / FEC_BLOCK_SIZE, ecc.blocks,
824 ecc.roots);
Badhri Jagan Sridharan8bb45a52015-12-14 20:09:39 -0800825 } else {
826 err = snprintf(buf, FEC_ARG_LENGTH,
Badhri Jagan Sridharanadb82b92016-05-20 16:45:45 -0700827 "%u " VERITY_TABLE_OPT_FEC_FORMAT,
828 VERITY_TABLE_OPT_FEC_ARGS, target_device,
829 ecc.start / FEC_BLOCK_SIZE, ecc.blocks,
830 ecc.roots);
Badhri Jagan Sridharan8bb45a52015-12-14 20:09:39 -0800831 }
832 } else if (mode) {
833 err = snprintf(buf, FEC_ARG_LENGTH,
834 "2 " VERITY_TABLE_OPT_IGNZERO " %s",
835 mode == DM_VERITY_MODE_RESTART ?
836 VERITY_TABLE_OPT_RESTART : VERITY_TABLE_OPT_LOGGING);
837 } else {
838 err = snprintf(buf, FEC_ARG_LENGTH, "1 %s",
839 "ignore_zero_blocks");
840 }
841
842 if (err < 0 || err >= FEC_ARG_LENGTH)
843 goto free_metadata;
844
845 buf_ptr = buf;
846
847 for (i = VERITY_TABLE_ARGS; i < (VERITY_TABLE_ARGS +
848 VERITY_TABLE_OPT_FEC_ARGS + 2); i++) {
849 verity_table_args[i] = strsep(&buf_ptr, " ");
850 if (verity_table_args[i] == NULL) {
851 no_of_args = i;
852 break;
853 }
854 }
855
856 err = verity_ctr(ti, no_of_args, verity_table_args);
Sandeep Patila3c8a092018-07-23 16:31:32 -0700857 if (err) {
858 DMERR("android-verity failed to create a verity target");
859 } else {
Badhri Jagan Sridharand0706bc2016-03-21 10:55:23 -0700860 target_added = true;
Sandeep Patila3c8a092018-07-23 16:31:32 -0700861 DMINFO("android-verity created as verity target");
Badhri Jagan Sridharand0706bc2016-03-21 10:55:23 -0700862 }
863
Badhri Jagan Sridharan8bb45a52015-12-14 20:09:39 -0800864free_metadata:
Badhri Jagan Sridharan76350642016-07-06 17:16:19 -0700865 if (metadata) {
866 kfree(metadata->header);
867 kfree(metadata->verity_table);
868 }
Badhri Jagan Sridharan8bb45a52015-12-14 20:09:39 -0800869 kfree(metadata);
870 return err;
871}
872
Badhri Jagan Sridharan8bb45a52015-12-14 20:09:39 -0800873static int __init dm_android_verity_init(void)
874{
875 int r;
Badhri Jagan Sridharand0706bc2016-03-21 10:55:23 -0700876 struct dentry *file;
Badhri Jagan Sridharan8bb45a52015-12-14 20:09:39 -0800877
878 r = dm_register_target(&android_verity_target);
879 if (r < 0)
880 DMERR("register failed %d", r);
881
Badhri Jagan Sridharand0706bc2016-03-21 10:55:23 -0700882 /* Tracks the status of the last added target */
883 debug_dir = debugfs_create_dir("android_verity", NULL);
884
885 if (IS_ERR_OR_NULL(debug_dir)) {
886 DMERR("Cannot create android_verity debugfs directory: %ld",
887 PTR_ERR(debug_dir));
888 goto end;
889 }
890
891 file = debugfs_create_bool("target_added", S_IRUGO, debug_dir,
Badhri Jagan Sridharan424861b2016-08-09 12:47:37 -0700892 &target_added);
Badhri Jagan Sridharand0706bc2016-03-21 10:55:23 -0700893
894 if (IS_ERR_OR_NULL(file)) {
895 DMERR("Cannot create android_verity debugfs directory: %ld",
896 PTR_ERR(debug_dir));
897 debugfs_remove_recursive(debug_dir);
898 goto end;
899 }
900
901 file = debugfs_create_bool("verity_enabled", S_IRUGO, debug_dir,
Badhri Jagan Sridharan424861b2016-08-09 12:47:37 -0700902 &verity_enabled);
Badhri Jagan Sridharand0706bc2016-03-21 10:55:23 -0700903
904 if (IS_ERR_OR_NULL(file)) {
905 DMERR("Cannot create android_verity debugfs directory: %ld",
906 PTR_ERR(debug_dir));
907 debugfs_remove_recursive(debug_dir);
908 }
909
910end:
Badhri Jagan Sridharan8bb45a52015-12-14 20:09:39 -0800911 return r;
912}
913
914static void __exit dm_android_verity_exit(void)
915{
Badhri Jagan Sridharand0706bc2016-03-21 10:55:23 -0700916 if (!IS_ERR_OR_NULL(debug_dir))
917 debugfs_remove_recursive(debug_dir);
918
Badhri Jagan Sridharan8bb45a52015-12-14 20:09:39 -0800919 dm_unregister_target(&android_verity_target);
920}
921
922module_init(dm_android_verity_init);
923module_exit(dm_android_verity_exit);