mirror of
https://git.proxmox.com/git/fwupd
synced 2026-01-03 20:26:51 +00:00
libfwupdplugin: Subclass FuFirmware in FuEfiSignatureList
This allows us to get fuzzing support 'for free' and also simplifies the code.
This commit is contained in:
parent
ac927583a3
commit
fcb5667d79
@ -137,5 +137,4 @@ There are several automated fuzzing tests in fwupd. These take some time to run:
|
||||
ninja install
|
||||
ninja fuzz-firmware
|
||||
ninja fuzz-smbios
|
||||
ninja fuzz-efidbx
|
||||
ninja fuzz-tpm-eventlog
|
||||
|
||||
@ -1,28 +0,0 @@
|
||||
#!/usr/bin/python3
|
||||
# SPDX-License-Identifier: LGPL-2.1+
|
||||
|
||||
import sys
|
||||
import struct
|
||||
|
||||
if __name__ == '__main__':
|
||||
|
||||
# SignatureType
|
||||
buf = b'0' * 16
|
||||
|
||||
# SignatureListSize
|
||||
buf += struct.pack('<I', 16 + 4 + 4 + 4 + 16 + 32)
|
||||
|
||||
# SignatureHeaderSize
|
||||
buf += struct.pack('<I', 0)
|
||||
|
||||
# SignatureSize
|
||||
buf += struct.pack('<I', 16 + 32)
|
||||
|
||||
# SignatureOwner
|
||||
buf += b'1' * 16
|
||||
|
||||
# SignatureData
|
||||
buf += b'2' * 32
|
||||
|
||||
with open(sys.argv[1], 'wb') as f:
|
||||
f.write(buf)
|
||||
@ -18,7 +18,7 @@
|
||||
#include "fu-efivar.h"
|
||||
#include "fu-uefi-dbx-common.h"
|
||||
#include "fu-efi-signature-common.h"
|
||||
#include "fu-efi-signature-parser.h"
|
||||
#include "fu-efi-signature.h"
|
||||
|
||||
/* custom return code */
|
||||
#define EXIT_NOTHING_TO_DO 2
|
||||
@ -29,29 +29,30 @@ fu_util_ignore_cb (const gchar *log_domain, GLogLevelFlags log_level,
|
||||
{
|
||||
}
|
||||
|
||||
static GPtrArray *
|
||||
static FuFirmware *
|
||||
fu_dbxtool_get_siglist_system (GError **error)
|
||||
{
|
||||
gsize bufsz = 0;
|
||||
g_autofree guint8 *buf = NULL;
|
||||
if (!fu_efivar_get_data (FU_EFIVAR_GUID_SECURITY_DATABASE, "dbx",
|
||||
&buf, &bufsz, NULL, error))
|
||||
g_autoptr(GBytes) blob = NULL;
|
||||
g_autoptr(FuFirmware) dbx = fu_efi_signature_list_new ();
|
||||
blob = fu_efivar_get_data_bytes (FU_EFIVAR_GUID_SECURITY_DATABASE, "dbx", NULL, error);
|
||||
if (blob == NULL)
|
||||
return NULL;
|
||||
return fu_efi_signature_parser_new (buf, bufsz,
|
||||
FU_EFI_SIGNATURE_PARSER_FLAGS_NONE,
|
||||
error);
|
||||
if (!fu_firmware_parse (dbx, blob, FWUPD_INSTALL_FLAG_NO_SEARCH, error))
|
||||
return NULL;
|
||||
return g_steal_pointer (&dbx);
|
||||
}
|
||||
|
||||
static GPtrArray *
|
||||
static FuFirmware *
|
||||
fu_dbxtool_get_siglist_local (const gchar *filename, GError **error)
|
||||
{
|
||||
gsize bufsz = 0;
|
||||
g_autofree guint8 *buf = NULL;
|
||||
if (!g_file_get_contents (filename, (gchar **) &buf, &bufsz, error))
|
||||
g_autoptr(GBytes) blob = NULL;
|
||||
g_autoptr(FuFirmware) siglist = fu_efi_signature_list_new ();
|
||||
blob = fu_common_get_contents_bytes (filename, error);
|
||||
if (blob == NULL)
|
||||
return NULL;
|
||||
return fu_efi_signature_parser_new (buf, bufsz,
|
||||
FU_EFI_SIGNATURE_PARSER_FLAGS_IGNORE_HEADER,
|
||||
error);
|
||||
if (!fu_firmware_parse (siglist, blob, FWUPD_INSTALL_FLAG_NONE, error))
|
||||
return NULL;
|
||||
return g_steal_pointer (&siglist);
|
||||
}
|
||||
|
||||
int
|
||||
@ -123,7 +124,8 @@ main (int argc, char *argv[])
|
||||
/* list contents, either of the existing system, or an update */
|
||||
if (action_list || action_version) {
|
||||
guint cnt = 1;
|
||||
g_autoptr(GPtrArray) dbx = NULL;
|
||||
g_autoptr(FuFirmware) dbx = NULL;
|
||||
g_autoptr(GPtrArray) sigs = NULL;
|
||||
if (dbxfile != NULL) {
|
||||
dbx = fu_dbxtool_get_siglist_local (dbxfile, &error);
|
||||
if (dbx == NULL) {
|
||||
@ -141,20 +143,21 @@ main (int argc, char *argv[])
|
||||
}
|
||||
if (action_version) {
|
||||
/* TRANSLATORS: the detected version number of the dbx */
|
||||
g_print ("%s: %u\n", _("Version"), fu_efi_signature_list_array_version (dbx));
|
||||
g_print ("%s: %s\n", _("Version"), fu_firmware_get_version (dbx));
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
for (guint j = 0; j < dbx->len; j++) {
|
||||
FuEfiSignatureList *siglist = g_ptr_array_index (dbx, j);
|
||||
GPtrArray *sigs = fu_efi_signature_list_get_all (siglist);
|
||||
for (guint i = 0; i < sigs->len; i++) {
|
||||
FuEfiSignature *sig = g_ptr_array_index (sigs, i);
|
||||
g_print ("%4u: {%s} {%s} %s\n",
|
||||
cnt++,
|
||||
fu_efi_signature_guid_to_string (fu_efi_signature_get_owner (sig)),
|
||||
fu_efi_signature_kind_to_string (fu_efi_signature_get_kind (sig)),
|
||||
fu_efi_signature_get_checksum (sig));
|
||||
}
|
||||
sigs = fu_firmware_get_images (FU_FIRMWARE (dbx));
|
||||
for (guint i = 0; i < sigs->len; i++) {
|
||||
FuEfiSignature *sig = g_ptr_array_index (sigs, i);
|
||||
g_autofree gchar *checksum = NULL;
|
||||
checksum = fu_firmware_image_get_checksum (FU_FIRMWARE_IMAGE (sig),
|
||||
G_CHECKSUM_SHA256,
|
||||
NULL);
|
||||
g_print ("%4u: {%s} {%s} %s\n",
|
||||
cnt++,
|
||||
fu_efi_signature_guid_to_string (fu_efi_signature_get_owner (sig)),
|
||||
fu_efi_signature_kind_to_string (fu_efi_signature_get_kind (sig)),
|
||||
checksum);
|
||||
}
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
@ -169,10 +172,9 @@ main (int argc, char *argv[])
|
||||
|
||||
/* apply update */
|
||||
if (action_apply) {
|
||||
gsize bufsz = 0;
|
||||
g_autofree guint8 *buf = NULL;
|
||||
g_autoptr(GPtrArray) dbx_system = NULL;
|
||||
g_autoptr(GPtrArray) dbx_update = NULL;
|
||||
g_autoptr(FuFirmware) dbx_system = NULL;
|
||||
g_autoptr(FuFirmware) dbx_update = fu_efi_signature_list_new ();
|
||||
g_autoptr(GBytes) blob = NULL;
|
||||
|
||||
if (dbxfile == NULL) {
|
||||
/* TRANSLATORS: user did not include a filename parameter */
|
||||
@ -191,27 +193,20 @@ main (int argc, char *argv[])
|
||||
|
||||
/* TRANSLATORS: reading new dbx from the update */
|
||||
g_print ("%s\n", _("Parsing dbx update…"));
|
||||
if (!g_file_get_contents (dbxfile, (gchar **) &buf, &bufsz, &error)) {
|
||||
blob = fu_common_get_contents_bytes (dbxfile, &error);
|
||||
if (blob == NULL) {
|
||||
/* TRANSLATORS: could not read file */
|
||||
g_printerr ("%s: %s\n", _("Failed to load local dbx"), error->message);
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
dbx_update = fu_efi_signature_parser_new (buf, bufsz,
|
||||
FU_EFI_SIGNATURE_PARSER_FLAGS_IGNORE_HEADER,
|
||||
&error);
|
||||
if (dbx_update == NULL) {
|
||||
if (!fu_firmware_parse (dbx_update, blob, FWUPD_INSTALL_FLAG_NONE, &error)) {
|
||||
/* TRANSLATORS: could not parse file */
|
||||
g_printerr ("%s: %s\n", _("Failed to parse local dbx"), error->message);
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
if (dbx_update->len != 1) {
|
||||
/* TRANSLATORS: could not parse file */
|
||||
g_printerr ("%s: %s\n", _("Failed to extract local dbx "), error->message);
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
/* check this is a newer dbx update */
|
||||
if (!force && fu_efi_signature_list_array_inclusive (dbx_system, dbx_update)) {
|
||||
if (!force && fu_efi_signature_list_inclusive (FU_EFI_SIGNATURE_LIST (dbx_system), FU_EFI_SIGNATURE_LIST (dbx_update))) {
|
||||
/* TRANSLATORS: same or newer update already applied */
|
||||
g_printerr ("%s\n", _("Cannot apply as dbx update has already been applied."));
|
||||
return EXIT_FAILURE;
|
||||
@ -228,7 +223,7 @@ main (int argc, char *argv[])
|
||||
if (!force) {
|
||||
/* TRANSLATORS: ESP refers to the EFI System Partition */
|
||||
g_print ("%s\n", _("Validating ESP contents…"));
|
||||
if (!fu_uefi_dbx_signature_list_validate (dbx_update, &error)) {
|
||||
if (!fu_uefi_dbx_signature_list_validate (FU_EFI_SIGNATURE_LIST (dbx_update), &error)) {
|
||||
/* TRANSLATORS: something with a blocked hash exists
|
||||
* in the users ESP -- which would be bad! */
|
||||
g_printerr ("%s: %s\n", _("Failed to validate ESP contents"), error->message);
|
||||
@ -238,14 +233,14 @@ main (int argc, char *argv[])
|
||||
|
||||
/* TRANSLATORS: actually sending the update to the hardware */
|
||||
g_print ("%s\n", _("Applying update…"));
|
||||
if (!fu_efivar_set_data (FU_EFIVAR_GUID_SECURITY_DATABASE,
|
||||
"dbx", buf, bufsz,
|
||||
FU_EFIVAR_ATTR_APPEND_WRITE |
|
||||
FU_EFIVAR_ATTR_TIME_BASED_AUTHENTICATED_WRITE_ACCESS |
|
||||
FU_EFIVAR_ATTR_RUNTIME_ACCESS |
|
||||
FU_EFIVAR_ATTR_BOOTSERVICE_ACCESS |
|
||||
FU_EFIVAR_ATTR_NON_VOLATILE,
|
||||
&error)) {
|
||||
if (!fu_efivar_set_data_bytes (FU_EFIVAR_GUID_SECURITY_DATABASE,
|
||||
"dbx", blob,
|
||||
FU_EFIVAR_ATTR_APPEND_WRITE |
|
||||
FU_EFIVAR_ATTR_TIME_BASED_AUTHENTICATED_WRITE_ACCESS |
|
||||
FU_EFIVAR_ATTR_RUNTIME_ACCESS |
|
||||
FU_EFIVAR_ATTR_BOOTSERVICE_ACCESS |
|
||||
FU_EFIVAR_ATTR_NON_VOLATILE,
|
||||
&error)) {
|
||||
/* TRANSLATORS: dbx file failed to be applied as an update */
|
||||
g_printerr ("%s: %s\n", _("Failed to apply update"), error->message);
|
||||
return EXIT_FAILURE;
|
||||
|
||||
@ -8,52 +8,29 @@
|
||||
|
||||
#include "fu-efi-signature-common.h"
|
||||
#include "fu-efi-signature-list.h"
|
||||
#include "fu-efi-signature.h"
|
||||
|
||||
gboolean
|
||||
fu_efi_signature_list_array_has_checksum (GPtrArray *siglists, const gchar *checksum)
|
||||
fu_efi_signature_list_has_checksum (FuEfiSignatureList *siglist, const gchar *checksum)
|
||||
{
|
||||
for (guint i = 0; i < siglists->len; i++) {
|
||||
FuEfiSignatureList *siglist = g_ptr_array_index (siglists, i);
|
||||
if (fu_efi_signature_list_has_checksum (siglist, checksum))
|
||||
return TRUE;
|
||||
}
|
||||
return FALSE;
|
||||
g_autoptr(FuFirmwareImage) img = NULL;
|
||||
img = fu_firmware_get_image_by_checksum (FU_FIRMWARE (siglist), checksum, NULL);
|
||||
return img != NULL;
|
||||
}
|
||||
|
||||
gboolean
|
||||
fu_efi_signature_list_array_inclusive (GPtrArray *outer, GPtrArray *inner)
|
||||
fu_efi_signature_list_inclusive (FuEfiSignatureList *outer, FuEfiSignatureList *inner)
|
||||
{
|
||||
for (guint j = 0; j < inner->len; j++) {
|
||||
FuEfiSignatureList *siglist = g_ptr_array_index (inner, j);
|
||||
GPtrArray *items = fu_efi_signature_list_get_all (siglist);
|
||||
for (guint i = 0; i < items->len; i++) {
|
||||
FuEfiSignature *sig = g_ptr_array_index (items, i);
|
||||
const gchar *checksum = fu_efi_signature_get_checksum (sig);
|
||||
if (!fu_efi_signature_list_array_has_checksum (outer, checksum))
|
||||
return FALSE;
|
||||
}
|
||||
g_autoptr(GPtrArray) sigs = fu_firmware_get_images (FU_FIRMWARE (inner));
|
||||
for (guint i = 0; i < sigs->len; i++) {
|
||||
FuEfiSignature *sig = g_ptr_array_index (sigs, i);
|
||||
g_autofree gchar *checksum = NULL;
|
||||
checksum = fu_firmware_image_get_checksum (FU_FIRMWARE_IMAGE (sig),
|
||||
G_CHECKSUM_SHA256, NULL);
|
||||
if (checksum == NULL)
|
||||
continue;
|
||||
if (!fu_efi_signature_list_has_checksum (outer, checksum))
|
||||
return FALSE;
|
||||
}
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
guint
|
||||
fu_efi_signature_list_array_version (GPtrArray *siglists)
|
||||
{
|
||||
guint csum_cnt = 0;
|
||||
const gchar *ignored_guids[] = {
|
||||
FU_EFI_SIGNATURE_GUID_OVMF,
|
||||
NULL };
|
||||
for (guint j = 0; j < siglists->len; j++) {
|
||||
FuEfiSignatureList *siglist = g_ptr_array_index (siglists, j);
|
||||
GPtrArray *items = fu_efi_signature_list_get_all (siglist);
|
||||
for (guint i = 0; i < items->len; i++) {
|
||||
FuEfiSignature *sig = g_ptr_array_index (items, i);
|
||||
if (fu_efi_signature_get_kind (sig) != FU_EFI_SIGNATURE_KIND_SHA256)
|
||||
continue;
|
||||
if (g_strv_contains (ignored_guids, fu_efi_signature_get_owner (sig)))
|
||||
continue;
|
||||
csum_cnt++;
|
||||
}
|
||||
}
|
||||
return csum_cnt;
|
||||
}
|
||||
|
||||
@ -6,10 +6,9 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "fu-efi-signature.h"
|
||||
#include "fu-efi-signature-list.h"
|
||||
|
||||
gboolean fu_efi_signature_list_array_inclusive (GPtrArray *outer,
|
||||
GPtrArray *inner);
|
||||
guint fu_efi_signature_list_array_version (GPtrArray *siglists);
|
||||
gboolean fu_efi_signature_list_array_has_checksum (GPtrArray *siglists,
|
||||
const gchar *checksum);
|
||||
gboolean fu_efi_signature_list_inclusive (FuEfiSignatureList *outer,
|
||||
FuEfiSignatureList *inner);
|
||||
gboolean fu_efi_signature_list_has_checksum (FuEfiSignatureList *siglist,
|
||||
const gchar *checksum);
|
||||
|
||||
@ -6,74 +6,242 @@
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include <fwupd.h>
|
||||
|
||||
#include "fu-common.h"
|
||||
#include "fu-efi-signature.h"
|
||||
#include "fu-efi-signature-list.h"
|
||||
|
||||
struct _FuEfiSignatureList {
|
||||
GObject parent_instance;
|
||||
FuEfiSignatureKind kind;
|
||||
GPtrArray *items; /* element-type: FuEfiSignature */
|
||||
FuFirmware parent_instance;
|
||||
};
|
||||
|
||||
G_DEFINE_TYPE (FuEfiSignatureList, fu_efi_signature_list, G_TYPE_OBJECT)
|
||||
G_DEFINE_TYPE (FuEfiSignatureList, fu_efi_signature_list, FU_TYPE_FIRMWARE)
|
||||
|
||||
FuEfiSignatureList *
|
||||
fu_efi_signature_list_new (FuEfiSignatureKind kind)
|
||||
static gboolean
|
||||
fu_efi_signature_list_parse_item (FuEfiSignatureList *self,
|
||||
FuEfiSignatureKind sig_kind,
|
||||
const guint8 *buf,
|
||||
gsize bufsz,
|
||||
gsize offset,
|
||||
guint32 sig_size,
|
||||
GError **error)
|
||||
{
|
||||
g_autoptr(FuEfiSignatureList) self = g_object_new (FU_TYPE_EFI_SIGNATURE_LIST, NULL);
|
||||
self->kind = kind;
|
||||
return g_steal_pointer (&self);
|
||||
}
|
||||
fwupd_guid_t guid;
|
||||
gsize sig_datasz = sig_size - sizeof(fwupd_guid_t);
|
||||
g_autofree gchar *sig_owner = NULL;
|
||||
g_autofree guint8 *sig_data = g_malloc0 (sig_datasz);
|
||||
g_autoptr(FuEfiSignature) sig = NULL;
|
||||
g_autoptr(GBytes) data = NULL;
|
||||
|
||||
FuEfiSignatureKind
|
||||
fu_efi_signature_list_get_kind (FuEfiSignatureList *self)
|
||||
{
|
||||
g_return_val_if_fail (FU_IS_EFI_SIGNATURE_LIST (self), 0);
|
||||
return self->kind;
|
||||
}
|
||||
|
||||
GPtrArray *
|
||||
fu_efi_signature_list_get_all (FuEfiSignatureList *self)
|
||||
{
|
||||
g_return_val_if_fail (FU_IS_EFI_SIGNATURE_LIST (self), NULL);
|
||||
return self->items;
|
||||
}
|
||||
|
||||
void
|
||||
fu_efi_signature_list_add (FuEfiSignatureList *self, FuEfiSignature *signature)
|
||||
{
|
||||
g_return_if_fail (FU_IS_EFI_SIGNATURE_LIST (self));
|
||||
g_ptr_array_add (self->items, g_object_ref (signature));
|
||||
}
|
||||
|
||||
gboolean
|
||||
fu_efi_signature_list_has_checksum (FuEfiSignatureList *self, const gchar *checksum)
|
||||
{
|
||||
g_return_val_if_fail (FU_IS_EFI_SIGNATURE_LIST (self), FALSE);
|
||||
for (guint i = 0; i < self->items->len; i++) {
|
||||
FuEfiSignature *item = g_ptr_array_index (self->items, i);
|
||||
if (g_strcmp0 (fu_efi_signature_get_checksum (item), checksum) == 0)
|
||||
return TRUE;
|
||||
/* read both blocks of data */
|
||||
if (!fu_memcpy_safe ((guint8 *) &guid, sizeof(guid), 0x0, /* dst */
|
||||
buf, bufsz, offset, /* src */
|
||||
sizeof(guid), error)) {
|
||||
g_prefix_error (error, "failed to read signature GUID: ");
|
||||
return FALSE;
|
||||
}
|
||||
return FALSE;
|
||||
if (!fu_memcpy_safe (sig_data, sig_datasz, 0x0, /* dst */
|
||||
buf, bufsz, offset + sizeof(fwupd_guid_t), /* src */
|
||||
sig_datasz, error)) {
|
||||
g_prefix_error (error, "failed to read signature data: ");
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/* create item */
|
||||
sig_owner = fwupd_guid_to_string (&guid, FWUPD_GUID_FLAG_MIXED_ENDIAN);
|
||||
data = g_bytes_new (sig_data, sig_datasz);
|
||||
sig = fu_efi_signature_new (sig_kind, sig_owner);
|
||||
fu_firmware_image_set_bytes (FU_FIRMWARE_IMAGE (sig), data);
|
||||
fu_firmware_add_image (FU_FIRMWARE (self), FU_FIRMWARE_IMAGE (sig));
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static void
|
||||
fu_efi_signature_list_finalize (GObject *obj)
|
||||
static gboolean
|
||||
fu_efi_signature_list_parse_list (FuEfiSignatureList *self,
|
||||
const guint8 *buf,
|
||||
gsize bufsz,
|
||||
gsize *offset,
|
||||
GError **error)
|
||||
{
|
||||
FuEfiSignatureList *self = FU_EFI_SIGNATURE_LIST (obj);
|
||||
g_ptr_array_unref (self->items);
|
||||
G_OBJECT_CLASS (fu_efi_signature_list_parent_class)->finalize (obj);
|
||||
FuEfiSignatureKind sig_kind = FU_EFI_SIGNATURE_KIND_UNKNOWN;
|
||||
fwupd_guid_t guid;
|
||||
gsize offset_tmp;
|
||||
guint32 sig_header_size = 0;
|
||||
guint32 sig_list_size = 0;
|
||||
guint32 sig_size = 0;
|
||||
g_autofree gchar *sig_type = NULL;
|
||||
|
||||
/* read EFI_SIGNATURE_LIST */
|
||||
if (!fu_memcpy_safe ((guint8 *) &guid, sizeof(guid), 0x0, /* dst */
|
||||
buf, bufsz, *offset, /* src */
|
||||
sizeof(guid), error)) {
|
||||
g_prefix_error (error, "failed to read GUID header: ");
|
||||
return FALSE;
|
||||
}
|
||||
sig_type = fwupd_guid_to_string (&guid, FWUPD_GUID_FLAG_MIXED_ENDIAN);
|
||||
if (g_strcmp0 (sig_type, "c1c41626-504c-4092-aca9-41f936934328") == 0) {
|
||||
sig_kind = FU_EFI_SIGNATURE_KIND_SHA256;
|
||||
} else if (g_strcmp0 (sig_type, "a5c059a1-94e4-4aa7-87b5-ab155c2bf072") == 0) {
|
||||
sig_kind = FU_EFI_SIGNATURE_KIND_X509;
|
||||
}
|
||||
if (!fu_common_read_uint32_safe (buf, bufsz, *offset + 0x10,
|
||||
&sig_list_size, G_LITTLE_ENDIAN, error))
|
||||
return FALSE;
|
||||
if (sig_list_size < 0x1c || sig_list_size > 1024 * 1024) {
|
||||
g_set_error (error,
|
||||
G_IO_ERROR,
|
||||
G_IO_ERROR_FAILED,
|
||||
"SignatureListSize invalid: 0x%x", sig_list_size);
|
||||
return FALSE;
|
||||
}
|
||||
if (!fu_common_read_uint32_safe (buf, bufsz, *offset + 0x14,
|
||||
&sig_header_size, G_LITTLE_ENDIAN, error))
|
||||
return FALSE;
|
||||
if (sig_header_size > 1024 * 1024) {
|
||||
g_set_error (error,
|
||||
G_IO_ERROR,
|
||||
G_IO_ERROR_FAILED,
|
||||
"SignatureHeaderSize invalid: 0x%x", sig_size);
|
||||
return FALSE;
|
||||
}
|
||||
if (!fu_common_read_uint32_safe (buf, bufsz, *offset + 0x18,
|
||||
&sig_size, G_LITTLE_ENDIAN, error))
|
||||
return FALSE;
|
||||
if (sig_size < sizeof(fwupd_guid_t) || sig_size > 1024 * 1024) {
|
||||
g_set_error (error,
|
||||
G_IO_ERROR,
|
||||
G_IO_ERROR_FAILED,
|
||||
"SignatureSize invalid: 0x%x", sig_size);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/* header is typically unused */
|
||||
offset_tmp = *offset + 0x1c + sig_header_size;
|
||||
for (guint i = 0; i < (sig_list_size - 0x1c) / sig_size; i++) {
|
||||
if (!fu_efi_signature_list_parse_item (self, sig_kind, buf, bufsz,
|
||||
offset_tmp, sig_size,
|
||||
error))
|
||||
return FALSE;
|
||||
offset_tmp += sig_size;
|
||||
}
|
||||
*offset += sig_list_size;
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static gchar *
|
||||
fu_efi_signature_list_get_version (FuEfiSignatureList *self)
|
||||
{
|
||||
guint csum_cnt = 0;
|
||||
const gchar *ignored_guids[] = {
|
||||
FU_EFI_SIGNATURE_GUID_OVMF,
|
||||
NULL };
|
||||
g_autoptr(GPtrArray) sigs = NULL;
|
||||
sigs = fu_firmware_get_images (FU_FIRMWARE (self));
|
||||
for (guint i = 0; i < sigs->len; i++) {
|
||||
FuEfiSignature *sig = g_ptr_array_index (sigs, i);
|
||||
if (fu_efi_signature_get_kind (sig) != FU_EFI_SIGNATURE_KIND_SHA256)
|
||||
continue;
|
||||
if (g_strv_contains (ignored_guids, fu_efi_signature_get_owner (sig)))
|
||||
continue;
|
||||
csum_cnt++;
|
||||
}
|
||||
return g_strdup_printf ("%u", csum_cnt);
|
||||
}
|
||||
|
||||
static gboolean
|
||||
fu_efi_signature_list_parse (FuFirmware *firmware,
|
||||
GBytes *fw,
|
||||
guint64 addr_start,
|
||||
guint64 addr_end,
|
||||
FwupdInstallFlags flags,
|
||||
GError **error)
|
||||
{
|
||||
FuEfiSignatureList *self = FU_EFI_SIGNATURE_LIST (firmware);
|
||||
gsize bufsz = 0;
|
||||
gsize offset_fs = 0;
|
||||
const guint8 *buf = g_bytes_get_data (fw, &bufsz);
|
||||
g_autofree gchar *version_str = NULL;
|
||||
|
||||
/* this allows us to skip the efi permissions uint32_t or even the
|
||||
* Microsoft PKCS-7 signature */
|
||||
if ((flags & FWUPD_INSTALL_FLAG_NO_SEARCH) == 0) {
|
||||
if (bufsz < 5) {
|
||||
g_set_error (error,
|
||||
G_IO_ERROR,
|
||||
G_IO_ERROR_FAILED,
|
||||
"signature invalid: 0x%x",
|
||||
(guint) bufsz);
|
||||
return FALSE;
|
||||
}
|
||||
for (gsize i = 0; i < bufsz - 5; i++) {
|
||||
if (memcmp (buf + i, "\x26\x16\xc4\xc1\x4c", 5) == 0) {
|
||||
g_debug ("found EFI_SIGNATURE_LIST @0x%x", (guint) i);
|
||||
offset_fs = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* parse each EFI_SIGNATURE_LIST */
|
||||
for (gsize offset = offset_fs; offset < bufsz;) {
|
||||
if (!fu_efi_signature_list_parse_list (self, buf, bufsz, &offset, error))
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/* set version */
|
||||
version_str = fu_efi_signature_list_get_version (self);
|
||||
if (version_str != NULL)
|
||||
fu_firmware_set_version (firmware, version_str);
|
||||
|
||||
/* success */
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static GBytes *
|
||||
fu_efi_signature_list_write (FuFirmware *firmware, GError **error)
|
||||
{
|
||||
GByteArray *buf = g_byte_array_new ();
|
||||
|
||||
/* SignatureType */
|
||||
for (guint i = 0; i < 16; i++)
|
||||
fu_byte_array_append_uint8 (buf, 0x0);
|
||||
|
||||
/* SignatureListSize */
|
||||
fu_byte_array_append_uint32 (buf, 16 + 4 + 4 + 4 + 16 + 32, G_LITTLE_ENDIAN);
|
||||
|
||||
/* SignatureHeaderSize */
|
||||
fu_byte_array_append_uint32 (buf, 0, G_LITTLE_ENDIAN);
|
||||
|
||||
/* SignatureSize */
|
||||
fu_byte_array_append_uint32 (buf, 16 + 32, G_LITTLE_ENDIAN);
|
||||
|
||||
/* SignatureOwner */
|
||||
for (guint i = 0; i < 16; i++)
|
||||
fu_byte_array_append_uint8 (buf, '1');
|
||||
|
||||
/* SignatureData */
|
||||
for (guint i = 0; i < 16; i++)
|
||||
fu_byte_array_append_uint8 (buf, '2');
|
||||
|
||||
return g_byte_array_free_to_bytes (buf);
|
||||
}
|
||||
|
||||
FuFirmware *
|
||||
fu_efi_signature_list_new (void)
|
||||
{
|
||||
return g_object_new (FU_TYPE_EFI_SIGNATURE_LIST, NULL);
|
||||
}
|
||||
|
||||
static void
|
||||
fu_efi_signature_list_class_init (FuEfiSignatureListClass *klass)
|
||||
{
|
||||
GObjectClass *object_class = G_OBJECT_CLASS (klass);
|
||||
object_class->finalize = fu_efi_signature_list_finalize;
|
||||
FuFirmwareClass *klass_firmware = FU_FIRMWARE_CLASS (klass);
|
||||
klass_firmware->parse = fu_efi_signature_list_parse;
|
||||
klass_firmware->write = fu_efi_signature_list_write;
|
||||
}
|
||||
|
||||
static void
|
||||
fu_efi_signature_list_init (FuEfiSignatureList *self)
|
||||
{
|
||||
self->items = g_ptr_array_new_with_free_func ((GDestroyNotify) g_object_unref);
|
||||
}
|
||||
|
||||
@ -6,16 +6,9 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "fu-efi-signature.h"
|
||||
#include "fu-firmware.h"
|
||||
|
||||
#define FU_TYPE_EFI_SIGNATURE_LIST (fu_efi_signature_list_get_type ())
|
||||
G_DECLARE_FINAL_TYPE (FuEfiSignatureList, fu_efi_signature_list, FU, EFI_SIGNATURE_LIST, GObject)
|
||||
G_DECLARE_FINAL_TYPE (FuEfiSignatureList, fu_efi_signature_list, FU, EFI_SIGNATURE_LIST, FuFirmware)
|
||||
|
||||
|
||||
FuEfiSignatureList*fu_efi_signature_list_new (FuEfiSignatureKind kind);
|
||||
FuEfiSignatureKind fu_efi_signature_list_get_kind (FuEfiSignatureList *self);
|
||||
void fu_efi_signature_list_add (FuEfiSignatureList *self,
|
||||
FuEfiSignature *signature);
|
||||
GPtrArray *fu_efi_signature_list_get_all (FuEfiSignatureList *self);
|
||||
gboolean fu_efi_signature_list_has_checksum (FuEfiSignatureList *self,
|
||||
const gchar *checksum);
|
||||
FuFirmware *fu_efi_signature_list_new (void);
|
||||
|
||||
@ -1,164 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2020 Richard Hughes <richard@hughsie.com>
|
||||
*
|
||||
* SPDX-License-Identifier: LGPL-2.1+
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include <string.h>
|
||||
#include <fwupd.h>
|
||||
|
||||
#include "fu-common.h"
|
||||
#include "fu-efi-signature-parser.h"
|
||||
|
||||
static gboolean
|
||||
fu_efi_signature_list_parse_item (FuEfiSignatureList *siglist,
|
||||
const guint8 *buf,
|
||||
gsize bufsz,
|
||||
gsize offset,
|
||||
guint32 sig_size,
|
||||
GError **error)
|
||||
{
|
||||
fwupd_guid_t guid;
|
||||
gsize sig_datasz = sig_size - sizeof(fwupd_guid_t);
|
||||
g_autofree gchar *sig_owner = NULL;
|
||||
g_autofree guint8 *sig_data = g_malloc0 (sig_datasz);
|
||||
g_autoptr(FuEfiSignature) sig = NULL;
|
||||
g_autoptr(GBytes) data = NULL;
|
||||
|
||||
/* read both blocks of data */
|
||||
if (!fu_memcpy_safe ((guint8 *) &guid, sizeof(guid), 0x0, /* dst */
|
||||
buf, bufsz, offset, /* src */
|
||||
sizeof(guid), error)) {
|
||||
g_prefix_error (error, "failed to read signature GUID: ");
|
||||
return FALSE;
|
||||
}
|
||||
if (!fu_memcpy_safe (sig_data, sig_datasz, 0x0, /* dst */
|
||||
buf, bufsz, offset + sizeof(fwupd_guid_t), /* src */
|
||||
sig_datasz, error)) {
|
||||
g_prefix_error (error, "failed to read signature data: ");
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/* create item */
|
||||
sig_owner = fwupd_guid_to_string (&guid, FWUPD_GUID_FLAG_MIXED_ENDIAN);
|
||||
data = g_bytes_new (sig_data, sig_datasz);
|
||||
sig = fu_efi_signature_new (fu_efi_signature_list_get_kind (siglist), sig_owner, data);
|
||||
fu_efi_signature_list_add (siglist, sig);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
fu_efi_signature_list_parse_list (GPtrArray *siglists,
|
||||
const guint8 *buf,
|
||||
gsize bufsz,
|
||||
gsize *offset,
|
||||
GError **error)
|
||||
{
|
||||
fwupd_guid_t guid;
|
||||
gsize offset_tmp;
|
||||
guint32 sig_header_size = 0;
|
||||
guint32 sig_list_size = 0;
|
||||
guint32 sig_size = 0;
|
||||
g_autofree gchar *sig_type = NULL;
|
||||
g_autoptr(FuEfiSignatureList) siglist = NULL;
|
||||
|
||||
/* read EFI_SIGNATURE_LIST */
|
||||
if (!fu_memcpy_safe ((guint8 *) &guid, sizeof(guid), 0x0, /* dst */
|
||||
buf, bufsz, *offset, /* src */
|
||||
sizeof(guid), error)) {
|
||||
g_prefix_error (error, "failed to read GUID header: ");
|
||||
return FALSE;
|
||||
}
|
||||
sig_type = fwupd_guid_to_string (&guid, FWUPD_GUID_FLAG_MIXED_ENDIAN);
|
||||
if (g_strcmp0 (sig_type, "c1c41626-504c-4092-aca9-41f936934328") == 0) {
|
||||
siglist = fu_efi_signature_list_new (FU_EFI_SIGNATURE_KIND_SHA256);
|
||||
} else if (g_strcmp0 (sig_type, "a5c059a1-94e4-4aa7-87b5-ab155c2bf072") == 0) {
|
||||
siglist = fu_efi_signature_list_new (FU_EFI_SIGNATURE_KIND_X509);
|
||||
} else {
|
||||
siglist = fu_efi_signature_list_new (FU_EFI_SIGNATURE_KIND_UNKNOWN);
|
||||
}
|
||||
if (!fu_common_read_uint32_safe (buf, bufsz, *offset + 0x10,
|
||||
&sig_list_size, G_LITTLE_ENDIAN, error))
|
||||
return FALSE;
|
||||
if (sig_list_size < 0x1c || sig_list_size > 1024 * 1024) {
|
||||
g_set_error (error,
|
||||
G_IO_ERROR,
|
||||
G_IO_ERROR_FAILED,
|
||||
"SignatureListSize invalid: 0x%x", sig_list_size);
|
||||
return FALSE;
|
||||
}
|
||||
if (!fu_common_read_uint32_safe (buf, bufsz, *offset + 0x14,
|
||||
&sig_header_size, G_LITTLE_ENDIAN, error))
|
||||
return FALSE;
|
||||
if (sig_header_size > 1024 * 1024) {
|
||||
g_set_error (error,
|
||||
G_IO_ERROR,
|
||||
G_IO_ERROR_FAILED,
|
||||
"SignatureHeaderSize invalid: 0x%x", sig_size);
|
||||
return FALSE;
|
||||
}
|
||||
if (!fu_common_read_uint32_safe (buf, bufsz, *offset + 0x18,
|
||||
&sig_size, G_LITTLE_ENDIAN, error))
|
||||
return FALSE;
|
||||
if (sig_size < sizeof(fwupd_guid_t) || sig_size > 1024 * 1024) {
|
||||
g_set_error (error,
|
||||
G_IO_ERROR,
|
||||
G_IO_ERROR_FAILED,
|
||||
"SignatureSize invalid: 0x%x", sig_size);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/* header is typically unused */
|
||||
offset_tmp = *offset + 0x1c + sig_header_size;
|
||||
for (guint i = 0; i < (sig_list_size - 0x1c) / sig_size; i++) {
|
||||
if (!fu_efi_signature_list_parse_item (siglist, buf, bufsz,
|
||||
offset_tmp, sig_size,
|
||||
error))
|
||||
return FALSE;
|
||||
offset_tmp += sig_size;
|
||||
}
|
||||
*offset += sig_list_size;
|
||||
g_ptr_array_add (siglists, g_steal_pointer (&siglist));
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
GPtrArray *
|
||||
fu_efi_signature_parser_new (const guint8 *buf, gsize bufsz,
|
||||
FuEfiSignatureParserFlags flags,
|
||||
GError **error)
|
||||
{
|
||||
gsize offset_fs = 0;
|
||||
g_autoptr(GPtrArray) siglists = NULL;
|
||||
|
||||
/* this allows us to skip the efi permissions uint32_t or even the
|
||||
* Microsoft PKCS-7 signature */
|
||||
if (flags & FU_EFI_SIGNATURE_PARSER_FLAGS_IGNORE_HEADER) {
|
||||
if (bufsz < 5) {
|
||||
g_set_error (error,
|
||||
G_IO_ERROR,
|
||||
G_IO_ERROR_FAILED,
|
||||
"signature invalid: 0x%x",
|
||||
(guint) bufsz);
|
||||
return NULL;
|
||||
}
|
||||
for (gsize i = 0; i < bufsz - 5; i++) {
|
||||
if (memcmp (buf + i, "\x26\x16\xc4\xc1\x4c", 5) == 0) {
|
||||
g_debug ("found EFI_SIGNATURE_LIST @0x%x", (guint) i);
|
||||
offset_fs = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* parse each EFI_SIGNATURE_LIST */
|
||||
siglists = g_ptr_array_new_with_free_func ((GDestroyNotify) g_object_unref);
|
||||
for (gsize offset = offset_fs; offset < bufsz;) {
|
||||
if (!fu_efi_signature_list_parse_list (siglists, buf, bufsz, &offset, error))
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* success */
|
||||
return g_steal_pointer (&siglists);
|
||||
}
|
||||
@ -1,19 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2020 Richard Hughes <richard@hughsie.com>
|
||||
*
|
||||
* SPDX-License-Identifier: LGPL-2.1+
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "fu-efi-signature-list.h"
|
||||
|
||||
typedef enum {
|
||||
FU_EFI_SIGNATURE_PARSER_FLAGS_NONE = 0,
|
||||
FU_EFI_SIGNATURE_PARSER_FLAGS_IGNORE_HEADER = 1 << 0,
|
||||
} FuEfiSignatureParserFlags;
|
||||
|
||||
GPtrArray *fu_efi_signature_parser_new (const guint8 *buf,
|
||||
gsize bufsz,
|
||||
FuEfiSignatureParserFlags flags,
|
||||
GError **error);
|
||||
@ -9,15 +9,12 @@
|
||||
#include "fu-efi-signature.h"
|
||||
|
||||
struct _FuEfiSignature {
|
||||
GObject parent_instance;
|
||||
FuFirmwareImage parent_instance;
|
||||
FuEfiSignatureKind kind;
|
||||
gchar *owner;
|
||||
gchar *checksum; /* (nullable) */
|
||||
GBytes *data;
|
||||
};
|
||||
|
||||
G_DEFINE_TYPE (FuEfiSignature, fu_efi_signature, G_TYPE_OBJECT)
|
||||
|
||||
G_DEFINE_TYPE (FuEfiSignature, fu_efi_signature, FU_TYPE_FIRMWARE_IMAGE)
|
||||
|
||||
const gchar *
|
||||
fu_efi_signature_kind_to_string (FuEfiSignatureKind kind)
|
||||
@ -42,12 +39,11 @@ fu_efi_signature_guid_to_string (const gchar *guid)
|
||||
}
|
||||
|
||||
FuEfiSignature *
|
||||
fu_efi_signature_new (FuEfiSignatureKind kind, const gchar *owner, GBytes *data)
|
||||
fu_efi_signature_new (FuEfiSignatureKind kind, const gchar *owner)
|
||||
{
|
||||
g_autoptr(FuEfiSignature) self = g_object_new (FU_TYPE_EFI_SIGNATURE, NULL);
|
||||
self->kind = kind;
|
||||
self->owner = g_strdup (owner);
|
||||
self->data = g_bytes_ref (data);
|
||||
return g_steal_pointer (&self);
|
||||
}
|
||||
|
||||
@ -65,34 +61,29 @@ fu_efi_signature_get_owner (FuEfiSignature *self)
|
||||
return self->owner;
|
||||
}
|
||||
|
||||
GBytes *
|
||||
fu_efi_signature_get_data (FuEfiSignature *self)
|
||||
static gchar *
|
||||
fu_efi_signature_get_checksum (FuFirmwareImage *firmware_image,
|
||||
GChecksumType csum_kind,
|
||||
GError **error)
|
||||
{
|
||||
g_return_val_if_fail (FU_IS_EFI_SIGNATURE (self), NULL);
|
||||
return self->data;
|
||||
}
|
||||
FuEfiSignature *self = FU_EFI_SIGNATURE (firmware_image);
|
||||
g_autoptr(GBytes) data = fu_firmware_image_get_bytes (firmware_image);
|
||||
|
||||
const gchar *
|
||||
fu_efi_signature_get_checksum (FuEfiSignature *self)
|
||||
{
|
||||
g_return_val_if_fail (FU_IS_EFI_SIGNATURE (self), NULL);
|
||||
|
||||
/* only create when required */
|
||||
if (self->checksum == NULL) {
|
||||
if (self->kind == FU_EFI_SIGNATURE_KIND_SHA256) {
|
||||
GString *str;
|
||||
const guint8 *buf;
|
||||
gsize bufsz = 0;
|
||||
buf = g_bytes_get_data (self->data, &bufsz);
|
||||
str = g_string_new (NULL);
|
||||
for (gsize i = 0; i < bufsz; i++)
|
||||
g_string_append_printf (str, "%02x", buf[i]);
|
||||
self->checksum = g_string_free (str, FALSE);
|
||||
} else {
|
||||
self->checksum = g_compute_checksum_for_bytes (G_CHECKSUM_SHA256, self->data);
|
||||
}
|
||||
/* special case: this is *literally* a hash */
|
||||
if (self->kind == FU_EFI_SIGNATURE_KIND_SHA256 &&
|
||||
csum_kind == G_CHECKSUM_SHA256) {
|
||||
GString *str;
|
||||
const guint8 *buf;
|
||||
gsize bufsz = 0;
|
||||
buf = g_bytes_get_data (data, &bufsz);
|
||||
str = g_string_new (NULL);
|
||||
for (gsize i = 0; i < bufsz; i++)
|
||||
g_string_append_printf (str, "%02x", buf[i]);
|
||||
return g_string_free (str, FALSE);
|
||||
}
|
||||
return self->checksum;
|
||||
|
||||
/* fallback */
|
||||
return g_compute_checksum_for_bytes (csum_kind, data);
|
||||
}
|
||||
|
||||
static void
|
||||
@ -100,8 +91,6 @@ fu_efi_signature_finalize (GObject *obj)
|
||||
{
|
||||
FuEfiSignature *self = FU_EFI_SIGNATURE (obj);
|
||||
g_free (self->owner);
|
||||
g_free (self->checksum);
|
||||
g_bytes_unref (self->data);
|
||||
G_OBJECT_CLASS (fu_efi_signature_parent_class)->finalize (obj);
|
||||
}
|
||||
|
||||
@ -109,7 +98,9 @@ static void
|
||||
fu_efi_signature_class_init (FuEfiSignatureClass *klass)
|
||||
{
|
||||
GObjectClass *object_class = G_OBJECT_CLASS (klass);
|
||||
FuFirmwareImageClass *firmware_image_class = FU_FIRMWARE_IMAGE_CLASS (klass);
|
||||
object_class->finalize = fu_efi_signature_finalize;
|
||||
firmware_image_class->get_checksum = fu_efi_signature_get_checksum;
|
||||
}
|
||||
|
||||
static void
|
||||
|
||||
@ -8,8 +8,10 @@
|
||||
|
||||
#include <gio/gio.h>
|
||||
|
||||
#include "fu-firmware-image.h"
|
||||
|
||||
#define FU_TYPE_EFI_SIGNATURE (fu_efi_signature_get_type ())
|
||||
G_DECLARE_FINAL_TYPE (FuEfiSignature, fu_efi_signature, FU, EFI_SIGNATURE, GObject)
|
||||
G_DECLARE_FINAL_TYPE (FuEfiSignature, fu_efi_signature, FU, EFI_SIGNATURE, FuFirmwareImage)
|
||||
|
||||
typedef enum {
|
||||
FU_EFI_SIGNATURE_KIND_UNKNOWN,
|
||||
@ -26,9 +28,6 @@ const gchar *fu_efi_signature_kind_to_string (FuEfiSignatureKind kind);
|
||||
const gchar *fu_efi_signature_guid_to_string (const gchar *guid);
|
||||
|
||||
FuEfiSignature *fu_efi_signature_new (FuEfiSignatureKind kind,
|
||||
const gchar *owner,
|
||||
GBytes *data);
|
||||
const gchar *owner);
|
||||
FuEfiSignatureKind fu_efi_signature_get_kind (FuEfiSignature *self);
|
||||
GBytes *fu_efi_signature_get_data (FuEfiSignature *self);
|
||||
const gchar *fu_efi_signature_get_checksum (FuEfiSignature *self);
|
||||
const gchar *fu_efi_signature_get_owner (FuEfiSignature *self);
|
||||
|
||||
@ -1,41 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2020 Richard Hughes <richard@hughsie.com>
|
||||
*
|
||||
* SPDX-License-Identifier: LGPL-2.1+
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "fu-efi-signature-parser.h"
|
||||
|
||||
int
|
||||
main (int argc, char *argv[])
|
||||
{
|
||||
gsize bufsz = 0;
|
||||
g_autofree guint8 *buf = NULL;
|
||||
g_autoptr(GError) error = NULL;
|
||||
g_autoptr(GPtrArray) siglists = NULL;
|
||||
|
||||
if (argc < 2) {
|
||||
g_printerr ("Not enough arguments, expected 'foo.bin'\n");
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
if (!g_file_get_contents (argv[1], (gchar **) &buf, &bufsz, &error)) {
|
||||
g_printerr ("Failed to load %s: %s\n", argv[1], error->message);
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
siglists = fu_efi_signature_parser_new (buf, bufsz,
|
||||
FU_EFI_SIGNATURE_PARSER_FLAGS_IGNORE_HEADER,
|
||||
&error);
|
||||
if (siglists == NULL) {
|
||||
g_printerr ("Failed to parse %s: %s\n", argv[1], error->message);
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
for (guint i = 0; i < siglists->len; i++) {
|
||||
FuEfiSignatureList *siglist = g_ptr_array_index (siglists, i);
|
||||
g_print ("%u checksums\n", fu_efi_signature_list_get_all(siglist)->len);
|
||||
}
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
@ -7,11 +7,8 @@
|
||||
#include "config.h"
|
||||
|
||||
#include "fu-plugin-vfuncs.h"
|
||||
#include "fu-efivar.h"
|
||||
#include "fu-hash.h"
|
||||
#include "fu-efi-signature-common.h"
|
||||
#include "fu-efi-signature-parser.h"
|
||||
#include "fu-uefi-dbx-common.h"
|
||||
#include "fu-efi-signature-list.h"
|
||||
#include "fu-uefi-dbx-device.h"
|
||||
|
||||
void
|
||||
@ -19,6 +16,7 @@ fu_plugin_init (FuPlugin *plugin)
|
||||
{
|
||||
fu_plugin_set_build_hash (plugin, FU_BUILD_HASH);
|
||||
fu_plugin_add_rule (plugin, FU_PLUGIN_RULE_METADATA_SOURCE, "uefi");
|
||||
fu_plugin_add_firmware_gtype (plugin, NULL, FU_TYPE_EFI_SIGNATURE_LIST);
|
||||
}
|
||||
|
||||
gboolean
|
||||
|
||||
@ -11,7 +11,6 @@
|
||||
#include "fu-common.h"
|
||||
#include "fu-uefi-dbx-common.h"
|
||||
#include "fu-efi-image.h"
|
||||
#include "fu-efi-signature-parser.h"
|
||||
|
||||
static void
|
||||
fu_efi_image_func (void)
|
||||
|
||||
@ -36,7 +36,7 @@ fu_uefi_dbx_get_authenticode_hash (const gchar *fn, GError **error)
|
||||
}
|
||||
|
||||
static gboolean
|
||||
fu_uefi_dbx_signature_list_validate_volume (GPtrArray *siglists, FuVolume *esp, GError **error)
|
||||
fu_uefi_dbx_signature_list_validate_volume (FuEfiSignatureList *siglist, FuVolume *esp, GError **error)
|
||||
{
|
||||
g_autofree gchar *esp_path = NULL;
|
||||
g_autoptr(GPtrArray) files = NULL;
|
||||
@ -64,7 +64,7 @@ fu_uefi_dbx_signature_list_validate_volume (GPtrArray *siglists, FuVolume *esp,
|
||||
|
||||
/* Authenticode signature is present in dbx! */
|
||||
g_debug ("fn=%s, checksum=%s", fn, checksum);
|
||||
if (fu_efi_signature_list_array_has_checksum (siglists, checksum)) {
|
||||
if (fu_efi_signature_list_has_checksum (siglist, checksum)) {
|
||||
g_set_error (error,
|
||||
FWUPD_ERROR,
|
||||
FWUPD_ERROR_NEEDS_USER_ACTION,
|
||||
@ -79,7 +79,7 @@ fu_uefi_dbx_signature_list_validate_volume (GPtrArray *siglists, FuVolume *esp,
|
||||
}
|
||||
|
||||
gboolean
|
||||
fu_uefi_dbx_signature_list_validate (GPtrArray *siglists, GError **error)
|
||||
fu_uefi_dbx_signature_list_validate (FuEfiSignatureList *siglist, GError **error)
|
||||
{
|
||||
g_autoptr(GPtrArray) volumes = NULL;
|
||||
volumes = fu_common_get_volumes_by_kind (FU_VOLUME_KIND_ESP, error);
|
||||
@ -91,7 +91,7 @@ fu_uefi_dbx_signature_list_validate (GPtrArray *siglists, GError **error)
|
||||
locker = fu_volume_locker (esp, error);
|
||||
if (locker == NULL)
|
||||
return FALSE;
|
||||
if (!fu_uefi_dbx_signature_list_validate_volume (siglists, esp, error))
|
||||
if (!fu_uefi_dbx_signature_list_validate_volume (siglist, esp, error))
|
||||
return FALSE;
|
||||
}
|
||||
return TRUE;
|
||||
|
||||
@ -8,7 +8,9 @@
|
||||
|
||||
#include <gio/gio.h>
|
||||
|
||||
#include "fu-efi-signature-list.h"
|
||||
|
||||
gchar *fu_uefi_dbx_get_authenticode_hash (const gchar *fn,
|
||||
GError **error);
|
||||
gboolean fu_uefi_dbx_signature_list_validate (GPtrArray *siglists,
|
||||
gboolean fu_uefi_dbx_signature_list_validate (FuEfiSignatureList *siglist,
|
||||
GError **error);
|
||||
|
||||
@ -9,7 +9,7 @@
|
||||
#include "fu-efivar.h"
|
||||
|
||||
#include "fu-efi-signature-common.h"
|
||||
#include "fu-efi-signature-parser.h"
|
||||
#include "fu-efi-signature.h"
|
||||
#include "fu-uefi-dbx-common.h"
|
||||
#include "fu-uefi-dbx-device.h"
|
||||
|
||||
@ -55,24 +55,18 @@ fu_uefi_dbx_device_write_firmware (FuDevice *device,
|
||||
static gboolean
|
||||
fu_uefi_dbx_device_set_version_number (FuDevice *device, GError **error)
|
||||
{
|
||||
gsize bufsz = 0;
|
||||
g_autofree gchar *version = NULL;
|
||||
g_autofree guint8 *buf = NULL;
|
||||
g_autoptr(GPtrArray) dbx = NULL;
|
||||
g_autoptr(GBytes) dbx_blob = NULL;
|
||||
g_autoptr(FuFirmware) dbx = fu_efi_signature_list_new ();
|
||||
|
||||
/* use the number of checksums in the dbx as a version number, ignoring
|
||||
* some owners that do not make sense */
|
||||
if (!fu_efivar_get_data (FU_EFIVAR_GUID_SECURITY_DATABASE, "dbx",
|
||||
&buf, &bufsz, NULL, error))
|
||||
dbx_blob = fu_efivar_get_data_bytes (FU_EFIVAR_GUID_SECURITY_DATABASE, "dbx", NULL, error);
|
||||
if (dbx_blob == NULL)
|
||||
return FALSE;
|
||||
dbx = fu_efi_signature_parser_new (buf, bufsz,
|
||||
FU_EFI_SIGNATURE_PARSER_FLAGS_NONE,
|
||||
error);
|
||||
if (dbx == NULL)
|
||||
if (!fu_firmware_parse (dbx, dbx_blob, FWUPD_INSTALL_FLAG_NO_SEARCH, error))
|
||||
return FALSE;
|
||||
version = g_strdup_printf ("%u", fu_efi_signature_list_array_version (dbx));
|
||||
fu_device_set_version (device, version);
|
||||
fu_device_set_version_lowest (device, version);
|
||||
fu_device_set_version (device, fu_firmware_get_version (dbx));
|
||||
fu_device_set_version_lowest (device, fu_firmware_get_version (dbx));
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
@ -82,22 +76,16 @@ fu_uefi_dbx_prepare_firmware (FuDevice *device,
|
||||
FwupdInstallFlags flags,
|
||||
GError **error)
|
||||
{
|
||||
const guint8 *buf;
|
||||
gsize bufsz = 0;
|
||||
g_autoptr(GPtrArray) siglists = NULL;
|
||||
g_autoptr(FuFirmware) siglist = fu_efi_signature_list_new ();
|
||||
|
||||
/* parse dbx */
|
||||
buf = g_bytes_get_data (fw, &bufsz);
|
||||
siglists = fu_efi_signature_parser_new (buf, bufsz,
|
||||
FU_EFI_SIGNATURE_PARSER_FLAGS_IGNORE_HEADER,
|
||||
error);
|
||||
if (siglists == NULL)
|
||||
if (!fu_firmware_parse (siglist, fw, flags, error))
|
||||
return NULL;
|
||||
|
||||
/* validate this is safe to apply */
|
||||
if ((flags & FWUPD_INSTALL_FLAG_FORCE) == 0) {
|
||||
fu_device_set_status (device, FWUPD_STATUS_DEVICE_VERIFY);
|
||||
if (!fu_uefi_dbx_signature_list_validate (siglists, error)) {
|
||||
if (!fu_uefi_dbx_signature_list_validate (FU_EFI_SIGNATURE_LIST (siglist), error)) {
|
||||
g_prefix_error (error,
|
||||
"Blocked executable in the ESP, "
|
||||
"ensure grub and shim are up to date: ");
|
||||
@ -112,37 +100,37 @@ fu_uefi_dbx_prepare_firmware (FuDevice *device,
|
||||
static gboolean
|
||||
fu_uefi_dbx_device_probe (FuDevice *device, GError **error)
|
||||
{
|
||||
gsize bufsz = 0;
|
||||
g_autofree gchar *arch_up = NULL;
|
||||
g_autofree guint8 *buf = NULL;
|
||||
g_autoptr(GPtrArray) kek = NULL;
|
||||
g_autoptr(FuFirmware) kek = fu_efi_signature_list_new ();
|
||||
g_autoptr(GBytes) kek_blob = NULL;
|
||||
g_autoptr(GPtrArray) sigs = NULL;
|
||||
|
||||
/* use each of the certificates in the KEK to generate the GUIDs */
|
||||
if (!fu_efivar_get_data (FU_EFIVAR_GUID_EFI_GLOBAL, "KEK",
|
||||
&buf, &bufsz, NULL, error))
|
||||
kek_blob = fu_efivar_get_data_bytes (FU_EFIVAR_GUID_EFI_GLOBAL, "KEK", NULL, error);
|
||||
if (kek_blob == NULL)
|
||||
return FALSE;
|
||||
kek = fu_efi_signature_parser_new (buf, bufsz,
|
||||
FU_EFI_SIGNATURE_PARSER_FLAGS_NONE,
|
||||
error);
|
||||
if (kek == NULL)
|
||||
if (!fu_firmware_parse (kek, kek_blob, FWUPD_INSTALL_FLAG_NO_SEARCH, error))
|
||||
return FALSE;
|
||||
arch_up = g_utf8_strup (EFI_MACHINE_TYPE_NAME, -1);
|
||||
for (guint i = 0; i < kek->len; i++) {
|
||||
FuEfiSignatureList *siglist = g_ptr_array_index (kek, i);
|
||||
GPtrArray *sigs = fu_efi_signature_list_get_all (siglist);
|
||||
for (guint j = 0; j < sigs->len; j++) {
|
||||
FuEfiSignature *sig = g_ptr_array_index (sigs, j);
|
||||
g_autofree gchar *checksum_up = NULL;
|
||||
g_autofree gchar *devid1 = NULL;
|
||||
g_autofree gchar *devid2 = NULL;
|
||||
sigs = fu_firmware_get_images (kek);
|
||||
for (guint j = 0; j < sigs->len; j++) {
|
||||
FuEfiSignature *sig = g_ptr_array_index (sigs, j);
|
||||
g_autofree gchar *checksum = NULL;
|
||||
g_autofree gchar *checksum_up = NULL;
|
||||
g_autofree gchar *devid1 = NULL;
|
||||
g_autofree gchar *devid2 = NULL;
|
||||
|
||||
checksum_up = g_utf8_strup (fu_efi_signature_get_checksum (sig), -1);
|
||||
devid1 = g_strdup_printf ("UEFI\\CRT_%s", checksum_up);
|
||||
fu_device_add_instance_id (device, devid1);
|
||||
devid2 = g_strdup_printf ("UEFI\\CRT_%s&ARCH_%s",
|
||||
checksum_up, arch_up);
|
||||
fu_device_add_instance_id (device, devid2);
|
||||
}
|
||||
checksum = fu_firmware_image_get_checksum (FU_FIRMWARE_IMAGE (sig),
|
||||
G_CHECKSUM_SHA256,
|
||||
error);
|
||||
if (checksum == NULL)
|
||||
return FALSE;
|
||||
checksum_up = g_utf8_strup (checksum, -1);
|
||||
devid1 = g_strdup_printf ("UEFI\\CRT_%s", checksum_up);
|
||||
fu_device_add_instance_id (device, devid1);
|
||||
devid2 = g_strdup_printf ("UEFI\\CRT_%s&ARCH_%s",
|
||||
checksum_up, arch_up);
|
||||
fu_device_add_instance_id (device, devid2);
|
||||
}
|
||||
return fu_uefi_dbx_device_set_version_number (device, error);
|
||||
}
|
||||
|
||||
@ -10,7 +10,6 @@ shared_module('fu_plugin_uefi_dbx',
|
||||
'fu-efi-signature.c',
|
||||
'fu-efi-signature-common.c',
|
||||
'fu-efi-signature-list.c',
|
||||
'fu-efi-signature-parser.c',
|
||||
],
|
||||
include_directories : [
|
||||
root_incdir,
|
||||
@ -43,7 +42,6 @@ if get_option('tests')
|
||||
'fu-efi-signature.c',
|
||||
'fu-efi-signature-common.c',
|
||||
'fu-efi-signature-list.c',
|
||||
'fu-efi-signature-parser.c',
|
||||
],
|
||||
include_directories : [
|
||||
root_incdir,
|
||||
@ -64,31 +62,6 @@ if get_option('tests')
|
||||
test('uefi-dbx-self-test', e, env : testdatadirs) # added to installed-tests
|
||||
endif
|
||||
|
||||
uefi_dbx_fuzzer = executable(
|
||||
'uefi-dbx-fuzzer',
|
||||
sources : [
|
||||
'fu-fuzzer.c',
|
||||
'fu-efi-image.c',
|
||||
'fu-efi-signature.c',
|
||||
'fu-efi-signature-common.c',
|
||||
'fu-efi-signature-list.c',
|
||||
'fu-efi-signature-parser.c',
|
||||
'fu-uefi-dbx-common.c',
|
||||
],
|
||||
include_directories : [
|
||||
root_incdir,
|
||||
fwupd_incdir,
|
||||
fwupdplugin_incdir,
|
||||
],
|
||||
dependencies : [
|
||||
plugin_deps,
|
||||
],
|
||||
link_with : [
|
||||
fwupd,
|
||||
fwupdplugin,
|
||||
],
|
||||
)
|
||||
|
||||
dbxtool = executable(
|
||||
'dbxtool',
|
||||
sources : [
|
||||
@ -98,7 +71,6 @@ dbxtool = executable(
|
||||
'fu-efi-signature.c',
|
||||
'fu-efi-signature-common.c',
|
||||
'fu-efi-signature-list.c',
|
||||
'fu-efi-signature-parser.c',
|
||||
],
|
||||
include_directories : [
|
||||
root_incdir,
|
||||
@ -136,16 +108,3 @@ if get_option('man')
|
||||
install_dir : join_paths(mandir, 'man1'),
|
||||
)
|
||||
endif
|
||||
|
||||
if honggfuzz.found()
|
||||
run_target('fuzz-efidbx',
|
||||
command: [
|
||||
honggfuzz,
|
||||
'--input', join_paths(meson.current_source_dir(), 'fuzzing'),
|
||||
'--output', join_paths(meson.current_build_dir(), 'fuzzing-corpus'),
|
||||
'--workspace', join_paths(meson.current_build_dir(), 'fuzzing-findings'),
|
||||
'--verifier',
|
||||
'--', uefi_dbx_fuzzer, '___FILE___',
|
||||
],
|
||||
)
|
||||
endif
|
||||
|
||||
Loading…
Reference in New Issue
Block a user