Skip to content

Commit b6c1c57

Browse files
Matthias Kaehlckekees
authored andcommitted
dm: Add verity helpers for LoadPin
LoadPin limits loading of kernel modules, firmware and certain other files to a 'pinned' file system (typically a read-only rootfs). To provide more flexibility LoadPin is being extended to also allow loading these files from trusted dm-verity devices. For that purpose LoadPin can be provided with a list of verity root digests that it should consider as trusted. Add a bunch of helpers to allow LoadPin to check whether a DM device is a trusted verity device. The new functions broadly fall in two categories: those that need access to verity internals (like the root digest), and the 'glue' between LoadPin and verity. The new file dm-verity-loadpin.c contains the glue functions. Signed-off-by: Matthias Kaehlcke <[email protected]> Acked-by: Mike Snitzer <[email protected]> Link: https://lore.kernel.org/lkml/20220627083512.v7.1.I3e928575a23481121e73286874c4c2bdb403355d@changeid Signed-off-by: Kees Cook <[email protected]>
1 parent 375561b commit b6c1c57

File tree

5 files changed

+143
-1
lines changed

5 files changed

+143
-1
lines changed

drivers/md/Makefile

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -108,6 +108,12 @@ ifeq ($(CONFIG_DM_VERITY_VERIFY_ROOTHASH_SIG),y)
108108
dm-verity-objs += dm-verity-verify-sig.o
109109
endif
110110

111+
ifeq ($(CONFIG_DM_VERITY),y)
112+
ifeq ($(CONFIG_SECURITY_LOADPIN),y)
113+
dm-verity-objs += dm-verity-loadpin.o
114+
endif
115+
endif
116+
111117
ifeq ($(CONFIG_DM_AUDIT),y)
112118
dm-mod-objs += dm-audit.o
113119
endif

drivers/md/dm-verity-loadpin.c

Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,74 @@
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-verity.h"
9+
10+
#define DM_MSG_PREFIX "verity-loadpin"
11+
12+
LIST_HEAD(dm_verity_loadpin_trusted_root_digests);
13+
14+
static bool is_trusted_verity_target(struct dm_target *ti)
15+
{
16+
u8 *root_digest;
17+
unsigned int digest_size;
18+
struct dm_verity_loadpin_trusted_root_digest *trd;
19+
bool trusted = false;
20+
21+
if (!dm_is_verity_target(ti))
22+
return false;
23+
24+
if (dm_verity_get_root_digest(ti, &root_digest, &digest_size))
25+
return false;
26+
27+
list_for_each_entry(trd, &dm_verity_loadpin_trusted_root_digests, node) {
28+
if ((trd->len == digest_size) &&
29+
!memcmp(trd->data, root_digest, digest_size)) {
30+
trusted = true;
31+
break;
32+
}
33+
}
34+
35+
kfree(root_digest);
36+
37+
return trusted;
38+
}
39+
40+
/*
41+
* Determines whether the file system of a superblock is located on
42+
* a verity device that is trusted by LoadPin.
43+
*/
44+
bool dm_verity_loadpin_is_bdev_trusted(struct block_device *bdev)
45+
{
46+
struct mapped_device *md;
47+
struct dm_table *table;
48+
struct dm_target *ti;
49+
int srcu_idx;
50+
bool trusted = false;
51+
52+
if (list_empty(&dm_verity_loadpin_trusted_root_digests))
53+
return false;
54+
55+
md = dm_get_md(bdev->bd_dev);
56+
if (!md)
57+
return false;
58+
59+
table = dm_get_live_table(md, &srcu_idx);
60+
61+
if (dm_table_get_num_targets(table) != 1)
62+
goto out;
63+
64+
ti = dm_table_get_target(table, 0);
65+
66+
if (is_trusted_verity_target(ti))
67+
trusted = true;
68+
69+
out:
70+
dm_put_live_table(md, srcu_idx);
71+
dm_put(md);
72+
73+
return trusted;
74+
}

drivers/md/dm-verity-target.c

Lines changed: 32 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
#include <linux/module.h>
2020
#include <linux/reboot.h>
2121
#include <linux/scatterlist.h>
22+
#include <linux/string.h>
2223

2324
#define DM_MSG_PREFIX "verity"
2425

@@ -1310,10 +1311,40 @@ static int verity_ctr(struct dm_target *ti, unsigned argc, char **argv)
13101311
return r;
13111312
}
13121313

1314+
/*
1315+
* Check whether a DM target is a verity target.
1316+
*/
1317+
bool dm_is_verity_target(struct dm_target *ti)
1318+
{
1319+
return ti->type->module == THIS_MODULE;
1320+
}
1321+
1322+
/*
1323+
* Get the root digest of a verity target.
1324+
*
1325+
* Returns a copy of the root digest, the caller is responsible for
1326+
* freeing the memory of the digest.
1327+
*/
1328+
int dm_verity_get_root_digest(struct dm_target *ti, u8 **root_digest, unsigned int *digest_size)
1329+
{
1330+
struct dm_verity *v = ti->private;
1331+
1332+
if (!dm_is_verity_target(ti))
1333+
return -EINVAL;
1334+
1335+
*root_digest = kmemdup(v->root_digest, v->digest_size, GFP_KERNEL);
1336+
if (*root_digest == NULL)
1337+
return -ENOMEM;
1338+
1339+
*digest_size = v->digest_size;
1340+
1341+
return 0;
1342+
}
1343+
13131344
static struct target_type verity_target = {
13141345
.name = "verity",
13151346
.features = DM_TARGET_IMMUTABLE,
1316-
.version = {1, 8, 0},
1347+
.version = {1, 8, 1},
13171348
.module = THIS_MODULE,
13181349
.ctr = verity_ctr,
13191350
.dtr = verity_dtr,

drivers/md/dm-verity.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -129,4 +129,8 @@ extern int verity_hash(struct dm_verity *v, struct ahash_request *req,
129129
extern int verity_hash_for_block(struct dm_verity *v, struct dm_verity_io *io,
130130
sector_t block, u8 *digest, bool *is_zero);
131131

132+
extern bool dm_is_verity_target(struct dm_target *ti);
133+
extern int dm_verity_get_root_digest(struct dm_target *ti, u8 **root_digest,
134+
unsigned int *digest_size);
135+
132136
#endif /* DM_VERITY_H */

include/linux/dm-verity-loadpin.h

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
/* SPDX-License-Identifier: GPL-2.0 */
2+
3+
#ifndef __LINUX_DM_VERITY_LOADPIN_H
4+
#define __LINUX_DM_VERITY_LOADPIN_H
5+
6+
#include <linux/list.h>
7+
8+
struct block_device;
9+
10+
extern struct list_head dm_verity_loadpin_trusted_root_digests;
11+
12+
struct dm_verity_loadpin_trusted_root_digest {
13+
struct list_head node;
14+
unsigned int len;
15+
u8 data[];
16+
};
17+
18+
#if IS_ENABLED(CONFIG_SECURITY_LOADPIN) && IS_BUILTIN(CONFIG_DM_VERITY)
19+
bool dm_verity_loadpin_is_bdev_trusted(struct block_device *bdev);
20+
#else
21+
static inline bool dm_verity_loadpin_is_bdev_trusted(struct block_device *bdev)
22+
{
23+
return false;
24+
}
25+
#endif
26+
27+
#endif /* __LINUX_DM_VERITY_LOADPIN_H */

0 commit comments

Comments
 (0)