If found, 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. If CONFIG_EARLY_CLAVIS is not enabled, the Clavis EFI RT variable will never be set and therefore not used.
Signed-off-by: Eric Snowberg <eric.snowb...@oracle.com> --- security/clavis/Makefile | 4 +++ security/clavis/clavis.h | 9 ++++++ security/clavis/clavis_efi.c | 50 ++++++++++++++++++++++++++++++++ security/clavis/clavis_keyring.c | 11 ++++++- 4 files changed, 73 insertions(+), 1 deletion(-) create mode 100644 security/clavis/clavis_efi.c diff --git a/security/clavis/Makefile b/security/clavis/Makefile index 082e6d3c0934..af68a44a0cb4 100644 --- a/security/clavis/Makefile +++ b/security/clavis/Makefile @@ -18,3 +18,7 @@ $(obj)/builtin_acl: $(CONFIG_SECURITY_CLAVIS_ACL_LIST) FORCE $(call if_changed,make_builtin_acl) $(obj)/clavis_builtin_acl.o: $(obj)/builtin_acl + +ifeq ($(CONFIG_EFI),y) +obj-$(CONFIG_SECURITY_CLAVIS) += clavis_efi.o +endif diff --git a/security/clavis/clavis.h b/security/clavis/clavis.h index 7099a517b111..6f68b560311e 100644 --- a/security/clavis/clavis.h +++ b/security/clavis/clavis.h @@ -24,6 +24,15 @@ const char __initconst *const clavis_module_acl[] = { extern const char __initconst *const clavis_module_acl[]; #endif +#ifdef CONFIG_EFI +int 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 + int __init clavis_keyring_init(void); int clavis_sig_verify(const struct key *key, const struct public_key_signature *sig); #endif /* _SECURITY_CLAVIS_H_ */ diff --git a/security/clavis/clavis_efi.c b/security/clavis/clavis_efi.c new file mode 100644 index 000000000000..0d9c392f4697 --- /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_debug("efi_enabled(EFI_BOOT) not set"); + return -EPERM; + } + + if (!efi_enabled(EFI_RUNTIME_SERVICES)) { + pr_debug("%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_debug("Error reading clavis parm or not found\n"); + return -EINVAL; + } + + if (attr & EFI_VARIABLE_NON_VOLATILE) { + pr_debug("Error: NV access set\n"); + return -EINVAL; + } else if (ascii_len > 0) { + hex_len = ascii_len / 2; + + if (hex_len > len) { + pr_debug("invalid length\n"); + return -EINVAL; + } + kid->len = hex_len; + return hex2bin(kid->data, buf, kid->len); + } + + pr_debug("Error: invalid size\n"); + return -EINVAL; +} diff --git a/security/clavis/clavis_keyring.c b/security/clavis/clavis_keyring.c index a4a95a931b50..81bfc3ed02a3 100644 --- a/security/clavis/clavis_keyring.c +++ b/security/clavis/clavis_keyring.c @@ -307,9 +307,18 @@ int __init clavis_keyring_init(void) void __init late_init_clavis_setup(void) { - if (!clavis_boot_akid) + struct asymmetric_setup_kid efi_keyid; + struct asymmetric_key_id *keyid = &efi_keyid.id; + int error; + + error = clavis_efi_param(keyid, ARRAY_SIZE(efi_keyid.data)); + + if (error && !clavis_boot_akid) return; + if (error) + keyid = clavis_boot_akid; + system_key_link(clavis_keyring, clavis_boot_akid); } -- 2.45.0