summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJaskaran Khurana <jaskarankhurana@linux.microsoft.com>2019-07-17 20:46:15 -0400
committerMike Snitzer <snitzer@redhat.com>2019-08-23 10:13:14 -0400
commit88cd3e6cfac915f50f7aa7b699bdf053afec866e (patch)
treea7fe35abcd39a0f98375d77a0a8e43d2bec60092
parent39d13a1ac41dc8254f484fcd21af7ff05e316fad (diff)
dm verity: add root hash pkcs#7 signature verification
The verification is to support cases where the root hash is not secured by Trusted Boot, UEFI Secureboot or similar technologies. One of the use cases for this is for dm-verity volumes mounted after boot, the root hash provided during the creation of the dm-verity volume has to be secure and thus in-kernel validation implemented here will be used before we trust the root hash and allow the block device to be created. The signature being provided for verification must verify the root hash and must be trusted by the builtin keyring for verification to succeed. The hash is added as a key of type "user" and the description is passed to the kernel so it can look it up and use it for verification. Adds CONFIG_DM_VERITY_VERIFY_ROOTHASH_SIG which can be turned on if root hash verification is needed. Kernel commandline dm_verity module parameter 'require_signatures' will indicate whether to force root hash signature verification (for all dm verity volumes). Signed-off-by: Jaskaran Khurana <jaskarankhurana@linux.microsoft.com> Tested-and-Reviewed-by: Milan Broz <gmazyland@gmail.com> Signed-off-by: Mike Snitzer <snitzer@redhat.com>
-rw-r--r--Documentation/admin-guide/device-mapper/verity.rst7
-rw-r--r--drivers/md/Kconfig12
-rw-r--r--drivers/md/Makefile4
-rw-r--r--drivers/md/dm-verity-target.c43
-rw-r--r--drivers/md/dm-verity-verify-sig.c133
-rw-r--r--drivers/md/dm-verity-verify-sig.h60
-rw-r--r--drivers/md/dm-verity.h2
7 files changed, 256 insertions, 5 deletions
diff --git a/Documentation/admin-guide/device-mapper/verity.rst b/Documentation/admin-guide/device-mapper/verity.rst
index a4d1c1476d72..bb02caa45289 100644
--- a/Documentation/admin-guide/device-mapper/verity.rst
+++ b/Documentation/admin-guide/device-mapper/verity.rst
@@ -125,6 +125,13 @@ check_at_most_once
125 blocks, and a hash block will not be verified any more after all the data 125 blocks, and a hash block will not be verified any more after all the data
126 blocks it covers have been verified anyway. 126 blocks it covers have been verified anyway.
127 127
128root_hash_sig_key_desc <key_description>
129 This is the description of the USER_KEY that the kernel will lookup to get
130 the pkcs7 signature of the roothash. The pkcs7 signature is used to validate
131 the root hash during the creation of the device mapper block device.
132 Verification of roothash depends on the config DM_VERITY_VERIFY_ROOTHASH_SIG
133 being set in the kernel.
134
128Theory of operation 135Theory of operation
129=================== 136===================
130 137
diff --git a/drivers/md/Kconfig b/drivers/md/Kconfig
index 3834332f4963..1856c0fb665d 100644
--- a/drivers/md/Kconfig
+++ b/drivers/md/Kconfig
@@ -490,6 +490,18 @@ config DM_VERITY
490 490
491 If unsure, say N. 491 If unsure, say N.
492 492
493config DM_VERITY_VERIFY_ROOTHASH_SIG
494 def_bool n
495 bool "Verity data device root hash signature verification support"
496 depends on DM_VERITY
497 select SYSTEM_DATA_VERIFICATION
498 help
499 Add ability for dm-verity device to be validated if the
500 pre-generated tree of cryptographic checksums passed has a pkcs#7
501 signature file that can validate the roothash of the tree.
502
503 If unsure, say N.
504
493config DM_VERITY_FEC 505config DM_VERITY_FEC
494 bool "Verity forward error correction support" 506 bool "Verity forward error correction support"
495 depends on DM_VERITY 507 depends on DM_VERITY
diff --git a/drivers/md/Makefile b/drivers/md/Makefile
index be7a6eb92abc..0d922335335c 100644
--- a/drivers/md/Makefile
+++ b/drivers/md/Makefile
@@ -81,3 +81,7 @@ endif
81ifeq ($(CONFIG_DM_VERITY_FEC),y) 81ifeq ($(CONFIG_DM_VERITY_FEC),y)
82dm-verity-objs += dm-verity-fec.o 82dm-verity-objs += dm-verity-fec.o
83endif 83endif
84
85ifeq ($(CONFIG_DM_VERITY_VERIFY_ROOTHASH_SIG),y)
86dm-verity-objs += dm-verity-verify-sig.o
87endif
diff --git a/drivers/md/dm-verity-target.c b/drivers/md/dm-verity-target.c
index ea24ff0612e3..4fb33e7562c5 100644
--- a/drivers/md/dm-verity-target.c
+++ b/drivers/md/dm-verity-target.c
@@ -15,7 +15,7 @@
15 15
16#include "dm-verity.h" 16#include "dm-verity.h"
17#include "dm-verity-fec.h" 17#include "dm-verity-fec.h"
18 18#include "dm-verity-verify-sig.h"
19#include <linux/module.h> 19#include <linux/module.h>
20#include <linux/reboot.h> 20#include <linux/reboot.h>
21 21
@@ -33,7 +33,8 @@
33#define DM_VERITY_OPT_IGN_ZEROES "ignore_zero_blocks" 33#define DM_VERITY_OPT_IGN_ZEROES "ignore_zero_blocks"
34#define DM_VERITY_OPT_AT_MOST_ONCE "check_at_most_once" 34#define DM_VERITY_OPT_AT_MOST_ONCE "check_at_most_once"
35 35
36#define DM_VERITY_OPTS_MAX (2 + DM_VERITY_OPTS_FEC) 36#define DM_VERITY_OPTS_MAX (2 + DM_VERITY_OPTS_FEC + \
37 DM_VERITY_ROOT_HASH_VERIFICATION_OPTS)
37 38
38static unsigned dm_verity_prefetch_cluster = DM_VERITY_DEFAULT_PREFETCH_SIZE; 39static unsigned dm_verity_prefetch_cluster = DM_VERITY_DEFAULT_PREFETCH_SIZE;
39 40
@@ -713,6 +714,8 @@ static void verity_status(struct dm_target *ti, status_type_t type,
713 args++; 714 args++;
714 if (v->validated_blocks) 715 if (v->validated_blocks)
715 args++; 716 args++;
717 if (v->signature_key_desc)
718 args += DM_VERITY_ROOT_HASH_VERIFICATION_OPTS;
716 if (!args) 719 if (!args)
717 return; 720 return;
718 DMEMIT(" %u", args); 721 DMEMIT(" %u", args);
@@ -734,6 +737,9 @@ static void verity_status(struct dm_target *ti, status_type_t type,
734 if (v->validated_blocks) 737 if (v->validated_blocks)
735 DMEMIT(" " DM_VERITY_OPT_AT_MOST_ONCE); 738 DMEMIT(" " DM_VERITY_OPT_AT_MOST_ONCE);
736 sz = verity_fec_status_table(v, sz, result, maxlen); 739 sz = verity_fec_status_table(v, sz, result, maxlen);
740 if (v->signature_key_desc)
741 DMEMIT(" " DM_VERITY_ROOT_HASH_VERIFICATION_OPT_SIG_KEY
742 " %s", v->signature_key_desc);
737 break; 743 break;
738 } 744 }
739} 745}
@@ -799,6 +805,8 @@ static void verity_dtr(struct dm_target *ti)
799 805
800 verity_fec_dtr(v); 806 verity_fec_dtr(v);
801 807
808 kfree(v->signature_key_desc);
809
802 kfree(v); 810 kfree(v);
803} 811}
804 812
@@ -854,7 +862,8 @@ out:
854 return r; 862 return r;
855} 863}
856 864
857static int verity_parse_opt_args(struct dm_arg_set *as, struct dm_verity *v) 865static int verity_parse_opt_args(struct dm_arg_set *as, struct dm_verity *v,
866 struct dm_verity_sig_opts *verify_args)
858{ 867{
859 int r; 868 int r;
860 unsigned argc; 869 unsigned argc;
@@ -903,6 +912,14 @@ static int verity_parse_opt_args(struct dm_arg_set *as, struct dm_verity *v)
903 if (r) 912 if (r)
904 return r; 913 return r;
905 continue; 914 continue;
915 } else if (verity_verify_is_sig_opt_arg(arg_name)) {
916 r = verity_verify_sig_parse_opt_args(as, v,
917 verify_args,
918 &argc, arg_name);
919 if (r)
920 return r;
921 continue;
922
906 } 923 }
907 924
908 ti->error = "Unrecognized verity feature request"; 925 ti->error = "Unrecognized verity feature request";
@@ -929,6 +946,7 @@ static int verity_parse_opt_args(struct dm_arg_set *as, struct dm_verity *v)
929static int verity_ctr(struct dm_target *ti, unsigned argc, char **argv) 946static int verity_ctr(struct dm_target *ti, unsigned argc, char **argv)
930{ 947{
931 struct dm_verity *v; 948 struct dm_verity *v;
949 struct dm_verity_sig_opts verify_args = {0};
932 struct dm_arg_set as; 950 struct dm_arg_set as;
933 unsigned int num; 951 unsigned int num;
934 unsigned long long num_ll; 952 unsigned long long num_ll;
@@ -936,6 +954,7 @@ static int verity_ctr(struct dm_target *ti, unsigned argc, char **argv)
936 int i; 954 int i;
937 sector_t hash_position; 955 sector_t hash_position;
938 char dummy; 956 char dummy;
957 char *root_hash_digest_to_validate;
939 958
940 v = kzalloc(sizeof(struct dm_verity), GFP_KERNEL); 959 v = kzalloc(sizeof(struct dm_verity), GFP_KERNEL);
941 if (!v) { 960 if (!v) {
@@ -1069,6 +1088,7 @@ static int verity_ctr(struct dm_target *ti, unsigned argc, char **argv)
1069 r = -EINVAL; 1088 r = -EINVAL;
1070 goto bad; 1089 goto bad;
1071 } 1090 }
1091 root_hash_digest_to_validate = argv[8];
1072 1092
1073 if (strcmp(argv[9], "-")) { 1093 if (strcmp(argv[9], "-")) {
1074 v->salt_size = strlen(argv[9]) / 2; 1094 v->salt_size = strlen(argv[9]) / 2;
@@ -1094,11 +1114,20 @@ static int verity_ctr(struct dm_target *ti, unsigned argc, char **argv)
1094 as.argc = argc; 1114 as.argc = argc;
1095 as.argv = argv; 1115 as.argv = argv;
1096 1116
1097 r = verity_parse_opt_args(&as, v); 1117 r = verity_parse_opt_args(&as, v, &verify_args);
1098 if (r < 0) 1118 if (r < 0)
1099 goto bad; 1119 goto bad;
1100 } 1120 }
1101 1121
1122 /* Root hash signature is a optional parameter*/
1123 r = verity_verify_root_hash(root_hash_digest_to_validate,
1124 strlen(root_hash_digest_to_validate),
1125 verify_args.sig,
1126 verify_args.sig_size);
1127 if (r < 0) {
1128 ti->error = "Root hash verification failed";
1129 goto bad;
1130 }
1102 v->hash_per_block_bits = 1131 v->hash_per_block_bits =
1103 __fls((1 << v->hash_dev_block_bits) / v->digest_size); 1132 __fls((1 << v->hash_dev_block_bits) / v->digest_size);
1104 1133
@@ -1164,9 +1193,13 @@ static int verity_ctr(struct dm_target *ti, unsigned argc, char **argv)
1164 ti->per_io_data_size = roundup(ti->per_io_data_size, 1193 ti->per_io_data_size = roundup(ti->per_io_data_size,
1165 __alignof__(struct dm_verity_io)); 1194 __alignof__(struct dm_verity_io));
1166 1195
1196 verity_verify_sig_opts_cleanup(&verify_args);
1197
1167 return 0; 1198 return 0;
1168 1199
1169bad: 1200bad:
1201
1202 verity_verify_sig_opts_cleanup(&verify_args);
1170 verity_dtr(ti); 1203 verity_dtr(ti);
1171 1204
1172 return r; 1205 return r;
@@ -1174,7 +1207,7 @@ bad:
1174 1207
1175static struct target_type verity_target = { 1208static struct target_type verity_target = {
1176 .name = "verity", 1209 .name = "verity",
1177 .version = {1, 4, 0}, 1210 .version = {1, 5, 0},
1178 .module = THIS_MODULE, 1211 .module = THIS_MODULE,
1179 .ctr = verity_ctr, 1212 .ctr = verity_ctr,
1180 .dtr = verity_dtr, 1213 .dtr = verity_dtr,
diff --git a/drivers/md/dm-verity-verify-sig.c b/drivers/md/dm-verity-verify-sig.c
new file mode 100644
index 000000000000..614e43db93aa
--- /dev/null
+++ b/drivers/md/dm-verity-verify-sig.c
@@ -0,0 +1,133 @@
1// SPDX-License-Identifier: GPL-2.0
2/*
3 * Copyright (C) 2019 Microsoft Corporation.
4 *
5 * Author: Jaskaran Singh Khurana <jaskarankhurana@linux.microsoft.com>
6 *
7 */
8#include <linux/device-mapper.h>
9#include <linux/verification.h>
10#include <keys/user-type.h>
11#include <linux/module.h>
12#include "dm-verity.h"
13#include "dm-verity-verify-sig.h"
14
15#define DM_VERITY_VERIFY_ERR(s) DM_VERITY_ROOT_HASH_VERIFICATION " " s
16
17static bool require_signatures;
18module_param(require_signatures, bool, false);
19MODULE_PARM_DESC(require_signatures,
20 "Verify the roothash of dm-verity hash tree");
21
22#define DM_VERITY_IS_SIG_FORCE_ENABLED() \
23 (require_signatures != false)
24
25bool verity_verify_is_sig_opt_arg(const char *arg_name)
26{
27 return (!strcasecmp(arg_name,
28 DM_VERITY_ROOT_HASH_VERIFICATION_OPT_SIG_KEY));
29}
30
31static int verity_verify_get_sig_from_key(const char *key_desc,
32 struct dm_verity_sig_opts *sig_opts)
33{
34 struct key *key;
35 const struct user_key_payload *ukp;
36 int ret = 0;
37
38 key = request_key(&key_type_user,
39 key_desc, NULL);
40 if (IS_ERR(key))
41 return PTR_ERR(key);
42
43 down_read(&key->sem);
44
45 ukp = user_key_payload_locked(key);
46 if (!ukp) {
47 ret = -EKEYREVOKED;
48 goto end;
49 }
50
51 sig_opts->sig = kmalloc(ukp->datalen, GFP_KERNEL);
52 if (!sig_opts->sig) {
53 ret = -ENOMEM;
54 goto end;
55 }
56 sig_opts->sig_size = ukp->datalen;
57
58 memcpy(sig_opts->sig, ukp->data, sig_opts->sig_size);
59
60end:
61 up_read(&key->sem);
62 key_put(key);
63
64 return ret;
65}
66
67int verity_verify_sig_parse_opt_args(struct dm_arg_set *as,
68 struct dm_verity *v,
69 struct dm_verity_sig_opts *sig_opts,
70 unsigned int *argc,
71 const char *arg_name)
72{
73 struct dm_target *ti = v->ti;
74 int ret = 0;
75 const char *sig_key = NULL;
76
77 if (!*argc) {
78 ti->error = DM_VERITY_VERIFY_ERR("Signature key not specified");
79 return -EINVAL;
80 }
81
82 sig_key = dm_shift_arg(as);
83 (*argc)--;
84
85 ret = verity_verify_get_sig_from_key(sig_key, sig_opts);
86 if (ret < 0)
87 ti->error = DM_VERITY_VERIFY_ERR("Invalid key specified");
88
89 v->signature_key_desc = kstrdup(sig_key, GFP_KERNEL);
90 if (!v->signature_key_desc)
91 return -ENOMEM;
92
93 return ret;
94}
95
96/*
97 * verify_verify_roothash - Verify the root hash of the verity hash device
98 * using builtin trusted keys.
99 *
100 * @root_hash: For verity, the roothash/data to be verified.
101 * @root_hash_len: Size of the roothash/data to be verified.
102 * @sig_data: The trusted signature that verifies the roothash/data.
103 * @sig_len: Size of the signature.
104 *
105 */
106int verity_verify_root_hash(const void *root_hash, size_t root_hash_len,
107 const void *sig_data, size_t sig_len)
108{
109 int ret;
110
111 if (!root_hash || root_hash_len == 0)
112 return -EINVAL;
113
114 if (!sig_data || sig_len == 0) {
115 if (DM_VERITY_IS_SIG_FORCE_ENABLED())
116 return -ENOKEY;
117 else
118 return 0;
119 }
120
121 ret = verify_pkcs7_signature(root_hash, root_hash_len, sig_data,
122 sig_len, NULL, VERIFYING_UNSPECIFIED_SIGNATURE,
123 NULL, NULL);
124
125 return ret;
126}
127
128void verity_verify_sig_opts_cleanup(struct dm_verity_sig_opts *sig_opts)
129{
130 kfree(sig_opts->sig);
131 sig_opts->sig = NULL;
132 sig_opts->sig_size = 0;
133}
diff --git a/drivers/md/dm-verity-verify-sig.h b/drivers/md/dm-verity-verify-sig.h
new file mode 100644
index 000000000000..19b1547aa741
--- /dev/null
+++ b/drivers/md/dm-verity-verify-sig.h
@@ -0,0 +1,60 @@
1// SPDX-License-Identifier: GPL-2.0
2/*
3 * Copyright (C) 2019 Microsoft Corporation.
4 *
5 * Author: Jaskaran Singh Khurana <jaskarankhurana@linux.microsoft.com>
6 *
7 */
8#ifndef DM_VERITY_SIG_VERIFICATION_H
9#define DM_VERITY_SIG_VERIFICATION_H
10
11#define DM_VERITY_ROOT_HASH_VERIFICATION "DM Verity Sig Verification"
12#define DM_VERITY_ROOT_HASH_VERIFICATION_OPT_SIG_KEY "root_hash_sig_key_desc"
13
14struct dm_verity_sig_opts {
15 unsigned int sig_size;
16 u8 *sig;
17};
18
19#ifdef CONFIG_DM_VERITY_VERIFY_ROOTHASH_SIG
20
21#define DM_VERITY_ROOT_HASH_VERIFICATION_OPTS 2
22
23int verity_verify_root_hash(const void *data, size_t data_len,
24 const void *sig_data, size_t sig_len);
25bool verity_verify_is_sig_opt_arg(const char *arg_name);
26
27int verity_verify_sig_parse_opt_args(struct dm_arg_set *as, struct dm_verity *v,
28 struct dm_verity_sig_opts *sig_opts,
29 unsigned int *argc, const char *arg_name);
30
31void verity_verify_sig_opts_cleanup(struct dm_verity_sig_opts *sig_opts);
32
33#else
34
35#define DM_VERITY_ROOT_HASH_VERIFICATION_OPTS 0
36
37int verity_verify_root_hash(const void *data, size_t data_len,
38 const void *sig_data, size_t sig_len)
39{
40 return 0;
41}
42
43bool verity_verify_is_sig_opt_arg(const char *arg_name)
44{
45 return false;
46}
47
48int verity_verify_sig_parse_opt_args(struct dm_arg_set *as, struct dm_verity *v,
49 struct dm_verity_sig_opts *sig_opts,
50 unsigned int *argc, const char *arg_name)
51{
52 return -EINVAL;
53}
54
55void verity_verify_sig_opts_cleanup(struct dm_verity_sig_opts *sig_opts)
56{
57}
58
59#endif /* CONFIG_DM_VERITY_VERIFY_ROOTHASH_SIG */
60#endif /* DM_VERITY_SIG_VERIFICATION_H */
diff --git a/drivers/md/dm-verity.h b/drivers/md/dm-verity.h
index eeaf940aef6d..641b9e3a399b 100644
--- a/drivers/md/dm-verity.h
+++ b/drivers/md/dm-verity.h
@@ -63,6 +63,8 @@ struct dm_verity {
63 63
64 struct dm_verity_fec *fec; /* forward error correction */ 64 struct dm_verity_fec *fec; /* forward error correction */
65 unsigned long *validated_blocks; /* bitset blocks validated */ 65 unsigned long *validated_blocks; /* bitset blocks validated */
66
67 char *signature_key_desc; /* signature keyring reference */
66}; 68};
67 69
68struct dm_verity_io { 70struct dm_verity_io {