Add patches to enable loading dbx and MOKX blacklists

Import patches from:

https://lore.kernel.org/patchwork/cover/933178/

that allow to also load dbx and MOKX as blacklists for modules.
These patches also disable loading MOK/MOKX when secure boot is
not enabled, as the variables will not be safe, and to check the
variables attributes before accepting them.
This commit is contained in:
Luca Boccassi 2019-05-02 23:03:39 +01:00
parent 188df85f5b
commit 643cc8a41c
6 changed files with 347 additions and 1 deletions

3
debian/changelog vendored
View File

@ -1105,7 +1105,8 @@ linux (4.19.37-1) UNRELEASED; urgency=medium
libbpf-generate-pkg-config.patch from bpf-next.
* Import patches to enable loading keys from UEFI db and MOK from
http://git.kernel.org/cgit/linux/kernel/git/dhowells/linux-fs.git to
allow kernel modules built by users (eg: by dkms) to be verified.
allow kernel modules built by users (eg: by dkms) to be verified, and
to load dbx and MOKX for the equivalent blacklisting functionality.
[ Bastian Blank ]
* Don't longer recommend irqbalance. (closes: #926967)

View File

@ -0,0 +1,59 @@
Origin: https://lore.kernel.org/patchwork/cover/933178/
From: "Lee, Chun-Yi" <joeyli.kernel@gmail.com>
Subject: [PATCH 1/5] MODSIGN: do not load mok when secure boot disabled
The mok can not be trusted when the secure boot is disabled. Which
means that the kernel embedded certificate is the only trusted key.
Due to db/dbx are authenticated variables, they needs manufacturer's
KEK for update. So db/dbx are secure when secureboot disabled.
Signed-off-by: "Lee, Chun-Yi" <jlee@suse.com>
---
certs/load_uefi.c | 26 +++++++++++++++-----------
1 file changed, 15 insertions(+), 11 deletions(-)
diff --git a/certs/load_uefi.c b/certs/load_uefi.c
index 3d88459..d6de4d0 100644
--- a/certs/load_uefi.c
+++ b/certs/load_uefi.c
@@ -171,17 +171,6 @@
}
}
- rc = get_cert_list(L"MokListRT", &mok_var, &moksize, &mok);
- if (rc < 0) {
- pr_info("MODSIGN: Couldn't get UEFI MokListRT\n");
- } else if (moksize != 0) {
- rc = parse_efi_signature_list("UEFI:MokListRT",
- mok, moksize, get_handler_for_db);
- if (rc)
- pr_err("Couldn't parse MokListRT signatures: %d\n", rc);
- kfree(mok);
- }
-
rc = get_cert_list(L"dbx", &secure_var, &dbxsize, &dbx);
if (rc < 0) {
pr_info("MODSIGN: Couldn't get UEFI dbx list\n");
@@ -194,6 +183,21 @@
kfree(dbx);
}
+ /* the MOK can not be trusted when secure boot is disabled */
+ if (!efi_enabled(EFI_SECURE_BOOT))
+ return 0;
+
+ rc = get_cert_list(L"MokListRT", &mok_var, &moksize, &mok);
+ if (rc < 0) {
+ pr_info("MODSIGN: Couldn't get UEFI MokListRT\n");
+ } else if (moksize != 0) {
+ rc = parse_efi_signature_list("UEFI:MokListRT",
+ mok, moksize, get_handler_for_db);
+ if (rc)
+ pr_err("Couldn't parse MokListRT signatures: %d\n", rc);
+ kfree(mok);
+ }
+
return rc;
}
late_initcall(load_uefi_certs);

View File

