mirror of
https://git.proxmox.com/git/fwupd
synced 2025-05-05 18:06:26 +00:00
383 lines
12 KiB
C
383 lines
12 KiB
C
/*
|
|
* Copyright (C) 2018 Richard Hughes <richard@hughsie.com>
|
|
*
|
|
* SPDX-License-Identifier: LGPL-2.1+
|
|
*/
|
|
|
|
#include "config.h"
|
|
|
|
#include <fwupdplugin.h>
|
|
|
|
#include "fu-context-private.h"
|
|
#include "fu-ucs2.h"
|
|
#include "fu-uefi-backend.h"
|
|
#include "fu-uefi-bgrt.h"
|
|
#include "fu-uefi-cod-device.h"
|
|
#include "fu-uefi-common.h"
|
|
#include "fu-uefi-pcrs.h"
|
|
|
|
static void
|
|
fu_uefi_pcrs_1_2_func(void)
|
|
{
|
|
gboolean ret;
|
|
g_autoptr(FuUefiPcrs) pcrs = fu_uefi_pcrs_new();
|
|
g_autoptr(GError) error = NULL;
|
|
g_autoptr(GPtrArray) pcr0s = NULL;
|
|
g_autoptr(GPtrArray) pcrXs = NULL;
|
|
|
|
g_setenv("FWUPD_SYSFSTPMDIR", TESTDATADIR, TRUE);
|
|
|
|
ret = fu_uefi_pcrs_setup(pcrs, &error);
|
|
g_assert_no_error(error);
|
|
g_assert_true(ret);
|
|
pcr0s = fu_uefi_pcrs_get_checksums(pcrs, 0);
|
|
g_assert_nonnull(pcr0s);
|
|
g_assert_cmpint(pcr0s->len, ==, 1);
|
|
pcrXs = fu_uefi_pcrs_get_checksums(pcrs, 999);
|
|
g_assert_nonnull(pcrXs);
|
|
g_assert_cmpint(pcrXs->len, ==, 0);
|
|
|
|
g_unsetenv("FWUPD_SYSFSTPMDIR");
|
|
}
|
|
|
|
static void
|
|
fu_uefi_pcrs_2_0_func(void)
|
|
{
|
|
g_autoptr(FuUefiPcrs) pcrs = fu_uefi_pcrs_new();
|
|
g_autoptr(GError) error = NULL;
|
|
g_autoptr(GPtrArray) pcr0s = NULL;
|
|
g_autoptr(GPtrArray) pcrXs = NULL;
|
|
const gchar *tpm_server_running = g_getenv("TPM_SERVER_RUNNING");
|
|
g_setenv("FWUPD_FORCE_TPM2", "1", TRUE);
|
|
|
|
#ifndef HAVE_TSS2
|
|
g_test_skip("Compiled without TPM2.0 support");
|
|
return;
|
|
#endif
|
|
|
|
#ifdef HAVE_GETUID
|
|
if (tpm_server_running == NULL && (getuid() != 0 || geteuid() != 0)) {
|
|
g_test_skip("TPM2.0 tests require simulated TPM2.0 running or need root access "
|
|
"with physical TPM");
|
|
return;
|
|
}
|
|
#endif
|
|
|
|
if (!fu_uefi_pcrs_setup(pcrs, &error)) {
|
|
if (tpm_server_running == NULL &&
|
|
g_error_matches(error, FWUPD_ERROR, FWUPD_ERROR_NOT_FOUND)) {
|
|
g_test_skip("no physical or simulated TPM 2.0 device available");
|
|
return;
|
|
}
|
|
}
|
|
g_assert_no_error(error);
|
|
pcr0s = fu_uefi_pcrs_get_checksums(pcrs, 0);
|
|
g_assert_nonnull(pcr0s);
|
|
g_assert_cmpint(pcr0s->len, >=, 1);
|
|
pcrXs = fu_uefi_pcrs_get_checksums(pcrs, 999);
|
|
g_assert_nonnull(pcrXs);
|
|
g_assert_cmpint(pcrXs->len, ==, 0);
|
|
g_unsetenv("FWUPD_FORCE_TPM2");
|
|
}
|
|
|
|
static void
|
|
fu_uefi_ucs2_func(void)
|
|
{
|
|
g_autofree guint16 *str1 = NULL;
|
|
g_autofree gchar *str2 = NULL;
|
|
str1 = fu_uft8_to_ucs2("hw!", -1);
|
|
g_assert_cmpint(fu_ucs2_strlen(str1, -1), ==, 3);
|
|
str2 = fu_ucs2_to_uft8(str1, -1);
|
|
g_assert_cmpstr("hw!", ==, str2);
|
|
}
|
|
|
|
static void
|
|
fu_uefi_bgrt_func(void)
|
|
{
|
|
gboolean ret;
|
|
g_autoptr(GError) error = NULL;
|
|
g_autoptr(FuUefiBgrt) bgrt = fu_uefi_bgrt_new();
|
|
ret = fu_uefi_bgrt_setup(bgrt, &error);
|
|
g_assert_no_error(error);
|
|
g_assert_true(ret);
|
|
g_assert_true(fu_uefi_bgrt_get_supported(bgrt));
|
|
g_assert_cmpint(fu_uefi_bgrt_get_xoffset(bgrt), ==, 123);
|
|
g_assert_cmpint(fu_uefi_bgrt_get_yoffset(bgrt), ==, 456);
|
|
g_assert_cmpint(fu_uefi_bgrt_get_width(bgrt), ==, 54);
|
|
g_assert_cmpint(fu_uefi_bgrt_get_height(bgrt), ==, 24);
|
|
}
|
|
|
|
static void
|
|
fu_uefi_framebuffer_func(void)
|
|
{
|
|
gboolean ret;
|
|
guint32 height = 0;
|
|
guint32 width = 0;
|
|
g_autoptr(GError) error = NULL;
|
|
ret = fu_uefi_get_framebuffer_size(&width, &height, &error);
|
|
g_assert_no_error(error);
|
|
g_assert_true(ret);
|
|
g_assert_cmpint(width, ==, 456);
|
|
g_assert_cmpint(height, ==, 789);
|
|
}
|
|
|
|
static void
|
|
fu_uefi_bitmap_func(void)
|
|
{
|
|
gboolean ret;
|
|
gsize sz = 0;
|
|
guint32 height = 0;
|
|
guint32 width = 0;
|
|
g_autofree gchar *fn = NULL;
|
|
g_autofree gchar *buf = NULL;
|
|
g_autoptr(GError) error = NULL;
|
|
|
|
fn = g_build_filename(TESTDATADIR, "test.bmp", NULL);
|
|
ret = g_file_get_contents(fn, &buf, &sz, &error);
|
|
g_assert_no_error(error);
|
|
g_assert_true(ret);
|
|
g_assert_nonnull(buf);
|
|
ret = fu_uefi_get_bitmap_size((guint8 *)buf, sz, &width, &height, &error);
|
|
g_assert_no_error(error);
|
|
g_assert_true(ret);
|
|
g_assert_cmpint(width, ==, 54);
|
|
g_assert_cmpint(height, ==, 24);
|
|
}
|
|
|
|
static GByteArray *
|
|
fu_uefi_cod_device_build_efi_string(const gchar *text)
|
|
{
|
|
GByteArray *array = g_byte_array_new();
|
|
glong items_written = 0;
|
|
g_autofree gunichar2 *test_utf16 = NULL;
|
|
g_autoptr(GError) error = NULL;
|
|
|
|
fu_byte_array_append_uint32(array, 0x0, G_LITTLE_ENDIAN); /* attrs */
|
|
test_utf16 = g_utf8_to_utf16(text, -1, NULL, &items_written, &error);
|
|
g_assert_no_error(error);
|
|
g_assert_nonnull(test_utf16);
|
|
g_byte_array_append(array, (const guint8 *)test_utf16, items_written * 2);
|
|
return array;
|
|
}
|
|
|
|
static GByteArray *
|
|
fu_uefi_cod_device_build_efi_result(const gchar *guidstr)
|
|
{
|
|
GByteArray *array = g_byte_array_new();
|
|
fwupd_guid_t guid = {0x0};
|
|
gboolean ret;
|
|
guint8 timestamp[16] = {0x0};
|
|
g_autoptr(GError) error = NULL;
|
|
|
|
fu_byte_array_append_uint32(array, 0x0, G_LITTLE_ENDIAN); /* attrs */
|
|
fu_byte_array_append_uint32(array, 0x3A, G_LITTLE_ENDIAN); /* VariableTotalSize */
|
|
fu_byte_array_append_uint32(array, 0xFF, G_LITTLE_ENDIAN); /* Reserved */
|
|
ret = fwupd_guid_from_string(guidstr, &guid, FWUPD_GUID_FLAG_MIXED_ENDIAN, &error);
|
|
g_assert_no_error(error);
|
|
g_assert_true(ret);
|
|
g_byte_array_append(array, guid, sizeof(guid)); /* CapsuleGuid */
|
|
g_byte_array_append(array, timestamp, sizeof(timestamp)); /* CapsuleProcessed */
|
|
fu_byte_array_append_uint32(array,
|
|
FU_UEFI_DEVICE_STATUS_ERROR_PWR_EVT_BATT,
|
|
G_LITTLE_ENDIAN); /* Status */
|
|
return array;
|
|
}
|
|
|
|
static void
|
|
fu_uefi_cod_device_write_efi_name(const gchar *name, GByteArray *array)
|
|
{
|
|
gboolean ret;
|
|
g_autoptr(GError) error = NULL;
|
|
g_autofree gchar *fn = g_strdup_printf("%s-%s", name, FU_EFIVAR_GUID_EFI_CAPSULE_REPORT);
|
|
g_autofree gchar *path = g_build_filename(TESTDATADIR, "efi", "efivars", fn, NULL);
|
|
ret = g_file_set_contents(path, (gchar *)array->data, array->len, &error);
|
|
g_assert_no_error(error);
|
|
g_assert_true(ret);
|
|
}
|
|
|
|
static void
|
|
fu_uefi_cod_device_func(void)
|
|
{
|
|
gboolean ret;
|
|
g_autoptr(FuDevice) dev = NULL;
|
|
g_autoptr(GError) error = NULL;
|
|
g_autofree gchar *str = NULL;
|
|
|
|
/* these are checked into git and so are not required */
|
|
if (g_getenv("FU_UEFI_CAPSULE_RECREATE_COD_SELF_TEST_DATA") != NULL) {
|
|
g_autoptr(GByteArray) cap0 = NULL;
|
|
g_autoptr(GByteArray) cap1 = NULL;
|
|
g_autoptr(GByteArray) last = NULL;
|
|
g_autoptr(GByteArray) max = NULL;
|
|
|
|
last = fu_uefi_cod_device_build_efi_string("Capsule0001");
|
|
max = fu_uefi_cod_device_build_efi_string("Capsule9999");
|
|
cap0 = fu_uefi_cod_device_build_efi_result("99999999-bf9d-540b-b92b-172ce31013c1");
|
|
cap1 = fu_uefi_cod_device_build_efi_result("cc4cbfa9-bf9d-540b-b92b-172ce31013c1");
|
|
fu_uefi_cod_device_write_efi_name("CapsuleLast", last);
|
|
fu_uefi_cod_device_write_efi_name("CapsuleMax", max);
|
|
fu_uefi_cod_device_write_efi_name("Capsule0000", cap0);
|
|
fu_uefi_cod_device_write_efi_name("Capsule0001", cap1);
|
|
}
|
|
|
|
/* create device */
|
|
dev = g_object_new(FU_TYPE_UEFI_COD_DEVICE,
|
|
"fw-class",
|
|
"cc4cbfa9-bf9d-540b-b92b-172ce31013c1",
|
|
NULL);
|
|
ret = fu_device_get_results(dev, &error);
|
|
g_assert_no_error(error);
|
|
g_assert_true(ret);
|
|
|
|
/* debug */
|
|
str = fu_device_to_string(dev);
|
|
g_debug("%s", str);
|
|
g_assert_cmpint(fu_device_get_update_state(dev), ==, FWUPD_UPDATE_STATE_FAILED_TRANSIENT);
|
|
g_assert_cmpstr(fu_device_get_update_error(dev),
|
|
==,
|
|
"failed to update to 0: battery level is too low");
|
|
g_assert_cmpint(fu_uefi_device_get_status(FU_UEFI_DEVICE(dev)),
|
|
==,
|
|
FU_UEFI_DEVICE_STATUS_ERROR_PWR_EVT_BATT);
|
|
}
|
|
|
|
static void
|
|
fu_uefi_device_func(void)
|
|
{
|
|
/* check enums all converted */
|
|
for (guint i = 0; i < FU_UEFI_DEVICE_STATUS_LAST; i++)
|
|
g_assert_nonnull(fu_uefi_device_status_to_string(i));
|
|
}
|
|
|
|
static void
|
|
fu_uefi_plugin_func(void)
|
|
{
|
|
FuUefiDevice *dev;
|
|
gboolean ret;
|
|
g_autoptr(FuContext) ctx = fu_context_new();
|
|
g_autoptr(FuBackend) backend = fu_uefi_backend_new(ctx);
|
|
g_autoptr(GError) error = NULL;
|
|
g_autoptr(GPtrArray) devices = NULL;
|
|
|
|
#ifndef __linux__
|
|
g_test_skip("ESRT data is mocked only on Linux");
|
|
return;
|
|
#endif
|
|
|
|
/* do not save silo */
|
|
ret = fu_context_load_quirks(ctx, FU_QUIRKS_LOAD_FLAG_NO_CACHE, &error);
|
|
g_assert_no_error(error);
|
|
g_assert_true(ret);
|
|
|
|
/* add each device */
|
|
ret = fu_backend_coldplug(backend, &error);
|
|
g_assert_no_error(error);
|
|
g_assert_true(ret);
|
|
devices = fu_backend_get_devices(backend);
|
|
g_assert_cmpint(devices->len, ==, 3);
|
|
|
|
/* system firmware */
|
|
dev = g_ptr_array_index(devices, 0);
|
|
ret = fu_device_probe(FU_DEVICE(dev), &error);
|
|
g_assert_no_error(error);
|
|
g_assert_true(ret);
|
|
g_assert_cmpint(fu_uefi_device_get_kind(dev), ==, FU_UEFI_DEVICE_KIND_SYSTEM_FIRMWARE);
|
|
g_assert_cmpstr(fu_uefi_device_get_guid(dev), ==, "ddc0ee61-e7f0-4e7d-acc5-c070a398838e");
|
|
g_assert_cmpint(fu_uefi_device_get_hardware_instance(dev), ==, 0x0);
|
|
g_assert_cmpint(fu_uefi_device_get_version(dev), ==, 65586);
|
|
g_assert_cmpint(fu_uefi_device_get_version_lowest(dev), ==, 65582);
|
|
g_assert_cmpint(fu_uefi_device_get_version_error(dev), ==, 18472960);
|
|
g_assert_cmpint(fu_uefi_device_get_capsule_flags(dev), ==, 0xfe);
|
|
g_assert_cmpint(fu_uefi_device_get_status(dev),
|
|
==,
|
|
FU_UEFI_DEVICE_STATUS_ERROR_UNSUCCESSFUL);
|
|
|
|
/* system firmware */
|
|
dev = g_ptr_array_index(devices, 1);
|
|
ret = fu_device_probe(FU_DEVICE(dev), &error);
|
|
g_assert_no_error(error);
|
|
g_assert_true(ret);
|
|
g_assert_cmpint(fu_uefi_device_get_kind(dev), ==, FU_UEFI_DEVICE_KIND_DEVICE_FIRMWARE);
|
|
g_assert_cmpstr(fu_uefi_device_get_guid(dev), ==, "671d19d0-d43c-4852-98d9-1ce16f9967e4");
|
|
g_assert_cmpint(fu_uefi_device_get_version(dev), ==, 3090287969);
|
|
g_assert_cmpint(fu_uefi_device_get_version_lowest(dev), ==, 1);
|
|
g_assert_cmpint(fu_uefi_device_get_version_error(dev), ==, 0);
|
|
g_assert_cmpint(fu_uefi_device_get_capsule_flags(dev), ==, 32784);
|
|
g_assert_cmpint(fu_uefi_device_get_status(dev), ==, FU_UEFI_DEVICE_STATUS_SUCCESS);
|
|
|
|
/* invalid */
|
|
dev = g_ptr_array_index(devices, 2);
|
|
ret = fu_device_probe(FU_DEVICE(dev), &error);
|
|
g_assert_error(error, FWUPD_ERROR, FWUPD_ERROR_NOT_SUPPORTED);
|
|
g_assert_false(ret);
|
|
}
|
|
|
|
static void
|
|
fu_uefi_update_info_func(void)
|
|
{
|
|
FuUefiDevice *dev;
|
|
gboolean ret;
|
|
g_autoptr(FuContext) ctx = fu_context_new();
|
|
g_autoptr(FuBackend) backend = fu_uefi_backend_new(ctx);
|
|
g_autoptr(FuUefiUpdateInfo) info = NULL;
|
|
g_autoptr(GError) error = NULL;
|
|
g_autoptr(GPtrArray) devices = NULL;
|
|
|
|
#ifndef __linux__
|
|
g_test_skip("ESRT data is mocked only on Linux");
|
|
return;
|
|
#endif
|
|
|
|
/* add each device */
|
|
ret = fu_backend_coldplug(backend, &error);
|
|
g_assert_no_error(error);
|
|
g_assert_true(ret);
|
|
|
|
devices = fu_backend_get_devices(backend);
|
|
g_assert_cmpint(devices->len, ==, 3);
|
|
dev = g_ptr_array_index(devices, 0);
|
|
g_assert_cmpint(fu_uefi_device_get_kind(dev), ==, FU_UEFI_DEVICE_KIND_SYSTEM_FIRMWARE);
|
|
g_assert_cmpstr(fu_uefi_device_get_guid(dev), ==, "ddc0ee61-e7f0-4e7d-acc5-c070a398838e");
|
|
info = fu_uefi_device_load_update_info(dev, &error);
|
|
g_assert_no_error(error);
|
|
g_assert_nonnull(info);
|
|
g_assert_cmpint(fu_uefi_update_info_get_version(info), ==, 0x7);
|
|
g_assert_cmpstr(fu_uefi_update_info_get_guid(info),
|
|
==,
|
|
"697bd920-12cf-4da9-8385-996909bc6559");
|
|
g_assert_cmpint(fu_uefi_update_info_get_capsule_flags(info), ==, 0x50000);
|
|
g_assert_cmpint(fu_uefi_update_info_get_hw_inst(info), ==, 0x0);
|
|
g_assert_cmpint(fu_uefi_update_info_get_status(info),
|
|
==,
|
|
FU_UEFI_UPDATE_INFO_STATUS_ATTEMPT_UPDATE);
|
|
g_assert_cmpstr(fu_uefi_update_info_get_capsule_fn(info),
|
|
==,
|
|
"/EFI/fedora/fw/fwupd-697bd920-12cf-4da9-8385-996909bc6559.cap");
|
|
}
|
|
|
|
int
|
|
main(int argc, char **argv)
|
|
{
|
|
g_test_init(&argc, &argv, NULL);
|
|
g_setenv("FWUPD_SYSFSFWDIR", TESTDATADIR, TRUE);
|
|
g_setenv("FWUPD_SYSFSDRIVERDIR", TESTDATADIR, TRUE);
|
|
g_setenv("FWUPD_UEFI_TEST", "1", TRUE);
|
|
|
|
/* only critical and error are fatal */
|
|
g_log_set_fatal_mask(NULL, G_LOG_LEVEL_ERROR | G_LOG_LEVEL_CRITICAL);
|
|
g_setenv("G_MESSAGES_DEBUG", "all", TRUE);
|
|
|
|
/* tests go here */
|
|
g_test_add_func("/uefi/pcrs1.2", fu_uefi_pcrs_1_2_func);
|
|
g_test_add_func("/uefi/pcrs2.0", fu_uefi_pcrs_2_0_func);
|
|
g_test_add_func("/uefi/ucs2", fu_uefi_ucs2_func);
|
|
g_test_add_func("/uefi/bgrt", fu_uefi_bgrt_func);
|
|
g_test_add_func("/uefi/framebuffer", fu_uefi_framebuffer_func);
|
|
g_test_add_func("/uefi/bitmap", fu_uefi_bitmap_func);
|
|
g_test_add_func("/uefi/device", fu_uefi_device_func);
|
|
g_test_add_func("/uefi/cod-device", fu_uefi_cod_device_func);
|
|
g_test_add_func("/uefi/update-info", fu_uefi_update_info_func);
|
|
g_test_add_func("/uefi/plugin", fu_uefi_plugin_func);
|
|
return g_test_run();
|
|
}
|