xref: /openbmc/linux/drivers/md/dm-verity-loadpin.c (revision 2612e3bbc0386368a850140a6c9b990cd496a5ec)
1b6c1c574SMatthias Kaehlcke // SPDX-License-Identifier: GPL-2.0-only
2b6c1c574SMatthias Kaehlcke 
3b6c1c574SMatthias Kaehlcke #include <linux/list.h>
4b6c1c574SMatthias Kaehlcke #include <linux/kernel.h>
5b6c1c574SMatthias Kaehlcke #include <linux/dm-verity-loadpin.h>
6b6c1c574SMatthias Kaehlcke 
7b6c1c574SMatthias Kaehlcke #include "dm.h"
827603a60SMatthias Kaehlcke #include "dm-core.h"
9b6c1c574SMatthias Kaehlcke #include "dm-verity.h"
10b6c1c574SMatthias Kaehlcke 
11b6c1c574SMatthias Kaehlcke #define DM_MSG_PREFIX	"verity-loadpin"
12b6c1c574SMatthias Kaehlcke 
13b6c1c574SMatthias Kaehlcke LIST_HEAD(dm_verity_loadpin_trusted_root_digests);
14b6c1c574SMatthias Kaehlcke 
is_trusted_verity_target(struct dm_target * ti)15b6c1c574SMatthias Kaehlcke static bool is_trusted_verity_target(struct dm_target *ti)
16b6c1c574SMatthias Kaehlcke {
17916ef623SMatthias Kaehlcke 	int verity_mode;
18b6c1c574SMatthias Kaehlcke 	u8 *root_digest;
19b6c1c574SMatthias Kaehlcke 	unsigned int digest_size;
20b6c1c574SMatthias Kaehlcke 	struct dm_verity_loadpin_trusted_root_digest *trd;
21b6c1c574SMatthias Kaehlcke 	bool trusted = false;
22b6c1c574SMatthias Kaehlcke 
23b6c1c574SMatthias Kaehlcke 	if (!dm_is_verity_target(ti))
24b6c1c574SMatthias Kaehlcke 		return false;
25b6c1c574SMatthias Kaehlcke 
26916ef623SMatthias Kaehlcke 	verity_mode = dm_verity_get_mode(ti);
27916ef623SMatthias Kaehlcke 
28916ef623SMatthias Kaehlcke 	if ((verity_mode != DM_VERITY_MODE_EIO) &&
29916ef623SMatthias Kaehlcke 	    (verity_mode != DM_VERITY_MODE_RESTART) &&
30916ef623SMatthias Kaehlcke 	    (verity_mode != DM_VERITY_MODE_PANIC))
31916ef623SMatthias Kaehlcke 		return false;
32916ef623SMatthias Kaehlcke 
33b6c1c574SMatthias Kaehlcke 	if (dm_verity_get_root_digest(ti, &root_digest, &digest_size))
34b6c1c574SMatthias Kaehlcke 		return false;
35b6c1c574SMatthias Kaehlcke 
36b6c1c574SMatthias Kaehlcke 	list_for_each_entry(trd, &dm_verity_loadpin_trusted_root_digests, node) {
37b6c1c574SMatthias Kaehlcke 		if ((trd->len == digest_size) &&
38b6c1c574SMatthias Kaehlcke 		    !memcmp(trd->data, root_digest, digest_size)) {
39b6c1c574SMatthias Kaehlcke 			trusted = true;
40b6c1c574SMatthias Kaehlcke 			break;
41b6c1c574SMatthias Kaehlcke 		}
42b6c1c574SMatthias Kaehlcke 	}
43b6c1c574SMatthias Kaehlcke 
44b6c1c574SMatthias Kaehlcke 	kfree(root_digest);
45b6c1c574SMatthias Kaehlcke 
46b6c1c574SMatthias Kaehlcke 	return trusted;
47b6c1c574SMatthias Kaehlcke }
48b6c1c574SMatthias Kaehlcke 
49b6c1c574SMatthias Kaehlcke /*
50b6c1c574SMatthias Kaehlcke  * Determines whether the file system of a superblock is located on
51b6c1c574SMatthias Kaehlcke  * a verity device that is trusted by LoadPin.
52b6c1c574SMatthias Kaehlcke  */
dm_verity_loadpin_is_bdev_trusted(struct block_device * bdev)53b6c1c574SMatthias Kaehlcke bool dm_verity_loadpin_is_bdev_trusted(struct block_device *bdev)
54b6c1c574SMatthias Kaehlcke {
55b6c1c574SMatthias Kaehlcke 	struct mapped_device *md;
56b6c1c574SMatthias Kaehlcke 	struct dm_table *table;
57b6c1c574SMatthias Kaehlcke 	struct dm_target *ti;
58b6c1c574SMatthias Kaehlcke 	int srcu_idx;
59b6c1c574SMatthias Kaehlcke 	bool trusted = false;
60b6c1c574SMatthias Kaehlcke 
61*47f04616SMatthias Kaehlcke 	if (bdev == NULL)
62*47f04616SMatthias Kaehlcke 		return false;
63*47f04616SMatthias Kaehlcke 
64b6c1c574SMatthias Kaehlcke 	if (list_empty(&dm_verity_loadpin_trusted_root_digests))
65b6c1c574SMatthias Kaehlcke 		return false;
66b6c1c574SMatthias Kaehlcke 
67b6c1c574SMatthias Kaehlcke 	md = dm_get_md(bdev->bd_dev);
68b6c1c574SMatthias Kaehlcke 	if (!md)
69b6c1c574SMatthias Kaehlcke 		return false;
70b6c1c574SMatthias Kaehlcke 
71b6c1c574SMatthias Kaehlcke 	table = dm_get_live_table(md, &srcu_idx);
72b6c1c574SMatthias Kaehlcke 
7327603a60SMatthias Kaehlcke 	if (table->num_targets != 1)
74b6c1c574SMatthias Kaehlcke 		goto out;
75b6c1c574SMatthias Kaehlcke 
76b6c1c574SMatthias Kaehlcke 	ti = dm_table_get_target(table, 0);
77b6c1c574SMatthias Kaehlcke 
78b6c1c574SMatthias Kaehlcke 	if (is_trusted_verity_target(ti))
79b6c1c574SMatthias Kaehlcke 		trusted = true;
80b6c1c574SMatthias Kaehlcke 
81b6c1c574SMatthias Kaehlcke out:
82b6c1c574SMatthias Kaehlcke 	dm_put_live_table(md, srcu_idx);
83b6c1c574SMatthias Kaehlcke 	dm_put(md);
84b6c1c574SMatthias Kaehlcke 
85b6c1c574SMatthias Kaehlcke 	return trusted;
86b6c1c574SMatthias Kaehlcke }
87