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__ */