From 7ecf0164dee4ad9d50d61b3f76a4c445d37a0e3e Mon Sep 17 00:00:00 2001 From: Richard Hughes Date: Tue, 26 Jun 2018 16:41:06 +0100 Subject: [PATCH] uefi: Show the stored capsule filename in fwupdate --- plugins/uefi/fu-self-test.c | 27 +++ plugins/uefi/fu-uefi-common.h | 3 - plugins/uefi/fu-uefi-device.c | 40 ++-- plugins/uefi/fu-uefi-device.h | 4 +- plugins/uefi/fu-uefi-tool.c | 44 ++--- plugins/uefi/fu-uefi-update-info.c | 186 ++++++++++++++++++ plugins/uefi/fu-uefi-update-info.h | 39 ++++ plugins/uefi/meson.build | 3 + plugins/uefi/tests/.gitignore | 1 + ...tNext-8be4df61-93ca-11d2-aa0d-00e098032b8c | 0 ...38e-0-0abba7dc-e516-4167-bbf5-4d9d1c739416 | Bin 0 -> 236 bytes 11 files changed, 291 insertions(+), 56 deletions(-) create mode 100644 plugins/uefi/fu-uefi-update-info.c create mode 100644 plugins/uefi/fu-uefi-update-info.h create mode 100644 plugins/uefi/tests/efi/efivars/BootNext-8be4df61-93ca-11d2-aa0d-00e098032b8c create mode 100644 plugins/uefi/tests/efi/efivars/fwupdate-ddc0ee61-e7f0-4e7d-acc5-c070a398838e-0-0abba7dc-e516-4167-bbf5-4d9d1c739416 diff --git a/plugins/uefi/fu-self-test.c b/plugins/uefi/fu-self-test.c index c0cd26603..c85b19cb0 100644 --- a/plugins/uefi/fu-self-test.c +++ b/plugins/uefi/fu-self-test.c @@ -212,6 +212,32 @@ fu_uefi_plugin_func (void) g_assert_cmpint (fu_uefi_device_get_status (dev), ==, FU_UEFI_DEVICE_STATUS_SUCCESS); } +static void +fu_uefi_update_info_func (void) +{ + g_autofree gchar *fn = NULL; + g_autoptr(FuUefiDevice) dev = NULL; + g_autoptr(FuUefiUpdateInfo) info = NULL; + g_autoptr(GError) error = NULL; + + fn = fu_test_get_filename (TESTDATADIR, "efi/esrt/entries/entry0"); + g_assert (fn != NULL); + dev = fu_uefi_device_new_from_entry (fn); + g_assert_nonnull (dev); + 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/fwupdate-697bd920-12cf-4da9-8385-996909bc6559.cap"); +} + int main (int argc, char **argv) { @@ -229,6 +255,7 @@ main (int argc, char **argv) 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/update-info", fu_uefi_update_info_func); g_test_add_func ("/uefi/plugin", fu_uefi_plugin_func); return g_test_run (); } diff --git a/plugins/uefi/fu-uefi-common.h b/plugins/uefi/fu-uefi-common.h index c6c50b6b9..94cc3b688 100644 --- a/plugins/uefi/fu-uefi-common.h +++ b/plugins/uefi/fu-uefi-common.h @@ -18,9 +18,6 @@ G_BEGIN_DECLS #define EFI_CAPSULE_HEADER_FLAGS_POPULATE_SYSTEM_TABLE 0x00020000 #define EFI_CAPSULE_HEADER_FLAGS_INITIATE_RESET 0x00040000 -#define EFI_UPDATE_INFO_STATUS_ATTEMPT_UPDATE 0x00000001 -#define EFI_UPDATE_INFO_STATUS_ATTEMPTED 0x00000002 - typedef struct __attribute__((__packed__)) { guint16 year; guint8 month; diff --git a/plugins/uefi/fu-uefi-device.c b/plugins/uefi/fu-uefi-device.c index 0724e279d..16d4cd95e 100644 --- a/plugins/uefi/fu-uefi-device.c +++ b/plugins/uefi/fu-uefi-device.c @@ -184,31 +184,13 @@ fu_uefi_device_set_efivar (FuUefiDevice *self, error); } -static gboolean -fu_uefi_device_info_from_databuf (efi_update_info_t *info, - const guint8 *data, - gsize sz, - GError **error) -{ - if (sz < sizeof(efi_update_info_t)) { - g_set_error_literal (error, - FWUPD_ERROR, - FWUPD_ERROR_INTERNAL, - "EFI variable is corrupt"); - return FALSE; - } - memcpy (info, data, sizeof(efi_update_info_t)); - return TRUE; -} - -gboolean -fu_uefi_device_get_update_info (FuUefiDevice *self, - efi_update_info_t *info, - GError **error) +FuUefiUpdateInfo * +fu_uefi_device_load_update_info (FuUefiDevice *self, GError **error) { gsize datasz = 0; g_autofree gchar *varname = fu_uefi_device_build_varname (self); g_autofree guint8 *data = NULL; + g_autoptr(FuUefiUpdateInfo) info = fu_uefi_update_info_new (); g_return_val_if_fail (FU_IS_UEFI_DEVICE (self), FALSE); g_return_val_if_fail (error == NULL || *error == NULL, FALSE); @@ -217,7 +199,9 @@ fu_uefi_device_get_update_info (FuUefiDevice *self, if (!fu_uefi_vars_get_data (FU_UEFI_VARS_GUID_FWUPDATE, varname, &data, &datasz, NULL, error)) return FALSE; - return fu_uefi_device_info_from_databuf (info, data, datasz, error); + if (!fu_uefi_update_info_parse (info, data, datasz, error)) + return FALSE; + return g_steal_pointer (&info); } gboolean @@ -235,10 +219,16 @@ fu_uefi_device_clear_status (FuUefiDevice *self, GError **error) if (!fu_uefi_vars_get_data (FU_UEFI_VARS_GUID_FWUPDATE, varname, &data, &datasz, NULL, error)) return FALSE; - if (!fu_uefi_device_info_from_databuf (&info, data, datasz, error)) + if (datasz < sizeof(efi_update_info_t)) { + g_set_error_literal (error, + FWUPD_ERROR, + FWUPD_ERROR_INTERNAL, + "EFI variable is corrupt"); return FALSE; + } - /* save it back */ + /* just copy the efi_update_info_t, ignore devpath then save it back */ + memcpy (&info, data, sizeof(info)); info.status = FU_UEFI_DEVICE_STATUS_SUCCESS; memcpy (data, &info, sizeof(info)); return fu_uefi_device_set_efivar (self, data, datasz, error); @@ -329,7 +319,7 @@ fu_uefi_device_write_firmware (FuDevice *device, GBytes *fw, GError **error) /* set the blob header shared with fwup.efi */ memset (&info, 0x0, sizeof(info)); - info.status = EFI_UPDATE_INFO_STATUS_ATTEMPT_UPDATE; + info.status = FU_UEFI_UPDATE_INFO_STATUS_ATTEMPT_UPDATE; info.capsule_flags = self->capsule_flags; info.update_info_version = 0x7; info.hw_inst = self->fmp_hardware_instance; diff --git a/plugins/uefi/fu-uefi-device.h b/plugins/uefi/fu-uefi-device.h index ea29e0698..202ce0f62 100644 --- a/plugins/uefi/fu-uefi-device.h +++ b/plugins/uefi/fu-uefi-device.h @@ -13,6 +13,7 @@ #include "fu-plugin.h" #include "fu-uefi-device.h" +#include "fu-uefi-update-info.h" G_BEGIN_DECLS @@ -55,8 +56,7 @@ guint64 fu_uefi_device_get_hardware_instance (FuUefiDevice *self); FuUefiDeviceStatus fu_uefi_device_get_status (FuUefiDevice *self); const gchar *fu_uefi_device_kind_to_string (FuUefiDeviceKind kind); const gchar *fu_uefi_device_status_to_string (FuUefiDeviceStatus status); -gboolean fu_uefi_device_get_update_info (FuUefiDevice *self, - efi_update_info_t *info, +FuUefiUpdateInfo *fu_uefi_device_load_update_info (FuUefiDevice *self, GError **error); G_END_DECLS diff --git a/plugins/uefi/fu-uefi-tool.c b/plugins/uefi/fu-uefi-tool.c index 14e2787bb..023456480 100644 --- a/plugins/uefi/fu-uefi-tool.c +++ b/plugins/uefi/fu-uefi-tool.c @@ -17,6 +17,7 @@ #include "fu-ucs2.h" #include "fu-uefi-common.h" #include "fu-uefi-device.h" +#include "fu-uefi-update-info.h" #include "fu-uefi-vars.h" /* custom return code */ @@ -47,16 +48,6 @@ fu_util_private_free (FuUtilPrivate *priv) G_DEFINE_AUTOPTR_CLEANUP_FUNC(FuUtilPrivate, fu_util_private_free) #pragma clang diagnostic pop -static const gchar * -fu_uefi_update_info_status_to_string (guint32 update_info_status) -{ - if (update_info_status == EFI_UPDATE_INFO_STATUS_ATTEMPT_UPDATE) - return "attempt-update"; - if (update_info_status == EFI_UPDATE_INFO_STATUS_ATTEMPTED) - return "attempted"; - return "unknown"; -} - int main (int argc, char *argv[]) { @@ -241,29 +232,30 @@ main (int argc, char *argv[]) /* show the information of firmware update status */ if (action_info) { - efi_update_info_t info; - g_autofree gchar *guid = NULL; for (guint i = 0; i < devices->len; i++) { FuUefiDevice *dev = g_ptr_array_index (devices, i); - efi_guid_t guid_tmp; + g_autoptr(FuUefiUpdateInfo) info = NULL; g_autoptr(GError) error_local = NULL; - if (!fu_uefi_device_get_update_info (dev, &info, &error_local)) { + + /* load any existing update info */ + info = fu_uefi_device_load_update_info (dev, &error_local); + if (info == NULL) { g_printerr ("failed: %s\n", error_local->message); continue; } - memcpy (&guid_tmp, &info.guid, sizeof(efi_guid_t)); - if (efi_guid_to_str (&guid_tmp, &guid) < 0) { - g_printerr ("failed to convert GUID: %s\n", - error_local->message); - continue; - } g_print ("Information for the update status entry %u:\n", i); - g_print (" Information Version: %" G_GUINT32_FORMAT "\n", info.update_info_version); - g_print (" Firmware GUID: {%s}\n", guid); - g_print (" Capsule Flags: 0x%08" G_GUINT32_FORMAT "x\n", info.capsule_flags); - g_print (" Hardware Instance: %" G_GUINT64_FORMAT "\n", info.hw_inst); - g_print (" Update Status: %s\n", fu_uefi_update_info_status_to_string (info.status)); - //g_print (" Capsule File Path: %s\n\n", info.capsule_fn); + g_print (" Information Version: %" G_GUINT32_FORMAT "\n", + fu_uefi_update_info_get_version (info)); + g_print (" Firmware GUID: {%s}\n", + fu_uefi_update_info_get_guid (info)); + g_print (" Capsule Flags: 0x%08" G_GUINT32_FORMAT "x\n", + fu_uefi_update_info_get_capsule_flags (info)); + g_print (" Hardware Instance: %" G_GUINT64_FORMAT "\n", + fu_uefi_update_info_get_hw_inst (info)); + g_print (" Update Status: %s\n", + fu_uefi_update_info_status_to_string (fu_uefi_update_info_get_status (info))); + g_print (" Capsule File Path: %s\n\n", + fu_uefi_update_info_get_capsule_fn (info)); } } diff --git a/plugins/uefi/fu-uefi-update-info.c b/plugins/uefi/fu-uefi-update-info.c new file mode 100644 index 000000000..8f2936e35 --- /dev/null +++ b/plugins/uefi/fu-uefi-update-info.c @@ -0,0 +1,186 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- + * + * Copyright (C) 2018 Richard Hughes + * + * SPDX-License-Identifier: LGPL-2.1+ + */ + +#include "config.h" + +#include + +#include "fu-common.h" +#include "fu-uefi-update-info.h" +#include "fu-uefi-common.h" +#include "fu-ucs2.h" + +#include "fwupd-error.h" + +struct _FuUefiUpdateInfo { + GObject parent_instance; + guint32 version; + gchar *guid; + gchar *capsule_fn; + guint32 capsule_flags; + guint64 hw_inst; + FuUefiUpdateInfoStatus status; +}; + +G_DEFINE_TYPE (FuUefiUpdateInfo, fu_uefi_update_info, G_TYPE_OBJECT) + +const gchar * +fu_uefi_update_info_status_to_string (FuUefiUpdateInfoStatus status) +{ + if (status == FU_UEFI_UPDATE_INFO_STATUS_ATTEMPT_UPDATE) + return "attempt-update"; + if (status == FU_UEFI_UPDATE_INFO_STATUS_ATTEMPTED) + return "attempted"; + return "unknown"; +} + +static gchar * +fu_uefi_update_info_parse_dp (const guint8 *buf, gsize sz) +{ + const_efidp idp; + guint16 ucs2sz = 0; + g_autofree gchar *relpath = NULL; + g_autofree guint16 *ucs2file = NULL; + + g_return_val_if_fail (buf != NULL, NULL); + g_return_val_if_fail (sz != 0, NULL); + + /* find UCS2 string */ + idp = (const_efidp) buf; + while (1) { + if (efidp_type (idp) == EFIDP_END_TYPE && + efidp_subtype (idp) == EFIDP_END_ENTIRE) + break; + if (efidp_type(idp) != EFIDP_MEDIA_TYPE || + efidp_subtype (idp) != EFIDP_MEDIA_FILE) { + if (efidp_next_node (idp, &idp) < 0) + break; + continue; + } + ucs2sz = efidp_node_size (idp) - 4; + ucs2file = g_new0 (guint16, (ucs2sz / 2) + 1); + memcpy (ucs2file, (guint8 *)idp + 4, ucs2sz); + break; + } + + /* nothing found */ + if (ucs2file == NULL || ucs2sz == 0) + return NULL; + + /* convert to something sane */ + relpath = fu_ucs2_to_uft8 (ucs2file, ucs2sz / sizeof (guint16)); + if (relpath == NULL) + return NULL; + g_strdelimit (relpath, "\\", '/'); + return g_steal_pointer (&relpath); +} + +gboolean +fu_uefi_update_info_parse (FuUefiUpdateInfo *self, const guint8 *buf, gsize sz, GError **error) +{ + efi_update_info_t info; + efi_guid_t guid_tmp; + + g_return_val_if_fail (FU_IS_UEFI_UPDATE_INFO (self), FALSE); + + if (sz < sizeof(efi_update_info_t)) { + g_set_error_literal (error, + FWUPD_ERROR, + FWUPD_ERROR_INTERNAL, + "EFI variable is corrupt"); + return FALSE; + } + memcpy (&info, buf, sizeof(info)); + self->version = info.update_info_version; + self->capsule_flags = info.capsule_flags; + self->hw_inst = info.hw_inst; + self->status = info.status; + memcpy (&guid_tmp, &info.guid, sizeof(efi_guid_t)); + if (efi_guid_to_str (&guid_tmp, &self->guid) < 0) { + g_set_error_literal (error, + FWUPD_ERROR, + FWUPD_ERROR_INTERNAL, + "failed to convert GUID"); + return FALSE; + } + if (sz > sizeof(efi_update_info_t)) { + self->capsule_fn = fu_uefi_update_info_parse_dp (buf + sizeof(efi_update_info_t), + sz - sizeof(efi_update_info_t)); + } + return TRUE; +} + +const gchar * +fu_uefi_update_info_get_guid (FuUefiUpdateInfo *self) +{ + g_return_val_if_fail (FU_IS_UEFI_UPDATE_INFO (self), NULL); + return self->guid; +} + +const gchar * +fu_uefi_update_info_get_capsule_fn (FuUefiUpdateInfo *self) +{ + g_return_val_if_fail (FU_IS_UEFI_UPDATE_INFO (self), NULL); + return self->capsule_fn; +} + +guint32 +fu_uefi_update_info_get_version (FuUefiUpdateInfo *self) +{ + g_return_val_if_fail (FU_IS_UEFI_UPDATE_INFO (self), 0); + return self->version; +} + +guint32 +fu_uefi_update_info_get_capsule_flags (FuUefiUpdateInfo *self) +{ + g_return_val_if_fail (FU_IS_UEFI_UPDATE_INFO (self), 0); + return self->capsule_flags; +} + +guint64 +fu_uefi_update_info_get_hw_inst (FuUefiUpdateInfo *self) +{ + g_return_val_if_fail (FU_IS_UEFI_UPDATE_INFO (self), 0); + return self->hw_inst; +} + +FuUefiUpdateInfoStatus +fu_uefi_update_info_get_status (FuUefiUpdateInfo *self) +{ + g_return_val_if_fail (FU_IS_UEFI_UPDATE_INFO (self), 0); + return self->status; +} + +static void +fu_uefi_update_info_finalize (GObject *object) +{ + FuUefiUpdateInfo *self = FU_UEFI_UPDATE_INFO (object); + g_free (self->guid); + g_free (self->capsule_fn); + G_OBJECT_CLASS (fu_uefi_update_info_parent_class)->finalize (object); +} + +static void +fu_uefi_update_info_class_init (FuUefiUpdateInfoClass *klass) +{ + GObjectClass *object_class = G_OBJECT_CLASS (klass); + object_class->finalize = fu_uefi_update_info_finalize; +} + +static void +fu_uefi_update_info_init (FuUefiUpdateInfo *self) +{ +} + +FuUefiUpdateInfo * +fu_uefi_update_info_new (void) +{ + FuUefiUpdateInfo *self; + self = g_object_new (FU_TYPE_UEFI_UPDATE_INFO, NULL); + return FU_UEFI_UPDATE_INFO (self); +} diff --git a/plugins/uefi/fu-uefi-update-info.h b/plugins/uefi/fu-uefi-update-info.h new file mode 100644 index 000000000..8b88249af --- /dev/null +++ b/plugins/uefi/fu-uefi-update-info.h @@ -0,0 +1,39 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- + * + * Copyright (C) 2018 Richard Hughes + * + * SPDX-License-Identifier: LGPL-2.1+ + */ + +#ifndef __FU_UEFI_UPDATE_INFO_H +#define __FU_UEFI_UPDATE_INFO_H + +#include + +G_BEGIN_DECLS + +#define FU_TYPE_UEFI_UPDATE_INFO (fu_uefi_update_info_get_type ()) +G_DECLARE_FINAL_TYPE (FuUefiUpdateInfo, fu_uefi_update_info, FU, UEFI_UPDATE_INFO, GObject) + +typedef enum { + FU_UEFI_UPDATE_INFO_STATUS_ATTEMPT_UPDATE = 0x00000001, + FU_UEFI_UPDATE_INFO_STATUS_ATTEMPTED = 0x00000002, +} FuUefiUpdateInfoStatus; + +const gchar *fu_uefi_update_info_status_to_string (FuUefiUpdateInfoStatus status); + +FuUefiUpdateInfo *fu_uefi_update_info_new (void); +gboolean fu_uefi_update_info_parse (FuUefiUpdateInfo *self, + const guint8 *buf, + gsize sz, + GError **error); +guint32 fu_uefi_update_info_get_version (FuUefiUpdateInfo *self); +const gchar *fu_uefi_update_info_get_guid (FuUefiUpdateInfo *self); +const gchar *fu_uefi_update_info_get_capsule_fn (FuUefiUpdateInfo *self); +guint32 fu_uefi_update_info_get_capsule_flags (FuUefiUpdateInfo *self); +guint64 fu_uefi_update_info_get_hw_inst (FuUefiUpdateInfo *self); +FuUefiUpdateInfoStatus fu_uefi_update_info_get_status (FuUefiUpdateInfo *self); + +G_END_DECLS + +#endif /* __FU_UEFI_UPDATE_INFO_H */ diff --git a/plugins/uefi/meson.build b/plugins/uefi/meson.build index d4e6750e5..a3ed573b0 100644 --- a/plugins/uefi/meson.build +++ b/plugins/uefi/meson.build @@ -11,6 +11,7 @@ shared_module('fu_plugin_uefi', 'fu-uefi-bootmgr.c', 'fu-uefi-common.c', 'fu-uefi-device.c', + 'fu-uefi-update-info.c', 'fu-uefi-vars.c', ], include_directories : [ @@ -38,6 +39,7 @@ executable( 'fu-uefi-bootmgr.c', 'fu-uefi-common.c', 'fu-uefi-device.c', + 'fu-uefi-update-info.c', 'fu-uefi-vars.c', ], include_directories : [ @@ -75,6 +77,7 @@ if get_option('tests') 'fu-uefi-bootmgr.c', 'fu-uefi-common.c', 'fu-uefi-device.c', + 'fu-uefi-update-info.c', 'fu-uefi-vars.c', 'fu-ucs2.c', ], diff --git a/plugins/uefi/tests/.gitignore b/plugins/uefi/tests/.gitignore index 8cee2f79d..a86ffc363 100644 --- a/plugins/uefi/tests/.gitignore +++ b/plugins/uefi/tests/.gitignore @@ -1 +1,2 @@ EFI +efi/efivars/fwupdate-c34cb672-a81e-5d32-9d89-cbcabe8ec37b-0-0abba7dc-e516-4167-bbf5-4d9d1c739416 diff --git a/plugins/uefi/tests/efi/efivars/BootNext-8be4df61-93ca-11d2-aa0d-00e098032b8c b/plugins/uefi/tests/efi/efivars/BootNext-8be4df61-93ca-11d2-aa0d-00e098032b8c new file mode 100644 index 000000000..e69de29bb diff --git a/plugins/uefi/tests/efi/efivars/fwupdate-ddc0ee61-e7f0-4e7d-acc5-c070a398838e-0-0abba7dc-e516-4167-bbf5-4d9d1c739416 b/plugins/uefi/tests/efi/efivars/fwupdate-ddc0ee61-e7f0-4e7d-acc5-c070a398838e-0-0abba7dc-e516-4167-bbf5-4d9d1c739416 new file mode 100644 index 0000000000000000000000000000000000000000..a8ef05b79c3fe4176bb9bc00aa32d33b2ead41bf GIT binary patch literal 236 zcmZQ)U|?VeVuhR4ndgO8`Zl-D%;emY8p*)G3KYc-7=gkpj9LsJnt=nV#(@pYh*~v0 zO5kdp=S=QXy{5h=a+#P|SlSq37+e|L7(9V=8bc~W3PV0a5kn%FR}Ljh847^ni3}w` zd0hrG21^EWh9sbfC4&)z0Z_ycNGAhz>oS;t)mZ{r77WHfYzkyq0wG9`0T3qv)tLcB TO@VAZAUhFgG6O^Xe-;J+|H34d literal 0 HcmV?d00001