Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
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>
- Loading branch information
Showing
7 changed files
with
256 additions
and
5 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,133 @@ | ||
// SPDX-License-Identifier: GPL-2.0 | ||
/* | ||
* Copyright (C) 2019 Microsoft Corporation. | ||
* | ||
* Author: Jaskaran Singh Khurana <jaskarankhurana@linux.microsoft.com> | ||
* | ||
*/ | ||
#include <linux/device-mapper.h> | ||
#include <linux/verification.h> | ||
#include <keys/user-type.h> | ||
#include <linux/module.h> | ||
#include "dm-verity.h" | ||
#include "dm-verity-verify-sig.h" | ||
|
||
#define DM_VERITY_VERIFY_ERR(s) DM_VERITY_ROOT_HASH_VERIFICATION " " s | ||
|
||
static bool require_signatures; | ||
module_param(require_signatures, bool, false); | ||
MODULE_PARM_DESC(require_signatures, | ||
"Verify the roothash of dm-verity hash tree"); | ||
|
||
#define DM_VERITY_IS_SIG_FORCE_ENABLED() \ | ||
(require_signatures != false) | ||
|
||
bool verity_verify_is_sig_opt_arg(const char *arg_name) | ||
{ | ||
return (!strcasecmp(arg_name, | ||
DM_VERITY_ROOT_HASH_VERIFICATION_OPT_SIG_KEY)); | ||
} | ||
|
||
static int verity_verify_get_sig_from_key(const char *key_desc, | ||
struct dm_verity_sig_opts *sig_opts) | ||
{ | ||
struct key *key; | ||
const struct user_key_payload *ukp; | ||
int ret = 0; | ||
|
||
key = request_key(&key_type_user, | ||
key_desc, NULL); | ||
if (IS_ERR(key)) | ||
return PTR_ERR(key); | ||
|
||
down_read(&key->sem); | ||
|
||
ukp = user_key_payload_locked(key); | ||
if (!ukp) { | ||
ret = -EKEYREVOKED; | ||
goto end; | ||
} | ||
|
||
sig_opts->sig = kmalloc(ukp->datalen, GFP_KERNEL); | ||
if (!sig_opts->sig) { | ||
ret = -ENOMEM; | ||
goto end; | ||
} | ||
sig_opts->sig_size = ukp->datalen; | ||
|
||
memcpy(sig_opts->sig, ukp->data, sig_opts->sig_size); | ||
|
||
end: | ||
up_read(&key->sem); | ||
key_put(key); | ||
|
||
return ret; | ||
} | ||
|
||
int verity_verify_sig_parse_opt_args(struct dm_arg_set *as, | ||
struct dm_verity *v, | ||
struct dm_verity_sig_opts *sig_opts, | ||
unsigned int *argc, | ||
const char *arg_name) | ||
{ | ||
struct dm_target *ti = v->ti; | ||
int ret = 0; | ||
const char *sig_key = NULL; | ||
|
||
if (!*argc) { | ||
ti->error = DM_VERITY_VERIFY_ERR("Signature key not specified"); | ||
return -EINVAL; | ||
} | ||
|
||
sig_key = dm_shift_arg(as); | ||
(*argc)--; | ||
|
||
ret = verity_verify_get_sig_from_key(sig_key, sig_opts); | ||
if (ret < 0) | ||
ti->error = DM_VERITY_VERIFY_ERR("Invalid key specified"); | ||
|
||
v->signature_key_desc = kstrdup(sig_key, GFP_KERNEL); | ||
if (!v->signature_key_desc) | ||
return -ENOMEM; | ||
|
||
return ret; | ||
} | ||
|
||
/* | ||
* verify_verify_roothash - Verify the root hash of the verity hash device | ||
* using builtin trusted keys. | ||
* | ||
* @root_hash: For verity, the roothash/data to be verified. | ||
* @root_hash_len: Size of the roothash/data to be verified. | ||
* @sig_data: The trusted signature that verifies the roothash/data. | ||
* @sig_len: Size of the signature. | ||
* | ||
*/ | ||
int verity_verify_root_hash(const void *root_hash, size_t root_hash_len, | ||
const void *sig_data, size_t sig_len) | ||
{ | ||
int ret; | ||
|
||
if (!root_hash || root_hash_len == 0) | ||
return -EINVAL; | ||
|
||
if (!sig_data || sig_len == 0) { | ||
if (DM_VERITY_IS_SIG_FORCE_ENABLED()) | ||
return -ENOKEY; | ||
else | ||
return 0; | ||
} | ||
|
||
ret = verify_pkcs7_signature(root_hash, root_hash_len, sig_data, | ||
sig_len, NULL, VERIFYING_UNSPECIFIED_SIGNATURE, | ||
NULL, NULL); | ||
|
||
return ret; | ||
} | ||
|
||
void verity_verify_sig_opts_cleanup(struct dm_verity_sig_opts *sig_opts) | ||
{ | ||
kfree(sig_opts->sig); | ||
sig_opts->sig = NULL; | ||
sig_opts->sig_size = 0; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,60 @@ | ||
// SPDX-License-Identifier: GPL-2.0 | ||
/* | ||
* Copyright (C) 2019 Microsoft Corporation. | ||
* | ||
* Author: Jaskaran Singh Khurana <jaskarankhurana@linux.microsoft.com> | ||
* | ||
*/ | ||
#ifndef DM_VERITY_SIG_VERIFICATION_H | ||
#define DM_VERITY_SIG_VERIFICATION_H | ||
|
||
#define DM_VERITY_ROOT_HASH_VERIFICATION "DM Verity Sig Verification" | ||
#define DM_VERITY_ROOT_HASH_VERIFICATION_OPT_SIG_KEY "root_hash_sig_key_desc" | ||
|
||
struct dm_verity_sig_opts { | ||
unsigned int sig_size; | ||
u8 *sig; | ||
}; | ||
|
||
#ifdef CONFIG_DM_VERITY_VERIFY_ROOTHASH_SIG | ||
|
||
#define DM_VERITY_ROOT_HASH_VERIFICATION_OPTS 2 | ||
|
||
int verity_verify_root_hash(const void *data, size_t data_len, | ||
const void *sig_data, size_t sig_len); | ||
bool verity_verify_is_sig_opt_arg(const char *arg_name); | ||
|
||
int verity_verify_sig_parse_opt_args(struct dm_arg_set *as, struct dm_verity *v, | ||
struct dm_verity_sig_opts *sig_opts, | ||
unsigned int *argc, const char *arg_name); | ||
|
||
void verity_verify_sig_opts_cleanup(struct dm_verity_sig_opts *sig_opts); | ||
|
||
#else | ||
|
||
#define DM_VERITY_ROOT_HASH_VERIFICATION_OPTS 0 | ||
|
||
int verity_verify_root_hash(const void *data, size_t data_len, | ||
const void *sig_data, size_t sig_len) | ||
{ | ||
return 0; | ||
} | ||
|
||
bool verity_verify_is_sig_opt_arg(const char *arg_name) | ||
{ | ||
return false; | ||
} | ||
|
||
int verity_verify_sig_parse_opt_args(struct dm_arg_set *as, struct dm_verity *v, | ||
struct dm_verity_sig_opts *sig_opts, | ||
unsigned int *argc, const char *arg_name) | ||
{ | ||
return -EINVAL; | ||
} | ||
|
||
void verity_verify_sig_opts_cleanup(struct dm_verity_sig_opts *sig_opts) | ||
{ | ||
} | ||
|
||
#endif /* CONFIG_DM_VERITY_VERIFY_ROOTHASH_SIG */ | ||
#endif /* DM_VERITY_SIG_VERIFICATION_H */ |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters