From 0658bb29b026a6af434b9e0cdeced5d25bdd206f Mon Sep 17 00:00:00 2001 From: AKASHI Takahiro Date: Wed, 12 Aug 2020 09:37:50 +0900 Subject: efi_loader: variable: keep temporary buffer during the authentication This is a bug fix; Setting an authenticated variable may fail due to a memory corruption in the authentication. A temporary buffer will, if needed, be allocated to parse a variable's authentication data, and some portion of buffer, specifically signer's certificates, will be referenced by efi_signature_verify(). So the buffer should be kept valid until the authentication process is finished. Signed-off-by: AKASHI Takahiro Tested-by: Heinrich Schuchardt --- lib/efi_loader/efi_variable.c | 27 ++++++++++++++++++++------- 1 file changed, 20 insertions(+), 7 deletions(-) (limited to 'lib/efi_loader/efi_variable.c') diff --git a/lib/efi_loader/efi_variable.c b/lib/efi_loader/efi_variable.c index e509d6dbf0c..0c06931135e 100644 --- a/lib/efi_loader/efi_variable.c +++ b/lib/efi_loader/efi_variable.c @@ -37,16 +37,21 @@ static u8 pkcs7_hdr[] = { * efi_variable_parse_signature - parse a signature in variable * @buf: Pointer to variable's value * @buflen: Length of @buf + * @tmpbuf: Pointer to temporary buffer * * Parse a signature embedded in variable's value and instantiate * a pkcs7_message structure. Since pkcs7_parse_message() accepts only * pkcs7's signedData, some header needed be prepended for correctly * parsing authentication data, particularly for variable's. + * A temporary buffer will be allocated if needed, and it should be + * kept valid during the authentication because some data in the buffer + * will be referenced by efi_signature_verify(). * * Return: Pointer to pkcs7_message structure on success, NULL on error */ static struct pkcs7_message *efi_variable_parse_signature(const void *buf, - size_t buflen) + size_t buflen, + u8 **tmpbuf) { u8 *ebuf; size_t ebuflen, len; @@ -59,7 +64,9 @@ static struct pkcs7_message *efi_variable_parse_signature(const void *buf, if (buflen > sizeof(pkcs7_hdr) && !memcmp(&((u8 *)buf)[4], &pkcs7_hdr[4], 11)) { msg = pkcs7_parse_message(buf, buflen); - goto out; + if (IS_ERR(msg)) + return NULL; + return msg; } /* @@ -94,12 +101,12 @@ static struct pkcs7_message *efi_variable_parse_signature(const void *buf, msg = pkcs7_parse_message(ebuf, ebuflen); - free(ebuf); - -out: - if (IS_ERR(msg)) + if (IS_ERR(msg)) { + free(ebuf); return NULL; + } + *tmpbuf = ebuf; return msg; } @@ -136,6 +143,7 @@ static efi_status_t efi_variable_authenticate(u16 *variable, struct efi_time timestamp; struct rtc_time tm; u64 new_time; + u8 *ebuf; enum efi_auth_var_type var_type; efi_status_t ret; @@ -143,6 +151,7 @@ static efi_status_t efi_variable_authenticate(u16 *variable, truststore = NULL; truststore2 = NULL; regs = NULL; + ebuf = NULL; ret = EFI_SECURITY_VIOLATION; if (*data_size < sizeof(struct efi_variable_authentication_2)) @@ -204,9 +213,12 @@ static efi_status_t efi_variable_authenticate(u16 *variable, /* variable's signature list */ if (auth->auth_info.hdr.dwLength < sizeof(auth->auth_info)) goto err; + + /* ebuf should be kept valid during the authentication */ var_sig = efi_variable_parse_signature(auth->auth_info.cert_data, auth->auth_info.hdr.dwLength - - sizeof(auth->auth_info)); + - sizeof(auth->auth_info), + &ebuf); if (!var_sig) { EFI_PRINT("Parsing variable's signature failed\n"); goto err; @@ -262,6 +274,7 @@ err: efi_sigstore_free(truststore); efi_sigstore_free(truststore2); pkcs7_free_message(var_sig); + free(ebuf); free(regs); return ret; -- cgit v1.2.3 From 1115edd8462b047f83fcca4abcf89b68f2d87041 Mon Sep 17 00:00:00 2001 From: AKASHI Takahiro Date: Tue, 21 Jul 2020 19:35:22 +0900 Subject: efi_loader: signature: rework for intermediate certificates support In this commit, efi_signature_verify(with_sigdb) will be re-implemented using pcks7_verify_one() in order to support certificates chain, where the signer's certificate will be signed by an intermediate CA (certificate authority) and the latter's certificate will also be signed by another CA and so on. What we need to do here is to search for certificates in a signature, build up a chain of certificates and verify one by one. pkcs7_verify_one() handles most of these steps except the last one. pkcs7_verify_one() returns, if succeeded, the last certificate to verify, which can be either a self-signed one or one that should be signed by one of certificates in "db". Re-worked efi_signature_verify() will take care of this step. Signed-off-by: AKASHI Takahiro --- lib/efi_loader/efi_variable.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) (limited to 'lib/efi_loader/efi_variable.c') diff --git a/lib/efi_loader/efi_variable.c b/lib/efi_loader/efi_variable.c index 0c06931135e..282d542a096 100644 --- a/lib/efi_loader/efi_variable.c +++ b/lib/efi_loader/efi_variable.c @@ -253,12 +253,11 @@ static efi_status_t efi_variable_authenticate(u16 *variable, } /* verify signature */ - if (efi_signature_verify_with_sigdb(regs, var_sig, truststore, NULL)) { + if (efi_signature_verify(regs, var_sig, truststore, NULL)) { EFI_PRINT("Verified\n"); } else { if (truststore2 && - efi_signature_verify_with_sigdb(regs, var_sig, - truststore2, NULL)) { + efi_signature_verify(regs, var_sig, truststore2, NULL)) { EFI_PRINT("Verified\n"); } else { EFI_PRINT("Verifying variable's signature failed\n"); -- cgit v1.2.3 From f68a6d583578799ec2011476ebd1e10590c6eb3c Mon Sep 17 00:00:00 2001 From: AKASHI Takahiro Date: Thu, 13 Aug 2020 17:05:29 +0900 Subject: efi_loader: variable: fix secure state initialization Under the new file-based variable implementation, the secure state is always and falsely set to 0 (hence, the secure boot gets disabled) after the reboot even if PK (and other signature database) has already been enrolled in the previous boot. This is because the secure state is set up *before* loading non-volatile variables' values from saved data. This patch fixes the order of variable initialization and secure state initialization. Signed-off-by: AKASHI Takahiro Fixes: 5f7dcf079de8 ("efi_loader: UEFI variable persistence") --- lib/efi_loader/efi_variable.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) (limited to 'lib/efi_loader/efi_variable.c') diff --git a/lib/efi_loader/efi_variable.c b/lib/efi_loader/efi_variable.c index 282d542a096..a10b9caa8b0 100644 --- a/lib/efi_loader/efi_variable.c +++ b/lib/efi_loader/efi_variable.c @@ -508,10 +508,6 @@ efi_status_t efi_init_variables(void) if (ret != EFI_SUCCESS) return ret; - ret = efi_init_secure_state(); - if (ret != EFI_SUCCESS) - return ret; - if (IS_ENABLED(CONFIG_EFI_VARIABLES_PRESEED)) { ret = efi_var_restore((struct efi_var_file *) __efi_var_file_begin); @@ -519,5 +515,9 @@ efi_status_t efi_init_variables(void) log_err("Invalid EFI variable seed\n"); } - return efi_var_from_file(); + ret = efi_var_from_file(); + if (ret != EFI_SUCCESS) + return ret; + + return efi_init_secure_state(); } -- cgit v1.2.3