Skip to content

Commit

Permalink
mokutil: delete key/hash from the reverse request
Browse files Browse the repository at this point in the history
This commit basically resurrects efa1e81 ("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 <[email protected]>
  • Loading branch information
lcp committed Jun 28, 2021
1 parent b3c6da7 commit 6230e82
Show file tree
Hide file tree
Showing 3 changed files with 165 additions and 2 deletions.
20 changes: 20 additions & 0 deletions src/mokutil.c
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down Expand Up @@ -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);
Expand Down Expand Up @@ -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;
Expand Down
143 changes: 141 additions & 2 deletions src/util.c
Original file line number Diff line number Diff line change
Expand Up @@ -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)
{
Expand All @@ -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)
{
Expand Down Expand Up @@ -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);
}
4 changes: 4 additions & 0 deletions src/util.h
Original file line number Diff line number Diff line change
Expand Up @@ -43,12 +43,16 @@ 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);
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__ */

0 comments on commit 6230e82

Please sign in to comment.