Use the new Clavis EFI RT variable to validate the clavis boot param didn't change during a reboot. If the boot param is different or missing, use the one stored in EFI instead. This will prevent a pivot in the root of trust for the upcoming Clavis LSM.
Signed-off-by: Eric Snowberg <eric.snowb...@oracle.com> --- security/clavis/Makefile | 3 ++ security/clavis/clavis.h | 12 ++++++++ security/clavis/clavis_efi.c | 50 ++++++++++++++++++++++++++++++++ security/clavis/clavis_keyring.c | 17 +++++++++-- 4 files changed, 80 insertions(+), 2 deletions(-) create mode 100644 security/clavis/clavis.h create mode 100644 security/clavis/clavis_efi.c diff --git a/security/clavis/Makefile b/security/clavis/Makefile index ff19c1e240fd..c008cb74c762 100644 --- a/security/clavis/Makefile +++ b/security/clavis/Makefile @@ -1,3 +1,6 @@ # SPDX-License-Identifier: GPL-2.0 obj-$(CONFIG_SECURITY_CLAVIS_KEYRING) += clavis_keyring.o +ifeq ($(CONFIG_EFI),y) +obj-$(CONFIG_SECURITY_CLAVIS_KEYRING) += clavis_efi.o +endif diff --git a/security/clavis/clavis.h b/security/clavis/clavis.h new file mode 100644 index 000000000000..3883c390b9e4 --- /dev/null +++ b/security/clavis/clavis.h @@ -0,0 +1,12 @@ +/* SPDX-License-Identifier: GPL-2.0 */ + +struct asymmetric_key_id; + +#ifdef CONFIG_EFI +int __init clavis_efi_param(struct asymmetric_key_id *kid, int len); +#else +static inline int __init clavis_efi_param(struct asymmetric_key_id *kid, int len) +{ + return -EINVAL; +} +#endif diff --git a/security/clavis/clavis_efi.c b/security/clavis/clavis_efi.c new file mode 100644 index 000000000000..7bc8ef03794a --- /dev/null +++ b/security/clavis/clavis_efi.c @@ -0,0 +1,50 @@ +// SPDX-License-Identifier: GPL-2.0 +#include <keys/asymmetric-type.h> +#include <linux/efi.h> +#include "clavis.h" + +static efi_char16_t clavis_param_name[] = L"Clavis"; +static efi_guid_t clavis_guid = LINUX_EFI_CLAVIS_GUID; + +int __init clavis_efi_param(struct asymmetric_key_id *kid, int len) +{ + unsigned char buf[64]; + unsigned long ascii_len = sizeof(buf); + efi_status_t error; + int hex_len; + u32 attr; + + if (!efi_enabled(EFI_BOOT)) { + pr_info("efi_enabled(EFI_BOOT) not set"); + return -EPERM; + } + + if (!efi_enabled(EFI_RUNTIME_SERVICES)) { + pr_info("%s : EFI runtime services are not enabled\n", __func__); + return -EPERM; + } + + error = efi.get_variable(clavis_param_name, &clavis_guid, &attr, &ascii_len, &buf); + + if (error) { + pr_err("Error reading clavis parm\n"); + return -EINVAL; + } + + if (attr & EFI_VARIABLE_NON_VOLATILE) { + pr_info("Error: NV access set\n"); + return -EINVAL; + } else if (ascii_len > 0) { + hex_len = ascii_len / 2; + + if (hex_len > len) { + pr_info("invalid length\n"); + return -EINVAL; + } + kid->len = hex_len; + return hex2bin(kid->data, buf, kid->len); + } + + pr_info("Error: invalid size\n"); + return -EINVAL; +} diff --git a/security/clavis/clavis_keyring.c b/security/clavis/clavis_keyring.c index 9f1aede81992..c5606ed101f6 100644 --- a/security/clavis/clavis_keyring.c +++ b/security/clavis/clavis_keyring.c @@ -3,6 +3,7 @@ #include <linux/security.h> #include <keys/asymmetric-type.h> #include <keys/system_keyring.h> +#include "clavis.h" static struct key *clavis_keyring; static struct asymmetric_key_id *setup_keyid; @@ -82,9 +83,21 @@ static int __init clavis_keyring_init(void) void __init late_init_clavis_setup(void) { - if (!setup_keyid) + int error; + struct { + struct asymmetric_key_id id; + unsigned char data[MAX_BIN_KID]; + } efi_keyid; + struct asymmetric_key_id *keyid = &efi_keyid.id; + + error = clavis_efi_param(keyid, sizeof(efi_keyid.data)); + + if (error && !setup_keyid) return; + if (error) + keyid = setup_keyid; + clavis_keyring_init(); - system_key_link(clavis_keyring, setup_keyid); + system_key_link(clavis_keyring, keyid); } -- 2.39.3