@ -0,0 +1,55 @@
Origin: https://lore.kernel.org/patchwork/cover/933178/
From: "Lee, Chun-Yi" <joeyli.kernel@gmail.com>
Subject: [PATCH 2/4] MODSIGN: load blacklist from MOKx
This patch adds the logic to load the blacklisted hash and
certificates from MOKx which is maintained by shim bootloader.
Signed-off-by: "Lee, Chun-Yi" <jlee@suse.com>
---
certs/load_uefi.c | 16 +++++++++++++---
1 file changed, 13 insertions(+), 3 deletions(-)
diff --git a/certs/load_uefi.c b/certs/load_uefi.c
index f2f372b..dc66a79 100644
--- a/certs/load_uefi.c
+++ b/certs/load_uefi.c
@@ -148,8 +148,8 @@
{
efi_guid_t secure_var = EFI_IMAGE_SECURITY_DATABASE_GUID;
efi_guid_t mok_var = EFI_SHIM_LOCK_GUID;
- void *db = NULL, *dbx = NULL, *mok = NULL;
- unsigned long dbsize = 0, dbxsize = 0, moksize = 0;
+ void *db = NULL, *dbx = NULL, *mok = NULL, *mokx = NULL;
+ unsigned long dbsize = 0, dbxsize = 0, moksize = 0, mokxsize = 0;
int rc = 0;
if (!efi.get_variable)
@@ -183,7 +183,7 @@
kfree(dbx);
}
- /* the MOK can not be trusted when secure boot is disabled */
+ /* the MOK and MOKx can not be trusted when secure boot is disabled */
if (!efi_enabled(EFI_SECURE_BOOT))
return 0;
@@ -198,6 +198,18 @@
kfree(mok);
}
+ rc = get_cert_list(L"MokListXRT", &mok_var, &mokxsize, &mokx);
+ if (rc < 0) {
+ pr_info("MODSIGN: Couldn't get UEFI MokListXRT\n");
+ } else if (mokxsize != 0) {
+ rc = parse_efi_signature_list("UEFI:mokx",
+ mokx, mokxsize,
+ get_handler_for_dbx);
+ if (rc)
+ pr_err("Couldn't parse MokListXRT signatures: %d\n", rc);
+ kfree(mokx);
+ }
+
return rc;
}
late_initcall(load_uefi_certs);

View File

