From 6230e824f806d468d1e698acf6cd2600f285c57f Mon Sep 17 00:00:00 2001 From: Gary Lin Date: Sat, 29 May 2021 19:45:00 +0800 Subject: [PATCH] mokutil: delete key/hash from the reverse request This commit basically resurrects efa1e819a0 ("Remove in_pending_request()"). Sometimes the user may remove a package with a MOK , e.g. kernel module package, and reinstall it, and then the key would be removed and enrolled before the next boot. Since the key is already in MokListRT, the enrollment would be skipped due to the duplicate key, and MokManager shows the deletion option during next boot and confuses the user. This commit neutralizes the given request from the existing reverse request to avoid such hassles. Signed-off-by: Gary Lin --- src/mokutil.c | 20 +++++++ src/util.c | 143 +++++++++++++++++++++++++++++++++++++++++++++++++- src/util.h | 4 ++ 3 files changed, 165 insertions(+), 2 deletions(-) diff --git a/src/mokutil.c b/src/mokutil.c index a3bd2b0..787b85e 100644 --- a/src/mokutil.c +++ b/src/mokutil.c @@ -757,6 +757,18 @@ is_in_trusted_keyring (const void *cert, const uint32_t cert_size) return ret; } +static int +in_reverse_pending_request (const efi_guid_t *type, const void *data, + uint32_t data_size, const MokRequest req) +{ + MokRequest reverse_req = get_reverse_req (req); + + if (!data || data_size == 0) + return 0; + + return delete_data_from_req_var (reverse_req, type, data, data_size); +} + static void print_skip_message (const char *filename, const void *mok, const uint32_t mok_size, const MokRequest req) @@ -935,6 +947,10 @@ issue_mok_request (char **files, const uint32_t total, const MokRequest req, if (is_valid_request (&efi_guid_x509_cert, mok, mok_size, req)) { ptr += mok_size; real_size += mok_size + sizeof(EFI_SIGNATURE_LIST) + sizeof(efi_guid_t); + } else if (in_reverse_pending_request (&efi_guid_x509_cert, mok, mok_size, req)) { + printf ("Removed %s from %s\n", files[i], + get_reverse_req_var_name (req)); + ptr -= sizeof(EFI_SIGNATURE_LIST) + sizeof(efi_guid_t); } else { printf ("SKIP: "); print_skip_message (files[i], mok, mok_size, req); @@ -1025,6 +1041,10 @@ issue_hash_request (const char *hash_str, const MokRequest req, printf ("Skip hash\n"); ret = 0; goto error; + } else if (in_reverse_pending_request (&hash_type, db_hash, hash_size, req)) { + printf ("Removed hash from %s\n", get_reverse_req_var_name (req)); + ret = 0; + goto error; } list_size = sizeof(EFI_SIGNATURE_LIST) + sizeof(efi_guid_t) + hash_size; diff --git a/src/util.c b/src/util.c index a819798..d875144 100644 --- a/src/util.c +++ b/src/util.c @@ -189,8 +189,6 @@ build_mok_list (const void *data, const uintptr_t data_size, return list; } - - int test_and_delete_mok_var (const char *var_name) { @@ -215,6 +213,126 @@ test_and_delete_mok_var (const char *var_name) return ret; } +int +delete_data_from_req_var (const MokRequest req, const efi_guid_t *type, + const void *data, const uint32_t data_size) +{ + const efi_guid_t *var_guid = &efi_guid_shim; + const char *var_name = get_req_var_name (req); + const char *authvar_name = get_req_auth_var_name (req); + uint8_t *var_data = NULL; + size_t var_data_size = 0; + uint32_t attributes; + MokListNode *list; + uint32_t mok_num, total, remain; + void *end, *start = NULL; + int del_ind, ret = 0; + uint32_t sig_list_size, sig_size; + + if (!var_name || !data || data_size == 0) + return 0; + + ret = efi_get_variable (*var_guid, var_name, &var_data, &var_data_size, + &attributes); + if (ret < 0) { + if (errno == ENOENT) + return 0; + fprintf (stderr, "Failed to read variable \"%s\": %m\n", + var_name); + return -1; + } + + total = var_data_size; + + list = build_mok_list (var_data, var_data_size, &mok_num); + if (list == NULL) + goto done; + + remain = total; + for (unsigned int i = 0; i < mok_num; i++) { + remain -= list[i].header->SignatureListSize; + efi_guid_t sigtype = list[i].header->SignatureType; + if (efi_guid_cmp (&sigtype, type) != 0) + continue; + + sig_list_size = list[i].header->SignatureListSize; + + if (efi_guid_cmp (type, &efi_guid_x509_cert) == 0) { + if (list[i].mok_size != data_size) + continue; + + if (memcmp (list[i].mok, data, data_size) == 0) { + /* Remove this key */ + start = (void *)list[i].header; + end = start + sig_list_size; + total -= sig_list_size; + break; + } + } else { + del_ind = match_hash_array (type, data, list[i].mok, + list[i].mok_size); + if (del_ind < 0) + continue; + + start = (void *)list[i].header; + sig_size = signature_size (type); + if (sig_list_size == (sizeof(EFI_SIGNATURE_LIST) + sig_size)) { + /* Only one hash in the list */ + end = start + sig_list_size; + total -= sig_list_size; + } else { + /* More than one hash in the list */ + start += sizeof(EFI_SIGNATURE_LIST) + sig_size * del_ind; + end = start + sig_size; + total -= sig_size; + list[i].header->SignatureListSize -= sig_size; + remain += sig_list_size - sizeof(EFI_SIGNATURE_LIST) - + (del_ind + 1) * sig_size; + } + break; + } + } + + /* the key or hash is not in this list */ + if (start == NULL) + return 0; + + /* all keys are removed */ + if (total == 0) { + if (test_and_delete_mok_var (var_name) != 0) + goto done; + if (test_and_delete_mok_var (authvar_name) != 0) + goto done; + ret = 1; + goto done; + } + + /* remove the key or hash */ + if (remain > 0) + memmove (start, end, remain); + + attributes = EFI_VARIABLE_NON_VOLATILE + | EFI_VARIABLE_BOOTSERVICE_ACCESS + | EFI_VARIABLE_RUNTIME_ACCESS; + ret = efi_set_variable (*var_guid, var_name, + var_data, total, attributes, + S_IRUSR | S_IWUSR); + if (ret < 0) { + fprintf (stderr, "Failed to write variable \"%s\": %m\n", + var_name); + goto done; + } + efi_chmod_variable(*var_guid, var_name, S_IRUSR | S_IWUSR); + + ret = 1; +done: + if (list) + free (list); + free (var_data); + + return ret; +} + unsigned long efichar_from_char (efi_char16_t *dest, const char *src, size_t dest_len) { @@ -314,3 +432,24 @@ get_req_auth_var_name (const MokRequest req) return auth_var_names[req]; } + +MokRequest +get_reverse_req (const MokRequest req) +{ + const MokRequest reverse_reqs[] = { + [DELETE_MOK] = ENROLL_MOK, + [ENROLL_MOK] = DELETE_MOK, + [DELETE_BLACKLIST] = ENROLL_BLACKLIST, + [ENROLL_BLACKLIST] = DELETE_BLACKLIST, + }; + + return reverse_reqs[req]; +} + +const char * +get_reverse_req_var_name (const MokRequest req) +{ + const MokRequest reverse_req = get_reverse_req (req); + + return get_req_var_name (reverse_req); +} diff --git a/src/util.h b/src/util.h index 99465a3..70deb31 100644 --- a/src/util.h +++ b/src/util.h @@ -43,6 +43,8 @@ int mok_get_variable(const char *name, uint8_t **datap, size_t *data_sizep); MokListNode *build_mok_list (const void *data, const uintptr_t data_size, uint32_t *mok_num); int test_and_delete_mok_var (const char *var_name); +int delete_data_from_req_var (const MokRequest req, const efi_guid_t *type, + const void *data, const uint32_t data_size); unsigned long efichar_from_char (efi_char16_t *dest, const char *src, size_t dest_len); int read_hidden_line (char **line, size_t *n); @@ -50,5 +52,7 @@ const char *get_db_var_name (const DBName db); const char *get_db_friendly_name (const DBName db); const char *get_req_var_name (const MokRequest req); const char *get_req_auth_var_name (const MokRequest req); +MokRequest get_reverse_req (const MokRequest req); +const char *get_reverse_req_var_name (const MokRequest req); #endif /* __UTIL_H__ */