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