@ -0,0 +1,124 @@
Origin: https://lore.kernel.org/patchwork/cover/933178/
From: "Lee, Chun-Yi" <joeyli.kernel@gmail.com>
Subject: [PATCH 3/4] MODSIGN: checking the blacklisted hash before loading a
kernel module
This patch adds the logic for checking the kernel module's hash
base on blacklist. The hash must be generated by sha256 and enrolled
to dbx/mokx.
For example:
sha256sum sample.ko
mokutil --mokx --import-hash $HASH_RESULT
Whether the signature on ko file is stripped or not, the hash can be
compared by kernel.
Signed-off-by: "Lee, Chun-Yi" <jlee@suse.com>
---
kernel/module_signing.c | 62 +++++++++++++++++++++++++++++++++++++++++++++++--
1 file changed, 60 insertions(+), 2 deletions(-)
diff --git a/kernel/module_signing.c b/kernel/module_signing.c
index d3d6f95..d30ac74 100644
--- a/kernel/module_signing.c
+++ b/kernel/module_signing.c
@@ -11,9 +11,12 @@
#include <linux/kernel.h>
#include <linux/errno.h>
+#include <linux/module.h>
#include <linux/string.h>
#include <linux/verification.h>
#include <crypto/public_key.h>
+#include <crypto/hash.h>
+#include <keys/system_keyring.h>
#include "module-internal.h"
enum pkey_id_type {
@@ -42,19 +45,67 @@
__be32 sig_len; /* Length of signature data */
};
+static int mod_is_hash_blacklisted(const void *mod, size_t verifylen)
+{
+ struct crypto_shash *tfm;
+ struct shash_desc *desc;
+ size_t digest_size, desc_size;
+ u8 *digest;
+ int ret = 0;
+
+ tfm = crypto_alloc_shash("sha256", 0, 0);
+ if (IS_ERR(tfm))
+ goto error_return;
+
+ desc_size = crypto_shash_descsize(tfm) + sizeof(*desc);
+ digest_size = crypto_shash_digestsize(tfm);
+ digest = kzalloc(digest_size + desc_size, GFP_KERNEL);
+ if (!digest) {
+ pr_err("digest memory buffer allocate fail\n");
+ ret = -ENOMEM;
+ goto error_digest;
+ }
+ desc = (void *)digest + digest_size;
+ desc->tfm = tfm;
+ desc->flags = CRYPTO_TFM_REQ_MAY_SLEEP;
+ ret = crypto_shash_init(desc);
+ if (ret < 0)
+ goto error_shash;
+
+ ret = crypto_shash_finup(desc, mod, verifylen, digest);
+ if (ret < 0)
+ goto error_shash;
+
+ pr_debug("%ld digest: %*phN\n", verifylen, (int) digest_size, digest);
+
+ ret = is_hash_blacklisted(digest, digest_size, "bin");
+ if (ret == -EKEYREJECTED)
+ pr_err("Module hash %*phN is blacklisted\n",
+ (int) digest_size, digest);
+
+error_shash:
+ kfree(digest);
+error_digest:
+ crypto_free_shash(tfm);
+error_return:
+ return ret;
+}
+
/*
* Verify the signature on a module.
*/
int mod_verify_sig(const void *mod, struct load_info *info)
{
struct module_signature ms;
- size_t sig_len, modlen = info->len;
+ size_t sig_len, modlen = info->len, wholelen;
+ int ret;;
pr_devel("==>%s(,%zu)\n", __func__, modlen);
if (modlen <= sizeof(ms))
return -EBADMSG;
+ wholelen = modlen + sizeof(MODULE_SIG_STRING) - 1;
memcpy(&ms, mod + (modlen - sizeof(ms)), sizeof(ms));
modlen -= sizeof(ms);
@@ -82,8 +133,15 @@
return -EBADMSG;
}
- return verify_pkcs7_signature(mod, modlen, mod + modlen, sig_len,
+ ret = verify_pkcs7_signature(mod, modlen, mod + modlen, sig_len,
VERIFY_USE_SECONDARY_KEYRING,
VERIFYING_MODULE_SIGNATURE,
NULL, NULL);
+ pr_devel("verify_pkcs7_signature() = %d\n", ret);
+
+ /* checking hash of module is in blacklist */
+ if (!ret)
+ ret = mod_is_hash_blacklisted(mod, wholelen);
+
+ return ret;
}

View File

@ -0,0 +1,103 @@
Origin: https://lore.kernel.org/patchwork/cover/933178/
From: "Lee, Chun-Yi" <joeyli.kernel@gmail.com>
Subject: [PATCH 4/4] MODSIGN: check the attributes of db and mok
That's better for checking the attributes of db and mok variables
before loading certificates to kernel keyring.
For db and dbx, both of them are authenticated variables. Which
means that they can only be modified by manufacturer's key. So
the kernel should checks EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS
attribute before we trust it.
For mok-rt and mokx-rt, both of them are created by shim boot loader
to forward the mok/mokx content to runtime. They must be runtime-volatile
variables. So kernel should checks that the attributes map did not set
EFI_VARIABLE_NON_VOLATILE bit before we trust it.
Signed-off-by: "Lee, Chun-Yi" <jlee@suse.com>
---
certs/load_uefi.c | 35 +++++++++++++++++++++++------------
1 file changed, 23 insertions(+), 12 deletions(-)
diff --git a/certs/load_uefi.c b/certs/load_uefi.c
index dc66a79..52526bd 100644
--- a/certs/load_uefi.c
+++ b/certs/load_uefi.c
@@ -36,12 +36,14 @@
* Get a certificate list blob from the named EFI variable.
*/
static __init int get_cert_list(efi_char16_t *name, efi_guid_t *guid,
- unsigned long *size, void **cert_list)
+ unsigned long *size, void **cert_list,
+ u32 pos_attr, u32 neg_attr)
{
efi_status_t status;
unsigned long lsize = 4;
unsigned long tmpdb[4];
void *db;
+ u32 attr = 0;
status = efi.get_variable(name, guid, NULL, &lsize, &tmpdb);
if (status == EFI_NOT_FOUND) {
@@ -61,12 +63,19 @@
return -ENOMEM;
}
- status = efi.get_variable(name, guid, NULL, &lsize, db);
+ status = efi.get_variable(name, guid, &attr, &lsize, db);
if (status != EFI_SUCCESS) {
kfree(db);
pr_err("Error reading db var: 0x%lx\n", status);
return efi_status_to_err(status);
}
+ /* must have positive attributes and no negative attributes */
+ if ((pos_attr && !(attr & pos_attr)) ||
+ (neg_attr && (attr & neg_attr))) {
+ kfree(db);
+ pr_err("Error reading db var attributes: 0x%016x\n", attr);
+ return -1;
+ }
*size = lsize;
*cert_list = db;
@@ -159,7 +168,8 @@
* an error if we can't get them.
*/
if (!uefi_check_ignore_db()) {
- rc = get_cert_list(L"db", &secure_var, &dbsize, &db);
+ rc = get_cert_list(L"db", &secure_var, &dbsize, &db,
+ EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS, 0);
if (rc < 0) {
pr_err("MODSIGN: Couldn't get UEFI db list\n");
} else if (dbsize != 0) {
@@ -171,7 +181,8 @@
}
}
- rc = get_cert_list(L"dbx", &secure_var, &dbxsize, &dbx);
+ rc = get_cert_list(L"dbx", &secure_var, &dbxsize, &dbx,
+ EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS, 0);
if (rc < 0) {
pr_info("MODSIGN: Couldn't get UEFI dbx list\n");
} else if (dbxsize != 0) {
@@ -187,7 +198,8 @@
if (!efi_enabled(EFI_SECURE_BOOT))
return 0;
- rc = get_cert_list(L"MokListRT", &mok_var, &moksize, &mok);
+ rc = get_cert_list(L"MokListRT", &mok_var, &moksize, &mok,
+ 0, EFI_VARIABLE_NON_VOLATILE);
if (rc < 0) {
pr_info("MODSIGN: Couldn't get UEFI MokListRT\n");
} else if (moksize != 0) {
@@ -198,7 +210,8 @@
kfree(mok);
}
- rc = get_cert_list(L"MokListXRT", &mok_var, &mokxsize, &mokx);
+ rc = get_cert_list(L"MokListXRT", &mok_var, &mokxsize, &mokx,
+ 0, EFI_VARIABLE_NON_VOLATILE);
if (rc < 0) {
pr_info("MODSIGN: Couldn't get UEFI MokListXRT\n");
} else if (mokxsize != 0) {

View File

@ -151,6 +151,10 @@ features/all/db-mok-keyring/0004-MODSIGN-Import-certificates-from-UEFI-Secure-Bo
features/all/db-mok-keyring/0005-MODSIGN-Allow-the-db-UEFI-variable-to-be-suppressed.patch
features/all/db-mok-keyring/0006-Make-get_cert_list-not-complain-about-cert-lists-tha.patch
features/all/db-mok-keyring/0007-modsign-Use-secondary-trust-keyring-for-module-signi.patch
features/all/db-mok-keyring/0001-MODSIGN-do-not-load-mok-when-secure-boot-disabled.patch
features/all/db-mok-keyring/0002-MODSIGN-load-blacklist-from-MOKx.patch
features/all/db-mok-keyring/0003-MODSIGN-checking-the-blacklisted-hash-before-loading-a-kernel-module.patch
features/all/db-mok-keyring/0004-MODSIGN-check-the-attributes-of-db-and-mok.patch
# Security fixes
debian/i386-686-pae-pci-set-pci-nobios-by-default.patch