From 09e63cd45dcfc762d32d52a00672c4b55b415d5a Mon Sep 17 00:00:00 2001 From: Richard Hughes Date: Mon, 27 Apr 2020 11:12:27 +0100 Subject: [PATCH 001/607] trivial: post release version bump --- RELEASE | 4 ++-- meson.build | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/RELEASE b/RELEASE index 2285740aa..80297efc3 100644 --- a/RELEASE +++ b/RELEASE @@ -2,7 +2,7 @@ fwupd Release Notes Write release entries: -git log --format="%s" --cherry-pick --right-only 1.4.0... | grep -i -v trivial | grep -v Merge | sort | uniq +git log --format="%s" --cherry-pick --right-only 1.4.1... | grep -i -v trivial | grep -v Merge | sort | uniq Add any user visible changes into ../data/org.freedesktop.fwupd.metainfo.xml appstream-util appdata-to-news ../data/org.freedesktop.fwupd.metainfo.xml > NEWS @@ -17,7 +17,7 @@ git add ../po/*.po 2. Commit changes to git: # MAKE SURE THIS IS CORRECT -export release_ver="1.4.1" +export release_ver="1.4.2" git commit -a -m "Release fwupd ${release_ver}" git tag -s -f -m "Release fwupd ${release_ver}" "${release_ver}" diff --git a/meson.build b/meson.build index 85420cf78..df7815847 100644 --- a/meson.build +++ b/meson.build @@ -1,5 +1,5 @@ project('fwupd', 'c', - version : '1.4.1', + version : '1.4.2', license : 'LGPL-2.1+', meson_version : '>=0.47.0', default_options : ['warning_level=2', 'c_std=c99'], From daf5ebb294e3f0920527130dbf2d1b64bd17af6e Mon Sep 17 00:00:00 2001 From: Richard Hughes Date: Mon, 27 Apr 2020 11:58:30 +0100 Subject: [PATCH 002/607] trivial: Do not build flashrom on all architectures --- contrib/fwupd.spec.in | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/contrib/fwupd.spec.in b/contrib/fwupd.spec.in index 348fcc810..63e85f472 100644 --- a/contrib/fwupd.spec.in +++ b/contrib/fwupd.spec.in @@ -18,6 +18,11 @@ %global have_uefi 1 %endif +# flashrom is only available on these arches +%ifarch i686 x86_64 armv7hl aarch64 ppc64le +%global have_flashrom 1 +%endif + # redfish is only available on this arch %ifarch x86_64 %global have_redfish 1 @@ -70,7 +75,9 @@ BuildRequires: json-glib-devel >= %{json_glib_version} BuildRequires: vala BuildRequires: bash-completion BuildRequires: git-core +%if 0%{?have_flashrom} BuildRequires: flashrom-devel >= 1.2-2 +%endif %if 0%{?have_modem_manager} BuildRequires: ModemManager-glib-devel >= 1.10.0 @@ -166,7 +173,11 @@ Data files for installed tests. %else -Dplugin_dummy=false \ %endif +%if 0%{?have_flashrom} -Dplugin_flashrom=true \ +%else + -Dplugin_flashrom=false \ +%endif -Dplugin_thunderbolt=true \ %if 0%{?have_redfish} -Dplugin_redfish=true \ @@ -331,7 +342,9 @@ mkdir -p --mode=0700 $RPM_BUILD_ROOT%{_localstatedir}/lib/fwupd/gnupg %{_libdir}/fwupd-plugins-3/libfu_plugin_emmc.so %{_libdir}/fwupd-plugins-3/libfu_plugin_ep963x.so %{_libdir}/fwupd-plugins-3/libfu_plugin_fastboot.so +%if 0%{?have_flashrom} %{_libdir}/fwupd-plugins-3/libfu_plugin_flashrom.so +%endif %{_libdir}/fwupd-plugins-3/libfu_plugin_fresco_pd.so %{_libdir}/fwupd-plugins-3/libfu_plugin_jabra.so %if 0%{?have_modem_manager} From 11a42d29a941b101f6a5fb8efb7f03c09534aa7a Mon Sep 17 00:00:00 2001 From: Richard Hughes Date: Mon, 27 Apr 2020 16:11:48 +0100 Subject: [PATCH 003/607] trivial: Fix another merge-conflict remnant spotted by Coverity --- src/fu-keyring-utils.c | 5 ----- 1 file changed, 5 deletions(-) diff --git a/src/fu-keyring-utils.c b/src/fu-keyring-utils.c index 96f0bf9c3..2bf46aae5 100644 --- a/src/fu-keyring-utils.c +++ b/src/fu-keyring-utils.c @@ -33,11 +33,6 @@ fu_keyring_get_release_flags (XbNode *release, if (blob == NULL) { g_debug ("no fwupd::ReleaseFlags set by loader"); return TRUE; - g_set_error_literal (error, - FWUPD_ERROR, - FWUPD_ERROR_INVALID_FILE, - "no fwupd::ReleaseFlags set by loader"); - return FALSE; } if (g_bytes_get_size (blob) != sizeof(FwupdReleaseFlags)) { g_set_error_literal (error, From 4eaf8829114644b916ee66ad4120da367ccc15fe Mon Sep 17 00:00:00 2001 From: Richard Hughes Date: Mon, 27 Apr 2020 16:12:13 +0100 Subject: [PATCH 004/607] trivial: Fix a potential NULL deref spotted by Coverity --- plugins/fresco-pd/fu-fresco-pd-device.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/plugins/fresco-pd/fu-fresco-pd-device.c b/plugins/fresco-pd/fu-fresco-pd-device.c index 2ee8c8f32..745f6f251 100644 --- a/plugins/fresco-pd/fu-fresco-pd-device.c +++ b/plugins/fresco-pd/fu-fresco-pd-device.c @@ -248,8 +248,7 @@ fu_fresco_pd_device_panther_reset_device (FuFrescoPdDevice *self, GError **error return TRUE; } g_propagate_prefixed_error (error, g_steal_pointer (&error_local), - "failed to reset device [%i]", - error_local->code); + "failed to reset device: "); return FALSE; } return TRUE; From 02930f1f23e67c410c808d7ead6dd7da6982c461 Mon Sep 17 00:00:00 2001 From: Richard Hughes Date: Tue, 28 Apr 2020 13:38:48 +0100 Subject: [PATCH 005/607] trivial: Fix DFU debug output --- plugins/dfu/dfu-device.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugins/dfu/dfu-device.c b/plugins/dfu/dfu-device.c index e9943edd0..9e11d22dc 100644 --- a/plugins/dfu/dfu-device.c +++ b/plugins/dfu/dfu-device.c @@ -116,7 +116,7 @@ dfu_device_to_string (FuDevice *device, guint idt, GString *str) if (priv->chip_id != NULL) fu_common_string_append_kv (str, idt, "ChipId", priv->chip_id); fu_common_string_append_kx (str, idt, "Version", priv->version); - fu_common_string_append_kx (str, idt, "Force_version", priv->force_version); + fu_common_string_append_kx (str, idt, "ForceVersion", priv->force_version); fu_common_string_append_kx (str, idt, "RuntimePid", priv->runtime_pid); fu_common_string_append_kx (str, idt, "RuntimeVid", priv->runtime_vid); fu_common_string_append_kx (str, idt, "RuntimeRelease", priv->runtime_release); From 89130342bcc6f1a41e1f39d8fa80aae714ed8907 Mon Sep 17 00:00:00 2001 From: Mario Limonciello Date: Tue, 28 Apr 2020 09:48:39 -0500 Subject: [PATCH 006/607] Generate a body for github releases (Fixes: #2034) --- .circleci/config.yml | 3 ++- contrib/ci/generate_news.py | 25 +++++++++++++++++++++++++ 2 files changed, 27 insertions(+), 1 deletion(-) create mode 100755 contrib/ci/generate_news.py diff --git a/.circleci/config.yml b/.circleci/config.yml index 89b6c86b0..42d78d6fc 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -165,7 +165,8 @@ jobs: command: | go get github.com/tcnksm/ghr VERSION=$(cat dist/VERSION) - ghr -t ${GITHUB_TOKEN} -u ${CIRCLE_PROJECT_USERNAME} -r ${CIRCLE_PROJECT_REPONAME} -c ${CIRCLE_SHA1} ${VERSION} ./dist/setup/ + BODY=$(./contrib/ci/generate_news.py $VERSION) + ghr -t ${GITHUB_TOKEN} -u ${CIRCLE_PROJECT_USERNAME} -r ${CIRCLE_PROJECT_REPONAME} -c ${CIRCLE_SHA1} -b ${BODY} ${VERSION} ./dist/setup/ workflows: version: 2 main: diff --git a/contrib/ci/generate_news.py b/contrib/ci/generate_news.py new file mode 100755 index 000000000..b0316ab11 --- /dev/null +++ b/contrib/ci/generate_news.py @@ -0,0 +1,25 @@ +#!/usr/bin/python3 +# +# Copyright (C) 2020 Dell Inc. +# +# SPDX-License-Identifier: LGPL-2.1+ +# +import os +import argparse +import xml.etree.ElementTree as etree + +if __name__ == "__main__": + parser = argparse.ArgumentParser() + parser.add_argument("version", help="Generate news for release") + args = parser.parse_args() + + tree = etree.parse(os.path.join("data", "org.freedesktop.fwupd.metainfo.xml")) + root = tree.getroot() + for release in root.iter("release"): + if "version" not in release.attrib: + continue + if release.attrib["version"] != args.version: + continue + description = release.find("description") + str = etree.tostring(description, encoding="unicode", method="text") + print(str.strip()) From e010c606e48118334ddd555ccfd26bab5b5233de Mon Sep 17 00:00:00 2001 From: Crag Wang Date: Tue, 28 Apr 2020 22:32:25 +0800 Subject: [PATCH 007/607] wacom-raw: fixup switching to bootloader mode --- plugins/wacom-raw/fu-wacom-device.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/plugins/wacom-raw/fu-wacom-device.c b/plugins/wacom-raw/fu-wacom-device.c index fb456d04c..745a88a61 100644 --- a/plugins/wacom-raw/fu-wacom-device.c +++ b/plugins/wacom-raw/fu-wacom-device.c @@ -106,8 +106,8 @@ fu_wacom_device_detach (FuDevice *device, GError **error) FU_WACOM_RAW_FW_REPORT_ID, FU_WACOM_RAW_FW_CMD_DETACH, }; - if (!fu_device_has_flag (device, FWUPD_DEVICE_FLAG_IS_BOOTLOADER)) { - g_debug ("already in runtime mode, skipping"); + if (fu_device_has_flag (device, FWUPD_DEVICE_FLAG_IS_BOOTLOADER)) { + g_debug ("already in bootloader mode, skipping"); return TRUE; } if (!fu_wacom_device_set_feature (self, buf, sizeof(buf), error)) { From 224b685fae6300395b8011aea29d446e966877a6 Mon Sep 17 00:00:00 2001 From: Mario Limonciello Date: Fri, 27 Mar 2020 10:11:30 -0500 Subject: [PATCH 008/607] fu-udev-device: Add support for reading arbitrary sysfs attributes Some devices provide 'non-standard' attributes that are relevant for use. --- libfwupdplugin/fu-udev-device.c | 51 +++++++++++++++++++++++++++++++++ libfwupdplugin/fu-udev-device.h | 3 ++ libfwupdplugin/fwupdplugin.map | 6 ++++ 3 files changed, 60 insertions(+) diff --git a/libfwupdplugin/fu-udev-device.c b/libfwupdplugin/fu-udev-device.c index 8f1d8fe95..250fc2fb7 100644 --- a/libfwupdplugin/fu-udev-device.c +++ b/libfwupdplugin/fu-udev-device.c @@ -943,6 +943,57 @@ fu_udev_device_pwrite (FuUdevDevice *self, goffset port, guint8 data, GError **e #endif } +/** + * fu_udev_device_get_sysfs_attr: + * @self: A #FuUdevDevice + * @attr: name of attribute to get + * @error: A #GError, or %NULL + * + * Reads an arbitrary sysfs attribute 'attr' associated with UDEV device + * + * Returns: string or NULL + * + * Since: 1.4.2 + **/ +const gchar * +fu_udev_device_get_sysfs_attr (FuUdevDevice *self, const gchar *attr, + GError **error) +{ +#ifdef HAVE_GUDEV + FuUdevDevicePrivate *priv = GET_PRIVATE (self); + const gchar *result; + + g_return_val_if_fail (FU_IS_UDEV_DEVICE (self), FALSE); + g_return_val_if_fail (attr != NULL, FALSE); + + /* nothing to do */ + if (priv->udev_device == NULL) { + g_set_error_literal (error, + G_IO_ERROR, + G_IO_ERROR_NOT_FOUND, + "not yet initialized"); + return NULL; + } + result = g_udev_device_get_sysfs_attr (priv->udev_device, attr); + if (result == NULL) { + g_set_error (error, + G_IO_ERROR, + G_IO_ERROR_NOT_FOUND, + "attribute %s returned no data", + attr); + return FALSE; + } + + return result; +#endif + g_set_error_literal (error, + G_IO_ERROR, + G_IO_ERROR_FAILED, + "not supported"); + return NULL; + +} + /** * fu_udev_device_pread: * @self: A #FuUdevDevice diff --git a/libfwupdplugin/fu-udev-device.h b/libfwupdplugin/fu-udev-device.h index b4b37ca5b..5e82e5d4f 100644 --- a/libfwupdplugin/fu-udev-device.h +++ b/libfwupdplugin/fu-udev-device.h @@ -85,3 +85,6 @@ gboolean fu_udev_device_pread (FuUdevDevice *self, goffset port, guint8 *data, GError **error); +const gchar *fu_udev_device_get_sysfs_attr (FuUdevDevice *self, + const gchar *attr, + GError **error); diff --git a/libfwupdplugin/fwupdplugin.map b/libfwupdplugin/fwupdplugin.map index 875afc744..91dd5d608 100644 --- a/libfwupdplugin/fwupdplugin.map +++ b/libfwupdplugin/fwupdplugin.map @@ -580,3 +580,9 @@ LIBFWUPDPLUGIN_1.4.1 { fu_device_set_proxy_guid; local: *; } LIBFWUPDPLUGIN_1.4.0; + +LIBFWUPDPLUGIN_1.4.2 { + global: + fu_udev_device_get_sysfs_attr; + local: *; +} LIBFWUPDPLUGIN_1.4.1; From 0d207d8dea58165ae6467a7d6610a65a75c8bb1a Mon Sep 17 00:00:00 2001 From: Mario Limonciello Date: Fri, 27 Mar 2020 14:35:46 -0500 Subject: [PATCH 009/607] fu-udev-device: add fu_udev_device_get_parent_name This will fetch the name from parent device --- libfwupdplugin/fu-udev-device.c | 26 ++++++++++++++++++++++++++ libfwupdplugin/fu-udev-device.h | 1 + libfwupdplugin/fwupdplugin.map | 1 + 3 files changed, 28 insertions(+) diff --git a/libfwupdplugin/fu-udev-device.c b/libfwupdplugin/fu-udev-device.c index 250fc2fb7..efc5a19f9 100644 --- a/libfwupdplugin/fu-udev-device.c +++ b/libfwupdplugin/fu-udev-device.c @@ -943,6 +943,32 @@ fu_udev_device_pwrite (FuUdevDevice *self, goffset port, guint8 data, GError **e #endif } +/** + * fu_udev_device_get_parent_name + * @self: A #FuUdevDevice + * + * Returns the name of the direct ancestor of this device + * + * Returns: string or NULL if unset or invalid + * + * Since: 1.4.2 + **/ +gchar * +fu_udev_device_get_parent_name (FuUdevDevice *self) +{ +#ifdef HAVE_GUDEV + FuUdevDevicePrivate *priv = GET_PRIVATE (self); + g_autoptr(GUdevDevice) parent = NULL; + + g_return_val_if_fail (FU_IS_UDEV_DEVICE (self), NULL); + + parent = g_udev_device_get_parent (priv->udev_device); + return parent == NULL ? NULL : g_strdup (g_udev_device_get_name (parent)); +#else + return NULL; +#endif +} + /** * fu_udev_device_get_sysfs_attr: * @self: A #FuUdevDevice diff --git a/libfwupdplugin/fu-udev-device.h b/libfwupdplugin/fu-udev-device.h index 5e82e5d4f..923e9c587 100644 --- a/libfwupdplugin/fu-udev-device.h +++ b/libfwupdplugin/fu-udev-device.h @@ -88,3 +88,4 @@ gboolean fu_udev_device_pread (FuUdevDevice *self, const gchar *fu_udev_device_get_sysfs_attr (FuUdevDevice *self, const gchar *attr, GError **error); +gchar *fu_udev_device_get_parent_name (FuUdevDevice *self); diff --git a/libfwupdplugin/fwupdplugin.map b/libfwupdplugin/fwupdplugin.map index 91dd5d608..3a8456640 100644 --- a/libfwupdplugin/fwupdplugin.map +++ b/libfwupdplugin/fwupdplugin.map @@ -583,6 +583,7 @@ LIBFWUPDPLUGIN_1.4.1 { LIBFWUPDPLUGIN_1.4.2 { global: + fu_udev_device_get_parent_name; fu_udev_device_get_sysfs_attr; local: *; } LIBFWUPDPLUGIN_1.4.1; From 096e3cfbb6eb065b42eab5a21847341341441551 Mon Sep 17 00:00:00 2001 From: Mario Limonciello Date: Tue, 28 Apr 2020 15:01:33 -0500 Subject: [PATCH 010/607] fu-plugin: add a new udev_device_changed function that calls rescan --- libfwupdplugin/fu-plugin.c | 20 +++++++++++++++++++- 1 file changed, 19 insertions(+), 1 deletion(-) diff --git a/libfwupdplugin/fu-plugin.c b/libfwupdplugin/fu-plugin.c index 13c94cb22..cdf2ec881 100644 --- a/libfwupdplugin/fu-plugin.c +++ b/libfwupdplugin/fu-plugin.c @@ -1694,6 +1694,18 @@ fu_plugin_usb_device_added (FuPlugin *self, FuUsbDevice *device, GError **error) return TRUE; } +static gboolean +fu_plugin_udev_device_changed (FuPlugin *self, FuUdevDevice *device, GError **error) +{ + g_autoptr(FuDeviceLocker) locker = NULL; + + /* open */ + locker = fu_device_locker_new (FU_DEVICE (device), error); + if (locker == NULL) + return FALSE; + return fu_device_rescan (FU_DEVICE (device), error); +} + static gboolean fu_plugin_udev_device_added (FuPlugin *self, FuUdevDevice *device, GError **error) { @@ -1872,8 +1884,14 @@ fu_plugin_runner_udev_device_changed (FuPlugin *self, FuUdevDevice *device, GErr /* optional */ g_module_symbol (priv->module, "fu_plugin_udev_device_changed", (gpointer *) &func); - if (func == NULL) + if (func == NULL) { + if (priv->device_gtype != G_TYPE_INVALID || + fu_device_get_specialized_gtype (FU_DEVICE (device)) != G_TYPE_INVALID) { + if (!fu_plugin_udev_device_changed (self, device, error)) + return FALSE; + } return TRUE; + } g_debug ("performing udev_device_changed() on %s", priv->name); if (!func (self, device, &error_local)) { if (error_local == NULL) { From 767c29e2cc0f43b89ef439ecf65816dfbf3c3f88 Mon Sep 17 00:00:00 2001 From: Mario Limonciello Date: Tue, 28 Apr 2020 13:25:36 -0500 Subject: [PATCH 011/607] trivial: make building plugins without gudev more obvious failures --- plugins/meson.build | 30 ++++++++++++++++++++++++------ 1 file changed, 24 insertions(+), 6 deletions(-) diff --git a/plugins/meson.build b/plugins/meson.build index 1a726f68c..cb3649b28 100644 --- a/plugins/meson.build +++ b/plugins/meson.build @@ -37,16 +37,25 @@ endif # depends on dfu subdir('csr') -if get_option('plugin_tpm') and get_option('gudev') +if get_option('plugin_tpm') +if not get_option('gudev') + error('gudev is required for plugin_tpm') +endif subdir('tpm') subdir('tpm-eventlog') endif -if get_option('plugin_emmc') and get_option('gudev') +if get_option('plugin_emmc') +if not get_option('gudev') + error('gudev is required for plugin_emmc') +endif subdir('emmc') endif -if get_option('plugin_nvme') and get_option('gudev') +if get_option('plugin_nvme') +if not get_option('gudev') + error('gudev is required for plugin_nvme') +endif subdir('nvme') endif @@ -54,7 +63,10 @@ if get_option('plugin_modem_manager') subdir('modem-manager') endif -if get_option('plugin_altos') and get_option('gudev') +if get_option('plugin_altos') +if not get_option('gudev') + error('gudev is required for plugin_altos') +endif subdir('altos') endif @@ -62,7 +74,10 @@ if get_option('plugin_amt') subdir('amt') endif -if get_option('plugin_thunderbolt') and get_option('gudev') +if get_option('plugin_thunderbolt') +if not get_option('gudev') + error('gudev is required for plugin_thunderbolt') +endif subdir('thunderbolt') subdir('thunderbolt-power') endif @@ -76,7 +91,10 @@ subdir('dell') subdir('dell-esrt') endif -if get_option('plugin_synaptics') and get_option('gudev') +if get_option('plugin_synaptics') +if not get_option('gudev') + error('gudev is required for plugin_synaptics_mst') +endif subdir('synaptics-mst') endif From ec44dd335333402087a780741a0ee1c4b88ff3c0 Mon Sep 17 00:00:00 2001 From: Mario Limonciello Date: Fri, 27 Mar 2020 15:22:37 -0500 Subject: [PATCH 012/607] Modernize the thunderbolt plugin. Remove it's references to it's own GUdevclient and instead use FuUdevDevice. Some intentional casualties of the move: * Plugin metadata around native and safe mode dropped. - These haven't been useful in debugging anything and aren't relevant on new hardware * Extra GUID for 2 host controllers in same system dropped - Although this was normally static information BIOS operations like turning off PCI-E SD card reader or LAN controller changed things. * The NVM version is parsed directly instead of through gudev to prevent cached data breaking change events. Remaining TODO: * Force power w/ thunderbolt-power doesn't work --- plugins/thunderbolt/fu-plugin-thunderbolt.c | 765 +---------------- plugins/thunderbolt/fu-self-test.c | 181 ++-- plugins/thunderbolt/fu-thunderbolt-device.c | 638 ++++++++++++++ plugins/thunderbolt/fu-thunderbolt-device.h | 13 + plugins/thunderbolt/fu-thunderbolt-firmware.c | 572 +++++++++++++ plugins/thunderbolt/fu-thunderbolt-firmware.h | 26 + plugins/thunderbolt/fu-thunderbolt-image.c | 796 ------------------ plugins/thunderbolt/fu-thunderbolt-image.h | 27 - plugins/thunderbolt/fu-thunderbolt-tool.c | 91 -- plugins/thunderbolt/meson.build | 36 +- plugins/thunderbolt/thunderbolt.quirk | 3 + 11 files changed, 1400 insertions(+), 1748 deletions(-) create mode 100644 plugins/thunderbolt/fu-thunderbolt-device.c create mode 100644 plugins/thunderbolt/fu-thunderbolt-device.h create mode 100644 plugins/thunderbolt/fu-thunderbolt-firmware.c create mode 100644 plugins/thunderbolt/fu-thunderbolt-firmware.h delete mode 100644 plugins/thunderbolt/fu-thunderbolt-image.c delete mode 100644 plugins/thunderbolt/fu-thunderbolt-image.h delete mode 100644 plugins/thunderbolt/fu-thunderbolt-tool.c create mode 100644 plugins/thunderbolt/thunderbolt.quirk diff --git a/plugins/thunderbolt/fu-plugin-thunderbolt.c b/plugins/thunderbolt/fu-plugin-thunderbolt.c index a54459ef9..efed63289 100644 --- a/plugins/thunderbolt/fu-plugin-thunderbolt.c +++ b/plugins/thunderbolt/fu-plugin-thunderbolt.c @@ -6,31 +6,12 @@ #include "config.h" -#include -#include #include -#include -#include -#include -#include -#include #include "fu-plugin-vfuncs.h" #include "fu-hash.h" -#include "fu-device-metadata.h" -#include "fu-thunderbolt-image.h" - -#define TBT_NVM_RETRY_TIMEOUT 200 /* ms */ -#define FU_PLUGIN_THUNDERBOLT_UPDATE_TIMEOUT 60000 /* ms */ - -typedef void (*UEventNotify) (FuPlugin *plugin, - GUdevDevice *udevice, - const gchar *action, - gpointer user_data); - -struct FuPluginData { - GUdevClient *udev; -}; +#include "fu-thunderbolt-device.h" +#include "fu-thunderbolt-firmware.h" static gboolean fu_plugin_thunderbolt_safe_kernel (FuPlugin *plugin, GError **error) @@ -65,758 +46,28 @@ fu_plugin_thunderbolt_safe_kernel (FuPlugin *plugin, GError **error) return TRUE; } -static gchar * -fu_plugin_thunderbolt_gen_id_from_syspath (const gchar *syspath) +gboolean +fu_plugin_device_created (FuPlugin *plugin, FuDevice *dev, GError **error) { - gchar *id; - id = g_strdup_printf ("tbt-%s", syspath); - g_strdelimit (id, "/:.-", '_'); - return id; -} - - -static gchar * -fu_plugin_thunderbolt_gen_id (GUdevDevice *device) -{ - const gchar *syspath = g_udev_device_get_sysfs_path (device); - return fu_plugin_thunderbolt_gen_id_from_syspath (syspath); -} - -static gboolean -udev_device_get_sysattr_guint64 (GUdevDevice *device, - const gchar *name, - guint64 *val_out, - GError **error) -{ - const gchar *sysfs; - - sysfs = g_udev_device_get_sysfs_attr (device, name); - if (sysfs == NULL) { - g_set_error (error, - FWUPD_ERROR, - FWUPD_ERROR_INTERNAL, - "missing sysfs attribute %s", name); - return FALSE; - } - - *val_out = g_ascii_strtoull (sysfs, NULL, 16); - if (*val_out == 0x0) { - g_set_error (error, - FWUPD_ERROR, - FWUPD_ERROR_INTERNAL, - "failed to parse %s", sysfs); - return FALSE; - } - - return TRUE; -} - -static guint16 -fu_plugin_thunderbolt_udev_get_uint16 (GUdevDevice *device, - const gchar *name, - GError **error) -{ - - guint64 id = 0; - - if (!udev_device_get_sysattr_guint64 (device, name, &id, error)) - return 0x0; - - if (id > G_MAXUINT16) { - g_set_error (error, - FWUPD_ERROR, - FWUPD_ERROR_INTERNAL, - "%s overflows", - name); - return 0x0; - } - - return (guint16) id; -} - -static gboolean -fu_plugin_thunderbolt_is_host (GUdevDevice *device) -{ - g_autoptr(GUdevDevice) parent = NULL; - const gchar *name; - - /* the (probably safe) assumption this code makes is - * that the thunderbolt device which is a direct child - * of the domain is the host controller device itself */ - parent = g_udev_device_get_parent (device); - name = g_udev_device_get_name (parent); - if (name == NULL) - return FALSE; - - return g_str_has_prefix (name, "domain"); -} - -static GFile * -fu_plugin_thunderbolt_find_nvmem (GUdevDevice *udevice, - gboolean active, - GError **error) -{ - const gchar *nvmem_dir = active ? "nvm_active" : "nvm_non_active"; - const gchar *devpath; - const gchar *name; - g_autoptr(GDir) d = NULL; - - devpath = g_udev_device_get_sysfs_path (udevice); - if (G_UNLIKELY (devpath == NULL)) { - g_set_error_literal (error, - FWUPD_ERROR, FWUPD_ERROR_INTERNAL, - "Could not determine sysfs path for device"); - return NULL; - } - - d = g_dir_open (devpath, 0, error); - if (d == NULL) - return NULL; - - while ((name = g_dir_read_name (d)) != NULL) { - if (g_str_has_prefix (name, nvmem_dir)) { - g_autoptr(GFile) parent = g_file_new_for_path (devpath); - g_autoptr(GFile) nvm_dir = g_file_get_child (parent, name); - return g_file_get_child (nvm_dir, "nvmem"); - } - } - - g_set_error_literal (error, - FWUPD_ERROR, FWUPD_ERROR_NOT_SUPPORTED, - "Could not find non-volatile memory location"); - return NULL; -} - -static gchar * -fu_plugin_thunderbolt_parse_version (const gchar *version_raw) -{ - g_auto(GStrv) split = NULL; - if (version_raw == NULL) - return NULL; - split = g_strsplit (version_raw, ".", -1); - if (g_strv_length (split) != 2) - return NULL; - return g_strdup_printf ("%02x.%02x", - (guint) g_ascii_strtoull (split[0], NULL, 16), - (guint) g_ascii_strtoull (split[1], NULL, 16)); -} - -static gchar * -fu_plugin_thunderbolt_udev_get_version (GUdevDevice *udevice) -{ - const gchar *version = NULL; - - for (guint i = 0; i < 50; i++) { - version = g_udev_device_get_sysfs_attr (udevice, "nvm_version"); - if (version != NULL) - break; - g_debug ("Attempt %u: Failed to read NVM version", i); - if (errno != EAGAIN) - break; - g_usleep (TBT_NVM_RETRY_TIMEOUT * 1000); - } - - return fu_plugin_thunderbolt_parse_version (version); -} - -static gboolean -fu_plugin_thunderbolt_is_native (GUdevDevice *udevice, gboolean *is_native, GError **error) -{ - gsize nr_chunks; - g_autoptr(GFile) nvmem = NULL; - g_autoptr(GBytes) controller_fw = NULL; - g_autoptr(GInputStream) istr = NULL; - - nvmem = fu_plugin_thunderbolt_find_nvmem (udevice, TRUE, error); - if (nvmem == NULL) - return FALSE; - - /* read just enough bytes to read the status byte */ - nr_chunks = (FU_TBT_OFFSET_NATIVE + FU_TBT_CHUNK_SZ - 1) / FU_TBT_CHUNK_SZ; - istr = G_INPUT_STREAM (g_file_read (nvmem, NULL, error)); - if (istr == NULL) - return FALSE; - controller_fw = g_input_stream_read_bytes (istr, - nr_chunks * FU_TBT_CHUNK_SZ, - NULL, error); - if (controller_fw == NULL) - return FALSE; - - return fu_thunderbolt_image_controller_is_native (controller_fw, - is_native, - error); -} - -static gboolean -fu_plugin_thunderbolt_can_update (GUdevDevice *udevice) -{ - g_autoptr(GError) nvmem_error = NULL; - g_autoptr(GFile) non_active_nvmem = NULL; - - non_active_nvmem = fu_plugin_thunderbolt_find_nvmem (udevice, FALSE, - &nvmem_error); - if (non_active_nvmem == NULL) { - g_debug ("%s", nvmem_error->message); - return FALSE; - } - - return TRUE; -} - -static void -fu_plugin_thunderbolt_add (FuPlugin *plugin, GUdevDevice *device) -{ - FuDevice *dev_tmp; - const gchar *name = NULL; - const gchar *uuid; - const gchar *vendor; - const gchar *devpath; - const gchar *devtype; - gboolean is_host; - gboolean is_safemode = FALSE; - gboolean is_native = FALSE; - guint16 did; - guint16 vid; - guint16 gen; - g_autofree gchar *id = NULL; - g_autofree gchar *version = NULL; - g_autofree gchar *vendor_id = NULL; - g_autofree gchar *device_id = NULL; - g_autofree gchar *domain_id = NULL; - g_autoptr(FuDevice) dev = NULL; - g_autoptr(GError) error_vid = NULL; - g_autoptr(GError) error_did = NULL; - g_autoptr(GError) error_gen = NULL; - g_autoptr(GError) error_setup = NULL; - - uuid = g_udev_device_get_sysfs_attr (device, "unique_id"); - if (uuid == NULL) { - /* most likely the domain itself, ignore */ - return; - } - - devpath = g_udev_device_get_sysfs_path (device); - - devtype = g_udev_device_get_devtype (device); - if (g_strcmp0 (devtype, "thunderbolt_device") != 0) { - g_debug ("ignoring %s device at %s", devtype, devpath); - return; - } - - g_debug ("adding udev device: %s at %s", uuid, devpath); - - id = fu_plugin_thunderbolt_gen_id (device); - dev_tmp = fu_plugin_cache_lookup (plugin, id); - if (dev_tmp != NULL) { - /* devices that are force-powered are re-added */ - g_debug ("ignoring duplicate %s", id); - return; - } - - /* these may be missing on ICL or later */ - vid = fu_plugin_thunderbolt_udev_get_uint16 (device, "vendor", &error_vid); - if (vid == 0x0) - g_debug ("failed to get Vendor ID: %s", error_vid->message); - - did = fu_plugin_thunderbolt_udev_get_uint16 (device, "device", &error_did); - if (did == 0x0) - g_debug ("failed to get Device ID: %s", error_did->message); - - /* requires kernel 5.5 or later, non-fatal if not available */ - gen = fu_plugin_thunderbolt_udev_get_uint16 (device, "generation", &error_gen); - if (gen == 0) - g_debug ("Unable to read generation: %s", error_gen->message); - - dev = fu_device_new (); - - is_host = fu_plugin_thunderbolt_is_host (device); - - version = fu_plugin_thunderbolt_udev_get_version (device); - /* test for safe mode */ - if (is_host && version == NULL && gen < 4) { - g_autoptr(GError) error_local = NULL; - g_autofree gchar *test_safe = NULL; - g_autofree gchar *safe_path = NULL; - /* glib can't return a properly mapped -ENODATA but the - * kernel only returns -ENODATA or -EAGAIN */ - safe_path = g_build_path ("/", devpath, "nvm_version", NULL); - if (!g_file_get_contents (safe_path, &test_safe, NULL, &error_local) && - !g_error_matches (error_local, G_IO_ERROR, G_IO_ERROR_WOULD_BLOCK)) { - g_warning ("%s is in safe mode -- VID/DID will " - "need to be set by another plugin", - devpath); - version = g_strdup ("00.00"); - is_safemode = TRUE; - device_id = g_strdup ("TBT-safemode"); - fu_device_set_metadata_boolean (dev, FU_DEVICE_METADATA_TBT_IS_SAFE_MODE, TRUE); - } - fu_plugin_add_report_metadata (plugin, "ThunderboltSafeMode", - is_safemode ? "True" : "False"); - } - if (!is_safemode) { - if (fu_plugin_thunderbolt_can_update (device)) { - /* USB4 controllers don't have a concept of legacy vs native - * so don't try to read a native attribute from their NVM */ - if (is_host && gen < 4) { - g_autofree gchar *domain = g_path_get_basename (devpath); - g_autoptr(GError) native_error = NULL; - if (!fu_plugin_thunderbolt_is_native (device, - &is_native, - &native_error)) { - g_warning ("failed to get native mode status: %s", - native_error->message); - return; - } - fu_plugin_add_report_metadata (plugin, - "ThunderboltNative", - is_native ? "True" : "False"); - domain_id = g_strdup_printf ("TBT-%04x%04x%s-controller%s", - (guint) vid, - (guint) did, - is_native ? "-native" : "", - domain); - - } - vendor_id = g_strdup_printf ("TBT:0x%04X", (guint) vid); - device_id = g_strdup_printf ("TBT-%04x%04x%s", - (guint) vid, - (guint) did, - is_native ? "-native" : ""); - fu_device_add_flag (dev, FWUPD_DEVICE_FLAG_UPDATABLE); - fu_device_add_flag (dev, FWUPD_DEVICE_FLAG_DUAL_IMAGE); - } else { - device_id = g_strdup ("TBT-fixed"); - fu_device_set_update_error (dev, "Missing non-active nvmem"); - } - } else { - fu_device_set_update_error (dev, "Device is in safe mode"); - } - - fu_device_set_physical_id (dev, uuid); - - fu_device_set_metadata (dev, "sysfs-path", devpath); - if (!is_host) - name = g_udev_device_get_sysfs_attr (device, "device_name"); - if (name == NULL) { - if (gen == 4) - name = "USB4 Controller"; - else - name = "Thunderbolt Controller"; - } - fu_device_set_name (dev, name); - if (is_host) - fu_device_set_summary (dev, "Unmatched performance for high-speed I/O"); - fu_device_add_icon (dev, "thunderbolt"); - fu_device_set_protocol (dev, "com.intel.thunderbolt"); - fu_device_set_version_format (dev, FWUPD_VERSION_FORMAT_PAIR); - fu_device_set_quirks (dev, fu_plugin_get_quirks (plugin)); - vendor = g_udev_device_get_sysfs_attr (device, "vendor_name"); - if (vendor != NULL) - fu_device_set_vendor (dev, vendor); - if (vendor_id != NULL) - fu_device_set_vendor_id (dev, vendor_id); - if (device_id != NULL) - fu_device_add_instance_id (dev, device_id); - if (domain_id != NULL) - fu_device_add_instance_id (dev, domain_id); - if (version != NULL) - fu_device_set_version (dev, version); - if (is_host) - fu_device_add_flag (dev, FWUPD_DEVICE_FLAG_INTERNAL); - fu_device_add_flag (dev, FWUPD_DEVICE_FLAG_REQUIRE_AC); - - /* we never open the device, so convert the instance IDs */ - if (!fu_device_setup (dev, &error_setup)) { - g_warning ("failed to setup: %s", error_setup->message); - return; - } - fu_plugin_cache_add (plugin, id, dev); - fu_plugin_device_add (plugin, dev); - - /* inhibit the idle sleep of the daemon */ fu_plugin_add_rule (plugin, FU_PLUGIN_RULE_INHIBITS_IDLE, "thunderbolt requires device wakeup"); -} - -static void -fu_plugin_thunderbolt_remove (FuPlugin *plugin, GUdevDevice *device) -{ - FuDevice *dev; - g_autofree gchar *id = NULL; - - id = fu_plugin_thunderbolt_gen_id (device); - dev = fu_plugin_cache_lookup (plugin, id); - if (dev == NULL) - return; - - /* on supported systems other plugins may use a GPIO to force - * power on supported devices even when in low power mode -- - * this will happen in coldplug_prepare and prepare_for_update */ - if (fu_plugin_thunderbolt_is_host (device) && - !fu_device_has_flag (dev, FWUPD_DEVICE_FLAG_WAIT_FOR_REPLUG) && - fu_device_get_metadata_boolean (dev, FU_DEVICE_METADATA_TBT_CAN_FORCE_POWER)) { - g_debug ("ignoring remove event as force powered"); - return; - } - - fu_plugin_device_remove (plugin, dev); - fu_plugin_cache_remove (plugin, id); -} - -static void -fu_plugin_thunderbolt_change (FuPlugin *plugin, GUdevDevice *device) -{ - FuDevice *dev; - g_autofree gchar *version = NULL; - g_autofree gchar *id = NULL; - - id = fu_plugin_thunderbolt_gen_id (device); - dev = fu_plugin_cache_lookup (plugin, id); - if (dev == NULL) { - g_warning ("got change event for unknown device, adding instead"); - fu_plugin_thunderbolt_add (plugin, device); - return; - } - - version = fu_plugin_thunderbolt_udev_get_version (device); - fu_device_set_version (dev, version); -} - -static gboolean -udev_uevent_cb (GUdevClient *udev, - const gchar *action, - GUdevDevice *device, - gpointer user_data) -{ - FuPlugin *plugin = (FuPlugin *) user_data; - - if (action == NULL) - return TRUE; - - g_debug ("uevent for %s: %s", g_udev_device_get_sysfs_path (device), action); - - if (g_str_equal (action, "add")) { - fu_plugin_thunderbolt_add (plugin, device); - } else if (g_str_equal (action, "remove")) { - fu_plugin_thunderbolt_remove (plugin, device); - } else if (g_str_equal (action, "change")) { - fu_plugin_thunderbolt_change (plugin, device); - } - + fu_device_set_quirks (dev, fu_plugin_get_quirks (plugin)); return TRUE; } -static FuPluginValidation -fu_plugin_thunderbolt_validate_firmware (GUdevDevice *udevice, - GBytes *blob_fw, - GError **error) -{ - g_autoptr(GFile) nvmem = NULL; - g_autoptr(GBytes) controller_fw = NULL; - gchar *content; - gsize length; - - nvmem = fu_plugin_thunderbolt_find_nvmem (udevice, TRUE, error); - if (nvmem == NULL) - return VALIDATION_FAILED; - - if (!g_file_load_contents (nvmem, NULL, &content, &length, NULL, error)) - return VALIDATION_FAILED; - - controller_fw = g_bytes_new_take (content, length); - return fu_thunderbolt_image_validate (controller_fw, blob_fw, error); -} - -static gboolean -fu_plugin_thunderbolt_trigger_update (GUdevDevice *udevice, - GError **error) -{ - - const gchar *devpath; - ssize_t n; - int fd; - int r; - g_autofree gchar *auth_path = NULL; - - devpath = g_udev_device_get_sysfs_path (udevice); - auth_path = g_build_filename (devpath, "nvm_authenticate", NULL); - - fd = open (auth_path, O_WRONLY | O_CLOEXEC); - if (fd < 0) { - g_set_error (error, G_IO_ERROR, - g_io_error_from_errno (errno), - "could not open 'nvm_authenticate': %s", - g_strerror (errno)); - return FALSE; - } - - do { - n = write (fd, "1", 1); - if (n < 1 && errno != EINTR) { - g_set_error (error, G_IO_ERROR, - g_io_error_from_errno (errno), - "could not write to 'nvm_authenticate': %s", - g_strerror (errno)); - (void) close (fd); - return FALSE; - } - } while (n < 1); - - r = close (fd); - if (r < 0 && errno != EINTR) { - g_set_error (error, G_IO_ERROR, - g_io_error_from_errno (errno), - "could not close 'nvm_authenticate': %s", - g_strerror (errno)); - return FALSE; - } - - return TRUE; -} - -static gboolean -fu_plugin_thunderbolt_write_firmware (FuDevice *device, - GUdevDevice *udevice, - GBytes *blob_fw, - GError **error) -{ - gsize fw_size; - gsize nwritten; - gssize n; - g_autoptr(GFile) nvmem = NULL; - g_autoptr(GOutputStream) os = NULL; - - nvmem = fu_plugin_thunderbolt_find_nvmem (udevice, FALSE, error); - if (nvmem == NULL) - return FALSE; - - os = (GOutputStream *) g_file_append_to (nvmem, - G_FILE_CREATE_NONE, - NULL, - error); - - if (os == NULL) - return FALSE; - - nwritten = 0; - fw_size = g_bytes_get_size (blob_fw); - fu_device_set_progress_full (device, nwritten, fw_size); - - do { - g_autoptr(GBytes) fw_data = NULL; - - fw_data = g_bytes_new_from_bytes (blob_fw, - nwritten, - fw_size - nwritten); - - n = g_output_stream_write_bytes (os, - fw_data, - NULL, - error); - if (n < 0) - return FALSE; - - nwritten += n; - fu_device_set_progress_full (device, nwritten, fw_size); - - } while (nwritten < fw_size); - - if (nwritten != fw_size) { - g_set_error_literal (error, - FWUPD_ERROR, - FWUPD_ERROR_WRITE, - "Could not write all data to nvmem"); - return FALSE; - } - - return g_output_stream_close (os, NULL, error); -} - -/* virtual functions */ - void fu_plugin_init (FuPlugin *plugin) { - FuPluginData *data = fu_plugin_alloc_data (plugin, sizeof (FuPluginData)); - const gchar *subsystems[] = { "thunderbolt", NULL }; - fu_plugin_set_build_hash (plugin, FU_BUILD_HASH); - data->udev = g_udev_client_new (subsystems); - g_signal_connect (data->udev, "uevent", - G_CALLBACK (udev_uevent_cb), plugin); - + fu_plugin_add_udev_subsystem (plugin, "thunderbolt"); + fu_plugin_set_device_gtype (plugin, FU_TYPE_THUNDERBOLT_DEVICE); + fu_plugin_add_firmware_gtype (plugin, "thunderbolt", FU_TYPE_THUNDERBOLT_FIRMWARE); /* dell-dock plugin uses a slower bus for flashing */ fu_plugin_add_rule (plugin, FU_PLUGIN_RULE_BETTER_THAN, "dell_dock"); } -void -fu_plugin_destroy (FuPlugin *plugin) -{ - FuPluginData *data = fu_plugin_get_data (plugin); - g_object_unref (data->udev); -} - -static gboolean -fu_plugin_thunderbolt_coldplug (FuPlugin *plugin, GError **error) -{ - FuPluginData *data = fu_plugin_get_data (plugin); - GList *devices; - - devices = g_udev_client_query_by_subsystem (data->udev, "thunderbolt"); - for (GList *l = devices; l != NULL; l = l->next) { - GUdevDevice *device = l->data; - fu_plugin_thunderbolt_add (plugin, device); - } - - g_list_foreach (devices, (GFunc) g_object_unref, NULL); - g_list_free (devices); - - return TRUE; -} - gboolean fu_plugin_startup (FuPlugin *plugin, GError **error) { return fu_plugin_thunderbolt_safe_kernel (plugin, error); } - -gboolean -fu_plugin_coldplug (FuPlugin *plugin, GError **error) -{ - return fu_plugin_thunderbolt_coldplug (plugin, error); -} - -gboolean -fu_plugin_recoldplug (FuPlugin *plugin, GError **error) -{ - return fu_plugin_thunderbolt_coldplug (plugin, error); -} - -gboolean -fu_plugin_update (FuPlugin *plugin, - FuDevice *dev, - GBytes *blob_fw, - FwupdInstallFlags flags, - GError **error) -{ - FuPluginData *data = fu_plugin_get_data (plugin); - const gchar *devpath; - g_autoptr(GUdevDevice) udevice = NULL; - g_autoptr(GError) error_local = NULL; - gboolean install_force = (flags & FWUPD_INSTALL_FLAG_FORCE) != 0; - gboolean device_ignore_validation = fu_device_has_flag (dev, FWUPD_DEVICE_FLAG_IGNORE_VALIDATION); - FuPluginValidation validation; - - devpath = fu_device_get_metadata (dev, "sysfs-path"); - g_return_val_if_fail (devpath, FALSE); - - udevice = g_udev_client_query_by_sysfs_path (data->udev, devpath); - if (udevice == NULL) { - g_set_error (error, - FWUPD_ERROR, - FWUPD_ERROR_NOT_FOUND, - "could not find thunderbolt device at %s", - devpath); - return FALSE; - } - - validation = fu_plugin_thunderbolt_validate_firmware (udevice, - blob_fw, - &error_local); - if (validation != VALIDATION_PASSED) { - g_autofree gchar* msg = NULL; - switch (validation) { - case VALIDATION_FAILED: - msg = g_strdup_printf ("could not validate firmware: %s", - error_local->message); - break; - case UNKNOWN_DEVICE: - msg = g_strdup ("firmware validation seems to be passed but the device is unknown"); - break; - default: - break; - } - if (!install_force && !device_ignore_validation) { - g_set_error (error, - FWUPD_ERROR, - FWUPD_ERROR_INVALID_FILE, - "%s. " - "See https://github.com/fwupd/fwupd/wiki/Thunderbolt:-Validation-failed-or-unknown-device for more information.", - msg); - return FALSE; - } - g_warning ("%s", msg); - } - - fu_device_set_status (dev, FWUPD_STATUS_DEVICE_WRITE); - if (!fu_plugin_thunderbolt_write_firmware (dev, udevice, blob_fw, error)) { - g_prefix_error (error, - "could not write firmware to thunderbolt device at %s: ", - devpath); - return FALSE; - } - - if (!fu_plugin_thunderbolt_trigger_update (udevice, error)) { - g_prefix_error (error, "could not start thunderbolt device upgrade: "); - return FALSE; - } - - fu_device_set_status (dev, FWUPD_STATUS_DEVICE_RESTART); - fu_device_set_remove_delay (dev, FU_PLUGIN_THUNDERBOLT_UPDATE_TIMEOUT); - fu_device_add_flag (dev, FWUPD_DEVICE_FLAG_WAIT_FOR_REPLUG); - - return TRUE; -} - -gboolean -fu_plugin_update_attach (FuPlugin *plugin, - FuDevice *dev, - GError **error) -{ - FuPluginData *data = fu_plugin_get_data (plugin); - const gchar *devpath; - const gchar *attribute; - guint64 status; - g_autoptr(GUdevDevice) udevice = NULL; - - devpath = fu_device_get_metadata (dev, "sysfs-path"); - udevice = g_udev_client_query_by_sysfs_path (data->udev, devpath); - if (udevice == NULL) { - g_set_error (error, - FWUPD_ERROR, - FWUPD_ERROR_NOT_FOUND, - "could not find thunderbolt device at %s", - devpath); - return FALSE; - } - - /* now check if the update actually worked */ - attribute = g_udev_device_get_sysfs_attr (udevice, "nvm_authenticate"); - if (attribute == NULL) { - g_set_error (error, - FWUPD_ERROR, - FWUPD_ERROR_INTERNAL, - "failed to find nvm_authenticate attribute for %s", - fu_device_get_name (dev)); - return FALSE; - } - status = g_ascii_strtoull (attribute, NULL, 16); - if (status == G_MAXUINT64 && errno == ERANGE) { - g_set_error (error, G_IO_ERROR, - g_io_error_from_errno (errno), - "failed to read 'nvm_authenticate: %s", - g_strerror (errno)); - return FALSE; - } - - /* anything else then 0x0 means we got an error */ - if (status != 0x0) { - g_set_error (error, - FWUPD_ERROR, - FWUPD_ERROR_INTERNAL, - "update failed (status %" G_GINT64_MODIFIER "x)", status); - return FALSE; - } - - return TRUE; -} diff --git a/plugins/thunderbolt/fu-self-test.c b/plugins/thunderbolt/fu-self-test.c index 91245f05c..993c45704 100644 --- a/plugins/thunderbolt/fu-self-test.c +++ b/plugins/thunderbolt/fu-self-test.c @@ -10,6 +10,7 @@ #include #include #include +#include #include #include @@ -23,7 +24,7 @@ #include #include "fu-plugin-private.h" -#include "fu-thunderbolt-image.h" +#include "fu-thunderbolt-firmware.h" static gchar * udev_mock_add_domain (UMockdevTestbed *bed, int id) @@ -342,7 +343,7 @@ write_controller_fw (const gchar *nvm) g_autoptr(GError) error = NULL; gssize n; - fw_path = g_build_filename (TESTDATADIR, "thunderbolt/minimal-fw-controller.bin", NULL); + fw_path = g_build_filename (TESTDATADIR, "thunderbolt/minimal-fw.bin", NULL); fw_file = g_file_new_for_path (fw_path); g_assert_nonnull (fw_file); @@ -659,6 +660,7 @@ typedef struct UpdateContext { UMockdevTestbed *bed; FuPlugin *plugin; + MockTree *node; gchar *version; } UpdateContext; @@ -839,11 +841,11 @@ typedef struct TestParam { typedef enum TestFlags { TEST_INITIALIZE_TREE = 1 << 0, - TEST_ATTACH_AND_COLDPLUG = 1 << 1, + TEST_ATTACH = 1 << 1, TEST_PREPARE_FIRMWARE = 1 << 2, TEST_PREPARE_ALL = TEST_INITIALIZE_TREE | - TEST_ATTACH_AND_COLDPLUG | + TEST_ATTACH | TEST_PREPARE_FIRMWARE } TestFlags; @@ -853,6 +855,7 @@ typedef enum TestFlags { typedef struct ThunderboltTest { UMockdevTestbed *bed; FuPlugin *plugin; + GUdevClient *udev_client; /* if TestParam::initialize_tree */ MockTree *tree; @@ -863,6 +866,32 @@ typedef struct ThunderboltTest { } ThunderboltTest; +static void +fu_thunderbolt_gudev_uevent_cb (GUdevClient *gudev_client, + const gchar *action, + GUdevDevice *udev_device, + ThunderboltTest *tt) +{ + g_autoptr(GError) error_local = NULL; + + if (g_strcmp0 (action, "add") == 0) { + g_autoptr(FuUdevDevice) device = fu_udev_device_new (udev_device); + fu_plugin_runner_udev_device_added (tt->plugin, device, &error_local); + return; + } + if (g_strcmp0 (action, "remove") == 0) { + if (tt->tree->fu_device != NULL) + fu_plugin_device_remove (tt->plugin, tt->tree->fu_device); + return; + } + if (g_strcmp0 (action, "change") == 0) { + const gchar *uuid = g_udev_device_get_sysfs_attr (udev_device, "unique_id"); + MockTree *target = (MockTree *) mock_tree_find_uuid (tt->tree, uuid); + fu_plugin_runner_udev_device_changed (tt->plugin, FU_UDEV_DEVICE (target->fu_device), + &error_local); + return; + } +} static void test_set_up (ThunderboltTest *tt, gconstpointer params) { @@ -871,6 +900,7 @@ test_set_up (ThunderboltTest *tt, gconstpointer params) g_autofree gchar *pluginfn = NULL; g_autofree gchar *sysfs = NULL; g_autoptr(GError) error = NULL; + const gchar *udev_subsystems[] = { "thunderbolt", NULL }; tt->bed = umockdev_testbed_new (); g_assert_nonnull (tt->bed); @@ -903,12 +933,13 @@ test_set_up (ThunderboltTest *tt, gconstpointer params) return; } - if (flags & TEST_ATTACH_AND_COLDPLUG) { - g_assert_true (flags & TEST_INITIALIZE_TREE); + tt->udev_client = g_udev_client_new (udev_subsystems); + g_assert_nonnull (tt->udev_client); + g_signal_connect (tt->udev_client, "uevent", + G_CALLBACK (fu_thunderbolt_gudev_uevent_cb), tt); - ret = fu_plugin_runner_coldplug (tt->plugin, &error); - g_assert_no_error (error); - g_assert_true (ret); + if (flags & TEST_ATTACH) { + g_assert_true (flags & TEST_INITIALIZE_TREE); ret = mock_tree_attach (tt->tree, tt->bed, tt->plugin); g_assert_true (ret); @@ -932,6 +963,7 @@ test_tear_down (ThunderboltTest *tt, gconstpointer user_data) { g_object_unref (tt->plugin); g_object_unref (tt->bed); + g_object_unref (tt->udev_client); if (tt->tree) mock_tree_free (tt->tree); @@ -982,10 +1014,6 @@ test_tree (ThunderboltTest *tt, gconstpointer user_data) found = mock_tree_find_uuid (tree, "nonexistentuuid"); g_assert_null (found); - ret = fu_plugin_runner_coldplug (tt->plugin, &error); - g_assert_no_error (error); - g_assert_true (ret); - ret = mock_tree_attach (tree, tt->bed, tt->plugin); g_assert_true (ret); @@ -994,10 +1022,72 @@ test_tree (ThunderboltTest *tt, gconstpointer user_data) g_assert_true (ret); } +static gboolean +_compare_images (FuThunderboltFirmware *firmware, FuThunderboltFirmware *firmware_old, GError **error) +{ + if (fu_thunderbolt_firmware_is_host (firmware) != + fu_thunderbolt_firmware_is_host (firmware_old)) { + g_set_error (error, + FWUPD_ERROR, + FWUPD_ERROR_INVALID_FILE, + "incorrect firmware mode, got %s, expected %s", + fu_thunderbolt_firmware_is_host (firmware) ? "host" : "device", + fu_thunderbolt_firmware_is_host (firmware_old) ? "host" : "device"); + return FALSE; + } + if (fu_thunderbolt_firmware_get_vendor_id (firmware) != + fu_thunderbolt_firmware_get_vendor_id (firmware_old)) { + g_set_error (error, + FWUPD_ERROR, + FWUPD_ERROR_INVALID_FILE, + "incorrect device vendor, got 0x%04x, expected 0x%04x", + fu_thunderbolt_firmware_get_vendor_id (firmware), + fu_thunderbolt_firmware_get_vendor_id (firmware_old)); + return FALSE; + } + if (fu_thunderbolt_firmware_get_device_id (firmware) != + fu_thunderbolt_firmware_get_device_id (firmware_old)) { + g_set_error (error, + FWUPD_ERROR, + FWUPD_ERROR_INVALID_FILE, + "incorrect device type, got 0x%04x, expected 0x%04x", + fu_thunderbolt_firmware_get_device_id (firmware), + fu_thunderbolt_firmware_get_device_id (firmware_old)); + return FALSE; + } + if (fu_thunderbolt_firmware_get_model_id (firmware) != + fu_thunderbolt_firmware_get_model_id (firmware_old)) { + g_set_error (error, + FWUPD_ERROR, + FWUPD_ERROR_INVALID_FILE, + "incorrect device model, got 0x%04x, expected 0x%04x", + fu_thunderbolt_firmware_get_model_id (firmware), + fu_thunderbolt_firmware_get_model_id (firmware_old)); + return FALSE; + } + if (fu_thunderbolt_firmware_get_has_pd (firmware) != + fu_thunderbolt_firmware_get_has_pd (firmware_old)) { + g_set_error_literal (error, + FWUPD_ERROR, + FWUPD_ERROR_INVALID_FILE, + "incorrect PD section"); + return FALSE; + } + if (fu_thunderbolt_firmware_get_flash_size (firmware) != + fu_thunderbolt_firmware_get_flash_size (firmware_old)) { + g_set_error_literal (error, + FWUPD_ERROR, + FWUPD_ERROR_INVALID_FILE, + "incorrect flash size"); + return FALSE; + } + return TRUE; +} + static void test_image_validation (ThunderboltTest *tt, gconstpointer user_data) { - FuPluginValidation val; + gboolean ret; g_autofree gchar *ctl_path = NULL; g_autofree gchar *fwi_path = NULL; g_autofree gchar *bad_path = NULL; @@ -1008,6 +1098,9 @@ test_image_validation (ThunderboltTest *tt, gconstpointer user_data) g_autoptr(GBytes) ctl_data = NULL; g_autoptr(GBytes) bad_data = NULL; g_autoptr(GError) error = NULL; + g_autoptr(FuThunderboltFirmware) firmware_fwi = fu_thunderbolt_firmware_new (); + g_autoptr(FuThunderboltFirmware) firmware_ctl = fu_thunderbolt_firmware_new (); + g_autoptr(FuThunderboltFirmware) firmware_bad = fu_thunderbolt_firmware_new (); /* image as if read from the controller (i.e. no headers) */ ctl_path = g_build_filename (TESTDATADIR, @@ -1019,6 +1112,13 @@ test_image_validation (ThunderboltTest *tt, gconstpointer user_data) ctl_data = g_mapped_file_get_bytes (ctl_file); g_assert_nonnull (ctl_data); + /* parse; should fail due to can't read host controller offset */ + ret = fu_firmware_parse (FU_FIRMWARE (firmware_ctl), ctl_data, FWUPD_INSTALL_FLAG_NONE, &error); + g_assert_false (ret); + g_assert_error (error, FWUPD_ERROR, FWUPD_ERROR_READ); + g_debug ("expected image validation error [ctl]: %s", error->message); + g_clear_error (&error); + /* valid firmware update image */ fwi_path = g_build_filename (TESTDATADIR, "thunderbolt/minimal-fw.bin", NULL); fwi_file = g_mapped_file_new (fwi_path, FALSE, &error); @@ -1028,6 +1128,11 @@ test_image_validation (ThunderboltTest *tt, gconstpointer user_data) fwi_data = g_mapped_file_get_bytes (fwi_file); g_assert_nonnull (fwi_data); + /* parse */ + ret = fu_firmware_parse (FU_FIRMWARE (firmware_fwi), fwi_data, FWUPD_INSTALL_FLAG_NONE, &error); + g_assert_true (ret); + g_assert_no_error (error); + /* a wrong/bad firmware update image */ bad_path = g_build_filename (TESTDATADIR, "colorhug/firmware.bin", NULL); bad_file = g_mapped_file_new (bad_path, FALSE, &error); @@ -1037,45 +1142,17 @@ test_image_validation (ThunderboltTest *tt, gconstpointer user_data) bad_data = g_mapped_file_get_bytes (bad_file); g_assert_nonnull (bad_data); + /* parse; should fail, bad image */ + ret = fu_firmware_parse (FU_FIRMWARE (firmware_bad), bad_data, FWUPD_INSTALL_FLAG_NONE, &error); + g_assert_false (ret); + g_assert_error (error, FWUPD_ERROR, FWUPD_ERROR_READ); + g_debug ("expected image validation error [ctl]: %s", error->message); + g_clear_error (&error); + /* now for some testing ... this should work */ - val = fu_thunderbolt_image_validate (ctl_data, fwi_data, &error); + ret = _compare_images (firmware_fwi, firmware_fwi, &error); + g_assert_true (ret); g_assert_no_error (error); - g_assert_cmpint (val, ==, VALIDATION_PASSED); - - - /* these all should fail */ - /* valid controller, bad update data */ - val = fu_thunderbolt_image_validate (ctl_data, ctl_data, &error); - g_assert_error (error, FWUPD_ERROR, FWUPD_ERROR_READ); - g_assert_cmpint (val, ==, VALIDATION_FAILED); - g_debug ("expected image validation error [ctl, ctl]: %s", error->message); - g_clear_error (&error); - - val = fu_thunderbolt_image_validate (ctl_data, bad_data, &error); - g_assert_error (error, FWUPD_ERROR, FWUPD_ERROR_READ); - g_assert_cmpint (val, ==, VALIDATION_FAILED); - g_debug ("expected image validation error [ctl, bad]: %s", error->message); - g_clear_error (&error); - - /* bad controller data, valid update data */ - val = fu_thunderbolt_image_validate (fwi_data, fwi_data, &error); - g_assert_error (error, FWUPD_ERROR, FWUPD_ERROR_INVALID_FILE); - g_assert_cmpint (val, ==, VALIDATION_FAILED); - g_debug ("expected image validation error [fwi, fwi]: %s", error->message); - g_clear_error (&error); - - val = fu_thunderbolt_image_validate (bad_data, fwi_data, &error); - g_assert_error (error, FWUPD_ERROR, FWUPD_ERROR_INVALID_FILE); - g_assert_cmpint (val, ==, VALIDATION_FAILED); - g_debug ("expected image validation error [bad, fwi]: %s", error->message); - g_clear_error (&error); - - /* both bad */ - val = fu_thunderbolt_image_validate (bad_data, bad_data, &error); - g_assert_error (error, FWUPD_ERROR, FWUPD_ERROR_READ); - g_assert_cmpint (val, ==, VALIDATION_FAILED); - g_debug ("expected image validation error [bad, bad]: %s", error->message); - g_clear_error (&error); } static void @@ -1255,7 +1332,7 @@ main (int argc, char **argv) g_test_add ("/thunderbolt/change-uevent", ThunderboltTest, GUINT_TO_POINTER (TEST_INITIALIZE_TREE | - TEST_ATTACH_AND_COLDPLUG), + TEST_ATTACH), test_set_up, test_change_uevent, test_tear_down); diff --git a/plugins/thunderbolt/fu-thunderbolt-device.c b/plugins/thunderbolt/fu-thunderbolt-device.c new file mode 100644 index 000000000..64f4627aa --- /dev/null +++ b/plugins/thunderbolt/fu-thunderbolt-device.c @@ -0,0 +1,638 @@ +/* + * Copyright (C) 2017 Christian J. Kellner + * Copyright (C) 2020 Mario Limonciello + * + * SPDX-License-Identifier: LGPL-2.1+ + */ + +#include "config.h" + +#include +#include +#include +#include +#include +#include +#include + +#include "fu-common.h" +#include "fu-device-metadata.h" +#include "fu-thunderbolt-device.h" +#include "fu-thunderbolt-firmware.h" + +struct _FuThunderboltDevice { + FuUdevDevice parent_instance; + gboolean host; + gboolean safe_mode; + gboolean is_native; + guint16 gen; + gchar *devpath; +}; + +#define TBT_NVM_RETRY_TIMEOUT 200 /* ms */ +#define FU_PLUGIN_THUNDERBOLT_UPDATE_TIMEOUT 60000 /* ms */ + +G_DEFINE_TYPE (FuThunderboltDevice, fu_thunderbolt_device, FU_TYPE_UDEV_DEVICE) + +static GFile * +fu_thunderbolt_device_find_nvmem (FuThunderboltDevice *self, + gboolean active, + GError **error) +{ + + const gchar *nvmem_dir = active ? "nvm_active" : "nvm_non_active"; + const gchar *name; + g_autoptr(GDir) d = NULL; + + if (G_UNLIKELY (self->devpath == NULL)) { + g_set_error_literal (error, + FWUPD_ERROR, FWUPD_ERROR_INTERNAL, + "Could not determine sysfs path for device"); + return NULL; + } + + d = g_dir_open (self->devpath, 0, error); + if (d == NULL) + return NULL; + + while ((name = g_dir_read_name (d)) != NULL) { + if (g_str_has_prefix (name, nvmem_dir)) { + g_autoptr(GFile) parent = g_file_new_for_path (self->devpath); + g_autoptr(GFile) nvm_dir = g_file_get_child (parent, name); + return g_file_get_child (nvm_dir, "nvmem"); + } + } + + g_set_error_literal (error, + FWUPD_ERROR, FWUPD_ERROR_NOT_SUPPORTED, + "Could not find non-volatile memory location"); + return NULL; +} + +static gboolean +fu_thunderbolt_device_read_status_block (FuThunderboltDevice *self, GError **error) +{ + gsize nr_chunks; + g_autoptr(GFile) nvmem = NULL; + g_autoptr(GBytes) controller_fw = NULL; + g_autoptr(GInputStream) istr = NULL; + g_autoptr(FuThunderboltFirmware) firmware = fu_thunderbolt_firmware_new (); + + nvmem = fu_thunderbolt_device_find_nvmem (self, TRUE, error); + if (nvmem == NULL) + return FALSE; + + /* read just enough bytes to read the status byte */ + nr_chunks = (FU_TBT_OFFSET_NATIVE + FU_TBT_CHUNK_SZ - 1) / FU_TBT_CHUNK_SZ; + istr = G_INPUT_STREAM (g_file_read (nvmem, NULL, error)); + if (istr == NULL) + return FALSE; + controller_fw = g_input_stream_read_bytes (istr, + nr_chunks * FU_TBT_CHUNK_SZ, + NULL, error); + if (controller_fw == NULL) + return FALSE; + if (!fu_firmware_parse (FU_FIRMWARE (firmware), + controller_fw, + FWUPD_INSTALL_FLAG_NONE, + error)) + return FALSE; + self->is_native = fu_thunderbolt_firmware_is_native (firmware); + return TRUE; +} + +static gboolean +fu_thunderbolt_device_can_update (FuThunderboltDevice *self) +{ + g_autoptr(GError) nvmem_error = NULL; + g_autoptr(GFile) non_active_nvmem = NULL; + + non_active_nvmem = fu_thunderbolt_device_find_nvmem (self, FALSE, + &nvmem_error); + if (non_active_nvmem == NULL) { + g_debug ("%s", nvmem_error->message); + return FALSE; + } + + return TRUE; +} + +static gboolean +fu_thunderbolt_device_get_version (FuThunderboltDevice *self) +{ + g_auto(GStrv) split = NULL; + g_autofree gchar *version_raw = NULL; + g_autofree gchar *version = NULL; + /* read directly from file to prevent udev caching */ + g_autofree gchar *safe_path = g_build_path ("/", self->devpath, "nvm_version", NULL); + + for (guint i = 0; i < 50; i++) { + g_autoptr(GError) error_local = NULL; + /* glib can't return a properly mapped -ENODATA but the + * kernel only returns -ENODATA or -EAGAIN */ + if (g_file_get_contents (safe_path, &version_raw, NULL, &error_local)) + break; + g_debug ("Attempt %u: Failed to read NVM version", i); + g_usleep (TBT_NVM_RETRY_TIMEOUT * 1000); + /* safe mode probably */ + if (g_error_matches (error_local, G_IO_ERROR, G_IO_ERROR_WOULD_BLOCK)) + break; + } + + if (version_raw == NULL) + return FALSE; + split = g_strsplit (version_raw, ".", -1); + if (g_strv_length (split) != 2) + return FALSE; + + version = g_strdup_printf ("%02x.%02x", + (guint) g_ascii_strtoull (split[0], NULL, 16), + (guint) g_ascii_strtoull (split[1], NULL, 16)); + fu_device_set_version (FU_DEVICE (self), version); + g_debug ("setting version to %s", version); + g_debug ("path is %s", self->devpath); + return TRUE; +} + +static void +fu_thunderbolt_device_check_safe_mode (FuThunderboltDevice *self) +{ + /* failed to read, for host check for safe mode */ + if (!self->host || self->gen >= 4) + return; + g_warning ("%s is in safe mode -- VID/DID will " + "need to be set by another plugin", + self->devpath); + self->safe_mode = TRUE; + fu_device_set_version (FU_DEVICE (self), "00.00"); + fu_device_add_instance_id (FU_DEVICE (self), "TBT-safemode"); + fu_device_set_metadata_boolean (FU_DEVICE (self), FU_DEVICE_METADATA_TBT_IS_SAFE_MODE, TRUE); +} + +static void +fu_thunderbolt_device_to_string (FuDevice *device, guint idt, GString *str) +{ + FuThunderboltDevice *self = FU_THUNDERBOLT_DEVICE (device); + fu_common_string_append_kb (str, idt, "Host Controller", self->host); + fu_common_string_append_kb (str, idt, "Safe Mode", self->safe_mode); + fu_common_string_append_kb (str, idt, "Native mode", self->is_native); + fu_common_string_append_ku (str, idt, "Generation", self->gen); +} + +static gboolean +fu_thunderbolt_device_probe (FuUdevDevice *device, GError **error) +{ + const gchar *tmp = fu_udev_device_get_sysfs_attr (device, "unique_id", NULL); + /* most likely the domain itself, ignore */ + if (tmp == NULL) { + g_set_error_literal (error, + FWUPD_ERROR, + FWUPD_ERROR_NOT_SUPPORTED, + "thunderbolt domain not used"); + return FALSE; + } + fu_device_set_physical_id (FU_DEVICE (device), tmp); + + return TRUE; +} + +static guint16 +fu_thunderbolt_device_get_attr_uint16 (FuThunderboltDevice *self, + const gchar *name, + GError **error) +{ + const gchar *str; + guint64 val; + + str = fu_udev_device_get_sysfs_attr (FU_UDEV_DEVICE (self), name, error); + if (str == NULL) + return 0x0; + + val = g_ascii_strtoull (str, NULL, 16); + if (val == 0x0) { + g_set_error (error, + FWUPD_ERROR, + FWUPD_ERROR_INTERNAL, + "failed to parse %s", str); + return 0; + } + if (val > G_MAXUINT16) { + g_set_error (error, + FWUPD_ERROR, + FWUPD_ERROR_INTERNAL, + "%s overflows", + name); + return 0x0; + } + return (guint16) val; +} + +static gboolean +fu_thunderbolt_device_setup (FuDevice *device, GError **error) +{ + FuThunderboltDevice *self = FU_THUNDERBOLT_DEVICE (device); + const gchar *tmp = NULL; + guint16 did; + guint16 vid; + g_autoptr(GError) error_gen = NULL; + g_autofree gchar *parent_name = fu_udev_device_get_parent_name (FU_UDEV_DEVICE (self)); + + self->devpath = g_strdup (fu_udev_device_get_sysfs_path (FU_UDEV_DEVICE (device))); + fu_device_set_metadata (device, "sysfs-path", self->devpath); + +/* TODO: + force power handling from old plugin on remove + on supported systems other plugins may use a GPIO to force + power on supported devices even when in low power mode -- + this will happen in coldplug_prepare and prepare_for_update + if (fu_thunderbolt_device_is_host (device) && + !fu_device_has_flag (dev, FWUPD_DEVICE_FLAG_WAIT_FOR_REPLUG) && + fu_device_get_metadata_boolean (dev, FU_DEVICE_METADATA_TBT_CAN_FORCE_POWER)) { + g_debug ("ignoring remove event as force powered"); + return; + } + + fu_plugin_device_remove (plugin, dev); +*/ + + /* these may be missing on ICL or later */ + vid = fu_udev_device_get_vendor (FU_UDEV_DEVICE (self)); + if (vid == 0x0) + g_debug ("failed to get Vendor ID"); + + did = fu_udev_device_get_model (FU_UDEV_DEVICE (self)); + if (did == 0x0) + g_debug ("failed to get Device ID"); + + /* requires kernel 5.5 or later, non-fatal if not available */ + self->gen = fu_thunderbolt_device_get_attr_uint16 (self, "generation", &error_gen); + if (self->gen == 0) + g_debug ("Unable to read generation: %s", error_gen->message); + + /* read the first block of firmware to get the is-native attribute */ + if (!fu_thunderbolt_device_read_status_block (self, error)) + return FALSE; + + /* determine if host controller or not */ + if (parent_name != NULL && g_str_has_prefix (parent_name, "domain")) { + self->host = TRUE; + fu_device_add_flag (device, FWUPD_DEVICE_FLAG_INTERNAL); + fu_device_set_summary (device, "Unmatched performance for high-speed I/O"); + } else { + tmp = fu_udev_device_get_sysfs_attr (FU_UDEV_DEVICE (self), "device_name", NULL); + } + + /* set the controller name */ + if (tmp == NULL) { + if (self->gen == 4) + tmp = "USB4 Controller"; + else + tmp = "Thunderbolt Controller"; + } + fu_device_set_name (device, tmp); + + /* set vendor string */ + tmp = fu_udev_device_get_sysfs_attr (FU_UDEV_DEVICE (self), "vendor_name", error); + if (tmp == NULL) + return FALSE; + fu_device_set_vendor (device, tmp); + + /* try to read the version */ + if (!fu_thunderbolt_device_get_version (self)) + fu_thunderbolt_device_check_safe_mode (self); + + if (self->safe_mode) { + fu_device_set_update_error (device, "Device is in safe mode"); + } else { + g_autofree gchar *device_id = NULL; + g_autofree gchar *domain_id = NULL; + if (fu_thunderbolt_device_can_update (self)) { + g_autofree gchar *vendor_id = NULL; + g_autofree gchar *domain = g_path_get_basename (self->devpath); + /* USB4 controllers don't have a concept of legacy vs native + * so don't try to read a native attribute from their NVM */ + if (self->host && self->gen < 4) { + domain_id = g_strdup_printf ("TBT-%04x%04x%s-controller%s", + (guint) vid, + (guint) did, + self->is_native ? "-native" : "", + domain); + } + vendor_id = g_strdup_printf ("TBT:0x%04X", (guint) vid); + fu_device_set_vendor_id (device, vendor_id); + device_id = g_strdup_printf ("TBT-%04x%04x%s", + (guint) vid, + (guint) did, + self->is_native ? "-native" : ""); + fu_device_add_flag (device, FWUPD_DEVICE_FLAG_UPDATABLE); + fu_device_add_flag (device, FWUPD_DEVICE_FLAG_DUAL_IMAGE); + } else { + device_id = g_strdup ("TBT-fixed"); + fu_device_set_update_error (device, "Missing non-active nvmem"); + } + fu_device_add_instance_id (device, device_id); + if (domain_id != NULL) + fu_device_add_instance_id (device, domain_id); + } + + /* success */ + return TRUE; +} + +static gboolean +fu_thunderbolt_device_trigger_update (FuThunderboltDevice *self, + GError **error) +{ + + ssize_t n; + int fd; + int r; + g_autofree gchar *auth_path = NULL; + + auth_path = g_build_filename (self->devpath, "nvm_authenticate", NULL); + + fd = open (auth_path, O_WRONLY | O_CLOEXEC); + if (fd < 0) { + g_set_error (error, G_IO_ERROR, + g_io_error_from_errno (errno), + "could not open 'nvm_authenticate': %s", + g_strerror (errno)); + return FALSE; + } + + do { + n = write (fd, "1", 1); + if (n < 1 && errno != EINTR) { + g_set_error (error, G_IO_ERROR, + g_io_error_from_errno (errno), + "could not write to 'nvm_authenticate': %s", + g_strerror (errno)); + (void) close (fd); + return FALSE; + } + } while (n < 1); + + r = close (fd); + if (r < 0 && errno != EINTR) { + g_set_error (error, G_IO_ERROR, + g_io_error_from_errno (errno), + "could not close 'nvm_authenticate': %s", + g_strerror (errno)); + return FALSE; + } + + return TRUE; +} + +static gboolean +fu_thunderbolt_device_attach (FuDevice *device, GError **error) +{ + const gchar *attribute; + guint64 status; + + /* now check if the update actually worked */ + attribute = fu_udev_device_get_sysfs_attr (FU_UDEV_DEVICE (device), + "nvm_authenticate", + error); + if (attribute == NULL) + return FALSE; + status = g_ascii_strtoull (attribute, NULL, 16); + if (status == G_MAXUINT64 && errno == ERANGE) { + g_set_error (error, G_IO_ERROR, + g_io_error_from_errno (errno), + "failed to read 'nvm_authenticate: %s", + g_strerror (errno)); + return FALSE; + } + + /* anything else then 0x0 means we got an error */ + if (status != 0x0) { + g_set_error (error, + FWUPD_ERROR, + FWUPD_ERROR_INTERNAL, + "update failed (status %" G_GINT64_MODIFIER "x)", status); + return FALSE; + } + + return TRUE; +} + +static gboolean +fu_thunderbolt_device_rescan (FuDevice *device, GError **error) +{ + FuThunderboltDevice *self = FU_THUNDERBOLT_DEVICE (device); + /* refresh the version */ + return fu_thunderbolt_device_get_version (self); +} + +static gboolean +fu_thunderbolt_device_write_data (FuThunderboltDevice *self, + GBytes *blob_fw, + GError **error) +{ + gsize fw_size; + gsize nwritten; + gssize n; + g_autoptr(GFile) nvmem = NULL; + g_autoptr(GOutputStream) os = NULL; + + nvmem = fu_thunderbolt_device_find_nvmem (self, FALSE, error); + if (nvmem == NULL) + return FALSE; + + os = (GOutputStream *) g_file_append_to (nvmem, + G_FILE_CREATE_NONE, + NULL, + error); + + if (os == NULL) + return FALSE; + + nwritten = 0; + fw_size = g_bytes_get_size (blob_fw); + fu_device_set_progress_full (FU_DEVICE (self), nwritten, fw_size); + + do { + g_autoptr(GBytes) fw_data = NULL; + + fw_data = g_bytes_new_from_bytes (blob_fw, + nwritten, + fw_size - nwritten); + + n = g_output_stream_write_bytes (os, + fw_data, + NULL, + error); + if (n < 0) + return FALSE; + + nwritten += n; + fu_device_set_progress_full (FU_DEVICE (self), nwritten, fw_size); + + } while (nwritten < fw_size); + + if (nwritten != fw_size) { + g_set_error_literal (error, + FWUPD_ERROR, + FWUPD_ERROR_WRITE, + "Could not write all data to nvmem"); + return FALSE; + } + + return g_output_stream_close (os, NULL, error); +} + +static FuFirmware * +fu_thunderbolt_device_prepare_firmware (FuDevice *device, + GBytes *fw, + FwupdInstallFlags flags, + GError **error) +{ + FuThunderboltDevice *self = FU_THUNDERBOLT_DEVICE (device); + g_autoptr(FuThunderboltFirmware) firmware = fu_thunderbolt_firmware_new (); + g_autoptr(FuThunderboltFirmware) firmware_old = fu_thunderbolt_firmware_new (); + g_autoptr(GBytes) controller_fw = NULL; + g_autoptr(GError) error_local = NULL; + g_autoptr(GFile) nvmem = NULL; + + /* parse */ + if (!fu_firmware_parse (FU_FIRMWARE (firmware), fw, flags, error)) + return NULL; + + /* get current NVMEM */ + nvmem = fu_thunderbolt_device_find_nvmem (self, TRUE, error); + if (nvmem == NULL) + return NULL; + controller_fw = g_file_load_bytes (nvmem, NULL, NULL, error); + if (!fu_firmware_parse (FU_FIRMWARE (firmware_old), controller_fw, flags, error)) + return NULL; + if (fu_thunderbolt_firmware_is_host (firmware) != + fu_thunderbolt_firmware_is_host (firmware_old)) { + g_set_error (error, + FWUPD_ERROR, + FWUPD_ERROR_INVALID_FILE, + "incorrect firmware mode, got %s, expected %s", + fu_thunderbolt_firmware_is_host (firmware) ? "host" : "device", + fu_thunderbolt_firmware_is_host (firmware_old) ? "host" : "device"); + return NULL; + } + if (fu_thunderbolt_firmware_get_vendor_id (firmware) != + fu_thunderbolt_firmware_get_vendor_id (firmware_old)) { + g_set_error (error, + FWUPD_ERROR, + FWUPD_ERROR_INVALID_FILE, + "incorrect device vendor, got 0x%04x, expected 0x%04x", + fu_thunderbolt_firmware_get_vendor_id (firmware), + fu_thunderbolt_firmware_get_vendor_id (firmware_old)); + return NULL; + } + if (fu_thunderbolt_firmware_get_device_id (firmware) != + fu_thunderbolt_firmware_get_device_id (firmware_old)) { + g_set_error (error, + FWUPD_ERROR, + FWUPD_ERROR_INVALID_FILE, + "incorrect device type, got 0x%04x, expected 0x%04x", + fu_thunderbolt_firmware_get_device_id (firmware), + fu_thunderbolt_firmware_get_device_id (firmware_old)); + return NULL; + } + if ((flags & FWUPD_INSTALL_FLAG_FORCE) == 0) { + if (fu_thunderbolt_firmware_get_model_id (firmware) != + fu_thunderbolt_firmware_get_model_id (firmware_old)) { + g_set_error (error, + FWUPD_ERROR, + FWUPD_ERROR_INVALID_FILE, + "incorrect device model, got 0x%04x, expected 0x%04x", + fu_thunderbolt_firmware_get_model_id (firmware), + fu_thunderbolt_firmware_get_model_id (firmware_old)); + return NULL; + } + if (fu_thunderbolt_firmware_get_has_pd (firmware) != + fu_thunderbolt_firmware_get_has_pd (firmware_old)) { + g_set_error_literal (error, + FWUPD_ERROR, + FWUPD_ERROR_INVALID_FILE, + "incorrect PD section"); + return NULL; + } + if (fu_thunderbolt_firmware_get_flash_size (firmware) != + fu_thunderbolt_firmware_get_flash_size (firmware_old)) { + g_set_error_literal (error, + FWUPD_ERROR, + FWUPD_ERROR_INVALID_FILE, + "incorrect flash size"); + return NULL; + } + } + + /* success */ + return FU_FIRMWARE (g_steal_pointer (&firmware)); +} + +static gboolean +fu_thunderbolt_device_write_firmware (FuDevice *device, + FuFirmware *firmware, + FwupdInstallFlags flags, + GError **error) +{ + FuThunderboltDevice *self = FU_THUNDERBOLT_DEVICE (device); + g_autoptr(GBytes) blob_fw = NULL; + + /* get default image */ + blob_fw = fu_firmware_get_image_default_bytes (firmware, error); + if (blob_fw == NULL) + return FALSE; + + fu_device_set_status (device, FWUPD_STATUS_DEVICE_WRITE); + if (!fu_thunderbolt_device_write_data (self, blob_fw, error)) { + g_prefix_error (error, + "could not write firmware to thunderbolt device at %s: ", + self->devpath); + return FALSE; + } + + if (!fu_thunderbolt_device_trigger_update (self, error)) { + g_prefix_error (error, "could not start thunderbolt device upgrade: "); + return FALSE; + } + + fu_device_set_status (device, FWUPD_STATUS_DEVICE_RESTART); + fu_device_set_remove_delay (device, FU_PLUGIN_THUNDERBOLT_UPDATE_TIMEOUT); + fu_device_add_flag (device, FWUPD_DEVICE_FLAG_WAIT_FOR_REPLUG); + + return TRUE; +} + +static void +fu_thunderbolt_device_init (FuThunderboltDevice *self) +{ + fu_device_add_flag (FU_DEVICE (self), FWUPD_DEVICE_FLAG_REQUIRE_AC); + fu_device_add_icon (FU_DEVICE (self), "thunderbolt"); + fu_device_set_protocol (FU_DEVICE (self), "com.intel.thunderbolt"); + fu_device_set_version_format (FU_DEVICE (self), FWUPD_VERSION_FORMAT_PAIR); +} + +static void +fu_thunderbolt_device_finalize (GObject *object) +{ + FuThunderboltDevice *self = FU_THUNDERBOLT_DEVICE (object); + G_OBJECT_CLASS (fu_thunderbolt_device_parent_class)->finalize (object); + g_free (self->devpath); +} + +static void +fu_thunderbolt_device_class_init (FuThunderboltDeviceClass *klass) +{ + GObjectClass *object_class = G_OBJECT_CLASS (klass); + FuDeviceClass *klass_device = FU_DEVICE_CLASS (klass); + FuUdevDeviceClass *klass_udev_device = FU_UDEV_DEVICE_CLASS (klass); + object_class->finalize = fu_thunderbolt_device_finalize; + klass_device->activate = fu_thunderbolt_device_trigger_update; + klass_device->to_string = fu_thunderbolt_device_to_string; + klass_device->setup = fu_thunderbolt_device_setup; + klass_device->prepare_firmware = fu_thunderbolt_device_prepare_firmware; + klass_device->write_firmware = fu_thunderbolt_device_write_firmware; + klass_device->attach = fu_thunderbolt_device_attach; + klass_device->rescan = fu_thunderbolt_device_rescan; + klass_udev_device->probe = fu_thunderbolt_device_probe; +} diff --git a/plugins/thunderbolt/fu-thunderbolt-device.h b/plugins/thunderbolt/fu-thunderbolt-device.h new file mode 100644 index 000000000..3c9167cc5 --- /dev/null +++ b/plugins/thunderbolt/fu-thunderbolt-device.h @@ -0,0 +1,13 @@ +/* + * Copyright (C) 2018 Richard Hughes + * Copyright (C) 2020 Mario Limonciello + * + * SPDX-License-Identifier: LGPL-2.1+ + */ + +#pragma once + +#include "fu-plugin.h" + +#define FU_TYPE_THUNDERBOLT_DEVICE (fu_thunderbolt_device_get_type ()) +G_DECLARE_FINAL_TYPE (FuThunderboltDevice, fu_thunderbolt_device, FU, THUNDERBOLT_DEVICE, FuUdevDevice) diff --git a/plugins/thunderbolt/fu-thunderbolt-firmware.c b/plugins/thunderbolt/fu-thunderbolt-firmware.c new file mode 100644 index 000000000..a01e81b05 --- /dev/null +++ b/plugins/thunderbolt/fu-thunderbolt-firmware.c @@ -0,0 +1,572 @@ +/* + * Copyright (C) 2017 Intel Corporation. + * Copyright (C) 2020 Richard Hughes + * + * SPDX-License-Identifier: LGPL-2.1+ + */ + +#include "config.h" + +#include + +#include "fu-common.h" +#include "fu-thunderbolt-firmware.h" + +typedef enum { + _SECTION_DIGITAL, + _SECTION_DROM, + _SECTION_ARC_PARAMS, + _SECTION_DRAM_UCODE, + _SECTION_LAST +} FuThunderboltSection; + +typedef enum { + _FAMILY_UNKNOWN, + _FAMILY_FR, + _FAMILY_WR, + _FAMILY_AR, + _FAMILY_AR_C, + _FAMILY_TR, + _FAMILY_BB, +} FuThunderboltFamily; + +struct _FuThunderboltFirmware { + FuFirmwareClass parent_instance; + guint32 sections[_SECTION_LAST]; + FuThunderboltFamily family; + gboolean is_host; + gboolean is_native; + gboolean has_pd; + guint16 device_id; + guint16 vendor_id; + guint16 model_id; + guint gen; + guint ports; + guint8 flash_size; +}; + +G_DEFINE_TYPE (FuThunderboltFirmware, fu_thunderbolt_firmware, FU_TYPE_FIRMWARE) + +typedef struct { + guint16 id; + guint gen; + FuThunderboltFamily family; + guint ports; +} FuThunderboltHwInfo; + +enum { + DROM_ENTRY_MC = 0x6, +}; + +gboolean +fu_thunderbolt_firmware_is_host (FuThunderboltFirmware *self) +{ + g_return_val_if_fail (FU_IS_THUNDERBOLT_FIRMWARE (self), FALSE); + return self->is_host; +} + +gboolean +fu_thunderbolt_firmware_is_native (FuThunderboltFirmware *self) +{ + g_return_val_if_fail (FU_IS_THUNDERBOLT_FIRMWARE (self), FALSE); + return self->is_native; +} + +gboolean +fu_thunderbolt_firmware_get_has_pd (FuThunderboltFirmware *self) +{ + g_return_val_if_fail (FU_IS_THUNDERBOLT_FIRMWARE (self), FALSE); + return self->has_pd; +} + +guint16 +fu_thunderbolt_firmware_get_device_id (FuThunderboltFirmware *self) +{ + g_return_val_if_fail (FU_IS_THUNDERBOLT_FIRMWARE (self), 0); + return self->device_id; +} + +guint16 +fu_thunderbolt_firmware_get_vendor_id (FuThunderboltFirmware *self) +{ + g_return_val_if_fail (FU_IS_THUNDERBOLT_FIRMWARE (self), 0); + return self->vendor_id; +} + +guint16 +fu_thunderbolt_firmware_get_model_id (FuThunderboltFirmware *self) +{ + g_return_val_if_fail (FU_IS_THUNDERBOLT_FIRMWARE (self), 0); + return self->model_id; +} + +guint8 +fu_thunderbolt_firmware_get_flash_size (FuThunderboltFirmware *self) +{ + g_return_val_if_fail (FU_IS_THUNDERBOLT_FIRMWARE (self), 0); + return self->flash_size; +} + +static const gchar * +fu_thunderbolt_firmware_family_to_string (FuThunderboltFamily family) +{ + if (family == _FAMILY_FR) + return "Falcon Ridge"; + if (family == _FAMILY_WR) + return "Win Ridge"; + if (family == _FAMILY_AR) + return "Alpine Ridge"; + if (family == _FAMILY_AR_C) + return "Alpine Ridge C"; + if (family == _FAMILY_TR) + return "Titan Ridge"; + if (family == _FAMILY_BB) + return "BB"; + return "Unknown"; +} + +static void +fu_thunderbolt_firmware_to_string (FuFirmware *firmware, guint idt, GString *str) +{ + FuThunderboltFirmware *self = FU_THUNDERBOLT_FIRMWARE (firmware); + fu_common_string_append_kv (str, idt, "Family", + fu_thunderbolt_firmware_family_to_string (self->family)); + fu_common_string_append_kb (str, idt, "IsHost", self->is_host); + fu_common_string_append_kb (str, idt, "IsNative", self->is_native); + fu_common_string_append_kx (str, idt, "DeviceId", self->device_id); + fu_common_string_append_kx (str, idt, "VendorId", self->vendor_id); + fu_common_string_append_kx (str, idt, "ModelId", self->model_id); + fu_common_string_append_kx (str, idt, "FlashSize", self->flash_size); + fu_common_string_append_kx (str, idt, "Generation", self->gen); + fu_common_string_append_kx (str, idt, "Ports", self->ports); + fu_common_string_append_kb (str, idt, "HasPd", self->has_pd); + for (guint i = 0; i < _SECTION_LAST; i++) { + g_autofree gchar *title = g_strdup_printf ("Section%u", i); + fu_common_string_append_kx (str, idt, title, self->sections[i]); + } +} + +static inline gboolean +fu_thunderbolt_firmware_valid_farb_pointer (guint32 pointer) +{ + return pointer != 0 && pointer != 0xFFFFFF; +} + +static inline gboolean +fu_thunderbolt_firmware_valid_pd_pointer (guint32 pointer) +{ + return pointer != 0 && pointer != 0xFFFFFFFF; +} + +static gboolean +fu_thunderbolt_firmware_read_location (FuThunderboltFirmware *self, + FuThunderboltSection section, + guint32 offset, + guint8 *buf, + guint32 len, + GError **error) +{ + const guint8 *srcbuf; + gsize srcbufsz = 0; + guint32 location_start = self->sections[section] + offset; + g_autoptr(GBytes) fw = NULL; + + /* get blob */ + fw = fu_firmware_get_image_default_bytes (FU_FIRMWARE (self), error); + if (fw == NULL) + return FALSE; + srcbuf = g_bytes_get_data (fw, &srcbufsz); + + if (!fu_memcpy_safe (buf, len, 0x0, /* dst */ + srcbuf, srcbufsz, location_start, /* src */ + len, error)) { + g_prefix_error (error, "location is outside of the given image: "); + return FALSE; + } + return TRUE; +} + +static gboolean +fu_thunderbolt_firmware_read_farb_pointer_impl (FuThunderboltFirmware *self, + FuThunderboltSection section, + guint32 offset, + guint32 *value, + GError **error) +{ + guint32 tmp = 0; + if (!fu_thunderbolt_firmware_read_location (self, section, offset, + (guint8 *) &tmp, 3, /* 24 bits */ + error)) { + g_prefix_error (error, "failed to read farb pointer: "); + return FALSE; + } + *value = GUINT32_FROM_LE (tmp); + return TRUE; +} + +/* returns invalid FARB pointer on error */ +static guint32 +fu_thunderbolt_firmware_read_farb_pointer (FuThunderboltFirmware *self, GError **error) +{ + guint32 value; + if (!fu_thunderbolt_firmware_read_farb_pointer_impl (self, + _SECTION_DIGITAL, + 0x0, &value, error)) + return 0; + if (fu_thunderbolt_firmware_valid_farb_pointer (value)) + return value; + + if (!fu_thunderbolt_firmware_read_farb_pointer_impl (self, + _SECTION_DIGITAL, + 0x1000, &value, error)) + return 0; + if (!fu_thunderbolt_firmware_valid_farb_pointer (value)) { + g_set_error_literal (error, + FWUPD_ERROR, + FWUPD_ERROR_INVALID_FILE, + "Invalid FW image file format"); + return 0; + } + + return value; +} + +static gboolean +fu_thunderbolt_firmware_read_uint8 (FuThunderboltFirmware *self, + FuThunderboltSection section, + guint32 offset, + guint8 *value, + GError **error) +{ + return fu_thunderbolt_firmware_read_location (self, section, offset, + value, 1, error); +} + +static gboolean +fu_thunderbolt_firmware_read_uint16 (FuThunderboltFirmware *self, + FuThunderboltSection section, + guint32 offset, + guint16 *value, + GError **error) +{ + guint16 tmp = 0; + if (!fu_thunderbolt_firmware_read_location (self, section, offset, + (guint8 *) &tmp, sizeof(tmp), + error)) { + g_prefix_error (error, "failed to read uint16: "); + return FALSE; + } + *value = GUINT16_FROM_LE (tmp); + return TRUE; +} + +static gboolean +fu_thunderbolt_firmware_read_uint32 (FuThunderboltFirmware *self, + FuThunderboltSection section, + guint32 offset, + guint32 *value, + GError **error) +{ + guint32 tmp = 0; + if (!fu_thunderbolt_firmware_read_location (self, section, offset, + (guint8 *) &tmp, sizeof(tmp), + error)) { + g_prefix_error (error, "failed to read uint32: "); + return FALSE; + } + *value = GUINT32_FROM_LE (tmp); + return TRUE; +} + +/* + * Size of ucode sections is uint16 value saved at the start of the section, + * it's in DWORDS (4-bytes) units and it doesn't include itself. We need the + * offset to the next section, so we translate it to bytes and add 2 for the + * size field itself. + * + * offset parameter must be relative to digital section + */ +static gboolean +fu_thunderbolt_firmware_read_ucode_section_len (FuThunderboltFirmware *self, + guint32 offset, + guint16 *value, + GError **error) +{ + if (!fu_thunderbolt_firmware_read_uint16 (self, + _SECTION_DIGITAL, + offset, + value, + error)) { + g_prefix_error (error, "failed to read ucode section len: "); + return FALSE; + } + *value *= sizeof(guint32); + *value += sizeof(guint16); + return TRUE; +} + +/* assumes sections[_SECTION_DIGITAL].offset is already set */ +static gboolean +fu_thunderbolt_firmware_read_sections (FuThunderboltFirmware *self, GError **error) +{ + guint32 offset; + + if (self->gen >= 3 || self->gen == 0) { + if (!fu_thunderbolt_firmware_read_uint32 (self, + _SECTION_DIGITAL, + 0x10e, + &offset, + error)) + return FALSE; + self->sections[_SECTION_DROM] = offset + self->sections[_SECTION_DIGITAL]; + + if (!fu_thunderbolt_firmware_read_uint32 (self, + _SECTION_DIGITAL, + 0x75, + &offset, + error)) + return FALSE; + self->sections[_SECTION_ARC_PARAMS] = offset + self->sections[_SECTION_DIGITAL]; + } + + if (self->is_host && self->gen > 2) { + /* + * To find the DRAM section, we have to jump from section to + * section in a chain of sections. + * available_sections location tells what sections exist at all + * (with a flag per section). + * ee_ucode_start_addr location tells the offset of the first + * section in the list relatively to the digital section start. + * After having the offset of the first section, we have a loop + * over the section list. If the section exists, we read its + * length (2 bytes at section start) and add it to current + * offset to find the start of the next section. Otherwise, we + * already have the next section offset... + */ + const guint8 DRAM_FLAG = 1 << 6; + guint16 ucode_offset; + guint8 available_sections = 0; + + if (!fu_thunderbolt_firmware_read_uint8 (self, + _SECTION_DIGITAL, + 0x2, + &available_sections, + error)) { + g_prefix_error (error, "failed to read available sections: "); + return FALSE; + } + if (!fu_thunderbolt_firmware_read_uint16 (self, + _SECTION_DIGITAL, + 0x3, + &ucode_offset, + error)) { + g_prefix_error (error, "failed to read ucode offset: "); + return FALSE; + } + offset = ucode_offset; + if ((available_sections & DRAM_FLAG) == 0) { + g_set_error_literal (error, + FWUPD_ERROR, FWUPD_ERROR_INVALID_FILE, + "Can't find needed FW sections in the FW image file"); + return FALSE; + } + + for (guint8 i = 1; i < DRAM_FLAG; i <<= 1) { + if (available_sections & i) { + if (!fu_thunderbolt_firmware_read_ucode_section_len (self, + offset, + &ucode_offset, + error)) + return FALSE; + offset += ucode_offset; + } + } + self->sections[_SECTION_DRAM_UCODE] = offset + self->sections[_SECTION_DIGITAL]; + } + + return TRUE; +} + +static gboolean +fu_thunderbolt_firmware_missing_needed_drom (FuThunderboltFirmware *self) +{ + if (self->sections[_SECTION_DROM] != 0) + return FALSE; + if (self->is_host && self->gen < 3) + return FALSE; + return TRUE; +} + +static gboolean +fu_thunderbolt_firmware_parse (FuFirmware *firmware, + GBytes *fw, + guint64 addr_start, + guint64 addr_end, + FwupdInstallFlags flags, + GError **error) +{ + FuThunderboltFirmware *self = FU_THUNDERBOLT_FIRMWARE (firmware); + guint8 tmp = 0; + static const FuThunderboltHwInfo hw_info_arr[] = { + { 0x156D, 2, _FAMILY_FR, 2 }, /* FR 4C */ + { 0x156B, 2, _FAMILY_FR, 1 }, /* FR 2C */ + { 0x157E, 2, _FAMILY_WR, 1 }, /* WR */ + { 0x1578, 3, _FAMILY_AR, 2 }, /* AR 4C */ + { 0x1576, 3, _FAMILY_AR, 1 }, /* AR 2C */ + { 0x15C0, 3, _FAMILY_AR, 1 }, /* AR LP */ + { 0x15D3, 3, _FAMILY_AR_C, 2 }, /* AR-C 4C */ + { 0x15DA, 3, _FAMILY_AR_C, 1 }, /* AR-C 2C */ + { 0x15E7, 3, _FAMILY_TR, 1 }, /* TR 2C */ + { 0x15EA, 3, _FAMILY_TR, 2 }, /* TR 4C */ + { 0x15EF, 3, _FAMILY_TR, 2 }, /* TR 4C device */ + { 0x15EE, 3, _FAMILY_BB, 0 }, /* BB device */ + { 0 } + }; + + g_autoptr(FuFirmwareImage) img = fu_firmware_image_new (fw); + + /* add this straight away so we can read it without a self */ + fu_firmware_add_image (firmware, img); + + /* is native */ + if (!fu_thunderbolt_firmware_read_uint8 (self, + _SECTION_DIGITAL, + FU_TBT_OFFSET_NATIVE, + &tmp, error)) { + g_prefix_error (error, "failed to read native: "); + return FALSE; + } + self->is_native = tmp & 0x20; + + self->sections[_SECTION_DIGITAL] = fu_thunderbolt_firmware_read_farb_pointer (self, error); + if (self->sections[_SECTION_DIGITAL] == 0) + return FALSE; + + /* we're only reading the first chunk */ + if (g_bytes_get_size (fw) == 0x80) + return TRUE; + + /* host or device */ + if (!fu_thunderbolt_firmware_read_uint8 (self, + _SECTION_DIGITAL, + 0x10, &tmp, error)) { + g_prefix_error (error, "failed to read is-host: "); + return FALSE; + } + self->is_host = tmp & (1 << 1); + + /* device ID */ + if (!fu_thunderbolt_firmware_read_uint16 (self, + _SECTION_DIGITAL, + 0x5, + &self->device_id, + error)) { + g_prefix_error (error, "failed to read device-id: "); + return FALSE; + } + + /* this is best-effort */ + for (guint i = 0; hw_info_arr[i].id != 0; i++) { + if (hw_info_arr[i].id == self->device_id) { + self->family = hw_info_arr[i].family; + self->gen = hw_info_arr[i].gen; + self->ports = hw_info_arr[i].ports; + break; + } + } + if (self->ports == 0 && self->is_host) { + g_set_error (error, + FWUPD_ERROR, + FWUPD_ERROR_NOT_SUPPORTED, + "Unknown controller"); + return FALSE; + } + + /* read sections from file */ + if (!fu_thunderbolt_firmware_read_sections (self, error)) + return FALSE; + if (fu_thunderbolt_firmware_missing_needed_drom (self)) { + g_set_error_literal (error, + FWUPD_ERROR, + FWUPD_ERROR_READ, + "Can't find required FW sections"); + return FALSE; + } + + /* vendor:model */ + if (self->sections[_SECTION_DROM] != 0) { + if (!fu_thunderbolt_firmware_read_uint16 (self, + _SECTION_DROM, + 0x10, + &self->vendor_id, + error)) { + g_prefix_error (error, "failed to read vendor-id: "); + return FALSE; + } + if (!fu_thunderbolt_firmware_read_uint16 (self, + _SECTION_DROM, + 0x12, + &self->model_id, + error)) { + g_prefix_error (error, "failed to read model-id: "); + return FALSE; + } + } + + /* has PD */ + if (self->sections[_SECTION_ARC_PARAMS] != 0) { + guint32 pd_pointer = 0x0; + if (!fu_thunderbolt_firmware_read_uint32 (self, + _SECTION_ARC_PARAMS, + 0x10C, + &pd_pointer, + error)) { + g_prefix_error (error, "failed to read pd-pointer: "); + return FALSE; + } + self->has_pd = fu_thunderbolt_firmware_valid_pd_pointer (pd_pointer); + } + + if (self->is_host) { + switch (self->family) { + case _FAMILY_AR: + case _FAMILY_AR_C: + case _FAMILY_TR: + /* This is used for comparison between old and new image, not a raw number */ + if (!fu_thunderbolt_firmware_read_uint8 (self, + _SECTION_DIGITAL, + 0x45, + &tmp, + error)) { + g_prefix_error (error, "failed to read flash size: "); + return FALSE; + } + self->flash_size = tmp & 0x07; + break; + default: + break; + } + } + + /* success */ + return TRUE; +} + +static void +fu_thunderbolt_firmware_init (FuThunderboltFirmware *self) +{ +} + +static void +fu_thunderbolt_firmware_class_init (FuThunderboltFirmwareClass *klass) +{ + FuFirmwareClass *klass_firmware = FU_FIRMWARE_CLASS (klass); + klass_firmware->parse = fu_thunderbolt_firmware_parse; + klass_firmware->to_string = fu_thunderbolt_firmware_to_string; +} + +FuThunderboltFirmware * +fu_thunderbolt_firmware_new (void) +{ + return g_object_new (FU_TYPE_THUNDERBOLT_FIRMWARE, NULL); +} diff --git a/plugins/thunderbolt/fu-thunderbolt-firmware.h b/plugins/thunderbolt/fu-thunderbolt-firmware.h new file mode 100644 index 000000000..b6ca050b0 --- /dev/null +++ b/plugins/thunderbolt/fu-thunderbolt-firmware.h @@ -0,0 +1,26 @@ +/* + * Copyright (C) 2017 Intel Corporation. + * Copyright (C) 2020 Richard Hughes + * + * SPDX-License-Identifier: LGPL-2.1+ + */ + +#pragma once + +#include "fu-firmware.h" + +#define FU_TYPE_THUNDERBOLT_FIRMWARE (fu_thunderbolt_firmware_get_type ()) +G_DECLARE_FINAL_TYPE (FuThunderboltFirmware, fu_thunderbolt_firmware, FU,THUNDERBOLT_FIRMWARE, FuFirmware) + +/* byte offsets in firmware image */ +#define FU_TBT_OFFSET_NATIVE 0x7B +#define FU_TBT_CHUNK_SZ 0x40 + +FuThunderboltFirmware *fu_thunderbolt_firmware_new (void); +gboolean fu_thunderbolt_firmware_is_host (FuThunderboltFirmware *self); +gboolean fu_thunderbolt_firmware_is_native (FuThunderboltFirmware *self); +gboolean fu_thunderbolt_firmware_get_has_pd (FuThunderboltFirmware *self); +guint16 fu_thunderbolt_firmware_get_device_id (FuThunderboltFirmware *self); +guint16 fu_thunderbolt_firmware_get_vendor_id (FuThunderboltFirmware *self); +guint16 fu_thunderbolt_firmware_get_model_id (FuThunderboltFirmware *self); +guint8 fu_thunderbolt_firmware_get_flash_size (FuThunderboltFirmware *self); diff --git a/plugins/thunderbolt/fu-thunderbolt-image.c b/plugins/thunderbolt/fu-thunderbolt-image.c deleted file mode 100644 index 38132e71c..000000000 --- a/plugins/thunderbolt/fu-thunderbolt-image.c +++ /dev/null @@ -1,796 +0,0 @@ -/* - * Copyright (C) 2017 Intel Corporation. - * - * SPDX-License-Identifier: LGPL-2.1+ - */ - -#include "config.h" - -#include "fu-thunderbolt-image.h" - -#include -#include - -enum FuThunderboltSection { - DIGITAL_SECTION, - DROM_SECTION, - ARC_PARAMS_SECTION, - DRAM_UCODE_SECTION, - SECTION_COUNT -}; - -typedef struct { - enum FuThunderboltSection section; /* default is DIGITAL_SECTION */ - guint32 offset; - guint32 len; - guint8 mask; /* 0 means "no mask" */ - const gchar *description; -} FuThunderboltFwLocation; - -typedef struct { - const guint8 *data; - gsize len; - guint32 *sections; -} FuThunderboltFwObject; - -typedef struct { - guint16 id; - guint gen; - guint ports; -} FuThunderboltHwInfo; - -enum { - DROM_ENTRY_MC = 0x6, -}; - -static const FuThunderboltHwInfo * -get_hw_info (guint16 id) -{ - static const FuThunderboltHwInfo hw_info_arr[] = { - { 0x156D, 2, 2 }, /* FR 4C */ - { 0x156B, 2, 1 }, /* FR 2C */ - { 0x157E, 2, 1 }, /* WR */ - - { 0x1578, 3, 2 }, /* AR 4C */ - { 0x1576, 3, 1 }, /* AR 2C */ - { 0x15C0, 3, 1 }, /* AR LP */ - { 0x15D3, 3, 2 }, /* AR-C 4C */ - { 0x15DA, 3, 1 }, /* AR-C 2C */ - - { 0x15E7, 3, 1 }, /* TR 2C */ - { 0x15EA, 3, 2 }, /* TR 4C */ - { 0x15EF, 3, 2 }, /* TR 4C device */ - - { 0 } - }; - - for (gint i = 0; hw_info_arr[i].id != 0; i++) - if (hw_info_arr[i].id == id) - return hw_info_arr + i; - return NULL; -} - -static inline gboolean -valid_farb_pointer (guint32 pointer) -{ - return pointer != 0 && pointer != 0xFFFFFF; -} - -static inline gboolean -valid_pd_pointer (guint32 pointer) -{ - return pointer != 0 && pointer != 0xFFFFFFFF; -} - -/* returns NULL on error */ -static GByteArray * -read_location (const FuThunderboltFwLocation *location, - const FuThunderboltFwObject *fw, - GError **error) -{ - guint32 location_start = fw->sections[location->section] + location->offset; - g_autoptr(GByteArray) read = g_byte_array_new (); - - if (location_start > fw->len || location_start + location->len > fw->len) { - g_set_error (error, - FWUPD_ERROR, FWUPD_ERROR_READ, - "Given location is outside of the given FW (%s)", - location->description ? location->description : "N/A"); - return NULL; - } - - read = g_byte_array_append (read, - fw->data + location_start, - location->len); - - if (location->mask) - read->data[0] &= location->mask; - return g_steal_pointer (&read); -} - -static gboolean -read_farb_pointer_impl (const FuThunderboltFwLocation *location, - const FuThunderboltFwObject *fw, - guint32 *value, - GError **error) -{ - g_autoptr(GByteArray) farb = read_location (location, fw, error); - if (farb == NULL) - return FALSE; - *value = 0; - memcpy (value, farb->data, farb->len); - *value = GUINT32_FROM_LE (*value); - return TRUE; -} - -/* returns invalid FARB pointer on error */ -static guint32 -read_farb_pointer (const FuThunderboltFwObject *fw, GError **error) -{ - const FuThunderboltFwLocation farb0 = { .offset = 0, .len = 3, .description = "farb0" }; - const FuThunderboltFwLocation farb1 = { .offset = 0x1000, .len = 3, .description = "farb1" }; - - guint32 value; - if (!read_farb_pointer_impl (&farb0, fw, &value, error)) - return 0; - if (valid_farb_pointer (value)) - return value; - - if (!read_farb_pointer_impl (&farb1, fw, &value, error)) - return 0; - if (!valid_farb_pointer (value)) { - g_set_error_literal (error, - FWUPD_ERROR, FWUPD_ERROR_INVALID_FILE, - "Invalid FW image file format"); - return 0; - } - - return value; -} - -static gboolean -compare (const FuThunderboltFwLocation *location, - const FuThunderboltFwObject *controller_fw, - const FuThunderboltFwObject *image_fw, - gboolean *result, - GError **error) -{ - g_autoptr(GByteArray) controller_data = NULL; - g_autoptr(GByteArray) image_data = NULL; - - controller_data = read_location (location, controller_fw, error); - if (controller_data == NULL) - return FALSE; - - image_data = read_location (location, image_fw, error); - if (image_data == NULL) - return FALSE; - - *result = memcmp (controller_data->data, image_data->data, location->len) == 0; - return TRUE; -} - -static gboolean -read_bool (const FuThunderboltFwLocation *location, - const FuThunderboltFwObject *fw, - gboolean *val, - GError **error) -{ - g_autoptr(GByteArray) read = read_location (location, fw, error); - if (read == NULL) - return FALSE; - for (gsize i = 0; i < read->len; i++) - if (read->data[i] != 0) { - *val = TRUE; - return TRUE; - } - *val = FALSE; - return TRUE; -} - -static gboolean -read_uint16 (const FuThunderboltFwLocation *location, - const FuThunderboltFwObject *fw, - guint16 *value, - GError **error) -{ - g_autoptr(GByteArray) read = read_location (location, fw, error); - g_assert_cmpuint (location->len, ==, sizeof (guint16)); - if (read == NULL) - return FALSE; - - *value = 0; - memcpy (value, read->data, read->len); - *value = GUINT16_FROM_LE (*value); - return TRUE; -} - -static gboolean -read_uint32 (const FuThunderboltFwLocation *location, - const FuThunderboltFwObject *fw, - guint32 *value, - GError **error) -{ - g_autoptr(GByteArray) read = read_location (location, fw, error); - g_assert_cmpuint (location->len, ==, sizeof (guint32)); - if (read == NULL) - return FALSE; - - *value = 0; - memcpy (value, read->data, read->len); - *value = GUINT32_FROM_LE (*value); - return TRUE; -} - -/* - * Size of ucode sections is uint16 value saved at the start of the section, - * it's in DWORDS (4-bytes) units and it doesn't include itself. We need the - * offset to the next section, so we translate it to bytes and add 2 for the - * size field itself. - * - * offset parameter must be relative to digital section - */ -static gboolean -read_ucode_section_len (guint32 offset, - const FuThunderboltFwObject *fw, - guint16 *value, - GError **error) -{ - const FuThunderboltFwLocation section_size = { .offset = offset, .len = 2, .description = "size field" }; - if (!read_uint16 (§ion_size, fw, value, error)) - return FALSE; - *value *= sizeof (guint32); - *value += section_size.len; - return TRUE; -} - -/* - * reads generic entries from DROM based on type field and fills - * location to point to the entry data if found. Returns TRUE if there - * was no error even if the entry was not found (location->offset is != 0 - * when entry was found). - */ -static gboolean -read_drom_entry_location (const FuThunderboltFwObject *fw, - guint8 type, - FuThunderboltFwLocation *location, - GError **error) -{ - const FuThunderboltFwLocation drom_len_loc = { .offset = 0x0E, .len = 2, .section = DROM_SECTION, .description = "DROM length" }; - FuThunderboltFwLocation drom_entry_loc = { .len = 2, .section = DROM_SECTION, .description = "DROM generic entry" }; - guint16 drom_size; - - if (!read_uint16 (&drom_len_loc, fw, &drom_size, error)) - return FALSE; - - drom_size &= 0x0FFF; - /* drom_size is size of DROM block except for identification - * section and crc32 so add them here */ - drom_size += 9 + 4; - - /* DROM entries start right after the identification section */ - drom_entry_loc.offset = 9 + 4 + 9; - - do { - g_autoptr(GByteArray) entry = NULL; - guint8 entry_type; - guint8 entry_length; - - entry = read_location (&drom_entry_loc, fw, error); - if (entry == NULL) - return FALSE; - - entry_length = entry->data[0]; - entry_type = entry->data[1] & 0x3F; - - /* generic entry (port bit is not set) */ - if ((entry->data[1] & (1 << 7)) == 0 && entry_type == type) { - location->len = entry_length - 2; - location->offset = drom_entry_loc.offset + 2; - return TRUE; - } - - drom_entry_loc.offset += entry_length; - } while (drom_entry_loc.offset < drom_size); - - return TRUE; -} - -/* - * Takes a FwObject and fills its section array up - * Assumes sections[DIGITAL_SECTION].offset is already set - */ -static gboolean -read_sections (const FuThunderboltFwObject *fw, gboolean is_host, guint gen, GError **error) -{ - const FuThunderboltFwLocation arc_params_offset = { .offset = 0x75, .len = 4, .description = "arc params offset" }; - const FuThunderboltFwLocation drom_offset = { .offset = 0x10E, .len = 4, .description = "DROM offset" }; - guint32 offset; - - if (gen >= 3 || gen == 0) { - if (!read_uint32 (&drom_offset, fw, &offset, error)) - return FALSE; - fw->sections[DROM_SECTION] = offset + fw->sections[DIGITAL_SECTION]; - - if (!read_uint32 (&arc_params_offset, fw, &offset, error)) - return FALSE; - fw->sections[ARC_PARAMS_SECTION] = offset + fw->sections[DIGITAL_SECTION]; - } - - if (is_host && gen > 2) { - /* - * Algorithm: - * To find the DRAM section, we have to jump from section to - * section in a chain of sections. - * available_sections location tells what sections exist at all - * (with a flag per section). - * ee_ucode_start_addr location tells the offset of the first - * section in the list relatively to the digital section start. - * After having the offset of the first section, we have a loop - * over the section list. If the section exists, we read its - * length (2 bytes at section start) and add it to current - * offset to find the start of the next section. Otherwise, we - * already have the next section offset... - */ - const unsigned DRAM_FLAG = 1 << 6; - const FuThunderboltFwLocation available_sections_loc = { .offset = 0x2, .len = 1, .description = "sections" }; - const FuThunderboltFwLocation ee_ucode_start_addr_loc = { .offset = 0x3, .len = 2, .description = "ucode start" }; - - guint16 ucode_offset; - - g_autoptr(GByteArray) available_sections = - read_location (&available_sections_loc, fw, error); - if (available_sections == NULL) - return FALSE; - - if (!read_uint16 (&ee_ucode_start_addr_loc, fw, &ucode_offset, error)) - return FALSE; - offset = ucode_offset; - - if ((available_sections->data[0] & DRAM_FLAG) == 0) { - g_set_error_literal (error, - FWUPD_ERROR, FWUPD_ERROR_INVALID_FILE, - "Can't find needed FW sections in the FW image file"); - return FALSE; - } - - for (unsigned u = 1; u < DRAM_FLAG; u <<= 1) - if (u & available_sections->data[0]) { - if (!read_ucode_section_len (offset, fw, &ucode_offset, error)) - return FALSE; - offset += ucode_offset; - } - - fw->sections[DRAM_UCODE_SECTION] = offset + fw->sections[DIGITAL_SECTION]; - } - - return TRUE; -} - -static inline gboolean -missing_needed_drom (const FuThunderboltFwObject *fw, gboolean is_host, guint gen) -{ - if (fw->sections[DROM_SECTION] != 0) - return FALSE; - if (is_host && gen < 3) - return FALSE; - return TRUE; -} - -/* - * Controllers that can have 1 or 2 ports have additional locations to check in - * the 2 ports case. To make this as generic as possible, both sets are stored - * in the same array with an empty entry separating them. The 1 port case should - * stop comparing at the separator and the 2 ports case should continue - * iterating the array to compare the rest. - */ -static const FuThunderboltFwLocation * -get_host_locations (guint16 id) -{ - static const FuThunderboltFwLocation FR[] = { - { .offset = 0x10, .len = 4, .description = "PCIe Settings" }, - { .offset = 0x143, .len = 1, .description = "CIO-Port0_TX" }, - { .offset = 0x153, .len = 1, .description = "CIO-Port0_RX" }, - { .offset = 0x147, .len = 1, .description = "CIO-Port1_TX" }, - { .offset = 0x157, .len = 1, .description = "CIO-Port1_RX" }, - { .offset = 0x211, .len = 1, .description = "Snk0_0(DP-in)" }, - { .offset = 0x215, .len = 1, .description = "Snk0_1(DP-in)" }, - { .offset = 0x219, .len = 1, .description = "Snk0_2(DP-in)" }, - { .offset = 0x21D, .len = 1, .description = "Snk0_3(DP-in)" }, - { .offset = 0X2175, .len = 1, .description = "PA(DP-out)" }, - { .offset = 0X2179, .len = 1, .description = "PB(DP-out)" }, - { .offset = 0X217D, .len = 1, .description = "Src0(DP-out)", .mask = 0xAA }, - { 0 }, - - { .offset = 0x14B, .len = 1, .description = "CIO-Port2_TX" }, - { .offset = 0x15B, .len = 1, .description = "CIO-Port2_RX" }, - { .offset = 0x14F, .len = 1, .description = "CIO-Port3_TX" }, - { .offset = 0x15F, .len = 1, .description = "CIO-Port3_RX" }, - { .offset = 0X11C3, .len = 1, .description = "Snk1_0(DP-in)" }, - { .offset = 0X11C7, .len = 1, .description = "Snk1_1(DP-in)" }, - { .offset = 0X11CB, .len = 1, .description = "Snk1_2(DP-in)" }, - { .offset = 0X11CF, .len = 1, .description = "Snk1_3(DP-in)" }, - { 0 } - }; - - static const FuThunderboltFwLocation WR[] = { - { .offset = 0x10, .len = 4, .description = "PCIe Settings" }, - { .offset = 0x14F, .len = 1, .description = "CIO-Port0_TX" }, - { .offset = 0x157, .len = 1, .description = "CIO-Port0_RX" }, - { .offset = 0x153, .len = 1, .description = "CIO-Port1_TX" }, - { .offset = 0x15B, .len = 1, .description = "CIO-Port1_RX" }, - { .offset = 0x1F1, .len = 1, .description = "Snk0_0(DP-in)" }, - { .offset = 0x1F5, .len = 1, .description = "Snk0_1(DP-in)" }, - { .offset = 0x1F9, .len = 1, .description = "Snk0_2(DP-in)" }, - { .offset = 0x1FD, .len = 1, .description = "Snk0_3(DP-in)" }, - { .offset = 0X11A5, .len = 1, .description = "PA(DP-out)" }, - { 0 } - }; - - static const FuThunderboltFwLocation AR[] = { - { .offset = 0x10, .len = 4, .description = "PCIe Settings" }, - { .offset = 0x12, .len = 1, .description = "PA", .mask = 0xCC, .section = DRAM_UCODE_SECTION }, - { .offset = 0x121, .len = 1, .description = "Snk0" }, - { .offset = 0x129, .len = 1, .description = "Snk1" }, - { .offset = 0x136, .len = 1, .description = "Src0", .mask = 0xF0 }, - { .offset = 0xB6, .len = 1, .description = "PA/PB (USB2)", .mask = 0xC0 }, - { .offset = 0x45, .len = 1, .description = "Flash Size", .mask = 0x07 }, - { .offset = 0x7B, .len = 1, .description = "Native", .mask = 0x20 }, - { 0 }, - - { .offset = 0x13, .len = 1, .description = "PB", .mask = 0xCC, .section = DRAM_UCODE_SECTION }, - { 0 } - }; - - static const FuThunderboltFwLocation AR_LP[] = { - { .offset = 0x10, .len = 4, .description = "PCIe Settings" }, - { .offset = 0x12, .len = 1, .description = "PA", .mask = 0xCC, .section = DRAM_UCODE_SECTION }, - { .offset = 0x13, .len = 1, .description = "PB", .mask = 0x44, .section = DRAM_UCODE_SECTION }, - { .offset = 0x121, .len = 1, .description = "Snk0" }, - { .offset = 0xB6, .len = 1, .description = "PA/PB (USB2)", .mask = 0xC0 }, - { .offset = 0x45, .len = 1, .description = "Flash Size", .mask = 0x07 }, - { .offset = 0x7B, .len = 1, .description = "Native", .mask = 0x20 }, - { 0 } - }; - - static const FuThunderboltFwLocation TR[] = { - { .offset = 0x10, .len = 4, .description = "PCIe Settings" }, - { .offset = 0x12, .len = 1, .description = "PA", .mask = 0xCC, .section = DRAM_UCODE_SECTION }, - { .offset = 0x121, .len = 1, .description = "Snk0" }, - { .offset = 0x129, .len = 1, .description = "Snk1" }, - { .offset = 0x136, .len = 1, .description = "Src0", .mask = 0xF0 }, - { .offset = 0xB6, .len = 1, .description = "PA/PB (USB2)", .mask = 0xC0 }, - { .offset = 0x5E, .len = 1, .description = "Aux", .mask = 0x0F }, - { .offset = 0x45, .len = 1, .description = "Flash Size", .mask = 0x07 }, - { .offset = 0x7B, .len = 1, .description = "Native", .mask = 0x20 }, - { 0 }, - - { .offset = 0x13, .len = 1, .description = "PB", .mask = 0xCC, .section = DRAM_UCODE_SECTION }, - { .offset = 0x5E, .len = 1, .description = "Aux (PB)", .mask = 0x10 }, - { 0 } - }; - - switch (id) { - case 0x156D: - case 0x156B: - return FR; - case 0x157E: - return WR; - case 0x1578: - case 0x1576: - case 0x15D3: - case 0x15DA: - return AR; - case 0x15C0: - return AR_LP; - case 0x15E7: - case 0x15EA: - return TR; - default: - return NULL; - } -} - -/* - * Finds optional multi controller (MC) entry from controller DROM. - * Returns TRUE if the controller did not have MC entry or the - * controller and image MC entries match. In any other case FALSE is - * returned and error is set accordingly. - */ -static gboolean -compare_device_mc (const FuThunderboltFwObject *controller, - const FuThunderboltFwObject *image, - GError **error) -{ - FuThunderboltFwLocation image_mc_loc = { .section = DROM_SECTION, .description = "Multi Controller" }; - FuThunderboltFwLocation controller_mc_loc = image_mc_loc; - g_autoptr(GByteArray) controller_mc = NULL; - g_autoptr(GByteArray) image_mc = NULL; - - if (!read_drom_entry_location (controller, DROM_ENTRY_MC, - &controller_mc_loc, error)) - return FALSE; - - /* it is fine if the controller does not have MC entry */ - if (controller_mc_loc.offset == 0) - return TRUE; - - if (!read_drom_entry_location (image, DROM_ENTRY_MC, &image_mc_loc, error)) - return FALSE; - - if (image_mc_loc.offset == 0) { - g_set_error_literal (error, - FWUPD_ERROR, FWUPD_ERROR_INVALID_FILE, - "firmware does not have multi controller entry"); - return FALSE; - } - if (controller_mc_loc.len != image_mc_loc.len) { - g_set_error_literal (error, - FWUPD_ERROR, FWUPD_ERROR_INVALID_FILE, - "firmware multi controller entry length mismatch"); - return FALSE; - } - - controller_mc = read_location (&controller_mc_loc, controller, error); - if (controller_mc == NULL) - return FALSE; - image_mc = read_location (&image_mc_loc, image, error); - if (image_mc == NULL) - return FALSE; - - if (memcmp (controller_mc->data, image_mc->data, controller_mc->len) != 0) { - g_set_error_literal (error, - FWUPD_ERROR, FWUPD_ERROR_INVALID_FILE, - "firmware multi controller entry mismatch"); - return FALSE; - } - - return TRUE; -} - -static const FuThunderboltFwLocation * -get_device_locations (guint16 id, const FuThunderboltFwObject *controller, - const FuThunderboltFwObject *image, GError **error) -{ - static const FuThunderboltFwLocation AR[] = { - { .offset = 0x45, .len = 1, .description = "Flash Size", .mask = 0x07 }, - { .offset = 0x124, .len = 1, .section = ARC_PARAMS_SECTION, .description = "X of N" }, - { 0 } - }; - - static const FuThunderboltFwLocation TR[] = { - { .offset = 0x45, .len = 1, .description = "Flash Size", .mask = 0x07 }, - { 0 } - }; - - switch (id) { - case 0x1578: - case 0x1576: - case 0x15D3: - case 0x15DA: - case 0x15C0: - return AR; - case 0x15E7: - case 0x15EA: - case 0x15EF: - /* if the controller has multi controller entry need to - * compare it against the image first. */ - if (!compare_device_mc (controller, image, error)) - return NULL; - return TR; - default: - return NULL; - } -} - -/* - * Compares the given locations, assuming locations is an array. - * Returns FALSE and sets error upon failure. - * locations points to the end of the array (the empty entry) upon - * successful return. - */ -static gboolean -compare_locations (const FuThunderboltFwLocation **locations, - const FuThunderboltFwObject *controller, - const FuThunderboltFwObject *image, - GError **error) -{ - gboolean result; - do { - if (!compare (*locations, controller, image, &result, error)) - return FALSE; - if (!result) { - g_set_error (error, - FWUPD_ERROR, FWUPD_ERROR_INVALID_FILE, - "FW image image not compatible to this controller (%s)", - (*locations)->description); - return FALSE; - } - } while ((++(*locations))->offset != 0); - return TRUE; -} - -static gboolean -compare_pd_existence (guint16 id, - const FuThunderboltFwObject *controller, - const FuThunderboltFwObject *image, - GError **error) -{ - const FuThunderboltFwLocation pd_pointer_loc = { .offset = 0x10C, .len = 4, .section = ARC_PARAMS_SECTION, .description = "PD pointer" }; - gboolean controller_has_pd; - gboolean image_has_pd; - guint32 pd_pointer; - - if (controller->sections[ARC_PARAMS_SECTION] == 0) - return TRUE; - - if (!read_uint32 (&pd_pointer_loc, controller, &pd_pointer, error)) - return FALSE; - controller_has_pd = valid_pd_pointer (pd_pointer); - - if (!read_uint32 (&pd_pointer_loc, image, &pd_pointer, error)) - return FALSE; - image_has_pd = valid_pd_pointer (pd_pointer); - - if (controller_has_pd != image_has_pd) { - g_set_error_literal (error, FWUPD_ERROR, FWUPD_ERROR_INVALID_FILE, - "PD section mismatch"); - return FALSE; - } - - return TRUE; -} - -FuPluginValidation -fu_thunderbolt_image_validate (GBytes *controller_fw, - GBytes *blob_fw, - GError **error) -{ - gboolean is_host; - guint16 device_id; - gboolean compare_result; - const FuThunderboltHwInfo *hw_info; - const FuThunderboltHwInfo unknown = { 0 }; - const FuThunderboltFwLocation *locations; - - gsize fw_size; - const guint8 *fw_data = g_bytes_get_data (controller_fw, &fw_size); - - gsize blob_size; - const guint8 *blob_data = g_bytes_get_data (blob_fw, &blob_size); - - guint32 controller_sections[SECTION_COUNT] = { [DIGITAL_SECTION] = 0 }; - guint32 image_sections [SECTION_COUNT] = { 0 }; - - const FuThunderboltFwObject controller = { fw_data, fw_size, controller_sections }; - const FuThunderboltFwObject image = { blob_data, blob_size, image_sections }; - - const FuThunderboltFwLocation is_host_loc = { .offset = 0x10, .len = 1, .mask = 1 << 1, .description = "host flag" }; - const FuThunderboltFwLocation device_id_loc = { .offset = 0x5, .len = 2, .description = "devID" }; - - image_sections[DIGITAL_SECTION] = read_farb_pointer (&image, error); - if (image_sections[DIGITAL_SECTION] == 0) - return VALIDATION_FAILED; - - if (!read_bool (&is_host_loc, &controller, &is_host, error)) - return VALIDATION_FAILED; - - if (!read_uint16 (&device_id_loc, &controller, &device_id, error)) - return VALIDATION_FAILED; - - hw_info = get_hw_info (device_id); - if (hw_info == NULL) { - if (is_host) { - g_set_error (error, - FWUPD_ERROR, FWUPD_ERROR_NOT_SUPPORTED, - "Unknown controller"); - return VALIDATION_FAILED; - } - hw_info = &unknown; - } - - if (!compare (&is_host_loc, &controller, &image, &compare_result, error)) - return VALIDATION_FAILED; - if (!compare_result) { - g_set_error (error, - FWUPD_ERROR, FWUPD_ERROR_INVALID_FILE, - "The FW image file is for a %s controller", - is_host ? "device" : "host"); - return VALIDATION_FAILED; - } - - if (!compare (&device_id_loc, &controller, &image, &compare_result, error)) - return VALIDATION_FAILED; - if (!compare_result) { - g_set_error_literal (error, - FWUPD_ERROR, FWUPD_ERROR_INVALID_FILE, - "The FW image file is for a different HW type"); - return VALIDATION_FAILED; - } - - if (!read_sections (&controller, is_host, hw_info->gen, error)) - return VALIDATION_FAILED; - if (missing_needed_drom (&controller, is_host, hw_info->gen)) { - g_set_error_literal (error, - FWUPD_ERROR, FWUPD_ERROR_READ, - "Can't find needed FW sections in the controller"); - return VALIDATION_FAILED; - } - - if (!read_sections (&image, is_host, hw_info->gen, error)) - return VALIDATION_FAILED; - if (missing_needed_drom (&image, is_host, hw_info->gen)) { - g_set_error_literal (error, - FWUPD_ERROR, FWUPD_ERROR_INVALID_FILE, - "Can't find needed FW sections in the FW image file"); - return VALIDATION_FAILED; - } - - if (controller.sections[DROM_SECTION] != 0) { - const FuThunderboltFwLocation drom_locations[] = { - { .offset = 0x10, .len = 2, .section = DROM_SECTION, .description = "vendor ID" }, - { .offset = 0x12, .len = 2, .section = DROM_SECTION, .description = "model ID" }, - { 0 } - }; - locations = drom_locations; - if (!compare_locations (&locations, &controller, &image, error)) - return VALIDATION_FAILED; - } - - if (!compare_pd_existence (hw_info->id, &controller, &image, error)) - return VALIDATION_FAILED; - - /* - * 0 is for the unknown device case, for being future-compatible with - * new devices; so we can't know which locations to check besides the - * vendor and model IDs that were validated already, but those should be - * good enough validation. - */ - if (hw_info->id == 0) - return UNKNOWN_DEVICE; - - if (is_host) { - locations = get_host_locations (hw_info->id); - if (locations == NULL) { - g_set_error_literal (error, - FWUPD_ERROR, FWUPD_ERROR_NOT_SUPPORTED, - "FW locations to check not found for this controller"); - return VALIDATION_FAILED; - } - } else { - locations = get_device_locations (hw_info->id, &controller, - &image, error); - if (locations == NULL) { - /* error is set already by the above */ - return VALIDATION_FAILED; - } - } - - if (!compare_locations (&locations, &controller, &image, error)) - return VALIDATION_FAILED; - - if (is_host && hw_info->ports == 2) { - locations++; - if (!compare_locations (&locations, &controller, &image, error)) - return VALIDATION_FAILED; - } - - return VALIDATION_PASSED; -} - -gboolean -fu_thunderbolt_image_controller_is_native (GBytes *controller_fw, - gboolean *is_native, - GError **error) -{ - guint32 controller_sections[SECTION_COUNT] = { [DIGITAL_SECTION] = 0 }; - gsize fw_size; - const guint8 *fw_data = g_bytes_get_data (controller_fw, &fw_size); - const FuThunderboltFwObject controller = { fw_data, fw_size, controller_sections }; - const FuThunderboltFwLocation location = { - .offset = FU_TBT_OFFSET_NATIVE, - .len = 1, - .description = "Native", - .mask = 0x20 }; - return read_bool (&location, &controller, is_native, error); -} diff --git a/plugins/thunderbolt/fu-thunderbolt-image.h b/plugins/thunderbolt/fu-thunderbolt-image.h deleted file mode 100644 index c9b25a02e..000000000 --- a/plugins/thunderbolt/fu-thunderbolt-image.h +++ /dev/null @@ -1,27 +0,0 @@ -/* - * Copyright (C) 2017 Intel Corporation. - * - * SPDX-License-Identifier: LGPL-2.1+ - */ - -#pragma once - -#include - -typedef enum { - VALIDATION_PASSED, - VALIDATION_FAILED, - UNKNOWN_DEVICE, -} FuPluginValidation; - -/* byte offsets in firmware image */ -#define FU_TBT_OFFSET_NATIVE 0x7B -#define FU_TBT_CHUNK_SZ 0x40 - -FuPluginValidation fu_thunderbolt_image_validate (GBytes *controller_fw, - GBytes *blob_fw, - GError **error); - -gboolean fu_thunderbolt_image_controller_is_native (GBytes *controller_fw, - gboolean *is_native, - GError **error); diff --git a/plugins/thunderbolt/fu-thunderbolt-tool.c b/plugins/thunderbolt/fu-thunderbolt-tool.c deleted file mode 100644 index 419ba5f7c..000000000 --- a/plugins/thunderbolt/fu-thunderbolt-tool.c +++ /dev/null @@ -1,91 +0,0 @@ -/* - * Copyright (C) 2017 Intel Corporation. - * - * SPDX-License-Identifier: LGPL-2.1+ - */ - -#include "config.h" - -#include -#include - -#include "fu-thunderbolt-image.h" -#include "fu-plugin-vfuncs.h" -#include "fu-hash.h" - -static gsize -read_farb_pointer (gchar *image) -{ - gsize ret = 0; - memcpy (&ret, image, 3); - ret = GSIZE_FROM_LE (ret); - if (ret != 0 && ret != 0xFFFFFF) - return ret; - ret = 0; - memcpy (&ret, image + 0x1000, 3); - ret = GSIZE_FROM_LE (ret); - g_assert (ret != 0 && ret != 0xFFFFFF); - return ret; -} - -int -main (int argc, char **argv) -{ - g_autoptr(GError) error = NULL; - g_autoptr(GFile) fw_file = NULL; - gboolean ok; - gsize len; - gchar *data = NULL; - g_autoptr(GBytes) image = NULL; - g_autoptr(GBytes) controller = NULL; - FuPluginValidation validation; - - if (argc < 2 || argc > 3) { - g_print ("Usage: %s []\n", argv[0]); - g_print ("Runs image validation on 'filename', comparing it to itself\n" - "after removing the headers or to 'controller' if given\n"); - return 1; - } - - fw_file = g_file_new_for_path (argv[1]); - g_assert_nonnull (fw_file); - - ok = g_file_load_contents (fw_file, NULL, &data, &len, NULL, &error); - g_assert_no_error (error); - g_assert_true (ok); - - image = g_bytes_new_take (data, len); - - if (argc == 2) { - gssize header_size = read_farb_pointer (data); - g_assert_cmpuint (header_size, !=, 0); - g_assert_cmpuint (header_size, <, len); - - controller = g_bytes_new_from_bytes (image, header_size, len - header_size); - } else { - g_autoptr(GFile) controller_file = NULL; - gsize controller_len; - gchar *controller_data = NULL; - - controller_file = g_file_new_for_path (argv[2]); - g_assert_nonnull (controller_file); - - ok = g_file_load_contents (controller_file, - NULL, - &controller_data, - &controller_len, - NULL, - &error); - g_assert_no_error (error); - g_assert_true (ok); - - controller = g_bytes_new_take (controller_data, controller_len); - } - - validation = fu_thunderbolt_image_validate (controller, image, &error); - g_assert_no_error (error); - g_assert_cmpint (validation, ==, VALIDATION_PASSED); - - g_print ("test passed\n"); - return 0; -} diff --git a/plugins/thunderbolt/meson.build b/plugins/thunderbolt/meson.build index 06ab34eec..6a805d11b 100644 --- a/plugins/thunderbolt/meson.build +++ b/plugins/thunderbolt/meson.build @@ -1,10 +1,16 @@ cargs = ['-DG_LOG_DOMAIN="FuPluginThunderbolt"'] - +cargs += '-DTESTDATADIR="' + join_paths(meson.source_root(), 'data', 'tests') + '"' +install_data([ + 'thunderbolt.quirk', + ], + install_dir: join_paths(datadir, 'fwupd', 'quirks.d') +) fu_plugin_thunderbolt = shared_module('fu_plugin_thunderbolt', fu_hash, sources : [ 'fu-plugin-thunderbolt.c', - 'fu-thunderbolt-image.c', + 'fu-thunderbolt-device.c', + 'fu-thunderbolt-firmware.c', ], include_directories : [ root_incdir, @@ -23,28 +29,6 @@ fu_plugin_thunderbolt = shared_module('fu_plugin_thunderbolt', ], ) -cargs += '-DTESTDATADIR="' + join_paths(meson.source_root(), 'data', 'tests') + '"' -executable('tbtfwucli', - fu_hash, - sources : [ - 'fu-thunderbolt-tool.c', - ], - include_directories : [ - root_incdir, - fwupd_incdir, - fwupdplugin_incdir, - ], - c_args : cargs, - link_with : [ - fu_plugin_thunderbolt, - fwupd, - fwupdplugin, - ], - dependencies : [ - plugin_deps, - ], -) - install_data(['thunderbolt.conf'], install_dir: join_paths(sysconfdir, 'fwupd') ) @@ -57,7 +41,8 @@ if get_option('tests') and umockdev.found() and gio.version().version_compare('> sources : [ 'fu-self-test.c', 'fu-plugin-thunderbolt.c', - 'fu-thunderbolt-image.c', + 'fu-thunderbolt-device.c', + 'fu-thunderbolt-firmware.c', ], include_directories : [ root_incdir, @@ -65,6 +50,7 @@ if get_option('tests') and umockdev.found() and gio.version().version_compare('> fwupdplugin_incdir, ], dependencies : [ + gudev, plugin_deps, umockdev, ], diff --git a/plugins/thunderbolt/thunderbolt.quirk b/plugins/thunderbolt/thunderbolt.quirk new file mode 100644 index 000000000..3bc3be565 --- /dev/null +++ b/plugins/thunderbolt/thunderbolt.quirk @@ -0,0 +1,3 @@ +# match all devices with this udev subsystem +[DeviceInstanceId=THUNDERBOLT] +Plugin = thunderbolt From 6358e23490acde05f1ca65c714d141bb8f6497ae Mon Sep 17 00:00:00 2001 From: Mario Limonciello Date: Wed, 29 Apr 2020 00:12:15 -0500 Subject: [PATCH 013/607] thunderbolt: drop support for force power The kernel interface for force power doesn't support tracking the state of the device, and so this had to be tracked by fwupd. Unfortunately due to system and thunderbolt controller firmware behavior on some systems the thunderbolt controller /still/ didn't return even when force power state was accurately tracked. The device model for the uevent related to the device removal being ignored doesn't really fit into the current fwupd architecture anymore either. Lastly this is a very legacy feature at this point. Thunderbolt3 controllers distributed in the last 3 years all operate in 'native' mode meaning that they will always be powered and use runtime power management. USB4 controllers won't have a concept of being force powered. USB4 reimers will have this concept, but the state will be tracked by the kernel and obfuscated from userspace. So with all that said, tear out all of the force power related code. --- contrib/fwupd.spec.in | 1 - libfwupdplugin/fu-device-metadata.h | 7 - plugins/meson.build | 1 - .../fu-plugin-thunderbolt-power.c | 463 ------------------ plugins/thunderbolt-power/meson.build | 23 - plugins/thunderbolt/fu-thunderbolt-device.c | 15 - 6 files changed, 510 deletions(-) delete mode 100644 plugins/thunderbolt-power/fu-plugin-thunderbolt-power.c delete mode 100644 plugins/thunderbolt-power/meson.build diff --git a/contrib/fwupd.spec.in b/contrib/fwupd.spec.in index 63e85f472..22940d918 100644 --- a/contrib/fwupd.spec.in +++ b/contrib/fwupd.spec.in @@ -375,7 +375,6 @@ mkdir -p --mode=0700 $RPM_BUILD_ROOT%{_localstatedir}/lib/fwupd/gnupg %endif %{_libdir}/fwupd-plugins-3/libfu_plugin_thelio_io.so %{_libdir}/fwupd-plugins-3/libfu_plugin_thunderbolt.so -%{_libdir}/fwupd-plugins-3/libfu_plugin_thunderbolt_power.so %if 0%{?have_uefi} %{_libdir}/fwupd-plugins-3/libfu_plugin_tpm.so %{_libdir}/fwupd-plugins-3/libfu_plugin_tpm_eventlog.so diff --git a/libfwupdplugin/fu-device-metadata.h b/libfwupdplugin/fu-device-metadata.h index d81b5301f..86318f78a 100644 --- a/libfwupdplugin/fu-device-metadata.h +++ b/libfwupdplugin/fu-device-metadata.h @@ -18,13 +18,6 @@ * See also: #FuDevice */ -/** - * FU_DEVICE_METADATA_TBT_CAN_FORCE_POWER: - * - * If the system can force-enable the Thunderbolt controller. - * Consumed by the thunderbolt plugin. - */ -#define FU_DEVICE_METADATA_TBT_CAN_FORCE_POWER "Thunderbolt::CanForcePower" /** * FU_DEVICE_METADATA_TBT_IS_SAFE_MODE: diff --git a/plugins/meson.build b/plugins/meson.build index cb3649b28..72de5661f 100644 --- a/plugins/meson.build +++ b/plugins/meson.build @@ -79,7 +79,6 @@ if not get_option('gudev') error('gudev is required for plugin_thunderbolt') endif subdir('thunderbolt') -subdir('thunderbolt-power') endif if get_option('plugin_redfish') diff --git a/plugins/thunderbolt-power/fu-plugin-thunderbolt-power.c b/plugins/thunderbolt-power/fu-plugin-thunderbolt-power.c deleted file mode 100644 index 63b038cc0..000000000 --- a/plugins/thunderbolt-power/fu-plugin-thunderbolt-power.c +++ /dev/null @@ -1,463 +0,0 @@ -/* - * Copyright (C) 2017 Dell, Inc. - * - * SPDX-License-Identifier: LGPL-2.1+ - */ - -#include "config.h" - -#include -#include -#include -#include - -#include "fu-plugin-vfuncs.h" -#include "fu-hash.h" -#include "fu-device-metadata.h" - -#define BOLT_DBUS_SERVICE "org.freedesktop.bolt" -#define BOLT_DBUS_PATH "/org/freedesktop/bolt" -#define BOLT_DBUS_INTERFACE "org.freedesktop.bolt1.Power" - -/* empirically measured amount of time for the TBT device to come and go */ -#define TBT_NEW_DEVICE_TIMEOUT 2 /* s */ - -struct FuPluginData { - GUdevClient *udev; - gchar *force_path; - gboolean needs_forcepower; - gboolean updating; - guint timeout_id; - gint bolt_fd; -}; - -static gboolean -fu_plugin_thunderbolt_power_bolt_supported (FuPlugin *plugin) -{ - g_autoptr(GDBusConnection) connection = NULL; - g_autoptr(GVariant) val = NULL; - g_autoptr(GDBusProxy) proxy = NULL; - g_autoptr(GError) error_local = NULL; - gboolean supported = FALSE; - - connection = g_bus_get_sync (G_BUS_TYPE_SYSTEM, NULL, &error_local); - if (connection == NULL) { - g_warning ("Failed to initialize d-bus connection: %s", - error_local->message); - return supported; - } - - proxy = g_dbus_proxy_new_sync (connection, - G_DBUS_PROXY_FLAGS_NONE, - NULL, - BOLT_DBUS_SERVICE, - BOLT_DBUS_PATH, - BOLT_DBUS_INTERFACE, - NULL, - &error_local); - if (proxy == NULL) { - g_warning ("Failed to initialize d-bus proxy: %s", - error_local->message); - return supported; - } - val = g_dbus_proxy_get_cached_property (proxy, "Supported"); - if (val != NULL) - g_variant_get (val, "b", &supported); - - g_debug ("Bolt force power support: %d", supported); - - return supported; -} - -static gboolean -fu_plugin_thunderbolt_power_bolt_force_power (FuPlugin *plugin, - GError **error) -{ - FuPluginData *data = fu_plugin_get_data (plugin); - g_autoptr(GDBusConnection) connection = NULL; - g_autoptr(GDBusProxy) proxy = NULL; - g_autoptr(GUnixFDList) fds = NULL; - g_autoptr(GVariant) val = NULL; - GVariant *input; - - input = g_variant_new ("(ss)", - "fwupd", /* who */ - ""); /* flags */ - - connection = g_bus_get_sync (G_BUS_TYPE_SYSTEM, NULL, error); - if (connection == NULL) - return FALSE; - - proxy = g_dbus_proxy_new_sync (connection, - G_DBUS_PROXY_FLAGS_NONE, - NULL, - BOLT_DBUS_SERVICE, - BOLT_DBUS_PATH, - BOLT_DBUS_INTERFACE, - NULL, - error); - if (proxy == NULL) - return FALSE; - - val = g_dbus_proxy_call_with_unix_fd_list_sync (proxy, - "ForcePower", - input, - G_DBUS_CALL_FLAGS_NONE, - -1, - NULL, - &fds, - NULL, - error); - - if (val == NULL) - return FALSE; - - if (g_unix_fd_list_get_length (fds) != 1) { - g_set_error (error, G_IO_ERROR, G_IO_ERROR_INVALID_ARGUMENT, - "invalid number of file descriptors returned: %d", - g_unix_fd_list_get_length (fds)); - return FALSE; - } - data->bolt_fd = g_unix_fd_list_get (fds, 0, NULL); - - return TRUE; -} - -static void -fu_plugin_thunderbolt_power_get_kernel_path (FuPlugin *plugin) -{ - FuPluginData *data = fu_plugin_get_data (plugin); - g_autoptr(GList) devices = NULL; - const gchar *basepath; - const gchar *driver; - - /* in case driver went away */ - if (data->force_path != NULL) { - g_free (data->force_path); - data->force_path = NULL; - } - - devices = g_udev_client_query_by_subsystem (data->udev, "wmi"); - for (GList* l = devices; l != NULL; l = l->next) { - g_autofree gchar *built_path = NULL; - GUdevDevice *device = l->data; - - /* only supports intel-wmi-thunderbolt for now */ - driver = g_udev_device_get_driver (device); - if (g_strcmp0 (driver, "intel-wmi-thunderbolt") != 0) - continue; - - /* check for the attribute to be loaded */ - basepath = g_udev_device_get_sysfs_path (device); - if (basepath == NULL) - continue; - built_path = g_build_path ("/", basepath, - "force_power", NULL); - if (g_file_test (built_path, G_FILE_TEST_IS_REGULAR)) { - data->force_path = g_steal_pointer (&built_path); - g_debug ("Direct kernel force power support at %s", - data->force_path); - break; - } - } - g_list_foreach (devices, (GFunc) g_object_unref, NULL); -} - -static gboolean -fu_plugin_thunderbolt_power_kernel_supported (FuPlugin *plugin) -{ - FuPluginData *data = fu_plugin_get_data (plugin); - return data->force_path != NULL; -} - -static gboolean -fu_plugin_thunderbolt_power_kernel_force_power (FuPlugin *plugin, gboolean enable, - GError **error) -{ - FuPluginData *data = fu_plugin_get_data (plugin); - gint fd; - gint ret; - - if (!fu_plugin_thunderbolt_power_kernel_supported (plugin)) { - g_set_error (error, - FWUPD_ERROR, - FWUPD_ERROR_NOT_SUPPORTED, - "unable to set power to %d (missing kernel support)", - enable); - return FALSE; - } - g_debug ("Setting force power to %d using kernel", enable); - fd = g_open (data->force_path, O_WRONLY, 0); - if (fd == -1) { - g_set_error (error, - FWUPD_ERROR, - FWUPD_ERROR_INTERNAL, - "failed to open %s", data->force_path); - return FALSE; - } - ret = write (fd, enable ? "1" : "0", 1); - if (ret < 1) { - g_set_error (error, G_IO_ERROR, - g_io_error_from_errno (errno), - "could not write to force_power': %s", - g_strerror (errno)); - g_close (fd, NULL); - return FALSE; - } - - return g_close (fd, error); -} - -static gboolean -fu_plugin_thunderbolt_power_set (FuPlugin *plugin, gboolean enable, - GError **error) -{ - FuPluginData *data = fu_plugin_get_data (plugin); - - /* prefer bolt API if available */ - if (fu_plugin_thunderbolt_power_bolt_supported (plugin)) { - g_debug ("Setting force power to %d using bolt", enable); - if (enable) - return fu_plugin_thunderbolt_power_bolt_force_power (plugin, error); - return data->bolt_fd >= 0 ? g_close (data->bolt_fd, error) : TRUE; - } - - return fu_plugin_thunderbolt_power_kernel_force_power (plugin, enable, error); -} - -static gboolean -fu_plugin_thunderbolt_power_reset_cb (gpointer user_data) -{ - FuPlugin *plugin = FU_PLUGIN (user_data); - FuPluginData *data = fu_plugin_get_data (plugin); - - if (!fu_plugin_thunderbolt_power_set (plugin, FALSE, NULL)) - g_warning ("failed to reset thunderbolt power"); - data->timeout_id = 0; - return FALSE; -} - -static void -fu_plugin_thunderbolt_reset_timeout (FuPlugin *plugin) -{ - FuPluginData *data = fu_plugin_get_data (plugin); - - if (!data->needs_forcepower || data->updating) - return; - - g_debug ("Setting timeout to %d seconds", - TBT_NEW_DEVICE_TIMEOUT * 10); - - /* in case this was a re-coldplug */ - if (data->timeout_id != 0) - g_source_remove (data->timeout_id); - - /* reset force power to off after enough time to enumerate */ - data->timeout_id = - g_timeout_add (TBT_NEW_DEVICE_TIMEOUT * 10000, - fu_plugin_thunderbolt_power_reset_cb, - plugin); -} - -static gboolean -udev_uevent_cb (GUdevClient *udev, - const gchar *action, - GUdevDevice *device, - gpointer user_data) -{ - FuPlugin *plugin = FU_PLUGIN(user_data); - - if (action == NULL) - return TRUE; - - g_debug ("uevent for %s: (%s) %s", - g_udev_device_get_name (device), - g_udev_device_get_sysfs_path (device), - action); - - /* thunderbolt device was turned on */ - if (g_str_equal (g_udev_device_get_subsystem (device), "thunderbolt") && - g_str_equal (action, "add")) { - fu_plugin_thunderbolt_reset_timeout (plugin); - /* intel-wmi-thunderbolt has been loaded/unloaded */ - } else if (g_str_equal (action, "change")) { - fu_plugin_thunderbolt_power_get_kernel_path (plugin); - if (fu_plugin_thunderbolt_power_kernel_supported (plugin)) { - fu_plugin_set_enabled (plugin, TRUE); - fu_plugin_request_recoldplug (plugin); - } else { - fu_plugin_set_enabled (plugin, FALSE); - } - } - - return TRUE; -} - -/* virtual functions */ - -void -fu_plugin_init (FuPlugin *plugin) -{ - FuPluginData *data = fu_plugin_alloc_data (plugin, sizeof (FuPluginData)); - const gchar *subsystems[] = { "thunderbolt", "wmi", NULL }; - - data->udev = g_udev_client_new (subsystems); - g_signal_connect (data->udev, "uevent", - G_CALLBACK (udev_uevent_cb), plugin); - /* initially set to true, will wait for a device_register to reset */ - data->needs_forcepower = TRUE; - /* will reset when needed */ - data->bolt_fd = -1; - - /* determines whether to run device_registered */ - fu_plugin_thunderbolt_power_get_kernel_path (plugin); - - /* make sure it's tried to coldplug */ - fu_plugin_add_rule (plugin, FU_PLUGIN_RULE_RUN_AFTER, "thunderbolt"); - fu_plugin_set_build_hash (plugin, FU_BUILD_HASH); -} - -void -fu_plugin_destroy (FuPlugin *plugin) -{ - FuPluginData *data = fu_plugin_get_data (plugin); - if (data->timeout_id != 0) { - g_source_remove (data->timeout_id); - data->timeout_id = 0; - } - g_object_unref (data->udev); - g_free (data->force_path); - /* in case destroying before force power turned off */ - if (data->bolt_fd >= 0) - g_close (data->bolt_fd, NULL); -} - -void -fu_plugin_device_registered (FuPlugin *plugin, FuDevice *device) -{ - FuPluginData *data = fu_plugin_get_data (plugin); - - /* We care only about the thunderbolt devices. NB: we don't care - * about avoiding to auto-starting boltd here, because if there - * is thunderbolt hardware present, boltd is already running */ - if (g_strcmp0 (fu_device_get_plugin (device), "thunderbolt") == 0 && - (fu_plugin_thunderbolt_power_bolt_supported (plugin) || - fu_plugin_thunderbolt_power_kernel_supported (plugin))) { - data->needs_forcepower = FALSE; - if (fu_device_has_flag (device, FWUPD_DEVICE_FLAG_INTERNAL)) { - fu_device_set_metadata_boolean (device, - FU_DEVICE_METADATA_TBT_CAN_FORCE_POWER, - TRUE); - } - } -} - -gboolean -fu_plugin_update_prepare (FuPlugin *plugin, - FwupdInstallFlags flags, - FuDevice *device, - GError **error) -{ - FuPluginData *data = fu_plugin_get_data (plugin); - g_autoptr(GUdevDevice) udevice = NULL; - const gchar *devpath; - - /* only run for thunderbolt plugin */ - if (g_strcmp0 (fu_device_get_plugin (device), "thunderbolt") != 0) - return TRUE; - - /* reset any timers that might still be running from coldplug */ - if (data->timeout_id != 0) { - g_source_remove (data->timeout_id); - data->timeout_id = 0; - } - - devpath = fu_device_get_metadata (device, "sysfs-path"); - - udevice = g_udev_client_query_by_sysfs_path (data->udev, devpath); - if (udevice != NULL) { - data->needs_forcepower = FALSE; - return TRUE; - } - data->updating = TRUE; - if (!fu_plugin_thunderbolt_power_set (plugin, TRUE, error)) - return FALSE; - - data->needs_forcepower = TRUE; - - /* wait for the device to come back onto the bus */ - fu_device_set_status (device, FWUPD_STATUS_DEVICE_RESTART); - for (guint i = 0; i < 5; i++) { - g_autoptr(GUdevDevice) udevice_tmp = NULL; - g_usleep (TBT_NEW_DEVICE_TIMEOUT * G_USEC_PER_SEC); - udevice_tmp = g_udev_client_query_by_sysfs_path (data->udev, devpath); - if (udevice_tmp != NULL) - return TRUE; - } - - /* device did not wake up */ - g_set_error (error, - FWUPD_ERROR, - FWUPD_ERROR_NOT_SUPPORTED, - "device did not wake up when required"); - return FALSE; -} - -gboolean -fu_plugin_update_cleanup (FuPlugin *plugin, - FwupdInstallFlags flags, - FuDevice *device, - GError **error) -{ - FuPluginData *data = fu_plugin_get_data (plugin); - - /* only run for thunderbolt plugin */ - if (g_strcmp0 (fu_device_get_plugin (device), "thunderbolt") != 0) - return TRUE; - - data->updating = FALSE; - if (data->needs_forcepower && - !fu_plugin_thunderbolt_power_set (plugin, FALSE, error)) - return FALSE; - return TRUE; -} - -static gboolean -fu_plugin_thunderbolt_power_coldplug (FuPlugin *plugin, GError **error) -{ - FuPluginData *data = fu_plugin_get_data (plugin); - - /* NB: we don't check for force-power support via bolt here - * (although we later prefer that), because boltd uses the - * same kernel interface and if that does not exist, we can - * avoid pinging bolt, potentially auto-starting it. */ - if (!fu_plugin_thunderbolt_power_kernel_supported (plugin)) { - g_set_error (error, - FWUPD_ERROR, - FWUPD_ERROR_NOT_SUPPORTED, - "No support for force power detected"); - return FALSE; - } - - /* this means no devices were found at coldplug by thunderbolt plugin */ - if (data->needs_forcepower) { - if (!fu_plugin_thunderbolt_power_set (plugin, TRUE, error)) - return FALSE; - - fu_plugin_thunderbolt_reset_timeout (plugin); - } - - return TRUE; -} - -gboolean -fu_plugin_coldplug (FuPlugin *plugin, GError **error) -{ - return fu_plugin_thunderbolt_power_coldplug (plugin, error); -} - -gboolean -fu_plugin_recoldplug (FuPlugin *plugin, GError **error) -{ - return fu_plugin_thunderbolt_power_coldplug (plugin, error); -} diff --git a/plugins/thunderbolt-power/meson.build b/plugins/thunderbolt-power/meson.build deleted file mode 100644 index bc0516f6e..000000000 --- a/plugins/thunderbolt-power/meson.build +++ /dev/null @@ -1,23 +0,0 @@ -cargs = ['-DG_LOG_DOMAIN="FuPluginThunderbolt"'] - -fu_plugin_thunderbolt_power = shared_module('fu_plugin_thunderbolt_power', - fu_hash, - sources : [ - 'fu-plugin-thunderbolt-power.c', - ], - include_directories : [ - root_incdir, - fwupd_incdir, - fwupdplugin_incdir, - ], - install : true, - install_dir: plugin_dir, - link_with : [ - fwupd, - fwupdplugin, - ], - c_args : cargs, - dependencies : [ - plugin_deps, - ], -) diff --git a/plugins/thunderbolt/fu-thunderbolt-device.c b/plugins/thunderbolt/fu-thunderbolt-device.c index 64f4627aa..fefd4fa84 100644 --- a/plugins/thunderbolt/fu-thunderbolt-device.c +++ b/plugins/thunderbolt/fu-thunderbolt-device.c @@ -240,21 +240,6 @@ fu_thunderbolt_device_setup (FuDevice *device, GError **error) self->devpath = g_strdup (fu_udev_device_get_sysfs_path (FU_UDEV_DEVICE (device))); fu_device_set_metadata (device, "sysfs-path", self->devpath); -/* TODO: - force power handling from old plugin on remove - on supported systems other plugins may use a GPIO to force - power on supported devices even when in low power mode -- - this will happen in coldplug_prepare and prepare_for_update - if (fu_thunderbolt_device_is_host (device) && - !fu_device_has_flag (dev, FWUPD_DEVICE_FLAG_WAIT_FOR_REPLUG) && - fu_device_get_metadata_boolean (dev, FU_DEVICE_METADATA_TBT_CAN_FORCE_POWER)) { - g_debug ("ignoring remove event as force powered"); - return; - } - - fu_plugin_device_remove (plugin, dev); -*/ - /* these may be missing on ICL or later */ vid = fu_udev_device_get_vendor (FU_UDEV_DEVICE (self)); if (vid == 0x0) From 16a96fbbe750f539479b43dcccfa89fd210eff20 Mon Sep 17 00:00:00 2001 From: Mario Limonciello Date: Wed, 29 Apr 2020 08:41:17 -0500 Subject: [PATCH 014/607] thunderbolt: Allow quirks to skip the authentication step This will allow being able to PoC some future kernel work to split up steps. --- plugins/thunderbolt/fu-thunderbolt-device.c | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/plugins/thunderbolt/fu-thunderbolt-device.c b/plugins/thunderbolt/fu-thunderbolt-device.c index fefd4fa84..c16ba0e49 100644 --- a/plugins/thunderbolt/fu-thunderbolt-device.c +++ b/plugins/thunderbolt/fu-thunderbolt-device.c @@ -325,10 +325,9 @@ fu_thunderbolt_device_setup (FuDevice *device, GError **error) } static gboolean -fu_thunderbolt_device_trigger_update (FuThunderboltDevice *self, - GError **error) +fu_thunderbolt_device_trigger_update (FuDevice *device, GError **error) { - + FuThunderboltDevice *self = FU_THUNDERBOLT_DEVICE (device); ssize_t n; int fd; int r; @@ -576,7 +575,13 @@ fu_thunderbolt_device_write_firmware (FuDevice *device, return FALSE; } - if (!fu_thunderbolt_device_trigger_update (self, error)) { + if (fu_device_has_custom_flag (device, "skip-restart")) { + g_debug ("Skipping Thunderbolt reset per quirk request"); + fu_device_add_flag (device, FWUPD_DEVICE_FLAG_NEEDS_ACTIVATION); + return TRUE; + } + + if (!fu_thunderbolt_device_trigger_update (FU_DEVICE (self), error)) { g_prefix_error (error, "could not start thunderbolt device upgrade: "); return FALSE; } From e1c8c018a5ec0792ed0cf94c667623ffbd61671f Mon Sep 17 00:00:00 2001 From: Mario Limonciello Date: Wed, 29 Apr 2020 12:43:26 -0500 Subject: [PATCH 015/607] tpm-eventlog: Correct the display of final calculated PCRs Although the calculation matched on my machine the actual numbers didn't match PCR0 values from the tpm2-tools. This was a display error. --- plugins/tpm-eventlog/fu-tpm-eventlog.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugins/tpm-eventlog/fu-tpm-eventlog.c b/plugins/tpm-eventlog/fu-tpm-eventlog.c index 5b84bb95b..ac66f0869 100644 --- a/plugins/tpm-eventlog/fu-tpm-eventlog.c +++ b/plugins/tpm-eventlog/fu-tpm-eventlog.c @@ -62,7 +62,7 @@ fu_tmp_eventlog_process (const gchar *fn, gint pcr, GError **error) continue; for (guint j = 0; j < pcrs->len; j++) { const gchar *csum = g_ptr_array_index (pcrs, j); - g_autofree gchar *title = g_strdup_printf ("%u", i); + g_autofree gchar *title = g_strdup_printf ("%x", i); fu_common_string_append_kv (str, 1, title, csum); } } From 38c80baff52a1ee03bf88de0f1bc4e8a36e0bab8 Mon Sep 17 00:00:00 2001 From: Mario Limonciello Date: Wed, 29 Apr 2020 12:44:05 -0500 Subject: [PATCH 016/607] tpm-eventlog: Disambiguate the output at the end of fwupdtpmevlog It's not obvious to users if this is the same value as tpm2-tools or the reconstructed value. --- plugins/tpm-eventlog/fu-tpm-eventlog.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugins/tpm-eventlog/fu-tpm-eventlog.c b/plugins/tpm-eventlog/fu-tpm-eventlog.c index ac66f0869..4a88b432d 100644 --- a/plugins/tpm-eventlog/fu-tpm-eventlog.c +++ b/plugins/tpm-eventlog/fu-tpm-eventlog.c @@ -55,7 +55,7 @@ fu_tmp_eventlog_process (const gchar *fn, gint pcr, GError **error) fu_tpm_eventlog_item_to_string (item, 0, str); g_string_append (str, "\n"); } - fu_common_string_append_kv (str, 0, "PCRs", NULL); + fu_common_string_append_kv (str, 0, "Reconstructed PCRs", NULL); for (guint8 i = 0; i < 10; i++) { g_autoptr(GPtrArray) pcrs = fu_tpm_eventlog_calc_checksums (items, i, NULL); if (pcrs == NULL) From 825c04df73fa5a3d6c844746583f1d9abdba22f4 Mon Sep 17 00:00:00 2001 From: Mario Limonciello Date: Wed, 29 Apr 2020 13:01:01 -0500 Subject: [PATCH 017/607] trivial: tpm-eventlog: Modify `-p` argument behavior If using this argument, only display the final calculated value. --- plugins/tpm-eventlog/fu-tpm-eventlog.c | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/plugins/tpm-eventlog/fu-tpm-eventlog.c b/plugins/tpm-eventlog/fu-tpm-eventlog.c index 4a88b432d..05f84118b 100644 --- a/plugins/tpm-eventlog/fu-tpm-eventlog.c +++ b/plugins/tpm-eventlog/fu-tpm-eventlog.c @@ -36,6 +36,7 @@ fu_tmp_eventlog_process (const gchar *fn, gint pcr, GError **error) g_autofree guint8 *buf = NULL; g_autoptr(GPtrArray) items = NULL; g_autoptr(GString) str = g_string_new (NULL); + gint max_pcr = 0; /* parse this */ if (!g_file_get_contents (fn, (gchar **) &buf, &bufsz, error)) @@ -50,19 +51,29 @@ fu_tmp_eventlog_process (const gchar *fn, gint pcr, GError **error) for (guint i = 0; i < items->len; i++) { FuTpmEventlogItem *item = g_ptr_array_index (items, i); + if (item->pcr > max_pcr) + max_pcr = item->pcr; if (pcr >= 0 && item->pcr != pcr) continue; fu_tpm_eventlog_item_to_string (item, 0, str); g_string_append (str, "\n"); } + if (pcr > max_pcr) { + g_set_error (error, G_IO_ERROR, G_IO_ERROR_INVALID_DATA, + "invalid PCR specified: %d", pcr); + return FALSE; + } fu_common_string_append_kv (str, 0, "Reconstructed PCRs", NULL); - for (guint8 i = 0; i < 10; i++) { + for (guint8 i = 0; i <= max_pcr; i++) { g_autoptr(GPtrArray) pcrs = fu_tpm_eventlog_calc_checksums (items, i, NULL); if (pcrs == NULL) continue; for (guint j = 0; j < pcrs->len; j++) { const gchar *csum = g_ptr_array_index (pcrs, j); - g_autofree gchar *title = g_strdup_printf ("%x", i); + g_autofree gchar *title = NULL; + if (pcr >= 0 && i != (guint) pcr) + continue; + title = g_strdup_printf ("%x", i); fu_common_string_append_kv (str, 1, title, csum); } } From cbc65bc0713471a6135ddeaa02a6984af59ec9d9 Mon Sep 17 00:00:00 2001 From: Richard Hughes Date: Sat, 18 Apr 2020 15:06:45 +0100 Subject: [PATCH 018/607] vli: Use GPIOB to reset the VL817 found in two Lenovo products --- plugins/vli/fu-vli-usbhub-device.c | 50 +++++++++++++++++++++++++++++ plugins/vli/vli-usbhub-lenovo.quirk | 14 +++++--- 2 files changed, 60 insertions(+), 4 deletions(-) diff --git a/plugins/vli/fu-vli-usbhub-device.c b/plugins/vli/fu-vli-usbhub-device.c index b9af8bf4a..fbc6ac997 100644 --- a/plugins/vli/fu-vli-usbhub-device.c +++ b/plugins/vli/fu-vli-usbhub-device.c @@ -325,11 +325,48 @@ fu_vli_usbhub_device_spi_write_data (FuVliDevice *self, return TRUE; } +#define VL817_ADDR_GPIO_OUTPUT_ENABLE 0xF6A0 /* 0=input, 1=output */ +#define VL817_ADDR_GPIO_SET_OUTPUT_DATA 0xF6A1 /* 0=low, 1=high */ +#define VL817_ADDR_GPIO_GET_INPUT_DATA 0xF6A2 /* 0=low, 1=high */ + +static gboolean +fu_vli_usbhub_device_attach_vl817_gpiob (FuDevice *device, GError **error) +{ + FuVliUsbhubDevice *self = FU_VLI_USBHUB_DEVICE (device); + guint8 tmp = 0x0; + + /* set GPIOB output enable */ + if (!fu_vli_usbhub_device_read_reg (self, VL817_ADDR_GPIO_OUTPUT_ENABLE, + &tmp, error)) + return FALSE; + if (!fu_vli_usbhub_device_write_reg (self, VL817_ADDR_GPIO_OUTPUT_ENABLE, + tmp | (1 << 1), error)) + return FALSE; + + /* toggle GPIOB to trigger reset */ + if (!fu_vli_usbhub_device_read_reg (self, VL817_ADDR_GPIO_SET_OUTPUT_DATA, + &tmp, error)) + return FALSE; + if (!fu_vli_usbhub_device_write_reg (self, VL817_ADDR_GPIO_SET_OUTPUT_DATA, + tmp ^ (1 << 1), error)) + return FALSE; + fu_device_set_status (device, FWUPD_STATUS_DEVICE_RESTART); + fu_device_add_flag (device, FWUPD_DEVICE_FLAG_WAIT_FOR_REPLUG); + return TRUE; +} + static gboolean fu_vli_usbhub_device_attach (FuDevice *device, GError **error) { g_autoptr(GError) error_local = NULL; + /* the proxy might be using a GPIO instead */ + if (fu_device_get_proxy (device) != NULL) { + FuDevice *proxy = fu_device_get_proxy (device); + g_debug ("using proxy device %s", fu_device_get_id (proxy)); + return fu_device_attach (proxy, error); + } + /* replug, and ignore the device going away */ fu_device_set_status (device, FWUPD_STATUS_DEVICE_RESTART); fu_device_add_flag (device, FWUPD_DEVICE_FLAG_WAIT_FOR_REPLUG); @@ -1006,12 +1043,25 @@ fu_vli_usbhub_device_write_firmware (FuDevice *device, return FALSE; } +static void +fu_vli_usbhub_device_kind_changed_cb (FuVliDevice *device, GParamSpec *pspec, gpointer user_data) +{ + FuDeviceClass *klass_device = FU_DEVICE_GET_CLASS (device); + if (fu_vli_device_get_kind (device) == FU_VLI_DEVICE_KIND_VL817 && + fu_device_has_custom_flag (FU_DEVICE (device), "attach-with-gpiob")) + klass_device->attach = fu_vli_usbhub_device_attach_vl817_gpiob; +} + static void fu_vli_usbhub_device_init (FuVliUsbhubDevice *self) { fu_device_add_icon (FU_DEVICE (self), "audio-card"); fu_device_set_protocol (FU_DEVICE (self), "com.vli.usbhub"); fu_device_set_remove_delay (FU_DEVICE (self), FU_DEVICE_REMOVE_DELAY_RE_ENUMERATE); + + /* connect up attach or detach vfuncs when kind is known */ + g_signal_connect (self, "notify::kind", + G_CALLBACK (fu_vli_usbhub_device_kind_changed_cb), NULL); } static void diff --git a/plugins/vli/vli-usbhub-lenovo.quirk b/plugins/vli/vli-usbhub-lenovo.quirk index 05f565796..29ff0b060 100644 --- a/plugins/vli/vli-usbhub-lenovo.quirk +++ b/plugins/vli/vli-usbhub-lenovo.quirk @@ -162,12 +162,18 @@ Flags = usb2,has-shared-spi-pd [DeviceInstanceId=USB\VID_17EF&PID_3094] Plugin = vli GType = FuVliUsbhubDevice -Flags = usb3,has-shared-spi-pd +Flags = usb3,has-shared-spi-pd,attach-with-gpiob CounterpartGuid = USB\VID_17EF&PID_3095 [DeviceInstanceId=USB\VID_17EF&PID_3095] Plugin = vli GType = FuVliUsbhubDevice -Flags = usb2,has-shared-spi-pd +Flags = usb2,attach-with-gpiob +ParentGuid = USB\VID_17EF&PID_3094 +[DeviceInstanceId=USB\VID_17EF&PID_3097] +Plugin = vli +GType = FuVliUsbhubDevice +Flags = usb2 +ParentGuid = USB\VID_17EF&PID_3094 # Lenovo Travel Hub 1in3 [DeviceInstanceId=USB\VID_17EF&PID_7228] @@ -195,12 +201,12 @@ Flags = usb2,has-shared-spi-pd [DeviceInstanceId=USB\VID_17EF&PID_1039] Plugin = vli GType = FuVliUsbhubDevice -Flags = usb3,has-shared-spi-pd +Flags = usb3,has-shared-spi-pd,attach-with-gpiob CounterpartGuid = USB\VID_17EF&PID_103A [DeviceInstanceId=USB\VID_17EF&PID_103A] Plugin = vli GType = FuVliUsbhubDevice -Flags = usb2,has-shared-spi-pd +Flags = usb2,has-shared-spi-pd,attach-with-gpiob # Lenovo Gen2 dock [DeviceInstanceId=USB\VID_17EF&PID_A391] From af917f558b84a31b2c544f77d8fa831f15fad98b Mon Sep 17 00:00:00 2001 From: Richard Hughes Date: Wed, 29 Apr 2020 14:39:19 +0100 Subject: [PATCH 019/607] vli: Add two standard USB instance IDs for shared-PD devices --- plugins/vli/fu-vli-usbhub-pd-device.c | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/plugins/vli/fu-vli-usbhub-pd-device.c b/plugins/vli/fu-vli-usbhub-pd-device.c index be2984245..9d2f8f2b7 100644 --- a/plugins/vli/fu-vli-usbhub-pd-device.c +++ b/plugins/vli/fu-vli-usbhub-pd-device.c @@ -45,6 +45,8 @@ fu_vli_usbhub_pd_device_probe (FuDevice *device, GError **error) guint32 fwver; g_autofree gchar *fwver_str = NULL; g_autofree gchar *instance_id1 = NULL; + g_autofree gchar *instance_id2 = NULL; + g_autofree gchar *instance_id3 = NULL; /* get version */ fwver = GUINT32_FROM_BE (self->hdr.fwver); @@ -68,6 +70,16 @@ fu_vli_usbhub_pd_device_probe (FuDevice *device, GError **error) fu_vli_common_device_kind_to_string (self->device_kind)); fu_device_add_instance_id (device, instance_id1); + /* add standard GUIDs in order of priority */ + instance_id2 = g_strdup_printf ("USB\\VID_%04X&PID_%04X", + GUINT16_FROM_LE (self->hdr.vid), + GUINT16_FROM_LE (self->hdr.pid)); + fu_device_add_instance_id (device, instance_id2); + instance_id3 = g_strdup_printf ("USB\\VID_%04X", + GUINT16_FROM_LE (self->hdr.vid)); + fu_device_add_instance_id_full (device, instance_id3, + FU_DEVICE_INSTANCE_FLAG_ONLY_QUIRKS); + /* these have a backup section */ if (fu_vli_common_device_kind_get_offset (self->device_kind) == VLI_USBHUB_FLASHMAP_ADDR_PD) fu_device_add_flag (FU_DEVICE (self), FWUPD_DEVICE_FLAG_SELF_RECOVERY); From 890963108e3b60f7c73d9dbdb0f54dff7504bd7f Mon Sep 17 00:00:00 2001 From: Mario Limonciello Date: Thu, 30 Apr 2020 09:51:14 -0500 Subject: [PATCH 020/607] Clarify invalid arguments display (Fixes: #2045) Avoid a wall of text and instead direct people to `--help` output. Also sync up this section of code between `fu-util.c` and `fu-tool.c` --- src/fu-tool.c | 13 +++++-------- src/fu-util.c | 26 ++++++++++---------------- 2 files changed, 15 insertions(+), 24 deletions(-) diff --git a/src/fu-tool.c b/src/fu-tool.c index b1dd886ca..268c8d5c5 100644 --- a/src/fu-tool.c +++ b/src/fu-tool.c @@ -2277,17 +2277,14 @@ main (int argc, char *argv[]) /* run the specified command */ ret = fu_util_cmd_array_run (cmd_array, priv, argv[1], (gchar**) &argv[2], &error); if (!ret) { + g_printerr ("%s\n", error->message); if (g_error_matches (error, FWUPD_ERROR, FWUPD_ERROR_INVALID_ARGS)) { - g_autofree gchar *tmp = NULL; - tmp = g_option_context_get_help (priv->context, TRUE, NULL); - g_print ("%s\n\n%s", error->message, tmp); - return EXIT_FAILURE; - } - if (g_error_matches (error, FWUPD_ERROR, FWUPD_ERROR_NOTHING_TO_DO)) { - g_print ("%s\n", error->message); + /* TRANSLATORS: error message explaining command to run to how to get help */ + g_printerr ("\n%s\n", _("Use fwupdtool --help for help")); + } else if (g_error_matches (error, FWUPD_ERROR, FWUPD_ERROR_NOTHING_TO_DO)) { + g_debug ("%s\n", error->message); return EXIT_NOTHING_TO_DO; } - g_print ("%s\n", error->message); return EXIT_FAILURE; } diff --git a/src/fu-util.c b/src/fu-util.c index 36aaf9a64..da8d961ed 100644 --- a/src/fu-util.c +++ b/src/fu-util.c @@ -2434,14 +2434,6 @@ fu_util_check_polkit_actions (GError **error) return TRUE; } -static void -fu_util_display_help (FuUtilPrivate *priv) -{ - g_autofree gchar *tmp = NULL; - tmp = g_option_context_get_help (priv->context, TRUE, NULL); - g_printerr ("%s\n", tmp); -} - #pragma clang diagnostic push #pragma clang diagnostic ignored "-Wunused-function" G_DEFINE_AUTOPTR_CLEANUP_FUNC(FuUtilPrivate, fu_util_private_free) @@ -2829,15 +2821,17 @@ main (int argc, char *argv[]) /* run the specified command */ ret = fu_util_cmd_array_run (cmd_array, priv, argv[1], (gchar**) &argv[2], &error); if (!ret) { - ret = EXIT_FAILURE; g_printerr ("%s\n", error->message); - if (g_error_matches (error, FWUPD_ERROR, FWUPD_ERROR_INVALID_ARGS)) - fu_util_display_help (priv); - else if (g_error_matches (error, FWUPD_ERROR, FWUPD_ERROR_NOTHING_TO_DO)) - ret = EXIT_NOTHING_TO_DO; - } else { - ret = EXIT_SUCCESS; + if (g_error_matches (error, FWUPD_ERROR, FWUPD_ERROR_INVALID_ARGS)) { + /* TRANSLATORS: error message explaining command to run to how to get help */ + g_printerr ("\n%s\n", _("Use fwupdmgr --help for help")); + } else if (g_error_matches (error, FWUPD_ERROR, FWUPD_ERROR_NOTHING_TO_DO)) { + g_debug ("%s\n", error->message); + return EXIT_NOTHING_TO_DO; + } + return EXIT_FAILURE; } - return ret; + /* success */ + return EXIT_SUCCESS; } From 0258c12af38eae27812695d3351a3797b65b8d6c Mon Sep 17 00:00:00 2001 From: Richard Hughes Date: Fri, 1 May 2020 17:14:18 +0100 Subject: [PATCH 021/607] uefi: Manually call fu_device_setup() during coldplug This forces the daemon to convert the main-system-firmware instance ID to a GUID, which allows us to find it using fu_device_list_get_by_guid() --- plugins/uefi/fu-plugin-uefi.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/plugins/uefi/fu-plugin-uefi.c b/plugins/uefi/fu-plugin-uefi.c index 56eefd4f4..204b338a0 100644 --- a/plugins/uefi/fu-plugin-uefi.c +++ b/plugins/uefi/fu-plugin-uefi.c @@ -499,6 +499,8 @@ fu_plugin_uefi_coldplug_device (FuPlugin *plugin, FuUefiDevice *dev, GError **er /* probe to get add GUIDs (and hence any quirk fixups) */ if (!fu_device_probe (FU_DEVICE (dev), error)) return FALSE; + if (!fu_device_setup (FU_DEVICE (dev), error)) + return FALSE; /* if not already set by quirks */ if (fu_device_get_custom_flags (FU_DEVICE (dev)) == NULL) { From f4b843db432cf16f2a4a651377fb3b3d4270fa36 Mon Sep 17 00:00:00 2001 From: Jakob Date: Sat, 2 May 2020 09:30:21 +0200 Subject: [PATCH 022/607] Add OUI quirk for SanDisk --- plugins/ata/ata.quirk | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/plugins/ata/ata.quirk b/plugins/ata/ata.quirk index 17bcb7207..0e79dfe4e 100644 --- a/plugins/ata/ata.quirk +++ b/plugins/ata/ata.quirk @@ -41,3 +41,8 @@ VendorId = ATA:0x8086 [DeviceInstanceId=OUI\707c18] Vendor = ADATA VendorId = ATA:0x1CC1 + +[DeviceInstanceId=OUI\001b44] +Vendor = SanDisk +VendorId = ATA:0x15B7 + From 86f6324a263849687247c31114857b11b619d9eb Mon Sep 17 00:00:00 2001 From: Richard Hughes Date: Sat, 2 May 2020 22:10:25 +0100 Subject: [PATCH 023/607] Switch the default of EnumerateAllDevices to false This was causing dozens of regressions to be reported. --- data/daemon.conf | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/data/daemon.conf b/data/daemon.conf index 44ca5a724..1cb93282c 100644 --- a/data/daemon.conf +++ b/data/daemon.conf @@ -27,4 +27,4 @@ VerboseDomains= UpdateMotd=true # For some plugins, enumerate only devices supported by metadata -EnumerateAllDevices=true +EnumerateAllDevices=false From 748a65f3c788abfc99769b4aa6d3eb25e815e0de Mon Sep 17 00:00:00 2001 From: Richard Hughes Date: Tue, 5 May 2020 11:33:28 +0100 Subject: [PATCH 024/607] trivial: Post branch version bump We're planning to ship fwupd 1.4.x in RHEL 8 and so it makes sense to have a stable branch to do point releases. I don't intend to release versions 1.5.x any time soon, so moderately-agressive backporting to 1_4_X is okay. --- RELEASE | 2 +- libfwupdplugin/fu-udev-device.c | 4 ++-- libfwupdplugin/fwupdplugin.map | 2 +- meson.build | 2 +- 4 files changed, 5 insertions(+), 5 deletions(-) diff --git a/RELEASE b/RELEASE index 80297efc3..33c64d83a 100644 --- a/RELEASE +++ b/RELEASE @@ -17,7 +17,7 @@ git add ../po/*.po 2. Commit changes to git: # MAKE SURE THIS IS CORRECT -export release_ver="1.4.2" +export release_ver="1.5.0" git commit -a -m "Release fwupd ${release_ver}" git tag -s -f -m "Release fwupd ${release_ver}" "${release_ver}" diff --git a/libfwupdplugin/fu-udev-device.c b/libfwupdplugin/fu-udev-device.c index efc5a19f9..3c9a6ee8e 100644 --- a/libfwupdplugin/fu-udev-device.c +++ b/libfwupdplugin/fu-udev-device.c @@ -951,7 +951,7 @@ fu_udev_device_pwrite (FuUdevDevice *self, goffset port, guint8 data, GError **e * * Returns: string or NULL if unset or invalid * - * Since: 1.4.2 + * Since: 1.5.0 **/ gchar * fu_udev_device_get_parent_name (FuUdevDevice *self) @@ -979,7 +979,7 @@ fu_udev_device_get_parent_name (FuUdevDevice *self) * * Returns: string or NULL * - * Since: 1.4.2 + * Since: 1.5.0 **/ const gchar * fu_udev_device_get_sysfs_attr (FuUdevDevice *self, const gchar *attr, diff --git a/libfwupdplugin/fwupdplugin.map b/libfwupdplugin/fwupdplugin.map index 3a8456640..b3ac35435 100644 --- a/libfwupdplugin/fwupdplugin.map +++ b/libfwupdplugin/fwupdplugin.map @@ -581,7 +581,7 @@ LIBFWUPDPLUGIN_1.4.1 { local: *; } LIBFWUPDPLUGIN_1.4.0; -LIBFWUPDPLUGIN_1.4.2 { +LIBFWUPDPLUGIN_1.5.0 { global: fu_udev_device_get_parent_name; fu_udev_device_get_sysfs_attr; diff --git a/meson.build b/meson.build index df7815847..a09a3db3c 100644 --- a/meson.build +++ b/meson.build @@ -1,5 +1,5 @@ project('fwupd', 'c', - version : '1.4.2', + version : '1.5.0', license : 'LGPL-2.1+', meson_version : '>=0.47.0', default_options : ['warning_level=2', 'c_std=c99'], From 3838b22a7cd1a869c3504c4afd1017df3c3b0d0b Mon Sep 17 00:00:00 2001 From: Mario Limonciello Date: Tue, 5 May 2020 13:02:48 -0500 Subject: [PATCH 025/607] trivial: add missing changelog entry for 1.3.9 This release came out after 1_3_X branched but long before 1.40 release so these entries are confusing to be missing. Fixes: #2059 --- data/org.freedesktop.fwupd.metainfo.xml | 29 +++++++++++++++++++++++++ 1 file changed, 29 insertions(+) diff --git a/data/org.freedesktop.fwupd.metainfo.xml b/data/org.freedesktop.fwupd.metainfo.xml index 4ddc4bf01..692123aad 100644 --- a/data/org.freedesktop.fwupd.metainfo.xml +++ b/data/org.freedesktop.fwupd.metainfo.xml @@ -30,6 +30,9 @@ fwupdmgr + fwupdtool + fwupdtpmevlog + fwupdagent @@ -103,6 +106,32 @@ + + +

This release adds the following features:

+
    +
  • Added completion script for fish shell
  • +
  • Inihbit all power management actions using logind when updating
  • +
+

This release fixes the following bugs:

+
    +
  • Always check for PLAIN when doing vercmp() operations
  • +
  • Always return AppStream markup for remote agreements
  • +
  • Apply UEFI capsule update even with single valid capsule
  • +
  • Check the device protocol before de-duping devices
  • +
  • Copy the version and format from donor device in get-details
  • +
  • Correctly append the release to devices in `fwupdtool get-details`
  • +
  • Decrease minimum battery requirement to 10%
  • +
  • Discard the reason upgrades aren't available
  • +
  • Do not fail loading in /etc/machine-id is not available
  • +
  • Fix a critical warning when installing some firmware
  • +
  • For the `get-details` command make sure to always show devices
  • +
  • Set the MSP430 version format to pair
  • +
  • Switch off the ATA verbose logging by default
  • +
  • Use unknown for version format by default on get-details
  • +
+
+

This release adds the following features:

From c3689585187aed2d638bd72c0f3acfda4d146555 Mon Sep 17 00:00:00 2001 From: Richard Hughes Date: Wed, 6 May 2020 12:35:20 +0100 Subject: [PATCH 026/607] swap: Add a plugin that parses /proc/swaps This will be used for future functionality. --- contrib/fwupd.spec.in | 1 + libfwupdplugin/fu-common.c | 6 +++ libfwupdplugin/fu-common.h | 2 + plugins/meson.build | 1 + plugins/swap/README.md | 8 ++++ plugins/swap/fu-plugin-swap.c | 76 +++++++++++++++++++++++++++++++++++ plugins/swap/fu-self-test.c | 72 +++++++++++++++++++++++++++++++++ plugins/swap/fu-swap.c | 66 ++++++++++++++++++++++++++++++ plugins/swap/fu-swap.h | 18 +++++++++ plugins/swap/meson.build | 48 ++++++++++++++++++++++ 10 files changed, 298 insertions(+) create mode 100644 plugins/swap/README.md create mode 100644 plugins/swap/fu-plugin-swap.c create mode 100644 plugins/swap/fu-self-test.c create mode 100644 plugins/swap/fu-swap.c create mode 100644 plugins/swap/fu-swap.h create mode 100644 plugins/swap/meson.build diff --git a/contrib/fwupd.spec.in b/contrib/fwupd.spec.in index 22940d918..0bf4eb921 100644 --- a/contrib/fwupd.spec.in +++ b/contrib/fwupd.spec.in @@ -366,6 +366,7 @@ mkdir -p --mode=0700 $RPM_BUILD_ROOT%{_localstatedir}/lib/fwupd/gnupg %if 0%{?have_dell} %{_libdir}/fwupd-plugins-3/libfu_plugin_synaptics_mst.so %endif +%{_libdir}/fwupd-plugins-3/libfu_plugin_swap.so %{_libdir}/fwupd-plugins-3/libfu_plugin_synaptics_cxaudio.so %{_libdir}/fwupd-plugins-3/libfu_plugin_synaptics_prometheus.so %{_libdir}/fwupd-plugins-3/libfu_plugin_synaptics_rmi.so diff --git a/libfwupdplugin/fu-common.c b/libfwupdplugin/fu-common.c index 81dfa3296..19acec92f 100644 --- a/libfwupdplugin/fu-common.c +++ b/libfwupdplugin/fu-common.c @@ -1026,6 +1026,12 @@ fu_common_get_path (FuPathKind path_kind) if (tmp != NULL) return g_build_filename (tmp, FWUPD_LOCALSTATEDIR, NULL); return g_build_filename (FWUPD_LOCALSTATEDIR, NULL); + /* /proc */ + case FU_PATH_KIND_PROCFS: + tmp = g_getenv ("FWUPD_PROCFS"); + if (tmp != NULL) + return g_strdup (tmp); + return g_strdup ("/proc"); /* /sys/firmware */ case FU_PATH_KIND_SYSFSDIR_FW: tmp = g_getenv ("FWUPD_SYSFSFWDIR"); diff --git a/libfwupdplugin/fu-common.h b/libfwupdplugin/fu-common.h index 6ebc1a381..c61627285 100644 --- a/libfwupdplugin/fu-common.h +++ b/libfwupdplugin/fu-common.h @@ -53,6 +53,7 @@ typedef guint FuEndianType; * @FU_PATH_KIND_SYSFSDIR_FW: The sysfs firmware location (IE /sys/firmware) * @FU_PATH_KIND_SYSFSDIR_DRIVERS: The platform sysfs directory (IE /sys/bus/platform/drivers) * @FU_PATH_KIND_SYSFSDIR_TPM: The TPM sysfs directory (IE /sys/class/tpm) + * @FU_PATH_KIND_PROCFS: The procfs location (IE /proc) * @FU_PATH_KIND_POLKIT_ACTIONS: The directory for policy kit actions (IE /usr/share/polkit-1/actions/) * @FU_PATH_KIND_OFFLINE_TRIGGER: The file for the offline trigger (IE /system-update) * @FU_PATH_KIND_SYSFSDIR_SECURITY: The sysfs security location (IE /sys/kernel/security) @@ -71,6 +72,7 @@ typedef enum { FU_PATH_KIND_SYSFSDIR_FW, FU_PATH_KIND_SYSFSDIR_DRIVERS, FU_PATH_KIND_SYSFSDIR_TPM, + FU_PATH_KIND_PROCFS, FU_PATH_KIND_POLKIT_ACTIONS, FU_PATH_KIND_OFFLINE_TRIGGER, FU_PATH_KIND_SYSFSDIR_SECURITY, diff --git a/plugins/meson.build b/plugins/meson.build index 72de5661f..676ff5593 100644 --- a/plugins/meson.build +++ b/plugins/meson.build @@ -13,6 +13,7 @@ subdir('nitrokey') subdir('rts54hid') subdir('rts54hub') subdir('solokey') +subdir('swap') subdir('synaptics-cxaudio') subdir('synaptics-prometheus') subdir('test') diff --git a/plugins/swap/README.md b/plugins/swap/README.md new file mode 100644 index 000000000..6a963965b --- /dev/null +++ b/plugins/swap/README.md @@ -0,0 +1,8 @@ +Swap Support +============ + +Introduction +------------ + +This plugin checks if the currently available swap partitions and files are +all encrypted. diff --git a/plugins/swap/fu-plugin-swap.c b/plugins/swap/fu-plugin-swap.c new file mode 100644 index 000000000..697e9bb1d --- /dev/null +++ b/plugins/swap/fu-plugin-swap.c @@ -0,0 +1,76 @@ +/* + * Copyright (C) 2020 Richard Hughes + * + * SPDX-License-Identifier: LGPL-2.1+ + */ + +#include "config.h" + +#include "fu-plugin-vfuncs.h" +#include "fu-hash.h" +#include "fu-swap.h" + +struct FuPluginData { + GFileMonitor *monitor; +}; + +void +fu_plugin_init (FuPlugin *plugin) +{ + fu_plugin_alloc_data (plugin, sizeof (FuPluginData)); + fu_plugin_set_build_hash (plugin, FU_BUILD_HASH); +} + +void +fu_plugin_destroy (FuPlugin *plugin) +{ + FuPluginData *data = fu_plugin_get_data (plugin); + if (data->monitor != NULL) + g_object_unref (data->monitor); +} + +static void +fu_plugin_swap_changed_cb (GFileMonitor *monitor, + GFile *file, + GFile *other_file, + GFileMonitorEvent event_type, + gpointer user_data) +{ + g_debug ("swap changed"); +} + +gboolean +fu_plugin_startup (FuPlugin *plugin, GError **error) +{ + FuPluginData *data = fu_plugin_get_data (plugin); + gsize bufsz = 0; + g_autofree gchar *buf = NULL; + g_autofree gchar *fn = NULL; + g_autofree gchar *procfs = NULL; + g_autoptr(FuSwap) swap = NULL; + g_autoptr(GFile) file = NULL; + + procfs = fu_common_get_path (FU_PATH_KIND_PROCFS); + fn = g_build_filename (procfs, "swaps", NULL); + file = g_file_new_for_path (fn); + data->monitor = g_file_monitor (file, G_FILE_MONITOR_NONE, NULL, error); + if (data->monitor == NULL) + return FALSE; + g_signal_connect (data->monitor, "changed", + G_CALLBACK (fu_plugin_swap_changed_cb), plugin); + + /* load list of swaps */ + if (!g_file_get_contents (fn, &buf, &bufsz, error)) { + g_prefix_error (error, "could not open %s: ", fn); + return FALSE; + } + swap = fu_swap_new (buf, bufsz, error); + if (swap == NULL) { + g_prefix_error (error, "could not parse %s: ", fn); + return FALSE; + } + g_debug ("swap %s and %s", + fu_swap_get_enabled (swap) ? "enabled" : "disabled", + fu_swap_get_encrypted (swap) ? "encrypted" : "unencrypted"); + return TRUE; +} diff --git a/plugins/swap/fu-self-test.c b/plugins/swap/fu-self-test.c new file mode 100644 index 000000000..b07e699cd --- /dev/null +++ b/plugins/swap/fu-self-test.c @@ -0,0 +1,72 @@ +/* + * Copyright (C) 2020 Richard Hughes + * + * SPDX-License-Identifier: LGPL-2.1+ + */ + +#include "config.h" + +#include + +#include "fu-swap.h" + +#include "fwupd-error.h" + +static void +fu_swap_none_func (void) +{ + g_autoptr(FuSwap) swap = NULL; + g_autoptr(GError) error = NULL; + + swap = fu_swap_new ("Filename\t\t\t\tType\t\tSize\tUsed\tPriority\n", 0, &error); + g_assert_no_error (error); + g_assert_nonnull (swap); + g_assert_false (fu_swap_get_enabled (swap)); + g_assert_false (fu_swap_get_encrypted (swap)); +} + +static void +fu_swap_plain_func (void) +{ + g_autoptr(FuSwap) swap = NULL; + g_autoptr(GError) error = NULL; + + swap = fu_swap_new ("Filename\t\t\t\tType\t\tSize\tUsed\tPriority\n" + "/dev/nvme0n1p4 partition\t5962748\t0\t-2\n", + 0, &error); + g_assert_no_error (error); + g_assert_nonnull (swap); + g_assert_true (fu_swap_get_enabled (swap)); + g_assert_false (fu_swap_get_encrypted (swap)); +} + +static void +fu_swap_encrypted_func (void) +{ + g_autoptr(FuSwap) swap = NULL; + g_autoptr(GError) error = NULL; + + swap = fu_swap_new ("Filename\t\t\t\tType\t\tSize\tUsed\tPriority\n" + "/dev/dm-1 partition\t5962748\t0\t-2\n", + 0, &error); + g_assert_no_error (error); + g_assert_nonnull (swap); + g_assert_true (fu_swap_get_enabled (swap)); + g_assert_true (fu_swap_get_encrypted (swap)); +} + +int +main (int argc, char **argv) +{ + g_test_init (&argc, &argv, NULL); + + /* 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 ("/swap/none", fu_swap_none_func); + g_test_add_func ("/swap/plain", fu_swap_plain_func); + g_test_add_func ("/swap/encrypted", fu_swap_encrypted_func); + return g_test_run (); +} diff --git a/plugins/swap/fu-swap.c b/plugins/swap/fu-swap.c new file mode 100644 index 000000000..e16a3c42d --- /dev/null +++ b/plugins/swap/fu-swap.c @@ -0,0 +1,66 @@ +/* + * Copyright (C) 2020 Richard Hughes + * + * SPDX-License-Identifier: LGPL-2.1+ + */ + +#include "config.h" + +#include + +#include "fu-common.h" +#include "fu-swap.h" + +struct _FuSwap { + GObject parent_instance; + gboolean encrypted; + gboolean enabled; +}; + +G_DEFINE_TYPE (FuSwap, fu_swap, G_TYPE_OBJECT) + +FuSwap * +fu_swap_new (const gchar *buf, gsize bufsz, GError **error) +{ + FuSwap *self = g_object_new (FU_TYPE_SWAP, NULL); + g_auto(GStrv) lines = NULL; + + if (bufsz == 0) + bufsz = strlen (buf); + lines = fu_common_strnsplit (buf, bufsz, "\n", -1); + if (g_strv_length (lines) > 2) { + self->enabled = TRUE; + for (guint i = 1; lines[i] != NULL && lines[i][0] != '\0'; i++) { + if (g_str_has_prefix (lines[i], "/dev/dm-") || + g_str_has_prefix (lines[i], "/dev/mapper")) { + self->encrypted = TRUE; + break; + } + } + } + return self; +} + +gboolean +fu_swap_get_encrypted (FuSwap *self) +{ + g_return_val_if_fail (FU_IS_SWAP (self), FALSE); + return self->encrypted; +} + +gboolean +fu_swap_get_enabled (FuSwap *self) +{ + g_return_val_if_fail (FU_IS_SWAP (self), FALSE); + return self->enabled; +} + +static void +fu_swap_class_init (FuSwapClass *klass) +{ +} + +static void +fu_swap_init (FuSwap *self) +{ +} diff --git a/plugins/swap/fu-swap.h b/plugins/swap/fu-swap.h new file mode 100644 index 000000000..006edb4be --- /dev/null +++ b/plugins/swap/fu-swap.h @@ -0,0 +1,18 @@ +/* + * Copyright (C) 2020 Richard Hughes + * + * SPDX-License-Identifier: LGPL-2.1+ + */ + +#pragma once + +#include + +#define FU_TYPE_SWAP (fu_swap_get_type ()) +G_DECLARE_FINAL_TYPE (FuSwap, fu_swap, FU, SWAP, GObject) + +FuSwap *fu_swap_new (const gchar *buf, + gsize bufsz, + GError **error); +gboolean fu_swap_get_enabled (FuSwap *self); +gboolean fu_swap_get_encrypted (FuSwap *self); diff --git a/plugins/swap/meson.build b/plugins/swap/meson.build new file mode 100644 index 000000000..7a13cdf81 --- /dev/null +++ b/plugins/swap/meson.build @@ -0,0 +1,48 @@ +cargs = ['-DG_LOG_DOMAIN="FuPluginSwap"'] + +shared_module('fu_plugin_swap', + fu_hash, + sources : [ + 'fu-plugin-swap.c', + 'fu-swap.c', + ], + include_directories : [ + root_incdir, + fwupd_incdir, + fwupdplugin_incdir, + ], + install : true, + install_dir: plugin_dir, + link_with : [ + fwupd, + fwupdplugin, + ], + c_args : cargs, + dependencies : [ + plugin_deps, + ], +) + +if get_option('tests') + e = executable( + 'swap-self-test', + fu_hash, + sources : [ + 'fu-self-test.c', + 'fu-swap.c', + ], + include_directories : [ + root_incdir, + fwupd_incdir, + fwupdplugin_incdir, + ], + dependencies : [ + plugin_deps, + ], + link_with : [ + fwupd, + fwupdplugin, + ], + ) + test('swap-self-test', e) +endif From 94874cd06726675aade037a1ba739436408a4b26 Mon Sep 17 00:00:00 2001 From: Mario Limonciello Date: Tue, 5 May 2020 14:06:26 -0500 Subject: [PATCH 027/607] thunderbolt: Add a new subclassed thunderbolt firmware update type Thunderbolt images brought in from the SPI don't have a FARB header. Thunderbolt update images do. So these two types of images need to be handled separately from the firmware parser. --- plugins/thunderbolt/fu-plugin-thunderbolt.c | 2 + plugins/thunderbolt/fu-self-test.c | 25 +-- plugins/thunderbolt/fu-thunderbolt-device.c | 26 ++- .../fu-thunderbolt-firmware-update.c | 108 +++++++++ .../fu-thunderbolt-firmware-update.h | 14 ++ plugins/thunderbolt/fu-thunderbolt-firmware.c | 212 ++++++++---------- plugins/thunderbolt/fu-thunderbolt-firmware.h | 41 +++- plugins/thunderbolt/meson.build | 2 + 8 files changed, 280 insertions(+), 150 deletions(-) create mode 100644 plugins/thunderbolt/fu-thunderbolt-firmware-update.c create mode 100644 plugins/thunderbolt/fu-thunderbolt-firmware-update.h diff --git a/plugins/thunderbolt/fu-plugin-thunderbolt.c b/plugins/thunderbolt/fu-plugin-thunderbolt.c index efed63289..e67952d8d 100644 --- a/plugins/thunderbolt/fu-plugin-thunderbolt.c +++ b/plugins/thunderbolt/fu-plugin-thunderbolt.c @@ -12,6 +12,7 @@ #include "fu-hash.h" #include "fu-thunderbolt-device.h" #include "fu-thunderbolt-firmware.h" +#include "fu-thunderbolt-firmware-update.h" static gboolean fu_plugin_thunderbolt_safe_kernel (FuPlugin *plugin, GError **error) @@ -62,6 +63,7 @@ fu_plugin_init (FuPlugin *plugin) fu_plugin_add_udev_subsystem (plugin, "thunderbolt"); fu_plugin_set_device_gtype (plugin, FU_TYPE_THUNDERBOLT_DEVICE); fu_plugin_add_firmware_gtype (plugin, "thunderbolt", FU_TYPE_THUNDERBOLT_FIRMWARE); + fu_plugin_add_firmware_gtype (plugin, "thunderbolt-update", FU_TYPE_THUNDERBOLT_FIRMWARE_UPDATE); /* dell-dock plugin uses a slower bus for flashing */ fu_plugin_add_rule (plugin, FU_PLUGIN_RULE_BETTER_THAN, "dell_dock"); } diff --git a/plugins/thunderbolt/fu-self-test.c b/plugins/thunderbolt/fu-self-test.c index 993c45704..7a450b90a 100644 --- a/plugins/thunderbolt/fu-self-test.c +++ b/plugins/thunderbolt/fu-self-test.c @@ -25,6 +25,7 @@ #include "fu-plugin-private.h" #include "fu-thunderbolt-firmware.h" +#include "fu-thunderbolt-firmware-update.h" static gchar * udev_mock_add_domain (UMockdevTestbed *bed, int id) @@ -343,7 +344,7 @@ write_controller_fw (const gchar *nvm) g_autoptr(GError) error = NULL; gssize n; - fw_path = g_build_filename (TESTDATADIR, "thunderbolt/minimal-fw.bin", NULL); + fw_path = g_build_filename (TESTDATADIR, "thunderbolt/minimal-fw-controller.bin", NULL); fw_file = g_file_new_for_path (fw_path); g_assert_nonnull (fw_file); @@ -1023,7 +1024,7 @@ test_tree (ThunderboltTest *tt, gconstpointer user_data) } static gboolean -_compare_images (FuThunderboltFirmware *firmware, FuThunderboltFirmware *firmware_old, GError **error) +_compare_images (FuThunderboltFirmware *firmware_old, FuThunderboltFirmware *firmware, GError **error) { if (fu_thunderbolt_firmware_is_host (firmware) != fu_thunderbolt_firmware_is_host (firmware_old)) { @@ -1065,12 +1066,12 @@ _compare_images (FuThunderboltFirmware *firmware, FuThunderboltFirmware *firmwar fu_thunderbolt_firmware_get_model_id (firmware_old)); return FALSE; } - if (fu_thunderbolt_firmware_get_has_pd (firmware) != - fu_thunderbolt_firmware_get_has_pd (firmware_old)) { + if (fu_thunderbolt_firmware_get_has_pd (firmware_old) && + !fu_thunderbolt_firmware_get_has_pd (firmware)) { g_set_error_literal (error, FWUPD_ERROR, FWUPD_ERROR_INVALID_FILE, - "incorrect PD section"); + "new firmware is missing PD"); return FALSE; } if (fu_thunderbolt_firmware_get_flash_size (firmware) != @@ -1098,7 +1099,7 @@ test_image_validation (ThunderboltTest *tt, gconstpointer user_data) g_autoptr(GBytes) ctl_data = NULL; g_autoptr(GBytes) bad_data = NULL; g_autoptr(GError) error = NULL; - g_autoptr(FuThunderboltFirmware) firmware_fwi = fu_thunderbolt_firmware_new (); + g_autoptr(FuThunderboltFirmwareUpdate) firmware_fwi = fu_thunderbolt_firmware_update_new (); g_autoptr(FuThunderboltFirmware) firmware_ctl = fu_thunderbolt_firmware_new (); g_autoptr(FuThunderboltFirmware) firmware_bad = fu_thunderbolt_firmware_new (); @@ -1112,12 +1113,10 @@ test_image_validation (ThunderboltTest *tt, gconstpointer user_data) ctl_data = g_mapped_file_get_bytes (ctl_file); g_assert_nonnull (ctl_data); - /* parse; should fail due to can't read host controller offset */ + /* parse controller image */ ret = fu_firmware_parse (FU_FIRMWARE (firmware_ctl), ctl_data, FWUPD_INSTALL_FLAG_NONE, &error); - g_assert_false (ret); - g_assert_error (error, FWUPD_ERROR, FWUPD_ERROR_READ); - g_debug ("expected image validation error [ctl]: %s", error->message); - g_clear_error (&error); + g_assert_true (ret); + g_assert_no_error (error); /* valid firmware update image */ fwi_path = g_build_filename (TESTDATADIR, "thunderbolt/minimal-fw.bin", NULL); @@ -1150,9 +1149,9 @@ test_image_validation (ThunderboltTest *tt, gconstpointer user_data) g_clear_error (&error); /* now for some testing ... this should work */ - ret = _compare_images (firmware_fwi, firmware_fwi, &error); - g_assert_true (ret); + ret = _compare_images (firmware_ctl, FU_THUNDERBOLT_FIRMWARE (firmware_fwi), &error); g_assert_no_error (error); + g_assert_true (ret); } static void diff --git a/plugins/thunderbolt/fu-thunderbolt-device.c b/plugins/thunderbolt/fu-thunderbolt-device.c index c16ba0e49..283e6abe4 100644 --- a/plugins/thunderbolt/fu-thunderbolt-device.c +++ b/plugins/thunderbolt/fu-thunderbolt-device.c @@ -19,6 +19,7 @@ #include "fu-device-metadata.h" #include "fu-thunderbolt-device.h" #include "fu-thunderbolt-firmware.h" +#include "fu-thunderbolt-firmware-update.h" struct _FuThunderboltDevice { FuUdevDevice parent_instance; @@ -473,7 +474,7 @@ fu_thunderbolt_device_prepare_firmware (FuDevice *device, GError **error) { FuThunderboltDevice *self = FU_THUNDERBOLT_DEVICE (device); - g_autoptr(FuThunderboltFirmware) firmware = fu_thunderbolt_firmware_new (); + g_autoptr(FuThunderboltFirmwareUpdate) firmware = fu_thunderbolt_firmware_update_new (); g_autoptr(FuThunderboltFirmware) firmware_old = fu_thunderbolt_firmware_new (); g_autoptr(GBytes) controller_fw = NULL; g_autoptr(GError) error_local = NULL; @@ -490,56 +491,57 @@ fu_thunderbolt_device_prepare_firmware (FuDevice *device, controller_fw = g_file_load_bytes (nvmem, NULL, NULL, error); if (!fu_firmware_parse (FU_FIRMWARE (firmware_old), controller_fw, flags, error)) return NULL; - if (fu_thunderbolt_firmware_is_host (firmware) != + if (fu_thunderbolt_firmware_is_host (FU_THUNDERBOLT_FIRMWARE (firmware)) != fu_thunderbolt_firmware_is_host (firmware_old)) { g_set_error (error, FWUPD_ERROR, FWUPD_ERROR_INVALID_FILE, "incorrect firmware mode, got %s, expected %s", - fu_thunderbolt_firmware_is_host (firmware) ? "host" : "device", + fu_thunderbolt_firmware_is_host (FU_THUNDERBOLT_FIRMWARE (firmware)) ? "host" : "device", fu_thunderbolt_firmware_is_host (firmware_old) ? "host" : "device"); return NULL; } - if (fu_thunderbolt_firmware_get_vendor_id (firmware) != + if (fu_thunderbolt_firmware_get_vendor_id (FU_THUNDERBOLT_FIRMWARE (firmware)) != fu_thunderbolt_firmware_get_vendor_id (firmware_old)) { g_set_error (error, FWUPD_ERROR, FWUPD_ERROR_INVALID_FILE, "incorrect device vendor, got 0x%04x, expected 0x%04x", - fu_thunderbolt_firmware_get_vendor_id (firmware), + fu_thunderbolt_firmware_get_vendor_id (FU_THUNDERBOLT_FIRMWARE (firmware)), fu_thunderbolt_firmware_get_vendor_id (firmware_old)); return NULL; } - if (fu_thunderbolt_firmware_get_device_id (firmware) != + if (fu_thunderbolt_firmware_get_device_id (FU_THUNDERBOLT_FIRMWARE (firmware)) != fu_thunderbolt_firmware_get_device_id (firmware_old)) { g_set_error (error, FWUPD_ERROR, FWUPD_ERROR_INVALID_FILE, "incorrect device type, got 0x%04x, expected 0x%04x", - fu_thunderbolt_firmware_get_device_id (firmware), + fu_thunderbolt_firmware_get_device_id (FU_THUNDERBOLT_FIRMWARE (firmware)), fu_thunderbolt_firmware_get_device_id (firmware_old)); return NULL; } if ((flags & FWUPD_INSTALL_FLAG_FORCE) == 0) { - if (fu_thunderbolt_firmware_get_model_id (firmware) != + if (fu_thunderbolt_firmware_get_model_id (FU_THUNDERBOLT_FIRMWARE (firmware)) != fu_thunderbolt_firmware_get_model_id (firmware_old)) { g_set_error (error, FWUPD_ERROR, FWUPD_ERROR_INVALID_FILE, "incorrect device model, got 0x%04x, expected 0x%04x", - fu_thunderbolt_firmware_get_model_id (firmware), + fu_thunderbolt_firmware_get_model_id (FU_THUNDERBOLT_FIRMWARE (firmware)), fu_thunderbolt_firmware_get_model_id (firmware_old)); return NULL; } - if (fu_thunderbolt_firmware_get_has_pd (firmware) != - fu_thunderbolt_firmware_get_has_pd (firmware_old)) { + /* old firmware has PD but new doesn't (we don't care about other way around) */ + if (fu_thunderbolt_firmware_get_has_pd (firmware_old) && + !fu_thunderbolt_firmware_get_has_pd (FU_THUNDERBOLT_FIRMWARE (firmware))) { g_set_error_literal (error, FWUPD_ERROR, FWUPD_ERROR_INVALID_FILE, "incorrect PD section"); return NULL; } - if (fu_thunderbolt_firmware_get_flash_size (firmware) != + if (fu_thunderbolt_firmware_get_flash_size (FU_THUNDERBOLT_FIRMWARE (firmware)) != fu_thunderbolt_firmware_get_flash_size (firmware_old)) { g_set_error_literal (error, FWUPD_ERROR, diff --git a/plugins/thunderbolt/fu-thunderbolt-firmware-update.c b/plugins/thunderbolt/fu-thunderbolt-firmware-update.c new file mode 100644 index 000000000..47203f0de --- /dev/null +++ b/plugins/thunderbolt/fu-thunderbolt-firmware-update.c @@ -0,0 +1,108 @@ +/* + * Copyright (C) 2020 Mario Limonciello + * + * SPDX-License-Identifier: LGPL-2.1+ + */ + +#include "config.h" + +#include + +#include "fu-common.h" +#include "fu-thunderbolt-firmware.h" +#include "fu-thunderbolt-firmware-update.h" + +struct _FuThunderboltFirmwareUpdate { + FuThunderboltFirmwareClass parent_instance; +}; + +G_DEFINE_TYPE (FuThunderboltFirmwareUpdate, fu_thunderbolt_firmware_update, FU_TYPE_THUNDERBOLT_FIRMWARE) + +static inline gboolean +fu_thunderbolt_firmware_valid_farb_pointer (guint32 pointer) +{ + return pointer != 0 && pointer != 0xFFFFFF; +} + +static gboolean +fu_thunderbolt_firmware_read_farb_pointer_impl (FuThunderboltFirmwareUpdate *self, + FuThunderboltSection section, + guint32 offset, + guint32 *value, + GError **error) +{ + FuThunderboltFirmware *tbt = FU_THUNDERBOLT_FIRMWARE (self); + guint32 tmp = 0; + if (!fu_thunderbolt_firmware_read_location (tbt, section, offset, + (guint8 *) &tmp, 3, /* 24 bits */ + error)) { + g_prefix_error (error, "failed to read farb pointer: "); + return FALSE; + } + *value = GUINT32_FROM_LE (tmp); + return TRUE; +} + + +/* returns invalid FARB pointer on error */ +static guint32 +fu_thunderbolt_firmware_read_farb_pointer (FuThunderboltFirmwareUpdate *self, GError **error) +{ + guint32 value; + if (!fu_thunderbolt_firmware_read_farb_pointer_impl (self, + _SECTION_DIGITAL, + 0x0, &value, error)) + return 0; + if (fu_thunderbolt_firmware_valid_farb_pointer (value)) + return value; + + if (!fu_thunderbolt_firmware_read_farb_pointer_impl (self, + _SECTION_DIGITAL, + 0x1000, &value, error)) + return 0; + if (!fu_thunderbolt_firmware_valid_farb_pointer (value)) { + g_set_error_literal (error, + FWUPD_ERROR, + FWUPD_ERROR_INVALID_FILE, + "Invalid FW image file format"); + return 0; + } + + return value; +} + +static gboolean +fu_thunderbolt_firmware_update_parse (FuFirmware *firmware, + GBytes *fw, + guint64 addr_start, + guint64 addr_end, + FwupdInstallFlags flags, + GError **error) +{ + FuThunderboltFirmwareUpdate *self = FU_THUNDERBOLT_FIRMWARE_UPDATE (firmware); + guint32 offset = fu_thunderbolt_firmware_read_farb_pointer (self, error); + if (offset == 0) + return FALSE; + g_debug ("detected digital section begins at 0x%x", offset); + fu_thunderbolt_firmware_set_digital (FU_THUNDERBOLT_FIRMWARE (firmware), offset); + + return TRUE; +} + +static void +fu_thunderbolt_firmware_update_init (FuThunderboltFirmwareUpdate *self) +{ +} + +static void +fu_thunderbolt_firmware_update_class_init (FuThunderboltFirmwareUpdateClass *klass) +{ + FuThunderboltFirmwareClass *klass_firmware = FU_THUNDERBOLT_FIRMWARE_CLASS (klass); + klass_firmware->parse = fu_thunderbolt_firmware_update_parse; +} + +FuThunderboltFirmwareUpdate * +fu_thunderbolt_firmware_update_new (void) +{ + return g_object_new (FU_TYPE_THUNDERBOLT_FIRMWARE_UPDATE, NULL); +} diff --git a/plugins/thunderbolt/fu-thunderbolt-firmware-update.h b/plugins/thunderbolt/fu-thunderbolt-firmware-update.h new file mode 100644 index 000000000..eb29e4fae --- /dev/null +++ b/plugins/thunderbolt/fu-thunderbolt-firmware-update.h @@ -0,0 +1,14 @@ +/* + * Copyright (C) 2020 Mario Limonciello + * + * SPDX-License-Identifier: LGPL-2.1+ + */ + +#pragma once + +#include "fu-firmware.h" + +#define FU_TYPE_THUNDERBOLT_FIRMWARE_UPDATE (fu_thunderbolt_firmware_update_get_type ()) +G_DECLARE_FINAL_TYPE (FuThunderboltFirmwareUpdate, fu_thunderbolt_firmware_update, FU,THUNDERBOLT_FIRMWARE_UPDATE, FuThunderboltFirmware) + +FuThunderboltFirmwareUpdate *fu_thunderbolt_firmware_update_new (void); \ No newline at end of file diff --git a/plugins/thunderbolt/fu-thunderbolt-firmware.c b/plugins/thunderbolt/fu-thunderbolt-firmware.c index a01e81b05..78a7a8cfd 100644 --- a/plugins/thunderbolt/fu-thunderbolt-firmware.c +++ b/plugins/thunderbolt/fu-thunderbolt-firmware.c @@ -12,26 +12,8 @@ #include "fu-common.h" #include "fu-thunderbolt-firmware.h" -typedef enum { - _SECTION_DIGITAL, - _SECTION_DROM, - _SECTION_ARC_PARAMS, - _SECTION_DRAM_UCODE, - _SECTION_LAST -} FuThunderboltSection; - -typedef enum { - _FAMILY_UNKNOWN, - _FAMILY_FR, - _FAMILY_WR, - _FAMILY_AR, - _FAMILY_AR_C, - _FAMILY_TR, - _FAMILY_BB, -} FuThunderboltFamily; - -struct _FuThunderboltFirmware { - FuFirmwareClass parent_instance; +typedef struct +{ guint32 sections[_SECTION_LAST]; FuThunderboltFamily family; gboolean is_host; @@ -43,9 +25,11 @@ struct _FuThunderboltFirmware { guint gen; guint ports; guint8 flash_size; -}; +} FuThunderboltFirmwarePrivate; -G_DEFINE_TYPE (FuThunderboltFirmware, fu_thunderbolt_firmware, FU_TYPE_FIRMWARE) +G_DEFINE_TYPE_WITH_PRIVATE (FuThunderboltFirmware, fu_thunderbolt_firmware, FU_TYPE_FIRMWARE) + +#define GET_PRIVATE(o) (fu_thunderbolt_firmware_get_instance_private (o)) typedef struct { guint16 id; @@ -61,50 +45,64 @@ enum { gboolean fu_thunderbolt_firmware_is_host (FuThunderboltFirmware *self) { + FuThunderboltFirmwarePrivate *priv; g_return_val_if_fail (FU_IS_THUNDERBOLT_FIRMWARE (self), FALSE); - return self->is_host; + priv = GET_PRIVATE (self); + return priv->is_host; } gboolean fu_thunderbolt_firmware_is_native (FuThunderboltFirmware *self) { + FuThunderboltFirmwarePrivate *priv; g_return_val_if_fail (FU_IS_THUNDERBOLT_FIRMWARE (self), FALSE); - return self->is_native; + priv = GET_PRIVATE (self); + return priv->is_native; } gboolean fu_thunderbolt_firmware_get_has_pd (FuThunderboltFirmware *self) { + FuThunderboltFirmwarePrivate *priv; g_return_val_if_fail (FU_IS_THUNDERBOLT_FIRMWARE (self), FALSE); - return self->has_pd; + priv = GET_PRIVATE (self); + return priv->has_pd; } guint16 fu_thunderbolt_firmware_get_device_id (FuThunderboltFirmware *self) { - g_return_val_if_fail (FU_IS_THUNDERBOLT_FIRMWARE (self), 0); - return self->device_id; + FuThunderboltFirmwarePrivate *priv; + g_return_val_if_fail (FU_IS_THUNDERBOLT_FIRMWARE (self), FALSE); + priv = GET_PRIVATE (self); + return priv->device_id; } guint16 fu_thunderbolt_firmware_get_vendor_id (FuThunderboltFirmware *self) { - g_return_val_if_fail (FU_IS_THUNDERBOLT_FIRMWARE (self), 0); - return self->vendor_id; + FuThunderboltFirmwarePrivate *priv; + g_return_val_if_fail (FU_IS_THUNDERBOLT_FIRMWARE (self), FALSE); + priv = GET_PRIVATE (self); + return priv->vendor_id; } guint16 fu_thunderbolt_firmware_get_model_id (FuThunderboltFirmware *self) { - g_return_val_if_fail (FU_IS_THUNDERBOLT_FIRMWARE (self), 0); - return self->model_id; + FuThunderboltFirmwarePrivate *priv; + g_return_val_if_fail (FU_IS_THUNDERBOLT_FIRMWARE (self), FALSE); + priv = GET_PRIVATE (self); + return priv->model_id; } guint8 fu_thunderbolt_firmware_get_flash_size (FuThunderboltFirmware *self) { - g_return_val_if_fail (FU_IS_THUNDERBOLT_FIRMWARE (self), 0); - return self->flash_size; + FuThunderboltFirmwarePrivate *priv; + g_return_val_if_fail (FU_IS_THUNDERBOLT_FIRMWARE (self), FALSE); + priv = GET_PRIVATE (self); + return priv->flash_size; } static const gchar * @@ -129,36 +127,32 @@ static void fu_thunderbolt_firmware_to_string (FuFirmware *firmware, guint idt, GString *str) { FuThunderboltFirmware *self = FU_THUNDERBOLT_FIRMWARE (firmware); + FuThunderboltFirmwarePrivate *priv = GET_PRIVATE (self); + fu_common_string_append_kv (str, idt, "Family", - fu_thunderbolt_firmware_family_to_string (self->family)); - fu_common_string_append_kb (str, idt, "IsHost", self->is_host); - fu_common_string_append_kb (str, idt, "IsNative", self->is_native); - fu_common_string_append_kx (str, idt, "DeviceId", self->device_id); - fu_common_string_append_kx (str, idt, "VendorId", self->vendor_id); - fu_common_string_append_kx (str, idt, "ModelId", self->model_id); - fu_common_string_append_kx (str, idt, "FlashSize", self->flash_size); - fu_common_string_append_kx (str, idt, "Generation", self->gen); - fu_common_string_append_kx (str, idt, "Ports", self->ports); - fu_common_string_append_kb (str, idt, "HasPd", self->has_pd); + fu_thunderbolt_firmware_family_to_string (priv->family)); + fu_common_string_append_kb (str, idt, "IsHost", priv->is_host); + fu_common_string_append_kb (str, idt, "IsNative", priv->is_native); + fu_common_string_append_kx (str, idt, "DeviceId", priv->device_id); + fu_common_string_append_kx (str, idt, "VendorId", priv->vendor_id); + fu_common_string_append_kx (str, idt, "ModelId", priv->model_id); + fu_common_string_append_kx (str, idt, "FlashSize", priv->flash_size); + fu_common_string_append_kx (str, idt, "Generation", priv->gen); + fu_common_string_append_kx (str, idt, "Ports", priv->ports); + fu_common_string_append_kb (str, idt, "HasPd", priv->has_pd); for (guint i = 0; i < _SECTION_LAST; i++) { g_autofree gchar *title = g_strdup_printf ("Section%u", i); - fu_common_string_append_kx (str, idt, title, self->sections[i]); + fu_common_string_append_kx (str, idt, title, priv->sections[i]); } } -static inline gboolean -fu_thunderbolt_firmware_valid_farb_pointer (guint32 pointer) -{ - return pointer != 0 && pointer != 0xFFFFFF; -} - static inline gboolean fu_thunderbolt_firmware_valid_pd_pointer (guint32 pointer) { return pointer != 0 && pointer != 0xFFFFFFFF; } -static gboolean +gboolean fu_thunderbolt_firmware_read_location (FuThunderboltFirmware *self, FuThunderboltSection section, guint32 offset, @@ -168,7 +162,8 @@ fu_thunderbolt_firmware_read_location (FuThunderboltFirmware *self, { const guint8 *srcbuf; gsize srcbufsz = 0; - guint32 location_start = self->sections[section] + offset; + FuThunderboltFirmwarePrivate *priv = GET_PRIVATE (self); + guint32 location_start = priv->sections[section] + offset; g_autoptr(GBytes) fw = NULL; /* get blob */ @@ -186,51 +181,6 @@ fu_thunderbolt_firmware_read_location (FuThunderboltFirmware *self, return TRUE; } -static gboolean -fu_thunderbolt_firmware_read_farb_pointer_impl (FuThunderboltFirmware *self, - FuThunderboltSection section, - guint32 offset, - guint32 *value, - GError **error) -{ - guint32 tmp = 0; - if (!fu_thunderbolt_firmware_read_location (self, section, offset, - (guint8 *) &tmp, 3, /* 24 bits */ - error)) { - g_prefix_error (error, "failed to read farb pointer: "); - return FALSE; - } - *value = GUINT32_FROM_LE (tmp); - return TRUE; -} - -/* returns invalid FARB pointer on error */ -static guint32 -fu_thunderbolt_firmware_read_farb_pointer (FuThunderboltFirmware *self, GError **error) -{ - guint32 value; - if (!fu_thunderbolt_firmware_read_farb_pointer_impl (self, - _SECTION_DIGITAL, - 0x0, &value, error)) - return 0; - if (fu_thunderbolt_firmware_valid_farb_pointer (value)) - return value; - - if (!fu_thunderbolt_firmware_read_farb_pointer_impl (self, - _SECTION_DIGITAL, - 0x1000, &value, error)) - return 0; - if (!fu_thunderbolt_firmware_valid_farb_pointer (value)) { - g_set_error_literal (error, - FWUPD_ERROR, - FWUPD_ERROR_INVALID_FILE, - "Invalid FW image file format"); - return 0; - } - - return value; -} - static gboolean fu_thunderbolt_firmware_read_uint8 (FuThunderboltFirmware *self, FuThunderboltSection section, @@ -310,15 +260,16 @@ static gboolean fu_thunderbolt_firmware_read_sections (FuThunderboltFirmware *self, GError **error) { guint32 offset; + FuThunderboltFirmwarePrivate *priv = GET_PRIVATE (self); - if (self->gen >= 3 || self->gen == 0) { + if (priv->gen >= 3 || priv->gen == 0) { if (!fu_thunderbolt_firmware_read_uint32 (self, _SECTION_DIGITAL, 0x10e, &offset, error)) return FALSE; - self->sections[_SECTION_DROM] = offset + self->sections[_SECTION_DIGITAL]; + priv->sections[_SECTION_DROM] = offset + priv->sections[_SECTION_DIGITAL]; if (!fu_thunderbolt_firmware_read_uint32 (self, _SECTION_DIGITAL, @@ -326,10 +277,10 @@ fu_thunderbolt_firmware_read_sections (FuThunderboltFirmware *self, GError **err &offset, error)) return FALSE; - self->sections[_SECTION_ARC_PARAMS] = offset + self->sections[_SECTION_DIGITAL]; + priv->sections[_SECTION_ARC_PARAMS] = offset + priv->sections[_SECTION_DIGITAL]; } - if (self->is_host && self->gen > 2) { + if (priv->is_host && priv->gen > 2) { /* * To find the DRAM section, we have to jump from section to * section in a chain of sections. @@ -381,7 +332,7 @@ fu_thunderbolt_firmware_read_sections (FuThunderboltFirmware *self, GError **err offset += ucode_offset; } } - self->sections[_SECTION_DRAM_UCODE] = offset + self->sections[_SECTION_DIGITAL]; + priv->sections[_SECTION_DRAM_UCODE] = offset + priv->sections[_SECTION_DIGITAL]; } return TRUE; @@ -390,13 +341,21 @@ fu_thunderbolt_firmware_read_sections (FuThunderboltFirmware *self, GError **err static gboolean fu_thunderbolt_firmware_missing_needed_drom (FuThunderboltFirmware *self) { - if (self->sections[_SECTION_DROM] != 0) + FuThunderboltFirmwarePrivate *priv = GET_PRIVATE (self); + if (priv->sections[_SECTION_DROM] != 0) return FALSE; - if (self->is_host && self->gen < 3) + if (priv->is_host && priv->gen < 3) return FALSE; return TRUE; } +void +fu_thunderbolt_firmware_set_digital (FuThunderboltFirmware *self, guint32 offset) +{ + FuThunderboltFirmwarePrivate *priv = GET_PRIVATE (self); + priv->sections[_SECTION_DIGITAL] = offset; +} + static gboolean fu_thunderbolt_firmware_parse (FuFirmware *firmware, GBytes *fw, @@ -406,6 +365,9 @@ fu_thunderbolt_firmware_parse (FuFirmware *firmware, GError **error) { FuThunderboltFirmware *self = FU_THUNDERBOLT_FIRMWARE (firmware); + FuThunderboltFirmwarePrivate *priv = GET_PRIVATE (self); + FuThunderboltFirmwareClass *klass_firmware = FU_THUNDERBOLT_FIRMWARE_GET_CLASS (firmware); + guint8 tmp = 0; static const FuThunderboltHwInfo hw_info_arr[] = { { 0x156D, 2, _FAMILY_FR, 2 }, /* FR 4C */ @@ -428,6 +390,12 @@ fu_thunderbolt_firmware_parse (FuFirmware *firmware, /* add this straight away so we can read it without a self */ fu_firmware_add_image (firmware, img); + /* subclassed */ + if (klass_firmware->parse != NULL) { + if (!klass_firmware->parse (firmware, fw, addr_start, addr_end, flags, error)) + return FALSE; + } + /* is native */ if (!fu_thunderbolt_firmware_read_uint8 (self, _SECTION_DIGITAL, @@ -436,11 +404,7 @@ fu_thunderbolt_firmware_parse (FuFirmware *firmware, g_prefix_error (error, "failed to read native: "); return FALSE; } - self->is_native = tmp & 0x20; - - self->sections[_SECTION_DIGITAL] = fu_thunderbolt_firmware_read_farb_pointer (self, error); - if (self->sections[_SECTION_DIGITAL] == 0) - return FALSE; + priv->is_native = tmp & 0x20; /* we're only reading the first chunk */ if (g_bytes_get_size (fw) == 0x80) @@ -453,13 +417,13 @@ fu_thunderbolt_firmware_parse (FuFirmware *firmware, g_prefix_error (error, "failed to read is-host: "); return FALSE; } - self->is_host = tmp & (1 << 1); + priv->is_host = tmp & (1 << 1); /* device ID */ if (!fu_thunderbolt_firmware_read_uint16 (self, _SECTION_DIGITAL, 0x5, - &self->device_id, + &priv->device_id, error)) { g_prefix_error (error, "failed to read device-id: "); return FALSE; @@ -467,14 +431,14 @@ fu_thunderbolt_firmware_parse (FuFirmware *firmware, /* this is best-effort */ for (guint i = 0; hw_info_arr[i].id != 0; i++) { - if (hw_info_arr[i].id == self->device_id) { - self->family = hw_info_arr[i].family; - self->gen = hw_info_arr[i].gen; - self->ports = hw_info_arr[i].ports; + if (hw_info_arr[i].id == priv->device_id) { + priv->family = hw_info_arr[i].family; + priv->gen = hw_info_arr[i].gen; + priv->ports = hw_info_arr[i].ports; break; } } - if (self->ports == 0 && self->is_host) { + if (priv->ports == 0 && priv->is_host) { g_set_error (error, FWUPD_ERROR, FWUPD_ERROR_NOT_SUPPORTED, @@ -494,11 +458,11 @@ fu_thunderbolt_firmware_parse (FuFirmware *firmware, } /* vendor:model */ - if (self->sections[_SECTION_DROM] != 0) { + if (priv->sections[_SECTION_DROM] != 0) { if (!fu_thunderbolt_firmware_read_uint16 (self, _SECTION_DROM, 0x10, - &self->vendor_id, + &priv->vendor_id, error)) { g_prefix_error (error, "failed to read vendor-id: "); return FALSE; @@ -506,7 +470,7 @@ fu_thunderbolt_firmware_parse (FuFirmware *firmware, if (!fu_thunderbolt_firmware_read_uint16 (self, _SECTION_DROM, 0x12, - &self->model_id, + &priv->model_id, error)) { g_prefix_error (error, "failed to read model-id: "); return FALSE; @@ -514,7 +478,7 @@ fu_thunderbolt_firmware_parse (FuFirmware *firmware, } /* has PD */ - if (self->sections[_SECTION_ARC_PARAMS] != 0) { + if (priv->sections[_SECTION_ARC_PARAMS] != 0) { guint32 pd_pointer = 0x0; if (!fu_thunderbolt_firmware_read_uint32 (self, _SECTION_ARC_PARAMS, @@ -524,11 +488,11 @@ fu_thunderbolt_firmware_parse (FuFirmware *firmware, g_prefix_error (error, "failed to read pd-pointer: "); return FALSE; } - self->has_pd = fu_thunderbolt_firmware_valid_pd_pointer (pd_pointer); + priv->has_pd = fu_thunderbolt_firmware_valid_pd_pointer (pd_pointer); } - if (self->is_host) { - switch (self->family) { + if (priv->is_host) { + switch (priv->family) { case _FAMILY_AR: case _FAMILY_AR_C: case _FAMILY_TR: @@ -541,7 +505,7 @@ fu_thunderbolt_firmware_parse (FuFirmware *firmware, g_prefix_error (error, "failed to read flash size: "); return FALSE; } - self->flash_size = tmp & 0x07; + priv->flash_size = tmp & 0x07; break; default: break; diff --git a/plugins/thunderbolt/fu-thunderbolt-firmware.h b/plugins/thunderbolt/fu-thunderbolt-firmware.h index b6ca050b0..8f07676bd 100644 --- a/plugins/thunderbolt/fu-thunderbolt-firmware.h +++ b/plugins/thunderbolt/fu-thunderbolt-firmware.h @@ -10,7 +10,38 @@ #include "fu-firmware.h" #define FU_TYPE_THUNDERBOLT_FIRMWARE (fu_thunderbolt_firmware_get_type ()) -G_DECLARE_FINAL_TYPE (FuThunderboltFirmware, fu_thunderbolt_firmware, FU,THUNDERBOLT_FIRMWARE, FuFirmware) +G_DECLARE_DERIVABLE_TYPE (FuThunderboltFirmware, fu_thunderbolt_firmware, FU,THUNDERBOLT_FIRMWARE, FuFirmware) + +typedef enum { + _SECTION_DIGITAL, + _SECTION_DROM, + _SECTION_ARC_PARAMS, + _SECTION_DRAM_UCODE, + _SECTION_LAST +} FuThunderboltSection; + +typedef enum { + _FAMILY_UNKNOWN, + _FAMILY_FR, + _FAMILY_WR, + _FAMILY_AR, + _FAMILY_AR_C, + _FAMILY_TR, + _FAMILY_BB, +} FuThunderboltFamily; + +struct _FuThunderboltFirmwareClass +{ + FuFirmwareClass parent_class; + gboolean (*parse) (FuFirmware *self, + GBytes *fw, + guint64 addr_start, + guint64 addr_end, + FwupdInstallFlags flags, + GError **error); + /*< private >*/ + gpointer padding[28]; +}; /* byte offsets in firmware image */ #define FU_TBT_OFFSET_NATIVE 0x7B @@ -24,3 +55,11 @@ guint16 fu_thunderbolt_firmware_get_device_id (FuThunderboltFirmware *self); guint16 fu_thunderbolt_firmware_get_vendor_id (FuThunderboltFirmware *self); guint16 fu_thunderbolt_firmware_get_model_id (FuThunderboltFirmware *self); guint8 fu_thunderbolt_firmware_get_flash_size (FuThunderboltFirmware *self); +void fu_thunderbolt_firmware_set_digital (FuThunderboltFirmware *self, + guint32 offset); +gboolean fu_thunderbolt_firmware_read_location (FuThunderboltFirmware *self, + FuThunderboltSection section, + guint32 offset, + guint8 *buf, + guint32 len, + GError **error); diff --git a/plugins/thunderbolt/meson.build b/plugins/thunderbolt/meson.build index 6a805d11b..6b2368fb3 100644 --- a/plugins/thunderbolt/meson.build +++ b/plugins/thunderbolt/meson.build @@ -11,6 +11,7 @@ fu_plugin_thunderbolt = shared_module('fu_plugin_thunderbolt', 'fu-plugin-thunderbolt.c', 'fu-thunderbolt-device.c', 'fu-thunderbolt-firmware.c', + 'fu-thunderbolt-firmware-update.c', ], include_directories : [ root_incdir, @@ -43,6 +44,7 @@ if get_option('tests') and umockdev.found() and gio.version().version_compare('> 'fu-plugin-thunderbolt.c', 'fu-thunderbolt-device.c', 'fu-thunderbolt-firmware.c', + 'fu-thunderbolt-firmware-update.c', ], include_directories : [ root_incdir, From da0d1880e1486e3b1f9480736108ae175e07616e Mon Sep 17 00:00:00 2001 From: Mario Limonciello Date: Tue, 5 May 2020 14:16:39 -0500 Subject: [PATCH 028/607] trivial: fu-engine: return firmware gtypes in a sorted list This makes the output in `firmware-parse` more predictable --- src/fu-engine.c | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/src/fu-engine.c b/src/fu-engine.c index 48c9c2772..c5f9dd073 100644 --- a/src/fu-engine.c +++ b/src/fu-engine.c @@ -136,6 +136,14 @@ fu_engine_emit_device_changed (FuEngine *self, FuDevice *device) g_signal_emit (self, signals[SIGNAL_DEVICE_CHANGED], 0, device); } +static gint +fu_engine_gtypes_sort_cb (gconstpointer a, gconstpointer b) +{ + const gchar *stra = *((const gchar **) a); + const gchar *strb = *((const gchar **) b); + return g_strcmp0 (stra, strb); +} + GPtrArray * fu_engine_get_firmware_gtype_ids (FuEngine *self) { @@ -145,6 +153,7 @@ fu_engine_get_firmware_gtype_ids (FuEngine *self) const gchar *id = l->data; g_ptr_array_add (firmware_gtypes, g_strdup (id)); } + g_ptr_array_sort (firmware_gtypes, fu_engine_gtypes_sort_cb); return firmware_gtypes; } From 0cd2f107113b23774187addb29611dd1daa019c6 Mon Sep 17 00:00:00 2001 From: Mario Limonciello Date: Tue, 5 May 2020 15:52:12 -0500 Subject: [PATCH 029/607] trivial: dell-dock: delay activation of the thunderbolt updates There was some regression between 1.4.0 and now that prevented updates containing a Thunderbolt controller from finishing. They would just sit pending Thunderbolt replug without ever finishing. Remove the old hack for replug and instead push activation to the end of the composite steps. This is to avoid the device tree from changing significantly during the update process. This still isn't really ideal, we want to be able to add the flag usable-during-update to the thunderbolt controller, but this requires some extra work in the kernel. --- plugins/dell-dock/dell-dock.quirk | 2 +- plugins/dell-dock/fu-plugin-dell-dock.c | 52 +++++++++---------------- 2 files changed, 20 insertions(+), 34 deletions(-) diff --git a/plugins/dell-dock/dell-dock.quirk b/plugins/dell-dock/dell-dock.quirk index 4b1257fce..2fb452947 100644 --- a/plugins/dell-dock/dell-dock.quirk +++ b/plugins/dell-dock/dell-dock.quirk @@ -107,7 +107,7 @@ VendorId = TBT:0x00D4 ParentGuid = USB\VID_413C&PID_B06E&hub&embedded FirmwareSizeMin=0x40000 FirmwareSizeMax=0x80000 -Flags = require-ac,dual-image +Flags = skip-restart,require-ac,dual-image Icon = thunderbolt InstallDuration = 22 DellDockInstallDurationI2C = 181 diff --git a/plugins/dell-dock/fu-plugin-dell-dock.c b/plugins/dell-dock/fu-plugin-dell-dock.c index 67b249499..a6070e915 100644 --- a/plugins/dell-dock/fu-plugin-dell-dock.c +++ b/plugins/dell-dock/fu-plugin-dell-dock.c @@ -164,38 +164,6 @@ fu_plugin_dell_dock_get_ec (GPtrArray *devices) return ec_parent; } -gboolean -fu_plugin_composite_prepare (FuPlugin *plugin, - GPtrArray *devices, - GError **error) -{ - FuDevice *parent = fu_plugin_dell_dock_get_ec (devices); - gboolean remaining_replug = FALSE; - - if (parent == NULL) - return TRUE; - - for (guint i = 0; i < devices->len; i++) { - FuDevice *dev = g_ptr_array_index (devices, i); - /* if thunderbolt is part of transaction our family is leaving us */ - if (g_strcmp0 (fu_device_get_plugin (dev), "thunderbolt") == 0) { - if (fu_device_get_parent (dev) != parent) - continue; - fu_dell_dock_will_replug (parent); - /* set all other devices to replug */ - remaining_replug = TRUE; - continue; - } - /* different device */ - if (fu_device_get_parent (dev) != parent) - continue; - if (remaining_replug) - fu_dell_dock_will_replug (dev); - } - - return TRUE; -} - gboolean fu_plugin_composite_cleanup (FuPlugin *plugin, GPtrArray *devices, @@ -211,5 +179,23 @@ fu_plugin_composite_cleanup (FuPlugin *plugin, if (locker == NULL) return FALSE; - return fu_dell_dock_ec_reboot_dock (parent, error); + if (!fu_dell_dock_ec_reboot_dock (parent, error)) + return FALSE; + + /* close this first so we don't have an error from the thunderbolt activation */ + if (!fu_device_locker_close (locker, error)) + return FALSE; + + /* if thunderbolt is in the transaction it needs to be activated separately */ + for (guint i = 0; i < devices->len; i++) { + FuDevice *dev = g_ptr_array_index (devices, i); + if (g_strcmp0 (fu_device_get_plugin (dev), "thunderbolt") == 0 && + fu_device_has_flag (dev, FWUPD_DEVICE_FLAG_NEEDS_ACTIVATION)) { + if (!fu_device_activate (dev, error)) + return FALSE; + break; + } + } + + return TRUE; } From 2d6456e0196bddbabaefb06f7fe21d33967116db Mon Sep 17 00:00:00 2001 From: Richard Hughes Date: Wed, 6 May 2020 17:32:52 +0100 Subject: [PATCH 030/607] cpu: Parse the CPU flags to detect the CET status New enough hardware to have this feature isn't going to be in the marketplace for a while. To use that newer hardware requires a very recent kernel (5.6 at least, although it will probably be at least 5.9 by the time the hardware is released). The CET status will be used in future functionality. --- plugins/cpu/fu-cpu-device.c | 44 ++++++++++++++++++++++++++++++++++++- plugins/cpu/fu-cpu-device.h | 2 ++ 2 files changed, 45 insertions(+), 1 deletion(-) diff --git a/plugins/cpu/fu-cpu-device.c b/plugins/cpu/fu-cpu-device.c index aa1fae22e..424865322 100644 --- a/plugins/cpu/fu-cpu-device.c +++ b/plugins/cpu/fu-cpu-device.c @@ -10,13 +10,49 @@ struct _FuCpuDevice { FuDevice parent_instance; + gboolean has_shstk; + gboolean has_ibt; }; G_DEFINE_TYPE (FuCpuDevice, fu_cpu_device, FU_TYPE_DEVICE) -static void fu_cpu_device_parse_section (FuDevice *dev, const gchar *data) +gboolean +fu_cpu_device_has_shstk (FuCpuDevice *self) +{ + return self->has_shstk; +} + +gboolean +fu_cpu_device_has_ibt (FuCpuDevice *self) +{ + return self->has_ibt; +} + +static void +fu_cpu_device_to_string (FuDevice *device, guint idt, GString *str) +{ + FuCpuDevice *self = FU_CPU_DEVICE (device); + fu_common_string_append_kb (str, idt, "HasSHSTK", self->has_shstk); + fu_common_string_append_kb (str, idt, "HasIBT", self->has_ibt); +} + +static void +fu_cpu_device_parse_flags (FuCpuDevice *self, const gchar *data) +{ + g_auto(GStrv) flags = g_strsplit (data, " ", -1); + for (guint i = 0; flags[i] != NULL; i++) { + if (g_strcmp0 (flags[i], "shstk") == 0) + self->has_shstk = TRUE; + if (g_strcmp0 (flags[i], "ibt") == 0) + self->has_ibt = TRUE; + } +} + +static void +fu_cpu_device_parse_section (FuDevice *dev, const gchar *data) { g_auto(GStrv) lines = NULL; + FuCpuDevice *self = FU_CPU_DEVICE (dev); lines = g_strsplit (data, "\n", 0); for (guint i = 0; lines[i] != NULL; i++) { @@ -38,6 +74,10 @@ static void fu_cpu_device_parse_section (FuDevice *dev, const gchar *data) g_autofree gchar *tmp = g_strdup_printf ("cpu:%s", g_strchug (fields[1])); fu_device_set_physical_id (dev, tmp); } + } else if (g_str_has_prefix (lines[i], "flags")) { + g_auto(GStrv) fields = g_strsplit (lines[i], ":", -1); + if (fields[1] != NULL) + fu_cpu_device_parse_flags (self, fields[1]); } } } @@ -54,6 +94,8 @@ fu_cpu_device_init (FuCpuDevice *self) static void fu_cpu_device_class_init (FuCpuDeviceClass *klass) { + FuDeviceClass *klass_device = FU_DEVICE_CLASS (klass); + klass_device->to_string = fu_cpu_device_to_string; } FuCpuDevice * diff --git a/plugins/cpu/fu-cpu-device.h b/plugins/cpu/fu-cpu-device.h index 1796c6b91..1d198de58 100644 --- a/plugins/cpu/fu-cpu-device.h +++ b/plugins/cpu/fu-cpu-device.h @@ -12,3 +12,5 @@ G_DECLARE_FINAL_TYPE (FuCpuDevice, fu_cpu_device, FU, CPU_DEVICE, FuDevice) FuCpuDevice *fu_cpu_device_new (const gchar *section); +gboolean fu_cpu_device_has_shstk (FuCpuDevice *self); +gboolean fu_cpu_device_has_ibt (FuCpuDevice *self); From 768a2680a6546395d2a89f53bdeac689870d2788 Mon Sep 17 00:00:00 2001 From: Mario Limonciello Date: Wed, 29 Apr 2020 11:18:43 -0500 Subject: [PATCH 031/607] Introduce a new flag skips-restart This flag is used internally by plugins to indicate that they will skip the phase of firmware installation that power cycles a device. It is intended to be set by quirks or other environment settings. --- libfwupd/fwupd-enums.c | 4 ++++ libfwupd/fwupd-enums.h | 2 ++ plugins/dell-dock/README.md | 6 ------ plugins/dell-dock/dell-dock.quirk | 4 ++-- plugins/dell-dock/fu-dell-dock-i2c-ec.c | 4 ++-- plugins/synaptics-mst/fu-plugin-synaptics-mst.c | 2 +- plugins/synaptics-mst/fu-synaptics-mst-device.c | 2 +- plugins/synaptics-mst/synaptics-mst.quirk | 2 +- plugins/thunderbolt/fu-thunderbolt-device.c | 2 +- src/fu-util-common.c | 4 ++++ 10 files changed, 18 insertions(+), 14 deletions(-) diff --git a/libfwupd/fwupd-enums.c b/libfwupd/fwupd-enums.c index c7a1f972d..16100b8e7 100644 --- a/libfwupd/fwupd-enums.c +++ b/libfwupd/fwupd-enums.c @@ -195,6 +195,8 @@ fwupd_device_flag_to_string (FwupdDeviceFlags device_flag) return "no-guid-matching"; if (device_flag == FWUPD_DEVICE_FLAG_UPDATABLE_HIDDEN) return "updatable-hidden"; + if (device_flag == FWUPD_DEVICE_FLAG_SKIPS_RESTART) + return "skips-restart"; if (device_flag == FWUPD_DEVICE_FLAG_UNKNOWN) return "unknown"; return NULL; @@ -291,6 +293,8 @@ fwupd_device_flag_from_string (const gchar *device_flag) return FWUPD_DEVICE_FLAG_NO_GUID_MATCHING; if (g_strcmp0 (device_flag, "updatable-hidden") == 0) return FWUPD_DEVICE_FLAG_UPDATABLE_HIDDEN; + if (g_strcmp0 (device_flag, "skips-restart") == 0) + return FWUPD_DEVICE_FLAG_SKIPS_RESTART; return FWUPD_DEVICE_FLAG_UNKNOWN; } diff --git a/libfwupd/fwupd-enums.h b/libfwupd/fwupd-enums.h index e57b24cb7..8550a2a2c 100644 --- a/libfwupd/fwupd-enums.h +++ b/libfwupd/fwupd-enums.h @@ -105,6 +105,7 @@ typedef enum { * @FWUPD_DEVICE_FLAG_ADD_COUNTERPART_GUIDS: Add counterpart GUIDs from an alternate mode like bootloader * @FWUPD_DEVICE_FLAG_NO_GUID_MATCHING: Force an explicit ID match when adding devices to the device list * @FWUPD_DEVICE_FLAG_UPDATABLE_HIDDEN: Device is updatable but should not be called by the client + * @FWUPD_DEVICE_FLAG_SKIPS_RESTART: Device relies upon activation or power cycle to load firmware * * The device flags. **/ @@ -147,6 +148,7 @@ typedef enum { #define FWUPD_DEVICE_FLAG_ADD_COUNTERPART_GUIDS (1llu << 35) /* Since: 1.4.0 */ #define FWUPD_DEVICE_FLAG_NO_GUID_MATCHING (1llu << 36) /* Since: 1.4.1 */ #define FWUPD_DEVICE_FLAG_UPDATABLE_HIDDEN (1llu << 37) /* Since: 1.4.1 */ +#define FWUPD_DEVICE_FLAG_SKIPS_RESTART (1llu << 38) /* Since: 1.5.0 */ #define FWUPD_DEVICE_FLAG_UNKNOWN G_MAXUINT64 /* Since: 0.7.3 */ typedef guint64 FwupdDeviceFlags; diff --git a/plugins/dell-dock/README.md b/plugins/dell-dock/README.md index ca24bf82e..67e213972 100644 --- a/plugins/dell-dock/README.md +++ b/plugins/dell-dock/README.md @@ -53,12 +53,6 @@ Vendor ID Security The vendor ID is set from the USB vendor, in this instance set to `USB:0x413C` -Custom flag use: ----------------- -This plugin uses the following plugin-specific custom flags: - -* `skip-restart`: Don't run the reset or reboot procedure of the component - Quirk use --------- This plugin uses the following plugin-specific quirks: diff --git a/plugins/dell-dock/dell-dock.quirk b/plugins/dell-dock/dell-dock.quirk index 2fb452947..2a3c713b8 100644 --- a/plugins/dell-dock/dell-dock.quirk +++ b/plugins/dell-dock/dell-dock.quirk @@ -88,7 +88,7 @@ Summary = Multi Stream Transport controller Vendor = Dell Inc. Plugin = synaptics_mst ParentGuid = USB\VID_413C&PID_B06E&hub&embedded -Flags = skip-restart,require-ac,dual-image,usable-during-update +Flags = skips-restart,require-ac,dual-image,usable-during-update FirmwareSize=524288 DellDockUnlockTarget = 9 InstallDuration = 95 @@ -107,7 +107,7 @@ VendorId = TBT:0x00D4 ParentGuid = USB\VID_413C&PID_B06E&hub&embedded FirmwareSizeMin=0x40000 FirmwareSizeMax=0x80000 -Flags = skip-restart,require-ac,dual-image +Flags = skips-restart,require-ac,dual-image Icon = thunderbolt InstallDuration = 22 DellDockInstallDurationI2C = 181 diff --git a/plugins/dell-dock/fu-dell-dock-i2c-ec.c b/plugins/dell-dock/fu-dell-dock-i2c-ec.c index 13d619896..75f70e91c 100644 --- a/plugins/dell-dock/fu-dell-dock-i2c-ec.c +++ b/plugins/dell-dock/fu-dell-dock-i2c-ec.c @@ -433,7 +433,7 @@ fu_dell_dock_ec_get_dock_info (FuDevice *device, if (fu_common_vercmp_full (hub_version, "1.42", FWUPD_VERSION_FORMAT_PAIR) >= 0) { g_debug ("using passive flow"); self->passive_flow = PASSIVE_REBOOT_MASK; - fu_device_set_custom_flags (device, "skip-restart"); + fu_device_add_flag (device, FWUPD_DEVICE_FLAG_SKIPS_RESTART); } else { g_debug ("not using passive flow (EC: %s Hub2: %s)", self->ec_version, hub_version); @@ -788,7 +788,7 @@ fu_dell_dock_ec_write_fw (FuDevice *device, if (self->passive_flow) self->passive_flow |= PASSIVE_RESET_MASK; - if (fu_device_has_custom_flag (device, "skip-restart")) { + if (fu_device_has_flag (device, FWUPD_DEVICE_FLAG_SKIPS_RESTART)) { g_debug ("Skipping EC reset per quirk request"); fu_device_add_flag (device, FWUPD_DEVICE_FLAG_NEEDS_ACTIVATION); return TRUE; diff --git a/plugins/synaptics-mst/fu-plugin-synaptics-mst.c b/plugins/synaptics-mst/fu-plugin-synaptics-mst.c index bc88b431a..a9c516023 100644 --- a/plugins/synaptics-mst/fu-plugin-synaptics-mst.c +++ b/plugins/synaptics-mst/fu-plugin-synaptics-mst.c @@ -155,7 +155,7 @@ fu_plugin_update (FuPlugin *plugin, return FALSE; if (!fu_device_write_firmware (device, blob_fw, flags, error)) return FALSE; - if (!fu_device_has_custom_flag (device, "skip-restart")) + if (!fu_device_has_flag (device, FWUPD_DEVICE_FLAG_SKIPS_RESTART)) fu_plugin_device_remove (plugin, device); return TRUE; } diff --git a/plugins/synaptics-mst/fu-synaptics-mst-device.c b/plugins/synaptics-mst/fu-synaptics-mst-device.c index 0fe7cea9a..b6e1d0137 100644 --- a/plugins/synaptics-mst/fu-synaptics-mst-device.c +++ b/plugins/synaptics-mst/fu-synaptics-mst-device.c @@ -815,7 +815,7 @@ fu_synaptics_mst_device_write_firmware (FuDevice *device, /* enable remote control and disable on exit */ fu_device_set_status (device, FWUPD_STATUS_DEVICE_WRITE); - if (!fu_device_has_custom_flag (device, "skip-restart")) { + if (!fu_device_has_flag (device, FWUPD_DEVICE_FLAG_SKIPS_RESTART)) { locker = fu_device_locker_new_full (self, (FuDeviceLockerFunc) fu_synaptics_mst_device_enable_rc, (FuDeviceLockerFunc) fu_synaptics_mst_device_restart, diff --git a/plugins/synaptics-mst/synaptics-mst.quirk b/plugins/synaptics-mst/synaptics-mst.quirk index e1af07bc4..9e3c89ad5 100644 --- a/plugins/synaptics-mst/synaptics-mst.quirk +++ b/plugins/synaptics-mst/synaptics-mst.quirk @@ -16,7 +16,7 @@ Plugin = synaptics_mst # * These GUIDs will look like MST-${DEVICEKIND}-${CHIPID}-${BOARDID} # # By default the Synaptics MST device will restart after update -# To override this behavior add the custom flag "skip-restart" +# To override this behavior add FWUPD_DEVICE_FLAG_SKIPS_RESTART # [SynapticsMSTBoardID=272] diff --git a/plugins/thunderbolt/fu-thunderbolt-device.c b/plugins/thunderbolt/fu-thunderbolt-device.c index 283e6abe4..ec25799ed 100644 --- a/plugins/thunderbolt/fu-thunderbolt-device.c +++ b/plugins/thunderbolt/fu-thunderbolt-device.c @@ -577,7 +577,7 @@ fu_thunderbolt_device_write_firmware (FuDevice *device, return FALSE; } - if (fu_device_has_custom_flag (device, "skip-restart")) { + if (fu_device_has_flag (device, FWUPD_DEVICE_FLAG_SKIPS_RESTART)) { g_debug ("Skipping Thunderbolt reset per quirk request"); fu_device_add_flag (device, FWUPD_DEVICE_FLAG_NEEDS_ACTIVATION); return TRUE; diff --git a/src/fu-util-common.c b/src/fu-util-common.c index 1cd81f949..abb282687 100644 --- a/src/fu-util-common.c +++ b/src/fu-util-common.c @@ -1091,6 +1091,10 @@ fu_util_device_flag_to_string (guint64 device_flag) /* skip */ return NULL; } + if (device_flag == FWUPD_DEVICE_FLAG_SKIPS_RESTART) { + /* skip */ + return NULL; + } if (device_flag == FWUPD_DEVICE_FLAG_UNKNOWN) { return NULL; } From d744fe8b67301be96504799f6b9864f52e4da7c2 Mon Sep 17 00:00:00 2001 From: Richard Hughes Date: Thu, 7 May 2020 12:17:33 +0100 Subject: [PATCH 032/607] linux-swap: Rename the plugin as it is Linux specific We'll be adding other linux-foo plugins in the future, so it makes sense to get the namespace correct now. --- contrib/fwupd.spec.in | 2 +- plugins/{swap => linux-swap}/README.md | 4 +- .../fu-swap.c => linux-swap/fu-linux-swap.c} | 24 +++---- plugins/linux-swap/fu-linux-swap.h | 18 +++++ .../fu-plugin-linux-swap.c} | 24 +++---- plugins/linux-swap/fu-self-test.c | 72 +++++++++++++++++++ plugins/{swap => linux-swap}/meson.build | 14 ++-- plugins/meson.build | 2 +- plugins/swap/fu-self-test.c | 72 ------------------- plugins/swap/fu-swap.h | 18 ----- 10 files changed, 125 insertions(+), 125 deletions(-) rename plugins/{swap => linux-swap}/README.md (75%) rename plugins/{swap/fu-swap.c => linux-swap/fu-linux-swap.c} (58%) create mode 100644 plugins/linux-swap/fu-linux-swap.h rename plugins/{swap/fu-plugin-swap.c => linux-swap/fu-plugin-linux-swap.c} (74%) create mode 100644 plugins/linux-swap/fu-self-test.c rename plugins/{swap => linux-swap}/meson.build (72%) delete mode 100644 plugins/swap/fu-self-test.c delete mode 100644 plugins/swap/fu-swap.h diff --git a/contrib/fwupd.spec.in b/contrib/fwupd.spec.in index 0bf4eb921..7ce8ee99f 100644 --- a/contrib/fwupd.spec.in +++ b/contrib/fwupd.spec.in @@ -347,6 +347,7 @@ mkdir -p --mode=0700 $RPM_BUILD_ROOT%{_localstatedir}/lib/fwupd/gnupg %endif %{_libdir}/fwupd-plugins-3/libfu_plugin_fresco_pd.so %{_libdir}/fwupd-plugins-3/libfu_plugin_jabra.so +%{_libdir}/fwupd-plugins-3/libfu_plugin_linux_swap.so %if 0%{?have_modem_manager} %{_libdir}/fwupd-plugins-3/libfu_plugin_modem_manager.so %endif @@ -366,7 +367,6 @@ mkdir -p --mode=0700 $RPM_BUILD_ROOT%{_localstatedir}/lib/fwupd/gnupg %if 0%{?have_dell} %{_libdir}/fwupd-plugins-3/libfu_plugin_synaptics_mst.so %endif -%{_libdir}/fwupd-plugins-3/libfu_plugin_swap.so %{_libdir}/fwupd-plugins-3/libfu_plugin_synaptics_cxaudio.so %{_libdir}/fwupd-plugins-3/libfu_plugin_synaptics_prometheus.so %{_libdir}/fwupd-plugins-3/libfu_plugin_synaptics_rmi.so diff --git a/plugins/swap/README.md b/plugins/linux-swap/README.md similarity index 75% rename from plugins/swap/README.md rename to plugins/linux-swap/README.md index 6a963965b..c4b49aa20 100644 --- a/plugins/swap/README.md +++ b/plugins/linux-swap/README.md @@ -1,5 +1,5 @@ -Swap Support -============ +Linux Swap Support +================== Introduction ------------ diff --git a/plugins/swap/fu-swap.c b/plugins/linux-swap/fu-linux-swap.c similarity index 58% rename from plugins/swap/fu-swap.c rename to plugins/linux-swap/fu-linux-swap.c index e16a3c42d..fd7aab915 100644 --- a/plugins/swap/fu-swap.c +++ b/plugins/linux-swap/fu-linux-swap.c @@ -9,20 +9,20 @@ #include #include "fu-common.h" -#include "fu-swap.h" +#include "fu-linux-swap.h" -struct _FuSwap { +struct _FuLinuxSwap { GObject parent_instance; gboolean encrypted; gboolean enabled; }; -G_DEFINE_TYPE (FuSwap, fu_swap, G_TYPE_OBJECT) +G_DEFINE_TYPE (FuLinuxSwap, fu_linux_swap, G_TYPE_OBJECT) -FuSwap * -fu_swap_new (const gchar *buf, gsize bufsz, GError **error) +FuLinuxSwap * +fu_linux_swap_new (const gchar *buf, gsize bufsz, GError **error) { - FuSwap *self = g_object_new (FU_TYPE_SWAP, NULL); + FuLinuxSwap *self = g_object_new (FU_TYPE_LINUX_SWAP, NULL); g_auto(GStrv) lines = NULL; if (bufsz == 0) @@ -42,25 +42,25 @@ fu_swap_new (const gchar *buf, gsize bufsz, GError **error) } gboolean -fu_swap_get_encrypted (FuSwap *self) +fu_linux_swap_get_encrypted (FuLinuxSwap *self) { - g_return_val_if_fail (FU_IS_SWAP (self), FALSE); + g_return_val_if_fail (FU_IS_LINUX_SWAP (self), FALSE); return self->encrypted; } gboolean -fu_swap_get_enabled (FuSwap *self) +fu_linux_swap_get_enabled (FuLinuxSwap *self) { - g_return_val_if_fail (FU_IS_SWAP (self), FALSE); + g_return_val_if_fail (FU_IS_LINUX_SWAP (self), FALSE); return self->enabled; } static void -fu_swap_class_init (FuSwapClass *klass) +fu_linux_swap_class_init (FuLinuxSwapClass *klass) { } static void -fu_swap_init (FuSwap *self) +fu_linux_swap_init (FuLinuxSwap *self) { } diff --git a/plugins/linux-swap/fu-linux-swap.h b/plugins/linux-swap/fu-linux-swap.h new file mode 100644 index 000000000..5d66e24fc --- /dev/null +++ b/plugins/linux-swap/fu-linux-swap.h @@ -0,0 +1,18 @@ +/* + * Copyright (C) 2020 Richard Hughes + * + * SPDX-License-Identifier: LGPL-2.1+ + */ + +#pragma once + +#include + +#define FU_TYPE_LINUX_SWAP (fu_linux_swap_get_type ()) +G_DECLARE_FINAL_TYPE (FuLinuxSwap, fu_linux_swap, FU, LINUX_SWAP, GObject) + +FuLinuxSwap *fu_linux_swap_new (const gchar *buf, + gsize bufsz, + GError **error); +gboolean fu_linux_swap_get_enabled (FuLinuxSwap *self); +gboolean fu_linux_swap_get_encrypted (FuLinuxSwap *self); diff --git a/plugins/swap/fu-plugin-swap.c b/plugins/linux-swap/fu-plugin-linux-swap.c similarity index 74% rename from plugins/swap/fu-plugin-swap.c rename to plugins/linux-swap/fu-plugin-linux-swap.c index 697e9bb1d..ed6e6a06a 100644 --- a/plugins/swap/fu-plugin-swap.c +++ b/plugins/linux-swap/fu-plugin-linux-swap.c @@ -8,7 +8,7 @@ #include "fu-plugin-vfuncs.h" #include "fu-hash.h" -#include "fu-swap.h" +#include "fu-linux-swap.h" struct FuPluginData { GFileMonitor *monitor; @@ -30,11 +30,11 @@ fu_plugin_destroy (FuPlugin *plugin) } static void -fu_plugin_swap_changed_cb (GFileMonitor *monitor, - GFile *file, - GFile *other_file, - GFileMonitorEvent event_type, - gpointer user_data) +fu_plugin_linux_swap_changed_cb (GFileMonitor *monitor, + GFile *file, + GFile *other_file, + GFileMonitorEvent event_type, + gpointer user_data) { g_debug ("swap changed"); } @@ -47,7 +47,7 @@ fu_plugin_startup (FuPlugin *plugin, GError **error) g_autofree gchar *buf = NULL; g_autofree gchar *fn = NULL; g_autofree gchar *procfs = NULL; - g_autoptr(FuSwap) swap = NULL; + g_autoptr(FuLinuxSwap) swap = NULL; g_autoptr(GFile) file = NULL; procfs = fu_common_get_path (FU_PATH_KIND_PROCFS); @@ -57,20 +57,20 @@ fu_plugin_startup (FuPlugin *plugin, GError **error) if (data->monitor == NULL) return FALSE; g_signal_connect (data->monitor, "changed", - G_CALLBACK (fu_plugin_swap_changed_cb), plugin); + G_CALLBACK (fu_plugin_linux_swap_changed_cb), plugin); - /* load list of swaps */ + /* load list of linux_swaps */ if (!g_file_get_contents (fn, &buf, &bufsz, error)) { g_prefix_error (error, "could not open %s: ", fn); return FALSE; } - swap = fu_swap_new (buf, bufsz, error); + swap = fu_linux_swap_new (buf, bufsz, error); if (swap == NULL) { g_prefix_error (error, "could not parse %s: ", fn); return FALSE; } g_debug ("swap %s and %s", - fu_swap_get_enabled (swap) ? "enabled" : "disabled", - fu_swap_get_encrypted (swap) ? "encrypted" : "unencrypted"); + fu_linux_swap_get_enabled (swap) ? "enabled" : "disabled", + fu_linux_swap_get_encrypted (swap) ? "encrypted" : "unencrypted"); return TRUE; } diff --git a/plugins/linux-swap/fu-self-test.c b/plugins/linux-swap/fu-self-test.c new file mode 100644 index 000000000..fccc3f457 --- /dev/null +++ b/plugins/linux-swap/fu-self-test.c @@ -0,0 +1,72 @@ +/* + * Copyright (C) 2020 Richard Hughes + * + * SPDX-License-Identifier: LGPL-2.1+ + */ + +#include "config.h" + +#include + +#include "fu-linux-swap.h" + +#include "fwupd-error.h" + +static void +fu_linux_swap_none_func (void) +{ + g_autoptr(FuLinuxSwap) swap = NULL; + g_autoptr(GError) error = NULL; + + swap = fu_linux_swap_new ("Filename\t\t\t\tType\t\tSize\tUsed\tPriority\n", 0, &error); + g_assert_no_error (error); + g_assert_nonnull (swap); + g_assert_false (fu_linux_swap_get_enabled (swap)); + g_assert_false (fu_linux_swap_get_encrypted (swap)); +} + +static void +fu_linux_swap_plain_func (void) +{ + g_autoptr(FuLinuxSwap) swap = NULL; + g_autoptr(GError) error = NULL; + + swap = fu_linux_swap_new ("Filename\t\t\t\tType\t\tSize\tUsed\tPriority\n" + "/dev/nvme0n1p4 partition\t5962748\t0\t-2\n", + 0, &error); + g_assert_no_error (error); + g_assert_nonnull (swap); + g_assert_true (fu_linux_swap_get_enabled (swap)); + g_assert_false (fu_linux_swap_get_encrypted (swap)); +} + +static void +fu_linux_swap_encrypted_func (void) +{ + g_autoptr(FuLinuxSwap) swap = NULL; + g_autoptr(GError) error = NULL; + + swap = fu_linux_swap_new ("Filename\t\t\t\tType\t\tSize\tUsed\tPriority\n" + "/dev/dm-1 partition\t5962748\t0\t-2\n", + 0, &error); + g_assert_no_error (error); + g_assert_nonnull (swap); + g_assert_true (fu_linux_swap_get_enabled (swap)); + g_assert_true (fu_linux_swap_get_encrypted (swap)); +} + +int +main (int argc, char **argv) +{ + g_test_init (&argc, &argv, NULL); + + /* 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 ("/linux-swap/none", fu_linux_swap_none_func); + g_test_add_func ("/linux-swap/plain", fu_linux_swap_plain_func); + g_test_add_func ("/linux-swap/encrypted", fu_linux_swap_encrypted_func); + return g_test_run (); +} diff --git a/plugins/swap/meson.build b/plugins/linux-swap/meson.build similarity index 72% rename from plugins/swap/meson.build rename to plugins/linux-swap/meson.build index 7a13cdf81..e5abe2fa4 100644 --- a/plugins/swap/meson.build +++ b/plugins/linux-swap/meson.build @@ -1,10 +1,10 @@ -cargs = ['-DG_LOG_DOMAIN="FuPluginSwap"'] +cargs = ['-DG_LOG_DOMAIN="FuPluginLinuxSwap"'] -shared_module('fu_plugin_swap', +shared_module('fu_plugin_linux_swap', fu_hash, sources : [ - 'fu-plugin-swap.c', - 'fu-swap.c', + 'fu-plugin-linux-swap.c', + 'fu-linux-swap.c', ], include_directories : [ root_incdir, @@ -25,11 +25,11 @@ shared_module('fu_plugin_swap', if get_option('tests') e = executable( - 'swap-self-test', + 'linux-swap-self-test', fu_hash, sources : [ 'fu-self-test.c', - 'fu-swap.c', + 'fu-linux-swap.c', ], include_directories : [ root_incdir, @@ -44,5 +44,5 @@ if get_option('tests') fwupdplugin, ], ) - test('swap-self-test', e) + test('linux-swap-self-test', e) endif diff --git a/plugins/meson.build b/plugins/meson.build index 676ff5593..a936c386b 100644 --- a/plugins/meson.build +++ b/plugins/meson.build @@ -7,13 +7,13 @@ subdir('ep963x') subdir('fastboot') subdir('fresco-pd') subdir('jabra') +subdir('linux-swap') subdir('steelseries') subdir('dell-dock') subdir('nitrokey') subdir('rts54hid') subdir('rts54hub') subdir('solokey') -subdir('swap') subdir('synaptics-cxaudio') subdir('synaptics-prometheus') subdir('test') diff --git a/plugins/swap/fu-self-test.c b/plugins/swap/fu-self-test.c deleted file mode 100644 index b07e699cd..000000000 --- a/plugins/swap/fu-self-test.c +++ /dev/null @@ -1,72 +0,0 @@ -/* - * Copyright (C) 2020 Richard Hughes - * - * SPDX-License-Identifier: LGPL-2.1+ - */ - -#include "config.h" - -#include - -#include "fu-swap.h" - -#include "fwupd-error.h" - -static void -fu_swap_none_func (void) -{ - g_autoptr(FuSwap) swap = NULL; - g_autoptr(GError) error = NULL; - - swap = fu_swap_new ("Filename\t\t\t\tType\t\tSize\tUsed\tPriority\n", 0, &error); - g_assert_no_error (error); - g_assert_nonnull (swap); - g_assert_false (fu_swap_get_enabled (swap)); - g_assert_false (fu_swap_get_encrypted (swap)); -} - -static void -fu_swap_plain_func (void) -{ - g_autoptr(FuSwap) swap = NULL; - g_autoptr(GError) error = NULL; - - swap = fu_swap_new ("Filename\t\t\t\tType\t\tSize\tUsed\tPriority\n" - "/dev/nvme0n1p4 partition\t5962748\t0\t-2\n", - 0, &error); - g_assert_no_error (error); - g_assert_nonnull (swap); - g_assert_true (fu_swap_get_enabled (swap)); - g_assert_false (fu_swap_get_encrypted (swap)); -} - -static void -fu_swap_encrypted_func (void) -{ - g_autoptr(FuSwap) swap = NULL; - g_autoptr(GError) error = NULL; - - swap = fu_swap_new ("Filename\t\t\t\tType\t\tSize\tUsed\tPriority\n" - "/dev/dm-1 partition\t5962748\t0\t-2\n", - 0, &error); - g_assert_no_error (error); - g_assert_nonnull (swap); - g_assert_true (fu_swap_get_enabled (swap)); - g_assert_true (fu_swap_get_encrypted (swap)); -} - -int -main (int argc, char **argv) -{ - g_test_init (&argc, &argv, NULL); - - /* 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 ("/swap/none", fu_swap_none_func); - g_test_add_func ("/swap/plain", fu_swap_plain_func); - g_test_add_func ("/swap/encrypted", fu_swap_encrypted_func); - return g_test_run (); -} diff --git a/plugins/swap/fu-swap.h b/plugins/swap/fu-swap.h deleted file mode 100644 index 006edb4be..000000000 --- a/plugins/swap/fu-swap.h +++ /dev/null @@ -1,18 +0,0 @@ -/* - * Copyright (C) 2020 Richard Hughes - * - * SPDX-License-Identifier: LGPL-2.1+ - */ - -#pragma once - -#include - -#define FU_TYPE_SWAP (fu_swap_get_type ()) -G_DECLARE_FINAL_TYPE (FuSwap, fu_swap, FU, SWAP, GObject) - -FuSwap *fu_swap_new (const gchar *buf, - gsize bufsz, - GError **error); -gboolean fu_swap_get_enabled (FuSwap *self); -gboolean fu_swap_get_encrypted (FuSwap *self); From 9ed79ae644bfcf17345b676e249e86fef12eebb6 Mon Sep 17 00:00:00 2001 From: Richard Hughes Date: Thu, 7 May 2020 12:04:30 +0100 Subject: [PATCH 033/607] Fix various build issues with -Wdiscarded-qualifiers Fixes https://github.com/fwupd/fwupd/issues/2068 --- meson.build | 2 +- plugins/ccgx/fu-ccgx-hpi-device.c | 6 +++--- plugins/ep963x/fu-ep963x-device.c | 19 +++++++++++-------- 3 files changed, 15 insertions(+), 12 deletions(-) diff --git a/meson.build b/meson.build index a09a3db3c..19b4c0310 100644 --- a/meson.build +++ b/meson.build @@ -63,6 +63,7 @@ warning_flags = [ '-Wcast-align', '-Wclobbered', '-Wdeclaration-after-statement', + '-Wdiscarded-qualifiers', '-Wduplicated-branches', '-Wduplicated-cond', '-Wempty-body', @@ -87,7 +88,6 @@ warning_flags = [ '-Wno-address-of-packed-member', # incompatible with g_autoptr() '-Wno-unknown-pragmas', '-Wno-deprecated-declarations', - '-Wno-discarded-qualifiers', '-Wno-missing-field-initializers', '-Wno-strict-aliasing', '-Wno-suggest-attribute=format', diff --git a/plugins/ccgx/fu-ccgx-hpi-device.c b/plugins/ccgx/fu-ccgx-hpi-device.c index 8996805d9..d9054cd6e 100644 --- a/plugins/ccgx/fu-ccgx-hpi-device.c +++ b/plugins/ccgx/fu-ccgx-hpi-device.c @@ -442,14 +442,14 @@ fu_ccgx_hpi_device_reg_write_cb (FuDevice *device, gpointer user_data, GError ** static gboolean fu_ccgx_hpi_device_reg_write (FuCcgxHpiDevice *self, guint16 addr, - guint8 *buf, + const guint8 *buf, gsize bufsz, GError **error) { FuCcgxHpiDeviceRetryHelper helper = { .addr = addr, .mode = CY_I2C_MODE_WRITE, - .buf = buf, + .buf = (guint8 *) buf, .bufsz = bufsz, }; return fu_device_retry (FU_DEVICE (self), @@ -812,7 +812,7 @@ fu_ccgx_hpi_leave_flash_mode (FuCcgxHpiDevice *self, GError **error) static gboolean fu_ccgx_hpi_write_flash (FuCcgxHpiDevice *self, guint16 addr, - guint8 *buf, + const guint8 *buf, guint16 bufsz, GError **error) { diff --git a/plugins/ep963x/fu-ep963x-device.c b/plugins/ep963x/fu-ep963x-device.c index f6408b88a..916b64c31 100644 --- a/plugins/ep963x/fu-ep963x-device.c +++ b/plugins/ep963x/fu-ep963x-device.c @@ -22,7 +22,7 @@ G_DEFINE_TYPE (FuEp963xDevice, fu_ep963x_device, FU_TYPE_HID_DEVICE) static gboolean fu_ep963x_device_write (FuEp963xDevice *self, guint8 ctrl_id, guint8 cmd, - guint8 *buf, gsize bufsz, + const guint8 *buf, gsize bufsz, GError **error) { guint8 bufhw[FU_EP963_FEATURE_ID1_SIZE] = { @@ -47,8 +47,9 @@ fu_ep963x_device_write (FuEp963xDevice *self, } static gboolean -fu_ep963x_device_write_icp (FuEp963xDevice *self, - guint8 cmd, guint8 *buf, gsize bufsz, +fu_ep963x_device_write_icp (FuEp963xDevice *self, guint8 cmd, + const guint8 *buf, gsize bufsz, + guint8 *bufout, gsize bufoutsz, GError **error) { /* wait for hardware */ @@ -69,10 +70,10 @@ fu_ep963x_device_write_icp (FuEp963xDevice *self, } if (bufhw[2] == FU_EP963_USB_STATE_READY) { /* optional data */ - if (buf != NULL) { - if (!fu_memcpy_safe (buf, bufsz, 0x0, + if (bufout != NULL) { + if (!fu_memcpy_safe (bufout, bufoutsz, 0x0, bufhw, sizeof(bufhw), 0x02, - bufsz, error)) + bufoutsz, error)) return FALSE; } return TRUE; @@ -102,7 +103,8 @@ fu_ep963x_device_detach (FuDevice *device, GError **error) } if (!fu_ep963x_device_write_icp (self, FU_EP963_ICP_ENTER, - buf, sizeof(buf), + buf, sizeof(buf), /* in */ + NULL, 0x0, /* out */ &error_local)) { g_set_error (error, FWUPD_ERROR, @@ -154,7 +156,8 @@ fu_ep963x_device_setup (FuDevice *device, GError **error) /* get version */ if (!fu_ep963x_device_write_icp (self, FU_EP963_UF_CMD_VERSION, - buf, sizeof(buf), + NULL, 0, /* in */ + buf, sizeof(buf), /* out */ error)) { return FALSE; } From a84d7a7e2a4dc978ccc03ec97983eb27e2860c47 Mon Sep 17 00:00:00 2001 From: Richard Hughes Date: Wed, 6 May 2020 12:11:51 +0100 Subject: [PATCH 034/607] trivial: Add fu_common_filename_glob() for future use --- libfwupdplugin/fu-common.c | 43 ++++++++++++++++++++++++++++++++++ libfwupdplugin/fu-common.h | 3 +++ libfwupdplugin/fwupdplugin.map | 1 + 3 files changed, 47 insertions(+) diff --git a/libfwupdplugin/fu-common.c b/libfwupdplugin/fu-common.c index 19acec92f..39293b36f 100644 --- a/libfwupdplugin/fu-common.c +++ b/libfwupdplugin/fu-common.c @@ -1678,6 +1678,49 @@ fu_common_fnmatch (const gchar *pattern, const gchar *str) #endif } +static gint +fu_common_filename_glob_sort_cb (gconstpointer a, gconstpointer b) +{ + return g_strcmp0 (*(const gchar **)a, *(const gchar **)b); +} + +/** + * fu_common_filename_glob: + * @directory: a directory path + * @pattern: a glob pattern, e.g. `*foo*` + * @error: A #GError or %NULL + * + * Returns all the filenames that match a specific glob pattern. + * Any results are sorted. No matching files will set @error. + * + * Return value: (element-type utf8) (transfer container): matching files, or %NULL + * + * Since: 1.5.0 + **/ +GPtrArray * +fu_common_filename_glob (const gchar *directory, const gchar *pattern, GError **error) +{ + const gchar *basename; + g_autoptr(GDir) dir = g_dir_open (directory, 0, error); + g_autoptr(GPtrArray) files = g_ptr_array_new_with_free_func (g_free); + if (dir == NULL) + return NULL; + while ((basename = g_dir_read_name (dir)) != NULL) { + if (!fu_common_fnmatch (pattern, basename)) + continue; + g_ptr_array_add (files, g_build_filename (directory, basename, NULL)); + } + if (files->len == 0) { + g_set_error_literal (error, + G_IO_ERROR, + G_IO_ERROR_NOT_FOUND, + "no files matched pattern"); + return NULL; + } + g_ptr_array_sort (files, fu_common_filename_glob_sort_cb); + return g_steal_pointer (&files); +} + /** * fu_common_strnsplit: * @str: a string to split diff --git a/libfwupdplugin/fu-common.h b/libfwupdplugin/fu-common.h index c61627285..50681202e 100644 --- a/libfwupdplugin/fu-common.h +++ b/libfwupdplugin/fu-common.h @@ -93,6 +93,9 @@ gboolean fu_common_spawn_sync (const gchar * const *argv, gchar *fu_common_get_path (FuPathKind path_kind); gchar *fu_common_realpath (const gchar *filename, GError **error); +GPtrArray *fu_common_filename_glob (const gchar *directory, + const gchar *pattern, + GError **error); gboolean fu_common_fnmatch (const gchar *pattern, const gchar *str); gboolean fu_common_rmtree (const gchar *directory, diff --git a/libfwupdplugin/fwupdplugin.map b/libfwupdplugin/fwupdplugin.map index b3ac35435..5d1db3e44 100644 --- a/libfwupdplugin/fwupdplugin.map +++ b/libfwupdplugin/fwupdplugin.map @@ -583,6 +583,7 @@ LIBFWUPDPLUGIN_1.4.1 { LIBFWUPDPLUGIN_1.5.0 { global: + fu_common_filename_glob; fu_udev_device_get_parent_name; fu_udev_device_get_sysfs_attr; local: *; From b9640a28ec81084bac540b4d601cd191494e3ea6 Mon Sep 17 00:00:00 2001 From: Richard Hughes Date: Tue, 5 May 2020 20:42:47 +0100 Subject: [PATCH 035/607] uefi-dbx: Add a plugin that analyses the UEFI dbx variable This will be used for future functionality. --- README.md | 1 + contrib/debian/control.in | 1 + contrib/debian/rules | 3 +- contrib/fwupd.spec.in | 6 + libfwupdplugin/fu-common.c | 14 ++ libfwupdplugin/fu-common.h | 2 + meson.build | 8 + meson_options.txt | 1 + plugins/meson.build | 1 + plugins/uefi-dbx/README.md | 8 + plugins/uefi-dbx/create-fuzzing-targets.py | 28 +++ plugins/uefi-dbx/fu-fuzzer.c | 38 ++++ plugins/uefi-dbx/fu-plugin-uefi-dbx.c | 96 ++++++++++ plugins/uefi-dbx/fu-self-test.c | 57 ++++++ plugins/uefi-dbx/fu-uefi-dbx-common.c | 28 +++ plugins/uefi-dbx/fu-uefi-dbx-common.h | 13 ++ plugins/uefi-dbx/fu-uefi-dbx-file.c | 201 +++++++++++++++++++++ plugins/uefi-dbx/fu-uefi-dbx-file.h | 26 +++ plugins/uefi-dbx/fuzzing/example.bin | Bin 0 -> 76 bytes plugins/uefi-dbx/meson.build | 80 ++++++++ 20 files changed, 611 insertions(+), 1 deletion(-) create mode 100644 plugins/uefi-dbx/README.md create mode 100755 plugins/uefi-dbx/create-fuzzing-targets.py create mode 100644 plugins/uefi-dbx/fu-fuzzer.c create mode 100644 plugins/uefi-dbx/fu-plugin-uefi-dbx.c create mode 100644 plugins/uefi-dbx/fu-self-test.c create mode 100644 plugins/uefi-dbx/fu-uefi-dbx-common.c create mode 100644 plugins/uefi-dbx/fu-uefi-dbx-common.h create mode 100644 plugins/uefi-dbx/fu-uefi-dbx-file.c create mode 100644 plugins/uefi-dbx/fu-uefi-dbx-file.h create mode 100644 plugins/uefi-dbx/fuzzing/example.bin create mode 100644 plugins/uefi-dbx/meson.build diff --git a/README.md b/README.md index d9f514146..9bcafb0fa 100644 --- a/README.md +++ b/README.md @@ -125,3 +125,4 @@ There are several automated fuzzing tests in fwupd. These take some time to run: ninja fuzz-synaptics-rmi ninja fuzz-firmware ninja fuzz-smbios + ninja fuzz-efidbx diff --git a/contrib/debian/control.in b/contrib/debian/control.in index 94c0868b2..752696172 100644 --- a/contrib/debian/control.in +++ b/contrib/debian/control.in @@ -49,6 +49,7 @@ Depends: ${misc:Depends}, shared-mime-info Recommends: python3, bolt, + secureboot-db, fwupd-signed Provides: fwupdate Conflicts: fwupdate-amd64-signed, diff --git a/contrib/debian/rules b/contrib/debian/rules index d362fcd21..1189ff6da 100755 --- a/contrib/debian/rules +++ b/contrib/debian/rules @@ -20,6 +20,7 @@ ifeq (yes,$(shell dpkg-vendor --derives-from Ubuntu && echo yes)) SB_STYLE := ubuntu tar_name := fwupd_$(deb_version)_$(DEB_HOST_ARCH).tar.gz export FLASHROM=-Dplugin_flashrom=false + export DBX=-Defi_dbxdir=/usr/share/secureboot/updates/dbx else TMPLDIR := debian/fwupd-$(DEB_HOST_ARCH)-signed-template/usr/share/code-signing/fwupd-$(DEB_HOST_ARCH)-signed-template export FLASHROM=-Dplugin_flashrom=true @@ -42,7 +43,7 @@ override_dh_auto_configure: export DELL="-Dplugin_dell=false"; \ fi; \ if pkg-config --exists efivar; then \ - export UEFI="-Dplugin_uefi=true -Dplugin_redfish=true -Dplugin_nvme=true"; \ + export UEFI="-Dplugin_uefi=true -Dplugin_redfish=true -Dplugin_nvme=true $$DBX"; \ else \ export UEFI="-Dplugin_uefi=false -Dplugin_redfish=false -Dplugin_nvme=false"; \ fi; \ diff --git a/contrib/fwupd.spec.in b/contrib/fwupd.spec.in index 7ce8ee99f..b4a2bfb29 100644 --- a/contrib/fwupd.spec.in +++ b/contrib/fwupd.spec.in @@ -117,6 +117,10 @@ Requires: libsoup%{?_isa} >= %{libsoup_version} Requires: bubblewrap Requires: shared-mime-info +%if 0%{?have_uefi} +Requires: dbxtool +%endif + %if 0%{?rhel} > 7 || 0%{?fedora} > 28 Recommends: python3 %endif @@ -163,6 +167,7 @@ Data files for installed tests. --werror \ %endif -Dgtkdoc=true \ + -Defi_dbxdir=%{_datadir}/dbxtool \ %if 0%{?enable_tests} -Dtests=true \ %else @@ -380,6 +385,7 @@ mkdir -p --mode=0700 $RPM_BUILD_ROOT%{_localstatedir}/lib/fwupd/gnupg %{_libdir}/fwupd-plugins-3/libfu_plugin_tpm.so %{_libdir}/fwupd-plugins-3/libfu_plugin_tpm_eventlog.so %{_libdir}/fwupd-plugins-3/libfu_plugin_uefi.so +%{_libdir}/fwupd-plugins-3/libfu_plugin_uefi_dbx.so %{_libdir}/fwupd-plugins-3/libfu_plugin_uefi_recovery.so %endif %{_libdir}/fwupd-plugins-3/libfu_plugin_logind.so diff --git a/libfwupdplugin/fu-common.c b/libfwupdplugin/fu-common.c index 39293b36f..064ce62b8 100644 --- a/libfwupdplugin/fu-common.c +++ b/libfwupdplugin/fu-common.c @@ -1095,6 +1095,20 @@ fu_common_get_path (FuPathKind path_kind) return g_strdup (EFI_APP_LOCATION); #else return NULL; +#endif + /* /usr/share/fwupd/dbx */ + case FU_PATH_KIND_EFIDBXDIR: + tmp = g_getenv ("FWUPD_EFIDBXDIR"); + if (tmp != NULL) + return g_strdup (tmp); +#ifdef FWUPD_EFI_DBXDIR + tmp = g_getenv ("SNAP"); + if (tmp != NULL) + return g_build_filename (tmp, FWUPD_EFI_DBXDIR, NULL); + return g_strdup (FWUPD_EFI_DBXDIR); +#else + basedir = fu_common_get_path (FU_PATH_KIND_LOCALSTATEDIR_PKG); + return g_build_filename (basedir, "dbx", NULL); #endif /* /etc/fwupd */ case FU_PATH_KIND_SYSCONFDIR_PKG: diff --git a/libfwupdplugin/fu-common.h b/libfwupdplugin/fu-common.h index 50681202e..ce5ef0c7f 100644 --- a/libfwupdplugin/fu-common.h +++ b/libfwupdplugin/fu-common.h @@ -57,6 +57,7 @@ typedef guint FuEndianType; * @FU_PATH_KIND_POLKIT_ACTIONS: The directory for policy kit actions (IE /usr/share/polkit-1/actions/) * @FU_PATH_KIND_OFFLINE_TRIGGER: The file for the offline trigger (IE /system-update) * @FU_PATH_KIND_SYSFSDIR_SECURITY: The sysfs security location (IE /sys/kernel/security) + * @FU_PATH_KIND_EFIDBXDIR: The location of the EFI dbx files * * Path types to use when dynamically determining a path at runtime **/ @@ -76,6 +77,7 @@ typedef enum { FU_PATH_KIND_POLKIT_ACTIONS, FU_PATH_KIND_OFFLINE_TRIGGER, FU_PATH_KIND_SYSFSDIR_SECURITY, + FU_PATH_KIND_EFIDBXDIR, /*< private >*/ FU_PATH_KIND_LAST } FuPathKind; diff --git a/meson.build b/meson.build index 19b4c0310..552dc7f06 100644 --- a/meson.build +++ b/meson.build @@ -289,6 +289,14 @@ if build_standalone and get_option('plugin_uefi') efi_app_location = join_paths(libexecdir, 'fwupd', 'efi') conf.set_quoted ('EFI_APP_LOCATION', efi_app_location) + # e.g. could be: + # * /usr/share/dbxtool for Red Hat + # * /usr/share/secureboot/updates/dbx for Ubuntu + efi_dbxdir = get_option('efi_dbxdir') + if efi_dbxdir != '' + conf.set_quoted ('FWUPD_EFI_DBXDIR', efi_dbxdir) + endif + efi_arch = host_machine.cpu_family() if efi_arch == 'x86' EFI_MACHINE_TYPE_NAME = 'ia32' diff --git a/meson_options.txt b/meson_options.txt index 41ba066d7..5dacb4cf4 100644 --- a/meson_options.txt +++ b/meson_options.txt @@ -26,6 +26,7 @@ option('systemd_root_prefix', type: 'string', value: '', description: 'Directory option('elogind', type : 'boolean', value : false, description : 'enable elogind support') option('tests', type : 'boolean', value : true, description : 'enable tests') option('udevdir', type: 'string', value: '', description: 'Directory for udev rules') +option('efi_dbxdir', type: 'string', value: '', description: 'Directory for UEFI dbx files') option('efi-cc', type : 'string', value : 'gcc', description : 'the compiler to use for EFI modules') option('efi-ld', type : 'string', value : 'ld', description : 'the linker to use for EFI modules') option('efi-libdir', type : 'string', description : 'path to the EFI lib directory') diff --git a/plugins/meson.build b/plugins/meson.build index a936c386b..f916228a6 100644 --- a/plugins/meson.build +++ b/plugins/meson.build @@ -101,6 +101,7 @@ endif if get_option('plugin_uefi') subdir('uefi') subdir('uefi-recovery') +subdir('uefi-dbx') endif if get_option('plugin_flashrom') diff --git a/plugins/uefi-dbx/README.md b/plugins/uefi-dbx/README.md new file mode 100644 index 000000000..d1c22a9fd --- /dev/null +++ b/plugins/uefi-dbx/README.md @@ -0,0 +1,8 @@ +UEFI dbx Support +================ + +Introduction +------------ + +This plugin checks if the UEFI dbx contains all the most recent blacklisted +checksums. diff --git a/plugins/uefi-dbx/create-fuzzing-targets.py b/plugins/uefi-dbx/create-fuzzing-targets.py new file mode 100755 index 000000000..9c2bba681 --- /dev/null +++ b/plugins/uefi-dbx/create-fuzzing-targets.py @@ -0,0 +1,28 @@ +#!/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(' + * + * SPDX-License-Identifier: LGPL-2.1+ + */ + +#include "config.h" + +#include + +#include "fu-uefi-dbx-file.h" + +int +main (int argc, char *argv[]) +{ + gsize bufsz = 0; + g_autofree guint8 *buf = NULL; + g_autoptr(FuUefiDbxFile) uefi_dbx_file = NULL; + g_autoptr(GError) error = 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; + } + uefi_dbx_file = fu_uefi_dbx_file_new (buf, bufsz, + FU_UEFI_DBX_FILE_PARSE_FLAGS_IGNORE_HEADER, + &error); + if (uefi_dbx_file == NULL) { + g_printerr ("Failed to parse %s: %s\n", argv[1], error->message); + return EXIT_FAILURE; + } + g_print ("%u checksums\n", fu_uefi_dbx_file_get_checksums(uefi_dbx_file)->len); + return EXIT_SUCCESS; +} diff --git a/plugins/uefi-dbx/fu-plugin-uefi-dbx.c b/plugins/uefi-dbx/fu-plugin-uefi-dbx.c new file mode 100644 index 000000000..f08a69c7c --- /dev/null +++ b/plugins/uefi-dbx/fu-plugin-uefi-dbx.c @@ -0,0 +1,96 @@ +/* + * Copyright (C) 2020 Richard Hughes + * + * SPDX-License-Identifier: LGPL-2.1+ + */ + +#include "config.h" + +#include "fu-plugin-vfuncs.h" +#include "fu-efivar.h" +#include "fu-hash.h" +#include "fu-uefi-dbx-common.h" +#include "fu-uefi-dbx-file.h" + +struct FuPluginData { + gchar *fn; +}; + +void +fu_plugin_init (FuPlugin *plugin) +{ + fu_plugin_alloc_data (plugin, sizeof (FuPluginData)); + fu_plugin_set_build_hash (plugin, FU_BUILD_HASH); +} + +void +fu_plugin_destroy (FuPlugin *plugin) +{ + FuPluginData *data = fu_plugin_get_data (plugin); + g_free (data->fn); +} + +gboolean +fu_plugin_startup (FuPlugin *plugin, GError **error) +{ + FuPluginData *data = fu_plugin_get_data (plugin); + GPtrArray *checksums; + gsize bufsz = 0; + guint missing_cnt = 0; + g_autofree guint8 *buf_system = NULL; + g_autofree guint8 *buf_update = NULL; + g_autoptr(FuUefiDbxFile) dbx_system = NULL; + g_autoptr(FuUefiDbxFile) dbx_update = NULL; + g_autoptr(GError) error_local = NULL; + + /* get binary blob */ + data->fn = fu_uefi_dbx_get_dbxupdate (error); + if (data->fn == NULL) { + g_autofree gchar *dbxdir = NULL; + dbxdir = fu_common_get_path (FU_PATH_KIND_EFIDBXDIR); + g_prefix_error (error, + "file can be downloaded from %s and decompressed into %s: ", + FU_UEFI_DBX_DATA_URL, dbxdir); + return FALSE; + } + + /* get update dbx */ + if (!g_file_get_contents (data->fn, (gchar **) &buf_update, &bufsz, error)) { + g_prefix_error (error, "failed to load %s: ", data->fn); + return FALSE; + } + dbx_update = fu_uefi_dbx_file_new (buf_update, bufsz, + FU_UEFI_DBX_FILE_PARSE_FLAGS_IGNORE_HEADER, + error); + if (dbx_update == NULL) { + g_prefix_error (error, "could not parse %s: ", data->fn); + return FALSE; + } + + /* get system dbx */ + if (!fu_efivar_get_data ("d719b2cb-3d3a-4596-a3bc-dad00e67656f", "dbx", + &buf_system, &bufsz, NULL, error)) { + g_prefix_error (error, "failed to get dbx: "); + return FALSE; + } + dbx_system = fu_uefi_dbx_file_new (buf_system, bufsz, + FU_UEFI_DBX_FILE_PARSE_FLAGS_NONE, + error); + if (dbx_system == NULL) { + g_prefix_error (error, "could not parse variable: "); + return FALSE; + } + + /* look for each checksum in the update in the system version */ + checksums = fu_uefi_dbx_file_get_checksums (dbx_update); + for (guint i = 0; i < checksums->len; i++) { + const gchar *checksum = g_ptr_array_index (checksums, i); + if (!fu_uefi_dbx_file_has_checksum (dbx_system, checksum)) { + g_debug ("%s missing from the system dbx", checksum); + missing_cnt += 1; + } + } + if (missing_cnt > 0) + g_warning ("%u hashes missing", missing_cnt); + return TRUE; +} diff --git a/plugins/uefi-dbx/fu-self-test.c b/plugins/uefi-dbx/fu-self-test.c new file mode 100644 index 000000000..706e0d988 --- /dev/null +++ b/plugins/uefi-dbx/fu-self-test.c @@ -0,0 +1,57 @@ +/* + * Copyright (C) 2020 Richard Hughes + * + * SPDX-License-Identifier: LGPL-2.1+ + */ + +#include "config.h" + +#include + +#include "fu-uefi-dbx-common.h" +#include "fu-uefi-dbx-file.h" + +static void +fu_uefi_dbx_file_parse_func (void) +{ + gboolean ret; + gsize bufsz = 0; + g_autofree gchar *fn = NULL; + g_autofree guint8 *buf = NULL; + g_autoptr(FuUefiDbxFile) uefi_dbx_file = NULL; + g_autoptr(GError) error = NULL; + + /* load file */ + fn = fu_uefi_dbx_get_dbxupdate (NULL); + if (fn == NULL) { + g_test_skip ("no dbx file, use -Defi_dbxdir="); + return; + } + ret = g_file_get_contents (fn, (gchar **) &buf, &bufsz, &error); + g_assert_no_error (error); + g_assert_true (ret); + + /* parse the update */ + uefi_dbx_file = fu_uefi_dbx_file_new (buf, bufsz, + FU_UEFI_DBX_FILE_PARSE_FLAGS_IGNORE_HEADER, + &error); + g_assert_no_error (error); + g_assert_nonnull (uefi_dbx_file); + g_assert_cmpint (fu_uefi_dbx_file_get_checksums(uefi_dbx_file)->len, ==, 77); + g_assert_true (fu_uefi_dbx_file_has_checksum (uefi_dbx_file, "72e0bd1867cf5d9d56ab158adf3bddbc82bf32a8d8aa1d8c5e2f6df29428d6d8")); + g_assert_false (fu_uefi_dbx_file_has_checksum (uefi_dbx_file, "dave")); +} + +int +main (int argc, char **argv) +{ + g_test_init (&argc, &argv, NULL); + + /* 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-dbx/file-parse", fu_uefi_dbx_file_parse_func); + return g_test_run (); +} diff --git a/plugins/uefi-dbx/fu-uefi-dbx-common.c b/plugins/uefi-dbx/fu-uefi-dbx-common.c new file mode 100644 index 000000000..2971e81a6 --- /dev/null +++ b/plugins/uefi-dbx/fu-uefi-dbx-common.c @@ -0,0 +1,28 @@ +/* + * Copyright (C) 2020 Richard Hughes + * + * SPDX-License-Identifier: LGPL-2.1+ + */ + +#include "config.h" + +#include "fu-common.h" +#include "fu-uefi-dbx-common.h" + +gchar * +fu_uefi_dbx_get_dbxupdate (GError **error) +{ + g_autofree gchar *dbxdir = NULL; + g_autofree gchar *glob = NULL; + g_autoptr(GPtrArray) files = NULL; + + /* get the newest files from dbxtool, prefer the per-arch ones first */ + dbxdir = fu_common_get_path (FU_PATH_KIND_EFIDBXDIR); + glob = g_strdup_printf ("*%s*.bin", EFI_MACHINE_TYPE_NAME); + files = fu_common_filename_glob (dbxdir, glob, NULL); + if (files == NULL) + files = fu_common_filename_glob (dbxdir, "*.bin", error); + if (files == NULL) + return NULL; + return g_strdup (g_ptr_array_index (files, 0)); +} diff --git a/plugins/uefi-dbx/fu-uefi-dbx-common.h b/plugins/uefi-dbx/fu-uefi-dbx-common.h new file mode 100644 index 000000000..7b02181c9 --- /dev/null +++ b/plugins/uefi-dbx/fu-uefi-dbx-common.h @@ -0,0 +1,13 @@ +/* + * Copyright (C) 2020 Richard Hughes + * + * SPDX-License-Identifier: LGPL-2.1+ + */ + +#pragma once + +#include + +#define FU_UEFI_DBX_DATA_URL "https://uefi.org/revocationlistfile" + +gchar *fu_uefi_dbx_get_dbxupdate (GError **error); diff --git a/plugins/uefi-dbx/fu-uefi-dbx-file.c b/plugins/uefi-dbx/fu-uefi-dbx-file.c new file mode 100644 index 000000000..64852d109 --- /dev/null +++ b/plugins/uefi-dbx/fu-uefi-dbx-file.c @@ -0,0 +1,201 @@ +/* + * Copyright (C) 2020 Richard Hughes + * + * SPDX-License-Identifier: LGPL-2.1+ + */ + +#include "config.h" + +#include +#include + +#include "fu-common.h" +#include "fu-uefi-dbx-common.h" +#include "fu-uefi-dbx-file.h" + +struct _FuUefiDbxFile { + GObject parent_instance; + GPtrArray *checksums; +}; + +G_DEFINE_TYPE (FuUefiDbxFile, fu_uefi_dbx_file, G_TYPE_OBJECT) + +static gboolean +fu_uefi_dbx_file_parse_sig_item (FuUefiDbxFile *self, + const guint8 *buf, + gsize bufsz, + gsize offset, + guint32 sig_size, + GError **error) +{ + GString *sig_datastr; + 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); + + /* 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; + } + + /* we don't care about the owner, so just store the checksum */ + sig_owner = fwupd_guid_to_string (&guid, FWUPD_GUID_FLAG_MIXED_ENDIAN); + sig_datastr = g_string_new (NULL); + for (gsize j = 0; j < sig_datasz; j++) + g_string_append_printf (sig_datastr, "%02x", sig_data[j]); + g_debug ("Owner: %s, Data: %s", sig_owner, sig_datastr->str); + g_ptr_array_add (self->checksums, g_string_free (sig_datastr, FALSE)); + return TRUE; +} + +static gboolean +fu_uefi_dbx_file_parse_sig_list (FuUefiDbxFile *self, + 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; + + /* 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) + g_debug ("EFI_SIGNATURE_LIST SHA256"); + else if (g_strcmp0 (sig_type, "a5c059a1-94e4-4aa7-87b5-ab155c2bf072") == 0) + g_debug ("EFI_SIGNATURE_LIST X509"); + else + g_debug ("EFI_SIGNATURE_LIST unknown: %s", sig_type); + 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_uefi_dbx_file_parse_sig_item (self, buf, bufsz, + offset_tmp, sig_size, + error)) + return FALSE; + offset_tmp += sig_size; + } + *offset += sig_list_size; + return TRUE; +} + +FuUefiDbxFile * +fu_uefi_dbx_file_new (const guint8 *buf, gsize bufsz, + FuUefiDbxFileParseFlags flags, + GError **error) +{ + gsize offset_fs = 0; + g_autoptr(FuUefiDbxFile) self = g_object_new (FU_TYPE_UEFI_DBX_FILE, NULL); + + /* this allows us to skip the efi permissions uint32_t or even the + * Microsoft PKCS-7 signature */ + if (flags & FU_UEFI_DBX_FILE_PARSE_FLAGS_IGNORE_HEADER) { + 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_uefi_dbx_file_parse_sig_list (self, buf, bufsz, &offset, error)) + return NULL; + } + + /* success */ + return g_steal_pointer (&self); +} + +gboolean +fu_uefi_dbx_file_has_checksum (FuUefiDbxFile *self, const gchar *checksum) +{ + g_return_val_if_fail (FU_IS_UEFI_DBX_FILE (self), FALSE); + for (guint i = 0; i < self->checksums->len; i++) { + const gchar *checksums_tmp = g_ptr_array_index (self->checksums, i); + if (g_strcmp0 (checksums_tmp, checksum) == 0) + return TRUE; + } + return FALSE; +} + +GPtrArray * +fu_uefi_dbx_file_get_checksums (FuUefiDbxFile *self) +{ + g_return_val_if_fail (FU_IS_UEFI_DBX_FILE (self), FALSE); + return self->checksums; +} + +static void +fu_uefi_dbx_file_finalize (GObject *obj) +{ + FuUefiDbxFile *self = FU_UEFI_DBX_FILE (obj); + g_ptr_array_unref (self->checksums); + G_OBJECT_CLASS (fu_uefi_dbx_file_parent_class)->finalize (obj); +} + +static void +fu_uefi_dbx_file_class_init (FuUefiDbxFileClass *klass) +{ + GObjectClass *object_class = G_OBJECT_CLASS (klass); + object_class->finalize = fu_uefi_dbx_file_finalize; +} + +static void +fu_uefi_dbx_file_init (FuUefiDbxFile *self) +{ + self->checksums = g_ptr_array_new_with_free_func (g_free); +} diff --git a/plugins/uefi-dbx/fu-uefi-dbx-file.h b/plugins/uefi-dbx/fu-uefi-dbx-file.h new file mode 100644 index 000000000..4a3b2c693 --- /dev/null +++ b/plugins/uefi-dbx/fu-uefi-dbx-file.h @@ -0,0 +1,26 @@ +/* + * Copyright (C) 2020 Richard Hughes + * + * SPDX-License-Identifier: LGPL-2.1+ + */ + +#pragma once + +#include + +#define FU_TYPE_UEFI_DBX_FILE (fu_uefi_dbx_file_get_type ()) +G_DECLARE_FINAL_TYPE (FuUefiDbxFile, fu_uefi_dbx_file, FU, UEFI_DBX_FILE, GObject) + + +typedef enum { + FU_UEFI_DBX_FILE_PARSE_FLAGS_NONE = 0, + FU_UEFI_DBX_FILE_PARSE_FLAGS_IGNORE_HEADER = 1 << 0, +} FuUefiDbxFileParseFlags; + +FuUefiDbxFile *fu_uefi_dbx_file_new (const guint8 *buf, + gsize bufsz, + FuUefiDbxFileParseFlags flags, + GError **error); +GPtrArray *fu_uefi_dbx_file_get_checksums (FuUefiDbxFile *self); +gboolean fu_uefi_dbx_file_has_checksum (FuUefiDbxFile *self, + const gchar *checksum); diff --git a/plugins/uefi-dbx/fuzzing/example.bin b/plugins/uefi-dbx/fuzzing/example.bin new file mode 100644 index 0000000000000000000000000000000000000000..5cfda85fe9a60a73f250736ebe6ab54586d7822b GIT binary patch literal 76 WcmXpoKm|Sw5MThL4AFoQ0RRBZlMKxO literal 0 HcmV?d00001 diff --git a/plugins/uefi-dbx/meson.build b/plugins/uefi-dbx/meson.build new file mode 100644 index 000000000..e64a55a85 --- /dev/null +++ b/plugins/uefi-dbx/meson.build @@ -0,0 +1,80 @@ +cargs = ['-DG_LOG_DOMAIN="FuPluginUefiDbx"'] + +shared_module('fu_plugin_uefi_dbx', + fu_hash, + sources : [ + 'fu-plugin-uefi-dbx.c', + 'fu-uefi-dbx-common.c', + 'fu-uefi-dbx-file.c', + ], + include_directories : [ + root_incdir, + fwupd_incdir, + fwupdplugin_incdir, + ], + install : true, + install_dir: plugin_dir, + link_with : [ + fwupd, + fwupdplugin, + ], + c_args : cargs, + dependencies : [ + plugin_deps, + ], +) + +if get_option('tests') + e = executable( + 'uefi-dbx-self-test', + fu_hash, + sources : [ + 'fu-self-test.c', + 'fu-uefi-dbx-common.c', + 'fu-uefi-dbx-file.c', + ], + include_directories : [ + root_incdir, + fwupd_incdir, + fwupdplugin_incdir, + ], + dependencies : [ + plugin_deps, + ], + link_with : [ + fwupd, + fwupdplugin, + ], + ) + test('uefi-dbx-self-test', e) +endif + +uefi_dbx_fuzzer = executable( + 'uefi-dbx-fuzzer', + sources : [ + 'fu-fuzzer.c', + 'fu-uefi-dbx-file.c', + ], + include_directories : [ + root_incdir, + fwupd_incdir, + fwupdplugin_incdir, + ], + dependencies : [ + plugin_deps, + ], + link_with : [ + fwupd, + fwupdplugin, + ], +) + +run_target('fuzz-efidbx', + command: [ + join_paths(meson.source_root(), 'contrib/afl-fuzz.py'), + '-i', join_paths(meson.current_source_dir(), 'fuzzing'), + '-o', join_paths(meson.current_build_dir(), 'findings'), + '--command', uefi_dbx_fuzzer, + fwupdtool, + ], +) From cb6ec2b18e7543a53e3543539ffb4e860ea46a57 Mon Sep 17 00:00:00 2001 From: Mario Limonciello Date: Thu, 7 May 2020 13:02:18 -0500 Subject: [PATCH 036/607] trivial: uefi-dbx: correct error message on missing file ``` unset error in plugin uefi_dbx for add_security_attrs() ``` --- plugins/uefi-dbx/fu-plugin-uefi-dbx.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/plugins/uefi-dbx/fu-plugin-uefi-dbx.c b/plugins/uefi-dbx/fu-plugin-uefi-dbx.c index f08a69c7c..a2089858d 100644 --- a/plugins/uefi-dbx/fu-plugin-uefi-dbx.c +++ b/plugins/uefi-dbx/fu-plugin-uefi-dbx.c @@ -48,9 +48,11 @@ fu_plugin_startup (FuPlugin *plugin, GError **error) if (data->fn == NULL) { g_autofree gchar *dbxdir = NULL; dbxdir = fu_common_get_path (FU_PATH_KIND_EFIDBXDIR); - g_prefix_error (error, - "file can be downloaded from %s and decompressed into %s: ", - FU_UEFI_DBX_DATA_URL, dbxdir); + g_set_error (error, + FWUPD_ERROR, + FWUPD_ERROR_NOT_SUPPORTED, + "file can be downloaded from %s and decompressed into %s: ", + FU_UEFI_DBX_DATA_URL, dbxdir); return FALSE; } From 46f5415edaa3d71850fd1c2a00ab2eeb8139f84c Mon Sep 17 00:00:00 2001 From: Ilya Guterman Date: Wed, 6 May 2020 02:58:10 +0300 Subject: [PATCH 037/607] dfu: Support MATEKF722SE quirk MATEKF722SE has unconvetional behavior for dfu protocol, where the sector size isn't specified and sector type is shiffted left by 1. This happens only for one sector. Sector parsing from MATEKF722SE: * `016Kg` * `64Kg` * `128Kg` * `048 e` * `528e` * `004 e` --- plugins/dfu/dfu-device.c | 1 + plugins/dfu/dfu-self-test.c | 2 ++ plugins/dfu/dfu-target.c | 9 +++++++++ plugins/dfu/dfu.quirk | 1 + 4 files changed, 13 insertions(+) diff --git a/plugins/dfu/dfu-device.c b/plugins/dfu/dfu-device.c index 9e11d22dc..eae6a353e 100644 --- a/plugins/dfu/dfu-device.c +++ b/plugins/dfu/dfu-device.c @@ -43,6 +43,7 @@ * * `use-protocol-zero`: Fix up the protocol number * * `legacy-protocol`: Use a legacy protocol version * * `detach-for-attach`: Requires a DFU_REQUEST_DETACH to attach + * * `absent-sector-size`: In absence of sector size, assume byte * * Default value: `none` * diff --git a/plugins/dfu/dfu-self-test.c b/plugins/dfu/dfu-self-test.c index 2a1e9ffe1..bb091526b 100644 --- a/plugins/dfu/dfu-self-test.c +++ b/plugins/dfu/dfu-self-test.c @@ -259,11 +259,13 @@ dfu_target_dfuse_func (void) { gboolean ret; gchar *tmp; + g_autoptr(DfuDevice) device = dfu_device_new (NULL); g_autoptr(DfuTarget) target = NULL; g_autoptr(GError) error = NULL; /* NULL */ target = g_object_new (DFU_TYPE_TARGET, NULL); + dfu_target_set_device (target, device); ret = dfu_target_parse_sectors (target, NULL, &error); g_assert_no_error (error); g_assert (ret); diff --git a/plugins/dfu/dfu-target.c b/plugins/dfu/dfu-target.c index 6d92789f9..5ada4f21a 100644 --- a/plugins/dfu/dfu-target.c +++ b/plugins/dfu/dfu-target.c @@ -198,6 +198,15 @@ dfu_target_parse_sector (DfuTarget *target, return FALSE; } + /* handle weirdness */ + if (fu_device_has_custom_flag (FU_DEVICE (dfu_target_get_device (target)), + "absent-sector-size")) { + if (tmp[1] == '\0') { + tmp[1] = tmp[0]; + tmp[0] = 'B'; + } + } + /* get multiplier */ switch (tmp[0]) { case 'B': /* byte */ diff --git a/plugins/dfu/dfu.quirk b/plugins/dfu/dfu.quirk index 2a5e755bd..bbf172a72 100644 --- a/plugins/dfu/dfu.quirk +++ b/plugins/dfu/dfu.quirk @@ -325,6 +325,7 @@ DfuAltName = @Flash/0x0/1*32Kg # STM32F745 dfuse bootloader [DeviceInstanceId=USB\VID_0483&PID_DF11] +Flags = absent-sector-size Plugin = dfu DfuForceVersion = 011a DfuForceTimeout = 5000 From 9223c89019824d2d0c72d63eb29f977691d01f89 Mon Sep 17 00:00:00 2001 From: Richard Hughes Date: Sat, 9 May 2020 20:32:08 +0100 Subject: [PATCH 038/607] trivial: Add a helper method to check for an Intel CPU Some plugins will be Intel specific. --- libfwupdplugin/fu-common.c | 30 ++++++++++++++++++++++++++++++ libfwupdplugin/fu-common.h | 1 + libfwupdplugin/fwupdplugin.map | 1 + 3 files changed, 32 insertions(+) diff --git a/libfwupdplugin/fu-common.c b/libfwupdplugin/fu-common.c index 064ce62b8..790cd6b7c 100644 --- a/libfwupdplugin/fu-common.c +++ b/libfwupdplugin/fu-common.c @@ -19,6 +19,8 @@ #include #endif +#include + #include #include #include @@ -2026,3 +2028,31 @@ fu_common_kernel_locked_down (void) return FALSE; #endif } + +/** + * fu_common_is_cpu_intel: + * + * Uses CPUID to discover the CPU vendor and check if it is Intel. + * + * Return value: %TRUE if the vendor was Intel. + * + * Since: 1.5.0 + **/ +gboolean +fu_common_is_cpu_intel (void) +{ + guint eax = 0; + guint ebx = 0; + guint ecx = 0; + guint edx = 0; + guint level = 0; + + /* get vendor */ + __get_cpuid(level, &eax, &ebx, &ecx, &edx); + if (ebx == signature_INTEL_ebx && + edx == signature_INTEL_edx && + ecx == signature_INTEL_ecx) { + return TRUE; + } + return FALSE; +} diff --git a/libfwupdplugin/fu-common.h b/libfwupdplugin/fu-common.h index ce5ef0c7f..13e0bbf7a 100644 --- a/libfwupdplugin/fu-common.h +++ b/libfwupdplugin/fu-common.h @@ -224,3 +224,4 @@ gchar **fu_common_strnsplit (const gchar *str, const gchar *delimiter, gint max_tokens); gboolean fu_common_kernel_locked_down (void); +gboolean fu_common_is_cpu_intel (void); diff --git a/libfwupdplugin/fwupdplugin.map b/libfwupdplugin/fwupdplugin.map index 5d1db3e44..f99275061 100644 --- a/libfwupdplugin/fwupdplugin.map +++ b/libfwupdplugin/fwupdplugin.map @@ -584,6 +584,7 @@ LIBFWUPDPLUGIN_1.4.1 { LIBFWUPDPLUGIN_1.5.0 { global: fu_common_filename_glob; + fu_common_is_cpu_intel; fu_udev_device_get_parent_name; fu_udev_device_get_sysfs_attr; local: *; From 6a07870fa2a8ecd1c42c0b583e98d53ec4618e44 Mon Sep 17 00:00:00 2001 From: Richard Hughes Date: Sat, 9 May 2020 20:36:33 +0100 Subject: [PATCH 039/607] Add a vfunc that gets run after the device has been added This allows per-plugin actions after the device has been open()ed and started. --- libfwupdplugin/fu-plugin-private.h | 2 ++ libfwupdplugin/fu-plugin-vfuncs.h | 11 +++++++++++ libfwupdplugin/fu-plugin.c | 31 ++++++++++++++++++++++++++++++ libfwupdplugin/fwupdplugin.map | 1 + 4 files changed, 45 insertions(+) diff --git a/libfwupdplugin/fu-plugin-private.h b/libfwupdplugin/fu-plugin-private.h index a1862440b..0544c0f92 100644 --- a/libfwupdplugin/fu-plugin-private.h +++ b/libfwupdplugin/fu-plugin-private.h @@ -89,6 +89,8 @@ gboolean fu_plugin_runner_udev_device_changed (FuPlugin *self, gboolean fu_plugin_runner_device_created (FuPlugin *self, FuDevice *device, GError **error); +void fu_plugin_runner_device_added (FuPlugin *self, + FuDevice *device); void fu_plugin_runner_device_removed (FuPlugin *self, FuDevice *device); void fu_plugin_runner_device_register (FuPlugin *self, diff --git a/libfwupdplugin/fu-plugin-vfuncs.h b/libfwupdplugin/fu-plugin-vfuncs.h index af89b198e..0858d8b01 100644 --- a/libfwupdplugin/fu-plugin-vfuncs.h +++ b/libfwupdplugin/fu-plugin-vfuncs.h @@ -311,6 +311,17 @@ gboolean fu_plugin_udev_device_added (FuPlugin *plugin, gboolean fu_plugin_udev_device_changed (FuPlugin *plugin, FuUdevDevice *device, GError **error); +/** + * fu_plugin_device_added + * @plugin: A #FuPlugin + * @device: A #FuDevice + * + * Function run when the subclassed device has been added. + * + * Since: 1.5.0 + **/ +void fu_plugin_device_added (FuPlugin *plugin, + FuDevice *dev); /** * fu_plugin_device_removed * @plugin: A #FuPlugin diff --git a/libfwupdplugin/fu-plugin.c b/libfwupdplugin/fu-plugin.c index cdf2ec881..810e8243d 100644 --- a/libfwupdplugin/fu-plugin.c +++ b/libfwupdplugin/fu-plugin.c @@ -1691,6 +1691,7 @@ fu_plugin_usb_device_added (FuPlugin *self, FuUsbDevice *device, GError **error) if (locker == NULL) return FALSE; fu_plugin_device_add (self, dev); + fu_plugin_runner_device_added (self, dev); return TRUE; } @@ -1742,6 +1743,7 @@ fu_plugin_udev_device_added (FuPlugin *self, FuUdevDevice *device, GError **erro if (locker == NULL) return FALSE; fu_plugin_device_add (self, FU_DEVICE (dev)); + fu_plugin_runner_device_added (self, dev); return TRUE; } @@ -1910,6 +1912,35 @@ fu_plugin_runner_udev_device_changed (FuPlugin *self, FuUdevDevice *device, GErr return TRUE; } +/** + * fu_plugin_runner_device_added: + * @self: a #FuPlugin + * @device: a #FuDevice + * + * Call the device_added routine for the plugin + * + * Since: 1.5.0 + **/ +void +fu_plugin_runner_device_added (FuPlugin *self, FuDevice *device) +{ + FuPluginPrivate *priv = GET_PRIVATE (self); + FuPluginDeviceRegisterFunc func = NULL; + + /* not enabled */ + if (!priv->enabled) + return; + if (priv->module == NULL) + return; + + /* optional */ + g_module_symbol (priv->module, "fu_plugin_device_added", (gpointer *) &func); + if (func == NULL) + return; + g_debug ("performing fu_plugin_device_added() on %s", priv->name); + func (self, device); +} + /** * fu_plugin_runner_device_removed: * @self: a #FuPlugin diff --git a/libfwupdplugin/fwupdplugin.map b/libfwupdplugin/fwupdplugin.map index f99275061..e1962298c 100644 --- a/libfwupdplugin/fwupdplugin.map +++ b/libfwupdplugin/fwupdplugin.map @@ -585,6 +585,7 @@ LIBFWUPDPLUGIN_1.5.0 { global: fu_common_filename_glob; fu_common_is_cpu_intel; + fu_plugin_runner_device_added; fu_udev_device_get_parent_name; fu_udev_device_get_sysfs_attr; local: *; From d1d83c083e8166170bf518fe9c15e9314f74e618 Mon Sep 17 00:00:00 2001 From: Subhendu Ghosh Date: Mon, 11 May 2020 00:27:15 -0400 Subject: [PATCH 040/607] ata: Add OUI quirk for Western Digital --- plugins/ata/ata.quirk | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/plugins/ata/ata.quirk b/plugins/ata/ata.quirk index 0e79dfe4e..b8b66409f 100644 --- a/plugins/ata/ata.quirk +++ b/plugins/ata/ata.quirk @@ -22,6 +22,10 @@ VendorId = ATA:0x101C Vendor = Intel VendorId = ATA:0x8086 +[DeviceInstanceId=OUI\001b44] +Vendor = Western Digital +VendorId = ATA:0x101C + [DeviceInstanceId=OUI\002303] Vendor = LITE-ON VendorId = ATA:0x14A4 From 173acd2e07d6e1508d435708cd851a879e5b9c3d Mon Sep 17 00:00:00 2001 From: Richard Hughes Date: Mon, 11 May 2020 17:11:10 +0100 Subject: [PATCH 041/607] Add FwupdSecurityAttr to libfwupd This will be used to store security attributes about platform security. --- libfwupd/fwupd-enums-private.h | 2 + libfwupd/fwupd-security-attr-private.h | 21 + libfwupd/fwupd-security-attr.c | 696 +++++++++++++++++++++++++ libfwupd/fwupd-security-attr.h | 107 ++++ libfwupd/fwupd.h | 1 + libfwupd/fwupd.map | 29 ++ libfwupd/meson.build | 5 + 7 files changed, 861 insertions(+) create mode 100644 libfwupd/fwupd-security-attr-private.h create mode 100644 libfwupd/fwupd-security-attr.c create mode 100644 libfwupd/fwupd-security-attr.h diff --git a/libfwupd/fwupd-enums-private.h b/libfwupd/fwupd-enums-private.h index 477b600cc..abb556895 100644 --- a/libfwupd/fwupd-enums-private.h +++ b/libfwupd/fwupd-enums-private.h @@ -23,6 +23,8 @@ G_BEGIN_DECLS #define FWUPD_RESULT_KEY_FLAGS "Flags" /* t */ #define FWUPD_RESULT_KEY_FLASHES_LEFT "FlashesLeft" /* u */ #define FWUPD_RESULT_KEY_URGENCY "Urgency" /* u */ +#define FWUPD_RESULT_KEY_HSI_LEVEL "HsiLevel" /* u */ +#define FWUPD_RESULT_KEY_HSI_RESULT "HsiResult" /* s */ #define FWUPD_RESULT_KEY_INSTALL_DURATION "InstallDuration" /* u */ #define FWUPD_RESULT_KEY_GUID "Guid" /* as */ #define FWUPD_RESULT_KEY_INSTANCE_IDS "InstanceIds" /* as */ diff --git a/libfwupd/fwupd-security-attr-private.h b/libfwupd/fwupd-security-attr-private.h new file mode 100644 index 000000000..6106ec1cb --- /dev/null +++ b/libfwupd/fwupd-security-attr-private.h @@ -0,0 +1,21 @@ +/* + * Copyright (C) 2020 Richard Hughes + * + * SPDX-License-Identifier: LGPL-2.1+ + */ + +#pragma once + +#include +#include + +#include "fwupd-security-attr.h" + +G_BEGIN_DECLS + +GVariant *fwupd_security_attr_to_variant (FwupdSecurityAttr *self); +void fwupd_security_attr_to_json (FwupdSecurityAttr *self, + JsonBuilder *builder); + +G_END_DECLS + diff --git a/libfwupd/fwupd-security-attr.c b/libfwupd/fwupd-security-attr.c new file mode 100644 index 000000000..7ce33b1d3 --- /dev/null +++ b/libfwupd/fwupd-security-attr.c @@ -0,0 +1,696 @@ +/* + * Copyright (C) 2020 Richard Hughes + * + * SPDX-License-Identifier: LGPL-2.1+ + */ + +#include "config.h" + +#include + +#include "fwupd-common-private.h" +#include "fwupd-enums-private.h" +#include "fwupd-security-attr-private.h" + +/** + * SECTION:fwupd-security-attr + * + * An object that represents an Host Security ID attribute. + */ + +static void fwupd_security_attr_finalize (GObject *object); + +typedef struct { + gchar *appstream_id; + GPtrArray *obsoletes; + gchar *name; + gchar *result; + FwupdSecurityAttrLevel level; + FwupdSecurityAttrFlags flags; +} FwupdSecurityAttrPrivate; + +G_DEFINE_TYPE_WITH_PRIVATE (FwupdSecurityAttr, fwupd_security_attr, G_TYPE_OBJECT) +#define GET_PRIVATE(o) (fwupd_security_attr_get_instance_private (o)) + +/** + * fwupd_security_attr_flag_to_string: + * @flag: A #FwupdSecurityAttrFlags, e.g. %FWUPD_SECURITY_ATTR_FLAG_SUCCESS + * + * Returns the printable string for the flag. + * + * Returns: string, or %NULL + * + * Since: 1.5.0 + **/ +const gchar * +fwupd_security_attr_flag_to_string (FwupdSecurityAttrFlags flag) +{ + if (flag == FWUPD_SECURITY_ATTR_FLAG_NONE) + return "none"; + if (flag == FWUPD_SECURITY_ATTR_FLAG_SUCCESS) + return "success"; + if (flag == FWUPD_SECURITY_ATTR_FLAG_OBSOLETED) + return "obsoleted"; + if (flag == FWUPD_SECURITY_ATTR_FLAG_RUNTIME_UPDATES) + return "runtime-updates"; + if (flag == FWUPD_SECURITY_ATTR_FLAG_RUNTIME_ATTESTATION) + return "runtime-attestation"; + if (flag == FWUPD_SECURITY_ATTR_FLAG_RUNTIME_ISSUE) + return "runtime-issue"; + return NULL; +} + +/** + * fwupd_security_attr_flag_to_suffix: + * @flag: A #FwupdSecurityAttrFlags, e.g. %FWUPD_SECURITY_ATTR_FLAG_RUNTIME_UPDATES + * + * Returns the string suffix for the flag. + * + * Returns: string, or %NULL + * + * Since: 1.5.0 + **/ +const gchar * +fwupd_security_attr_flag_to_suffix (FwupdSecurityAttrFlags flag) +{ + if (flag == FWUPD_SECURITY_ATTR_FLAG_RUNTIME_UPDATES) + return "U"; + if (flag == FWUPD_SECURITY_ATTR_FLAG_RUNTIME_ATTESTATION) + return "A"; + if (flag == FWUPD_SECURITY_ATTR_FLAG_RUNTIME_ISSUE) + return "!"; + return NULL; +} + +/** + * fwupd_security_attr_get_obsoletes: + * @self: A #FwupdSecurityAttr + * + * Gets the list of attribute obsoletes. The obsoleted attributes will not + * contribute to the calculated HSI value or be visible in command line tools. + * + * Returns: (element-type utf8) (transfer none): the obsoletes, which may be empty + * + * Since: 1.5.0 + **/ +GPtrArray * +fwupd_security_attr_get_obsoletes (FwupdSecurityAttr *self) +{ + FwupdSecurityAttrPrivate *priv = GET_PRIVATE (self); + g_return_val_if_fail (FWUPD_IS_SECURITY_ATTR (self), NULL); + return priv->obsoletes; +} + +/** + * fwupd_security_attr_add_obsolete: + * @self: A #FwupdSecurityAttr + * @appstream_id: the appstream_id + * + * Adds an attribute appstream_id to obsolete. The obsoleted attribute will not + * contribute to the calculated HSI value or be visible in command line tools. + * + * Since: 1.5.0 + **/ +void +fwupd_security_attr_add_obsolete (FwupdSecurityAttr *self, const gchar *appstream_id) +{ + FwupdSecurityAttrPrivate *priv = GET_PRIVATE (self); + g_return_if_fail (FWUPD_IS_SECURITY_ATTR (self)); + g_return_if_fail (appstream_id != NULL); + if (fwupd_security_attr_has_obsolete (self, appstream_id)) + return; + g_ptr_array_add (priv->obsoletes, g_strdup (appstream_id)); +} + +/** + * fwupd_security_attr_has_obsolete: + * @self: A #FwupdSecurityAttr + * @appstream_id: the attribute appstream_id + * + * Finds out if the attribute obsoletes a specific appstream_id. + * + * Returns: %TRUE if the self matches + * + * Since: 1.5.0 + **/ +gboolean +fwupd_security_attr_has_obsolete (FwupdSecurityAttr *self, const gchar *appstream_id) +{ + FwupdSecurityAttrPrivate *priv = GET_PRIVATE (self); + g_return_val_if_fail (FWUPD_IS_SECURITY_ATTR (self), FALSE); + g_return_val_if_fail (appstream_id != NULL, FALSE); + for (guint i = 0; i < priv->obsoletes->len; i++) { + const gchar *obsolete_tmp = g_ptr_array_index (priv->obsoletes, i); + if (g_strcmp0 (obsolete_tmp, appstream_id) == 0) + return TRUE; + } + return FALSE; +} + +/** + * fwupd_security_attr_get_appstream_id: + * @self: A #FwupdSecurityAttr + * + * Gets the AppStream ID. + * + * Returns: the AppStream ID, or %NULL if unset + * + * Since: 1.5.0 + **/ +const gchar * +fwupd_security_attr_get_appstream_id (FwupdSecurityAttr *self) +{ + FwupdSecurityAttrPrivate *priv = GET_PRIVATE (self); + g_return_val_if_fail (FWUPD_IS_SECURITY_ATTR (self), NULL); + return priv->appstream_id; +} + +/** + * fwupd_security_attr_set_appstream_id: + * @self: A #FwupdSecurityAttr + * @appstream_id: the AppStream component ID, e.g. `com.intel.BiosGuard` + * + * Sets the AppStream ID. + * + * Since: 1.5.0 + **/ +void +fwupd_security_attr_set_appstream_id (FwupdSecurityAttr *self, const gchar *appstream_id) +{ + FwupdSecurityAttrPrivate *priv = GET_PRIVATE (self); + g_return_if_fail (FWUPD_IS_SECURITY_ATTR (self)); + g_free (priv->appstream_id); + priv->appstream_id = g_strdup (appstream_id); +} + +/** + * fwupd_security_attr_get_result: + * @self: A #FwupdSecurityAttr + * + * Gets the attribute result. + * + * Returns: the attribute result, or %NULL if unset + * + * Since: 1.5.0 + **/ +const gchar * +fwupd_security_attr_get_result (FwupdSecurityAttr *self) +{ + FwupdSecurityAttrPrivate *priv = GET_PRIVATE (self); + g_return_val_if_fail (FWUPD_IS_SECURITY_ATTR (self), NULL); + return priv->result; +} + +/** + * fwupd_security_attr_set_name: + * @self: A #FwupdSecurityAttr + * @result: the attribute one line result + * + * Sets the attribute name. + * + * Since: 1.5.0 + **/ +void +fwupd_security_attr_set_name (FwupdSecurityAttr *self, const gchar *name) +{ + FwupdSecurityAttrPrivate *priv = GET_PRIVATE (self); + g_return_if_fail (FWUPD_IS_SECURITY_ATTR (self)); + g_free (priv->name); + priv->name = g_strdup (name); +} + +/** + * fwupd_security_attr_set_result: + * @self: A #FwupdSecurityAttr + * @result: the attribute one line result + * + * Sets the attribute result. + * + * Since: 1.5.0 + **/ +void +fwupd_security_attr_set_result (FwupdSecurityAttr *self, const gchar *result) +{ + FwupdSecurityAttrPrivate *priv = GET_PRIVATE (self); + g_return_if_fail (FWUPD_IS_SECURITY_ATTR (self)); + g_free (priv->result); + priv->result = g_strdup (result); +} + +/** + * fwupd_security_attr_get_name: + * @self: A #FwupdSecurityAttr + * + * Gets the attribute name. + * + * Returns: the attribute name, or %NULL if unset + * + * Since: 1.5.0 + **/ +const gchar * +fwupd_security_attr_get_name (FwupdSecurityAttr *self) +{ + FwupdSecurityAttrPrivate *priv = GET_PRIVATE (self); + g_return_val_if_fail (FWUPD_IS_SECURITY_ATTR (self), NULL); + return priv->name; +} + +/** + * fwupd_security_attr_get_flags: + * @self: A #FwupdSecurityAttr + * + * Gets the self flags. + * + * Returns: the self flags, or 0 if unset + * + * Since: 1.5.0 + **/ +FwupdSecurityAttrFlags +fwupd_security_attr_get_flags (FwupdSecurityAttr *self) +{ + FwupdSecurityAttrPrivate *priv = GET_PRIVATE (self); + g_return_val_if_fail (FWUPD_IS_SECURITY_ATTR (self), 0); + return priv->flags; +} + +/** + * fwupd_security_attr_set_flags: + * @self: A #FwupdSecurityAttr + * @flags: the self flags, e.g. %FWUPD_SECURITY_ATTR_FLAG_TRUSTED_PAYLOAD + * + * Sets the self flags. + * + * Since: 1.5.0 + **/ +void +fwupd_security_attr_set_flags (FwupdSecurityAttr *self, FwupdSecurityAttrFlags flags) +{ + FwupdSecurityAttrPrivate *priv = GET_PRIVATE (self); + g_return_if_fail (FWUPD_IS_SECURITY_ATTR (self)); + priv->flags = flags; +} + +/** + * fwupd_security_attr_add_flag: + * @self: A #FwupdSecurityAttr + * @flag: the #FwupdSecurityAttrFlags + * + * Adds a specific self flag to the self. + * + * Since: 1.5.0 + **/ +void +fwupd_security_attr_add_flag (FwupdSecurityAttr *self, FwupdSecurityAttrFlags flag) +{ + FwupdSecurityAttrPrivate *priv = GET_PRIVATE (self); + g_return_if_fail (FWUPD_IS_SECURITY_ATTR (self)); + priv->flags |= flag; +} + +/** + * fwupd_security_attr_has_flag: + * @self: A #FwupdSecurityAttr + * @flag: the #FwupdSecurityAttrFlags + * + * Finds if the self has a specific self flag. + * + * Returns: %TRUE if the flag is set + * + * Since: 1.5.0 + **/ +gboolean +fwupd_security_attr_has_flag (FwupdSecurityAttr *self, FwupdSecurityAttrFlags flag) +{ + FwupdSecurityAttrPrivate *priv = GET_PRIVATE (self); + g_return_val_if_fail (FWUPD_IS_SECURITY_ATTR (self), FALSE); + return (priv->flags & flag) > 0; +} + +/** + * fwupd_security_attr_get_level: + * @self: A #FwupdSecurityAttr + * + * Gets the HSI level. + * + * Returns: the #FwupdSecurityAttrLevel, or %FWUPD_SECURITY_ATTR_LEVEL_NONE if unset + * + * Since: 1.5.0 + **/ +FwupdSecurityAttrLevel +fwupd_security_attr_get_level (FwupdSecurityAttr *self) +{ + FwupdSecurityAttrPrivate *priv = GET_PRIVATE (self); + g_return_val_if_fail (FWUPD_IS_SECURITY_ATTR (self), 0); + return priv->level; +} + +/** + * fwupd_security_attr_set_level: + * @self: A #FwupdSecurityAttr + * @level: A #FwupdSecurityAttrLevel, e.g. %FWUPD_SECURITY_ATTR_LEVEL_IMPORTANT + * + * Sets the HSI level. A @level of %FWUPD_SECURITY_ATTR_LEVEL_NONE is not used + * for the HSI calculation. + * + * Since: 1.5.0 + **/ +void +fwupd_security_attr_set_level (FwupdSecurityAttr *self, FwupdSecurityAttrLevel level) +{ + FwupdSecurityAttrPrivate *priv = GET_PRIVATE (self); + g_return_if_fail (FWUPD_IS_SECURITY_ATTR (self)); + priv->level = level; +} + +/** + * fwupd_security_attr_to_variant: + * @self: A #FwupdSecurityAttr + * + * Creates a GVariant from the self data. + * + * Returns: the GVariant, or %NULL for error + * + * Since: 1.5.0 + **/ +GVariant * +fwupd_security_attr_to_variant (FwupdSecurityAttr *self) +{ + FwupdSecurityAttrPrivate *priv = GET_PRIVATE (self); + GVariantBuilder builder; + + g_return_val_if_fail (FWUPD_IS_SECURITY_ATTR (self), NULL); + + g_variant_builder_init (&builder, G_VARIANT_TYPE_VARDICT); + if (priv->appstream_id != NULL) { + g_variant_builder_add (&builder, "{sv}", + FWUPD_RESULT_KEY_APPSTREAM_ID, + g_variant_new_string (priv->appstream_id)); + } + if (priv->name != NULL) { + g_variant_builder_add (&builder, "{sv}", + FWUPD_RESULT_KEY_NAME, + g_variant_new_string (priv->name)); + } + if (priv->result != NULL) { + g_variant_builder_add (&builder, "{sv}", + FWUPD_RESULT_KEY_HSI_RESULT, + g_variant_new_string (priv->result)); + } + if (priv->obsoletes->len > 0) { + g_autofree const gchar **strv = g_new0 (const gchar *, priv->obsoletes->len + 1); + for (guint i = 0; i < priv->obsoletes->len; i++) + strv[i] = (const gchar *) g_ptr_array_index (priv->obsoletes, i); + g_variant_builder_add (&builder, "{sv}", + FWUPD_RESULT_KEY_CATEGORIES, + g_variant_new_strv (strv, -1)); + } + if (priv->flags != 0) { + g_variant_builder_add (&builder, "{sv}", + FWUPD_RESULT_KEY_FLAGS, + g_variant_new_uint64 (priv->flags)); + } + if (priv->level > 0) { + g_variant_builder_add (&builder, "{sv}", + FWUPD_RESULT_KEY_HSI_LEVEL, + g_variant_new_uint32 (priv->level)); + } + return g_variant_new ("a{sv}", &builder); +} + +static void +fwupd_security_attr_from_key_value (FwupdSecurityAttr *self, const gchar *key, GVariant *value) +{ + if (g_strcmp0 (key, FWUPD_RESULT_KEY_APPSTREAM_ID) == 0) { + fwupd_security_attr_set_appstream_id (self, g_variant_get_string (value, NULL)); + return; + } + if (g_strcmp0 (key, FWUPD_RESULT_KEY_NAME) == 0) { + fwupd_security_attr_set_name (self, g_variant_get_string (value, NULL)); + return; + } + if (g_strcmp0 (key, FWUPD_RESULT_KEY_HSI_RESULT) == 0) { + fwupd_security_attr_set_result (self, g_variant_get_string (value, NULL)); + return; + } + if (g_strcmp0 (key, FWUPD_RESULT_KEY_FLAGS) == 0) { + fwupd_security_attr_set_flags (self, g_variant_get_uint64 (value)); + return; + } + if (g_strcmp0 (key, FWUPD_RESULT_KEY_HSI_LEVEL) == 0) { + fwupd_security_attr_set_level (self, g_variant_get_uint32 (value)); + return; + } +} + +static void +fwupd_pad_kv_str (GString *str, const gchar *key, const gchar *value) +{ + /* ignore */ + if (key == NULL || value == NULL) + return; + g_string_append_printf (str, " %s: ", key); + for (gsize i = strlen (key); i < 20; i++) + g_string_append (str, " "); + g_string_append_printf (str, "%s\n", value); +} + +static void +fwupd_pad_kv_tfl (GString *str, const gchar *key, FwupdSecurityAttrFlags security_attr_flags) +{ + g_autoptr(GString) tmp = g_string_new (""); + for (guint i = 0; i < 64; i++) { + if ((security_attr_flags & ((guint64) 1 << i)) == 0) + continue; + g_string_append_printf (tmp, "%s|", + fwupd_security_attr_flag_to_string ((guint64) 1 << i)); + } + if (tmp->len == 0) { + g_string_append (tmp, fwupd_security_attr_flag_to_string (0)); + } else { + g_string_truncate (tmp, tmp->len - 1); + } + fwupd_pad_kv_str (str, key, tmp->str); +} + +static void +fwupd_pad_kv_int (GString *str, const gchar *key, guint32 value) +{ + g_autofree gchar *tmp = NULL; + + /* ignore */ + if (value == 0) + return; + tmp = g_strdup_printf("%" G_GUINT32_FORMAT, value); + fwupd_pad_kv_str (str, key, tmp); +} + +static void +fwupd_security_attr_json_add_string (JsonBuilder *builder, const gchar *key, const gchar *str) +{ + if (str == NULL) + return; + json_builder_set_member_name (builder, key); + json_builder_add_string_value (builder, str); +} + +static void +fwupd_security_attr_json_add_int (JsonBuilder *builder, const gchar *key, guint64 num) +{ + if (num == 0) + return; + json_builder_set_member_name (builder, key); + json_builder_add_int_value (builder, num); +} + +/** + * fwupd_security_attr_to_json: + * @self: A #FwupdSecurityAttr + * @builder: A #JsonBuilder + * + * Adds a fwupd self to a JSON builder + * + * Since: 1.5.0 + **/ +void +fwupd_security_attr_to_json (FwupdSecurityAttr *self, JsonBuilder *builder) +{ + FwupdSecurityAttrPrivate *priv = GET_PRIVATE (self); + g_autoptr(GList) keys = NULL; + + g_return_if_fail (FWUPD_IS_SECURITY_ATTR (self)); + g_return_if_fail (builder != NULL); + + fwupd_security_attr_json_add_string (builder, FWUPD_RESULT_KEY_APPSTREAM_ID, priv->appstream_id); + fwupd_security_attr_json_add_int (builder, FWUPD_RESULT_KEY_HSI_LEVEL, priv->level); + fwupd_security_attr_json_add_string (builder, FWUPD_RESULT_KEY_NAME, priv->name); + fwupd_security_attr_json_add_string (builder, FWUPD_RESULT_KEY_HSI_RESULT, priv->result); + if (priv->flags != FWUPD_SECURITY_ATTR_FLAG_NONE) { + json_builder_set_member_name (builder, FWUPD_RESULT_KEY_FLAGS); + json_builder_begin_array (builder); + for (guint i = 0; i < 64; i++) { + const gchar *tmp; + if ((priv->flags & ((guint64) 1 << i)) == 0) + continue; + tmp = fwupd_security_attr_flag_to_string ((guint64) 1 << i); + json_builder_add_string_value (builder, tmp); + } + json_builder_end_array (builder); + } +} + +/** + * fwupd_security_attr_to_string: + * @self: A #FwupdSecurityAttr + * + * Builds a text representation of the object. + * + * Returns: text, or %NULL for invalid + * + * Since: 1.5.0 + **/ +gchar * +fwupd_security_attr_to_string (FwupdSecurityAttr *self) +{ + FwupdSecurityAttrPrivate *priv = GET_PRIVATE (self); + GString *str; + g_autoptr(GList) keys = NULL; + + g_return_val_if_fail (FWUPD_IS_SECURITY_ATTR (self), NULL); + + str = g_string_new (""); + fwupd_pad_kv_str (str, FWUPD_RESULT_KEY_APPSTREAM_ID, priv->appstream_id); + fwupd_pad_kv_int (str, FWUPD_RESULT_KEY_HSI_LEVEL, priv->level); + if (priv->flags != FWUPD_SECURITY_ATTR_FLAG_NONE) + fwupd_pad_kv_tfl (str, FWUPD_RESULT_KEY_FLAGS, priv->flags); + fwupd_pad_kv_str (str, FWUPD_RESULT_KEY_NAME, priv->name); + fwupd_pad_kv_str (str, FWUPD_RESULT_KEY_HSI_RESULT, priv->result); + for (guint i = 0; i < priv->obsoletes->len; i++) { + const gchar *appstream_id = g_ptr_array_index (priv->obsoletes, i); + fwupd_pad_kv_str (str, "Obsolete", appstream_id); + } + + return g_string_free (str, FALSE); +} + +static void +fwupd_security_attr_class_init (FwupdSecurityAttrClass *klass) +{ + GObjectClass *object_class = G_OBJECT_CLASS (klass); + object_class->finalize = fwupd_security_attr_finalize; +} + +static void +fwupd_security_attr_init (FwupdSecurityAttr *self) +{ + FwupdSecurityAttrPrivate *priv = GET_PRIVATE (self); + priv->obsoletes = g_ptr_array_new_with_free_func (g_free); +} + +static void +fwupd_security_attr_finalize (GObject *object) +{ + FwupdSecurityAttr *self = FWUPD_SECURITY_ATTR (object); + FwupdSecurityAttrPrivate *priv = GET_PRIVATE (self); + + g_free (priv->appstream_id); + g_free (priv->name); + g_free (priv->result); + g_ptr_array_unref (priv->obsoletes); + + G_OBJECT_CLASS (fwupd_security_attr_parent_class)->finalize (object); +} + +static void +fwupd_security_attr_set_from_variant_iter (FwupdSecurityAttr *self, GVariantIter *iter) +{ + GVariant *value; + const gchar *key; + while (g_variant_iter_next (iter, "{&sv}", &key, &value)) { + fwupd_security_attr_from_key_value (self, key, value); + g_variant_unref (value); + } +} + +/** + * fwupd_security_attr_from_variant: + * @value: a #GVariant + * + * Creates a new self using packed data. + * + * Returns: (transfer full): a new #FwupdSecurityAttr, or %NULL if @value was invalid + * + * Since: 1.5.0 + **/ +FwupdSecurityAttr * +fwupd_security_attr_from_variant (GVariant *value) +{ + FwupdSecurityAttr *rel = NULL; + const gchar *type_string; + g_autoptr(GVariantIter) iter = NULL; + + type_string = g_variant_get_type_string (value); + if (g_strcmp0 (type_string, "(a{sv})") == 0) { + rel = fwupd_security_attr_new (NULL); + g_variant_get (value, "(a{sv})", &iter); + fwupd_security_attr_set_from_variant_iter (rel, iter); + } else if (g_strcmp0 (type_string, "a{sv}") == 0) { + rel = fwupd_security_attr_new (NULL); + g_variant_get (value, "a{sv}", &iter); + fwupd_security_attr_set_from_variant_iter (rel, iter); + } else { + g_warning ("type %s not known", type_string); + } + return rel; +} + +/** + * fwupd_security_attr_array_from_variant: + * @value: a #GVariant + * + * Creates an array of new security_attrs using packed data. + * + * Returns: (transfer container) (element-type FwupdSecurityAttr): attributes, or %NULL if @value was invalid + * + * Since: 1.5.0 + **/ +GPtrArray * +fwupd_security_attr_array_from_variant (GVariant *value) +{ + GPtrArray *array = NULL; + gsize sz; + g_autoptr(GVariant) untuple = NULL; + + array = g_ptr_array_new_with_free_func ((GDestroyNotify) g_object_unref); + untuple = g_variant_get_child_value (value, 0); + sz = g_variant_n_children (untuple); + for (guint i = 0; i < sz; i++) { + FwupdSecurityAttr *rel; + g_autoptr(GVariant) data = NULL; + data = g_variant_get_child_value (untuple, i); + rel = fwupd_security_attr_from_variant (data); + if (rel == NULL) + continue; + g_ptr_array_add (array, rel); + } + return array; +} + +/** + * fwupd_security_attr_new: + * @appstream_id: (allow-none): the AppStream component ID, e.g. `com.intel.BiosGuard` + * + * Creates a new self. + * + * Returns: a new #FwupdSecurityAttr + * + * Since: 1.5.0 + **/ +FwupdSecurityAttr * +fwupd_security_attr_new (const gchar *appstream_id) +{ + FwupdSecurityAttr *self; + self = g_object_new (FWUPD_TYPE_SECURITY_ATTR, NULL); + if (appstream_id != NULL) + fwupd_security_attr_set_appstream_id (self, appstream_id); + return FWUPD_SECURITY_ATTR (self); +} diff --git a/libfwupd/fwupd-security-attr.h b/libfwupd/fwupd-security-attr.h new file mode 100644 index 000000000..089b56e70 --- /dev/null +++ b/libfwupd/fwupd-security-attr.h @@ -0,0 +1,107 @@ +/* + * Copyright (C) 2020 Richard Hughes + * + * SPDX-License-Identifier: LGPL-2.1+ + */ + +#pragma once + +#include + +#include "fwupd-enums.h" + +G_BEGIN_DECLS + +#define FWUPD_TYPE_SECURITY_ATTR (fwupd_security_attr_get_type ()) +G_DECLARE_DERIVABLE_TYPE (FwupdSecurityAttr, fwupd_security_attr, FWUPD, SECURITY_ATTR, GObject) + +struct _FwupdSecurityAttrClass +{ + GObjectClass parent_class; + /*< private >*/ + void (*_fwupd_reserved1) (void); + void (*_fwupd_reserved2) (void); + void (*_fwupd_reserved3) (void); + void (*_fwupd_reserved4) (void); + void (*_fwupd_reserved5) (void); + void (*_fwupd_reserved6) (void); + void (*_fwupd_reserved7) (void); +}; + + +/** + * FwupdSecurityAttrFlags: + * @FWUPD_SECURITY_ATTR_FLAG_NONE: No flags set + * @FWUPD_SECURITY_ATTR_FLAG_SUCCESS: Success + * @FWUPD_SECURITY_ATTR_FLAG_OBSOLETED: Obsoleted by another attribute + * @FWUPD_SECURITY_ATTR_FLAG_RUNTIME_UPDATES: Suffix `U` + * @FWUPD_SECURITY_ATTR_FLAG_RUNTIME_ATTESTATION: Suffix `A` + * @FWUPD_SECURITY_ATTR_FLAG_RUNTIME_ISSUE: Suffix `!` + * + * The flags available for HSI attributes. + **/ +typedef enum { + FWUPD_SECURITY_ATTR_FLAG_NONE = 0, + FWUPD_SECURITY_ATTR_FLAG_SUCCESS = 1 << 0, + FWUPD_SECURITY_ATTR_FLAG_OBSOLETED = 1 << 1, + FWUPD_SECURITY_ATTR_FLAG_RUNTIME_UPDATES = 1 << 8, + FWUPD_SECURITY_ATTR_FLAG_RUNTIME_ATTESTATION = 1 << 9, + FWUPD_SECURITY_ATTR_FLAG_RUNTIME_ISSUE = 1 << 10, +} FwupdSecurityAttrFlags; + +/** + * FwupdSecurityAttrLevel: + * @FWUPD_SECURITY_ATTR_LEVEL_NONE: Very few detected firmware protections + * @FWUPD_SECURITY_ATTR_LEVEL_CRITICAL: The most basic of security protections + * @FWUPD_SECURITY_ATTR_LEVEL_IMPORTANT: Firmware security issues considered important + * @FWUPD_SECURITY_ATTR_LEVEL_THEORETICAL: Firmware security issues that pose a theoretical concern + * @FWUPD_SECURITY_ATTR_LEVEL_SYSTEM_PROTECTION: Out-of-band protection of the system firmware + * @FWUPD_SECURITY_ATTR_LEVEL_SYSTEM_ATTESTATION: Out-of-band attestation of the system firmware + * + * The HSI level. + **/ +typedef enum { + FWUPD_SECURITY_ATTR_LEVEL_NONE = 0, /* Since: 1.5.0 */ + FWUPD_SECURITY_ATTR_LEVEL_CRITICAL = 1, /* Since: 1.5.0 */ + FWUPD_SECURITY_ATTR_LEVEL_IMPORTANT = 2, /* Since: 1.5.0 */ + FWUPD_SECURITY_ATTR_LEVEL_THEORETICAL = 3, /* Since: 1.5.0 */ + FWUPD_SECURITY_ATTR_LEVEL_SYSTEM_PROTECTION = 4, /* Since: 1.5.0 */ + FWUPD_SECURITY_ATTR_LEVEL_SYSTEM_ATTESTATION = 5, /* Since: 1.5.0 */ + /*< private >*/ + FWUPD_SECURITY_ATTR_LEVEL_LAST = 6 /* perhaps increased in the future */ +} FwupdSecurityAttrLevel; + +FwupdSecurityAttr *fwupd_security_attr_new (const gchar *appstream_id); +gchar *fwupd_security_attr_to_string (FwupdSecurityAttr *self); + +const gchar *fwupd_security_attr_get_appstream_id (FwupdSecurityAttr *self); +void fwupd_security_attr_set_appstream_id (FwupdSecurityAttr *self, + const gchar *appstream_id); +FwupdSecurityAttrLevel fwupd_security_attr_get_level (FwupdSecurityAttr *self); +void fwupd_security_attr_set_level (FwupdSecurityAttr *self, + FwupdSecurityAttrLevel level); +const gchar *fwupd_security_attr_get_name (FwupdSecurityAttr *self); +void fwupd_security_attr_set_name (FwupdSecurityAttr *self, + const gchar *name); +const gchar *fwupd_security_attr_get_result (FwupdSecurityAttr *self); +void fwupd_security_attr_set_result (FwupdSecurityAttr *self, + const gchar *result); +GPtrArray *fwupd_security_attr_get_obsoletes (FwupdSecurityAttr *self); +void fwupd_security_attr_add_obsolete (FwupdSecurityAttr *self, + const gchar *appstream_id); +gboolean fwupd_security_attr_has_obsolete (FwupdSecurityAttr *self, + const gchar *appstream_id); +FwupdSecurityAttrFlags fwupd_security_attr_get_flags (FwupdSecurityAttr *self); +void fwupd_security_attr_set_flags (FwupdSecurityAttr *self, + FwupdSecurityAttrFlags flags); +void fwupd_security_attr_add_flag (FwupdSecurityAttr *self, + FwupdSecurityAttrFlags flag); +gboolean fwupd_security_attr_has_flag (FwupdSecurityAttr *self, + FwupdSecurityAttrFlags flag); +const gchar *fwupd_security_attr_flag_to_string (FwupdSecurityAttrFlags flag); +const gchar *fwupd_security_attr_flag_to_suffix (FwupdSecurityAttrFlags flag); + +FwupdSecurityAttr *fwupd_security_attr_from_variant (GVariant *value); +GPtrArray *fwupd_security_attr_array_from_variant (GVariant *value); + +G_END_DECLS diff --git a/libfwupd/fwupd.h b/libfwupd/fwupd.h index 82571aa26..149f47862 100644 --- a/libfwupd/fwupd.h +++ b/libfwupd/fwupd.h @@ -18,6 +18,7 @@ #include #include #include +#include #include #include #include diff --git a/libfwupd/fwupd.map b/libfwupd/fwupd.map index 6c2d00192..94266d11e 100644 --- a/libfwupd/fwupd.map +++ b/libfwupd/fwupd.map @@ -446,3 +446,32 @@ LIBFWUPD_1.4.1 { fwupd_device_id_is_valid; local: *; } LIBFWUPD_1.4.0; + +LIBFWUPD_1.5.0 { + global: + fwupd_security_attr_add_flag; + fwupd_security_attr_add_obsolete; + fwupd_security_attr_array_from_variant; + fwupd_security_attr_flag_to_string; + fwupd_security_attr_flag_to_suffix; + fwupd_security_attr_from_variant; + fwupd_security_attr_get_appstream_id; + fwupd_security_attr_get_flags; + fwupd_security_attr_get_level; + fwupd_security_attr_get_name; + fwupd_security_attr_get_obsoletes; + fwupd_security_attr_get_result; + fwupd_security_attr_get_type; + fwupd_security_attr_has_flag; + fwupd_security_attr_has_obsolete; + fwupd_security_attr_new; + fwupd_security_attr_set_appstream_id; + fwupd_security_attr_set_flags; + fwupd_security_attr_set_level; + fwupd_security_attr_set_name; + fwupd_security_attr_set_result; + fwupd_security_attr_to_json; + fwupd_security_attr_to_string; + fwupd_security_attr_to_variant; + local: *; +} LIBFWUPD_1.4.1; diff --git a/libfwupd/meson.build b/libfwupd/meson.build index 9fe6cec3f..a8772030c 100644 --- a/libfwupd/meson.build +++ b/libfwupd/meson.build @@ -21,6 +21,7 @@ install_headers([ 'fwupd-enums.h', 'fwupd-error.h', 'fwupd-remote.h', + 'fwupd-security-attr.h', 'fwupd-release.h', fwupd_version_h, ], @@ -37,6 +38,7 @@ fwupd = shared_library( 'fwupd-device.c', 'fwupd-enums.c', 'fwupd-error.c', + 'fwupd-security-attr.c', 'fwupd-release.c', 'fwupd-remote.c', ], @@ -85,6 +87,9 @@ if get_option('introspection') 'fwupd-enums-private.h', 'fwupd-error.c', 'fwupd-error.h', + 'fwupd-security-attr.c', + 'fwupd-security-attr.h', + 'fwupd-security-attr-private.h', 'fwupd-release.c', 'fwupd-release.h', 'fwupd-release-private.h', From a715791707377ddad27ea99416547f4470a7d4ad Mon Sep 17 00:00:00 2001 From: Richard Hughes Date: Mon, 11 May 2020 17:14:05 +0100 Subject: [PATCH 042/607] Add a new path enum of FU_PATH_KIND_ACPI_TABLES --- libfwupdplugin/fu-common.c | 6 ++++++ libfwupdplugin/fu-common.h | 2 ++ 2 files changed, 8 insertions(+) diff --git a/libfwupdplugin/fu-common.c b/libfwupdplugin/fu-common.c index 790cd6b7c..5eb9c279d 100644 --- a/libfwupdplugin/fu-common.c +++ b/libfwupdplugin/fu-common.c @@ -1058,6 +1058,12 @@ fu_common_get_path (FuPathKind path_kind) if (tmp != NULL) return g_strdup (tmp); return g_strdup ("/sys/kernel/security"); + /* /sys/firmware/acpi/tables */ + case FU_PATH_KIND_ACPI_TABLES: + tmp = g_getenv ("FWUPD_ACPITABLESDIR"); + if (tmp != NULL) + return g_strdup (tmp); + return g_strdup ("/sys/firmware/acpi/tables"); /* /etc */ case FU_PATH_KIND_SYSCONFDIR: tmp = g_getenv ("FWUPD_SYSCONFDIR"); diff --git a/libfwupdplugin/fu-common.h b/libfwupdplugin/fu-common.h index 13e0bbf7a..1ba975978 100644 --- a/libfwupdplugin/fu-common.h +++ b/libfwupdplugin/fu-common.h @@ -58,6 +58,7 @@ typedef guint FuEndianType; * @FU_PATH_KIND_OFFLINE_TRIGGER: The file for the offline trigger (IE /system-update) * @FU_PATH_KIND_SYSFSDIR_SECURITY: The sysfs security location (IE /sys/kernel/security) * @FU_PATH_KIND_EFIDBXDIR: The location of the EFI dbx files + * @FU_PATH_KIND_ACPI_TABLES: The location of the ACPI tables * * Path types to use when dynamically determining a path at runtime **/ @@ -78,6 +79,7 @@ typedef enum { FU_PATH_KIND_OFFLINE_TRIGGER, FU_PATH_KIND_SYSFSDIR_SECURITY, FU_PATH_KIND_EFIDBXDIR, + FU_PATH_KIND_ACPI_TABLES, /*< private >*/ FU_PATH_KIND_LAST } FuPathKind; From c1407ed14f0c6d4ecfe83f4855ee4d5e25d762be Mon Sep 17 00:00:00 2001 From: Richard Hughes Date: Mon, 11 May 2020 17:16:23 +0100 Subject: [PATCH 043/607] trivial: Add a --force argument to fwupdagent to match the other tools --- src/fu-agent.c | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/src/fu-agent.c b/src/fu-agent.c index 72a8d17f9..634831cc8 100644 --- a/src/fu-agent.c +++ b/src/fu-agent.c @@ -27,6 +27,7 @@ struct FuUtilPrivate { GMainLoop *loop; GOptionContext *context; FwupdClient *client; + FwupdInstallFlags flags; }; static gboolean @@ -235,6 +236,7 @@ int main (int argc, char *argv[]) { gboolean ret; + gboolean force = FALSE; gboolean verbose = FALSE; g_autoptr(FuUtilPrivate) priv = g_new0 (FuUtilPrivate, 1); g_autoptr(GError) error = NULL; @@ -244,6 +246,9 @@ main (int argc, char *argv[]) { "verbose", 'v', 0, G_OPTION_ARG_NONE, &verbose, /* TRANSLATORS: command line option */ _("Show extra debugging information"), NULL }, + { "force", '\0', 0, G_OPTION_ARG_NONE, &force, + /* TRANSLATORS: command line option */ + _("Override warnings and force the action"), NULL }, { NULL} }; @@ -260,6 +265,10 @@ main (int argc, char *argv[]) priv->loop = g_main_loop_new (NULL, FALSE); priv->client = fwupd_client_new (); + /* set flags */ + if (force) + priv->flags |= FWUPD_INSTALL_FLAG_FORCE; + /* add commands */ fu_util_cmd_array_add (cmd_array, "get-devices", NULL, From 196c6c69dbc21660b5af7399ebaa9d0bbf5f77a0 Mon Sep 17 00:00:00 2001 From: Richard Hughes Date: Mon, 11 May 2020 19:42:47 +0100 Subject: [PATCH 044/607] Add support for the Host Security ID The HSI specification assigns a simple text ID to the current state of firmware security. As new vulnerabilities are found, and as protection measures are updated, new requirements will be added to the required firmware behaviours for each HSI value. The HSI specification is currently incomplete and in active development, and so the --force flag is required in all command line tools. The current ID value will probably change on a given platform so please do not start using the result for any kind of compliance requirements. --- data/bash-completion/fwupdagent | 1 + data/bash-completion/fwupdmgr.in | 1 + data/bash-completion/fwupdtool.in | 1 + libfwupd/fwupd-client.c | 96 ++++++++++++++++++++++++ libfwupd/fwupd-client.h | 4 + libfwupd/fwupd.map | 2 + libfwupdplugin/fu-plugin-private.h | 3 + libfwupdplugin/fu-plugin-vfuncs.h | 13 ++++ libfwupdplugin/fu-plugin.c | 20 +++++ libfwupdplugin/fwupdplugin.map | 1 + src/fu-agent.c | 80 ++++++++++++++++++++ src/fu-engine.c | 55 ++++++++++++++ src/fu-engine.h | 3 + src/fu-main.c | 32 ++++++++ src/fu-security-attrs.c | 115 +++++++++++++++++++++++++++++ src/fu-security-attrs.h | 12 +++ src/fu-self-test.c | 72 ++++++++++++++++++ src/fu-tool.c | 38 ++++++++++ src/fu-util-common.c | 69 +++++++++++++++++ src/fu-util-common.h | 1 + src/fu-util.c | 39 +++++++++- src/meson.build | 3 + src/org.freedesktop.fwupd.xml | 29 ++++++++ 23 files changed, 689 insertions(+), 1 deletion(-) create mode 100644 src/fu-security-attrs.c create mode 100644 src/fu-security-attrs.h diff --git a/data/bash-completion/fwupdagent b/data/bash-completion/fwupdagent index f4c3fd582..5234625da 100644 --- a/data/bash-completion/fwupdagent +++ b/data/bash-completion/fwupdagent @@ -2,6 +2,7 @@ _fwupdagent_cmd_list=( 'get-devices' 'get-updates' 'get-upgrades' + 'security' ) _fwupdagent_opts=( diff --git a/data/bash-completion/fwupdmgr.in b/data/bash-completion/fwupdmgr.in index 2fe070f9b..ccdd89c55 100644 --- a/data/bash-completion/fwupdmgr.in +++ b/data/bash-completion/fwupdmgr.in @@ -22,6 +22,7 @@ _fwupdmgr_cmd_list=( 'reinstall' 'refresh' 'report-history' + 'security' 'set-approved-firmware' 'unlock' 'update' diff --git a/data/bash-completion/fwupdtool.in b/data/bash-completion/fwupdtool.in index 2d2865802..4e9ce103e 100644 --- a/data/bash-completion/fwupdtool.in +++ b/data/bash-completion/fwupdtool.in @@ -20,6 +20,7 @@ _fwupdtool_cmd_list=( 'install-blob' 'monitor' 'reinstall' + 'security' 'self-sign' 'smbios-dump' 'attach' diff --git a/libfwupd/fwupd-client.c b/libfwupd/fwupd-client.c index 18729c027..bfa0403e0 100644 --- a/libfwupd/fwupd-client.c +++ b/libfwupd/fwupd-client.c @@ -23,6 +23,7 @@ #include "fwupd-enums.h" #include "fwupd-error.h" #include "fwupd-device-private.h" +#include "fwupd-security-attr-private.h" #include "fwupd-release-private.h" #include "fwupd-remote-private.h" @@ -45,6 +46,7 @@ typedef struct { gchar *daemon_version; gchar *host_product; gchar *host_machine_id; + gchar *host_security_id; GDBusConnection *conn; GDBusProxy *proxy; } FwupdClientPrivate; @@ -66,6 +68,7 @@ enum { PROP_TAINTED, PROP_HOST_PRODUCT, PROP_HOST_MACHINE_ID, + PROP_HOST_SECURITY_ID, PROP_INTERACTIVE, PROP_LAST }; @@ -128,6 +131,15 @@ fwupd_client_set_host_machine_id (FwupdClient *client, const gchar *host_machine g_object_notify (G_OBJECT (client), "host-machine-id"); } +static void +fwupd_client_set_host_security_id (FwupdClient *client, const gchar *host_security_id) +{ + FwupdClientPrivate *priv = GET_PRIVATE (client); + g_free (priv->host_security_id); + priv->host_security_id = g_strdup (host_security_id); + g_object_notify (G_OBJECT (client), "host-security-id"); +} + static void fwupd_client_set_daemon_version (FwupdClient *client, const gchar *daemon_version) { @@ -201,6 +213,12 @@ fwupd_client_properties_changed_cb (GDBusProxy *proxy, if (val != NULL) fwupd_client_set_host_machine_id (client, g_variant_get_string (val, NULL)); } + if (g_variant_dict_contains (dict, "HostSecurityId")) { + g_autoptr(GVariant) val = NULL; + val = g_dbus_proxy_get_cached_property (proxy, "HostSecurityId"); + if (val != NULL) + fwupd_client_set_host_security_id (client, g_variant_get_string (val, NULL)); + } } static void @@ -304,6 +322,9 @@ fwupd_client_connect (FwupdClient *client, GCancellable *cancellable, GError **e val = g_dbus_proxy_get_cached_property (priv->proxy, "HostMachineId"); if (val != NULL) fwupd_client_set_host_machine_id (client, g_variant_get_string (val, NULL)); + val = g_dbus_proxy_get_cached_property (priv->proxy, "HostSecurityId"); + if (val != NULL) + fwupd_client_set_host_security_id (client, g_variant_get_string (val, NULL)); return TRUE; } @@ -341,6 +362,48 @@ fwupd_client_fixup_dbus_error (GError *error) g_dbus_error_strip_remote_error (error); } +/** + * fwupd_client_get_host_security_attrs: + * @client: A #FwupdClient + * @cancellable: the #GCancellable, or %NULL + * @error: the #GError, or %NULL + * + * Gets all the host security attributes from the daemon. + * + * Returns: (element-type FwupdSecurityAttr) (transfer container): attributes + * + * Since: 1.5.0 + **/ +GPtrArray * +fwupd_client_get_host_security_attrs (FwupdClient *client, GCancellable *cancellable, GError **error) +{ + FwupdClientPrivate *priv = GET_PRIVATE (client); + g_autoptr(GVariant) val = NULL; + + g_return_val_if_fail (FWUPD_IS_CLIENT (client), NULL); + g_return_val_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable), NULL); + g_return_val_if_fail (error == NULL || *error == NULL, NULL); + + /* connect */ + if (!fwupd_client_connect (client, cancellable, error)) + return NULL; + + /* call into daemon */ + val = g_dbus_proxy_call_sync (priv->proxy, + "GetHostSecurityAttrs", + NULL, + G_DBUS_CALL_FLAGS_NONE, + -1, + cancellable, + error); + if (val == NULL) { + if (error != NULL) + fwupd_client_fixup_dbus_error (*error); + return NULL; + } + return fwupd_security_attr_array_from_variant (val); +} + /** * fwupd_client_get_devices: * @client: A #FwupdClient @@ -1314,6 +1377,24 @@ fwupd_client_get_host_machine_id (FwupdClient *client) return priv->host_machine_id; } +/** + * fwupd_client_get_host_security_id: + * @client: A #FwupdClient + * + * Gets the string that represents the host machine ID + * + * Returns: a string, or %NULL for unknown. + * + * Since: 1.5.0 + **/ +const gchar * +fwupd_client_get_host_security_id (FwupdClient *client) +{ + FwupdClientPrivate *priv = GET_PRIVATE (client); + g_return_val_if_fail (FWUPD_IS_CLIENT (client), NULL); + return priv->host_security_id; +} + /** * fwupd_client_get_status: * @client: A #FwupdClient @@ -1869,6 +1950,9 @@ fwupd_client_get_property (GObject *object, guint prop_id, case PROP_HOST_MACHINE_ID: g_value_set_string (value, priv->host_machine_id); break; + case PROP_HOST_SECURITY_ID: + g_value_set_string (value, priv->host_security_id); + break; case PROP_INTERACTIVE: g_value_set_boolean (value, priv->interactive); break; @@ -2069,6 +2153,17 @@ fwupd_client_class_init (FwupdClientClass *klass) pspec = g_param_spec_string ("host-machine-id", NULL, NULL, NULL, G_PARAM_READABLE | G_PARAM_STATIC_NAME); g_object_class_install_property (object_class, PROP_HOST_MACHINE_ID, pspec); + + /** + * FwupdClient:host-security-id: + * + * The host machine-id string + * + * Since: 1.5.0 + */ + pspec = g_param_spec_string ("host-security-id", NULL, NULL, + NULL, G_PARAM_READABLE | G_PARAM_STATIC_NAME); + g_object_class_install_property (object_class, PROP_HOST_SECURITY_ID, pspec); } static void @@ -2085,6 +2180,7 @@ fwupd_client_finalize (GObject *object) g_free (priv->daemon_version); g_free (priv->host_product); g_free (priv->host_machine_id); + g_free (priv->host_security_id); if (priv->conn != NULL) g_object_unref (priv->conn); if (priv->proxy != NULL) diff --git a/libfwupd/fwupd-client.h b/libfwupd/fwupd-client.h index 18b3b6336..077e22092 100644 --- a/libfwupd/fwupd-client.h +++ b/libfwupd/fwupd-client.h @@ -95,6 +95,9 @@ FwupdDevice *fwupd_client_get_results (FwupdClient *client, const gchar *device_id, GCancellable *cancellable, GError **error); +GPtrArray *fwupd_client_get_host_security_attrs (FwupdClient *client, + GCancellable *cancellable, + GError **error); FwupdDevice *fwupd_client_get_device_by_id (FwupdClient *client, const gchar *device_id, GCancellable *cancellable, @@ -134,6 +137,7 @@ guint fwupd_client_get_percentage (FwupdClient *client); const gchar *fwupd_client_get_daemon_version (FwupdClient *client); const gchar *fwupd_client_get_host_product (FwupdClient *client); const gchar *fwupd_client_get_host_machine_id (FwupdClient *client); +const gchar *fwupd_client_get_host_security_id (FwupdClient *client); GPtrArray *fwupd_client_get_remotes (FwupdClient *client, GCancellable *cancellable, diff --git a/libfwupd/fwupd.map b/libfwupd/fwupd.map index 94266d11e..4fb789aee 100644 --- a/libfwupd/fwupd.map +++ b/libfwupd/fwupd.map @@ -449,6 +449,8 @@ LIBFWUPD_1.4.1 { LIBFWUPD_1.5.0 { global: + fwupd_client_get_host_security_attrs; + fwupd_client_get_host_security_id; fwupd_security_attr_add_flag; fwupd_security_attr_add_obsolete; fwupd_security_attr_array_from_variant; diff --git a/libfwupdplugin/fu-plugin-private.h b/libfwupdplugin/fu-plugin-private.h index 0544c0f92..a5e51cd59 100644 --- a/libfwupdplugin/fu-plugin-private.h +++ b/libfwupdplugin/fu-plugin-private.h @@ -116,6 +116,9 @@ gboolean fu_plugin_runner_clear_results (FuPlugin *self, gboolean fu_plugin_runner_get_results (FuPlugin *self, FuDevice *device, GError **error); +gboolean fu_plugin_runner_add_security_attrs (FuPlugin *self, + GPtrArray *attrs, + GError **error); gint fu_plugin_name_compare (FuPlugin *plugin1, FuPlugin *plugin2); gint fu_plugin_order_compare (FuPlugin *plugin1, diff --git a/libfwupdplugin/fu-plugin-vfuncs.h b/libfwupdplugin/fu-plugin-vfuncs.h index 0858d8b01..287cf2e44 100644 --- a/libfwupdplugin/fu-plugin-vfuncs.h +++ b/libfwupdplugin/fu-plugin-vfuncs.h @@ -359,3 +359,16 @@ gboolean fu_plugin_device_created (FuPlugin *plugin, **/ void fu_plugin_device_registered (FuPlugin *plugin, FuDevice *dev); +/** + * fu_plugin_add_security_attrs + * @plugin: A #FuPlugin + * @attrs: A #GPtrArray of #FwupdSecurityAttr + * @error: A #GError or NULL + * + * Function that asks plugins to add Host Security Attributes. + * + * Since: 1.5.0 + **/ +gboolean fu_plugin_add_security_attrs (FuPlugin *plugin, + GPtrArray *attrs, + GError **error); diff --git a/libfwupdplugin/fu-plugin.c b/libfwupdplugin/fu-plugin.c index 810e8243d..29dc02c0a 100644 --- a/libfwupdplugin/fu-plugin.c +++ b/libfwupdplugin/fu-plugin.c @@ -1579,6 +1579,26 @@ fu_plugin_runner_update_reload (FuPlugin *self, FuDevice *device, GError **error return fu_device_reload (device, error); } +/** + * fu_plugin_runner_add_security_attrs: + * @self: a #FuPlugin + * @attrs: (element-type FwupdSecurityAttr): a #GPtrArray of attributes + * @error: a #GError or NULL + * + * Runs the composite_prepare routine for the plugin + * + * Returns: #TRUE for success, #FALSE for failure + * + * Since: 1.5.0 + **/ +gboolean +fu_plugin_runner_add_security_attrs (FuPlugin *self, GPtrArray *attrs, GError **error) +{ + return fu_plugin_runner_device_array_generic (self, attrs, + "fu_plugin_add_security_attrs", + error); +} + /** * fu_plugin_add_udev_subsystem: * @self: a #FuPlugin diff --git a/libfwupdplugin/fwupdplugin.map b/libfwupdplugin/fwupdplugin.map index e1962298c..7401131c8 100644 --- a/libfwupdplugin/fwupdplugin.map +++ b/libfwupdplugin/fwupdplugin.map @@ -585,6 +585,7 @@ LIBFWUPDPLUGIN_1.5.0 { global: fu_common_filename_glob; fu_common_is_cpu_intel; + fu_plugin_runner_add_security_attrs; fu_plugin_runner_device_added; fu_udev_device_get_parent_name; fu_udev_device_get_sysfs_attr; diff --git a/src/fu-agent.c b/src/fu-agent.c index 634831cc8..9329ec81b 100644 --- a/src/fu-agent.c +++ b/src/fu-agent.c @@ -21,6 +21,7 @@ #include "fu-util-common.h" #include "fwupd-device-private.h" #include "fwupd-enums-private.h" +#include "fwupd-security-attr-private.h" struct FuUtilPrivate { GCancellable *cancellable; @@ -113,6 +114,37 @@ fu_util_add_updates_json (FuUtilPrivate *priv, JsonBuilder *builder, GError **er return TRUE; } +static gboolean +fu_util_add_security_attributes_json (FuUtilPrivate *priv, JsonBuilder *builder, GError **error) +{ + g_autoptr(GPtrArray) attrs = NULL; + + /* not ready yet */ + if ((priv->flags & FWUPD_INSTALL_FLAG_FORCE) == 0) { + g_set_error_literal (error, + FWUPD_ERROR, + FWUPD_ERROR_NOT_SUPPORTED, + "The HSI specification is not yet complete. " + "To ignore this warning, use --force"); + return FALSE; + } + + /* get attrs from daemon */ + attrs = fwupd_client_get_host_security_attrs (priv->client, NULL, error); + if (attrs == NULL) + return FALSE; + json_builder_set_member_name (builder, "HostSecurityAttributes"); + json_builder_begin_array (builder); + for (guint i = 0; i < attrs->len; i++) { + FwupdSecurityAttr *attr = g_ptr_array_index (attrs, i); + json_builder_begin_object (builder); + fwupd_security_attr_to_json (attr, builder); + json_builder_end_object (builder); + } + json_builder_end_array (builder); + return TRUE; +} + static gboolean fu_util_get_devices (FuUtilPrivate *priv, gchar **values, GError **error) { @@ -199,6 +231,49 @@ fu_util_get_updates (FuUtilPrivate *priv, gchar **values, GError **error) return TRUE; } +static gboolean +fu_util_security (FuUtilPrivate *priv, gchar **values, GError **error) +{ + g_autofree gchar *data = NULL; + g_autoptr(JsonBuilder) builder = NULL; + g_autoptr(JsonGenerator) json_generator = NULL; + g_autoptr(JsonNode) json_root = NULL; + + /* check args */ + if (g_strv_length (values) != 0) { + g_set_error_literal (error, + FWUPD_ERROR, + FWUPD_ERROR_INVALID_ARGS, + "Invalid arguments"); + return FALSE; + } + + /* create header */ + builder = json_builder_new (); + json_builder_begin_object (builder); + if (!fu_util_add_security_attributes_json (priv, builder, error)) + return FALSE; + json_builder_end_object (builder); + + /* export as a string */ + json_root = json_builder_get_root (builder); + json_generator = json_generator_new (); + json_generator_set_pretty (json_generator, TRUE); + json_generator_set_root (json_generator, json_root); + data = json_generator_to_data (json_generator, NULL); + if (data == NULL) { + g_set_error_literal (error, + FWUPD_ERROR, + FWUPD_ERROR_INTERNAL, + "Failed to convert to JSON string"); + return FALSE; + } + + /* just print */ + g_print ("%s\n", data); + return TRUE; +} + static void fu_util_ignore_cb (const gchar *log_domain, GLogLevelFlags log_level, const gchar *message, gpointer user_data) @@ -280,6 +355,11 @@ main (int argc, char *argv[]) /* TRANSLATORS: command description */ _("Gets the list of updates for connected hardware"), fu_util_get_updates); + fu_util_cmd_array_add (cmd_array, + "security", NULL, + /* TRANSLATORS: command description */ + _("Gets the host security attributes"), + fu_util_security); /* sort by command name */ fu_util_cmd_array_sort (cmd_array); diff --git a/src/fu-engine.c b/src/fu-engine.c index c5f9dd073..c33935a47 100644 --- a/src/fu-engine.c +++ b/src/fu-engine.c @@ -49,6 +49,7 @@ #include "fu-plugin-private.h" #include "fu-quirks.h" #include "fu-remote-list.h" +#include "fu-security-attrs.h" #include "fu-smbios-private.h" #include "fu-udev-device-private.h" #include "fu-usb-device-private.h" @@ -99,6 +100,8 @@ struct _FuEngine gchar *host_machine_id; JcatContext *jcat_context; gboolean loaded; + gchar *host_security_id; + gboolean host_security_id_valid; }; enum { @@ -133,6 +136,7 @@ fu_engine_emit_changed (FuEngine *self) static void fu_engine_emit_device_changed (FuEngine *self, FuDevice *device) { + self->host_security_id_valid = FALSE; g_signal_emit (self, signals[SIGNAL_DEVICE_CHANGED], 0, device); } @@ -5026,6 +5030,56 @@ fu_engine_get_host_machine_id (FuEngine *self) return self->host_machine_id; } +GPtrArray * +fu_engine_get_host_security_attrs (FuEngine *self, GError **error) +{ + GPtrArray *plugins = fu_plugin_list_get_all (self->plugin_list); + g_autoptr(GPtrArray) attrs = NULL; + + attrs = g_ptr_array_new_with_free_func ((GDestroyNotify) g_object_unref); + for (guint j = 0; j < plugins->len; j++) { + FuPlugin *plugin_tmp = g_ptr_array_index (plugins, j); + g_autoptr(GError) error_local = NULL; + if (!fu_plugin_runner_add_security_attrs (plugin_tmp, + attrs, + &error_local)) { + FwupdSecurityAttr *attr; + g_autofree gchar *appstream_id = NULL; + g_autofree gchar *msg = NULL; + appstream_id = g_strdup_printf ("org.fwupd.plugin.%s", + fu_plugin_get_name (plugin_tmp)); + msg = g_strdup_printf ("Failed to add HSI attribute: %s", + error_local->message); + attr = fwupd_security_attr_new (appstream_id); + fwupd_security_attr_set_name (attr, "fwupd"); + fwupd_security_attr_add_flag (attr, FWUPD_SECURITY_ATTR_FLAG_RUNTIME_ISSUE); + fwupd_security_attr_set_result (attr, msg); + g_ptr_array_add (attrs, attr); + continue; + } + } + + /* set the obsoletes flag for each attr */ + fu_security_attrs_depsolve (attrs); + return g_steal_pointer (&attrs); +} + +const gchar * +fu_engine_get_host_security_id (FuEngine *self) +{ + g_return_val_if_fail (FU_IS_ENGINE (self), NULL); + + /* rebuild */ + if (!self->host_security_id_valid) { + g_autoptr(GPtrArray) attrs = fu_engine_get_host_security_attrs (self, NULL); + g_free (self->host_security_id); + self->host_security_id = fu_security_attrs_calculate_hsi (attrs); + self->host_security_id_valid = TRUE; + } + + return self->host_security_id; +} + gboolean fu_engine_load_plugins (FuEngine *self, GError **error) { @@ -5745,6 +5799,7 @@ fu_engine_finalize (GObject *obj) g_source_remove (self->coldplug_id); g_free (self->host_machine_id); + g_free (self->host_security_id); g_object_unref (self->idle); g_object_unref (self->config); g_object_unref (self->remote_list); diff --git a/src/fu-engine.h b/src/fu-engine.h index 1829ee18c..028d778d2 100644 --- a/src/fu-engine.h +++ b/src/fu-engine.h @@ -49,6 +49,7 @@ gboolean fu_engine_load_plugins (FuEngine *self, gboolean fu_engine_get_tainted (FuEngine *self); const gchar *fu_engine_get_host_product (FuEngine *self); const gchar *fu_engine_get_host_machine_id (FuEngine *self); +const gchar *fu_engine_get_host_security_id (FuEngine *self); FwupdStatus fu_engine_get_status (FuEngine *self); XbSilo *fu_engine_get_silo_from_blob (FuEngine *self, GBytes *blob_cab, @@ -82,6 +83,8 @@ GPtrArray *fu_engine_get_upgrades (FuEngine *self, FwupdDevice *fu_engine_get_results (FuEngine *self, const gchar *device_id, GError **error); +GPtrArray *fu_engine_get_host_security_attrs (FuEngine *self, + GError **error); gboolean fu_engine_clear_results (FuEngine *self, const gchar *device_id, GError **error); diff --git a/src/fu-main.c b/src/fu-main.c index 8ff196e4c..c8d2b055d 100644 --- a/src/fu-main.c +++ b/src/fu-main.c @@ -20,6 +20,7 @@ #include #include "fwupd-device-private.h" +#include "fwupd-security-attr-private.h" #include "fwupd-release-private.h" #include "fwupd-remote-private.h" #include "fwupd-resources.h" @@ -254,6 +255,22 @@ fu_main_device_array_to_variant (FuMainPrivate *priv, const gchar *sender, return g_variant_new ("(aa{sv})", &builder); } +static GVariant * +fu_main_security_attr_array_to_variant (FuMainPrivate *priv, GPtrArray *attrs) +{ + GVariantBuilder builder; + + g_return_val_if_fail (attrs->len > 0, NULL); + g_variant_builder_init (&builder, G_VARIANT_TYPE_ARRAY); + + for (guint i = 0; i < attrs->len; i++) { + FwupdSecurityAttr *security_attr = g_ptr_array_index (attrs, i); + GVariant *tmp = fwupd_security_attr_to_variant (security_attr); + g_variant_builder_add_value (&builder, tmp); + } + return g_variant_new ("(aa{sv})", &builder); +} + static GVariant * fu_main_release_array_to_variant (GPtrArray *results) { @@ -987,6 +1004,18 @@ fu_main_daemon_method_call (GDBusConnection *connection, const gchar *sender, g_dbus_method_invocation_return_value (invocation, val); return; } + if (g_strcmp0 (method_name, "GetHostSecurityAttrs") == 0) { + g_autoptr(GPtrArray) attrs = NULL; + g_debug ("Called %s()", method_name); + attrs = fu_engine_get_host_security_attrs (priv->engine, &error); + if (attrs == NULL) { + g_dbus_method_invocation_return_gerror (invocation, error); + return; + } + val = fu_main_security_attr_array_to_variant (priv, attrs); + g_dbus_method_invocation_return_value (invocation, val); + return; + } if (g_strcmp0 (method_name, "ClearResults") == 0) { const gchar *device_id; g_variant_get (parameters, "(&s)", &device_id); @@ -1388,6 +1417,9 @@ fu_main_daemon_get_property (GDBusConnection *connection_, const gchar *sender, if (g_strcmp0 (property_name, "HostMachineId") == 0) return g_variant_new_string (fu_engine_get_host_machine_id (priv->engine)); + if (g_strcmp0 (property_name, "HostSecurityId") == 0) + return g_variant_new_string (fu_engine_get_host_security_id (priv->engine)); + if (g_strcmp0 (property_name, "Interactive") == 0) return g_variant_new_boolean (isatty (fileno (stdout)) != 0); diff --git a/src/fu-security-attrs.c b/src/fu-security-attrs.c new file mode 100644 index 000000000..ff862f8cd --- /dev/null +++ b/src/fu-security-attrs.c @@ -0,0 +1,115 @@ +/* + * Copyright (C) 2020 Richard Hughes + * + * SPDX-License-Identifier: LGPL-2.1+ + */ + +#include "config.h" + +#include + +#include "fwupd-security-attr.h" + +#include "fu-security-attrs.h" + +gchar * +fu_security_attrs_calculate_hsi (GPtrArray *attrs) +{ + guint hsi_number = 0; + FwupdSecurityAttrFlags flags = FWUPD_SECURITY_ATTR_FLAG_NONE; + GString *str = g_string_new ("HSI:"); + const FwupdSecurityAttrFlags hpi_suffixes[] = { + FWUPD_SECURITY_ATTR_FLAG_RUNTIME_UPDATES, + FWUPD_SECURITY_ATTR_FLAG_RUNTIME_ATTESTATION, + FWUPD_SECURITY_ATTR_FLAG_RUNTIME_ISSUE, + FWUPD_SECURITY_ATTR_FLAG_NONE, + }; + + /* find the highest HSI number where there are no failures and at least + * one success */ + for (guint j = 1; j <= FWUPD_SECURITY_ATTR_LEVEL_LAST; j++) { + gboolean success_cnt = 0; + gboolean failure_cnt = 0; + for (guint i = 0; i < attrs->len; i++) { + FwupdSecurityAttr *attr = g_ptr_array_index (attrs, i); + if (fwupd_security_attr_get_level (attr) != j) + continue; + if (fwupd_security_attr_has_flag (attr, FWUPD_SECURITY_ATTR_FLAG_SUCCESS)) + success_cnt++; + else if (!fwupd_security_attr_has_flag (attr, FWUPD_SECURITY_ATTR_FLAG_OBSOLETED)) + failure_cnt++; + } + + /* abort */ + if (failure_cnt > 0) { + hsi_number = j - 1; + break; + } + + /* we matched at least one thing on this level */ + if (success_cnt > 0) + hsi_number = j; + } + + /* get a logical OR of the runtime flags */ + for (guint i = 0; i < attrs->len; i++) { + FwupdSecurityAttr *attr = g_ptr_array_index (attrs, i); + if (fwupd_security_attr_has_flag (attr, FWUPD_SECURITY_ATTR_FLAG_OBSOLETED)) + continue; + /* positive things */ + if (fwupd_security_attr_has_flag (attr, FWUPD_SECURITY_ATTR_FLAG_RUNTIME_UPDATES) || + fwupd_security_attr_has_flag (attr, FWUPD_SECURITY_ATTR_FLAG_RUNTIME_ATTESTATION)) { + if (!fwupd_security_attr_has_flag (attr, FWUPD_SECURITY_ATTR_FLAG_SUCCESS)) + continue; + } + /* negative things */ + if (fwupd_security_attr_has_flag (attr, FWUPD_SECURITY_ATTR_FLAG_RUNTIME_ISSUE)) { + if (fwupd_security_attr_has_flag (attr, FWUPD_SECURITY_ATTR_FLAG_SUCCESS)) + continue; + } + flags |= fwupd_security_attr_get_flags (attr); + } + + g_string_append_printf (str, "%u", hsi_number); + if (flags & (FWUPD_SECURITY_ATTR_FLAG_RUNTIME_UPDATES | + FWUPD_SECURITY_ATTR_FLAG_RUNTIME_ATTESTATION | + FWUPD_SECURITY_ATTR_FLAG_RUNTIME_ISSUE)) { + g_string_append (str, "+"); + for (guint j = 0; hpi_suffixes[j] != FWUPD_SECURITY_ATTR_FLAG_NONE; j++) { + if (flags & hpi_suffixes[j]) + g_string_append (str, fwupd_security_attr_flag_to_suffix (hpi_suffixes[j])); + } + } + return g_string_free (str, FALSE); +} + +void +fu_security_attrs_depsolve (GPtrArray *attrs) +{ + g_autoptr(GHashTable) attrs_by_id = NULL; + + /* make hash of ID -> object */ + attrs_by_id = g_hash_table_new (g_str_hash, g_str_equal); + for (guint i = 0; i < attrs->len; i++) { + FwupdSecurityAttr *attr = g_ptr_array_index (attrs, i); + g_hash_table_insert (attrs_by_id, + (gpointer) fwupd_security_attr_get_appstream_id (attr), + (gpointer) attr); + } + + /* set flat where required */ + for (guint i = 0; i < attrs->len; i++) { + FwupdSecurityAttr *attr = g_ptr_array_index (attrs, i); + GPtrArray *obsoletes = fwupd_security_attr_get_obsoletes (attr); + for (guint j = 0; j < obsoletes->len; j++) { + const gchar *obsolete = g_ptr_array_index (obsoletes, j); + FwupdSecurityAttr *attr_tmp = g_hash_table_lookup (attrs_by_id, obsolete); + if (attr_tmp != NULL) { + g_debug ("security attr %s obsoleted by %s", obsolete, + fwupd_security_attr_get_appstream_id (attr)); + fwupd_security_attr_add_flag (attr_tmp, + FWUPD_SECURITY_ATTR_FLAG_OBSOLETED); + } + } + } +} diff --git a/src/fu-security-attrs.h b/src/fu-security-attrs.h new file mode 100644 index 000000000..a0ab3ec18 --- /dev/null +++ b/src/fu-security-attrs.h @@ -0,0 +1,12 @@ +/* + * Copyright (C) 2020 Richard Hughes + * + * SPDX-License-Identifier: LGPL-2.1+ + */ + +#pragma once + +#include + +gchar *fu_security_attrs_calculate_hsi (GPtrArray *attrs); +void fu_security_attrs_depsolve (GPtrArray *attrs); diff --git a/src/fu-self-test.c b/src/fu-self-test.c index f3cbe26ac..29c104de7 100644 --- a/src/fu-self-test.c +++ b/src/fu-self-test.c @@ -25,6 +25,7 @@ #include "fu-plugin-list.h" #include "fu-progressbar.h" #include "fu-hash.h" +#include "fu-security-attrs.h" #include "fu-smbios-private.h" typedef struct { @@ -151,6 +152,75 @@ fu_engine_generate_md_func (gconstpointer user_data) g_assert_cmpstr (tmp, ==, NULL); } +static void +fu_plugin_hsi_func (gconstpointer user_data) +{ + FwupdSecurityAttr *attr; + g_autofree gchar *hsi1 = NULL; + g_autofree gchar *hsi2 = NULL; + g_autofree gchar *hsi3 = NULL; + g_autofree gchar *hsi4 = NULL; + g_autofree gchar *hsi5 = NULL; + g_autofree gchar *hsi6 = NULL; + g_autofree gchar *hsi7 = NULL; + g_autoptr(FuEngine) engine = fu_engine_new (FU_APP_FLAGS_NONE); + g_autoptr(GPtrArray) attrs = NULL; + + /* no attrs */ + attrs = g_ptr_array_new_with_free_func ((GDestroyNotify) g_object_unref); + hsi1 = fu_security_attrs_calculate_hsi (attrs); + g_assert_cmpstr (hsi1, ==, "HSI:0"); + + /* just success from HSI:1 */ + attr = fwupd_security_attr_new ("org.fwupd.Hsi.BIOSWE"); + fwupd_security_attr_set_level (attr, 1); + fwupd_security_attr_add_flag (attr, FWUPD_SECURITY_ATTR_FLAG_SUCCESS); + g_ptr_array_add (attrs, attr); + hsi2 = fu_security_attrs_calculate_hsi (attrs); + g_assert_cmpstr (hsi2, ==, "HSI:1"); + + /* add failed from HSI:2, so still HSI:1 */ + attr = fwupd_security_attr_new ("org.fwupd.Hsi.PRX"); + fwupd_security_attr_set_level (attr, 2); + g_ptr_array_add (attrs, attr); + hsi3 = fu_security_attrs_calculate_hsi (attrs); + g_assert_cmpstr (hsi3, ==, "HSI:1"); + + /* add attr from HSI:3, obsoleting the failure */ + attr = fwupd_security_attr_new ("org.fwupd.Hsi.BIOSGuard"); + fwupd_security_attr_set_level (attr, 3); + fwupd_security_attr_add_flag (attr, FWUPD_SECURITY_ATTR_FLAG_SUCCESS); + fwupd_security_attr_add_obsolete (attr, "org.fwupd.Hsi.PRX"); + g_ptr_array_add (attrs, attr); + fu_security_attrs_depsolve (attrs); + hsi4 = fu_security_attrs_calculate_hsi (attrs); + g_assert_cmpstr (hsi4, ==, "HSI:3"); + + /* add taint that was fine */ + attr = fwupd_security_attr_new ("org.fwupd.Hsi.PluginsTainted"); + fwupd_security_attr_add_flag (attr, FWUPD_SECURITY_ATTR_FLAG_SUCCESS); + fwupd_security_attr_add_flag (attr, FWUPD_SECURITY_ATTR_FLAG_RUNTIME_ISSUE); + g_ptr_array_add (attrs, attr); + hsi5 = fu_security_attrs_calculate_hsi (attrs); + g_assert_cmpstr (hsi5, ==, "HSI:3"); + + /* add updates and attestation */ + attr = fwupd_security_attr_new ("org.fwupd.Hsi.LVFS"); + fwupd_security_attr_add_flag (attr, FWUPD_SECURITY_ATTR_FLAG_RUNTIME_UPDATES); + fwupd_security_attr_add_flag (attr, FWUPD_SECURITY_ATTR_FLAG_RUNTIME_ATTESTATION); + fwupd_security_attr_add_flag (attr, FWUPD_SECURITY_ATTR_FLAG_SUCCESS); + g_ptr_array_add (attrs, attr); + hsi6 = fu_security_attrs_calculate_hsi (attrs); + g_assert_cmpstr (hsi6, ==, "HSI:3+UA"); + + /* add issue that was uncool */ + attr = fwupd_security_attr_new ("org.fwupd.Hsi.Swap"); + fwupd_security_attr_add_flag (attr, FWUPD_SECURITY_ATTR_FLAG_RUNTIME_ISSUE); + g_ptr_array_add (attrs, attr); + hsi7 = fu_security_attrs_calculate_hsi (attrs); + g_assert_cmpstr (hsi7, ==, "HSI:3+UA!"); +} + static void fu_plugin_hash_func (gconstpointer user_data) { @@ -2980,6 +3050,8 @@ main (int argc, char **argv) g_test_add_data_func ("/fwupd/progressbar", self, fu_progressbar_func); } + g_test_add_data_func ("/fwupd/plugin{hsi}", self, + fu_plugin_hsi_func); g_test_add_data_func ("/fwupd/plugin{build-hash}", self, fu_plugin_hash_func); g_test_add_data_func ("/fwupd/plugin{module}", self, diff --git a/src/fu-tool.c b/src/fu-tool.c index 268c8d5c5..52ed222f0 100644 --- a/src/fu-tool.c +++ b/src/fu-tool.c @@ -1937,6 +1937,38 @@ fu_util_get_remotes (FuUtilPrivate *priv, gchar **values, GError **error) return TRUE; } +static gboolean +fu_util_security (FuUtilPrivate *priv, gchar **values, GError **error) +{ + g_autoptr(GPtrArray) attrs = NULL; + g_autofree gchar *str = NULL; + + /* not ready yet */ + if ((priv->flags & FWUPD_INSTALL_FLAG_FORCE) == 0) { + g_set_error_literal (error, + FWUPD_ERROR, + FWUPD_ERROR_NOT_SUPPORTED, + "The HSI specification is not yet complete. " + "To ignore this warning, use --force"); + return FALSE; + } + + if (!fu_util_start_engine (priv, FU_ENGINE_LOAD_FLAG_NONE, error)) + return FALSE; + + /* TRANSLATORS: this is a string like 'HSI:2-U' */ + g_print ("%s \033[1m%s\033[0m\n", _("Host Security ID:"), + fu_engine_get_host_security_id (priv->engine)); + + /* print the "why" */ + attrs = fu_engine_get_host_security_attrs (priv->engine, error); + if (attrs == NULL) + return FALSE; + str = fu_util_security_attrs_to_string (attrs); + g_print ("%s\n", str); + return TRUE; +} + int main (int argc, char *argv[]) { @@ -2176,6 +2208,12 @@ main (int argc, char *argv[]) /* TRANSLATORS: command description */ _("Refresh metadata from remote server"), fu_util_refresh); + fu_util_cmd_array_add (cmd_array, + "security", + NULL, + /* TRANSLATORS: command description */ + _("Gets the host security attributes."), + fu_util_security); /* do stuff on ctrl+c */ priv->cancellable = g_cancellable_new (); diff --git a/src/fu-util-common.c b/src/fu-util-common.c index abb282687..1eb128cea 100644 --- a/src/fu-util-common.c +++ b/src/fu-util-common.c @@ -16,6 +16,7 @@ #include "fu-common.h" #include "fu-util-common.h" #include "fu-device.h" +#include "fu-security-attrs.h" #ifdef HAVE_SYSTEMD #include "fu-systemd.h" @@ -1547,3 +1548,71 @@ fu_util_remote_to_string (FwupdRemote *remote, guint idt) return g_string_free (str, FALSE); } + +static void +fu_security_attr_append_str (FwupdSecurityAttr *attr, GString *str) +{ + if (fwupd_security_attr_has_flag (attr, FWUPD_SECURITY_ATTR_FLAG_SUCCESS)) { + g_string_append_printf (str, "\033[32m✔\033[0m "); + } else { + g_string_append_printf (str, "\033[31m✘\033[0m "); + } + g_string_append_printf (str, "%s", fwupd_security_attr_get_name (attr)); + if (fwupd_security_attr_get_result (attr) != NULL) { + g_string_append_printf (str, ": %s", + fwupd_security_attr_get_result (attr)); + } else { + g_string_append_printf (str, ": %s", + fwupd_security_attr_has_flag (attr, FWUPD_SECURITY_ATTR_FLAG_SUCCESS) + ? "OK" : "Failed"); + } + if (fwupd_security_attr_has_flag (attr, FWUPD_SECURITY_ATTR_FLAG_OBSOLETED)) + g_string_append (str, " (obsoleted)"); + g_string_append_printf (str, "\n"); +} + +gchar * +fu_util_security_attrs_to_string (GPtrArray *attrs) +{ + FwupdSecurityAttrFlags flags = FWUPD_SECURITY_ATTR_FLAG_NONE; + const FwupdSecurityAttrFlags hpi_suffixes[] = { + FWUPD_SECURITY_ATTR_FLAG_RUNTIME_UPDATES, + FWUPD_SECURITY_ATTR_FLAG_RUNTIME_ATTESTATION, + FWUPD_SECURITY_ATTR_FLAG_RUNTIME_ISSUE, + FWUPD_SECURITY_ATTR_FLAG_NONE, + }; + GString *str = g_string_new (NULL); + + for (guint j = 1; j <= FWUPD_SECURITY_ATTR_LEVEL_LAST; j++) { + gboolean has_header = FALSE; + for (guint i = 0; i < attrs->len; i++) { + FwupdSecurityAttr *attr = g_ptr_array_index (attrs, i); + if (fwupd_security_attr_get_level (attr) != j) + continue; + if (!has_header) { + g_string_append_printf (str, "\n\033[1mHSI-%u\033[0m\n", j); + has_header = TRUE; + } + fu_security_attr_append_str (attr, str); + } + } + for (guint i = 0; i < attrs->len; i++) { + FwupdSecurityAttr *attr = g_ptr_array_index (attrs, i); + flags |= fwupd_security_attr_get_flags (attr); + } + for (guint j = 0; hpi_suffixes[j] != FWUPD_SECURITY_ATTR_FLAG_NONE; j++) { + if (flags & hpi_suffixes[j]) { + g_string_append_printf (str, "\n\033[1m%s -%s\033[0m\n", + /* TRANSLATORS: this is the HSI suffix */ + _("Runtime Suffix"), + fwupd_security_attr_flag_to_suffix (hpi_suffixes[j])); + for (guint i = 0; i < attrs->len; i++) { + FwupdSecurityAttr *attr = g_ptr_array_index (attrs, i); + if (!fwupd_security_attr_has_flag (attr, hpi_suffixes[j])) + continue; + fu_security_attr_append_str (attr, str); + } + } + } + return g_string_free (str, FALSE); +} diff --git a/src/fu-util-common.h b/src/fu-util-common.h index 9013d159d..77ca43133 100644 --- a/src/fu-util-common.h +++ b/src/fu-util-common.h @@ -77,3 +77,4 @@ gchar *fu_util_release_to_string (FwupdRelease *rel, guint idt); gchar *fu_util_remote_to_string (FwupdRemote *remote, guint idt); +gchar *fu_util_security_attrs_to_string (GPtrArray *attrs); diff --git a/src/fu-util.c b/src/fu-util.c index da8d961ed..aa2bbde0f 100644 --- a/src/fu-util.c +++ b/src/fu-util.c @@ -26,6 +26,7 @@ #include "fu-history.h" #include "fu-plugin-private.h" #include "fu-progressbar.h" +#include "fu-security-attrs.h" #include "fu-util-common.h" #include "fwupd-common-private.h" @@ -2364,6 +2365,37 @@ fu_util_modify_config (FuUtilPrivate *priv, gchar **values, GError **error) return TRUE; } +static gboolean +fu_util_security (FuUtilPrivate *priv, gchar **values, GError **error) +{ + g_autoptr(GPtrArray) attrs = NULL; + g_autofree gchar *str = NULL; + + /* not ready yet */ + if ((priv->flags & FWUPD_INSTALL_FLAG_FORCE) == 0) { + g_set_error_literal (error, + FWUPD_ERROR, + FWUPD_ERROR_NOT_SUPPORTED, + "The HSI specification is not yet complete. " + "To ignore this warning, use --force"); + return FALSE; + } + + /* TRANSLATORS: this is a string like 'HSI:2-U' */ + g_print ("%s \033[1m%s\033[0m\n", _("Host Security ID:"), + fwupd_client_get_host_security_id (priv->client)); + + /* print the "why" */ + attrs = fwupd_client_get_host_security_attrs (priv->client, + priv->cancellable, + error); + if (attrs == NULL) + return FALSE; + str = fu_util_security_attrs_to_string (attrs); + g_print ("%s\n", str); + return TRUE; +} + static void fu_util_ignore_cb (const gchar *log_domain, GLogLevelFlags log_level, const gchar *message, gpointer user_data) @@ -2678,7 +2710,12 @@ main (int argc, char *argv[]) /* TRANSLATORS: command description */ _("Reinstall current firmware on the device."), fu_util_reinstall); - + fu_util_cmd_array_add (cmd_array, + "security", + NULL, + /* TRANSLATORS: command description */ + _("Gets the host security attributes."), + fu_util_security); /* do stuff on ctrl+c */ priv->cancellable = g_cancellable_new (); diff --git a/src/meson.build b/src/meson.build index aae719fef..95bdc5967 100644 --- a/src/meson.build +++ b/src/meson.build @@ -131,6 +131,7 @@ fwupdtool = executable( 'fu-plugin-list.c', 'fu-progressbar.c', 'fu-remote-list.c', + 'fu-security-attrs.c', 'fu-util-common.c', systemd_src ], @@ -229,6 +230,7 @@ executable( 'fu-main.c', 'fu-plugin-list.c', 'fu-remote-list.c', + 'fu-security-attrs.c', systemd_src ], include_directories : [ @@ -285,6 +287,7 @@ if get_option('tests') 'fu-plugin-list.c', 'fu-progressbar.c', 'fu-remote-list.c', + 'fu-security-attrs.c', 'fu-self-test.c', systemd_src ], diff --git a/src/org.freedesktop.fwupd.xml b/src/org.freedesktop.fwupd.xml index 23cef8704..ea33f626f 100644 --- a/src/org.freedesktop.fwupd.xml +++ b/src/org.freedesktop.fwupd.xml @@ -44,6 +44,17 @@ + + + + + + The Host Security ID, for instance HSI:2UA + + + + + @@ -242,6 +253,24 @@ + + + + + + Gets a list of all the Host Security ID attributes. + + + + + + + An array of HSI attributes, with any properties set on each. + + + + + From 399859e48bfe3072a9d4e0b19f93ecdfdc9b1a52 Mon Sep 17 00:00:00 2001 From: Richard Hughes Date: Mon, 11 May 2020 19:44:03 +0100 Subject: [PATCH 045/607] trivial: Allow plugins to signal that the security status has changed --- libfwupdplugin/fu-plugin.c | 22 ++++++++++++++++++++++ libfwupdplugin/fu-plugin.h | 4 +++- libfwupdplugin/fwupdplugin.map | 1 + src/fu-engine.c | 10 ++++++++++ 4 files changed, 36 insertions(+), 1 deletion(-) diff --git a/libfwupdplugin/fu-plugin.c b/libfwupdplugin/fu-plugin.c index 29dc02c0a..951b037fc 100644 --- a/libfwupdplugin/fu-plugin.c +++ b/libfwupdplugin/fu-plugin.c @@ -65,6 +65,7 @@ enum { SIGNAL_SET_COLDPLUG_DELAY, SIGNAL_CHECK_SUPPORTED, SIGNAL_ADD_FIRMWARE_GTYPE, + SIGNAL_SECURITY_CHANGED, SIGNAL_LAST }; @@ -555,6 +556,21 @@ fu_plugin_request_recoldplug (FuPlugin *self) g_signal_emit (self, signals[SIGNAL_RECOLDPLUG], 0); } +/** + * fu_plugin_security_changed: + * @self: A #FuPlugin + * + * Informs the daemon that the HSI state may have changed. + * + * Since: 1.5.0 + **/ +void +fu_plugin_security_changed (FuPlugin *self) +{ + g_return_if_fail (FU_IS_PLUGIN (self)); + g_signal_emit (self, signals[SIGNAL_SECURITY_CHANGED], 0); +} + /** * fu_plugin_check_hwid: * @self: A #FuPlugin @@ -2679,6 +2695,12 @@ fu_plugin_class_init (FuPluginClass *klass) G_STRUCT_OFFSET (FuPluginClass, recoldplug), NULL, NULL, g_cclosure_marshal_VOID__VOID, G_TYPE_NONE, 0); + signals[SIGNAL_SECURITY_CHANGED] = + g_signal_new ("security-changed", + G_TYPE_FROM_CLASS (object_class), G_SIGNAL_RUN_LAST, + G_STRUCT_OFFSET (FuPluginClass, security_changed), + NULL, NULL, g_cclosure_marshal_VOID__VOID, + G_TYPE_NONE, 0); signals[SIGNAL_SET_COLDPLUG_DELAY] = g_signal_new ("set-coldplug-delay", G_TYPE_FROM_CLASS (object_class), G_SIGNAL_RUN_LAST, diff --git a/libfwupdplugin/fu-plugin.h b/libfwupdplugin/fu-plugin.h index 65625e2df..671d5a12d 100644 --- a/libfwupdplugin/fu-plugin.h +++ b/libfwupdplugin/fu-plugin.h @@ -49,8 +49,9 @@ struct _FuPluginClass gboolean (* add_firmware_gtype) (FuPlugin *self, const gchar *id, GType gtype); + void (* security_changed) (FuPlugin *self); /*< private >*/ - gpointer padding[21]; + gpointer padding[20]; }; /** @@ -108,6 +109,7 @@ void fu_plugin_device_remove (FuPlugin *self, void fu_plugin_device_register (FuPlugin *self, FuDevice *device); void fu_plugin_request_recoldplug (FuPlugin *self); +void fu_plugin_security_changed (FuPlugin *self); void fu_plugin_set_coldplug_delay (FuPlugin *self, guint duration); void fu_plugin_set_device_gtype (FuPlugin *self, diff --git a/libfwupdplugin/fwupdplugin.map b/libfwupdplugin/fwupdplugin.map index 7401131c8..a612f0d82 100644 --- a/libfwupdplugin/fwupdplugin.map +++ b/libfwupdplugin/fwupdplugin.map @@ -587,6 +587,7 @@ LIBFWUPDPLUGIN_1.5.0 { fu_common_is_cpu_intel; fu_plugin_runner_add_security_attrs; fu_plugin_runner_device_added; + fu_plugin_security_changed; fu_udev_device_get_parent_name; fu_udev_device_get_sysfs_attr; local: *; diff --git a/src/fu-engine.c b/src/fu-engine.c index c33935a47..6953b2f2c 100644 --- a/src/fu-engine.c +++ b/src/fu-engine.c @@ -4671,6 +4671,13 @@ fu_engine_plugin_rules_changed_cb (FuPlugin *plugin, gpointer user_data) } } +static void +fu_engine_plugin_security_changed_cb (FuPlugin *plugin, gpointer user_data) +{ + FuEngine *self = FU_ENGINE (user_data); + fu_engine_emit_changed (self); +} + static void fu_engine_plugin_device_removed_cb (FuPlugin *plugin, FuDevice *device, @@ -5169,6 +5176,9 @@ fu_engine_load_plugins (FuEngine *self, GError **error) g_signal_connect (plugin, "rules-changed", G_CALLBACK (fu_engine_plugin_rules_changed_cb), self); + g_signal_connect (plugin, "security-changed", + G_CALLBACK (fu_engine_plugin_security_changed_cb), + self); /* add */ fu_engine_add_plugin (self, plugin); From ad45158d6ae399c910c3d40d903ac16e1e38dcdd Mon Sep 17 00:00:00 2001 From: Richard Hughes Date: Mon, 11 May 2020 22:14:47 +0100 Subject: [PATCH 046/607] hsi: Taint the result if unknown fwupd plugins are running --- src/fu-engine.c | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/src/fu-engine.c b/src/fu-engine.c index 6953b2f2c..45d44d7ae 100644 --- a/src/fu-engine.c +++ b/src/fu-engine.c @@ -5037,13 +5037,31 @@ fu_engine_get_host_machine_id (FuEngine *self) return self->host_machine_id; } +static void +fu_engine_add_security_attrs_tainted (FuEngine *self, GPtrArray *attrs) +{ + FwupdSecurityAttr *attr = fwupd_security_attr_new ("org.fwupd.Hsi.Plugins"); + fwupd_security_attr_set_name (attr, "fwupd plugins"); + fwupd_security_attr_add_flag (attr, FWUPD_SECURITY_ATTR_FLAG_RUNTIME_ISSUE); + if (self->tainted) { + fwupd_security_attr_set_result (attr, "Tainted"); + } else { + fwupd_security_attr_add_flag (attr, FWUPD_SECURITY_ATTR_FLAG_SUCCESS); + } + g_ptr_array_add (attrs, attr); +} + GPtrArray * fu_engine_get_host_security_attrs (FuEngine *self, GError **error) { GPtrArray *plugins = fu_plugin_list_get_all (self->plugin_list); g_autoptr(GPtrArray) attrs = NULL; + /* built in */ attrs = g_ptr_array_new_with_free_func ((GDestroyNotify) g_object_unref); + fu_engine_add_security_attrs_tainted (self, attrs); + + /* call into plugins */ for (guint j = 0; j < plugins->len; j++) { FuPlugin *plugin_tmp = g_ptr_array_index (plugins, j); g_autoptr(GError) error_local = NULL; From 31c1a45833cc68468cbfde3a48b883afce5cac64 Mon Sep 17 00:00:00 2001 From: Richard Hughes Date: Mon, 11 May 2020 22:16:10 +0100 Subject: [PATCH 047/607] hsi: Add support for 'U' and 'A' suffixes --- src/fu-engine.c | 69 +++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 69 insertions(+) diff --git a/src/fu-engine.c b/src/fu-engine.c index 45d44d7ae..3bbf998fa 100644 --- a/src/fu-engine.c +++ b/src/fu-engine.c @@ -5051,6 +5051,74 @@ fu_engine_add_security_attrs_tainted (FuEngine *self, GPtrArray *attrs) g_ptr_array_add (attrs, attr); } +static void +fu_engine_add_security_attrs_supported (FuEngine *self, GPtrArray *attrs) +{ + FwupdRelease *rel_current = NULL; + FwupdRelease *rel_newest = NULL; + FwupdSecurityAttr *attr_a; + FwupdSecurityAttr *attr_u; + guint64 now = (guint64) g_get_real_time () / G_USEC_PER_SEC; + g_autoptr(FuDevice) device = NULL; + g_autoptr(GPtrArray) releases = NULL; + + /* find out if there is firmware less than 12 months old */ + attr_u = fwupd_security_attr_new ("org.fwupd.Hsi.Updates"); + fwupd_security_attr_add_flag (attr_u, FWUPD_SECURITY_ATTR_FLAG_RUNTIME_UPDATES); + fwupd_security_attr_set_name (attr_u, "Firmware Updates"); + g_ptr_array_add (attrs, attr_u); + + /* get device */ + device = fu_device_list_get_by_guid (self->device_list, + /* main-system-firmware */ + "230c8b18-8d9b-53ec-838b-6cfc0383493a", + NULL); + if (device == NULL) { + fwupd_security_attr_set_result (attr_u, "No system device"); + } else { + releases = fu_engine_get_releases_for_device (self, device, NULL); + if (releases == NULL) { + fwupd_security_attr_set_result (attr_u, "No releases"); + } else { + /* check the age */ + g_autofree gchar *str = NULL; + for (guint i = 0; i < releases->len; i++) { + FwupdRelease *rel_tmp = g_ptr_array_index (releases, i); + if (rel_newest == NULL || + fwupd_release_get_created (rel_tmp) > fwupd_release_get_created (rel_newest)) + rel_newest = rel_tmp; + } + str = g_strdup_printf ("Newest release is %" G_GUINT64_FORMAT " months old", + (now - fwupd_release_get_created (rel_newest)) / (60 * 60 * 24 * 30)); + fwupd_security_attr_set_result (attr_u, str); + if (now - fwupd_release_get_created (rel_newest) < 60 * 60 * 24 * 30 * 12) + fwupd_security_attr_add_flag (attr_u, FWUPD_SECURITY_ATTR_FLAG_SUCCESS); + } + } + + /* do we have attestation checksums */ + attr_a = fwupd_security_attr_new ("org.fwupd.Hsi.Attestation"); + fwupd_security_attr_set_name (attr_a, "Firmware Attestation"); + fwupd_security_attr_add_flag (attr_a, FWUPD_SECURITY_ATTR_FLAG_RUNTIME_ATTESTATION); + g_ptr_array_add (attrs, attr_a); + if (releases != NULL) { + for (guint i = 0; i < releases->len; i++) { + FwupdRelease *rel_tmp = g_ptr_array_index (releases, i); + if (fu_common_vercmp_full (fu_device_get_version (device), + fwupd_release_get_version (rel_tmp), + fu_device_get_version_format (device)) == 0) { + rel_current = rel_tmp; + break; + } + } + } + if (rel_current == NULL) { + fwupd_security_attr_set_result (attr_a, "No PCR0s"); + } else if (fwupd_release_get_checksums(rel_current)->len > 0) { + fwupd_security_attr_add_flag (attr_a, FWUPD_SECURITY_ATTR_FLAG_SUCCESS); + } +} + GPtrArray * fu_engine_get_host_security_attrs (FuEngine *self, GError **error) { @@ -5060,6 +5128,7 @@ fu_engine_get_host_security_attrs (FuEngine *self, GError **error) /* built in */ attrs = g_ptr_array_new_with_free_func ((GDestroyNotify) g_object_unref); fu_engine_add_security_attrs_tainted (self, attrs); + fu_engine_add_security_attrs_supported (self, attrs); /* call into plugins */ for (guint j = 0; j < plugins->len; j++) { From 99cc658a75b2ac6fc9170c5b5c446111a6e36b8c Mon Sep 17 00:00:00 2001 From: Richard Hughes Date: Mon, 11 May 2020 22:21:03 +0100 Subject: [PATCH 048/607] tpm-eventlog: Add an HSI attr for reconstruction failure --- plugins/tpm-eventlog/fu-plugin-tpm-eventlog.c | 20 ++++++++++++++++++- 1 file changed, 19 insertions(+), 1 deletion(-) diff --git a/plugins/tpm-eventlog/fu-plugin-tpm-eventlog.c b/plugins/tpm-eventlog/fu-plugin-tpm-eventlog.c index 0f9a007b5..c85307192 100644 --- a/plugins/tpm-eventlog/fu-plugin-tpm-eventlog.c +++ b/plugins/tpm-eventlog/fu-plugin-tpm-eventlog.c @@ -15,6 +15,7 @@ struct FuPluginData { GPtrArray *pcr0s; gboolean secure_boot_problem; + gboolean reconstructed; }; void @@ -112,7 +113,7 @@ fu_plugin_device_registered (FuPlugin *plugin, FuDevice *device) for (guint j = 0; j < data->pcr0s->len; j++) { const gchar *checksum_tmp = g_ptr_array_index (data->pcr0s, j); if (g_strcmp0 (checksum, checksum_tmp) == 0) { - g_debug ("TPM reconstructed event log matched PCR0 reading"); + data->reconstructed = TRUE; return; } } @@ -123,3 +124,20 @@ fu_plugin_device_registered (FuPlugin *plugin, FuDevice *device) "TPM PCR0 differs from reconstruction, " "please see https://github.com/fwupd/fwupd/wiki/TPM-PCR0-differs-from-reconstruction"); } + +gboolean +fu_plugin_add_security_attrs (FuPlugin *plugin, GPtrArray *attrs, GError **error) +{ + FuPluginData *data = fu_plugin_get_data (plugin); + FwupdSecurityAttr *attr = fwupd_security_attr_new ("org.trustedcomputinggroup.TpmEventLog"); + fwupd_security_attr_set_level (attr, FWUPD_SECURITY_ATTR_LEVEL_IMPORTANT); + fwupd_security_attr_set_name (attr, "TPM Reconstruction"); + if (data->reconstructed) { + fwupd_security_attr_set_result (attr, "Matched PCR0 reading"); + fwupd_security_attr_add_flag (attr, FWUPD_SECURITY_ATTR_FLAG_SUCCESS); + } else { + fwupd_security_attr_set_result (attr, "Did not match PCR0 reading"); + } + g_ptr_array_add (attrs, attr); + return TRUE; +} From f58ac7316c451f716aa978b9354feffe511e6dac Mon Sep 17 00:00:00 2001 From: Richard Hughes Date: Tue, 12 May 2020 15:23:44 +0100 Subject: [PATCH 049/607] hsi: Abstract out the list of FwupdSecurityAttr objects for plugins This exports FuSecurityAttrs into libfwupdplugin so that we can pass the plugins this object rather than a 'bare' GPtrArray. This greatly simplifies the object ownership, and also allows us to check the object type before adding. In the future we could also check for duplicate appstream IDs or missing properties at insertion time. This change also changes the fu_plugin_add_security_attrs() to not return an error. This forces the plugin to handle the error, storing the failure in the attribute itself. Only the plugin know if a missing file it needs to read indicates a runtime problem or a simple failure to obtain a specific HSI level. --- libfwupdplugin/fu-plugin-private.h | 6 +- libfwupdplugin/fu-plugin-vfuncs.h | 9 +- libfwupdplugin/fu-plugin.c | 28 +- libfwupdplugin/fu-security-attrs-private.h | 15 ++ libfwupdplugin/fu-security-attrs.c | 241 ++++++++++++++++++ libfwupdplugin/fu-security-attrs.h | 18 ++ libfwupdplugin/fu-self-test.c | 76 ++++++ libfwupdplugin/fwupdplugin.h | 1 + libfwupdplugin/fwupdplugin.map | 7 + libfwupdplugin/meson.build | 3 + meson.build | 1 + plugins/tpm-eventlog/fu-plugin-tpm-eventlog.c | 15 +- src/fu-engine.c | 43 +--- src/fu-engine.h | 3 +- src/fu-main.c | 21 +- src/fu-security-attrs.c | 115 --------- src/fu-security-attrs.h | 12 - src/fu-self-test.c | 71 ------ src/fu-tool.c | 7 +- src/meson.build | 4 +- 20 files changed, 422 insertions(+), 274 deletions(-) create mode 100644 libfwupdplugin/fu-security-attrs-private.h create mode 100644 libfwupdplugin/fu-security-attrs.c create mode 100644 libfwupdplugin/fu-security-attrs.h delete mode 100644 src/fu-security-attrs.c delete mode 100644 src/fu-security-attrs.h diff --git a/libfwupdplugin/fu-plugin-private.h b/libfwupdplugin/fu-plugin-private.h index a5e51cd59..bb703fcdd 100644 --- a/libfwupdplugin/fu-plugin-private.h +++ b/libfwupdplugin/fu-plugin-private.h @@ -8,6 +8,7 @@ #include "fu-quirks.h" #include "fu-plugin.h" +#include "fu-security-attrs.h" #include "fu-smbios.h" FuPlugin *fu_plugin_new (void); @@ -116,9 +117,8 @@ gboolean fu_plugin_runner_clear_results (FuPlugin *self, gboolean fu_plugin_runner_get_results (FuPlugin *self, FuDevice *device, GError **error); -gboolean fu_plugin_runner_add_security_attrs (FuPlugin *self, - GPtrArray *attrs, - GError **error); +void fu_plugin_runner_add_security_attrs (FuPlugin *self, + FuSecurityAttrs*attrs); gint fu_plugin_name_compare (FuPlugin *plugin1, FuPlugin *plugin2); gint fu_plugin_order_compare (FuPlugin *plugin1, diff --git a/libfwupdplugin/fu-plugin-vfuncs.h b/libfwupdplugin/fu-plugin-vfuncs.h index 287cf2e44..8b9292092 100644 --- a/libfwupdplugin/fu-plugin-vfuncs.h +++ b/libfwupdplugin/fu-plugin-vfuncs.h @@ -8,6 +8,7 @@ #include "fu-plugin.h" #include "fu-device.h" +#include "fu-security-attrs.h" /** * SECTION:fu-plugin-vfuncs @@ -362,13 +363,11 @@ void fu_plugin_device_registered (FuPlugin *plugin, /** * fu_plugin_add_security_attrs * @plugin: A #FuPlugin - * @attrs: A #GPtrArray of #FwupdSecurityAttr - * @error: A #GError or NULL + * @attrs: A #FuSecurityAttrs * * Function that asks plugins to add Host Security Attributes. * * Since: 1.5.0 **/ -gboolean fu_plugin_add_security_attrs (FuPlugin *plugin, - GPtrArray *attrs, - GError **error); +void fu_plugin_add_security_attrs (FuPlugin *plugin, + FuSecurityAttrs *attrs); diff --git a/libfwupdplugin/fu-plugin.c b/libfwupdplugin/fu-plugin.c index 951b037fc..75c199b55 100644 --- a/libfwupdplugin/fu-plugin.c +++ b/libfwupdplugin/fu-plugin.c @@ -105,6 +105,8 @@ typedef gboolean (*FuPluginUsbDeviceAddedFunc) (FuPlugin *self, typedef gboolean (*FuPluginUdevDeviceAddedFunc) (FuPlugin *self, FuUdevDevice *device, GError **error); +typedef void (*FuPluginSecurityAttrsFunc) (FuPlugin *self, + FuSecurityAttrs *attrs); /** * fu_plugin_is_open: @@ -1599,20 +1601,28 @@ fu_plugin_runner_update_reload (FuPlugin *self, FuDevice *device, GError **error * fu_plugin_runner_add_security_attrs: * @self: a #FuPlugin * @attrs: (element-type FwupdSecurityAttr): a #GPtrArray of attributes - * @error: a #GError or NULL * - * Runs the composite_prepare routine for the plugin - * - * Returns: #TRUE for success, #FALSE for failure + * Runs the add_security_attrs routine for the plugin * * Since: 1.5.0 **/ -gboolean -fu_plugin_runner_add_security_attrs (FuPlugin *self, GPtrArray *attrs, GError **error) +void +fu_plugin_runner_add_security_attrs (FuPlugin *self, FuSecurityAttrs *attrs) { - return fu_plugin_runner_device_array_generic (self, attrs, - "fu_plugin_add_security_attrs", - error); + FuPluginPrivate *priv = GET_PRIVATE (self); + FuPluginSecurityAttrsFunc func = NULL; + const gchar *symbol_name = "fu_plugin_add_security_attrs"; + + /* no object loaded */ + if (priv->module == NULL) + return; + + /* optional, but gets called even for disabled plugins */ + g_module_symbol (priv->module, symbol_name, (gpointer *) &func); + if (func == NULL) + return; + g_debug ("performing %s() on %s", symbol_name + 10, priv->name); + func (self, attrs); } /** diff --git a/libfwupdplugin/fu-security-attrs-private.h b/libfwupdplugin/fu-security-attrs-private.h new file mode 100644 index 000000000..5e9c262e5 --- /dev/null +++ b/libfwupdplugin/fu-security-attrs-private.h @@ -0,0 +1,15 @@ +/* + * Copyright (C) 2020 Richard Hughes + * + * SPDX-License-Identifier: LGPL-2.1+ + */ + +#pragma once + +#include "fu-security-attrs.h" + +FuSecurityAttrs *fu_security_attrs_new (void); +gchar *fu_security_attrs_calculate_hsi (FuSecurityAttrs *self); +void fu_security_attrs_depsolve (FuSecurityAttrs *self); +GVariant *fu_security_attrs_to_variant (FuSecurityAttrs *self); +GPtrArray *fu_security_attrs_get_all (FuSecurityAttrs *self); diff --git a/libfwupdplugin/fu-security-attrs.c b/libfwupdplugin/fu-security-attrs.c new file mode 100644 index 000000000..b175238b4 --- /dev/null +++ b/libfwupdplugin/fu-security-attrs.c @@ -0,0 +1,241 @@ +/* + * Copyright (C) 2020 Richard Hughes + * + * SPDX-License-Identifier: LGPL-2.1+ + */ + +#include "config.h" + +#include + +#include "fu-security-attrs-private.h" + +struct _FuSecurityAttrs { + GObject parent_instance; + GPtrArray *attrs; +}; + +G_DEFINE_TYPE (FuSecurityAttrs, fu_security_attrs, G_TYPE_OBJECT) + +static void +fu_security_attrs_finalize (GObject *obj) +{ + FuSecurityAttrs *self = FU_SECURITY_ATTRS (obj); + g_ptr_array_unref (self->attrs); + G_OBJECT_CLASS (fu_security_attrs_parent_class)->finalize (obj); +} + +static void +fu_security_attrs_class_init (FuSecurityAttrsClass *klass) +{ + GObjectClass *object_class = G_OBJECT_CLASS (klass); + object_class->finalize = fu_security_attrs_finalize; +} + +static void +fu_security_attrs_init (FuSecurityAttrs *self) +{ + self->attrs = g_ptr_array_new_with_free_func ((GDestroyNotify) g_object_unref); +} + +/** + * fu_security_attrs_append: + * @self: A #FuSecurityAttrs + * @attr: a #FwupdSecurityAttr + * + * Adds a #FwupdSecurityAttr to the array. + * + * Since: 1.5.0 + **/ +void +fu_security_attrs_append (FuSecurityAttrs *self, FwupdSecurityAttr *attr) +{ + g_return_if_fail (FU_IS_SECURITY_ATTRS (self)); + g_return_if_fail (FWUPD_IS_SECURITY_ATTR (attr)); + g_ptr_array_add (self->attrs, g_object_ref (attr)); +} + +/** + * fu_security_attrs_to_variant: + * @self: A #FuSecurityAttrs + * + * Converts the #FwupdSecurityAttr objects into a variant array. + * + * Returns: a #GVariant or %NULL + * + * Since: 1.5.0 + **/ +GVariant * +fu_security_attrs_to_variant (FuSecurityAttrs *self) +{ + GVariantBuilder builder; + + g_return_val_if_fail (FU_IS_SECURITY_ATTRS (self), NULL); + g_return_val_if_fail (self->attrs->len > 0, NULL); + g_variant_builder_init (&builder, G_VARIANT_TYPE_ARRAY); + + for (guint i = 0; i < self->attrs->len; i++) { + FwupdSecurityAttr *security_attr = g_ptr_array_index (self->attrs, i); + GVariant *tmp = fwupd_security_attr_to_variant (security_attr); + g_variant_builder_add_value (&builder, tmp); + } + return g_variant_new ("(aa{sv})", &builder); +} + +/** + * fu_security_attrs_get_all: + * @self: A #FuSecurityAttrs + * + * Gets all the attributes in the object. + * + * Returns: (transfer container) (element-type FwupdSecurityAttr): attributes + * + * Since: 1.5.0 + **/ +GPtrArray * +fu_security_attrs_get_all (FuSecurityAttrs *self) +{ + g_return_val_if_fail (FU_IS_SECURITY_ATTRS (self), NULL); + return g_ptr_array_ref (self->attrs); +} + +/** + * fu_security_attrs_calculate_hsi: + * @self: A #FuSecurityAttrs + * + * Calculates the HSI string from the appended attribues. + * + * Returns: (transfer full): a string or %NULL + * + * Since: 1.5.0 + **/ +gchar * +fu_security_attrs_calculate_hsi (FuSecurityAttrs *self) +{ + guint hsi_number = 0; + FwupdSecurityAttrFlags flags = FWUPD_SECURITY_ATTR_FLAG_NONE; + GString *str = g_string_new ("HSI:"); + const FwupdSecurityAttrFlags hpi_suffixes[] = { + FWUPD_SECURITY_ATTR_FLAG_RUNTIME_UPDATES, + FWUPD_SECURITY_ATTR_FLAG_RUNTIME_ATTESTATION, + FWUPD_SECURITY_ATTR_FLAG_RUNTIME_ISSUE, + FWUPD_SECURITY_ATTR_FLAG_NONE, + }; + + g_return_val_if_fail (FU_IS_SECURITY_ATTRS (self), NULL); + + /* find the highest HSI number where there are no failures and at least + * one success */ + for (guint j = 1; j <= FWUPD_SECURITY_ATTR_LEVEL_LAST; j++) { + gboolean success_cnt = 0; + gboolean failure_cnt = 0; + for (guint i = 0; i < self->attrs->len; i++) { + FwupdSecurityAttr *attr = g_ptr_array_index (self->attrs, i); + if (fwupd_security_attr_get_level (attr) != j) + continue; + if (fwupd_security_attr_has_flag (attr, FWUPD_SECURITY_ATTR_FLAG_SUCCESS)) + success_cnt++; + else if (!fwupd_security_attr_has_flag (attr, FWUPD_SECURITY_ATTR_FLAG_OBSOLETED)) + failure_cnt++; + } + + /* abort */ + if (failure_cnt > 0) { + hsi_number = j - 1; + break; + } + + /* we matched at least one thing on this level */ + if (success_cnt > 0) + hsi_number = j; + } + + /* get a logical OR of the runtime flags */ + for (guint i = 0; i < self->attrs->len; i++) { + FwupdSecurityAttr *attr = g_ptr_array_index (self->attrs, i); + if (fwupd_security_attr_has_flag (attr, FWUPD_SECURITY_ATTR_FLAG_OBSOLETED)) + continue; + /* positive things */ + if (fwupd_security_attr_has_flag (attr, FWUPD_SECURITY_ATTR_FLAG_RUNTIME_UPDATES) || + fwupd_security_attr_has_flag (attr, FWUPD_SECURITY_ATTR_FLAG_RUNTIME_ATTESTATION)) { + if (!fwupd_security_attr_has_flag (attr, FWUPD_SECURITY_ATTR_FLAG_SUCCESS)) + continue; + } + /* negative things */ + if (fwupd_security_attr_has_flag (attr, FWUPD_SECURITY_ATTR_FLAG_RUNTIME_ISSUE)) { + if (fwupd_security_attr_has_flag (attr, FWUPD_SECURITY_ATTR_FLAG_SUCCESS)) + continue; + } + flags |= fwupd_security_attr_get_flags (attr); + } + + g_string_append_printf (str, "%u", hsi_number); + if (flags & (FWUPD_SECURITY_ATTR_FLAG_RUNTIME_UPDATES | + FWUPD_SECURITY_ATTR_FLAG_RUNTIME_ATTESTATION | + FWUPD_SECURITY_ATTR_FLAG_RUNTIME_ISSUE)) { + g_string_append (str, "+"); + for (guint j = 0; hpi_suffixes[j] != FWUPD_SECURITY_ATTR_FLAG_NONE; j++) { + if (flags & hpi_suffixes[j]) + g_string_append (str, fwupd_security_attr_flag_to_suffix (hpi_suffixes[j])); + } + } + return g_string_free (str, FALSE); +} + +/** + * fu_security_attrs_depsolve: + * @self: A #FuSecurityAttrs + * + * Marks any attributes with %FWUPD_SECURITY_ATTR_FLAG_OBSOLETED that have been + * defined as obsoleted by other attributes. + * + * It is only required to call this function once, and should be done when all + * attributes have been added. + * + * Since: 1.5.0 + **/ +void +fu_security_attrs_depsolve (FuSecurityAttrs *self) +{ + g_autoptr(GHashTable) attrs_by_id = NULL; + + g_return_if_fail (FU_IS_SECURITY_ATTRS (self)); + + /* make hash of ID -> object */ + attrs_by_id = g_hash_table_new (g_str_hash, g_str_equal); + for (guint i = 0; i < self->attrs->len; i++) { + FwupdSecurityAttr *attr = g_ptr_array_index (self->attrs, i); + g_hash_table_insert (attrs_by_id, + (gpointer) fwupd_security_attr_get_appstream_id (attr), + (gpointer) attr); + } + + /* set flat where required */ + for (guint i = 0; i < self->attrs->len; i++) { + FwupdSecurityAttr *attr = g_ptr_array_index (self->attrs, i); + GPtrArray *obsoletes = fwupd_security_attr_get_obsoletes (attr); + for (guint j = 0; j < obsoletes->len; j++) { + const gchar *obsolete = g_ptr_array_index (obsoletes, j); + FwupdSecurityAttr *attr_tmp = g_hash_table_lookup (attrs_by_id, obsolete); + if (attr_tmp != NULL) { + g_debug ("security attr %s obsoleted by %s", obsolete, + fwupd_security_attr_get_appstream_id (attr)); + fwupd_security_attr_add_flag (attr_tmp, + FWUPD_SECURITY_ATTR_FLAG_OBSOLETED); + } + } + } +} + +/** + * fu_security_attrs_new: + * + * Returns: a #FuSecurityAttrs + * + * Since: 1.5.0 + **/ +FuSecurityAttrs * +fu_security_attrs_new (void) +{ + return g_object_new (FU_TYPE_SECURITY_ATTRS, NULL); +} diff --git a/libfwupdplugin/fu-security-attrs.h b/libfwupdplugin/fu-security-attrs.h new file mode 100644 index 000000000..fbd55cb64 --- /dev/null +++ b/libfwupdplugin/fu-security-attrs.h @@ -0,0 +1,18 @@ +/* + * Copyright (C) 2020 Richard Hughes + * + * SPDX-License-Identifier: LGPL-2.1+ + */ + +#pragma once + +#include + +#include "fwupd-security-attr-private.h" + +#define FU_TYPE_SECURITY_ATTRS (fu_security_attrs_get_type ()) + +G_DECLARE_FINAL_TYPE (FuSecurityAttrs, fu_security_attrs, FU, SECURITY_ATTRS, GObject) + +void fu_security_attrs_append (FuSecurityAttrs *self, + FwupdSecurityAttr *attr); diff --git a/libfwupdplugin/fu-self-test.c b/libfwupdplugin/fu-self-test.c index afdf652ff..e5265fa1c 100644 --- a/libfwupdplugin/fu-self-test.c +++ b/libfwupdplugin/fu-self-test.c @@ -14,6 +14,7 @@ #include "fu-device-private.h" #include "fu-plugin-private.h" +#include "fu-security-attrs-private.h" #include "fu-smbios-private.h" static GMainLoop *_test_loop = NULL; @@ -1742,6 +1743,80 @@ fu_device_retry_hardware_func (void) g_assert_cmpint (helper.cnt_failed, ==, 2); } +static void +fu_security_attrs_hsi_func (void) +{ + g_autofree gchar *hsi1 = NULL; + g_autofree gchar *hsi2 = NULL; + g_autofree gchar *hsi3 = NULL; + g_autofree gchar *hsi4 = NULL; + g_autofree gchar *hsi5 = NULL; + g_autofree gchar *hsi6 = NULL; + g_autofree gchar *hsi7 = NULL; + g_autoptr(FuSecurityAttrs) attrs = NULL; + g_autoptr(FwupdSecurityAttr) attr = NULL; + + /* no attrs */ + attrs = fu_security_attrs_new (); + hsi1 = fu_security_attrs_calculate_hsi (attrs); + g_assert_cmpstr (hsi1, ==, "HSI:0"); + + /* just success from HSI:1 */ + attr = fwupd_security_attr_new ("org.fwupd.Hsi.BIOSWE"); + fwupd_security_attr_set_level (attr, 1); + fwupd_security_attr_add_flag (attr, FWUPD_SECURITY_ATTR_FLAG_SUCCESS); + fu_security_attrs_append (attrs, attr); + hsi2 = fu_security_attrs_calculate_hsi (attrs); + g_assert_cmpstr (hsi2, ==, "HSI:1"); + g_clear_object (&attr); + + /* add failed from HSI:2, so still HSI:1 */ + attr = fwupd_security_attr_new ("org.fwupd.Hsi.PRX"); + fwupd_security_attr_set_level (attr, 2); + fu_security_attrs_append (attrs, attr); + hsi3 = fu_security_attrs_calculate_hsi (attrs); + g_assert_cmpstr (hsi3, ==, "HSI:1"); + g_clear_object (&attr); + + /* add attr from HSI:3, obsoleting the failure */ + attr = fwupd_security_attr_new ("org.fwupd.Hsi.BIOSGuard"); + fwupd_security_attr_set_level (attr, 3); + fwupd_security_attr_add_flag (attr, FWUPD_SECURITY_ATTR_FLAG_SUCCESS); + fwupd_security_attr_add_obsolete (attr, "org.fwupd.Hsi.PRX"); + fu_security_attrs_append (attrs, attr); + fu_security_attrs_depsolve (attrs); + hsi4 = fu_security_attrs_calculate_hsi (attrs); + g_assert_cmpstr (hsi4, ==, "HSI:3"); + g_clear_object (&attr); + + /* add taint that was fine */ + attr = fwupd_security_attr_new ("org.fwupd.Hsi.PluginsTainted"); + fwupd_security_attr_add_flag (attr, FWUPD_SECURITY_ATTR_FLAG_SUCCESS); + fwupd_security_attr_add_flag (attr, FWUPD_SECURITY_ATTR_FLAG_RUNTIME_ISSUE); + fu_security_attrs_append (attrs, attr); + hsi5 = fu_security_attrs_calculate_hsi (attrs); + g_assert_cmpstr (hsi5, ==, "HSI:3"); + g_clear_object (&attr); + + /* add updates and attestation */ + attr = fwupd_security_attr_new ("org.fwupd.Hsi.LVFS"); + fwupd_security_attr_add_flag (attr, FWUPD_SECURITY_ATTR_FLAG_RUNTIME_UPDATES); + fwupd_security_attr_add_flag (attr, FWUPD_SECURITY_ATTR_FLAG_RUNTIME_ATTESTATION); + fwupd_security_attr_add_flag (attr, FWUPD_SECURITY_ATTR_FLAG_SUCCESS); + fu_security_attrs_append (attrs, attr); + hsi6 = fu_security_attrs_calculate_hsi (attrs); + g_assert_cmpstr (hsi6, ==, "HSI:3+UA"); + g_clear_object (&attr); + + /* add issue that was uncool */ + attr = fwupd_security_attr_new ("org.fwupd.Hsi.Swap"); + fwupd_security_attr_add_flag (attr, FWUPD_SECURITY_ATTR_FLAG_RUNTIME_ISSUE); + fu_security_attrs_append (attrs, attr); + hsi7 = fu_security_attrs_calculate_hsi (attrs); + g_assert_cmpstr (hsi7, ==, "HSI:3+UA!"); + g_clear_object (&attr); +} + int main (int argc, char **argv) { @@ -1757,6 +1832,7 @@ main (int argc, char **argv) g_setenv ("FWUPD_OFFLINE_TRIGGER", "/tmp/fwupd-self-test/system-update", TRUE); g_setenv ("FWUPD_LOCALSTATEDIR", "/tmp/fwupd-self-test/var", TRUE); + g_test_add_func ("/fwupd/security-attrs{hsi}", fu_security_attrs_hsi_func); g_test_add_func ("/fwupd/plugin{delay}", fu_plugin_delay_func); g_test_add_func ("/fwupd/plugin{quirks}", fu_plugin_quirks_func); g_test_add_func ("/fwupd/plugin{quirks-performance}", fu_plugin_quirks_performance_func); diff --git a/libfwupdplugin/fwupdplugin.h b/libfwupdplugin/fwupdplugin.h index 52d8cb6b5..b35ce5968 100644 --- a/libfwupdplugin/fwupdplugin.h +++ b/libfwupdplugin/fwupdplugin.h @@ -32,6 +32,7 @@ #include #include #include +#include #include #include #include diff --git a/libfwupdplugin/fwupdplugin.map b/libfwupdplugin/fwupdplugin.map index a612f0d82..fd2734c1d 100644 --- a/libfwupdplugin/fwupdplugin.map +++ b/libfwupdplugin/fwupdplugin.map @@ -588,6 +588,13 @@ LIBFWUPDPLUGIN_1.5.0 { fu_plugin_runner_add_security_attrs; fu_plugin_runner_device_added; fu_plugin_security_changed; + fu_security_attrs_append; + fu_security_attrs_calculate_hsi; + fu_security_attrs_depsolve; + fu_security_attrs_get_all; + fu_security_attrs_get_type; + fu_security_attrs_new; + fu_security_attrs_to_variant; fu_udev_device_get_parent_name; fu_udev_device_get_sysfs_attr; local: *; diff --git a/libfwupdplugin/meson.build b/libfwupdplugin/meson.build index 40b59668a..dd5639f05 100644 --- a/libfwupdplugin/meson.build +++ b/libfwupdplugin/meson.build @@ -17,6 +17,7 @@ fwupdplugin_src = [ 'fu-io-channel.c', 'fu-plugin.c', 'fu-quirks.c', + 'fu-security-attrs.c', 'fu-smbios.c', 'fu-srec-firmware.c', 'fu-efivar.c', @@ -45,6 +46,7 @@ fwupdplugin_headers = [ 'fu-io-channel.h', 'fu-plugin.h', 'fu-quirks.h', + 'fu-security-attrs.h', 'fu-smbios.h', 'fu-srec-firmware.h', 'fu-efivar.h', @@ -73,6 +75,7 @@ fwupdplugin_headers_private = [ fu_hash, 'fu-device-private.h', 'fu-plugin-private.h', + 'fu-security-attrs-private.h', 'fu-smbios-private.h', 'fu-usb-device-private.h', ] diff --git a/meson.build b/meson.build index 552dc7f06..7106de70b 100644 --- a/meson.build +++ b/meson.build @@ -424,6 +424,7 @@ if build_standalone plugin_deps += soup plugin_deps += libarchive plugin_deps += gudev + plugin_deps += libjsonglib endif root_incdir = include_directories('.') diff --git a/plugins/tpm-eventlog/fu-plugin-tpm-eventlog.c b/plugins/tpm-eventlog/fu-plugin-tpm-eventlog.c index c85307192..4fec2f1c6 100644 --- a/plugins/tpm-eventlog/fu-plugin-tpm-eventlog.c +++ b/plugins/tpm-eventlog/fu-plugin-tpm-eventlog.c @@ -125,19 +125,22 @@ fu_plugin_device_registered (FuPlugin *plugin, FuDevice *device) "please see https://github.com/fwupd/fwupd/wiki/TPM-PCR0-differs-from-reconstruction"); } -gboolean -fu_plugin_add_security_attrs (FuPlugin *plugin, GPtrArray *attrs, GError **error) +void +fu_plugin_add_security_attrs (FuPlugin *plugin, FuSecurityAttrs *attrs) { FuPluginData *data = fu_plugin_get_data (plugin); - FwupdSecurityAttr *attr = fwupd_security_attr_new ("org.trustedcomputinggroup.TpmEventLog"); + g_autoptr(FwupdSecurityAttr) attr = NULL; + + attr = fwupd_security_attr_new ("org.trustedcomputinggroup.TpmEventLog"); fwupd_security_attr_set_level (attr, FWUPD_SECURITY_ATTR_LEVEL_IMPORTANT); fwupd_security_attr_set_name (attr, "TPM Reconstruction"); - if (data->reconstructed) { + if (!fu_plugin_get_enabled (plugin)) { + fwupd_security_attr_set_result (attr, "No binary bios measurements available"); + } else if (data->reconstructed) { fwupd_security_attr_set_result (attr, "Matched PCR0 reading"); fwupd_security_attr_add_flag (attr, FWUPD_SECURITY_ATTR_FLAG_SUCCESS); } else { fwupd_security_attr_set_result (attr, "Did not match PCR0 reading"); } - g_ptr_array_add (attrs, attr); - return TRUE; + fu_security_attrs_append (attrs, attr); } diff --git a/src/fu-engine.c b/src/fu-engine.c index 3bbf998fa..7c64786dd 100644 --- a/src/fu-engine.c +++ b/src/fu-engine.c @@ -49,7 +49,7 @@ #include "fu-plugin-private.h" #include "fu-quirks.h" #include "fu-remote-list.h" -#include "fu-security-attrs.h" +#include "fu-security-attrs-private.h" #include "fu-smbios-private.h" #include "fu-udev-device-private.h" #include "fu-usb-device-private.h" @@ -5038,7 +5038,7 @@ fu_engine_get_host_machine_id (FuEngine *self) } static void -fu_engine_add_security_attrs_tainted (FuEngine *self, GPtrArray *attrs) +fu_engine_add_security_attrs_tainted (FuEngine *self, FuSecurityAttrs *attrs) { FwupdSecurityAttr *attr = fwupd_security_attr_new ("org.fwupd.Hsi.Plugins"); fwupd_security_attr_set_name (attr, "fwupd plugins"); @@ -5048,11 +5048,11 @@ fu_engine_add_security_attrs_tainted (FuEngine *self, GPtrArray *attrs) } else { fwupd_security_attr_add_flag (attr, FWUPD_SECURITY_ATTR_FLAG_SUCCESS); } - g_ptr_array_add (attrs, attr); + fu_security_attrs_append (attrs, attr); } static void -fu_engine_add_security_attrs_supported (FuEngine *self, GPtrArray *attrs) +fu_engine_add_security_attrs_supported (FuEngine *self, FuSecurityAttrs *attrs) { FwupdRelease *rel_current = NULL; FwupdRelease *rel_newest = NULL; @@ -5066,7 +5066,7 @@ fu_engine_add_security_attrs_supported (FuEngine *self, GPtrArray *attrs) attr_u = fwupd_security_attr_new ("org.fwupd.Hsi.Updates"); fwupd_security_attr_add_flag (attr_u, FWUPD_SECURITY_ATTR_FLAG_RUNTIME_UPDATES); fwupd_security_attr_set_name (attr_u, "Firmware Updates"); - g_ptr_array_add (attrs, attr_u); + fu_security_attrs_append (attrs, attr_u); /* get device */ device = fu_device_list_get_by_guid (self->device_list, @@ -5100,7 +5100,7 @@ fu_engine_add_security_attrs_supported (FuEngine *self, GPtrArray *attrs) attr_a = fwupd_security_attr_new ("org.fwupd.Hsi.Attestation"); fwupd_security_attr_set_name (attr_a, "Firmware Attestation"); fwupd_security_attr_add_flag (attr_a, FWUPD_SECURITY_ATTR_FLAG_RUNTIME_ATTESTATION); - g_ptr_array_add (attrs, attr_a); + fu_security_attrs_append (attrs, attr_a); if (releases != NULL) { for (guint i = 0; i < releases->len; i++) { FwupdRelease *rel_tmp = g_ptr_array_index (releases, i); @@ -5119,38 +5119,20 @@ fu_engine_add_security_attrs_supported (FuEngine *self, GPtrArray *attrs) } } -GPtrArray * +FuSecurityAttrs * fu_engine_get_host_security_attrs (FuEngine *self, GError **error) { GPtrArray *plugins = fu_plugin_list_get_all (self->plugin_list); - g_autoptr(GPtrArray) attrs = NULL; + g_autoptr(FuSecurityAttrs) attrs = fu_security_attrs_new (); /* built in */ - attrs = g_ptr_array_new_with_free_func ((GDestroyNotify) g_object_unref); fu_engine_add_security_attrs_tainted (self, attrs); fu_engine_add_security_attrs_supported (self, attrs); /* call into plugins */ for (guint j = 0; j < plugins->len; j++) { FuPlugin *plugin_tmp = g_ptr_array_index (plugins, j); - g_autoptr(GError) error_local = NULL; - if (!fu_plugin_runner_add_security_attrs (plugin_tmp, - attrs, - &error_local)) { - FwupdSecurityAttr *attr; - g_autofree gchar *appstream_id = NULL; - g_autofree gchar *msg = NULL; - appstream_id = g_strdup_printf ("org.fwupd.plugin.%s", - fu_plugin_get_name (plugin_tmp)); - msg = g_strdup_printf ("Failed to add HSI attribute: %s", - error_local->message); - attr = fwupd_security_attr_new (appstream_id); - fwupd_security_attr_set_name (attr, "fwupd"); - fwupd_security_attr_add_flag (attr, FWUPD_SECURITY_ATTR_FLAG_RUNTIME_ISSUE); - fwupd_security_attr_set_result (attr, msg); - g_ptr_array_add (attrs, attr); - continue; - } + fu_plugin_runner_add_security_attrs (plugin_tmp, attrs); } /* set the obsoletes flag for each attr */ @@ -5165,10 +5147,13 @@ fu_engine_get_host_security_id (FuEngine *self) /* rebuild */ if (!self->host_security_id_valid) { - g_autoptr(GPtrArray) attrs = fu_engine_get_host_security_attrs (self, NULL); + g_autoptr(FuSecurityAttrs) attrs = NULL; g_free (self->host_security_id); - self->host_security_id = fu_security_attrs_calculate_hsi (attrs); + self->host_security_id = NULL; self->host_security_id_valid = TRUE; + attrs = fu_engine_get_host_security_attrs (self, NULL); + if (attrs != NULL) + self->host_security_id = fu_security_attrs_calculate_hsi (attrs); } return self->host_security_id; diff --git a/src/fu-engine.h b/src/fu-engine.h index 028d778d2..f8c8205d8 100644 --- a/src/fu-engine.h +++ b/src/fu-engine.h @@ -16,6 +16,7 @@ #include "fu-common.h" #include "fu-install-task.h" #include "fu-plugin.h" +#include "fu-security-attrs.h" #define FU_TYPE_ENGINE (fu_engine_get_type ()) G_DECLARE_FINAL_TYPE (FuEngine, fu_engine, FU, ENGINE, GObject) @@ -83,7 +84,7 @@ GPtrArray *fu_engine_get_upgrades (FuEngine *self, FwupdDevice *fu_engine_get_results (FuEngine *self, const gchar *device_id, GError **error); -GPtrArray *fu_engine_get_host_security_attrs (FuEngine *self, +FuSecurityAttrs *fu_engine_get_host_security_attrs (FuEngine *self, GError **error); gboolean fu_engine_clear_results (FuEngine *self, const gchar *device_id, diff --git a/src/fu-main.c b/src/fu-main.c index c8d2b055d..0360e06c3 100644 --- a/src/fu-main.c +++ b/src/fu-main.c @@ -30,6 +30,7 @@ #include "fu-device-private.h" #include "fu-engine.h" #include "fu-install-task.h" +#include "fu-security-attrs-private.h" #ifndef HAVE_POLKIT_0_114 #pragma clang diagnostic push @@ -255,22 +256,6 @@ fu_main_device_array_to_variant (FuMainPrivate *priv, const gchar *sender, return g_variant_new ("(aa{sv})", &builder); } -static GVariant * -fu_main_security_attr_array_to_variant (FuMainPrivate *priv, GPtrArray *attrs) -{ - GVariantBuilder builder; - - g_return_val_if_fail (attrs->len > 0, NULL); - g_variant_builder_init (&builder, G_VARIANT_TYPE_ARRAY); - - for (guint i = 0; i < attrs->len; i++) { - FwupdSecurityAttr *security_attr = g_ptr_array_index (attrs, i); - GVariant *tmp = fwupd_security_attr_to_variant (security_attr); - g_variant_builder_add_value (&builder, tmp); - } - return g_variant_new ("(aa{sv})", &builder); -} - static GVariant * fu_main_release_array_to_variant (GPtrArray *results) { @@ -1005,14 +990,14 @@ fu_main_daemon_method_call (GDBusConnection *connection, const gchar *sender, return; } if (g_strcmp0 (method_name, "GetHostSecurityAttrs") == 0) { - g_autoptr(GPtrArray) attrs = NULL; + g_autoptr(FuSecurityAttrs) attrs = NULL; g_debug ("Called %s()", method_name); attrs = fu_engine_get_host_security_attrs (priv->engine, &error); if (attrs == NULL) { g_dbus_method_invocation_return_gerror (invocation, error); return; } - val = fu_main_security_attr_array_to_variant (priv, attrs); + val = fu_security_attrs_to_variant (attrs); g_dbus_method_invocation_return_value (invocation, val); return; } diff --git a/src/fu-security-attrs.c b/src/fu-security-attrs.c deleted file mode 100644 index ff862f8cd..000000000 --- a/src/fu-security-attrs.c +++ /dev/null @@ -1,115 +0,0 @@ -/* - * Copyright (C) 2020 Richard Hughes - * - * SPDX-License-Identifier: LGPL-2.1+ - */ - -#include "config.h" - -#include - -#include "fwupd-security-attr.h" - -#include "fu-security-attrs.h" - -gchar * -fu_security_attrs_calculate_hsi (GPtrArray *attrs) -{ - guint hsi_number = 0; - FwupdSecurityAttrFlags flags = FWUPD_SECURITY_ATTR_FLAG_NONE; - GString *str = g_string_new ("HSI:"); - const FwupdSecurityAttrFlags hpi_suffixes[] = { - FWUPD_SECURITY_ATTR_FLAG_RUNTIME_UPDATES, - FWUPD_SECURITY_ATTR_FLAG_RUNTIME_ATTESTATION, - FWUPD_SECURITY_ATTR_FLAG_RUNTIME_ISSUE, - FWUPD_SECURITY_ATTR_FLAG_NONE, - }; - - /* find the highest HSI number where there are no failures and at least - * one success */ - for (guint j = 1; j <= FWUPD_SECURITY_ATTR_LEVEL_LAST; j++) { - gboolean success_cnt = 0; - gboolean failure_cnt = 0; - for (guint i = 0; i < attrs->len; i++) { - FwupdSecurityAttr *attr = g_ptr_array_index (attrs, i); - if (fwupd_security_attr_get_level (attr) != j) - continue; - if (fwupd_security_attr_has_flag (attr, FWUPD_SECURITY_ATTR_FLAG_SUCCESS)) - success_cnt++; - else if (!fwupd_security_attr_has_flag (attr, FWUPD_SECURITY_ATTR_FLAG_OBSOLETED)) - failure_cnt++; - } - - /* abort */ - if (failure_cnt > 0) { - hsi_number = j - 1; - break; - } - - /* we matched at least one thing on this level */ - if (success_cnt > 0) - hsi_number = j; - } - - /* get a logical OR of the runtime flags */ - for (guint i = 0; i < attrs->len; i++) { - FwupdSecurityAttr *attr = g_ptr_array_index (attrs, i); - if (fwupd_security_attr_has_flag (attr, FWUPD_SECURITY_ATTR_FLAG_OBSOLETED)) - continue; - /* positive things */ - if (fwupd_security_attr_has_flag (attr, FWUPD_SECURITY_ATTR_FLAG_RUNTIME_UPDATES) || - fwupd_security_attr_has_flag (attr, FWUPD_SECURITY_ATTR_FLAG_RUNTIME_ATTESTATION)) { - if (!fwupd_security_attr_has_flag (attr, FWUPD_SECURITY_ATTR_FLAG_SUCCESS)) - continue; - } - /* negative things */ - if (fwupd_security_attr_has_flag (attr, FWUPD_SECURITY_ATTR_FLAG_RUNTIME_ISSUE)) { - if (fwupd_security_attr_has_flag (attr, FWUPD_SECURITY_ATTR_FLAG_SUCCESS)) - continue; - } - flags |= fwupd_security_attr_get_flags (attr); - } - - g_string_append_printf (str, "%u", hsi_number); - if (flags & (FWUPD_SECURITY_ATTR_FLAG_RUNTIME_UPDATES | - FWUPD_SECURITY_ATTR_FLAG_RUNTIME_ATTESTATION | - FWUPD_SECURITY_ATTR_FLAG_RUNTIME_ISSUE)) { - g_string_append (str, "+"); - for (guint j = 0; hpi_suffixes[j] != FWUPD_SECURITY_ATTR_FLAG_NONE; j++) { - if (flags & hpi_suffixes[j]) - g_string_append (str, fwupd_security_attr_flag_to_suffix (hpi_suffixes[j])); - } - } - return g_string_free (str, FALSE); -} - -void -fu_security_attrs_depsolve (GPtrArray *attrs) -{ - g_autoptr(GHashTable) attrs_by_id = NULL; - - /* make hash of ID -> object */ - attrs_by_id = g_hash_table_new (g_str_hash, g_str_equal); - for (guint i = 0; i < attrs->len; i++) { - FwupdSecurityAttr *attr = g_ptr_array_index (attrs, i); - g_hash_table_insert (attrs_by_id, - (gpointer) fwupd_security_attr_get_appstream_id (attr), - (gpointer) attr); - } - - /* set flat where required */ - for (guint i = 0; i < attrs->len; i++) { - FwupdSecurityAttr *attr = g_ptr_array_index (attrs, i); - GPtrArray *obsoletes = fwupd_security_attr_get_obsoletes (attr); - for (guint j = 0; j < obsoletes->len; j++) { - const gchar *obsolete = g_ptr_array_index (obsoletes, j); - FwupdSecurityAttr *attr_tmp = g_hash_table_lookup (attrs_by_id, obsolete); - if (attr_tmp != NULL) { - g_debug ("security attr %s obsoleted by %s", obsolete, - fwupd_security_attr_get_appstream_id (attr)); - fwupd_security_attr_add_flag (attr_tmp, - FWUPD_SECURITY_ATTR_FLAG_OBSOLETED); - } - } - } -} diff --git a/src/fu-security-attrs.h b/src/fu-security-attrs.h deleted file mode 100644 index a0ab3ec18..000000000 --- a/src/fu-security-attrs.h +++ /dev/null @@ -1,12 +0,0 @@ -/* - * Copyright (C) 2020 Richard Hughes - * - * SPDX-License-Identifier: LGPL-2.1+ - */ - -#pragma once - -#include - -gchar *fu_security_attrs_calculate_hsi (GPtrArray *attrs); -void fu_security_attrs_depsolve (GPtrArray *attrs); diff --git a/src/fu-self-test.c b/src/fu-self-test.c index 29c104de7..6f0db881e 100644 --- a/src/fu-self-test.c +++ b/src/fu-self-test.c @@ -152,75 +152,6 @@ fu_engine_generate_md_func (gconstpointer user_data) g_assert_cmpstr (tmp, ==, NULL); } -static void -fu_plugin_hsi_func (gconstpointer user_data) -{ - FwupdSecurityAttr *attr; - g_autofree gchar *hsi1 = NULL; - g_autofree gchar *hsi2 = NULL; - g_autofree gchar *hsi3 = NULL; - g_autofree gchar *hsi4 = NULL; - g_autofree gchar *hsi5 = NULL; - g_autofree gchar *hsi6 = NULL; - g_autofree gchar *hsi7 = NULL; - g_autoptr(FuEngine) engine = fu_engine_new (FU_APP_FLAGS_NONE); - g_autoptr(GPtrArray) attrs = NULL; - - /* no attrs */ - attrs = g_ptr_array_new_with_free_func ((GDestroyNotify) g_object_unref); - hsi1 = fu_security_attrs_calculate_hsi (attrs); - g_assert_cmpstr (hsi1, ==, "HSI:0"); - - /* just success from HSI:1 */ - attr = fwupd_security_attr_new ("org.fwupd.Hsi.BIOSWE"); - fwupd_security_attr_set_level (attr, 1); - fwupd_security_attr_add_flag (attr, FWUPD_SECURITY_ATTR_FLAG_SUCCESS); - g_ptr_array_add (attrs, attr); - hsi2 = fu_security_attrs_calculate_hsi (attrs); - g_assert_cmpstr (hsi2, ==, "HSI:1"); - - /* add failed from HSI:2, so still HSI:1 */ - attr = fwupd_security_attr_new ("org.fwupd.Hsi.PRX"); - fwupd_security_attr_set_level (attr, 2); - g_ptr_array_add (attrs, attr); - hsi3 = fu_security_attrs_calculate_hsi (attrs); - g_assert_cmpstr (hsi3, ==, "HSI:1"); - - /* add attr from HSI:3, obsoleting the failure */ - attr = fwupd_security_attr_new ("org.fwupd.Hsi.BIOSGuard"); - fwupd_security_attr_set_level (attr, 3); - fwupd_security_attr_add_flag (attr, FWUPD_SECURITY_ATTR_FLAG_SUCCESS); - fwupd_security_attr_add_obsolete (attr, "org.fwupd.Hsi.PRX"); - g_ptr_array_add (attrs, attr); - fu_security_attrs_depsolve (attrs); - hsi4 = fu_security_attrs_calculate_hsi (attrs); - g_assert_cmpstr (hsi4, ==, "HSI:3"); - - /* add taint that was fine */ - attr = fwupd_security_attr_new ("org.fwupd.Hsi.PluginsTainted"); - fwupd_security_attr_add_flag (attr, FWUPD_SECURITY_ATTR_FLAG_SUCCESS); - fwupd_security_attr_add_flag (attr, FWUPD_SECURITY_ATTR_FLAG_RUNTIME_ISSUE); - g_ptr_array_add (attrs, attr); - hsi5 = fu_security_attrs_calculate_hsi (attrs); - g_assert_cmpstr (hsi5, ==, "HSI:3"); - - /* add updates and attestation */ - attr = fwupd_security_attr_new ("org.fwupd.Hsi.LVFS"); - fwupd_security_attr_add_flag (attr, FWUPD_SECURITY_ATTR_FLAG_RUNTIME_UPDATES); - fwupd_security_attr_add_flag (attr, FWUPD_SECURITY_ATTR_FLAG_RUNTIME_ATTESTATION); - fwupd_security_attr_add_flag (attr, FWUPD_SECURITY_ATTR_FLAG_SUCCESS); - g_ptr_array_add (attrs, attr); - hsi6 = fu_security_attrs_calculate_hsi (attrs); - g_assert_cmpstr (hsi6, ==, "HSI:3+UA"); - - /* add issue that was uncool */ - attr = fwupd_security_attr_new ("org.fwupd.Hsi.Swap"); - fwupd_security_attr_add_flag (attr, FWUPD_SECURITY_ATTR_FLAG_RUNTIME_ISSUE); - g_ptr_array_add (attrs, attr); - hsi7 = fu_security_attrs_calculate_hsi (attrs); - g_assert_cmpstr (hsi7, ==, "HSI:3+UA!"); -} - static void fu_plugin_hash_func (gconstpointer user_data) { @@ -3050,8 +2981,6 @@ main (int argc, char **argv) g_test_add_data_func ("/fwupd/progressbar", self, fu_progressbar_func); } - g_test_add_data_func ("/fwupd/plugin{hsi}", self, - fu_plugin_hsi_func); g_test_add_data_func ("/fwupd/plugin{build-hash}", self, fu_plugin_hash_func); g_test_add_data_func ("/fwupd/plugin{module}", self, diff --git a/src/fu-tool.c b/src/fu-tool.c index 52ed222f0..85f43a0ce 100644 --- a/src/fu-tool.c +++ b/src/fu-tool.c @@ -26,6 +26,7 @@ #include "fu-history.h" #include "fu-plugin-private.h" #include "fu-progressbar.h" +#include "fu-security-attrs-private.h" #include "fu-smbios-private.h" #include "fu-util-common.h" #include "fu-debug.h" @@ -1940,7 +1941,8 @@ fu_util_get_remotes (FuUtilPrivate *priv, gchar **values, GError **error) static gboolean fu_util_security (FuUtilPrivate *priv, gchar **values, GError **error) { - g_autoptr(GPtrArray) attrs = NULL; + g_autoptr(FuSecurityAttrs) attrs = NULL; + g_autoptr(GPtrArray) items = NULL; g_autofree gchar *str = NULL; /* not ready yet */ @@ -1964,7 +1966,8 @@ fu_util_security (FuUtilPrivate *priv, gchar **values, GError **error) attrs = fu_engine_get_host_security_attrs (priv->engine, error); if (attrs == NULL) return FALSE; - str = fu_util_security_attrs_to_string (attrs); + items = fu_security_attrs_get_all (attrs); + str = fu_util_security_attrs_to_string (items); g_print ("%s\n", str); return TRUE; } diff --git a/src/meson.build b/src/meson.build index 95bdc5967..c1ed9a979 100644 --- a/src/meson.build +++ b/src/meson.build @@ -92,6 +92,7 @@ fwupdoffline = executable( giounix, gudev, gusb, + libjsonglib, libxmlb, soup, sqlite, @@ -131,7 +132,6 @@ fwupdtool = executable( 'fu-plugin-list.c', 'fu-progressbar.c', 'fu-remote-list.c', - 'fu-security-attrs.c', 'fu-util-common.c', systemd_src ], @@ -230,7 +230,6 @@ executable( 'fu-main.c', 'fu-plugin-list.c', 'fu-remote-list.c', - 'fu-security-attrs.c', systemd_src ], include_directories : [ @@ -287,7 +286,6 @@ if get_option('tests') 'fu-plugin-list.c', 'fu-progressbar.c', 'fu-remote-list.c', - 'fu-security-attrs.c', 'fu-self-test.c', systemd_src ], From c1eda7d516376326105fb67cd055f0e318504f12 Mon Sep 17 00:00:00 2001 From: Richard Hughes Date: Fri, 1 May 2020 15:51:44 +0100 Subject: [PATCH 050/607] Add many new plugins to support for the Host Security ID MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The HSI specification is currently incomplete and in active development. Sample output for my Lenovo P50 Laptop: Host Security ID: HSI:2+UA! HSI-1 ✔ UEFI dbx: OK ✔ TPM: v2.0 ✔ SPI: Write disabled ✔ SPI: Lock enabled ✔ SPI: SMM required ✔ UEFI Secure Boot: Enabled HSI-2 ✔ TPM Reconstruction: Matched PCR0 reading HSI-3 ✘ Linux Kernel S3 Sleep: Deep sleep available HSI-4 ✘ Intel CET: Unavailable Runtime Suffix -U ✔ Firmware Updates: Newest release is 8 months old Runtime Suffix -A ✔ Firmware Attestation: OK Runtime Suffix -! ✔ fwupd plugins: OK ✔ Linux Kernel: OK ✔ Linux Kernel: Locked down ✘ Linux Swap: Not encrypted --- contrib/fwupd.spec.in | 6 + plugins/acpi-dmar/README.md | 8 + plugins/acpi-dmar/fu-acpi-dmar.c | 81 ++++++++++ plugins/acpi-dmar/fu-acpi-dmar.h | 16 ++ plugins/acpi-dmar/fu-plugin-acpi-dmar.c | 61 ++++++++ plugins/acpi-dmar/fu-self-test.c | 65 ++++++++ plugins/acpi-dmar/meson.build | 51 +++++++ plugins/acpi-dmar/tests/DMAR | Bin 0 -> 168 bytes plugins/acpi-dmar/tests/DMAR-OPTOUT | Bin 0 -> 168 bytes plugins/acpi-facp/README.md | 8 + plugins/acpi-facp/fu-acpi-facp.c | 54 +++++++ plugins/acpi-facp/fu-acpi-facp.h | 16 ++ plugins/acpi-facp/fu-plugin-acpi-facp.c | 57 +++++++ plugins/acpi-facp/fu-self-test.c | 64 ++++++++ plugins/acpi-facp/meson.build | 51 +++++++ plugins/acpi-facp/tests/FACP | Bin 0 -> 244 bytes plugins/acpi-facp/tests/FACP-S2I | Bin 0 -> 276 bytes plugins/cpu/fu-plugin-cpu.c | 40 ++++- plugins/linux-lockdown/README.md | 8 + .../linux-lockdown/fu-plugin-linux-lockdown.c | 94 ++++++++++++ plugins/linux-lockdown/meson.build | 23 +++ plugins/linux-sleep/README.md | 8 + plugins/linux-sleep/fu-plugin-linux-sleep.c | 47 ++++++ plugins/linux-sleep/meson.build | 23 +++ plugins/linux-spi-lpc/README.md | 8 + .../linux-spi-lpc/fu-plugin-linux-spi-lpc.c | 139 ++++++++++++++++++ plugins/linux-spi-lpc/meson.build | 23 +++ plugins/linux-swap/README.md | 2 +- plugins/linux-swap/fu-plugin-linux-swap.c | 76 +++++++--- plugins/linux-tainted/README.md | 8 + .../linux-tainted/fu-plugin-linux-tainted.c | 92 ++++++++++++ plugins/linux-tainted/meson.build | 23 +++ plugins/meson.build | 6 + plugins/tpm-eventlog/fu-plugin-tpm-eventlog.c | 19 ++- plugins/tpm/fu-plugin-tpm.c | 42 ++++++ plugins/tpm/fu-tpm-device.c | 19 ++- plugins/tpm/fu-tpm-device.h | 2 + plugins/uefi-dbx/README.md | 2 +- plugins/uefi-dbx/fu-plugin-uefi-dbx.c | 77 ++++++---- plugins/uefi/fu-plugin-uefi.c | 22 +++ 40 files changed, 1279 insertions(+), 62 deletions(-) create mode 100644 plugins/acpi-dmar/README.md create mode 100644 plugins/acpi-dmar/fu-acpi-dmar.c create mode 100644 plugins/acpi-dmar/fu-acpi-dmar.h create mode 100644 plugins/acpi-dmar/fu-plugin-acpi-dmar.c create mode 100644 plugins/acpi-dmar/fu-self-test.c create mode 100644 plugins/acpi-dmar/meson.build create mode 100644 plugins/acpi-dmar/tests/DMAR create mode 100644 plugins/acpi-dmar/tests/DMAR-OPTOUT create mode 100644 plugins/acpi-facp/README.md create mode 100644 plugins/acpi-facp/fu-acpi-facp.c create mode 100644 plugins/acpi-facp/fu-acpi-facp.h create mode 100644 plugins/acpi-facp/fu-plugin-acpi-facp.c create mode 100644 plugins/acpi-facp/fu-self-test.c create mode 100644 plugins/acpi-facp/meson.build create mode 100644 plugins/acpi-facp/tests/FACP create mode 100644 plugins/acpi-facp/tests/FACP-S2I create mode 100644 plugins/linux-lockdown/README.md create mode 100644 plugins/linux-lockdown/fu-plugin-linux-lockdown.c create mode 100644 plugins/linux-lockdown/meson.build create mode 100644 plugins/linux-sleep/README.md create mode 100644 plugins/linux-sleep/fu-plugin-linux-sleep.c create mode 100644 plugins/linux-sleep/meson.build create mode 100644 plugins/linux-spi-lpc/README.md create mode 100644 plugins/linux-spi-lpc/fu-plugin-linux-spi-lpc.c create mode 100644 plugins/linux-spi-lpc/meson.build create mode 100644 plugins/linux-tainted/README.md create mode 100644 plugins/linux-tainted/fu-plugin-linux-tainted.c create mode 100644 plugins/linux-tainted/meson.build diff --git a/contrib/fwupd.spec.in b/contrib/fwupd.spec.in index b4a2bfb29..78f3777f8 100644 --- a/contrib/fwupd.spec.in +++ b/contrib/fwupd.spec.in @@ -329,6 +329,8 @@ mkdir -p --mode=0700 $RPM_BUILD_ROOT%{_localstatedir}/lib/fwupd/gnupg /usr/lib/udev/rules.d/*.rules /usr/lib/systemd/system-shutdown/fwupd.shutdown %dir %{_libdir}/fwupd-plugins-3 +%{_libdir}/fwupd-plugins-3/libfu_plugin_acpi_dmar.so +%{_libdir}/fwupd-plugins-3/libfu_plugin_acpi_facp.so %{_libdir}/fwupd-plugins-3/libfu_plugin_altos.so %{_libdir}/fwupd-plugins-3/libfu_plugin_amt.so %{_libdir}/fwupd-plugins-3/libfu_plugin_ata.so @@ -352,7 +354,11 @@ mkdir -p --mode=0700 $RPM_BUILD_ROOT%{_localstatedir}/lib/fwupd/gnupg %endif %{_libdir}/fwupd-plugins-3/libfu_plugin_fresco_pd.so %{_libdir}/fwupd-plugins-3/libfu_plugin_jabra.so +%{_libdir}/fwupd-plugins-3/libfu_plugin_linux_lockdown.so +%{_libdir}/fwupd-plugins-3/libfu_plugin_linux_sleep.so +%{_libdir}/fwupd-plugins-3/libfu_plugin_linux_spi_lpc.so %{_libdir}/fwupd-plugins-3/libfu_plugin_linux_swap.so +%{_libdir}/fwupd-plugins-3/libfu_plugin_linux_tainted.so %if 0%{?have_modem_manager} %{_libdir}/fwupd-plugins-3/libfu_plugin_modem_manager.so %endif diff --git a/plugins/acpi-dmar/README.md b/plugins/acpi-dmar/README.md new file mode 100644 index 000000000..da544cb50 --- /dev/null +++ b/plugins/acpi-dmar/README.md @@ -0,0 +1,8 @@ +DMA Protection +============== + +Introduction +------------ + +This plugin checks if DMA remapping for Thunderbolt devices is available. The +result will be stored in an security attribute for HSI. diff --git a/plugins/acpi-dmar/fu-acpi-dmar.c b/plugins/acpi-dmar/fu-acpi-dmar.c new file mode 100644 index 000000000..e972d0e65 --- /dev/null +++ b/plugins/acpi-dmar/fu-acpi-dmar.c @@ -0,0 +1,81 @@ +/* + * Copyright (C) 2020 Richard Hughes + * + * SPDX-License-Identifier: LGPL-2.1+ + */ + +#include "config.h" + +#include + +#include "fu-common.h" +#include "fu-acpi-dmar.h" + +struct _FuAcpiDmar { + GObject parent_instance; + gboolean opt_in; +}; + +G_DEFINE_TYPE (FuAcpiDmar, fu_acpi_dmar, G_TYPE_OBJECT) + +#define DMAR_DMA_CTRL_PLATFORM_OPT_IN_FLAG 2 + +FuAcpiDmar * +fu_acpi_dmar_new (GBytes *blob, GError **error) +{ + FuAcpiDmar *self = g_object_new (FU_TYPE_ACPI_DMAR, NULL); + gchar creator_id[5] = { '\0' }; + gchar oem_table_id[9] = { '\0' }; + gchar signature[5] = { '\0' }; + gsize bufsz = 0; + guint8 flags = 0; + const guint8 *buf = g_bytes_get_data (blob, &bufsz); + + /* parse table */ + if (!fu_memcpy_safe ((guint8 *) signature, sizeof(signature), 0x0, /* dst */ + buf, bufsz, 0x00, /* src */ + sizeof(signature) - 1, error)) + return FALSE; + if (strcmp (signature, "DMAR") != 0) { + g_set_error (error, + G_IO_ERROR, + G_IO_ERROR_NOT_SUPPORTED, + "Not a DMAR table, got %s", + signature); + return FALSE; + } + if (!fu_memcpy_safe ((guint8 *) oem_table_id, sizeof(oem_table_id), 0x0,/* dst */ + buf, bufsz, 0x10, /* src */ + sizeof(oem_table_id) - 1, error)) + return FALSE; + g_debug ("OemTableId: %s", oem_table_id); + if (!fu_memcpy_safe ((guint8 *) creator_id, sizeof(creator_id), 0x0, /* dst */ + buf, bufsz, 0x1c, /* src */ + sizeof(creator_id) - 1, error)) + return FALSE; + g_debug ("CreatorId: %s", creator_id); + if (!fu_memcpy_safe (&flags, sizeof(flags), 0x0, /* dst */ + buf, bufsz, 0x25, /* src */ + sizeof(flags), error)) + return FALSE; + g_debug ("Flags: 0x%02x", flags); + self->opt_in = (flags & DMAR_DMA_CTRL_PLATFORM_OPT_IN_FLAG) > 0; + return self; +} + +gboolean +fu_acpi_dmar_get_opt_in (FuAcpiDmar *self) +{ + g_return_val_if_fail (FU_IS_ACPI_DMAR (self), FALSE); + return self->opt_in; +} + +static void +fu_acpi_dmar_class_init (FuAcpiDmarClass *klass) +{ +} + +static void +fu_acpi_dmar_init (FuAcpiDmar *self) +{ +} diff --git a/plugins/acpi-dmar/fu-acpi-dmar.h b/plugins/acpi-dmar/fu-acpi-dmar.h new file mode 100644 index 000000000..57dcc0f8e --- /dev/null +++ b/plugins/acpi-dmar/fu-acpi-dmar.h @@ -0,0 +1,16 @@ +/* + * Copyright (C) 2020 Richard Hughes + * + * SPDX-License-Identifier: LGPL-2.1+ + */ + +#pragma once + +#include + +#define FU_TYPE_ACPI_DMAR (fu_acpi_dmar_get_type ()) +G_DECLARE_FINAL_TYPE (FuAcpiDmar, fu_acpi_dmar, FU, ACPI_DMAR, GObject) + +FuAcpiDmar *fu_acpi_dmar_new (GBytes *blob, + GError **error); +gboolean fu_acpi_dmar_get_opt_in (FuAcpiDmar *self); diff --git a/plugins/acpi-dmar/fu-plugin-acpi-dmar.c b/plugins/acpi-dmar/fu-plugin-acpi-dmar.c new file mode 100644 index 000000000..02b42e330 --- /dev/null +++ b/plugins/acpi-dmar/fu-plugin-acpi-dmar.c @@ -0,0 +1,61 @@ +/* + * Copyright (C) 2020 Richard Hughes + * + * SPDX-License-Identifier: LGPL-2.1+ + */ + +#include "config.h" + +#include "fu-plugin-vfuncs.h" +#include "fu-hash.h" +#include "fu-acpi-dmar.h" + +void +fu_plugin_init (FuPlugin *plugin) +{ + fu_plugin_set_build_hash (plugin, FU_BUILD_HASH); +} + +void +fu_plugin_add_security_attrs (FuPlugin *plugin, FuSecurityAttrs *attrs) +{ + g_autofree gchar *fn = NULL; + g_autofree gchar *path = NULL; + g_autoptr(FuAcpiDmar) dmar = NULL; + g_autoptr(FwupdSecurityAttr) attr = NULL; + g_autoptr(GBytes) blob = NULL; + g_autoptr(GError) error_local = NULL; + + /* only Intel */ + if (!fu_common_is_cpu_intel ()) + return; + + /* create attr */ + attr = fwupd_security_attr_new ("org.uefi.ACPI.Dmar"); + fwupd_security_attr_set_level (attr, FWUPD_SECURITY_ATTR_LEVEL_THEORETICAL); + fwupd_security_attr_set_name (attr, "Pre-boot kernel DMA protection"); + fu_security_attrs_append (attrs, attr); + + /* load DMAR table */ + path = fu_common_get_path (FU_PATH_KIND_ACPI_TABLES); + fn = g_build_filename (path, "DMAR", NULL); + blob = fu_common_get_contents_bytes (fn, &error_local); + if (blob == NULL) { + g_warning ("failed to load %s: %s", fn, error_local->message); + fwupd_security_attr_set_result (attr, "Could not load DMAR"); + return; + } + dmar = fu_acpi_dmar_new (blob, &error_local); + if (dmar == NULL) { + g_warning ("failed to parse %s: %s", fn, error_local->message); + fwupd_security_attr_set_result (attr, "Could not parse DMAR"); + return; + } + if (!fu_acpi_dmar_get_opt_in (dmar)) { + fwupd_security_attr_set_result (attr, "Unavailable"); + return; + } + + /* success */ + fwupd_security_attr_add_flag (attr, FWUPD_SECURITY_ATTR_FLAG_SUCCESS); +} diff --git a/plugins/acpi-dmar/fu-self-test.c b/plugins/acpi-dmar/fu-self-test.c new file mode 100644 index 000000000..aa9bf7f2a --- /dev/null +++ b/plugins/acpi-dmar/fu-self-test.c @@ -0,0 +1,65 @@ +/* + * Copyright (C) 2020 Richard Hughes + * + * SPDX-License-Identifier: LGPL-2.1+ + */ + +#include "config.h" + +#include + +#include "fu-common.h" + +#include "fu-acpi-dmar.h" + +static void +fu_acpi_dmar_opt_in_func (void) +{ + g_autoptr(FuAcpiDmar) dmar = NULL; + g_autoptr(GError) error = NULL; + g_autoptr(GBytes) blob = NULL; + g_autofree gchar *fn = NULL; + + fn = g_build_filename (TESTDATADIR, "DMAR", NULL); + blob = fu_common_get_contents_bytes (fn, &error); + g_assert_no_error (error); + g_assert_nonnull (blob); + dmar = fu_acpi_dmar_new (blob, &error); + g_assert_no_error (error); + g_assert_nonnull (dmar); + g_assert_true (fu_acpi_dmar_get_opt_in (dmar)); +} + +static void +fu_acpi_dmar_opt_out_func (void) +{ + g_autoptr(FuAcpiDmar) dmar = NULL; + g_autoptr(GError) error = NULL; + g_autoptr(GBytes) blob = NULL; + g_autofree gchar *fn = NULL; + + fn = g_build_filename (TESTDATADIR, "DMAR-OPTOUT", NULL); + blob = fu_common_get_contents_bytes (fn, &error); + g_assert_no_error (error); + g_assert_nonnull (blob); + dmar = fu_acpi_dmar_new (blob, &error); + g_assert_no_error (error); + g_assert_nonnull (dmar); + g_assert_false (fu_acpi_dmar_get_opt_in (dmar)); +} + +int +main (int argc, char **argv) +{ + g_test_init (&argc, &argv, NULL); + + /* 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 ("/acpi-dmar/opt-in", fu_acpi_dmar_opt_in_func); + g_test_add_func ("/acpi-dmar/opt-out", fu_acpi_dmar_opt_out_func); + + return g_test_run (); +} diff --git a/plugins/acpi-dmar/meson.build b/plugins/acpi-dmar/meson.build new file mode 100644 index 000000000..95df341ee --- /dev/null +++ b/plugins/acpi-dmar/meson.build @@ -0,0 +1,51 @@ +cargs = ['-DG_LOG_DOMAIN="FuPluginAcpiDmar"'] + +shared_module('fu_plugin_acpi_dmar', + fu_hash, + sources : [ + 'fu-plugin-acpi-dmar.c', + 'fu-acpi-dmar.c', + ], + include_directories : [ + root_incdir, + fwupd_incdir, + fwupdplugin_incdir, + ], + install : true, + install_dir: plugin_dir, + link_with : [ + fwupd, + fwupdplugin, + ], + c_args : cargs, + dependencies : [ + plugin_deps, + ], +) + +if get_option('tests') + testdatadir = join_paths(meson.current_source_dir(), 'tests') + cargs += '-DTESTDATADIR="' + testdatadir + '"' + e = executable( + 'acpi-dmar-self-test', + fu_hash, + sources : [ + 'fu-self-test.c', + 'fu-acpi-dmar.c', + ], + include_directories : [ + root_incdir, + fwupd_incdir, + fwupdplugin_incdir, + ], + dependencies : [ + plugin_deps, + ], + link_with : [ + fwupd, + fwupdplugin, + ], + c_args : cargs, + ) + test('acpi-dmar-self-test', e) +endif diff --git a/plugins/acpi-dmar/tests/DMAR b/plugins/acpi-dmar/tests/DMAR new file mode 100644 index 0000000000000000000000000000000000000000..0a64fc85e24b841fd88a3a7cfa3ad2e2d2410fd9 GIT binary patch literal 168 zcmZ?qbqrd;z`(#b-N)6>Kg>TQK-bUERY75bC<8-4h^sRbP)>~*NWg&vly&nTh{4DK zB0;JY7#KlJ0f;y=P@L(5JOc|@ULGi?0Fq^3_~7XeqW-`42GbDzA_#c~hA6Q7|N1x( H4Kp7Ay}T6x literal 0 HcmV?d00001 diff --git a/plugins/acpi-dmar/tests/DMAR-OPTOUT b/plugins/acpi-dmar/tests/DMAR-OPTOUT new file mode 100644 index 0000000000000000000000000000000000000000..d55cec2dff9990754e1ac3331f4b842ad50db544 GIT binary patch literal 168 zcmZ?qbqrd;z`(%B;OQ6Q>Z9P2nvVF7e;@`U2Z#i# z2ATl`0uXU#pg0qQ96JkGUXG2CK>;Moz!2aU52F722Y_jaei5Kv1&}ZZWP^zR|LgNX HG|YSenmQ5z literal 0 HcmV?d00001 diff --git a/plugins/acpi-facp/README.md b/plugins/acpi-facp/README.md new file mode 100644 index 000000000..5a4bd120d --- /dev/null +++ b/plugins/acpi-facp/README.md @@ -0,0 +1,8 @@ +ACPI FACP +========= + +Introduction +------------ + +This plugin checks if S2I sleep is available. The result will be stored in an +security attribute for HSI. diff --git a/plugins/acpi-facp/fu-acpi-facp.c b/plugins/acpi-facp/fu-acpi-facp.c new file mode 100644 index 000000000..0adc47271 --- /dev/null +++ b/plugins/acpi-facp/fu-acpi-facp.c @@ -0,0 +1,54 @@ +/* + * Copyright (C) 2020 Richard Hughes + * + * SPDX-License-Identifier: LGPL-2.1+ + */ + +#include "config.h" + +#include + +#include "fu-common.h" +#include "fu-acpi-facp.h" + +struct _FuAcpiFacp { + GObject parent_instance; + gboolean get_s2i; +}; + +G_DEFINE_TYPE (FuAcpiFacp, fu_acpi_facp, G_TYPE_OBJECT) + +#define LOW_POWER_S0_IDLE_CAPABLE (1 << 21) + +FuAcpiFacp * +fu_acpi_facp_new (GBytes *blob, GError **error) +{ + FuAcpiFacp *self = g_object_new (FU_TYPE_ACPI_FACP, NULL); + gsize bufsz = 0; + guint32 flags = 0; + const guint8 *buf = g_bytes_get_data (blob, &bufsz); + + /* parse table */ + if (!fu_common_read_uint32_safe (buf, bufsz, 0x70, &flags, G_LITTLE_ENDIAN, error)) + return FALSE; + g_debug ("Flags: 0x%04x", flags); + self->get_s2i = (flags & LOW_POWER_S0_IDLE_CAPABLE) > 0; + return self; +} + +gboolean +fu_acpi_facp_get_s2i (FuAcpiFacp *self) +{ + g_return_val_if_fail (FU_IS_ACPI_FACP (self), FALSE); + return self->get_s2i; +} + +static void +fu_acpi_facp_class_init (FuAcpiFacpClass *klass) +{ +} + +static void +fu_acpi_facp_init (FuAcpiFacp *self) +{ +} diff --git a/plugins/acpi-facp/fu-acpi-facp.h b/plugins/acpi-facp/fu-acpi-facp.h new file mode 100644 index 000000000..f143c233c --- /dev/null +++ b/plugins/acpi-facp/fu-acpi-facp.h @@ -0,0 +1,16 @@ +/* + * Copyright (C) 2020 Richard Hughes + * + * SPDX-License-Identifier: LGPL-2.1+ + */ + +#pragma once + +#include + +#define FU_TYPE_ACPI_FACP (fu_acpi_facp_get_type ()) +G_DECLARE_FINAL_TYPE (FuAcpiFacp, fu_acpi_facp, FU, ACPI_FACP, GObject) + +FuAcpiFacp *fu_acpi_facp_new (GBytes *blob, + GError **error); +gboolean fu_acpi_facp_get_s2i (FuAcpiFacp *self); diff --git a/plugins/acpi-facp/fu-plugin-acpi-facp.c b/plugins/acpi-facp/fu-plugin-acpi-facp.c new file mode 100644 index 000000000..2575a5802 --- /dev/null +++ b/plugins/acpi-facp/fu-plugin-acpi-facp.c @@ -0,0 +1,57 @@ +/* + * Copyright (C) 2020 Richard Hughes + * + * SPDX-License-Identifier: LGPL-2.1+ + */ + +#include "config.h" + +#include "fu-plugin-vfuncs.h" +#include "fu-hash.h" +#include "fu-acpi-facp.h" + +void +fu_plugin_init (FuPlugin *plugin) +{ + fu_plugin_set_build_hash (plugin, FU_BUILD_HASH); +} + +void +fu_plugin_add_security_attrs (FuPlugin *plugin, FuSecurityAttrs *attrs) +{ + g_autofree gchar *fn = NULL; + g_autofree gchar *path = NULL; + g_autoptr(FuAcpiFacp) facp = NULL; + g_autoptr(FwupdSecurityAttr) attr = NULL; + g_autoptr(GBytes) blob = NULL; + g_autoptr(GError) error_local = NULL; + + /* create attr */ + attr = fwupd_security_attr_new ("org.uefi.ACPI.Facp"); + fwupd_security_attr_set_level (attr, FWUPD_SECURITY_ATTR_LEVEL_THEORETICAL); + fwupd_security_attr_set_name (attr, "Suspend2Idle"); + fu_security_attrs_append (attrs, attr); + + /* load FACP table */ + path = fu_common_get_path (FU_PATH_KIND_ACPI_TABLES); + fn = g_build_filename (path, "FACP", NULL); + blob = fu_common_get_contents_bytes (fn, &error_local); + if (blob == NULL) { + g_warning ("failed to load %s: %s", fn, error_local->message); + fwupd_security_attr_set_result (attr, "Could not load FACP"); + return; + } + facp = fu_acpi_facp_new (blob, &error_local); + if (facp == NULL) { + g_warning ("failed to parse %s: %s", fn, error_local->message); + fwupd_security_attr_set_result (attr, "Could not parse FACP"); + return; + } + if (!fu_acpi_facp_get_s2i (facp)) { + fwupd_security_attr_set_result (attr, "Default set as suspend-to-ram (S3)"); + return; + } + + /* success */ + fwupd_security_attr_add_flag (attr, FWUPD_SECURITY_ATTR_FLAG_SUCCESS); +} diff --git a/plugins/acpi-facp/fu-self-test.c b/plugins/acpi-facp/fu-self-test.c new file mode 100644 index 000000000..2fd4ca43e --- /dev/null +++ b/plugins/acpi-facp/fu-self-test.c @@ -0,0 +1,64 @@ +/* + * Copyright (C) 2020 Richard Hughes + * + * SPDX-License-Identifier: LGPL-2.1+ + */ + +#include "config.h" + +#include + +#include "fu-common.h" + +#include "fu-acpi-facp.h" + +static void +fu_acpi_facp_s2i_disabled_func (void) +{ + g_autofree gchar *fn = NULL; + g_autoptr(FuAcpiFacp) facp = NULL; + g_autoptr(GBytes) blob = NULL; + g_autoptr(GError) error = NULL; + + fn = g_build_filename (TESTDATADIR, "FACP", NULL); + blob = fu_common_get_contents_bytes (fn, &error); + g_assert_no_error (error); + g_assert_nonnull (blob); + facp = fu_acpi_facp_new (blob, &error); + g_assert_no_error (error); + g_assert_nonnull (facp); + g_assert_false (fu_acpi_facp_get_s2i (facp)); +} + +static void +fu_acpi_facp_s2i_enabled_func (void) +{ + g_autofree gchar *fn = NULL; + g_autoptr(FuAcpiFacp) facp = NULL; + g_autoptr(GBytes) blob = NULL; + g_autoptr(GError) error = NULL; + + fn = g_build_filename (TESTDATADIR, "FACP-S2I", NULL); + blob = fu_common_get_contents_bytes (fn, &error); + g_assert_no_error (error); + g_assert_nonnull (blob); + facp = fu_acpi_facp_new (blob, &error); + g_assert_no_error (error); + g_assert_nonnull (facp); + g_assert_true (fu_acpi_facp_get_s2i (facp)); +} + +int +main (int argc, char **argv) +{ + g_test_init (&argc, &argv, NULL); + + /* 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 ("/acpi-facp/s2i{disabled}", fu_acpi_facp_s2i_disabled_func); + g_test_add_func ("/acpi-facp/s2i{enabled}", fu_acpi_facp_s2i_enabled_func); + return g_test_run (); +} diff --git a/plugins/acpi-facp/meson.build b/plugins/acpi-facp/meson.build new file mode 100644 index 000000000..9a3c96a25 --- /dev/null +++ b/plugins/acpi-facp/meson.build @@ -0,0 +1,51 @@ +cargs = ['-DG_LOG_DOMAIN="FuPluginAcpiFacp"'] + +shared_module('fu_plugin_acpi_facp', + fu_hash, + sources : [ + 'fu-plugin-acpi-facp.c', + 'fu-acpi-facp.c', + ], + include_directories : [ + root_incdir, + fwupd_incdir, + fwupdplugin_incdir, + ], + install : true, + install_dir: plugin_dir, + link_with : [ + fwupd, + fwupdplugin, + ], + c_args : cargs, + dependencies : [ + plugin_deps, + ], +) + +if get_option('tests') + testdatadir = join_paths(meson.current_source_dir(), 'tests') + cargs += '-DTESTDATADIR="' + testdatadir + '"' + e = executable( + 'acpi-facp-self-test', + fu_hash, + sources : [ + 'fu-self-test.c', + 'fu-acpi-facp.c', + ], + include_directories : [ + root_incdir, + fwupd_incdir, + fwupdplugin_incdir, + ], + dependencies : [ + plugin_deps, + ], + link_with : [ + fwupd, + fwupdplugin, + ], + c_args : cargs, + ) + test('acpi-facp-self-test', e) +endif diff --git a/plugins/acpi-facp/tests/FACP b/plugins/acpi-facp/tests/FACP new file mode 100644 index 0000000000000000000000000000000000000000..e438f978c5fb2596ebb7421e28c67b315ea044d7 GIT binary patch literal 244 zcmZ>BbPo8!z`($I!^hRnKg>TQK-bUERY75bC<8-4h^sRbP>!MDhd)EZUw;NBPKHfD z?uU<`7#Ji#5)2G1P&xoea{zGzOq_|4MS($}HI?BdGe{jHGcSV?BLl;$m500R@uJ`{1Fc_912Y7`ilLGA#vfkwgH15^)0 G5C8ya=@|h4 literal 0 HcmV?d00001 diff --git a/plugins/acpi-facp/tests/FACP-S2I b/plugins/acpi-facp/tests/FACP-S2I new file mode 100644 index 0000000000000000000000000000000000000000..6ee6211d2f801c1b62492bbb4510dd6588ac969c GIT binary patch literal 276 zcmY*TF$%&!5S+aW5(^=PsO91l{DBw+;fnk~LDB^qzn~uy>@0mizG0^+t(;A~fCG0s z?9R^YX1OZH0u1i?It10ctSa3e4}z(lFCom6iK1?Hs6RWnA+7*k?*^EW5Xr9=tSR3< z_MIe(3?-i4bmB)?Fz5DAND46@!-=Dg@wW^@6fXL6=&Wau3@+yV_33B%tw!PPj+S#J S-a~z#!+hWSkjJcU3-|&8^BMsF literal 0 HcmV?d00001 diff --git a/plugins/cpu/fu-plugin-cpu.c b/plugins/cpu/fu-plugin-cpu.c index 43e58e12d..d62a3e5e4 100644 --- a/plugins/cpu/fu-plugin-cpu.c +++ b/plugins/cpu/fu-plugin-cpu.c @@ -10,23 +10,29 @@ #include "fu-hash.h" #include "fu-cpu-device.h" +struct FuPluginData { + gboolean has_cet; +}; + void fu_plugin_init (FuPlugin *plugin) { fu_plugin_set_build_hash (plugin, FU_BUILD_HASH); + fu_plugin_alloc_data (plugin, sizeof (FuPluginData)); } gboolean fu_plugin_coldplug (FuPlugin *plugin, GError **error) { + FuPluginData *data = fu_plugin_get_data (plugin); gsize length; - g_autofree gchar *data = NULL; + g_autofree gchar *buf = NULL; g_auto(GStrv) lines = NULL; - if (!g_file_get_contents ("/proc/cpuinfo", &data, &length, error)) + if (!g_file_get_contents ("/proc/cpuinfo", &buf, &length, error)) return FALSE; - lines = g_strsplit (data, "\n\n", 0); + lines = g_strsplit (buf, "\n\n", 0); for (guint i = 0; lines[i] != NULL; i++) { g_autoptr(FuCpuDevice) dev = NULL; if (strlen (lines[i]) == 0) @@ -34,8 +40,36 @@ fu_plugin_coldplug (FuPlugin *plugin, GError **error) dev = fu_cpu_device_new (lines[i]); if (!fu_device_setup (FU_DEVICE (dev), error)) return FALSE; + if (fu_cpu_device_has_shstk (dev) && + fu_cpu_device_has_ibt (dev)) + data->has_cet = TRUE; fu_plugin_device_add (plugin, FU_DEVICE (dev)); } return TRUE; } + +void +fu_plugin_add_security_attrs (FuPlugin *plugin, FuSecurityAttrs *attrs) +{ + FuPluginData *data = fu_plugin_get_data (plugin); + g_autoptr(FwupdSecurityAttr) attr = NULL; + + /* only Intel */ + if (!fu_common_is_cpu_intel ()) + return; + + /* create attr */ + attr = fwupd_security_attr_new ("com.intel.CET"); + fwupd_security_attr_set_level (attr, FWUPD_SECURITY_ATTR_LEVEL_SYSTEM_PROTECTION); + fwupd_security_attr_set_name (attr, "Intel CET"); + fu_security_attrs_append (attrs, attr); + + /* check for CET */ + if (!data->has_cet) { + fwupd_security_attr_set_result (attr, "Unavailable"); + return; + } + fwupd_security_attr_add_flag (attr, FWUPD_SECURITY_ATTR_FLAG_SUCCESS); + fwupd_security_attr_set_result (attr, "SHSTK+IBT"); +} diff --git a/plugins/linux-lockdown/README.md b/plugins/linux-lockdown/README.md new file mode 100644 index 000000000..0cd58d6b9 --- /dev/null +++ b/plugins/linux-lockdown/README.md @@ -0,0 +1,8 @@ +Linux Kernel Lockdown +===================== + +Introduction +------------ + +This plugin checks if the currently running kernel is locked down. The result +will be stored in an security attribute for HSI. diff --git a/plugins/linux-lockdown/fu-plugin-linux-lockdown.c b/plugins/linux-lockdown/fu-plugin-linux-lockdown.c new file mode 100644 index 000000000..ed00e63fc --- /dev/null +++ b/plugins/linux-lockdown/fu-plugin-linux-lockdown.c @@ -0,0 +1,94 @@ +/* + * Copyright (C) 2020 Richard Hughes + * + * SPDX-License-Identifier: LGPL-2.1+ + */ + +#include "config.h" + +#include "fu-plugin-vfuncs.h" +#include "fu-hash.h" + +struct FuPluginData { + GFile *file; + GFileMonitor *monitor; +}; + +void +fu_plugin_init (FuPlugin *plugin) +{ + fu_plugin_alloc_data (plugin, sizeof (FuPluginData)); + fu_plugin_set_build_hash (plugin, FU_BUILD_HASH); +} + +void +fu_plugin_destroy (FuPlugin *plugin) +{ + FuPluginData *data = fu_plugin_get_data (plugin); + if (data->file != NULL) + g_object_unref (data->file); + if (data->monitor != NULL) + g_object_unref (data->monitor); +} + +static void +fu_plugin_linux_lockdown_changed_cb (GFileMonitor *monitor, + GFile *file, + GFile *other_file, + GFileMonitorEvent event_type, + gpointer user_data) +{ + FuPlugin *plugin = FU_PLUGIN (user_data); + fu_plugin_security_changed (plugin); +} + +gboolean +fu_plugin_startup (FuPlugin *plugin, GError **error) +{ + FuPluginData *data = fu_plugin_get_data (plugin); + g_autofree gchar *path = NULL; + g_autofree gchar *fn = NULL; + + path = fu_common_get_path (FU_PATH_KIND_SYSFSDIR_SECURITY); + fn = g_build_filename (path, "lockdown", NULL); + data->file = g_file_new_for_path (fn); + data->monitor = g_file_monitor (data->file, G_FILE_MONITOR_NONE, NULL, error); + if (data->monitor == NULL) + return FALSE; + g_signal_connect (data->monitor, "changed", + G_CALLBACK (fu_plugin_linux_lockdown_changed_cb), plugin); + return TRUE; +} + +void +fu_plugin_add_security_attrs (FuPlugin *plugin, FuSecurityAttrs *attrs) +{ + FuPluginData *data = fu_plugin_get_data (plugin); + gsize bufsz = 0; + g_autofree gchar *buf = NULL; + g_autoptr(FwupdSecurityAttr) attr = NULL; + g_autoptr(GError) error_local = NULL; + + /* create attr */ + attr = fwupd_security_attr_new ("org.kernel.CheckLockdown"); + fwupd_security_attr_set_name (attr, "Linux Kernel"); + fwupd_security_attr_add_flag (attr, FWUPD_SECURITY_ATTR_FLAG_RUNTIME_ISSUE); + fu_security_attrs_append (attrs, attr); + + /* load file */ + if (!g_file_load_contents (data->file, NULL, &buf, &bufsz, NULL, &error_local)) { + g_autofree gchar *fn = g_file_get_path (data->file); + g_warning ("could not open %s: %s", fn, error_local->message); + fwupd_security_attr_set_result (attr, "Could not open file"); + return; + } + if (g_strstr_len (buf, bufsz, "[integrity]") == NULL && + g_strstr_len (buf, bufsz, "[confidentiality]") == NULL) { + fwupd_security_attr_set_result (attr, "Not locked down"); + return; + } + + /* success */ + fwupd_security_attr_add_flag (attr, FWUPD_SECURITY_ATTR_FLAG_SUCCESS); + fwupd_security_attr_set_result (attr, "Locked down"); +} diff --git a/plugins/linux-lockdown/meson.build b/plugins/linux-lockdown/meson.build new file mode 100644 index 000000000..82857848f --- /dev/null +++ b/plugins/linux-lockdown/meson.build @@ -0,0 +1,23 @@ +cargs = ['-DG_LOG_DOMAIN="FuPluginLinuxLockdown"'] + +shared_module('fu_plugin_linux_lockdown', + fu_hash, + sources : [ + 'fu-plugin-linux-lockdown.c', + ], + include_directories : [ + root_incdir, + fwupd_incdir, + fwupdplugin_incdir, + ], + install : true, + install_dir: plugin_dir, + link_with : [ + fwupd, + fwupdplugin, + ], + c_args : cargs, + dependencies : [ + plugin_deps, + ], +) diff --git a/plugins/linux-sleep/README.md b/plugins/linux-sleep/README.md new file mode 100644 index 000000000..b7864933e --- /dev/null +++ b/plugins/linux-sleep/README.md @@ -0,0 +1,8 @@ +Linux Kernel Sleep +================== + +Introduction +------------ + +This plugin checks if s3 sleep is available. The result will be stored in an +security attribute for HSI. diff --git a/plugins/linux-sleep/fu-plugin-linux-sleep.c b/plugins/linux-sleep/fu-plugin-linux-sleep.c new file mode 100644 index 000000000..c7f8793fa --- /dev/null +++ b/plugins/linux-sleep/fu-plugin-linux-sleep.c @@ -0,0 +1,47 @@ +/* + * Copyright (C) 2020 Richard Hughes + * + * SPDX-License-Identifier: LGPL-2.1+ + */ + +#include "config.h" + +#include "fu-plugin-vfuncs.h" +#include "fu-hash.h" + +void +fu_plugin_init (FuPlugin *plugin) +{ + fu_plugin_set_build_hash (plugin, FU_BUILD_HASH); +} + +void +fu_plugin_add_security_attrs (FuPlugin *plugin, FuSecurityAttrs *attrs) +{ + gsize bufsz = 0; + g_autofree gchar *buf = NULL; + g_autoptr(FwupdSecurityAttr) attr = NULL; + g_autoptr(GError) error_local = NULL; + g_autoptr(GFile) file = g_file_new_for_path ("/sys/power/mem_sleep"); + + /* create attr */ + attr = fwupd_security_attr_new ("org.kernel.CheckS3Sleep"); + fwupd_security_attr_set_level (attr, FWUPD_SECURITY_ATTR_LEVEL_THEORETICAL); + fwupd_security_attr_set_name (attr, "Linux Kernel S3 Sleep"); + fu_security_attrs_append (attrs, attr); + + /* load file */ + if (!g_file_load_contents (file, NULL, &buf, &bufsz, NULL, &error_local)) { + g_autofree gchar *fn = g_file_get_path (file); + g_warning ("could not open %s: %s", fn, error_local->message); + fwupd_security_attr_set_result (attr, "Deep sleep status unavailable"); + return; + } + if (g_strstr_len (buf, bufsz, "[deep]") != NULL) { + fwupd_security_attr_set_result (attr, "System configured to suspend-to-ram (S3)"); + return; + } + + /* success */ + fwupd_security_attr_add_flag (attr, FWUPD_SECURITY_ATTR_FLAG_SUCCESS); +} diff --git a/plugins/linux-sleep/meson.build b/plugins/linux-sleep/meson.build new file mode 100644 index 000000000..a1a288d3f --- /dev/null +++ b/plugins/linux-sleep/meson.build @@ -0,0 +1,23 @@ +cargs = ['-DG_LOG_DOMAIN="FuPluginLinuxSleep"'] + +shared_module('fu_plugin_linux_sleep', + fu_hash, + sources : [ + 'fu-plugin-linux-sleep.c', + ], + include_directories : [ + root_incdir, + fwupd_incdir, + fwupdplugin_incdir, + ], + install : true, + install_dir: plugin_dir, + link_with : [ + fwupd, + fwupdplugin, + ], + c_args : cargs, + dependencies : [ + plugin_deps, + ], +) diff --git a/plugins/linux-spi-lpc/README.md b/plugins/linux-spi-lpc/README.md new file mode 100644 index 000000000..04d1909b2 --- /dev/null +++ b/plugins/linux-spi-lpc/README.md @@ -0,0 +1,8 @@ +Linux SPI LPC +============= + +Introduction +------------ + +This plugin checks if the system SPI chip is locked. The result will be stored +in an security attribute for HSI. diff --git a/plugins/linux-spi-lpc/fu-plugin-linux-spi-lpc.c b/plugins/linux-spi-lpc/fu-plugin-linux-spi-lpc.c new file mode 100644 index 000000000..2ff323c2f --- /dev/null +++ b/plugins/linux-spi-lpc/fu-plugin-linux-spi-lpc.c @@ -0,0 +1,139 @@ +/* + * Copyright (C) 2020 Richard Hughes + * + * SPDX-License-Identifier: LGPL-2.1+ + */ + +#include "config.h" + + +#include "fu-plugin-vfuncs.h" +#include "fu-hash.h" + +#define FU_PLUGIN_LINUX_SPI_LPC_SYSFS_DIR "/sys/kernel/security/spi" + +void +fu_plugin_init (FuPlugin *plugin) +{ + fu_plugin_set_build_hash (plugin, FU_BUILD_HASH); +} + +static void +fu_plugin_add_security_attr_bioswe (FuPlugin *plugin, FuSecurityAttrs *attrs) +{ + gsize bufsz = 0; + g_autofree gchar *buf = NULL; + g_autofree gchar *fn = NULL; + g_autoptr(FwupdSecurityAttr) attr = NULL; + g_autoptr(GError) error_local = NULL; + + /* create attr */ + attr = fwupd_security_attr_new ("org.kernel.BIOSWE"); + fwupd_security_attr_set_level (attr, FWUPD_SECURITY_ATTR_LEVEL_CRITICAL); + fwupd_security_attr_set_name (attr, "SPI"); + fu_security_attrs_append (attrs, attr); + + /* load file */ + fn = g_build_filename (FU_PLUGIN_LINUX_SPI_LPC_SYSFS_DIR, "bioswe", NULL); + if (!g_file_get_contents (fn, &buf, &bufsz, &error_local)) { + g_warning ("could not open %s: %s", fn, error_local->message); + fwupd_security_attr_set_result (attr, "Could not open file"); + return; + } + if (g_strcmp0 (buf, "0\n") != 0) { + fwupd_security_attr_set_result (attr, "Write enabled"); + return; + } + + /* success */ + fwupd_security_attr_add_flag (attr, FWUPD_SECURITY_ATTR_FLAG_SUCCESS); + fwupd_security_attr_set_result (attr, "Write disabled"); +} + +static void +fu_plugin_add_security_attr_ble (FuPlugin *plugin, FuSecurityAttrs *attrs) +{ + gsize bufsz = 0; + g_autofree gchar *buf = NULL; + g_autofree gchar *fn = NULL; + g_autoptr(FwupdSecurityAttr) attr = NULL; + g_autoptr(GError) error_local = NULL; + + /* create attr */ + attr = fwupd_security_attr_new ("org.kernel.BLE"); + fwupd_security_attr_set_level (attr, FWUPD_SECURITY_ATTR_LEVEL_CRITICAL); + fwupd_security_attr_set_name (attr, "SPI"); + fu_security_attrs_append (attrs, attr); + + /* load file */ + fn = g_build_filename (FU_PLUGIN_LINUX_SPI_LPC_SYSFS_DIR, "ble", NULL); + if (!g_file_get_contents (fn, &buf, &bufsz, &error_local)) { + g_warning ("could not open %s: %s", fn, error_local->message); + fwupd_security_attr_set_result (attr, "Could not open file"); + return; + } + if (g_strcmp0 (buf, "1\n") != 0) { + fwupd_security_attr_set_result (attr, "Lock disabled"); + return; + } + + /* success */ + fwupd_security_attr_add_flag (attr, FWUPD_SECURITY_ATTR_FLAG_SUCCESS); + fwupd_security_attr_set_result (attr, "Lock enabled"); +} + +static void +fu_plugin_add_security_attr_smm_bwp (FuPlugin *plugin, FuSecurityAttrs *attrs) +{ + gsize bufsz = 0; + g_autofree gchar *buf = NULL; + g_autofree gchar *fn = NULL; + g_autoptr(FwupdSecurityAttr) attr = NULL; + g_autoptr(GError) error_local = NULL; + + /* create attr */ + attr = fwupd_security_attr_new ("org.kernel.SMM_BWP"); + fwupd_security_attr_set_level (attr, FWUPD_SECURITY_ATTR_LEVEL_CRITICAL); + fwupd_security_attr_set_name (attr, "BIOS region of SPI"); + fu_security_attrs_append (attrs, attr); + + /* load file */ + fn = g_build_filename (FU_PLUGIN_LINUX_SPI_LPC_SYSFS_DIR, "smm_bwp", NULL); + if (!g_file_get_contents (fn, &buf, &bufsz, &error_local)) { + g_warning ("could not open %s: %s", fn, error_local->message); + fwupd_security_attr_set_result (attr, "Could not open file"); + return; + } + if (g_strcmp0 (buf, "1\n") != 0) { + fwupd_security_attr_set_result (attr, "Writable by OS"); + return; + } + + /* success */ + fwupd_security_attr_add_flag (attr, FWUPD_SECURITY_ATTR_FLAG_SUCCESS); + fwupd_security_attr_set_result (attr, "Writable only through BIOS"); +} + +void +fu_plugin_add_security_attrs (FuPlugin *plugin, FuSecurityAttrs *attrs) +{ + /* only Intel */ + if (!fu_common_is_cpu_intel ()) + return; + + /* maybe the kernel module does not exist */ + if (!g_file_test (FU_PLUGIN_LINUX_SPI_LPC_SYSFS_DIR, G_FILE_TEST_IS_DIR)) { + g_autoptr(FwupdSecurityAttr) attr = NULL; + attr = fwupd_security_attr_new ("org.kernel.BIOSWE"); + fwupd_security_attr_set_level (attr, FWUPD_SECURITY_ATTR_LEVEL_CRITICAL); + fwupd_security_attr_set_name (attr, "SPI"); + fwupd_security_attr_set_result (attr, "Kernel support not present"); + fu_security_attrs_append (attrs, attr); + return; + } + + /* look for the three files in sysfs */ + fu_plugin_add_security_attr_bioswe (plugin, attrs); + fu_plugin_add_security_attr_ble (plugin, attrs); + fu_plugin_add_security_attr_smm_bwp (plugin, attrs); +} diff --git a/plugins/linux-spi-lpc/meson.build b/plugins/linux-spi-lpc/meson.build new file mode 100644 index 000000000..cba7801bc --- /dev/null +++ b/plugins/linux-spi-lpc/meson.build @@ -0,0 +1,23 @@ +cargs = ['-DG_LOG_DOMAIN="FuPluginLinuxSpiLpc"'] + +shared_module('fu_plugin_linux_spi_lpc', + fu_hash, + sources : [ + 'fu-plugin-linux-spi-lpc.c', + ], + include_directories : [ + root_incdir, + fwupd_incdir, + fwupdplugin_incdir, + ], + install : true, + install_dir: plugin_dir, + link_with : [ + fwupd, + fwupdplugin, + ], + c_args : cargs, + dependencies : [ + plugin_deps, + ], +) diff --git a/plugins/linux-swap/README.md b/plugins/linux-swap/README.md index c4b49aa20..f7e28574a 100644 --- a/plugins/linux-swap/README.md +++ b/plugins/linux-swap/README.md @@ -5,4 +5,4 @@ Introduction ------------ This plugin checks if the currently available swap partitions and files are -all encrypted. +all encrypted. The result will be stored in an security attribute for HSI. diff --git a/plugins/linux-swap/fu-plugin-linux-swap.c b/plugins/linux-swap/fu-plugin-linux-swap.c index ed6e6a06a..646e3f00d 100644 --- a/plugins/linux-swap/fu-plugin-linux-swap.c +++ b/plugins/linux-swap/fu-plugin-linux-swap.c @@ -11,6 +11,7 @@ #include "fu-linux-swap.h" struct FuPluginData { + GFile *file; GFileMonitor *monitor; }; @@ -25,6 +26,8 @@ void fu_plugin_destroy (FuPlugin *plugin) { FuPluginData *data = fu_plugin_get_data (plugin); + if (data->file != NULL) + g_object_unref (data->file); if (data->monitor != NULL) g_object_unref (data->monitor); } @@ -36,41 +39,72 @@ fu_plugin_linux_swap_changed_cb (GFileMonitor *monitor, GFileMonitorEvent event_type, gpointer user_data) { - g_debug ("swap changed"); + FuPlugin *plugin = FU_PLUGIN (user_data); + fu_plugin_security_changed (plugin); } gboolean fu_plugin_startup (FuPlugin *plugin, GError **error) { FuPluginData *data = fu_plugin_get_data (plugin); - gsize bufsz = 0; - g_autofree gchar *buf = NULL; g_autofree gchar *fn = NULL; g_autofree gchar *procfs = NULL; - g_autoptr(FuLinuxSwap) swap = NULL; - g_autoptr(GFile) file = NULL; procfs = fu_common_get_path (FU_PATH_KIND_PROCFS); fn = g_build_filename (procfs, "swaps", NULL); - file = g_file_new_for_path (fn); - data->monitor = g_file_monitor (file, G_FILE_MONITOR_NONE, NULL, error); + data->file = g_file_new_for_path (fn); + data->monitor = g_file_monitor (data->file, G_FILE_MONITOR_NONE, NULL, error); if (data->monitor == NULL) return FALSE; g_signal_connect (data->monitor, "changed", G_CALLBACK (fu_plugin_linux_swap_changed_cb), plugin); - - /* load list of linux_swaps */ - if (!g_file_get_contents (fn, &buf, &bufsz, error)) { - g_prefix_error (error, "could not open %s: ", fn); - return FALSE; - } - swap = fu_linux_swap_new (buf, bufsz, error); - if (swap == NULL) { - g_prefix_error (error, "could not parse %s: ", fn); - return FALSE; - } - g_debug ("swap %s and %s", - fu_linux_swap_get_enabled (swap) ? "enabled" : "disabled", - fu_linux_swap_get_encrypted (swap) ? "encrypted" : "unencrypted"); return TRUE; } + +void +fu_plugin_add_security_attrs (FuPlugin *plugin, FuSecurityAttrs *attrs) +{ + FuPluginData *data = fu_plugin_get_data (plugin); + gsize bufsz = 0; + g_autofree gchar *buf = NULL; + g_autoptr(FuLinuxSwap) swap = NULL; + g_autoptr(FwupdSecurityAttr) attr = NULL; + g_autoptr(GError) error_local = NULL; + + /* create attr */ + attr = fwupd_security_attr_new ("org.kernel.Swap"); + fwupd_security_attr_add_flag (attr, FWUPD_SECURITY_ATTR_FLAG_RUNTIME_ISSUE); + fwupd_security_attr_set_name (attr, "Linux Swap"); + fu_security_attrs_append (attrs, attr); + + /* load list of swaps */ + if (!g_file_load_contents (data->file, NULL, &buf, &bufsz, NULL, &error_local)) { + g_autofree gchar *fn = g_file_get_path (data->file); + g_warning ("could not open %s: %s", fn, error_local->message); + fwupd_security_attr_set_result (attr, "Could not open file"); + return; + } + swap = fu_linux_swap_new (buf, bufsz, &error_local); + if (swap == NULL) { + g_autofree gchar *fn = g_file_get_path (data->file); + g_warning ("could not parse %s: %s", fn, error_local->message); + fwupd_security_attr_set_result (attr, "Could not parse file"); + return; + } + + /* none configured */ + if (!fu_linux_swap_get_enabled (swap)) { + fwupd_security_attr_add_flag (attr, FWUPD_SECURITY_ATTR_FLAG_SUCCESS); + return; + } + + /* add security attribute */ + if (!fu_linux_swap_get_encrypted (swap)) { + fwupd_security_attr_set_result (attr, "Not encrypted"); + return; + } + + /* success */ + fwupd_security_attr_add_flag (attr, FWUPD_SECURITY_ATTR_FLAG_SUCCESS); + fwupd_security_attr_set_result (attr, "Encrypted"); +} diff --git a/plugins/linux-tainted/README.md b/plugins/linux-tainted/README.md new file mode 100644 index 000000000..3c1a72d71 --- /dev/null +++ b/plugins/linux-tainted/README.md @@ -0,0 +1,8 @@ +Linux Kernel Tainted +==================== + +Introduction +------------ + +This plugin checks if the currently running kernel is tainted. The result will +be stored in an security attribute for HSI. diff --git a/plugins/linux-tainted/fu-plugin-linux-tainted.c b/plugins/linux-tainted/fu-plugin-linux-tainted.c new file mode 100644 index 000000000..de543ee14 --- /dev/null +++ b/plugins/linux-tainted/fu-plugin-linux-tainted.c @@ -0,0 +1,92 @@ +/* + * Copyright (C) 2020 Richard Hughes + * + * SPDX-License-Identifier: LGPL-2.1+ + */ + +#include "config.h" + +#include "fu-plugin-vfuncs.h" +#include "fu-hash.h" + +struct FuPluginData { + GFile *file; + GFileMonitor *monitor; +}; + +void +fu_plugin_init (FuPlugin *plugin) +{ + fu_plugin_alloc_data (plugin, sizeof (FuPluginData)); + fu_plugin_set_build_hash (plugin, FU_BUILD_HASH); +} + +void +fu_plugin_destroy (FuPlugin *plugin) +{ + FuPluginData *data = fu_plugin_get_data (plugin); + if (data->file != NULL) + g_object_unref (data->file); + if (data->monitor != NULL) + g_object_unref (data->monitor); +} + +static void +fu_plugin_linux_tainted_changed_cb (GFileMonitor *monitor, + GFile *file, + GFile *other_file, + GFileMonitorEvent event_type, + gpointer user_data) +{ + FuPlugin *plugin = FU_PLUGIN (user_data); + fu_plugin_security_changed (plugin); +} + +gboolean +fu_plugin_startup (FuPlugin *plugin, GError **error) +{ + FuPluginData *data = fu_plugin_get_data (plugin); + g_autofree gchar *fn = NULL; + g_autofree gchar *procfs = NULL; + + procfs = fu_common_get_path (FU_PATH_KIND_PROCFS); + fn = g_build_filename (procfs, "sys", "kernel", "tainted", NULL); + data->file = g_file_new_for_path (fn); + data->monitor = g_file_monitor (data->file, G_FILE_MONITOR_NONE, NULL, error); + if (data->monitor == NULL) + return FALSE; + g_signal_connect (data->monitor, "changed", + G_CALLBACK (fu_plugin_linux_tainted_changed_cb), plugin); + return TRUE; +} + +void +fu_plugin_add_security_attrs (FuPlugin *plugin, FuSecurityAttrs *attrs) +{ + FuPluginData *data = fu_plugin_get_data (plugin); + gsize bufsz = 0; + g_autofree gchar *buf = NULL; + g_autoptr(FwupdSecurityAttr) attr = NULL; + g_autoptr(GError) error_local = NULL; + + /* create attr */ + attr = fwupd_security_attr_new ("org.kernel.CheckTainted"); + fwupd_security_attr_set_name (attr, "Linux Kernel"); + fwupd_security_attr_add_flag (attr, FWUPD_SECURITY_ATTR_FLAG_RUNTIME_ISSUE); + fu_security_attrs_append (attrs, attr); + + /* load file */ + if (!g_file_load_contents (data->file, NULL, &buf, &bufsz, NULL, &error_local)) { + g_autofree gchar *fn = g_file_get_path (data->file); + g_warning ("could not open %s: %s", fn, error_local->message); + fwupd_security_attr_set_result (attr, "Could not open file"); + return; + } + if (g_strcmp0 (buf, "0\n") != 0) { + fwupd_security_attr_set_result (attr, "Tainted"); + return; + } + + /* success */ + fwupd_security_attr_add_flag (attr, FWUPD_SECURITY_ATTR_FLAG_SUCCESS); +} diff --git a/plugins/linux-tainted/meson.build b/plugins/linux-tainted/meson.build new file mode 100644 index 000000000..41d12a073 --- /dev/null +++ b/plugins/linux-tainted/meson.build @@ -0,0 +1,23 @@ +cargs = ['-DG_LOG_DOMAIN="FuPluginLinuxTainted"'] + +shared_module('fu_plugin_linux_tainted', + fu_hash, + sources : [ + 'fu-plugin-linux-tainted.c', + ], + include_directories : [ + root_incdir, + fwupd_incdir, + fwupdplugin_incdir, + ], + install : true, + install_dir: plugin_dir, + link_with : [ + fwupd, + fwupdplugin, + ], + c_args : cargs, + dependencies : [ + plugin_deps, + ], +) diff --git a/plugins/meson.build b/plugins/meson.build index f916228a6..f63e4f52a 100644 --- a/plugins/meson.build +++ b/plugins/meson.build @@ -1,3 +1,5 @@ +subdir('acpi-dmar') +subdir('acpi-facp') subdir('ccgx') subdir('cpu') subdir('dfu') @@ -7,7 +9,11 @@ subdir('ep963x') subdir('fastboot') subdir('fresco-pd') subdir('jabra') +subdir('linux-lockdown') +subdir('linux-sleep') +subdir('linux-spi-lpc') subdir('linux-swap') +subdir('linux-tainted') subdir('steelseries') subdir('dell-dock') subdir('nitrokey') diff --git a/plugins/tpm-eventlog/fu-plugin-tpm-eventlog.c b/plugins/tpm-eventlog/fu-plugin-tpm-eventlog.c index 4fec2f1c6..442649353 100644 --- a/plugins/tpm-eventlog/fu-plugin-tpm-eventlog.c +++ b/plugins/tpm-eventlog/fu-plugin-tpm-eventlog.c @@ -131,16 +131,23 @@ fu_plugin_add_security_attrs (FuPlugin *plugin, FuSecurityAttrs *attrs) FuPluginData *data = fu_plugin_get_data (plugin); g_autoptr(FwupdSecurityAttr) attr = NULL; + /* create attr */ attr = fwupd_security_attr_new ("org.trustedcomputinggroup.TpmEventLog"); fwupd_security_attr_set_level (attr, FWUPD_SECURITY_ATTR_LEVEL_IMPORTANT); fwupd_security_attr_set_name (attr, "TPM Reconstruction"); + fu_security_attrs_append (attrs, attr); + + /* check reconstructed to PCR0 */ if (!fu_plugin_get_enabled (plugin)) { fwupd_security_attr_set_result (attr, "No binary bios measurements available"); - } else if (data->reconstructed) { - fwupd_security_attr_set_result (attr, "Matched PCR0 reading"); - fwupd_security_attr_add_flag (attr, FWUPD_SECURITY_ATTR_FLAG_SUCCESS); - } else { - fwupd_security_attr_set_result (attr, "Did not match PCR0 reading"); + return; } - fu_security_attrs_append (attrs, attr); + if (!data->reconstructed) { + fwupd_security_attr_set_result (attr, "Did not match PCR0 reading"); + return; + } + + /* success */ + fwupd_security_attr_add_flag (attr, FWUPD_SECURITY_ATTR_FLAG_SUCCESS); + fwupd_security_attr_set_result (attr, "Matched PCR0 reading"); } diff --git a/plugins/tpm/fu-plugin-tpm.c b/plugins/tpm/fu-plugin-tpm.c index fec3842eb..918d2b86e 100644 --- a/plugins/tpm/fu-plugin-tpm.c +++ b/plugins/tpm/fu-plugin-tpm.c @@ -11,10 +11,52 @@ #include "fu-tpm-device.h" +struct FuPluginData { + gboolean has_tpm; + gboolean has_tpm_v20; +}; + void fu_plugin_init (FuPlugin *plugin) { + fu_plugin_alloc_data (plugin, sizeof (FuPluginData)); fu_plugin_set_build_hash (plugin, FU_BUILD_HASH); fu_plugin_add_udev_subsystem (plugin, "tpm"); fu_plugin_set_device_gtype (plugin, FU_TYPE_TPM_DEVICE); } + +void +fu_plugin_device_added (FuPlugin *plugin, FuDevice *dev) +{ + FuPluginData *data = fu_plugin_get_data (plugin); + data->has_tpm = TRUE; + if (g_strcmp0 (fu_tpm_device_get_family (FU_TPM_DEVICE (dev)), "2.0") == 0) + data->has_tpm_v20 = TRUE; +} + +void +fu_plugin_add_security_attrs (FuPlugin *plugin, FuSecurityAttrs *attrs) +{ + FuPluginData *data = fu_plugin_get_data (plugin); + g_autoptr(FwupdSecurityAttr) attr = NULL; + + /* create attr */ + attr = fwupd_security_attr_new ("org.trustedcomputinggroup.Tpm"); + fwupd_security_attr_set_level (attr, FWUPD_SECURITY_ATTR_LEVEL_CRITICAL); + fwupd_security_attr_set_name (attr, "TPM"); + fu_security_attrs_append (attrs, attr); + + /* check exists, and in v2.0 mode */ + if (!data->has_tpm) { + fwupd_security_attr_set_result (attr, "Not found"); + return; + } + if (!data->has_tpm_v20) { + fwupd_security_attr_set_result (attr, "Not in v2.0 mode"); + return; + } + + /* success */ + fwupd_security_attr_add_flag (attr, FWUPD_SECURITY_ATTR_FLAG_SUCCESS); + fwupd_security_attr_set_result (attr, "v2.0"); +} diff --git a/plugins/tpm/fu-tpm-device.c b/plugins/tpm/fu-tpm-device.c index fd3a95abd..90dde789e 100644 --- a/plugins/tpm/fu-tpm-device.c +++ b/plugins/tpm/fu-tpm-device.c @@ -12,6 +12,7 @@ struct _FuTpmDevice { FuUdevDevice parent_instance; + gchar *family; }; G_DEFINE_TYPE (FuTpmDevice, fu_tpm_device, FU_TYPE_UDEV_DEVICE) @@ -22,6 +23,12 @@ static void Esys_Finalize_autoptr_cleanup (ESYS_CONTEXT *esys_context) } G_DEFINE_AUTOPTR_CLEANUP_FUNC (ESYS_CONTEXT, Esys_Finalize_autoptr_cleanup) +const gchar * +fu_tpm_device_get_family (FuTpmDevice *self) +{ + return self->family; +} + static gboolean fu_tpm_device_probe (FuUdevDevice *device, GError **error) { @@ -134,6 +141,7 @@ fu_tpm_device_convert_manufacturer (const gchar *manufacturer) static gboolean fu_tpm_device_setup (FuDevice *device, GError **error) { + FuTpmDevice *self = FU_TPM_DEVICE (device); FwupdVersionFormat verfmt; TSS2_RC rc; const gchar *tmp; @@ -141,7 +149,6 @@ fu_tpm_device_setup (FuDevice *device, GError **error) guint32 version1 = 0; guint32 version2 = 0; guint64 version_raw; - g_autofree gchar *family = NULL; g_autofree gchar *id1 = NULL; g_autofree gchar *id2 = NULL; g_autofree gchar *id3 = NULL; @@ -171,8 +178,8 @@ fu_tpm_device_setup (FuDevice *device, GError **error) } /* lookup guaranteed details from TPM */ - family = fu_tpm_device_get_string (ctx, TPM2_PT_FAMILY_INDICATOR, error); - if (family == NULL) { + self->family = fu_tpm_device_get_string (ctx, TPM2_PT_FAMILY_INDICATOR, error); + if (self->family == NULL) { g_prefix_error (error, "failed to read TPM family"); return FALSE; } @@ -202,9 +209,9 @@ fu_tpm_device_setup (FuDevice *device, GError **error) fu_device_add_instance_id (device, id1); id2 = g_strdup_printf ("TPM\\VEN_%s&MOD_%s", manufacturer, model); fu_device_add_instance_id (device, id2); - id3 = g_strdup_printf ("TPM\\VEN_%s&DEV_%04X&VER_%s", manufacturer, tpm_type, family); + id3 = g_strdup_printf ("TPM\\VEN_%s&DEV_%04X&VER_%s", manufacturer, tpm_type, self->family); fu_device_add_instance_id (device, id3); - id4 = g_strdup_printf ("TPM\\VEN_%s&MOD_%s&VER_%s", manufacturer, model, family); + id4 = g_strdup_printf ("TPM\\VEN_%s&MOD_%s&VER_%s", manufacturer, model, self->family); fu_device_add_instance_id (device, id4); /* enforce vendors can only ship updates for their own hardware */ @@ -245,6 +252,8 @@ fu_tpm_device_init (FuTpmDevice *self) static void fu_tpm_device_finalize (GObject *object) { + FuTpmDevice *self = FU_TPM_DEVICE (object); + g_free (self->family); G_OBJECT_CLASS (fu_tpm_device_parent_class)->finalize (object); } diff --git a/plugins/tpm/fu-tpm-device.h b/plugins/tpm/fu-tpm-device.h index 55c1ef312..0584f9d26 100644 --- a/plugins/tpm/fu-tpm-device.h +++ b/plugins/tpm/fu-tpm-device.h @@ -10,3 +10,5 @@ #define FU_TYPE_TPM_DEVICE (fu_tpm_device_get_type ()) G_DECLARE_FINAL_TYPE (FuTpmDevice, fu_tpm_device, FU, TPM_DEVICE, FuUdevDevice) + +const gchar *fu_tpm_device_get_family (FuTpmDevice *self); diff --git a/plugins/uefi-dbx/README.md b/plugins/uefi-dbx/README.md index d1c22a9fd..cdd07c988 100644 --- a/plugins/uefi-dbx/README.md +++ b/plugins/uefi-dbx/README.md @@ -5,4 +5,4 @@ Introduction ------------ This plugin checks if the UEFI dbx contains all the most recent blacklisted -checksums. +checksums. The result will be stored in an security attribute for HSI. diff --git a/plugins/uefi-dbx/fu-plugin-uefi-dbx.c b/plugins/uefi-dbx/fu-plugin-uefi-dbx.c index a2089858d..b38836967 100644 --- a/plugins/uefi-dbx/fu-plugin-uefi-dbx.c +++ b/plugins/uefi-dbx/fu-plugin-uefi-dbx.c @@ -32,6 +32,17 @@ fu_plugin_destroy (FuPlugin *plugin) gboolean fu_plugin_startup (FuPlugin *plugin, GError **error) +{ + FuPluginData *data = fu_plugin_get_data (plugin); + data->fn = fu_uefi_dbx_get_dbxupdate (error); + if (data->fn == NULL) + return FALSE; + g_debug ("using %s", data->fn); + return TRUE; +} + +void +fu_plugin_add_security_attrs (FuPlugin *plugin, FuSecurityAttrs *attrs) { FuPluginData *data = fu_plugin_get_data (plugin); GPtrArray *checksums; @@ -41,46 +52,55 @@ fu_plugin_startup (FuPlugin *plugin, GError **error) g_autofree guint8 *buf_update = NULL; g_autoptr(FuUefiDbxFile) dbx_system = NULL; g_autoptr(FuUefiDbxFile) dbx_update = NULL; + g_autoptr(FwupdSecurityAttr) attr = NULL; g_autoptr(GError) error_local = NULL; - /* get binary blob */ - data->fn = fu_uefi_dbx_get_dbxupdate (error); - if (data->fn == NULL) { + /* create attr */ + attr = fwupd_security_attr_new ("org.uefi.SecureBoot.dbx"); + fwupd_security_attr_set_level (attr, FWUPD_SECURITY_ATTR_LEVEL_CRITICAL); + fwupd_security_attr_set_name (attr, "UEFI dbx"); + fu_security_attrs_append (attrs, attr); + + /* no binary blob */ + if (!fu_plugin_get_enabled (plugin)) { g_autofree gchar *dbxdir = NULL; + g_autofree gchar *result = NULL; dbxdir = fu_common_get_path (FU_PATH_KIND_EFIDBXDIR); - g_set_error (error, - FWUPD_ERROR, - FWUPD_ERROR_NOT_SUPPORTED, - "file can be downloaded from %s and decompressed into %s: ", - FU_UEFI_DBX_DATA_URL, dbxdir); - return FALSE; + result = g_strdup_printf ("DBX can be downloaded from %s and decompressed into %s: ", + FU_UEFI_DBX_DATA_URL, dbxdir); + fwupd_security_attr_set_result (attr, result); + return; } /* get update dbx */ - if (!g_file_get_contents (data->fn, (gchar **) &buf_update, &bufsz, error)) { - g_prefix_error (error, "failed to load %s: ", data->fn); - return FALSE; + if (!g_file_get_contents (data->fn, (gchar **) &buf_update, &bufsz, &error_local)) { + g_warning ("failed to load %s: %s", data->fn, error_local->message); + fwupd_security_attr_set_result (attr, "Failed to load update DBX"); + return; } dbx_update = fu_uefi_dbx_file_new (buf_update, bufsz, FU_UEFI_DBX_FILE_PARSE_FLAGS_IGNORE_HEADER, - error); + &error_local); if (dbx_update == NULL) { - g_prefix_error (error, "could not parse %s: ", data->fn); - return FALSE; + g_warning ("failed to parse %s: %s", data->fn, error_local->message); + fwupd_security_attr_set_result (attr, "Failed to parse update DBX"); + return; } /* get system dbx */ if (!fu_efivar_get_data ("d719b2cb-3d3a-4596-a3bc-dad00e67656f", "dbx", - &buf_system, &bufsz, NULL, error)) { - g_prefix_error (error, "failed to get dbx: "); - return FALSE; + &buf_system, &bufsz, NULL, &error_local)) { + g_warning ("failed to load EFI dbx: %s", error_local->message); + fwupd_security_attr_set_result (attr, "Failed to load EFI DBX"); + return; } dbx_system = fu_uefi_dbx_file_new (buf_system, bufsz, FU_UEFI_DBX_FILE_PARSE_FLAGS_NONE, - error); + &error_local); if (dbx_system == NULL) { - g_prefix_error (error, "could not parse variable: "); - return FALSE; + g_warning ("failed to parse EFI dbx: %s", error_local->message); + fwupd_security_attr_set_result (attr, "Failed to parse EFI DBX"); + return; } /* look for each checksum in the update in the system version */ @@ -88,11 +108,18 @@ fu_plugin_startup (FuPlugin *plugin, GError **error) for (guint i = 0; i < checksums->len; i++) { const gchar *checksum = g_ptr_array_index (checksums, i); if (!fu_uefi_dbx_file_has_checksum (dbx_system, checksum)) { - g_debug ("%s missing from the system dbx", checksum); + g_debug ("%s missing from the system DBX", checksum); missing_cnt += 1; } } - if (missing_cnt > 0) - g_warning ("%u hashes missing", missing_cnt); - return TRUE; + + /* add security attribute */ + if (missing_cnt > 0) { + g_autofree gchar *summary = g_strdup_printf ("%u hashes missing", missing_cnt); + fwupd_security_attr_set_result (attr, summary); + return; + } + + /* success */ + fwupd_security_attr_add_flag (attr, FWUPD_SECURITY_ATTR_FLAG_SUCCESS); } diff --git a/plugins/uefi/fu-plugin-uefi.c b/plugins/uefi/fu-plugin-uefi.c index 204b338a0..ba9563716 100644 --- a/plugins/uefi/fu-plugin-uefi.c +++ b/plugins/uefi/fu-plugin-uefi.c @@ -91,6 +91,28 @@ fu_plugin_get_results (FuPlugin *plugin, FuDevice *device, GError **error) return TRUE; } +void +fu_plugin_add_security_attrs (FuPlugin *plugin, FuSecurityAttrs *attrs) +{ + g_autoptr(FwupdSecurityAttr) attr = NULL; + + /* create attr */ + attr = fwupd_security_attr_new ("com.uefi.SecureBoot"); + fwupd_security_attr_set_level (attr, FWUPD_SECURITY_ATTR_LEVEL_CRITICAL); + fwupd_security_attr_set_name (attr, "UEFI Secure Boot"); + fu_security_attrs_append (attrs, attr); + + /* SB disabled */ + if (!fu_efivar_secure_boot_enabled ()) { + fwupd_security_attr_set_result (attr, "Disabled"); + return; + } + + /* success */ + fwupd_security_attr_add_flag (attr, FWUPD_SECURITY_ATTR_FLAG_SUCCESS); + fwupd_security_attr_set_result (attr, "Enabled"); +} + static GBytes * fu_plugin_uefi_get_splash_data (guint width, guint height, GError **error) { From 66bab9d8f428dd76475e24b549829a664d8e4ae1 Mon Sep 17 00:00:00 2001 From: Mario Limonciello Date: Tue, 12 May 2020 15:33:07 -0500 Subject: [PATCH 051/607] trivial: reword the security cases for a few plugins MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit On a system that is not at all locked down running an old kernel several of the items are a bit confusing. ``` Runtime Suffix -! ✔ fwupd plugins: OK ✔ Linux Kernel: OK ✘ Linux Kernel: Could not open file ✘ Linux Swap: Not encrypted ``` --- plugins/acpi-facp/fu-plugin-acpi-facp.c | 2 +- plugins/linux-lockdown/fu-plugin-linux-lockdown.c | 4 ++-- plugins/linux-tainted/fu-plugin-linux-tainted.c | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/plugins/acpi-facp/fu-plugin-acpi-facp.c b/plugins/acpi-facp/fu-plugin-acpi-facp.c index 2575a5802..5409d2c47 100644 --- a/plugins/acpi-facp/fu-plugin-acpi-facp.c +++ b/plugins/acpi-facp/fu-plugin-acpi-facp.c @@ -29,7 +29,7 @@ fu_plugin_add_security_attrs (FuPlugin *plugin, FuSecurityAttrs *attrs) /* create attr */ attr = fwupd_security_attr_new ("org.uefi.ACPI.Facp"); fwupd_security_attr_set_level (attr, FWUPD_SECURITY_ATTR_LEVEL_THEORETICAL); - fwupd_security_attr_set_name (attr, "Suspend2Idle"); + fwupd_security_attr_set_name (attr, "Suspend To Idle"); fu_security_attrs_append (attrs, attr); /* load FACP table */ diff --git a/plugins/linux-lockdown/fu-plugin-linux-lockdown.c b/plugins/linux-lockdown/fu-plugin-linux-lockdown.c index ed00e63fc..c81690dc7 100644 --- a/plugins/linux-lockdown/fu-plugin-linux-lockdown.c +++ b/plugins/linux-lockdown/fu-plugin-linux-lockdown.c @@ -71,7 +71,7 @@ fu_plugin_add_security_attrs (FuPlugin *plugin, FuSecurityAttrs *attrs) /* create attr */ attr = fwupd_security_attr_new ("org.kernel.CheckLockdown"); - fwupd_security_attr_set_name (attr, "Linux Kernel"); + fwupd_security_attr_set_name (attr, "Linux Kernel Lockdown"); fwupd_security_attr_add_flag (attr, FWUPD_SECURITY_ATTR_FLAG_RUNTIME_ISSUE); fu_security_attrs_append (attrs, attr); @@ -79,7 +79,7 @@ fu_plugin_add_security_attrs (FuPlugin *plugin, FuSecurityAttrs *attrs) if (!g_file_load_contents (data->file, NULL, &buf, &bufsz, NULL, &error_local)) { g_autofree gchar *fn = g_file_get_path (data->file); g_warning ("could not open %s: %s", fn, error_local->message); - fwupd_security_attr_set_result (attr, "Could not open file"); + fwupd_security_attr_set_result (attr, "Not supported"); return; } if (g_strstr_len (buf, bufsz, "[integrity]") == NULL && diff --git a/plugins/linux-tainted/fu-plugin-linux-tainted.c b/plugins/linux-tainted/fu-plugin-linux-tainted.c index de543ee14..1d3936f78 100644 --- a/plugins/linux-tainted/fu-plugin-linux-tainted.c +++ b/plugins/linux-tainted/fu-plugin-linux-tainted.c @@ -71,7 +71,7 @@ fu_plugin_add_security_attrs (FuPlugin *plugin, FuSecurityAttrs *attrs) /* create attr */ attr = fwupd_security_attr_new ("org.kernel.CheckTainted"); - fwupd_security_attr_set_name (attr, "Linux Kernel"); + fwupd_security_attr_set_name (attr, "Linux Kernel Taint"); fwupd_security_attr_add_flag (attr, FWUPD_SECURITY_ATTR_FLAG_RUNTIME_ISSUE); fu_security_attrs_append (attrs, attr); From ff303e11504eda67a11e355c459913f3e490d4c4 Mon Sep 17 00:00:00 2001 From: Mario Limonciello Date: Wed, 13 May 2020 10:25:41 -0500 Subject: [PATCH 052/607] trivial: fu-engine: correct a memory leak --- src/fu-engine.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/fu-engine.c b/src/fu-engine.c index 7c64786dd..ca0daa214 100644 --- a/src/fu-engine.c +++ b/src/fu-engine.c @@ -5040,7 +5040,7 @@ fu_engine_get_host_machine_id (FuEngine *self) static void fu_engine_add_security_attrs_tainted (FuEngine *self, FuSecurityAttrs *attrs) { - FwupdSecurityAttr *attr = fwupd_security_attr_new ("org.fwupd.Hsi.Plugins"); + g_autoptr(FwupdSecurityAttr) attr = fwupd_security_attr_new ("org.fwupd.Hsi.Plugins"); fwupd_security_attr_set_name (attr, "fwupd plugins"); fwupd_security_attr_add_flag (attr, FWUPD_SECURITY_ATTR_FLAG_RUNTIME_ISSUE); if (self->tainted) { @@ -5056,8 +5056,8 @@ fu_engine_add_security_attrs_supported (FuEngine *self, FuSecurityAttrs *attrs) { FwupdRelease *rel_current = NULL; FwupdRelease *rel_newest = NULL; - FwupdSecurityAttr *attr_a; - FwupdSecurityAttr *attr_u; + g_autoptr(FwupdSecurityAttr) attr_a = NULL; + g_autoptr(FwupdSecurityAttr) attr_u = NULL; guint64 now = (guint64) g_get_real_time () / G_USEC_PER_SEC; g_autoptr(FuDevice) device = NULL; g_autoptr(GPtrArray) releases = NULL; From b8a57e598afdd8cb84000b04e0efa22ec0c4a5ab Mon Sep 17 00:00:00 2001 From: Mario Limonciello Date: Wed, 13 May 2020 09:34:29 -0500 Subject: [PATCH 053/607] trivial: send users to a wiki page for runtime issues Specifically send people here when the runtime issue suffix is in place to give them more information on mitigations. --- src/fu-util-common.c | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/src/fu-util-common.c b/src/fu-util-common.c index 1eb128cea..25f5349e1 100644 --- a/src/fu-util-common.c +++ b/src/fu-util-common.c @@ -1582,6 +1582,7 @@ fu_util_security_attrs_to_string (GPtrArray *attrs) FWUPD_SECURITY_ATTR_FLAG_NONE, }; GString *str = g_string_new (NULL); + gboolean runtime_help = FALSE; for (guint j = 1; j <= FWUPD_SECURITY_ATTR_LEVEL_LAST; j++) { gboolean has_header = FALSE; @@ -1610,9 +1611,20 @@ fu_util_security_attrs_to_string (GPtrArray *attrs) FwupdSecurityAttr *attr = g_ptr_array_index (attrs, i); if (!fwupd_security_attr_has_flag (attr, hpi_suffixes[j])) continue; + if (fwupd_security_attr_has_flag (attr, FWUPD_SECURITY_ATTR_FLAG_RUNTIME_ISSUE) && + !fwupd_security_attr_has_flag (attr, FWUPD_SECURITY_ATTR_FLAG_SUCCESS)) + runtime_help = TRUE; fu_security_attr_append_str (attr, str); } } } + + if (runtime_help) { + g_string_append_printf (str, "\n%s %s", + /* TRANSLATORS: this is instructions on how to improve the HSI suffix */ + _("Your system has runtime issues. Visit this URL for more information: "), + "https://github.com/fwupd/fwupd/wiki/Host-security-ID-runtime-issues"); + } + return g_string_free (str, FALSE); } From c88d4eadf1770c3cf0df25ea2e961df60e2ac5b0 Mon Sep 17 00:00:00 2001 From: Mario Limonciello Date: Wed, 13 May 2020 09:39:35 -0500 Subject: [PATCH 054/607] trivial: fu-engine: raise a runtime issue if plugin whitelist set MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit If a plugin whitelist is set, the HSI value will be wrong. ``` $ sudo ./build/src/fwupdtool security --force --plugin-whitelist=tpm Loading… [***************************************] Host Security ID: HSI:1 HSI-1 ✔ TPM: v2.0 Runtime Suffix -U ✘ Firmware Updates: No system device Runtime Suffix -A ✘ Firmware Attestation: No PCR0s Runtime Suffix -! ✔ fwupd plugins: OK ``` --- src/fu-engine.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/fu-engine.c b/src/fu-engine.c index ca0daa214..dd7619ae4 100644 --- a/src/fu-engine.c +++ b/src/fu-engine.c @@ -5045,6 +5045,8 @@ fu_engine_add_security_attrs_tainted (FuEngine *self, FuSecurityAttrs *attrs) fwupd_security_attr_add_flag (attr, FWUPD_SECURITY_ATTR_FLAG_RUNTIME_ISSUE); if (self->tainted) { fwupd_security_attr_set_result (attr, "Tainted"); + } else if (self->plugin_filter->len > 0) { + fwupd_security_attr_set_result (attr, "Disabled plugins"); } else { fwupd_security_attr_add_flag (attr, FWUPD_SECURITY_ATTR_FLAG_SUCCESS); } From a83428462d483864608c78cf275821cd04b02203 Mon Sep 17 00:00:00 2001 From: Mario Limonciello Date: Wed, 13 May 2020 09:47:16 -0500 Subject: [PATCH 055/607] trivial: fu-engine: if plugins are blacklisted in daemon.conf raise runtime issue --- src/fu-engine.c | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/src/fu-engine.c b/src/fu-engine.c index dd7619ae4..8b5511782 100644 --- a/src/fu-engine.c +++ b/src/fu-engine.c @@ -5040,12 +5040,22 @@ fu_engine_get_host_machine_id (FuEngine *self) static void fu_engine_add_security_attrs_tainted (FuEngine *self, FuSecurityAttrs *attrs) { + gboolean disabled_plugins = FALSE; + GPtrArray *blacklist = fu_config_get_blacklist_plugins (self->config); g_autoptr(FwupdSecurityAttr) attr = fwupd_security_attr_new ("org.fwupd.Hsi.Plugins"); fwupd_security_attr_set_name (attr, "fwupd plugins"); fwupd_security_attr_add_flag (attr, FWUPD_SECURITY_ATTR_FLAG_RUNTIME_ISSUE); + for (guint i = 0; i < blacklist->len; i++) { + const gchar *name_tmp = g_ptr_array_index (blacklist, i); + if (g_strcmp0 (name_tmp, "test") != 0 && + g_strcmp0 (name_tmp, "invalid") != 0) { + disabled_plugins = TRUE; + break; + } + } if (self->tainted) { fwupd_security_attr_set_result (attr, "Tainted"); - } else if (self->plugin_filter->len > 0) { + } else if (self->plugin_filter->len > 0 || disabled_plugins) { fwupd_security_attr_set_result (attr, "Disabled plugins"); } else { fwupd_security_attr_add_flag (attr, FWUPD_SECURITY_ATTR_FLAG_SUCCESS); From 6ed9cbd20128c222cc400895b8e2134d1634e5c4 Mon Sep 17 00:00:00 2001 From: Mario Limonciello Date: Wed, 13 May 2020 10:40:45 -0500 Subject: [PATCH 056/607] trivial: add a wiki page for low HSI levels When HSI level is below 2, direct users here to help improve the level --- src/fu-util-common.c | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/src/fu-util-common.c b/src/fu-util-common.c index 25f5349e1..16a604aee 100644 --- a/src/fu-util-common.c +++ b/src/fu-util-common.c @@ -1582,6 +1582,7 @@ fu_util_security_attrs_to_string (GPtrArray *attrs) FWUPD_SECURITY_ATTR_FLAG_NONE, }; GString *str = g_string_new (NULL); + gboolean low_help = FALSE; gboolean runtime_help = FALSE; for (guint j = 1; j <= FWUPD_SECURITY_ATTR_LEVEL_LAST; j++) { @@ -1595,6 +1596,10 @@ fu_util_security_attrs_to_string (GPtrArray *attrs) has_header = TRUE; } fu_security_attr_append_str (attr, str); + /* make sure they have at least HSI-1 */ + if (j < FWUPD_SECURITY_ATTR_LEVEL_IMPORTANT && + !fwupd_security_attr_has_flag (attr, FWUPD_SECURITY_ATTR_FLAG_SUCCESS)) + low_help = TRUE; } } for (guint i = 0; i < attrs->len; i++) { @@ -1619,6 +1624,12 @@ fu_util_security_attrs_to_string (GPtrArray *attrs) } } + if (low_help) { + g_string_append_printf (str, "\n%s %s", + /* TRANSLATORS: this is instructions on how to improve the HSI security level */ + _("Your system has a low HSI security level. Visit this URL for more information: "), + "https://github.com/fwupd/fwupd/wiki/Low-host-security-level"); + } if (runtime_help) { g_string_append_printf (str, "\n%s %s", /* TRANSLATORS: this is instructions on how to improve the HSI suffix */ From f160e6b7fc75b5b5f5f3e42e0c391d5bede9de9e Mon Sep 17 00:00:00 2001 From: Mario Limonciello Date: Wed, 13 May 2020 11:13:06 -0500 Subject: [PATCH 057/607] amt: Add a security attestation for provisioning --- plugins/amt/fu-plugin-amt.c | 37 +++++++++++++++++++++++++++++++++++-- 1 file changed, 35 insertions(+), 2 deletions(-) diff --git a/plugins/amt/fu-plugin-amt.c b/plugins/amt/fu-plugin-amt.c index b1f023025..46f2bbf0d 100644 --- a/plugins/amt/fu-plugin-amt.c +++ b/plugins/amt/fu-plugin-amt.c @@ -17,6 +17,11 @@ #include "fu-plugin-vfuncs.h" #include "fu-hash.h" +struct FuPluginData { + gboolean has_mei; + gboolean provisioned; +}; + typedef struct { uuid_le guid; guint buf_size; @@ -444,8 +449,9 @@ G_DEFINE_AUTOPTR_CLEANUP_FUNC(mei_context, mei_context_free) #pragma clang diagnostic pop static FuDevice * -fu_plugin_amt_create_device (GError **error) +fu_plugin_amt_create_device (FuPlugin *plugin, GError **error) { + FuPluginData *data = fu_plugin_get_data (plugin); guint8 state; struct amt_code_versions ver; fwupd_guid_t uu; @@ -491,15 +497,19 @@ fu_plugin_amt_create_device (GError **error) switch (state) { case 0: fu_device_set_name (dev, "Intel AMT [unprovisioned]"); + data->provisioned = FALSE; break; case 1: fu_device_set_name (dev, "Intel AMT [being provisioned]"); + data->provisioned = TRUE; break; case 2: fu_device_set_name (dev, "Intel AMT [provisioned]"); + data->provisioned = TRUE; break; default: fu_device_set_name (dev, "Intel AMT [unknown]"); + data->provisioned = FALSE; break; } fu_device_set_summary (dev, "Hardware and firmware technology for remote " @@ -536,6 +546,7 @@ fu_plugin_amt_create_device (GError **error) fu_device_set_version (dev, version_fw->str); if (version_bl->len > 0) fu_device_set_version_bootloader (dev, version_bl->str); + data->has_mei = TRUE; return g_steal_pointer (&dev); } @@ -544,15 +555,37 @@ void fu_plugin_init (FuPlugin *plugin) { fu_plugin_set_build_hash (plugin, FU_BUILD_HASH); + fu_plugin_alloc_data (plugin, sizeof (FuPluginData)); } gboolean fu_plugin_coldplug (FuPlugin *plugin, GError **error) { g_autoptr(FuDevice) dev = NULL; - dev = fu_plugin_amt_create_device (error); + dev = fu_plugin_amt_create_device (plugin, error); if (dev == NULL) return FALSE; fu_plugin_device_add (plugin, dev); return TRUE; } + +void +fu_plugin_add_security_attrs (FuPlugin *plugin, FuSecurityAttrs *attrs) +{ + FuPluginData *data = fu_plugin_get_data (plugin); + g_autoptr(FwupdSecurityAttr) attr = NULL; + + if (!fu_common_is_cpu_intel () || !data->has_mei) + return; + + attr = fwupd_security_attr_new ("com.intel.AMT"); + fwupd_security_attr_set_level (attr, FWUPD_SECURITY_ATTR_LEVEL_SYSTEM_PROTECTION); + fwupd_security_attr_set_name (attr, "Intel AMT"); + fu_security_attrs_append (attrs, attr); + if (data->provisioned) { + fwupd_security_attr_set_result (attr, "Provisioned"); + return; + } + + fwupd_security_attr_add_flag (attr, FWUPD_SECURITY_ATTR_FLAG_SUCCESS); +} From 92da8a894d7b7608c7427b73595deaa068b9a269 Mon Sep 17 00:00:00 2001 From: Ilya Guterman Date: Tue, 5 May 2020 04:23:25 +0300 Subject: [PATCH 058/607] dfu: Avoid communicating when bitManifestationTolerant is off --- plugins/dfu/dfu-device.c | 8 ++++++++ plugins/dfu/dfu-target-stm.c | 2 ++ plugins/dfu/dfu-tool.c | 7 +++++-- 3 files changed, 15 insertions(+), 2 deletions(-) diff --git a/plugins/dfu/dfu-device.c b/plugins/dfu/dfu-device.c index eae6a353e..9e4c31f8d 100644 --- a/plugins/dfu/dfu-device.c +++ b/plugins/dfu/dfu-device.c @@ -871,6 +871,14 @@ dfu_device_refresh (DfuDevice *device, GError **error) if (!dfu_device_ensure_interface (device, error)) return FALSE; + /* Device that cannot communicate via the USB after the + * Manifestation phase indicated this limitation to the + * host by clearing bmAttributes bit bitManifestationTolerant. + * so we assume the operation was succesful */ + if (priv->state == DFU_STATE_DFU_MANIFEST && + !(priv->attributes & DFU_DEVICE_ATTRIBUTE_MANIFEST_TOL)) + return TRUE; + if (!g_usb_device_control_transfer (usb_device, G_USB_DEVICE_DIRECTION_DEVICE_TO_HOST, G_USB_DEVICE_REQUEST_TYPE_CLASS, diff --git a/plugins/dfu/dfu-target-stm.c b/plugins/dfu/dfu-target-stm.c index de41292d4..3857f9c05 100644 --- a/plugins/dfu/dfu-target-stm.c +++ b/plugins/dfu/dfu-target-stm.c @@ -29,6 +29,8 @@ G_DEFINE_TYPE (DfuTargetStm, dfu_target_stm, DFU_TYPE_TARGET) static gboolean dfu_target_stm_attach (DfuTarget *target, GError **error) { + /* downloading empty payload will cause a dfu to leave, + * the returned status will be dfuMANIFEST and expect the device to disconnect */ g_autoptr(GBytes) bytes_tmp = g_bytes_new (NULL, 0); return dfu_target_download_chunk (target, 2, bytes_tmp, error); } diff --git a/plugins/dfu/dfu-tool.c b/plugins/dfu/dfu-tool.c index fb473651d..222d1fe82 100644 --- a/plugins/dfu/dfu-tool.c +++ b/plugins/dfu/dfu-tool.c @@ -938,8 +938,11 @@ dfu_tool_write (DfuToolPrivate *priv, gchar **values, GError **error) /* do host reset */ if (!fu_device_attach (FU_DEVICE (device), error)) return FALSE; - if (!dfu_device_wait_for_replug (priv, device, FU_DEVICE_REMOVE_DELAY_RE_ENUMERATE, error)) - return FALSE; + + if (dfu_device_has_attribute (device, DFU_DEVICE_ATTRIBUTE_MANIFEST_TOL)) { + if (!dfu_device_wait_for_replug (priv, device, FU_DEVICE_REMOVE_DELAY_RE_ENUMERATE, error)) + return FALSE; + } /* success */ g_print ("%u bytes successfully downloaded to device\n", From 5b24547197f37107e9ec16c290cca9ec9f96aacd Mon Sep 17 00:00:00 2001 From: Richard Hughes Date: Thu, 14 May 2020 12:06:37 +0100 Subject: [PATCH 059/607] synaptics-rmi: Essentially blacklist Dell K12A Fixes https://github.com/fwupd/fwupd/issues/2052 --- plugins/synaptics-rmi/synaptics-rmi.quirk | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/plugins/synaptics-rmi/synaptics-rmi.quirk b/plugins/synaptics-rmi/synaptics-rmi.quirk index e880ded23..e47b7b878 100644 --- a/plugins/synaptics-rmi/synaptics-rmi.quirk +++ b/plugins/synaptics-rmi/synaptics-rmi.quirk @@ -1,3 +1,7 @@ [DeviceInstanceId=HIDRAW\VEN_06CB] Plugin = synaptics_rmi Vendor = Synaptics + +# Dell K12A kbd-dock +[DeviceInstanceId=HIDRAW\VEN_06CB&DEV_2819] +Flags = only-supported From d617d9e2874df82ac4186fcbef7363ea0713936e Mon Sep 17 00:00:00 2001 From: Mario Limonciello Date: Thu, 14 May 2020 13:15:40 -0500 Subject: [PATCH 060/607] trivial: downgrade CET to HSI:3 This is not actually a system protection, but rather a theoretical protection --- plugins/cpu/fu-plugin-cpu.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugins/cpu/fu-plugin-cpu.c b/plugins/cpu/fu-plugin-cpu.c index d62a3e5e4..030861199 100644 --- a/plugins/cpu/fu-plugin-cpu.c +++ b/plugins/cpu/fu-plugin-cpu.c @@ -61,7 +61,7 @@ fu_plugin_add_security_attrs (FuPlugin *plugin, FuSecurityAttrs *attrs) /* create attr */ attr = fwupd_security_attr_new ("com.intel.CET"); - fwupd_security_attr_set_level (attr, FWUPD_SECURITY_ATTR_LEVEL_SYSTEM_PROTECTION); + fwupd_security_attr_set_level (attr, FWUPD_SECURITY_ATTR_LEVEL_THEORETICAL); fwupd_security_attr_set_name (attr, "Intel CET"); fu_security_attrs_append (attrs, attr); From 9d07b7c23c51a8d59de347b155f4dbb7971bcd7b Mon Sep 17 00:00:00 2001 From: Michael Date: Thu, 14 May 2020 11:02:14 -0700 Subject: [PATCH 061/607] ata: Add WD OUI quirk 000cca --- plugins/ata/ata.quirk | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/plugins/ata/ata.quirk b/plugins/ata/ata.quirk index b8b66409f..49ab391af 100644 --- a/plugins/ata/ata.quirk +++ b/plugins/ata/ata.quirk @@ -14,6 +14,10 @@ VendorId = ATA:0x1BB1 Vendor = Seagate VendorId = ATA:0x1BB1 +[DeviceInstanceId=OUI\000cca] +Vendor = Western Digital +VendorId = ATA:0x101C + [DeviceInstanceId=OUI\0014ee] Vendor = Western Digital VendorId = ATA:0x101C From 7180536c6954227f056536d692502a0846f39e26 Mon Sep 17 00:00:00 2001 From: HROMANO Date: Thu, 14 May 2020 22:10:08 +0200 Subject: [PATCH 062/607] Add two OUI quirks Two OUI quirks outputed by 'fwupdtool get-updates' on my computer. --- plugins/ata/ata.quirk | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/plugins/ata/ata.quirk b/plugins/ata/ata.quirk index 49ab391af..8d71e2679 100644 --- a/plugins/ata/ata.quirk +++ b/plugins/ata/ata.quirk @@ -6,6 +6,10 @@ Plugin = ata Vendor = Toshiba VendorId = ATA:0x1179 +[DeviceInstanceId=OUI\0000f0] +Vendor = Samsung +VendorId = ATA:0x144D + [DeviceInstanceId=OUI\0004cf] Vendor = Seagate VendorId = ATA:0x1BB1 @@ -42,6 +46,10 @@ VendorId = ATA:0x144D Vendor = Micron VendorId = ATA:0x1344 +[DeviceInstanceId=OUI\550380] +Vendor = Kingston +VendorId = ATA:0x2646 + [DeviceInstanceId=OUI\5cd2e4] Vendor = Intel VendorId = ATA:0x8086 From 05b9eb59368f33f6d6af165794b5b689fb40e07e Mon Sep 17 00:00:00 2001 From: Mario Limonciello Date: Thu, 14 May 2020 15:40:24 -0500 Subject: [PATCH 063/607] trivial: remove an extra colon at the end of uefi-dbx error --- plugins/uefi-dbx/fu-plugin-uefi-dbx.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugins/uefi-dbx/fu-plugin-uefi-dbx.c b/plugins/uefi-dbx/fu-plugin-uefi-dbx.c index b38836967..46adf6429 100644 --- a/plugins/uefi-dbx/fu-plugin-uefi-dbx.c +++ b/plugins/uefi-dbx/fu-plugin-uefi-dbx.c @@ -66,7 +66,7 @@ fu_plugin_add_security_attrs (FuPlugin *plugin, FuSecurityAttrs *attrs) g_autofree gchar *dbxdir = NULL; g_autofree gchar *result = NULL; dbxdir = fu_common_get_path (FU_PATH_KIND_EFIDBXDIR); - result = g_strdup_printf ("DBX can be downloaded from %s and decompressed into %s: ", + result = g_strdup_printf ("DBX can be downloaded from %s and decompressed into %s", FU_UEFI_DBX_DATA_URL, dbxdir); fwupd_security_attr_set_result (attr, result); return; From fd732d219d87117f46a26fdc104f1f12dd64bfeb Mon Sep 17 00:00:00 2001 From: Richard Hughes Date: Thu, 14 May 2020 13:13:57 +0100 Subject: [PATCH 064/607] trivial: Fix a -Wnull-dereference false positive --- plugins/thunderbolt/fu-self-test.c | 1 + 1 file changed, 1 insertion(+) diff --git a/plugins/thunderbolt/fu-self-test.c b/plugins/thunderbolt/fu-self-test.c index 7a450b90a..12175ebfa 100644 --- a/plugins/thunderbolt/fu-self-test.c +++ b/plugins/thunderbolt/fu-self-test.c @@ -990,6 +990,7 @@ test_tree_uuids (const MockTree *node, gpointer data) g_debug ("Looking for %s", uuid); found = mock_tree_find_uuid (root, uuid); + g_assert_nonnull (node); g_assert_nonnull (found); g_assert_cmpstr (node->uuid, ==, found->uuid); From 9d4ce3c4f1b1817bedc03afd6ce40fddb47d2f84 Mon Sep 17 00:00:00 2001 From: Richard Hughes Date: Thu, 14 May 2020 13:26:11 +0100 Subject: [PATCH 065/607] trivial: Turn off werror for Arch CI --- contrib/PKGBUILD | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/contrib/PKGBUILD b/contrib/PKGBUILD index 55be00aec..df332515c 100644 --- a/contrib/PKGBUILD +++ b/contrib/PKGBUILD @@ -25,7 +25,7 @@ pkgver() { build() { cd ${pkgname} if [ -n "$CI" ]; then - export CI="--werror --wrap-mode=default" + export CI="--wrap-mode=default" fi arch-meson -D b_lto=false $CI ../build From 4661cc52d7f88be3b21dcdd44efb776a4db174e0 Mon Sep 17 00:00:00 2001 From: Richard Hughes Date: Thu, 14 May 2020 20:47:31 +0100 Subject: [PATCH 066/607] trivial: Set a log domain for the obsoleted message --- libfwupdplugin/fu-security-attrs.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/libfwupdplugin/fu-security-attrs.c b/libfwupdplugin/fu-security-attrs.c index b175238b4..dce052f58 100644 --- a/libfwupdplugin/fu-security-attrs.c +++ b/libfwupdplugin/fu-security-attrs.c @@ -4,6 +4,8 @@ * SPDX-License-Identifier: LGPL-2.1+ */ +#define G_LOG_DOMAIN "FuSecurityAttrs" + #include "config.h" #include From 1b97ee29c9c6d4663125cc4602fcaba10a3304aa Mon Sep 17 00:00:00 2001 From: Richard Hughes Date: Thu, 14 May 2020 20:48:06 +0100 Subject: [PATCH 067/607] trivial: Do not use a failed checkmark for an obsoleted attr --- src/fu-util-common.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/fu-util-common.c b/src/fu-util-common.c index 16a604aee..ba863f0e6 100644 --- a/src/fu-util-common.c +++ b/src/fu-util-common.c @@ -1552,7 +1552,9 @@ fu_util_remote_to_string (FwupdRemote *remote, guint idt) static void fu_security_attr_append_str (FwupdSecurityAttr *attr, GString *str) { - if (fwupd_security_attr_has_flag (attr, FWUPD_SECURITY_ATTR_FLAG_SUCCESS)) { + if (fwupd_security_attr_has_flag (attr, FWUPD_SECURITY_ATTR_FLAG_OBSOLETED)) { + g_string_append_printf (str, "\033[37m✦\033[0m "); + } else if (fwupd_security_attr_has_flag (attr, FWUPD_SECURITY_ATTR_FLAG_SUCCESS)) { g_string_append_printf (str, "\033[32m✔\033[0m "); } else { g_string_append_printf (str, "\033[31m✘\033[0m "); From 0f68c29908fbbd3c762308ebb09e8e66d25579e9 Mon Sep 17 00:00:00 2001 From: Mario Limonciello Date: Thu, 14 May 2020 16:28:15 -0500 Subject: [PATCH 068/607] trivial: Sort the HSI attribute list in the daemon Sort by level, success/fail/obsoleted, then by name. --- libfwupdplugin/fu-security-attrs.c | 42 +++++++++++++++++++++++++++++- 1 file changed, 41 insertions(+), 1 deletion(-) diff --git a/libfwupdplugin/fu-security-attrs.c b/libfwupdplugin/fu-security-attrs.c index dce052f58..ce5b41351 100644 --- a/libfwupdplugin/fu-security-attrs.c +++ b/libfwupdplugin/fu-security-attrs.c @@ -184,6 +184,43 @@ fu_security_attrs_calculate_hsi (FuSecurityAttrs *self) return g_string_free (str, FALSE); } +static gchar * +fu_security_attrs_get_sort_key (FwupdSecurityAttr *attr) +{ + GString *str = g_string_new (NULL); + + /* level */ + g_string_append_printf (str, "%u", fwupd_security_attr_get_level (attr)); + + /* success -> fail -> obsoletes */ + if (fwupd_security_attr_has_flag (attr, FWUPD_SECURITY_ATTR_FLAG_SUCCESS)) { + g_string_append (str, "0"); + } else if (!fwupd_security_attr_has_flag (attr, FWUPD_SECURITY_ATTR_FLAG_SUCCESS) && + !fwupd_security_attr_has_flag (attr, FWUPD_SECURITY_ATTR_FLAG_OBSOLETED)) { + g_string_append (str, "1"); + } else { + g_string_append (str, "9"); + } + + /* prefer name, but fallback to appstream-id for tests */ + if (fwupd_security_attr_get_name (attr) != NULL) { + g_string_append (str, fwupd_security_attr_get_name (attr)); + } else { + g_string_append (str, fwupd_security_attr_get_appstream_id (attr)); + } + return g_string_free (str, FALSE); +} + +static gint +fu_security_attrs_sort_cb (gconstpointer item1, gconstpointer item2) +{ + FwupdSecurityAttr *attr1 = *((FwupdSecurityAttr **) item1); + FwupdSecurityAttr *attr2 = *((FwupdSecurityAttr **) item2); + g_autofree gchar *sort1 = fu_security_attrs_get_sort_key (attr1); + g_autofree gchar *sort2 = fu_security_attrs_get_sort_key (attr2); + return g_strcmp0 (sort1, sort2); +} + /** * fu_security_attrs_depsolve: * @self: A #FuSecurityAttrs @@ -192,7 +229,7 @@ fu_security_attrs_calculate_hsi (FuSecurityAttrs *self) * defined as obsoleted by other attributes. * * It is only required to call this function once, and should be done when all - * attributes have been added. + * attributes have been added. This will also sort the attrs. * * Since: 1.5.0 **/ @@ -227,6 +264,9 @@ fu_security_attrs_depsolve (FuSecurityAttrs *self) } } } + + /* sort */ + g_ptr_array_sort (self->attrs, fu_security_attrs_sort_cb); } /** From 8fdefd459b69d867343952b44ed318f3f8045ae9 Mon Sep 17 00:00:00 2001 From: Richard Hughes Date: Thu, 14 May 2020 20:53:38 +0100 Subject: [PATCH 069/607] pci-bcr: Read the PCI BCR config register from userspace We can read this from userspace even when SB is turned on and with the kernel locked down. The kernel securityfs patches are still in-progress, but will take significant time to get upstream. The kernel patches are needed when the PCI device is hidden from userspace. --- contrib/debian/lintian/fwupd | 1 + contrib/fwupd.spec.in | 1 + plugins/meson.build | 1 + plugins/pci-bcr/README.md | 8 ++ plugins/pci-bcr/config | Bin 0 -> 64 bytes plugins/pci-bcr/fu-plugin-pci-bcr.c | 162 +++++++++++++++++++++++++ plugins/pci-bcr/meson.build | 27 +++++ plugins/pci-bcr/pci-bcr.quirk | 181 ++++++++++++++++++++++++++++ 8 files changed, 381 insertions(+) create mode 100644 plugins/pci-bcr/README.md create mode 100644 plugins/pci-bcr/config create mode 100644 plugins/pci-bcr/fu-plugin-pci-bcr.c create mode 100644 plugins/pci-bcr/meson.build create mode 100644 plugins/pci-bcr/pci-bcr.quirk diff --git a/contrib/debian/lintian/fwupd b/contrib/debian/lintian/fwupd index b262ba053..369f1b991 100644 --- a/contrib/debian/lintian/fwupd +++ b/contrib/debian/lintian/fwupd @@ -9,3 +9,4 @@ fwupd: library-not-linked-against-libc usr/lib/*/fwupd-plugins-3/libfu_plugin_ue fwupd: executable-not-elf-or-script usr/libexec/fwupd/efi/*.efi fwupd: portable-executable-missing-security-features usr/libexec/fwupd/efi/*.efi SafeSEH fwupd: library-not-linked-against-libc usr/lib/*/fwupd-plugins-3/libfu_plugin_modem_manager.so +fwupd: library-not-linked-against-libc usr/lib/*/fwupd-plugins-3/libfu_plugin_pci_bcr.so diff --git a/contrib/fwupd.spec.in b/contrib/fwupd.spec.in index 78f3777f8..5f13d19d0 100644 --- a/contrib/fwupd.spec.in +++ b/contrib/fwupd.spec.in @@ -367,6 +367,7 @@ mkdir -p --mode=0700 $RPM_BUILD_ROOT%{_localstatedir}/lib/fwupd/gnupg %{_libdir}/fwupd-plugins-3/libfu_plugin_nvme.so %endif %{_libdir}/fwupd-plugins-3/libfu_plugin_optionrom.so +%{_libdir}/fwupd-plugins-3/libfu_plugin_pci_bcr.so %if 0%{?have_redfish} %{_libdir}/fwupd-plugins-3/libfu_plugin_redfish.so %endif diff --git a/plugins/meson.build b/plugins/meson.build index f63e4f52a..a9d4096cd 100644 --- a/plugins/meson.build +++ b/plugins/meson.build @@ -17,6 +17,7 @@ subdir('linux-tainted') subdir('steelseries') subdir('dell-dock') subdir('nitrokey') +subdir('pci-bcr') subdir('rts54hid') subdir('rts54hub') subdir('solokey') diff --git a/plugins/pci-bcr/README.md b/plugins/pci-bcr/README.md new file mode 100644 index 000000000..c838edea9 --- /dev/null +++ b/plugins/pci-bcr/README.md @@ -0,0 +1,8 @@ +PCI BIOS Control Register +========================= + +Introduction +------------ + +This plugin checks if the system SPI chip is locked. The result will be stored +in an security attribute for HSI. diff --git a/plugins/pci-bcr/config b/plugins/pci-bcr/config new file mode 100644 index 0000000000000000000000000000000000000000..7d79f10fbee5a4d3f8443503d26591c517628adc GIT binary patch literal 64 fcmZo`2w2F@z`$h4z{tkH(7=EXtPn# literal 0 HcmV?d00001 diff --git a/plugins/pci-bcr/fu-plugin-pci-bcr.c b/plugins/pci-bcr/fu-plugin-pci-bcr.c new file mode 100644 index 000000000..f22b0a4fd --- /dev/null +++ b/plugins/pci-bcr/fu-plugin-pci-bcr.c @@ -0,0 +1,162 @@ +/* + * Copyright (C) 2020 Richard Hughes + * + * SPDX-License-Identifier: LGPL-2.1+ + */ + +#include "config.h" + +#include +#include +#include + +#include "fu-plugin-vfuncs.h" +#include "fu-hash.h" + +struct FuPluginData { + gboolean has_device; + guint8 bcr; +}; + +#define BCR 0xdc +#define BCR_WPD (1 << 0) +#define BCR_BLE (1 << 1) +#define BCR_SMM_BWP (1 << 5) + +void +fu_plugin_init (FuPlugin *plugin) +{ + fu_plugin_alloc_data (plugin, sizeof (FuPluginData)); + fu_plugin_set_build_hash (plugin, FU_BUILD_HASH); +} + +static void +fu_plugin_add_security_attr_bioswe (FuPlugin *plugin, FuSecurityAttrs *attrs) +{ + FuPluginData *priv = fu_plugin_get_data (plugin); + g_autoptr(FwupdSecurityAttr) attr = NULL; + + /* create attr */ + attr = fwupd_security_attr_new ("com.intel.BIOSWE"); + fwupd_security_attr_set_level (attr, FWUPD_SECURITY_ATTR_LEVEL_CRITICAL); + fwupd_security_attr_set_name (attr, "SPI"); + fwupd_security_attr_add_obsolete (attr, "org.kernel.BIOSWE"); + fu_security_attrs_append (attrs, attr); + + /* load file */ + if ((priv->bcr & BCR_WPD) == 1) { + fwupd_security_attr_set_result (attr, "Write enabled"); + return; + } + + /* success */ + fwupd_security_attr_add_flag (attr, FWUPD_SECURITY_ATTR_FLAG_SUCCESS); + fwupd_security_attr_set_result (attr, "Write disabled"); +} + +static void +fu_plugin_add_security_attr_ble (FuPlugin *plugin, FuSecurityAttrs *attrs) +{ + FuPluginData *priv = fu_plugin_get_data (plugin); + g_autoptr(FwupdSecurityAttr) attr = NULL; + + /* create attr */ + attr = fwupd_security_attr_new ("com.intel.BLE"); + fwupd_security_attr_set_level (attr, FWUPD_SECURITY_ATTR_LEVEL_CRITICAL); + fwupd_security_attr_set_name (attr, "SPI"); + fwupd_security_attr_add_obsolete (attr, "org.kernel.BLE"); + fu_security_attrs_append (attrs, attr); + + /* load file */ + if ((priv->bcr & BCR_BLE) == 0) { + fwupd_security_attr_set_result (attr, "Lock disabled"); + return; + } + + /* success */ + fwupd_security_attr_add_flag (attr, FWUPD_SECURITY_ATTR_FLAG_SUCCESS); + fwupd_security_attr_set_result (attr, "Lock enabled"); +} + +static void +fu_plugin_add_security_attr_smm_bwp (FuPlugin *plugin, FuSecurityAttrs *attrs) +{ + FuPluginData *priv = fu_plugin_get_data (plugin); + g_autoptr(FwupdSecurityAttr) attr = NULL; + + /* create attr */ + attr = fwupd_security_attr_new ("com.intel.SMM_BWP"); + fwupd_security_attr_set_level (attr, FWUPD_SECURITY_ATTR_LEVEL_CRITICAL); + fwupd_security_attr_set_name (attr, "BIOS region of SPI"); + fwupd_security_attr_add_obsolete (attr, "org.kernel.SMM_BWP"); + fu_security_attrs_append (attrs, attr); + + /* load file */ + if ((priv->bcr & BCR_SMM_BWP) == 0) { + fwupd_security_attr_set_result (attr, "Writable by OS"); + return; + } + + /* success */ + fwupd_security_attr_add_flag (attr, FWUPD_SECURITY_ATTR_FLAG_SUCCESS); + fwupd_security_attr_set_result (attr, "Writable only through BIOS"); +} + +gboolean +fu_plugin_udev_device_added (FuPlugin *plugin, FuUdevDevice *device, GError **error) +{ +#ifndef _WIN32 + FuPluginData *priv = fu_plugin_get_data (plugin); + gint fd; + g_autofree gchar *fn = NULL; + + /* interesting device? */ + if (g_strcmp0 (fu_udev_device_get_subsystem (device), "pci") != 0) + return TRUE; + + /* open config */ + fn = g_build_filename (fu_udev_device_get_sysfs_path (device), "config", NULL); + fd = g_open (fn, O_RDONLY); + if (fd < 0) { + g_set_error (error, + G_IO_ERROR, + G_IO_ERROR_FAILED, + "could not open %s", fn); + return FALSE; + } + + /* grab BIOS Control Register */ + if (pread (fd, &priv->bcr, 0x01, BCR) != 1) { + g_close (fd, NULL); + g_set_error (error, + G_IO_ERROR, + G_IO_ERROR_FAILED, + "could not read BCR from %s", + fn); + return FALSE; + } + priv->has_device = TRUE; + return g_close (fd, error); +#else + g_set_error_literal (error, + FWUPD_ERROR, + FWUPD_ERROR_NOT_SUPPORTED, + "pci reads not currently supported on Windows"); + return FALSE; +#endif +} + +void +fu_plugin_add_security_attrs (FuPlugin *plugin, FuSecurityAttrs *attrs) +{ + FuPluginData *priv = fu_plugin_get_data (plugin); + + /* only Intel */ + if (!priv->has_device) + return; + + /* add attrs */ + fu_plugin_add_security_attr_bioswe (plugin, attrs); + fu_plugin_add_security_attr_ble (plugin, attrs); + fu_plugin_add_security_attr_smm_bwp (plugin, attrs); +} diff --git a/plugins/pci-bcr/meson.build b/plugins/pci-bcr/meson.build new file mode 100644 index 000000000..f5345935b --- /dev/null +++ b/plugins/pci-bcr/meson.build @@ -0,0 +1,27 @@ +cargs = ['-DG_LOG_DOMAIN="FuPluginPciBcr"'] + +install_data(['pci-bcr.quirk'], + install_dir: join_paths(datadir, 'fwupd', 'quirks.d') +) + +shared_module('fu_plugin_pci_bcr', + fu_hash, + sources : [ + 'fu-plugin-pci-bcr.c', + ], + include_directories : [ + root_incdir, + fwupd_incdir, + fwupdplugin_incdir, + ], + install : true, + install_dir: plugin_dir, + link_with : [ + fwupd, + fwupdplugin, + ], + c_args : cargs, + dependencies : [ + plugin_deps, + ], +) diff --git a/plugins/pci-bcr/pci-bcr.quirk b/plugins/pci-bcr/pci-bcr.quirk new file mode 100644 index 000000000..d5afebf30 --- /dev/null +++ b/plugins/pci-bcr/pci-bcr.quirk @@ -0,0 +1,181 @@ +# ISA bridge i.e. 00:1F.0 +# -> drivers/mfd/lpc_ich.c + +# Sunrise Point LPC/eSPI +[DeviceInstanceId=PCI\VEN_8086&DEV_9D4E] +Plugin = pci_bcr + +# Tiger Lake +[DeviceInstanceId=PCI\VEN_8086&DEV_A0A4] +Plugin = pci_bcr + +# Sunrise Point-H LPC +[DeviceInstanceId=PCI\VEN_8086&DEV_A140] +Plugin = pci_bcr + +# Sunrise Point-H LPC +[DeviceInstanceId=PCI\VEN_8086&DEV_A141] +Plugin = pci_bcr + +# Sunrise Point-H LPC +[DeviceInstanceId=PCI\VEN_8086&DEV_A142] +Plugin = pci_bcr + +# H110 LPC/eSPI +[DeviceInstanceId=PCI\VEN_8086&DEV_A143] +Plugin = pci_bcr + +# H170 LPC/eSPI +[DeviceInstanceId=PCI\VEN_8086&DEV_A144] +Plugin = pci_bcr + +# Z170 LPC/eSPI +[DeviceInstanceId=PCI\VEN_8086&DEV_A145] +Plugin = pci_bcr + +# Q170 LPC/eSPI +[DeviceInstanceId=PCI\VEN_8086&DEV_A146] +Plugin = pci_bcr + +# Q150 LPC/eSPI +[DeviceInstanceId=PCI\VEN_8086&DEV_A147] +Plugin = pci_bcr + +# B150 LPC/eSPI +[DeviceInstanceId=PCI\VEN_8086&DEV_A148] +Plugin = pci_bcr + +# C236 LPC/eSPI +[DeviceInstanceId=PCI\VEN_8086&DEV_A149] +Plugin = pci_bcr + +# C232 LPC/eSPI +[DeviceInstanceId=PCI\VEN_8086&DEV_A14A] +Plugin = pci_bcr + +# Sunrise Point-H LPC +[DeviceInstanceId=PCI\VEN_8086&DEV_A14B] +Plugin = pci_bcr + +# Sunrise Point-H LPC +[DeviceInstanceId=PCI\VEN_8086&DEV_A14C] +Plugin = pci_bcr + +# QM170 LPC/eSPI +[DeviceInstanceId=PCI\VEN_8086&DEV_A14D] +Plugin = pci_bcr + +# HM170 LPC/eSPI +[DeviceInstanceId=PCI\VEN_8086&DEV_A14E] +Plugin = pci_bcr + +# Sunrise Point-H LPC +[DeviceInstanceId=PCI\VEN_8086&DEV_A14F] +Plugin = pci_bcr + +# CM236 LPC/eSPI +[DeviceInstanceId=PCI\VEN_8086&DEV_A150] +Plugin = pci_bcr + +# Sunrise Point-H LPC +[DeviceInstanceId=PCI\VEN_8086&DEV_A151] +Plugin = pci_bcr + +# HM175 LPC/eSPI +[DeviceInstanceId=PCI\VEN_8086&DEV_A152] +Plugin = pci_bcr + +# QM175 LPC/eSPI +[DeviceInstanceId=PCI\VEN_8086&DEV_A153] +Plugin = pci_bcr + +# CM238 LPC/eSPI +[DeviceInstanceId=PCI\VEN_8086&DEV_A154] +Plugin = pci_bcr + +# Sunrise Point-H LPC +[DeviceInstanceId=PCI\VEN_8086&DEV_A155] +Plugin = pci_bcr + +# C621 LPC/eSPI +[DeviceInstanceId=PCI\VEN_8086&DEV_A1C1] +Plugin = pci_bcr + +# C622 LPC/eSPI +[DeviceInstanceId=PCI\VEN_8086&DEV_A1C2] +Plugin = pci_bcr + +# C624 LPC/eSPI +[DeviceInstanceId=PCI\VEN_8086&DEV_A1C3] +Plugin = pci_bcr + +# C625 LPC/eSPI +[DeviceInstanceId=PCI\VEN_8086&DEV_A1C4] +Plugin = pci_bcr + +# C626 LPC/eSPI +[DeviceInstanceId=PCI\VEN_8086&DEV_A1C5] +Plugin = pci_bcr + +# C627 LPC/eSPI +[DeviceInstanceId=PCI\VEN_8086&DEV_A1C6] +Plugin = pci_bcr + +# C628 LPC/eSPI +[DeviceInstanceId=PCI\VEN_8086&DEV_A1C7] +Plugin = pci_bcr + +# H370 LPC/eSPI +[DeviceInstanceId=PCI\VEN_8086&DEV_A304] +Plugin = pci_bcr + +# Z390 LPC/eSPI +[DeviceInstanceId=PCI\VEN_8086&DEV_A305] +Plugin = pci_bcr + +# Q370 LPC/eSPI +[DeviceInstanceId=PCI\VEN_8086&DEV_A306] +Plugin = pci_bcr + +# QM370 LPC/eSPI +[DeviceInstanceId=PCI\VEN_8086&DEV_A30C] +Plugin = pci_bcr + +# PCI devices, i.e. 00:1F.5 +# -> drivers/mtd/spi-nor/controllers/intel-spi-pci.c + +# Comet Lake SPI +[DeviceInstanceId=PCI\VEN_8086&DEV_02A4] +Plugin = pci_bcr + +# Comet Lake H +[DeviceInstanceId=PCI\VEN_8086&DEV_06A4] +Plugin = pci_bcr + +# Ice Lake-LP SPI +[DeviceInstanceId=PCI\VEN_8086&DEV_34A4] +Plugin = pci_bcr + +# Elkhart Lake +[DeviceInstanceId=PCI\VEN_8086&DEV_4B24] +Plugin = pci_bcr + +# Jasper Lake +[DeviceInstanceId=PCI\VEN_8086&DEV_4DA4] +Plugin = pci_bcr + +# Cannon Point-LP SPI +[DeviceInstanceId=PCI\VEN_8086&DEV_9DA4] +Plugin = pci_bcr + +# C620 SPI +[DeviceInstanceId=PCI\VEN_8086&DEV_A1A4] +Plugin = pci_bcr + +# Cannon Lake PCH SPI +[DeviceInstanceId=PCI\VEN_8086&DEV_A324] +Plugin = pci_bcr + +# Comet Lake V +[DeviceInstanceId=PCI\VEN_8086&DEV_A3A4] +Plugin = pci_bcr From 730e2bd6e373c25151b81268a1740c982b36e5bb Mon Sep 17 00:00:00 2001 From: Richard Hughes Date: Fri, 15 May 2020 09:56:02 +0100 Subject: [PATCH 070/607] linux-spi-lpc: Disable by default The kernel patches are a log way from being upstreamed, so disable this until there is even a chance the user might be running it. This removes the obsoletes line from *every* system running 'fwupdmgr security'. --- contrib/fwupd.spec.in | 1 - meson_options.txt | 1 + plugins/meson.build | 5 ++++- 3 files changed, 5 insertions(+), 2 deletions(-) diff --git a/contrib/fwupd.spec.in b/contrib/fwupd.spec.in index 5f13d19d0..86633a743 100644 --- a/contrib/fwupd.spec.in +++ b/contrib/fwupd.spec.in @@ -356,7 +356,6 @@ mkdir -p --mode=0700 $RPM_BUILD_ROOT%{_localstatedir}/lib/fwupd/gnupg %{_libdir}/fwupd-plugins-3/libfu_plugin_jabra.so %{_libdir}/fwupd-plugins-3/libfu_plugin_linux_lockdown.so %{_libdir}/fwupd-plugins-3/libfu_plugin_linux_sleep.so -%{_libdir}/fwupd-plugins-3/libfu_plugin_linux_spi_lpc.so %{_libdir}/fwupd-plugins-3/libfu_plugin_linux_swap.so %{_libdir}/fwupd-plugins-3/libfu_plugin_linux_tainted.so %if 0%{?have_modem_manager} diff --git a/meson_options.txt b/meson_options.txt index 5dacb4cf4..2e8f71a4b 100644 --- a/meson_options.txt +++ b/meson_options.txt @@ -21,6 +21,7 @@ option('plugin_nvme', type : 'boolean', value : true, description : 'enable NVMe option('plugin_modem_manager', type : 'boolean', value : false, description : 'enable ModemManager support') option('plugin_flashrom', type : 'boolean', value : false, description : 'enable libflashrom support') option('plugin_coreboot', type : 'boolean', value : true, description : 'enable coreboot support') +option('plugin_linux_spi_lpc', type : 'boolean', value : false, description : 'enable Linux SPI SecurityFS support') option('systemd', type : 'boolean', value : true, description : 'enable systemd support') option('systemd_root_prefix', type: 'string', value: '', description: 'Directory to base systemd’s installation directories on') option('elogind', type : 'boolean', value : false, description : 'enable elogind support') diff --git a/plugins/meson.build b/plugins/meson.build index a9d4096cd..eabdb7844 100644 --- a/plugins/meson.build +++ b/plugins/meson.build @@ -11,7 +11,6 @@ subdir('fresco-pd') subdir('jabra') subdir('linux-lockdown') subdir('linux-sleep') -subdir('linux-spi-lpc') subdir('linux-swap') subdir('linux-tainted') subdir('steelseries') @@ -28,6 +27,10 @@ subdir('upower') subdir('wacom-usb') subdir('vli') +if get_option('plugin_linux_spi_lpc') +subdir('linux-spi-lpc') +endif + if get_option('gudev') subdir('ata') subdir('logitech-hidpp') From 983263bc8d0bdeffbad79c90f89d8612bc083871 Mon Sep 17 00:00:00 2001 From: Mario Limonciello Date: Thu, 14 May 2020 20:08:34 -0500 Subject: [PATCH 071/607] cpu: Add support for a security attribute related to Intel TME This only checks that it was available from the CPU. To be complete an additional check should be made to show that it was actually enabled from the firmware. This will require a kernel modification though because MSR access will be forbidden from userland while in kernel lockdown. --- plugins/cpu/fu-cpu-device.c | 27 +++++++++---------- plugins/cpu/fu-cpu-device.h | 11 ++++++-- plugins/cpu/fu-plugin-cpu.c | 53 ++++++++++++++++++++++++++++++------- 3 files changed, 65 insertions(+), 26 deletions(-) diff --git a/plugins/cpu/fu-cpu-device.c b/plugins/cpu/fu-cpu-device.c index 424865322..bbfa77387 100644 --- a/plugins/cpu/fu-cpu-device.c +++ b/plugins/cpu/fu-cpu-device.c @@ -10,30 +10,27 @@ struct _FuCpuDevice { FuDevice parent_instance; - gboolean has_shstk; - gboolean has_ibt; + FuCpuDeviceFlag flags; }; G_DEFINE_TYPE (FuCpuDevice, fu_cpu_device, FU_TYPE_DEVICE) gboolean -fu_cpu_device_has_shstk (FuCpuDevice *self) +fu_cpu_device_has_flag (FuCpuDevice *self, FuCpuDeviceFlag flag) { - return self->has_shstk; -} - -gboolean -fu_cpu_device_has_ibt (FuCpuDevice *self) -{ - return self->has_ibt; + return (self->flags & flag) > 0; } static void fu_cpu_device_to_string (FuDevice *device, guint idt, GString *str) { FuCpuDevice *self = FU_CPU_DEVICE (device); - fu_common_string_append_kb (str, idt, "HasSHSTK", self->has_shstk); - fu_common_string_append_kb (str, idt, "HasIBT", self->has_ibt); + fu_common_string_append_kb (str, idt, "HasSHSTK", + fu_cpu_device_has_flag (self, FU_CPU_DEVICE_FLAG_SHSTK)); + fu_common_string_append_kb (str, idt, "HasIBT", + fu_cpu_device_has_flag (self, FU_CPU_DEVICE_FLAG_IBT)); + fu_common_string_append_kb (str, idt, "HasTME", + fu_cpu_device_has_flag (self, FU_CPU_DEVICE_FLAG_TME)); } static void @@ -42,9 +39,11 @@ fu_cpu_device_parse_flags (FuCpuDevice *self, const gchar *data) g_auto(GStrv) flags = g_strsplit (data, " ", -1); for (guint i = 0; flags[i] != NULL; i++) { if (g_strcmp0 (flags[i], "shstk") == 0) - self->has_shstk = TRUE; + self->flags |= FU_CPU_DEVICE_FLAG_SHSTK; if (g_strcmp0 (flags[i], "ibt") == 0) - self->has_ibt = TRUE; + self->flags |= FU_CPU_DEVICE_FLAG_IBT; + if (g_strcmp0 (flags[i], "tme") == 0) + self->flags |= FU_CPU_DEVICE_FLAG_TME; } } diff --git a/plugins/cpu/fu-cpu-device.h b/plugins/cpu/fu-cpu-device.h index 1d198de58..b0c7de2a7 100644 --- a/plugins/cpu/fu-cpu-device.h +++ b/plugins/cpu/fu-cpu-device.h @@ -11,6 +11,13 @@ #define FU_TYPE_CPU_DEVICE (fu_cpu_device_get_type ()) G_DECLARE_FINAL_TYPE (FuCpuDevice, fu_cpu_device, FU, CPU_DEVICE, FuDevice) +typedef enum { + FU_CPU_DEVICE_FLAG_NONE = 0, + FU_CPU_DEVICE_FLAG_SHSTK = 1 << 0, + FU_CPU_DEVICE_FLAG_IBT = 1 << 1, + FU_CPU_DEVICE_FLAG_TME = 1 << 2, +} FuCpuDeviceFlag; + FuCpuDevice *fu_cpu_device_new (const gchar *section); -gboolean fu_cpu_device_has_shstk (FuCpuDevice *self); -gboolean fu_cpu_device_has_ibt (FuCpuDevice *self); +gboolean fu_cpu_device_has_flag (FuCpuDevice *self, + FuCpuDeviceFlag flag); diff --git a/plugins/cpu/fu-plugin-cpu.c b/plugins/cpu/fu-plugin-cpu.c index 030861199..a2196ca0f 100644 --- a/plugins/cpu/fu-plugin-cpu.c +++ b/plugins/cpu/fu-plugin-cpu.c @@ -12,6 +12,7 @@ struct FuPluginData { gboolean has_cet; + gboolean has_tme; }; void @@ -40,8 +41,8 @@ fu_plugin_coldplug (FuPlugin *plugin, GError **error) dev = fu_cpu_device_new (lines[i]); if (!fu_device_setup (FU_DEVICE (dev), error)) return FALSE; - if (fu_cpu_device_has_shstk (dev) && - fu_cpu_device_has_ibt (dev)) + if (fu_cpu_device_has_flag (dev, FU_CPU_DEVICE_FLAG_SHSTK) && + fu_cpu_device_has_flag (dev, FU_CPU_DEVICE_FLAG_IBT)) data->has_cet = TRUE; fu_plugin_device_add (plugin, FU_DEVICE (dev)); } @@ -49,20 +50,16 @@ fu_plugin_coldplug (FuPlugin *plugin, GError **error) return TRUE; } -void -fu_plugin_add_security_attrs (FuPlugin *plugin, FuSecurityAttrs *attrs) +static void +fu_plugin_add_security_attrs_intel_cet (FuPlugin *plugin, FuSecurityAttrs *attrs) { FuPluginData *data = fu_plugin_get_data (plugin); g_autoptr(FwupdSecurityAttr) attr = NULL; - /* only Intel */ - if (!fu_common_is_cpu_intel ()) - return; - /* create attr */ attr = fwupd_security_attr_new ("com.intel.CET"); fwupd_security_attr_set_level (attr, FWUPD_SECURITY_ATTR_LEVEL_THEORETICAL); - fwupd_security_attr_set_name (attr, "Intel CET"); + fwupd_security_attr_set_name (attr, "Intel control enforcement technology (CET)"); fu_security_attrs_append (attrs, attr); /* check for CET */ @@ -70,6 +67,42 @@ fu_plugin_add_security_attrs (FuPlugin *plugin, FuSecurityAttrs *attrs) fwupd_security_attr_set_result (attr, "Unavailable"); return; } + + /* success */ fwupd_security_attr_add_flag (attr, FWUPD_SECURITY_ATTR_FLAG_SUCCESS); - fwupd_security_attr_set_result (attr, "SHSTK+IBT"); + fwupd_security_attr_set_result (attr, "Available"); +} + +static void +fu_plugin_add_security_attrs_intel_tme (FuPlugin *plugin, FuSecurityAttrs *attrs) +{ + FuPluginData *data = fu_plugin_get_data (plugin); + g_autoptr(FwupdSecurityAttr) attr = NULL; + + /* create attr */ + attr = fwupd_security_attr_new ("com.intel.TME"); + fwupd_security_attr_set_level (attr, FWUPD_SECURITY_ATTR_LEVEL_SYSTEM_PROTECTION); + fwupd_security_attr_set_name (attr, "Intel total memory encryption (TME)"); + fu_security_attrs_append (attrs, attr); + + /* check for TME */ + if (!data->has_tme) { + fwupd_security_attr_set_result (attr, "Unavailable"); + return; + } + + /* success */ + fwupd_security_attr_add_flag (attr, FWUPD_SECURITY_ATTR_FLAG_SUCCESS); + fwupd_security_attr_set_result (attr, "Available"); +} + +void +fu_plugin_add_security_attrs (FuPlugin *plugin, FuSecurityAttrs *attrs) +{ + /* only Intel */ + if (!fu_common_is_cpu_intel ()) + return; + + fu_plugin_add_security_attrs_intel_cet (plugin, attrs); + fu_plugin_add_security_attrs_intel_tme (plugin, attrs); } From 43451d458b2c8c57619471b40351dad6c42dfae3 Mon Sep 17 00:00:00 2001 From: Richard Hughes Date: Fri, 15 May 2020 14:48:41 +0100 Subject: [PATCH 072/607] pci-bcr: Fail HSI:1 if the BCR register cannot be loaded Add obsoletes to attributes added by linux-spi-lpc if we're using the kernel support for hidden PCI devices. --- plugins/linux-spi-lpc/fu-plugin-linux-spi-lpc.c | 5 ++++- plugins/pci-bcr/fu-plugin-pci-bcr.c | 16 +++++++++++++++- 2 files changed, 19 insertions(+), 2 deletions(-) diff --git a/plugins/linux-spi-lpc/fu-plugin-linux-spi-lpc.c b/plugins/linux-spi-lpc/fu-plugin-linux-spi-lpc.c index 2ff323c2f..b20b50529 100644 --- a/plugins/linux-spi-lpc/fu-plugin-linux-spi-lpc.c +++ b/plugins/linux-spi-lpc/fu-plugin-linux-spi-lpc.c @@ -31,6 +31,7 @@ fu_plugin_add_security_attr_bioswe (FuPlugin *plugin, FuSecurityAttrs *attrs) attr = fwupd_security_attr_new ("org.kernel.BIOSWE"); fwupd_security_attr_set_level (attr, FWUPD_SECURITY_ATTR_LEVEL_CRITICAL); fwupd_security_attr_set_name (attr, "SPI"); + fwupd_security_attr_add_obsolete (attr, "org.fwupd.plugin.pci-bcr"); fu_security_attrs_append (attrs, attr); /* load file */ @@ -63,6 +64,7 @@ fu_plugin_add_security_attr_ble (FuPlugin *plugin, FuSecurityAttrs *attrs) attr = fwupd_security_attr_new ("org.kernel.BLE"); fwupd_security_attr_set_level (attr, FWUPD_SECURITY_ATTR_LEVEL_CRITICAL); fwupd_security_attr_set_name (attr, "SPI"); + fwupd_security_attr_add_obsolete (attr, "org.fwupd.plugin.pci-bcr"); fu_security_attrs_append (attrs, attr); /* load file */ @@ -95,6 +97,7 @@ fu_plugin_add_security_attr_smm_bwp (FuPlugin *plugin, FuSecurityAttrs *attrs) attr = fwupd_security_attr_new ("org.kernel.SMM_BWP"); fwupd_security_attr_set_level (attr, FWUPD_SECURITY_ATTR_LEVEL_CRITICAL); fwupd_security_attr_set_name (attr, "BIOS region of SPI"); + fwupd_security_attr_add_obsolete (attr, "org.fwupd.plugin.pci-bcr"); fu_security_attrs_append (attrs, attr); /* load file */ @@ -124,7 +127,7 @@ fu_plugin_add_security_attrs (FuPlugin *plugin, FuSecurityAttrs *attrs) /* maybe the kernel module does not exist */ if (!g_file_test (FU_PLUGIN_LINUX_SPI_LPC_SYSFS_DIR, G_FILE_TEST_IS_DIR)) { g_autoptr(FwupdSecurityAttr) attr = NULL; - attr = fwupd_security_attr_new ("org.kernel.BIOSWE"); + attr = fwupd_security_attr_new ("org.fwupd.plugin.linux-spi-lpc"); fwupd_security_attr_set_level (attr, FWUPD_SECURITY_ATTR_LEVEL_CRITICAL); fwupd_security_attr_set_name (attr, "SPI"); fwupd_security_attr_set_result (attr, "Kernel support not present"); diff --git a/plugins/pci-bcr/fu-plugin-pci-bcr.c b/plugins/pci-bcr/fu-plugin-pci-bcr.c index f22b0a4fd..92c3fb9ba 100644 --- a/plugins/pci-bcr/fu-plugin-pci-bcr.c +++ b/plugins/pci-bcr/fu-plugin-pci-bcr.c @@ -41,6 +41,7 @@ fu_plugin_add_security_attr_bioswe (FuPlugin *plugin, FuSecurityAttrs *attrs) fwupd_security_attr_set_level (attr, FWUPD_SECURITY_ATTR_LEVEL_CRITICAL); fwupd_security_attr_set_name (attr, "SPI"); fwupd_security_attr_add_obsolete (attr, "org.kernel.BIOSWE"); + fwupd_security_attr_add_obsolete (attr, "org.fwupd.plugin.linux-spi-lpc"); fu_security_attrs_append (attrs, attr); /* load file */ @@ -65,6 +66,7 @@ fu_plugin_add_security_attr_ble (FuPlugin *plugin, FuSecurityAttrs *attrs) fwupd_security_attr_set_level (attr, FWUPD_SECURITY_ATTR_LEVEL_CRITICAL); fwupd_security_attr_set_name (attr, "SPI"); fwupd_security_attr_add_obsolete (attr, "org.kernel.BLE"); + fwupd_security_attr_add_obsolete (attr, "org.fwupd.plugin.linux-spi-lpc"); fu_security_attrs_append (attrs, attr); /* load file */ @@ -89,6 +91,7 @@ fu_plugin_add_security_attr_smm_bwp (FuPlugin *plugin, FuSecurityAttrs *attrs) fwupd_security_attr_set_level (attr, FWUPD_SECURITY_ATTR_LEVEL_CRITICAL); fwupd_security_attr_set_name (attr, "BIOS region of SPI"); fwupd_security_attr_add_obsolete (attr, "org.kernel.SMM_BWP"); + fwupd_security_attr_add_obsolete (attr, "org.fwupd.plugin.linux-spi-lpc"); fu_security_attrs_append (attrs, attr); /* load file */ @@ -152,9 +155,20 @@ fu_plugin_add_security_attrs (FuPlugin *plugin, FuSecurityAttrs *attrs) FuPluginData *priv = fu_plugin_get_data (plugin); /* only Intel */ - if (!priv->has_device) + if (!fu_common_is_cpu_intel ()) return; + /* only Intel */ + if (!priv->has_device) { + g_autoptr(FwupdSecurityAttr) attr = NULL; + attr = fwupd_security_attr_new ("org.fwupd.plugin.pci-bcr"); + fwupd_security_attr_set_level (attr, FWUPD_SECURITY_ATTR_LEVEL_CRITICAL); + fwupd_security_attr_set_name (attr, "SPI"); + fwupd_security_attr_set_result (attr, "No PCI devices with BCR"); + fu_security_attrs_append (attrs, attr); + return; + } + /* add attrs */ fu_plugin_add_security_attr_bioswe (plugin, attrs); fu_plugin_add_security_attr_ble (plugin, attrs); From 07f3fe702b6e426a1e5019179e5c94c4dc6825c6 Mon Sep 17 00:00:00 2001 From: Mario Limonciello Date: Thu, 14 May 2020 15:55:26 -0500 Subject: [PATCH 073/607] trivial: if not specified try to use some better dbx defaults --- meson.build | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/meson.build b/meson.build index 7106de70b..766bf8776 100644 --- a/meson.build +++ b/meson.build @@ -289,11 +289,16 @@ if build_standalone and get_option('plugin_uefi') efi_app_location = join_paths(libexecdir, 'fwupd', 'efi') conf.set_quoted ('EFI_APP_LOCATION', efi_app_location) - # e.g. could be: - # * /usr/share/dbxtool for Red Hat - # * /usr/share/secureboot/updates/dbx for Ubuntu efi_dbxdir = get_option('efi_dbxdir') + if efi_dbxdir == '' + foreach dir : ['/usr/share/secureboot/updates/dbx', '/usr/share/dbxtool'] + if run_command('[', '-d', dir, ']').returncode() == 0 + efi_dbxdir = dir + endif + endforeach + endif if efi_dbxdir != '' + message('efi-dbxdir: "@0@"'.format(efi_dbxdir)) conf.set_quoted ('FWUPD_EFI_DBXDIR', efi_dbxdir) endif From cae111d1de2fbdfe377f02e018cf24619352e800 Mon Sep 17 00:00:00 2001 From: Richard Hughes Date: Fri, 15 May 2020 15:20:24 +0100 Subject: [PATCH 074/607] Save the plugin that created the FwupdSecurityAttr This is really useful for debugging. --- libfwupd/fwupd-security-attr.c | 40 +++++++++++++++++++ libfwupd/fwupd-security-attr.h | 3 ++ libfwupd/fwupd.map | 2 + libfwupdplugin/fu-security-attrs.c | 6 +++ libfwupdplugin/fu-self-test.c | 6 +++ plugins/acpi-dmar/fu-plugin-acpi-dmar.c | 1 + plugins/acpi-facp/fu-plugin-acpi-facp.c | 1 + plugins/amt/fu-plugin-amt.c | 2 + plugins/cpu/fu-plugin-cpu.c | 2 + .../linux-lockdown/fu-plugin-linux-lockdown.c | 1 + plugins/linux-sleep/fu-plugin-linux-sleep.c | 1 + .../linux-spi-lpc/fu-plugin-linux-spi-lpc.c | 1 + plugins/linux-swap/fu-plugin-linux-swap.c | 1 + .../linux-tainted/fu-plugin-linux-tainted.c | 1 + plugins/pci-bcr/fu-plugin-pci-bcr.c | 4 ++ plugins/tpm-eventlog/fu-plugin-tpm-eventlog.c | 1 + plugins/tpm/fu-plugin-tpm.c | 1 + plugins/uefi-dbx/fu-plugin-uefi-dbx.c | 1 + plugins/uefi/fu-plugin-uefi.c | 1 + src/fu-engine.c | 3 ++ 20 files changed, 79 insertions(+) diff --git a/libfwupd/fwupd-security-attr.c b/libfwupd/fwupd-security-attr.c index 7ce33b1d3..c0d4a2191 100644 --- a/libfwupd/fwupd-security-attr.c +++ b/libfwupd/fwupd-security-attr.c @@ -24,6 +24,7 @@ typedef struct { gchar *appstream_id; GPtrArray *obsoletes; gchar *name; + gchar *plugin; gchar *result; FwupdSecurityAttrLevel level; FwupdSecurityAttrFlags flags; @@ -219,6 +220,24 @@ fwupd_security_attr_set_name (FwupdSecurityAttr *self, const gchar *name) priv->name = g_strdup (name); } +/** + * fwupd_security_attr_set_plugin: + * @self: A #FwupdSecurityAttr + * @plugin: the plugin name + * + * Sets the plugin that created the attribute. + * + * Since: 1.5.0 + **/ +void +fwupd_security_attr_set_plugin (FwupdSecurityAttr *self, const gchar *plugin) +{ + FwupdSecurityAttrPrivate *priv = GET_PRIVATE (self); + g_return_if_fail (FWUPD_IS_SECURITY_ATTR (self)); + g_free (priv->plugin); + priv->plugin = g_strdup (plugin); +} + /** * fwupd_security_attr_set_result: * @self: A #FwupdSecurityAttr @@ -255,6 +274,24 @@ fwupd_security_attr_get_name (FwupdSecurityAttr *self) return priv->name; } +/** + * fwupd_security_attr_get_plugin: + * @self: A #FwupdSecurityAttr + * + * Gets the plugin that created the attribute. + * + * Returns: the plugin name, or %NULL if unset + * + * Since: 1.5.0 + **/ +const gchar * +fwupd_security_attr_get_plugin (FwupdSecurityAttr *self) +{ + FwupdSecurityAttrPrivate *priv = GET_PRIVATE (self); + g_return_val_if_fail (FWUPD_IS_SECURITY_ATTR (self), NULL); + return priv->plugin; +} + /** * fwupd_security_attr_get_flags: * @self: A #FwupdSecurityAttr @@ -523,6 +560,7 @@ fwupd_security_attr_to_json (FwupdSecurityAttr *self, JsonBuilder *builder) fwupd_security_attr_json_add_string (builder, FWUPD_RESULT_KEY_APPSTREAM_ID, priv->appstream_id); fwupd_security_attr_json_add_int (builder, FWUPD_RESULT_KEY_HSI_LEVEL, priv->level); fwupd_security_attr_json_add_string (builder, FWUPD_RESULT_KEY_NAME, priv->name); + fwupd_security_attr_json_add_string (builder, FWUPD_RESULT_KEY_PLUGIN, priv->plugin); fwupd_security_attr_json_add_string (builder, FWUPD_RESULT_KEY_HSI_RESULT, priv->result); if (priv->flags != FWUPD_SECURITY_ATTR_FLAG_NONE) { json_builder_set_member_name (builder, FWUPD_RESULT_KEY_FLAGS); @@ -563,6 +601,7 @@ fwupd_security_attr_to_string (FwupdSecurityAttr *self) if (priv->flags != FWUPD_SECURITY_ATTR_FLAG_NONE) fwupd_pad_kv_tfl (str, FWUPD_RESULT_KEY_FLAGS, priv->flags); fwupd_pad_kv_str (str, FWUPD_RESULT_KEY_NAME, priv->name); + fwupd_pad_kv_str (str, FWUPD_RESULT_KEY_PLUGIN, priv->plugin); fwupd_pad_kv_str (str, FWUPD_RESULT_KEY_HSI_RESULT, priv->result); for (guint i = 0; i < priv->obsoletes->len; i++) { const gchar *appstream_id = g_ptr_array_index (priv->obsoletes, i); @@ -594,6 +633,7 @@ fwupd_security_attr_finalize (GObject *object) g_free (priv->appstream_id); g_free (priv->name); + g_free (priv->plugin); g_free (priv->result); g_ptr_array_unref (priv->obsoletes); diff --git a/libfwupd/fwupd-security-attr.h b/libfwupd/fwupd-security-attr.h index 089b56e70..4ced33435 100644 --- a/libfwupd/fwupd-security-attr.h +++ b/libfwupd/fwupd-security-attr.h @@ -83,6 +83,9 @@ void fwupd_security_attr_set_level (FwupdSecurityAttr *self, const gchar *fwupd_security_attr_get_name (FwupdSecurityAttr *self); void fwupd_security_attr_set_name (FwupdSecurityAttr *self, const gchar *name); +const gchar *fwupd_security_attr_get_plugin (FwupdSecurityAttr *self); +void fwupd_security_attr_set_plugin (FwupdSecurityAttr *self, + const gchar *plugin); const gchar *fwupd_security_attr_get_result (FwupdSecurityAttr *self); void fwupd_security_attr_set_result (FwupdSecurityAttr *self, const gchar *result); diff --git a/libfwupd/fwupd.map b/libfwupd/fwupd.map index 4fb789aee..54dbe74b5 100644 --- a/libfwupd/fwupd.map +++ b/libfwupd/fwupd.map @@ -462,6 +462,7 @@ LIBFWUPD_1.5.0 { fwupd_security_attr_get_level; fwupd_security_attr_get_name; fwupd_security_attr_get_obsoletes; + fwupd_security_attr_get_plugin; fwupd_security_attr_get_result; fwupd_security_attr_get_type; fwupd_security_attr_has_flag; @@ -471,6 +472,7 @@ LIBFWUPD_1.5.0 { fwupd_security_attr_set_flags; fwupd_security_attr_set_level; fwupd_security_attr_set_name; + fwupd_security_attr_set_plugin; fwupd_security_attr_set_result; fwupd_security_attr_to_json; fwupd_security_attr_to_string; diff --git a/libfwupdplugin/fu-security-attrs.c b/libfwupdplugin/fu-security-attrs.c index ce5b41351..6ae739366 100644 --- a/libfwupdplugin/fu-security-attrs.c +++ b/libfwupdplugin/fu-security-attrs.c @@ -54,6 +54,12 @@ fu_security_attrs_append (FuSecurityAttrs *self, FwupdSecurityAttr *attr) { g_return_if_fail (FU_IS_SECURITY_ATTRS (self)); g_return_if_fail (FWUPD_IS_SECURITY_ATTR (attr)); + + /* sanity check */ + if (fwupd_security_attr_get_plugin (attr) == NULL) { + g_warning ("%s has no plugin set", + fwupd_security_attr_get_appstream_id (attr)); + } g_ptr_array_add (self->attrs, g_object_ref (attr)); } diff --git a/libfwupdplugin/fu-self-test.c b/libfwupdplugin/fu-self-test.c index e5265fa1c..0406ce112 100644 --- a/libfwupdplugin/fu-self-test.c +++ b/libfwupdplugin/fu-self-test.c @@ -1763,6 +1763,7 @@ fu_security_attrs_hsi_func (void) /* just success from HSI:1 */ attr = fwupd_security_attr_new ("org.fwupd.Hsi.BIOSWE"); + fwupd_security_attr_set_plugin (attr, "test"); fwupd_security_attr_set_level (attr, 1); fwupd_security_attr_add_flag (attr, FWUPD_SECURITY_ATTR_FLAG_SUCCESS); fu_security_attrs_append (attrs, attr); @@ -1772,6 +1773,7 @@ fu_security_attrs_hsi_func (void) /* add failed from HSI:2, so still HSI:1 */ attr = fwupd_security_attr_new ("org.fwupd.Hsi.PRX"); + fwupd_security_attr_set_plugin (attr, "test"); fwupd_security_attr_set_level (attr, 2); fu_security_attrs_append (attrs, attr); hsi3 = fu_security_attrs_calculate_hsi (attrs); @@ -1780,6 +1782,7 @@ fu_security_attrs_hsi_func (void) /* add attr from HSI:3, obsoleting the failure */ attr = fwupd_security_attr_new ("org.fwupd.Hsi.BIOSGuard"); + fwupd_security_attr_set_plugin (attr, "test"); fwupd_security_attr_set_level (attr, 3); fwupd_security_attr_add_flag (attr, FWUPD_SECURITY_ATTR_FLAG_SUCCESS); fwupd_security_attr_add_obsolete (attr, "org.fwupd.Hsi.PRX"); @@ -1791,6 +1794,7 @@ fu_security_attrs_hsi_func (void) /* add taint that was fine */ attr = fwupd_security_attr_new ("org.fwupd.Hsi.PluginsTainted"); + fwupd_security_attr_set_plugin (attr, "test"); fwupd_security_attr_add_flag (attr, FWUPD_SECURITY_ATTR_FLAG_SUCCESS); fwupd_security_attr_add_flag (attr, FWUPD_SECURITY_ATTR_FLAG_RUNTIME_ISSUE); fu_security_attrs_append (attrs, attr); @@ -1800,6 +1804,7 @@ fu_security_attrs_hsi_func (void) /* add updates and attestation */ attr = fwupd_security_attr_new ("org.fwupd.Hsi.LVFS"); + fwupd_security_attr_set_plugin (attr, "test"); fwupd_security_attr_add_flag (attr, FWUPD_SECURITY_ATTR_FLAG_RUNTIME_UPDATES); fwupd_security_attr_add_flag (attr, FWUPD_SECURITY_ATTR_FLAG_RUNTIME_ATTESTATION); fwupd_security_attr_add_flag (attr, FWUPD_SECURITY_ATTR_FLAG_SUCCESS); @@ -1810,6 +1815,7 @@ fu_security_attrs_hsi_func (void) /* add issue that was uncool */ attr = fwupd_security_attr_new ("org.fwupd.Hsi.Swap"); + fwupd_security_attr_set_plugin (attr, "test"); fwupd_security_attr_add_flag (attr, FWUPD_SECURITY_ATTR_FLAG_RUNTIME_ISSUE); fu_security_attrs_append (attrs, attr); hsi7 = fu_security_attrs_calculate_hsi (attrs); diff --git a/plugins/acpi-dmar/fu-plugin-acpi-dmar.c b/plugins/acpi-dmar/fu-plugin-acpi-dmar.c index 02b42e330..255c9a843 100644 --- a/plugins/acpi-dmar/fu-plugin-acpi-dmar.c +++ b/plugins/acpi-dmar/fu-plugin-acpi-dmar.c @@ -32,6 +32,7 @@ fu_plugin_add_security_attrs (FuPlugin *plugin, FuSecurityAttrs *attrs) /* create attr */ attr = fwupd_security_attr_new ("org.uefi.ACPI.Dmar"); + fwupd_security_attr_set_plugin (attr, fu_plugin_get_name (plugin)); fwupd_security_attr_set_level (attr, FWUPD_SECURITY_ATTR_LEVEL_THEORETICAL); fwupd_security_attr_set_name (attr, "Pre-boot kernel DMA protection"); fu_security_attrs_append (attrs, attr); diff --git a/plugins/acpi-facp/fu-plugin-acpi-facp.c b/plugins/acpi-facp/fu-plugin-acpi-facp.c index 5409d2c47..09927db56 100644 --- a/plugins/acpi-facp/fu-plugin-acpi-facp.c +++ b/plugins/acpi-facp/fu-plugin-acpi-facp.c @@ -28,6 +28,7 @@ fu_plugin_add_security_attrs (FuPlugin *plugin, FuSecurityAttrs *attrs) /* create attr */ attr = fwupd_security_attr_new ("org.uefi.ACPI.Facp"); + fwupd_security_attr_set_plugin (attr, fu_plugin_get_name (plugin)); fwupd_security_attr_set_level (attr, FWUPD_SECURITY_ATTR_LEVEL_THEORETICAL); fwupd_security_attr_set_name (attr, "Suspend To Idle"); fu_security_attrs_append (attrs, attr); diff --git a/plugins/amt/fu-plugin-amt.c b/plugins/amt/fu-plugin-amt.c index 46f2bbf0d..74b8a47b8 100644 --- a/plugins/amt/fu-plugin-amt.c +++ b/plugins/amt/fu-plugin-amt.c @@ -578,7 +578,9 @@ fu_plugin_add_security_attrs (FuPlugin *plugin, FuSecurityAttrs *attrs) if (!fu_common_is_cpu_intel () || !data->has_mei) return; + /* create attr */ attr = fwupd_security_attr_new ("com.intel.AMT"); + fwupd_security_attr_set_plugin (attr, fu_plugin_get_name (plugin)); fwupd_security_attr_set_level (attr, FWUPD_SECURITY_ATTR_LEVEL_SYSTEM_PROTECTION); fwupd_security_attr_set_name (attr, "Intel AMT"); fu_security_attrs_append (attrs, attr); diff --git a/plugins/cpu/fu-plugin-cpu.c b/plugins/cpu/fu-plugin-cpu.c index a2196ca0f..832e0ca8b 100644 --- a/plugins/cpu/fu-plugin-cpu.c +++ b/plugins/cpu/fu-plugin-cpu.c @@ -58,6 +58,7 @@ fu_plugin_add_security_attrs_intel_cet (FuPlugin *plugin, FuSecurityAttrs *attrs /* create attr */ attr = fwupd_security_attr_new ("com.intel.CET"); + fwupd_security_attr_set_plugin (attr, fu_plugin_get_name (plugin)); fwupd_security_attr_set_level (attr, FWUPD_SECURITY_ATTR_LEVEL_THEORETICAL); fwupd_security_attr_set_name (attr, "Intel control enforcement technology (CET)"); fu_security_attrs_append (attrs, attr); @@ -81,6 +82,7 @@ fu_plugin_add_security_attrs_intel_tme (FuPlugin *plugin, FuSecurityAttrs *attrs /* create attr */ attr = fwupd_security_attr_new ("com.intel.TME"); + fwupd_security_attr_set_plugin (attr, fu_plugin_get_name (plugin)); fwupd_security_attr_set_level (attr, FWUPD_SECURITY_ATTR_LEVEL_SYSTEM_PROTECTION); fwupd_security_attr_set_name (attr, "Intel total memory encryption (TME)"); fu_security_attrs_append (attrs, attr); diff --git a/plugins/linux-lockdown/fu-plugin-linux-lockdown.c b/plugins/linux-lockdown/fu-plugin-linux-lockdown.c index c81690dc7..8c2e21e47 100644 --- a/plugins/linux-lockdown/fu-plugin-linux-lockdown.c +++ b/plugins/linux-lockdown/fu-plugin-linux-lockdown.c @@ -71,6 +71,7 @@ fu_plugin_add_security_attrs (FuPlugin *plugin, FuSecurityAttrs *attrs) /* create attr */ attr = fwupd_security_attr_new ("org.kernel.CheckLockdown"); + fwupd_security_attr_set_plugin (attr, fu_plugin_get_name (plugin)); fwupd_security_attr_set_name (attr, "Linux Kernel Lockdown"); fwupd_security_attr_add_flag (attr, FWUPD_SECURITY_ATTR_FLAG_RUNTIME_ISSUE); fu_security_attrs_append (attrs, attr); diff --git a/plugins/linux-sleep/fu-plugin-linux-sleep.c b/plugins/linux-sleep/fu-plugin-linux-sleep.c index c7f8793fa..f54ed2be5 100644 --- a/plugins/linux-sleep/fu-plugin-linux-sleep.c +++ b/plugins/linux-sleep/fu-plugin-linux-sleep.c @@ -26,6 +26,7 @@ fu_plugin_add_security_attrs (FuPlugin *plugin, FuSecurityAttrs *attrs) /* create attr */ attr = fwupd_security_attr_new ("org.kernel.CheckS3Sleep"); + fwupd_security_attr_set_plugin (attr, fu_plugin_get_name (plugin)); fwupd_security_attr_set_level (attr, FWUPD_SECURITY_ATTR_LEVEL_THEORETICAL); fwupd_security_attr_set_name (attr, "Linux Kernel S3 Sleep"); fu_security_attrs_append (attrs, attr); diff --git a/plugins/linux-spi-lpc/fu-plugin-linux-spi-lpc.c b/plugins/linux-spi-lpc/fu-plugin-linux-spi-lpc.c index b20b50529..2f0dec11d 100644 --- a/plugins/linux-spi-lpc/fu-plugin-linux-spi-lpc.c +++ b/plugins/linux-spi-lpc/fu-plugin-linux-spi-lpc.c @@ -29,6 +29,7 @@ fu_plugin_add_security_attr_bioswe (FuPlugin *plugin, FuSecurityAttrs *attrs) /* create attr */ attr = fwupd_security_attr_new ("org.kernel.BIOSWE"); + fwupd_security_attr_set_plugin (attr, fu_plugin_get_name (plugin)); fwupd_security_attr_set_level (attr, FWUPD_SECURITY_ATTR_LEVEL_CRITICAL); fwupd_security_attr_set_name (attr, "SPI"); fwupd_security_attr_add_obsolete (attr, "org.fwupd.plugin.pci-bcr"); diff --git a/plugins/linux-swap/fu-plugin-linux-swap.c b/plugins/linux-swap/fu-plugin-linux-swap.c index 646e3f00d..c54d293d1 100644 --- a/plugins/linux-swap/fu-plugin-linux-swap.c +++ b/plugins/linux-swap/fu-plugin-linux-swap.c @@ -73,6 +73,7 @@ fu_plugin_add_security_attrs (FuPlugin *plugin, FuSecurityAttrs *attrs) /* create attr */ attr = fwupd_security_attr_new ("org.kernel.Swap"); + fwupd_security_attr_set_plugin (attr, fu_plugin_get_name (plugin)); fwupd_security_attr_add_flag (attr, FWUPD_SECURITY_ATTR_FLAG_RUNTIME_ISSUE); fwupd_security_attr_set_name (attr, "Linux Swap"); fu_security_attrs_append (attrs, attr); diff --git a/plugins/linux-tainted/fu-plugin-linux-tainted.c b/plugins/linux-tainted/fu-plugin-linux-tainted.c index 1d3936f78..c1317256f 100644 --- a/plugins/linux-tainted/fu-plugin-linux-tainted.c +++ b/plugins/linux-tainted/fu-plugin-linux-tainted.c @@ -71,6 +71,7 @@ fu_plugin_add_security_attrs (FuPlugin *plugin, FuSecurityAttrs *attrs) /* create attr */ attr = fwupd_security_attr_new ("org.kernel.CheckTainted"); + fwupd_security_attr_set_plugin (attr, fu_plugin_get_name (plugin)); fwupd_security_attr_set_name (attr, "Linux Kernel Taint"); fwupd_security_attr_add_flag (attr, FWUPD_SECURITY_ATTR_FLAG_RUNTIME_ISSUE); fu_security_attrs_append (attrs, attr); diff --git a/plugins/pci-bcr/fu-plugin-pci-bcr.c b/plugins/pci-bcr/fu-plugin-pci-bcr.c index 92c3fb9ba..7d82c73d9 100644 --- a/plugins/pci-bcr/fu-plugin-pci-bcr.c +++ b/plugins/pci-bcr/fu-plugin-pci-bcr.c @@ -38,6 +38,7 @@ fu_plugin_add_security_attr_bioswe (FuPlugin *plugin, FuSecurityAttrs *attrs) /* create attr */ attr = fwupd_security_attr_new ("com.intel.BIOSWE"); + fwupd_security_attr_set_plugin (attr, fu_plugin_get_name (plugin)); fwupd_security_attr_set_level (attr, FWUPD_SECURITY_ATTR_LEVEL_CRITICAL); fwupd_security_attr_set_name (attr, "SPI"); fwupd_security_attr_add_obsolete (attr, "org.kernel.BIOSWE"); @@ -63,6 +64,7 @@ fu_plugin_add_security_attr_ble (FuPlugin *plugin, FuSecurityAttrs *attrs) /* create attr */ attr = fwupd_security_attr_new ("com.intel.BLE"); + fwupd_security_attr_set_plugin (attr, fu_plugin_get_name (plugin)); fwupd_security_attr_set_level (attr, FWUPD_SECURITY_ATTR_LEVEL_CRITICAL); fwupd_security_attr_set_name (attr, "SPI"); fwupd_security_attr_add_obsolete (attr, "org.kernel.BLE"); @@ -88,6 +90,7 @@ fu_plugin_add_security_attr_smm_bwp (FuPlugin *plugin, FuSecurityAttrs *attrs) /* create attr */ attr = fwupd_security_attr_new ("com.intel.SMM_BWP"); + fwupd_security_attr_set_plugin (attr, fu_plugin_get_name (plugin)); fwupd_security_attr_set_level (attr, FWUPD_SECURITY_ATTR_LEVEL_CRITICAL); fwupd_security_attr_set_name (attr, "BIOS region of SPI"); fwupd_security_attr_add_obsolete (attr, "org.kernel.SMM_BWP"); @@ -162,6 +165,7 @@ fu_plugin_add_security_attrs (FuPlugin *plugin, FuSecurityAttrs *attrs) if (!priv->has_device) { g_autoptr(FwupdSecurityAttr) attr = NULL; attr = fwupd_security_attr_new ("org.fwupd.plugin.pci-bcr"); + fwupd_security_attr_set_plugin (attr, fu_plugin_get_name (plugin)); fwupd_security_attr_set_level (attr, FWUPD_SECURITY_ATTR_LEVEL_CRITICAL); fwupd_security_attr_set_name (attr, "SPI"); fwupd_security_attr_set_result (attr, "No PCI devices with BCR"); diff --git a/plugins/tpm-eventlog/fu-plugin-tpm-eventlog.c b/plugins/tpm-eventlog/fu-plugin-tpm-eventlog.c index 442649353..4e7ff0803 100644 --- a/plugins/tpm-eventlog/fu-plugin-tpm-eventlog.c +++ b/plugins/tpm-eventlog/fu-plugin-tpm-eventlog.c @@ -133,6 +133,7 @@ fu_plugin_add_security_attrs (FuPlugin *plugin, FuSecurityAttrs *attrs) /* create attr */ attr = fwupd_security_attr_new ("org.trustedcomputinggroup.TpmEventLog"); + fwupd_security_attr_set_plugin (attr, fu_plugin_get_name (plugin)); fwupd_security_attr_set_level (attr, FWUPD_SECURITY_ATTR_LEVEL_IMPORTANT); fwupd_security_attr_set_name (attr, "TPM Reconstruction"); fu_security_attrs_append (attrs, attr); diff --git a/plugins/tpm/fu-plugin-tpm.c b/plugins/tpm/fu-plugin-tpm.c index 918d2b86e..18b0d263e 100644 --- a/plugins/tpm/fu-plugin-tpm.c +++ b/plugins/tpm/fu-plugin-tpm.c @@ -42,6 +42,7 @@ fu_plugin_add_security_attrs (FuPlugin *plugin, FuSecurityAttrs *attrs) /* create attr */ attr = fwupd_security_attr_new ("org.trustedcomputinggroup.Tpm"); + fwupd_security_attr_set_plugin (attr, fu_plugin_get_name (plugin)); fwupd_security_attr_set_level (attr, FWUPD_SECURITY_ATTR_LEVEL_CRITICAL); fwupd_security_attr_set_name (attr, "TPM"); fu_security_attrs_append (attrs, attr); diff --git a/plugins/uefi-dbx/fu-plugin-uefi-dbx.c b/plugins/uefi-dbx/fu-plugin-uefi-dbx.c index 46adf6429..84dafd5ef 100644 --- a/plugins/uefi-dbx/fu-plugin-uefi-dbx.c +++ b/plugins/uefi-dbx/fu-plugin-uefi-dbx.c @@ -57,6 +57,7 @@ fu_plugin_add_security_attrs (FuPlugin *plugin, FuSecurityAttrs *attrs) /* create attr */ attr = fwupd_security_attr_new ("org.uefi.SecureBoot.dbx"); + fwupd_security_attr_set_plugin (attr, fu_plugin_get_name (plugin)); fwupd_security_attr_set_level (attr, FWUPD_SECURITY_ATTR_LEVEL_CRITICAL); fwupd_security_attr_set_name (attr, "UEFI dbx"); fu_security_attrs_append (attrs, attr); diff --git a/plugins/uefi/fu-plugin-uefi.c b/plugins/uefi/fu-plugin-uefi.c index ba9563716..a80ed250e 100644 --- a/plugins/uefi/fu-plugin-uefi.c +++ b/plugins/uefi/fu-plugin-uefi.c @@ -98,6 +98,7 @@ fu_plugin_add_security_attrs (FuPlugin *plugin, FuSecurityAttrs *attrs) /* create attr */ attr = fwupd_security_attr_new ("com.uefi.SecureBoot"); + fwupd_security_attr_set_plugin (attr, fu_plugin_get_name (plugin)); fwupd_security_attr_set_level (attr, FWUPD_SECURITY_ATTR_LEVEL_CRITICAL); fwupd_security_attr_set_name (attr, "UEFI Secure Boot"); fu_security_attrs_append (attrs, attr); diff --git a/src/fu-engine.c b/src/fu-engine.c index 8b5511782..b51686907 100644 --- a/src/fu-engine.c +++ b/src/fu-engine.c @@ -5043,6 +5043,7 @@ fu_engine_add_security_attrs_tainted (FuEngine *self, FuSecurityAttrs *attrs) gboolean disabled_plugins = FALSE; GPtrArray *blacklist = fu_config_get_blacklist_plugins (self->config); g_autoptr(FwupdSecurityAttr) attr = fwupd_security_attr_new ("org.fwupd.Hsi.Plugins"); + fwupd_security_attr_set_plugin (attr, "core"); fwupd_security_attr_set_name (attr, "fwupd plugins"); fwupd_security_attr_add_flag (attr, FWUPD_SECURITY_ATTR_FLAG_RUNTIME_ISSUE); for (guint i = 0; i < blacklist->len; i++) { @@ -5076,6 +5077,7 @@ fu_engine_add_security_attrs_supported (FuEngine *self, FuSecurityAttrs *attrs) /* find out if there is firmware less than 12 months old */ attr_u = fwupd_security_attr_new ("org.fwupd.Hsi.Updates"); + fwupd_security_attr_set_plugin (attr_u, "core"); fwupd_security_attr_add_flag (attr_u, FWUPD_SECURITY_ATTR_FLAG_RUNTIME_UPDATES); fwupd_security_attr_set_name (attr_u, "Firmware Updates"); fu_security_attrs_append (attrs, attr_u); @@ -5110,6 +5112,7 @@ fu_engine_add_security_attrs_supported (FuEngine *self, FuSecurityAttrs *attrs) /* do we have attestation checksums */ attr_a = fwupd_security_attr_new ("org.fwupd.Hsi.Attestation"); + fwupd_security_attr_set_plugin (attr_a, "core"); fwupd_security_attr_set_name (attr_a, "Firmware Attestation"); fwupd_security_attr_add_flag (attr_a, FWUPD_SECURITY_ATTR_FLAG_RUNTIME_ATTESTATION); fu_security_attrs_append (attrs, attr_a); From 0613b3cdf32e73ed894aa5d11cfe809abbd282f0 Mon Sep 17 00:00:00 2001 From: Richard Hughes Date: Fri, 15 May 2020 15:29:54 +0100 Subject: [PATCH 075/607] trivial: Fix the docstring for fwupd_security_attr_set_name() --- libfwupd/fwupd-security-attr.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libfwupd/fwupd-security-attr.c b/libfwupd/fwupd-security-attr.c index c0d4a2191..5a0a2b094 100644 --- a/libfwupd/fwupd-security-attr.c +++ b/libfwupd/fwupd-security-attr.c @@ -205,7 +205,7 @@ fwupd_security_attr_get_result (FwupdSecurityAttr *self) /** * fwupd_security_attr_set_name: * @self: A #FwupdSecurityAttr - * @result: the attribute one line result + * @name: the attribute name * * Sets the attribute name. * From 71d6fe5ffa56cf5ef184f2bd428d5dc46c728f0c Mon Sep 17 00:00:00 2001 From: Richard Hughes Date: Fri, 15 May 2020 16:18:27 +0100 Subject: [PATCH 076/607] vli: Remove a copy-and-paste mistake This is not a PD device, it's a USB hub. --- plugins/vli/vli-pd.quirk | 4 ---- 1 file changed, 4 deletions(-) diff --git a/plugins/vli/vli-pd.quirk b/plugins/vli/vli-pd.quirk index a055d8a06..586c6aeda 100644 --- a/plugins/vli/vli-pd.quirk +++ b/plugins/vli/vli-pd.quirk @@ -1,7 +1,3 @@ -[DeviceInstanceId=USB\VID_17EF&PID_3070] -Plugin = vli -GType = FuVliPdDevice - # Generic [DeviceInstanceId=USB\VID_0800&PID_0800] Plugin = vli From 8a71bd128f432530e676160c8e6ac3f5e055b2e8 Mon Sep 17 00:00:00 2001 From: Richard Hughes Date: Fri, 15 May 2020 16:36:05 +0100 Subject: [PATCH 077/607] vli: Add no-guid-matching for all VLI devices We need to detect different USB 3.x hubs on the ThinkPad Basic, Pro and Ultra docking stations. --- plugins/vli/fu-vli-device.c | 1 + 1 file changed, 1 insertion(+) diff --git a/plugins/vli/fu-vli-device.c b/plugins/vli/fu-vli-device.c index b91c827aa..d83f38c6f 100644 --- a/plugins/vli/fu-vli-device.c +++ b/plugins/vli/fu-vli-device.c @@ -675,6 +675,7 @@ fu_vli_device_init (FuVliDevice *self) priv->spi_cmd_read_id_sz = 2; priv->spi_auto_detect = TRUE; fu_device_add_flag (FU_DEVICE (self), FWUPD_DEVICE_FLAG_ADD_COUNTERPART_GUIDS); + fu_device_add_flag (FU_DEVICE (self), FWUPD_DEVICE_FLAG_NO_GUID_MATCHING); } static void From 921c22725a0eca8d006cac9eeeb916fc9bbc7fe5 Mon Sep 17 00:00:00 2001 From: Mario Limonciello Date: Fri, 15 May 2020 09:01:32 -0500 Subject: [PATCH 078/607] trivial: acpi-dmar: Correct platform-opt in flag --- plugins/acpi-dmar/fu-acpi-dmar.c | 2 +- plugins/acpi-dmar/tests/DMAR | Bin 168 -> 168 bytes 2 files changed, 1 insertion(+), 1 deletion(-) diff --git a/plugins/acpi-dmar/fu-acpi-dmar.c b/plugins/acpi-dmar/fu-acpi-dmar.c index e972d0e65..582544c26 100644 --- a/plugins/acpi-dmar/fu-acpi-dmar.c +++ b/plugins/acpi-dmar/fu-acpi-dmar.c @@ -18,7 +18,7 @@ struct _FuAcpiDmar { G_DEFINE_TYPE (FuAcpiDmar, fu_acpi_dmar, G_TYPE_OBJECT) -#define DMAR_DMA_CTRL_PLATFORM_OPT_IN_FLAG 2 +#define DMAR_DMA_CTRL_PLATFORM_OPT_IN_FLAG 0x4 FuAcpiDmar * fu_acpi_dmar_new (GBytes *blob, GError **error) diff --git a/plugins/acpi-dmar/tests/DMAR b/plugins/acpi-dmar/tests/DMAR index 0a64fc85e24b841fd88a3a7cfa3ad2e2d2410fd9..9f37918eee5c7e8926d9ca46a92c188424e650b9 100644 GIT binary patch literal 168 zcmZ?qbqrd;z`(%x$I~yw)knc4H77^GGcTD5D5d}e!aylCRv-rsB%rLD|3C~z4iE`e z&AKg>TQK-bUERY75bC<8-4h^sRbP)>~*NWg&vly&nTh{4DK zB0;JY7#KlJ0f;y=P@L(5JOc|@ULGi?0Fq^3_~7XeqW-`42GbDzA_#c~hA6Q7|N1x( H4Kp7Ay}T6x From 6ecf511d5258fa6c0920f3fabb08366c967b9bc2 Mon Sep 17 00:00:00 2001 From: Mario Limonciello Date: Fri, 15 May 2020 10:29:44 -0500 Subject: [PATCH 079/607] trivial: pci-bcr: request pci udev subsystem If another plugin didn't do this, the pci-bcr plugin doesn't work. It's noticable by --plugin-whitelist=pci_bcr --- plugins/pci-bcr/fu-plugin-pci-bcr.c | 1 + 1 file changed, 1 insertion(+) diff --git a/plugins/pci-bcr/fu-plugin-pci-bcr.c b/plugins/pci-bcr/fu-plugin-pci-bcr.c index 7d82c73d9..20307d679 100644 --- a/plugins/pci-bcr/fu-plugin-pci-bcr.c +++ b/plugins/pci-bcr/fu-plugin-pci-bcr.c @@ -28,6 +28,7 @@ fu_plugin_init (FuPlugin *plugin) { fu_plugin_alloc_data (plugin, sizeof (FuPluginData)); fu_plugin_set_build_hash (plugin, FU_BUILD_HASH); + fu_plugin_add_udev_subsystem (plugin, "pci"); } static void From 8b5bcbb9e3f465946b3552eccc38830c91d1fea0 Mon Sep 17 00:00:00 2001 From: Mario Limonciello Date: Thu, 14 May 2020 20:08:34 -0500 Subject: [PATCH 080/607] Add a new plugin for IOMMU support --- contrib/debian/lintian/fwupd | 1 + contrib/fwupd.spec.in | 1 + plugins/iommu/README.md | 7 ++++ plugins/iommu/fu-plugin-iommu.c | 57 +++++++++++++++++++++++++++++++++ plugins/iommu/iommu.quirk | 3 ++ plugins/iommu/meson.build | 29 +++++++++++++++++ plugins/meson.build | 1 + 7 files changed, 99 insertions(+) create mode 100644 plugins/iommu/README.md create mode 100644 plugins/iommu/fu-plugin-iommu.c create mode 100644 plugins/iommu/iommu.quirk create mode 100644 plugins/iommu/meson.build diff --git a/contrib/debian/lintian/fwupd b/contrib/debian/lintian/fwupd index 369f1b991..28fb38bfb 100644 --- a/contrib/debian/lintian/fwupd +++ b/contrib/debian/lintian/fwupd @@ -10,3 +10,4 @@ fwupd: executable-not-elf-or-script usr/libexec/fwupd/efi/*.efi fwupd: portable-executable-missing-security-features usr/libexec/fwupd/efi/*.efi SafeSEH fwupd: library-not-linked-against-libc usr/lib/*/fwupd-plugins-3/libfu_plugin_modem_manager.so fwupd: library-not-linked-against-libc usr/lib/*/fwupd-plugins-3/libfu_plugin_pci_bcr.so +fwupd: library-not-linked-against-libc usr/lib/*/fwupd-plugins-3/libfu_plugin_iommu.so diff --git a/contrib/fwupd.spec.in b/contrib/fwupd.spec.in index 86633a743..c2a32f942 100644 --- a/contrib/fwupd.spec.in +++ b/contrib/fwupd.spec.in @@ -353,6 +353,7 @@ mkdir -p --mode=0700 $RPM_BUILD_ROOT%{_localstatedir}/lib/fwupd/gnupg %{_libdir}/fwupd-plugins-3/libfu_plugin_flashrom.so %endif %{_libdir}/fwupd-plugins-3/libfu_plugin_fresco_pd.so +%{_libdir}/fwupd-plugins-3/libfu_plugin_iommu.so %{_libdir}/fwupd-plugins-3/libfu_plugin_jabra.so %{_libdir}/fwupd-plugins-3/libfu_plugin_linux_lockdown.so %{_libdir}/fwupd-plugins-3/libfu_plugin_linux_sleep.so diff --git a/plugins/iommu/README.md b/plugins/iommu/README.md new file mode 100644 index 000000000..12574ffd6 --- /dev/null +++ b/plugins/iommu/README.md @@ -0,0 +1,7 @@ +Linux IOMMU +================== + +Introduction +------------ + +This plugin checks if an IOMMU is available on the system. diff --git a/plugins/iommu/fu-plugin-iommu.c b/plugins/iommu/fu-plugin-iommu.c new file mode 100644 index 000000000..3d1a6921e --- /dev/null +++ b/plugins/iommu/fu-plugin-iommu.c @@ -0,0 +1,57 @@ +/* + * Copyright (C) 2019 Richard Hughes + * + * SPDX-License-Identifier: LGPL-2.1+ + */ + +#include "config.h" + +#include "fu-hash.h" +#include "fu-plugin-vfuncs.h" + +struct FuPluginData { + gboolean has_iommu; +}; + +void +fu_plugin_init (FuPlugin *plugin) +{ + fu_plugin_alloc_data (plugin, sizeof (FuPluginData)); + fu_plugin_set_build_hash (plugin, FU_BUILD_HASH); + fu_plugin_add_udev_subsystem (plugin, "iommu"); +} + +gboolean +fu_plugin_udev_device_added (FuPlugin *plugin, FuUdevDevice *device, GError **error) +{ + FuPluginData *priv = fu_plugin_get_data (plugin); + + /* interesting device? */ + if (g_strcmp0 (fu_udev_device_get_subsystem (device), "iommu") != 0) + return TRUE; + priv->has_iommu = TRUE; + + return TRUE; +} + +void +fu_plugin_add_security_attrs (FuPlugin *plugin, FuSecurityAttrs *attrs) +{ + FuPluginData *data = fu_plugin_get_data (plugin); + g_autoptr(FwupdSecurityAttr) attr = NULL; + + /* create attr */ + attr = fwupd_security_attr_new ("org.kernel.IOMMU"); + fwupd_security_attr_set_level (attr, FWUPD_SECURITY_ATTR_LEVEL_IMPORTANT); + fwupd_security_attr_set_name (attr, "IOMMU"); + fwupd_security_attr_set_plugin (attr, fu_plugin_get_name (plugin)); + fu_security_attrs_append (attrs, attr); + + if (!data->has_iommu) { + fwupd_security_attr_set_result (attr, "Not found"); + return; + } + + /* success */ + fwupd_security_attr_add_flag (attr, FWUPD_SECURITY_ATTR_FLAG_SUCCESS); +} diff --git a/plugins/iommu/iommu.quirk b/plugins/iommu/iommu.quirk new file mode 100644 index 000000000..26245a6a3 --- /dev/null +++ b/plugins/iommu/iommu.quirk @@ -0,0 +1,3 @@ +# match all devices with this udev subsystem +[DeviceInstanceId=IOMMU] +Plugin = iommu diff --git a/plugins/iommu/meson.build b/plugins/iommu/meson.build new file mode 100644 index 000000000..f60289650 --- /dev/null +++ b/plugins/iommu/meson.build @@ -0,0 +1,29 @@ +cargs = ['-DG_LOG_DOMAIN="FuPluginIommu"'] + +install_data([ + 'iommu.quirk', + ], + install_dir: join_paths(datadir, 'fwupd', 'quirks.d') +) + +shared_module('fu_plugin_iommu', + fu_hash, + sources : [ + 'fu-plugin-iommu.c', + ], + include_directories : [ + root_incdir, + fwupd_incdir, + fwupdplugin_incdir, + ], + install : true, + install_dir: plugin_dir, + link_with : [ + fwupdplugin, + fwupd, + ], + c_args : cargs, + dependencies : [ + plugin_deps, + ], +) diff --git a/plugins/meson.build b/plugins/meson.build index eabdb7844..1653332b5 100644 --- a/plugins/meson.build +++ b/plugins/meson.build @@ -8,6 +8,7 @@ subdir('ebitdo') subdir('ep963x') subdir('fastboot') subdir('fresco-pd') +subdir('iommu') subdir('jabra') subdir('linux-lockdown') subdir('linux-sleep') From 63fa4effd3b6e4ee9ef7dbdc90cdd9779ba362d8 Mon Sep 17 00:00:00 2001 From: Richard Hughes Date: Fri, 15 May 2020 21:35:45 +0100 Subject: [PATCH 081/607] pci-mei: Check the ME device is not in manufacturing mode --- contrib/debian/lintian/fwupd | 1 + contrib/fwupd.spec.in | 1 + libfwupdplugin/fu-udev-device.c | 9 ++ libfwupdplugin/fu-udev-device.h | 2 + plugins/meson.build | 1 + plugins/pci-bcr/fu-plugin-pci-bcr.c | 41 +++------ plugins/pci-mei/README.md | 8 ++ plugins/pci-mei/fu-plugin-pci-mei.c | 81 ++++++++++++++++++ plugins/pci-mei/meson.build | 27 ++++++ plugins/pci-mei/pci-mei.quirk | 126 ++++++++++++++++++++++++++++ 10 files changed, 266 insertions(+), 31 deletions(-) create mode 100644 plugins/pci-mei/README.md create mode 100644 plugins/pci-mei/fu-plugin-pci-mei.c create mode 100644 plugins/pci-mei/meson.build create mode 100644 plugins/pci-mei/pci-mei.quirk diff --git a/contrib/debian/lintian/fwupd b/contrib/debian/lintian/fwupd index 28fb38bfb..75afa4600 100644 --- a/contrib/debian/lintian/fwupd +++ b/contrib/debian/lintian/fwupd @@ -10,4 +10,5 @@ fwupd: executable-not-elf-or-script usr/libexec/fwupd/efi/*.efi fwupd: portable-executable-missing-security-features usr/libexec/fwupd/efi/*.efi SafeSEH fwupd: library-not-linked-against-libc usr/lib/*/fwupd-plugins-3/libfu_plugin_modem_manager.so fwupd: library-not-linked-against-libc usr/lib/*/fwupd-plugins-3/libfu_plugin_pci_bcr.so +fwupd: library-not-linked-against-libc usr/lib/*/fwupd-plugins-3/libfu_plugin_pci_mei.so fwupd: library-not-linked-against-libc usr/lib/*/fwupd-plugins-3/libfu_plugin_iommu.so diff --git a/contrib/fwupd.spec.in b/contrib/fwupd.spec.in index c2a32f942..c106b6596 100644 --- a/contrib/fwupd.spec.in +++ b/contrib/fwupd.spec.in @@ -368,6 +368,7 @@ mkdir -p --mode=0700 $RPM_BUILD_ROOT%{_localstatedir}/lib/fwupd/gnupg %endif %{_libdir}/fwupd-plugins-3/libfu_plugin_optionrom.so %{_libdir}/fwupd-plugins-3/libfu_plugin_pci_bcr.so +%{_libdir}/fwupd-plugins-3/libfu_plugin_pci_mei.so %if 0%{?have_redfish} %{_libdir}/fwupd-plugins-3/libfu_plugin_redfish.so %endif diff --git a/libfwupdplugin/fu-udev-device.c b/libfwupdplugin/fu-udev-device.c index 3c9a6ee8e..71b8dae0a 100644 --- a/libfwupdplugin/fu-udev-device.c +++ b/libfwupdplugin/fu-udev-device.c @@ -777,6 +777,15 @@ fu_udev_device_set_flags (FuUdevDevice *self, FuUdevDeviceFlags flags) FuUdevDevicePrivate *priv = GET_PRIVATE (self); g_return_if_fail (FU_IS_UDEV_DEVICE (self)); priv->flags = flags; + +#ifdef HAVE_GUDEV + /* overwrite */ + if (flags & FU_UDEV_DEVICE_FLAG_USE_CONFIG) { + g_free (priv->device_file); + priv->device_file = g_build_filename (g_udev_device_get_sysfs_path (priv->udev_device), + "config", NULL); + } +#endif } static gboolean diff --git a/libfwupdplugin/fu-udev-device.h b/libfwupdplugin/fu-udev-device.h index 923e9c587..94f3c2749 100644 --- a/libfwupdplugin/fu-udev-device.h +++ b/libfwupdplugin/fu-udev-device.h @@ -38,6 +38,7 @@ struct _FuUdevDeviceClass * @FU_UDEV_DEVICE_FLAG_OPEN_READ: Open the device read-only * @FU_UDEV_DEVICE_FLAG_OPEN_WRITE: Open the device write-only * @FU_UDEV_DEVICE_FLAG_VENDOR_FROM_PARENT: Get the vendor ID fallback from the parent + * @FU_UDEV_DEVICE_FLAG_USE_CONFIG: Read and write from the device config * * Flags used when opening the device using fu_device_open(). **/ @@ -46,6 +47,7 @@ typedef enum { FU_UDEV_DEVICE_FLAG_OPEN_READ = 1 << 0, FU_UDEV_DEVICE_FLAG_OPEN_WRITE = 1 << 1, FU_UDEV_DEVICE_FLAG_VENDOR_FROM_PARENT = 1 << 2, + FU_UDEV_DEVICE_FLAG_USE_CONFIG = 1 << 3, /*< private >*/ FU_UDEV_DEVICE_FLAG_LAST } FuUdevDeviceFlags; diff --git a/plugins/meson.build b/plugins/meson.build index 1653332b5..a3c380e1d 100644 --- a/plugins/meson.build +++ b/plugins/meson.build @@ -18,6 +18,7 @@ subdir('steelseries') subdir('dell-dock') subdir('nitrokey') subdir('pci-bcr') +subdir('pci-mei') subdir('rts54hid') subdir('rts54hub') subdir('solokey') diff --git a/plugins/pci-bcr/fu-plugin-pci-bcr.c b/plugins/pci-bcr/fu-plugin-pci-bcr.c index 20307d679..41433548f 100644 --- a/plugins/pci-bcr/fu-plugin-pci-bcr.c +++ b/plugins/pci-bcr/fu-plugin-pci-bcr.c @@ -6,10 +6,6 @@ #include "config.h" -#include -#include -#include - #include "fu-plugin-vfuncs.h" #include "fu-hash.h" @@ -112,45 +108,28 @@ fu_plugin_add_security_attr_smm_bwp (FuPlugin *plugin, FuSecurityAttrs *attrs) gboolean fu_plugin_udev_device_added (FuPlugin *plugin, FuUdevDevice *device, GError **error) { -#ifndef _WIN32 FuPluginData *priv = fu_plugin_get_data (plugin); - gint fd; - g_autofree gchar *fn = NULL; + g_autoptr(FuDeviceLocker) locker = NULL; /* interesting device? */ if (g_strcmp0 (fu_udev_device_get_subsystem (device), "pci") != 0) return TRUE; - /* open config */ - fn = g_build_filename (fu_udev_device_get_sysfs_path (device), "config", NULL); - fd = g_open (fn, O_RDONLY); - if (fd < 0) { - g_set_error (error, - G_IO_ERROR, - G_IO_ERROR_FAILED, - "could not open %s", fn); + /* open the config */ + fu_udev_device_set_flags (device, FU_UDEV_DEVICE_FLAG_USE_CONFIG); + if (!fu_udev_device_set_physical_id (device, "pci", error)) + return FALSE; + locker = fu_device_locker_new (device, error); + if (locker == NULL) return FALSE; - } /* grab BIOS Control Register */ - if (pread (fd, &priv->bcr, 0x01, BCR) != 1) { - g_close (fd, NULL); - g_set_error (error, - G_IO_ERROR, - G_IO_ERROR_FAILED, - "could not read BCR from %s", - fn); + if (!fu_udev_device_pread (device, BCR, &priv->bcr, error)) { + g_prefix_error (error, "could not read MEI"); return FALSE; } priv->has_device = TRUE; - return g_close (fd, error); -#else - g_set_error_literal (error, - FWUPD_ERROR, - FWUPD_ERROR_NOT_SUPPORTED, - "pci reads not currently supported on Windows"); - return FALSE; -#endif + return TRUE; } void diff --git a/plugins/pci-mei/README.md b/plugins/pci-mei/README.md new file mode 100644 index 000000000..1744c6c4a --- /dev/null +++ b/plugins/pci-mei/README.md @@ -0,0 +1,8 @@ +PCI MEI +======= + +Introduction +------------ + +This plugin checks if the ME is in Manufacturing Mode. The result will be stored +in an security attribute for HSI. diff --git a/plugins/pci-mei/fu-plugin-pci-mei.c b/plugins/pci-mei/fu-plugin-pci-mei.c new file mode 100644 index 000000000..c7443b78e --- /dev/null +++ b/plugins/pci-mei/fu-plugin-pci-mei.c @@ -0,0 +1,81 @@ +/* + * Copyright (C) 2020 Richard Hughes + * + * SPDX-License-Identifier: LGPL-2.1+ + */ + +#include "config.h" + +#include "fu-plugin-vfuncs.h" +#include "fu-hash.h" + +struct FuPluginData { + gboolean has_device; + guint8 mei_cfg; +}; + +#define PCI_CFG_HFS_1 0x40 + +void +fu_plugin_init (FuPlugin *plugin) +{ + fu_plugin_alloc_data (plugin, sizeof (FuPluginData)); + fu_plugin_set_build_hash (plugin, FU_BUILD_HASH); + fu_plugin_add_udev_subsystem (plugin, "pci"); +} + +gboolean +fu_plugin_udev_device_added (FuPlugin *plugin, FuUdevDevice *device, GError **error) +{ + FuPluginData *priv = fu_plugin_get_data (plugin); + g_autoptr(FuDeviceLocker) locker = NULL; + + /* interesting device? */ + if (g_strcmp0 (fu_udev_device_get_subsystem (device), "pci") != 0) + return TRUE; + + /* open the config */ + fu_udev_device_set_flags (device, FU_UDEV_DEVICE_FLAG_USE_CONFIG); + if (!fu_udev_device_set_physical_id (device, "pci", error)) + return FALSE; + locker = fu_device_locker_new (device, error); + if (locker == NULL) + return FALSE; + + /* grab MEI config Register */ + if (!fu_udev_device_pread (device, PCI_CFG_HFS_1, &priv->mei_cfg, error)) { + g_prefix_error (error, "could not read MEI"); + return FALSE; + } + priv->has_device = TRUE; + return TRUE; +} + +void +fu_plugin_add_security_attrs (FuPlugin *plugin, FuSecurityAttrs *attrs) +{ + FuPluginData *priv = fu_plugin_get_data (plugin); + g_autoptr(FwupdSecurityAttr) attr = NULL; + + /* only Intel */ + if (!fu_common_is_cpu_intel ()) + return; + if (!priv->has_device) + return; + + /* create attr */ + attr = fwupd_security_attr_new ("com.intel.MEI"); + fwupd_security_attr_set_plugin (attr, fu_plugin_get_name (plugin)); + fwupd_security_attr_set_level (attr, FWUPD_SECURITY_ATTR_LEVEL_CRITICAL); + fwupd_security_attr_set_name (attr, "MEI"); + fu_security_attrs_append (attrs, attr); + + /* load file */ + if ((priv->mei_cfg & (1 << 4)) != 0) { + fwupd_security_attr_set_result (attr, "Manufacturing Mode"); + return; + } + + /* success */ + fwupd_security_attr_add_flag (attr, FWUPD_SECURITY_ATTR_FLAG_SUCCESS); +} diff --git a/plugins/pci-mei/meson.build b/plugins/pci-mei/meson.build new file mode 100644 index 000000000..ce87f4920 --- /dev/null +++ b/plugins/pci-mei/meson.build @@ -0,0 +1,27 @@ +cargs = ['-DG_LOG_DOMAIN="FuPluginPciMei"'] + +install_data(['pci-mei.quirk'], + install_dir: join_paths(datadir, 'fwupd', 'quirks.d') +) + +shared_module('fu_plugin_pci_mei', + fu_hash, + sources : [ + 'fu-plugin-pci-mei.c', + ], + include_directories : [ + root_incdir, + fwupd_incdir, + fwupdplugin_incdir, + ], + install : true, + install_dir: plugin_dir, + link_with : [ + fwupd, + fwupdplugin, + ], + c_args : cargs, + dependencies : [ + plugin_deps, + ], +) diff --git a/plugins/pci-mei/pci-mei.quirk b/plugins/pci-mei/pci-mei.quirk new file mode 100644 index 000000000..5d834e5d2 --- /dev/null +++ b/plugins/pci-mei/pci-mei.quirk @@ -0,0 +1,126 @@ +[DeviceInstanceId=PCI\VEN_8086&DEV_02E0] +Plugin = pci_mei +[DeviceInstanceId=PCI\VEN_8086&DEV_02E4] +Plugin = pci_mei +[DeviceInstanceId=PCI\VEN_8086&DEV_06E0] +Plugin = pci_mei +[DeviceInstanceId=PCI\VEN_8086&DEV_06E4] +Plugin = pci_mei +[DeviceInstanceId=PCI\VEN_8086&DEV_18D3] +Plugin = pci_mei +[DeviceInstanceId=PCI\VEN_8086&DEV_19E5] +Plugin = pci_mei +[DeviceInstanceId=PCI\VEN_8086&DEV_1A9A] +Plugin = pci_mei +[DeviceInstanceId=PCI\VEN_8086&DEV_1C3A] +Plugin = pci_mei +[DeviceInstanceId=PCI\VEN_8086&DEV_1CBA] +Plugin = pci_mei +[DeviceInstanceId=PCI\VEN_8086&DEV_1D3A] +Plugin = pci_mei +[DeviceInstanceId=PCI\VEN_8086&DEV_1DBA] +Plugin = pci_mei +[DeviceInstanceId=PCI\VEN_8086&DEV_1E3A] +Plugin = pci_mei +[DeviceInstanceId=PCI\VEN_8086&DEV_28B4] +Plugin = pci_mei +[DeviceInstanceId=PCI\VEN_8086&DEV_28C4] +Plugin = pci_mei +[DeviceInstanceId=PCI\VEN_8086&DEV_28D4] +Plugin = pci_mei +[DeviceInstanceId=PCI\VEN_8086&DEV_28E4] +Plugin = pci_mei +[DeviceInstanceId=PCI\VEN_8086&DEV_28F4] +Plugin = pci_mei +[DeviceInstanceId=PCI\VEN_8086&DEV_2974] +Plugin = pci_mei +[DeviceInstanceId=PCI\VEN_8086&DEV_2984] +Plugin = pci_mei +[DeviceInstanceId=PCI\VEN_8086&DEV_2994] +Plugin = pci_mei +[DeviceInstanceId=PCI\VEN_8086&DEV_29A4] +Plugin = pci_mei +[DeviceInstanceId=PCI\VEN_8086&DEV_29B4] +Plugin = pci_mei +[DeviceInstanceId=PCI\VEN_8086&DEV_29C4] +Plugin = pci_mei +[DeviceInstanceId=PCI\VEN_8086&DEV_29D4] +Plugin = pci_mei +[DeviceInstanceId=PCI\VEN_8086&DEV_29E4] +Plugin = pci_mei +[DeviceInstanceId=PCI\VEN_8086&DEV_29F4] +Plugin = pci_mei +[DeviceInstanceId=PCI\VEN_8086&DEV_2A04] +Plugin = pci_mei +[DeviceInstanceId=PCI\VEN_8086&DEV_2A14] +Plugin = pci_mei +[DeviceInstanceId=PCI\VEN_8086&DEV_2A44] +Plugin = pci_mei +[DeviceInstanceId=PCI\VEN_8086&DEV_2A54] +Plugin = pci_mei +[DeviceInstanceId=PCI\VEN_8086&DEV_2A64] +Plugin = pci_mei +[DeviceInstanceId=PCI\VEN_8086&DEV_2A74] +Plugin = pci_mei +[DeviceInstanceId=PCI\VEN_8086&DEV_2E04] +Plugin = pci_mei +[DeviceInstanceId=PCI\VEN_8086&DEV_2E14] +Plugin = pci_mei +[DeviceInstanceId=PCI\VEN_8086&DEV_2E24] +Plugin = pci_mei +[DeviceInstanceId=PCI\VEN_8086&DEV_2E34] +Plugin = pci_mei +[DeviceInstanceId=PCI\VEN_8086&DEV_319A] +Plugin = pci_mei +[DeviceInstanceId=PCI\VEN_8086&DEV_34E0] +Plugin = pci_mei +[DeviceInstanceId=PCI\VEN_8086&DEV_3B64] +Plugin = pci_mei +[DeviceInstanceId=PCI\VEN_8086&DEV_3B65] +Plugin = pci_mei +[DeviceInstanceId=PCI\VEN_8086&DEV_4B70] +Plugin = pci_mei +[DeviceInstanceId=PCI\VEN_8086&DEV_4B75] +Plugin = pci_mei +[DeviceInstanceId=PCI\VEN_8086&DEV_4DE0] +Plugin = pci_mei +[DeviceInstanceId=PCI\VEN_8086&DEV_5A9A] +Plugin = pci_mei +[DeviceInstanceId=PCI\VEN_8086&DEV_8C3A] +Plugin = pci_mei +[DeviceInstanceId=PCI\VEN_8086&DEV_8CBA] +Plugin = pci_mei +[DeviceInstanceId=PCI\VEN_8086&DEV_8D3A] +Plugin = pci_mei +[DeviceInstanceId=PCI\VEN_8086&DEV_9C3A] +Plugin = pci_mei +[DeviceInstanceId=PCI\VEN_8086&DEV_9CBA] +Plugin = pci_mei +[DeviceInstanceId=PCI\VEN_8086&DEV_9CBB] +Plugin = pci_mei +[DeviceInstanceId=PCI\VEN_8086&DEV_9D3A] +Plugin = pci_mei +[DeviceInstanceId=PCI\VEN_8086&DEV_9D3B] +Plugin = pci_mei +[DeviceInstanceId=PCI\VEN_8086&DEV_9DE0] +Plugin = pci_mei +[DeviceInstanceId=PCI\VEN_8086&DEV_9DE4] +Plugin = pci_mei +[DeviceInstanceId=PCI\VEN_8086&DEV_A0E0] +Plugin = pci_mei +[DeviceInstanceId=PCI\VEN_8086&DEV_A13A] +Plugin = pci_mei +[DeviceInstanceId=PCI\VEN_8086&DEV_A13B] +Plugin = pci_mei +[DeviceInstanceId=PCI\VEN_8086&DEV_A1BA] +Plugin = pci_mei +[DeviceInstanceId=PCI\VEN_8086&DEV_A2BA] +Plugin = pci_mei +[DeviceInstanceId=PCI\VEN_8086&DEV_A2BB] +Plugin = pci_mei +[DeviceInstanceId=PCI\VEN_8086&DEV_A360] +Plugin = pci_mei +[DeviceInstanceId=PCI\VEN_8086&DEV_A364] +Plugin = pci_mei +[DeviceInstanceId=PCI\VEN_8086&DEV_A3BA] +Plugin = pci_mei From d67a77cb9da1665486b03675e01777db5416e55d Mon Sep 17 00:00:00 2001 From: Mario Limonciello Date: Fri, 15 May 2020 20:04:49 -0500 Subject: [PATCH 082/607] trivial: fix TME support On a CPU that does support it the security check was still failing. --- plugins/cpu/fu-plugin-cpu.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/plugins/cpu/fu-plugin-cpu.c b/plugins/cpu/fu-plugin-cpu.c index 832e0ca8b..453a6b835 100644 --- a/plugins/cpu/fu-plugin-cpu.c +++ b/plugins/cpu/fu-plugin-cpu.c @@ -44,6 +44,8 @@ fu_plugin_coldplug (FuPlugin *plugin, GError **error) if (fu_cpu_device_has_flag (dev, FU_CPU_DEVICE_FLAG_SHSTK) && fu_cpu_device_has_flag (dev, FU_CPU_DEVICE_FLAG_IBT)) data->has_cet = TRUE; + if (fu_cpu_device_has_flag (dev, FU_CPU_DEVICE_FLAG_TME)) + data->has_tme = TRUE; fu_plugin_device_add (plugin, FU_DEVICE (dev)); } From f50c6b552682a20e557efac82740c21d229cd54e Mon Sep 17 00:00:00 2001 From: Richard Hughes Date: Sun, 17 May 2020 20:32:23 +0100 Subject: [PATCH 083/607] trivial: Make --force wotk in fwupdagent --- src/fu-agent.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/fu-agent.c b/src/fu-agent.c index 9329ec81b..c85b91166 100644 --- a/src/fu-agent.c +++ b/src/fu-agent.c @@ -340,10 +340,6 @@ main (int argc, char *argv[]) priv->loop = g_main_loop_new (NULL, FALSE); priv->client = fwupd_client_new (); - /* set flags */ - if (force) - priv->flags |= FWUPD_INSTALL_FLAG_FORCE; - /* add commands */ fu_util_cmd_array_add (cmd_array, "get-devices", NULL, @@ -398,6 +394,10 @@ main (int argc, char *argv[]) fu_util_ignore_cb, NULL); } + /* set flags */ + if (force) + priv->flags |= FWUPD_INSTALL_FLAG_FORCE; + /* run the specified command */ ret = fu_util_cmd_array_run (cmd_array, priv, argv[1], (gchar**) &argv[2], &error); if (!ret) { From 56e7ae503a4d47af73abe85533a7f599ee73c836 Mon Sep 17 00:00:00 2001 From: Richard Hughes Date: Sun, 17 May 2020 21:00:23 +0100 Subject: [PATCH 084/607] trivial: Remove the GError from fu_engine_get_host_security_attrs() It cannot fail. --- src/fu-engine.c | 7 +++---- src/fu-engine.h | 3 +-- src/fu-main.c | 6 +----- src/fu-tool.c | 4 +--- 4 files changed, 6 insertions(+), 14 deletions(-) diff --git a/src/fu-engine.c b/src/fu-engine.c index b51686907..4143c39dc 100644 --- a/src/fu-engine.c +++ b/src/fu-engine.c @@ -5135,7 +5135,7 @@ fu_engine_add_security_attrs_supported (FuEngine *self, FuSecurityAttrs *attrs) } FuSecurityAttrs * -fu_engine_get_host_security_attrs (FuEngine *self, GError **error) +fu_engine_get_host_security_attrs (FuEngine *self) { GPtrArray *plugins = fu_plugin_list_get_all (self->plugin_list); g_autoptr(FuSecurityAttrs) attrs = fu_security_attrs_new (); @@ -5166,9 +5166,8 @@ fu_engine_get_host_security_id (FuEngine *self) g_free (self->host_security_id); self->host_security_id = NULL; self->host_security_id_valid = TRUE; - attrs = fu_engine_get_host_security_attrs (self, NULL); - if (attrs != NULL) - self->host_security_id = fu_security_attrs_calculate_hsi (attrs); + attrs = fu_engine_get_host_security_attrs (self); + self->host_security_id = fu_security_attrs_calculate_hsi (attrs); } return self->host_security_id; diff --git a/src/fu-engine.h b/src/fu-engine.h index f8c8205d8..5f9a376fc 100644 --- a/src/fu-engine.h +++ b/src/fu-engine.h @@ -84,8 +84,7 @@ GPtrArray *fu_engine_get_upgrades (FuEngine *self, FwupdDevice *fu_engine_get_results (FuEngine *self, const gchar *device_id, GError **error); -FuSecurityAttrs *fu_engine_get_host_security_attrs (FuEngine *self, - GError **error); +FuSecurityAttrs *fu_engine_get_host_security_attrs (FuEngine *self); gboolean fu_engine_clear_results (FuEngine *self, const gchar *device_id, GError **error); diff --git a/src/fu-main.c b/src/fu-main.c index 0360e06c3..97636f93b 100644 --- a/src/fu-main.c +++ b/src/fu-main.c @@ -992,11 +992,7 @@ fu_main_daemon_method_call (GDBusConnection *connection, const gchar *sender, if (g_strcmp0 (method_name, "GetHostSecurityAttrs") == 0) { g_autoptr(FuSecurityAttrs) attrs = NULL; g_debug ("Called %s()", method_name); - attrs = fu_engine_get_host_security_attrs (priv->engine, &error); - if (attrs == NULL) { - g_dbus_method_invocation_return_gerror (invocation, error); - return; - } + attrs = fu_engine_get_host_security_attrs (priv->engine); val = fu_security_attrs_to_variant (attrs); g_dbus_method_invocation_return_value (invocation, val); return; diff --git a/src/fu-tool.c b/src/fu-tool.c index 85f43a0ce..09455daa6 100644 --- a/src/fu-tool.c +++ b/src/fu-tool.c @@ -1963,9 +1963,7 @@ fu_util_security (FuUtilPrivate *priv, gchar **values, GError **error) fu_engine_get_host_security_id (priv->engine)); /* print the "why" */ - attrs = fu_engine_get_host_security_attrs (priv->engine, error); - if (attrs == NULL) - return FALSE; + attrs = fu_engine_get_host_security_attrs (priv->engine); items = fu_security_attrs_get_all (attrs); str = fu_util_security_attrs_to_string (items); g_print ("%s\n", str); From cef874f8f313964bcbbe6a86357f019844ccf1fb Mon Sep 17 00:00:00 2001 From: Richard Hughes Date: Sun, 17 May 2020 21:03:13 +0100 Subject: [PATCH 085/607] Include the HSI results and attributes in the uploaded report But only for system firmware devices otherwise it's probably crossing the line from a privacy point of view. --- src/fu-engine.c | 39 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 39 insertions(+) diff --git a/src/fu-engine.c b/src/fu-engine.c index 4143c39dc..23e2927e3 100644 --- a/src/fu-engine.c +++ b/src/fu-engine.c @@ -3585,6 +3585,38 @@ fu_engine_get_devices_by_guid (FuEngine *self, const gchar *guid, GError **error return g_steal_pointer (&devices); } +static const gchar * +fu_engine_get_security_attr_result_string (FwupdSecurityAttr *attr) +{ + if (fwupd_security_attr_get_result (attr) != NULL) + return fwupd_security_attr_get_result (attr); + if (fwupd_security_attr_has_flag (attr, FWUPD_SECURITY_ATTR_FLAG_SUCCESS)) + return "True"; + return "False"; +} + +static void +fu_engine_get_history_set_hsi_attrs (FuEngine *self, FuDevice *device) +{ + g_autofree gchar *host_security_id = NULL; + g_autoptr(FuSecurityAttrs) attrs = NULL; + g_autoptr(GPtrArray) vals = NULL; + + /* add attributes */ + attrs = fu_engine_get_host_security_attrs (self); + vals = fu_security_attrs_get_all (attrs); + for (guint i = 0; i < vals->len; i++) { + FwupdSecurityAttr *attr = g_ptr_array_index (vals, i); + fu_device_set_metadata (device, + fwupd_security_attr_get_appstream_id (attr), + fu_engine_get_security_attr_result_string (attr)); + } + + /* computed value */ + host_security_id = fu_security_attrs_calculate_hsi (attrs); + fu_device_set_metadata (device, "HSI", host_security_id); +} + /** * fu_engine_get_history: * @self: A #FuEngine @@ -3613,6 +3645,13 @@ fu_engine_get_history (FuEngine *self, GError **error) return NULL; } + /* if this is the system firmware device, add the HSI attrs */ + for (guint i = 0; i < devices->len; i++) { + FuDevice *dev = g_ptr_array_index (devices, i); + if (fu_device_has_instance_id (dev, "main-system-firmware")) + fu_engine_get_history_set_hsi_attrs (self, dev); + } + /* try to set the remote ID for each device */ for (guint i = 0; i < devices->len; i++) { FuDevice *dev = g_ptr_array_index (devices, i); From b246bcaecb84c2facc0b42a54c145fab5148bc2a Mon Sep 17 00:00:00 2001 From: Richard Hughes Date: Mon, 18 May 2020 14:31:35 +0100 Subject: [PATCH 086/607] Allow client tools to translate the HSI attributes and results To do this, rely on the AppStream ID to map to a translated string (providing a fallback for clients that do not care) and switch the free-form result string into a set of enumerated values that can be translated. This fixes some of the problems where some things have to be enabled to "pass" and other attributes have to be some other state. For cases where we want the user to "do" something, provide a URL to a wiki page that we update out-of-band of fwupd releases. --- libfwupd/fwupd-enums-private.h | 2 +- libfwupd/fwupd-security-attr.c | 137 ++++++++++++-- libfwupd/fwupd-security-attr.h | 72 +++++++- libfwupd/fwupd.map | 3 + libfwupdplugin/fu-security-attrs.c | 15 +- libfwupdplugin/fu-self-test.c | 20 +- plugins/acpi-dmar/fu-plugin-acpi-dmar.c | 10 +- plugins/acpi-facp/fu-plugin-acpi-facp.c | 10 +- plugins/amt/fu-plugin-amt.c | 7 +- plugins/cpu/fu-plugin-cpu.c | 14 +- plugins/iommu/fu-plugin-iommu.c | 6 +- .../linux-lockdown/fu-plugin-linux-lockdown.c | 9 +- plugins/linux-sleep/fu-plugin-linux-sleep.c | 8 +- .../linux-spi-lpc/fu-plugin-linux-spi-lpc.c | 62 ++++--- plugins/linux-swap/fu-plugin-linux-swap.c | 12 +- .../linux-tainted/fu-plugin-linux-tainted.c | 8 +- plugins/pci-bcr/fu-plugin-pci-bcr.c | 64 ++++--- plugins/pci-mei/fu-plugin-pci-mei.c | 6 +- plugins/tpm-eventlog/fu-plugin-tpm-eventlog.c | 9 +- plugins/tpm/fu-plugin-tpm.c | 9 +- plugins/uefi-dbx/fu-plugin-uefi-dbx.c | 23 +-- plugins/uefi-dbx/fu-uefi-dbx-common.h | 2 - plugins/uefi/fu-plugin-uefi.c | 7 +- po/POTFILES.in | 1 + src/fu-engine.c | 78 ++++---- src/fu-security-attr.c | 174 ++++++++++++++++++ src/fu-security-attr.h | 12 ++ src/fu-self-test.c | 12 ++ src/fu-util-common.c | 24 ++- src/meson.build | 6 + 30 files changed, 608 insertions(+), 214 deletions(-) create mode 100644 src/fu-security-attr.c create mode 100644 src/fu-security-attr.h diff --git a/libfwupd/fwupd-enums-private.h b/libfwupd/fwupd-enums-private.h index abb556895..7d2bc8136 100644 --- a/libfwupd/fwupd-enums-private.h +++ b/libfwupd/fwupd-enums-private.h @@ -24,7 +24,7 @@ G_BEGIN_DECLS #define FWUPD_RESULT_KEY_FLASHES_LEFT "FlashesLeft" /* u */ #define FWUPD_RESULT_KEY_URGENCY "Urgency" /* u */ #define FWUPD_RESULT_KEY_HSI_LEVEL "HsiLevel" /* u */ -#define FWUPD_RESULT_KEY_HSI_RESULT "HsiResult" /* s */ +#define FWUPD_RESULT_KEY_HSI_RESULT "HsiResult" /* u */ #define FWUPD_RESULT_KEY_INSTALL_DURATION "InstallDuration" /* u */ #define FWUPD_RESULT_KEY_GUID "Guid" /* as */ #define FWUPD_RESULT_KEY_INSTANCE_IDS "InstanceIds" /* as */ diff --git a/libfwupd/fwupd-security-attr.c b/libfwupd/fwupd-security-attr.c index 5a0a2b094..6e618f894 100644 --- a/libfwupd/fwupd-security-attr.c +++ b/libfwupd/fwupd-security-attr.c @@ -25,8 +25,9 @@ typedef struct { GPtrArray *obsoletes; gchar *name; gchar *plugin; - gchar *result; + gchar *url; FwupdSecurityAttrLevel level; + FwupdSecurityAttrResult result; FwupdSecurityAttrFlags flags; } FwupdSecurityAttrPrivate; @@ -61,6 +62,50 @@ fwupd_security_attr_flag_to_string (FwupdSecurityAttrFlags flag) return NULL; } +/** + * fwupd_security_attr_result_to_string: + * @result: A #FwupdSecurityAttrResult, e.g. %FWUPD_SECURITY_ATTR_RESULT_ENABLED + * + * Returns the printable string for the result enum. + * + * Returns: string, or %NULL + * + * Since: 1.5.0 + **/ +const gchar * +fwupd_security_attr_result_to_string (FwupdSecurityAttrResult result) +{ + if (result == FWUPD_SECURITY_ATTR_RESULT_VALID) + return "valid"; + if (result == FWUPD_SECURITY_ATTR_RESULT_NOT_VALID) + return "not-valid"; + if (result == FWUPD_SECURITY_ATTR_RESULT_ENABLED) + return "enabled"; + if (result == FWUPD_SECURITY_ATTR_RESULT_NOT_ENABLED) + return "not-enabled"; + if (result == FWUPD_SECURITY_ATTR_RESULT_LOCKED) + return "locked"; + if (result == FWUPD_SECURITY_ATTR_RESULT_NOT_LOCKED) + return "not-locked"; + if (result == FWUPD_SECURITY_ATTR_RESULT_ENCRYPTED) + return "encrypted"; + if (result == FWUPD_SECURITY_ATTR_RESULT_NOT_ENCRYPTED) + return "not-encrypted"; + if (result == FWUPD_SECURITY_ATTR_RESULT_TAINTED) + return "tainted"; + if (result == FWUPD_SECURITY_ATTR_RESULT_NOT_TAINTED) + return "not-tainted"; + if (result == FWUPD_SECURITY_ATTR_RESULT_FOUND) + return "found"; + if (result == FWUPD_SECURITY_ATTR_RESULT_NOT_FOUND) + return "not-found"; + if (result == FWUPD_SECURITY_ATTR_RESULT_SUPPORTED) + return "supported"; + if (result == FWUPD_SECURITY_ATTR_RESULT_NOT_SUPPORTED) + return "not-supported"; + return NULL; +} + /** * fwupd_security_attr_flag_to_suffix: * @flag: A #FwupdSecurityAttrFlags, e.g. %FWUPD_SECURITY_ATTR_FLAG_RUNTIME_UPDATES @@ -105,7 +150,7 @@ fwupd_security_attr_get_obsoletes (FwupdSecurityAttr *self) /** * fwupd_security_attr_add_obsolete: * @self: A #FwupdSecurityAttr - * @appstream_id: the appstream_id + * @appstream_id: the appstream_id or plugin name * * Adds an attribute appstream_id to obsolete. The obsoleted attribute will not * contribute to the calculated HSI value or be visible in command line tools. @@ -180,26 +225,31 @@ fwupd_security_attr_set_appstream_id (FwupdSecurityAttr *self, const gchar *apps { FwupdSecurityAttrPrivate *priv = GET_PRIVATE (self); g_return_if_fail (FWUPD_IS_SECURITY_ATTR (self)); + + /* sanity check */ + if (!g_str_has_prefix (appstream_id, "org.fwupd.hsi.")) + g_critical ("HSI attributes need to have a 'org.fwupd.hsi.' prefix"); + g_free (priv->appstream_id); priv->appstream_id = g_strdup (appstream_id); } /** - * fwupd_security_attr_get_result: + * fwupd_security_attr_get_url: * @self: A #FwupdSecurityAttr * - * Gets the attribute result. + * Gets the attribute URL. * * Returns: the attribute result, or %NULL if unset * * Since: 1.5.0 **/ const gchar * -fwupd_security_attr_get_result (FwupdSecurityAttr *self) +fwupd_security_attr_get_url (FwupdSecurityAttr *self) { FwupdSecurityAttrPrivate *priv = GET_PRIVATE (self); g_return_val_if_fail (FWUPD_IS_SECURITY_ATTR (self), NULL); - return priv->result; + return priv->url; } /** @@ -239,21 +289,21 @@ fwupd_security_attr_set_plugin (FwupdSecurityAttr *self, const gchar *plugin) } /** - * fwupd_security_attr_set_result: + * fwupd_security_attr_set_url: * @self: A #FwupdSecurityAttr - * @result: the attribute one line result + * @url: the attribute URL * * Sets the attribute result. * * Since: 1.5.0 **/ void -fwupd_security_attr_set_result (FwupdSecurityAttr *self, const gchar *result) +fwupd_security_attr_set_url (FwupdSecurityAttr *self, const gchar *url) { FwupdSecurityAttrPrivate *priv = GET_PRIVATE (self); g_return_if_fail (FWUPD_IS_SECURITY_ATTR (self)); - g_free (priv->result); - priv->result = g_strdup (result); + g_free (priv->url); + priv->url = g_strdup (url); } /** @@ -399,6 +449,42 @@ fwupd_security_attr_set_level (FwupdSecurityAttr *self, FwupdSecurityAttrLevel l priv->level = level; } +/** + * fwupd_security_attr_set_result: + * @self: A #FwupdSecurityAttr + * @result: A #FwupdSecurityAttrResult, e.g. %FWUPD_SECURITY_ATTR_LEVEL_LOCKED + * + * Sets the optional HSI result. This is required because some attributes may + * be a "success" when something is `locked` or may be "failed" if `found`. + * + * Since: 1.5.0 + **/ +void +fwupd_security_attr_set_result (FwupdSecurityAttr *self, FwupdSecurityAttrResult result) +{ + FwupdSecurityAttrPrivate *priv = GET_PRIVATE (self); + g_return_if_fail (FWUPD_IS_SECURITY_ATTR (self)); + priv->result = result; +} + +/** + * fwupd_security_attr_get_result: + * @self: A #FwupdSecurityAttr + * + * Gets the optional HSI result. + * + * Returns: the #FwupdSecurityAttrResult, e.g %FWUPD_SECURITY_ATTR_LEVEL_LOCKED + * + * Since: 1.5.0 + **/ +FwupdSecurityAttrResult +fwupd_security_attr_get_result (FwupdSecurityAttr *self) +{ + FwupdSecurityAttrPrivate *priv = GET_PRIVATE (self); + g_return_val_if_fail (FWUPD_IS_SECURITY_ATTR (self), 0); + return priv->result; +} + /** * fwupd_security_attr_to_variant: * @self: A #FwupdSecurityAttr @@ -428,10 +514,10 @@ fwupd_security_attr_to_variant (FwupdSecurityAttr *self) FWUPD_RESULT_KEY_NAME, g_variant_new_string (priv->name)); } - if (priv->result != NULL) { + if (priv->url != NULL) { g_variant_builder_add (&builder, "{sv}", - FWUPD_RESULT_KEY_HSI_RESULT, - g_variant_new_string (priv->result)); + FWUPD_RESULT_KEY_URI, + g_variant_new_string (priv->url)); } if (priv->obsoletes->len > 0) { g_autofree const gchar **strv = g_new0 (const gchar *, priv->obsoletes->len + 1); @@ -451,6 +537,11 @@ fwupd_security_attr_to_variant (FwupdSecurityAttr *self) FWUPD_RESULT_KEY_HSI_LEVEL, g_variant_new_uint32 (priv->level)); } + if (priv->result > 0) { + g_variant_builder_add (&builder, "{sv}", + FWUPD_RESULT_KEY_HSI_RESULT, + g_variant_new_uint32 (priv->result)); + } return g_variant_new ("a{sv}", &builder); } @@ -465,8 +556,8 @@ fwupd_security_attr_from_key_value (FwupdSecurityAttr *self, const gchar *key, G fwupd_security_attr_set_name (self, g_variant_get_string (value, NULL)); return; } - if (g_strcmp0 (key, FWUPD_RESULT_KEY_HSI_RESULT) == 0) { - fwupd_security_attr_set_result (self, g_variant_get_string (value, NULL)); + if (g_strcmp0 (key, FWUPD_RESULT_KEY_URI) == 0) { + fwupd_security_attr_set_url (self, g_variant_get_string (value, NULL)); return; } if (g_strcmp0 (key, FWUPD_RESULT_KEY_FLAGS) == 0) { @@ -477,6 +568,10 @@ fwupd_security_attr_from_key_value (FwupdSecurityAttr *self, const gchar *key, G fwupd_security_attr_set_level (self, g_variant_get_uint32 (value)); return; } + if (g_strcmp0 (key, FWUPD_RESULT_KEY_HSI_RESULT) == 0) { + fwupd_security_attr_set_result (self, g_variant_get_uint32 (value)); + return; + } } static void @@ -559,9 +654,11 @@ fwupd_security_attr_to_json (FwupdSecurityAttr *self, JsonBuilder *builder) fwupd_security_attr_json_add_string (builder, FWUPD_RESULT_KEY_APPSTREAM_ID, priv->appstream_id); fwupd_security_attr_json_add_int (builder, FWUPD_RESULT_KEY_HSI_LEVEL, priv->level); + fwupd_security_attr_json_add_string (builder, FWUPD_RESULT_KEY_HSI_RESULT, + fwupd_security_attr_result_to_string (priv->result)); fwupd_security_attr_json_add_string (builder, FWUPD_RESULT_KEY_NAME, priv->name); fwupd_security_attr_json_add_string (builder, FWUPD_RESULT_KEY_PLUGIN, priv->plugin); - fwupd_security_attr_json_add_string (builder, FWUPD_RESULT_KEY_HSI_RESULT, priv->result); + fwupd_security_attr_json_add_string (builder, FWUPD_RESULT_KEY_URI, priv->url); if (priv->flags != FWUPD_SECURITY_ATTR_FLAG_NONE) { json_builder_set_member_name (builder, FWUPD_RESULT_KEY_FLAGS); json_builder_begin_array (builder); @@ -598,11 +695,13 @@ fwupd_security_attr_to_string (FwupdSecurityAttr *self) str = g_string_new (""); fwupd_pad_kv_str (str, FWUPD_RESULT_KEY_APPSTREAM_ID, priv->appstream_id); fwupd_pad_kv_int (str, FWUPD_RESULT_KEY_HSI_LEVEL, priv->level); + fwupd_pad_kv_str (str, FWUPD_RESULT_KEY_HSI_RESULT, + fwupd_security_attr_result_to_string (priv->result)); if (priv->flags != FWUPD_SECURITY_ATTR_FLAG_NONE) fwupd_pad_kv_tfl (str, FWUPD_RESULT_KEY_FLAGS, priv->flags); fwupd_pad_kv_str (str, FWUPD_RESULT_KEY_NAME, priv->name); fwupd_pad_kv_str (str, FWUPD_RESULT_KEY_PLUGIN, priv->plugin); - fwupd_pad_kv_str (str, FWUPD_RESULT_KEY_HSI_RESULT, priv->result); + fwupd_pad_kv_str (str, FWUPD_RESULT_KEY_URI, priv->url); for (guint i = 0; i < priv->obsoletes->len; i++) { const gchar *appstream_id = g_ptr_array_index (priv->obsoletes, i); fwupd_pad_kv_str (str, "Obsolete", appstream_id); @@ -634,7 +733,7 @@ fwupd_security_attr_finalize (GObject *object) g_free (priv->appstream_id); g_free (priv->name); g_free (priv->plugin); - g_free (priv->result); + g_free (priv->url); g_ptr_array_unref (priv->obsoletes); G_OBJECT_CLASS (fwupd_security_attr_parent_class)->finalize (object); diff --git a/libfwupd/fwupd-security-attr.h b/libfwupd/fwupd-security-attr.h index 4ced33435..44033ebed 100644 --- a/libfwupd/fwupd-security-attr.h +++ b/libfwupd/fwupd-security-attr.h @@ -71,6 +71,68 @@ typedef enum { FWUPD_SECURITY_ATTR_LEVEL_LAST = 6 /* perhaps increased in the future */ } FwupdSecurityAttrLevel; +/** + * FwupdSecurityAttrResult: + * @FWUPD_SECURITY_ATTR_RESULT_UNKNOWN: Not known + * @FWUPD_SECURITY_ATTR_RESULT_ENABLED: Enabled + * @FWUPD_SECURITY_ATTR_RESULT_NOT_ENABLED: Not enabled + * @FWUPD_SECURITY_ATTR_RESULT_VALID: Valid + * @FWUPD_SECURITY_ATTR_RESULT_NOT_VALID: Not valid + * @FWUPD_SECURITY_ATTR_RESULT_LOCKED: Locked + * @FWUPD_SECURITY_ATTR_RESULT_NOT_LOCKED: Not locked + * @FWUPD_SECURITY_ATTR_RESULT_ENCRYPTED: Encrypted + * @FWUPD_SECURITY_ATTR_RESULT_NOT_ENCRYPTED: Not encrypted + * @FWUPD_SECURITY_ATTR_RESULT_TAINTED: Tainted + * @FWUPD_SECURITY_ATTR_RESULT_NOT_TAINTED: Not tainted + * @FWUPD_SECURITY_ATTR_RESULT_FOUND: Found + * @FWUPD_SECURITY_ATTR_RESULT_NOT_FOUND: NOt found + * @FWUPD_SECURITY_ATTR_RESULT_SUPPORTED: Supported + * @FWUPD_SECURITY_ATTR_RESULT_NOT_SUPPORTED: Not supported + * + * The HSI result. + **/ +typedef enum { + FWUPD_SECURITY_ATTR_RESULT_UNKNOWN, /* Since: 1.5.0 */ + FWUPD_SECURITY_ATTR_RESULT_ENABLED, /* Since: 1.5.0 */ + FWUPD_SECURITY_ATTR_RESULT_NOT_ENABLED, /* Since: 1.5.0 */ + FWUPD_SECURITY_ATTR_RESULT_VALID, /* Since: 1.5.0 */ + FWUPD_SECURITY_ATTR_RESULT_NOT_VALID, /* Since: 1.5.0 */ + FWUPD_SECURITY_ATTR_RESULT_LOCKED, /* Since: 1.5.0 */ + FWUPD_SECURITY_ATTR_RESULT_NOT_LOCKED, /* Since: 1.5.0 */ + FWUPD_SECURITY_ATTR_RESULT_ENCRYPTED, /* Since: 1.5.0 */ + FWUPD_SECURITY_ATTR_RESULT_NOT_ENCRYPTED, /* Since: 1.5.0 */ + FWUPD_SECURITY_ATTR_RESULT_TAINTED, /* Since: 1.5.0 */ + FWUPD_SECURITY_ATTR_RESULT_NOT_TAINTED, /* Since: 1.5.0 */ + FWUPD_SECURITY_ATTR_RESULT_FOUND, /* Since: 1.5.0 */ + FWUPD_SECURITY_ATTR_RESULT_NOT_FOUND, /* Since: 1.5.0 */ + FWUPD_SECURITY_ATTR_RESULT_SUPPORTED, /* Since: 1.5.0 */ + FWUPD_SECURITY_ATTR_RESULT_NOT_SUPPORTED, /* Since: 1.5.0 */ + /*< private >*/ + FWUPD_SECURITY_ATTR_RESULT_LAST +} FwupdSecurityAttrResult; + +#define FWUPD_SECURITY_ATTR_ID_ACPI_DMAR "org.fwupd.hsi.AcpiDmar" /* Since: 1.5.0 */ +#define FWUPD_SECURITY_ATTR_ID_ENCRYPTED_RAM "org.fwupd.hsi.EncryptedRam" /* Since: 1.5.0 */ +#define FWUPD_SECURITY_ATTR_ID_FWUPD_ATTESTATION "org.fwupd.hsi.FwupdAttestation" /* Since: 1.5.0 */ +#define FWUPD_SECURITY_ATTR_ID_FWUPD_PLUGINS "org.fwupd.hsi.FwupdPlugins" /* Since: 1.5.0 */ +#define FWUPD_SECURITY_ATTR_ID_FWUPD_UPDATES "org.fwupd.hsi.FwupdUpdates" /* Since: 1.5.0 */ +#define FWUPD_SECURITY_ATTR_ID_INTEL_AMT "org.fwupd.hsi.IntelAmt" /* Since: 1.5.0 */ +#define FWUPD_SECURITY_ATTR_ID_INTEL_CET "org.fwupd.hsi.IntelCet" /* Since: 1.5.0 */ +#define FWUPD_SECURITY_ATTR_ID_IOMMU "org.fwupd.hsi.Iommu" /* Since: 1.5.0 */ +#define FWUPD_SECURITY_ATTR_ID_KERNEL_LOCKDOWN "org.fwupd.hsi.KernelLockdown" /* Since: 1.5.0 */ +#define FWUPD_SECURITY_ATTR_ID_KERNEL_SWAP "org.fwupd.hsi.KernelSwap" /* Since: 1.5.0 */ +#define FWUPD_SECURITY_ATTR_ID_KERNEL_TAINTED "org.fwupd.hsi.KernelTainted" /* Since: 1.5.0 */ +#define FWUPD_SECURITY_ATTR_ID_MEI_MANUFACTURING_MODE "org.fwupd.hsi.MeiManufacturingMode" /* Since: 1.5.0 */ +#define FWUPD_SECURITY_ATTR_ID_SPI_BIOSWE "org.fwupd.hsi.SpiBioswe" /* Since: 1.5.0 */ +#define FWUPD_SECURITY_ATTR_ID_SPI_BLE "org.fwupd.hsi.SpiBle" /* Since: 1.5.0 */ +#define FWUPD_SECURITY_ATTR_ID_SPI_SMM_BWP "org.fwupd.hsi.SpiSmmBwp" /* Since: 1.5.0 */ +#define FWUPD_SECURITY_ATTR_ID_SUSPEND_TO_IDLE "org.fwupd.hsi.SuspendToIdle" /* Since: 1.5.0 */ +#define FWUPD_SECURITY_ATTR_ID_SUSPEND_TO_RAM "org.fwupd.hsi.SuspendToRam" /* Since: 1.5.0 */ +#define FWUPD_SECURITY_ATTR_ID_TPM_RECONSTRUCTION_PCR0 "org.fwupd.hsi.TpmReconstructionPcr0" /* Since: 1.5.0 */ +#define FWUPD_SECURITY_ATTR_ID_TPM_VERSION_20 "org.fwupd.hsi.TpmVersion20" /* Since: 1.5.0 */ +#define FWUPD_SECURITY_ATTR_ID_UEFI_DBX "org.fwupd.hsi.UefiDbx" /* Since: 1.5.0 */ +#define FWUPD_SECURITY_ATTR_ID_UEFI_SECUREBOOT "org.fwupd.hsi.UefiSecureBoot" /* Since: 1.5.0 */ + FwupdSecurityAttr *fwupd_security_attr_new (const gchar *appstream_id); gchar *fwupd_security_attr_to_string (FwupdSecurityAttr *self); @@ -80,15 +142,18 @@ void fwupd_security_attr_set_appstream_id (FwupdSecurityAttr *self, FwupdSecurityAttrLevel fwupd_security_attr_get_level (FwupdSecurityAttr *self); void fwupd_security_attr_set_level (FwupdSecurityAttr *self, FwupdSecurityAttrLevel level); +FwupdSecurityAttrResult fwupd_security_attr_get_result (FwupdSecurityAttr *self); +void fwupd_security_attr_set_result (FwupdSecurityAttr *self, + FwupdSecurityAttrResult result); const gchar *fwupd_security_attr_get_name (FwupdSecurityAttr *self); void fwupd_security_attr_set_name (FwupdSecurityAttr *self, const gchar *name); const gchar *fwupd_security_attr_get_plugin (FwupdSecurityAttr *self); void fwupd_security_attr_set_plugin (FwupdSecurityAttr *self, const gchar *plugin); -const gchar *fwupd_security_attr_get_result (FwupdSecurityAttr *self); -void fwupd_security_attr_set_result (FwupdSecurityAttr *self, - const gchar *result); +const gchar *fwupd_security_attr_get_url (FwupdSecurityAttr *self); +void fwupd_security_attr_set_url (FwupdSecurityAttr *self, + const gchar *url); GPtrArray *fwupd_security_attr_get_obsoletes (FwupdSecurityAttr *self); void fwupd_security_attr_add_obsolete (FwupdSecurityAttr *self, const gchar *appstream_id); @@ -103,6 +168,7 @@ gboolean fwupd_security_attr_has_flag (FwupdSecurityAttr *self, FwupdSecurityAttrFlags flag); const gchar *fwupd_security_attr_flag_to_string (FwupdSecurityAttrFlags flag); const gchar *fwupd_security_attr_flag_to_suffix (FwupdSecurityAttrFlags flag); +const gchar *fwupd_security_attr_result_to_string (FwupdSecurityAttrResult result); FwupdSecurityAttr *fwupd_security_attr_from_variant (GVariant *value); GPtrArray *fwupd_security_attr_array_from_variant (GVariant *value); diff --git a/libfwupd/fwupd.map b/libfwupd/fwupd.map index 54dbe74b5..3a3bf6402 100644 --- a/libfwupd/fwupd.map +++ b/libfwupd/fwupd.map @@ -465,15 +465,18 @@ LIBFWUPD_1.5.0 { fwupd_security_attr_get_plugin; fwupd_security_attr_get_result; fwupd_security_attr_get_type; + fwupd_security_attr_get_url; fwupd_security_attr_has_flag; fwupd_security_attr_has_obsolete; fwupd_security_attr_new; + fwupd_security_attr_result_to_string; fwupd_security_attr_set_appstream_id; fwupd_security_attr_set_flags; fwupd_security_attr_set_level; fwupd_security_attr_set_name; fwupd_security_attr_set_plugin; fwupd_security_attr_set_result; + fwupd_security_attr_set_url; fwupd_security_attr_to_json; fwupd_security_attr_to_string; fwupd_security_attr_to_variant; diff --git a/libfwupdplugin/fu-security-attrs.c b/libfwupdplugin/fu-security-attrs.c index 6ae739366..16b0da571 100644 --- a/libfwupdplugin/fu-security-attrs.c +++ b/libfwupdplugin/fu-security-attrs.c @@ -262,12 +262,25 @@ fu_security_attrs_depsolve (FuSecurityAttrs *self) for (guint j = 0; j < obsoletes->len; j++) { const gchar *obsolete = g_ptr_array_index (obsoletes, j); FwupdSecurityAttr *attr_tmp = g_hash_table_lookup (attrs_by_id, obsolete); + + /* by AppStream ID */ if (attr_tmp != NULL) { g_debug ("security attr %s obsoleted by %s", obsolete, - fwupd_security_attr_get_appstream_id (attr)); + fwupd_security_attr_get_appstream_id (attr_tmp)); fwupd_security_attr_add_flag (attr_tmp, FWUPD_SECURITY_ATTR_FLAG_OBSOLETED); } + + /* by plugin name */ + for (guint k = 0; k < self->attrs->len; k++) { + attr_tmp = g_ptr_array_index (self->attrs, k); + if (g_strcmp0 (obsolete, fwupd_security_attr_get_plugin (attr_tmp)) == 0) { + g_debug ("security attr %s obsoleted by %s", obsolete, + fwupd_security_attr_get_appstream_id (attr_tmp)); + fwupd_security_attr_add_flag (attr_tmp, + FWUPD_SECURITY_ATTR_FLAG_OBSOLETED); + } + } } } diff --git a/libfwupdplugin/fu-self-test.c b/libfwupdplugin/fu-self-test.c index 0406ce112..f820a6f01 100644 --- a/libfwupdplugin/fu-self-test.c +++ b/libfwupdplugin/fu-self-test.c @@ -1762,9 +1762,9 @@ fu_security_attrs_hsi_func (void) g_assert_cmpstr (hsi1, ==, "HSI:0"); /* just success from HSI:1 */ - attr = fwupd_security_attr_new ("org.fwupd.Hsi.BIOSWE"); + attr = fwupd_security_attr_new (FWUPD_SECURITY_ATTR_ID_SPI_BIOSWE); fwupd_security_attr_set_plugin (attr, "test"); - fwupd_security_attr_set_level (attr, 1); + fwupd_security_attr_set_level (attr, FWUPD_SECURITY_ATTR_LEVEL_CRITICAL); fwupd_security_attr_add_flag (attr, FWUPD_SECURITY_ATTR_FLAG_SUCCESS); fu_security_attrs_append (attrs, attr); hsi2 = fu_security_attrs_calculate_hsi (attrs); @@ -1772,20 +1772,20 @@ fu_security_attrs_hsi_func (void) g_clear_object (&attr); /* add failed from HSI:2, so still HSI:1 */ - attr = fwupd_security_attr_new ("org.fwupd.Hsi.PRX"); + attr = fwupd_security_attr_new ("org.fwupd.hsi.PRX"); fwupd_security_attr_set_plugin (attr, "test"); - fwupd_security_attr_set_level (attr, 2); + fwupd_security_attr_set_level (attr, FWUPD_SECURITY_ATTR_LEVEL_IMPORTANT); fu_security_attrs_append (attrs, attr); hsi3 = fu_security_attrs_calculate_hsi (attrs); g_assert_cmpstr (hsi3, ==, "HSI:1"); g_clear_object (&attr); /* add attr from HSI:3, obsoleting the failure */ - attr = fwupd_security_attr_new ("org.fwupd.Hsi.BIOSGuard"); + attr = fwupd_security_attr_new ("org.fwupd.hsi.BIOSGuard"); fwupd_security_attr_set_plugin (attr, "test"); - fwupd_security_attr_set_level (attr, 3); + fwupd_security_attr_set_level (attr, FWUPD_SECURITY_ATTR_LEVEL_THEORETICAL); fwupd_security_attr_add_flag (attr, FWUPD_SECURITY_ATTR_FLAG_SUCCESS); - fwupd_security_attr_add_obsolete (attr, "org.fwupd.Hsi.PRX"); + fwupd_security_attr_add_obsolete (attr, "org.fwupd.hsi.PRX"); fu_security_attrs_append (attrs, attr); fu_security_attrs_depsolve (attrs); hsi4 = fu_security_attrs_calculate_hsi (attrs); @@ -1793,7 +1793,7 @@ fu_security_attrs_hsi_func (void) g_clear_object (&attr); /* add taint that was fine */ - attr = fwupd_security_attr_new ("org.fwupd.Hsi.PluginsTainted"); + attr = fwupd_security_attr_new (FWUPD_SECURITY_ATTR_ID_FWUPD_PLUGINS); fwupd_security_attr_set_plugin (attr, "test"); fwupd_security_attr_add_flag (attr, FWUPD_SECURITY_ATTR_FLAG_SUCCESS); fwupd_security_attr_add_flag (attr, FWUPD_SECURITY_ATTR_FLAG_RUNTIME_ISSUE); @@ -1803,7 +1803,7 @@ fu_security_attrs_hsi_func (void) g_clear_object (&attr); /* add updates and attestation */ - attr = fwupd_security_attr_new ("org.fwupd.Hsi.LVFS"); + attr = fwupd_security_attr_new (FWUPD_SECURITY_ATTR_ID_FWUPD_UPDATES); fwupd_security_attr_set_plugin (attr, "test"); fwupd_security_attr_add_flag (attr, FWUPD_SECURITY_ATTR_FLAG_RUNTIME_UPDATES); fwupd_security_attr_add_flag (attr, FWUPD_SECURITY_ATTR_FLAG_RUNTIME_ATTESTATION); @@ -1814,7 +1814,7 @@ fu_security_attrs_hsi_func (void) g_clear_object (&attr); /* add issue that was uncool */ - attr = fwupd_security_attr_new ("org.fwupd.Hsi.Swap"); + attr = fwupd_security_attr_new (FWUPD_SECURITY_ATTR_ID_KERNEL_SWAP); fwupd_security_attr_set_plugin (attr, "test"); fwupd_security_attr_add_flag (attr, FWUPD_SECURITY_ATTR_FLAG_RUNTIME_ISSUE); fu_security_attrs_append (attrs, attr); diff --git a/plugins/acpi-dmar/fu-plugin-acpi-dmar.c b/plugins/acpi-dmar/fu-plugin-acpi-dmar.c index 255c9a843..4f637cd70 100644 --- a/plugins/acpi-dmar/fu-plugin-acpi-dmar.c +++ b/plugins/acpi-dmar/fu-plugin-acpi-dmar.c @@ -31,10 +31,9 @@ fu_plugin_add_security_attrs (FuPlugin *plugin, FuSecurityAttrs *attrs) return; /* create attr */ - attr = fwupd_security_attr_new ("org.uefi.ACPI.Dmar"); + attr = fwupd_security_attr_new (FWUPD_SECURITY_ATTR_ID_ACPI_DMAR); fwupd_security_attr_set_plugin (attr, fu_plugin_get_name (plugin)); fwupd_security_attr_set_level (attr, FWUPD_SECURITY_ATTR_LEVEL_THEORETICAL); - fwupd_security_attr_set_name (attr, "Pre-boot kernel DMA protection"); fu_security_attrs_append (attrs, attr); /* load DMAR table */ @@ -43,20 +42,21 @@ fu_plugin_add_security_attrs (FuPlugin *plugin, FuSecurityAttrs *attrs) blob = fu_common_get_contents_bytes (fn, &error_local); if (blob == NULL) { g_warning ("failed to load %s: %s", fn, error_local->message); - fwupd_security_attr_set_result (attr, "Could not load DMAR"); + fwupd_security_attr_set_result (attr, FWUPD_SECURITY_ATTR_RESULT_NOT_VALID); return; } dmar = fu_acpi_dmar_new (blob, &error_local); if (dmar == NULL) { g_warning ("failed to parse %s: %s", fn, error_local->message); - fwupd_security_attr_set_result (attr, "Could not parse DMAR"); + fwupd_security_attr_set_result (attr, FWUPD_SECURITY_ATTR_RESULT_NOT_VALID); return; } if (!fu_acpi_dmar_get_opt_in (dmar)) { - fwupd_security_attr_set_result (attr, "Unavailable"); + fwupd_security_attr_set_result (attr, FWUPD_SECURITY_ATTR_RESULT_NOT_ENABLED); return; } /* success */ + fwupd_security_attr_set_result (attr, FWUPD_SECURITY_ATTR_RESULT_ENABLED); fwupd_security_attr_add_flag (attr, FWUPD_SECURITY_ATTR_FLAG_SUCCESS); } diff --git a/plugins/acpi-facp/fu-plugin-acpi-facp.c b/plugins/acpi-facp/fu-plugin-acpi-facp.c index 09927db56..e0fef9189 100644 --- a/plugins/acpi-facp/fu-plugin-acpi-facp.c +++ b/plugins/acpi-facp/fu-plugin-acpi-facp.c @@ -27,10 +27,9 @@ fu_plugin_add_security_attrs (FuPlugin *plugin, FuSecurityAttrs *attrs) g_autoptr(GError) error_local = NULL; /* create attr */ - attr = fwupd_security_attr_new ("org.uefi.ACPI.Facp"); + attr = fwupd_security_attr_new (FWUPD_SECURITY_ATTR_ID_SUSPEND_TO_IDLE); fwupd_security_attr_set_plugin (attr, fu_plugin_get_name (plugin)); fwupd_security_attr_set_level (attr, FWUPD_SECURITY_ATTR_LEVEL_THEORETICAL); - fwupd_security_attr_set_name (attr, "Suspend To Idle"); fu_security_attrs_append (attrs, attr); /* load FACP table */ @@ -39,20 +38,21 @@ fu_plugin_add_security_attrs (FuPlugin *plugin, FuSecurityAttrs *attrs) blob = fu_common_get_contents_bytes (fn, &error_local); if (blob == NULL) { g_warning ("failed to load %s: %s", fn, error_local->message); - fwupd_security_attr_set_result (attr, "Could not load FACP"); + fwupd_security_attr_set_result (attr, FWUPD_SECURITY_ATTR_RESULT_NOT_VALID); return; } facp = fu_acpi_facp_new (blob, &error_local); if (facp == NULL) { g_warning ("failed to parse %s: %s", fn, error_local->message); - fwupd_security_attr_set_result (attr, "Could not parse FACP"); + fwupd_security_attr_set_result (attr, FWUPD_SECURITY_ATTR_RESULT_NOT_VALID); return; } if (!fu_acpi_facp_get_s2i (facp)) { - fwupd_security_attr_set_result (attr, "Default set as suspend-to-ram (S3)"); + fwupd_security_attr_set_result (attr, FWUPD_SECURITY_ATTR_RESULT_NOT_ENABLED); return; } /* success */ + fwupd_security_attr_set_result (attr, FWUPD_SECURITY_ATTR_RESULT_ENABLED); fwupd_security_attr_add_flag (attr, FWUPD_SECURITY_ATTR_FLAG_SUCCESS); } diff --git a/plugins/amt/fu-plugin-amt.c b/plugins/amt/fu-plugin-amt.c index 74b8a47b8..ed568f2a2 100644 --- a/plugins/amt/fu-plugin-amt.c +++ b/plugins/amt/fu-plugin-amt.c @@ -579,15 +579,16 @@ fu_plugin_add_security_attrs (FuPlugin *plugin, FuSecurityAttrs *attrs) return; /* create attr */ - attr = fwupd_security_attr_new ("com.intel.AMT"); + attr = fwupd_security_attr_new (FWUPD_SECURITY_ATTR_ID_INTEL_AMT); fwupd_security_attr_set_plugin (attr, fu_plugin_get_name (plugin)); fwupd_security_attr_set_level (attr, FWUPD_SECURITY_ATTR_LEVEL_SYSTEM_PROTECTION); - fwupd_security_attr_set_name (attr, "Intel AMT"); fu_security_attrs_append (attrs, attr); if (data->provisioned) { - fwupd_security_attr_set_result (attr, "Provisioned"); + fwupd_security_attr_set_result (attr, FWUPD_SECURITY_ATTR_RESULT_ENABLED); return; } + /* success */ + fwupd_security_attr_set_result (attr, FWUPD_SECURITY_ATTR_RESULT_NOT_ENABLED); fwupd_security_attr_add_flag (attr, FWUPD_SECURITY_ATTR_FLAG_SUCCESS); } diff --git a/plugins/cpu/fu-plugin-cpu.c b/plugins/cpu/fu-plugin-cpu.c index 453a6b835..b293b9e60 100644 --- a/plugins/cpu/fu-plugin-cpu.c +++ b/plugins/cpu/fu-plugin-cpu.c @@ -59,21 +59,20 @@ fu_plugin_add_security_attrs_intel_cet (FuPlugin *plugin, FuSecurityAttrs *attrs g_autoptr(FwupdSecurityAttr) attr = NULL; /* create attr */ - attr = fwupd_security_attr_new ("com.intel.CET"); + attr = fwupd_security_attr_new (FWUPD_SECURITY_ATTR_ID_INTEL_CET); fwupd_security_attr_set_plugin (attr, fu_plugin_get_name (plugin)); fwupd_security_attr_set_level (attr, FWUPD_SECURITY_ATTR_LEVEL_THEORETICAL); - fwupd_security_attr_set_name (attr, "Intel control enforcement technology (CET)"); fu_security_attrs_append (attrs, attr); /* check for CET */ if (!data->has_cet) { - fwupd_security_attr_set_result (attr, "Unavailable"); + fwupd_security_attr_set_result (attr, FWUPD_SECURITY_ATTR_RESULT_NOT_SUPPORTED); return; } /* success */ fwupd_security_attr_add_flag (attr, FWUPD_SECURITY_ATTR_FLAG_SUCCESS); - fwupd_security_attr_set_result (attr, "Available"); + fwupd_security_attr_set_result (attr, FWUPD_SECURITY_ATTR_RESULT_ENABLED); } static void @@ -83,21 +82,20 @@ fu_plugin_add_security_attrs_intel_tme (FuPlugin *plugin, FuSecurityAttrs *attrs g_autoptr(FwupdSecurityAttr) attr = NULL; /* create attr */ - attr = fwupd_security_attr_new ("com.intel.TME"); + attr = fwupd_security_attr_new (FWUPD_SECURITY_ATTR_ID_ENCRYPTED_RAM); fwupd_security_attr_set_plugin (attr, fu_plugin_get_name (plugin)); fwupd_security_attr_set_level (attr, FWUPD_SECURITY_ATTR_LEVEL_SYSTEM_PROTECTION); - fwupd_security_attr_set_name (attr, "Intel total memory encryption (TME)"); fu_security_attrs_append (attrs, attr); /* check for TME */ if (!data->has_tme) { - fwupd_security_attr_set_result (attr, "Unavailable"); + fwupd_security_attr_set_result (attr, FWUPD_SECURITY_ATTR_RESULT_NOT_SUPPORTED); return; } /* success */ fwupd_security_attr_add_flag (attr, FWUPD_SECURITY_ATTR_FLAG_SUCCESS); - fwupd_security_attr_set_result (attr, "Available"); + fwupd_security_attr_set_result (attr, FWUPD_SECURITY_ATTR_RESULT_ENABLED); } void diff --git a/plugins/iommu/fu-plugin-iommu.c b/plugins/iommu/fu-plugin-iommu.c index 3d1a6921e..bfbaf4aa9 100644 --- a/plugins/iommu/fu-plugin-iommu.c +++ b/plugins/iommu/fu-plugin-iommu.c @@ -41,17 +41,17 @@ fu_plugin_add_security_attrs (FuPlugin *plugin, FuSecurityAttrs *attrs) g_autoptr(FwupdSecurityAttr) attr = NULL; /* create attr */ - attr = fwupd_security_attr_new ("org.kernel.IOMMU"); + attr = fwupd_security_attr_new (FWUPD_SECURITY_ATTR_ID_IOMMU); fwupd_security_attr_set_level (attr, FWUPD_SECURITY_ATTR_LEVEL_IMPORTANT); - fwupd_security_attr_set_name (attr, "IOMMU"); fwupd_security_attr_set_plugin (attr, fu_plugin_get_name (plugin)); fu_security_attrs_append (attrs, attr); if (!data->has_iommu) { - fwupd_security_attr_set_result (attr, "Not found"); + fwupd_security_attr_set_result (attr, FWUPD_SECURITY_ATTR_RESULT_NOT_FOUND); return; } /* success */ fwupd_security_attr_add_flag (attr, FWUPD_SECURITY_ATTR_FLAG_SUCCESS); + fwupd_security_attr_set_result (attr, FWUPD_SECURITY_ATTR_RESULT_ENABLED); } diff --git a/plugins/linux-lockdown/fu-plugin-linux-lockdown.c b/plugins/linux-lockdown/fu-plugin-linux-lockdown.c index 8c2e21e47..ccfdefe40 100644 --- a/plugins/linux-lockdown/fu-plugin-linux-lockdown.c +++ b/plugins/linux-lockdown/fu-plugin-linux-lockdown.c @@ -70,9 +70,8 @@ fu_plugin_add_security_attrs (FuPlugin *plugin, FuSecurityAttrs *attrs) g_autoptr(GError) error_local = NULL; /* create attr */ - attr = fwupd_security_attr_new ("org.kernel.CheckLockdown"); + attr = fwupd_security_attr_new (FWUPD_SECURITY_ATTR_ID_KERNEL_LOCKDOWN); fwupd_security_attr_set_plugin (attr, fu_plugin_get_name (plugin)); - fwupd_security_attr_set_name (attr, "Linux Kernel Lockdown"); fwupd_security_attr_add_flag (attr, FWUPD_SECURITY_ATTR_FLAG_RUNTIME_ISSUE); fu_security_attrs_append (attrs, attr); @@ -80,16 +79,16 @@ fu_plugin_add_security_attrs (FuPlugin *plugin, FuSecurityAttrs *attrs) if (!g_file_load_contents (data->file, NULL, &buf, &bufsz, NULL, &error_local)) { g_autofree gchar *fn = g_file_get_path (data->file); g_warning ("could not open %s: %s", fn, error_local->message); - fwupd_security_attr_set_result (attr, "Not supported"); + fwupd_security_attr_set_result (attr, FWUPD_SECURITY_ATTR_RESULT_NOT_VALID); return; } if (g_strstr_len (buf, bufsz, "[integrity]") == NULL && g_strstr_len (buf, bufsz, "[confidentiality]") == NULL) { - fwupd_security_attr_set_result (attr, "Not locked down"); + fwupd_security_attr_set_result (attr, FWUPD_SECURITY_ATTR_RESULT_NOT_ENABLED); return; } /* success */ fwupd_security_attr_add_flag (attr, FWUPD_SECURITY_ATTR_FLAG_SUCCESS); - fwupd_security_attr_set_result (attr, "Locked down"); + fwupd_security_attr_set_result (attr, FWUPD_SECURITY_ATTR_RESULT_ENABLED); } diff --git a/plugins/linux-sleep/fu-plugin-linux-sleep.c b/plugins/linux-sleep/fu-plugin-linux-sleep.c index f54ed2be5..09cbd485b 100644 --- a/plugins/linux-sleep/fu-plugin-linux-sleep.c +++ b/plugins/linux-sleep/fu-plugin-linux-sleep.c @@ -25,24 +25,24 @@ fu_plugin_add_security_attrs (FuPlugin *plugin, FuSecurityAttrs *attrs) g_autoptr(GFile) file = g_file_new_for_path ("/sys/power/mem_sleep"); /* create attr */ - attr = fwupd_security_attr_new ("org.kernel.CheckS3Sleep"); + attr = fwupd_security_attr_new (FWUPD_SECURITY_ATTR_ID_SUSPEND_TO_RAM); fwupd_security_attr_set_plugin (attr, fu_plugin_get_name (plugin)); fwupd_security_attr_set_level (attr, FWUPD_SECURITY_ATTR_LEVEL_THEORETICAL); - fwupd_security_attr_set_name (attr, "Linux Kernel S3 Sleep"); fu_security_attrs_append (attrs, attr); /* load file */ if (!g_file_load_contents (file, NULL, &buf, &bufsz, NULL, &error_local)) { g_autofree gchar *fn = g_file_get_path (file); g_warning ("could not open %s: %s", fn, error_local->message); - fwupd_security_attr_set_result (attr, "Deep sleep status unavailable"); + fwupd_security_attr_set_result (attr, FWUPD_SECURITY_ATTR_RESULT_NOT_VALID); return; } if (g_strstr_len (buf, bufsz, "[deep]") != NULL) { - fwupd_security_attr_set_result (attr, "System configured to suspend-to-ram (S3)"); + fwupd_security_attr_set_result (attr, FWUPD_SECURITY_ATTR_RESULT_ENABLED); return; } /* success */ fwupd_security_attr_add_flag (attr, FWUPD_SECURITY_ATTR_FLAG_SUCCESS); + fwupd_security_attr_set_result (attr, FWUPD_SECURITY_ATTR_RESULT_NOT_ENABLED); } diff --git a/plugins/linux-spi-lpc/fu-plugin-linux-spi-lpc.c b/plugins/linux-spi-lpc/fu-plugin-linux-spi-lpc.c index 2f0dec11d..479c0cd73 100644 --- a/plugins/linux-spi-lpc/fu-plugin-linux-spi-lpc.c +++ b/plugins/linux-spi-lpc/fu-plugin-linux-spi-lpc.c @@ -28,28 +28,33 @@ fu_plugin_add_security_attr_bioswe (FuPlugin *plugin, FuSecurityAttrs *attrs) g_autoptr(GError) error_local = NULL; /* create attr */ - attr = fwupd_security_attr_new ("org.kernel.BIOSWE"); + attr = fwupd_security_attr_new (FWUPD_SECURITY_ATTR_ID_SPI_BIOSWE); fwupd_security_attr_set_plugin (attr, fu_plugin_get_name (plugin)); fwupd_security_attr_set_level (attr, FWUPD_SECURITY_ATTR_LEVEL_CRITICAL); - fwupd_security_attr_set_name (attr, "SPI"); - fwupd_security_attr_add_obsolete (attr, "org.fwupd.plugin.pci-bcr"); + fwupd_security_attr_add_obsolete (attr, "pci_bcr"); fu_security_attrs_append (attrs, attr); + /* maybe the kernel module does not exist */ + if (!g_file_test (FU_PLUGIN_LINUX_SPI_LPC_SYSFS_DIR, G_FILE_TEST_IS_DIR)) { + fwupd_security_attr_set_result (attr, FWUPD_SECURITY_ATTR_RESULT_NOT_FOUND); + return; + } + /* load file */ fn = g_build_filename (FU_PLUGIN_LINUX_SPI_LPC_SYSFS_DIR, "bioswe", NULL); if (!g_file_get_contents (fn, &buf, &bufsz, &error_local)) { g_warning ("could not open %s: %s", fn, error_local->message); - fwupd_security_attr_set_result (attr, "Could not open file"); + fwupd_security_attr_set_result (attr, FWUPD_SECURITY_ATTR_RESULT_NOT_VALID); return; } if (g_strcmp0 (buf, "0\n") != 0) { - fwupd_security_attr_set_result (attr, "Write enabled"); + fwupd_security_attr_set_result (attr, FWUPD_SECURITY_ATTR_RESULT_NOT_ENABLED); return; } /* success */ fwupd_security_attr_add_flag (attr, FWUPD_SECURITY_ATTR_FLAG_SUCCESS); - fwupd_security_attr_set_result (attr, "Write disabled"); + fwupd_security_attr_set_result (attr, FWUPD_SECURITY_ATTR_RESULT_ENABLED); } static void @@ -62,27 +67,32 @@ fu_plugin_add_security_attr_ble (FuPlugin *plugin, FuSecurityAttrs *attrs) g_autoptr(GError) error_local = NULL; /* create attr */ - attr = fwupd_security_attr_new ("org.kernel.BLE"); + attr = fwupd_security_attr_new (FWUPD_SECURITY_ATTR_ID_SPI_BLE); fwupd_security_attr_set_level (attr, FWUPD_SECURITY_ATTR_LEVEL_CRITICAL); - fwupd_security_attr_set_name (attr, "SPI"); - fwupd_security_attr_add_obsolete (attr, "org.fwupd.plugin.pci-bcr"); + fwupd_security_attr_add_obsolete (attr, "pci_bcr"); fu_security_attrs_append (attrs, attr); + /* maybe the kernel module does not exist */ + if (!g_file_test (FU_PLUGIN_LINUX_SPI_LPC_SYSFS_DIR, G_FILE_TEST_IS_DIR)) { + fwupd_security_attr_set_result (attr, FWUPD_SECURITY_ATTR_RESULT_NOT_FOUND); + return; + } + /* load file */ fn = g_build_filename (FU_PLUGIN_LINUX_SPI_LPC_SYSFS_DIR, "ble", NULL); if (!g_file_get_contents (fn, &buf, &bufsz, &error_local)) { g_warning ("could not open %s: %s", fn, error_local->message); - fwupd_security_attr_set_result (attr, "Could not open file"); + fwupd_security_attr_set_result (attr, FWUPD_SECURITY_ATTR_RESULT_NOT_VALID); return; } if (g_strcmp0 (buf, "1\n") != 0) { - fwupd_security_attr_set_result (attr, "Lock disabled"); + fwupd_security_attr_set_result (attr, FWUPD_SECURITY_ATTR_RESULT_ENABLED); return; } /* success */ fwupd_security_attr_add_flag (attr, FWUPD_SECURITY_ATTR_FLAG_SUCCESS); - fwupd_security_attr_set_result (attr, "Lock enabled"); + fwupd_security_attr_set_result (attr, FWUPD_SECURITY_ATTR_RESULT_NOT_ENABLED); } static void @@ -95,27 +105,32 @@ fu_plugin_add_security_attr_smm_bwp (FuPlugin *plugin, FuSecurityAttrs *attrs) g_autoptr(GError) error_local = NULL; /* create attr */ - attr = fwupd_security_attr_new ("org.kernel.SMM_BWP"); + attr = fwupd_security_attr_new (FWUPD_SECURITY_ATTR_ID_SPI_SMM_BWP); fwupd_security_attr_set_level (attr, FWUPD_SECURITY_ATTR_LEVEL_CRITICAL); - fwupd_security_attr_set_name (attr, "BIOS region of SPI"); - fwupd_security_attr_add_obsolete (attr, "org.fwupd.plugin.pci-bcr"); + fwupd_security_attr_add_obsolete (attr, "pci_bcr"); fu_security_attrs_append (attrs, attr); + /* maybe the kernel module does not exist */ + if (!g_file_test (FU_PLUGIN_LINUX_SPI_LPC_SYSFS_DIR, G_FILE_TEST_IS_DIR)) { + fwupd_security_attr_set_result (attr, FWUPD_SECURITY_ATTR_RESULT_NOT_FOUND); + return; + } + /* load file */ fn = g_build_filename (FU_PLUGIN_LINUX_SPI_LPC_SYSFS_DIR, "smm_bwp", NULL); if (!g_file_get_contents (fn, &buf, &bufsz, &error_local)) { g_warning ("could not open %s: %s", fn, error_local->message); - fwupd_security_attr_set_result (attr, "Could not open file"); + fwupd_security_attr_set_result (attr, FWUPD_SECURITY_ATTR_RESULT_NOT_VALID); return; } if (g_strcmp0 (buf, "1\n") != 0) { - fwupd_security_attr_set_result (attr, "Writable by OS"); + fwupd_security_attr_set_result (attr, FWUPD_SECURITY_ATTR_RESULT_NOT_LOCKED); return; } /* success */ fwupd_security_attr_add_flag (attr, FWUPD_SECURITY_ATTR_FLAG_SUCCESS); - fwupd_security_attr_set_result (attr, "Writable only through BIOS"); + fwupd_security_attr_set_result (attr, FWUPD_SECURITY_ATTR_RESULT_LOCKED); } void @@ -125,17 +140,6 @@ fu_plugin_add_security_attrs (FuPlugin *plugin, FuSecurityAttrs *attrs) if (!fu_common_is_cpu_intel ()) return; - /* maybe the kernel module does not exist */ - if (!g_file_test (FU_PLUGIN_LINUX_SPI_LPC_SYSFS_DIR, G_FILE_TEST_IS_DIR)) { - g_autoptr(FwupdSecurityAttr) attr = NULL; - attr = fwupd_security_attr_new ("org.fwupd.plugin.linux-spi-lpc"); - fwupd_security_attr_set_level (attr, FWUPD_SECURITY_ATTR_LEVEL_CRITICAL); - fwupd_security_attr_set_name (attr, "SPI"); - fwupd_security_attr_set_result (attr, "Kernel support not present"); - fu_security_attrs_append (attrs, attr); - return; - } - /* look for the three files in sysfs */ fu_plugin_add_security_attr_bioswe (plugin, attrs); fu_plugin_add_security_attr_ble (plugin, attrs); diff --git a/plugins/linux-swap/fu-plugin-linux-swap.c b/plugins/linux-swap/fu-plugin-linux-swap.c index c54d293d1..a92d86de2 100644 --- a/plugins/linux-swap/fu-plugin-linux-swap.c +++ b/plugins/linux-swap/fu-plugin-linux-swap.c @@ -72,40 +72,40 @@ fu_plugin_add_security_attrs (FuPlugin *plugin, FuSecurityAttrs *attrs) g_autoptr(GError) error_local = NULL; /* create attr */ - attr = fwupd_security_attr_new ("org.kernel.Swap"); + attr = fwupd_security_attr_new (FWUPD_SECURITY_ATTR_ID_KERNEL_SWAP); fwupd_security_attr_set_plugin (attr, fu_plugin_get_name (plugin)); fwupd_security_attr_add_flag (attr, FWUPD_SECURITY_ATTR_FLAG_RUNTIME_ISSUE); - fwupd_security_attr_set_name (attr, "Linux Swap"); fu_security_attrs_append (attrs, attr); /* load list of swaps */ if (!g_file_load_contents (data->file, NULL, &buf, &bufsz, NULL, &error_local)) { g_autofree gchar *fn = g_file_get_path (data->file); g_warning ("could not open %s: %s", fn, error_local->message); - fwupd_security_attr_set_result (attr, "Could not open file"); + fwupd_security_attr_set_result (attr, FWUPD_SECURITY_ATTR_RESULT_NOT_VALID); return; } swap = fu_linux_swap_new (buf, bufsz, &error_local); if (swap == NULL) { g_autofree gchar *fn = g_file_get_path (data->file); g_warning ("could not parse %s: %s", fn, error_local->message); - fwupd_security_attr_set_result (attr, "Could not parse file"); + fwupd_security_attr_set_result (attr, FWUPD_SECURITY_ATTR_RESULT_NOT_VALID); return; } /* none configured */ if (!fu_linux_swap_get_enabled (swap)) { fwupd_security_attr_add_flag (attr, FWUPD_SECURITY_ATTR_FLAG_SUCCESS); + fwupd_security_attr_set_result (attr, FWUPD_SECURITY_ATTR_RESULT_NOT_ENABLED); return; } /* add security attribute */ if (!fu_linux_swap_get_encrypted (swap)) { - fwupd_security_attr_set_result (attr, "Not encrypted"); + fwupd_security_attr_set_result (attr, FWUPD_SECURITY_ATTR_RESULT_NOT_ENCRYPTED); return; } /* success */ fwupd_security_attr_add_flag (attr, FWUPD_SECURITY_ATTR_FLAG_SUCCESS); - fwupd_security_attr_set_result (attr, "Encrypted"); + fwupd_security_attr_set_result (attr, FWUPD_SECURITY_ATTR_RESULT_ENCRYPTED); } diff --git a/plugins/linux-tainted/fu-plugin-linux-tainted.c b/plugins/linux-tainted/fu-plugin-linux-tainted.c index c1317256f..86c69655e 100644 --- a/plugins/linux-tainted/fu-plugin-linux-tainted.c +++ b/plugins/linux-tainted/fu-plugin-linux-tainted.c @@ -70,9 +70,8 @@ fu_plugin_add_security_attrs (FuPlugin *plugin, FuSecurityAttrs *attrs) g_autoptr(GError) error_local = NULL; /* create attr */ - attr = fwupd_security_attr_new ("org.kernel.CheckTainted"); + attr = fwupd_security_attr_new (FWUPD_SECURITY_ATTR_ID_KERNEL_TAINTED); fwupd_security_attr_set_plugin (attr, fu_plugin_get_name (plugin)); - fwupd_security_attr_set_name (attr, "Linux Kernel Taint"); fwupd_security_attr_add_flag (attr, FWUPD_SECURITY_ATTR_FLAG_RUNTIME_ISSUE); fu_security_attrs_append (attrs, attr); @@ -80,14 +79,15 @@ fu_plugin_add_security_attrs (FuPlugin *plugin, FuSecurityAttrs *attrs) if (!g_file_load_contents (data->file, NULL, &buf, &bufsz, NULL, &error_local)) { g_autofree gchar *fn = g_file_get_path (data->file); g_warning ("could not open %s: %s", fn, error_local->message); - fwupd_security_attr_set_result (attr, "Could not open file"); + fwupd_security_attr_set_result (attr, FWUPD_SECURITY_ATTR_RESULT_NOT_VALID); return; } if (g_strcmp0 (buf, "0\n") != 0) { - fwupd_security_attr_set_result (attr, "Tainted"); + fwupd_security_attr_set_result (attr, FWUPD_SECURITY_ATTR_RESULT_TAINTED); return; } /* success */ fwupd_security_attr_add_flag (attr, FWUPD_SECURITY_ATTR_FLAG_SUCCESS); + fwupd_security_attr_set_result (attr, FWUPD_SECURITY_ATTR_RESULT_NOT_TAINTED); } diff --git a/plugins/pci-bcr/fu-plugin-pci-bcr.c b/plugins/pci-bcr/fu-plugin-pci-bcr.c index 41433548f..fa2f8e50a 100644 --- a/plugins/pci-bcr/fu-plugin-pci-bcr.c +++ b/plugins/pci-bcr/fu-plugin-pci-bcr.c @@ -34,23 +34,27 @@ fu_plugin_add_security_attr_bioswe (FuPlugin *plugin, FuSecurityAttrs *attrs) g_autoptr(FwupdSecurityAttr) attr = NULL; /* create attr */ - attr = fwupd_security_attr_new ("com.intel.BIOSWE"); + attr = fwupd_security_attr_new (FWUPD_SECURITY_ATTR_ID_SPI_BIOSWE); fwupd_security_attr_set_plugin (attr, fu_plugin_get_name (plugin)); fwupd_security_attr_set_level (attr, FWUPD_SECURITY_ATTR_LEVEL_CRITICAL); - fwupd_security_attr_set_name (attr, "SPI"); - fwupd_security_attr_add_obsolete (attr, "org.kernel.BIOSWE"); - fwupd_security_attr_add_obsolete (attr, "org.fwupd.plugin.linux-spi-lpc"); + fwupd_security_attr_add_obsolete (attr, "linux_spi_lpc"); fu_security_attrs_append (attrs, attr); + /* no device */ + if (!priv->has_device) { + fwupd_security_attr_set_result (attr, FWUPD_SECURITY_ATTR_RESULT_NOT_FOUND); + return; + } + /* load file */ if ((priv->bcr & BCR_WPD) == 1) { - fwupd_security_attr_set_result (attr, "Write enabled"); + fwupd_security_attr_set_result (attr, FWUPD_SECURITY_ATTR_RESULT_ENABLED); return; } /* success */ fwupd_security_attr_add_flag (attr, FWUPD_SECURITY_ATTR_FLAG_SUCCESS); - fwupd_security_attr_set_result (attr, "Write disabled"); + fwupd_security_attr_set_result (attr, FWUPD_SECURITY_ATTR_RESULT_NOT_ENABLED); } static void @@ -60,23 +64,27 @@ fu_plugin_add_security_attr_ble (FuPlugin *plugin, FuSecurityAttrs *attrs) g_autoptr(FwupdSecurityAttr) attr = NULL; /* create attr */ - attr = fwupd_security_attr_new ("com.intel.BLE"); + attr = fwupd_security_attr_new (FWUPD_SECURITY_ATTR_ID_SPI_BLE); fwupd_security_attr_set_plugin (attr, fu_plugin_get_name (plugin)); fwupd_security_attr_set_level (attr, FWUPD_SECURITY_ATTR_LEVEL_CRITICAL); - fwupd_security_attr_set_name (attr, "SPI"); - fwupd_security_attr_add_obsolete (attr, "org.kernel.BLE"); - fwupd_security_attr_add_obsolete (attr, "org.fwupd.plugin.linux-spi-lpc"); + fwupd_security_attr_add_obsolete (attr, "linux_spi_lpc"); fu_security_attrs_append (attrs, attr); + /* no device */ + if (!priv->has_device) { + fwupd_security_attr_set_result (attr, FWUPD_SECURITY_ATTR_RESULT_NOT_FOUND); + return; + } + /* load file */ if ((priv->bcr & BCR_BLE) == 0) { - fwupd_security_attr_set_result (attr, "Lock disabled"); + fwupd_security_attr_set_result (attr, FWUPD_SECURITY_ATTR_RESULT_NOT_ENABLED); return; } /* success */ fwupd_security_attr_add_flag (attr, FWUPD_SECURITY_ATTR_FLAG_SUCCESS); - fwupd_security_attr_set_result (attr, "Lock enabled"); + fwupd_security_attr_set_result (attr, FWUPD_SECURITY_ATTR_RESULT_ENABLED); } static void @@ -86,23 +94,27 @@ fu_plugin_add_security_attr_smm_bwp (FuPlugin *plugin, FuSecurityAttrs *attrs) g_autoptr(FwupdSecurityAttr) attr = NULL; /* create attr */ - attr = fwupd_security_attr_new ("com.intel.SMM_BWP"); + attr = fwupd_security_attr_new (FWUPD_SECURITY_ATTR_ID_SPI_SMM_BWP); fwupd_security_attr_set_plugin (attr, fu_plugin_get_name (plugin)); fwupd_security_attr_set_level (attr, FWUPD_SECURITY_ATTR_LEVEL_CRITICAL); - fwupd_security_attr_set_name (attr, "BIOS region of SPI"); - fwupd_security_attr_add_obsolete (attr, "org.kernel.SMM_BWP"); - fwupd_security_attr_add_obsolete (attr, "org.fwupd.plugin.linux-spi-lpc"); + fwupd_security_attr_add_obsolete (attr, "linux_spi_lpc"); fu_security_attrs_append (attrs, attr); + /* no device */ + if (!priv->has_device) { + fwupd_security_attr_set_result (attr, FWUPD_SECURITY_ATTR_RESULT_NOT_FOUND); + return; + } + /* load file */ if ((priv->bcr & BCR_SMM_BWP) == 0) { - fwupd_security_attr_set_result (attr, "Writable by OS"); + fwupd_security_attr_set_result (attr, FWUPD_SECURITY_ATTR_RESULT_NOT_LOCKED); return; } /* success */ fwupd_security_attr_add_flag (attr, FWUPD_SECURITY_ATTR_FLAG_SUCCESS); - fwupd_security_attr_set_result (attr, "Writable only through BIOS"); + fwupd_security_attr_set_result (attr, FWUPD_SECURITY_ATTR_RESULT_LOCKED); } gboolean @@ -125,7 +137,7 @@ fu_plugin_udev_device_added (FuPlugin *plugin, FuUdevDevice *device, GError **er /* grab BIOS Control Register */ if (!fu_udev_device_pread (device, BCR, &priv->bcr, error)) { - g_prefix_error (error, "could not read MEI"); + g_prefix_error (error, "could not read BCR"); return FALSE; } priv->has_device = TRUE; @@ -135,24 +147,10 @@ fu_plugin_udev_device_added (FuPlugin *plugin, FuUdevDevice *device, GError **er void fu_plugin_add_security_attrs (FuPlugin *plugin, FuSecurityAttrs *attrs) { - FuPluginData *priv = fu_plugin_get_data (plugin); - /* only Intel */ if (!fu_common_is_cpu_intel ()) return; - /* only Intel */ - if (!priv->has_device) { - g_autoptr(FwupdSecurityAttr) attr = NULL; - attr = fwupd_security_attr_new ("org.fwupd.plugin.pci-bcr"); - fwupd_security_attr_set_plugin (attr, fu_plugin_get_name (plugin)); - fwupd_security_attr_set_level (attr, FWUPD_SECURITY_ATTR_LEVEL_CRITICAL); - fwupd_security_attr_set_name (attr, "SPI"); - fwupd_security_attr_set_result (attr, "No PCI devices with BCR"); - fu_security_attrs_append (attrs, attr); - return; - } - /* add attrs */ fu_plugin_add_security_attr_bioswe (plugin, attrs); fu_plugin_add_security_attr_ble (plugin, attrs); diff --git a/plugins/pci-mei/fu-plugin-pci-mei.c b/plugins/pci-mei/fu-plugin-pci-mei.c index c7443b78e..9d4735850 100644 --- a/plugins/pci-mei/fu-plugin-pci-mei.c +++ b/plugins/pci-mei/fu-plugin-pci-mei.c @@ -64,18 +64,18 @@ fu_plugin_add_security_attrs (FuPlugin *plugin, FuSecurityAttrs *attrs) return; /* create attr */ - attr = fwupd_security_attr_new ("com.intel.MEI"); + attr = fwupd_security_attr_new (FWUPD_SECURITY_ATTR_ID_MEI_MANUFACTURING_MODE); fwupd_security_attr_set_plugin (attr, fu_plugin_get_name (plugin)); fwupd_security_attr_set_level (attr, FWUPD_SECURITY_ATTR_LEVEL_CRITICAL); - fwupd_security_attr_set_name (attr, "MEI"); fu_security_attrs_append (attrs, attr); /* load file */ if ((priv->mei_cfg & (1 << 4)) != 0) { - fwupd_security_attr_set_result (attr, "Manufacturing Mode"); + fwupd_security_attr_set_result (attr, FWUPD_SECURITY_ATTR_RESULT_NOT_LOCKED); return; } /* success */ fwupd_security_attr_add_flag (attr, FWUPD_SECURITY_ATTR_FLAG_SUCCESS); + fwupd_security_attr_set_result (attr, FWUPD_SECURITY_ATTR_RESULT_LOCKED); } diff --git a/plugins/tpm-eventlog/fu-plugin-tpm-eventlog.c b/plugins/tpm-eventlog/fu-plugin-tpm-eventlog.c index 4e7ff0803..a4ae71f8f 100644 --- a/plugins/tpm-eventlog/fu-plugin-tpm-eventlog.c +++ b/plugins/tpm-eventlog/fu-plugin-tpm-eventlog.c @@ -132,23 +132,22 @@ fu_plugin_add_security_attrs (FuPlugin *plugin, FuSecurityAttrs *attrs) g_autoptr(FwupdSecurityAttr) attr = NULL; /* create attr */ - attr = fwupd_security_attr_new ("org.trustedcomputinggroup.TpmEventLog"); + attr = fwupd_security_attr_new (FWUPD_SECURITY_ATTR_ID_TPM_RECONSTRUCTION_PCR0); fwupd_security_attr_set_plugin (attr, fu_plugin_get_name (plugin)); fwupd_security_attr_set_level (attr, FWUPD_SECURITY_ATTR_LEVEL_IMPORTANT); - fwupd_security_attr_set_name (attr, "TPM Reconstruction"); fu_security_attrs_append (attrs, attr); /* check reconstructed to PCR0 */ if (!fu_plugin_get_enabled (plugin)) { - fwupd_security_attr_set_result (attr, "No binary bios measurements available"); + fwupd_security_attr_set_result (attr, FWUPD_SECURITY_ATTR_RESULT_NOT_FOUND); return; } if (!data->reconstructed) { - fwupd_security_attr_set_result (attr, "Did not match PCR0 reading"); + fwupd_security_attr_set_result (attr, FWUPD_SECURITY_ATTR_RESULT_NOT_VALID); return; } /* success */ fwupd_security_attr_add_flag (attr, FWUPD_SECURITY_ATTR_FLAG_SUCCESS); - fwupd_security_attr_set_result (attr, "Matched PCR0 reading"); + fwupd_security_attr_set_result (attr, FWUPD_SECURITY_ATTR_RESULT_VALID); } diff --git a/plugins/tpm/fu-plugin-tpm.c b/plugins/tpm/fu-plugin-tpm.c index 18b0d263e..83e9534d8 100644 --- a/plugins/tpm/fu-plugin-tpm.c +++ b/plugins/tpm/fu-plugin-tpm.c @@ -41,23 +41,22 @@ fu_plugin_add_security_attrs (FuPlugin *plugin, FuSecurityAttrs *attrs) g_autoptr(FwupdSecurityAttr) attr = NULL; /* create attr */ - attr = fwupd_security_attr_new ("org.trustedcomputinggroup.Tpm"); + attr = fwupd_security_attr_new (FWUPD_SECURITY_ATTR_ID_TPM_VERSION_20); fwupd_security_attr_set_plugin (attr, fu_plugin_get_name (plugin)); fwupd_security_attr_set_level (attr, FWUPD_SECURITY_ATTR_LEVEL_CRITICAL); - fwupd_security_attr_set_name (attr, "TPM"); fu_security_attrs_append (attrs, attr); /* check exists, and in v2.0 mode */ if (!data->has_tpm) { - fwupd_security_attr_set_result (attr, "Not found"); + fwupd_security_attr_set_result (attr, FWUPD_SECURITY_ATTR_RESULT_NOT_FOUND); return; } if (!data->has_tpm_v20) { - fwupd_security_attr_set_result (attr, "Not in v2.0 mode"); + fwupd_security_attr_set_result (attr, FWUPD_SECURITY_ATTR_RESULT_NOT_ENABLED); return; } /* success */ fwupd_security_attr_add_flag (attr, FWUPD_SECURITY_ATTR_FLAG_SUCCESS); - fwupd_security_attr_set_result (attr, "v2.0"); + fwupd_security_attr_set_result (attr, FWUPD_SECURITY_ATTR_RESULT_FOUND); } diff --git a/plugins/uefi-dbx/fu-plugin-uefi-dbx.c b/plugins/uefi-dbx/fu-plugin-uefi-dbx.c index 84dafd5ef..4aed0eb48 100644 --- a/plugins/uefi-dbx/fu-plugin-uefi-dbx.c +++ b/plugins/uefi-dbx/fu-plugin-uefi-dbx.c @@ -56,27 +56,22 @@ fu_plugin_add_security_attrs (FuPlugin *plugin, FuSecurityAttrs *attrs) g_autoptr(GError) error_local = NULL; /* create attr */ - attr = fwupd_security_attr_new ("org.uefi.SecureBoot.dbx"); + attr = fwupd_security_attr_new (FWUPD_SECURITY_ATTR_ID_UEFI_DBX); fwupd_security_attr_set_plugin (attr, fu_plugin_get_name (plugin)); fwupd_security_attr_set_level (attr, FWUPD_SECURITY_ATTR_LEVEL_CRITICAL); - fwupd_security_attr_set_name (attr, "UEFI dbx"); fu_security_attrs_append (attrs, attr); /* no binary blob */ if (!fu_plugin_get_enabled (plugin)) { - g_autofree gchar *dbxdir = NULL; - g_autofree gchar *result = NULL; - dbxdir = fu_common_get_path (FU_PATH_KIND_EFIDBXDIR); - result = g_strdup_printf ("DBX can be downloaded from %s and decompressed into %s", - FU_UEFI_DBX_DATA_URL, dbxdir); - fwupd_security_attr_set_result (attr, result); + fwupd_security_attr_set_result (attr, FWUPD_SECURITY_ATTR_RESULT_NOT_FOUND); + fwupd_security_attr_set_url (attr, "https://github.com/fwupd/fwupd/wiki/Missingdbx"); return; } /* get update dbx */ if (!g_file_get_contents (data->fn, (gchar **) &buf_update, &bufsz, &error_local)) { g_warning ("failed to load %s: %s", data->fn, error_local->message); - fwupd_security_attr_set_result (attr, "Failed to load update DBX"); + fwupd_security_attr_set_result (attr, FWUPD_SECURITY_ATTR_RESULT_NOT_VALID); return; } dbx_update = fu_uefi_dbx_file_new (buf_update, bufsz, @@ -84,7 +79,7 @@ fu_plugin_add_security_attrs (FuPlugin *plugin, FuSecurityAttrs *attrs) &error_local); if (dbx_update == NULL) { g_warning ("failed to parse %s: %s", data->fn, error_local->message); - fwupd_security_attr_set_result (attr, "Failed to parse update DBX"); + fwupd_security_attr_set_result (attr, FWUPD_SECURITY_ATTR_RESULT_NOT_VALID); return; } @@ -92,7 +87,7 @@ fu_plugin_add_security_attrs (FuPlugin *plugin, FuSecurityAttrs *attrs) if (!fu_efivar_get_data ("d719b2cb-3d3a-4596-a3bc-dad00e67656f", "dbx", &buf_system, &bufsz, NULL, &error_local)) { g_warning ("failed to load EFI dbx: %s", error_local->message); - fwupd_security_attr_set_result (attr, "Failed to load EFI DBX"); + fwupd_security_attr_set_result (attr, FWUPD_SECURITY_ATTR_RESULT_NOT_VALID); return; } dbx_system = fu_uefi_dbx_file_new (buf_system, bufsz, @@ -100,7 +95,7 @@ fu_plugin_add_security_attrs (FuPlugin *plugin, FuSecurityAttrs *attrs) &error_local); if (dbx_system == NULL) { g_warning ("failed to parse EFI dbx: %s", error_local->message); - fwupd_security_attr_set_result (attr, "Failed to parse EFI DBX"); + fwupd_security_attr_set_result (attr, FWUPD_SECURITY_ATTR_RESULT_NOT_VALID); return; } @@ -116,11 +111,11 @@ fu_plugin_add_security_attrs (FuPlugin *plugin, FuSecurityAttrs *attrs) /* add security attribute */ if (missing_cnt > 0) { - g_autofree gchar *summary = g_strdup_printf ("%u hashes missing", missing_cnt); - fwupd_security_attr_set_result (attr, summary); + fwupd_security_attr_set_result (attr, FWUPD_SECURITY_ATTR_RESULT_NOT_FOUND); return; } /* success */ fwupd_security_attr_add_flag (attr, FWUPD_SECURITY_ATTR_FLAG_SUCCESS); + fwupd_security_attr_set_result (attr, FWUPD_SECURITY_ATTR_RESULT_FOUND); } diff --git a/plugins/uefi-dbx/fu-uefi-dbx-common.h b/plugins/uefi-dbx/fu-uefi-dbx-common.h index 7b02181c9..fd4243217 100644 --- a/plugins/uefi-dbx/fu-uefi-dbx-common.h +++ b/plugins/uefi-dbx/fu-uefi-dbx-common.h @@ -8,6 +8,4 @@ #include -#define FU_UEFI_DBX_DATA_URL "https://uefi.org/revocationlistfile" - gchar *fu_uefi_dbx_get_dbxupdate (GError **error); diff --git a/plugins/uefi/fu-plugin-uefi.c b/plugins/uefi/fu-plugin-uefi.c index a80ed250e..f953e0c98 100644 --- a/plugins/uefi/fu-plugin-uefi.c +++ b/plugins/uefi/fu-plugin-uefi.c @@ -97,21 +97,20 @@ fu_plugin_add_security_attrs (FuPlugin *plugin, FuSecurityAttrs *attrs) g_autoptr(FwupdSecurityAttr) attr = NULL; /* create attr */ - attr = fwupd_security_attr_new ("com.uefi.SecureBoot"); + attr = fwupd_security_attr_new (FWUPD_SECURITY_ATTR_ID_UEFI_SECUREBOOT); fwupd_security_attr_set_plugin (attr, fu_plugin_get_name (plugin)); fwupd_security_attr_set_level (attr, FWUPD_SECURITY_ATTR_LEVEL_CRITICAL); - fwupd_security_attr_set_name (attr, "UEFI Secure Boot"); fu_security_attrs_append (attrs, attr); /* SB disabled */ if (!fu_efivar_secure_boot_enabled ()) { - fwupd_security_attr_set_result (attr, "Disabled"); + fwupd_security_attr_set_result (attr, FWUPD_SECURITY_ATTR_RESULT_NOT_ENABLED); return; } /* success */ fwupd_security_attr_add_flag (attr, FWUPD_SECURITY_ATTR_FLAG_SUCCESS); - fwupd_security_attr_set_result (attr, "Enabled"); + fwupd_security_attr_set_result (attr, FWUPD_SECURITY_ATTR_RESULT_ENABLED); } static GBytes * diff --git a/po/POTFILES.in b/po/POTFILES.in index ff7003b3f..95ac721db 100644 --- a/po/POTFILES.in +++ b/po/POTFILES.in @@ -12,6 +12,7 @@ src/fu-main.c src/fu-offline.c src/fu-progressbar.c src/fu-remote-list.c +src/fu-security-attr.c src/fu-tool.c src/fu-util.c src/fu-util-common.c diff --git a/src/fu-engine.c b/src/fu-engine.c index 23e2927e3..c3b1c9a78 100644 --- a/src/fu-engine.c +++ b/src/fu-engine.c @@ -49,6 +49,7 @@ #include "fu-plugin-private.h" #include "fu-quirks.h" #include "fu-remote-list.h" +#include "fu-security-attr.h" #include "fu-security-attrs-private.h" #include "fu-smbios-private.h" #include "fu-udev-device-private.h" @@ -3585,16 +3586,6 @@ fu_engine_get_devices_by_guid (FuEngine *self, const gchar *guid, GError **error return g_steal_pointer (&devices); } -static const gchar * -fu_engine_get_security_attr_result_string (FwupdSecurityAttr *attr) -{ - if (fwupd_security_attr_get_result (attr) != NULL) - return fwupd_security_attr_get_result (attr); - if (fwupd_security_attr_has_flag (attr, FWUPD_SECURITY_ATTR_FLAG_SUCCESS)) - return "True"; - return "False"; -} - static void fu_engine_get_history_set_hsi_attrs (FuEngine *self, FuDevice *device) { @@ -3607,9 +3598,9 @@ fu_engine_get_history_set_hsi_attrs (FuEngine *self, FuDevice *device) vals = fu_security_attrs_get_all (attrs); for (guint i = 0; i < vals->len; i++) { FwupdSecurityAttr *attr = g_ptr_array_index (vals, i); - fu_device_set_metadata (device, - fwupd_security_attr_get_appstream_id (attr), - fu_engine_get_security_attr_result_string (attr)); + const gchar *tmp; + tmp = fwupd_security_attr_result_to_string (fwupd_security_attr_get_result (attr)); + fu_device_set_metadata (device, fwupd_security_attr_get_appstream_id (attr), tmp); } /* computed value */ @@ -5081,10 +5072,10 @@ fu_engine_add_security_attrs_tainted (FuEngine *self, FuSecurityAttrs *attrs) { gboolean disabled_plugins = FALSE; GPtrArray *blacklist = fu_config_get_blacklist_plugins (self->config); - g_autoptr(FwupdSecurityAttr) attr = fwupd_security_attr_new ("org.fwupd.Hsi.Plugins"); + g_autoptr(FwupdSecurityAttr) attr = fwupd_security_attr_new (FWUPD_SECURITY_ATTR_ID_FWUPD_PLUGINS); fwupd_security_attr_set_plugin (attr, "core"); - fwupd_security_attr_set_name (attr, "fwupd plugins"); fwupd_security_attr_add_flag (attr, FWUPD_SECURITY_ATTR_FLAG_RUNTIME_ISSUE); + fu_security_attrs_append (attrs, attr); for (guint i = 0; i < blacklist->len; i++) { const gchar *name_tmp = g_ptr_array_index (blacklist, i); if (g_strcmp0 (name_tmp, "test") != 0 && @@ -5094,13 +5085,17 @@ fu_engine_add_security_attrs_tainted (FuEngine *self, FuSecurityAttrs *attrs) } } if (self->tainted) { - fwupd_security_attr_set_result (attr, "Tainted"); - } else if (self->plugin_filter->len > 0 || disabled_plugins) { - fwupd_security_attr_set_result (attr, "Disabled plugins"); - } else { - fwupd_security_attr_add_flag (attr, FWUPD_SECURITY_ATTR_FLAG_SUCCESS); + fwupd_security_attr_set_result (attr, FWUPD_SECURITY_ATTR_RESULT_TAINTED); + return; } - fu_security_attrs_append (attrs, attr); + if (self->plugin_filter->len > 0 || disabled_plugins) { + fwupd_security_attr_set_result (attr, FWUPD_SECURITY_ATTR_RESULT_NOT_ENABLED); + return; + } + + /* success */ + fwupd_security_attr_add_flag (attr, FWUPD_SECURITY_ATTR_FLAG_SUCCESS); + fwupd_security_attr_set_result (attr, FWUPD_SECURITY_ATTR_RESULT_NOT_TAINTED); } static void @@ -5115,10 +5110,9 @@ fu_engine_add_security_attrs_supported (FuEngine *self, FuSecurityAttrs *attrs) g_autoptr(GPtrArray) releases = NULL; /* find out if there is firmware less than 12 months old */ - attr_u = fwupd_security_attr_new ("org.fwupd.Hsi.Updates"); + attr_u = fwupd_security_attr_new (FWUPD_SECURITY_ATTR_ID_FWUPD_UPDATES); fwupd_security_attr_set_plugin (attr_u, "core"); fwupd_security_attr_add_flag (attr_u, FWUPD_SECURITY_ATTR_FLAG_RUNTIME_UPDATES); - fwupd_security_attr_set_name (attr_u, "Firmware Updates"); fu_security_attrs_append (attrs, attr_u); /* get device */ @@ -5127,32 +5121,32 @@ fu_engine_add_security_attrs_supported (FuEngine *self, FuSecurityAttrs *attrs) "230c8b18-8d9b-53ec-838b-6cfc0383493a", NULL); if (device == NULL) { - fwupd_security_attr_set_result (attr_u, "No system device"); + fwupd_security_attr_set_result (attr_u, FWUPD_SECURITY_ATTR_RESULT_NOT_FOUND); } else { releases = fu_engine_get_releases_for_device (self, device, NULL); if (releases == NULL) { - fwupd_security_attr_set_result (attr_u, "No releases"); + fwupd_security_attr_set_result (attr_u, FWUPD_SECURITY_ATTR_RESULT_NOT_SUPPORTED); } else { /* check the age */ - g_autofree gchar *str = NULL; for (guint i = 0; i < releases->len; i++) { FwupdRelease *rel_tmp = g_ptr_array_index (releases, i); if (rel_newest == NULL || fwupd_release_get_created (rel_tmp) > fwupd_release_get_created (rel_newest)) rel_newest = rel_tmp; } - str = g_strdup_printf ("Newest release is %" G_GUINT64_FORMAT " months old", - (now - fwupd_release_get_created (rel_newest)) / (60 * 60 * 24 * 30)); - fwupd_security_attr_set_result (attr_u, str); - if (now - fwupd_release_get_created (rel_newest) < 60 * 60 * 24 * 30 * 12) + g_debug ("newest release is %" G_GUINT64_FORMAT " months old", + (now - fwupd_release_get_created (rel_newest)) / (60 * 60 * 24 * 30)); + fwupd_security_attr_set_result (attr_u, FWUPD_SECURITY_ATTR_RESULT_SUPPORTED); + if (now - fwupd_release_get_created (rel_newest) < 60 * 60 * 24 * 30 * 12) { fwupd_security_attr_add_flag (attr_u, FWUPD_SECURITY_ATTR_FLAG_SUCCESS); + fwupd_security_attr_set_result (attr_a, FWUPD_SECURITY_ATTR_RESULT_SUPPORTED); + } } } /* do we have attestation checksums */ - attr_a = fwupd_security_attr_new ("org.fwupd.Hsi.Attestation"); + attr_a = fwupd_security_attr_new (FWUPD_SECURITY_ATTR_ID_FWUPD_ATTESTATION); fwupd_security_attr_set_plugin (attr_a, "core"); - fwupd_security_attr_set_name (attr_a, "Firmware Attestation"); fwupd_security_attr_add_flag (attr_a, FWUPD_SECURITY_ATTR_FLAG_RUNTIME_ATTESTATION); fu_security_attrs_append (attrs, attr_a); if (releases != NULL) { @@ -5167,9 +5161,10 @@ fu_engine_add_security_attrs_supported (FuEngine *self, FuSecurityAttrs *attrs) } } if (rel_current == NULL) { - fwupd_security_attr_set_result (attr_a, "No PCR0s"); + fwupd_security_attr_set_result (attr_a, FWUPD_SECURITY_ATTR_RESULT_NOT_SUPPORTED); } else if (fwupd_release_get_checksums(rel_current)->len > 0) { fwupd_security_attr_add_flag (attr_a, FWUPD_SECURITY_ATTR_FLAG_SUCCESS); + fwupd_security_attr_set_result (attr_a, FWUPD_SECURITY_ATTR_RESULT_SUPPORTED); } } @@ -5178,6 +5173,7 @@ fu_engine_get_host_security_attrs (FuEngine *self) { GPtrArray *plugins = fu_plugin_list_get_all (self->plugin_list); g_autoptr(FuSecurityAttrs) attrs = fu_security_attrs_new (); + g_autoptr(GPtrArray) items = NULL; /* built in */ fu_engine_add_security_attrs_tainted (self, attrs); @@ -5189,8 +5185,24 @@ fu_engine_get_host_security_attrs (FuEngine *self) fu_plugin_runner_add_security_attrs (plugin_tmp, attrs); } + /* set the fallback names for clients without native translations */ + items = fu_security_attrs_get_all (attrs); + for (guint i = 0; i < items->len; i++) { + FwupdSecurityAttr *attr = g_ptr_array_index (items, i); + if (fwupd_security_attr_get_name (attr) == NULL) { + const gchar *name_tmp = fu_security_attr_get_name (attr); + if (name_tmp == NULL) { + g_warning ("failed to get fallback for %s", + fwupd_security_attr_get_appstream_id (attr)); + continue; + } + fwupd_security_attr_set_name (attr, name_tmp); + } + } + /* set the obsoletes flag for each attr */ fu_security_attrs_depsolve (attrs); + return g_steal_pointer (&attrs); } diff --git a/src/fu-security-attr.c b/src/fu-security-attr.c new file mode 100644 index 000000000..61dd52be0 --- /dev/null +++ b/src/fu-security-attr.c @@ -0,0 +1,174 @@ +/* + * Copyright (C) 2020 Richard Hughes + * + * SPDX-License-Identifier: LGPL-2.1+ + */ + +#include +#include + +#include "fu-security-attr.h" + +const gchar * +fu_security_attr_get_name (FwupdSecurityAttr *attr) +{ + const gchar *appstream_id = fwupd_security_attr_get_appstream_id (attr); + if (g_strcmp0 (appstream_id, FWUPD_SECURITY_ATTR_ID_SPI_BIOSWE) == 0) { + /* TRANSLATORS: Title: SPI refers to the flash chip in the computer */ + return _("SPI write"); + } + if (g_strcmp0 (appstream_id, FWUPD_SECURITY_ATTR_ID_SPI_BLE) == 0) { + /* TRANSLATORS: Title: SPI refers to the flash chip in the computer */ + return _("SPI lock"); + } + if (g_strcmp0 (appstream_id, FWUPD_SECURITY_ATTR_ID_SPI_SMM_BWP) == 0) { + /* TRANSLATORS: Title: SPI refers to the flash chip in the computer */ + return _("SPI BIOS region"); + } + if (g_strcmp0 (appstream_id, FWUPD_SECURITY_ATTR_ID_ACPI_DMAR) == 0) { + /* TRANSLATORS: Title: DMA as in https://en.wikipedia.org/wiki/DMA_attack */ + return _("Pre-boot DMA protection"); + } + if (g_strcmp0 (appstream_id, FWUPD_SECURITY_ATTR_ID_INTEL_AMT) == 0) { + /* TRANSLATORS: Title: AMT = Active Management Technology */ + return _("Intel AMT"); + } + if (g_strcmp0 (appstream_id, FWUPD_SECURITY_ATTR_ID_INTEL_CET) == 0) { + /* TRANSLATORS: Title: CET = Control-flow Enforcement Technology */ + return _("Intel CET"); + } + if (g_strcmp0 (appstream_id, FWUPD_SECURITY_ATTR_ID_ENCRYPTED_RAM) == 0) { + /* TRANSLATORS: Title: Memory contents are encrypted, e.g. Intel TME */ + return _("Encrypted RAM"); + } + if (g_strcmp0 (appstream_id, FWUPD_SECURITY_ATTR_ID_IOMMU) == 0) { + /* TRANSLATORS: Title: https://en.wikipedia.org/wiki/Input%E2%80%93output_memory_management_unit */ + return _("IOMMU"); + } + if (g_strcmp0 (appstream_id, FWUPD_SECURITY_ATTR_ID_KERNEL_LOCKDOWN) == 0) { + /* TRANSLATORS: Title: lockdown is a security mode of the kernel */ + return _("Linux kernel lockdown"); + } + if (g_strcmp0 (appstream_id, FWUPD_SECURITY_ATTR_ID_KERNEL_TAINTED) == 0) { + /* TRANSLATORS: Title: if it's tainted or not */ + return _("Linux kernel"); + } + if (g_strcmp0 (appstream_id, FWUPD_SECURITY_ATTR_ID_KERNEL_SWAP) == 0) { + /* TRANSLATORS: Title: swap space or swap partition */ + return _("Linux swap"); + } + if (g_strcmp0 (appstream_id, FWUPD_SECURITY_ATTR_ID_SUSPEND_TO_RAM) == 0) { + /* TRANSLATORS: Title: sleep state */ + return _("Suspend-to-ram"); + } + if (g_strcmp0 (appstream_id, FWUPD_SECURITY_ATTR_ID_SUSPEND_TO_IDLE) == 0) { + /* TRANSLATORS: Title: a better sleep state */ + return _("Suspend-to-idle"); + } + if (g_strcmp0 (appstream_id, FWUPD_SECURITY_ATTR_ID_UEFI_DBX) == 0) { + /* TRANSLATORS: Title: dbx is the database with revoked hashes */ + return _("UEFI dbx"); + } + if (g_strcmp0 (appstream_id, FWUPD_SECURITY_ATTR_ID_UEFI_SECUREBOOT) == 0) { + /* TRANSLATORS: Title: SB is a way of locking down UEFI */ + return _("UEFI secure boot"); + } + if (g_strcmp0 (appstream_id, FWUPD_SECURITY_ATTR_ID_TPM_RECONSTRUCTION_PCR0) == 0) { + /* TRANSLATORS: Title: the PCR is rebuilt from the TPM event log */ + return _("TPM PCR0 reconstruction"); + } + if (g_strcmp0 (appstream_id, FWUPD_SECURITY_ATTR_ID_TPM_VERSION_20) == 0) { + /* TRANSLATORS: Title: TPM = Trusted Platform Module */ + return _("TPM v2.0"); + } + if (g_strcmp0 (appstream_id, FWUPD_SECURITY_ATTR_ID_MEI_MANUFACTURING_MODE) == 0) { + /* TRANSLATORS: Title: MEI = Intel Management Engine */ + return _("MEI manufacturing mode"); + } + if (g_strcmp0 (appstream_id, FWUPD_SECURITY_ATTR_ID_FWUPD_UPDATES) == 0) { + /* TRANSLATORS: Title: if firmware updates are available */ + return _("Firmware updates"); + } + if (g_strcmp0 (appstream_id, FWUPD_SECURITY_ATTR_ID_FWUPD_ATTESTATION) == 0) { + /* TRANSLATORS: Title: if we can verify the firmware checksums */ + return _("Firmware attestation"); + } + if (g_strcmp0 (appstream_id, FWUPD_SECURITY_ATTR_ID_FWUPD_PLUGINS) == 0) { + /* TRANSLATORS: Title: if the fwupd plugins are all present and correct */ + return _("fwupd plugins"); + } + + /* we should not get here */ + return fwupd_security_attr_get_name (attr); +} + +const gchar * +fu_security_attr_get_result (FwupdSecurityAttr *attr) +{ + FwupdSecurityAttrResult result = fwupd_security_attr_get_result (attr); + if (result == FWUPD_SECURITY_ATTR_RESULT_VALID) { + /* TRANSLATORS: Suffix: the HSI result */ + return _("Valid"); + } + if (result == FWUPD_SECURITY_ATTR_RESULT_NOT_VALID) { + /* TRANSLATORS: Suffix: the HSI result */ + return _("Not Valid"); + } + if (result == FWUPD_SECURITY_ATTR_RESULT_ENABLED) { + /* TRANSLATORS: Suffix: the HSI result */ + return _("Enabled"); + } + if (result == FWUPD_SECURITY_ATTR_RESULT_NOT_ENABLED) { + /* TRANSLATORS: Suffix: the HSI result */ + return _("Disabled"); + } + if (result == FWUPD_SECURITY_ATTR_RESULT_LOCKED) { + /* TRANSLATORS: Suffix: the HSI result */ + return _("Locked"); + } + if (result == FWUPD_SECURITY_ATTR_RESULT_NOT_LOCKED) { + /* TRANSLATORS: Suffix: the HSI result */ + return _("Unlocked"); + } + if (result == FWUPD_SECURITY_ATTR_RESULT_ENCRYPTED) { + /* TRANSLATORS: Suffix: the HSI result */ + return _("Encrypted"); + } + if (result == FWUPD_SECURITY_ATTR_RESULT_NOT_ENCRYPTED) { + /* TRANSLATORS: Suffix: the HSI result */ + return _("Unencrypted"); + } + if (result == FWUPD_SECURITY_ATTR_RESULT_TAINTED) { + /* TRANSLATORS: Suffix: the HSI result */ + return _("Tainted"); + } + if (result == FWUPD_SECURITY_ATTR_RESULT_NOT_TAINTED) { + /* TRANSLATORS: Suffix: the HSI result */ + return _("Untainted"); + } + if (result == FWUPD_SECURITY_ATTR_RESULT_FOUND) { + /* TRANSLATORS: Suffix: the HSI result */ + return _("Found"); + } + if (result == FWUPD_SECURITY_ATTR_RESULT_NOT_FOUND) { + /* TRANSLATORS: Suffix: the HSI result */ + return _("Not found"); + } + if (result == FWUPD_SECURITY_ATTR_RESULT_SUPPORTED) { + /* TRANSLATORS: Suffix: the HSI result */ + return _("Supported"); + } + if (result == FWUPD_SECURITY_ATTR_RESULT_NOT_SUPPORTED) { + /* TRANSLATORS: Suffix: the HSI result */ + return _("Not supported"); + } + + /* fallback */ + if (fwupd_security_attr_has_flag (attr, FWUPD_SECURITY_ATTR_FLAG_SUCCESS)) { + /* TRANSLATORS: Suffix: the HSI result */ + return _("OK"); + } + + /* TRANSLATORS: Suffix: the fallback HSI result */ + return _("Failed"); +} diff --git a/src/fu-security-attr.h b/src/fu-security-attr.h new file mode 100644 index 000000000..d81e33ce9 --- /dev/null +++ b/src/fu-security-attr.h @@ -0,0 +1,12 @@ +/* + * Copyright (C) 2020 Richard Hughes + * + * SPDX-License-Identifier: LGPL-2.1+ + */ + +#pragma once + +#include + +const gchar *fu_security_attr_get_name (FwupdSecurityAttr *attr); +const gchar *fu_security_attr_get_result (FwupdSecurityAttr *attr); diff --git a/src/fu-self-test.c b/src/fu-self-test.c index 6f0db881e..0991a3618 100644 --- a/src/fu-self-test.c +++ b/src/fu-self-test.c @@ -25,6 +25,7 @@ #include "fu-plugin-list.h" #include "fu-progressbar.h" #include "fu-hash.h" +#include "fu-security-attr.h" #include "fu-security-attrs.h" #include "fu-smbios-private.h" @@ -2806,6 +2807,15 @@ fu_plugin_composite_func (gconstpointer user_data) } } +static void +fu_security_attr_func (gconstpointer user_data) +{ + g_autoptr(FwupdSecurityAttr) attr = fwupd_security_attr_new (NULL); + for (guint i = 0; i < FWUPD_SECURITY_ATTR_RESULT_LAST; i++) { + fwupd_security_attr_set_result (attr, i); + g_assert_cmpstr (fu_security_attr_get_result (attr), !=, NULL); + } +} static void fu_memcpy_func (gconstpointer user_data) @@ -2987,6 +2997,8 @@ main (int argc, char **argv) fu_plugin_module_func); g_test_add_data_func ("/fwupd/memcpy", self, fu_memcpy_func); + g_test_add_data_func ("/fwupd/security-attr", self, + fu_security_attr_func); g_test_add_data_func ("/fwupd/device-list", self, fu_device_list_func); g_test_add_data_func ("/fwupd/device-list{delay}", self, diff --git a/src/fu-util-common.c b/src/fu-util-common.c index ba863f0e6..6d3f45a8c 100644 --- a/src/fu-util-common.c +++ b/src/fu-util-common.c @@ -16,6 +16,7 @@ #include "fu-common.h" #include "fu-util-common.h" #include "fu-device.h" +#include "fu-security-attr.h" #include "fu-security-attrs.h" #ifdef HAVE_SYSTEMD @@ -1553,20 +1554,25 @@ static void fu_security_attr_append_str (FwupdSecurityAttr *attr, GString *str) { if (fwupd_security_attr_has_flag (attr, FWUPD_SECURITY_ATTR_FLAG_OBSOLETED)) { - g_string_append_printf (str, "\033[37m✦\033[0m "); + g_string_append (str, "✦ "); } else if (fwupd_security_attr_has_flag (attr, FWUPD_SECURITY_ATTR_FLAG_SUCCESS)) { - g_string_append_printf (str, "\033[32m✔\033[0m "); + g_string_append (str, "✔ "); } else { - g_string_append_printf (str, "\033[31m✘\033[0m "); + g_string_append (str, "✘ "); } - g_string_append_printf (str, "%s", fwupd_security_attr_get_name (attr)); - if (fwupd_security_attr_get_result (attr) != NULL) { - g_string_append_printf (str, ": %s", - fwupd_security_attr_get_result (attr)); + g_string_append_printf (str, "%s:", fu_security_attr_get_name (attr)); + for (guint i = fu_common_strwidth (fu_security_attr_get_name (attr)); i < 30; i++) + g_string_append (str, " "); + if (fwupd_security_attr_has_flag (attr, FWUPD_SECURITY_ATTR_FLAG_OBSOLETED)) { + g_string_append_printf (str, "\033[37m\033[1m%s\033[0m", fu_security_attr_get_result (attr)); + } else if (fwupd_security_attr_has_flag (attr, FWUPD_SECURITY_ATTR_FLAG_SUCCESS)) { + g_string_append_printf (str, "\033[32m\033[1m%s\033[0m", fu_security_attr_get_result (attr)); } else { + g_string_append_printf (str, "\033[31m\033[1m%s\033[0m", fu_security_attr_get_result (attr)); + } + if (fwupd_security_attr_get_url (attr) != NULL) { g_string_append_printf (str, ": %s", - fwupd_security_attr_has_flag (attr, FWUPD_SECURITY_ATTR_FLAG_SUCCESS) - ? "OK" : "Failed"); + fwupd_security_attr_get_url (attr)); } if (fwupd_security_attr_has_flag (attr, FWUPD_SECURITY_ATTR_FLAG_OBSOLETED)) g_string_append (str, " (obsoleted)"); diff --git a/src/meson.build b/src/meson.build index c1ed9a979..7a0b2976a 100644 --- a/src/meson.build +++ b/src/meson.build @@ -17,6 +17,7 @@ fwupdmgr = executable( 'fu-util.c', 'fu-history.c', 'fu-progressbar.c', + 'fu-security-attr.c', 'fu-util-common.c', systemd_src ], @@ -49,6 +50,7 @@ fwupdagent = executable( 'fwupdagent', sources : [ 'fu-agent.c', + 'fu-security-attr.c', 'fu-util-common.c', systemd_src, ], @@ -80,6 +82,7 @@ fwupdoffline = executable( sources : [ 'fu-history.c', 'fu-offline.c', + 'fu-security-attr.c', 'fu-util-common.c', systemd_src ], @@ -132,6 +135,7 @@ fwupdtool = executable( 'fu-plugin-list.c', 'fu-progressbar.c', 'fu-remote-list.c', + 'fu-security-attr.c', 'fu-util-common.c', systemd_src ], @@ -230,6 +234,7 @@ executable( 'fu-main.c', 'fu-plugin-list.c', 'fu-remote-list.c', + 'fu-security-attr.c', systemd_src ], include_directories : [ @@ -286,6 +291,7 @@ if get_option('tests') 'fu-plugin-list.c', 'fu-progressbar.c', 'fu-remote-list.c', + 'fu-security-attr.c', 'fu-self-test.c', systemd_src ], From b0d2e9e07b3eac78b63139bdf44f03cdd909b577 Mon Sep 17 00:00:00 2001 From: Mario Limonciello Date: Mon, 18 May 2020 12:30:47 -0500 Subject: [PATCH 087/607] trivial: correct an assertion for HSI attributes --- src/fu-engine.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/fu-engine.c b/src/fu-engine.c index c3b1c9a78..5e61e8db3 100644 --- a/src/fu-engine.c +++ b/src/fu-engine.c @@ -5109,17 +5109,21 @@ fu_engine_add_security_attrs_supported (FuEngine *self, FuSecurityAttrs *attrs) g_autoptr(FuDevice) device = NULL; g_autoptr(GPtrArray) releases = NULL; - /* find out if there is firmware less than 12 months old */ attr_u = fwupd_security_attr_new (FWUPD_SECURITY_ATTR_ID_FWUPD_UPDATES); fwupd_security_attr_set_plugin (attr_u, "core"); fwupd_security_attr_add_flag (attr_u, FWUPD_SECURITY_ATTR_FLAG_RUNTIME_UPDATES); fu_security_attrs_append (attrs, attr_u); - + attr_a = fwupd_security_attr_new (FWUPD_SECURITY_ATTR_ID_FWUPD_ATTESTATION); + fwupd_security_attr_set_plugin (attr_a, "core"); + fwupd_security_attr_add_flag (attr_a, FWUPD_SECURITY_ATTR_FLAG_RUNTIME_ATTESTATION); + fu_security_attrs_append (attrs, attr_a); /* get device */ device = fu_device_list_get_by_guid (self->device_list, /* main-system-firmware */ "230c8b18-8d9b-53ec-838b-6cfc0383493a", NULL); + + /* find out if there is firmware less than 12 months old */ if (device == NULL) { fwupd_security_attr_set_result (attr_u, FWUPD_SECURITY_ATTR_RESULT_NOT_FOUND); } else { @@ -5145,10 +5149,6 @@ fu_engine_add_security_attrs_supported (FuEngine *self, FuSecurityAttrs *attrs) } /* do we have attestation checksums */ - attr_a = fwupd_security_attr_new (FWUPD_SECURITY_ATTR_ID_FWUPD_ATTESTATION); - fwupd_security_attr_set_plugin (attr_a, "core"); - fwupd_security_attr_add_flag (attr_a, FWUPD_SECURITY_ATTR_FLAG_RUNTIME_ATTESTATION); - fu_security_attrs_append (attrs, attr_a); if (releases != NULL) { for (guint i = 0; i < releases->len; i++) { FwupdRelease *rel_tmp = g_ptr_array_index (releases, i); From 5d8c630d83f4fa0c3ca68cbcbb0cfb0dcdd80ede Mon Sep 17 00:00:00 2001 From: Mario Limonciello Date: Mon, 18 May 2020 12:44:15 -0500 Subject: [PATCH 088/607] trivial: fix attestation checksum verification It was just checking if a checksum was in the release, which it was for the payload. It didn't make sure that it actually matched the device. --- src/fu-engine.c | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/src/fu-engine.c b/src/fu-engine.c index 5e61e8db3..ad8ccc99c 100644 --- a/src/fu-engine.c +++ b/src/fu-engine.c @@ -5162,9 +5162,15 @@ fu_engine_add_security_attrs_supported (FuEngine *self, FuSecurityAttrs *attrs) } if (rel_current == NULL) { fwupd_security_attr_set_result (attr_a, FWUPD_SECURITY_ATTR_RESULT_NOT_SUPPORTED); - } else if (fwupd_release_get_checksums(rel_current)->len > 0) { - fwupd_security_attr_add_flag (attr_a, FWUPD_SECURITY_ATTR_FLAG_SUCCESS); - fwupd_security_attr_set_result (attr_a, FWUPD_SECURITY_ATTR_RESULT_SUPPORTED); + } else { + g_autoptr(GError) error_local = NULL; + if (!fu_engine_verify (self, fu_device_get_id (device), &error_local)) { + fwupd_security_attr_set_result (attr_a, FWUPD_SECURITY_ATTR_RESULT_NOT_SUPPORTED); + g_debug ("Failed to find attestation checksums: %s", error_local->message); + } else { + fwupd_security_attr_add_flag (attr_a, FWUPD_SECURITY_ATTR_FLAG_SUCCESS); + fwupd_security_attr_set_result (attr_a, FWUPD_SECURITY_ATTR_RESULT_SUPPORTED); + } } } From b0e1e5ec12068266304357fb6135934119479888 Mon Sep 17 00:00:00 2001 From: Mario Limonciello Date: Mon, 18 May 2020 13:50:29 -0500 Subject: [PATCH 089/607] Add daemon version into the HSI string --- libfwupdplugin/fu-security-attrs-private.h | 17 ++++++++++++- libfwupdplugin/fu-security-attrs.c | 24 ++++++++++++------ libfwupdplugin/fu-self-test.c | 29 ++++++++++++++++------ src/fu-engine.c | 5 ++-- 4 files changed, 58 insertions(+), 17 deletions(-) diff --git a/libfwupdplugin/fu-security-attrs-private.h b/libfwupdplugin/fu-security-attrs-private.h index 5e9c262e5..fc435fc42 100644 --- a/libfwupdplugin/fu-security-attrs-private.h +++ b/libfwupdplugin/fu-security-attrs-private.h @@ -6,10 +6,25 @@ #pragma once +/** + * FuSecurityAttrsFlags: + * @FU_SECURITY_ATTRS_FLAG_NONE: No flags set + * @FU_SECURITY_ATTRS_FLAG_ADD_VERSION: Add the daemon version to the HSI string + * + * The flags to use when calculating an HSI version. + **/ +typedef enum { + FU_SECURITY_ATTRS_FLAG_NONE = 0, + FU_SECURITY_ATTRS_FLAG_ADD_VERSION = 1 << 0, + /*< private >*/ + FU_SECURITY_ATTRS_FLAG_LAST +} FuSecurityAttrsFlags; + #include "fu-security-attrs.h" FuSecurityAttrs *fu_security_attrs_new (void); -gchar *fu_security_attrs_calculate_hsi (FuSecurityAttrs *self); +gchar *fu_security_attrs_calculate_hsi (FuSecurityAttrs *self, + FuSecurityAttrsFlags flags); void fu_security_attrs_depsolve (FuSecurityAttrs *self); GVariant *fu_security_attrs_to_variant (FuSecurityAttrs *self); GPtrArray *fu_security_attrs_get_all (FuSecurityAttrs *self); diff --git a/libfwupdplugin/fu-security-attrs.c b/libfwupdplugin/fu-security-attrs.c index 16b0da571..0ce964bd9 100644 --- a/libfwupdplugin/fu-security-attrs.c +++ b/libfwupdplugin/fu-security-attrs.c @@ -110,6 +110,7 @@ fu_security_attrs_get_all (FuSecurityAttrs *self) /** * fu_security_attrs_calculate_hsi: * @self: A #FuSecurityAttrs + * @flags: Flags to use while calcuating the HSI * * Calculates the HSI string from the appended attribues. * @@ -118,10 +119,11 @@ fu_security_attrs_get_all (FuSecurityAttrs *self) * Since: 1.5.0 **/ gchar * -fu_security_attrs_calculate_hsi (FuSecurityAttrs *self) +fu_security_attrs_calculate_hsi (FuSecurityAttrs *self, + FuSecurityAttrsFlags flags) { guint hsi_number = 0; - FwupdSecurityAttrFlags flags = FWUPD_SECURITY_ATTR_FLAG_NONE; + FwupdSecurityAttrFlags attr_flags = FWUPD_SECURITY_ATTR_FLAG_NONE; GString *str = g_string_new ("HSI:"); const FwupdSecurityAttrFlags hpi_suffixes[] = { FWUPD_SECURITY_ATTR_FLAG_RUNTIME_UPDATES, @@ -174,19 +176,27 @@ fu_security_attrs_calculate_hsi (FuSecurityAttrs *self) if (fwupd_security_attr_has_flag (attr, FWUPD_SECURITY_ATTR_FLAG_SUCCESS)) continue; } - flags |= fwupd_security_attr_get_flags (attr); + attr_flags |= fwupd_security_attr_get_flags (attr); } g_string_append_printf (str, "%u", hsi_number); - if (flags & (FWUPD_SECURITY_ATTR_FLAG_RUNTIME_UPDATES | - FWUPD_SECURITY_ATTR_FLAG_RUNTIME_ATTESTATION | - FWUPD_SECURITY_ATTR_FLAG_RUNTIME_ISSUE)) { + if (attr_flags & (FWUPD_SECURITY_ATTR_FLAG_RUNTIME_UPDATES | + FWUPD_SECURITY_ATTR_FLAG_RUNTIME_ATTESTATION | + FWUPD_SECURITY_ATTR_FLAG_RUNTIME_ISSUE)) { g_string_append (str, "+"); for (guint j = 0; hpi_suffixes[j] != FWUPD_SECURITY_ATTR_FLAG_NONE; j++) { - if (flags & hpi_suffixes[j]) + if (attr_flags & hpi_suffixes[j]) g_string_append (str, fwupd_security_attr_flag_to_suffix (hpi_suffixes[j])); } } + + if (flags & FU_SECURITY_ATTRS_FLAG_ADD_VERSION) { + g_string_append_printf (str, " (v%d.%d.%d)", + FWUPD_MAJOR_VERSION, + FWUPD_MINOR_VERSION, + FWUPD_MICRO_VERSION); + } + return g_string_free (str, FALSE); } diff --git a/libfwupdplugin/fu-self-test.c b/libfwupdplugin/fu-self-test.c index f820a6f01..3a2d49c59 100644 --- a/libfwupdplugin/fu-self-test.c +++ b/libfwupdplugin/fu-self-test.c @@ -1753,12 +1753,14 @@ fu_security_attrs_hsi_func (void) g_autofree gchar *hsi5 = NULL; g_autofree gchar *hsi6 = NULL; g_autofree gchar *hsi7 = NULL; + g_autofree gchar *hsi8 = NULL; + g_autofree gchar *expected_hsi8 = NULL; g_autoptr(FuSecurityAttrs) attrs = NULL; g_autoptr(FwupdSecurityAttr) attr = NULL; /* no attrs */ attrs = fu_security_attrs_new (); - hsi1 = fu_security_attrs_calculate_hsi (attrs); + hsi1 = fu_security_attrs_calculate_hsi (attrs, FU_SECURITY_ATTRS_FLAG_NONE); g_assert_cmpstr (hsi1, ==, "HSI:0"); /* just success from HSI:1 */ @@ -1767,7 +1769,7 @@ fu_security_attrs_hsi_func (void) fwupd_security_attr_set_level (attr, FWUPD_SECURITY_ATTR_LEVEL_CRITICAL); fwupd_security_attr_add_flag (attr, FWUPD_SECURITY_ATTR_FLAG_SUCCESS); fu_security_attrs_append (attrs, attr); - hsi2 = fu_security_attrs_calculate_hsi (attrs); + hsi2 = fu_security_attrs_calculate_hsi (attrs, FU_SECURITY_ATTRS_FLAG_NONE); g_assert_cmpstr (hsi2, ==, "HSI:1"); g_clear_object (&attr); @@ -1776,7 +1778,7 @@ fu_security_attrs_hsi_func (void) fwupd_security_attr_set_plugin (attr, "test"); fwupd_security_attr_set_level (attr, FWUPD_SECURITY_ATTR_LEVEL_IMPORTANT); fu_security_attrs_append (attrs, attr); - hsi3 = fu_security_attrs_calculate_hsi (attrs); + hsi3 = fu_security_attrs_calculate_hsi (attrs, FU_SECURITY_ATTRS_FLAG_NONE); g_assert_cmpstr (hsi3, ==, "HSI:1"); g_clear_object (&attr); @@ -1788,7 +1790,7 @@ fu_security_attrs_hsi_func (void) fwupd_security_attr_add_obsolete (attr, "org.fwupd.hsi.PRX"); fu_security_attrs_append (attrs, attr); fu_security_attrs_depsolve (attrs); - hsi4 = fu_security_attrs_calculate_hsi (attrs); + hsi4 = fu_security_attrs_calculate_hsi (attrs, FU_SECURITY_ATTRS_FLAG_NONE); g_assert_cmpstr (hsi4, ==, "HSI:3"); g_clear_object (&attr); @@ -1798,7 +1800,7 @@ fu_security_attrs_hsi_func (void) fwupd_security_attr_add_flag (attr, FWUPD_SECURITY_ATTR_FLAG_SUCCESS); fwupd_security_attr_add_flag (attr, FWUPD_SECURITY_ATTR_FLAG_RUNTIME_ISSUE); fu_security_attrs_append (attrs, attr); - hsi5 = fu_security_attrs_calculate_hsi (attrs); + hsi5 = fu_security_attrs_calculate_hsi (attrs, FU_SECURITY_ATTRS_FLAG_NONE); g_assert_cmpstr (hsi5, ==, "HSI:3"); g_clear_object (&attr); @@ -1809,7 +1811,7 @@ fu_security_attrs_hsi_func (void) fwupd_security_attr_add_flag (attr, FWUPD_SECURITY_ATTR_FLAG_RUNTIME_ATTESTATION); fwupd_security_attr_add_flag (attr, FWUPD_SECURITY_ATTR_FLAG_SUCCESS); fu_security_attrs_append (attrs, attr); - hsi6 = fu_security_attrs_calculate_hsi (attrs); + hsi6 = fu_security_attrs_calculate_hsi (attrs, FU_SECURITY_ATTRS_FLAG_NONE); g_assert_cmpstr (hsi6, ==, "HSI:3+UA"); g_clear_object (&attr); @@ -1818,9 +1820,22 @@ fu_security_attrs_hsi_func (void) fwupd_security_attr_set_plugin (attr, "test"); fwupd_security_attr_add_flag (attr, FWUPD_SECURITY_ATTR_FLAG_RUNTIME_ISSUE); fu_security_attrs_append (attrs, attr); - hsi7 = fu_security_attrs_calculate_hsi (attrs); + hsi7 = fu_security_attrs_calculate_hsi (attrs, FU_SECURITY_ATTRS_FLAG_NONE); g_assert_cmpstr (hsi7, ==, "HSI:3+UA!"); g_clear_object (&attr); + + /* show version in the attribute */ + attr = fwupd_security_attr_new (FWUPD_SECURITY_ATTR_ID_KERNEL_SWAP); + fwupd_security_attr_set_plugin (attr, "test"); + fwupd_security_attr_add_flag (attr, FWUPD_SECURITY_ATTR_FLAG_RUNTIME_ISSUE); + fu_security_attrs_append (attrs, attr); + hsi8 = fu_security_attrs_calculate_hsi (attrs, FU_SECURITY_ATTRS_FLAG_ADD_VERSION); + expected_hsi8 = g_strdup_printf ("HSI:3+UA! (v%d.%d.%d)", + FWUPD_MAJOR_VERSION, + FWUPD_MINOR_VERSION, + FWUPD_MICRO_VERSION); + g_assert_cmpstr (hsi8, ==, expected_hsi8); + g_clear_object (&attr); } int diff --git a/src/fu-engine.c b/src/fu-engine.c index ad8ccc99c..01ec50b12 100644 --- a/src/fu-engine.c +++ b/src/fu-engine.c @@ -3604,7 +3604,7 @@ fu_engine_get_history_set_hsi_attrs (FuEngine *self, FuDevice *device) } /* computed value */ - host_security_id = fu_security_attrs_calculate_hsi (attrs); + host_security_id = fu_security_attrs_calculate_hsi (attrs, FU_SECURITY_ATTRS_FLAG_ADD_VERSION); fu_device_set_metadata (device, "HSI", host_security_id); } @@ -5224,7 +5224,8 @@ fu_engine_get_host_security_id (FuEngine *self) self->host_security_id = NULL; self->host_security_id_valid = TRUE; attrs = fu_engine_get_host_security_attrs (self); - self->host_security_id = fu_security_attrs_calculate_hsi (attrs); + self->host_security_id = fu_security_attrs_calculate_hsi (attrs, + FU_SECURITY_ATTRS_FLAG_ADD_VERSION); } return self->host_security_id; From dcd32eb582ea104d93d9a833f6f8d56463fd9198 Mon Sep 17 00:00:00 2001 From: Richard Hughes Date: Mon, 18 May 2020 20:58:08 +0100 Subject: [PATCH 090/607] trivial: Fix obsoleted line prefix to match the others --- src/fu-util-common.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/fu-util-common.c b/src/fu-util-common.c index 6d3f45a8c..7878c21fd 100644 --- a/src/fu-util-common.c +++ b/src/fu-util-common.c @@ -1554,7 +1554,7 @@ static void fu_security_attr_append_str (FwupdSecurityAttr *attr, GString *str) { if (fwupd_security_attr_has_flag (attr, FWUPD_SECURITY_ATTR_FLAG_OBSOLETED)) { - g_string_append (str, "✦ "); + g_string_append (str, "✦ "); } else if (fwupd_security_attr_has_flag (attr, FWUPD_SECURITY_ATTR_FLAG_SUCCESS)) { g_string_append (str, "✔ "); } else { From 2157468709e244d6303b42158e9e7087871a69fa Mon Sep 17 00:00:00 2001 From: Richard Hughes Date: Mon, 18 May 2020 21:02:06 +0100 Subject: [PATCH 091/607] pcr-bpc: Don't show the 'Not found' message for BLE and SMM_BWP If we did not find the device for BIOSWP it is completely useless. --- .../linux-spi-lpc/fu-plugin-linux-spi-lpc.c | 20 ++++++++----------- plugins/pci-bcr/fu-plugin-pci-bcr.c | 20 ++++++++----------- 2 files changed, 16 insertions(+), 24 deletions(-) diff --git a/plugins/linux-spi-lpc/fu-plugin-linux-spi-lpc.c b/plugins/linux-spi-lpc/fu-plugin-linux-spi-lpc.c index 479c0cd73..bcdede6ad 100644 --- a/plugins/linux-spi-lpc/fu-plugin-linux-spi-lpc.c +++ b/plugins/linux-spi-lpc/fu-plugin-linux-spi-lpc.c @@ -66,18 +66,16 @@ fu_plugin_add_security_attr_ble (FuPlugin *plugin, FuSecurityAttrs *attrs) g_autoptr(FwupdSecurityAttr) attr = NULL; g_autoptr(GError) error_local = NULL; + /* maybe the kernel module does not exist */ + if (!g_file_test (FU_PLUGIN_LINUX_SPI_LPC_SYSFS_DIR, G_FILE_TEST_IS_DIR)) + return; + /* create attr */ attr = fwupd_security_attr_new (FWUPD_SECURITY_ATTR_ID_SPI_BLE); fwupd_security_attr_set_level (attr, FWUPD_SECURITY_ATTR_LEVEL_CRITICAL); fwupd_security_attr_add_obsolete (attr, "pci_bcr"); fu_security_attrs_append (attrs, attr); - /* maybe the kernel module does not exist */ - if (!g_file_test (FU_PLUGIN_LINUX_SPI_LPC_SYSFS_DIR, G_FILE_TEST_IS_DIR)) { - fwupd_security_attr_set_result (attr, FWUPD_SECURITY_ATTR_RESULT_NOT_FOUND); - return; - } - /* load file */ fn = g_build_filename (FU_PLUGIN_LINUX_SPI_LPC_SYSFS_DIR, "ble", NULL); if (!g_file_get_contents (fn, &buf, &bufsz, &error_local)) { @@ -104,18 +102,16 @@ fu_plugin_add_security_attr_smm_bwp (FuPlugin *plugin, FuSecurityAttrs *attrs) g_autoptr(FwupdSecurityAttr) attr = NULL; g_autoptr(GError) error_local = NULL; + /* maybe the kernel module does not exist */ + if (!g_file_test (FU_PLUGIN_LINUX_SPI_LPC_SYSFS_DIR, G_FILE_TEST_IS_DIR)) + return; + /* create attr */ attr = fwupd_security_attr_new (FWUPD_SECURITY_ATTR_ID_SPI_SMM_BWP); fwupd_security_attr_set_level (attr, FWUPD_SECURITY_ATTR_LEVEL_CRITICAL); fwupd_security_attr_add_obsolete (attr, "pci_bcr"); fu_security_attrs_append (attrs, attr); - /* maybe the kernel module does not exist */ - if (!g_file_test (FU_PLUGIN_LINUX_SPI_LPC_SYSFS_DIR, G_FILE_TEST_IS_DIR)) { - fwupd_security_attr_set_result (attr, FWUPD_SECURITY_ATTR_RESULT_NOT_FOUND); - return; - } - /* load file */ fn = g_build_filename (FU_PLUGIN_LINUX_SPI_LPC_SYSFS_DIR, "smm_bwp", NULL); if (!g_file_get_contents (fn, &buf, &bufsz, &error_local)) { diff --git a/plugins/pci-bcr/fu-plugin-pci-bcr.c b/plugins/pci-bcr/fu-plugin-pci-bcr.c index fa2f8e50a..e2fc1e9f4 100644 --- a/plugins/pci-bcr/fu-plugin-pci-bcr.c +++ b/plugins/pci-bcr/fu-plugin-pci-bcr.c @@ -63,6 +63,10 @@ fu_plugin_add_security_attr_ble (FuPlugin *plugin, FuSecurityAttrs *attrs) FuPluginData *priv = fu_plugin_get_data (plugin); g_autoptr(FwupdSecurityAttr) attr = NULL; + /* no device */ + if (!priv->has_device) + return; + /* create attr */ attr = fwupd_security_attr_new (FWUPD_SECURITY_ATTR_ID_SPI_BLE); fwupd_security_attr_set_plugin (attr, fu_plugin_get_name (plugin)); @@ -70,12 +74,6 @@ fu_plugin_add_security_attr_ble (FuPlugin *plugin, FuSecurityAttrs *attrs) fwupd_security_attr_add_obsolete (attr, "linux_spi_lpc"); fu_security_attrs_append (attrs, attr); - /* no device */ - if (!priv->has_device) { - fwupd_security_attr_set_result (attr, FWUPD_SECURITY_ATTR_RESULT_NOT_FOUND); - return; - } - /* load file */ if ((priv->bcr & BCR_BLE) == 0) { fwupd_security_attr_set_result (attr, FWUPD_SECURITY_ATTR_RESULT_NOT_ENABLED); @@ -93,6 +91,10 @@ fu_plugin_add_security_attr_smm_bwp (FuPlugin *plugin, FuSecurityAttrs *attrs) FuPluginData *priv = fu_plugin_get_data (plugin); g_autoptr(FwupdSecurityAttr) attr = NULL; + /* no device */ + if (!priv->has_device) + return; + /* create attr */ attr = fwupd_security_attr_new (FWUPD_SECURITY_ATTR_ID_SPI_SMM_BWP); fwupd_security_attr_set_plugin (attr, fu_plugin_get_name (plugin)); @@ -100,12 +102,6 @@ fu_plugin_add_security_attr_smm_bwp (FuPlugin *plugin, FuSecurityAttrs *attrs) fwupd_security_attr_add_obsolete (attr, "linux_spi_lpc"); fu_security_attrs_append (attrs, attr); - /* no device */ - if (!priv->has_device) { - fwupd_security_attr_set_result (attr, FWUPD_SECURITY_ATTR_RESULT_NOT_FOUND); - return; - } - /* load file */ if ((priv->bcr & BCR_SMM_BWP) == 0) { fwupd_security_attr_set_result (attr, FWUPD_SECURITY_ATTR_RESULT_NOT_LOCKED); From de8d40d602de07cacfb91d59d0b135eebaba9da6 Mon Sep 17 00:00:00 2001 From: Richard Hughes Date: Mon, 18 May 2020 21:08:49 +0100 Subject: [PATCH 092/607] tpm-eventlog: Do not return a security attr if there is no TPM device There is literally no point in showing two TPM failures. --- plugins/tpm-eventlog/fu-plugin-tpm-eventlog.c | 37 ++++++++++++++++--- 1 file changed, 31 insertions(+), 6 deletions(-) diff --git a/plugins/tpm-eventlog/fu-plugin-tpm-eventlog.c b/plugins/tpm-eventlog/fu-plugin-tpm-eventlog.c index a4ae71f8f..e6e69577d 100644 --- a/plugins/tpm-eventlog/fu-plugin-tpm-eventlog.c +++ b/plugins/tpm-eventlog/fu-plugin-tpm-eventlog.c @@ -15,6 +15,7 @@ struct FuPluginData { GPtrArray *pcr0s; gboolean secure_boot_problem; + gboolean has_device; gboolean reconstructed; }; @@ -23,6 +24,7 @@ fu_plugin_init (FuPlugin *plugin) { fu_plugin_alloc_data (plugin, sizeof (FuPluginData)); fu_plugin_add_rule (plugin, FU_PLUGIN_RULE_RUN_BEFORE, "uefi"); + fu_plugin_add_rule (plugin, FU_PLUGIN_RULE_RUN_AFTER, "tpm"); fu_plugin_set_build_hash (plugin, FU_BUILD_HASH); } @@ -86,16 +88,19 @@ fu_plugin_coldplug (FuPlugin *plugin, GError **error) return TRUE; } -void -fu_plugin_device_registered (FuPlugin *plugin, FuDevice *device) +static void +fu_plugin_device_registered_tpm (FuPlugin *plugin, FuDevice *device) +{ + FuPluginData *data = fu_plugin_get_data (plugin); + data->has_device = TRUE; +} + +static void +fu_plugin_device_registered_uefi (FuPlugin *plugin, FuDevice *device) { FuPluginData *data = fu_plugin_get_data (plugin); GPtrArray *checksums; - /* only care about UEFI devices from ESRT */ - if (g_strcmp0 (fu_device_get_plugin (device), "uefi") != 0) - return; - /* only the system-firmware device gets checksums */ checksums = fu_device_get_checksums (device); if (checksums->len == 0) @@ -125,12 +130,32 @@ fu_plugin_device_registered (FuPlugin *plugin, FuDevice *device) "please see https://github.com/fwupd/fwupd/wiki/TPM-PCR0-differs-from-reconstruction"); } +void +fu_plugin_device_registered (FuPlugin *plugin, FuDevice *device) +{ + /* only care about UEFI devices from ESRT */ + if (g_strcmp0 (fu_device_get_plugin (device), "uefi") == 0) { + fu_plugin_device_registered_uefi (plugin, device); + return; + } + + /* detect the system TPM device */ + if (g_strcmp0 (fu_device_get_plugin (device), "tpm") == 0) { + fu_plugin_device_registered_tpm (plugin, device); + return; + } +} + void fu_plugin_add_security_attrs (FuPlugin *plugin, FuSecurityAttrs *attrs) { FuPluginData *data = fu_plugin_get_data (plugin); g_autoptr(FwupdSecurityAttr) attr = NULL; + /* no TPM device */ + if (!data->has_device) + return; + /* create attr */ attr = fwupd_security_attr_new (FWUPD_SECURITY_ATTR_ID_TPM_RECONSTRUCTION_PCR0); fwupd_security_attr_set_plugin (attr, fu_plugin_get_name (plugin)); From f6b48edebff00743ce7d6247241fd1a42851a813 Mon Sep 17 00:00:00 2001 From: Richard Hughes Date: Mon, 18 May 2020 21:32:06 +0100 Subject: [PATCH 093/607] pci-bcr: Read the ISA bridge BCR from the PCI device class The SPI controllers are always identified with one of two device classes. --- libfwupdplugin/fu-udev-device.c | 13 +++ plugins/pci-bcr/pci-bcr.quirk | 176 +------------------------------- 2 files changed, 15 insertions(+), 174 deletions(-) diff --git a/libfwupdplugin/fu-udev-device.c b/libfwupdplugin/fu-udev-device.c index 71b8dae0a..9c42b7735 100644 --- a/libfwupdplugin/fu-udev-device.c +++ b/libfwupdplugin/fu-udev-device.c @@ -322,6 +322,19 @@ fu_udev_device_probe (FuDevice *device, GError **error) FU_DEVICE_INSTANCE_FLAG_ONLY_QUIRKS); } + /* add device class */ + tmp = g_udev_device_get_sysfs_attr (priv->udev_device, "class"); + if (tmp != NULL && g_str_has_prefix (tmp, "0x")) { + g_autofree gchar *class_id = g_utf8_strup (tmp + 2, -1); + g_autofree gchar *devid = NULL; + devid = g_strdup_printf ("%s\\VEN_%04X&CLASS_%s", + subsystem, + priv->vendor, + class_id); + fu_device_add_instance_id_full (device, devid, + FU_DEVICE_INSTANCE_FLAG_ONLY_QUIRKS); + } + /* add subsystem to match in plugins */ if (subsystem != NULL) { fu_device_add_instance_id_full (device, subsystem, diff --git a/plugins/pci-bcr/pci-bcr.quirk b/plugins/pci-bcr/pci-bcr.quirk index d5afebf30..4ddb5007d 100644 --- a/plugins/pci-bcr/pci-bcr.quirk +++ b/plugins/pci-bcr/pci-bcr.quirk @@ -1,181 +1,9 @@ # ISA bridge i.e. 00:1F.0 # -> drivers/mfd/lpc_ich.c - -# Sunrise Point LPC/eSPI -[DeviceInstanceId=PCI\VEN_8086&DEV_9D4E] -Plugin = pci_bcr - -# Tiger Lake -[DeviceInstanceId=PCI\VEN_8086&DEV_A0A4] -Plugin = pci_bcr - -# Sunrise Point-H LPC -[DeviceInstanceId=PCI\VEN_8086&DEV_A140] -Plugin = pci_bcr - -# Sunrise Point-H LPC -[DeviceInstanceId=PCI\VEN_8086&DEV_A141] -Plugin = pci_bcr - -# Sunrise Point-H LPC -[DeviceInstanceId=PCI\VEN_8086&DEV_A142] -Plugin = pci_bcr - -# H110 LPC/eSPI -[DeviceInstanceId=PCI\VEN_8086&DEV_A143] -Plugin = pci_bcr - -# H170 LPC/eSPI -[DeviceInstanceId=PCI\VEN_8086&DEV_A144] -Plugin = pci_bcr - -# Z170 LPC/eSPI -[DeviceInstanceId=PCI\VEN_8086&DEV_A145] -Plugin = pci_bcr - -# Q170 LPC/eSPI -[DeviceInstanceId=PCI\VEN_8086&DEV_A146] -Plugin = pci_bcr - -# Q150 LPC/eSPI -[DeviceInstanceId=PCI\VEN_8086&DEV_A147] -Plugin = pci_bcr - -# B150 LPC/eSPI -[DeviceInstanceId=PCI\VEN_8086&DEV_A148] -Plugin = pci_bcr - -# C236 LPC/eSPI -[DeviceInstanceId=PCI\VEN_8086&DEV_A149] -Plugin = pci_bcr - -# C232 LPC/eSPI -[DeviceInstanceId=PCI\VEN_8086&DEV_A14A] -Plugin = pci_bcr - -# Sunrise Point-H LPC -[DeviceInstanceId=PCI\VEN_8086&DEV_A14B] -Plugin = pci_bcr - -# Sunrise Point-H LPC -[DeviceInstanceId=PCI\VEN_8086&DEV_A14C] -Plugin = pci_bcr - -# QM170 LPC/eSPI -[DeviceInstanceId=PCI\VEN_8086&DEV_A14D] -Plugin = pci_bcr - -# HM170 LPC/eSPI -[DeviceInstanceId=PCI\VEN_8086&DEV_A14E] -Plugin = pci_bcr - -# Sunrise Point-H LPC -[DeviceInstanceId=PCI\VEN_8086&DEV_A14F] -Plugin = pci_bcr - -# CM236 LPC/eSPI -[DeviceInstanceId=PCI\VEN_8086&DEV_A150] -Plugin = pci_bcr - -# Sunrise Point-H LPC -[DeviceInstanceId=PCI\VEN_8086&DEV_A151] -Plugin = pci_bcr - -# HM175 LPC/eSPI -[DeviceInstanceId=PCI\VEN_8086&DEV_A152] -Plugin = pci_bcr - -# QM175 LPC/eSPI -[DeviceInstanceId=PCI\VEN_8086&DEV_A153] -Plugin = pci_bcr - -# CM238 LPC/eSPI -[DeviceInstanceId=PCI\VEN_8086&DEV_A154] -Plugin = pci_bcr - -# Sunrise Point-H LPC -[DeviceInstanceId=PCI\VEN_8086&DEV_A155] -Plugin = pci_bcr - -# C621 LPC/eSPI -[DeviceInstanceId=PCI\VEN_8086&DEV_A1C1] -Plugin = pci_bcr - -# C622 LPC/eSPI -[DeviceInstanceId=PCI\VEN_8086&DEV_A1C2] -Plugin = pci_bcr - -# C624 LPC/eSPI -[DeviceInstanceId=PCI\VEN_8086&DEV_A1C3] -Plugin = pci_bcr - -# C625 LPC/eSPI -[DeviceInstanceId=PCI\VEN_8086&DEV_A1C4] -Plugin = pci_bcr - -# C626 LPC/eSPI -[DeviceInstanceId=PCI\VEN_8086&DEV_A1C5] -Plugin = pci_bcr - -# C627 LPC/eSPI -[DeviceInstanceId=PCI\VEN_8086&DEV_A1C6] -Plugin = pci_bcr - -# C628 LPC/eSPI -[DeviceInstanceId=PCI\VEN_8086&DEV_A1C7] -Plugin = pci_bcr - -# H370 LPC/eSPI -[DeviceInstanceId=PCI\VEN_8086&DEV_A304] -Plugin = pci_bcr - -# Z390 LPC/eSPI -[DeviceInstanceId=PCI\VEN_8086&DEV_A305] -Plugin = pci_bcr - -# Q370 LPC/eSPI -[DeviceInstanceId=PCI\VEN_8086&DEV_A306] -Plugin = pci_bcr - -# QM370 LPC/eSPI -[DeviceInstanceId=PCI\VEN_8086&DEV_A30C] +[DeviceInstanceId=PCI\VEN_8086&CLASS_060100] Plugin = pci_bcr # PCI devices, i.e. 00:1F.5 # -> drivers/mtd/spi-nor/controllers/intel-spi-pci.c - -# Comet Lake SPI -[DeviceInstanceId=PCI\VEN_8086&DEV_02A4] -Plugin = pci_bcr - -# Comet Lake H -[DeviceInstanceId=PCI\VEN_8086&DEV_06A4] -Plugin = pci_bcr - -# Ice Lake-LP SPI -[DeviceInstanceId=PCI\VEN_8086&DEV_34A4] -Plugin = pci_bcr - -# Elkhart Lake -[DeviceInstanceId=PCI\VEN_8086&DEV_4B24] -Plugin = pci_bcr - -# Jasper Lake -[DeviceInstanceId=PCI\VEN_8086&DEV_4DA4] -Plugin = pci_bcr - -# Cannon Point-LP SPI -[DeviceInstanceId=PCI\VEN_8086&DEV_9DA4] -Plugin = pci_bcr - -# C620 SPI -[DeviceInstanceId=PCI\VEN_8086&DEV_A1A4] -Plugin = pci_bcr - -# Cannon Lake PCH SPI -[DeviceInstanceId=PCI\VEN_8086&DEV_A324] -Plugin = pci_bcr - -# Comet Lake V -[DeviceInstanceId=PCI\VEN_8086&DEV_A3A4] +[DeviceInstanceId=PCI\VEN_8086&CLASS_0C8000] Plugin = pci_bcr From e36d3e3faa0f4c020ccd16f9957818b0e30f167d Mon Sep 17 00:00:00 2001 From: Mario Limonciello Date: Mon, 18 May 2020 21:52:30 -0500 Subject: [PATCH 094/607] trivial: fu-udev-device: create another instance ID for the driver --- libfwupdplugin/fu-udev-device.c | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/libfwupdplugin/fu-udev-device.c b/libfwupdplugin/fu-udev-device.c index 9c42b7735..66ce4f2bf 100644 --- a/libfwupdplugin/fu-udev-device.c +++ b/libfwupdplugin/fu-udev-device.c @@ -335,6 +335,17 @@ fu_udev_device_probe (FuDevice *device, GError **error) FU_DEVICE_INSTANCE_FLAG_ONLY_QUIRKS); } + /* add the driver */ + tmp = g_udev_device_get_driver (priv->udev_device); + if (tmp != NULL) { + g_autofree gchar *devid = NULL; + devid = g_strdup_printf ("%s\\DRIVER_%s", + subsystem, + tmp); + fu_device_add_instance_id_full (device, devid, + FU_DEVICE_INSTANCE_FLAG_ONLY_QUIRKS); + } + /* add subsystem to match in plugins */ if (subsystem != NULL) { fu_device_add_instance_id_full (device, subsystem, From 7c8e9cf316c0f29edb60e0be7f4784fcaa19d751 Mon Sep 17 00:00:00 2001 From: Mario Limonciello Date: Mon, 18 May 2020 21:52:58 -0500 Subject: [PATCH 095/607] trivial: pci-mei: use driver to detect which plugin to use instead of a list Let the kernel keep track of all the supported devices instead. --- plugins/pci-mei/pci-mei.quirk | 126 +--------------------------------- 1 file changed, 1 insertion(+), 125 deletions(-) diff --git a/plugins/pci-mei/pci-mei.quirk b/plugins/pci-mei/pci-mei.quirk index 5d834e5d2..4b9112cb4 100644 --- a/plugins/pci-mei/pci-mei.quirk +++ b/plugins/pci-mei/pci-mei.quirk @@ -1,126 +1,2 @@ -[DeviceInstanceId=PCI\VEN_8086&DEV_02E0] -Plugin = pci_mei -[DeviceInstanceId=PCI\VEN_8086&DEV_02E4] -Plugin = pci_mei -[DeviceInstanceId=PCI\VEN_8086&DEV_06E0] -Plugin = pci_mei -[DeviceInstanceId=PCI\VEN_8086&DEV_06E4] -Plugin = pci_mei -[DeviceInstanceId=PCI\VEN_8086&DEV_18D3] -Plugin = pci_mei -[DeviceInstanceId=PCI\VEN_8086&DEV_19E5] -Plugin = pci_mei -[DeviceInstanceId=PCI\VEN_8086&DEV_1A9A] -Plugin = pci_mei -[DeviceInstanceId=PCI\VEN_8086&DEV_1C3A] -Plugin = pci_mei -[DeviceInstanceId=PCI\VEN_8086&DEV_1CBA] -Plugin = pci_mei -[DeviceInstanceId=PCI\VEN_8086&DEV_1D3A] -Plugin = pci_mei -[DeviceInstanceId=PCI\VEN_8086&DEV_1DBA] -Plugin = pci_mei -[DeviceInstanceId=PCI\VEN_8086&DEV_1E3A] -Plugin = pci_mei -[DeviceInstanceId=PCI\VEN_8086&DEV_28B4] -Plugin = pci_mei -[DeviceInstanceId=PCI\VEN_8086&DEV_28C4] -Plugin = pci_mei -[DeviceInstanceId=PCI\VEN_8086&DEV_28D4] -Plugin = pci_mei -[DeviceInstanceId=PCI\VEN_8086&DEV_28E4] -Plugin = pci_mei -[DeviceInstanceId=PCI\VEN_8086&DEV_28F4] -Plugin = pci_mei -[DeviceInstanceId=PCI\VEN_8086&DEV_2974] -Plugin = pci_mei -[DeviceInstanceId=PCI\VEN_8086&DEV_2984] -Plugin = pci_mei -[DeviceInstanceId=PCI\VEN_8086&DEV_2994] -Plugin = pci_mei -[DeviceInstanceId=PCI\VEN_8086&DEV_29A4] -Plugin = pci_mei -[DeviceInstanceId=PCI\VEN_8086&DEV_29B4] -Plugin = pci_mei -[DeviceInstanceId=PCI\VEN_8086&DEV_29C4] -Plugin = pci_mei -[DeviceInstanceId=PCI\VEN_8086&DEV_29D4] -Plugin = pci_mei -[DeviceInstanceId=PCI\VEN_8086&DEV_29E4] -Plugin = pci_mei -[DeviceInstanceId=PCI\VEN_8086&DEV_29F4] -Plugin = pci_mei -[DeviceInstanceId=PCI\VEN_8086&DEV_2A04] -Plugin = pci_mei -[DeviceInstanceId=PCI\VEN_8086&DEV_2A14] -Plugin = pci_mei -[DeviceInstanceId=PCI\VEN_8086&DEV_2A44] -Plugin = pci_mei -[DeviceInstanceId=PCI\VEN_8086&DEV_2A54] -Plugin = pci_mei -[DeviceInstanceId=PCI\VEN_8086&DEV_2A64] -Plugin = pci_mei -[DeviceInstanceId=PCI\VEN_8086&DEV_2A74] -Plugin = pci_mei -[DeviceInstanceId=PCI\VEN_8086&DEV_2E04] -Plugin = pci_mei -[DeviceInstanceId=PCI\VEN_8086&DEV_2E14] -Plugin = pci_mei -[DeviceInstanceId=PCI\VEN_8086&DEV_2E24] -Plugin = pci_mei -[DeviceInstanceId=PCI\VEN_8086&DEV_2E34] -Plugin = pci_mei -[DeviceInstanceId=PCI\VEN_8086&DEV_319A] -Plugin = pci_mei -[DeviceInstanceId=PCI\VEN_8086&DEV_34E0] -Plugin = pci_mei -[DeviceInstanceId=PCI\VEN_8086&DEV_3B64] -Plugin = pci_mei -[DeviceInstanceId=PCI\VEN_8086&DEV_3B65] -Plugin = pci_mei -[DeviceInstanceId=PCI\VEN_8086&DEV_4B70] -Plugin = pci_mei -[DeviceInstanceId=PCI\VEN_8086&DEV_4B75] -Plugin = pci_mei -[DeviceInstanceId=PCI\VEN_8086&DEV_4DE0] -Plugin = pci_mei -[DeviceInstanceId=PCI\VEN_8086&DEV_5A9A] -Plugin = pci_mei -[DeviceInstanceId=PCI\VEN_8086&DEV_8C3A] -Plugin = pci_mei -[DeviceInstanceId=PCI\VEN_8086&DEV_8CBA] -Plugin = pci_mei -[DeviceInstanceId=PCI\VEN_8086&DEV_8D3A] -Plugin = pci_mei -[DeviceInstanceId=PCI\VEN_8086&DEV_9C3A] -Plugin = pci_mei -[DeviceInstanceId=PCI\VEN_8086&DEV_9CBA] -Plugin = pci_mei -[DeviceInstanceId=PCI\VEN_8086&DEV_9CBB] -Plugin = pci_mei -[DeviceInstanceId=PCI\VEN_8086&DEV_9D3A] -Plugin = pci_mei -[DeviceInstanceId=PCI\VEN_8086&DEV_9D3B] -Plugin = pci_mei -[DeviceInstanceId=PCI\VEN_8086&DEV_9DE0] -Plugin = pci_mei -[DeviceInstanceId=PCI\VEN_8086&DEV_9DE4] -Plugin = pci_mei -[DeviceInstanceId=PCI\VEN_8086&DEV_A0E0] -Plugin = pci_mei -[DeviceInstanceId=PCI\VEN_8086&DEV_A13A] -Plugin = pci_mei -[DeviceInstanceId=PCI\VEN_8086&DEV_A13B] -Plugin = pci_mei -[DeviceInstanceId=PCI\VEN_8086&DEV_A1BA] -Plugin = pci_mei -[DeviceInstanceId=PCI\VEN_8086&DEV_A2BA] -Plugin = pci_mei -[DeviceInstanceId=PCI\VEN_8086&DEV_A2BB] -Plugin = pci_mei -[DeviceInstanceId=PCI\VEN_8086&DEV_A360] -Plugin = pci_mei -[DeviceInstanceId=PCI\VEN_8086&DEV_A364] -Plugin = pci_mei -[DeviceInstanceId=PCI\VEN_8086&DEV_A3BA] +[DeviceInstanceId=PCI\DRIVER_mei_me] Plugin = pci_mei From 0a11350396df38b98ac3e0bc854fea3d4a1d7918 Mon Sep 17 00:00:00 2001 From: Vincent Huang Date: Tue, 19 May 2020 13:09:28 +0800 Subject: [PATCH 096/607] synaptics-prometheus: Force the minor version from 0x02 to 0x01 to make sure the devices can be updated back to 0x01. --- plugins/synaptics-prometheus/fu-synaprom-device.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/plugins/synaptics-prometheus/fu-synaprom-device.c b/plugins/synaptics-prometheus/fu-synaprom-device.c index 5a19203cf..299ebde27 100644 --- a/plugins/synaptics-prometheus/fu-synaprom-device.c +++ b/plugins/synaptics-prometheus/fu-synaprom-device.c @@ -142,6 +142,14 @@ fu_synaprom_device_set_version (FuSynapromDevice *self, { g_autofree gchar *str = NULL; + /* We decide to skip 10.02.xxxxxx firmware, so we force the minor version from 0x02 + ** to 0x01 to make the devices with 0x02 minor version firmware allow to be updated + ** back to minor version 0x01. */ + if (vmajor == 0x0a && vminor == 0x02) { + g_debug ("quirking vminor from %02x to 01", vminor); + vminor = 0x01; + } + /* set display version */ str = g_strdup_printf ("%02u.%02u.%u", vmajor, vminor, buildnum); fu_device_set_version (FU_DEVICE (self), str); From 81c371098cdca1e56b3e39cbe7d6032d477a9314 Mon Sep 17 00:00:00 2001 From: Richard Hughes Date: Tue, 19 May 2020 14:01:49 +0100 Subject: [PATCH 097/607] Export the host vendor, family and SKU The 'product name' is not typically what the hardware is known as. We need the vendor, family and SKU if the user is going to recognise the hardware. --- libfwupd/fwupd-client.c | 159 ++++++++++++++++++++++++++++++++++ libfwupd/fwupd-client.h | 3 + libfwupd/fwupd.map | 3 + src/fu-engine.c | 27 ++++++ src/fu-engine.h | 7 +- src/fu-main.c | 9 ++ src/org.freedesktop.fwupd.xml | 33 +++++++ 7 files changed, 239 insertions(+), 2 deletions(-) diff --git a/libfwupd/fwupd-client.c b/libfwupd/fwupd-client.c index bfa0403e0..5736923f1 100644 --- a/libfwupd/fwupd-client.c +++ b/libfwupd/fwupd-client.c @@ -45,6 +45,9 @@ typedef struct { guint percentage; gchar *daemon_version; gchar *host_product; + gchar *host_family; + gchar *host_sku; + gchar *host_vendor; gchar *host_machine_id; gchar *host_security_id; GDBusConnection *conn; @@ -67,6 +70,9 @@ enum { PROP_DAEMON_VERSION, PROP_TAINTED, PROP_HOST_PRODUCT, + PROP_HOST_FAMILY, + PROP_HOST_SKU, + PROP_HOST_VENDOR, PROP_HOST_MACHINE_ID, PROP_HOST_SECURITY_ID, PROP_INTERACTIVE, @@ -122,6 +128,33 @@ fwupd_client_set_host_product (FwupdClient *client, const gchar *host_product) g_object_notify (G_OBJECT (client), "host-product"); } +static void +fwupd_client_set_host_family (FwupdClient *client, const gchar *host_family) +{ + FwupdClientPrivate *priv = GET_PRIVATE (client); + g_free (priv->host_family); + priv->host_family = g_strdup (host_family); + g_object_notify (G_OBJECT (client), "host-family"); +} + +static void +fwupd_client_set_host_sku (FwupdClient *client, const gchar *host_sku) +{ + FwupdClientPrivate *priv = GET_PRIVATE (client); + g_free (priv->host_sku); + priv->host_sku = g_strdup (host_sku); + g_object_notify (G_OBJECT (client), "host-sku"); +} + +static void +fwupd_client_set_host_vendor (FwupdClient *client, const gchar *host_vendor) +{ + FwupdClientPrivate *priv = GET_PRIVATE (client); + g_free (priv->host_vendor); + priv->host_vendor = g_strdup (host_vendor); + g_object_notify (G_OBJECT (client), "host-vendor"); +} + static void fwupd_client_set_host_machine_id (FwupdClient *client, const gchar *host_machine_id) { @@ -207,6 +240,24 @@ fwupd_client_properties_changed_cb (GDBusProxy *proxy, if (val != NULL) fwupd_client_set_host_product (client, g_variant_get_string (val, NULL)); } + if (g_variant_dict_contains (dict, "HostFamily")) { + g_autoptr(GVariant) val = NULL; + val = g_dbus_proxy_get_cached_property (proxy, "HostFamily"); + if (val != NULL) + fwupd_client_set_host_family (client, g_variant_get_string (val, NULL)); + } + if (g_variant_dict_contains (dict, "HostSku")) { + g_autoptr(GVariant) val = NULL; + val = g_dbus_proxy_get_cached_property (proxy, "HostSku"); + if (val != NULL) + fwupd_client_set_host_sku (client, g_variant_get_string (val, NULL)); + } + if (g_variant_dict_contains (dict, "HostVendor")) { + g_autoptr(GVariant) val = NULL; + val = g_dbus_proxy_get_cached_property (proxy, "HostVendor"); + if (val != NULL) + fwupd_client_set_host_vendor (client, g_variant_get_string (val, NULL)); + } if (g_variant_dict_contains (dict, "HostMachineId")) { g_autoptr(GVariant) val = NULL; val = g_dbus_proxy_get_cached_property (proxy, "HostMachineId"); @@ -319,6 +370,15 @@ fwupd_client_connect (FwupdClient *client, GCancellable *cancellable, GError **e val = g_dbus_proxy_get_cached_property (priv->proxy, "HostProduct"); if (val != NULL) fwupd_client_set_host_product (client, g_variant_get_string (val, NULL)); + val = g_dbus_proxy_get_cached_property (priv->proxy, "HostFamily"); + if (val != NULL) + fwupd_client_set_host_family (client, g_variant_get_string (val, NULL)); + val = g_dbus_proxy_get_cached_property (priv->proxy, "HostSku"); + if (val != NULL) + fwupd_client_set_host_sku (client, g_variant_get_string (val, NULL)); + val = g_dbus_proxy_get_cached_property (priv->proxy, "HostVendor"); + if (val != NULL) + fwupd_client_set_host_vendor (client, g_variant_get_string (val, NULL)); val = g_dbus_proxy_get_cached_property (priv->proxy, "HostMachineId"); if (val != NULL) fwupd_client_set_host_machine_id (client, g_variant_get_string (val, NULL)); @@ -1359,6 +1419,60 @@ fwupd_client_get_host_product (FwupdClient *client) return priv->host_product; } +/** + * fwupd_client_get_host_family: + * @client: A #FwupdClient + * + * Gets the string that represents the host running fwupd + * + * Returns: a string, or %NULL for unknown. + * + * Since: 1.5.0 + **/ +const gchar * +fwupd_client_get_host_family (FwupdClient *client) +{ + FwupdClientPrivate *priv = GET_PRIVATE (client); + g_return_val_if_fail (FWUPD_IS_CLIENT (client), NULL); + return priv->host_family; +} + +/** + * fwupd_client_get_host_sku: + * @client: A #FwupdClient + * + * Gets the string that represents the host running fwupd + * + * Returns: a string, or %NULL for unknown. + * + * Since: 1.5.0 + **/ +const gchar * +fwupd_client_get_host_sku (FwupdClient *client) +{ + FwupdClientPrivate *priv = GET_PRIVATE (client); + g_return_val_if_fail (FWUPD_IS_CLIENT (client), NULL); + return priv->host_sku; +} + +/** + * fwupd_client_get_host_vendor: + * @client: A #FwupdClient + * + * Gets the string that represents the host running fwupd + * + * Returns: a string, or %NULL for unknown. + * + * Since: 1.5.0 + **/ +const gchar * +fwupd_client_get_host_vendor (FwupdClient *client) +{ + FwupdClientPrivate *priv = GET_PRIVATE (client); + g_return_val_if_fail (FWUPD_IS_CLIENT (client), NULL); + return priv->host_vendor; +} + /** * fwupd_client_get_host_machine_id: * @client: A #FwupdClient @@ -1947,6 +2061,15 @@ fwupd_client_get_property (GObject *object, guint prop_id, case PROP_HOST_PRODUCT: g_value_set_string (value, priv->host_product); break; + case PROP_HOST_FAMILY: + g_value_set_string (value, priv->host_family); + break; + case PROP_HOST_SKU: + g_value_set_string (value, priv->host_sku); + break; + case PROP_HOST_VENDOR: + g_value_set_string (value, priv->host_vendor); + break; case PROP_HOST_MACHINE_ID: g_value_set_string (value, priv->host_machine_id); break; @@ -2143,6 +2266,39 @@ fwupd_client_class_init (FwupdClientClass *klass) NULL, G_PARAM_READABLE | G_PARAM_STATIC_NAME); g_object_class_install_property (object_class, PROP_HOST_PRODUCT, pspec); + /** + * FwupdClient:host-family: + * + * The host family string, e.g. "ThinkPad P50" + * + * Since: 1.5.0 + */ + pspec = g_param_spec_string ("host-family", NULL, NULL, + NULL, G_PARAM_READABLE | G_PARAM_STATIC_NAME); + g_object_class_install_property (object_class, PROP_HOST_FAMILY, pspec); + + /** + * FwupdClient:host-sku: + * + * The host SKU string, e.g. "ABC12345" + * + * Since: 1.5.0 + */ + pspec = g_param_spec_string ("host-sku", NULL, NULL, + NULL, G_PARAM_READABLE | G_PARAM_STATIC_NAME); + g_object_class_install_property (object_class, PROP_HOST_SKU, pspec); + + /** + * FwupdClient:host-vendor: + * + * The host vendor string, e.g. "Lenovo" + * + * Since: 1.5.0 + */ + pspec = g_param_spec_string ("host-vendor", NULL, NULL, + NULL, G_PARAM_READABLE | G_PARAM_STATIC_NAME); + g_object_class_install_property (object_class, PROP_HOST_VENDOR, pspec); + /** * FwupdClient:host-machine-id: * @@ -2179,6 +2335,9 @@ fwupd_client_finalize (GObject *object) g_free (priv->daemon_version); g_free (priv->host_product); + g_free (priv->host_family); + g_free (priv->host_sku); + g_free (priv->host_vendor); g_free (priv->host_machine_id); g_free (priv->host_security_id); if (priv->conn != NULL) diff --git a/libfwupd/fwupd-client.h b/libfwupd/fwupd-client.h index 077e22092..05e993581 100644 --- a/libfwupd/fwupd-client.h +++ b/libfwupd/fwupd-client.h @@ -136,6 +136,9 @@ gboolean fwupd_client_get_daemon_interactive (FwupdClient *client); guint fwupd_client_get_percentage (FwupdClient *client); const gchar *fwupd_client_get_daemon_version (FwupdClient *client); const gchar *fwupd_client_get_host_product (FwupdClient *client); +const gchar *fwupd_client_get_host_family (FwupdClient *client); +const gchar *fwupd_client_get_host_sku (FwupdClient *client); +const gchar *fwupd_client_get_host_vendor (FwupdClient *client); const gchar *fwupd_client_get_host_machine_id (FwupdClient *client); const gchar *fwupd_client_get_host_security_id (FwupdClient *client); diff --git a/libfwupd/fwupd.map b/libfwupd/fwupd.map index 3a3bf6402..fd8367b9f 100644 --- a/libfwupd/fwupd.map +++ b/libfwupd/fwupd.map @@ -449,8 +449,11 @@ LIBFWUPD_1.4.1 { LIBFWUPD_1.5.0 { global: + fwupd_client_get_host_family; fwupd_client_get_host_security_attrs; fwupd_client_get_host_security_id; + fwupd_client_get_host_sku; + fwupd_client_get_host_vendor; fwupd_security_attr_add_flag; fwupd_security_attr_add_obsolete; fwupd_security_attr_array_from_variant; diff --git a/src/fu-engine.c b/src/fu-engine.c index 01ec50b12..c9f5798bb 100644 --- a/src/fu-engine.c +++ b/src/fu-engine.c @@ -5060,6 +5060,33 @@ fu_engine_get_host_product (FuEngine *self) return result != NULL ? result : "Unknown Product"; } +const gchar * +fu_engine_get_host_family (FuEngine *self) +{ + const gchar *result = NULL; + g_return_val_if_fail (FU_IS_ENGINE (self), NULL); + result = fu_hwids_get_value (self->hwids, FU_HWIDS_KEY_FAMILY); + return result != NULL ? result : "Unknown"; +} + +const gchar * +fu_engine_get_host_sku (FuEngine *self) +{ + const gchar *result = NULL; + g_return_val_if_fail (FU_IS_ENGINE (self), NULL); + result = fu_hwids_get_value (self->hwids, FU_HWIDS_KEY_PRODUCT_SKU); + return result != NULL ? result : "Unknown"; +} + +const gchar * +fu_engine_get_host_vendor (FuEngine *self) +{ + const gchar *result = NULL; + g_return_val_if_fail (FU_IS_ENGINE (self), NULL); + result = fu_hwids_get_value (self->hwids, FU_HWIDS_KEY_MANUFACTURER); + return result != NULL ? result : "Unknown"; +} + const gchar * fu_engine_get_host_machine_id (FuEngine *self) { diff --git a/src/fu-engine.h b/src/fu-engine.h index 5f9a376fc..94ac2741d 100644 --- a/src/fu-engine.h +++ b/src/fu-engine.h @@ -48,8 +48,11 @@ gboolean fu_engine_load (FuEngine *self, gboolean fu_engine_load_plugins (FuEngine *self, GError **error); gboolean fu_engine_get_tainted (FuEngine *self); -const gchar *fu_engine_get_host_product (FuEngine *self); -const gchar *fu_engine_get_host_machine_id (FuEngine *self); +const gchar *fu_engine_get_host_product (FuEngine *self); +const gchar *fu_engine_get_host_family (FuEngine *self); +const gchar *fu_engine_get_host_sku (FuEngine *self); +const gchar *fu_engine_get_host_vendor (FuEngine *self); +const gchar *fu_engine_get_host_machine_id (FuEngine *self); const gchar *fu_engine_get_host_security_id (FuEngine *self); FwupdStatus fu_engine_get_status (FuEngine *self); XbSilo *fu_engine_get_silo_from_blob (FuEngine *self, diff --git a/src/fu-main.c b/src/fu-main.c index 97636f93b..0fb6f64ae 100644 --- a/src/fu-main.c +++ b/src/fu-main.c @@ -1395,6 +1395,15 @@ fu_main_daemon_get_property (GDBusConnection *connection_, const gchar *sender, if (g_strcmp0 (property_name, "HostProduct") == 0) return g_variant_new_string (fu_engine_get_host_product (priv->engine)); + if (g_strcmp0 (property_name, "HostFamily") == 0) + return g_variant_new_string (fu_engine_get_host_family (priv->engine)); + + if (g_strcmp0 (property_name, "HostSku") == 0) + return g_variant_new_string (fu_engine_get_host_sku (priv->engine)); + + if (g_strcmp0 (property_name, "HostVendor") == 0) + return g_variant_new_string (fu_engine_get_host_vendor (priv->engine)); + if (g_strcmp0 (property_name, "HostMachineId") == 0) return g_variant_new_string (fu_engine_get_host_machine_id (priv->engine)); diff --git a/src/org.freedesktop.fwupd.xml b/src/org.freedesktop.fwupd.xml index ea33f626f..a24fae9a7 100644 --- a/src/org.freedesktop.fwupd.xml +++ b/src/org.freedesktop.fwupd.xml @@ -33,6 +33,39 @@ + + + + + + The product family string for the host. + + + + + + + + + + + The product SKU string for the host. + + + + + + + + + + + The product vendor string for the host. + + + + + From b05f2d60c52a399799014290ba19561db08003cf Mon Sep 17 00:00:00 2001 From: Richard Hughes Date: Tue, 19 May 2020 20:09:27 +0100 Subject: [PATCH 098/607] trivial: Fix up the NOT_VALID translated string --- src/fu-security-attr.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/fu-security-attr.c b/src/fu-security-attr.c index 61dd52be0..8b13c2135 100644 --- a/src/fu-security-attr.c +++ b/src/fu-security-attr.c @@ -112,7 +112,7 @@ fu_security_attr_get_result (FwupdSecurityAttr *attr) } if (result == FWUPD_SECURITY_ATTR_RESULT_NOT_VALID) { /* TRANSLATORS: Suffix: the HSI result */ - return _("Not Valid"); + return _("Invalid"); } if (result == FWUPD_SECURITY_ATTR_RESULT_ENABLED) { /* TRANSLATORS: Suffix: the HSI result */ From c11bed40796a7489ec8a663bf8499ebb5e307dea Mon Sep 17 00:00:00 2001 From: Richard Hughes Date: Tue, 19 May 2020 20:10:45 +0100 Subject: [PATCH 099/607] trivial: Fix the HSI warnings after some translator feedback. --- src/fu-util-common.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/fu-util-common.c b/src/fu-util-common.c index 7878c21fd..a2ceca81c 100644 --- a/src/fu-util-common.c +++ b/src/fu-util-common.c @@ -1633,15 +1633,15 @@ fu_util_security_attrs_to_string (GPtrArray *attrs) } if (low_help) { - g_string_append_printf (str, "\n%s %s", + g_string_append_printf (str, "\n%s\n » %s\n", /* TRANSLATORS: this is instructions on how to improve the HSI security level */ - _("Your system has a low HSI security level. Visit this URL for more information: "), + _("This system has a low HSI security level."), "https://github.com/fwupd/fwupd/wiki/Low-host-security-level"); } if (runtime_help) { - g_string_append_printf (str, "\n%s %s", + g_string_append_printf (str, "\n%s\n » %s\n", /* TRANSLATORS: this is instructions on how to improve the HSI suffix */ - _("Your system has runtime issues. Visit this URL for more information: "), + _("This system has HSI runtime issues."), "https://github.com/fwupd/fwupd/wiki/Host-security-ID-runtime-issues"); } From e56fe2a0ca8e2a79f52c965389950d3ee30f4815 Mon Sep 17 00:00:00 2001 From: Richard Hughes Date: Tue, 19 May 2020 20:13:26 +0100 Subject: [PATCH 100/607] trivial: Fix fu_efivar_set_data() gtk-doc header --- libfwupdplugin/fu-efivar.c | 1 - 1 file changed, 1 deletion(-) diff --git a/libfwupdplugin/fu-efivar.c b/libfwupdplugin/fu-efivar.c index c27954477..7579b383a 100644 --- a/libfwupdplugin/fu-efivar.c +++ b/libfwupdplugin/fu-efivar.c @@ -411,7 +411,6 @@ fu_efivar_set_data (const gchar *guid, const gchar *name, const guint8 *data, /** * fu_efivar_secure_boot_enabled: - * @error: #GError * * Determines if secure boot was enabled * From 3ecd22c764db45f796bfa89b37745e52f39dbc08 Mon Sep 17 00:00:00 2001 From: Richard Hughes Date: Tue, 19 May 2020 20:13:47 +0100 Subject: [PATCH 101/607] trivial: Fix fu_plugin_runner_add_security_attrs() gtk-doc header --- libfwupdplugin/fu-plugin.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/libfwupdplugin/fu-plugin.c b/libfwupdplugin/fu-plugin.c index 75c199b55..4ba255bde 100644 --- a/libfwupdplugin/fu-plugin.c +++ b/libfwupdplugin/fu-plugin.c @@ -1600,9 +1600,9 @@ fu_plugin_runner_update_reload (FuPlugin *self, FuDevice *device, GError **error /** * fu_plugin_runner_add_security_attrs: * @self: a #FuPlugin - * @attrs: (element-type FwupdSecurityAttr): a #GPtrArray of attributes + * @attrs: a #FuSecurityAttrs * - * Runs the add_security_attrs routine for the plugin + * Runs the `add_security_attrs()` routine for the plugin * * Since: 1.5.0 **/ From 0c6efe2e042d76ec646032edc7a27f98311bfe2a Mon Sep 17 00:00:00 2001 From: Richard Hughes Date: Wed, 20 May 2020 18:31:48 +0100 Subject: [PATCH 102/607] Revert "Export the host vendor, family and SKU" This reverts commit 81c371098cdca1e56b3e39cbe7d6032d477a9314. --- libfwupd/fwupd-client.c | 159 ---------------------------------- libfwupd/fwupd-client.h | 3 - libfwupd/fwupd.map | 3 - src/fu-engine.c | 27 ------ src/fu-engine.h | 7 +- src/fu-main.c | 9 -- src/org.freedesktop.fwupd.xml | 33 ------- 7 files changed, 2 insertions(+), 239 deletions(-) diff --git a/libfwupd/fwupd-client.c b/libfwupd/fwupd-client.c index 5736923f1..bfa0403e0 100644 --- a/libfwupd/fwupd-client.c +++ b/libfwupd/fwupd-client.c @@ -45,9 +45,6 @@ typedef struct { guint percentage; gchar *daemon_version; gchar *host_product; - gchar *host_family; - gchar *host_sku; - gchar *host_vendor; gchar *host_machine_id; gchar *host_security_id; GDBusConnection *conn; @@ -70,9 +67,6 @@ enum { PROP_DAEMON_VERSION, PROP_TAINTED, PROP_HOST_PRODUCT, - PROP_HOST_FAMILY, - PROP_HOST_SKU, - PROP_HOST_VENDOR, PROP_HOST_MACHINE_ID, PROP_HOST_SECURITY_ID, PROP_INTERACTIVE, @@ -128,33 +122,6 @@ fwupd_client_set_host_product (FwupdClient *client, const gchar *host_product) g_object_notify (G_OBJECT (client), "host-product"); } -static void -fwupd_client_set_host_family (FwupdClient *client, const gchar *host_family) -{ - FwupdClientPrivate *priv = GET_PRIVATE (client); - g_free (priv->host_family); - priv->host_family = g_strdup (host_family); - g_object_notify (G_OBJECT (client), "host-family"); -} - -static void -fwupd_client_set_host_sku (FwupdClient *client, const gchar *host_sku) -{ - FwupdClientPrivate *priv = GET_PRIVATE (client); - g_free (priv->host_sku); - priv->host_sku = g_strdup (host_sku); - g_object_notify (G_OBJECT (client), "host-sku"); -} - -static void -fwupd_client_set_host_vendor (FwupdClient *client, const gchar *host_vendor) -{ - FwupdClientPrivate *priv = GET_PRIVATE (client); - g_free (priv->host_vendor); - priv->host_vendor = g_strdup (host_vendor); - g_object_notify (G_OBJECT (client), "host-vendor"); -} - static void fwupd_client_set_host_machine_id (FwupdClient *client, const gchar *host_machine_id) { @@ -240,24 +207,6 @@ fwupd_client_properties_changed_cb (GDBusProxy *proxy, if (val != NULL) fwupd_client_set_host_product (client, g_variant_get_string (val, NULL)); } - if (g_variant_dict_contains (dict, "HostFamily")) { - g_autoptr(GVariant) val = NULL; - val = g_dbus_proxy_get_cached_property (proxy, "HostFamily"); - if (val != NULL) - fwupd_client_set_host_family (client, g_variant_get_string (val, NULL)); - } - if (g_variant_dict_contains (dict, "HostSku")) { - g_autoptr(GVariant) val = NULL; - val = g_dbus_proxy_get_cached_property (proxy, "HostSku"); - if (val != NULL) - fwupd_client_set_host_sku (client, g_variant_get_string (val, NULL)); - } - if (g_variant_dict_contains (dict, "HostVendor")) { - g_autoptr(GVariant) val = NULL; - val = g_dbus_proxy_get_cached_property (proxy, "HostVendor"); - if (val != NULL) - fwupd_client_set_host_vendor (client, g_variant_get_string (val, NULL)); - } if (g_variant_dict_contains (dict, "HostMachineId")) { g_autoptr(GVariant) val = NULL; val = g_dbus_proxy_get_cached_property (proxy, "HostMachineId"); @@ -370,15 +319,6 @@ fwupd_client_connect (FwupdClient *client, GCancellable *cancellable, GError **e val = g_dbus_proxy_get_cached_property (priv->proxy, "HostProduct"); if (val != NULL) fwupd_client_set_host_product (client, g_variant_get_string (val, NULL)); - val = g_dbus_proxy_get_cached_property (priv->proxy, "HostFamily"); - if (val != NULL) - fwupd_client_set_host_family (client, g_variant_get_string (val, NULL)); - val = g_dbus_proxy_get_cached_property (priv->proxy, "HostSku"); - if (val != NULL) - fwupd_client_set_host_sku (client, g_variant_get_string (val, NULL)); - val = g_dbus_proxy_get_cached_property (priv->proxy, "HostVendor"); - if (val != NULL) - fwupd_client_set_host_vendor (client, g_variant_get_string (val, NULL)); val = g_dbus_proxy_get_cached_property (priv->proxy, "HostMachineId"); if (val != NULL) fwupd_client_set_host_machine_id (client, g_variant_get_string (val, NULL)); @@ -1419,60 +1359,6 @@ fwupd_client_get_host_product (FwupdClient *client) return priv->host_product; } -/** - * fwupd_client_get_host_family: - * @client: A #FwupdClient - * - * Gets the string that represents the host running fwupd - * - * Returns: a string, or %NULL for unknown. - * - * Since: 1.5.0 - **/ -const gchar * -fwupd_client_get_host_family (FwupdClient *client) -{ - FwupdClientPrivate *priv = GET_PRIVATE (client); - g_return_val_if_fail (FWUPD_IS_CLIENT (client), NULL); - return priv->host_family; -} - -/** - * fwupd_client_get_host_sku: - * @client: A #FwupdClient - * - * Gets the string that represents the host running fwupd - * - * Returns: a string, or %NULL for unknown. - * - * Since: 1.5.0 - **/ -const gchar * -fwupd_client_get_host_sku (FwupdClient *client) -{ - FwupdClientPrivate *priv = GET_PRIVATE (client); - g_return_val_if_fail (FWUPD_IS_CLIENT (client), NULL); - return priv->host_sku; -} - -/** - * fwupd_client_get_host_vendor: - * @client: A #FwupdClient - * - * Gets the string that represents the host running fwupd - * - * Returns: a string, or %NULL for unknown. - * - * Since: 1.5.0 - **/ -const gchar * -fwupd_client_get_host_vendor (FwupdClient *client) -{ - FwupdClientPrivate *priv = GET_PRIVATE (client); - g_return_val_if_fail (FWUPD_IS_CLIENT (client), NULL); - return priv->host_vendor; -} - /** * fwupd_client_get_host_machine_id: * @client: A #FwupdClient @@ -2061,15 +1947,6 @@ fwupd_client_get_property (GObject *object, guint prop_id, case PROP_HOST_PRODUCT: g_value_set_string (value, priv->host_product); break; - case PROP_HOST_FAMILY: - g_value_set_string (value, priv->host_family); - break; - case PROP_HOST_SKU: - g_value_set_string (value, priv->host_sku); - break; - case PROP_HOST_VENDOR: - g_value_set_string (value, priv->host_vendor); - break; case PROP_HOST_MACHINE_ID: g_value_set_string (value, priv->host_machine_id); break; @@ -2266,39 +2143,6 @@ fwupd_client_class_init (FwupdClientClass *klass) NULL, G_PARAM_READABLE | G_PARAM_STATIC_NAME); g_object_class_install_property (object_class, PROP_HOST_PRODUCT, pspec); - /** - * FwupdClient:host-family: - * - * The host family string, e.g. "ThinkPad P50" - * - * Since: 1.5.0 - */ - pspec = g_param_spec_string ("host-family", NULL, NULL, - NULL, G_PARAM_READABLE | G_PARAM_STATIC_NAME); - g_object_class_install_property (object_class, PROP_HOST_FAMILY, pspec); - - /** - * FwupdClient:host-sku: - * - * The host SKU string, e.g. "ABC12345" - * - * Since: 1.5.0 - */ - pspec = g_param_spec_string ("host-sku", NULL, NULL, - NULL, G_PARAM_READABLE | G_PARAM_STATIC_NAME); - g_object_class_install_property (object_class, PROP_HOST_SKU, pspec); - - /** - * FwupdClient:host-vendor: - * - * The host vendor string, e.g. "Lenovo" - * - * Since: 1.5.0 - */ - pspec = g_param_spec_string ("host-vendor", NULL, NULL, - NULL, G_PARAM_READABLE | G_PARAM_STATIC_NAME); - g_object_class_install_property (object_class, PROP_HOST_VENDOR, pspec); - /** * FwupdClient:host-machine-id: * @@ -2335,9 +2179,6 @@ fwupd_client_finalize (GObject *object) g_free (priv->daemon_version); g_free (priv->host_product); - g_free (priv->host_family); - g_free (priv->host_sku); - g_free (priv->host_vendor); g_free (priv->host_machine_id); g_free (priv->host_security_id); if (priv->conn != NULL) diff --git a/libfwupd/fwupd-client.h b/libfwupd/fwupd-client.h index 05e993581..077e22092 100644 --- a/libfwupd/fwupd-client.h +++ b/libfwupd/fwupd-client.h @@ -136,9 +136,6 @@ gboolean fwupd_client_get_daemon_interactive (FwupdClient *client); guint fwupd_client_get_percentage (FwupdClient *client); const gchar *fwupd_client_get_daemon_version (FwupdClient *client); const gchar *fwupd_client_get_host_product (FwupdClient *client); -const gchar *fwupd_client_get_host_family (FwupdClient *client); -const gchar *fwupd_client_get_host_sku (FwupdClient *client); -const gchar *fwupd_client_get_host_vendor (FwupdClient *client); const gchar *fwupd_client_get_host_machine_id (FwupdClient *client); const gchar *fwupd_client_get_host_security_id (FwupdClient *client); diff --git a/libfwupd/fwupd.map b/libfwupd/fwupd.map index fd8367b9f..3a3bf6402 100644 --- a/libfwupd/fwupd.map +++ b/libfwupd/fwupd.map @@ -449,11 +449,8 @@ LIBFWUPD_1.4.1 { LIBFWUPD_1.5.0 { global: - fwupd_client_get_host_family; fwupd_client_get_host_security_attrs; fwupd_client_get_host_security_id; - fwupd_client_get_host_sku; - fwupd_client_get_host_vendor; fwupd_security_attr_add_flag; fwupd_security_attr_add_obsolete; fwupd_security_attr_array_from_variant; diff --git a/src/fu-engine.c b/src/fu-engine.c index c9f5798bb..01ec50b12 100644 --- a/src/fu-engine.c +++ b/src/fu-engine.c @@ -5060,33 +5060,6 @@ fu_engine_get_host_product (FuEngine *self) return result != NULL ? result : "Unknown Product"; } -const gchar * -fu_engine_get_host_family (FuEngine *self) -{ - const gchar *result = NULL; - g_return_val_if_fail (FU_IS_ENGINE (self), NULL); - result = fu_hwids_get_value (self->hwids, FU_HWIDS_KEY_FAMILY); - return result != NULL ? result : "Unknown"; -} - -const gchar * -fu_engine_get_host_sku (FuEngine *self) -{ - const gchar *result = NULL; - g_return_val_if_fail (FU_IS_ENGINE (self), NULL); - result = fu_hwids_get_value (self->hwids, FU_HWIDS_KEY_PRODUCT_SKU); - return result != NULL ? result : "Unknown"; -} - -const gchar * -fu_engine_get_host_vendor (FuEngine *self) -{ - const gchar *result = NULL; - g_return_val_if_fail (FU_IS_ENGINE (self), NULL); - result = fu_hwids_get_value (self->hwids, FU_HWIDS_KEY_MANUFACTURER); - return result != NULL ? result : "Unknown"; -} - const gchar * fu_engine_get_host_machine_id (FuEngine *self) { diff --git a/src/fu-engine.h b/src/fu-engine.h index 94ac2741d..5f9a376fc 100644 --- a/src/fu-engine.h +++ b/src/fu-engine.h @@ -48,11 +48,8 @@ gboolean fu_engine_load (FuEngine *self, gboolean fu_engine_load_plugins (FuEngine *self, GError **error); gboolean fu_engine_get_tainted (FuEngine *self); -const gchar *fu_engine_get_host_product (FuEngine *self); -const gchar *fu_engine_get_host_family (FuEngine *self); -const gchar *fu_engine_get_host_sku (FuEngine *self); -const gchar *fu_engine_get_host_vendor (FuEngine *self); -const gchar *fu_engine_get_host_machine_id (FuEngine *self); +const gchar *fu_engine_get_host_product (FuEngine *self); +const gchar *fu_engine_get_host_machine_id (FuEngine *self); const gchar *fu_engine_get_host_security_id (FuEngine *self); FwupdStatus fu_engine_get_status (FuEngine *self); XbSilo *fu_engine_get_silo_from_blob (FuEngine *self, diff --git a/src/fu-main.c b/src/fu-main.c index 0fb6f64ae..97636f93b 100644 --- a/src/fu-main.c +++ b/src/fu-main.c @@ -1395,15 +1395,6 @@ fu_main_daemon_get_property (GDBusConnection *connection_, const gchar *sender, if (g_strcmp0 (property_name, "HostProduct") == 0) return g_variant_new_string (fu_engine_get_host_product (priv->engine)); - if (g_strcmp0 (property_name, "HostFamily") == 0) - return g_variant_new_string (fu_engine_get_host_family (priv->engine)); - - if (g_strcmp0 (property_name, "HostSku") == 0) - return g_variant_new_string (fu_engine_get_host_sku (priv->engine)); - - if (g_strcmp0 (property_name, "HostVendor") == 0) - return g_variant_new_string (fu_engine_get_host_vendor (priv->engine)); - if (g_strcmp0 (property_name, "HostMachineId") == 0) return g_variant_new_string (fu_engine_get_host_machine_id (priv->engine)); diff --git a/src/org.freedesktop.fwupd.xml b/src/org.freedesktop.fwupd.xml index a24fae9a7..ea33f626f 100644 --- a/src/org.freedesktop.fwupd.xml +++ b/src/org.freedesktop.fwupd.xml @@ -33,39 +33,6 @@ - - - - - - The product family string for the host. - - - - - - - - - - - The product SKU string for the host. - - - - - - - - - - - The product vendor string for the host. - - - - - From 6ecc4ca14492de4893149ecd28c967099e70df35 Mon Sep 17 00:00:00 2001 From: Richard Hughes Date: Wed, 20 May 2020 18:42:46 +0100 Subject: [PATCH 103/607] Export the report metadata on the D-Bus interface This allows the client to easily query metadata to upload with the report, without exporting rarely used attributes as D-Bus properties on the interface. It also allows us to add extra metadata values in the future without changing the public API. --- libfwupd/fwupd-client.c | 65 +++++++++++++++++++++++++++++++++++ libfwupd/fwupd-client.h | 3 ++ libfwupd/fwupd.map | 1 + src/fu-engine.c | 61 +++++++++++++++++++------------- src/fu-engine.h | 2 ++ src/fu-main.c | 25 ++++++++++++++ src/org.freedesktop.fwupd.xml | 18 ++++++++++ 7 files changed, 152 insertions(+), 23 deletions(-) diff --git a/libfwupd/fwupd-client.c b/libfwupd/fwupd-client.c index bfa0403e0..92b051826 100644 --- a/libfwupd/fwupd-client.c +++ b/libfwupd/fwupd-client.c @@ -404,6 +404,71 @@ fwupd_client_get_host_security_attrs (FwupdClient *client, GCancellable *cancell return fwupd_security_attr_array_from_variant (val); } +static GHashTable * +fwupd_report_metadata_hash_from_variant (GVariant *value) +{ + GHashTable *hash; + gsize sz; + g_autoptr(GVariant) untuple = NULL; + + hash = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_free); + untuple = g_variant_get_child_value (value, 0); + sz = g_variant_n_children (untuple); + for (guint i = 0; i < sz; i++) { + g_autoptr(GVariant) data = NULL; + const gchar *key = NULL; + const gchar *val = NULL; + data = g_variant_get_child_value (untuple, i); + g_variant_get (data, "{&s&s}", &key, &val); + g_hash_table_insert (hash, g_strdup (key), g_strdup (val)); + } + return hash; +} + +/** + * fwupd_client_get_report_metadata: + * @client: A #FwupdClient + * @cancellable: the #GCancellable, or %NULL + * @error: the #GError, or %NULL + * + * Gets all the report metadata from the daemon. + * + * Returns: (transfer container): attributes + * + * Since: 1.5.0 + **/ +GHashTable * +fwupd_client_get_report_metadata (FwupdClient *client, + GCancellable *cancellable, + GError **error) +{ + FwupdClientPrivate *priv = GET_PRIVATE (client); + g_autoptr(GVariant) val = NULL; + + g_return_val_if_fail (FWUPD_IS_CLIENT (client), NULL); + g_return_val_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable), NULL); + g_return_val_if_fail (error == NULL || *error == NULL, NULL); + + /* connect */ + if (!fwupd_client_connect (client, cancellable, error)) + return NULL; + + /* call into daemon */ + val = g_dbus_proxy_call_sync (priv->proxy, + "GetReportMetadata", + NULL, + G_DBUS_CALL_FLAGS_NONE, + -1, + cancellable, + error); + if (val == NULL) { + if (error != NULL) + fwupd_client_fixup_dbus_error (*error); + return NULL; + } + return fwupd_report_metadata_hash_from_variant (val); +} + /** * fwupd_client_get_devices: * @client: A #FwupdClient diff --git a/libfwupd/fwupd-client.h b/libfwupd/fwupd-client.h index 077e22092..80e84818d 100644 --- a/libfwupd/fwupd-client.h +++ b/libfwupd/fwupd-client.h @@ -130,6 +130,9 @@ gboolean fwupd_client_modify_device (FwupdClient *client, const gchar *value, GCancellable *cancellable, GError **error); +GHashTable *fwupd_client_get_report_metadata (FwupdClient *client, + GCancellable *cancellable, + GError **error); FwupdStatus fwupd_client_get_status (FwupdClient *client); gboolean fwupd_client_get_tainted (FwupdClient *client); gboolean fwupd_client_get_daemon_interactive (FwupdClient *client); diff --git a/libfwupd/fwupd.map b/libfwupd/fwupd.map index 3a3bf6402..7e2aca08a 100644 --- a/libfwupd/fwupd.map +++ b/libfwupd/fwupd.map @@ -451,6 +451,7 @@ LIBFWUPD_1.5.0 { global: fwupd_client_get_host_security_attrs; fwupd_client_get_host_security_id; + fwupd_client_get_report_metadata; fwupd_security_attr_add_flag; fwupd_security_attr_add_obsolete; fwupd_security_attr_array_from_variant; diff --git a/src/fu-engine.c b/src/fu-engine.c index 01ec50b12..e80e0b103 100644 --- a/src/fu-engine.c +++ b/src/fu-engine.c @@ -1342,14 +1342,43 @@ fu_engine_get_boot_time (void) return NULL; } -static GHashTable * -fu_engine_get_report_metadata (FuEngine *self) +static gboolean +fu_engine_get_report_metadata_os_release (GHashTable *hash, GError **error) +{ + g_autoptr(GHashTable) os_release = NULL; + struct { + const gchar *key; + const gchar *val; + } distro_kv[] = { + { "ID", "DistroId" }, + { "VERSION_ID", "DistroVersion" }, + { "VARIANT_ID", "DistroVariant" }, + { NULL, NULL } + }; + + /* get all required os-release keys */ + os_release = fwupd_get_os_release (error); + if (os_release == NULL) + return FALSE; + for (guint i = 0; distro_kv[i].key != NULL; i++) { + const gchar *tmp = g_hash_table_lookup (os_release, distro_kv[i].key); + if (tmp != NULL) { + g_hash_table_insert (hash, + g_strdup (distro_kv[i].val), + g_strdup (tmp)); + } + } + return TRUE; +} + +GHashTable * +fu_engine_get_report_metadata (FuEngine *self, GError **error) { - GHashTable *hash; gchar *btime; #ifdef HAVE_UTSNAME_H struct utsname name_tmp; #endif + g_autoptr(GHashTable) hash = NULL; g_autoptr(GList) compile_keys = g_hash_table_get_keys (self->compile_versions); g_autoptr(GList) runtime_keys = g_hash_table_get_keys (self->runtime_versions); @@ -1369,6 +1398,8 @@ fu_engine_get_report_metadata (FuEngine *self) g_strdup_printf ("RuntimeVersion(%s)", id), g_strdup (version)); } + if (!fu_engine_get_report_metadata_os_release (hash, error)) + return NULL; /* kernel version is often important for debugging failures */ #ifdef HAVE_UTSNAME_H @@ -1385,7 +1416,7 @@ fu_engine_get_report_metadata (FuEngine *self) if (btime != NULL) g_hash_table_insert (hash, g_strdup ("BootTime"), btime); - return hash; + return g_steal_pointer (&hash); } /** @@ -1530,18 +1561,13 @@ static FwupdRelease * fu_engine_create_release_metadata (FuEngine *self, FuPlugin *plugin, GError **error) { GPtrArray *metadata_sources; - const gchar *tmp; g_autoptr(FwupdRelease) release = fwupd_release_new (); g_autoptr(GHashTable) metadata_hash = NULL; - g_autoptr(GHashTable) os_release = NULL; - - /* add release data from os-release */ - os_release = fwupd_get_os_release (error); - if (os_release == NULL) - return NULL; /* build the version metadata */ - metadata_hash = fu_engine_get_report_metadata (self); + metadata_hash = fu_engine_get_report_metadata (self, error); + if (metadata_hash == NULL) + return NULL; fwupd_release_add_metadata (release, metadata_hash); fwupd_release_add_metadata (release, fu_plugin_get_report_metadata (plugin)); @@ -1564,17 +1590,6 @@ fu_engine_create_release_metadata (FuEngine *self, FuPlugin *plugin, GError **er fwupd_release_add_metadata (release, fu_plugin_get_report_metadata (plugin_tmp)); } - - /* add details from os-release as metadata */ - tmp = g_hash_table_lookup (os_release, "ID"); - if (tmp != NULL) - fwupd_release_add_metadata_item (release, "DistroId", tmp); - tmp = g_hash_table_lookup (os_release, "VERSION_ID"); - if (tmp != NULL) - fwupd_release_add_metadata_item (release, "DistroVersion", tmp); - tmp = g_hash_table_lookup (os_release, "VARIANT_ID"); - if (tmp != NULL) - fwupd_release_add_metadata_item (release, "DistroVariant", tmp); return g_steal_pointer (&release); } diff --git a/src/fu-engine.h b/src/fu-engine.h index 5f9a376fc..a1bd5df97 100644 --- a/src/fu-engine.h +++ b/src/fu-engine.h @@ -85,6 +85,8 @@ FwupdDevice *fu_engine_get_results (FuEngine *self, const gchar *device_id, GError **error); FuSecurityAttrs *fu_engine_get_host_security_attrs (FuEngine *self); +GHashTable *fu_engine_get_report_metadata (FuEngine *self, + GError **error); gboolean fu_engine_clear_results (FuEngine *self, const gchar *device_id, GError **error); diff --git a/src/fu-main.c b/src/fu-main.c index 97636f93b..bc7e8cf7e 100644 --- a/src/fu-main.c +++ b/src/fu-main.c @@ -858,6 +858,31 @@ fu_main_daemon_method_call (GDBusConnection *connection, const gchar *sender, g_variant_new_tuple (&val, 1)); return; } + if (g_strcmp0 (method_name, "GetReportMetadata") == 0) { + GHashTableIter iter; + GVariantBuilder builder; + const gchar *key; + const gchar *value; + g_autoptr(GHashTable) metadata = NULL; + + metadata = fu_engine_get_report_metadata (priv->engine, &error); + if (metadata == NULL) { + g_dbus_method_invocation_return_gerror (invocation, error); + return; + } + g_variant_builder_init (&builder, G_VARIANT_TYPE ("a{ss}")); + g_hash_table_iter_init (&iter, metadata); + while (g_hash_table_iter_next (&iter, + (gpointer *) &key, + (gpointer *) &value)) { + g_variant_builder_add_value (&builder, + g_variant_new ("{ss}", key, value)); + } + val = g_variant_builder_end (&builder); + g_dbus_method_invocation_return_value (invocation, + g_variant_new_tuple (&val, 1)); + return; + } if (g_strcmp0 (method_name, "SetApprovedFirmware") == 0) { g_autofree gchar *checksums_str = NULL; g_auto(GStrv) checksums = NULL; diff --git a/src/org.freedesktop.fwupd.xml b/src/org.freedesktop.fwupd.xml index ea33f626f..5f85bafdd 100644 --- a/src/org.freedesktop.fwupd.xml +++ b/src/org.freedesktop.fwupd.xml @@ -271,6 +271,24 @@ + + + + + + Gets metadata to include with the firmware and security reports. + + + + + + + An array of string key values. + + + + + From 08bb9223ecd97d9f4393d638b043675350673977 Mon Sep 17 00:00:00 2001 From: Richard Hughes Date: Wed, 20 May 2020 18:43:59 +0100 Subject: [PATCH 104/607] trivial: Include the kernel version in the report metadata --- src/fu-engine.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/fu-engine.c b/src/fu-engine.c index e80e0b103..1566f9723 100644 --- a/src/fu-engine.c +++ b/src/fu-engine.c @@ -1408,6 +1408,9 @@ fu_engine_get_report_metadata (FuEngine *self, GError **error) g_hash_table_insert (hash, g_strdup ("CpuArchitecture"), g_strdup (name_tmp.machine)); + g_hash_table_insert (hash, + g_strdup ("KernelVersion"), + g_strdup (name_tmp.release)); } #endif From a778ac989948e133b598b6f772079a2face1b8df Mon Sep 17 00:00:00 2001 From: Richard Hughes Date: Wed, 20 May 2020 18:44:24 +0100 Subject: [PATCH 105/607] trivial: Include some useful DMI values in the report metadata --- src/fu-engine.c | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/src/fu-engine.c b/src/fu-engine.c index 1566f9723..fc15ead53 100644 --- a/src/fu-engine.c +++ b/src/fu-engine.c @@ -1374,6 +1374,7 @@ fu_engine_get_report_metadata_os_release (GHashTable *hash, GError **error) GHashTable * fu_engine_get_report_metadata (FuEngine *self, GError **error) { + const gchar *tmp; gchar *btime; #ifdef HAVE_UTSNAME_H struct utsname name_tmp; @@ -1401,6 +1402,20 @@ fu_engine_get_report_metadata (FuEngine *self, GError **error) if (!fu_engine_get_report_metadata_os_release (hash, error)) return NULL; + /* DMI data */ + tmp = fu_hwids_get_value (self->hwids, FU_HWIDS_KEY_PRODUCT_NAME); + if (tmp != NULL) + g_hash_table_insert (hash, g_strdup ("HostProduct"), g_strdup (tmp)); + tmp = fu_hwids_get_value (self->hwids, FU_HWIDS_KEY_FAMILY); + if (tmp != NULL) + g_hash_table_insert (hash, g_strdup ("HostFamily"), g_strdup (tmp)); + tmp = fu_hwids_get_value (self->hwids, FU_HWIDS_KEY_PRODUCT_SKU); + if (tmp != NULL) + g_hash_table_insert (hash, g_strdup ("HostSku"), g_strdup (tmp)); + tmp = fu_hwids_get_value (self->hwids, FU_HWIDS_KEY_MANUFACTURER); + if (tmp != NULL) + g_hash_table_insert (hash, g_strdup ("HostVendor"), g_strdup (tmp)); + /* kernel version is often important for debugging failures */ #ifdef HAVE_UTSNAME_H memset (&name_tmp, 0, sizeof (struct utsname)); From dc867ddd777cd8c400d1e8f1197abb9e00fcdacc Mon Sep 17 00:00:00 2001 From: Richard Hughes Date: Wed, 20 May 2020 18:47:20 +0100 Subject: [PATCH 106/607] trivial: Include a safe version of the kernel cmdline in the report metadata --- src/fu-engine.c | 56 +++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 56 insertions(+) diff --git a/src/fu-engine.c b/src/fu-engine.c index fc15ead53..250463a11 100644 --- a/src/fu-engine.c +++ b/src/fu-engine.c @@ -1371,6 +1371,60 @@ fu_engine_get_report_metadata_os_release (GHashTable *hash, GError **error) return TRUE; } +static gboolean +fu_engine_get_report_metadata_kernel_cmdline (GHashTable *hash, GError **error) +{ + gsize bufsz = 0; + g_autofree gchar *buf = NULL; + const gchar *ignore[] = { + "", + "BOOT_IMAGE", + "console", + "cryptdevice", + "initrd", + "LANG", + "loglevel", + "ostree", + "quiet", + "rd.luks.uuid", + "rd.lvm.lv", + "resume", + "rhgb", + "ro", + "root", + "rootflags", + "rw", + "showopts", + "splash", + "swap", + "vt.handoff", + "zfs", + NULL, /* last entry */ + }; + + /* get a PII-safe kernel command line */ + if (!g_file_get_contents ("/proc/cmdline", &buf, &bufsz, error)) + return FALSE; + if (bufsz > 0) { + g_auto(GStrv) tokens = fu_common_strnsplit (buf, bufsz - 1, " ", -1); + g_autoptr(GString) cmdline_safe = g_string_new (NULL); + for (guint i = 0; tokens[i] != NULL; i++) { + g_auto(GStrv) kv = g_strsplit (tokens[i], "=", 2); + if (g_strv_contains (ignore, kv[0])) + continue; + if (cmdline_safe->len > 0) + g_string_append (cmdline_safe, " "); + g_string_append (cmdline_safe, tokens[i]); + } + if (cmdline_safe->len > 0) { + g_hash_table_insert (hash, + g_strdup ("KernelCmdline"), + g_strdup (cmdline_safe->str)); + } + } + return TRUE; +} + GHashTable * fu_engine_get_report_metadata (FuEngine *self, GError **error) { @@ -1401,6 +1455,8 @@ fu_engine_get_report_metadata (FuEngine *self, GError **error) } if (!fu_engine_get_report_metadata_os_release (hash, error)) return NULL; + if (!fu_engine_get_report_metadata_kernel_cmdline (hash, error)) + return NULL; /* DMI data */ tmp = fu_hwids_get_value (self->hwids, FU_HWIDS_KEY_PRODUCT_NAME); From 0abba6cbb0215191fc20bac6974ead0ba77a6cfc Mon Sep 17 00:00:00 2001 From: Richard Hughes Date: Thu, 21 May 2020 11:16:06 +0100 Subject: [PATCH 107/607] ata: A OUI quirk for Kingston Fixes https://github.com/fwupd/fwupd/issues/2121 --- plugins/ata/ata.quirk | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/plugins/ata/ata.quirk b/plugins/ata/ata.quirk index 8d71e2679..801011347 100644 --- a/plugins/ata/ata.quirk +++ b/plugins/ata/ata.quirk @@ -42,6 +42,10 @@ VendorId = ATA:0x14A4 Vendor = Samsung VendorId = ATA:0x144D +[DeviceInstanceId=OUI\0026b7] +Vendor = Kingston +VendorId = ATA:0x2646 + [DeviceInstanceId=OUI\00a075] Vendor = Micron VendorId = ATA:0x1344 From c05ac2d074b64a1699240c0786e4db01a5234a09 Mon Sep 17 00:00:00 2001 From: Richard Hughes Date: Wed, 20 May 2020 22:35:09 +0100 Subject: [PATCH 108/607] trivial: Add three more things to the cmdline blocklist --- src/fu-engine.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/fu-engine.c b/src/fu-engine.c index 250463a11..ece2dac53 100644 --- a/src/fu-engine.c +++ b/src/fu-engine.c @@ -1378,12 +1378,14 @@ fu_engine_get_report_metadata_kernel_cmdline (GHashTable *hash, GError **error) g_autofree gchar *buf = NULL; const gchar *ignore[] = { "", + "auto", "BOOT_IMAGE", "console", "cryptdevice", "initrd", "LANG", "loglevel", + "noplymouth", "ostree", "quiet", "rd.luks.uuid", @@ -1397,6 +1399,7 @@ fu_engine_get_report_metadata_kernel_cmdline (GHashTable *hash, GError **error) "showopts", "splash", "swap", + "verbose", "vt.handoff", "zfs", NULL, /* last entry */ From 9bc9debd983f0ce8323b4c211c7653209d0dfdbb Mon Sep 17 00:00:00 2001 From: Richard Hughes Date: Tue, 19 May 2020 19:49:51 +0100 Subject: [PATCH 109/607] Allow uploading security attributes to the LVFS We sign the data with the client cert to allow users with LVFS accounts to publish 'official' HSI ratings. --- data/remotes.d/lvfs.conf | 2 + libfwupd/fwupd-remote.c | 81 +++++++++++++++ libfwupd/fwupd-remote.h | 2 + libfwupd/fwupd.map | 2 + src/fu-engine.c | 11 ++- src/fu-util.c | 209 ++++++++++++++++++++++++++++++++++++++- 6 files changed, 305 insertions(+), 2 deletions(-) diff --git a/data/remotes.d/lvfs.conf b/data/remotes.d/lvfs.conf index 1249ef746..f956bc97a 100644 --- a/data/remotes.d/lvfs.conf +++ b/data/remotes.d/lvfs.conf @@ -5,6 +5,8 @@ Enabled=true Title=Linux Vendor Firmware Service MetadataURI=https://cdn.fwupd.org/downloads/firmware.xml.gz ReportURI=https://fwupd.org/lvfs/firmware/report +SecurityReportURI=https://fwupd.org/lvfs/hsireports/upload OrderBefore=fwupd AutomaticReports=false +AutomaticSecurityReports=false ApprovalRequired=false diff --git a/libfwupd/fwupd-remote.c b/libfwupd/fwupd-remote.c index 705bd4328..c8eaeb1b1 100644 --- a/libfwupd/fwupd-remote.c +++ b/libfwupd/fwupd-remote.c @@ -32,6 +32,7 @@ typedef struct { gchar *id; gchar *firmware_base_uri; gchar *report_uri; + gchar *security_report_uri; gchar *metadata_uri; gchar *metadata_uri_sig; gchar *username; @@ -50,6 +51,7 @@ typedef struct { gchar **order_before; gchar *remotes_dir; gboolean automatic_reports; + gboolean automatic_security_reports; } FwupdRemotePrivate; enum { @@ -58,6 +60,7 @@ enum { PROP_ENABLED, PROP_APPROVAL_REQUIRED, PROP_AUTOMATIC_REPORTS, + PROP_AUTOMATIC_SECURITY_REPORTS, PROP_LAST }; @@ -252,6 +255,13 @@ fwupd_remote_set_report_uri (FwupdRemote *self, const gchar *report_uri) priv->report_uri = g_strdup (report_uri); } +static void +fwupd_remote_set_security_report_uri (FwupdRemote *self, const gchar *security_report_uri) +{ + FwupdRemotePrivate *priv = GET_PRIVATE (self); + priv->security_report_uri = g_strdup (security_report_uri); +} + /** * fwupd_remote_kind_from_string: * @kind: a string, e.g. `download` @@ -343,6 +353,7 @@ fwupd_remote_load_from_filename (FwupdRemote *self, g_autofree gchar *order_after = NULL; g_autofree gchar *order_before = NULL; g_autofree gchar *report_uri = NULL; + g_autofree gchar *security_report_uri = NULL; g_autoptr(GKeyFile) kf = NULL; g_return_val_if_fail (FWUPD_IS_REMOTE (self), FALSE); @@ -415,8 +426,14 @@ fwupd_remote_load_from_filename (FwupdRemote *self, if (report_uri != NULL && report_uri[0] != '\0') fwupd_remote_set_report_uri (self, report_uri); + /* security reporting is optional */ + security_report_uri = g_key_file_get_string (kf, group, "SecurityReportURI", NULL); + if (security_report_uri != NULL && security_report_uri[0] != '\0') + fwupd_remote_set_security_report_uri (self, security_report_uri); + /* automatic report uploading */ priv->automatic_reports = g_key_file_get_boolean (kf, group, "AutomaticReports", NULL); + priv->automatic_security_reports = g_key_file_get_boolean (kf, group, "AutomaticSecurityReports", NULL); /* DOWNLOAD-type remotes */ if (priv->kind == FWUPD_REMOTE_KIND_DOWNLOAD) { @@ -879,6 +896,24 @@ fwupd_remote_get_report_uri (FwupdRemote *self) return priv->report_uri; } +/** + * fwupd_remote_get_security_report_uri: + * @self: A #FwupdRemote + * + * Gets the URI for the security report. + * + * Returns: (transfer none): a URI, or %NULL for invalid. + * + * Since: 1.5.0 + **/ +const gchar * +fwupd_remote_get_security_report_uri (FwupdRemote *self) +{ + FwupdRemotePrivate *priv = GET_PRIVATE (self); + g_return_val_if_fail (FWUPD_IS_REMOTE (self), NULL); + return priv->security_report_uri; +} + /** * fwupd_remote_get_metadata_uri: * @self: A #FwupdRemote @@ -1035,6 +1070,24 @@ fwupd_remote_get_automatic_reports (FwupdRemote *self) return priv->automatic_reports; } +/** + * fwupd_remote_get_automatic_security_reports: + * @self: A #FwupdRemote + * + * Gets if security reports should be automatically uploaded to this remote + * + * Returns: a #TRUE if the remote should have reports uploaded automatically + * + * Since: 1.5.0 + **/ +gboolean +fwupd_remote_get_automatic_security_reports (FwupdRemote *self) +{ + FwupdRemotePrivate *priv = GET_PRIVATE (self); + g_return_val_if_fail (FWUPD_IS_REMOTE (self), FALSE); + return priv->automatic_security_reports; +} + /** * fwupd_remote_get_approval_required: * @self: A #FwupdRemote @@ -1099,6 +1152,8 @@ fwupd_remote_set_from_variant_iter (FwupdRemote *self, GVariantIter *iter) fwupd_remote_set_filename_source (self, g_variant_get_string (value, NULL)); if (g_strcmp0 (key, "ReportUri") == 0) fwupd_remote_set_report_uri (self, g_variant_get_string (value, NULL)); + if (g_strcmp0 (key, "SecurityReportUri") == 0) + fwupd_remote_set_security_report_uri (self, g_variant_get_string (value, NULL)); } while (g_variant_iter_loop (iter3, "{sv}", &key, &value)) { if (g_strcmp0 (key, "Username") == 0) { @@ -1123,6 +1178,8 @@ fwupd_remote_set_from_variant_iter (FwupdRemote *self, GVariantIter *iter) fwupd_remote_set_firmware_base_uri (self, g_variant_get_string (value, NULL)); } else if (g_strcmp0 (key, "AutomaticReports") == 0) { priv->automatic_reports = g_variant_get_boolean (value); + } else if (g_strcmp0 (key, "AutomaticSecurityReports") == 0) { + priv->automatic_security_reports = g_variant_get_boolean (value); } } } @@ -1179,6 +1236,10 @@ fwupd_remote_to_variant (FwupdRemote *self) g_variant_builder_add (&builder, "{sv}", "ReportUri", g_variant_new_string (priv->report_uri)); } + if (priv->security_report_uri != NULL) { + g_variant_builder_add (&builder, "{sv}", "SecurityReportUri", + g_variant_new_string (priv->security_report_uri)); + } if (priv->firmware_base_uri != NULL) { g_variant_builder_add (&builder, "{sv}", "FirmwareBaseUri", g_variant_new_string (priv->firmware_base_uri)); @@ -1217,6 +1278,8 @@ fwupd_remote_to_variant (FwupdRemote *self) g_variant_new_boolean (priv->approval_required)); g_variant_builder_add (&builder, "{sv}", "AutomaticReports", g_variant_new_boolean (priv->automatic_reports)); + g_variant_builder_add (&builder, "{sv}", "AutomaticSecurityReports", + g_variant_new_boolean (priv->automatic_security_reports)); return g_variant_new ("a{sv}", &builder); } @@ -1240,6 +1303,9 @@ fwupd_remote_get_property (GObject *obj, guint prop_id, case PROP_AUTOMATIC_REPORTS: g_value_set_boolean (value, priv->automatic_reports); break; + case PROP_AUTOMATIC_SECURITY_REPORTS: + g_value_set_boolean (value, priv->automatic_security_reports); + break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (obj, prop_id, pspec); break; @@ -1266,6 +1332,9 @@ fwupd_remote_set_property (GObject *obj, guint prop_id, case PROP_AUTOMATIC_REPORTS: priv->automatic_reports = g_value_get_boolean (value); break; + case PROP_AUTOMATIC_SECURITY_REPORTS: + priv->automatic_security_reports = g_value_get_boolean (value); + break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (obj, prop_id, pspec); break; @@ -1326,6 +1395,17 @@ fwupd_remote_class_init (FwupdRemoteClass *klass) FALSE, G_PARAM_READWRITE | G_PARAM_STATIC_NAME); g_object_class_install_property (object_class, PROP_AUTOMATIC_REPORTS, pspec); + /** + * FwupdRemote:automatic-security-reports: + * + * The behavior for auto-uploading security reports. + * + * Since: 1.5.0 + */ + pspec = g_param_spec_boolean ("automatic-security-reports", NULL, NULL, + FALSE, G_PARAM_READWRITE | G_PARAM_STATIC_NAME); + g_object_class_install_property (object_class, PROP_AUTOMATIC_SECURITY_REPORTS, pspec); + } static void @@ -1344,6 +1424,7 @@ fwupd_remote_finalize (GObject *obj) g_free (priv->metadata_uri_sig); g_free (priv->firmware_base_uri); g_free (priv->report_uri); + g_free (priv->security_report_uri); g_free (priv->username); g_free (priv->password); g_free (priv->title); diff --git a/libfwupd/fwupd-remote.h b/libfwupd/fwupd-remote.h index efdf207a0..c8da71173 100644 --- a/libfwupd/fwupd-remote.h +++ b/libfwupd/fwupd-remote.h @@ -60,11 +60,13 @@ const gchar *fwupd_remote_get_filename_cache_sig (FwupdRemote *self); const gchar *fwupd_remote_get_filename_source (FwupdRemote *self); const gchar *fwupd_remote_get_firmware_base_uri (FwupdRemote *self); const gchar *fwupd_remote_get_report_uri (FwupdRemote *self); +const gchar *fwupd_remote_get_security_report_uri (FwupdRemote *self); const gchar *fwupd_remote_get_metadata_uri (FwupdRemote *self); const gchar *fwupd_remote_get_metadata_uri_sig (FwupdRemote *self); gboolean fwupd_remote_get_enabled (FwupdRemote *self); gboolean fwupd_remote_get_approval_required (FwupdRemote *self); gboolean fwupd_remote_get_automatic_reports (FwupdRemote *self); +gboolean fwupd_remote_get_automatic_security_reports (FwupdRemote *self); gint fwupd_remote_get_priority (FwupdRemote *self); guint64 fwupd_remote_get_age (FwupdRemote *self); FwupdRemoteKind fwupd_remote_get_kind (FwupdRemote *self); diff --git a/libfwupd/fwupd.map b/libfwupd/fwupd.map index 7e2aca08a..08279c991 100644 --- a/libfwupd/fwupd.map +++ b/libfwupd/fwupd.map @@ -452,6 +452,8 @@ LIBFWUPD_1.5.0 { fwupd_client_get_host_security_attrs; fwupd_client_get_host_security_id; fwupd_client_get_report_metadata; + fwupd_remote_get_automatic_security_reports; + fwupd_remote_get_security_report_uri; fwupd_security_attr_add_flag; fwupd_security_attr_add_obsolete; fwupd_security_attr_array_from_variant; diff --git a/src/fu-engine.c b/src/fu-engine.c index ece2dac53..8e5ad9246 100644 --- a/src/fu-engine.c +++ b/src/fu-engine.c @@ -561,7 +561,16 @@ fu_engine_modify_remote (FuEngine *self, const gchar *value, GError **error) { - const gchar *keys[] = { "Enabled", "MetadataURI", "FirmwareBaseURI", "ReportURI", "AutomaticReports", NULL }; + const gchar *keys[] = { + "AutomaticReports", + "AutomaticSecurityReports", + "Enabled", + "FirmwareBaseURI", + "MetadataURI", + "ReportURI", + "SecurityReportURI", + NULL, + }; /* check keys are valid */ if (!g_strv_contains (keys, key)) { diff --git a/src/fu-util.c b/src/fu-util.c index aa2bbde0f..b4a44235c 100644 --- a/src/fu-util.c +++ b/src/fu-util.c @@ -2365,6 +2365,207 @@ fu_util_modify_config (FuUtilPrivate *priv, gchar **values, GError **error) return TRUE; } +static FwupdRemote * +fu_util_get_remote_with_security_report_uri (FuUtilPrivate *priv, GError **error) +{ + g_autoptr(GPtrArray) remotes = NULL; + + /* get all remotes */ + remotes = fwupd_client_get_remotes (priv->client, NULL, error); + if (remotes == NULL) + return NULL; + + for (guint i = 0; i < remotes->len; i++) { + FwupdRemote *remote = g_ptr_array_index (remotes, i); + if (!fwupd_remote_get_enabled (remote)) + continue; + if (fwupd_remote_get_security_report_uri (remote) != NULL) + return g_object_ref (remote); + } + + /* failed */ + g_set_error_literal (error, + FWUPD_ERROR, + FWUPD_ERROR_NOT_SUPPORTED, + "No remotes specified SecurityReportURI"); + return FALSE; +} + +static gboolean +fu_util_upload_security (FuUtilPrivate *priv, GPtrArray *attrs, GError **error) +{ + guint status_code; + GHashTableIter iter; + const gchar *key; + const gchar *value; + g_autofree gchar *data = NULL; + g_autofree gchar *sig = NULL; + g_autoptr(FwupdRemote) remote = NULL; + g_autoptr(GError) error_local = NULL; + g_autoptr(GHashTable) metadata = NULL; + g_autoptr(JsonBuilder) builder = NULL; + g_autoptr(JsonGenerator) json_generator = NULL; + g_autoptr(JsonNode) json_root = NULL; + g_autoptr(SoupMessage) msg = NULL; + g_autoptr(SoupMultipart) mp = NULL; + + /* can we find a remote with a security attr */ + remote = fu_util_get_remote_with_security_report_uri (priv, &error_local); + if (remote == NULL) { + g_debug ("failed to find suitable remote: %s", error_local->message); + return TRUE; + } + if (!priv->assume_yes && + !fwupd_remote_get_automatic_security_reports (remote)) { + g_autofree gchar *tmp = NULL; + /* TRANSLATORS: ask the user to share, %s is something like: + * "Linux Vendor Firmware Service" */ + tmp = g_strdup_printf ("Upload these anonymous results to the %s to help other users?", + fwupd_remote_get_title (remote)); + + g_print ("\n%s [y|N]: ", tmp); + if (!fu_util_prompt_for_boolean (FALSE)) { + g_print ("%s [Y|n]: ", + /* TRANSLATORS: stop nagging the user */ + _("Ask again next time?")); + if (!fu_util_prompt_for_boolean (TRUE)) { + if (!fwupd_client_modify_remote (priv->client, + fwupd_remote_get_id (remote), + "SecurityReportURI", "", + NULL, error)) + return FALSE; + } + return TRUE; + } + } + + /* set up networking */ + if (priv->soup_session == NULL) { + priv->soup_session = fu_util_setup_networking (error); + if (priv->soup_session == NULL) + return FALSE; + } + + /* get metadata */ + metadata = fwupd_client_get_report_metadata (priv->client, + priv->cancellable, + error); + if (metadata == NULL) + return FALSE; + + /* create header */ + builder = json_builder_new (); + json_builder_begin_object (builder); + json_builder_set_member_name (builder, "ReportVersion"); + json_builder_add_int_value (builder, 2); + json_builder_set_member_name (builder, "MachineId"); + json_builder_add_string_value (builder, fwupd_client_get_host_machine_id (priv->client)); + + /* this is system metadata not stored in the database */ + json_builder_set_member_name (builder, "Metadata"); + json_builder_begin_object (builder); + + g_hash_table_iter_init (&iter, metadata); + while (g_hash_table_iter_next (&iter, (gpointer *) &key, (gpointer *) &value)) { + json_builder_set_member_name (builder, key); + json_builder_add_string_value (builder, value); + } + json_builder_set_member_name (builder, "HostSecurityId"); + json_builder_add_string_value (builder, fwupd_client_get_host_security_id (priv->client)); + json_builder_end_object (builder); + + /* attrs */ + json_builder_set_member_name (builder, "SecurityAttributes"); + json_builder_begin_array (builder); + for (guint i = 0; i < attrs->len; i++) { + FwupdSecurityAttr *attr = g_ptr_array_index (attrs, i); + json_builder_begin_object (builder); + fwupd_security_attr_to_json (attr, builder); + json_builder_end_object (builder); + } + json_builder_end_array (builder); + json_builder_end_object (builder); + + /* export as a string */ + json_root = json_builder_get_root (builder); + json_generator = json_generator_new (); + json_generator_set_pretty (json_generator, TRUE); + json_generator_set_root (json_generator, json_root); + data = json_generator_to_data (json_generator, NULL); + if (data == NULL) { + g_set_error_literal (error, + FWUPD_ERROR, + FWUPD_ERROR_INTERNAL, + "Failed to convert to JSON string"); + return FALSE; + } + + /* self sign data */ + if (priv->sign) { + sig = fwupd_client_self_sign (priv->client, data, + FWUPD_SELF_SIGN_FLAG_ADD_TIMESTAMP, + priv->cancellable, error); + if (sig == NULL) + return FALSE; + } + + /* ask for permission */ + if (!priv->assume_yes && + !fwupd_remote_get_automatic_security_reports (remote)) { + fu_util_print_data (_("Target"), fwupd_remote_get_security_report_uri (remote)); + fu_util_print_data (_("Payload"), data); + if (sig != NULL) + fu_util_print_data (_("Signature"), sig); + g_print ("%s [Y|n]: ", _("Proceed with upload?")); + if (!fu_util_prompt_for_boolean (TRUE)) { + g_set_error_literal (error, + FWUPD_ERROR, + FWUPD_ERROR_PERMISSION_DENIED, + "User declined action"); + return FALSE; + } + } + + /* POST request */ + mp = soup_multipart_new (SOUP_FORM_MIME_TYPE_MULTIPART); + soup_multipart_append_form_string (mp, "payload", data); + if (sig != NULL) + soup_multipart_append_form_string (mp, "signature", sig); + msg = soup_form_request_new_from_multipart (fwupd_remote_get_security_report_uri (remote), mp); + status_code = soup_session_send_message (priv->soup_session, msg); + g_debug ("server returned: %s", msg->response_body->data); + + /* fall back to HTTP status codes in case the server is offline */ + if (!SOUP_STATUS_IS_SUCCESSFUL (status_code)) { + g_set_error (error, + FWUPD_ERROR, + FWUPD_ERROR_INVALID_FILE, + "Failed to upload to %s: %s", + fwupd_remote_get_security_report_uri (remote), + soup_status_get_phrase (status_code)); + return FALSE; + } + + /* TRANSLATORS: success, so say thank you to the user */ + g_print ("%s\n", "Host Security ID attributes uploaded successfully, thanks!"); + + /* as this worked, ask if the user want to do this every time */ + if (!fwupd_remote_get_automatic_security_reports (remote)) { + g_print ("%s [y|N]: ", + /* TRANSLATORS: can we JFDI? */ + _("Automatically upload every time?")); + if (fu_util_prompt_for_boolean (FALSE)) { + if (!fwupd_client_modify_remote (priv->client, + fwupd_remote_get_id (remote), + "AutomaticSecurityReports", "true", + NULL, error)) + return FALSE; + } + } + + return TRUE; +} + static gboolean fu_util_security (FuUtilPrivate *priv, gchar **values, GError **error) { @@ -2393,7 +2594,13 @@ fu_util_security (FuUtilPrivate *priv, gchar **values, GError **error) return FALSE; str = fu_util_security_attrs_to_string (attrs); g_print ("%s\n", str); - return TRUE; + + /* opted-out */ + if (priv->no_unreported_check) + return TRUE; + + /* upload, with confirmation */ + return fu_util_upload_security (priv, attrs, error); } static void From bd44432240278c5453bb34e723e4274b4638d317 Mon Sep 17 00:00:00 2001 From: Richard Hughes Date: Thu, 21 May 2020 12:05:03 +0100 Subject: [PATCH 110/607] trivial: Fix a build failure on aarch64 It seems cpuid.h isn't available everywhere, which make sense in retrospect. --- libfwupdplugin/fu-common.c | 4 ++++ meson.build | 3 +++ 2 files changed, 7 insertions(+) diff --git a/libfwupdplugin/fu-common.c b/libfwupdplugin/fu-common.c index 5eb9c279d..071a7e5a1 100644 --- a/libfwupdplugin/fu-common.c +++ b/libfwupdplugin/fu-common.c @@ -19,7 +19,9 @@ #include #endif +#ifdef HAVE_CPUID_H #include +#endif #include #include @@ -2047,6 +2049,7 @@ fu_common_kernel_locked_down (void) gboolean fu_common_is_cpu_intel (void) { +#ifdef HAVE_CPUID_H guint eax = 0; guint ebx = 0; guint ecx = 0; @@ -2060,5 +2063,6 @@ fu_common_is_cpu_intel (void) ecx == signature_INTEL_ecx) { return TRUE; } +#endif return FALSE; } diff --git a/meson.build b/meson.build index 766bf8776..3e3afa773 100644 --- a/meson.build +++ b/meson.build @@ -258,6 +258,9 @@ endif if cc.has_header('fnmatch.h') conf.set('HAVE_FNMATCH_H', '1') endif +if cc.has_header('cpuid.h') + conf.set('HAVE_CPUID_H', '1') +endif if cc.has_function('getuid') conf.set('HAVE_GETUID', '1') endif From 4a6232940124bb6b080c2d225ec8792f1e43b57f Mon Sep 17 00:00:00 2001 From: Richard Hughes Date: Thu, 21 May 2020 20:58:28 +0100 Subject: [PATCH 111/607] trivial: One more thing to ignore in the kernel cmdline --- src/fu-engine.c | 1 + 1 file changed, 1 insertion(+) diff --git a/src/fu-engine.c b/src/fu-engine.c index 8e5ad9246..ced8776f7 100644 --- a/src/fu-engine.c +++ b/src/fu-engine.c @@ -1399,6 +1399,7 @@ fu_engine_get_report_metadata_kernel_cmdline (GHashTable *hash, GError **error) "quiet", "rd.luks.uuid", "rd.lvm.lv", + "rd.md.uuid", "resume", "rhgb", "ro", From c821923668d43d4b375be998f8872623f375cdcf Mon Sep 17 00:00:00 2001 From: Richard Hughes Date: Thu, 21 May 2020 21:57:16 +0100 Subject: [PATCH 112/607] Add an HSI attribute for Intel SMAP See https://en.wikipedia.org/wiki/Supervisor_Mode_Access_Prevention for details. --- libfwupd/fwupd-security-attr.h | 1 + plugins/cpu/fu-cpu-device.c | 4 ++++ plugins/cpu/fu-cpu-device.h | 1 + plugins/cpu/fu-plugin-cpu.c | 27 +++++++++++++++++++++++++++ src/fu-security-attr.c | 4 ++++ 5 files changed, 37 insertions(+) diff --git a/libfwupd/fwupd-security-attr.h b/libfwupd/fwupd-security-attr.h index 44033ebed..00977397e 100644 --- a/libfwupd/fwupd-security-attr.h +++ b/libfwupd/fwupd-security-attr.h @@ -118,6 +118,7 @@ typedef enum { #define FWUPD_SECURITY_ATTR_ID_FWUPD_UPDATES "org.fwupd.hsi.FwupdUpdates" /* Since: 1.5.0 */ #define FWUPD_SECURITY_ATTR_ID_INTEL_AMT "org.fwupd.hsi.IntelAmt" /* Since: 1.5.0 */ #define FWUPD_SECURITY_ATTR_ID_INTEL_CET "org.fwupd.hsi.IntelCet" /* Since: 1.5.0 */ +#define FWUPD_SECURITY_ATTR_ID_INTEL_SMAP "org.fwupd.hsi.IntelSmap" /* Since: 1.5.0 */ #define FWUPD_SECURITY_ATTR_ID_IOMMU "org.fwupd.hsi.Iommu" /* Since: 1.5.0 */ #define FWUPD_SECURITY_ATTR_ID_KERNEL_LOCKDOWN "org.fwupd.hsi.KernelLockdown" /* Since: 1.5.0 */ #define FWUPD_SECURITY_ATTR_ID_KERNEL_SWAP "org.fwupd.hsi.KernelSwap" /* Since: 1.5.0 */ diff --git a/plugins/cpu/fu-cpu-device.c b/plugins/cpu/fu-cpu-device.c index bbfa77387..9a54218d0 100644 --- a/plugins/cpu/fu-cpu-device.c +++ b/plugins/cpu/fu-cpu-device.c @@ -31,6 +31,8 @@ fu_cpu_device_to_string (FuDevice *device, guint idt, GString *str) fu_cpu_device_has_flag (self, FU_CPU_DEVICE_FLAG_IBT)); fu_common_string_append_kb (str, idt, "HasTME", fu_cpu_device_has_flag (self, FU_CPU_DEVICE_FLAG_TME)); + fu_common_string_append_kb (str, idt, "HasSMAP", + fu_cpu_device_has_flag (self, FU_CPU_DEVICE_FLAG_SMAP)); } static void @@ -44,6 +46,8 @@ fu_cpu_device_parse_flags (FuCpuDevice *self, const gchar *data) self->flags |= FU_CPU_DEVICE_FLAG_IBT; if (g_strcmp0 (flags[i], "tme") == 0) self->flags |= FU_CPU_DEVICE_FLAG_TME; + if (g_strcmp0 (flags[i], "smap") == 0) + self->flags |= FU_CPU_DEVICE_FLAG_SMAP; } } diff --git a/plugins/cpu/fu-cpu-device.h b/plugins/cpu/fu-cpu-device.h index b0c7de2a7..50d50d154 100644 --- a/plugins/cpu/fu-cpu-device.h +++ b/plugins/cpu/fu-cpu-device.h @@ -16,6 +16,7 @@ typedef enum { FU_CPU_DEVICE_FLAG_SHSTK = 1 << 0, FU_CPU_DEVICE_FLAG_IBT = 1 << 1, FU_CPU_DEVICE_FLAG_TME = 1 << 2, + FU_CPU_DEVICE_FLAG_SMAP = 1 << 3, } FuCpuDeviceFlag; FuCpuDevice *fu_cpu_device_new (const gchar *section); diff --git a/plugins/cpu/fu-plugin-cpu.c b/plugins/cpu/fu-plugin-cpu.c index b293b9e60..e5e83821a 100644 --- a/plugins/cpu/fu-plugin-cpu.c +++ b/plugins/cpu/fu-plugin-cpu.c @@ -12,6 +12,7 @@ struct FuPluginData { gboolean has_cet; + gboolean has_smap; gboolean has_tme; }; @@ -46,6 +47,8 @@ fu_plugin_coldplug (FuPlugin *plugin, GError **error) data->has_cet = TRUE; if (fu_cpu_device_has_flag (dev, FU_CPU_DEVICE_FLAG_TME)) data->has_tme = TRUE; + if (fu_cpu_device_has_flag (dev, FU_CPU_DEVICE_FLAG_SMAP)) + data->has_smap = TRUE; fu_plugin_device_add (plugin, FU_DEVICE (dev)); } @@ -98,6 +101,29 @@ fu_plugin_add_security_attrs_intel_tme (FuPlugin *plugin, FuSecurityAttrs *attrs fwupd_security_attr_set_result (attr, FWUPD_SECURITY_ATTR_RESULT_ENABLED); } +static void +fu_plugin_add_security_attrs_intel_smap (FuPlugin *plugin, FuSecurityAttrs *attrs) +{ + FuPluginData *data = fu_plugin_get_data (plugin); + g_autoptr(FwupdSecurityAttr) attr = NULL; + + /* create attr */ + attr = fwupd_security_attr_new (FWUPD_SECURITY_ATTR_ID_INTEL_SMAP); + fwupd_security_attr_set_plugin (attr, fu_plugin_get_name (plugin)); + fwupd_security_attr_set_level (attr, FWUPD_SECURITY_ATTR_LEVEL_SYSTEM_PROTECTION); + fu_security_attrs_append (attrs, attr); + + /* check for SMEP and SMAP */ + if (!data->has_smap) { + fwupd_security_attr_set_result (attr, FWUPD_SECURITY_ATTR_RESULT_NOT_SUPPORTED); + return; + } + + /* success */ + fwupd_security_attr_add_flag (attr, FWUPD_SECURITY_ATTR_FLAG_SUCCESS); + fwupd_security_attr_set_result (attr, FWUPD_SECURITY_ATTR_RESULT_ENABLED); +} + void fu_plugin_add_security_attrs (FuPlugin *plugin, FuSecurityAttrs *attrs) { @@ -107,4 +133,5 @@ fu_plugin_add_security_attrs (FuPlugin *plugin, FuSecurityAttrs *attrs) fu_plugin_add_security_attrs_intel_cet (plugin, attrs); fu_plugin_add_security_attrs_intel_tme (plugin, attrs); + fu_plugin_add_security_attrs_intel_smap (plugin, attrs); } diff --git a/src/fu-security-attr.c b/src/fu-security-attr.c index 8b13c2135..df94007c6 100644 --- a/src/fu-security-attr.c +++ b/src/fu-security-attr.c @@ -37,6 +37,10 @@ fu_security_attr_get_name (FwupdSecurityAttr *attr) /* TRANSLATORS: Title: CET = Control-flow Enforcement Technology */ return _("Intel CET"); } + if (g_strcmp0 (appstream_id, FWUPD_SECURITY_ATTR_ID_INTEL_SMAP) == 0) { + /* TRANSLATORS: Title: SMAP = Supervisor Mode Access Prevention */ + return _("Intel SMAP"); + } if (g_strcmp0 (appstream_id, FWUPD_SECURITY_ATTR_ID_ENCRYPTED_RAM) == 0) { /* TRANSLATORS: Title: Memory contents are encrypted, e.g. Intel TME */ return _("Encrypted RAM"); From bb6b1a869331c33396d61381e82c8ace1aaf4587 Mon Sep 17 00:00:00 2001 From: Mario Limonciello Date: Fri, 22 May 2020 08:36:16 -0500 Subject: [PATCH 113/607] Revert "amt: Add a security attestation for provisioning" This reverts commit f160e6b7fc75b5b5f5f3e42e0c391d5bede9de9e. --- libfwupd/fwupd-security-attr.h | 1 - plugins/amt/fu-plugin-amt.c | 40 ++-------------------------------- src/fu-security-attr.c | 4 ---- 3 files changed, 2 insertions(+), 43 deletions(-) diff --git a/libfwupd/fwupd-security-attr.h b/libfwupd/fwupd-security-attr.h index 00977397e..b46a00684 100644 --- a/libfwupd/fwupd-security-attr.h +++ b/libfwupd/fwupd-security-attr.h @@ -116,7 +116,6 @@ typedef enum { #define FWUPD_SECURITY_ATTR_ID_FWUPD_ATTESTATION "org.fwupd.hsi.FwupdAttestation" /* Since: 1.5.0 */ #define FWUPD_SECURITY_ATTR_ID_FWUPD_PLUGINS "org.fwupd.hsi.FwupdPlugins" /* Since: 1.5.0 */ #define FWUPD_SECURITY_ATTR_ID_FWUPD_UPDATES "org.fwupd.hsi.FwupdUpdates" /* Since: 1.5.0 */ -#define FWUPD_SECURITY_ATTR_ID_INTEL_AMT "org.fwupd.hsi.IntelAmt" /* Since: 1.5.0 */ #define FWUPD_SECURITY_ATTR_ID_INTEL_CET "org.fwupd.hsi.IntelCet" /* Since: 1.5.0 */ #define FWUPD_SECURITY_ATTR_ID_INTEL_SMAP "org.fwupd.hsi.IntelSmap" /* Since: 1.5.0 */ #define FWUPD_SECURITY_ATTR_ID_IOMMU "org.fwupd.hsi.Iommu" /* Since: 1.5.0 */ diff --git a/plugins/amt/fu-plugin-amt.c b/plugins/amt/fu-plugin-amt.c index ed568f2a2..b1f023025 100644 --- a/plugins/amt/fu-plugin-amt.c +++ b/plugins/amt/fu-plugin-amt.c @@ -17,11 +17,6 @@ #include "fu-plugin-vfuncs.h" #include "fu-hash.h" -struct FuPluginData { - gboolean has_mei; - gboolean provisioned; -}; - typedef struct { uuid_le guid; guint buf_size; @@ -449,9 +444,8 @@ G_DEFINE_AUTOPTR_CLEANUP_FUNC(mei_context, mei_context_free) #pragma clang diagnostic pop static FuDevice * -fu_plugin_amt_create_device (FuPlugin *plugin, GError **error) +fu_plugin_amt_create_device (GError **error) { - FuPluginData *data = fu_plugin_get_data (plugin); guint8 state; struct amt_code_versions ver; fwupd_guid_t uu; @@ -497,19 +491,15 @@ fu_plugin_amt_create_device (FuPlugin *plugin, GError **error) switch (state) { case 0: fu_device_set_name (dev, "Intel AMT [unprovisioned]"); - data->provisioned = FALSE; break; case 1: fu_device_set_name (dev, "Intel AMT [being provisioned]"); - data->provisioned = TRUE; break; case 2: fu_device_set_name (dev, "Intel AMT [provisioned]"); - data->provisioned = TRUE; break; default: fu_device_set_name (dev, "Intel AMT [unknown]"); - data->provisioned = FALSE; break; } fu_device_set_summary (dev, "Hardware and firmware technology for remote " @@ -546,7 +536,6 @@ fu_plugin_amt_create_device (FuPlugin *plugin, GError **error) fu_device_set_version (dev, version_fw->str); if (version_bl->len > 0) fu_device_set_version_bootloader (dev, version_bl->str); - data->has_mei = TRUE; return g_steal_pointer (&dev); } @@ -555,40 +544,15 @@ void fu_plugin_init (FuPlugin *plugin) { fu_plugin_set_build_hash (plugin, FU_BUILD_HASH); - fu_plugin_alloc_data (plugin, sizeof (FuPluginData)); } gboolean fu_plugin_coldplug (FuPlugin *plugin, GError **error) { g_autoptr(FuDevice) dev = NULL; - dev = fu_plugin_amt_create_device (plugin, error); + dev = fu_plugin_amt_create_device (error); if (dev == NULL) return FALSE; fu_plugin_device_add (plugin, dev); return TRUE; } - -void -fu_plugin_add_security_attrs (FuPlugin *plugin, FuSecurityAttrs *attrs) -{ - FuPluginData *data = fu_plugin_get_data (plugin); - g_autoptr(FwupdSecurityAttr) attr = NULL; - - if (!fu_common_is_cpu_intel () || !data->has_mei) - return; - - /* create attr */ - attr = fwupd_security_attr_new (FWUPD_SECURITY_ATTR_ID_INTEL_AMT); - fwupd_security_attr_set_plugin (attr, fu_plugin_get_name (plugin)); - fwupd_security_attr_set_level (attr, FWUPD_SECURITY_ATTR_LEVEL_SYSTEM_PROTECTION); - fu_security_attrs_append (attrs, attr); - if (data->provisioned) { - fwupd_security_attr_set_result (attr, FWUPD_SECURITY_ATTR_RESULT_ENABLED); - return; - } - - /* success */ - fwupd_security_attr_set_result (attr, FWUPD_SECURITY_ATTR_RESULT_NOT_ENABLED); - fwupd_security_attr_add_flag (attr, FWUPD_SECURITY_ATTR_FLAG_SUCCESS); -} diff --git a/src/fu-security-attr.c b/src/fu-security-attr.c index df94007c6..b18332bc1 100644 --- a/src/fu-security-attr.c +++ b/src/fu-security-attr.c @@ -29,10 +29,6 @@ fu_security_attr_get_name (FwupdSecurityAttr *attr) /* TRANSLATORS: Title: DMA as in https://en.wikipedia.org/wiki/DMA_attack */ return _("Pre-boot DMA protection"); } - if (g_strcmp0 (appstream_id, FWUPD_SECURITY_ATTR_ID_INTEL_AMT) == 0) { - /* TRANSLATORS: Title: AMT = Active Management Technology */ - return _("Intel AMT"); - } if (g_strcmp0 (appstream_id, FWUPD_SECURITY_ATTR_ID_INTEL_CET) == 0) { /* TRANSLATORS: Title: CET = Control-flow Enforcement Technology */ return _("Intel CET"); From e3091c394bb7f6c4cc4077dc548c3888144f3857 Mon Sep 17 00:00:00 2001 From: Richard Hughes Date: Fri, 22 May 2020 14:46:18 +0100 Subject: [PATCH 114/607] trivial: Move the SecureBoot attr to a runtime issue --- plugins/uefi/fu-plugin-uefi.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugins/uefi/fu-plugin-uefi.c b/plugins/uefi/fu-plugin-uefi.c index f953e0c98..01f97a156 100644 --- a/plugins/uefi/fu-plugin-uefi.c +++ b/plugins/uefi/fu-plugin-uefi.c @@ -99,7 +99,7 @@ fu_plugin_add_security_attrs (FuPlugin *plugin, FuSecurityAttrs *attrs) /* create attr */ attr = fwupd_security_attr_new (FWUPD_SECURITY_ATTR_ID_UEFI_SECUREBOOT); fwupd_security_attr_set_plugin (attr, fu_plugin_get_name (plugin)); - fwupd_security_attr_set_level (attr, FWUPD_SECURITY_ATTR_LEVEL_CRITICAL); + fwupd_security_attr_add_flag (attr, FWUPD_SECURITY_ATTR_FLAG_RUNTIME_ISSUE); fu_security_attrs_append (attrs, attr); /* SB disabled */ From 4b16642dc5568ab3f0d11126673486cfe8f9572a Mon Sep 17 00:00:00 2001 From: Richard Hughes Date: Fri, 22 May 2020 15:34:16 +0100 Subject: [PATCH 115/607] ccgx: Fix a potential division by zero Spotted by Coverity. --- plugins/ccgx/fu-ccgx-firmware.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/plugins/ccgx/fu-ccgx-firmware.c b/plugins/ccgx/fu-ccgx-firmware.c index 1d339ede9..d23ac0408 100644 --- a/plugins/ccgx/fu-ccgx-firmware.c +++ b/plugins/ccgx/fu-ccgx-firmware.c @@ -164,6 +164,13 @@ fu_ccgx_firmware_parse_md_block (FuCcgxFirmware *self, FuFirmwareImage *img, GEr /* read metadata from correct ofsset */ rcd = g_ptr_array_index (self->records, self->records->len - 1); buf = g_bytes_get_data (rcd->data, &bufsz); + if (bufsz == 0) { + g_set_error_literal (error, + FWUPD_ERROR, + FWUPD_ERROR_NOT_SUPPORTED, + "invalid buffer size"); + return FALSE; + } switch (bufsz) { case 0x80: md_offset = 0x40; From b3d3f21a00fbbdd0724b1f820c3da740458bca13 Mon Sep 17 00:00:00 2001 From: Richard Hughes Date: Thu, 21 May 2020 21:14:49 +0100 Subject: [PATCH 116/607] Check the device requirements when returning from GetDetails One vendor is shipping a cab archive with two metadata files, both referencing the same GUID. The 'correct' metainfo description is selected using a GUID 'other device' requirement. This works fine when installing, but breaks when double clicking on the .cab file as both components are valid, and thus get returned. In this case, return the component that matches the requirement 'first' so that it gets chosen by gnome-software as the default. --- src/fu-engine.c | 40 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 40 insertions(+) diff --git a/src/fu-engine.c b/src/fu-engine.c index ced8776f7..9fef0b56a 100644 --- a/src/fu-engine.c +++ b/src/fu-engine.c @@ -3502,6 +3502,20 @@ fu_engine_get_result_from_component (FuEngine *self, XbNode *component, GError * return g_steal_pointer (&dev); } +static gint +fu_engine_get_details_sort_cb (gconstpointer a, gconstpointer b) +{ + FuDevice *device1 = *((FuDevice **) a); + FuDevice *device2 = *((FuDevice **) b); + if (!fu_device_has_flag (device1, FWUPD_DEVICE_FLAG_UPDATABLE) && + fu_device_has_flag (device2, FWUPD_DEVICE_FLAG_UPDATABLE)) + return 1; + if (fu_device_has_flag (device1, FWUPD_DEVICE_FLAG_UPDATABLE) && + !fu_device_has_flag (device2, FWUPD_DEVICE_FLAG_UPDATABLE)) + return -1; + return 0; +} + /** * fu_engine_get_details: * @self: A #FuEngine @@ -3574,8 +3588,34 @@ fu_engine_get_details (FuEngine *self, gint fd, GError **error) fu_device_add_flag (dev, FWUPD_DEVICE_FLAG_SUPPORTED); } fu_engine_md_refresh_device_from_component (self, dev, component); + + /* if this matched a device on the system, ensure all the + * requirements passed before setting UPDATABLE */ + if (fu_device_has_flag (dev, FWUPD_DEVICE_FLAG_UPDATABLE)) { + g_autoptr(FuInstallTask) task = fu_install_task_new (dev, component); + g_autoptr(GError) error_req = NULL; + if (!fu_engine_check_requirements (self, task, + FWUPD_INSTALL_FLAG_OFFLINE | + FWUPD_INSTALL_FLAG_ALLOW_REINSTALL | + FWUPD_INSTALL_FLAG_ALLOW_OLDER, + &error_req)) { + g_debug ("%s failed requirement checks: %s", + fu_device_get_id (dev), + error_req->message); + fu_device_remove_flag (dev, FWUPD_DEVICE_FLAG_UPDATABLE); + } else { + g_debug ("%s passed requirement checks", + fu_device_get_id (dev)); + } + } + g_ptr_array_add (details, dev); } + + /* order multiple devices so that the one that passes the requirement + * is listed first */ + g_ptr_array_sort (details, fu_engine_get_details_sort_cb); + return g_steal_pointer (&details); } From 4a844c3024179ec82b0efde7bed10f17eb25d146 Mon Sep 17 00:00:00 2001 From: Mario Limonciello Date: Tue, 26 May 2020 00:56:56 -0500 Subject: [PATCH 117/607] trivial: drop libgpgme deps These aren't needed anymore since moving to libjcat Note: snap still keeps them because libjcat builds in snap and needs them. --- contrib/ci/dependencies.xml | 18 ------------------ contrib/fwupd.spec.in | 1 - 2 files changed, 19 deletions(-) diff --git a/contrib/ci/dependencies.xml b/contrib/ci/dependencies.xml index fb09674cf..c5aa7ed85 100644 --- a/contrib/ci/dependencies.xml +++ b/contrib/ci/dependencies.xml @@ -495,24 +495,6 @@ - - - gpgme-devel - - - gpgme-devel - - - - - libgpgme-dev:s390x - - - - - - - diff --git a/contrib/fwupd.spec.in b/contrib/fwupd.spec.in index c106b6596..cfc7e8f98 100644 --- a/contrib/fwupd.spec.in +++ b/contrib/fwupd.spec.in @@ -56,7 +56,6 @@ BuildRequires: libsoup-devel >= %{libsoup_version} BuildRequires: libjcat-devel >= %{libjcat_version} BuildRequires: polkit-devel >= 0.103 BuildRequires: sqlite-devel -BuildRequires: gpgme-devel BuildRequires: systemd >= %{systemd_version} BuildRequires: libarchive-devel BuildRequires: gobject-introspection-devel From a42daefb9e5df893375bcd683c7f7848b01f72d4 Mon Sep 17 00:00:00 2001 From: Mario Limonciello Date: Tue, 26 May 2020 00:07:19 -0500 Subject: [PATCH 118/607] dell-dock: Capture the dock SKU in metadata Should be helpful in reproducing failure reports. --- plugins/dell-dock/fu-dell-dock-i2c-ec.c | 16 ++++++++++++++++ plugins/dell-dock/fu-dell-dock-i2c-ec.h | 1 + plugins/dell-dock/fu-plugin-dell-dock.c | 19 +++++++++++++++++++ 3 files changed, 36 insertions(+) diff --git a/plugins/dell-dock/fu-dell-dock-i2c-ec.c b/plugins/dell-dock/fu-dell-dock-i2c-ec.c index 75f70e91c..eebdf6615 100644 --- a/plugins/dell-dock/fu-dell-dock-i2c-ec.c +++ b/plugins/dell-dock/fu-dell-dock-i2c-ec.c @@ -172,6 +172,22 @@ fu_dell_dock_ec_set_board (FuDevice *device) fu_device_set_summary (device, summary); } +const gchar * +fu_dell_dock_ec_get_module_type (FuDevice *device) +{ + FuDellDockEc *self = FU_DELL_DOCK_EC (device); + switch (self->data->module_type) { + case MODULE_TYPE_SINGLE: + return "WD19"; + case MODULE_TYPE_DUAL: + return "WD19DC"; + case MODULE_TYPE_TBT: + return "WD19TB"; + default: + return NULL; + } +} + gboolean fu_dell_dock_ec_needs_tbt (FuDevice *device) { diff --git a/plugins/dell-dock/fu-dell-dock-i2c-ec.h b/plugins/dell-dock/fu-dell-dock-i2c-ec.h index 50e19dfa4..2e1b182cb 100644 --- a/plugins/dell-dock/fu-dell-dock-i2c-ec.h +++ b/plugins/dell-dock/fu-dell-dock-i2c-ec.h @@ -26,6 +26,7 @@ G_DECLARE_FINAL_TYPE (FuDellDockEc, fu_dell_dock_ec, FU, DELL_DOCK_EC, FuDevice) FuDellDockEc *fu_dell_dock_ec_new (FuDevice *proxy); +const gchar *fu_dell_dock_ec_get_module_type (FuDevice *device); gboolean fu_dell_dock_ec_needs_tbt (FuDevice *device); gboolean fu_dell_dock_ec_tbt_passive (FuDevice *device); gboolean fu_dell_dock_ec_modify_lock (FuDevice *self, diff --git a/plugins/dell-dock/fu-plugin-dell-dock.c b/plugins/dell-dock/fu-plugin-dell-dock.c index a6070e915..41e850588 100644 --- a/plugins/dell-dock/fu-plugin-dell-dock.c +++ b/plugins/dell-dock/fu-plugin-dell-dock.c @@ -164,6 +164,25 @@ fu_plugin_dell_dock_get_ec (GPtrArray *devices) return ec_parent; } +gboolean +fu_plugin_composite_prepare (FuPlugin *plugin, GPtrArray *devices, + GError **error) +{ + FuDevice *parent = fu_plugin_dell_dock_get_ec (devices); + const gchar *sku; + if (parent == NULL) + return TRUE; + sku = fu_dell_dock_ec_get_module_type (parent); + if (sku == NULL) { + g_set_error_literal (error, FWUPD_ERROR, FWUPD_ERROR_INTERNAL, + "unable to detect SKU"); + return FALSE; + } + fu_plugin_add_report_metadata (plugin, "DellDockSKU", sku); + + return TRUE; +} + gboolean fu_plugin_composite_cleanup (FuPlugin *plugin, GPtrArray *devices, From 1a520514717cca78c2d8e15b3bbb856e71ec7df2 Mon Sep 17 00:00:00 2001 From: Mario Limonciello Date: Tue, 26 May 2020 10:44:53 -0500 Subject: [PATCH 119/607] fu-engine: Allow --plugin-whitelist to use dashes instead of underscores I have found this confusing myself that even if plugins have the dash in the name the daemon needs to internally use underscores. --- src/fu-engine.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/fu-engine.c b/src/fu-engine.c index 9fef0b56a..56859b600 100644 --- a/src/fu-engine.c +++ b/src/fu-engine.c @@ -5166,9 +5166,12 @@ fu_engine_is_plugin_name_whitelisted (FuEngine *self, const gchar *name) void fu_engine_add_plugin_filter (FuEngine *self, const gchar *plugin_glob) { + GString *str; g_return_if_fail (FU_IS_ENGINE (self)); g_return_if_fail (plugin_glob != NULL); - g_ptr_array_add (self->plugin_filter, g_strdup (plugin_glob)); + str = g_string_new (plugin_glob); + fu_common_string_replace (str, "-", "_"); + g_ptr_array_add (self->plugin_filter, g_string_free (str, FALSE)); } static gboolean From d39bcee29d71eb19ba2a3c18e8bf6709397b6056 Mon Sep 17 00:00:00 2001 From: Mario Limonciello Date: Tue, 26 May 2020 14:49:51 -0500 Subject: [PATCH 120/607] trivial: detect `cpuid.h` and also look for host architecture Fixes cross compilation for arm with clang which provides cpuid.h but helpfully has this error: ``` #if !(__x86_64__ || __i386__) #error this header is for x86 only #endif ``` Fixes: #2131 --- meson.build | 13 +++++++------ plugins/uefi/efi/meson.build | 6 +++--- 2 files changed, 10 insertions(+), 9 deletions(-) diff --git a/meson.build b/meson.build index 3e3afa773..426760d91 100644 --- a/meson.build +++ b/meson.build @@ -243,6 +243,8 @@ if build_standalone and get_option('plugin_altos') libelf = dependency('libelf') endif +host_cpu = host_machine.cpu_family() + if cc.has_header('sys/utsname.h') conf.set('HAVE_UTSNAME_H', '1') endif @@ -258,7 +260,7 @@ endif if cc.has_header('fnmatch.h') conf.set('HAVE_FNMATCH_H', '1') endif -if cc.has_header('cpuid.h') +if cc.has_header('cpuid.h') and (host_cpu == 'x86' or host_cpu == 'x86_64') conf.set('HAVE_CPUID_H', '1') endif if cc.has_function('getuid') @@ -305,17 +307,16 @@ if build_standalone and get_option('plugin_uefi') conf.set_quoted ('FWUPD_EFI_DBXDIR', efi_dbxdir) endif - efi_arch = host_machine.cpu_family() - if efi_arch == 'x86' + if host_cpu == 'x86' EFI_MACHINE_TYPE_NAME = 'ia32' gnu_efi_arch = 'ia32' - elif efi_arch == 'x86_64' + elif host_cpu == 'x86_64' EFI_MACHINE_TYPE_NAME = 'x64' gnu_efi_arch = 'x86_64' - elif efi_arch == 'arm' + elif host_cpu == 'arm' EFI_MACHINE_TYPE_NAME = 'arm' gnu_efi_arch = 'arm' - elif efi_arch == 'aarch64' + elif host_cpu == 'aarch64' EFI_MACHINE_TYPE_NAME = 'aa64' gnu_efi_arch = 'aarch64' else diff --git a/plugins/uefi/efi/meson.build b/plugins/uefi/efi/meson.build index c6be302a6..d834e6267 100644 --- a/plugins/uefi/efi/meson.build +++ b/plugins/uefi/efi/meson.build @@ -90,13 +90,13 @@ compile_args = ['-Og', if get_option('werror') compile_args += '-Werror' endif -if efi_arch == 'x86_64' +if host_cpu == 'x86_64' compile_args += ['-mno-red-zone', '-mno-sse', '-mno-mmx', '-DEFI_FUNCTION_WRAPPER', '-DGNU_EFI_USE_MS_ABI'] -elif efi_arch == 'ia32' +elif host_cpu == 'x86' compile_args += ['-mno-sse', '-mno-mmx', '-mno-red-zone', @@ -113,7 +113,7 @@ efi_ldflags = ['-T', '-L', efi_ldsdir, '-L', efi_libdir, join_paths(efi_ldsdir, arch_crt)] -if efi_arch == 'aarch64' or efi_arch == 'arm' +if host_cpu == 'aarch64' or host_cpu == 'arm' # Aarch64 and ARM32 don't have an EFI capable objcopy. Use 'binary' # instead, and add required symbols manually. efi_ldflags += ['--defsym=EFI_SUBSYSTEM=0xa'] From 862ec5c65b28be2fb82f742e943a622351e0c672 Mon Sep 17 00:00:00 2001 From: Richard Hughes Date: Fri, 22 May 2020 14:38:02 +0100 Subject: [PATCH 121/607] Skip module unloading only if we are actually running under valgrind See also: https://github.com/fwupd/fwupd/issues/2119 Reported-by: Anton Farygin Based on a patch by Gleb Fotengauer-Malinovskiy --- libfwupdplugin/fu-plugin.c | 6 +- plugins/dell/fu-self-test.c | 223 ++++++++++++++++++++---------------- 2 files changed, 126 insertions(+), 103 deletions(-) diff --git a/libfwupdplugin/fu-plugin.c b/libfwupdplugin/fu-plugin.c index 4ba255bde..12c036196 100644 --- a/libfwupdplugin/fu-plugin.c +++ b/libfwupdplugin/fu-plugin.c @@ -2792,10 +2792,12 @@ fu_plugin_finalize (GObject *object) g_free (priv->data); /* Must happen as the last step to avoid prematurely * freeing memory held by the plugin */ -#ifndef RUNNING_ON_VALGRIND +#ifdef RUNNING_ON_VALGRIND + if (priv->module != NULL && RUNNING_ON_VALGRIND == 0) +#else if (priv->module != NULL) - g_module_close (priv->module); #endif + g_module_close (priv->module); G_OBJECT_CLASS (fu_plugin_parent_class)->finalize (object); } diff --git a/plugins/dell/fu-self-test.c b/plugins/dell/fu-self-test.c index d69ca6bd2..705dc736a 100644 --- a/plugins/dell/fu-self-test.c +++ b/plugins/dell/fu-self-test.c @@ -16,6 +16,11 @@ #include "fu-plugin-vfuncs.h" #include "fu-hash.h" +typedef struct { + FuPlugin *plugin_uefi; + FuPlugin *plugin_dell; +} FuTest; + static FuDevice * _find_device_by_id (GPtrArray *devices, const gchar *device_id) { @@ -62,57 +67,21 @@ fu_engine_plugin_device_register_cb (FuPlugin *plugin_dell, } static void -fu_plugin_dell_tpm_func (void) +fu_plugin_dell_tpm_func (gconstpointer user_data) { + FuTest *self = (FuTest *) user_data; FuDevice *device_v12; FuDevice *device_v20; const guint8 fw[30] = { 'F', 'W', 0x00 }; gboolean ret; + gulong added_id; + gulong register_id; struct tpm_status tpm_out; const gchar *tpm_server_running = g_getenv ("TPM_SERVER_RUNNING"); - g_autofree gchar *pluginfn_uefi = NULL; - g_autofree gchar *pluginfn_dell = NULL; - g_autoptr(FuPlugin) plugin_dell = NULL; - g_autoptr(FuPlugin) plugin_uefi = NULL; g_autoptr(GBytes) blob_fw = g_bytes_new_static (fw, sizeof(fw)); g_autoptr(GError) error = NULL; g_autoptr(GPtrArray) devices = NULL; - pluginfn_uefi = g_build_filename (PLUGINBUILDDIR, "..", "uefi", - "libfu_plugin_uefi." G_MODULE_SUFFIX, - NULL); - pluginfn_dell = g_build_filename (PLUGINBUILDDIR, - "libfu_plugin_dell." G_MODULE_SUFFIX, - NULL); - - memset (&tpm_out, 0x0, sizeof(tpm_out)); - - plugin_uefi = fu_plugin_new (); - ret = fu_plugin_open (plugin_uefi, pluginfn_uefi, &error); - g_assert_no_error (error); - g_assert (ret); - ret = fu_plugin_runner_startup (plugin_uefi, &error); - g_assert_no_error (error); - g_assert (ret); - devices = g_ptr_array_new_with_free_func ((GDestroyNotify) g_object_unref); - g_signal_connect (plugin_uefi, "device-added", - G_CALLBACK (_plugin_device_added_cb), - devices); - - plugin_dell = fu_plugin_new (); - ret = fu_plugin_open (plugin_dell, pluginfn_dell, &error); - g_assert_no_error (error); - g_assert (ret); - ret = fu_plugin_runner_startup (plugin_dell, &error); - g_assert_no_error (error); - g_assert (ret); - g_signal_connect (plugin_dell, "device-register", - G_CALLBACK (fu_engine_plugin_device_register_cb), - plugin_uefi); - ret = fu_plugin_runner_coldplug (plugin_dell, &error); - g_assert_no_error (error); - g_assert (ret); - #ifdef HAVE_GETUID if (tpm_server_running == NULL && (getuid () != 0 || geteuid () != 0)) { @@ -121,12 +90,28 @@ fu_plugin_dell_tpm_func (void) } #endif + memset (&tpm_out, 0x0, sizeof(tpm_out)); + + devices = g_ptr_array_new_with_free_func ((GDestroyNotify) g_object_unref); + added_id = + g_signal_connect (self->plugin_uefi, "device-added", + G_CALLBACK (_plugin_device_added_cb), + devices); + + register_id = + g_signal_connect (self->plugin_dell, "device-register", + G_CALLBACK (fu_engine_plugin_device_register_cb), + self->plugin_uefi); + ret = fu_plugin_runner_coldplug (self->plugin_dell, &error); + g_assert_no_error (error); + g_assert (ret); + /* inject fake data (no TPM) */ tpm_out.ret = -2; - fu_plugin_dell_inject_fake_data (plugin_dell, + fu_plugin_dell_inject_fake_data (self->plugin_dell, (guint32 *) &tpm_out, 0, 0, NULL, FALSE); - ret = fu_plugin_dell_detect_tpm (plugin_dell, &error); + ret = fu_plugin_dell_detect_tpm (self->plugin_dell, &error); g_assert_no_error (error); g_assert_false (ret); g_assert_cmpint (devices->len, ==, 0); @@ -141,10 +126,10 @@ fu_plugin_dell_tpm_func (void) tpm_out.fw_version = 0; tpm_out.status = TPM_EN_MASK | (TPM_1_2_MODE << 8); tpm_out.flashes_left = 0; - fu_plugin_dell_inject_fake_data (plugin_dell, + fu_plugin_dell_inject_fake_data (self->plugin_dell, (guint32 *) &tpm_out, 0, 0, NULL, TRUE); - ret = fu_plugin_dell_detect_tpm (plugin_dell, &error); + ret = fu_plugin_dell_detect_tpm (self->plugin_dell, &error); g_assert_true (ret); g_assert_cmpint (devices->len, ==, 2); @@ -159,7 +144,7 @@ fu_plugin_dell_tpm_func (void) g_assert_false (fu_device_has_flag (device_v12, FWUPD_DEVICE_FLAG_UPDATABLE)); /* try to unlock 2.0 */ - ret = fu_plugin_runner_unlock (plugin_uefi, device_v20, &error); + ret = fu_plugin_runner_unlock (self->plugin_uefi, device_v20, &error); g_assert_error (error, FWUPD_ERROR, FWUPD_ERROR_NOT_SUPPORTED); g_assert_false (ret); g_clear_error (&error); @@ -175,10 +160,10 @@ fu_plugin_dell_tpm_func (void) */ tpm_out.status = TPM_EN_MASK | TPM_OWN_MASK | (TPM_1_2_MODE << 8); tpm_out.flashes_left = 125; - fu_plugin_dell_inject_fake_data (plugin_dell, + fu_plugin_dell_inject_fake_data (self->plugin_dell, (guint32 *) &tpm_out, 0, 0, NULL, TRUE); - ret = fu_plugin_dell_detect_tpm (plugin_dell, &error); + ret = fu_plugin_dell_detect_tpm (self->plugin_dell, &error); g_assert_no_error (error); g_assert (ret); @@ -190,7 +175,7 @@ fu_plugin_dell_tpm_func (void) /* try to unlock 2.0 */ device_v20 = _find_device_by_name (devices, "TPM 2.0"); g_assert_nonnull (device_v20); - ret = fu_plugin_runner_unlock (plugin_uefi, device_v20, &error); + ret = fu_plugin_runner_unlock (self->plugin_uefi, device_v20, &error); g_assert_error (error, FWUPD_ERROR, FWUPD_ERROR_NOT_SUPPORTED); g_assert_false (ret); g_clear_error (&error); @@ -206,10 +191,10 @@ fu_plugin_dell_tpm_func (void) */ tpm_out.status = TPM_EN_MASK | (TPM_1_2_MODE << 8); tpm_out.flashes_left = 125; - fu_plugin_dell_inject_fake_data (plugin_dell, + fu_plugin_dell_inject_fake_data (self->plugin_dell, (guint32 *) &tpm_out, 0, 0, NULL, TRUE); - ret = fu_plugin_dell_detect_tpm (plugin_dell, &error); + ret = fu_plugin_dell_detect_tpm (self->plugin_dell, &error); g_assert_no_error (error); g_assert (ret); @@ -222,7 +207,7 @@ fu_plugin_dell_tpm_func (void) g_assert_false (fu_device_has_flag (device_v20, FWUPD_DEVICE_FLAG_UPDATABLE)); /* try to unlock 2.0 */ - ret = fu_plugin_runner_unlock (plugin_uefi, device_v20, &error); + ret = fu_plugin_runner_unlock (self->plugin_uefi, device_v20, &error); g_assert_no_error (error); g_assert (ret); @@ -241,10 +226,10 @@ fu_plugin_dell_tpm_func (void) */ tpm_out.status = TPM_EN_MASK | (TPM_2_0_MODE << 8); tpm_out.flashes_left = 1; - fu_plugin_dell_inject_fake_data (plugin_dell, + fu_plugin_dell_inject_fake_data (self->plugin_dell, (guint32 *) &tpm_out, 0, 0, NULL, TRUE); - ret = fu_plugin_dell_detect_tpm (plugin_dell, &error); + ret = fu_plugin_dell_detect_tpm (self->plugin_dell, &error); g_assert_no_error (error); g_assert (ret); @@ -257,7 +242,7 @@ fu_plugin_dell_tpm_func (void) g_assert_false (fu_device_has_flag (device_v12, FWUPD_DEVICE_FLAG_UPDATABLE)); /* With one flash left we need an override */ - ret = fu_plugin_runner_update (plugin_uefi, device_v20, blob_fw, + ret = fu_plugin_runner_update (self->plugin_uefi, device_v20, blob_fw, FWUPD_INSTALL_FLAG_NONE, &error); g_assert_error (error, FWUPD_ERROR, FWUPD_ERROR_NOT_SUPPORTED); g_assert_false (ret); @@ -266,62 +251,45 @@ fu_plugin_dell_tpm_func (void) /* test override */ g_test_expect_message ("FuPluginUefi", G_LOG_LEVEL_WARNING, "missing or invalid embedded capsule header"); - ret = fu_plugin_runner_update (plugin_uefi, device_v20, blob_fw, + ret = fu_plugin_runner_update (self->plugin_uefi, device_v20, blob_fw, FWUPD_INSTALL_FLAG_FORCE, &error); g_test_assert_expected_messages (); g_assert_no_error (error); g_assert (ret); + + /* all */ + g_signal_handler_disconnect (self->plugin_uefi, added_id); + g_signal_handler_disconnect (self->plugin_dell, register_id); } static void -fu_plugin_dell_dock_func (void) +fu_plugin_dell_dock_func (gconstpointer user_data) { + FuTest *self = (FuTest *) user_data; gboolean ret; guint32 out[4] = { 0x0, 0x0, 0x0, 0x0 }; DOCK_UNION buf; DOCK_INFO *dock_info; - g_autofree gchar *pluginfn_uefi = NULL; - g_autofree gchar *pluginfn_dell = NULL; g_autoptr(GError) error = NULL; g_autoptr(GPtrArray) devices = NULL; - g_autoptr(FuPlugin) plugin_uefi = fu_plugin_new (); - g_autoptr(FuPlugin) plugin_dell = fu_plugin_new (); + gulong added_id; + gulong register_id; - pluginfn_uefi = g_build_filename (PLUGINBUILDDIR, "..", "uefi", - "libfu_plugin_uefi." G_MODULE_SUFFIX, - NULL); - pluginfn_dell = g_build_filename (PLUGINBUILDDIR, - "libfu_plugin_dell." G_MODULE_SUFFIX, - NULL); - - ret = fu_plugin_open (plugin_uefi, pluginfn_uefi, &error); - g_assert_no_error (error); - g_assert (ret); - ret = fu_plugin_runner_startup (plugin_uefi, &error); - g_assert_no_error (error); - g_assert (ret); devices = g_ptr_array_new_with_free_func ((GDestroyNotify) g_object_unref); - g_signal_connect (plugin_uefi, "device-added", + added_id = + g_signal_connect (self->plugin_uefi, "device-added", G_CALLBACK (_plugin_device_added_cb), devices); - ret = fu_plugin_open (plugin_dell, pluginfn_dell, &error); - g_assert_no_error (error); - g_assert (ret); - ret = fu_plugin_runner_startup (plugin_dell, &error); - g_assert_no_error (error); - g_assert (ret); - g_signal_connect (plugin_dell, "device-register", + register_id = + g_signal_connect (self->plugin_dell, "device-register", G_CALLBACK (fu_engine_plugin_device_register_cb), - plugin_uefi); - ret = fu_plugin_runner_coldplug (plugin_dell, &error); - g_assert_no_error (error); - g_assert (ret); + self->plugin_uefi); /* make sure bad device doesn't trigger this */ - fu_plugin_dell_inject_fake_data (plugin_dell, + fu_plugin_dell_inject_fake_data (self->plugin_dell, (guint32 *) &out, 0x1234, 0x4321, NULL, FALSE); - ret = fu_plugin_usb_device_added (plugin_dell, NULL, &error); + ret = fu_plugin_usb_device_added (self->plugin_dell, NULL, &error); g_assert_false (ret); g_clear_error (&error); g_assert_cmpint (devices->len, ==, 0); @@ -329,11 +297,11 @@ fu_plugin_dell_dock_func (void) /* inject a USB dongle matching correct VID/PID */ out[0] = 0; out[1] = 0; - fu_plugin_dell_inject_fake_data (plugin_dell, + fu_plugin_dell_inject_fake_data (self->plugin_dell, (guint32 *) &out, DOCK_NIC_VID, DOCK_NIC_PID, NULL, FALSE); - ret = fu_plugin_usb_device_added (plugin_dell, NULL, &error); + ret = fu_plugin_usb_device_added (self->plugin_dell, NULL, &error); g_assert_true (ret); g_clear_error (&error); g_assert_cmpint (devices->len, ==, 0); @@ -363,11 +331,11 @@ fu_plugin_dell_dock_func (void) "Dock1,Cable,Cyp,TBT_Cable,0 :Query 2 2 2 3 0", 44); out[0] = 0; out[1] = 1; - fu_plugin_dell_inject_fake_data (plugin_dell, + fu_plugin_dell_inject_fake_data (self->plugin_dell, (guint32 *) &out, DOCK_NIC_VID, DOCK_NIC_PID, buf.buf, FALSE); - ret = fu_plugin_usb_device_added (plugin_dell, NULL, NULL); + ret = fu_plugin_usb_device_added (self->plugin_dell, NULL, NULL); g_assert (ret); g_assert_cmpint (devices->len, ==, 4); g_ptr_array_set_size (devices, 0); @@ -398,11 +366,11 @@ fu_plugin_dell_dock_func (void) "Dock1,Cable,Cyp,TBT_Cable,0 :Query 2 2 2 3 0", 44); out[0] = 0; out[1] = 1; - fu_plugin_dell_inject_fake_data (plugin_dell, + fu_plugin_dell_inject_fake_data (self->plugin_dell, (guint32 *) &out, DOCK_NIC_VID, DOCK_NIC_PID, buf.buf, FALSE); - ret = fu_plugin_usb_device_added (plugin_dell, NULL, NULL); + ret = fu_plugin_usb_device_added (self->plugin_dell, NULL, NULL); g_assert (ret); g_assert_cmpint (devices->len, ==, 3); g_ptr_array_set_size (devices, 0); @@ -430,11 +398,11 @@ fu_plugin_dell_dock_func (void) "Dock1,Cable,Cyp,IE_Cable,0 :Query 2 2 2 1 0", 43); out[0] = 0; out[1] = 1; - fu_plugin_dell_inject_fake_data (plugin_dell, + fu_plugin_dell_inject_fake_data (self->plugin_dell, (guint32 *) &out, DOCK_NIC_VID, DOCK_NIC_PID, buf.buf, FALSE); - ret = fu_plugin_usb_device_added (plugin_dell, NULL, &error); + ret = fu_plugin_usb_device_added (self->plugin_dell, NULL, &error); g_assert (ret); g_assert_no_error (error); g_assert_cmpint (devices->len, ==, 3); @@ -463,11 +431,11 @@ fu_plugin_dell_dock_func (void) "Dock1,Cable,Cyp,IE_Cable,0 :Query 2 2 2 1 0", 43); out[0] = 0; out[1] = 1; - fu_plugin_dell_inject_fake_data (plugin_dell, + fu_plugin_dell_inject_fake_data (self->plugin_dell, (guint32 *) &out, DOCK_NIC_VID, DOCK_NIC_PID, buf.buf, FALSE); - ret = fu_plugin_usb_device_added (plugin_dell, NULL, &error); + ret = fu_plugin_usb_device_added (self->plugin_dell, NULL, &error); g_assert (ret); g_assert_no_error (error); g_assert_cmpint (devices->len, ==, 2); @@ -490,20 +458,72 @@ fu_plugin_dell_dock_func (void) "Dock1,EC,MIPS32,FUT_Dock,0 :Query 2 0 2 2 0", 43); out[0] = 0; out[1] = 1; - fu_plugin_dell_inject_fake_data (plugin_dell, + fu_plugin_dell_inject_fake_data (self->plugin_dell, (guint32 *) &out, DOCK_NIC_VID, DOCK_NIC_PID, buf.buf, FALSE); - ret = fu_plugin_usb_device_added (plugin_dell, NULL, &error); + ret = fu_plugin_usb_device_added (self->plugin_dell, NULL, &error); g_assert_false (ret); g_assert_cmpint (devices->len, ==, 0); g_free (buf.record); + + /* all */ + g_signal_handler_disconnect (self->plugin_uefi, added_id); + g_signal_handler_disconnect (self->plugin_dell, register_id); } +static void +fu_test_self_init (FuTest *self) +{ + gboolean ret; + g_autoptr(GError) error = NULL; + g_autofree gchar *pluginfn_uefi = NULL; + g_autofree gchar *pluginfn_dell = NULL; + + self->plugin_uefi = fu_plugin_new (); + pluginfn_uefi = g_build_filename (PLUGINBUILDDIR, "..", "uefi", + "libfu_plugin_uefi." G_MODULE_SUFFIX, + NULL); + ret = fu_plugin_open (self->plugin_uefi, pluginfn_uefi, &error); + g_assert_no_error (error); + g_assert (ret); + ret = fu_plugin_runner_startup (self->plugin_uefi, &error); + g_assert_no_error (error); + g_assert (ret); + + self->plugin_dell = fu_plugin_new (); + pluginfn_dell = g_build_filename (PLUGINBUILDDIR, + "libfu_plugin_dell." G_MODULE_SUFFIX, + NULL); + ret = fu_plugin_open (self->plugin_dell, pluginfn_dell, &error); + g_assert_no_error (error); + g_assert (ret); + ret = fu_plugin_runner_startup (self->plugin_dell, &error); + g_assert_no_error (error); + g_assert (ret); +} + +static void +fu_test_self_free (FuTest *self) +{ + if (self->plugin_uefi != NULL) + g_object_unref (self->plugin_uefi); + if (self->plugin_dell != NULL) + g_object_unref (self->plugin_dell); + g_free (self); +} + +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wunused-function" +G_DEFINE_AUTOPTR_CLEANUP_FUNC(FuTest, fu_test_self_free) +#pragma clang diagnostic pop + int main (int argc, char **argv) { g_autofree gchar *sysfsdir = NULL; + g_autoptr(FuTest) self = g_new0 (FuTest, 1); + g_test_init (&argc, &argv, NULL); /* change path */ @@ -521,7 +541,8 @@ main (int argc, char **argv) g_assert_cmpint (g_mkdir_with_parents ("/tmp/fwupd-self-test/var/lib/fwupd", 0755), ==, 0); /* tests go here */ - g_test_add_func ("/fwupd/plugin{dell:tpm}", fu_plugin_dell_tpm_func); - g_test_add_func ("/fwupd/plugin{dell:dock}", fu_plugin_dell_dock_func); + fu_test_self_init (self); + g_test_add_data_func ("/fwupd/plugin{dell:tpm}", self, fu_plugin_dell_tpm_func); + g_test_add_data_func ("/fwupd/plugin{dell:dock}", self, fu_plugin_dell_dock_func); return g_test_run (); } From 137649d9b24c5105690552e233b57f7686b376de Mon Sep 17 00:00:00 2001 From: Richard Hughes Date: Thu, 28 May 2020 13:36:24 +0100 Subject: [PATCH 122/607] Fix regression when using GetDetails on a device with _MD_SET_NAME set In f430da0 we added code that was supposed to copy the verfmt from the component to the device. We accidentally overwrote the component-provided because the device had _MD_SET_NAME set. Use the specific function to just set the verfmt like we intended. --- src/fu-engine.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/fu-engine.c b/src/fu-engine.c index 56859b600..174f07ea6 100644 --- a/src/fu-engine.c +++ b/src/fu-engine.c @@ -3587,7 +3587,8 @@ fu_engine_get_details (FuEngine *self, gint fd, GError **error) fwupd_release_set_remote_id (rel, remote_id); fu_device_add_flag (dev, FWUPD_DEVICE_FLAG_SUPPORTED); } - fu_engine_md_refresh_device_from_component (self, dev, component); + if (fu_device_has_flag (dev, FWUPD_DEVICE_FLAG_MD_SET_VERFMT)) + fu_engine_md_refresh_device_verfmt (self, dev, component); /* if this matched a device on the system, ensure all the * requirements passed before setting UPDATABLE */ From 838ae163e33edff682874ef0930f24da58643662 Mon Sep 17 00:00:00 2001 From: Mario Limonciello Date: Wed, 27 May 2020 13:03:53 -0500 Subject: [PATCH 123/607] dell-dock: prevent updates to occur via synaptics-mst plugin Although they normally work, some failures have been reported in the field related to the MST hub not responding in the MST plugin. When these failures have occurred the dell_dock plugin also fails to enumerate. So rather than allow some people who don't have dell_dock compiled to update their MST hub using synaptics_mst, perform ALL updates for mst hub via dell_dock. ``` 18:06:24:0324 FuPluginSynapticsMST no device found on drm_dp_aux1: VMM5331 inside Dell dock is only supported by dell_dock ``` --- plugins/dell-dock/dell-dock.quirk | 2 +- plugins/synaptics-mst/fu-synaptics-mst-device.c | 11 +++++++++++ plugins/synaptics-mst/synaptics-mst.quirk | 3 --- 3 files changed, 12 insertions(+), 4 deletions(-) diff --git a/plugins/dell-dock/dell-dock.quirk b/plugins/dell-dock/dell-dock.quirk index 2a3c713b8..f3f58719a 100644 --- a/plugins/dell-dock/dell-dock.quirk +++ b/plugins/dell-dock/dell-dock.quirk @@ -86,7 +86,7 @@ DellDockBlobVersionOffset = 0x14 Name = VMM5331 in Dell dock Summary = Multi Stream Transport controller Vendor = Dell Inc. -Plugin = synaptics_mst +Plugin = dell_dock ParentGuid = USB\VID_413C&PID_B06E&hub&embedded Flags = skips-restart,require-ac,dual-image,usable-during-update FirmwareSize=524288 diff --git a/plugins/synaptics-mst/fu-synaptics-mst-device.c b/plugins/synaptics-mst/fu-synaptics-mst-device.c index b6e1d0137..77649a2d1 100644 --- a/plugins/synaptics-mst/fu-synaptics-mst-device.c +++ b/plugins/synaptics-mst/fu-synaptics-mst-device.c @@ -1000,6 +1000,7 @@ fu_synaptics_mst_device_rescan (FuDevice *device, GError **error) const gchar *guid_template; const gchar *name_parent; const gchar *name_family; + const gchar *plugin; guint8 buf_ver[16]; /* read vendor ID */ @@ -1092,6 +1093,16 @@ fu_synaptics_mst_device_rescan (FuDevice *device, GError **error) } fu_device_set_name (FU_DEVICE (self), name); + plugin = fu_quirks_lookup_by_id (quirks, group, FU_QUIRKS_PLUGIN); + if (plugin != NULL && g_strcmp0 (plugin, "synaptics_mst") != 0) { + g_set_error (error, + FWUPD_ERROR, + FWUPD_ERROR_NOT_SUPPORTED, + "%s is only supported by %s", + name, plugin); + return FALSE; + } + /* this is a host system, use system ID */ guid_template = fu_quirks_lookup_by_id (quirks, group, "DeviceKind"); name_family = fu_synaptics_mst_family_to_string (self->family); diff --git a/plugins/synaptics-mst/synaptics-mst.quirk b/plugins/synaptics-mst/synaptics-mst.quirk index 9e3c89ad5..76695d6a6 100644 --- a/plugins/synaptics-mst/synaptics-mst.quirk +++ b/plugins/synaptics-mst/synaptics-mst.quirk @@ -39,9 +39,6 @@ DeviceKind = wld15 Name = Dell Rugged Platform DeviceKind = system -[SynapticsMSTBoardID=259] -Name = Dell dock - # ThinkPad Workstation Dock [DeviceInstanceId=MST-tesla-vmm2322-513] ParentGuid = USB\VID_17EF&PID_305A From b483044a8d861cb5375b7ebff3ac94821ca74225 Mon Sep 17 00:00:00 2001 From: Benson Leung Date: Fri, 15 May 2020 22:29:12 -0700 Subject: [PATCH 124/607] cros-ec: Initial skeleton Set it up as a USB device plugin, with the initial device in quirks being Servo Micro debug board. --- contrib/fwupd.spec.in | 1 + plugins/cros-ec/README.md | 41 ++++ plugins/cros-ec/cros-ec.quirk | 4 + plugins/cros-ec/data/lsusb-servo-micro.txt | 239 +++++++++++++++++++++ plugins/cros-ec/fu-cros-ec-usb-device.c | 50 +++++ plugins/cros-ec/fu-cros-ec-usb-device.h | 17 ++ plugins/cros-ec/fu-plugin-cros-ec.c | 19 ++ plugins/cros-ec/meson.build | 27 +++ plugins/meson.build | 1 + 9 files changed, 399 insertions(+) create mode 100644 plugins/cros-ec/README.md create mode 100644 plugins/cros-ec/cros-ec.quirk create mode 100644 plugins/cros-ec/data/lsusb-servo-micro.txt create mode 100644 plugins/cros-ec/fu-cros-ec-usb-device.c create mode 100644 plugins/cros-ec/fu-cros-ec-usb-device.h create mode 100644 plugins/cros-ec/fu-plugin-cros-ec.c create mode 100644 plugins/cros-ec/meson.build diff --git a/contrib/fwupd.spec.in b/contrib/fwupd.spec.in index cfc7e8f98..b4f3609d3 100644 --- a/contrib/fwupd.spec.in +++ b/contrib/fwupd.spec.in @@ -336,6 +336,7 @@ mkdir -p --mode=0700 $RPM_BUILD_ROOT%{_localstatedir}/lib/fwupd/gnupg %{_libdir}/fwupd-plugins-3/libfu_plugin_ccgx.so %{_libdir}/fwupd-plugins-3/libfu_plugin_colorhug.so %{_libdir}/fwupd-plugins-3/libfu_plugin_coreboot.so +%{_libdir}/fwupd-plugins-3/libfu_plugin_cros_ec.so %{_libdir}/fwupd-plugins-3/libfu_plugin_csr.so %{_libdir}/fwupd-plugins-3/libfu_plugin_cpu.so %if 0%{?have_dell} diff --git a/plugins/cros-ec/README.md b/plugins/cros-ec/README.md new file mode 100644 index 000000000..3d444df2e --- /dev/null +++ b/plugins/cros-ec/README.md @@ -0,0 +1,41 @@ +Chrome OS EC Support +=================== + +Introduction +------------ + +This plugin provides support for the firmware updates for Chrome OS EC +project based devices. + +Initially, it supports the USB endpoint updater, but lays the groundwork for +future updaters which use other update methods other than the USB endpoint. + +This is based on the chromeos ec project's usb_updater2 application [1]. + +Information about the USB update protocol is available at [2]. + +Firmware Format +--------------- + +The plugin at the moment does not support a firmware payload, but will +support the Google firmware format used in Chrome OS firmware +known as `flashmap`[3]. + +GUID Generation +--------------- + +These devices use the standard USB DeviceInstanceId values, e.g. + + * `USB\VID_18D1&PID_501A` + +Vendor ID Security +------------------ + +The vendor ID is set from the USB vendor, which is set to various different +values depending on the model and device mode. The list of USB VIDs used is: + + * `USB:0x18D1` + +[1] https://chromium.googlesource.com/chromiumos/platform/ec/+/master/extra/usb_updater/usb_updater2.c +[2] https://chromium.googlesource.com/chromiumos/platform/ec/+/master/docs/usb_updater.md +[3] https://www.chromium.org/chromium-os/firmware-porting-guide/fmap diff --git a/plugins/cros-ec/cros-ec.quirk b/plugins/cros-ec/cros-ec.quirk new file mode 100644 index 000000000..0df5faf0f --- /dev/null +++ b/plugins/cros-ec/cros-ec.quirk @@ -0,0 +1,4 @@ +# Servo Micro +[DeviceInstanceId=USB\VID_18D1&PID_501A] +Plugin = cros_ec +Summary = Servo Micro (aka "uServo") Debug Board diff --git a/plugins/cros-ec/data/lsusb-servo-micro.txt b/plugins/cros-ec/data/lsusb-servo-micro.txt new file mode 100644 index 000000000..358ad1724 --- /dev/null +++ b/plugins/cros-ec/data/lsusb-servo-micro.txt @@ -0,0 +1,239 @@ + +Bus 003 Device 006: ID 18d1:501a Google Inc. +Device Descriptor: + bLength 18 + bDescriptorType 1 + bcdUSB 2.00 + bDeviceClass 0 (Defined at Interface level) + bDeviceSubClass 0 + bDeviceProtocol 0 + bMaxPacketSize0 64 + idVendor 0x18d1 Google Inc. + idProduct 0x501a + bcdDevice 1.00 + iManufacturer 1 Google Inc. + iProduct 2 Servo Micro + iSerial 3 CMO653-00166-040491U00771 + bNumConfigurations 1 + Configuration Descriptor: + bLength 9 + bDescriptorType 2 + wTotalLength 170 + bNumInterfaces 7 + bConfigurationValue 1 + iConfiguration 4 servo_micro_v2.4.17-df61092c3 + bmAttributes 0x80 + (Bus Powered) + MaxPower 100mA + Interface Descriptor: + bLength 9 + bDescriptorType 4 + bInterfaceNumber 0 + bAlternateSetting 0 + bNumEndpoints 2 + bInterfaceClass 255 Vendor Specific Class + bInterfaceSubClass 80 + bInterfaceProtocol 1 + iInterface 6 UART3 + Endpoint Descriptor: + bLength 7 + bDescriptorType 5 + bEndpointAddress 0x81 EP 1 IN + bmAttributes 2 + Transfer Type Bulk + Synch Type None + Usage Type Data + wMaxPacketSize 0x0040 1x 64 bytes + bInterval 10 + Endpoint Descriptor: + bLength 7 + bDescriptorType 5 + bEndpointAddress 0x01 EP 1 OUT + bmAttributes 2 + Transfer Type Bulk + Synch Type None + Usage Type Data + wMaxPacketSize 0x0020 1x 32 bytes + bInterval 0 + Interface Descriptor: + bLength 9 + bDescriptorType 4 + bInterfaceNumber 1 + bAlternateSetting 0 + bNumEndpoints 2 + bInterfaceClass 255 Vendor Specific Class + bInterfaceSubClass 83 + bInterfaceProtocol 255 + iInterface 10 Firmware update + Endpoint Descriptor: + bLength 7 + bDescriptorType 5 + bEndpointAddress 0x82 EP 2 IN + bmAttributes 2 + Transfer Type Bulk + Synch Type None + Usage Type Data + wMaxPacketSize 0x0040 1x 64 bytes + bInterval 10 + Endpoint Descriptor: + bLength 7 + bDescriptorType 5 + bEndpointAddress 0x02 EP 2 OUT + bmAttributes 2 + Transfer Type Bulk + Synch Type None + Usage Type Data + wMaxPacketSize 0x0040 1x 64 bytes + bInterval 0 + Interface Descriptor: + bLength 9 + bDescriptorType 4 + bInterfaceNumber 2 + bAlternateSetting 0 + bNumEndpoints 2 + bInterfaceClass 255 Vendor Specific Class + bInterfaceSubClass 81 + bInterfaceProtocol 1 + iInterface 0 + Endpoint Descriptor: + bLength 7 + bDescriptorType 5 + bEndpointAddress 0x83 EP 3 IN + bmAttributes 2 + Transfer Type Bulk + Synch Type None + Usage Type Data + wMaxPacketSize 0x0040 1x 64 bytes + bInterval 10 + Endpoint Descriptor: + bLength 7 + bDescriptorType 5 + bEndpointAddress 0x03 EP 3 OUT + bmAttributes 2 + Transfer Type Bulk + Synch Type None + Usage Type Data + wMaxPacketSize 0x0040 1x 64 bytes + bInterval 0 + Interface Descriptor: + bLength 9 + bDescriptorType 4 + bInterfaceNumber 3 + bAlternateSetting 0 + bNumEndpoints 2 + bInterfaceClass 255 Vendor Specific Class + bInterfaceSubClass 80 + bInterfaceProtocol 1 + iInterface 7 Servo Shell + Endpoint Descriptor: + bLength 7 + bDescriptorType 5 + bEndpointAddress 0x84 EP 4 IN + bmAttributes 2 + Transfer Type Bulk + Synch Type None + Usage Type Data + wMaxPacketSize 0x0040 1x 64 bytes + bInterval 10 + Endpoint Descriptor: + bLength 7 + bDescriptorType 5 + bEndpointAddress 0x04 EP 4 OUT + bmAttributes 2 + Transfer Type Bulk + Synch Type None + Usage Type Data + wMaxPacketSize 0x0040 1x 64 bytes + bInterval 0 + Interface Descriptor: + bLength 9 + bDescriptorType 4 + bInterfaceNumber 4 + bAlternateSetting 0 + bNumEndpoints 2 + bInterfaceClass 255 Vendor Specific Class + bInterfaceSubClass 82 + bInterfaceProtocol 1 + iInterface 5 I2C + Endpoint Descriptor: + bLength 7 + bDescriptorType 5 + bEndpointAddress 0x85 EP 5 IN + bmAttributes 2 + Transfer Type Bulk + Synch Type None + Usage Type Data + wMaxPacketSize 0x0040 1x 64 bytes + bInterval 10 + Endpoint Descriptor: + bLength 7 + bDescriptorType 5 + bEndpointAddress 0x05 EP 5 OUT + bmAttributes 2 + Transfer Type Bulk + Synch Type None + Usage Type Data + wMaxPacketSize 0x0040 1x 64 bytes + bInterval 0 + Interface Descriptor: + bLength 9 + bDescriptorType 4 + bInterfaceNumber 5 + bAlternateSetting 0 + bNumEndpoints 2 + bInterfaceClass 255 Vendor Specific Class + bInterfaceSubClass 80 + bInterfaceProtocol 1 + iInterface 8 CPU + Endpoint Descriptor: + bLength 7 + bDescriptorType 5 + bEndpointAddress 0x86 EP 6 IN + bmAttributes 2 + Transfer Type Bulk + Synch Type None + Usage Type Data + wMaxPacketSize 0x0040 1x 64 bytes + bInterval 10 + Endpoint Descriptor: + bLength 7 + bDescriptorType 5 + bEndpointAddress 0x06 EP 6 OUT + bmAttributes 2 + Transfer Type Bulk + Synch Type None + Usage Type Data + wMaxPacketSize 0x0020 1x 32 bytes + bInterval 0 + Interface Descriptor: + bLength 9 + bDescriptorType 4 + bInterfaceNumber 6 + bAlternateSetting 0 + bNumEndpoints 2 + bInterfaceClass 255 Vendor Specific Class + bInterfaceSubClass 80 + bInterfaceProtocol 1 + iInterface 9 EC + Endpoint Descriptor: + bLength 7 + bDescriptorType 5 + bEndpointAddress 0x87 EP 7 IN + bmAttributes 2 + Transfer Type Bulk + Synch Type None + Usage Type Data + wMaxPacketSize 0x0040 1x 64 bytes + bInterval 10 + Endpoint Descriptor: + bLength 7 + bDescriptorType 5 + bEndpointAddress 0x07 EP 7 OUT + bmAttributes 2 + Transfer Type Bulk + Synch Type None + Usage Type Data + wMaxPacketSize 0x0020 1x 32 bytes + bInterval 0 +Device Status: 0x0000 + (Bus Powered) diff --git a/plugins/cros-ec/fu-cros-ec-usb-device.c b/plugins/cros-ec/fu-cros-ec-usb-device.c new file mode 100644 index 000000000..f68ecc5fc --- /dev/null +++ b/plugins/cros-ec/fu-cros-ec-usb-device.c @@ -0,0 +1,50 @@ +/* + * Copyright (C) 2020 Benson Leung + * + * SPDX-License-Identifier: LGPL-2.1+ + */ + +#include "config.h" + +#include + +#include "fu-cros-ec-usb-device.h" + +G_DEFINE_TYPE (FuCrosEcUsbDevice, fu_cros_ec_usb_device, FU_TYPE_USB_DEVICE) + +static gboolean +fu_cros_ec_usb_device_open (FuUsbDevice *device, GError **error) +{ + /* success */ + return TRUE; +} + +static gboolean +fu_cros_ec_usb_device_setup (FuDevice *device, GError **error) +{ + /* success */ + return TRUE; +} + +static gboolean +fu_cros_ec_usb_device_close (FuUsbDevice *device, GError **error) +{ + /* success */ + return TRUE; +} + +static void +fu_cros_ec_usb_device_init (FuCrosEcUsbDevice *device) +{ + fu_device_set_version_format (FU_DEVICE (device), FWUPD_VERSION_FORMAT_TRIPLET); +} + +static void +fu_cros_ec_usb_device_class_init (FuCrosEcUsbDeviceClass *klass) +{ + FuDeviceClass *klass_device = FU_DEVICE_CLASS (klass); + FuUsbDeviceClass *klass_usb_device = FU_USB_DEVICE_CLASS (klass); + klass_device->setup = fu_cros_ec_usb_device_setup; + klass_usb_device->open = fu_cros_ec_usb_device_open; + klass_usb_device->close = fu_cros_ec_usb_device_close; +} diff --git a/plugins/cros-ec/fu-cros-ec-usb-device.h b/plugins/cros-ec/fu-cros-ec-usb-device.h new file mode 100644 index 000000000..6a437d418 --- /dev/null +++ b/plugins/cros-ec/fu-cros-ec-usb-device.h @@ -0,0 +1,17 @@ +/* + * Copyright (C) 2020 Benson Leung + * + * SPDX-License-Identifier: LGPL-2.1+ + */ + +#pragma once + +#include "fu-plugin.h" + +#define FU_TYPE_CROS_EC_USB_DEVICE (fu_cros_ec_usb_device_get_type ()) +G_DECLARE_DERIVABLE_TYPE (FuCrosEcUsbDevice, fu_cros_ec_usb_device, FU, CROS_EC_USB_DEVICE, FuUsbDevice) + +struct _FuCrosEcUsbDeviceClass +{ + FuUsbDeviceClass parent_class; +}; diff --git a/plugins/cros-ec/fu-plugin-cros-ec.c b/plugins/cros-ec/fu-plugin-cros-ec.c new file mode 100644 index 000000000..cd55e8652 --- /dev/null +++ b/plugins/cros-ec/fu-plugin-cros-ec.c @@ -0,0 +1,19 @@ +/* + * Copyright (C) 2020 Benson Leung + * + * SPDX-License-Identifier: LGPL-2.1+ + */ + +#include "config.h" + +#include "fu-plugin-vfuncs.h" +#include "fu-hash.h" + +#include "fu-cros-ec-usb-device.h" + +void +fu_plugin_init (FuPlugin *plugin) +{ + fu_plugin_set_build_hash (plugin, FU_BUILD_HASH); + fu_plugin_set_device_gtype (plugin, FU_TYPE_CROS_EC_USB_DEVICE); +} diff --git a/plugins/cros-ec/meson.build b/plugins/cros-ec/meson.build new file mode 100644 index 000000000..9764abeda --- /dev/null +++ b/plugins/cros-ec/meson.build @@ -0,0 +1,27 @@ +cargs = ['-DG_LOG_DOMAIN="FuPluginCrosEc"'] + +install_data(['cros-ec.quirk'], + install_dir: join_paths(datadir, 'fwupd', 'quirks.d') +) + +shared_module('fu_plugin_cros_ec', + fu_hash, + sources : [ + 'fu-plugin-cros-ec.c', + 'fu-cros-ec-usb-device.c', + ], + include_directories : [ + root_incdir, + fwupd_incdir, + fwupdplugin_incdir, + ], + install : true, + install_dir: plugin_dir, + link_with : [ + fwupdplugin, + ], + c_args : cargs, + dependencies : [ + plugin_deps, + ], +) diff --git a/plugins/meson.build b/plugins/meson.build index a3c380e1d..aeb1ea66a 100644 --- a/plugins/meson.build +++ b/plugins/meson.build @@ -1,6 +1,7 @@ subdir('acpi-dmar') subdir('acpi-facp') subdir('ccgx') +subdir('cros-ec') subdir('cpu') subdir('dfu') subdir('colorhug') From cd65aeaa419751aa367581db05a0b8fe27f5deff Mon Sep 17 00:00:00 2001 From: Benson Leung Date: Fri, 22 May 2020 15:38:02 -0700 Subject: [PATCH 125/607] Require libgusb 0.3.3 Newer version of libgusb has support for a usb endpoint wrapper. --- contrib/ci/dependencies.xml | 4 ++-- contrib/fwupd.spec.in | 2 +- meson.build | 2 +- subprojects/gusb.wrap | 2 +- 4 files changed, 5 insertions(+), 5 deletions(-) diff --git a/contrib/ci/dependencies.xml b/contrib/ci/dependencies.xml index c5aa7ed85..6f03a9dab 100644 --- a/contrib/ci/dependencies.xml +++ b/contrib/ci/dependencies.xml @@ -766,7 +766,7 @@ - (>= 0.2.9) + (>= 0.3.3) libgusb-dev:s390x @@ -774,7 +774,7 @@ - (>= 0.2.9) + (>= 0.3.3) diff --git a/contrib/fwupd.spec.in b/contrib/fwupd.spec.in index b4f3609d3..e4695afad 100644 --- a/contrib/fwupd.spec.in +++ b/contrib/fwupd.spec.in @@ -1,6 +1,6 @@ %global glib2_version 2.45.8 %global libxmlb_version 0.1.3 -%global libgusb_version 0.2.11 +%global libgusb_version 0.3.3 %global libsoup_version 2.51.92 %global libjcat_version 0.1.0 %global systemd_version 231 diff --git a/meson.build b/meson.build index 426760d91..1af9eb90f 100644 --- a/meson.build +++ b/meson.build @@ -195,7 +195,7 @@ else endif libxmlb = dependency('xmlb', version : '>= 0.1.13', fallback : ['libxmlb', 'libxmlb_dep']) libjcat = dependency('jcat', version : '>= 0.1.0', fallback : ['libjcat', 'libjcat_dep']) -gusb = dependency('gusb', version : '>= 0.2.9', fallback : ['gusb', 'gusb_dep']) +gusb = dependency('gusb', version : '>= 0.3.3', fallback : ['gusb', 'gusb_dep']) sqlite = dependency('sqlite3') libarchive = dependency('libarchive') endif diff --git a/subprojects/gusb.wrap b/subprojects/gusb.wrap index 9d331e370..d0ce92146 100644 --- a/subprojects/gusb.wrap +++ b/subprojects/gusb.wrap @@ -1,4 +1,4 @@ [wrap-git] directory = gusb url = https://github.com/hughsie/libgusb.git -revision = 43b327a1e213aff00833842c455a796a068077cd +revision = 0.3.3 From 7aa00f6ee8cc4433e56e42d7800f1976317866f6 Mon Sep 17 00:00:00 2001 From: Benson Leung Date: Mon, 18 May 2020 10:57:40 -0700 Subject: [PATCH 126/607] cros-ec: Add usb_findit functionality Find the interface and endpoint used for firmware updates. Note: this change now requires libgusb 0.3.3 or later. --- plugins/cros-ec/fu-cros-ec-usb-device.c | 96 +++++++++++++++++++++++++ plugins/cros-ec/fu-cros-ec-usb-device.h | 2 +- 2 files changed, 97 insertions(+), 1 deletion(-) diff --git a/plugins/cros-ec/fu-cros-ec-usb-device.c b/plugins/cros-ec/fu-cros-ec-usb-device.c index f68ecc5fc..e1c49d6c9 100644 --- a/plugins/cros-ec/fu-cros-ec-usb-device.c +++ b/plugins/cros-ec/fu-cros-ec-usb-device.c @@ -10,11 +10,96 @@ #include "fu-cros-ec-usb-device.h" +#define USB_SUBCLASS_GOOGLE_UPDATE 0x53 +#define USB_PROTOCOL_GOOGLE_UPDATE 0xff + +struct _FuCrosEcUsbDevice { + FuUsbDevice parent_instance; + guint8 iface_idx; /* bInterfaceNumber */ + guint8 ep_num; /* bEndpointAddress */ + guint16 chunk_len; /* wMaxPacketSize */ + +}; + G_DEFINE_TYPE (FuCrosEcUsbDevice, fu_cros_ec_usb_device, FU_TYPE_USB_DEVICE) +static gboolean +fu_cros_ec_usb_device_find_interface (FuUsbDevice *device, + GError **error) +{ + GUsbDevice *usb_device = fu_usb_device_get_dev (device); + FuCrosEcUsbDevice *self = FU_CROS_EC_USB_DEVICE (device); + g_autoptr(GPtrArray) intfs = NULL; + + /* based on usb_updater2's find_interfacei() and find_endpoint() */ + + intfs = g_usb_device_get_interfaces (usb_device, error); + if (intfs == NULL) + return FALSE; + for (guint i = 0; i < intfs->len; i++) { + GUsbInterface *intf = g_ptr_array_index (intfs, i); + if (g_usb_interface_get_class (intf) == 255 && + g_usb_interface_get_subclass (intf) == USB_SUBCLASS_GOOGLE_UPDATE && + g_usb_interface_get_protocol (intf) == USB_PROTOCOL_GOOGLE_UPDATE) { + GUsbEndpoint *ep; + g_autoptr(GPtrArray) endpoints = NULL; + + endpoints = g_usb_interface_get_endpoints (intf); + if (NULL == endpoints || 0 == endpoints->len) + continue; + ep = g_ptr_array_index (endpoints, 0); + self->iface_idx = g_usb_interface_get_number (intf); + self->ep_num = g_usb_endpoint_get_address (ep) & 0x7f; + self->chunk_len = g_usb_endpoint_get_maximum_packet_size (ep); + + return TRUE; + } + } + g_set_error_literal (error, + FWUPD_ERROR, + FWUPD_ERROR_NOT_FOUND, + "no update interface found"); + return FALSE; +} + static gboolean fu_cros_ec_usb_device_open (FuUsbDevice *device, GError **error) { + GUsbDevice *usb_device = fu_usb_device_get_dev (device); + FuCrosEcUsbDevice *self = FU_CROS_EC_USB_DEVICE (device); + + if (!g_usb_device_claim_interface (usb_device, self->iface_idx, + G_USB_DEVICE_CLAIM_INTERFACE_BIND_KERNEL_DRIVER, + error)) { + g_prefix_error (error, "failed to claim interface: "); + return FALSE; + } + + /* success */ + return TRUE; +} + +static gboolean +fu_cros_ec_usb_device_probe (FuUsbDevice *device, GError **error) +{ + FuCrosEcUsbDevice *self = FU_CROS_EC_USB_DEVICE (device); + + /* very much like usb_updater2's usb_findit() */ + + if (!fu_cros_ec_usb_device_find_interface (device, error)) { + g_prefix_error (error, "failed to find update interface: "); + return FALSE; + } + + if (self->chunk_len == 0) { + g_set_error (error, + G_IO_ERROR, + G_IO_ERROR_INVALID_DATA, + "wMaxPacketSize isn't valid: %" G_GUINT16_FORMAT, + self->chunk_len); + return FALSE; + } + /* success */ return TRUE; } @@ -29,6 +114,16 @@ fu_cros_ec_usb_device_setup (FuDevice *device, GError **error) static gboolean fu_cros_ec_usb_device_close (FuUsbDevice *device, GError **error) { + GUsbDevice *usb_device = fu_usb_device_get_dev (device); + FuCrosEcUsbDevice *self = FU_CROS_EC_USB_DEVICE (device); + + if (!g_usb_device_release_interface (usb_device, self->iface_idx, + G_USB_DEVICE_CLAIM_INTERFACE_BIND_KERNEL_DRIVER, + error)) { + g_prefix_error (error, "failed to release interface: "); + return FALSE; + } + /* success */ return TRUE; } @@ -46,5 +141,6 @@ fu_cros_ec_usb_device_class_init (FuCrosEcUsbDeviceClass *klass) FuUsbDeviceClass *klass_usb_device = FU_USB_DEVICE_CLASS (klass); klass_device->setup = fu_cros_ec_usb_device_setup; klass_usb_device->open = fu_cros_ec_usb_device_open; + klass_usb_device->probe = fu_cros_ec_usb_device_probe; klass_usb_device->close = fu_cros_ec_usb_device_close; } diff --git a/plugins/cros-ec/fu-cros-ec-usb-device.h b/plugins/cros-ec/fu-cros-ec-usb-device.h index 6a437d418..ea3785b43 100644 --- a/plugins/cros-ec/fu-cros-ec-usb-device.h +++ b/plugins/cros-ec/fu-cros-ec-usb-device.h @@ -9,7 +9,7 @@ #include "fu-plugin.h" #define FU_TYPE_CROS_EC_USB_DEVICE (fu_cros_ec_usb_device_get_type ()) -G_DECLARE_DERIVABLE_TYPE (FuCrosEcUsbDevice, fu_cros_ec_usb_device, FU, CROS_EC_USB_DEVICE, FuUsbDevice) +G_DECLARE_FINAL_TYPE (FuCrosEcUsbDevice, fu_cros_ec_usb_device, FU, CROS_EC_USB_DEVICE, FuUsbDevice) struct _FuCrosEcUsbDeviceClass { From 00bb3341d27f4326413550db4b246c5a22b82058 Mon Sep 17 00:00:00 2001 From: Benson Leung Date: Mon, 18 May 2020 19:17:33 -0700 Subject: [PATCH 127/607] cros-ec: Add enough infrastructure for setup connection This should do the bulk transfers using protocol 6. The output here is now equivalent to the output of usb_updater2 -d 18d1:501a -f fwupdtool --plugin-whitelist cros_ec get-devices --verbose Servo Micro DeviceId: 84d0e3f2a0f8b2328f7995767b23ebb40494723f Guid: 8e2f7625-a164-55d7-8f09-f193c8ec33f1 <- USB\VID_18D1&PID_501A&REV_0100 Guid: 13564257-c649-586d-b4e4-4f048d480f36 <- USB\VID_18D1&PID_501A Serial: CMO653-00166-040491U00771 Summary: Servo Micro (aka "uServo") Debug Board Plugin: cros_ec_usb Flags: registered Vendor: Google Inc. VendorId: USB:0x18D1 Version: servo_micro_v2.4.17-df61092c3 VersionFormat: plain Created: 2020-05-20 PhysicalId: usb:03:00:02 --- plugins/cros-ec/fu-cros-ec-common.h | 125 +++++++++++++++++ plugins/cros-ec/fu-cros-ec-usb-device.c | 176 +++++++++++++++++++++++- 2 files changed, 300 insertions(+), 1 deletion(-) create mode 100644 plugins/cros-ec/fu-cros-ec-common.h diff --git a/plugins/cros-ec/fu-cros-ec-common.h b/plugins/cros-ec/fu-cros-ec-common.h new file mode 100644 index 000000000..b5fd8a8e7 --- /dev/null +++ b/plugins/cros-ec/fu-cros-ec-common.h @@ -0,0 +1,125 @@ +/* + * Copyright (C) 2020 Benson Leung + * + * SPDX-License-Identifier: LGPL-2.1+ + */ + +#define UPDATE_PROTOCOL_VERSION 6 + +/* + * This is the format of the update PDU header. + * + * block digest: the first four bytes of the sha1 digest of the rest of the + * structure (can be 0 on boards where digest is ignored). + * block_base: offset of this PDU into the flash SPI. + */ +typedef struct __attribute__((packed)) { + guint32 block_digest; + guint32 block_base; + /* The actual payload goes here. */ +} update_command; + +/* + * This is the frame format the host uses when sending update PDUs over USB. + * + * The PDUs are up to 1K bytes in size, they are fragmented into USB chunks of + * 64 bytes each and reassembled on the receive side before being passed to + * the flash update function. + * + * The flash update function receives the unframed PDU body (starting at the + * cmd field below), and puts its reply into the same buffer the PDU was in. + */ +struct update_frame_header { + guint32 block_size; /* Total frame size, including this field. */ + update_command cmd; +}; + +/* + * A convenience structure which allows to group together various revision + * fields of the header created by the signer (cr50-specific). + * + * These fields are compared when deciding if versions of two images are the + * same or when deciding which one of the available images to run. + */ +struct signed_header_version { + guint32 minor; + guint32 major; + guint32 epoch; +}; + +/* + * Response to the connection establishment request. + * + * When responding to the very first packet of the update sequence, the + * original USB update implementation was responding with a four byte value, + * just as to any other block of the transfer sequence. + * + * It became clear that there is a need to be able to enhance the update + * protocol, while staying backwards compatible. + * + * All newer protocol versions (starting with version 2) respond to the very + * first packet with an 8 byte or larger response, where the first 4 bytes are + * a version specific data, and the second 4 bytes - the protocol version + * number. + * + * This way the host receiving of a four byte value in response to the first + * packet is considered an indication of the target running the 'legacy' + * protocol, version 1. Receiving of an 8 byte or longer response would + * communicates the protocol version in the second 4 bytes. + */ +struct first_response_pdu { + guint32 return_value; + + /* The below fields are present in versions 2 and up. */ + + /* Type of header following (one of first_response_pdu_header_type) */ + guint16 header_type; + + /* Must be UPDATE_PROTOCOL_VERSION */ + guint16 protocol_version; + + /* In version 6 and up, a board-specific header follows. */ + union { + /* cr50 (header_type = UPDATE_HEADER_TYPE_CR50) */ + struct { + /* The below fields are present in versions 3 and up. */ + guint32 backup_ro_offset; + guint32 backup_rw_offset; + + /* The below fields are present in versions 4 and up. */ + /* + * Versions of the currently active RO and RW sections. + */ + struct signed_header_version shv[2]; + + /* The below fields are present in versions 5 and up */ + /* keyids of the currently active RO and RW sections. */ + guint32 keyid[2]; + } cr50; + /* Common code (header_type = UPDATE_HEADER_TYPE_COMMON) */ + struct { + /* Maximum PDU size */ + guint32 maximum_pdu_size; + + /* Flash protection status */ + guint32 flash_protection; + + /* Offset of the other region */ + guint32 offset; + + /* Version string of the other region */ + gchar version[32]; + + /* Minimum rollback version that RO will accept */ + gint32 min_rollback; + + /* RO public key version */ + guint32 key_version; + } common; + }; +}; + +enum first_response_pdu_header_type { + UPDATE_HEADER_TYPE_CR50 = 0, /* Must be 0 for backwards compatibility */ + UPDATE_HEADER_TYPE_COMMON = 1, +}; diff --git a/plugins/cros-ec/fu-cros-ec-usb-device.c b/plugins/cros-ec/fu-cros-ec-usb-device.c index e1c49d6c9..eaf49b385 100644 --- a/plugins/cros-ec/fu-cros-ec-usb-device.c +++ b/plugins/cros-ec/fu-cros-ec-usb-device.c @@ -9,20 +9,34 @@ #include #include "fu-cros-ec-usb-device.h" +#include "fu-cros-ec-common.h" #define USB_SUBCLASS_GOOGLE_UPDATE 0x53 #define USB_PROTOCOL_GOOGLE_UPDATE 0xff +#define SETUP_RETRY_CNT 5 +#define FLUSH_TIMEOUT_MS 10 +#define BULK_SEND_TIMEOUT_MS 2000 +#define BULK_RECV_TIMEOUT_MS 5000 + struct _FuCrosEcUsbDevice { FuUsbDevice parent_instance; guint8 iface_idx; /* bInterfaceNumber */ guint8 ep_num; /* bEndpointAddress */ guint16 chunk_len; /* wMaxPacketSize */ + struct first_response_pdu targ; + guint16 protocol_version; + guint16 header_type; }; G_DEFINE_TYPE (FuCrosEcUsbDevice, fu_cros_ec_usb_device, FU_TYPE_USB_DEVICE) +typedef union _START_RESP { + struct first_response_pdu rpdu; + guint32 legacy_resp; +} START_RESP; + static gboolean fu_cros_ec_usb_device_find_interface (FuUsbDevice *device, GError **error) @@ -104,9 +118,169 @@ fu_cros_ec_usb_device_probe (FuUsbDevice *device, GError **error) return TRUE; } +static gboolean +fu_cros_ec_usb_device_do_xfer (FuCrosEcUsbDevice * self, guint8 *outbuf, + gsize outlen, guint8 *inbuf, gsize inlen, + gboolean allow_less, gsize *rxed_count, + GError **error) +{ + GUsbDevice *usb_device = fu_usb_device_get_dev (FU_USB_DEVICE (self)); + gsize actual = 0; + + /* send data out */ + if (outbuf != NULL && outlen > 0) { + if (!g_usb_device_bulk_transfer (usb_device, self->ep_num, + outbuf, outlen, + &actual, BULK_SEND_TIMEOUT_MS, + NULL, error)) { + return FALSE; + } + if (actual != outlen) { + g_set_error (error, + G_IO_ERROR, + G_IO_ERROR_PARTIAL_INPUT, + "only sent %" G_GSIZE_FORMAT "/%" + G_GSIZE_FORMAT " bytes", + actual, outlen); + return FALSE; + } + } + + /* read reply back */ + if (inbuf != NULL && inlen > 0) { + actual = 0; + if (!g_usb_device_bulk_transfer (usb_device, + self->ep_num | 0x80, + inbuf, inlen, + &actual, BULK_RECV_TIMEOUT_MS, + NULL, error)) { + return FALSE; + } + if (actual != inlen && !allow_less) { + g_set_error (error, + G_IO_ERROR, + G_IO_ERROR_PARTIAL_INPUT, + "only received %" G_GSIZE_FORMAT "/%" + G_GSIZE_FORMAT " bytes", + actual, outlen); + return FALSE; + } + } + + if (rxed_count != NULL) + *rxed_count = actual; + + return TRUE; +} + +static gboolean +fu_cros_ec_usb_device_flush (FuDevice *device, gpointer user_data, + GError **error) +{ + GUsbDevice *usb_device = fu_usb_device_get_dev (FU_USB_DEVICE (device)); + FuCrosEcUsbDevice *self = FU_CROS_EC_USB_DEVICE (device); + gsize actual = 0; + g_autofree guint8 *inbuf = g_malloc0 (self->chunk_len); + + if (g_usb_device_bulk_transfer (usb_device, self->ep_num | 0x80, inbuf, + self->chunk_len, &actual, + FLUSH_TIMEOUT_MS, NULL, NULL)) { + g_debug ("flushing %" G_GSIZE_FORMAT " bytes", actual); + g_set_error (error, + G_IO_ERROR, + G_IO_ERROR_FAILED, + "flushing %" G_GSIZE_FORMAT " bytes", actual); + return FALSE; + } + + /* success */ + return TRUE; +} + +static gboolean +fu_cros_ec_usb_device_start_request (FuDevice *device, gpointer user_data, + GError **error) +{ + FuCrosEcUsbDevice *self = FU_CROS_EC_USB_DEVICE (device); + guint8 *start_resp = (guint8 *) user_data; + struct update_frame_header ufh; + gsize rxed_size = 0; + + memset(&ufh, 0, sizeof (ufh)); + ufh.block_size = GUINT32_TO_BE (sizeof(ufh)); + if (!fu_cros_ec_usb_device_do_xfer (self, (guint8 *)&ufh, sizeof(ufh), + start_resp, + sizeof(START_RESP), TRUE, + &rxed_size, error)) + return FALSE; + + /* we got something, so check for errors in response */ + if (rxed_size < 8) { + g_set_error (error, + G_IO_ERROR, + G_IO_ERROR_PARTIAL_INPUT, + "unexpected response size %" G_GSIZE_FORMAT, + rxed_size); + return FALSE; + } + + /* success */ + return TRUE; +} + static gboolean fu_cros_ec_usb_device_setup (FuDevice *device, GError **error) { + FuCrosEcUsbDevice *self = FU_CROS_EC_USB_DEVICE (device); + guint32 error_code; + START_RESP start_resp; + + /* flush all data from endpoint to recover in case of error */ + if (!fu_device_retry (device, fu_cros_ec_usb_device_flush, + SETUP_RETRY_CNT, NULL, error)) { + g_prefix_error (error, "failed to flush device to idle state: "); + return FALSE; + } + + /* send start request */ + if (!fu_device_retry (device, fu_cros_ec_usb_device_start_request, + SETUP_RETRY_CNT, &start_resp, error)) { + g_prefix_error (error, "failed to send start request: "); + return FALSE; + } + + self->protocol_version = GUINT16_FROM_BE (start_resp.rpdu.protocol_version); + + if (self->protocol_version < 5 || self->protocol_version > 6) { + g_set_error (error, + G_IO_ERROR, + G_IO_ERROR_NOT_SUPPORTED, + "unsupported protocol version %d", + self->protocol_version); + return FALSE; + } + self->header_type = GUINT16_FROM_BE (start_resp.rpdu.header_type); + + error_code = GUINT32_FROM_BE (start_resp.rpdu.return_value); + if (error_code != 0) { + g_set_error (error, + G_IO_ERROR, + G_IO_ERROR_FAILED, + "target reporting error %u", error_code); + return FALSE; + } + + memcpy (self->targ.common.version, start_resp.rpdu.common.version, + sizeof(start_resp.rpdu.common.version)); + self->targ.common.maximum_pdu_size = + GUINT32_FROM_BE (start_resp.rpdu.common.maximum_pdu_size); + self->targ.common.flash_protection = + GUINT32_FROM_BE (start_resp.rpdu.common.flash_protection); + self->targ.common.min_rollback = GINT32_FROM_BE (start_resp.rpdu.common.min_rollback); + self->targ.common.key_version = GUINT32_FROM_BE (start_resp.rpdu.common.key_version); + + fu_device_set_version (FU_DEVICE (device), self->targ.common.version); + /* success */ return TRUE; } @@ -131,7 +305,7 @@ fu_cros_ec_usb_device_close (FuUsbDevice *device, GError **error) static void fu_cros_ec_usb_device_init (FuCrosEcUsbDevice *device) { - fu_device_set_version_format (FU_DEVICE (device), FWUPD_VERSION_FORMAT_TRIPLET); + fu_device_set_version_format (FU_DEVICE (device), FWUPD_VERSION_FORMAT_PLAIN); } static void From 086d0c0eb606dd95c083e827e4f9a8d41ef82c48 Mon Sep 17 00:00:00 2001 From: Benson Leung Date: Tue, 19 May 2020 19:07:49 -0700 Subject: [PATCH 128/607] cros-ec: Parse version number into triplet Add fu_cros_ec_parse_version to common, as this will be used to parse the firmware bundle's version string too. --- plugins/cros-ec/fu-cros-ec-common.c | 72 +++++++++++++++++++++++++ plugins/cros-ec/fu-cros-ec-common.h | 17 ++++++ plugins/cros-ec/fu-cros-ec-usb-device.c | 27 ++++++---- plugins/cros-ec/meson.build | 2 + 4 files changed, 109 insertions(+), 9 deletions(-) create mode 100644 plugins/cros-ec/fu-cros-ec-common.c diff --git a/plugins/cros-ec/fu-cros-ec-common.c b/plugins/cros-ec/fu-cros-ec-common.c new file mode 100644 index 000000000..07111b40a --- /dev/null +++ b/plugins/cros-ec/fu-cros-ec-common.c @@ -0,0 +1,72 @@ +/* + * Copyright (C) 2020 Benson Leung + * + * SPDX-License-Identifier: LGPL-2.1+ + */ + +#include "config.h" + +#include + +#include "fu-cros-ec-common.h" + +gboolean +fu_cros_ec_parse_version (const gchar *version_raw, + struct cros_ec_version *version, GError **error) +{ + g_auto(GStrv) v_split = NULL; + g_auto(GStrv) marker_split = NULL; + g_auto(GStrv) triplet_split = NULL; + + if (NULL == version_raw || 0 == strlen (version_raw)) { + g_set_error_literal (error, + FWUPD_ERROR, + FWUPD_ERROR_INTERNAL, + "no version string to parse"); + return FALSE; + } + + /* sample version string: cheese_v1.1.1755-4da9520 */ + v_split = g_strsplit (version_raw, "_v", 2); + if (g_strv_length (v_split) < 2) { + g_set_error_literal (error, + FWUPD_ERROR, + FWUPD_ERROR_INTERNAL, + "version marker not found"); + return FALSE; + } + marker_split = g_strsplit_set (v_split[1], "-+", 2); + if (g_strv_length (marker_split) < 2) { + g_set_error (error, + FWUPD_ERROR, + FWUPD_ERROR_INTERNAL, + "hash marker not found: %s", v_split[1]); + return FALSE; + } + triplet_split = g_strsplit_set (marker_split[0], ".", 3); + if (g_strv_length (triplet_split) < 3) { + g_set_error (error, + FWUPD_ERROR, + FWUPD_ERROR_INTERNAL, + "improper version triplet: %s", marker_split[0]); + return FALSE; + } + g_strlcpy (version->triplet, marker_split[0], 32); + if (g_strlcpy (version->boardname, v_split[0], 32) == 0) { + g_set_error_literal (error, + FWUPD_ERROR, + FWUPD_ERROR_INTERNAL, + "empty board name"); + return FALSE; + } + if (g_strlcpy (version->sha1, marker_split[1], 32) == 0) { + g_set_error_literal (error, + FWUPD_ERROR, + FWUPD_ERROR_INTERNAL, + "empty SHA"); + return FALSE; + } + version->dirty = (g_strrstr(v_split[1], "+") != NULL); + + return TRUE; +} diff --git a/plugins/cros-ec/fu-cros-ec-common.h b/plugins/cros-ec/fu-cros-ec-common.h index b5fd8a8e7..e7e07c9c2 100644 --- a/plugins/cros-ec/fu-cros-ec-common.h +++ b/plugins/cros-ec/fu-cros-ec-common.h @@ -4,6 +4,12 @@ * SPDX-License-Identifier: LGPL-2.1+ */ +#pragma once + +#include + +#include "fu-plugin.h" + #define UPDATE_PROTOCOL_VERSION 6 /* @@ -123,3 +129,14 @@ enum first_response_pdu_header_type { UPDATE_HEADER_TYPE_CR50 = 0, /* Must be 0 for backwards compatibility */ UPDATE_HEADER_TYPE_COMMON = 1, }; + +struct cros_ec_version { + gchar boardname[32]; + gchar triplet[32]; + gchar sha1[32]; + gboolean dirty; +}; + +gboolean fu_cros_ec_parse_version (const gchar *version_raw, + struct cros_ec_version *version, + GError **error); diff --git a/plugins/cros-ec/fu-cros-ec-usb-device.c b/plugins/cros-ec/fu-cros-ec-usb-device.c index eaf49b385..104e7a84d 100644 --- a/plugins/cros-ec/fu-cros-ec-usb-device.c +++ b/plugins/cros-ec/fu-cros-ec-usb-device.c @@ -20,14 +20,15 @@ #define BULK_RECV_TIMEOUT_MS 5000 struct _FuCrosEcUsbDevice { - FuUsbDevice parent_instance; - guint8 iface_idx; /* bInterfaceNumber */ - guint8 ep_num; /* bEndpointAddress */ - guint16 chunk_len; /* wMaxPacketSize */ + FuUsbDevice parent_instance; + guint8 iface_idx; /* bInterfaceNumber */ + guint8 ep_num; /* bEndpointAddress */ + guint16 chunk_len; /* wMaxPacketSize */ - struct first_response_pdu targ; - guint16 protocol_version; - guint16 header_type; + struct first_response_pdu targ; + guint16 protocol_version; + guint16 header_type; + struct cros_ec_version version; }; G_DEFINE_TYPE (FuCrosEcUsbDevice, fu_cros_ec_usb_device, FU_TYPE_USB_DEVICE) @@ -279,7 +280,15 @@ fu_cros_ec_usb_device_setup (FuDevice *device, GError **error) self->targ.common.min_rollback = GINT32_FROM_BE (start_resp.rpdu.common.min_rollback); self->targ.common.key_version = GUINT32_FROM_BE (start_resp.rpdu.common.key_version); - fu_device_set_version (FU_DEVICE (device), self->targ.common.version); + if (!fu_cros_ec_parse_version (self->targ.common.version, + &self->version, error)) { + g_prefix_error (error, + "failed parsing device's version: %32s: ", + self->targ.common.version); + return FALSE; + } + + fu_device_set_version (FU_DEVICE (device), self->version.triplet); /* success */ return TRUE; @@ -305,7 +314,7 @@ fu_cros_ec_usb_device_close (FuUsbDevice *device, GError **error) static void fu_cros_ec_usb_device_init (FuCrosEcUsbDevice *device) { - fu_device_set_version_format (FU_DEVICE (device), FWUPD_VERSION_FORMAT_PLAIN); + fu_device_set_version_format (FU_DEVICE (device), FWUPD_VERSION_FORMAT_TRIPLET); } static void diff --git a/plugins/cros-ec/meson.build b/plugins/cros-ec/meson.build index 9764abeda..ff41c03d9 100644 --- a/plugins/cros-ec/meson.build +++ b/plugins/cros-ec/meson.build @@ -9,6 +9,7 @@ shared_module('fu_plugin_cros_ec', sources : [ 'fu-plugin-cros-ec.c', 'fu-cros-ec-usb-device.c', + 'fu-cros-ec-common.c', ], include_directories : [ root_incdir, @@ -18,6 +19,7 @@ shared_module('fu_plugin_cros_ec', install : true, install_dir: plugin_dir, link_with : [ + fwupd, fwupdplugin, ], c_args : cargs, From 092f87ae0c2f33048fe84ed424512ce9e4339ad2 Mon Sep 17 00:00:00 2001 From: Benson Leung Date: Tue, 19 May 2020 22:27:03 -0700 Subject: [PATCH 129/607] cros-ec: Add board name as a instance id and hash as metadata These couple of extra things in the CrOS EC version string were split off of the triplet, so give them a home. --- plugins/cros-ec/fu-cros-ec-usb-device.c | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/plugins/cros-ec/fu-cros-ec-usb-device.c b/plugins/cros-ec/fu-cros-ec-usb-device.c index 104e7a84d..7fcd0c8bb 100644 --- a/plugins/cros-ec/fu-cros-ec-usb-device.c +++ b/plugins/cros-ec/fu-cros-ec-usb-device.c @@ -289,6 +289,7 @@ fu_cros_ec_usb_device_setup (FuDevice *device, GError **error) } fu_device_set_version (FU_DEVICE (device), self->version.triplet); + fu_device_add_instance_id (FU_DEVICE (device), self->version.boardname); /* success */ return TRUE; @@ -317,12 +318,20 @@ fu_cros_ec_usb_device_init (FuCrosEcUsbDevice *device) fu_device_set_version_format (FU_DEVICE (device), FWUPD_VERSION_FORMAT_TRIPLET); } +static void +fu_cros_ec_usb_device_to_string (FuDevice *device, guint idt, GString *str) +{ + FuCrosEcUsbDevice *self = FU_CROS_EC_USB_DEVICE (device); + fu_common_string_append_kv (str, idt, "GitHash", self->version.sha1); +} + static void fu_cros_ec_usb_device_class_init (FuCrosEcUsbDeviceClass *klass) { FuDeviceClass *klass_device = FU_DEVICE_CLASS (klass); FuUsbDeviceClass *klass_usb_device = FU_USB_DEVICE_CLASS (klass); klass_device->setup = fu_cros_ec_usb_device_setup; + klass_device->to_string = fu_cros_ec_usb_device_to_string; klass_usb_device->open = fu_cros_ec_usb_device_open; klass_usb_device->probe = fu_cros_ec_usb_device_probe; klass_usb_device->close = fu_cros_ec_usb_device_close; From a22310374e3c24ec6544b943257a1d00d5ccd81f Mon Sep 17 00:00:00 2001 From: Benson Leung Date: Fri, 22 May 2020 20:43:35 -0700 Subject: [PATCH 130/607] cros-ec: Provide device metadata as a part of to_string Provide the following metadata: "Dirty firmware" bit Protocol version Header type Maximum PDU Size Flash protection status Raw version string Key Version Minimum rollback --- plugins/cros-ec/fu-cros-ec-usb-device.c | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/plugins/cros-ec/fu-cros-ec-usb-device.c b/plugins/cros-ec/fu-cros-ec-usb-device.c index 7fcd0c8bb..082562292 100644 --- a/plugins/cros-ec/fu-cros-ec-usb-device.c +++ b/plugins/cros-ec/fu-cros-ec-usb-device.c @@ -322,7 +322,26 @@ static void fu_cros_ec_usb_device_to_string (FuDevice *device, guint idt, GString *str) { FuCrosEcUsbDevice *self = FU_CROS_EC_USB_DEVICE (device); + g_autofree gchar *min_rollback = NULL; + fu_common_string_append_kv (str, idt, "GitHash", self->version.sha1); + fu_common_string_append_kb (str, idt, "Dirty", + self->version.dirty); + fu_common_string_append_ku (str, idt, "ProtocolVersion", + self->protocol_version); + fu_common_string_append_ku (str, idt, "HeaderType", + self->header_type); + fu_common_string_append_ku (str, idt, "MaxPDUSize", + self->targ.common.maximum_pdu_size); + fu_common_string_append_kx (str, idt, "FlashProtectionStatus", + self->targ.common.flash_protection); + fu_common_string_append_kv (str, idt, "RawVersion", + self->targ.common.version); + fu_common_string_append_ku (str, idt, "KeyVersion", + self->targ.common.key_version); + min_rollback = g_strdup_printf ("%" G_GINT32_FORMAT, + self->targ.common.min_rollback); + fu_common_string_append_kv (str, idt, "MinRollback", min_rollback); } static void From 64ebf911247c025eefe3d1ac94e3000e176f8ef4 Mon Sep 17 00:00:00 2001 From: Richard Hughes Date: Fri, 29 May 2020 07:51:38 +0100 Subject: [PATCH 131/607] Always enforce the metadata signature has a valid timestamp Although this is something that we have always done on the LVFS, corporate deployments that resign the firmware or metadata might not be signing the files in the same way. Always require a timestamp to prevent allowing an inadvertent rollback attack. --- src/fu-engine.c | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/src/fu-engine.c b/src/fu-engine.c index 174f07ea6..f930c1d46 100644 --- a/src/fu-engine.c +++ b/src/fu-engine.c @@ -3175,8 +3175,14 @@ fu_engine_validate_result_timestamp (JcatResult *jcat_result, g_return_val_if_fail (JCAT_IS_RESULT (jcat_result), FALSE); g_return_val_if_fail (JCAT_IS_RESULT (jcat_result_old), FALSE); - if (jcat_result_get_timestamp (jcat_result) > 0 && - jcat_result_get_timestamp (jcat_result_old) > 0) { + if (jcat_result_get_timestamp (jcat_result) == 0) { + g_set_error (error, + FWUPD_ERROR, + FWUPD_ERROR_INVALID_FILE, + "no signing timestamp"); + return FALSE; + } + if (jcat_result_get_timestamp (jcat_result_old) > 0) { delta = jcat_result_get_timestamp (jcat_result) - jcat_result_get_timestamp (jcat_result_old); } From d5d496b62a1b84c0da5416aa04e29a1c78046ce9 Mon Sep 17 00:00:00 2001 From: Mario Limonciello Date: Thu, 28 May 2020 16:41:38 -0500 Subject: [PATCH 132/607] trivial: uefi: fix dell TPM updates Adding an extra header makes the firmware reject the GUID in the real header. --- plugins/dell/fu-self-test.c | 3 --- plugins/uefi/fu-uefi-device.c | 13 ++++++++++--- 2 files changed, 10 insertions(+), 6 deletions(-) diff --git a/plugins/dell/fu-self-test.c b/plugins/dell/fu-self-test.c index 705dc736a..159673f1c 100644 --- a/plugins/dell/fu-self-test.c +++ b/plugins/dell/fu-self-test.c @@ -249,11 +249,8 @@ fu_plugin_dell_tpm_func (gconstpointer user_data) g_clear_error (&error); /* test override */ - g_test_expect_message ("FuPluginUefi", G_LOG_LEVEL_WARNING, - "missing or invalid embedded capsule header"); ret = fu_plugin_runner_update (self->plugin_uefi, device_v20, blob_fw, FWUPD_INSTALL_FLAG_FORCE, &error); - g_test_assert_expected_messages (); g_assert_no_error (error); g_assert (ret); diff --git a/plugins/uefi/fu-uefi-device.c b/plugins/uefi/fu-uefi-device.c index f52744784..23550959f 100644 --- a/plugins/uefi/fu-uefi-device.c +++ b/plugins/uefi/fu-uefi-device.c @@ -35,6 +35,7 @@ struct _FuUefiDevice { guint64 fmp_hardware_instance; gboolean missing_header; gboolean automounted_esp; + gboolean requires_header; }; G_DEFINE_TYPE (FuUefiDevice, fu_uefi_device, FU_TYPE_DEVICE) @@ -320,9 +321,8 @@ fu_uefi_device_fixup_firmware (FuDevice *device, GBytes *fw, GError **error) if (efi_guid_cmp (&esrt_guid, &payload_guid) == 0) { g_debug ("ESRT matches payload GUID"); return g_bytes_new_from_bytes (fw, 0, fw_length); - /* FMP payload */ - } else if (fu_uefi_device_get_kind (self) == FU_UEFI_DEVICE_KIND_FMP) { - g_debug ("performing FMP update"); + /* Type that doesn't require a header */ + } else if (!self->requires_header) { return g_bytes_new_from_bytes (fw, 0, fw_length); /* Missing, add a header */ } else { @@ -715,6 +715,13 @@ fu_uefi_device_probe (FuDevice *device, GError **error) g_warning ("Failed to get PCR0s: %s", error_local->message); } + /* whether to create a missing header */ + if (self->kind == FU_UEFI_DEVICE_KIND_FMP || + self->kind == FU_UEFI_DEVICE_KIND_DELL_TPM_FIRMWARE) + self->requires_header = FALSE; + else + self->requires_header = TRUE; + /* Windows seems to be case insensitive, but for convenience we'll * match the upper case values typically specified in the .inf file */ guid_strup = g_ascii_strup (self->fw_class, -1); From cafea91f5363dc78547d99d72ce305da08a1c592 Mon Sep 17 00:00:00 2001 From: Mario Limonciello Date: Fri, 29 May 2020 06:54:25 -0500 Subject: [PATCH 133/607] trivial: fix windows and snap CI Introducing newer gusb caused these builds to run gusb as a subproject and hence the introspection binaries were looked for. Fixes: cd65ae ("Require libgusb 0.3.3") --- contrib/ci/build_windows.sh | 4 ++++ snap/snapcraft.yaml | 6 ++++-- 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/contrib/ci/build_windows.sh b/contrib/ci/build_windows.sh index 9e1c4ca89..a42993990 100755 --- a/contrib/ci/build_windows.sh +++ b/contrib/ci/build_windows.sh @@ -39,6 +39,10 @@ meson .. \ -Dlibjcat:man=false \ -Dlibjcat:gpg=false \ -Dlibjcat:introspection=false \ + -Dgusb:tests=false \ + -Dgusb:docs=false \ + -Dgusb:introspection=false \ + -Dgusb:vapi=false \ -Dgudev=false $@ meson introspect . --projectinfo | jq -r .version > $DESTDIR/VERSION ninja -v diff --git a/snap/snapcraft.yaml b/snap/snapcraft.yaml index 3bc4a9461..cd8536137 100644 --- a/snap/snapcraft.yaml +++ b/snap/snapcraft.yaml @@ -174,6 +174,10 @@ parts: -Dman=false, -Dplugin_modem_manager=true, -Dudevdir=$SNAPCRAFT_STAGE/lib/udev, + "-Dgusb:tests=false", + "-Dgusb:docs=false", + "-Dgusb:introspection=false", + "-Dgusb:vapi=false", "-Dlibxmlb:gtkdoc=false", "-Dlibxmlb:introspection=false", "-Dlibjcat:man=false", @@ -196,7 +200,6 @@ parts: - libefivar-dev - libftdi1-dev - libgudev-1.0-dev - - libgusb-dev - libgcab-dev - libglib2.0-dev - libgpgme11-dev @@ -219,7 +222,6 @@ parts: - libefivar1 - libefiboot1 - libelf1 - - libgusb2 - libusb-1.0-0 - libgudev-1.0-0 - libgpgme11 From bdfccdf0972b4616c860e1f67c7cca43620cdc6a Mon Sep 17 00:00:00 2001 From: Richard Hughes Date: Fri, 29 May 2020 16:49:23 +0100 Subject: [PATCH 134/607] Allow multi-byte FuUdevDevice preads and writes --- libfwupdplugin/fu-udev-device.c | 106 ++++++++++++++++++++++---------- libfwupdplugin/fu-udev-device.h | 10 +++ libfwupdplugin/fwupdplugin.map | 2 + 3 files changed, 87 insertions(+), 31 deletions(-) diff --git a/libfwupdplugin/fu-udev-device.c b/libfwupdplugin/fu-udev-device.c index 66ce4f2bf..e53c93700 100644 --- a/libfwupdplugin/fu-udev-device.c +++ b/libfwupdplugin/fu-udev-device.c @@ -935,20 +935,69 @@ fu_udev_device_ioctl (FuUdevDevice *self, } /** - * fu_udev_device_pwrite: + * fu_udev_device_pread_full: * @self: A #FuUdevDevice * @port: offset address - * @data: value + * @buf: (in): data + * @bufsz: size of @buf * @error: A #GError, or %NULL * - * Write to a file descriptor at a given offset. + * Read a buffer from a file descriptor at a given offset. * * Returns: %TRUE for success * - * Since: 1.3.3 + * Since: 1.5.0 **/ gboolean -fu_udev_device_pwrite (FuUdevDevice *self, goffset port, guint8 data, GError **error) +fu_udev_device_pread_full (FuUdevDevice *self, goffset port, + guint8 *buf, gsize bufsz, + GError **error) +{ + FuUdevDevicePrivate *priv = GET_PRIVATE (self); + + g_return_val_if_fail (FU_IS_UDEV_DEVICE (self), FALSE); + g_return_val_if_fail (port != 0x0, FALSE); + g_return_val_if_fail (buf != NULL, FALSE); + g_return_val_if_fail (priv->fd > 0, FALSE); + +#ifdef HAVE_PWRITE + if (pread (priv->fd, buf, bufsz, port) != (gssize) bufsz) { + g_set_error (error, + G_IO_ERROR, + G_IO_ERROR_FAILED, + "failed to read from port 0x%04x: %s", + (guint) port, + strerror (errno)); + return FALSE; + } + return TRUE; +#else + g_set_error_literal (error, + FWUPD_ERROR, + FWUPD_ERROR_NOT_SUPPORTED, + "Not supported as pread() is unavailable"); + return FALSE; +#endif +} + +/** + * fu_udev_device_pwrite_full: + * @self: A #FuUdevDevice + * @port: offset address + * @buf: (out): data + * @bufsz: size of @data + * @error: A #GError, or %NULL + * + * Write a buffer to a file descriptor at a given offset. + * + * Returns: %TRUE for success + * + * Since: 1.5.0 + **/ +gboolean +fu_udev_device_pwrite_full (FuUdevDevice *self, goffset port, + const guint8 *buf, gsize bufsz, + GError **error) { FuUdevDevicePrivate *priv = GET_PRIVATE (self); @@ -957,7 +1006,7 @@ fu_udev_device_pwrite (FuUdevDevice *self, goffset port, guint8 data, GError **e g_return_val_if_fail (priv->fd > 0, FALSE); #ifdef HAVE_PWRITE - if (pwrite (priv->fd, &data, 1, port) != 1) { + if (pwrite (priv->fd, buf, bufsz, port) != (gssize) bufsz) { g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED, @@ -976,6 +1025,25 @@ fu_udev_device_pwrite (FuUdevDevice *self, goffset port, guint8 data, GError **e #endif } +/** + * fu_udev_device_pwrite: + * @self: A #FuUdevDevice + * @port: offset address + * @data: value + * @error: A #GError, or %NULL + * + * Write to a file descriptor at a given offset. + * + * Returns: %TRUE for success + * + * Since: 1.3.3 + **/ +gboolean +fu_udev_device_pwrite (FuUdevDevice *self, goffset port, guint8 data, GError **error) +{ + return fu_udev_device_pwrite_full (self, port, &data, 0x01, error); +} + /** * fu_udev_device_get_parent_name * @self: A #FuUdevDevice @@ -1069,31 +1137,7 @@ fu_udev_device_get_sysfs_attr (FuUdevDevice *self, const gchar *attr, gboolean fu_udev_device_pread (FuUdevDevice *self, goffset port, guint8 *data, GError **error) { - FuUdevDevicePrivate *priv = GET_PRIVATE (self); - - g_return_val_if_fail (FU_IS_UDEV_DEVICE (self), FALSE); - g_return_val_if_fail (port != 0x0, FALSE); - g_return_val_if_fail (data != NULL, FALSE); - g_return_val_if_fail (priv->fd > 0, FALSE); - -#ifdef HAVE_PWRITE - if (pread (priv->fd, data, 1, port) != 1) { - g_set_error (error, - G_IO_ERROR, - G_IO_ERROR_FAILED, - "failed to read from port %04x: %s", - (guint) port, - strerror (errno)); - return FALSE; - } - return TRUE; -#else - g_set_error_literal (error, - FWUPD_ERROR, - FWUPD_ERROR_NOT_SUPPORTED, - "Not supported as pread() is unavailable"); - return FALSE; -#endif + return fu_udev_device_pread_full (self, port, data, 0x1, error); } static void diff --git a/libfwupdplugin/fu-udev-device.h b/libfwupdplugin/fu-udev-device.h index 94f3c2749..9b8115419 100644 --- a/libfwupdplugin/fu-udev-device.h +++ b/libfwupdplugin/fu-udev-device.h @@ -83,10 +83,20 @@ gboolean fu_udev_device_pwrite (FuUdevDevice *self, goffset port, guint8 data, GError **error); +gboolean fu_udev_device_pwrite_full (FuUdevDevice *self, + goffset port, + const guint8 *buf, + gsize bufsz, + GError **error); gboolean fu_udev_device_pread (FuUdevDevice *self, goffset port, guint8 *data, GError **error); +gboolean fu_udev_device_pread_full (FuUdevDevice *self, + goffset port, + guint8 *buf, + gsize bufsz, + GError **error); const gchar *fu_udev_device_get_sysfs_attr (FuUdevDevice *self, const gchar *attr, GError **error); diff --git a/libfwupdplugin/fwupdplugin.map b/libfwupdplugin/fwupdplugin.map index fd2734c1d..6fee21124 100644 --- a/libfwupdplugin/fwupdplugin.map +++ b/libfwupdplugin/fwupdplugin.map @@ -597,5 +597,7 @@ LIBFWUPDPLUGIN_1.5.0 { fu_security_attrs_to_variant; fu_udev_device_get_parent_name; fu_udev_device_get_sysfs_attr; + fu_udev_device_pread_full; + fu_udev_device_pwrite_full; local: *; } LIBFWUPDPLUGIN_1.4.1; From bb228cbe53914fc0dd02ff403ae17866f3f8b40f Mon Sep 17 00:00:00 2001 From: Richard Hughes Date: Thu, 21 May 2020 22:52:15 +0100 Subject: [PATCH 135/607] pci-mei: Check the HFS register for the override strap --- libfwupd/fwupd-security-attr.h | 1 + plugins/pci-mei/fu-plugin-pci-mei.c | 60 ++++++++++++++++++++++------- src/fu-security-attr.c | 4 ++ 3 files changed, 52 insertions(+), 13 deletions(-) diff --git a/libfwupd/fwupd-security-attr.h b/libfwupd/fwupd-security-attr.h index b46a00684..16154f696 100644 --- a/libfwupd/fwupd-security-attr.h +++ b/libfwupd/fwupd-security-attr.h @@ -123,6 +123,7 @@ typedef enum { #define FWUPD_SECURITY_ATTR_ID_KERNEL_SWAP "org.fwupd.hsi.KernelSwap" /* Since: 1.5.0 */ #define FWUPD_SECURITY_ATTR_ID_KERNEL_TAINTED "org.fwupd.hsi.KernelTainted" /* Since: 1.5.0 */ #define FWUPD_SECURITY_ATTR_ID_MEI_MANUFACTURING_MODE "org.fwupd.hsi.MeiManufacturingMode" /* Since: 1.5.0 */ +#define FWUPD_SECURITY_ATTR_ID_MEI_OVERRIDE_STRAP "org.fwupd.hsi.MeiOverrideStrap" /* Since: 1.5.0 */ #define FWUPD_SECURITY_ATTR_ID_SPI_BIOSWE "org.fwupd.hsi.SpiBioswe" /* Since: 1.5.0 */ #define FWUPD_SECURITY_ATTR_ID_SPI_BLE "org.fwupd.hsi.SpiBle" /* Since: 1.5.0 */ #define FWUPD_SECURITY_ATTR_ID_SPI_SMM_BWP "org.fwupd.hsi.SpiSmmBwp" /* Since: 1.5.0 */ diff --git a/plugins/pci-mei/fu-plugin-pci-mei.c b/plugins/pci-mei/fu-plugin-pci-mei.c index 9d4735850..b0e8300c5 100644 --- a/plugins/pci-mei/fu-plugin-pci-mei.c +++ b/plugins/pci-mei/fu-plugin-pci-mei.c @@ -11,7 +11,7 @@ struct FuPluginData { gboolean has_device; - guint8 mei_cfg; + guint32 mei_cfg; }; #define PCI_CFG_HFS_1 0x40 @@ -28,6 +28,7 @@ gboolean fu_plugin_udev_device_added (FuPlugin *plugin, FuUdevDevice *device, GError **error) { FuPluginData *priv = fu_plugin_get_data (plugin); + guint8 buf[4] = { 0x0 }; g_autoptr(FuDeviceLocker) locker = NULL; /* interesting device? */ @@ -43,34 +44,29 @@ fu_plugin_udev_device_added (FuPlugin *plugin, FuUdevDevice *device, GError **er return FALSE; /* grab MEI config Register */ - if (!fu_udev_device_pread (device, PCI_CFG_HFS_1, &priv->mei_cfg, error)) { - g_prefix_error (error, "could not read MEI"); + if (!fu_udev_device_pread_full (device, PCI_CFG_HFS_1, buf, sizeof(buf), error)) { + g_prefix_error (error, "could not read MEI: "); return FALSE; } + priv->mei_cfg = fu_common_read_uint32 (buf, G_LITTLE_ENDIAN); priv->has_device = TRUE; return TRUE; } -void -fu_plugin_add_security_attrs (FuPlugin *plugin, FuSecurityAttrs *attrs) +static void +fu_plugin_add_security_attrs_manufacturing_mode (FuPlugin *plugin, FuSecurityAttrs *attrs) { FuPluginData *priv = fu_plugin_get_data (plugin); g_autoptr(FwupdSecurityAttr) attr = NULL; - /* only Intel */ - if (!fu_common_is_cpu_intel ()) - return; - if (!priv->has_device) - return; - /* create attr */ attr = fwupd_security_attr_new (FWUPD_SECURITY_ATTR_ID_MEI_MANUFACTURING_MODE); fwupd_security_attr_set_plugin (attr, fu_plugin_get_name (plugin)); fwupd_security_attr_set_level (attr, FWUPD_SECURITY_ATTR_LEVEL_CRITICAL); fu_security_attrs_append (attrs, attr); - /* load file */ - if ((priv->mei_cfg & (1 << 4)) != 0) { + /* Manufacturing Mode */ + if (((priv->mei_cfg >> 4) & 0x1) != 0) { fwupd_security_attr_set_result (attr, FWUPD_SECURITY_ATTR_RESULT_NOT_LOCKED); return; } @@ -79,3 +75,41 @@ fu_plugin_add_security_attrs (FuPlugin *plugin, FuSecurityAttrs *attrs) fwupd_security_attr_add_flag (attr, FWUPD_SECURITY_ATTR_FLAG_SUCCESS); fwupd_security_attr_set_result (attr, FWUPD_SECURITY_ATTR_RESULT_LOCKED); } + +static void +fu_plugin_add_security_attrs_override_strap (FuPlugin *plugin, FuSecurityAttrs *attrs) +{ + FuPluginData *priv = fu_plugin_get_data (plugin); + g_autoptr(FwupdSecurityAttr) attr = NULL; + + /* create attr */ + attr = fwupd_security_attr_new (FWUPD_SECURITY_ATTR_ID_MEI_OVERRIDE_STRAP); + fwupd_security_attr_set_plugin (attr, fu_plugin_get_name (plugin)); + fwupd_security_attr_set_level (attr, FWUPD_SECURITY_ATTR_LEVEL_CRITICAL); + fu_security_attrs_append (attrs, attr); + + /* Flash Descriptor Security Override Strap */ + if (((priv->mei_cfg >> 16) & 0x7) != 0) { + fwupd_security_attr_set_result (attr, FWUPD_SECURITY_ATTR_RESULT_NOT_LOCKED); + return; + } + + /* success */ + fwupd_security_attr_add_flag (attr, FWUPD_SECURITY_ATTR_FLAG_SUCCESS); + fwupd_security_attr_set_result (attr, FWUPD_SECURITY_ATTR_RESULT_LOCKED); +} + +void +fu_plugin_add_security_attrs (FuPlugin *plugin, FuSecurityAttrs *attrs) +{ + FuPluginData *priv = fu_plugin_get_data (plugin); + + /* only Intel */ + if (!fu_common_is_cpu_intel ()) + return; + if (!priv->has_device) + return; + + fu_plugin_add_security_attrs_manufacturing_mode (plugin, attrs); + fu_plugin_add_security_attrs_override_strap (plugin, attrs); +} diff --git a/src/fu-security-attr.c b/src/fu-security-attr.c index b18332bc1..657908d69 100644 --- a/src/fu-security-attr.c +++ b/src/fu-security-attr.c @@ -85,6 +85,10 @@ fu_security_attr_get_name (FwupdSecurityAttr *attr) /* TRANSLATORS: Title: MEI = Intel Management Engine */ return _("MEI manufacturing mode"); } + if (g_strcmp0 (appstream_id, FWUPD_SECURITY_ATTR_ID_MEI_OVERRIDE_STRAP) == 0) { + /* TRANSLATORS: Title: MEI = Intel Management Engine */ + return _("MEI override strap"); + } if (g_strcmp0 (appstream_id, FWUPD_SECURITY_ATTR_ID_FWUPD_UPDATES) == 0) { /* TRANSLATORS: Title: if firmware updates are available */ return _("Firmware updates"); From 0f6d754d5a57c9ad9c74166841c8f615007c60a2 Mon Sep 17 00:00:00 2001 From: Richard Hughes Date: Mon, 1 Jun 2020 17:03:00 +0100 Subject: [PATCH 136/607] Detect if the MEI device has known security issues If it has, fail HSI-1. --- libfwupd/fwupd-security-attr.h | 1 + plugins/pci-mei/fu-mei-common.c | 148 ++++++++++++++++++++++++++++ plugins/pci-mei/fu-mei-common.h | 37 +++++++ plugins/pci-mei/fu-plugin-pci-mei.c | 131 ++++++++++++++++++++++++ plugins/pci-mei/meson.build | 1 + src/fu-security-attr.c | 4 + 6 files changed, 322 insertions(+) create mode 100644 plugins/pci-mei/fu-mei-common.c create mode 100644 plugins/pci-mei/fu-mei-common.h diff --git a/libfwupd/fwupd-security-attr.h b/libfwupd/fwupd-security-attr.h index 16154f696..9087af619 100644 --- a/libfwupd/fwupd-security-attr.h +++ b/libfwupd/fwupd-security-attr.h @@ -124,6 +124,7 @@ typedef enum { #define FWUPD_SECURITY_ATTR_ID_KERNEL_TAINTED "org.fwupd.hsi.KernelTainted" /* Since: 1.5.0 */ #define FWUPD_SECURITY_ATTR_ID_MEI_MANUFACTURING_MODE "org.fwupd.hsi.MeiManufacturingMode" /* Since: 1.5.0 */ #define FWUPD_SECURITY_ATTR_ID_MEI_OVERRIDE_STRAP "org.fwupd.hsi.MeiOverrideStrap" /* Since: 1.5.0 */ +#define FWUPD_SECURITY_ATTR_ID_MEI_VERSION "org.fwupd.hsi.MeiVersion" /* Since: 1.5.0 */ #define FWUPD_SECURITY_ATTR_ID_SPI_BIOSWE "org.fwupd.hsi.SpiBioswe" /* Since: 1.5.0 */ #define FWUPD_SECURITY_ATTR_ID_SPI_BLE "org.fwupd.hsi.SpiBle" /* Since: 1.5.0 */ #define FWUPD_SECURITY_ATTR_ID_SPI_SMM_BWP "org.fwupd.hsi.SpiSmmBwp" /* Since: 1.5.0 */ diff --git a/plugins/pci-mei/fu-mei-common.c b/plugins/pci-mei/fu-mei-common.c new file mode 100644 index 000000000..3e9b123a9 --- /dev/null +++ b/plugins/pci-mei/fu-mei-common.c @@ -0,0 +1,148 @@ +/* + * Copyright (C) 2020 Richard Hughes + * + * SPDX-License-Identifier: LGPL-2.1+ + */ + +#include "config.h" + +#include "fu-mei-common.h" + +const gchar * +fu_mei_common_family_to_string (FuMeiFamily family) +{ + if (family == FU_MEI_FAMILY_SPS) + return "SPS"; + if (family == FU_MEI_FAMILY_TXE) + return "TXE"; + if (family == FU_MEI_FAMILY_ME) + return "ME"; + if (family == FU_MEI_FAMILY_CSME) + return "CSME"; + return "AMT"; +} + +static gint +fu_mei_common_cmp_version (FuMeiVersion *vers1, FuMeiVersion *vers2) +{ + guint16 vers1buf[] = { + vers1->major, + vers1->minor, + vers1->hotfix, + vers1->buildno, + }; + guint16 vers2buf[] = { + vers2->major, + vers2->minor, + vers2->hotfix, + vers2->buildno, + }; + for (guint i = 0; i < 4; i++) { + if (vers1buf[i] < vers2buf[i]) + return -1; + if (vers1buf[i] > vers2buf[i]) + return 1; + } + return 0; +} + +FuMeiIssue +fu_mei_common_is_csme_vulnerable (FuMeiVersion *vers) +{ + if (vers->major == 11 && vers->minor == 8 && vers->hotfix >= 70) + return FU_MEI_ISSUE_PATCHED; + if (vers->major == 11 && vers->minor == 11 && vers->hotfix >= 70) + return FU_MEI_ISSUE_PATCHED; + if (vers->major == 11 && vers->minor == 22 && vers->hotfix >= 70) + return FU_MEI_ISSUE_PATCHED; + if (vers->major == 12 && vers->minor == 0 && (vers->hotfix == 49 || vers->hotfix >= 56)) + return FU_MEI_ISSUE_PATCHED; + if (vers->major == 13 && vers->minor == 0 && vers->hotfix >= 21) + return FU_MEI_ISSUE_PATCHED; + if (vers->major == 14 && vers->minor == 0 && vers->hotfix >= 11) + return FU_MEI_ISSUE_PATCHED; + if (vers->major == 15) + return FU_MEI_ISSUE_NOT_VULNERABLE; + return FU_MEI_ISSUE_VULNERABLE; +} + +FuMeiIssue +fu_mei_common_is_txe_vulnerable (FuMeiVersion *vers) +{ + if (vers->major == 3 && vers->minor == 1 && vers->hotfix >= 70) + return FU_MEI_ISSUE_PATCHED; + if (vers->major == 4 && vers->minor == 0 && vers->hotfix >= 20) + return FU_MEI_ISSUE_PATCHED; + if (vers->major == 5) + return FU_MEI_ISSUE_NOT_VULNERABLE; + return FU_MEI_ISSUE_VULNERABLE; +} + +FuMeiIssue +fu_mei_common_is_sps_vulnerable (FuMeiVersion *vers) +{ + if (vers->major == 3 || vers->major > 5) + return FU_MEI_ISSUE_NOT_VULNERABLE; + if (vers->major == 4) { + if (vers->hotfix < 44) + return FU_MEI_ISSUE_VULNERABLE; + if (vers->platform == 0xA) { /* Purley */ + FuMeiVersion ver2 = { + .major = 4, + .minor = 1, + .hotfix = 4, + .buildno = 339, + }; + if (fu_mei_common_cmp_version (vers, &ver2) < 0) + return FU_MEI_ISSUE_VULNERABLE; + } else if (vers->platform == 0xE) { /* Bakerville */ + FuMeiVersion ver2 = { + .major = 4, + .minor = 0, + .hotfix = 4, + .buildno = 112, + }; + if (fu_mei_common_cmp_version (vers, &ver2) < 0) + return FU_MEI_ISSUE_VULNERABLE; + } else if (vers->platform == 0xB) { /* Harrisonville */ + FuMeiVersion ver2 = { + .major = 4, + .minor = 0, + .hotfix = 4, + .buildno = 193, + }; + if (fu_mei_common_cmp_version (vers, &ver2) < 0) + return FU_MEI_ISSUE_VULNERABLE; + } else if (vers->platform == 0x9) { /* Greenlow */ + FuMeiVersion ver2 = { + .major = 4, + .minor = 1, + .hotfix = 4, + .buildno = 88, + }; + if (vers->minor < 1) + return FU_MEI_ISSUE_NOT_VULNERABLE; + if (fu_mei_common_cmp_version (vers, &ver2) < 0) + return FU_MEI_ISSUE_VULNERABLE; + } else if (vers->platform == 0xD) { /* MonteVista */ + FuMeiVersion ver2 = { + .major = 4, + .minor = 8, + .hotfix = 4, + .buildno = 51, + }; + if (fu_mei_common_cmp_version (vers, &ver2) < 0) + return FU_MEI_ISSUE_VULNERABLE; + } + return FU_MEI_ISSUE_NOT_VULNERABLE; + } + if (vers->major == 5) { + if (vers->platform == 0x10) { /* Mehlow */ + FuMeiVersion ver2 = { 5, 1, 3, 89 }; + if (fu_mei_common_cmp_version (vers, &ver2) < 0) + return FU_MEI_ISSUE_VULNERABLE; + } + return FU_MEI_ISSUE_NOT_VULNERABLE; + } + return FU_MEI_ISSUE_PATCHED; +} diff --git a/plugins/pci-mei/fu-mei-common.h b/plugins/pci-mei/fu-mei-common.h new file mode 100644 index 000000000..0d990c4dc --- /dev/null +++ b/plugins/pci-mei/fu-mei-common.h @@ -0,0 +1,37 @@ +/* + * Copyright (C) 2020 Richard Hughes + * + * SPDX-License-Identifier: LGPL-2.1+ + */ + +#pragma once + +#include "fu-plugin.h" + +typedef enum { + FU_MEI_FAMILY_UNKNOWN, + FU_MEI_FAMILY_SPS, + FU_MEI_FAMILY_TXE, + FU_MEI_FAMILY_ME, + FU_MEI_FAMILY_CSME, +} FuMeiFamily; + +typedef enum { + FU_MEI_ISSUE_UNKNOWN, + FU_MEI_ISSUE_NOT_VULNERABLE, + FU_MEI_ISSUE_VULNERABLE, + FU_MEI_ISSUE_PATCHED, +} FuMeiIssue; + +typedef struct { + guint8 platform; + guint8 major; + guint8 minor; + guint8 hotfix; + guint16 buildno; +} FuMeiVersion; + +const gchar *fu_mei_common_family_to_string (FuMeiFamily family); +FuMeiIssue fu_mei_common_is_csme_vulnerable (FuMeiVersion *vers); +FuMeiIssue fu_mei_common_is_txe_vulnerable (FuMeiVersion *vers); +FuMeiIssue fu_mei_common_is_sps_vulnerable (FuMeiVersion *vers); diff --git a/plugins/pci-mei/fu-plugin-pci-mei.c b/plugins/pci-mei/fu-plugin-pci-mei.c index b0e8300c5..c8684d239 100644 --- a/plugins/pci-mei/fu-plugin-pci-mei.c +++ b/plugins/pci-mei/fu-plugin-pci-mei.c @@ -9,9 +9,13 @@ #include "fu-plugin-vfuncs.h" #include "fu-hash.h" +#include "fu-mei-common.h" + struct FuPluginData { gboolean has_device; guint32 mei_cfg; + FuMeiVersion vers; + FuMeiIssue issue; }; #define PCI_CFG_HFS_1 0x40 @@ -24,10 +28,95 @@ fu_plugin_init (FuPlugin *plugin) fu_plugin_add_udev_subsystem (plugin, "pci"); } +static FuMeiFamily +fu_mei_detect_family (FuPlugin *plugin) +{ + FuPluginData *priv = fu_plugin_get_data (plugin); + guint8 operating_mode = (priv->mei_cfg >> 16) & 0xF; + guint8 ver = priv->vers.major; + + if (ver == 1 || ver == 2) { + if (operating_mode == 0xF) + return FU_MEI_FAMILY_SPS; + return FU_MEI_FAMILY_TXE; + } + if (ver == 3 || ver == 4 || ver == 5) + return FU_MEI_FAMILY_TXE; + if (ver == 6 || ver == 7 || ver == 8 || ver == 9 || ver == 10) + return FU_MEI_FAMILY_ME; + if (ver == 11 || ver == 12 || ver == 13 || ver == 14 || ver == 15) + return FU_MEI_FAMILY_CSME; + return FU_MEI_FAMILY_UNKNOWN; +} + +static gboolean +fu_mei_parse_fwvers (FuPlugin *plugin, const gchar *fwvers, GError **error) +{ + FuPluginData *priv = fu_plugin_get_data (plugin); + FuMeiFamily family; + g_auto(GStrv) lines = NULL; + g_auto(GStrv) sections = NULL; + g_auto(GStrv) split = NULL; + + /* we only care about the first version */ + lines = g_strsplit (fwvers, "\n", -1); + if (g_strv_length (lines) < 1) { + g_set_error (error, + G_IO_ERROR, + G_IO_ERROR_INVALID_DATA, + "expected data, got %s", fwvers); + return FALSE; + } + + /* split platform : version */ + sections = g_strsplit (lines[0], ":", -1); + if (g_strv_length (sections) != 2) { + g_set_error (error, + G_IO_ERROR, + G_IO_ERROR_INVALID_DATA, + "expected platform:major.minor.micro.build, got %s", + lines[0]); + return FALSE; + } + + /* parse platform and versions */ + priv->vers.platform = fu_common_strtoull (sections[0]); + split = g_strsplit (sections[1], ".", -1); + if (g_strv_length (split) != 4) { + g_set_error (error, + G_IO_ERROR, + G_IO_ERROR_INVALID_DATA, + "expected major.minor.micro.build, got %s", + sections[1]); + return FALSE; + } + priv->vers.major = fu_common_strtoull (split[0]); + priv->vers.minor = fu_common_strtoull (split[1]); + priv->vers.hotfix = fu_common_strtoull (split[2]); + priv->vers.buildno = fu_common_strtoull (split[3]); + + /* check the AMT version for issues using the data from: + * https://downloadcenter.intel.com/download/28632 */ + family = fu_mei_detect_family (plugin); + if (family == FU_MEI_FAMILY_CSME) + priv->issue = fu_mei_common_is_csme_vulnerable (&priv->vers); + else if (family == FU_MEI_FAMILY_TXE) + priv->issue = fu_mei_common_is_txe_vulnerable (&priv->vers); + else if (family == FU_MEI_FAMILY_SPS) + priv->issue = fu_mei_common_is_sps_vulnerable (&priv->vers); + if (g_getenv ("FWUPD_MEI_VERBOSE") != NULL) { + g_debug ("%s version parsed as %u.%u.%u", + fu_mei_common_family_to_string (family), + priv->vers.major, priv->vers.minor, priv->vers.hotfix); + } + return TRUE; +} + gboolean fu_plugin_udev_device_added (FuPlugin *plugin, FuUdevDevice *device, GError **error) { FuPluginData *priv = fu_plugin_get_data (plugin); + const gchar *fwvers; guint8 buf[4] = { 0x0 }; g_autoptr(FuDeviceLocker) locker = NULL; @@ -50,6 +139,15 @@ fu_plugin_udev_device_added (FuPlugin *plugin, FuUdevDevice *device, GError **er } priv->mei_cfg = fu_common_read_uint32 (buf, G_LITTLE_ENDIAN); priv->has_device = TRUE; + + /* check firmware version */ + fwvers = fu_udev_device_get_sysfs_attr (device, "mei/mei0/fw_ver", NULL); + if (fwvers != NULL) { + if (!fu_mei_parse_fwvers (plugin, fwvers, error)) + return FALSE; + } + + /* success */ return TRUE; } @@ -99,6 +197,38 @@ fu_plugin_add_security_attrs_override_strap (FuPlugin *plugin, FuSecurityAttrs * fwupd_security_attr_set_result (attr, FWUPD_SECURITY_ATTR_RESULT_LOCKED); } +static void +fu_plugin_add_security_attrs_csme_version (FuPlugin *plugin, FuSecurityAttrs *attrs) +{ + FuPluginData *priv = fu_plugin_get_data (plugin); + g_autoptr(FwupdSecurityAttr) attr = NULL; + + if (priv->issue == FU_MEI_ISSUE_UNKNOWN) { + g_warning ("ME family not supported for %u:%u.%u.%u.%u", + priv->vers.platform, + priv->vers.major, + priv->vers.minor, + priv->vers.hotfix, + priv->vers.buildno); + return; + } + + /* create attr */ + attr = fwupd_security_attr_new (FWUPD_SECURITY_ATTR_ID_MEI_VERSION); + fwupd_security_attr_set_plugin (attr, fu_plugin_get_name (plugin)); + fwupd_security_attr_set_level (attr, FWUPD_SECURITY_ATTR_LEVEL_CRITICAL); + fu_security_attrs_append (attrs, attr); + + /* Flash Descriptor Security Override Strap */ + if (priv->issue == FU_MEI_ISSUE_VULNERABLE) { + fwupd_security_attr_set_result (attr, FWUPD_SECURITY_ATTR_RESULT_NOT_VALID); + return; + } + + /* success */ + fwupd_security_attr_add_flag (attr, FWUPD_SECURITY_ATTR_FLAG_SUCCESS); +} + void fu_plugin_add_security_attrs (FuPlugin *plugin, FuSecurityAttrs *attrs) { @@ -112,4 +242,5 @@ fu_plugin_add_security_attrs (FuPlugin *plugin, FuSecurityAttrs *attrs) fu_plugin_add_security_attrs_manufacturing_mode (plugin, attrs); fu_plugin_add_security_attrs_override_strap (plugin, attrs); + fu_plugin_add_security_attrs_csme_version (plugin, attrs); } diff --git a/plugins/pci-mei/meson.build b/plugins/pci-mei/meson.build index ce87f4920..4b8c4f01c 100644 --- a/plugins/pci-mei/meson.build +++ b/plugins/pci-mei/meson.build @@ -8,6 +8,7 @@ shared_module('fu_plugin_pci_mei', fu_hash, sources : [ 'fu-plugin-pci-mei.c', + 'fu-mei-common.c', ], include_directories : [ root_incdir, diff --git a/src/fu-security-attr.c b/src/fu-security-attr.c index 657908d69..2596e75f9 100644 --- a/src/fu-security-attr.c +++ b/src/fu-security-attr.c @@ -89,6 +89,10 @@ fu_security_attr_get_name (FwupdSecurityAttr *attr) /* TRANSLATORS: Title: MEI = Intel Management Engine */ return _("MEI override strap"); } + if (g_strcmp0 (appstream_id, FWUPD_SECURITY_ATTR_ID_MEI_VERSION) == 0) { + /* TRANSLATORS: Title: MEI = Intel Management Engine */ + return _("MEI version"); + } if (g_strcmp0 (appstream_id, FWUPD_SECURITY_ATTR_ID_FWUPD_UPDATES) == 0) { /* TRANSLATORS: Title: if firmware updates are available */ return _("Firmware updates"); From c0a2798fb5f55bc719802ecf4dc43422cacada55 Mon Sep 17 00:00:00 2001 From: Mario Limonciello Date: Tue, 2 Jun 2020 10:14:33 -0500 Subject: [PATCH 137/607] trivial: logitech_hidpp: set the protocol properly when bootloader unknown This appears to be a regression from c6ae0d998b7e5577b3de4763c25d9d90056bebf1 where the case of bootloader version 0 didn't get protocol set. Fixes: #2156 --- plugins/logitech-hidpp/fu-logitech-hidpp-runtime.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/plugins/logitech-hidpp/fu-logitech-hidpp-runtime.c b/plugins/logitech-hidpp/fu-logitech-hidpp-runtime.c index 547b029c5..869ff5065 100644 --- a/plugins/logitech-hidpp/fu-logitech-hidpp-runtime.c +++ b/plugins/logitech-hidpp/fu-logitech-hidpp-runtime.c @@ -230,10 +230,10 @@ fu_logitech_hidpp_runtime_setup_internal (FuDevice *device, GError **error) (self->version_bl_major == 0x03 && config[8] >= 0x02)) { self->signed_firmware = TRUE; fu_device_set_protocol (device, "com.logitech.unifyingsigned"); - } else { - fu_device_set_protocol (device, "com.logitech.unifying"); } } + if (!self->signed_firmware) + fu_device_set_protocol (device, "com.logitech.unifying"); /* enable HID++ notifications */ if (!fu_logitech_hidpp_runtime_enable_notifications (self, error)) { From 5c2c782446c6c0dc4a44a90708ecce767976c93f Mon Sep 17 00:00:00 2001 From: Mario Limonciello Date: Tue, 2 Jun 2020 10:52:13 -0500 Subject: [PATCH 138/607] trivial: add a bug report target for Dell WD19 --- .github/ISSUE_TEMPLATE/bug-report-wd19.md | 64 +++++++++++++++++++++++ 1 file changed, 64 insertions(+) create mode 100644 .github/ISSUE_TEMPLATE/bug-report-wd19.md diff --git a/.github/ISSUE_TEMPLATE/bug-report-wd19.md b/.github/ISSUE_TEMPLATE/bug-report-wd19.md new file mode 100644 index 000000000..fa0045c2e --- /dev/null +++ b/.github/ISSUE_TEMPLATE/bug-report-wd19.md @@ -0,0 +1,64 @@ +--- +name: Bug report (Dell WD19) +about: Create a report to help us improve +title: 'Dell WD19 upgrade issue' +labels: bug +assignees: 'superm1' + +--- + +**Describe the bug** +A clear and concise description of what the bug is. + + +**Steps to Reproduce** +Steps to reproduce the behavior. + + +**Expected behavior** +A clear and concise description of what you expected to happen. + +**fwupd version information** +Please provide the version of the daemon and client. +```shell +$ fwupdmgr --version +``` + +Please note how you installed it (`apt`, `dnf`, `pacman`, source, etc): + +**fwupd device information** +Please provide the output of the external fwupd devices recognized in your system. + +```shell +$ fwupdmgr get-devices --filter=~internal +``` + +**Dock SKU** +Please mention which module is installed in your WD19. + +- [ ] WD19 (Single-C) +- [ ] WD19TB (Thunderbolt) +- [ ] WD19DC (Dual-C) + +**Peripherals connected to the dock** +Please describe all devices connected to the dock. Be as specific as possible, +including USB devices, hubs, monitors, and downstream type-C devices. + +**Verbose daemon logs** +First enable daemon verbose logs collection. +```shell +fwupdmgr modify-config "VerboseDomains" "*" +``` + +Then try to reproduce the issue. Even if it doesn't reproduce, please attach the +daemon verbose logs collected from the system journal. +```shell +journalctl -b -u fwupd.service +``` + +**Additional questions** +- Operating system and version: +- Have you tried unplugging the dock or any peripherals from your machine? +- Have you tried to power cycle the dock from the AC adapter? +- Is this a regression? + From 2e3605ffdc2b710410678bb8a7ba34eea9d91e83 Mon Sep 17 00:00:00 2001 From: Richard Hughes Date: Fri, 5 Jun 2020 12:17:21 +0100 Subject: [PATCH 139/607] trivial: Add RemoveDelay as a standard FuDevice quirk --- libfwupdplugin/fu-device.c | 4 ++++ libfwupdplugin/fu-quirks.h | 1 + 2 files changed, 5 insertions(+) diff --git a/libfwupdplugin/fu-device.c b/libfwupdplugin/fu-device.c index 887d7d52b..a4f225e38 100644 --- a/libfwupdplugin/fu-device.c +++ b/libfwupdplugin/fu-device.c @@ -1038,6 +1038,10 @@ fu_device_set_quirk_kv (FuDevice *self, fu_device_set_priority (self, fu_common_strtoull (value)); return TRUE; } + if (g_strcmp0 (key, FU_QUIRKS_REMOVE_DELAY) == 0) { + fu_device_set_remove_delay (self, fu_common_strtoull (value)); + return TRUE; + } if (g_strcmp0 (key, FU_QUIRKS_VERSION_FORMAT) == 0) { fu_device_set_version_format (self, fwupd_version_format_from_string (value)); return TRUE; diff --git a/libfwupdplugin/fu-quirks.h b/libfwupdplugin/fu-quirks.h index 1ebfdab8c..213cbf155 100644 --- a/libfwupdplugin/fu-quirks.h +++ b/libfwupdplugin/fu-quirks.h @@ -65,3 +65,4 @@ gboolean fu_quirks_lookup_by_id_iter (FuQuirks *self, #define FU_QUIRKS_PROTOCOL "Protocol" #define FU_QUIRKS_UPDATE_MESSAGE "UpdateMessage" #define FU_QUIRKS_PRIORITY "Priority" +#define FU_QUIRKS_REMOVE_DELAY "RemoveDelay" From 0942dcc413cf20b3f015db075c59bad5edc2f9a3 Mon Sep 17 00:00:00 2001 From: Ryan Lee Date: Mon, 1 Jun 2020 21:00:45 +0900 Subject: [PATCH 140/607] ccgx: Add support for HP DMC dock devices --- plugins/ccgx/README.md | 33 +- plugins/ccgx/ccgx.quirk | 22 + plugins/ccgx/fu-ccgx-common.c | 4 + plugins/ccgx/fu-ccgx-common.h | 3 +- plugins/ccgx/fu-ccgx-dmc-common.c | 20 + plugins/ccgx/fu-ccgx-dmc-common.h | 297 ++++++++++++ plugins/ccgx/fu-ccgx-dmc-device.c | 669 ++++++++++++++++++++++++++++ plugins/ccgx/fu-ccgx-dmc-device.h | 13 + plugins/ccgx/fu-ccgx-dmc-firmware.c | 368 +++++++++++++++ plugins/ccgx/fu-ccgx-dmc-firmware.h | 35 ++ plugins/ccgx/fu-plugin-ccgx.c | 4 + plugins/ccgx/meson.build | 3 + 12 files changed, 1466 insertions(+), 5 deletions(-) create mode 100644 plugins/ccgx/fu-ccgx-dmc-common.c create mode 100644 plugins/ccgx/fu-ccgx-dmc-common.h create mode 100644 plugins/ccgx/fu-ccgx-dmc-device.c create mode 100644 plugins/ccgx/fu-ccgx-dmc-device.h create mode 100644 plugins/ccgx/fu-ccgx-dmc-firmware.c create mode 100644 plugins/ccgx/fu-ccgx-dmc-firmware.h diff --git a/plugins/ccgx/README.md b/plugins/ccgx/README.md index 82f0a3539..508ba2373 100644 --- a/plugins/ccgx/README.md +++ b/plugins/ccgx/README.md @@ -10,11 +10,13 @@ Supported devices: * Lenovo Gen2 Dock * Lenovo Hybrid Dock + * HP USB-C Dock G5 + * HP USB-C/A Universal Dock G2 Device Flash ============ -There are three kinds of flash layout. Single image firmware is not currently +There are four kinds of flash layout. Single image firmware is not currently supported in this plugin. Symmetric Firmware @@ -49,12 +51,33 @@ Case 2: FW1 is running (recovery case) The `CY_PD_JUMP_TO_ALT_FW_CMD_SIG` command is allowed only in asymmetric FW, but `CY_PD_DEVICE_RESET_CMD_SIG` is allowed in both asymmetric FW and symmetric FW. +DMC(Dock Management Controller) Composite Firmware +--------------------------------------------------- + +In composite firmware topology, a single firmware image contains metadata and +firmware images of multiple devices including DMC itself in a dock system. + + Firmware Format ---------------- +=============== + +There are two kinds of firmware format. + +Cyacd firmware format +--------------------- + The daemon will decompress the cabinet archive and extract several firmware blobs in cyacd file format. See https://community.cypress.com/docs/DOC-10562 for more details. +DMC composite firmware format +------------------------------ + +The daemon will decompress the cabinet archive and extract several firmware +blobs in a combined image file format. See 4.4.1 Single Composite +(Combined) Dock Image at https://www.cypress.com/file/387471/download +for more details. + This plugin supports the following protocol ID: * com.cypress.ccgx @@ -65,9 +88,11 @@ GUID Generation These devices use the standard USB DeviceInstanceId values, e.g. * `USB\VID_17EF&PID_A38F` + * `USB\VID_03F0&PID_046B` -They additionally add other instance IDs which corresponds to the silicon ID, -application ID and device mode, e.g. +For cyacd firmware device, + They additionally add other instance IDs which corresponds to the silicon ID, + application ID and device mode, e.g. * `USB\VID_17EF&PID_A38F&SID_1234` * `USB\VID_17EF&PID_A38F&SID_1234&APP_5678` diff --git a/plugins/ccgx/ccgx.quirk b/plugins/ccgx/ccgx.quirk index 6b674633b..69ed22df0 100644 --- a/plugins/ccgx/ccgx.quirk +++ b/plugins/ccgx/ccgx.quirk @@ -41,3 +41,25 @@ Name = ThinkPad USB-C Dock Hybrid PD Controller Summary = CCGx Power Delivery Device ImageKind = dual-symmetric ParentGuid = USB\VID_17EF&PID_1028 + +# HP Adicora Dock A Type +[DeviceInstanceId=USB\VID_03F0&PID_046B] +Plugin = ccgx +GType = FuCcgxDmcDevice +Summary = Dock Management Controller Device +ParentGuid = USB\VID_03F0&PID_0363 +Name = HP USB-C Dock G5 +ImageKind = dmc-composite +InstallDuration = 40 +RemoveDelay = 150000 + +# HP Adicora Dock D Type +[DeviceInstanceId=USB\VID_03F0&PID_0A6B] +Plugin = ccgx +GType = FuCcgxDmcDevice +Summary = Dock Management Controller Device +ParentGuid = USB\VID_03F0&PID_096B +Name = HP USB-C/A Universal Dock G2 +ImageKind = dmc-composite +InstallDuration = 25 +RemoveDelay = 85000 diff --git a/plugins/ccgx/fu-ccgx-common.c b/plugins/ccgx/fu-ccgx-common.c index e7848ccce..0aaf3231f 100644 --- a/plugins/ccgx/fu-ccgx-common.c +++ b/plugins/ccgx/fu-ccgx-common.c @@ -44,6 +44,8 @@ fu_ccgx_fw_image_type_to_string (FWImageType val) return "dual-asymmetric"; if (val == FW_IMAGE_TYPE_DUAL_ASYMMETRIC_VARIABLE) return "dual-asymmetric-variable"; + if (val == FW_IMAGE_TYPE_DMC_COMPOSITE) + return "dmc-composite"; return NULL; } @@ -58,6 +60,8 @@ fu_ccgx_fw_image_type_from_string (const gchar *val) return FW_IMAGE_TYPE_DUAL_ASYMMETRIC; if (g_strcmp0 (val, "dual-asymmetric-variable") == 0) return FW_IMAGE_TYPE_DUAL_ASYMMETRIC_VARIABLE; + if (g_strcmp0 (val, "dmc-composite") == 0) + return FW_IMAGE_TYPE_DMC_COMPOSITE; return FW_IMAGE_TYPE_UNKNOWN; } diff --git a/plugins/ccgx/fu-ccgx-common.h b/plugins/ccgx/fu-ccgx-common.h index aff581aad..af9e2a8a6 100644 --- a/plugins/ccgx/fu-ccgx-common.h +++ b/plugins/ccgx/fu-ccgx-common.h @@ -18,7 +18,7 @@ typedef struct __attribute__((packed)) { guint8 reserved1[2]; /* reserved */ guint32 fw_size; /* firmware size */ guint8 reserved2[9]; /* reserved */ - guint16 metadata_valid; /* meta data valid "CY" */ + guint16 metadata_valid; /* metadata valid "CY" */ guint8 reserved3[4]; /* reserved */ guint32 boot_seq; /* boot sequence number */ } CCGxMetaData; @@ -38,6 +38,7 @@ typedef enum { FW_IMAGE_TYPE_DUAL_SYMMETRIC, /* A/B runtime */ FW_IMAGE_TYPE_DUAL_ASYMMETRIC, /* A=bootloader (fixed), B=runtime */ FW_IMAGE_TYPE_DUAL_ASYMMETRIC_VARIABLE, /* A=bootloader (variable), B=runtime */ + FW_IMAGE_TYPE_DMC_COMPOSITE, /* composite firmware image for dmc */ } FWImageType; gchar *fu_ccgx_version_to_string (guint32 val); diff --git a/plugins/ccgx/fu-ccgx-dmc-common.c b/plugins/ccgx/fu-ccgx-dmc-common.c new file mode 100644 index 000000000..88ac096e3 --- /dev/null +++ b/plugins/ccgx/fu-ccgx-dmc-common.c @@ -0,0 +1,20 @@ +/* + * Copyright (C) 2020 Richard Hughes + * + * SPDX-License-Identifier: LGPL-2.1+ + */ + +#include "config.h" +#include "fu-ccgx-dmc-common.h" + +const gchar * +fu_ccgx_dmc_update_model_type_to_string (DmcUpdateModel val) +{ + if (val == DMC_UPDATE_MODEL_UNKNOWN) + return "Unknown"; + if (val == DMC_UPDATE_MODEL_DOWNLOAD_TRIGGER) + return "Download Trigger"; + if (val == DMC_UPDATE_MODEL_PENDING_RESET) + return "Pending Reset"; + return NULL; +} diff --git a/plugins/ccgx/fu-ccgx-dmc-common.h b/plugins/ccgx/fu-ccgx-dmc-common.h new file mode 100644 index 000000000..767955d29 --- /dev/null +++ b/plugins/ccgx/fu-ccgx-dmc-common.h @@ -0,0 +1,297 @@ +/* + * Copyright (C) 2020 Cypress Semiconductor Corporation. + * + * SPDX-License-Identifier: LGPL-2.1+ + */ + +#pragma once + +#include + +/* maximum number of programmable devices expected to be connected in dock. +* this is design limitation. This shall not be edited, unless stated by C Y*/ +#define DMC_DOCK_MAX_DEV_COUNT 8 + +/* size of FW version structure in bytes */ +#define DMC_DOCK_FW_VERSION_SIZE 8 + +/* indicates length of string in dock identity*/ +#define DMC_IDENTITY_STRING_LEN 32 + +/* interrupt end point for DMC Dock */ +#define DMC_INTERRUPT_PIPE_ID 0x82 + +/* USB bulk end point for DMC Dock */ +#define DMC_BULK_PIPE_ID 1 + +/* indicates length of interrupt structure's data array filed */ +#define DMC_INTERRUPT_DATA_LEN 8 + +/* status of the dmc will have different length. so first few bytes of status +* is read, which will contain actual length of status. this value indicates +* how much byte should read at first stage */ +#define DMC_GET_STATUS_MIN_LEN 32 + +#define DMC_HASH_SIZE 32 + +/* time out to be set in control in/out pipe policy in ms */ +#define DMC_CONTROL_TRANSFER_DEFAULT_TIMEOUT 5000 + +/* time out to be set in bulk out pipe policy in ms */ +#define DMC_BULK_OUT_PIPE_TIMEOUT 2000 + +/* time out to be set in bulk out pipe policy in ms */ +#define DMC_GET_REQUEST_TIMEOUT 20000 + + +#define DMC_FWCT_SIGN 0x54435746 /* 'F' 'W' 'C' 'T' */ + +/* first we have to read few bytes to know the actual length of FWCT + * this constant defines, number bytest to be read for getting length */ +#define DMC_FWCT_MIN_LENGTH 6 +#define DMC_FWCT_LENGTH_OFFSET 4 +#define DMC_FWCT_MAX_SIZE 2048 + +#define DMC_CUSTOM_META_LENGTH_FIELD_SIZE 2 +#define DMC_CUSTOM_META_LENGTH_OFFSET 0 +#define DMC_CUSTOM_META_MAX_SIZE 256 + +/* this data type enumerates the image types */ +typedef enum { + DMC_IMG_TYPE_INVALID = 0, + DMC_IMG_TYPE_IMAGE_0, + DMC_IMG_TYPE_IMAGE_1 +} DmcImgType; + +/* this data type enumerates the image status */ +typedef enum { + DMC_IMG_STATUS_UNKNOWN = 0, + DMC_IMG_STATUS_VALID, + DMC_IMG_STATUS_INVALID, + DMC_IMG_STATUS_RECOVERY, + DMC_IMG_STATUS_RECOVERED_FROM_SECONDARY, + DMC_IMG_STATUS_NOT_SUPPORTED = 0x0F +} DmcImgStatus; + +/* this data type enumerates the image modes or flash architecture */ +typedef enum { + /* indicates that the device has a single image */ + DMC_IMG_MODE_SINGLE_IMG = 0, + /* the device supports symmetric boot. In symmetric mode the bootloader + * boots the image with higher version, when they are valid */ + DMC_IMG_MODE_DUAL_IMG_SYM, + /* the device supports Asymmetric boot. Image-1 & 2 can be different or + * same. in this method Bootloader is hard coded to boot the primary + * image. Secondary acts as recovery */ + DMC_IMG_MODE_DUAL_IMG_ASYM, + DMC_IMG_MODE_SINGLE_IMG_WITH_RAM_IMG, +} DmcImgMode; + +/* this data type enumerates the dock status */ +typedef enum { + /* status code indicating DOCK IDLE state. SUCCESS: no malfunctioning + * no outstanding request or event */ + DMC_DEVICE_STATUS_IDLE = 0, + /* status code indicating dock FW update in progress */ + DMC_DEVICE_STATUS_UPDATE_IN_PROGRESS, + /* status code indicating dock FW update is partially complete */ + DMC_DEVICE_STATUS_UPDATE_PARTIAL, + /* status code indicating dock FW update SUCCESS - all m_images of all + * devices are valid */ + DMC_DEVICE_STATUS_UPDATE_COMPLETE_FULL, + /* status code indicating dock FW update SUCCESS - not all m_images of all + * devices are valid */ + DMC_DEVICE_STATUS_UPDATE_COMPLETE_PARTIAL, + /* fw download status */ + DMC_DEVICE_STATUS_UPDATE_PHASE_1_COMPLETE, + DMC_DEVICE_STATUS_FW_DOWNLOADED_UPDATE_PEND, + DMC_DEVICE_STATUS_FW_DOWNLOADED_PARTIAL_UPDATE_PEND, + DMC_DEVICE_STATUS_PHASE2_UPDATE_IN_PROGRESS = 0x81, + DMC_DEVICE_STATUS_PHASE2_UPDATE_PARTIAL, + DMC_DEVICE_STATUS_PHASE2_UPDATE_FACTORY_BACKUP, + DMC_DEVICE_STATUS_PHASE2_UPDATE_COMPLETE_PARTIAL, + DMC_DEVICE_STATUS_PHASE2_UPDATE_COMPLETE_FULL, + DMC_DEVICE_STATUS_PHASE2_UPDATE_FAIL_INVALID_FWCT, + DMC_DEVICE_STATUS_PHASE2_UPDATE_FAIL_INVALID_DOCK_IDENTITY, + DMC_DEVICE_STATUS_PHASE2_UPDATE_FAIL_INVALID_COMPOSITE_VER, + DMC_DEVICE_STATUS_PHASE2_UPDATE_FAIL_AUTHENTICATION_FAILED, + DMC_DEVICE_STATUS_PHASE2_UPDATE_FAIL_INVALID_ALGORITHM, + DMC_DEVICE_STATUS_PHASE2_UPDATE_FAIL_SPI_READ_FAILED, + DMC_DEVICE_STATUS_PHASE2_UPDATE_FAIL_NO_VALID_KEY, + DMC_DEVICE_STATUS_PHASE2_UPDATE_FAIL_NO_VALID_SPI_PACKAGE, + DMC_DEVICE_STATUS_PHASE2_UPDATE_FAIL_RAM_INIT_FAILED, + DMC_DEVICE_STATUS_PHASE2_UPDATE_FAIL_FACTORY_BACKUP_FAILED, + DMC_DEVICE_STATUS_PHASE2_UPDATE_FAIL_NO_VALID_FACTORY_PACKAGE, + /* status code indicating dock FW update FAILED */ + DMC_DEVICE_STATUS_UPDATE_FAIL = 0xFF +} DmcDeviceStatus; + +/* this data type enumerates the request codes for vendor interface */ +typedef enum { + DMC_RQT_CODE_UPGRADE_START = 0xD0, + DMC_RQT_CODE_RESERV_0, + DMC_RQT_CODE_FWCT_WRITE, + DMC_RQT_CODE_IMG_WRITE, + DMC_RQT_CODE_RESERV_1, + DMC_RQT_CODE_RESERV_2, + DMC_RQT_CODE_DOCK_STATUS, + DMC_RQT_CODE_DOCK_IDENTITY, + /* command to reset dmc state machine of DMC */ + DMC_RQT_CODE_RESET_STATE_MACHINE, + /* command to reset for online enhanced mode (no reset during update) */ + DMC_RQT_CODE_SOFT_RESET = 0xDC, + /* Update Trigger command for offline mode */ + DMC_RQT_CODE_TRIGGER = 0xDA +} DmcRqtCode; + +/* this data type enumerates the opcode of triggering the download, in case of +* 2 stage update */ +typedef enum { + DMC_TRIGGER_CODE_DONT_UPDATE, + DMC_TRIGGER_CODE_UPDATE_NOW, + DMC_TRIGGER_CODE_UPDATE_ON_DISCONNECT, + DMC_TRIGGER_CODE_UNKNOWN +} DmcTriggerCode; + +/* this data type enumerates the opcode of interrupt read */ +typedef enum { + DMC_INT_OPCODE_FW_UPGRADE_RQT = 1, + DMC_INT_OPCODE_FW_UPGRADE_STATUS = 0x80, + DMC_INT_OPCODE_IMG_WRITE_STATUS, + DMC_INT_OPCODE_REENUM, + DMC_INT_OPCODE_FWCT_ANALYSIS_STATUS +} DmcIntOpcode; + +/* this data type enumerates the fwct analysis status */ +typedef enum { + DMC_FWCT_ANALYSIS_STATUS_INVALID_FWCT = 0, + DMC_FWCT_ANALYSIS_STATUS_INVALID_DOCK_IDENTITY, + DMC_FWCT_ANALYSIS_STATUS_INVALID_COMPOSITE_VERSION, + DMC_FWCT_ANALYSIS_STATUS_AUTHENTICATION_FAILED, + DMC_FWCT_ANALYSIS_STATUS_INVALID_ALGORITHM +} DmcFwctAnalysisStatus; + +typedef enum { + DMC_UPDATE_MODEL_UNKNOWN= 0, + /* need to trigger after updating FW */ + DMC_UPDATE_MODEL_DOWNLOAD_TRIGGER, + /* need to set soft reset after updating FW */ + DMC_UPDATE_MODEL_PENDING_RESET, +} DmcUpdateModel; + +/* this structure defines the fields of data returned when reading dock_identity + * for new firmware */ +typedef struct __attribute__((packed)) { + /* this field indicates both validity and structure version + * 0 : invalid + * 1 : old structure + * 2 : new structure */ + guint8 structure_version; + guint8 cdtt_version; + guint16 vid; + guint16 pid; + guint16 device_id; + gchar vendor_string[DMC_IDENTITY_STRING_LEN]; + gchar product_string[DMC_IDENTITY_STRING_LEN]; + guint8 custom_meta_data_flag; + /* model field indicates the type of the firmware upgrade status + * 0 - online/offline + * 1 - Online model + * 2 - ADICORA/Offline model + * 3 - No reset + * 4 - 0xFF - Reserved + */ + guint8 model; +} DmcDockIdentity; + +/* this structure defines the fields of status of a specific device */ +typedef struct __attribute__((packed)) { + /* device ID of the device */ + guint8 device_type; + /* component ID of the device */ + guint8 component_id; + /* image mode of the device - single image/ dual symmetric/ dual + * assymetric image > */ + guint8 image_mode; + /* current running image */ + guint8 current_image; + /* image status + * b7:b4 => Image 2 status + * b3:b0 => Image 1 status + * 0 = Unknown + * 1 = Valid + * 2 = Invalid + * 3-0xF = Reserved + */ + guint8 img_status; + /* padding */ + guint8 reserved_0[3]; + /* complete fw version 8 bytes for bootload, image1 and image2. 8 byte + * for fw version and application version */ + guint8 fw_version[24]; +} DmcDevxStatus; + +/* this structure defines the fields of data returned when reading dock_status */ +typedef struct __attribute__((packed)) { + /* overall status of dock. see DmcDeviceStatus */ + guint8 device_status; + /* eevice count */ + guint8 device_count; + /* length of status bytes including dock_status, + devx_status for each device */ + guint16 status_length; + /* dock composite version m_fwct_info */ + guint32 composite_version; + /* fw status of device of interest */ + DmcDevxStatus devx_status[DMC_DOCK_MAX_DEV_COUNT]; +} DmcDockStatus; + +/* This structure defines the fields of data returned when reading an interrupt +* from DMC */ +typedef struct __attribute__((packed)) { + guint8 opcode; + guint8 length; + guint8 data[DMC_INTERRUPT_DATA_LEN]; +} DmcIntRqt; + +/* this structure defines header structure of FWCT */ +typedef struct __attribute__((packed)) { + guint32 signature; + guint16 size; + guint8 checksum; + guint8 version; + guint8 custom_meta_type; + guint8 cdtt_version; + guint16 vid; + guint16 pid; + guint16 device_id; + guint8 reserv0[16]; + guint32 composite_version; + guint8 image_count; + guint8 reserv1[3]; +} FwctInfo; + +typedef struct __attribute__((packed)) { + guint8 device_type; + guint8 img_type; + guint8 comp_id; + guint8 row_size; + guint8 reserv0[4]; + guint32 fw_version; + guint32 app_version; + guint32 img_offset; + guint32 img_size; + guint8 img_digest[32]; + guint8 num_img_segments; + guint8 reserv1[3]; +} FwctImageInfo; + +typedef struct __attribute__((packed)) { + guint8 img_id; + guint8 type; + guint16 start_row; + guint16 num_rows; /* size */ + guint8 reserv0[2]; +} FwctSegmentationInfo; + +const gchar *fu_ccgx_dmc_update_model_type_to_string (DmcUpdateModel val); diff --git a/plugins/ccgx/fu-ccgx-dmc-device.c b/plugins/ccgx/fu-ccgx-dmc-device.c new file mode 100644 index 000000000..c05a39027 --- /dev/null +++ b/plugins/ccgx/fu-ccgx-dmc-device.c @@ -0,0 +1,669 @@ +/* + * Copyright (C) 2020 Cypress Semiconductor Corporation. + * Copyright (C) 2020 Richard Hughes + * + * SPDX-License-Identifier: LGPL-2.1+ + */ + +#include "config.h" + +#include "fu-chunk.h" + +#include "fu-ccgx-common.h" +#include "fu-ccgx-dmc-common.h" +#include "fu-ccgx-dmc-device.h" +#include "fu-ccgx-dmc-firmware.h" + +#define DMC_FW_WRITE_STATUS_RETRY_COUNT 3 +#define DMC_FW_WRITE_STATUS_RETRY_DELAY_MS 30 + +struct _FuCcgxDmcDevice { + FuUsbDevice parent_instance; + FWImageType fw_image_type; + DmcDockIdentity dock_id; + guint8 ep_intr_in; + guint8 ep_bulk_out; + DmcUpdateModel update_model; +}; + +G_DEFINE_TYPE (FuCcgxDmcDevice, fu_ccgx_dmc_device, FU_TYPE_USB_DEVICE) + +static gboolean +fu_ccgx_dmc_device_get_dock_id (FuCcgxDmcDevice *self, + DmcDockIdentity *dock_id, + GError **error) +{ + g_return_val_if_fail (dock_id != NULL, FALSE); + + if (!g_usb_device_control_transfer (fu_usb_device_get_dev (FU_USB_DEVICE (self)), + G_USB_DEVICE_DIRECTION_DEVICE_TO_HOST, + G_USB_DEVICE_REQUEST_TYPE_VENDOR, + G_USB_DEVICE_RECIPIENT_DEVICE, + DMC_RQT_CODE_DOCK_IDENTITY, /* request */ + 0, /* value */ + 0, /* index */ + (guint8 *) dock_id, /* data */ + sizeof (DmcDockIdentity), /* length */ + NULL, /* actual length */ + DMC_CONTROL_TRANSFER_DEFAULT_TIMEOUT, + NULL, error)) { + g_prefix_error (error, "get_dock_id error: "); + return FALSE; + } + return TRUE; +} + +static gboolean +fu_ccgx_dmc_device_get_dock_status (FuCcgxDmcDevice *self, + DmcDockStatus *dock_status, + GError **error) +{ + g_return_val_if_fail (dock_status != NULL, FALSE); + + /* read minimum status length */ + if (!g_usb_device_control_transfer (fu_usb_device_get_dev (FU_USB_DEVICE (self)), + G_USB_DEVICE_DIRECTION_DEVICE_TO_HOST, + G_USB_DEVICE_REQUEST_TYPE_VENDOR, + G_USB_DEVICE_RECIPIENT_DEVICE, + DMC_RQT_CODE_DOCK_STATUS, /* request */ + 0, /* value */ + 0, /* index */ + (guint8 *) dock_status, /* data */ + DMC_GET_STATUS_MIN_LEN, /* length */ + NULL, /* actual length */ + DMC_CONTROL_TRANSFER_DEFAULT_TIMEOUT, + NULL, error)) { + g_prefix_error (error, "get_dock_status min size error: "); + return FALSE; + } + if (dock_status->status_length <= sizeof(DmcDockStatus)) { + /* read full status length */ + if (!g_usb_device_control_transfer (fu_usb_device_get_dev (FU_USB_DEVICE (self)), + G_USB_DEVICE_DIRECTION_DEVICE_TO_HOST, + G_USB_DEVICE_REQUEST_TYPE_VENDOR, + G_USB_DEVICE_RECIPIENT_DEVICE, + DMC_RQT_CODE_DOCK_STATUS, /* request */ + 0, /* value */ + 0, /* index */ + (guint8 *) dock_status, /* data */ + sizeof(DmcDockStatus), /* length */ + NULL, /* actual length */ + DMC_CONTROL_TRANSFER_DEFAULT_TIMEOUT, + NULL, error)) { + g_prefix_error (error, "get_dock_status actual size error: "); + return FALSE; + } + } + return TRUE; +} + +static gboolean +fu_ccgx_dmc_device_send_reset_state_machine (FuCcgxDmcDevice *self, GError **error) +{ + if (!g_usb_device_control_transfer (fu_usb_device_get_dev (FU_USB_DEVICE (self)), + G_USB_DEVICE_DIRECTION_HOST_TO_DEVICE, + G_USB_DEVICE_REQUEST_TYPE_VENDOR, + G_USB_DEVICE_RECIPIENT_DEVICE, + DMC_RQT_CODE_RESET_STATE_MACHINE, /* request */ + 0, /* value */ + 0, /* index */ + 0, /* data */ + 0, /* length */ + NULL, /* actual length */ + DMC_CONTROL_TRANSFER_DEFAULT_TIMEOUT, + NULL, error)) { + g_prefix_error (error, "send reset state machine error: "); + return FALSE; + } + return TRUE; +} + +static gboolean +fu_ccgx_dmc_device_send_sort_reset (FuCcgxDmcDevice *self, + gboolean reset_later, + GError **error) +{ + if (!g_usb_device_control_transfer (fu_usb_device_get_dev (FU_USB_DEVICE (self)), + G_USB_DEVICE_DIRECTION_HOST_TO_DEVICE, + G_USB_DEVICE_REQUEST_TYPE_VENDOR, + G_USB_DEVICE_RECIPIENT_DEVICE, + DMC_RQT_CODE_SOFT_RESET, /* request */ + reset_later, /* value */ + 0, /* index */ + 0, /* data */ + 0, /* length */ + NULL, /* actual length */ + DMC_CONTROL_TRANSFER_DEFAULT_TIMEOUT, + NULL, error)) { + g_prefix_error (error, "send reset error: "); + return FALSE; + } + return TRUE; +} + + +static gboolean +fu_ccgx_dmc_device_send_start_upgrade (FuCcgxDmcDevice *self, + const guint8 *custom_meta_data, + guint16 custom_meta_bufsz, + GError **error) +{ + guint16 value = 0; + if (custom_meta_bufsz > 0) + value = 1; + + if (custom_meta_bufsz > 0 && custom_meta_data == NULL) { + g_set_error(error, + FWUPD_ERROR, + FWUPD_ERROR_NOT_SUPPORTED, + "invalid metadata, buffer is NULL but size = %d",custom_meta_bufsz); + return FALSE; + } + if (!g_usb_device_control_transfer (fu_usb_device_get_dev (FU_USB_DEVICE (self)), + G_USB_DEVICE_DIRECTION_HOST_TO_DEVICE, + G_USB_DEVICE_REQUEST_TYPE_VENDOR, + G_USB_DEVICE_RECIPIENT_DEVICE, + DMC_RQT_CODE_UPGRADE_START, /* request */ + value, /* value */ + 1, /* index, forced update for Adicora only, other dock will ignore it */ + (guint8 *)custom_meta_data, /* data */ + custom_meta_bufsz, /* length */ + NULL, /* actual length */ + DMC_CONTROL_TRANSFER_DEFAULT_TIMEOUT, + NULL, error)) { + g_prefix_error (error, "send reset error: "); + return FALSE; + } + return TRUE; +} + +static gboolean +fu_ccgx_dmc_device_send_download_trigger (FuCcgxDmcDevice *self, + DmcTriggerCode trigger, + GError **error) +{ + if (!g_usb_device_control_transfer (fu_usb_device_get_dev (FU_USB_DEVICE (self)), + G_USB_DEVICE_DIRECTION_HOST_TO_DEVICE, + G_USB_DEVICE_REQUEST_TYPE_VENDOR, + G_USB_DEVICE_RECIPIENT_DEVICE, + DMC_RQT_CODE_TRIGGER, /* request */ + trigger, /* value */ + 0, /* index */ + 0, /* data */ + 0, /* length */ + NULL, /* actual length */ + DMC_CONTROL_TRANSFER_DEFAULT_TIMEOUT, + NULL, error)) { + g_prefix_error (error, "send download trigger error: "); + return FALSE; + } + return TRUE; +} + + +static gboolean +fu_ccgx_dmc_device_send_fwct (FuCcgxDmcDevice *self, + const guint8 *fwct_buf, + guint16 fwct_sz, + GError **error) +{ + g_return_val_if_fail (fwct_buf != NULL, FALSE); + + if (!g_usb_device_control_transfer (fu_usb_device_get_dev (FU_USB_DEVICE (self)), + G_USB_DEVICE_DIRECTION_HOST_TO_DEVICE, + G_USB_DEVICE_REQUEST_TYPE_VENDOR, + G_USB_DEVICE_RECIPIENT_DEVICE, + DMC_RQT_CODE_FWCT_WRITE, /* request */ + 0, /* value */ + 0, /* index */ + (guint8 *) fwct_buf, /* data */ + fwct_sz, /* length */ + NULL, /* actual length */ + DMC_CONTROL_TRANSFER_DEFAULT_TIMEOUT, + NULL, error)) { + g_prefix_error (error, "send fwct error: "); + return FALSE; + } + return TRUE; +} + +static gboolean +fu_ccgx_dmc_device_read_intr_req (FuCcgxDmcDevice *self, + DmcIntRqt *intr_rqt, + GError **error) +{ + g_return_val_if_fail (intr_rqt != NULL, FALSE); + + if (!g_usb_device_interrupt_transfer (fu_usb_device_get_dev (FU_USB_DEVICE (self)), + self->ep_intr_in, + (guint8 *) intr_rqt, + sizeof(DmcIntRqt), + NULL, + DMC_GET_REQUEST_TIMEOUT, + NULL, error)) { + g_prefix_error (error, "read intr rqt error: "); + return FALSE; + } + return TRUE; +} + +static gboolean +fu_ccgx_dmc_device_send_write_command (FuCcgxDmcDevice *self, + guint16 start_row, + guint16 num_of_row, + GError **error) +{ + if (!g_usb_device_control_transfer (fu_usb_device_get_dev (FU_USB_DEVICE (self)), + G_USB_DEVICE_DIRECTION_HOST_TO_DEVICE, + G_USB_DEVICE_REQUEST_TYPE_VENDOR, + G_USB_DEVICE_RECIPIENT_DEVICE, + DMC_RQT_CODE_IMG_WRITE, /* request */ + start_row, /* value */ + num_of_row, /* index */ + 0, /* data */ + 0, /* length */ + NULL, /* actual length */ + DMC_CONTROL_TRANSFER_DEFAULT_TIMEOUT, + NULL, error)) { + g_prefix_error (error, "send fwct error: "); + return FALSE; + } + return TRUE; +} + +static gboolean +fu_ccgx_dmc_device_send_row_data (FuCcgxDmcDevice *self, + const guint8 *row_buffer, + guint16 row_size, + GError **error) +{ + g_return_val_if_fail (row_buffer != NULL, FALSE); + + if (!g_usb_device_bulk_transfer (fu_usb_device_get_dev (FU_USB_DEVICE (self)), + self->ep_bulk_out, + (guint8 *)row_buffer, row_size, NULL, + DMC_BULK_OUT_PIPE_TIMEOUT, + NULL, error)) { + g_prefix_error (error, "write row data error: "); + return FALSE; + } + return TRUE; +} + + +static void +fu_ccgx_dmc_device_to_string (FuDevice *device, guint idt, GString *str) +{ + FuCcgxDmcDevice *self = FU_CCGX_DMC_DEVICE (device); + fu_common_string_append_kv (str, idt, "UpdateModel", + fu_ccgx_dmc_update_model_type_to_string (self->update_model)); + fu_common_string_append_kv (str, idt, "FwImageType", + fu_ccgx_fw_image_type_to_string (self->fw_image_type)); + fu_common_string_append_kx (str, idt, "EpBulkOut", self->ep_bulk_out); + fu_common_string_append_kx (str, idt, "EpIntrIn", self->ep_intr_in); +} + +static gboolean +fu_ccgx_dmc_get_image_write_status_cb (FuDevice *device, gpointer user_data, GError **error) +{ + FuCcgxDmcDevice *self = FU_CCGX_DMC_DEVICE (device); + DmcIntRqt dmc_int_req = {0}; + + /* get interrupt request */ + if (!fu_ccgx_dmc_device_read_intr_req (self, &dmc_int_req, error)) { + g_prefix_error (error, "read intr req error in image write status: "); + return FALSE; + } + /* check opcode for fw write */ + if (dmc_int_req.opcode != DMC_INT_OPCODE_IMG_WRITE_STATUS) { + g_set_error (error, + FWUPD_ERROR, + FWUPD_ERROR_NOT_SUPPORTED, + "invalid dmc intr req opcode in image write status = %d", + dmc_int_req.opcode); + return FALSE; + } + + /* retry if data[0] is 1 otherwise error */ + if (dmc_int_req.data[0] != 0) { + g_set_error (error, + FWUPD_ERROR, + FWUPD_ERROR_NOT_SUPPORTED, + "invalid dmc intr req data in image write status = %d", + dmc_int_req.data[0]); + g_usleep (DMC_FW_WRITE_STATUS_RETRY_DELAY_MS * 1000); + return FALSE; + } + return TRUE; +} + +static gboolean +fu_ccgx_dmc_write_firmware_image (FuDevice *device, + FuCcgxDmcFirmwareImageRecord *img_rcd, + gsize *fw_data_written, + const gsize fw_data_size, + GError **error) +{ + FuCcgxDmcDevice *self = FU_CCGX_DMC_DEVICE (device); + GPtrArray *seg_records; + + g_return_val_if_fail (img_rcd != NULL, FALSE); + g_return_val_if_fail (fw_data_written != NULL, FALSE); + + /* get segment records */ + seg_records = img_rcd->seg_records; + for (guint32 seg_index = 0; seg_index < seg_records->len; seg_index++) { + GPtrArray *data_records = NULL; + FuCcgxDmcFirmwareSegmentRecord *seg_rcd = g_ptr_array_index (seg_records, seg_index); + + /* write start row and number of rows to a device */ + if (!fu_ccgx_dmc_device_send_write_command (self, + seg_rcd->info_header.start_row, + seg_rcd->info_header.num_rows, + error)) + return FALSE; + + /* get data records */ + data_records = seg_rcd->data_records; + for (guint32 data_index = 0; data_index < data_records->len; data_index++) { + FuCcgxDmcFirmwareDataRecord *data_rcd; + const guint8 *row_buffer = NULL; + gsize row_size = 0; + + /* write row data */ + data_rcd = g_ptr_array_index (data_records, data_index); + row_buffer = g_bytes_get_data (data_rcd->data, &row_size); + if (!fu_ccgx_dmc_device_send_row_data (self, + row_buffer, + (guint16) row_size, + error)) + return FALSE; + + /* increase fw written size */ + *fw_data_written += row_size; + fu_device_set_progress_full (device, *fw_data_written, fw_data_size); + + /* get status */ + if (!fu_device_retry (FU_DEVICE (self), + fu_ccgx_dmc_get_image_write_status_cb, + DMC_FW_WRITE_STATUS_RETRY_COUNT, + NULL, error)) + return FALSE; + } + } + return TRUE; +} + +static gboolean +fu_ccgx_dmc_write_firmware (FuDevice *device, + FuFirmware *firmware, + FwupdInstallFlags flags, + GError **error) +{ + FuCcgxDmcDevice *self = FU_CCGX_DMC_DEVICE (device); + FuCcgxDmcFirmwareImageRecord *img_rcd = NULL; + DmcIntRqt dmc_int_rqt = {0}; + GBytes *custom_meta_blob; + GBytes *fwct_blob; + GPtrArray *image_records; + const guint8 *custom_meta_data = NULL; + const guint8 *fwct_buf = NULL; + gsize custom_meta_bufsz = 0; + gsize fwct_sz = 0; + gsize fw_data_size = 0; + gsize fw_data_written = 0; + guint8 img_index = 0; + + /* get fwct record */ + fwct_blob = fu_ccgx_dmc_firmware_get_fwct_record (FU_CCGX_DMC_FIRMWARE (firmware)); + fwct_buf = g_bytes_get_data (fwct_blob, &fwct_sz); + if (fwct_buf == NULL) { + g_set_error_literal (error, + FWUPD_ERROR, + FWUPD_ERROR_NOT_SUPPORTED, + "invalid fwct data"); + return FALSE; + } + + /* get custom meta record */ + custom_meta_blob = fu_ccgx_dmc_firmware_get_custom_meta_record (FU_CCGX_DMC_FIRMWARE (firmware)); + if (custom_meta_blob != NULL) + custom_meta_data = g_bytes_get_data (custom_meta_blob, &custom_meta_bufsz); + + /* reset */ + fu_device_set_status (device, FWUPD_STATUS_DEVICE_BUSY); + if (!fu_ccgx_dmc_device_send_reset_state_machine (self, error)) + return FALSE; + + /* start fw upgrade with custom metadata */ + if (!fu_ccgx_dmc_device_send_start_upgrade (self, custom_meta_data, custom_meta_bufsz, error)) + return FALSE; + + /* send fwct data */ + if (!fu_ccgx_dmc_device_send_fwct (self, fwct_buf, fwct_sz, error)) + return FALSE; + + /* get total fw size */ + image_records = fu_ccgx_dmc_firmware_get_image_records (FU_CCGX_DMC_FIRMWARE (firmware)); + fw_data_size = fu_ccgx_dmc_firmware_get_fw_data_size (FU_CCGX_DMC_FIRMWARE (firmware)); + fu_device_set_status (device, FWUPD_STATUS_DEVICE_WRITE); + while (1) { + + /* get interrupt request */ + if (!fu_ccgx_dmc_device_read_intr_req (self, &dmc_int_rqt, error)) + return FALSE; + + /* fw upgrade request */ + if (dmc_int_rqt.opcode != DMC_INT_OPCODE_FW_UPGRADE_RQT) + break; + + img_index = dmc_int_rqt.data[0]; + if (img_index >= image_records->len) { + g_set_error (error, + FWUPD_ERROR, + FWUPD_ERROR_NOT_SUPPORTED, + "invalid image index %d, expected less than %u", + img_index, image_records->len); + return FALSE; + } + + /* write image */ + img_rcd = g_ptr_array_index (image_records, img_index); + if (!fu_ccgx_dmc_write_firmware_image (device, img_rcd, &fw_data_written, + fw_data_size, error)) + return FALSE; + } + + if (dmc_int_rqt.opcode != DMC_INT_OPCODE_FW_UPGRADE_STATUS) { + if (dmc_int_rqt.opcode == DMC_INT_OPCODE_FWCT_ANALYSIS_STATUS) { + g_set_error (error, + FWUPD_ERROR, + FWUPD_ERROR_NOT_SUPPORTED, + "fwct analysis failed with status = %d", + dmc_int_rqt.data[0]); + return FALSE; + } + g_set_error (error, + FWUPD_ERROR, + FWUPD_ERROR_NOT_SUPPORTED, + "invalid dmc intr req opcode = %d with status = %d", + dmc_int_rqt.opcode, dmc_int_rqt.data[0]); + return FALSE; + } + + if (dmc_int_rqt.data[0] == DMC_DEVICE_STATUS_UPDATE_PHASE_1_COMPLETE) { + self->update_model = DMC_UPDATE_MODEL_DOWNLOAD_TRIGGER; + } else if (dmc_int_rqt.data[0] == DMC_DEVICE_STATUS_FW_DOWNLOADED_UPDATE_PEND) { + self->update_model = DMC_UPDATE_MODEL_PENDING_RESET; + } else { + g_set_error (error, + FWUPD_ERROR, + FWUPD_ERROR_NOT_SUPPORTED, + "invalid status code = %u", + dmc_int_rqt.data[0]); + return FALSE; + } + return TRUE; +} + +static FuFirmware * +fu_ccgx_dmc_device_prepare_firmware (FuDevice *device, + GBytes *fw, + FwupdInstallFlags flags, + GError **error) +{ + g_autoptr(FuFirmware) firmware = fu_ccgx_dmc_firmware_new (); + FuCcgxDmcDevice *self = FU_CCGX_DMC_DEVICE (device); + GBytes* custom_meta_blob = NULL; + gboolean custom_meta_exist = FALSE; + + /* parse all images */ + if (!fu_firmware_parse (firmware, fw, flags, error)) + return NULL; + + /* get custom meta record */ + custom_meta_blob = fu_ccgx_dmc_firmware_get_custom_meta_record (FU_CCGX_DMC_FIRMWARE (firmware)); + if (custom_meta_blob) + if (g_bytes_get_size (custom_meta_blob) > 0) + custom_meta_exist = TRUE; + + /* check custom meta flag */ + if (self->dock_id.custom_meta_data_flag != custom_meta_exist) { + g_set_error_literal (error, + FWUPD_ERROR, + FWUPD_ERROR_NOT_SUPPORTED, + "custom metadata mismatch"); + return NULL; + } + return g_steal_pointer (&firmware); +} + +static gboolean +fu_ccgx_dmc_device_attach (FuDevice *device, GError **error) +{ + FuCcgxDmcDevice *self = FU_CCGX_DMC_DEVICE (device); + gboolean manual_replug = FALSE; + + if (fu_device_has_custom_flag (device, "has-manual-replug")) + manual_replug = TRUE; + + if (fu_device_get_update_state (self) != FWUPD_UPDATE_STATE_SUCCESS) + return TRUE; + + if (self->update_model == DMC_UPDATE_MODEL_DOWNLOAD_TRIGGER) { + DmcTriggerCode trigger_code = DMC_TRIGGER_CODE_UPDATE_NOW; + + if (manual_replug) + trigger_code = DMC_TRIGGER_CODE_UPDATE_ON_DISCONNECT; + + if (!fu_ccgx_dmc_device_send_download_trigger (self, + trigger_code, + error)) { + g_prefix_error (error, "download trigger error: "); + return FALSE; + } + } else if (self->update_model == DMC_UPDATE_MODEL_PENDING_RESET) { + if (!fu_ccgx_dmc_device_send_sort_reset (self, + manual_replug, + error)) { + g_prefix_error (error, "soft reset error: "); + return FALSE; + } + } else { + g_set_error (error, + FWUPD_ERROR, + FWUPD_ERROR_NOT_SUPPORTED, + "invalid update model = %u", + self->update_model); + return FALSE; + } + + if (manual_replug) + return TRUE; + + fu_device_set_status (device, FWUPD_STATUS_DEVICE_RESTART); + fu_device_add_flag (device, FWUPD_DEVICE_FLAG_WAIT_FOR_REPLUG); + return TRUE; +} + +static gboolean +fu_ccgx_dmc_device_setup (FuDevice *device, GError **error) +{ + FuCcgxDmcDevice *self = FU_CCGX_DMC_DEVICE (device); + DmcDockStatus dock_status = {0}; + DmcDockIdentity dock_id = {0}; + guint32 version_raw = 0; + g_autofree gchar *version = NULL; + + /* get dock identity */ + if (!fu_ccgx_dmc_device_get_dock_id (self, &dock_id, error)) + return FALSE; + + /* store dock identity */ + if (!fu_memcpy_safe ((guint8 *) &self->dock_id, sizeof(DmcDockIdentity), 0x0, /* dst */ + (guint8 *) &dock_id, sizeof(DmcDockIdentity), 0, /* src */ + sizeof(DmcDockIdentity), error)) + return FALSE; + + /* get dock status */ + if (!fu_ccgx_dmc_device_get_dock_status (self, &dock_status, error)) + return FALSE; + + /* set composite version */ + version_raw = dock_status.composite_version; + version = fu_common_version_from_uint32 (version_raw, FWUPD_VERSION_FORMAT_QUAD); + fu_device_set_version (FU_DEVICE (self), version); + fu_device_set_version_raw (FU_DEVICE (self), version_raw); + fu_device_add_flag (FU_DEVICE (self), FWUPD_DEVICE_FLAG_UPDATABLE); + return TRUE; +} + +static gboolean +fu_ccgx_dmc_device_set_quirk_kv (FuDevice *device, + const gchar *key, + const gchar *value, + GError **error) +{ + FuCcgxDmcDevice *self = FU_CCGX_DMC_DEVICE (device); + + if (g_strcmp0 (key, "ImageKind") == 0) { + self->fw_image_type = fu_ccgx_fw_image_type_from_string (value); + if (self->fw_image_type != FW_IMAGE_TYPE_UNKNOWN) + return TRUE; + g_set_error_literal (error, + G_IO_ERROR, + G_IO_ERROR_INVALID_DATA, + "invalid ImageKind"); + return FALSE; + } + g_set_error_literal (error, + G_IO_ERROR, + G_IO_ERROR_NOT_SUPPORTED, + "no supported"); + return FALSE; +} + +static void +fu_ccgx_dmc_device_init (FuCcgxDmcDevice *self) +{ + self->ep_intr_in = DMC_INTERRUPT_PIPE_ID; + self->ep_bulk_out = DMC_BULK_PIPE_ID; + fu_device_set_protocol (FU_DEVICE (self), "com.cypress.ccgx"); + fu_device_set_version_format (FU_DEVICE (self), FWUPD_VERSION_FORMAT_QUAD); + fu_device_add_flag (FU_DEVICE (self), FWUPD_DEVICE_FLAG_REQUIRE_AC); + fu_device_add_flag (FU_DEVICE (self), FWUPD_DEVICE_FLAG_DUAL_IMAGE); + fu_device_add_flag (FU_DEVICE (self), FWUPD_DEVICE_FLAG_CAN_VERIFY_IMAGE); + fu_device_add_flag (FU_DEVICE (self), FWUPD_DEVICE_FLAG_SELF_RECOVERY); +} + +static void +fu_ccgx_dmc_device_class_init (FuCcgxDmcDeviceClass *klass) +{ + FuDeviceClass *klass_device = FU_DEVICE_CLASS (klass); + klass_device->to_string = fu_ccgx_dmc_device_to_string; + klass_device->write_firmware = fu_ccgx_dmc_write_firmware; + klass_device->prepare_firmware = fu_ccgx_dmc_device_prepare_firmware; + klass_device->attach = fu_ccgx_dmc_device_attach; + klass_device->setup = fu_ccgx_dmc_device_setup; + klass_device->set_quirk_kv = fu_ccgx_dmc_device_set_quirk_kv; +} diff --git a/plugins/ccgx/fu-ccgx-dmc-device.h b/plugins/ccgx/fu-ccgx-dmc-device.h new file mode 100644 index 000000000..e537d6eb4 --- /dev/null +++ b/plugins/ccgx/fu-ccgx-dmc-device.h @@ -0,0 +1,13 @@ +/* + * Copyright (C) 2020 Cypress Semiconductor Corporation. + * Copyright (C) 2020 Richard Hughes + * + * SPDX-License-Identifier: LGPL-2.1+ + */ + +#pragma once + +#include "fu-usb-device.h" + +#define FU_TYPE_CCGX_DMC_DEVICE (fu_ccgx_dmc_device_get_type ()) +G_DECLARE_FINAL_TYPE (FuCcgxDmcDevice, fu_ccgx_dmc_device, FU, CCGX_DMC_DEVICE, FuUsbDevice) diff --git a/plugins/ccgx/fu-ccgx-dmc-firmware.c b/plugins/ccgx/fu-ccgx-dmc-firmware.c new file mode 100644 index 000000000..9dc51f7cf --- /dev/null +++ b/plugins/ccgx/fu-ccgx-dmc-firmware.c @@ -0,0 +1,368 @@ +/* + * Copyright (C) 2020 Cypress Semiconductor Corporation. + * Copyright (C) 2020 Richard Hughes + * + * SPDX-License-Identifier: LGPL-2.1+ + */ + +#include "config.h" + +#include "fu-common.h" +#include "fu-common-version.h" +#include "fu-ccgx-dmc-common.h" +#include "fu-ccgx-common.h" +#include "fu-ccgx-dmc-firmware.h" + +struct _FuCcgxDmcFirmware { + FuFirmwareClass parent_instance; + GPtrArray *image_records; + GBytes *fwct_blob; + GBytes *custom_meta_blob; + guint32 row_data_offset_start; + FwctInfo fwct_info; + guint32 fw_data_size; +}; + +G_DEFINE_TYPE (FuCcgxDmcFirmware, fu_ccgx_dmc_firmware, FU_TYPE_FIRMWARE) + +static void +fu_ccgx_dmc_firmware_image_record_free (FuCcgxDmcFirmwareImageRecord *rcd) +{ + if (rcd->seg_records != NULL) + g_ptr_array_unref (rcd->seg_records); + g_free (rcd); +} + +static void +fu_ccgx_dmc_firmware_segment_record_free (FuCcgxDmcFirmwareSegmentRecord *rcd) +{ + if (rcd->data_records != NULL) + g_ptr_array_unref (rcd->data_records); + g_free (rcd); +} + +static void +fu_ccgx_dmc_firmware_data_record_free (FuCcgxDmcFirmwareDataRecord *rcd) +{ + if (rcd->data != NULL) + g_bytes_unref (rcd->data); + g_free (rcd); +} + +G_DEFINE_AUTOPTR_CLEANUP_FUNC(FuCcgxDmcFirmwareImageRecord, fu_ccgx_dmc_firmware_image_record_free) +G_DEFINE_AUTOPTR_CLEANUP_FUNC(FuCcgxDmcFirmwareSegmentRecord, fu_ccgx_dmc_firmware_segment_record_free) +G_DEFINE_AUTOPTR_CLEANUP_FUNC(FuCcgxDmcFirmwareDataRecord, fu_ccgx_dmc_firmware_data_record_free) + +GPtrArray * +fu_ccgx_dmc_firmware_get_image_records (FuCcgxDmcFirmware *self) +{ + g_return_val_if_fail (FU_IS_CCGX_DMC_FIRMWARE (self), NULL); + return self->image_records; +} + +GBytes * +fu_ccgx_dmc_firmware_get_fwct_record (FuCcgxDmcFirmware *self) +{ + g_return_val_if_fail (FU_IS_CCGX_DMC_FIRMWARE (self), NULL); + return self->fwct_blob; +} + +GBytes * +fu_ccgx_dmc_firmware_get_custom_meta_record (FuCcgxDmcFirmware *self) +{ + g_return_val_if_fail (FU_IS_CCGX_DMC_FIRMWARE (self), NULL); + return self->custom_meta_blob; +} + +FwctInfo * +fu_ccgx_dmc_firmware_get_fwct_info (FuCcgxDmcFirmware *self) +{ + g_return_val_if_fail (FU_IS_CCGX_DMC_FIRMWARE (self), NULL); + return &self->fwct_info; +} + +guint32 +fu_ccgx_dmc_firmware_get_fw_data_size (FuCcgxDmcFirmware *self) +{ + g_return_val_if_fail (FU_IS_CCGX_DMC_FIRMWARE (self), 0); + return self->fw_data_size; +} + +static void +fu_ccgx_dmc_firmware_to_string (FuFirmware *firmware, guint idt, GString *str) +{ + FuCcgxDmcFirmware *self = FU_CCGX_DMC_FIRMWARE (firmware); + fu_common_string_append_kx (str, idt, "FwDataSize", self->fw_data_size); + fu_common_string_append_ku (str, idt, "ImageRecords", self->image_records->len); +} + +static gboolean +fu_ccgx_dmc_firmware_parse_segment (FuFirmware *firmware, + const guint8 *fw_buf, + gsize fw_bufsz, + FuCcgxDmcFirmwareImageRecord *img_rcd, + gsize *segment_info_offset, + GError **error) +{ + FuCcgxDmcFirmware *self = FU_CCGX_DMC_FIRMWARE (firmware); + gsize fw_buffer_offset = 0; + gsize row_data_offset; + gsize digestlen = DMC_HASH_SIZE; + guint8 hash[DMC_HASH_SIZE]; + g_autoptr(GChecksum) csum = g_checksum_new (G_CHECKSUM_SHA256); + + /* set row data offset in current image */ + row_data_offset = self->row_data_offset_start + img_rcd->info_header.img_offset; + + /* create segment record array in image record */ + img_rcd->seg_records = g_ptr_array_new_with_free_func ((GFreeFunc) fu_ccgx_dmc_firmware_segment_record_free); + + /* parse segment in image */ + for (guint32 seg_num = 0; seg_num < img_rcd->info_header.num_img_segments; seg_num++) { + guint16 actual_row_size = 0; + g_autofree guint8 *row_buf = NULL; + g_autoptr(FuCcgxDmcFirmwareSegmentRecord) seg_rcd = NULL; + + /* set segment info offset */ + fw_buffer_offset = *segment_info_offset; + + /* read segment info */ + seg_rcd = g_new0 (FuCcgxDmcFirmwareSegmentRecord, 1); + if (!fu_memcpy_safe ((guint8 *) &seg_rcd->info_header, sizeof(seg_rcd->info_header), 0x0, /* dst */ + fw_buf, fw_bufsz, fw_buffer_offset, /* src */ + sizeof(seg_rcd->info_header), error)) + return FALSE; + + /* calculate actual row size */ + actual_row_size = img_rcd->info_header.row_size * 64; + + /* create data record array in segment record */ + seg_rcd->data_records = g_ptr_array_new_with_free_func ((GFreeFunc) fu_ccgx_dmc_firmware_data_record_free); + + /* read row data in segment */ + row_buf = g_malloc0 (actual_row_size); + for (int row = 0; row < seg_rcd->info_header.num_rows; row++) { + g_autoptr(FuCcgxDmcFirmwareDataRecord) data_rcd = NULL; + + /* set row data offset */ + fw_buffer_offset = row_data_offset; + + /* read row data */ + if (!fu_memcpy_safe (row_buf, actual_row_size, 0x0, /* dst */ + fw_buf, fw_bufsz, fw_buffer_offset, /* src */ + actual_row_size, error)) + return FALSE; + + /* update hash */ + g_checksum_update (csum, (guchar *) row_buf, actual_row_size); + + /* add row data to data record */ + data_rcd = g_new0 (FuCcgxDmcFirmwareDataRecord, 1); + data_rcd->data = g_bytes_new (row_buf, actual_row_size); + + /* add data record to data record array */ + g_ptr_array_add (seg_rcd->data_records, g_steal_pointer (&data_rcd)); + + /* increment row data offset */ + row_data_offset += actual_row_size; + } + + /* add segment record to segment array */ + g_ptr_array_add (img_rcd->seg_records, g_steal_pointer (&seg_rcd)); + + /* increment segment info offset */ + *segment_info_offset += sizeof(FwctSegmentationInfo); + } + + /* check checksum */ + g_checksum_get_digest (csum, hash, &digestlen); + if (memcmp (hash, img_rcd->info_header.img_digest, DMC_HASH_SIZE) != 0) { + g_set_error_literal (error, + FWUPD_ERROR, + FWUPD_ERROR_NOT_SUPPORTED, + "invalid hash"); + return FALSE; + } + + /* success */ + return TRUE; +} + +static gboolean +fu_ccgx_dmc_firmware_parse_image (FuFirmware *firmware, + const guint8 *fw_buf, + gsize fw_bufsz, + GError **error) +{ + FuCcgxDmcFirmware *self = FU_CCGX_DMC_FIRMWARE (firmware); + gsize fw_buffer_offset = 0; + gsize img_info_offset = sizeof(FwctInfo); + gsize seg_info_offset = 0; + + /* set initial segment info offset */ + seg_info_offset = img_info_offset + self->fwct_info.image_count * sizeof(FwctImageInfo); + for (guint32 img_num = 0; img_num < self->fwct_info.image_count; img_num++) { + g_autoptr(FuCcgxDmcFirmwareImageRecord) img_rcd = NULL; + + /* set image info offset to fw buffer */ + fw_buffer_offset = img_info_offset; + + /* read image info */ + img_rcd = g_new0 (FuCcgxDmcFirmwareImageRecord, 1); + if (!fu_memcpy_safe ((guint8 *) &img_rcd->info_header, sizeof(img_rcd->info_header), 0x0, /* dst */ + fw_buf, fw_bufsz, fw_buffer_offset, /* src */ + sizeof(img_rcd->info_header), error)) + return FALSE; + + if (img_rcd->info_header.num_img_segments == 0) { + g_set_error (error, + FWUPD_ERROR, + FWUPD_ERROR_NOT_SUPPORTED, + "invalid segment number = %d", + img_rcd->info_header.num_img_segments); + return FALSE; + } + + /* parse segment */ + if (!fu_ccgx_dmc_firmware_parse_segment (firmware, fw_buf, fw_bufsz, img_rcd, + &seg_info_offset, error)) + return FALSE; + + /* add image record to image record arrary */ + g_ptr_array_add (self->image_records, g_steal_pointer (&img_rcd)); + + /* increment image offset */ + img_info_offset += sizeof(FwctImageInfo); + } + + return TRUE; +} + +static gboolean +fu_ccgx_dmc_firmware_parse (FuFirmware *firmware, + GBytes *fw, + guint64 addr_start, + guint64 addr_end, + FwupdInstallFlags flags, + GError **error) +{ + FuCcgxDmcFirmware *self = FU_CCGX_DMC_FIRMWARE (firmware); + gsize fw_bufsz = 0; + guint16 custom_meta_bufsz = 0; + const guint8 *fw_buf = g_bytes_get_data (fw, &fw_bufsz); + g_autofree guint8 *custom_meta_buf = NULL; + g_autofree guint8 *fwct_buf = NULL; + g_autoptr(FuFirmwareImage) img = fu_firmware_image_new (fw); + + /* read fwct info */ + if (!fu_memcpy_safe ((guint8 *) &self->fwct_info, sizeof(self->fwct_info), 0x0, /* dst */ + fw_buf, fw_bufsz, 0, /* src */ + sizeof(self->fwct_info), error)) + return FALSE; + + /* check for 'F' 'W' 'C' 'T' in signature */ + if (self->fwct_info.signature != DMC_FWCT_SIGN) { + g_set_error (error, + FWUPD_ERROR, + FWUPD_ERROR_NOT_SUPPORTED, + "invalid dmc signature, expected 0x%04X got 0x%04X", + (guint32) DMC_FWCT_SIGN, + (guint32) self->fwct_info.signature); + return FALSE; + } + /* check fwct size */ + if (self->fwct_info.size > DMC_FWCT_MAX_SIZE || + self->fwct_info.size == 0) { + g_set_error (error, + FWUPD_ERROR, + FWUPD_ERROR_NOT_SUPPORTED, + "invalid dmc fwct size, expected equal to or less than %u, got %u", + (guint32) DMC_FWCT_MAX_SIZE, + (guint32) self->fwct_info.size); + return FALSE; + } + + /* set version */ + if (self->fwct_info.composite_version != 0) { + g_autofree gchar *ver = NULL; + ver = fu_common_version_from_uint32 (self->fwct_info.composite_version, + FWUPD_VERSION_FORMAT_QUAD); + fu_firmware_set_version (firmware, ver); + } + + /* read fwct data */ + fwct_buf = g_malloc0 (self->fwct_info.size); + if (!fu_memcpy_safe ((guint8 *) fwct_buf, self->fwct_info.size, 0x0, /* dst */ + fw_buf, fw_bufsz, 0, /* src */ + self->fwct_info.size, error)) + return FALSE; + + /* create fwct binary */ + self->fwct_blob = g_bytes_new (fwct_buf, self->fwct_info.size); + + /* create custom meta binary */ + if (!fu_common_read_uint16_safe (fw_buf, fw_bufsz, self->fwct_info.size, &custom_meta_bufsz, + G_LITTLE_ENDIAN,error)) + return FALSE; + + if (custom_meta_bufsz > 0) { + /* alloc custom meta buffer */ + custom_meta_buf = g_malloc0 (custom_meta_bufsz); + /* read custom metadata */ + if (!fu_memcpy_safe ((guint8 *)custom_meta_buf, custom_meta_bufsz, 0x0, /* dst */ + fw_buf, fw_bufsz, self->fwct_info.size + 2, /* src */ + custom_meta_bufsz, error)) + return FALSE; + self->custom_meta_blob = g_bytes_new (custom_meta_buf, custom_meta_bufsz); + } + + /* set row data start offset */ + self->row_data_offset_start = self->fwct_info.size + DMC_CUSTOM_META_LENGTH_FIELD_SIZE + custom_meta_bufsz; + self->fw_data_size = fw_bufsz - self->row_data_offset_start; + + /* parse image */ + if (!fu_ccgx_dmc_firmware_parse_image (firmware, fw_buf, fw_bufsz, error)) + return FALSE; + + /* add something, although we'll use the records for the update */ + fu_firmware_image_set_addr (img, 0x0); + fu_firmware_add_image (firmware, img); + return TRUE; +} + +static void +fu_ccgx_dmc_firmware_init (FuCcgxDmcFirmware *self) +{ + self->image_records = g_ptr_array_new_with_free_func ((GFreeFunc) fu_ccgx_dmc_firmware_image_record_free); +} + +static void +fu_ccgx_dmc_firmware_finalize (GObject *object) +{ + FuCcgxDmcFirmware *self = FU_CCGX_DMC_FIRMWARE (object); + + if (self->fwct_blob != NULL) + g_bytes_unref (self->fwct_blob); + if (self->custom_meta_blob != NULL) + g_bytes_unref (self->custom_meta_blob); + if (self->image_records != NULL) + g_ptr_array_unref (self->image_records); + + G_OBJECT_CLASS (fu_ccgx_dmc_firmware_parent_class)->finalize (object); +} + +static void +fu_ccgx_dmc_firmware_class_init (FuCcgxDmcFirmwareClass *klass) +{ + GObjectClass *object_class = G_OBJECT_CLASS (klass); + FuFirmwareClass *klass_firmware = FU_FIRMWARE_CLASS (klass); + object_class->finalize = fu_ccgx_dmc_firmware_finalize; + klass_firmware->parse = fu_ccgx_dmc_firmware_parse; + klass_firmware->to_string = fu_ccgx_dmc_firmware_to_string; +} + +FuFirmware * +fu_ccgx_dmc_firmware_new (void) +{ + return FU_FIRMWARE (g_object_new (FU_TYPE_CCGX_DMC_FIRMWARE, NULL)); +} diff --git a/plugins/ccgx/fu-ccgx-dmc-firmware.h b/plugins/ccgx/fu-ccgx-dmc-firmware.h new file mode 100644 index 000000000..063cdfb4f --- /dev/null +++ b/plugins/ccgx/fu-ccgx-dmc-firmware.h @@ -0,0 +1,35 @@ +/* + * Copyright (C) 2020 Cypress Semiconductor Corporation. + * Copyright (C) 2020 Richard Hughes + * + * SPDX-License-Identifier: LGPL-2.1+ + */ + +#pragma once + +#include "fu-firmware.h" +#include "fu-ccgx-dmc-common.h" + +#define FU_TYPE_CCGX_DMC_FIRMWARE (fu_ccgx_dmc_firmware_get_type ()) +G_DECLARE_FINAL_TYPE (FuCcgxDmcFirmware, fu_ccgx_dmc_firmware, FU,CCGX_DMC_FIRMWARE, FuFirmware) + +typedef struct { + GBytes *data; +} FuCcgxDmcFirmwareDataRecord; + +typedef struct { + FwctSegmentationInfo info_header; + GPtrArray *data_records; +} FuCcgxDmcFirmwareSegmentRecord; + +typedef struct { + FwctImageInfo info_header; + GPtrArray *seg_records; +} FuCcgxDmcFirmwareImageRecord; + +FuFirmware *fu_ccgx_dmc_firmware_new (void); +GPtrArray *fu_ccgx_dmc_firmware_get_image_records (FuCcgxDmcFirmware *self); +GBytes *fu_ccgx_dmc_firmware_get_fwct_record (FuCcgxDmcFirmware *self); +GBytes *fu_ccgx_dmc_firmware_get_custom_meta_record (FuCcgxDmcFirmware *self); +FwctInfo *fu_ccgx_dmc_firmware_get_fwct_info (FuCcgxDmcFirmware *self); +guint32 fu_ccgx_dmc_firmware_get_fw_data_size (FuCcgxDmcFirmware *self); diff --git a/plugins/ccgx/fu-plugin-ccgx.c b/plugins/ccgx/fu-plugin-ccgx.c index 2e58e5dca..7fc816f88 100644 --- a/plugins/ccgx/fu-plugin-ccgx.c +++ b/plugins/ccgx/fu-plugin-ccgx.c @@ -12,12 +12,16 @@ #include "fu-ccgx-firmware.h" #include "fu-ccgx-hid-device.h" #include "fu-ccgx-hpi-device.h" +#include "fu-ccgx-dmc-device.h" +#include "fu-ccgx-dmc-firmware.h" void fu_plugin_init (FuPlugin *plugin) { fu_plugin_set_build_hash (plugin, FU_BUILD_HASH); fu_plugin_add_firmware_gtype (plugin, "ccgx", FU_TYPE_CCGX_FIRMWARE); + fu_plugin_add_firmware_gtype (plugin, "ccgx", FU_TYPE_CCGX_DMC_FIRMWARE); fu_plugin_set_device_gtype (plugin, FU_TYPE_CCGX_HID_DEVICE); fu_plugin_set_device_gtype (plugin, FU_TYPE_CCGX_HPI_DEVICE); + fu_plugin_set_device_gtype (plugin, FU_TYPE_CCGX_DMC_DEVICE); } diff --git a/plugins/ccgx/meson.build b/plugins/ccgx/meson.build index 087456de4..b726d9874 100644 --- a/plugins/ccgx/meson.build +++ b/plugins/ccgx/meson.build @@ -16,6 +16,9 @@ shared_module('fu_plugin_ccgx', 'fu-ccgx-hid-device.c', 'fu-ccgx-hpi-common.c', 'fu-ccgx-hpi-device.c', + 'fu-ccgx-dmc-device.c', + 'fu-ccgx-dmc-firmware.c', + 'fu-ccgx-dmc-common.c', ], include_directories : [ root_incdir, From 49f99d186d84bc09f84943d31fe008647265f8fd Mon Sep 17 00:00:00 2001 From: Richard Hughes Date: Tue, 9 Jun 2020 09:09:47 +0100 Subject: [PATCH 141/607] trivial: Fix Debian CI targets --- contrib/ci/debian.sh | 1 - 1 file changed, 1 deletion(-) diff --git a/contrib/ci/debian.sh b/contrib/ci/debian.sh index ac4e2f509..8f46311c2 100755 --- a/contrib/ci/debian.sh +++ b/contrib/ci/debian.sh @@ -39,7 +39,6 @@ lintian ../*changes \ --no-tag-display-limit \ --suppress-tags bad-distribution-in-changes-file \ --suppress-tags source-contains-unsafe-symlink \ - --suppress-tags changelog-should-mention-nmu \ --suppress-tags debian-watch-file-in-native-package \ --suppress-tags source-nmu-has-incorrect-version-number \ --suppress-tags no-symbols-control-file \ From 59bb497a3ed2fa8513a76cbb0f201bffde7a356d Mon Sep 17 00:00:00 2001 From: Ryan Lee Date: Tue, 9 Jun 2020 18:25:40 +0900 Subject: [PATCH 142/607] ccgx: modify install duration for dmc device --- plugins/ccgx/ccgx.quirk | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/plugins/ccgx/ccgx.quirk b/plugins/ccgx/ccgx.quirk index 69ed22df0..02d9d0e96 100644 --- a/plugins/ccgx/ccgx.quirk +++ b/plugins/ccgx/ccgx.quirk @@ -50,7 +50,7 @@ Summary = Dock Management Controller Device ParentGuid = USB\VID_03F0&PID_0363 Name = HP USB-C Dock G5 ImageKind = dmc-composite -InstallDuration = 40 +InstallDuration = 190 RemoveDelay = 150000 # HP Adicora Dock D Type @@ -61,5 +61,5 @@ Summary = Dock Management Controller Device ParentGuid = USB\VID_03F0&PID_096B Name = HP USB-C/A Universal Dock G2 ImageKind = dmc-composite -InstallDuration = 25 +InstallDuration = 110 RemoveDelay = 85000 From 09950a13cea545dac8d2ef16201ee0f4f2f62f99 Mon Sep 17 00:00:00 2001 From: Richard Hughes Date: Mon, 8 Jun 2020 15:19:52 +0100 Subject: [PATCH 143/607] vli: Do not modify the class vfuncs depending on device type We can have multiple FuVliPdDevice objects registered with the daemon, but they will all share the FuVliPdDeviceClass instance. If one device requries a silicon workaround, do not 'hijack' the vfunc for all devices of this type. This means we do the right thing when updating both the one that requires the workaround, and the 'normal' one. --- plugins/vli/fu-vli-pd-device.c | 103 +++++++++++++-------------------- 1 file changed, 40 insertions(+), 63 deletions(-) diff --git a/plugins/vli/fu-vli-pd-device.c b/plugins/vli/fu-vli-pd-device.c index 3d657960d..2e39e01a7 100644 --- a/plugins/vli/fu-vli-pd-device.c +++ b/plugins/vli/fu-vli-pd-device.c @@ -437,7 +437,7 @@ fu_vli_pd_device_write_firmware (FuDevice *device, } static gboolean -fu_vli_pd_device_detach_vl103 (FuDevice *device, GError **error) +fu_vli_pd_device_detach (FuDevice *device, GError **error) { FuVliPdDevice *self = FU_VLI_PD_DEVICE (device); g_autoptr(GError) error_local = NULL; @@ -453,46 +453,31 @@ fu_vli_pd_device_detach_vl103 (FuDevice *device, GError **error) return FALSE; /* VL103 set ROM sig does not work, so use alternate function */ - fu_device_set_status (device, FWUPD_STATUS_DEVICE_RESTART); - if (!g_usb_device_control_transfer (fu_usb_device_get_dev (FU_USB_DEVICE (device)), - G_USB_DEVICE_DIRECTION_HOST_TO_DEVICE, - G_USB_DEVICE_REQUEST_TYPE_VENDOR, - G_USB_DEVICE_RECIPIENT_DEVICE, - 0xc0, 0x0000, 0x0000, - NULL, 0x0, NULL, - FU_VLI_DEVICE_TIMEOUT, - NULL, &error_local)) { - if (g_error_matches (error_local, - G_USB_DEVICE_ERROR, - G_USB_DEVICE_ERROR_FAILED)) { - g_debug ("ignoring %s", error_local->message); - } else { - g_propagate_prefixed_error (error, - g_steal_pointer (&error_local), - "failed to restart device: "); - return FALSE; + if (fu_vli_device_get_kind (FU_VLI_DEVICE (device)) == FU_VLI_DEVICE_KIND_VL103) { + fu_device_set_status (device, FWUPD_STATUS_DEVICE_RESTART); + if (!g_usb_device_control_transfer (fu_usb_device_get_dev (FU_USB_DEVICE (device)), + G_USB_DEVICE_DIRECTION_HOST_TO_DEVICE, + G_USB_DEVICE_REQUEST_TYPE_VENDOR, + G_USB_DEVICE_RECIPIENT_DEVICE, + 0xc0, 0x0000, 0x0000, + NULL, 0x0, NULL, + FU_VLI_DEVICE_TIMEOUT, + NULL, &error_local)) { + if (g_error_matches (error_local, + G_USB_DEVICE_ERROR, + G_USB_DEVICE_ERROR_FAILED)) { + g_debug ("ignoring %s", error_local->message); + } else { + g_propagate_prefixed_error (error, + g_steal_pointer (&error_local), + "failed to restart device: "); + return FALSE; + } } - } - fu_device_add_flag (device, FWUPD_DEVICE_FLAG_WAIT_FOR_REPLUG); - return TRUE; -} - -static gboolean -fu_vli_pd_device_detach (FuDevice *device, GError **error) -{ - FuVliPdDevice *self = FU_VLI_PD_DEVICE (device); - g_autoptr(GError) error_local = NULL; - - /* sanity check */ - if (fu_device_has_flag (device, FWUPD_DEVICE_FLAG_IS_BOOTLOADER)) { - g_debug ("already in bootloader mode, skipping"); + fu_device_add_flag (device, FWUPD_DEVICE_FLAG_WAIT_FOR_REPLUG); return TRUE; } - /* write GPIOs */ - if (!fu_vli_pd_device_write_gpios (self, error)) - return FALSE; - /* patch APP5 FW bug (2AF2 -> 2AE2) on VL100-App5 and VL102 */ if (fu_vli_device_get_kind (FU_VLI_DEVICE (device)) == FU_VLI_DEVICE_KIND_VL100 || fu_vli_device_get_kind (FU_VLI_DEVICE (device)) == FU_VLI_DEVICE_KIND_VL102) { @@ -551,8 +536,24 @@ fu_vli_pd_device_detach (FuDevice *device, GError **error) static gboolean fu_vli_pd_device_attach (FuDevice *device, GError **error) { + FuVliPdDevice *self = FU_VLI_PD_DEVICE (device); g_autoptr(GError) error_local = NULL; + /* Work around a silicon bug: Once the CC-resistor is removed, the + * CC-host thinks the device is un-plugged and turn off VBUS (power). + * When VL103 is powered-off, VL103 puts a resistor at CC-pin. + * The CC-host will think the device is re-plugged and provides VBUS + * again. Then, VL103 will be powered on and runs new FW. */ + if (fu_vli_device_get_kind (FU_VLI_DEVICE (device)) == FU_VLI_DEVICE_KIND_VL103) { + if (!fu_vli_pd_device_write_reg (self, 0x1201, 0xf6, error)) + return FALSE; + if (!fu_vli_pd_device_write_reg (self, 0x1001, 0xf6, error)) + return FALSE; + fu_device_set_status (device, FWUPD_STATUS_DEVICE_RESTART); + fu_device_add_flag (device, FWUPD_DEVICE_FLAG_WAIT_FOR_REPLUG); + return TRUE; + } + /* sanity check */ if (!fu_device_has_flag (device, FWUPD_DEVICE_FLAG_IS_BOOTLOADER)) { g_debug ("already in runtime mode, skipping"); @@ -593,38 +594,12 @@ fu_vli_pd_device_attach (FuDevice *device, GError **error) return TRUE; } -static gboolean -fu_vli_pd_device_attach_vl103 (FuDevice *device, GError **error) -{ - FuVliPdDevice *self = FU_VLI_PD_DEVICE (device); - - /* Work around a silicon bug: Once the CC-resistor is removed, the - * CC-host thinks the device is un-plugged and turn off VBUS (power). - * When VL103 is powered-off, VL103 puts a resistor at CC-pin. - * The CC-host will think the device is re-plugged and provides VBUS - * again. Then, VL103 will be powered on and runs new FW. */ - if (!fu_vli_pd_device_write_reg (self, 0x1201, 0xf6, error)) - return FALSE; - if (!fu_vli_pd_device_write_reg (self, 0x1001, 0xf6, error)) - return FALSE; - fu_device_set_status (device, FWUPD_STATUS_DEVICE_RESTART); - fu_device_add_flag (device, FWUPD_DEVICE_FLAG_WAIT_FOR_REPLUG); - return TRUE; -} - static void fu_vli_pd_device_kind_changed_cb (FuVliDevice *device, GParamSpec *pspec, gpointer user_data) { - FuDeviceClass *klass_device = FU_DEVICE_GET_CLASS (device); if (fu_vli_device_get_kind (device) == FU_VLI_DEVICE_KIND_VL103) { - klass_device->attach = fu_vli_pd_device_attach_vl103; - klass_device->detach = fu_vli_pd_device_detach_vl103; - /* wait for USB-C timeout */ fu_device_set_remove_delay (FU_DEVICE (device), 10000); - } else { - klass_device->attach = fu_vli_pd_device_attach; - klass_device->detach = fu_vli_pd_device_detach; } } @@ -653,6 +628,8 @@ fu_vli_pd_device_class_init (FuVliPdDeviceClass *klass) klass_device->read_firmware = fu_vli_pd_device_read_firmware; klass_device->write_firmware = fu_vli_pd_device_write_firmware; klass_device->prepare_firmware = fu_vli_pd_device_prepare_firmware; + klass_device->attach = fu_vli_pd_device_attach; + klass_device->detach = fu_vli_pd_device_detach; klass_vli_device->setup = fu_vli_pd_device_setup; klass_vli_device->spi_chip_erase = fu_vli_pd_device_spi_chip_erase; klass_vli_device->spi_sector_erase = fu_vli_pd_device_spi_sector_erase; From 83a21cb7cd478f99a7f3e8739318a8dbd373b158 Mon Sep 17 00:00:00 2001 From: Richard Hughes Date: Mon, 8 Jun 2020 15:24:38 +0100 Subject: [PATCH 144/607] vli: Allow chained usb hub devices where the parent needs GPIOB reset As both hub devices share a FuVliUsbhubDeviceClass instance we cannot 'hijack' the vfuncs depending on object type. This allows the downstream hub to proxy to the upstream hub where a GPIOB reset can be performed. --- plugins/vli/fu-vli-usbhub-device.c | 128 +++++++++++++++-------------- 1 file changed, 66 insertions(+), 62 deletions(-) diff --git a/plugins/vli/fu-vli-usbhub-device.c b/plugins/vli/fu-vli-usbhub-device.c index fbc6ac997..ab6838658 100644 --- a/plugins/vli/fu-vli-usbhub-device.c +++ b/plugins/vli/fu-vli-usbhub-device.c @@ -330,27 +330,65 @@ fu_vli_usbhub_device_spi_write_data (FuVliDevice *self, #define VL817_ADDR_GPIO_GET_INPUT_DATA 0xF6A2 /* 0=low, 1=high */ static gboolean -fu_vli_usbhub_device_attach_vl817_gpiob (FuDevice *device, GError **error) +fu_vli_usbhub_device_attach_full (FuDevice *device, FuDevice *proxy, GError **error) { - FuVliUsbhubDevice *self = FU_VLI_USBHUB_DEVICE (device); - guint8 tmp = 0x0; + g_autoptr(GError) error_local = NULL; - /* set GPIOB output enable */ - if (!fu_vli_usbhub_device_read_reg (self, VL817_ADDR_GPIO_OUTPUT_ENABLE, - &tmp, error)) - return FALSE; - if (!fu_vli_usbhub_device_write_reg (self, VL817_ADDR_GPIO_OUTPUT_ENABLE, - tmp | (1 << 1), error)) - return FALSE; - - /* toggle GPIOB to trigger reset */ - if (!fu_vli_usbhub_device_read_reg (self, VL817_ADDR_GPIO_SET_OUTPUT_DATA, - &tmp, error)) - return FALSE; - if (!fu_vli_usbhub_device_write_reg (self, VL817_ADDR_GPIO_SET_OUTPUT_DATA, - tmp ^ (1 << 1), error)) - return FALSE; + /* update UI */ fu_device_set_status (device, FWUPD_STATUS_DEVICE_RESTART); + + /* some hardware has to toggle a GPIO to reset the entire PCB */ + if (fu_vli_device_get_kind (FU_VLI_DEVICE (proxy)) == FU_VLI_DEVICE_KIND_VL817 && + fu_device_has_custom_flag (proxy, "attach-with-gpiob")) { + guint8 tmp = 0x0; + + /* set GPIOB output enable */ + g_debug ("using GPIO reset for %s", fu_device_get_id (device)); + if (!fu_vli_usbhub_device_read_reg (FU_VLI_USBHUB_DEVICE (proxy), + VL817_ADDR_GPIO_OUTPUT_ENABLE, + &tmp, error)) + return FALSE; + if (!fu_vli_usbhub_device_write_reg (FU_VLI_USBHUB_DEVICE (proxy), + VL817_ADDR_GPIO_OUTPUT_ENABLE, + tmp | (1 << 1), error)) + return FALSE; + + /* toggle GPIOB to trigger reset */ + if (!fu_vli_usbhub_device_read_reg (FU_VLI_USBHUB_DEVICE (proxy), + VL817_ADDR_GPIO_SET_OUTPUT_DATA, + &tmp, error)) + return FALSE; + if (!fu_vli_usbhub_device_write_reg (FU_VLI_USBHUB_DEVICE (proxy), + VL817_ADDR_GPIO_SET_OUTPUT_DATA, + tmp ^ (1 << 1), error)) + return FALSE; + } else { + /* replug, and ignore the device going away */ + if (!g_usb_device_control_transfer (fu_usb_device_get_dev (FU_USB_DEVICE (proxy)), + G_USB_DEVICE_DIRECTION_HOST_TO_DEVICE, + G_USB_DEVICE_REQUEST_TYPE_VENDOR, + G_USB_DEVICE_RECIPIENT_DEVICE, + 0xf6, 0x0040, 0x0002, + NULL, 0x0, NULL, + FU_VLI_DEVICE_TIMEOUT, + NULL, &error_local)) { + if (g_error_matches (error_local, + G_USB_DEVICE_ERROR, + G_USB_DEVICE_ERROR_NO_DEVICE) || + g_error_matches (error_local, + G_USB_DEVICE_ERROR, + G_USB_DEVICE_ERROR_FAILED)) { + g_debug ("ignoring %s", error_local->message); + } else { + g_propagate_prefixed_error (error, + g_steal_pointer (&error_local), + "failed to restart device: "); + return FALSE; + } + } + } + + /* success */ fu_device_add_flag (device, FWUPD_DEVICE_FLAG_WAIT_FOR_REPLUG); return TRUE; } @@ -358,41 +396,20 @@ fu_vli_usbhub_device_attach_vl817_gpiob (FuDevice *device, GError **error) static gboolean fu_vli_usbhub_device_attach (FuDevice *device, GError **error) { - g_autoptr(GError) error_local = NULL; + FuDevice *proxy = fu_device_get_proxy (device); - /* the proxy might be using a GPIO instead */ - if (fu_device_get_proxy (device) != NULL) { - FuDevice *proxy = fu_device_get_proxy (device); + /* if we do this in another plugin, perhaps move to the engine? */ + if (proxy != NULL) { + g_autoptr(FuDeviceLocker) locker = NULL; g_debug ("using proxy device %s", fu_device_get_id (proxy)); - return fu_device_attach (proxy, error); + locker = fu_device_locker_new (proxy, error); + if (locker == NULL) + return FALSE; + return fu_vli_usbhub_device_attach_full (device, proxy, error); } - /* replug, and ignore the device going away */ - fu_device_set_status (device, FWUPD_STATUS_DEVICE_RESTART); - fu_device_add_flag (device, FWUPD_DEVICE_FLAG_WAIT_FOR_REPLUG); - if (!g_usb_device_control_transfer (fu_usb_device_get_dev (FU_USB_DEVICE (device)), - G_USB_DEVICE_DIRECTION_HOST_TO_DEVICE, - G_USB_DEVICE_REQUEST_TYPE_VENDOR, - G_USB_DEVICE_RECIPIENT_DEVICE, - 0xf6, 0x0040, 0x0002, - NULL, 0x0, NULL, - FU_VLI_DEVICE_TIMEOUT, - NULL, &error_local)) { - if (g_error_matches (error_local, - G_USB_DEVICE_ERROR, - G_USB_DEVICE_ERROR_NO_DEVICE) || - g_error_matches (error_local, - G_USB_DEVICE_ERROR, - G_USB_DEVICE_ERROR_FAILED)) { - g_debug ("ignoring %s", error_local->message); - } else { - g_propagate_prefixed_error (error, - g_steal_pointer (&error_local), - "failed to restart device: "); - return FALSE; - } - } - return TRUE; + /* normal case */ + return fu_vli_usbhub_device_attach_full (device, device, error); } /* disable hub sleep states -- not really required by 815~ hubs */ @@ -1043,25 +1060,12 @@ fu_vli_usbhub_device_write_firmware (FuDevice *device, return FALSE; } -static void -fu_vli_usbhub_device_kind_changed_cb (FuVliDevice *device, GParamSpec *pspec, gpointer user_data) -{ - FuDeviceClass *klass_device = FU_DEVICE_GET_CLASS (device); - if (fu_vli_device_get_kind (device) == FU_VLI_DEVICE_KIND_VL817 && - fu_device_has_custom_flag (FU_DEVICE (device), "attach-with-gpiob")) - klass_device->attach = fu_vli_usbhub_device_attach_vl817_gpiob; -} - static void fu_vli_usbhub_device_init (FuVliUsbhubDevice *self) { fu_device_add_icon (FU_DEVICE (self), "audio-card"); fu_device_set_protocol (FU_DEVICE (self), "com.vli.usbhub"); fu_device_set_remove_delay (FU_DEVICE (self), FU_DEVICE_REMOVE_DELAY_RE_ENUMERATE); - - /* connect up attach or detach vfuncs when kind is known */ - g_signal_connect (self, "notify::kind", - G_CALLBACK (fu_vli_usbhub_device_kind_changed_cb), NULL); } static void From 6b9664168d19cd21a091b556dc99da807d2ebea4 Mon Sep 17 00:00:00 2001 From: Mario Limonciello Date: Tue, 9 Jun 2020 09:42:32 -0500 Subject: [PATCH 145/607] trivial: checkout branch to fix changelog publishing --- .circleci/config.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.circleci/config.yml b/.circleci/config.yml index 42d78d6fc..6c337f9c2 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -160,6 +160,7 @@ jobs: steps: - attach_workspace: at: . + - checkout - run: name: "Publish Release on GitHub" command: | From 471a0e2105f52e6489edc157f8a61d12934f1edd Mon Sep 17 00:00:00 2001 From: Mario Limonciello Date: Tue, 9 Jun 2020 10:49:49 -0500 Subject: [PATCH 146/607] fu-main: Make it clearer what lost name is and bump it to warning This happens often enough when people switch from snap to distro package that we should mention it in non-verbose logs. Fixes: #2112 --- src/fu-main.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/fu-main.c b/src/fu-main.c index bc7e8cf7e..363c9dacc 100644 --- a/src/fu-main.c +++ b/src/fu-main.c @@ -1493,7 +1493,7 @@ fu_main_on_name_lost_cb (GDBusConnection *connection, gpointer user_data) { FuMainPrivate *priv = (FuMainPrivate *) user_data; - g_debug ("FuMain: lost name: %s", name); + g_warning ("another service has claimed the dbus name %s", name); g_main_loop_quit (priv->loop); } From afda962cba029d9676291f3ec6d7f8d1113f1802 Mon Sep 17 00:00:00 2001 From: Richard Hughes Date: Wed, 10 Jun 2020 12:48:31 +0100 Subject: [PATCH 147/607] Fix regression when checking for downgraded metadata When verifying a signature the valid results are ordered by timestamp. The CHECKSUM results have a zero timestamp and should have been ordered last. The sorting callback was wrong, which explains the odd result where we could downgrade Jcat signatures before we fixed 64ebf9, and nicely explains why we ignored a timestamp of zero in the first place. When getting the timestamp, ensure we actually get the newest _signature_ not just the newest result in case checksums start having timestamps in the future for some reason. Use new API from libjcat where available, else fall back to sneaking it out using GObject properties and magic values. --- src/fu-engine.c | 49 +++++++++++++++++++++++++++++++++++++++++-------- 1 file changed, 41 insertions(+), 8 deletions(-) diff --git a/src/fu-engine.c b/src/fu-engine.c index f930c1d46..d7c4b0f1a 100644 --- a/src/fu-engine.c +++ b/src/fu-engine.c @@ -59,6 +59,9 @@ #include "fu-ihex-firmware.h" #include "fu-srec-firmware.h" +/* only needed until we hard depend on jcat 0.1.3 */ +#include + #ifdef HAVE_SYSTEMD #include "fu-systemd.h" #endif @@ -3122,12 +3125,42 @@ fu_engine_sort_jcat_results_timestamp_cb (gconstpointer a, gconstpointer b) JcatResult *ra = *((JcatResult **) a); JcatResult *rb = *((JcatResult **) b); if (jcat_result_get_timestamp (ra) < jcat_result_get_timestamp (rb)) - return -1; - if (jcat_result_get_timestamp (ra) > jcat_result_get_timestamp (rb)) return 1; + if (jcat_result_get_timestamp (ra) > jcat_result_get_timestamp (rb)) + return -1; return 0; } +static JcatResult * +fu_engine_get_newest_signature_jcat_result (GPtrArray *results, GError **error) +{ + /* sort by timestamp, newest first */ + g_ptr_array_sort (results, fu_engine_sort_jcat_results_timestamp_cb); + + /* get the first signature, ignoring the checksums */ + for (guint i = 0; i < results->len; i++) { + JcatResult *result = g_ptr_array_index (results, i); +#if LIBJCAT_CHECK_VERSION(0, 1, 3) + if (jcat_result_get_method (result) == JCAT_BLOB_METHOD_SIGNATURE) + return g_object_ref (result); +#else + guint verify_kind = 0; + g_autoptr(JcatEngine) engine = NULL; + g_object_get (result, "engine", &engine, NULL); + g_object_get (engine, "verify-kind", &verify_kind, NULL); + if (verify_kind == 2) /* SIGNATURE */ + return g_object_ref (result); +#endif + } + + /* should never happen due to %JCAT_VERIFY_FLAG_REQUIRE_SIGNATURE */ + g_set_error_literal (error, + FWUPD_ERROR, + FWUPD_ERROR_INVALID_FILE, + "no signature method in results"); + return NULL; +} + static JcatResult * fu_engine_get_system_jcat_result (FuEngine *self, FwupdRemote *remote, GError **error) { @@ -3159,10 +3192,9 @@ fu_engine_get_system_jcat_result (FuEngine *self, FwupdRemote *remote, GError ** error); if (results == NULL) return NULL; - g_ptr_array_sort (results, fu_engine_sort_jcat_results_timestamp_cb); - /* return the newest one */ - return g_object_ref (g_ptr_array_index (results, 0)); + /* return the newest signature */ + return fu_engine_get_newest_signature_jcat_result (results, error); } static gboolean @@ -3274,9 +3306,10 @@ fu_engine_update_metadata_bytes (FuEngine *self, const gchar *remote_id, if (results == NULL) return FALSE; - /* return the newest one */ - g_ptr_array_sort (results, fu_engine_sort_jcat_results_timestamp_cb); - jcat_result = g_ptr_array_index (results, 0); + /* return the newest signature */ + jcat_result = fu_engine_get_newest_signature_jcat_result (results, error); + if (jcat_result == NULL) + return FALSE; /* verify the metadata was signed later than the existing * metadata for this remote to mitigate a rollback attack */ From 0143c67c7660c5b673669e543fa1cfafe62c0af6 Mon Sep 17 00:00:00 2001 From: Richard Hughes Date: Wed, 10 Jun 2020 13:16:26 +0100 Subject: [PATCH 148/607] trivial: Build a specific tag from the libjcat subproject --- subprojects/libjcat.wrap | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/subprojects/libjcat.wrap b/subprojects/libjcat.wrap index 15615559a..ad352fb73 100644 --- a/subprojects/libjcat.wrap +++ b/subprojects/libjcat.wrap @@ -1,4 +1,4 @@ [wrap-git] directory = libjcat url = https://github.com/hughsie/libjcat.git -revision = master +revision = 0.1.0 From 080789916fa9486e72e730c489c772ddaeba3119 Mon Sep 17 00:00:00 2001 From: Mario Limonciello Date: Wed, 10 Jun 2020 11:15:14 -0500 Subject: [PATCH 149/607] trivial: fix news generation script --- .circleci/config.yml | 4 ++-- contrib/ci/build_windows.sh | 14 +++++++++----- 2 files changed, 11 insertions(+), 7 deletions(-) diff --git a/.circleci/config.yml b/.circleci/config.yml index 6c337f9c2..719e29198 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -74,6 +74,7 @@ jobs: paths: - "dist/setup/*.exe" - "dist/VERSION" + - "dist/news.txt" - store_artifacts: path: dist/setup @@ -160,13 +161,12 @@ jobs: steps: - attach_workspace: at: . - - checkout - run: name: "Publish Release on GitHub" command: | go get github.com/tcnksm/ghr VERSION=$(cat dist/VERSION) - BODY=$(./contrib/ci/generate_news.py $VERSION) + BODY=$(cat dist/news.txt) ghr -t ${GITHUB_TOKEN} -u ${CIRCLE_PROJECT_USERNAME} -r ${CIRCLE_PROJECT_REPONAME} -c ${CIRCLE_SHA1} -b ${BODY} ${VERSION} ./dist/setup/ workflows: version: 2 diff --git a/contrib/ci/build_windows.sh b/contrib/ci/build_windows.sh index a42993990..33c2a8604 100755 --- a/contrib/ci/build_windows.sh +++ b/contrib/ci/build_windows.sh @@ -3,7 +3,8 @@ set -e #prep export LC_ALL=C.UTF-8 export DESTDIR=`pwd`/dist -build=`pwd`/build-win32 +root=`pwd` +build=$root/build-win32 rm -rf $DESTDIR $build #build @@ -44,14 +45,17 @@ meson .. \ -Dgusb:introspection=false \ -Dgusb:vapi=false \ -Dgudev=false $@ -meson introspect . --projectinfo | jq -r .version > $DESTDIR/VERSION +VERSION=$(meson introspect . --projectinfo | jq -r .version) ninja -v - -#prepare archive to run on Windows ninja -v install -cd $DESTDIR + +#generate news release +cd $root +contrib/ci/generate_news.py $VERSION > $DESTDIR/news.txt +echo $VERSION > $DESTDIR/VERSION # create a setup binary +cd $DESTDIR mkdir -p $DESTDIR/setup makensis -NOCD $build/contrib/setup-win32.nsi From 92072b4239cfa2813ea439be86b5ad80e8bc1055 Mon Sep 17 00:00:00 2001 From: Richard Hughes Date: Wed, 10 Jun 2020 17:23:37 +0100 Subject: [PATCH 150/607] vli: Add the project ID shared SPI PD controllers The Mini-Dock and Travel-Hub accidentally share the same VID:PID and this is the only way to tell them apart. --- plugins/vli/README.md | 3 ++- plugins/vli/fu-vli-usbhub-pd-device.c | 6 ++++++ 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/plugins/vli/README.md b/plugins/vli/README.md index d1e4d57ba..71f459b65 100644 --- a/plugins/vli/README.md +++ b/plugins/vli/README.md @@ -37,9 +37,10 @@ These devices also use custom GUID values for the SPI flash configuration, e.g. * `VLI_USBHUB\SPI_3730` * `VLI_USBHUB\SPI_37` -Optional PD child devices sharing the SPI flash use just one extra GUID, e.g. +Optional PD child devices sharing the SPI flash use two extra GUIDs, e.g. * `USB\VID_17EF&PID_3083&DEV_VL102` + * `USB\VID_17EF&PID_3083&APP_26` Optional I²C child devices use just one extra GUID, e.g. diff --git a/plugins/vli/fu-vli-usbhub-pd-device.c b/plugins/vli/fu-vli-usbhub-pd-device.c index 9d2f8f2b7..9209e6436 100644 --- a/plugins/vli/fu-vli-usbhub-pd-device.c +++ b/plugins/vli/fu-vli-usbhub-pd-device.c @@ -44,6 +44,7 @@ fu_vli_usbhub_pd_device_probe (FuDevice *device, GError **error) guint32 fwver; g_autofree gchar *fwver_str = NULL; + g_autofree gchar *instance_id0 = NULL; g_autofree gchar *instance_id1 = NULL; g_autofree gchar *instance_id2 = NULL; g_autofree gchar *instance_id3 = NULL; @@ -64,6 +65,11 @@ fu_vli_usbhub_pd_device_probe (FuDevice *device, GError **error) fu_device_set_version_raw (device, fwver); fwver_str = fu_common_version_from_uint32 (fwver, FWUPD_VERSION_FORMAT_QUAD); fu_device_set_version (device, fwver_str); + instance_id0 = g_strdup_printf ("USB\\VID_%04X&PID_%04X&APP_%02X", + GUINT16_FROM_LE (self->hdr.vid), + GUINT16_FROM_LE (self->hdr.pid), + fwver & 0xff); + fu_device_add_instance_id (device, instance_id0); instance_id1 = g_strdup_printf ("USB\\VID_%04X&PID_%04X&DEV_%s", GUINT16_FROM_LE (self->hdr.vid), GUINT16_FROM_LE (self->hdr.pid), From 6cd6e2adb65f52fc61336eec49b1dd793dafd3ec Mon Sep 17 00:00:00 2001 From: Richard Hughes Date: Wed, 10 Jun 2020 17:23:58 +0100 Subject: [PATCH 151/607] vli: Set FuQuirks on the shared SPI object --- plugins/vli/fu-vli-usbhub-device.c | 1 + 1 file changed, 1 insertion(+) diff --git a/plugins/vli/fu-vli-usbhub-device.c b/plugins/vli/fu-vli-usbhub-device.c index ab6838658..fecf09398 100644 --- a/plugins/vli/fu-vli-usbhub-device.c +++ b/plugins/vli/fu-vli-usbhub-device.c @@ -606,6 +606,7 @@ fu_vli_usbhub_device_pd_setup (FuVliUsbhubDevice *self, GError **error) /* add child */ dev = fu_vli_usbhub_pd_device_new (&hdr); + fu_device_set_quirks (dev, fu_device_get_quirks (FU_DEVICE (self))); if (!fu_device_probe (dev, &error_local)) { g_warning ("cannot create PD device: %s", error_local->message); return TRUE; From 4fd61e4756d37e37f6dffbcdd5d6fd2e615c20b1 Mon Sep 17 00:00:00 2001 From: Richard Hughes Date: Wed, 10 Jun 2020 17:24:22 +0100 Subject: [PATCH 152/607] vli: Use the GPIOB reset for the MiniDock VL103 --- plugins/vli/vli-usbhub-lenovo.quirk | 3 +++ 1 file changed, 3 insertions(+) diff --git a/plugins/vli/vli-usbhub-lenovo.quirk b/plugins/vli/vli-usbhub-lenovo.quirk index 29ff0b060..4f9637584 100644 --- a/plugins/vli/vli-usbhub-lenovo.quirk +++ b/plugins/vli/vli-usbhub-lenovo.quirk @@ -174,6 +174,9 @@ Plugin = vli GType = FuVliUsbhubDevice Flags = usb2 ParentGuid = USB\VID_17EF&PID_3094 +[DeviceInstanceId=USB\VID_17EF&PID_721C&APP_26] +ProxyGuid = USB\VID_17EF&PID_3094 +FirmwareSize = 0x8000 # Lenovo Travel Hub 1in3 [DeviceInstanceId=USB\VID_17EF&PID_7228] From d94ce34d563581f10489f4ffcd310afbbbe95598 Mon Sep 17 00:00:00 2001 From: Richard Hughes Date: Fri, 12 Jun 2020 17:13:14 +0100 Subject: [PATCH 153/607] trivial: Add more items to the kernel command line checker This data is from Pascal Ernster, many thanks. --- src/fu-engine.c | 27 +++++++++++++++++++++++++++ 1 file changed, 27 insertions(+) diff --git a/src/fu-engine.c b/src/fu-engine.c index d7c4b0f1a..5d10bedd1 100644 --- a/src/fu-engine.c +++ b/src/fu-engine.c @@ -1391,27 +1391,54 @@ fu_engine_get_report_metadata_kernel_cmdline (GHashTable *hash, GError **error) const gchar *ignore[] = { "", "auto", + "boot", "BOOT_IMAGE", "console", "cryptdevice", "initrd", + "ip", "LANG", "loglevel", + "luks.key", + "luks.name", + "luks.options", + "luks.uuid", + "mount.usr", + "mount.usrflags", + "mount.usrfstype", + "netroot", + "nfsaddrs", + "nfs.nfs4_unique_id", + "nfsroot", "noplymouth", "ostree", "quiet", + "rd.dm.uuid", + "rd.luks.allow-discards", + "rd.luks.key", + "rd.luks.name", + "rd.luks.options", "rd.luks.uuid", "rd.lvm.lv", + "rd.lvm.vg", "rd.md.uuid", + "rd.systemd.mask", + "rd.systemd.wants", "resume", + "resumeflags", "rhgb", "ro", "root", "rootflags", + "roothash", "rw", "showopts", "splash", "swap", + "systemd.mask", + "systemd.verity_root_data", + "systemd.verity_root_hash", + "systemd.wants", "verbose", "vt.handoff", "zfs", From 7f7f0aed1faebd225a4ee60099eddb78a2f66021 Mon Sep 17 00:00:00 2001 From: Richard Hughes Date: Mon, 15 Jun 2020 12:10:58 +0100 Subject: [PATCH 154/607] trivial: Add more items to the kernel command line checker This data is from Pascal Ernster, many thanks. --- src/fu-engine.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/fu-engine.c b/src/fu-engine.c index 5d10bedd1..704612d33 100644 --- a/src/fu-engine.c +++ b/src/fu-engine.c @@ -1395,6 +1395,10 @@ fu_engine_get_report_metadata_kernel_cmdline (GHashTable *hash, GError **error) "BOOT_IMAGE", "console", "cryptdevice", + "cryptkey", + "earlycon", + "earlyprintk", + "ether", "initrd", "ip", "LANG", @@ -1406,6 +1410,7 @@ fu_engine_get_report_metadata_kernel_cmdline (GHashTable *hash, GError **error) "mount.usr", "mount.usrflags", "mount.usrfstype", + "netdev", "netroot", "nfsaddrs", "nfs.nfs4_unique_id", @@ -1436,6 +1441,7 @@ fu_engine_get_report_metadata_kernel_cmdline (GHashTable *hash, GError **error) "splash", "swap", "systemd.mask", + "systemd.unit", "systemd.verity_root_data", "systemd.verity_root_hash", "systemd.wants", From e261bb6fa09de0c1ee25880b4e4f27a7daab8343 Mon Sep 17 00:00:00 2001 From: Richard Hughes Date: Wed, 10 Jun 2020 19:03:00 +0100 Subject: [PATCH 155/607] Record the UEFI failure in more cases Ensure the historical error is set for failed NEEDS_REBOOT UEFI devices that do not set LastAttemptStatus. --- src/fu-engine.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/fu-engine.c b/src/fu-engine.c index 704612d33..31002ae42 100644 --- a/src/fu-engine.c +++ b/src/fu-engine.c @@ -5740,6 +5740,7 @@ fu_engine_update_history_device (FuEngine *self, FuDevice *dev_history, GError * fu_device_set_version (dev_history, fu_device_get_version (dev)); fu_device_remove_flag (dev_history, FWUPD_DEVICE_FLAG_NEEDS_ACTIVATION); fu_device_set_update_state (dev_history, FWUPD_UPDATE_STATE_SUCCESS); + fu_device_set_update_error (dev_history, NULL); return fu_history_modify_device (self->history, dev_history, error); } @@ -5756,11 +5757,14 @@ fu_engine_update_history_device (FuEngine *self, FuDevice *dev_history, GError * if (fu_device_get_update_state (dev) != FWUPD_UPDATE_STATE_FAILED && fu_device_get_update_state (dev) != FWUPD_UPDATE_STATE_FAILED_TRANSIENT) { g_debug ("falling back to generic failure"); + fu_device_set_update_state (dev_history, FWUPD_UPDATE_STATE_FAILED); fu_device_set_update_error (dev_history, "failed to run update on reboot"); + } else { + fu_device_set_update_state (dev_history, fu_device_get_update_state (dev)); + fu_device_set_update_error (dev_history, fu_device_get_update_error (dev)); } /* update the state in the database */ - fu_device_set_update_error (dev_history, fu_device_get_update_error (dev)); return fu_history_modify_device (self->history, dev_history, error); } From 2caea542029345e6cb409f8cd6e870a2c363e96e Mon Sep 17 00:00:00 2001 From: Mario Limonciello Date: Mon, 15 Jun 2020 10:05:36 -0500 Subject: [PATCH 156/607] uefi: check for free space after cleaning up ESP In a very small ESP situation it's possible that the amount of free space is insufficient until it's actually been cleaned. Fixes: #2179 --- plugins/uefi/fu-uefi-device.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/plugins/uefi/fu-uefi-device.c b/plugins/uefi/fu-uefi-device.c index 23550959f..65d2ac539 100644 --- a/plugins/uefi/fu-uefi-device.c +++ b/plugins/uefi/fu-uefi-device.c @@ -515,10 +515,10 @@ fu_uefi_device_prepare (FuDevice *device, /* sanity checks */ if (!fu_uefi_device_is_esp_mounted (device, error)) return FALSE; - if (!fu_uefi_device_check_esp_free (device, error)) - return FALSE; if (!fu_uefi_device_cleanup_esp (device, error)) return FALSE; + if (!fu_uefi_device_check_esp_free (device, error)) + return FALSE; return TRUE; } From 5b63015c19b4bb3c2e0b38326e10277931a96002 Mon Sep 17 00:00:00 2001 From: Mario Limonciello Date: Mon, 15 Jun 2020 16:02:05 -0500 Subject: [PATCH 157/607] tpm-eventlog: fix PCR0 calculation One of the core problems is that systems with both sha1 and sha256 were miscalculating. Fixes: #2181 --- plugins/tpm-eventlog/fu-tpm-eventlog-parser.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugins/tpm-eventlog/fu-tpm-eventlog-parser.c b/plugins/tpm-eventlog/fu-tpm-eventlog-parser.c index 1d28ce8b0..1f133b7c0 100644 --- a/plugins/tpm-eventlog/fu-tpm-eventlog-parser.c +++ b/plugins/tpm-eventlog/fu-tpm-eventlog-parser.c @@ -141,7 +141,7 @@ fu_tpm_eventlog_parser_parse_blob_v2 (const guint8 *buf, gsize bufsz, if (alg_type == TPM2_ALG_SHA1) checksum_sha1 = g_bytes_new_take (g_steal_pointer (&digest), alg_size); else if (alg_type == TPM2_ALG_SHA256) - checksum_sha1 = g_bytes_new_take (g_steal_pointer (&digest), alg_size); + checksum_sha256 = g_bytes_new_take (g_steal_pointer (&digest), alg_size); } /* next block */ From 589270a7c4bbbd4c4fd821843d06a3d5a7533198 Mon Sep 17 00:00:00 2001 From: Richard Hughes Date: Tue, 16 Jun 2020 11:27:49 +0100 Subject: [PATCH 158/607] trivial: Simplify some reporting code This is not a fast path, so make getting the FwupdRemote simpler. --- src/fu-util.c | 31 +++++++------------------------ 1 file changed, 7 insertions(+), 24 deletions(-) diff --git a/src/fu-util.c b/src/fu-util.c index b4a44235c..a13cfe489 100644 --- a/src/fu-util.c +++ b/src/fu-util.c @@ -826,7 +826,6 @@ fu_util_report_history_for_remote (FuUtilPrivate *priv, static gboolean fu_util_report_history (FuUtilPrivate *priv, gchar **values, GError **error) { - g_autoptr(GHashTable) remote_id_uri_map = NULL; g_autoptr(GHashTable) report_map = NULL; g_autoptr(GList) ids = NULL; g_autoptr(GPtrArray) devices = NULL; @@ -840,25 +839,6 @@ fu_util_report_history (FuUtilPrivate *priv, gchar **values, GError **error) return FALSE; } - /* create a map of RemoteID to RemoteURI */ - remotes = fwupd_client_get_remotes (priv->client, NULL, error); - if (remotes == NULL) - return FALSE; - remote_id_uri_map = g_hash_table_new (g_str_hash, g_str_equal); - for (guint i = 0; i < remotes->len; i++) { - FwupdRemote *remote = g_ptr_array_index (remotes, i); - if (fwupd_remote_get_id (remote) == NULL) - continue; - if (fwupd_remote_get_report_uri (remote) == NULL) - continue; - g_debug ("adding %s for %s", - fwupd_remote_get_report_uri (remote), - fwupd_remote_get_id (remote)); - g_hash_table_insert (remote_id_uri_map, - (gpointer) fwupd_remote_get_id (remote), - (gpointer) fwupd_remote_get_report_uri (remote)); - } - /* get all devices from the history database, then filter them, * adding to a hash map of report-ids */ devices = fwupd_client_get_history (priv->client, NULL, error); @@ -870,8 +850,8 @@ fu_util_report_history (FuUtilPrivate *priv, gchar **values, GError **error) FwupdDevice *dev = g_ptr_array_index (devices, i); FwupdRelease *rel = fwupd_device_get_release_default (dev); const gchar *remote_id; - const gchar *remote_uri; GPtrArray *devices_tmp; + g_autoptr(FwupdRemote) remote = NULL; /* filter, if not forcing */ if (!fu_util_filter_device (priv, dev)) @@ -897,9 +877,12 @@ fu_util_report_history (FuUtilPrivate *priv, gchar **values, GError **error) g_debug ("%s has no RemoteID", fwupd_device_get_id (dev)); continue; } - remote_uri = g_hash_table_lookup (remote_id_uri_map, remote_id); - if (remote_uri == NULL) { - g_debug ("%s has no RemoteURI", remote_id); + remote = fwupd_client_get_remote_by_id (priv->client, remote_id, + NULL, error); + if (remote == NULL) + return FALSE; + if (fwupd_remote_get_report_uri (remote) == NULL) { + g_debug ("%s has no RemoteURI", fwupd_remote_get_report_uri (remote)); continue; } From 4837ab5a222406b6d175fb2c9e6e57949af8d3b4 Mon Sep 17 00:00:00 2001 From: Richard Hughes Date: Tue, 16 Jun 2020 11:49:45 +0100 Subject: [PATCH 159/607] trivial: Simplify marking devices as reported --- src/fu-util.c | 24 ++++++++++-------------- 1 file changed, 10 insertions(+), 14 deletions(-) diff --git a/src/fu-util.c b/src/fu-util.c index a13cfe489..2e1abe3f3 100644 --- a/src/fu-util.c +++ b/src/fu-util.c @@ -912,21 +912,17 @@ fu_util_report_history (FuUtilPrivate *priv, gchar **values, GError **error) GPtrArray *devices_tmp = g_hash_table_lookup (report_map, id); if (!fu_util_report_history_for_remote (priv, id, devices_tmp, error)) return FALSE; - } - /* mark each device as reported */ - for (guint i = 0; i < devices->len; i++) { - FwupdDevice *dev = g_ptr_array_index (devices, i); - if (fwupd_device_has_flag (dev, FWUPD_DEVICE_FLAG_REPORTED)) - continue; - if (!fwupd_device_has_flag (dev, FWUPD_DEVICE_FLAG_SUPPORTED)) - continue; - g_debug ("setting flag on %s", fwupd_device_get_id (dev)); - if (!fwupd_client_modify_device (priv->client, - fwupd_device_get_id (dev), - "Flags", "reported", - NULL, error)) - return FALSE; + /* mark each device as reported */ + for (guint i = 0; i < devices_tmp->len; i++) { + FwupdDevice *dev = g_ptr_array_index (devices_tmp, i); + g_debug ("setting flag on %s", fwupd_device_get_id (dev)); + if (!fwupd_client_modify_device (priv->client, + fwupd_device_get_id (dev), + "Flags", "reported", + NULL, error)) + return FALSE; + } } /* TRANSLATORS: success message -- where the user has uploaded From e012513bed9975188cfb2b5d592e9fe8423a3264 Mon Sep 17 00:00:00 2001 From: Richard Hughes Date: Tue, 16 Jun 2020 14:52:37 +0100 Subject: [PATCH 160/607] trivial: Allow modifying the historical device metadata --- src/fu-history.c | 56 ++++++++++++++++++++++++++++++++++++++++++++++++ src/fu-history.h | 4 ++++ 2 files changed, 60 insertions(+) diff --git a/src/fu-history.c b/src/fu-history.c index baa4a217e..d9f09813f 100644 --- a/src/fu-history.c +++ b/src/fu-history.c @@ -517,6 +517,62 @@ fu_history_modify_device (FuHistory *self, FuDevice *device, GError **error) return fu_history_stmt_exec (self, stmt, NULL, error); } +/** + * fu_history_set_device_metadata: + * @self: A #FuHistory + * @device_id: A DeviceID string + * @metadata: A #GHashTable of string:string + * @error: A #GError or NULL + * + * Modify a device in the history database + * + * Returns: @TRUE if successful, @FALSE for failure + * + * Since: 1.5.0 + **/ +gboolean +fu_history_set_device_metadata (FuHistory *self, + const gchar *device_id, + GHashTable *metadata, + GError **error) +{ + gint rc; + g_autofree gchar *metadata_str = NULL; + g_autoptr(GRWLockWriterLocker) locker = NULL; + g_autoptr(sqlite3_stmt) stmt = NULL; + + g_return_val_if_fail (FU_IS_HISTORY (self), FALSE); + g_return_val_if_fail (device_id != NULL, FALSE); + + /* lazy load */ + if (!fu_history_load (self, error)) + return FALSE; + + /* overwrite entry if it exists */ + locker = g_rw_lock_writer_locker_new (&self->db_mutex); + g_return_val_if_fail (locker != NULL, FALSE); + g_debug ("modifying %s", device_id); + rc = sqlite3_prepare_v2 (self->db, + "UPDATE history SET " + "metadata = ?1 " + "WHERE device_id = ?2;", + -1, &stmt, NULL); + if (rc != SQLITE_OK) { + g_set_error (error, FWUPD_ERROR, FWUPD_ERROR_INTERNAL, + "failed to prepare SQL to update history: %s", + sqlite3_errmsg (self->db)); + return FALSE; + } + + + /* metadata is stored as a simple string */ + metadata_str = _convert_hash_to_string (metadata); + sqlite3_bind_text (stmt, 1, metadata_str, -1, SQLITE_STATIC); + sqlite3_bind_text (stmt, 2, device_id, -1, SQLITE_STATIC); + + return fu_history_stmt_exec (self, stmt, NULL, error); +} + /** * fu_history_add_device: * @self: A #FuHistory diff --git a/src/fu-history.h b/src/fu-history.h index 93d04640a..f5b92fa12 100644 --- a/src/fu-history.h +++ b/src/fu-history.h @@ -22,6 +22,10 @@ gboolean fu_history_add_device (FuHistory *self, gboolean fu_history_modify_device (FuHistory *self, FuDevice *device, GError **error); +gboolean fu_history_set_device_metadata (FuHistory *self, + const gchar *device_id, + GHashTable *metadata, + GError **error); gboolean fu_history_remove_device (FuHistory *self, FuDevice *device, GError **error); From b114661a254e7be2e1c3a7668531e650b905dcd5 Mon Sep 17 00:00:00 2001 From: Richard Hughes Date: Tue, 16 Jun 2020 14:56:16 +0100 Subject: [PATCH 161/607] Collect per-device report metadata for the history database Add two new vfuncs that can be used to collect report metadata from devices both before and after the update has run. This means we can remove the hacks where we set add 'global' metadata entries and just hope that there is only one device from the same plugin that is updated. This also allows us to collect debugging metadata from devices after an offline update has been run. --- libfwupdplugin/fu-device.c | 56 ++++++++++++++++++++++++++++++++++ libfwupdplugin/fu-device.h | 8 ++++- libfwupdplugin/fwupdplugin.map | 2 ++ plugins/uefi/fu-plugin-uefi.c | 13 +------- plugins/uefi/fu-uefi-device.c | 39 ++++++++++++++++++----- plugins/uefi/fu-uefi-device.h | 1 - plugins/vli/fu-vli-device.c | 10 ++++++ src/fu-engine.c | 27 ++++++++++++++-- 8 files changed, 132 insertions(+), 24 deletions(-) diff --git a/libfwupdplugin/fu-device.c b/libfwupdplugin/fu-device.c index a4f225e38..3dfb23780 100644 --- a/libfwupdplugin/fu-device.c +++ b/libfwupdplugin/fu-device.c @@ -2972,6 +2972,62 @@ fu_device_probe_invalidate (FuDevice *self) priv->done_setup = FALSE; } +/** + * fu_device_report_metadata_pre: + * @self: A #FuDevice + * + * Collects metadata that would be useful for debugging a failed update report. + * + * Returns: (transfer full) (nullable): A #GHashTable, or %NULL if there is no data + * + * Since: 1.5.0 + **/ +GHashTable * +fu_device_report_metadata_pre (FuDevice *self) +{ + FuDeviceClass *klass = FU_DEVICE_GET_CLASS (self); + g_autoptr(GHashTable) metadata = NULL; + + g_return_val_if_fail (FU_IS_DEVICE (self), NULL); + + /* not implemented */ + if (klass->report_metadata_pre == NULL) + return NULL; + + /* metadata for all devices */ + metadata = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_free); + klass->report_metadata_pre (self, metadata); + return g_steal_pointer (&metadata); +} + +/** + * fu_device_report_metadata_post: + * @self: A #FuDevice + * + * Collects metadata that would be useful for debugging a failed update report. + * + * Returns: (transfer full) (nullable): A #GHashTable, or %NULL if there is no data + * + * Since: 1.5.0 + **/ +GHashTable * +fu_device_report_metadata_post (FuDevice *self) +{ + FuDeviceClass *klass = FU_DEVICE_GET_CLASS (self); + g_autoptr(GHashTable) metadata = NULL; + + g_return_val_if_fail (FU_IS_DEVICE (self), NULL); + + /* not implemented */ + if (klass->report_metadata_post == NULL) + return NULL; + + /* metadata for all devices */ + metadata = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_free); + klass->report_metadata_post (self, metadata); + return g_steal_pointer (&metadata); +} + /** * fu_device_incorporate: * @self: A #FuDevice diff --git a/libfwupdplugin/fu-device.h b/libfwupdplugin/fu-device.h index d7d310d92..f2c91850f 100644 --- a/libfwupdplugin/fu-device.h +++ b/libfwupdplugin/fu-device.h @@ -64,8 +64,12 @@ struct _FuDeviceClass gboolean (*cleanup) (FuDevice *self, FwupdInstallFlags flags, GError **error); + void (*report_metadata_pre) (FuDevice *self, + GHashTable *metadata); + void (*report_metadata_post)(FuDevice *self, + GHashTable *metadata); /*< private >*/ - gpointer padding[16]; + gpointer padding[14]; }; /** @@ -317,3 +321,5 @@ gboolean fu_device_retry (FuDevice *self, guint count, gpointer user_data, GError **error); +GHashTable *fu_device_report_metadata_pre (FuDevice *self); +GHashTable *fu_device_report_metadata_post (FuDevice *self); diff --git a/libfwupdplugin/fwupdplugin.map b/libfwupdplugin/fwupdplugin.map index 6fee21124..495fc94a0 100644 --- a/libfwupdplugin/fwupdplugin.map +++ b/libfwupdplugin/fwupdplugin.map @@ -585,6 +585,8 @@ LIBFWUPDPLUGIN_1.5.0 { global: fu_common_filename_glob; fu_common_is_cpu_intel; + fu_device_report_metadata_post; + fu_device_report_metadata_pre; fu_plugin_runner_add_security_attrs; fu_plugin_runner_device_added; fu_plugin_security_changed; diff --git a/plugins/uefi/fu-plugin-uefi.c b/plugins/uefi/fu-plugin-uefi.c index 01f97a156..2b4acde34 100644 --- a/plugins/uefi/fu-plugin-uefi.c +++ b/plugins/uefi/fu-plugin-uefi.c @@ -405,18 +405,7 @@ fu_plugin_update (FuPlugin *plugin, error_splash->message); } - if (!fu_device_write_firmware (device, blob_fw, flags, error)) - return FALSE; - - /* record if we had an invalid header during update */ - str = fu_uefi_missing_capsule_header (device) ? "True" : "False"; - fu_plugin_add_report_metadata (plugin, "MissingCapsuleHeader", str); - - /* where the ESP was mounted during installation */ - str = fu_device_get_metadata (device, "EspPath"); - fu_plugin_add_report_metadata (plugin, "ESPMountPoint", str); - - return TRUE; + return fu_device_write_firmware (device, blob_fw, flags, error); } static gboolean diff --git a/plugins/uefi/fu-uefi-device.c b/plugins/uefi/fu-uefi-device.c index 65d2ac539..4d90fcd0f 100644 --- a/plugins/uefi/fu-uefi-device.c +++ b/plugins/uefi/fu-uefi-device.c @@ -116,6 +116,36 @@ fu_uefi_device_to_string (FuDevice *device, guint idt, GString *str) fu_device_get_metadata_boolean (device, "RequireShimForSecureBoot")); } +static void +fu_uefi_device_report_metadata_pre (FuDevice *device, GHashTable *metadata) +{ + FuUefiDevice *self = FU_UEFI_DEVICE (device); + + /* record if we had an invalid header during update */ + g_hash_table_insert (metadata, + g_strdup ("MissingCapsuleHeader"), + g_strdup (self->missing_header ? "True" : "False")); + + /* where the ESP was mounted during installation */ + g_hash_table_insert (metadata, + g_strdup ("EspPath"), + g_strdup (fu_device_get_metadata (device, "EspPath"))); +} + +static void +fu_uefi_device_report_metadata_post (FuDevice *device, GHashTable *metadata) +{ + FuUefiDevice *self = FU_UEFI_DEVICE (device); + + /* the actual last_attempt values */ + g_hash_table_insert (metadata, + g_strdup ("LastAttemptStatus"), + g_strdup_printf ("0x%x", self->last_attempt_status)); + g_hash_table_insert (metadata, + g_strdup ("LastAttemptVersion"), + g_strdup_printf ("0x%x", self->last_attempt_version)); +} + FuUefiDeviceKind fu_uefi_device_get_kind (FuUefiDevice *self) { @@ -343,13 +373,6 @@ fu_uefi_device_fixup_firmware (FuDevice *device, GBytes *fw, GError **error) } } -gboolean -fu_uefi_missing_capsule_header (FuDevice *device) -{ - FuUefiDevice *self = FU_UEFI_DEVICE (device); - return self->missing_header; -} - gboolean fu_uefi_device_write_update_info (FuUefiDevice *self, const gchar *filename, @@ -758,6 +781,8 @@ fu_uefi_device_class_init (FuUefiDeviceClass *klass) klass_device->prepare = fu_uefi_device_prepare; klass_device->write_firmware = fu_uefi_device_write_firmware; klass_device->cleanup = fu_uefi_device_cleanup; + klass_device->report_metadata_pre = fu_uefi_device_report_metadata_pre; + klass_device->report_metadata_post = fu_uefi_device_report_metadata_post; } FuUefiDevice * diff --git a/plugins/uefi/fu-uefi-device.h b/plugins/uefi/fu-uefi-device.h index 8a771d096..d9e7ffd98 100644 --- a/plugins/uefi/fu-uefi-device.h +++ b/plugins/uefi/fu-uefi-device.h @@ -54,7 +54,6 @@ const gchar *fu_uefi_device_kind_to_string (FuUefiDeviceKind kind); const gchar *fu_uefi_device_status_to_string (FuUefiDeviceStatus status); FuUefiUpdateInfo *fu_uefi_device_load_update_info (FuUefiDevice *self, GError **error); -gboolean fu_uefi_missing_capsule_header (FuDevice *device); gboolean fu_uefi_device_write_update_info (FuUefiDevice *self, const gchar *filename, const gchar *varname, diff --git a/plugins/vli/fu-vli-device.c b/plugins/vli/fu-vli-device.c index d83f38c6f..ad1292d22 100644 --- a/plugins/vli/fu-vli-device.c +++ b/plugins/vli/fu-vli-device.c @@ -631,6 +631,15 @@ fu_vli_device_set_quirk_kv (FuDevice *device, return FALSE; } +static void +fu_vli_device_report_metadata_pre (FuDevice *device, GHashTable *metadata) +{ + FuVliDevice *self = FU_VLI_DEVICE (device); + g_hash_table_insert (metadata, + g_strdup ("GType"), + g_strdup (G_OBJECT_TYPE_NAME (self))); +} + static void fu_vli_device_get_property (GObject *object, guint prop_id, GValue *value, GParamSpec *pspec) { @@ -697,4 +706,5 @@ fu_vli_device_class_init (FuVliDeviceClass *klass) klass_device->to_string = fu_vli_device_to_string; klass_device->set_quirk_kv = fu_vli_device_set_quirk_kv; klass_device->setup = fu_vli_device_setup; + klass_device->report_metadata_pre = fu_vli_device_report_metadata_pre; } diff --git a/src/fu-engine.c b/src/fu-engine.c index 31002ae42..59cb76e60 100644 --- a/src/fu-engine.c +++ b/src/fu-engine.c @@ -1681,10 +1681,14 @@ fu_engine_install_tasks (FuEngine *self, } static FwupdRelease * -fu_engine_create_release_metadata (FuEngine *self, FuPlugin *plugin, GError **error) +fu_engine_create_release_metadata (FuEngine *self, + FuDevice *device, + FuPlugin *plugin, + GError **error) { GPtrArray *metadata_sources; g_autoptr(FwupdRelease) release = fwupd_release_new (); + g_autoptr(GHashTable) metadata_device = NULL; g_autoptr(GHashTable) metadata_hash = NULL; /* build the version metadata */ @@ -1693,6 +1697,9 @@ fu_engine_create_release_metadata (FuEngine *self, FuPlugin *plugin, GError **er return NULL; fwupd_release_add_metadata (release, metadata_hash); fwupd_release_add_metadata (release, fu_plugin_get_report_metadata (plugin)); + metadata_device = fu_device_report_metadata_pre (device); + if (metadata_device != NULL) + fwupd_release_add_metadata (release, metadata_device); /* allow other plugins to contribute metadata too */ metadata_sources = fu_plugin_get_rules (plugin, FU_PLUGIN_RULE_METADATA_SOURCE); @@ -1939,7 +1946,7 @@ fu_engine_install_release (FuEngine *self, /* add device to database */ if ((flags & FWUPD_INSTALL_FLAG_NO_HISTORY) == 0) { g_autoptr(FwupdRelease) release_tmp = NULL; - release_tmp = fu_engine_create_release_metadata (self, plugin, error); + release_tmp = fu_engine_create_release_metadata (self, device, plugin, error); if (release_tmp == NULL) return FALSE; tmp = xb_node_query_text (component, @@ -2174,7 +2181,7 @@ fu_engine_install (FuEngine *self, if (!fu_plugin_runner_update_prepare (plugin, flags, device, error)) return FALSE; } - release_tmp = fu_engine_create_release_metadata (self, plugin, error); + release_tmp = fu_engine_create_release_metadata (self, device, plugin, error); if (release_tmp == NULL) return FALSE; fwupd_release_set_version (release_tmp, version_rel); @@ -5693,6 +5700,7 @@ fu_engine_update_history_device (FuEngine *self, FuDevice *dev_history, GError * FwupdRelease *rel_history; g_autofree gchar *btime = NULL; g_autoptr(FuDevice) dev = NULL; + g_autoptr(GHashTable) metadata_device = NULL; /* is in the device list */ dev = fu_device_list_get_by_id (self->device_list, @@ -5721,6 +5729,19 @@ fu_engine_update_history_device (FuEngine *self, FuDevice *dev_history, GError * return TRUE; } + /* save any additional report metadata */ + metadata_device = fu_device_report_metadata_post (dev); + if (metadata_device != NULL && g_hash_table_size (metadata_device) > 0) { + fwupd_release_add_metadata (rel_history, metadata_device); + if (!fu_history_set_device_metadata (self->history, + fu_device_get_id (dev_history), + fwupd_release_get_metadata (rel_history), + error)) { + g_prefix_error (error, "failed to set metadata: "); + return FALSE; + } + } + /* the system is running with the new firmware version */ if (fu_common_vercmp_full (fu_device_get_version (dev), fwupd_release_get_version (rel_history), From 6d9ae625ed222ef211a3e9566ff7b217702e3658 Mon Sep 17 00:00:00 2001 From: Richard Hughes Date: Tue, 16 Jun 2020 15:20:23 +0100 Subject: [PATCH 162/607] trivial: Move the report success report to common code This would allow us to use it from fwupdagent in the future. --- src/fu-util-common.c | 110 +++++++++++++++++++++++++++++++++++++++++ src/fu-util-common.h | 6 +++ src/fu-util.c | 115 ++++++------------------------------------- 3 files changed, 130 insertions(+), 101 deletions(-) diff --git a/src/fu-util-common.c b/src/fu-util-common.c index a2ceca81c..553f586f9 100644 --- a/src/fu-util-common.c +++ b/src/fu-util-common.c @@ -1647,3 +1647,113 @@ fu_util_security_attrs_to_string (GPtrArray *attrs) return g_string_free (str, FALSE); } + +gboolean +fu_util_send_report (SoupSession *soup_session, + const gchar *report_uri, + const gchar *data, + const gchar *sig, + gchar **uri, /* (nullable) (out) */ + GError **error) +{ + const gchar *server_msg = NULL; + guint status_code; + JsonNode *json_root; + JsonObject *json_object; + g_autoptr(JsonParser) json_parser = NULL; + g_autoptr(SoupMessage) msg = NULL; + + /* POST request */ + if (sig != NULL) { + g_autoptr(SoupMultipart) mp = NULL; + mp = soup_multipart_new (SOUP_FORM_MIME_TYPE_MULTIPART); + soup_multipart_append_form_string (mp, "payload", data); + soup_multipart_append_form_string (mp, "signature", sig); + msg = soup_form_request_new_from_multipart (report_uri, mp); + } else { + msg = soup_message_new (SOUP_METHOD_POST, report_uri); + soup_message_set_request (msg, "application/json; charset=utf-8", + SOUP_MEMORY_COPY, data, strlen (data)); + } + status_code = soup_session_send_message (soup_session, msg); + g_debug ("server returned: %s", msg->response_body->data); + + /* server returned nothing, and probably exploded in a ball of flames */ + if (msg->response_body->length == 0) { + g_set_error (error, + FWUPD_ERROR, + FWUPD_ERROR_INVALID_FILE, + "Failed to upload to %s: %s", + report_uri, soup_status_get_phrase (status_code)); + return FALSE; + } + + /* parse JSON reply */ + json_parser = json_parser_new (); + if (!json_parser_load_from_data (json_parser, + msg->response_body->data, + msg->response_body->length, + error)) { + g_autofree gchar *str = g_strndup (msg->response_body->data, + msg->response_body->length); + g_prefix_error (error, "Failed to parse JSON response from '%s': ", str); + return FALSE; + } + json_root = json_parser_get_root (json_parser); + if (json_root == NULL) { + g_autofree gchar *str = g_strndup (msg->response_body->data, + msg->response_body->length); + g_set_error (error, + FWUPD_ERROR, + FWUPD_ERROR_PERMISSION_DENIED, + "JSON response was malformed: '%s'", str); + return FALSE; + } + json_object = json_node_get_object (json_root); + if (json_object == NULL) { + g_autofree gchar *str = g_strndup (msg->response_body->data, + msg->response_body->length); + g_set_error (error, + FWUPD_ERROR, + FWUPD_ERROR_PERMISSION_DENIED, + "JSON response object was malformed: '%s'", str); + return FALSE; + } + + /* get any optional server message */ + if (json_object_has_member (json_object, "msg")) + server_msg = json_object_get_string_member (json_object, "msg"); + + /* server reported failed */ + if (!json_object_get_boolean_member (json_object, "success")) { + g_set_error (error, + FWUPD_ERROR, + FWUPD_ERROR_PERMISSION_DENIED, + "Server rejected report: %s", + server_msg != NULL ? server_msg : "unspecified"); + return FALSE; + } + + /* server wanted us to see the message */ + if (server_msg != NULL) { + g_debug ("server message: %s", server_msg); + if (g_strstr_len (server_msg, -1, "known issue") != NULL && + json_object_has_member (json_object, "uri")) { + if (uri != NULL) + *uri = g_strdup (json_object_get_string_member (json_object, "uri")); + } + } + + /* fall back to HTTP status codes in case the server is offline */ + if (!SOUP_STATUS_IS_SUCCESSFUL (status_code)) { + g_set_error (error, + FWUPD_ERROR, + FWUPD_ERROR_INVALID_FILE, + "Failed to upload to %s: %s", + report_uri, soup_status_get_phrase (status_code)); + return FALSE; + } + + /* success */ + return TRUE; +} diff --git a/src/fu-util-common.h b/src/fu-util-common.h index 77ca43133..31c114715 100644 --- a/src/fu-util-common.h +++ b/src/fu-util-common.h @@ -78,3 +78,9 @@ gchar *fu_util_release_to_string (FwupdRelease *rel, gchar *fu_util_remote_to_string (FwupdRemote *remote, guint idt); gchar *fu_util_security_attrs_to_string (GPtrArray *attrs); +gboolean fu_util_send_report (SoupSession *soup_session, + const gchar *report_uri, + const gchar *data, + const gchar *sig, + gchar **uri, + GError **error); diff --git a/src/fu-util.c b/src/fu-util.c index 2e1abe3f3..3dc8f8814 100644 --- a/src/fu-util.c +++ b/src/fu-util.c @@ -678,15 +678,9 @@ fu_util_report_history_for_remote (FuUtilPrivate *priv, GPtrArray *devices, GError **error) { - JsonNode *json_root; - JsonObject *json_object; - const gchar *server_msg = NULL; - guint status_code; - const gchar *report_uri; g_autofree gchar *data = NULL; g_autofree gchar *sig = NULL; - g_autoptr(JsonParser) json_parser = NULL; - g_autoptr(SoupMessage) msg = NULL; + g_autofree gchar *uri = NULL; g_autoptr(FwupdRemote) remote = NULL; /* convert to JSON */ @@ -707,11 +701,10 @@ fu_util_report_history_for_remote (FuUtilPrivate *priv, NULL, error); if (remote == NULL) return FALSE; - report_uri = fwupd_remote_get_report_uri (remote); /* ask for permission */ if (!priv->assume_yes && !fwupd_remote_get_automatic_reports (remote)) { - fu_util_print_data (_("Target"), report_uri); + fu_util_print_data (_("Target"), fwupd_remote_get_report_uri (remote)); fu_util_print_data (_("Payload"), data); if (sig != NULL) fu_util_print_data (_("Signature"), sig); @@ -725,101 +718,21 @@ fu_util_report_history_for_remote (FuUtilPrivate *priv, } } - /* POST request */ - if (sig != NULL) { - g_autoptr(SoupMultipart) mp = NULL; - mp = soup_multipart_new (SOUP_FORM_MIME_TYPE_MULTIPART); - soup_multipart_append_form_string (mp, "payload", data); - soup_multipart_append_form_string (mp, "signature", sig); - msg = soup_form_request_new_from_multipart (report_uri, mp); - } else { - msg = soup_message_new (SOUP_METHOD_POST, report_uri); - soup_message_set_request (msg, "application/json; charset=utf-8", - SOUP_MEMORY_COPY, data, strlen (data)); - } - status_code = soup_session_send_message (priv->soup_session, msg); - g_debug ("server returned: %s", msg->response_body->data); - - /* server returned nothing, and probably exploded in a ball of flames */ - if (msg->response_body->length == 0) { - g_set_error (error, - FWUPD_ERROR, - FWUPD_ERROR_INVALID_FILE, - "Failed to upload to %s: %s", - report_uri, soup_status_get_phrase (status_code)); - return FALSE; - } - - /* parse JSON reply */ - json_parser = json_parser_new (); - if (!json_parser_load_from_data (json_parser, - msg->response_body->data, - msg->response_body->length, - error)) { - g_autofree gchar *str = g_strndup (msg->response_body->data, - msg->response_body->length); - g_prefix_error (error, "Failed to parse JSON response from '%s': ", str); - return FALSE; - } - json_root = json_parser_get_root (json_parser); - if (json_root == NULL) { - g_autofree gchar *str = g_strndup (msg->response_body->data, - msg->response_body->length); - g_set_error (error, - FWUPD_ERROR, - FWUPD_ERROR_PERMISSION_DENIED, - "JSON response was malformed: '%s'", str); - return FALSE; - } - json_object = json_node_get_object (json_root); - if (json_object == NULL) { - g_autofree gchar *str = g_strndup (msg->response_body->data, - msg->response_body->length); - g_set_error (error, - FWUPD_ERROR, - FWUPD_ERROR_PERMISSION_DENIED, - "JSON response object was malformed: '%s'", str); - return FALSE; - } - - /* get any optional server message */ - if (json_object_has_member (json_object, "msg")) - server_msg = json_object_get_string_member (json_object, "msg"); - - /* server reported failed */ - if (!json_object_get_boolean_member (json_object, "success")) { - g_set_error (error, - FWUPD_ERROR, - FWUPD_ERROR_PERMISSION_DENIED, - "Server rejected report: %s", - server_msg != NULL ? server_msg : "unspecified"); - return FALSE; - } - - /* server wanted us to see the message */ - if (server_msg != NULL) { - if (g_strstr_len (server_msg, -1, "known issue") != NULL && - json_object_has_member (json_object, "uri")) { - g_print ("%s %s\n", - /* TRANSLATORS: the server sent the user a small message */ - _("Update failure is a known issue, visit this URL for more information:"), - json_object_get_string_member (json_object, "uri")); - } else { - /* TRANSLATORS: the server sent the user a small message */ - g_print ("%s %s\n", _("Upload message:"), server_msg); - } - } - - /* fall back to HTTP status codes in case the server is offline */ - if (!SOUP_STATUS_IS_SUCCESSFUL (status_code)) { - g_set_error (error, - FWUPD_ERROR, - FWUPD_ERROR_INVALID_FILE, - "Failed to upload to %s: %s", - report_uri, soup_status_get_phrase (status_code)); + /* POST request and parse reply */ + if (!fu_util_send_report (priv->soup_session, + fwupd_remote_get_report_uri (remote), + data, sig, &uri, error)) return FALSE; + + /* server wanted us to see a message */ + if (uri != NULL) { + g_print ("%s %s\n", + /* TRANSLATORS: the server sent the user a small message */ + _("Update failure is a known issue, visit this URL for more information:"), + uri); } + /* success */ return TRUE; } From 1ec96e31f50697b34e5b322161bedef17d3f491f Mon Sep 17 00:00:00 2001 From: Richard Hughes Date: Tue, 16 Jun 2020 21:14:37 +0100 Subject: [PATCH 163/607] Allow plugins to set remove delay only on the child Force the FuDevice parent to have the largest of the child removal delays. This avoids each plugin enumerating the children (which may not even be added yet) to increase the length of the allowed parent delay. --- libfwupdplugin/fu-device.c | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/libfwupdplugin/fu-device.c b/libfwupdplugin/fu-device.c index 3dfb23780..64a8723af 100644 --- a/libfwupdplugin/fu-device.c +++ b/libfwupdplugin/fu-device.c @@ -770,6 +770,17 @@ fu_device_add_child (FuDevice *self, FuDevice *child) } g_ptr_array_add (priv->children, g_object_ref (child)); + /* ensure the parent has the MAX() of the childrens removal delay */ + for (guint i = 0; i < priv->children->len; i++) { + FuDevice *child_tmp = g_ptr_array_index (priv->children, i); + guint remove_delay = fu_device_get_remove_delay (child_tmp); + if (remove_delay > priv->remove_delay) { + g_debug ("setting remove delay to %u as child is greater than %u", + remove_delay, priv->remove_delay); + priv->remove_delay = remove_delay; + } + } + /* copy from main device if unset */ if (fu_device_get_physical_id (child) == NULL && fu_device_get_physical_id (self) != NULL) From a8610c30277fa3ad52d44226b44e55722b4701d2 Mon Sep 17 00:00:00 2001 From: Richard Hughes Date: Tue, 16 Jun 2020 21:19:21 +0100 Subject: [PATCH 164/607] vli: Do not use GUID matching for the MSP device Not strictly required, but it makes the FuDeviceList operation much simpler. --- plugins/vli/fu-vli-usbhub-i2c-device.c | 1 + 1 file changed, 1 insertion(+) diff --git a/plugins/vli/fu-vli-usbhub-i2c-device.c b/plugins/vli/fu-vli-usbhub-i2c-device.c index a22c5c212..760e723ca 100644 --- a/plugins/vli/fu-vli-usbhub-i2c-device.c +++ b/plugins/vli/fu-vli-usbhub-i2c-device.c @@ -275,6 +275,7 @@ fu_vli_usbhub_i2c_device_init (FuVliUsbhubI2cDevice *self) fu_device_add_icon (FU_DEVICE (self), "audio-card"); fu_device_set_protocol (FU_DEVICE (self), "com.vli.i2c"); fu_device_add_flag (FU_DEVICE (self), FWUPD_DEVICE_FLAG_UPDATABLE); + fu_device_add_flag (FU_DEVICE (self), FWUPD_DEVICE_FLAG_NO_GUID_MATCHING); fu_device_set_version_format (FU_DEVICE (self), FWUPD_VERSION_FORMAT_PAIR); fu_device_set_logical_id (FU_DEVICE (self), "I2C"); fu_device_set_summary (FU_DEVICE (self), "I²C Dock Management Device"); From 33b0f48b6ffe2c8c055bf1389551c80cb9fef20f Mon Sep 17 00:00:00 2001 From: Richard Hughes Date: Tue, 16 Jun 2020 21:28:18 +0100 Subject: [PATCH 165/607] vli: Wait for the root device to be replugged when updating the MSP430 The MSP device is a virtual child of the USB hub. --- plugins/vli/fu-vli-usbhub-i2c-device.c | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/plugins/vli/fu-vli-usbhub-i2c-device.c b/plugins/vli/fu-vli-usbhub-i2c-device.c index 760e723ca..23566b507 100644 --- a/plugins/vli/fu-vli-usbhub-i2c-device.c +++ b/plugins/vli/fu-vli-usbhub-i2c-device.c @@ -250,11 +250,9 @@ fu_vli_usbhub_i2c_device_write_firmware (FuDevice *device, fu_device_set_status (device, FWUPD_STATUS_DEVICE_RESTART); fu_device_set_progress (device, 0); - /* this is unusual, but the MSP device reboot takes down the entire hub - * for ~60 seconds and we don't want the parent device removing us */ + /* as soon as the parent comes back we can query the child */ root = fu_device_get_root (device); - fu_device_add_flag (device, FWUPD_DEVICE_FLAG_WAIT_FOR_REPLUG); - fu_device_set_remove_delay (root, 120000); + fu_device_add_flag (root, FWUPD_DEVICE_FLAG_WAIT_FOR_REPLUG); /* success */ return TRUE; @@ -279,6 +277,9 @@ fu_vli_usbhub_i2c_device_init (FuVliUsbhubI2cDevice *self) fu_device_set_version_format (FU_DEVICE (self), FWUPD_VERSION_FORMAT_PAIR); fu_device_set_logical_id (FU_DEVICE (self), "I2C"); fu_device_set_summary (FU_DEVICE (self), "I²C Dock Management Device"); + + /* the MSP device reboot takes down the entire hub for ~60 seconds */ + fu_device_set_remove_delay (FU_DEVICE (self), 120 * 1000); } static void From 8012fb3c8df37ecdea61d58c8b3b8c017c9298a0 Mon Sep 17 00:00:00 2001 From: Mario Limonciello Date: Wed, 17 Jun 2020 11:39:33 -0500 Subject: [PATCH 166/607] trivial: dell-dock: clarify the pending update message (#2185) To a user it's not obvious if being unplugged means host or AC adapter. Unplugging from AC adapter will prevent the dock from completing an update. --- plugins/dell-dock/fu-dell-dock-i2c-ec.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/plugins/dell-dock/fu-dell-dock-i2c-ec.c b/plugins/dell-dock/fu-dell-dock-i2c-ec.c index eebdf6615..16dbc9166 100644 --- a/plugins/dell-dock/fu-dell-dock-i2c-ec.c +++ b/plugins/dell-dock/fu-dell-dock-i2c-ec.c @@ -523,9 +523,9 @@ fu_dell_dock_ec_get_dock_data (FuDevice *device, fu_device_add_flag (device, FWUPD_DEVICE_FLAG_UPDATABLE); } else { fu_device_add_flag (device, FWUPD_DEVICE_FLAG_NEEDS_ACTIVATION); - fu_device_set_update_error (device, "An update is pending " + fu_device_set_update_error (device, "A pending update will be completed " "next time the dock is " - "unplugged"); + "unplugged from your computer"); } } else { g_warning ("This utility does not support this board, disabling updates for %s", From 19a60e62bc20cef923e52cde3fe579f397b8ccdc Mon Sep 17 00:00:00 2001 From: Richard Hughes Date: Wed, 17 Jun 2020 18:31:18 +0100 Subject: [PATCH 167/607] trivial: Check for the _UNKNOWN enum when mashalling to GVariant --- libfwupd/fwupd-security-attr.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libfwupd/fwupd-security-attr.c b/libfwupd/fwupd-security-attr.c index 6e618f894..9a4297b35 100644 --- a/libfwupd/fwupd-security-attr.c +++ b/libfwupd/fwupd-security-attr.c @@ -537,7 +537,7 @@ fwupd_security_attr_to_variant (FwupdSecurityAttr *self) FWUPD_RESULT_KEY_HSI_LEVEL, g_variant_new_uint32 (priv->level)); } - if (priv->result > 0) { + if (priv->result != FWUPD_SECURITY_ATTR_RESULT_UNKNOWN) { g_variant_builder_add (&builder, "{sv}", FWUPD_RESULT_KEY_HSI_RESULT, g_variant_new_uint32 (priv->result)); From 87143298cd212e6bf298a488e0eff359b90c1a9d Mon Sep 17 00:00:00 2001 From: Richard Hughes Date: Wed, 17 Jun 2020 18:32:01 +0100 Subject: [PATCH 168/607] pci-mei: Set the security attr result for a passed version --- plugins/pci-mei/fu-plugin-pci-mei.c | 1 + 1 file changed, 1 insertion(+) diff --git a/plugins/pci-mei/fu-plugin-pci-mei.c b/plugins/pci-mei/fu-plugin-pci-mei.c index c8684d239..ac7cc2c54 100644 --- a/plugins/pci-mei/fu-plugin-pci-mei.c +++ b/plugins/pci-mei/fu-plugin-pci-mei.c @@ -226,6 +226,7 @@ fu_plugin_add_security_attrs_csme_version (FuPlugin *plugin, FuSecurityAttrs *at } /* success */ + fwupd_security_attr_set_result (attr, FWUPD_SECURITY_ATTR_RESULT_VALID); fwupd_security_attr_add_flag (attr, FWUPD_SECURITY_ATTR_FLAG_SUCCESS); } From fe862a1d1b312349d8b447b74ce63b419ff82ca6 Mon Sep 17 00:00:00 2001 From: Mario Limonciello Date: Wed, 17 Jun 2020 13:19:01 -0500 Subject: [PATCH 169/607] tpm-eventlog: Always look at all supported algorithms This will effectively mean that both sha1 and sha256 results are sent back to uefi plugin for analysis. --- plugins/tpm-eventlog/fu-self-test.c | 4 ++- plugins/tpm-eventlog/fu-tpm-eventlog-parser.c | 26 +++++++++---------- plugins/tpm-eventlog/fu-tpm-eventlog-parser.h | 1 - plugins/tpm-eventlog/fu-tpm-eventlog.c | 1 - 4 files changed, 15 insertions(+), 17 deletions(-) diff --git a/plugins/tpm-eventlog/fu-self-test.c b/plugins/tpm-eventlog/fu-self-test.c index 0e238f63f..73fcaff48 100644 --- a/plugins/tpm-eventlog/fu-self-test.c +++ b/plugins/tpm-eventlog/fu-self-test.c @@ -75,9 +75,11 @@ fu_test_tpm_eventlog_parse_v2_func (void) pcr0s = fu_tpm_eventlog_device_get_checksums (dev, 0, &error); g_assert_no_error (error); g_assert_nonnull (pcr0s); - g_assert_cmpint (pcr0s->len, ==, 1); + g_assert_cmpint (pcr0s->len, ==, 2); tmp = g_ptr_array_index (pcr0s, 0); g_assert_cmpstr (tmp, ==, "ebead4b31c7c49e193c440cd6ee90bc1b61a3ca6"); + tmp = g_ptr_array_index (pcr0s, 1); + g_assert_cmpstr (tmp, ==, "6d9fed68092cfb91c9552bcb7879e75e1df36efd407af67690dc3389a5722fab"); } int diff --git a/plugins/tpm-eventlog/fu-tpm-eventlog-parser.c b/plugins/tpm-eventlog/fu-tpm-eventlog-parser.c index 1f133b7c0..5b6e48eee 100644 --- a/plugins/tpm-eventlog/fu-tpm-eventlog-parser.c +++ b/plugins/tpm-eventlog/fu-tpm-eventlog-parser.c @@ -110,6 +110,7 @@ fu_tpm_eventlog_parser_parse_blob_v2 (const guint8 *buf, gsize bufsz, for (guint i = 0; i < digestcnt; i++) { guint16 alg_type = 0; guint32 alg_size = 0; + g_autofree guint8 *digest = NULL; /* get checksum type */ if (!fu_common_read_uint16_safe (buf, bufsz, idx, @@ -127,22 +128,19 @@ fu_tpm_eventlog_parser_parse_blob_v2 (const guint8 *buf, gsize bufsz, /* build checksum */ idx += sizeof(alg_type); - if (alg_type == TPM2_ALG_SHA1 || - flags & FU_TPM_EVENTLOG_PARSER_FLAG_ALL_ALGS) { - g_autofree guint8 *digest = g_malloc0 (alg_size); - /* copy hash */ - if (!fu_memcpy_safe (digest, alg_size, 0x0, /* dst */ - buf, bufsz, idx, /* src */ - alg_size, error)) - return NULL; + /* copy hash */ + digest = g_malloc0 (alg_size); + if (!fu_memcpy_safe (digest, alg_size, 0x0, /* dst */ + buf, bufsz, idx, /* src */ + alg_size, error)) + return NULL; - /* save this for analysis */ - if (alg_type == TPM2_ALG_SHA1) - checksum_sha1 = g_bytes_new_take (g_steal_pointer (&digest), alg_size); - else if (alg_type == TPM2_ALG_SHA256) - checksum_sha256 = g_bytes_new_take (g_steal_pointer (&digest), alg_size); - } + /* save this for analysis */ + if (alg_type == TPM2_ALG_SHA1) + checksum_sha1 = g_bytes_new_take (g_steal_pointer (&digest), alg_size); + else if (alg_type == TPM2_ALG_SHA256) + checksum_sha256 = g_bytes_new_take (g_steal_pointer (&digest), alg_size); /* next block */ idx += alg_size; diff --git a/plugins/tpm-eventlog/fu-tpm-eventlog-parser.h b/plugins/tpm-eventlog/fu-tpm-eventlog-parser.h index 74c3ccd12..61a1f4d65 100644 --- a/plugins/tpm-eventlog/fu-tpm-eventlog-parser.h +++ b/plugins/tpm-eventlog/fu-tpm-eventlog-parser.h @@ -13,7 +13,6 @@ typedef enum { FU_TPM_EVENTLOG_PARSER_FLAG_NONE = 0, FU_TPM_EVENTLOG_PARSER_FLAG_ALL_PCRS = 1 << 0, - FU_TPM_EVENTLOG_PARSER_FLAG_ALL_ALGS = 1 << 1, FU_TPM_EVENTLOG_PARSER_FLAG_LAST } FuTpmEventlogParserFlags; diff --git a/plugins/tpm-eventlog/fu-tpm-eventlog.c b/plugins/tpm-eventlog/fu-tpm-eventlog.c index 05f84118b..f8c661efe 100644 --- a/plugins/tpm-eventlog/fu-tpm-eventlog.c +++ b/plugins/tpm-eventlog/fu-tpm-eventlog.c @@ -42,7 +42,6 @@ fu_tmp_eventlog_process (const gchar *fn, gint pcr, GError **error) if (!g_file_get_contents (fn, (gchar **) &buf, &bufsz, error)) return FALSE; items = fu_tpm_eventlog_parser_new (buf, bufsz, - FU_TPM_EVENTLOG_PARSER_FLAG_ALL_ALGS | FU_TPM_EVENTLOG_PARSER_FLAG_ALL_PCRS, error); if (items == NULL) From 9122999bfb952d1e48735b51f34acff531aafc7d Mon Sep 17 00:00:00 2001 From: Mario Limonciello Date: Wed, 17 Jun 2020 13:27:48 -0500 Subject: [PATCH 170/607] tpm-eventlog: verify all algorithms, not just one of them This will help to suss out any problems that are specific to sha1 or sha256 eventlog calculation. --- plugins/tpm-eventlog/fu-plugin-tpm-eventlog.c | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) diff --git a/plugins/tpm-eventlog/fu-plugin-tpm-eventlog.c b/plugins/tpm-eventlog/fu-plugin-tpm-eventlog.c index e6e69577d..7d2951ea6 100644 --- a/plugins/tpm-eventlog/fu-plugin-tpm-eventlog.c +++ b/plugins/tpm-eventlog/fu-plugin-tpm-eventlog.c @@ -115,19 +115,25 @@ fu_plugin_device_registered_uefi (FuPlugin *plugin, FuDevice *device) for (guint i = 0; i < checksums->len; i++) { const gchar *checksum = g_ptr_array_index (checksums, i); + data->reconstructed = FALSE; for (guint j = 0; j < data->pcr0s->len; j++) { const gchar *checksum_tmp = g_ptr_array_index (data->pcr0s, j); + /* skip unless same algorithm */ + if (strlen (checksum) != strlen (checksum_tmp)) + continue; if (g_strcmp0 (checksum, checksum_tmp) == 0) { data->reconstructed = TRUE; - return; + break; } } + /* check at least one reconstruction for this algorithm */ + if (!data->reconstructed) { + fu_device_set_update_message (device, + "TPM PCR0 differs from reconstruction, " + "please see https://github.com/fwupd/fwupd/wiki/TPM-PCR0-differs-from-reconstruction"); + return; + } } - - /* urgh, this is unexpected */ - fu_device_set_update_message (device, - "TPM PCR0 differs from reconstruction, " - "please see https://github.com/fwupd/fwupd/wiki/TPM-PCR0-differs-from-reconstruction"); } void From 28bcecc028142bb828ca392614fc68531ed4fba4 Mon Sep 17 00:00:00 2001 From: Mario Limonciello Date: Wed, 17 Jun 2020 13:47:29 -0500 Subject: [PATCH 171/607] trivial: fwupdtpmevlog: make clearer which algorithm is used --- plugins/tpm-eventlog/fu-tpm-eventlog.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/plugins/tpm-eventlog/fu-tpm-eventlog.c b/plugins/tpm-eventlog/fu-tpm-eventlog.c index f8c661efe..4a48b552a 100644 --- a/plugins/tpm-eventlog/fu-tpm-eventlog.c +++ b/plugins/tpm-eventlog/fu-tpm-eventlog.c @@ -9,6 +9,7 @@ #include "config.h" #include +#include "fwupd-common-private.h" #include #include #include @@ -70,10 +71,12 @@ fu_tmp_eventlog_process (const gchar *fn, gint pcr, GError **error) for (guint j = 0; j < pcrs->len; j++) { const gchar *csum = g_ptr_array_index (pcrs, j); g_autofree gchar *title = NULL; + g_autofree gchar *pretty = NULL; if (pcr >= 0 && i != (guint) pcr) continue; - title = g_strdup_printf ("%x", i); - fu_common_string_append_kv (str, 1, title, csum); + title = g_strdup_printf ("PCR %x", i); + pretty = fwupd_checksum_format_for_display (csum); + fu_common_string_append_kv (str, 1, title, pretty); } } From f41222741538e936a372c2341431a62b9927ff21 Mon Sep 17 00:00:00 2001 From: Mario Limonciello Date: Wed, 17 Jun 2020 13:51:13 -0500 Subject: [PATCH 172/607] trivial: don't show reconstruction errors if uefi device is missing The system must support UEFI capsule updates in order to measure this. (Fixes: #2181) --- plugins/tpm-eventlog/fu-plugin-tpm-eventlog.c | 10 ++++++---- plugins/tpm-eventlog/fu-tpm-eventlog.c | 2 +- 2 files changed, 7 insertions(+), 5 deletions(-) diff --git a/plugins/tpm-eventlog/fu-plugin-tpm-eventlog.c b/plugins/tpm-eventlog/fu-plugin-tpm-eventlog.c index 7d2951ea6..b3641333a 100644 --- a/plugins/tpm-eventlog/fu-plugin-tpm-eventlog.c +++ b/plugins/tpm-eventlog/fu-plugin-tpm-eventlog.c @@ -15,7 +15,8 @@ struct FuPluginData { GPtrArray *pcr0s; gboolean secure_boot_problem; - gboolean has_device; + gboolean has_tpm_device; + gboolean has_uefi_device; gboolean reconstructed; }; @@ -92,7 +93,7 @@ static void fu_plugin_device_registered_tpm (FuPlugin *plugin, FuDevice *device) { FuPluginData *data = fu_plugin_get_data (plugin); - data->has_device = TRUE; + data->has_tpm_device = TRUE; } static void @@ -105,6 +106,7 @@ fu_plugin_device_registered_uefi (FuPlugin *plugin, FuDevice *device) checksums = fu_device_get_checksums (device); if (checksums->len == 0) return; + data->has_uefi_device = TRUE; if (data->secure_boot_problem) { fu_device_set_update_message (device, @@ -159,7 +161,7 @@ fu_plugin_add_security_attrs (FuPlugin *plugin, FuSecurityAttrs *attrs) g_autoptr(FwupdSecurityAttr) attr = NULL; /* no TPM device */ - if (!data->has_device) + if (!data->has_tpm_device) return; /* create attr */ @@ -169,7 +171,7 @@ fu_plugin_add_security_attrs (FuPlugin *plugin, FuSecurityAttrs *attrs) fu_security_attrs_append (attrs, attr); /* check reconstructed to PCR0 */ - if (!fu_plugin_get_enabled (plugin)) { + if (!fu_plugin_get_enabled (plugin) || !data->has_uefi_device) { fwupd_security_attr_set_result (attr, FWUPD_SECURITY_ATTR_RESULT_NOT_FOUND); return; } diff --git a/plugins/tpm-eventlog/fu-tpm-eventlog.c b/plugins/tpm-eventlog/fu-tpm-eventlog.c index 4a48b552a..dce7f09d9 100644 --- a/plugins/tpm-eventlog/fu-tpm-eventlog.c +++ b/plugins/tpm-eventlog/fu-tpm-eventlog.c @@ -9,13 +9,13 @@ #include "config.h" #include -#include "fwupd-common-private.h" #include #include #include #include #include +#include "fwupd-common-private.h" #include "fu-tpm-eventlog-parser.h" static gint From 1b8047be1da9e333e2522ff248c17a5bc68a627d Mon Sep 17 00:00:00 2001 From: Mario Limonciello Date: Wed, 17 Jun 2020 15:23:13 -0500 Subject: [PATCH 173/607] trivial: fu-util: correct an assertion when no remotes configured ``` (fwupdmgr:185983): FuMain-CRITICAL **: 15:20:57.044: fu_util_time_to_str: assertion 'tmp != 0' failed ``` --- src/fu-util.c | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/src/fu-util.c b/src/fu-util.c index 3dc8f8814..1c8d6b557 100644 --- a/src/fu-util.c +++ b/src/fu-util.c @@ -1244,6 +1244,7 @@ static gboolean fu_util_check_oldest_remote (FuUtilPrivate *priv, guint64 *age_oldest, GError **error) { g_autoptr(GPtrArray) remotes = NULL; + gboolean checked = FALSE; /* get the age of the oldest enabled remotes */ remotes = fwupd_client_get_remotes (priv->client, NULL, error); @@ -1255,9 +1256,18 @@ fu_util_check_oldest_remote (FuUtilPrivate *priv, guint64 *age_oldest, GError ** continue; if (fwupd_remote_get_kind (remote) != FWUPD_REMOTE_KIND_DOWNLOAD) continue; + checked = TRUE; if (fwupd_remote_get_age (remote) > *age_oldest) *age_oldest = fwupd_remote_get_age (remote); } + if (!checked) { + g_set_error_literal (error, + FWUPD_ERROR, + FWUPD_ERROR_NOTHING_TO_DO, + /* TRANSLATORS: error message for a user who ran fwupdmgr refresh recently but no remotes */ + "No remotes enabled."); + return FALSE; + } return TRUE; } From 7d5f6b023208e4b9949027b99fc66e07c5305fe1 Mon Sep 17 00:00:00 2001 From: Mario Limonciello Date: Wed, 17 Jun 2020 16:13:53 -0500 Subject: [PATCH 174/607] dell-dock: Add more module types to the enum Unfortunately module type has more than I previously realized. The meanings that previously were applied fortunately worked for the most important case (130-180W TBT) but didn't for single C, dual C or small power (45W) cases. Since composite_prepare was trying to read and interpret these, it causes failures when these other ones are encountered. I reproduced this on a 130W adapter plugged into a single C (type 0x4). This meant the update wouldn't install since NULL was returned for the type. In case a new module ID is added later, also return an "unknown" for the metadata. --- plugins/dell-dock/fu-dell-dock-i2c-ec.c | 41 +++++++++++++++++-------- plugins/dell-dock/fu-plugin-dell-dock.c | 8 ++--- 2 files changed, 30 insertions(+), 19 deletions(-) diff --git a/plugins/dell-dock/fu-dell-dock-i2c-ec.c b/plugins/dell-dock/fu-dell-dock-i2c-ec.c index 16dbc9166..de8af0187 100644 --- a/plugins/dell-dock/fu-dell-dock-i2c-ec.c +++ b/plugins/dell-dock/fu-dell-dock-i2c-ec.c @@ -100,9 +100,13 @@ typedef struct __attribute__ ((packed)) { } FuDellDockEcQueryEntry; typedef enum { - MODULE_TYPE_SINGLE = 1, - MODULE_TYPE_DUAL, - MODULE_TYPE_TBT, + MODULE_TYPE_45_TBT = 1, + MODULE_TYPE_45, + MODULE_TYPE_130_TBT, + MODULE_TYPE_130_DP, + MODULE_TYPE_130_UNIVERSAL, + MODULE_TYPE_240_TRIN, + MODULE_TYPE_210_DUAL, } FuDellDockDockModule; typedef struct __attribute__ ((packed)) { @@ -177,14 +181,22 @@ fu_dell_dock_ec_get_module_type (FuDevice *device) { FuDellDockEc *self = FU_DELL_DOCK_EC (device); switch (self->data->module_type) { - case MODULE_TYPE_SINGLE: - return "WD19"; - case MODULE_TYPE_DUAL: - return "WD19DC"; - case MODULE_TYPE_TBT: - return "WD19TB"; + case MODULE_TYPE_45_TBT: + return "45 (TBT)"; + case MODULE_TYPE_45: + return "45"; + case MODULE_TYPE_130_TBT: + return "130 (TBT)"; + case MODULE_TYPE_130_DP: + return "130 (DP)"; + case MODULE_TYPE_130_UNIVERSAL: + return "130 (Universal)"; + case MODULE_TYPE_240_TRIN: + return "240 (Trinity)"; + case MODULE_TYPE_210_DUAL: + return "210 (Dual)"; default: - return NULL; + return "unknown"; } } @@ -195,7 +207,8 @@ fu_dell_dock_ec_needs_tbt (FuDevice *device) gboolean port0_tbt_mode = self->data->port0_dock_status & TBT_MODE_MASK; /* check for TBT module type */ - if (self->data->module_type != MODULE_TYPE_TBT) + if (self->data->module_type != MODULE_TYPE_130_TBT && + self->data->module_type != MODULE_TYPE_45_TBT) return FALSE; g_debug ("found thunderbolt dock, port mode: %d", port0_tbt_mode); @@ -393,7 +406,8 @@ fu_dell_dock_ec_get_dock_info (FuDevice *device, device_entry[i].version.version_8[3]); g_debug ("\tParsed version %s", self->mst_version); } else if (map->device_type == FU_DELL_DOCK_DEVICETYPE_TBT && - self->data->module_type == MODULE_TYPE_TBT) { + (self->data->module_type == MODULE_TYPE_130_TBT || + self->data->module_type == MODULE_TYPE_45_TBT)) { /* guard against invalid Thunderbolt version read from EC */ if (!fu_dell_dock_test_valid_byte (device_entry[i].version.version_8, 2)) { g_warning ("[EC bug] EC read invalid Thunderbolt version %08x", @@ -426,7 +440,8 @@ fu_dell_dock_ec_get_dock_info (FuDevice *device, } /* Thunderbolt SKU takes a little longer */ - if (self->data->module_type == MODULE_TYPE_TBT) { + if (self->data->module_type == MODULE_TYPE_130_TBT || + self->data->module_type == MODULE_TYPE_45_TBT) { guint64 tmp = fu_device_get_install_duration (device); fu_device_set_install_duration (device, tmp + 20); } diff --git a/plugins/dell-dock/fu-plugin-dell-dock.c b/plugins/dell-dock/fu-plugin-dell-dock.c index 41e850588..d6680b72f 100644 --- a/plugins/dell-dock/fu-plugin-dell-dock.c +++ b/plugins/dell-dock/fu-plugin-dell-dock.c @@ -173,12 +173,8 @@ fu_plugin_composite_prepare (FuPlugin *plugin, GPtrArray *devices, if (parent == NULL) return TRUE; sku = fu_dell_dock_ec_get_module_type (parent); - if (sku == NULL) { - g_set_error_literal (error, FWUPD_ERROR, FWUPD_ERROR_INTERNAL, - "unable to detect SKU"); - return FALSE; - } - fu_plugin_add_report_metadata (plugin, "DellDockSKU", sku); + if (sku != NULL) + fu_plugin_add_report_metadata (plugin, "DellDockSKU", sku); return TRUE; } From 5164e713f620972b43c54e34a653a932c968e653 Mon Sep 17 00:00:00 2001 From: Mario Limonciello Date: Thu, 18 Jun 2020 12:11:31 -0500 Subject: [PATCH 175/607] trivial: fix issue with agent on but man off Fixes: #2192 --- src/meson.build | 64 +++++++++++++++++++++++++------------------------ 1 file changed, 33 insertions(+), 31 deletions(-) diff --git a/src/meson.build b/src/meson.build index 7a0b2976a..9a8334973 100644 --- a/src/meson.build +++ b/src/meson.build @@ -166,22 +166,24 @@ fwupdtool = executable( install_dir : bindir ) -if build_daemon and get_option('man') +if get_option('man') help2man = find_program('help2man') - custom_target('fwupdmgr-man', - input : fwupdmgr, - output : 'fwupdmgr.1', - command : [ - help2man, '@INPUT@', - '--no-info', - '--output', '@OUTPUT@', - '--name', 'Firmware update manager client utility', - '--manual', 'User Commands', - '--version-string', fwupd_version, - ], - install : true, - install_dir : join_paths(mandir, 'man1'), - ) + if build_daemon + custom_target('fwupdmgr-man', + input : fwupdmgr, + output : 'fwupdmgr.1', + command : [ + help2man, '@INPUT@', + '--no-info', + '--output', '@OUTPUT@', + '--name', 'Firmware update manager client utility', + '--manual', 'User Commands', + '--version-string', fwupd_version, + ], + install : true, + install_dir : join_paths(mandir, 'man1'), + ) + endif if get_option('agent') custom_target('fwupdagent-man', input : fwupdagent, @@ -198,22 +200,22 @@ if build_daemon and get_option('man') install_dir : join_paths(mandir, 'man1'), ) endif -endif -if get_option('man') - custom_target('fwupdtool-man', - input : fwupdtool, - output : 'fwupdtool.1', - command : [ - help2man, '@INPUT@', - '--no-info', - '--output', '@OUTPUT@', - '--name', 'Standalone firmware update utility', - '--manual', 'User Commands', - '--version-string', fwupd_version, - ], - install : true, - install_dir : join_paths(mandir, 'man1'), - ) + if build_standalone + custom_target('fwupdtool-man', + input : fwupdtool, + output : 'fwupdtool.1', + command : [ + help2man, '@INPUT@', + '--no-info', + '--output', '@OUTPUT@', + '--name', 'Standalone firmware update utility', + '--manual', 'User Commands', + '--version-string', fwupd_version, + ], + install : true, + install_dir : join_paths(mandir, 'man1'), + ) + endif endif if build_daemon From e5a4d52ea12c9c00c6a2911e3a4b3ea75f85fd3d Mon Sep 17 00:00:00 2001 From: Richard Hughes Date: Thu, 18 Jun 2020 20:48:43 +0100 Subject: [PATCH 176/607] trivial: Spelling fixes from codespell --- plugins/ccgx/fu-ccgx-dmc-common.h | 2 +- plugins/ccgx/fu-ccgx-dmc-firmware.c | 2 +- plugins/ccgx/fu-ccgx-firmware.c | 2 +- plugins/ccgx/fu-ccgx-hpi-common.h | 8 ++++---- plugins/dfu/dfu-device.c | 2 +- plugins/upower/fu-plugin-upower.c | 2 +- 6 files changed, 9 insertions(+), 9 deletions(-) diff --git a/plugins/ccgx/fu-ccgx-dmc-common.h b/plugins/ccgx/fu-ccgx-dmc-common.h index 767955d29..84523a2d7 100644 --- a/plugins/ccgx/fu-ccgx-dmc-common.h +++ b/plugins/ccgx/fu-ccgx-dmc-common.h @@ -211,7 +211,7 @@ typedef struct __attribute__((packed)) { /* component ID of the device */ guint8 component_id; /* image mode of the device - single image/ dual symmetric/ dual - * assymetric image > */ + * asymmetric image > */ guint8 image_mode; /* current running image */ guint8 current_image; diff --git a/plugins/ccgx/fu-ccgx-dmc-firmware.c b/plugins/ccgx/fu-ccgx-dmc-firmware.c index 9dc51f7cf..c2227a9ab 100644 --- a/plugins/ccgx/fu-ccgx-dmc-firmware.c +++ b/plugins/ccgx/fu-ccgx-dmc-firmware.c @@ -228,7 +228,7 @@ fu_ccgx_dmc_firmware_parse_image (FuFirmware *firmware, &seg_info_offset, error)) return FALSE; - /* add image record to image record arrary */ + /* add image record to image record array */ g_ptr_array_add (self->image_records, g_steal_pointer (&img_rcd)); /* increment image offset */ diff --git a/plugins/ccgx/fu-ccgx-firmware.c b/plugins/ccgx/fu-ccgx-firmware.c index d23ac0408..03ee7eab0 100644 --- a/plugins/ccgx/fu-ccgx-firmware.c +++ b/plugins/ccgx/fu-ccgx-firmware.c @@ -24,7 +24,7 @@ struct _FuCcgxFirmware { G_DEFINE_TYPE (FuCcgxFirmware, fu_ccgx_firmware, FU_TYPE_FIRMWARE) -/* offset stored appication version for CCGx */ +/* offset stored application version for CCGx */ #define CCGX_APP_VERSION_OFFSET 228 /* 128+64+32+4 */ GPtrArray * diff --git a/plugins/ccgx/fu-ccgx-hpi-common.h b/plugins/ccgx/fu-ccgx-hpi-common.h index 03ab220f5..4812f4d36 100644 --- a/plugins/ccgx/fu-ccgx-hpi-common.h +++ b/plugins/ccgx/fu-ccgx-hpi-common.h @@ -40,19 +40,19 @@ typedef enum { CY_GET_SIGNATURE_CMD = 0xBD, /* get the signature of the firmware * It is suppose to be 'CYUS' for normal firmware * and 'CYBL' for Bootloader */ - CY_UART_GET_CONFIG_CMD = 0xC0, /* retreive the 16 byte UART configuration information + CY_UART_GET_CONFIG_CMD = 0xC0, /* retrieve the 16 byte UART configuration information * MS bit of value indicates the SCB index * length = 16, data_in = 16 byte configuration */ CY_UART_SET_CONFIG_CMD, /* update the 16 byte UART configuration information * MS bit of value indicates the SCB index. * length = 16, data_out = 16 byte configuration information */ - CY_SPI_GET_CONFIG_CMD, /* retreive the 16 byte SPI configuration information + CY_SPI_GET_CONFIG_CMD, /* retrieve the 16 byte SPI configuration information * MS bit of value indicates the SCB index * length = 16, data_in = 16 byte configuration */ CY_SPI_SET_CONFIG_CMD, /* update the 16 byte SPI configuration information * MS bit of value indicates the SCB index * length = 16, data_out = 16 byte configuration information */ - CY_I2C_GET_CONFIG_CMD, /* retreive the 16 byte I2C configuration information + CY_I2C_GET_CONFIG_CMD, /* retrieve the 16 byte I2C configuration information * MS bit of value indicates the SCB index * length = 16, data_in = 16 byte configuration */ CY_I2C_SET_CONFIG_CMD = 0xC5, /* update the 16 byte I2C configuration information @@ -66,7 +66,7 @@ typedef enum { * value = bit0 - start, bit1 - stop, bit2 - Nak last byte, * bit3 - start on idle, bits[14:8] - slave address, bit15 - scbIndex, * length = 0. The data is provided over the bulk endpoints */ - CY_I2C_GET_STATUS_CMD, /* retreive the I2C bus status. + CY_I2C_GET_STATUS_CMD, /* retrieve the I2C bus status. * value = bit0 - 0: TX 1: RX, bit15 - scbIndex, length = 3, * data_in = byte0: bit0 - flag, bit1 - bus_state, bit2 - SDA state, * bit3 - TX underflow, bit4 - arbitration error, bit5 - NAK diff --git a/plugins/dfu/dfu-device.c b/plugins/dfu/dfu-device.c index 9e4c31f8d..2138f5a46 100644 --- a/plugins/dfu/dfu-device.c +++ b/plugins/dfu/dfu-device.c @@ -874,7 +874,7 @@ dfu_device_refresh (DfuDevice *device, GError **error) /* Device that cannot communicate via the USB after the * Manifestation phase indicated this limitation to the * host by clearing bmAttributes bit bitManifestationTolerant. - * so we assume the operation was succesful */ + * so we assume the operation was successful */ if (priv->state == DFU_STATE_DFU_MANIFEST && !(priv->attributes & DFU_DEVICE_ATTRIBUTE_MANIFEST_TOL)) return TRUE; diff --git a/plugins/upower/fu-plugin-upower.c b/plugins/upower/fu-plugin-upower.c index 4f882ab94..25546c229 100644 --- a/plugins/upower/fu-plugin-upower.c +++ b/plugins/upower/fu-plugin-upower.c @@ -158,7 +158,7 @@ fu_plugin_update_prepare (FuPlugin *plugin, return FALSE; } - /* deteremine if battery high enough */ + /* determine if battery high enough */ if (!fu_plugin_upower_check_percentage_level (plugin) && (flags & FWUPD_INSTALL_FLAG_FORCE) == 0) { FuPluginData *data = fu_plugin_get_data (plugin); From 0164141f9bbc9e0d06c1bf5ddbf557c3353736f7 Mon Sep 17 00:00:00 2001 From: Richard Hughes Date: Fri, 19 Jun 2020 10:59:16 +0100 Subject: [PATCH 177/607] trivial: Fix incorrect comment text --- plugins/fastboot/fu-fastboot-device.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugins/fastboot/fu-fastboot-device.c b/plugins/fastboot/fu-fastboot-device.c index c7857f1f8..5887819af 100644 --- a/plugins/fastboot/fu-fastboot-device.c +++ b/plugins/fastboot/fu-fastboot-device.c @@ -656,7 +656,7 @@ fu_fastboot_device_set_quirk_kv (FuDevice *device, { FuFastbootDevice *self = FU_FASTBOOT_DEVICE (device); - /* load slave address from quirks */ + /* load from quirks */ if (g_strcmp0 (key, "FastbootBlockSize") == 0) { guint64 tmp = fu_common_strtoull (value); if (tmp >= 0x40 && tmp < 0x100000) { From acba98bd5058b2487b41c4b58f0bef3460f56bdd Mon Sep 17 00:00:00 2001 From: Benson Leung Date: Fri, 29 May 2020 14:39:41 -0700 Subject: [PATCH 178/607] fmap-firmware: Add initial skeleton for fmap fmap is a Google flash layout format that is used in several of Google's firmware projects, including Chrome OS Embedded Controller and the Chrome OS coreboot firmwares. Introduce it as a firmware format in libfwupdplugin. --- libfwupdplugin/fu-fmap-firmware.c | 55 +++++++++++++++++++++++++++++++ libfwupdplugin/fu-fmap-firmware.h | 14 ++++++++ libfwupdplugin/fwupdplugin.map | 2 ++ libfwupdplugin/meson.build | 2 ++ src/fu-engine.c | 2 ++ 5 files changed, 75 insertions(+) create mode 100644 libfwupdplugin/fu-fmap-firmware.c create mode 100644 libfwupdplugin/fu-fmap-firmware.h diff --git a/libfwupdplugin/fu-fmap-firmware.c b/libfwupdplugin/fu-fmap-firmware.c new file mode 100644 index 000000000..8c3c46344 --- /dev/null +++ b/libfwupdplugin/fu-fmap-firmware.c @@ -0,0 +1,55 @@ +/* + * Copyright (C) 2020 Benson Leung + * + * SPDX-License-Identifier: LGPL-2.1+ + */ + +#include "config.h" + +#include "fu-fmap-firmware.h" + +struct _FuFmapFirmware { + FuFirmware parent_instance; +}; + +G_DEFINE_TYPE (FuFmapFirmware, fu_fmap_firmware, FU_TYPE_FIRMWARE) + +static gboolean +fu_fmap_firmware_parse (FuFirmware *firmware, + GBytes *fw, + guint64 addr_start, + guint64 addr_end, + FwupdInstallFlags flags, + GError **error) +{ + /* set bogus version */ + fu_firmware_set_version (firmware, "1.2.3"); + + /* success */ + return TRUE; +} + +static void +fu_fmap_firmware_init (FuFmapFirmware *self) +{ +} + +static void +fu_fmap_firmware_class_init (FuFmapFirmwareClass *klass) +{ + FuFirmwareClass *klass_firmware = FU_FIRMWARE_CLASS (klass); + klass_firmware->parse = fu_fmap_firmware_parse; +} + +/** + * fu_fmap_firmware_new + * + * Creates a new #FuFirmware of sub type fmap + * + * Since: 1.5.0 + **/ +FuFirmware * +fu_fmap_firmware_new (void) +{ + return FU_FIRMWARE (g_object_new (FU_TYPE_FMAP_FIRMWARE, NULL)); +} diff --git a/libfwupdplugin/fu-fmap-firmware.h b/libfwupdplugin/fu-fmap-firmware.h new file mode 100644 index 000000000..934d826d4 --- /dev/null +++ b/libfwupdplugin/fu-fmap-firmware.h @@ -0,0 +1,14 @@ +/* + * Copyright (C) 2020 Benson Leung + * + * SPDX-License-Identifier: LGPL-2.1+ + */ + +#pragma once + +#include "fu-firmware.h" + +#define FU_TYPE_FMAP_FIRMWARE (fu_fmap_firmware_get_type ()) +G_DECLARE_FINAL_TYPE (FuFmapFirmware, fu_fmap_firmware, FU, FMAP_FIRMWARE, FuFirmware) + +FuFirmware *fu_fmap_firmware_new (void); diff --git a/libfwupdplugin/fwupdplugin.map b/libfwupdplugin/fwupdplugin.map index 495fc94a0..44eeb027f 100644 --- a/libfwupdplugin/fwupdplugin.map +++ b/libfwupdplugin/fwupdplugin.map @@ -587,6 +587,8 @@ LIBFWUPDPLUGIN_1.5.0 { fu_common_is_cpu_intel; fu_device_report_metadata_post; fu_device_report_metadata_pre; + fu_fmap_firmware_get_type; + fu_fmap_firmware_new; fu_plugin_runner_add_security_attrs; fu_plugin_runner_device_added; fu_plugin_security_changed; diff --git a/libfwupdplugin/meson.build b/libfwupdplugin/meson.build index dd5639f05..8793938e0 100644 --- a/libfwupdplugin/meson.build +++ b/libfwupdplugin/meson.build @@ -12,6 +12,7 @@ fwupdplugin_src = [ 'fu-firmware.c', 'fu-firmware-common.c', 'fu-firmware-image.c', + 'fu-fmap-firmware.c', 'fu-hwids.c', 'fu-ihex-firmware.c', 'fu-io-channel.c', @@ -41,6 +42,7 @@ fwupdplugin_headers = [ 'fu-firmware.h', 'fu-firmware-common.h', 'fu-firmware-image.h', + 'fu-fmap-firmware.h', 'fu-hwids.h', 'fu-ihex-firmware.h', 'fu-io-channel.h', diff --git a/src/fu-engine.c b/src/fu-engine.c index 59cb76e60..93f38951c 100644 --- a/src/fu-engine.c +++ b/src/fu-engine.c @@ -56,6 +56,7 @@ #include "fu-usb-device-private.h" #include "fu-dfu-firmware.h" +#include "fu-fmap-firmware.h" #include "fu-ihex-firmware.h" #include "fu-srec-firmware.h" @@ -5947,6 +5948,7 @@ fu_engine_load (FuEngine *self, FuEngineLoadFlags flags, GError **error) /* add the "built-in" firmware types */ fu_engine_add_firmware_gtype (self, "raw", FU_TYPE_FIRMWARE); fu_engine_add_firmware_gtype (self, "dfu", FU_TYPE_DFU_FIRMWARE); + fu_engine_add_firmware_gtype (self, "fmap", FU_TYPE_FMAP_FIRMWARE); fu_engine_add_firmware_gtype (self, "ihex", FU_TYPE_IHEX_FIRMWARE); fu_engine_add_firmware_gtype (self, "srec", FU_TYPE_SREC_FIRMWARE); From 23ca19acf84f912d1dfd3b3c3e92fd8f12f739d3 Mon Sep 17 00:00:00 2001 From: Benson Leung Date: Wed, 3 Jun 2020 13:32:59 -0700 Subject: [PATCH 179/607] fmap-firmware: Parse flashmap format into images Implements a search for the fmap, and follow the map to break the firmware into the constituent images. Tested using a servo_micro firmware: $ fwupdtool firmware-parse servo_micro_v2.4.17-df61092c3.bin FuCrosEcFirmware: Version: 2.4.17 FuFirmwareImage: ID: EC_RO Index: 0x1 Version: servo_micro_v2.4.17-df61092c3 Data: 0xf000 FuFirmwareImage: ID: FR_MAIN Index: 0x2 Data: 0xf000 FuFirmwareImage: ID: RO_FRID Index: 0x3 Address: 0xc4 Data: 0x20 FuFirmwareImage: ID: FMAP Index: 0x4 Address: 0x9a40 Version: 1.0 Data: 0x15e FuFirmwareImage: ID: WP_RO Index: 0x5 Data: 0x10000 FuFirmwareImage: ID: EC_RW Index: 0x6 Address: 0x10000 Version: servo_micro_v2.4.17-df61092c3 Data: 0x10000 FuFirmwareImage: ID: RW_FWID Index: 0x7 Address: 0x100c4 Data: 0x20 --- plugins/cros-ec/fu-cros-ec-firmware.c | 136 ++++++++++++++++++++++++++ plugins/cros-ec/fu-cros-ec-firmware.h | 41 ++++++++ plugins/cros-ec/fu-plugin-cros-ec.c | 2 + plugins/cros-ec/meson.build | 1 + 4 files changed, 180 insertions(+) create mode 100644 plugins/cros-ec/fu-cros-ec-firmware.c create mode 100644 plugins/cros-ec/fu-cros-ec-firmware.h diff --git a/plugins/cros-ec/fu-cros-ec-firmware.c b/plugins/cros-ec/fu-cros-ec-firmware.c new file mode 100644 index 000000000..a4934ac4a --- /dev/null +++ b/plugins/cros-ec/fu-cros-ec-firmware.c @@ -0,0 +1,136 @@ +/* + * Copyright (C) 2020 Benson Leung + * + * SPDX-License-Identifier: LGPL-2.1+ + */ + +#include "config.h" + +#include "fu-fmap-firmware.h" +#include "fu-cros-ec-common.h" +#include "fu-cros-ec-firmware.h" + +#define MAXSECTIONS 2 + +struct _FuCrosEcFirmware { + FuFmapFirmware parent_instance; + struct cros_ec_version version; + FuCrosEcFirmwareSection sections[MAXSECTIONS]; +}; + +G_DEFINE_TYPE (FuCrosEcFirmware, fu_cros_ec_firmware, FU_TYPE_FMAP_FIRMWARE) + +static gboolean +fu_cros_ec_firmware_parse (FuFirmware *firmware, + GBytes *fw, + guint64 addr_start, + guint64 addr_end, + FwupdInstallFlags flags, + GError **error) +{ + FuCrosEcFirmware *self = FU_CROS_EC_FIRMWARE (firmware); + FuFirmware *fmap_firmware = FU_FIRMWARE (firmware); + + self->sections[0].name = "RO"; + self->sections[1].name = "RW"; + + for (gsize i = 0; i < G_N_ELEMENTS (self->sections); i++) { + gboolean rw = FALSE; + FuCrosEcFirmwareSection *section = &self->sections[i]; + const gchar *fmap_name; + const gchar *fmap_fwid_name; + g_autoptr(FuFirmwareImage) img = NULL; + g_autoptr(FuFirmwareImage) fwid_img = NULL; + g_autoptr(GBytes) payload_bytes = NULL; + g_autoptr(GBytes) fwid_bytes = NULL; + + if (g_strcmp0 (section->name, "RO") == 0) { + fmap_name = "EC_RO"; + fmap_fwid_name = "RO_FRID"; + } else if (g_strcmp0 (section->name, "RW") == 0) { + rw = TRUE; + fmap_name = "EC_RW"; + fmap_fwid_name = "RW_FWID"; + } else { + g_set_error_literal (error, + G_IO_ERROR, + G_IO_ERROR_INVALID_DATA, + "incorrect section name"); + return FALSE; + } + + img = fu_firmware_get_image_by_id (fmap_firmware, + fmap_name, error); + if (img == NULL) { + g_prefix_error (error, "%s image not found: ", + fmap_name); + return FALSE; + } + + fwid_img = fu_firmware_get_image_by_id (fmap_firmware, + fmap_fwid_name, error); + if (fwid_img == NULL) { + g_prefix_error (error, "%s image not found: ", + fmap_fwid_name); + return FALSE; + } + fwid_bytes = fu_firmware_image_write (fwid_img, error); + if (fwid_bytes == NULL) { + g_prefix_error (error, + "unable to get bytes from %s: ", + fmap_fwid_name); + return FALSE; + } + if (!fu_memcpy_safe ((guint8 *) section->version, + FMAP_STRLEN, 0x0, + g_bytes_get_data (fwid_bytes, NULL), + g_bytes_get_size (fwid_bytes), 0x0, + g_bytes_get_size (fwid_bytes), error)) + return FALSE; + + payload_bytes = fu_firmware_image_write (img, error); + if (payload_bytes == NULL) { + g_prefix_error (error, + "unable to get bytes from %s: ", + fmap_name); + return FALSE; + } + section->offset = fu_firmware_image_get_addr (img); + section->size = g_bytes_get_size (payload_bytes); + fu_firmware_image_set_version (img, section->version); + + if (rw) { + if (!fu_cros_ec_parse_version (section->version, + &self->version, + error)) { + g_prefix_error (error, + "failed parsing firmware's version: %32s: ", + section->version); + return FALSE; + } + fu_firmware_set_version (firmware, + self->version.triplet); + } + } + + /* success */ + return TRUE; +} + +static void +fu_cros_ec_firmware_init (FuCrosEcFirmware *self) +{ +} + +static void +fu_cros_ec_firmware_class_init (FuCrosEcFirmwareClass *klass) +{ + FuFmapFirmwareClass *klass_firmware = FU_FMAP_FIRMWARE_CLASS (klass); + klass_firmware->parse = fu_cros_ec_firmware_parse; +} + +FuFirmware * +fu_cros_ec_firmware_new (void) +{ + return g_object_new (FU_TYPE_CROS_EC_FIRMWARE, NULL); +} diff --git a/plugins/cros-ec/fu-cros-ec-firmware.h b/plugins/cros-ec/fu-cros-ec-firmware.h new file mode 100644 index 000000000..54c975320 --- /dev/null +++ b/plugins/cros-ec/fu-cros-ec-firmware.h @@ -0,0 +1,41 @@ +/* + * Copyright (C) 2020 Benson Leung + * + * SPDX-License-Identifier: LGPL-2.1+ + */ + +#pragma once + +#include "fu-firmware.h" +#include "fu-fmap-firmware.h" + +#define FU_TYPE_CROS_EC_FIRMWARE (fu_cros_ec_firmware_get_type ()) +G_DECLARE_FINAL_TYPE (FuCrosEcFirmware, fu_cros_ec_firmware, FU, CROS_EC_FIRMWARE, FuFmapFirmware) + +/* + * Each RO or RW section of the new image can be in one of the following + * states. + */ +typedef enum { + FU_CROS_EC_FW_NOT_NEEDED= 0, /* Version below or equal that on the target. */ + FU_CROS_EC_FW_NOT_POSSIBLE, /* + * RO is newer, but can't be transferred due to + * target RW shortcomings. + */ + FU_CROS_EC_FW_NEEDED /* + * This section needs to be transferred to the + * target. + */ +} FuCrosEcFirmwareUpgradeStatus; + +typedef struct { + const gchar *name; + guint32 offset; + gsize size; + FuCrosEcFirmwareUpgradeStatus ustatus; + gchar version[FMAP_STRLEN]; + gint32 rollback; + guint32 key_version; +} FuCrosEcFirmwareSection; + +FuFirmware *fu_cros_ec_firmware_new (void); diff --git a/plugins/cros-ec/fu-plugin-cros-ec.c b/plugins/cros-ec/fu-plugin-cros-ec.c index cd55e8652..5c1f430c1 100644 --- a/plugins/cros-ec/fu-plugin-cros-ec.c +++ b/plugins/cros-ec/fu-plugin-cros-ec.c @@ -10,10 +10,12 @@ #include "fu-hash.h" #include "fu-cros-ec-usb-device.h" +#include "fu-cros-ec-firmware.h" void fu_plugin_init (FuPlugin *plugin) { fu_plugin_set_build_hash (plugin, FU_BUILD_HASH); fu_plugin_set_device_gtype (plugin, FU_TYPE_CROS_EC_USB_DEVICE); + fu_plugin_add_firmware_gtype (plugin, "cros-ec", FU_TYPE_CROS_EC_FIRMWARE); } diff --git a/plugins/cros-ec/meson.build b/plugins/cros-ec/meson.build index ff41c03d9..643aa9d1e 100644 --- a/plugins/cros-ec/meson.build +++ b/plugins/cros-ec/meson.build @@ -10,6 +10,7 @@ shared_module('fu_plugin_cros_ec', 'fu-plugin-cros-ec.c', 'fu-cros-ec-usb-device.c', 'fu-cros-ec-common.c', + 'fu-cros-ec-firmware.c', ], include_directories : [ root_incdir, From 53fad4cd6c19ec4db2a2fb4a004e8343d867f6d9 Mon Sep 17 00:00:00 2001 From: Benson Leung Date: Wed, 17 Jun 2020 18:52:32 -0700 Subject: [PATCH 181/607] trivial: cros-ec: Use fu-memcpy-safe --- plugins/cros-ec/fu-cros-ec-common.h | 9 +++++---- plugins/cros-ec/fu-cros-ec-usb-device.c | 8 ++++++-- 2 files changed, 11 insertions(+), 6 deletions(-) diff --git a/plugins/cros-ec/fu-cros-ec-common.h b/plugins/cros-ec/fu-cros-ec-common.h index e7e07c9c2..e626e9cda 100644 --- a/plugins/cros-ec/fu-cros-ec-common.h +++ b/plugins/cros-ec/fu-cros-ec-common.h @@ -11,6 +11,7 @@ #include "fu-plugin.h" #define UPDATE_PROTOCOL_VERSION 6 +#define FU_CROS_EC_STRLEN 32 /* * This is the format of the update PDU header. @@ -114,7 +115,7 @@ struct first_response_pdu { guint32 offset; /* Version string of the other region */ - gchar version[32]; + gchar version[FU_CROS_EC_STRLEN]; /* Minimum rollback version that RO will accept */ gint32 min_rollback; @@ -131,9 +132,9 @@ enum first_response_pdu_header_type { }; struct cros_ec_version { - gchar boardname[32]; - gchar triplet[32]; - gchar sha1[32]; + gchar boardname[FU_CROS_EC_STRLEN]; + gchar triplet[FU_CROS_EC_STRLEN]; + gchar sha1[FU_CROS_EC_STRLEN]; gboolean dirty; }; diff --git a/plugins/cros-ec/fu-cros-ec-usb-device.c b/plugins/cros-ec/fu-cros-ec-usb-device.c index 082562292..811a0898e 100644 --- a/plugins/cros-ec/fu-cros-ec-usb-device.c +++ b/plugins/cros-ec/fu-cros-ec-usb-device.c @@ -271,8 +271,12 @@ fu_cros_ec_usb_device_setup (FuDevice *device, GError **error) return FALSE; } - memcpy (self->targ.common.version, start_resp.rpdu.common.version, - sizeof(start_resp.rpdu.common.version)); + if (!fu_memcpy_safe ((guint8 *) self->targ.common.version, + FU_CROS_EC_STRLEN, 0x0, + (const guint8 *) start_resp.rpdu.common.version, + sizeof(start_resp.rpdu.common.version), 0x0, + sizeof(start_resp.rpdu.common.version), error)) + return FALSE; self->targ.common.maximum_pdu_size = GUINT32_FROM_BE (start_resp.rpdu.common.maximum_pdu_size); self->targ.common.flash_protection = From d63cedc444dac74a41e90101d0360fb115134e64 Mon Sep 17 00:00:00 2001 From: Richard Hughes Date: Sun, 21 Jun 2020 13:56:50 +0100 Subject: [PATCH 182/607] Check all AppStream components when verifying Additionally, ignore the 'not found' error codes so we drop down to the release missing error. Fixes https://github.com/fwupd/fwupd/issues/2196 --- src/fu-engine.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/src/fu-engine.c b/src/fu-engine.c index 93f38951c..d5ab374b1 100644 --- a/src/fu-engine.c +++ b/src/fu-engine.c @@ -863,14 +863,23 @@ fu_engine_verify (FuEngine *self, const gchar *device_id, GError **error) for (guint i = 0; i < guids->len; i++) { const gchar *guid = g_ptr_array_index (guids, i); g_autofree gchar *xpath2 = NULL; + g_autoptr(GError) error_local = NULL; g_autoptr(GPtrArray) releases = NULL; xpath2 = g_strdup_printf ("components/component/" "provides/firmware[@type='flashed'][text()='%s']/" "../../releases/release", guid); - releases = xb_silo_query (self->silo, xpath2, 0, error); - if (releases == NULL) + releases = xb_silo_query (self->silo, xpath2, 0, &error_local); + if (releases == NULL) { + if (g_error_matches (error_local, G_IO_ERROR, G_IO_ERROR_NOT_FOUND) || + g_error_matches (error_local, G_IO_ERROR, G_IO_ERROR_INVALID_ARGUMENT)) { + g_debug ("could not find %s: %s", + guid, error_local->message); + continue; + } + g_propagate_error (error, g_steal_pointer (&error_local)); return FALSE; + } for (guint j = 0; j < releases->len; j++) { XbNode *rel = g_ptr_array_index (releases, j); const gchar *rel_ver = xb_node_get_attr (rel, "version"); From 5a831fa7abf3cc9610807d6138ec93328fccf3f2 Mon Sep 17 00:00:00 2001 From: Richard Hughes Date: Fri, 17 Apr 2020 14:35:20 +0100 Subject: [PATCH 183/607] vli: Set the i2c instance IDs in probe() They do not need to query the device, so ->setup() is not required. --- plugins/vli/fu-vli-usbhub-i2c-device.c | 19 +++++++++++-------- 1 file changed, 11 insertions(+), 8 deletions(-) diff --git a/plugins/vli/fu-vli-usbhub-i2c-device.c b/plugins/vli/fu-vli-usbhub-i2c-device.c index 23566b507..a50e7f4ec 100644 --- a/plugins/vli/fu-vli-usbhub-i2c-device.c +++ b/plugins/vli/fu-vli-usbhub-i2c-device.c @@ -37,7 +37,6 @@ fu_vli_usbhub_i2c_device_setup (FuDevice *device, GError **error) FuVliUsbhubI2cDevice *self = FU_VLI_USBHUB_I2C_DEVICE (device); FuVliUsbhubDevice *parent = FU_VLI_USBHUB_DEVICE (fu_device_get_parent (device)); guint8 buf[11] = { 0x0 }; - g_autofree gchar *instance_id = NULL; g_autofree gchar *version = NULL; /* get versions */ @@ -57,13 +56,6 @@ fu_vli_usbhub_i2c_device_setup (FuDevice *device, GError **error) return FALSE; } - /* add instance ID */ - instance_id = g_strdup_printf ("USB\\VID_%04X&PID_%04X&I2C_%s", - fu_usb_device_get_vid (FU_USB_DEVICE (parent)), - fu_usb_device_get_pid (FU_USB_DEVICE (parent)), - fu_vli_common_device_kind_to_string (self->device_kind)); - fu_device_add_instance_id (device, instance_id); - /* set version */ version = g_strdup_printf ("%x.%x", buf[0], buf[1]); fu_device_set_version (device, version); @@ -261,9 +253,20 @@ fu_vli_usbhub_i2c_device_write_firmware (FuDevice *device, static gboolean fu_vli_usbhub_i2c_device_probe (FuDevice *device, GError **error) { + FuVliUsbhubDevice *parent = FU_VLI_USBHUB_DEVICE (fu_device_get_parent (device)); FuVliUsbhubI2cDevice *self = FU_VLI_USBHUB_I2C_DEVICE (device); + g_autofree gchar *instance_id = NULL; + self->device_kind = FU_VLI_DEVICE_KIND_MSP430; fu_device_set_name (device, fu_vli_common_device_kind_to_string (self->device_kind)); + + /* add instance ID */ + instance_id = g_strdup_printf ("USB\\VID_%04X&PID_%04X&I2C_%s", + fu_usb_device_get_vid (FU_USB_DEVICE (parent)), + fu_usb_device_get_pid (FU_USB_DEVICE (parent)), + fu_vli_common_device_kind_to_string (self->device_kind)); + fu_device_add_instance_id (device, instance_id); + return TRUE; } From 91e27e145a1f7cb97ec78875d08f1b9a9496dadf Mon Sep 17 00:00:00 2001 From: Mario Limonciello Date: Sun, 21 Jun 2020 16:25:24 -0500 Subject: [PATCH 184/607] Add a new plugin for legacy BIOS This plugin is only enabled when coreboot isn't detected. It intentionally does not check for EFI to be disabled at startup since it can also notify the user that UEFI capsule updates are disabled on the system even if running in UEFI mode. --- contrib/fwupd.spec.in | 1 + plugins/bios/fu-plugin-bios.c | 98 +++++++++++++++++++++++++ plugins/bios/meson.build | 23 ++++++ plugins/dell-esrt/fu-plugin-dell-esrt.c | 4 +- plugins/meson.build | 1 + plugins/uefi/fu-plugin-uefi.c | 53 ++----------- 6 files changed, 131 insertions(+), 49 deletions(-) create mode 100644 plugins/bios/fu-plugin-bios.c create mode 100644 plugins/bios/meson.build diff --git a/contrib/fwupd.spec.in b/contrib/fwupd.spec.in index e4695afad..64465edd7 100644 --- a/contrib/fwupd.spec.in +++ b/contrib/fwupd.spec.in @@ -333,6 +333,7 @@ mkdir -p --mode=0700 $RPM_BUILD_ROOT%{_localstatedir}/lib/fwupd/gnupg %{_libdir}/fwupd-plugins-3/libfu_plugin_altos.so %{_libdir}/fwupd-plugins-3/libfu_plugin_amt.so %{_libdir}/fwupd-plugins-3/libfu_plugin_ata.so +%{_libdir}/fwupd-plugins-3/libfu_plugin_bios.so %{_libdir}/fwupd-plugins-3/libfu_plugin_ccgx.so %{_libdir}/fwupd-plugins-3/libfu_plugin_colorhug.so %{_libdir}/fwupd-plugins-3/libfu_plugin_coreboot.so diff --git a/plugins/bios/fu-plugin-bios.c b/plugins/bios/fu-plugin-bios.c new file mode 100644 index 000000000..7b643a46b --- /dev/null +++ b/plugins/bios/fu-plugin-bios.c @@ -0,0 +1,98 @@ +/* + * Copyright (C) 2020 Mario Limonciello + * + * SPDX-License-Identifier: LGPL-2.1+ + */ + +#include "config.h" + +#include "fu-efivar.h" +#include "fu-plugin-vfuncs.h" +#include "fu-hash.h" + +void +fu_plugin_init (FuPlugin *plugin) +{ + fu_plugin_set_build_hash (plugin, FU_BUILD_HASH); +} + + +gboolean +fu_plugin_startup (FuPlugin *plugin, GError **error) +{ + const gchar *vendor; + + vendor = fu_plugin_get_dmi_value (plugin, FU_HWIDS_KEY_BIOS_VENDOR); + if (g_strcmp0 (vendor, "coreboot") == 0) { + g_set_error (error, + FWUPD_ERROR, + FWUPD_ERROR_NOT_FOUND, + "system uses coreboot"); + return FALSE; + } + + return TRUE; +} + + +static gboolean +fu_plugin_bios_create_dummy (FuPlugin *plugin, const gchar *reason, GError **error) +{ + const gchar *key; + g_autoptr(FuDevice) dev = fu_device_new (); + + fu_device_set_version_format (dev, FWUPD_VERSION_FORMAT_PLAIN); + key = fu_plugin_get_dmi_value (plugin, FU_HWIDS_KEY_MANUFACTURER); + if (key != NULL) + fu_device_set_vendor (dev, key); + key = fu_plugin_get_dmi_value (plugin, FU_HWIDS_KEY_BIOS_VENDOR); + if (key != NULL) { + g_autofree gchar *vendor_id = g_strdup_printf ("DMI:%s", key); + fu_device_set_vendor_id (FU_DEVICE (dev), vendor_id); + } + key = "System Firmware"; + fu_device_set_name (dev, key); + key = fu_plugin_get_dmi_value (plugin, FU_HWIDS_KEY_BIOS_VERSION); + if (key != NULL) + fu_device_set_version (dev, key); + fu_device_set_update_error (dev, reason); + + fu_device_add_flag (dev, FWUPD_DEVICE_FLAG_INTERNAL); + + fu_device_add_icon (dev, "computer"); + fu_device_set_id (dev, "BIOS-dummy"); + fu_device_add_instance_id (dev, "main-system-firmware"); + if (!fu_device_setup (dev, error)) + return FALSE; + fu_plugin_device_add (plugin, dev); + + return TRUE; +} + +gboolean +fu_plugin_coldplug (FuPlugin *plugin, GError **error) +{ + g_autofree gchar *sysfsfwdir = NULL; + g_autoptr(GError) error_local = NULL; + g_autofree gchar *esrt_path = NULL; + + /* are the EFI dirs set up so we can update each device */ + if (!fu_efivar_supported (&error_local)) { + const gchar *reason = "Firmware can not be updated in legacy BIOS mode, switch to UEFI mode"; + g_warning ("%s", error_local->message); + return fu_plugin_bios_create_dummy (plugin, reason, error); + } + + /* get the directory of ESRT entries */ + sysfsfwdir = fu_common_get_path (FU_PATH_KIND_SYSFSDIR_FW); + esrt_path = g_build_filename (sysfsfwdir, "efi", "esrt", NULL); + if (!g_file_test (esrt_path, G_FILE_TEST_IS_DIR)) { + const gchar *reason = "UEFI Capsule updates not available or enabled"; + return fu_plugin_bios_create_dummy (plugin, reason, error); + } + + /* we appear to have UEFI capsule updates */ + fu_plugin_set_enabled (plugin, FALSE); + + return TRUE; +} diff --git a/plugins/bios/meson.build b/plugins/bios/meson.build new file mode 100644 index 000000000..9e7189089 --- /dev/null +++ b/plugins/bios/meson.build @@ -0,0 +1,23 @@ +cargs = ['-DG_LOG_DOMAIN="FuPluginBios"'] + +shared_module('fu_plugin_bios', + fu_hash, + sources : [ + 'fu-plugin-bios.c', + ], + include_directories : [ + root_incdir, + fwupd_incdir, + fwupdplugin_incdir, + ], + install : true, + install_dir: plugin_dir, + link_with : [ + fwupd, + fwupdplugin, + ], + c_args : cargs, + dependencies : [ + plugin_deps, + ], +) diff --git a/plugins/dell-esrt/fu-plugin-dell-esrt.c b/plugins/dell-esrt/fu-plugin-dell-esrt.c index 5f0b0b1d7..bc746d018 100644 --- a/plugins/dell-esrt/fu-plugin-dell-esrt.c +++ b/plugins/dell-esrt/fu-plugin-dell-esrt.c @@ -87,7 +87,7 @@ void fu_plugin_init (FuPlugin *plugin) { fu_plugin_set_build_hash (plugin, FU_BUILD_HASH); - fu_plugin_add_rule (plugin, FU_PLUGIN_RULE_BETTER_THAN, "uefi"); + fu_plugin_add_rule (plugin, FU_PLUGIN_RULE_BETTER_THAN, "bios"); } gboolean @@ -172,6 +172,8 @@ fu_plugin_coldplug (FuPlugin *plugin, GError **error) fu_device_add_flag (dev, FWUPD_DEVICE_FLAG_LOCKED); fu_device_add_flag (dev, FWUPD_DEVICE_FLAG_NEEDS_REBOOT); fu_device_set_update_error (dev, "Firmware updates disabled; run 'fwupdmgr unlock' to enable"); + if (!fu_device_setup (dev, error)) + return FALSE; fu_plugin_device_add (plugin, dev); return TRUE; } diff --git a/plugins/meson.build b/plugins/meson.build index aeb1ea66a..e1ec6a612 100644 --- a/plugins/meson.build +++ b/plugins/meson.build @@ -1,5 +1,6 @@ subdir('acpi-dmar') subdir('acpi-facp') +subdir('bios') subdir('ccgx') subdir('cros-ec') subdir('cpu') diff --git a/plugins/uefi/fu-plugin-uefi.c b/plugins/uefi/fu-plugin-uefi.c index 2b4acde34..dc5807525 100644 --- a/plugins/uefi/fu-plugin-uefi.c +++ b/plugins/uefi/fu-plugin-uefi.c @@ -725,43 +725,6 @@ fu_plugin_unlock (FuPlugin *plugin, FuDevice *device, GError **error) return TRUE; } -static gboolean -fu_plugin_uefi_create_dummy (FuPlugin *plugin, const gchar *reason, GError **error) -{ - const gchar *key; - g_autoptr(FuDevice) dev = fu_device_new (); - - fu_device_set_version_format (dev, FWUPD_VERSION_FORMAT_PLAIN); - key = fu_plugin_get_dmi_value (plugin, FU_HWIDS_KEY_MANUFACTURER); - if (key != NULL) - fu_device_set_vendor (dev, key); - key = fu_plugin_get_dmi_value (plugin, FU_HWIDS_KEY_BIOS_VENDOR); - if (key != NULL) { - g_autofree gchar *vendor_id = g_strdup_printf ("DMI:%s", key); - fu_device_set_vendor_id (FU_DEVICE (dev), vendor_id); - } - key = fu_plugin_uefi_get_name_for_type (plugin, FU_UEFI_DEVICE_KIND_SYSTEM_FIRMWARE); - fu_device_set_name (dev, key); - key = fu_plugin_get_dmi_value (plugin, FU_HWIDS_KEY_BIOS_VERSION); - if (key != NULL) - fu_device_set_version (dev, key); - fu_device_set_update_error (dev, reason); - - fu_device_add_flag (dev, FWUPD_DEVICE_FLAG_INTERNAL); - fu_device_add_flag (dev, FWUPD_DEVICE_FLAG_NEEDS_REBOOT); - fu_device_add_flag (dev, FWUPD_DEVICE_FLAG_REQUIRE_AC); - fu_device_add_flag (dev, FWUPD_DEVICE_FLAG_MD_SET_VERFMT); - - fu_device_add_icon (dev, "computer"); - fu_device_set_id (dev, "UEFI-dummy"); - fu_device_add_instance_id (dev, "main-system-firmware"); - if (!fu_device_setup (dev, error)) - return FALSE; - fu_plugin_device_add (plugin, dev); - - return TRUE; -} - gboolean fu_plugin_coldplug (FuPlugin *plugin, GError **error) { @@ -776,21 +739,15 @@ fu_plugin_coldplug (FuPlugin *plugin, GError **error) g_autoptr(GPtrArray) entries = NULL; /* are the EFI dirs set up so we can update each device */ - if (!fu_efivar_supported (&error_local)) { - const gchar *reason = "Firmware can not be updated in legacy mode, switch to UEFI mode"; - g_warning ("%s", error_local->message); - return fu_plugin_uefi_create_dummy (plugin, reason, error); - } + if (!fu_efivar_supported (error)) + return FALSE; /* get the directory of ESRT entries */ sysfsfwdir = fu_common_get_path (FU_PATH_KIND_SYSFSDIR_FW); esrt_path = g_build_filename (sysfsfwdir, "efi", "esrt", NULL); - entries = fu_uefi_get_esrt_entry_paths (esrt_path, &error_local); - if (entries == NULL) { - const gchar *reason = "UEFI Capsule updates not available or enabled"; - g_warning ("%s", error_local->message); - return fu_plugin_uefi_create_dummy (plugin, reason, error); - } + entries = fu_uefi_get_esrt_entry_paths (esrt_path, error); + if (entries == NULL) + return FALSE; /* make sure that efivarfs is rw */ if (!fu_plugin_uefi_ensure_efivarfs_rw (&error_efivarfs)) From 4c177ad5403e06d10aae9d19aaa73c86c0078194 Mon Sep 17 00:00:00 2001 From: Ryan Lee Date: Mon, 22 Jun 2020 20:20:02 +0900 Subject: [PATCH 185/607] ccgx: add new protocol for dmc dock --- plugins/ccgx/fu-ccgx-dmc-device.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugins/ccgx/fu-ccgx-dmc-device.c b/plugins/ccgx/fu-ccgx-dmc-device.c index c05a39027..46963b688 100644 --- a/plugins/ccgx/fu-ccgx-dmc-device.c +++ b/plugins/ccgx/fu-ccgx-dmc-device.c @@ -648,7 +648,7 @@ fu_ccgx_dmc_device_init (FuCcgxDmcDevice *self) { self->ep_intr_in = DMC_INTERRUPT_PIPE_ID; self->ep_bulk_out = DMC_BULK_PIPE_ID; - fu_device_set_protocol (FU_DEVICE (self), "com.cypress.ccgx"); + fu_device_set_protocol (FU_DEVICE (self), "com.cypress.ccgx.dmc"); fu_device_set_version_format (FU_DEVICE (self), FWUPD_VERSION_FORMAT_QUAD); fu_device_add_flag (FU_DEVICE (self), FWUPD_DEVICE_FLAG_REQUIRE_AC); fu_device_add_flag (FU_DEVICE (self), FWUPD_DEVICE_FLAG_DUAL_IMAGE); From b0426f8a24417c7c14ecfe0b7d7482affe236f78 Mon Sep 17 00:00:00 2001 From: Richard Hughes Date: Mon, 22 Jun 2020 14:27:52 +0100 Subject: [PATCH 186/607] tpm-eventlog: Fix memory leak when reading file The file contents were literally just read four lines above. --- plugins/tpm-eventlog/fu-plugin-tpm-eventlog.c | 3 --- 1 file changed, 3 deletions(-) diff --git a/plugins/tpm-eventlog/fu-plugin-tpm-eventlog.c b/plugins/tpm-eventlog/fu-plugin-tpm-eventlog.c index b3641333a..95fd3e225 100644 --- a/plugins/tpm-eventlog/fu-plugin-tpm-eventlog.c +++ b/plugins/tpm-eventlog/fu-plugin-tpm-eventlog.c @@ -56,9 +56,6 @@ fu_plugin_coldplug (FuPlugin *plugin, GError **error) g_propagate_error (error, g_steal_pointer (&error_local)); return FALSE; } - - if (!g_file_get_contents (fn, (gchar **) &buf, &bufsz, error)) - return FALSE; if (bufsz == 0) { g_set_error (error, FWUPD_ERROR, From b1ae0dcbbc52fcedc274657dc3e3966d47e6b2ba Mon Sep 17 00:00:00 2001 From: Richard Hughes Date: Mon, 22 Jun 2020 14:28:38 +0100 Subject: [PATCH 187/607] logind: Fix trivial memory leak at startup The g_dbus_proxy_get_name_owner() function is (return full). --- plugins/logind/fu-plugin-logind.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/plugins/logind/fu-plugin-logind.c b/plugins/logind/fu-plugin-logind.c index 67bb32fa0..5aa490723 100644 --- a/plugins/logind/fu-plugin-logind.c +++ b/plugins/logind/fu-plugin-logind.c @@ -38,6 +38,8 @@ gboolean fu_plugin_startup (FuPlugin *plugin, GError **error) { FuPluginData *data = fu_plugin_get_data (plugin); + g_autofree gchar *name_owner = NULL; + data->logind_proxy = g_dbus_proxy_new_for_bus_sync (G_BUS_TYPE_SYSTEM, G_DBUS_PROXY_FLAGS_DO_NOT_CONNECT_SIGNALS | @@ -52,7 +54,8 @@ fu_plugin_startup (FuPlugin *plugin, GError **error) g_prefix_error (error, "failed to connect to logind: "); return FALSE; } - if (g_dbus_proxy_get_name_owner (data->logind_proxy) == NULL) { + name_owner = g_dbus_proxy_get_name_owner (data->logind_proxy); + if (name_owner == NULL) { g_set_error (error, FWUPD_ERROR, FWUPD_ERROR_NOT_SUPPORTED, From 5bb537c214e62bbf51019ab3cff64eddf874003d Mon Sep 17 00:00:00 2001 From: Richard Hughes Date: Mon, 22 Jun 2020 14:29:56 +0100 Subject: [PATCH 188/607] libfwupdplugin: Fix trivial memory leak when using fu_udev_device_incorporate() This also adds two missing property notify events. --- libfwupdplugin/fu-udev-device.c | 41 +++++++++++++++++++++++++++------ 1 file changed, 34 insertions(+), 7 deletions(-) diff --git a/libfwupdplugin/fu-udev-device.c b/libfwupdplugin/fu-udev-device.c index e53c93700..5aa79d3d1 100644 --- a/libfwupdplugin/fu-udev-device.c +++ b/libfwupdplugin/fu-udev-device.c @@ -156,6 +156,34 @@ fu_udev_device_to_string (FuDevice *device, guint idt, GString *str) #endif } +static void +fu_udev_device_set_subsystem (FuUdevDevice *self, const gchar *subsystem) +{ + FuUdevDevicePrivate *priv = GET_PRIVATE (self); + + /* not changed */ + if (g_strcmp0 (priv->subsystem, subsystem) == 0) + return; + + g_free (priv->subsystem); + priv->subsystem = g_strdup (subsystem); + g_object_notify (G_OBJECT (self), "subsystem"); +} + +static void +fu_udev_device_set_device_file (FuUdevDevice *self, const gchar *device_file) +{ + FuUdevDevicePrivate *priv = GET_PRIVATE (self); + + /* not changed */ + if (g_strcmp0 (priv->device_file, device_file) == 0) + return; + + g_free (priv->device_file); + priv->device_file = g_strdup (device_file); + g_object_notify (G_OBJECT (self), "device-file"); +} + static gboolean fu_udev_device_probe (FuDevice *device, GError **error) { @@ -385,8 +413,8 @@ fu_udev_device_set_dev (FuUdevDevice *self, GUdevDevice *udev_device) if (priv->udev_device == NULL) return; #ifdef HAVE_GUDEV - priv->subsystem = g_strdup (g_udev_device_get_subsystem (priv->udev_device)); - priv->device_file = g_strdup (g_udev_device_get_device_file (priv->udev_device)); + fu_udev_device_set_subsystem (self, g_udev_device_get_subsystem (priv->udev_device)); + fu_udev_device_set_device_file (self, g_udev_device_get_device_file (priv->udev_device)); /* try to get one line summary */ summary = g_udev_device_get_sysfs_attr (priv->udev_device, "description"); @@ -443,8 +471,8 @@ fu_udev_device_incorporate (FuDevice *self, FuDevice *donor) fu_udev_device_set_dev (uself, fu_udev_device_get_dev (udonor)); if (priv->device_file == NULL) { - priv->subsystem = g_strdup (fu_udev_device_get_subsystem (udonor)); - priv->device_file = g_strdup (fu_udev_device_get_device_file (udonor)); + fu_udev_device_set_subsystem (uself, fu_udev_device_get_subsystem (udonor)); + fu_udev_device_set_device_file (uself, fu_udev_device_get_device_file (udonor)); } } @@ -1167,16 +1195,15 @@ fu_udev_device_set_property (GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec) { FuUdevDevice *self = FU_UDEV_DEVICE (object); - FuUdevDevicePrivate *priv = GET_PRIVATE (self); switch (prop_id) { case PROP_UDEV_DEVICE: fu_udev_device_set_dev (self, g_value_get_object (value)); break; case PROP_SUBSYSTEM: - priv->subsystem = g_value_dup_string (value); + fu_udev_device_set_subsystem (self, g_value_get_string (value)); break; case PROP_DEVICE_FILE: - priv->device_file = g_value_dup_string (value); + fu_udev_device_set_device_file (self, g_value_get_string (value)); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); From 4d7edc65b0f6f35fd838661dbdc7f7998e6b1c4f Mon Sep 17 00:00:00 2001 From: Richard Hughes Date: Mon, 22 Jun 2020 15:10:02 +0100 Subject: [PATCH 189/607] libfwupdplugin: Lazy load FuDevice::metadata --- libfwupdplugin/fu-device.c | 47 ++++++++++++++++++++++++-------------- 1 file changed, 30 insertions(+), 17 deletions(-) diff --git a/libfwupdplugin/fu-device.c b/libfwupdplugin/fu-device.c index 64a8723af..b2c3998bd 100644 --- a/libfwupdplugin/fu-device.c +++ b/libfwupdplugin/fu-device.c @@ -41,7 +41,7 @@ typedef struct { FuDevice *parent; /* noref */ FuDevice *proxy; /* noref */ FuQuirks *quirks; - GHashTable *metadata; + GHashTable *metadata; /* (nullable) */ GRWLock metadata_mutex; GPtrArray *parent_guids; GRWLock parent_guids_mutex; @@ -1405,6 +1405,8 @@ fu_device_get_metadata (FuDevice *self, const gchar *key) g_return_val_if_fail (FU_IS_DEVICE (self), NULL); g_return_val_if_fail (key != NULL, NULL); g_return_val_if_fail (locker != NULL, NULL); + if (priv->metadata == NULL) + return NULL; return g_hash_table_lookup (priv->metadata, key); } @@ -1430,6 +1432,8 @@ fu_device_get_metadata_boolean (FuDevice *self, const gchar *key) g_return_val_if_fail (key != NULL, FALSE); g_return_val_if_fail (locker != NULL, FALSE); + if (priv->metadata == NULL) + return FALSE; tmp = g_hash_table_lookup (priv->metadata, key); if (tmp == NULL) return FALSE; @@ -1460,6 +1464,8 @@ fu_device_get_metadata_integer (FuDevice *self, const gchar *key) g_return_val_if_fail (key != NULL, G_MAXUINT); g_return_val_if_fail (locker != NULL, G_MAXUINT); + if (priv->metadata == NULL) + return G_MAXUINT; tmp = g_hash_table_lookup (priv->metadata, key); if (tmp == NULL) return G_MAXUINT; @@ -1488,6 +1494,8 @@ fu_device_remove_metadata (FuDevice *self, const gchar *key) g_return_if_fail (FU_IS_DEVICE (self)); g_return_if_fail (key != NULL); g_return_if_fail (locker != NULL); + if (priv->metadata == NULL) + return; g_hash_table_remove (priv->metadata, key); } @@ -1510,6 +1518,10 @@ fu_device_set_metadata (FuDevice *self, const gchar *key, const gchar *value) g_return_if_fail (key != NULL); g_return_if_fail (value != NULL); g_return_if_fail (locker != NULL); + if (priv->metadata == NULL) { + priv->metadata = g_hash_table_new_full (g_str_hash, g_str_equal, + g_free, g_free); + } g_hash_table_insert (priv->metadata, g_strdup (key), g_strdup (value)); } @@ -2253,7 +2265,6 @@ fu_device_add_string (FuDevice *self, guint idt, GString *str) FuDeviceClass *klass = FU_DEVICE_GET_CLASS (self); FuDevicePrivate *priv = GET_PRIVATE (self); g_autofree gchar *tmp = NULL; - g_autoptr(GList) keys = NULL; g_autoptr(GRWLockReaderLocker) locker = g_rw_lock_reader_locker_new (&priv->metadata_mutex); g_return_if_fail (locker != NULL); @@ -2288,11 +2299,13 @@ fu_device_add_string (FuDevice *self, guint idt, GString *str) fu_common_string_append_ku (str, idt + 1, "Order", priv->order); if (priv->priority > 0) fu_common_string_append_ku (str, idt + 1, "Priority", priv->priority); - keys = g_hash_table_get_keys (priv->metadata); - for (GList *l = keys; l != NULL; l = l->next) { - const gchar *key = l->data; - const gchar *value = g_hash_table_lookup (priv->metadata, key); - fu_common_string_append_kv (str, idt + 1, key, value); + if (priv->metadata != NULL) { + g_autoptr(GList) keys = g_hash_table_get_keys (priv->metadata); + for (GList *l = keys; l != NULL; l = l->next) { + const gchar *key = l->data; + const gchar *value = g_hash_table_lookup (priv->metadata, key); + fu_common_string_append_kv (str, idt + 1, key, value); + } } /* subclassed */ @@ -3056,7 +3069,6 @@ fu_device_incorporate (FuDevice *self, FuDevice *donor) FuDevicePrivate *priv_donor = GET_PRIVATE (donor); GPtrArray *instance_ids = fu_device_get_instance_ids (donor); GPtrArray *parent_guids = fu_device_get_parent_guids (donor); - g_autoptr(GList) metadata_keys = NULL; g_return_if_fail (FU_IS_DEVICE (self)); g_return_if_fail (FU_IS_DEVICE (donor)); @@ -3081,12 +3093,14 @@ fu_device_incorporate (FuDevice *self, FuDevice *donor) fu_device_add_parent_guid (self, g_ptr_array_index (parent_guids, i)); g_rw_lock_reader_unlock (&priv_donor->parent_guids_mutex); g_rw_lock_reader_lock (&priv_donor->metadata_mutex); - metadata_keys = g_hash_table_get_keys (priv_donor->metadata); - for (GList *l = metadata_keys; l != NULL; l = l->next) { - const gchar *key = l->data; - if (g_hash_table_lookup (priv->metadata, key) == NULL) { - const gchar *value = g_hash_table_lookup (priv_donor->metadata, key); - fu_device_set_metadata (self, key, value); + if (priv->metadata != NULL) { + g_autoptr(GList) keys = g_hash_table_get_keys (priv_donor->metadata); + for (GList *l = keys; l != NULL; l = l->next) { + const gchar *key = l->data; + if (g_hash_table_lookup (priv->metadata, key) == NULL) { + const gchar *value = g_hash_table_lookup (priv_donor->metadata, key); + fu_device_set_metadata (self, key, value); + } } } g_rw_lock_reader_unlock (&priv_donor->metadata_mutex); @@ -3207,8 +3221,6 @@ fu_device_init (FuDevice *self) priv->possible_plugins = g_ptr_array_new_with_free_func (g_free); priv->retry_recs = g_ptr_array_new_with_free_func (g_free); g_rw_lock_init (&priv->parent_guids_mutex); - priv->metadata = g_hash_table_new_full (g_str_hash, g_str_equal, - g_free, g_free); g_rw_lock_init (&priv->metadata_mutex); } @@ -3228,9 +3240,10 @@ fu_device_finalize (GObject *object) g_object_unref (priv->quirks); if (priv->poll_id != 0) g_source_remove (priv->poll_id); + if (priv->metadata != NULL) + g_hash_table_unref (priv->metadata); g_rw_lock_clear (&priv->metadata_mutex); g_rw_lock_clear (&priv->parent_guids_mutex); - g_hash_table_unref (priv->metadata); g_ptr_array_unref (priv->children); g_ptr_array_unref (priv->parent_guids); g_ptr_array_unref (priv->possible_plugins); From 3444cf629bba17a3da9e52bc5d702c692a887743 Mon Sep 17 00:00:00 2001 From: Richard Hughes Date: Mon, 22 Jun 2020 15:10:28 +0100 Subject: [PATCH 190/607] Lazy load FuEngine::approved_firmware The common case is no approved list, and an empty hash table. --- src/fu-engine.c | 24 +++++++++++++++++------- 1 file changed, 17 insertions(+), 7 deletions(-) diff --git a/src/fu-engine.c b/src/fu-engine.c index d5ab374b1..7464f4c43 100644 --- a/src/fu-engine.c +++ b/src/fu-engine.c @@ -100,7 +100,7 @@ struct _FuEngine FuQuirks *quirks; GHashTable *runtime_versions; GHashTable *compile_versions; - GHashTable *approved_firmware; + GHashTable *approved_firmware; /* (nullable) */ GHashTable *firmware_gtypes; gchar *host_machine_id; JcatContext *jcat_context; @@ -3977,6 +3977,8 @@ static gboolean fu_engine_check_release_is_approved (FuEngine *self, FwupdRelease *rel) { GPtrArray *csums = fwupd_release_get_checksums (rel); + if (self->approved_firmware == NULL) + return FALSE; for (guint i = 0; i < csums->len; i++) { const gchar *csum = g_ptr_array_index (csums, i); g_debug ("checking %s against approved list", csum); @@ -4312,10 +4314,12 @@ GPtrArray * fu_engine_get_approved_firmware (FuEngine *self) { GPtrArray *checksums = g_ptr_array_new_with_free_func (g_free); - g_autoptr(GList) keys = g_hash_table_get_keys (self->approved_firmware); - for (GList *l = keys; l != NULL; l = l->next) { - const gchar *csum = l->data; - g_ptr_array_add (checksums, g_strdup (csum)); + if (self->approved_firmware != NULL) { + g_autoptr(GList) keys = g_hash_table_get_keys (self->approved_firmware); + for (GList *l = keys; l != NULL; l = l->next) { + const gchar *csum = l->data; + g_ptr_array_add (checksums, g_strdup (csum)); + } } return checksums; } @@ -4323,6 +4327,12 @@ fu_engine_get_approved_firmware (FuEngine *self) void fu_engine_add_approved_firmware (FuEngine *self, const gchar *checksum) { + if (self->approved_firmware == NULL) { + self->approved_firmware = g_hash_table_new_full (g_str_hash, + g_str_equal, + g_free, + NULL); + } g_hash_table_add (self->approved_firmware, g_strdup (checksum)); } @@ -6137,7 +6147,6 @@ fu_engine_init (FuEngine *self) #endif self->runtime_versions = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_free); self->compile_versions = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_free); - self->approved_firmware = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, NULL); self->firmware_gtypes = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, NULL); g_signal_connect (self->config, "changed", @@ -6205,6 +6214,8 @@ fu_engine_finalize (GObject *obj) #endif if (self->coldplug_id != 0) g_source_remove (self->coldplug_id); + if (self->approved_firmware != NULL) + g_hash_table_unref (self->approved_firmware); g_free (self->host_machine_id); g_free (self->host_security_id); @@ -6224,7 +6235,6 @@ fu_engine_finalize (GObject *obj) #endif g_hash_table_unref (self->runtime_versions); g_hash_table_unref (self->compile_versions); - g_hash_table_unref (self->approved_firmware); g_hash_table_unref (self->firmware_gtypes); g_object_unref (self->plugin_list); From 1d900f7d605f5cd004edf66d3f1c1a891b330af4 Mon Sep 17 00:00:00 2001 From: Richard Hughes Date: Mon, 22 Jun 2020 15:17:39 +0100 Subject: [PATCH 191/607] libfwupdplugin: Make FuPlugin::report_metadata lazy loaded --- libfwupdplugin/fu-plugin.c | 14 ++++++++++---- src/fu-engine.c | 9 ++++++--- 2 files changed, 16 insertions(+), 7 deletions(-) diff --git a/libfwupdplugin/fu-plugin.c b/libfwupdplugin/fu-plugin.c index 12c036196..92826274c 100644 --- a/libfwupdplugin/fu-plugin.c +++ b/libfwupdplugin/fu-plugin.c @@ -52,7 +52,7 @@ typedef struct { GType device_gtype; GHashTable *devices; /* platform_id:GObject */ GRWLock devices_mutex; - GHashTable *report_metadata; /* key:value */ + GHashTable *report_metadata; /* (nullable): key:value */ FuPluginData *data; } FuPluginPrivate; @@ -2563,6 +2563,12 @@ void fu_plugin_add_report_metadata (FuPlugin *self, const gchar *key, const gchar *value) { FuPluginPrivate *priv = fu_plugin_get_instance_private (self); + if (priv->report_metadata == NULL) { + priv->report_metadata = g_hash_table_new_full (g_str_hash, + g_str_equal, + g_free, + g_free); + } g_hash_table_insert (priv->report_metadata, g_strdup (key), g_strdup (value)); } @@ -2572,7 +2578,7 @@ fu_plugin_add_report_metadata (FuPlugin *self, const gchar *key, const gchar *va * * Returns the list of additional metadata to be added when filing a report. * - * Returns: (transfer none): the map of report metadata + * Returns: (transfer none) (nullable): the map of report metadata * * Since: 1.0.4 **/ @@ -2746,7 +2752,6 @@ fu_plugin_init (FuPlugin *self) priv->devices = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, (GDestroyNotify) g_object_unref); g_rw_lock_init (&priv->devices_mutex); - priv->report_metadata = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_free); for (guint i = 0; i < FU_PLUGIN_RULE_LAST; i++) priv->rules[i] = g_ptr_array_new_with_free_func (g_free); } @@ -2784,8 +2789,9 @@ fu_plugin_finalize (GObject *object) g_hash_table_unref (priv->runtime_versions); if (priv->compile_versions != NULL) g_hash_table_unref (priv->compile_versions); + if (priv->report_metadata != NULL) + g_hash_table_unref (priv->report_metadata); g_hash_table_unref (priv->devices); - g_hash_table_unref (priv->report_metadata); g_rw_lock_clear (&priv->devices_mutex); g_free (priv->build_hash); g_free (priv->name); diff --git a/src/fu-engine.c b/src/fu-engine.c index 7464f4c43..ae003ca97 100644 --- a/src/fu-engine.c +++ b/src/fu-engine.c @@ -1706,7 +1706,8 @@ fu_engine_create_release_metadata (FuEngine *self, if (metadata_hash == NULL) return NULL; fwupd_release_add_metadata (release, metadata_hash); - fwupd_release_add_metadata (release, fu_plugin_get_report_metadata (plugin)); + if (fu_plugin_get_report_metadata (plugin) != NULL) + fwupd_release_add_metadata (release, fu_plugin_get_report_metadata (plugin)); metadata_device = fu_device_report_metadata_pre (device); if (metadata_device != NULL) fwupd_release_add_metadata (release, metadata_device); @@ -1727,8 +1728,10 @@ fu_engine_create_release_metadata (FuEngine *self, error_local->message); continue; } - fwupd_release_add_metadata (release, - fu_plugin_get_report_metadata (plugin_tmp)); + if (fu_plugin_get_report_metadata (plugin_tmp) != NULL) { + fwupd_release_add_metadata (release, + fu_plugin_get_report_metadata (plugin_tmp)); + } } return g_steal_pointer (&release); } From 371f6b2bfa7747927622dfc0956582a22dbe5d7f Mon Sep 17 00:00:00 2001 From: Richard Hughes Date: Mon, 22 Jun 2020 15:21:17 +0100 Subject: [PATCH 192/607] libfwupdplugin: Make FuPlugin::devices lazy loaded Most plugins don't actually use the per-plugin cache... --- libfwupdplugin/fu-plugin.c | 17 +++++++++++++---- 1 file changed, 13 insertions(+), 4 deletions(-) diff --git a/libfwupdplugin/fu-plugin.c b/libfwupdplugin/fu-plugin.c index 92826274c..b1479c80c 100644 --- a/libfwupdplugin/fu-plugin.c +++ b/libfwupdplugin/fu-plugin.c @@ -50,7 +50,7 @@ typedef struct { GPtrArray *udev_subsystems; FuSmbios *smbios; GType device_gtype; - GHashTable *devices; /* platform_id:GObject */ + GHashTable *devices; /* (nullable): platform_id:GObject */ GRWLock devices_mutex; GHashTable *report_metadata; /* (nullable): key:value */ FuPluginData *data; @@ -219,6 +219,8 @@ fu_plugin_cache_lookup (FuPlugin *self, const gchar *id) g_return_val_if_fail (FU_IS_PLUGIN (self), NULL); g_return_val_if_fail (id != NULL, NULL); g_return_val_if_fail (locker != NULL, NULL); + if (priv->devices == NULL) + return NULL; return g_hash_table_lookup (priv->devices, id); } @@ -240,6 +242,12 @@ fu_plugin_cache_add (FuPlugin *self, const gchar *id, gpointer dev) g_return_if_fail (FU_IS_PLUGIN (self)); g_return_if_fail (id != NULL); g_return_if_fail (locker != NULL); + if (priv->devices == NULL) { + priv->devices = g_hash_table_new_full (g_str_hash, + g_str_equal, + g_free, + (GDestroyNotify) g_object_unref); + } g_hash_table_insert (priv->devices, g_strdup (id), g_object_ref (dev)); } @@ -260,6 +268,8 @@ fu_plugin_cache_remove (FuPlugin *self, const gchar *id) g_return_if_fail (FU_IS_PLUGIN (self)); g_return_if_fail (id != NULL); g_return_if_fail (locker != NULL); + if (priv->devices == NULL) + return; g_hash_table_remove (priv->devices, id); } @@ -2749,8 +2759,6 @@ fu_plugin_init (FuPlugin *self) FuPluginPrivate *priv = GET_PRIVATE (self); priv->enabled = TRUE; priv->udev_subsystems = g_ptr_array_new_with_free_func (g_free); - priv->devices = g_hash_table_new_full (g_str_hash, g_str_equal, - g_free, (GDestroyNotify) g_object_unref); g_rw_lock_init (&priv->devices_mutex); for (guint i = 0; i < FU_PLUGIN_RULE_LAST; i++) priv->rules[i] = g_ptr_array_new_with_free_func (g_free); @@ -2791,7 +2799,8 @@ fu_plugin_finalize (GObject *object) g_hash_table_unref (priv->compile_versions); if (priv->report_metadata != NULL) g_hash_table_unref (priv->report_metadata); - g_hash_table_unref (priv->devices); + if (priv->devices != NULL) + g_hash_table_unref (priv->devices); g_rw_lock_clear (&priv->devices_mutex); g_free (priv->build_hash); g_free (priv->name); From ea327fc13f32ef4217778e6e28b527141e931d2b Mon Sep 17 00:00:00 2001 From: Richard Hughes Date: Mon, 22 Jun 2020 15:23:29 +0100 Subject: [PATCH 193/607] libfwupdplugin: Make FuPlugin::udev_subsystems lazy loaded In most cases except tests the engine uses fu_plugin_set_udev_subsystems()... --- libfwupdplugin/fu-plugin.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/libfwupdplugin/fu-plugin.c b/libfwupdplugin/fu-plugin.c index b1479c80c..512acd92c 100644 --- a/libfwupdplugin/fu-plugin.c +++ b/libfwupdplugin/fu-plugin.c @@ -1650,6 +1650,8 @@ void fu_plugin_add_udev_subsystem (FuPlugin *self, const gchar *subsystem) { FuPluginPrivate *priv = GET_PRIVATE (self); + if (priv->udev_subsystems == NULL) + priv->udev_subsystems = g_ptr_array_new_with_free_func (g_free); for (guint i = 0; i < priv->udev_subsystems->len; i++) { const gchar *subsystem_tmp = g_ptr_array_index (priv->udev_subsystems, i); if (g_strcmp0 (subsystem_tmp, subsystem) == 0) @@ -2758,7 +2760,6 @@ fu_plugin_init (FuPlugin *self) { FuPluginPrivate *priv = GET_PRIVATE (self); priv->enabled = TRUE; - priv->udev_subsystems = g_ptr_array_new_with_free_func (g_free); g_rw_lock_init (&priv->devices_mutex); for (guint i = 0; i < FU_PLUGIN_RULE_LAST; i++) priv->rules[i] = g_ptr_array_new_with_free_func (g_free); From 11c5941f2318bad7ece410f989b31884215e1164 Mon Sep 17 00:00:00 2001 From: Richard Hughes Date: Mon, 22 Jun 2020 15:29:48 +0100 Subject: [PATCH 194/607] libfwupdplugin: Make FuPlugin::rules lazy loaded --- libfwupdplugin/fu-plugin.c | 15 +++++++++------ src/fu-engine.c | 36 ++++++++++++++++++++---------------- src/fu-plugin-list.c | 8 ++++++++ 3 files changed, 37 insertions(+), 22 deletions(-) diff --git a/libfwupdplugin/fu-plugin.c b/libfwupdplugin/fu-plugin.c index 512acd92c..f4881c089 100644 --- a/libfwupdplugin/fu-plugin.c +++ b/libfwupdplugin/fu-plugin.c @@ -2510,6 +2510,8 @@ void fu_plugin_add_rule (FuPlugin *self, FuPluginRule rule, const gchar *name) { FuPluginPrivate *priv = fu_plugin_get_instance_private (self); + if (priv->rules[rule] == NULL) + priv->rules[rule] = g_ptr_array_new_with_free_func (g_free); g_ptr_array_add (priv->rules[rule], g_strdup (name)); g_signal_emit (self, signals[SIGNAL_RULES_CHANGED], 0); } @@ -2521,7 +2523,7 @@ fu_plugin_add_rule (FuPlugin *self, FuPluginRule rule, const gchar *name) * * Gets the plugin IDs that should be run after this plugin. * - * Returns: (element-type utf8) (transfer none): the list of plugin names, e.g. ['appstream'] + * Returns: (element-type utf8) (transfer none) (nullable): the list of plugin names, e.g. ['appstream'] * * Since: 1.0.0 **/ @@ -2549,6 +2551,8 @@ gboolean fu_plugin_has_rule (FuPlugin *self, FuPluginRule rule, const gchar *name) { FuPluginPrivate *priv = fu_plugin_get_instance_private (self); + if (priv->rules[rule] == NULL) + return FALSE; for (guint i = 0; i < priv->rules[rule]->len; i++) { const gchar *tmp = g_ptr_array_index (priv->rules[rule], i); if (g_strcmp0 (tmp, name) == 0) @@ -2761,8 +2765,6 @@ fu_plugin_init (FuPlugin *self) FuPluginPrivate *priv = GET_PRIVATE (self); priv->enabled = TRUE; g_rw_lock_init (&priv->devices_mutex); - for (guint i = 0; i < FU_PLUGIN_RULE_LAST; i++) - priv->rules[i] = g_ptr_array_new_with_free_func (g_free); } static void @@ -2781,9 +2783,10 @@ fu_plugin_finalize (GObject *object) } } - for (guint i = 0; i < FU_PLUGIN_RULE_LAST; i++) - g_ptr_array_unref (priv->rules[i]); - + for (guint i = 0; i < FU_PLUGIN_RULE_LAST; i++) { + if (priv->rules[i] != NULL) + g_ptr_array_unref (priv->rules[i]); + } if (priv->usb_ctx != NULL) g_object_unref (priv->usb_ctx); if (priv->hwids != NULL) diff --git a/src/fu-engine.c b/src/fu-engine.c index ae003ca97..e7cce7100 100644 --- a/src/fu-engine.c +++ b/src/fu-engine.c @@ -1714,23 +1714,25 @@ fu_engine_create_release_metadata (FuEngine *self, /* allow other plugins to contribute metadata too */ metadata_sources = fu_plugin_get_rules (plugin, FU_PLUGIN_RULE_METADATA_SOURCE); - for (guint i = 0; i < metadata_sources->len; i++) { - FuPlugin *plugin_tmp; - const gchar *plugin_name = g_ptr_array_index (metadata_sources, i); - g_autoptr(GError) error_local = NULL; + if (metadata_sources != NULL) { + for (guint i = 0; i < metadata_sources->len; i++) { + FuPlugin *plugin_tmp; + const gchar *plugin_name = g_ptr_array_index (metadata_sources, i); + g_autoptr(GError) error_local = NULL; - plugin_tmp = fu_plugin_list_find_by_name (self->plugin_list, - plugin_name, - &error_local); - if (plugin_tmp == NULL) { - g_warning ("could not add metadata for %s: %s", - plugin_name, - error_local->message); - continue; - } - if (fu_plugin_get_report_metadata (plugin_tmp) != NULL) { - fwupd_release_add_metadata (release, - fu_plugin_get_report_metadata (plugin_tmp)); + plugin_tmp = fu_plugin_list_find_by_name (self->plugin_list, + plugin_name, + &error_local); + if (plugin_tmp == NULL) { + g_warning ("could not add metadata for %s: %s", + plugin_name, + error_local->message); + continue; + } + if (fu_plugin_get_report_metadata (plugin_tmp) != NULL) { + fwupd_release_add_metadata (release, + fu_plugin_get_report_metadata (plugin_tmp)); + } } } return g_steal_pointer (&release); @@ -4940,6 +4942,8 @@ fu_engine_plugin_rules_changed_cb (FuPlugin *plugin, gpointer user_data) { FuEngine *self = FU_ENGINE (user_data); GPtrArray *rules = fu_plugin_get_rules (plugin, FU_PLUGIN_RULE_INHIBITS_IDLE); + if (rules == NULL) + return; for (guint j = 0; j < rules->len; j++) { const gchar *tmp = g_ptr_array_index (rules, j); fu_idle_inhibit (self->idle, tmp); diff --git a/src/fu-plugin-list.c b/src/fu-plugin-list.c index 08cb3b7eb..5283a5278 100644 --- a/src/fu-plugin-list.c +++ b/src/fu-plugin-list.c @@ -145,6 +145,8 @@ fu_plugin_list_depsolve (FuPluginList *self, GError **error) for (guint i = 0; i < self->plugins->len; i++) { FuPlugin *plugin = g_ptr_array_index (self->plugins, i); deps = fu_plugin_get_rules (plugin, FU_PLUGIN_RULE_RUN_AFTER); + if (deps == NULL) + continue; for (guint j = 0; j < deps->len && !changes; j++) { const gchar *plugin_name = g_ptr_array_index (deps, j); dep = fu_plugin_list_find_by_name (self, plugin_name, NULL); @@ -173,6 +175,8 @@ fu_plugin_list_depsolve (FuPluginList *self, GError **error) for (guint i = 0; i < self->plugins->len; i++) { FuPlugin *plugin = g_ptr_array_index (self->plugins, i); deps = fu_plugin_get_rules (plugin, FU_PLUGIN_RULE_RUN_BEFORE); + if (deps == NULL) + continue; for (guint j = 0; j < deps->len && !changes; j++) { const gchar *plugin_name = g_ptr_array_index (deps, j); dep = fu_plugin_list_find_by_name (self, plugin_name, NULL); @@ -203,6 +207,8 @@ fu_plugin_list_depsolve (FuPluginList *self, GError **error) for (guint i = 0; i < self->plugins->len; i++) { FuPlugin *plugin = g_ptr_array_index (self->plugins, i); deps = fu_plugin_get_rules (plugin, FU_PLUGIN_RULE_BETTER_THAN); + if (deps == NULL) + continue; for (guint j = 0; j < deps->len && !changes; j++) { const gchar *plugin_name = g_ptr_array_index (deps, j); dep = fu_plugin_list_find_by_name (self, plugin_name, NULL); @@ -245,6 +251,8 @@ fu_plugin_list_depsolve (FuPluginList *self, GError **error) if (!fu_plugin_get_enabled (plugin)) continue; deps = fu_plugin_get_rules (plugin, FU_PLUGIN_RULE_CONFLICTS); + if (deps == NULL) + continue; for (guint j = 0; j < deps->len && !changes; j++) { const gchar *plugin_name = g_ptr_array_index (deps, j); dep = fu_plugin_list_find_by_name (self, plugin_name, NULL); From aae22e4df56e3d3592ac1c2ab610592f8266b41a Mon Sep 17 00:00:00 2001 From: Richard Hughes Date: Mon, 22 Jun 2020 21:32:59 +0100 Subject: [PATCH 195/607] trivial: Always clear the mutex before clearing the thing it protects --- libfwupdplugin/fu-device.c | 5 +++-- libfwupdplugin/fu-plugin.c | 3 ++- src/fu-device-list.c | 3 ++- src/fu-history.c | 3 ++- src/fu-idle.c | 2 +- 5 files changed, 10 insertions(+), 6 deletions(-) diff --git a/libfwupdplugin/fu-device.c b/libfwupdplugin/fu-device.c index b2c3998bd..c51f7a2b0 100644 --- a/libfwupdplugin/fu-device.c +++ b/libfwupdplugin/fu-device.c @@ -3230,6 +3230,9 @@ fu_device_finalize (GObject *object) FuDevice *self = FU_DEVICE (object); FuDevicePrivate *priv = GET_PRIVATE (self); + g_rw_lock_clear (&priv->metadata_mutex); + g_rw_lock_clear (&priv->parent_guids_mutex); + if (priv->alternate != NULL) g_object_unref (priv->alternate); if (priv->parent != NULL) @@ -3242,8 +3245,6 @@ fu_device_finalize (GObject *object) g_source_remove (priv->poll_id); if (priv->metadata != NULL) g_hash_table_unref (priv->metadata); - g_rw_lock_clear (&priv->metadata_mutex); - g_rw_lock_clear (&priv->parent_guids_mutex); g_ptr_array_unref (priv->children); g_ptr_array_unref (priv->parent_guids); g_ptr_array_unref (priv->possible_plugins); diff --git a/libfwupdplugin/fu-plugin.c b/libfwupdplugin/fu-plugin.c index f4881c089..36a1a3612 100644 --- a/libfwupdplugin/fu-plugin.c +++ b/libfwupdplugin/fu-plugin.c @@ -2774,6 +2774,8 @@ fu_plugin_finalize (GObject *object) FuPluginPrivate *priv = GET_PRIVATE (self); FuPluginInitFunc func = NULL; + g_rw_lock_clear (&priv->devices_mutex); + /* optional */ if (priv->module != NULL) { g_module_symbol (priv->module, "fu_plugin_destroy", (gpointer *) &func); @@ -2805,7 +2807,6 @@ fu_plugin_finalize (GObject *object) g_hash_table_unref (priv->report_metadata); if (priv->devices != NULL) g_hash_table_unref (priv->devices); - g_rw_lock_clear (&priv->devices_mutex); g_free (priv->build_hash); g_free (priv->name); g_free (priv->data); diff --git a/src/fu-device-list.c b/src/fu-device-list.c index 4081006e5..9f503596e 100644 --- a/src/fu-device-list.c +++ b/src/fu-device-list.c @@ -947,11 +947,12 @@ fu_device_list_finalize (GObject *obj) { FuDeviceList *self = FU_DEVICE_LIST (obj); + g_rw_lock_clear (&self->devices_mutex); + if (self->replug_id != 0) g_source_remove (self->replug_id); g_ptr_array_unref (self->devices); g_main_loop_unref (self->replug_loop); - g_rw_lock_clear (&self->devices_mutex); G_OBJECT_CLASS (fu_device_list_parent_class)->finalize (obj); } diff --git a/src/fu-history.c b/src/fu-history.c index d9f09813f..e3132267d 100644 --- a/src/fu-history.c +++ b/src/fu-history.c @@ -1082,9 +1082,10 @@ fu_history_finalize (GObject *object) { FuHistory *self = FU_HISTORY (object); + g_rw_lock_clear (&self->db_mutex); + if (self->db != NULL) sqlite3_close (self->db); - g_rw_lock_clear (&self->db_mutex); G_OBJECT_CLASS (fu_history_parent_class)->finalize (object); } diff --git a/src/fu-idle.c b/src/fu-idle.c index 5873e4c8e..796f6bcb1 100644 --- a/src/fu-idle.c +++ b/src/fu-idle.c @@ -222,8 +222,8 @@ fu_idle_finalize (GObject *obj) FuIdle *self = FU_IDLE (obj); fu_idle_stop (self); - g_ptr_array_unref (self->items); g_rw_lock_clear (&self->items_mutex); + g_ptr_array_unref (self->items); G_OBJECT_CLASS (fu_idle_parent_class)->finalize (obj); } From 5521e47511a45048471b38e7fcb43a81c3342e37 Mon Sep 17 00:00:00 2001 From: Mario Limonciello Date: Mon, 22 Jun 2020 13:34:05 -0500 Subject: [PATCH 196/607] trivial: add Vendor ID into Modem manager devices Fixes: #2200 --- plugins/modem-manager/modem-manager.quirk | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/plugins/modem-manager/modem-manager.quirk b/plugins/modem-manager/modem-manager.quirk index b110d7c6c..55101c4d7 100644 --- a/plugins/modem-manager/modem-manager.quirk +++ b/plugins/modem-manager/modem-manager.quirk @@ -3,38 +3,46 @@ [DeviceInstanceId=USB\VID_413C&PID_81D7] Summary = Dell DW5821e LTE modem CounterpartGuid = USB\VID_413C&PID_81D6 +VendorId = USB:0x413C # DW5821e in fastboot mode [DeviceInstanceId=USB\VID_413C&PID_81D6] Summary = Dell DW5821e LTE modem (fastboot) CounterpartGuid = USB\VID_413C&PID_81D7 +VendorId = USB:0x413C # DW5821e/eSIM [DeviceInstanceId=USB\VID_413C&PID_81E0] Summary = Dell DW5821e/eSIM LTE modem CounterpartGuid = USB\VID_413C&PID_81E1 +VendorId = USB:0x413C # DW5821e/eSIM in fastboot mode [DeviceInstanceId=USB\VID_413C&PID_81E1] Summary = Dell DW5821e/eSIM LTE modem (fastboot) CounterpartGuid = USB\VID_413C&PID_81E0 +VendorId = USB:0x413C # T77W968 [DeviceInstanceId=USB\VID_0489&PID_E0B4] Summary = Foxconn T77w968 LTE modem CounterpartGuid = USB\VID_0489&PID_E0B7 +VendorId = USB:0x0489 # T77W968 in fastboot mode [DeviceInstanceId=USB\VID_0489&PID_E0B7] Summary = Foxconn T77w968 LTE modem (fastboot) CounterpartGuid = USB\VID_0489&PID_E0B4 +VendorId = USB:0x0489 # T77W968/eSIM [DeviceInstanceId=USB\VID_0489&PID_E0B5] Summary = Foxconn T77w968/eSIM LTE modem CounterpartGuid = USB\VID_0489&PID_E0B8 +VendorId = USB:0x0489 # T77W968/eSIM in fastboot mode [DeviceInstanceId=USB\VID_0489&PID_E0B8] Summary = Foxconn T77w968/eSIM LTE modem (fastboot) CounterpartGuid = USB\VID_0489&PID_E0B5 +VendorId = USB:0x0489 From 412e170b26774764bf1b6547826d0f75b4b86c49 Mon Sep 17 00:00:00 2001 From: Mario Limonciello Date: Mon, 22 Jun 2020 13:07:38 -0500 Subject: [PATCH 197/607] trivial: libfwupdplugin: add a new method to write strings to sysfs files --- libfwupdplugin/fu-udev-device.c | 73 +++++++++++++++++++++++++++++++++ libfwupdplugin/fu-udev-device.h | 5 +++ libfwupdplugin/fwupdplugin.map | 1 + 3 files changed, 79 insertions(+) diff --git a/libfwupdplugin/fu-udev-device.c b/libfwupdplugin/fu-udev-device.c index 5aa79d3d1..6c40adf9a 100644 --- a/libfwupdplugin/fu-udev-device.c +++ b/libfwupdplugin/fu-udev-device.c @@ -1168,6 +1168,79 @@ fu_udev_device_pread (FuUdevDevice *self, goffset port, guint8 *data, GError **e return fu_udev_device_pread_full (self, port, data, 0x1, error); } + +/** + * fu_udev_device_write_sysfs: + * @self: A #FuUdevDevice + * @attribute: sysfs attribute name + * @val: data to write into the attribute + * @error: A #GError, or %NULL + * + * Writes data into a sysfs attribute + * + * Returns: %TRUE for success + * + * Since: 1.5.0 + **/ +gboolean +fu_udev_device_write_sysfs (FuUdevDevice *self, const gchar *attribute, + const gchar *val, GError **error) +{ +#ifndef _WIN32 + ssize_t n; + int r; + int fd; + g_autofree gchar *path = NULL; + + g_return_val_if_fail (FU_IS_UDEV_DEVICE (self), FALSE); + g_return_val_if_fail (attribute != NULL, FALSE); + g_return_val_if_fail (val != NULL, FALSE); + + path = g_build_filename (fu_udev_device_get_sysfs_path (self), + attribute, NULL); + fd = open (path, O_WRONLY | O_CLOEXEC); + if (fd < 0) { + g_set_error (error, G_IO_ERROR, + g_io_error_from_errno (errno), + "could not open %s: %s", + path, + g_strerror (errno)); + return FALSE; + } + + do { + n = write (fd, val, strlen (val)); + if (n < 1 && errno != EINTR) { + g_set_error (error, G_IO_ERROR, + g_io_error_from_errno (errno), + "could not write to %s: %s", + path, + g_strerror (errno)); + (void) close (fd); + return FALSE; + } + } while (n < 1); + + r = close (fd); + if (r < 0 && errno != EINTR) { + g_set_error (error, G_IO_ERROR, + g_io_error_from_errno (errno), + "could not close %s: %s", + path, + g_strerror (errno)); + return FALSE; + } + + return TRUE; +#else + g_set_error_literal (error, + FWUPD_ERROR, + FWUPD_ERROR_NOT_SUPPORTED, + "sysfs attributes not supported on Windows"); + return FALSE; +#endif +} + static void fu_udev_device_get_property (GObject *object, guint prop_id, GValue *value, GParamSpec *pspec) diff --git a/libfwupdplugin/fu-udev-device.h b/libfwupdplugin/fu-udev-device.h index 9b8115419..d181258d5 100644 --- a/libfwupdplugin/fu-udev-device.h +++ b/libfwupdplugin/fu-udev-device.h @@ -101,3 +101,8 @@ const gchar *fu_udev_device_get_sysfs_attr (FuUdevDevice *self, const gchar *attr, GError **error); gchar *fu_udev_device_get_parent_name (FuUdevDevice *self); + +gboolean fu_udev_device_write_sysfs (FuUdevDevice *self, + const gchar *attribute, + const gchar *val, + GError **error); diff --git a/libfwupdplugin/fwupdplugin.map b/libfwupdplugin/fwupdplugin.map index 44eeb027f..d989dfd21 100644 --- a/libfwupdplugin/fwupdplugin.map +++ b/libfwupdplugin/fwupdplugin.map @@ -603,5 +603,6 @@ LIBFWUPDPLUGIN_1.5.0 { fu_udev_device_get_sysfs_attr; fu_udev_device_pread_full; fu_udev_device_pwrite_full; + fu_udev_device_write_sysfs; local: *; } LIBFWUPDPLUGIN_1.4.1; From 834b28009d7e8fab9d37621456973a51a521c284 Mon Sep 17 00:00:00 2001 From: Mario Limonciello Date: Tue, 5 May 2020 21:06:36 -0500 Subject: [PATCH 198/607] Add support for a delayed activation flow for Thunderbolt This allows delaying the activation of Thunderbolt firmware until shutdown/reboot or when the dock is unplugged. This functionality requires features in the kernel: https://lore.kernel.org/linux-usb/20200622143035.25327-1-mario.limonciello@dell.com/T/#t Matrix of cases to support: * Distro Old Linux kernel (doesn't support authenticate on disconnect) - WD19TB: Should have `skips-restart` flag set No flush or activate features called in `thunderbolt` plugin. `dell_dock` plugin will activate at end of composite update - All other devices: Shouldn't have flags set Should authenticate in Thunderbolt plugin. `1 > nvm_authenticate` * Distro New Linux kernel (supports authenticate on disconnect) - WD19TB: Should have `usable-during-update` flag set but not `skips-restart` Should flush image to SPI in `thunderbolt` plugin `2 > nvm_authenticate_on_disconnect` Should configure TBT device for authenticate on disconnect `1 > nvm_authenticate_on_disconnect` `dell_dock` plugin will configure dock for authenticate on disconnect - All other devices: Shouldn't have flags set Should authenticate in `thunderbolt` plugin. `1 > nvm_authenticate` * ChromeOS (supports authenticate on disconnect) - `thunerbolt.conf` will have `DelayedActivation=true`. - WD19TB: Should have `usable-during-update` flag set but not `skips-restart` Should flush image to SPI in `thunderbolt` plugin `2 > nvm_authenticate_on_disconnect` Should configure device for authenticate on disconnect `1 > nvm_authenticate_on_disconnect` `dell_dock` plugin will configure dock for authenticate on disconnect - All other devices: Should have both `usable-during-update` and `skips-restart` set Should flush image to SPI in `thunderbolt` plugin `2 > nvm_authenticate` Will activate upon logout/shutdown/reboot `1 > nvm_authenticate` --- plugins/dell-dock/fu-plugin-dell-dock.c | 30 +++++--- plugins/thunderbolt/fu-plugin-thunderbolt.c | 15 ++++ plugins/thunderbolt/fu-thunderbolt-device.c | 83 +++++++++++---------- plugins/thunderbolt/thunderbolt.conf | 3 + 4 files changed, 81 insertions(+), 50 deletions(-) diff --git a/plugins/dell-dock/fu-plugin-dell-dock.c b/plugins/dell-dock/fu-plugin-dell-dock.c index d6680b72f..2d5a2aac5 100644 --- a/plugins/dell-dock/fu-plugin-dell-dock.c +++ b/plugins/dell-dock/fu-plugin-dell-dock.c @@ -185,11 +185,29 @@ fu_plugin_composite_cleanup (FuPlugin *plugin, GError **error) { FuDevice *parent = fu_plugin_dell_dock_get_ec (devices); + FuDevice *dev = NULL; g_autoptr(FuDeviceLocker) locker = NULL; + gboolean needs_activation = FALSE; if (parent == NULL) return TRUE; + /* if thunderbolt is in the transaction it needs to be activated separately */ + for (guint i = 0; i < devices->len; i++) { + dev = g_ptr_array_index (devices, i); + if (g_strcmp0 (fu_device_get_plugin (dev), "thunderbolt") == 0 && + fu_device_has_flag (dev, FWUPD_DEVICE_FLAG_NEEDS_ACTIVATION)) { + /* the kernel and/or thunderbolt plugin have been configured to let HW finish the update */ + if (fu_device_has_flag (dev, FWUPD_DEVICE_FLAG_USABLE_DURING_UPDATE)) { + fu_dell_dock_ec_tbt_passive (parent); + /* run the update immediately - no kernel support */ + } else { + needs_activation = TRUE; + break; + } + } + } + locker = fu_device_locker_new (parent, error); if (locker == NULL) return FALSE; @@ -201,15 +219,9 @@ fu_plugin_composite_cleanup (FuPlugin *plugin, if (!fu_device_locker_close (locker, error)) return FALSE; - /* if thunderbolt is in the transaction it needs to be activated separately */ - for (guint i = 0; i < devices->len; i++) { - FuDevice *dev = g_ptr_array_index (devices, i); - if (g_strcmp0 (fu_device_get_plugin (dev), "thunderbolt") == 0 && - fu_device_has_flag (dev, FWUPD_DEVICE_FLAG_NEEDS_ACTIVATION)) { - if (!fu_device_activate (dev, error)) - return FALSE; - break; - } + if (needs_activation && dev != NULL) { + if (!fu_device_activate (dev, error)) + return FALSE; } return TRUE; diff --git a/plugins/thunderbolt/fu-plugin-thunderbolt.c b/plugins/thunderbolt/fu-plugin-thunderbolt.c index e67952d8d..ea8a00805 100644 --- a/plugins/thunderbolt/fu-plugin-thunderbolt.c +++ b/plugins/thunderbolt/fu-plugin-thunderbolt.c @@ -56,6 +56,21 @@ fu_plugin_device_created (FuPlugin *plugin, FuDevice *dev, GError **error) return TRUE; } +void +fu_plugin_device_registered (FuPlugin *plugin, FuDevice *device) +{ + if (g_strcmp0 (fu_device_get_plugin (device), "thunderbolt") != 0) + return; + + /* Operating system will handle finishing updates later */ + if (fu_plugin_get_config_value_boolean (plugin, "DelayedActivation")) { + g_debug ("Turning on delayed activation for %s", + fu_device_get_name (device)); + fu_device_add_flag (device, FWUPD_DEVICE_FLAG_USABLE_DURING_UPDATE); + fu_device_add_flag (device, FWUPD_DEVICE_FLAG_SKIPS_RESTART); + } +} + void fu_plugin_init (FuPlugin *plugin) { diff --git a/plugins/thunderbolt/fu-thunderbolt-device.c b/plugins/thunderbolt/fu-thunderbolt-device.c index ec25799ed..6262a1f04 100644 --- a/plugins/thunderbolt/fu-thunderbolt-device.c +++ b/plugins/thunderbolt/fu-thunderbolt-device.c @@ -28,6 +28,7 @@ struct _FuThunderboltDevice { gboolean is_native; guint16 gen; gchar *devpath; + const gchar *auth_method; }; #define TBT_NVM_RETRY_TIMEOUT 200 /* ms */ @@ -178,6 +179,7 @@ fu_thunderbolt_device_to_string (FuDevice *device, guint idt, GString *str) fu_common_string_append_kb (str, idt, "Safe Mode", self->safe_mode); fu_common_string_append_kb (str, idt, "Native mode", self->is_native); fu_common_string_append_ku (str, idt, "Generation", self->gen); + fu_common_string_append_kv (str, idt, "AuthAttribute", self->auth_method); } static gboolean @@ -321,52 +323,39 @@ fu_thunderbolt_device_setup (FuDevice *device, GError **error) fu_device_add_instance_id (device, domain_id); } + /* determine if we can update on unplug */ + if (fu_udev_device_get_sysfs_attr (FU_UDEV_DEVICE (device), + "nvm_authenticate_on_disconnect", + NULL) != NULL) { + self->auth_method = "nvm_authenticate_on_disconnect"; + /* flushes image */ + fu_device_add_flag (device, FWUPD_DEVICE_FLAG_USABLE_DURING_UPDATE); + /* forces the device to write to authenticate on disconnect attribute */ + fu_device_remove_flag (device, FWUPD_DEVICE_FLAG_SKIPS_RESTART); + } else { + self->auth_method = "nvm_authenticate"; + } + /* success */ return TRUE; } static gboolean -fu_thunderbolt_device_trigger_update (FuDevice *device, GError **error) +fu_thunderbolt_device_authenticate (FuDevice *device, GError **error) { FuThunderboltDevice *self = FU_THUNDERBOLT_DEVICE (device); - ssize_t n; - int fd; - int r; - g_autofree gchar *auth_path = NULL; + FuUdevDevice *udev = FU_UDEV_DEVICE (device); - auth_path = g_build_filename (self->devpath, "nvm_authenticate", NULL); + return fu_udev_device_write_sysfs (udev, self->auth_method, "1", error); +} - fd = open (auth_path, O_WRONLY | O_CLOEXEC); - if (fd < 0) { - g_set_error (error, G_IO_ERROR, - g_io_error_from_errno (errno), - "could not open 'nvm_authenticate': %s", - g_strerror (errno)); - return FALSE; - } +static gboolean +fu_thunderbolt_device_flush_update (FuDevice *device, GError **error) +{ + FuThunderboltDevice *self = FU_THUNDERBOLT_DEVICE (device); + FuUdevDevice *udev = FU_UDEV_DEVICE (device); - do { - n = write (fd, "1", 1); - if (n < 1 && errno != EINTR) { - g_set_error (error, G_IO_ERROR, - g_io_error_from_errno (errno), - "could not write to 'nvm_authenticate': %s", - g_strerror (errno)); - (void) close (fd); - return FALSE; - } - } while (n < 1); - - r = close (fd); - if (r < 0 && errno != EINTR) { - g_set_error (error, G_IO_ERROR, - g_io_error_from_errno (errno), - "could not close 'nvm_authenticate': %s", - g_strerror (errno)); - return FALSE; - } - - return TRUE; + return fu_udev_device_write_sysfs (udev, self->auth_method, "2", error); } static gboolean @@ -577,20 +566,32 @@ fu_thunderbolt_device_write_firmware (FuDevice *device, return FALSE; } + /* flush the image if supported by kernel and/or device */ + if (fu_device_has_flag (device, FWUPD_DEVICE_FLAG_USABLE_DURING_UPDATE)) { + if (!fu_thunderbolt_device_flush_update (device, error)) + return FALSE; + fu_device_add_flag (device, FWUPD_DEVICE_FLAG_NEEDS_ACTIVATION); + } + + /* using an active delayed activation flow later (either shutdown or another plugin) */ if (fu_device_has_flag (device, FWUPD_DEVICE_FLAG_SKIPS_RESTART)) { g_debug ("Skipping Thunderbolt reset per quirk request"); fu_device_add_flag (device, FWUPD_DEVICE_FLAG_NEEDS_ACTIVATION); return TRUE; } - if (!fu_thunderbolt_device_trigger_update (FU_DEVICE (self), error)) { + /* authenticate (possibly on unplug if device supports it) */ + if (!fu_thunderbolt_device_authenticate (FU_DEVICE (self), error)) { g_prefix_error (error, "could not start thunderbolt device upgrade: "); return FALSE; } - fu_device_set_status (device, FWUPD_STATUS_DEVICE_RESTART); - fu_device_set_remove_delay (device, FU_PLUGIN_THUNDERBOLT_UPDATE_TIMEOUT); - fu_device_add_flag (device, FWUPD_DEVICE_FLAG_WAIT_FOR_REPLUG); + /* whether to wait for a device replug or not */ + if (!fu_device_has_flag (device, FWUPD_DEVICE_FLAG_USABLE_DURING_UPDATE)) { + fu_device_set_status (device, FWUPD_STATUS_DEVICE_RESTART); + fu_device_set_remove_delay (device, FU_PLUGIN_THUNDERBOLT_UPDATE_TIMEOUT); + fu_device_add_flag (device, FWUPD_DEVICE_FLAG_WAIT_FOR_REPLUG); + } return TRUE; } @@ -619,7 +620,7 @@ fu_thunderbolt_device_class_init (FuThunderboltDeviceClass *klass) FuDeviceClass *klass_device = FU_DEVICE_CLASS (klass); FuUdevDeviceClass *klass_udev_device = FU_UDEV_DEVICE_CLASS (klass); object_class->finalize = fu_thunderbolt_device_finalize; - klass_device->activate = fu_thunderbolt_device_trigger_update; + klass_device->activate = fu_thunderbolt_device_authenticate; klass_device->to_string = fu_thunderbolt_device_to_string; klass_device->setup = fu_thunderbolt_device_setup; klass_device->prepare_firmware = fu_thunderbolt_device_prepare_firmware; diff --git a/plugins/thunderbolt/thunderbolt.conf b/plugins/thunderbolt/thunderbolt.conf index 72dc0e4ee..d6a61d169 100644 --- a/plugins/thunderbolt/thunderbolt.conf +++ b/plugins/thunderbolt/thunderbolt.conf @@ -4,3 +4,6 @@ # It's important that all backports from this kernel have been # made if using an older kernel MinimumKernelVersion=4.13.0 + +# Forces delaying activation until shutdown/logout/reboot +DelayedActivation=false From e2a77fc10b8de1b90b5336deb2de3647b2f88675 Mon Sep 17 00:00:00 2001 From: Mario Limonciello Date: Mon, 22 Jun 2020 20:18:05 -0500 Subject: [PATCH 199/607] trivial: modem-manager: add a protocol for updating the devices --- plugins/modem-manager/README.md | 3 +++ plugins/modem-manager/fu-mm-device.c | 4 ++++ 2 files changed, 7 insertions(+) diff --git a/plugins/modem-manager/README.md b/plugins/modem-manager/README.md index 30da0c96d..a2ab7645e 100644 --- a/plugins/modem-manager/README.md +++ b/plugins/modem-manager/README.md @@ -32,6 +32,8 @@ as defined e.g. in the 'flashfile.xml' file. Every file included in the CAB that is not listed in the associated 'flashfile.xml' will be totally ignored during the fastboot upgrade procedure. +Update Protocol: com.google.fastboot + Update method: qmi-pdc ---------------------- @@ -45,3 +47,4 @@ operation will always be run before the QMI operation, so that e.g. the full partition where the MCFG files are stored can be wiped out before installing the new ones. +Update protocol: com.qualcomm.qmi_pdc diff --git a/plugins/modem-manager/fu-mm-device.c b/plugins/modem-manager/fu-mm-device.c index e77dc31e1..8d8af9b5f 100644 --- a/plugins/modem-manager/fu-mm-device.c +++ b/plugins/modem-manager/fu-mm-device.c @@ -180,6 +180,7 @@ fu_mm_device_probe_default (FuDevice *device, GError **error) break; } } + fu_device_set_protocol (device, "com.google.fastboot"); } if (self->update_methods & MM_MODEM_FIRMWARE_UPDATE_METHOD_QMI_PDC) { for (guint i = 0; i < n_ports; i++) { @@ -189,6 +190,9 @@ fu_mm_device_probe_default (FuDevice *device, GError **error) break; } } + /* only set if fastboot wasn't already set */ + if (fu_device_get_protocol (device) != NULL) + fu_device_set_protocol (device, "com.qualcomm.qmi_pdc"); } mm_modem_port_info_array_free (ports, n_ports); From 50638657cc87d1c114af59f83b543943dd9c4b77 Mon Sep 17 00:00:00 2001 From: Mario Limonciello Date: Mon, 22 Jun 2020 20:33:41 -0500 Subject: [PATCH 200/607] modem-manager: read the vendor ID directly from sysfs attribute Fixes: #2209 --- plugins/modem-manager/fu-mm-device.c | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/plugins/modem-manager/fu-mm-device.c b/plugins/modem-manager/fu-mm-device.c index 8d8af9b5f..b8a6dedfc 100644 --- a/plugins/modem-manager/fu-mm-device.c +++ b/plugins/modem-manager/fu-mm-device.c @@ -243,6 +243,18 @@ fu_mm_device_probe_default (FuDevice *device, GError **error) fu_device_set_version (device, version); for (guint i = 0; device_ids[i] != NULL; i++) fu_device_add_instance_id (device, device_ids[i]); + if (fu_device_get_vendor_id (device) == NULL) { + g_autofree gchar *path = g_build_filename (device_sysfs_path, "idVendor", NULL); + g_autofree gchar *value = NULL; + g_autoptr(GError) error_local = NULL; + + if (!g_file_get_contents (path, &value, NULL, &error_local)) { + g_warning ("failed to set vendor ID: %s", error_local->message); + } else { + g_autofree gchar *vendor_id = g_strdup_printf ("USB:0x%s", value); + fu_device_set_vendor_id (device, vendor_id); + } + } /* convert the instance IDs to GUIDs */ fu_device_convert_instance_ids (device); From 752dc715ea3f3d2a46d4cf793cd472319bbfa3a1 Mon Sep 17 00:00:00 2001 From: Mario Limonciello Date: Mon, 22 Jun 2020 20:34:21 -0500 Subject: [PATCH 201/607] Revert "trivial: add Vendor ID into Modem manager devices" This reverts commit 5521e47511a45048471b38e7fcb43a81c3342e37. --- plugins/modem-manager/modem-manager.quirk | 8 -------- 1 file changed, 8 deletions(-) diff --git a/plugins/modem-manager/modem-manager.quirk b/plugins/modem-manager/modem-manager.quirk index 55101c4d7..b110d7c6c 100644 --- a/plugins/modem-manager/modem-manager.quirk +++ b/plugins/modem-manager/modem-manager.quirk @@ -3,46 +3,38 @@ [DeviceInstanceId=USB\VID_413C&PID_81D7] Summary = Dell DW5821e LTE modem CounterpartGuid = USB\VID_413C&PID_81D6 -VendorId = USB:0x413C # DW5821e in fastboot mode [DeviceInstanceId=USB\VID_413C&PID_81D6] Summary = Dell DW5821e LTE modem (fastboot) CounterpartGuid = USB\VID_413C&PID_81D7 -VendorId = USB:0x413C # DW5821e/eSIM [DeviceInstanceId=USB\VID_413C&PID_81E0] Summary = Dell DW5821e/eSIM LTE modem CounterpartGuid = USB\VID_413C&PID_81E1 -VendorId = USB:0x413C # DW5821e/eSIM in fastboot mode [DeviceInstanceId=USB\VID_413C&PID_81E1] Summary = Dell DW5821e/eSIM LTE modem (fastboot) CounterpartGuid = USB\VID_413C&PID_81E0 -VendorId = USB:0x413C # T77W968 [DeviceInstanceId=USB\VID_0489&PID_E0B4] Summary = Foxconn T77w968 LTE modem CounterpartGuid = USB\VID_0489&PID_E0B7 -VendorId = USB:0x0489 # T77W968 in fastboot mode [DeviceInstanceId=USB\VID_0489&PID_E0B7] Summary = Foxconn T77w968 LTE modem (fastboot) CounterpartGuid = USB\VID_0489&PID_E0B4 -VendorId = USB:0x0489 # T77W968/eSIM [DeviceInstanceId=USB\VID_0489&PID_E0B5] Summary = Foxconn T77w968/eSIM LTE modem CounterpartGuid = USB\VID_0489&PID_E0B8 -VendorId = USB:0x0489 # T77W968/eSIM in fastboot mode [DeviceInstanceId=USB\VID_0489&PID_E0B8] Summary = Foxconn T77w968/eSIM LTE modem (fastboot) CounterpartGuid = USB\VID_0489&PID_E0B5 -VendorId = USB:0x0489 From f7d83a2f45187ab5025a35aa1e86b21615c21fb2 Mon Sep 17 00:00:00 2001 From: Mario Limonciello Date: Tue, 23 Jun 2020 08:44:21 -0500 Subject: [PATCH 202/607] trivial: modem-manager: fix a logic error --- plugins/modem-manager/fu-mm-device.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugins/modem-manager/fu-mm-device.c b/plugins/modem-manager/fu-mm-device.c index b8a6dedfc..2ee8bc8a4 100644 --- a/plugins/modem-manager/fu-mm-device.c +++ b/plugins/modem-manager/fu-mm-device.c @@ -191,7 +191,7 @@ fu_mm_device_probe_default (FuDevice *device, GError **error) } } /* only set if fastboot wasn't already set */ - if (fu_device_get_protocol (device) != NULL) + if (fu_device_get_protocol (device) == NULL) fu_device_set_protocol (device, "com.qualcomm.qmi_pdc"); } mm_modem_port_info_array_free (ports, n_ports); From 4a4377fab0329c08b83ec7d5d508adda1c74af2f Mon Sep 17 00:00:00 2001 From: Richard Hughes Date: Tue, 23 Jun 2020 14:02:54 +0100 Subject: [PATCH 203/607] Disable the SQLite lookaside cache This saves ~45Kb of RSS and has no measurable slowdown when reading from the pending database. --- src/fu-history.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/fu-history.c b/src/fu-history.c index e3132267d..96db6bd91 100644 --- a/src/fu-history.c +++ b/src/fu-history.c @@ -360,6 +360,9 @@ fu_history_open (FuHistory *self, const gchar *filename, GError **error) filename, sqlite3_errmsg (self->db)); return FALSE; } + + /* turn off the lookaside cache */ + sqlite3_db_config (self->db, SQLITE_DBCONFIG_LOOKASIDE, NULL, 0, 0); return TRUE; } From 664b8aa9ad595992c8f683fe56dd7c5da81698b7 Mon Sep 17 00:00:00 2001 From: Richard Hughes Date: Mon, 22 Jun 2020 21:22:42 +0100 Subject: [PATCH 204/607] Add XB_QUERY_FLAG_FORCE_NODE_CACHE Newer versions of libxmlb do not auto-cache XbNodes, and we have to opt-into this beahviour for the _set_data() and _get_data() to work. Although this is a behaviour change which also increases complexity, it lowers our RSS usage by 200kB which is about a quarter of the total RSS used... --- libfwupdplugin/fu-cabinet.c | 15 +++++++++++++- libfwupdplugin/fu-self-test.c | 39 +++++++++++++++++++++++++++++++++++ src/fu-engine.c | 17 +++++++++++++++ 3 files changed, 70 insertions(+), 1 deletion(-) diff --git a/libfwupdplugin/fu-cabinet.c b/libfwupdplugin/fu-cabinet.c index ef8fe2bc7..86a87954b 100644 --- a/libfwupdplugin/fu-cabinet.c +++ b/libfwupdplugin/fu-cabinet.c @@ -657,6 +657,7 @@ fu_cabinet_parse (FuCabinet *self, { g_autoptr(GError) error_local = NULL; g_autoptr(GPtrArray) components = NULL; + g_autoptr(XbQuery) query = NULL; g_return_val_if_fail (FU_IS_CABINET (self), FALSE); g_return_val_if_fail (data != NULL, FALSE); @@ -683,11 +684,23 @@ fu_cabinet_parse (FuCabinet *self, return FALSE; } + /* prepare query */ + query = xb_query_new_full (self->silo, + "releases/release", +#if LIBXMLB_CHECK_VERSION(0,2,0) + XB_QUERY_FLAG_FORCE_NODE_CACHE, +#else + XB_QUERY_FLAG_NONE, +#endif + error); + if (query == NULL) + return FALSE; + /* process each listed release */ for (guint i = 0; i < components->len; i++) { XbNode *component = g_ptr_array_index (components, i); g_autoptr(GPtrArray) releases = NULL; - releases = xb_node_query (component, "releases/release", 0, &error_local); + releases = xb_node_query_full (component, query, &error_local); if (releases == NULL) { g_set_error (error, FWUPD_ERROR, diff --git a/libfwupdplugin/fu-self-test.c b/libfwupdplugin/fu-self-test.c index 3a2d49c59..245a69232 100644 --- a/libfwupdplugin/fu-self-test.c +++ b/libfwupdplugin/fu-self-test.c @@ -708,6 +708,9 @@ fu_common_store_cab_func (void) g_autoptr(XbNode) rel = NULL; g_autoptr(XbNode) req = NULL; g_autoptr(XbSilo) silo = NULL; +#if LIBXMLB_CHECK_VERSION(0,2,0) + g_autoptr(XbQuery) query = NULL; +#endif /* create silo */ blob = _build_cab (GCAB_COMPRESSION_NONE, @@ -740,7 +743,17 @@ fu_common_store_cab_func (void) component = xb_silo_query_first (silo, "components/component/id[text()='com.acme.example.firmware']/..", &error); g_assert_no_error (error); g_assert_nonnull (component); +#if LIBXMLB_CHECK_VERSION(0,2,0) + query = xb_query_new_full (xb_node_get_silo (component), + "releases/release", + XB_QUERY_FLAG_FORCE_NODE_CACHE, + &error); + g_assert_no_error (error); + g_assert_nonnull (query); + rel = xb_node_query_first_full (component, query, &error); +#else rel = xb_node_query_first (component, "releases/release", &error); +#endif g_assert_no_error (error); g_assert_nonnull (rel); g_assert_cmpstr (xb_node_get_attr (rel, "version"), ==, "1.2.3"); @@ -764,6 +777,9 @@ fu_common_store_cab_unsigned_func (void) g_autoptr(XbNode) csum = NULL; g_autoptr(XbNode) rel = NULL; g_autoptr(XbSilo) silo = NULL; +#if LIBXMLB_CHECK_VERSION(0,2,0) + g_autoptr(XbQuery) query = NULL; +#endif /* create silo */ blob = _build_cab (GCAB_COMPRESSION_NONE, @@ -784,7 +800,17 @@ fu_common_store_cab_unsigned_func (void) component = xb_silo_query_first (silo, "components/component/id[text()='com.acme.example.firmware']/..", &error); g_assert_no_error (error); g_assert_nonnull (component); +#if LIBXMLB_CHECK_VERSION(0,2,0) + query = xb_query_new_full (xb_node_get_silo (component), + "releases/release", + XB_QUERY_FLAG_FORCE_NODE_CACHE, + &error); + g_assert_no_error (error); + g_assert_nonnull (query); + rel = xb_node_query_first_full (component, query, &error); +#else rel = xb_node_query_first (component, "releases/release", &error); +#endif g_assert_no_error (error); g_assert_nonnull (rel); g_assert_cmpstr (xb_node_get_attr (rel, "version"), ==, "1.2.3"); @@ -803,6 +829,9 @@ fu_common_store_cab_folder_func (void) g_autoptr(XbNode) component = NULL; g_autoptr(XbNode) rel = NULL; g_autoptr(XbSilo) silo = NULL; +#if LIBXMLB_CHECK_VERSION(0,2,0) + g_autoptr(XbQuery) query = NULL; +#endif /* create silo */ blob = _build_cab (GCAB_COMPRESSION_NONE, @@ -823,7 +852,17 @@ fu_common_store_cab_folder_func (void) component = xb_silo_query_first (silo, "components/component/id[text()='com.acme.example.firmware']/..", &error); g_assert_no_error (error); g_assert_nonnull (component); +#if LIBXMLB_CHECK_VERSION(0,2,0) + query = xb_query_new_full (xb_node_get_silo (component), + "releases/release", + XB_QUERY_FLAG_FORCE_NODE_CACHE, + &error); + g_assert_no_error (error); + g_assert_nonnull (query); + rel = xb_node_query_first_full (component, query, &error); +#else rel = xb_node_query_first (component, "releases/release", &error); +#endif g_assert_no_error (error); g_assert_nonnull (rel); g_assert_cmpstr (xb_node_get_attr (rel, "version"), ==, "1.2.3"); diff --git a/src/fu-engine.c b/src/fu-engine.c index e7cce7100..5907ac65a 100644 --- a/src/fu-engine.c +++ b/src/fu-engine.c @@ -2136,6 +2136,9 @@ fu_engine_install (FuEngine *self, g_autoptr(FuDevice) device = NULL; g_autoptr(GError) error_local = NULL; g_autoptr(XbNode) rel_newest = NULL; +#if LIBXMLB_CHECK_VERSION(0,2,0) + g_autoptr(XbQuery) query = NULL; +#endif g_return_val_if_fail (FU_IS_ENGINE (self), FALSE); g_return_val_if_fail (XB_IS_NODE (component), FALSE); @@ -2169,7 +2172,17 @@ fu_engine_install (FuEngine *self, } /* get the newest version */ +#if LIBXMLB_CHECK_VERSION(0,2,0) + query = xb_query_new_full (xb_node_get_silo (component), + "releases/release", + XB_QUERY_FLAG_FORCE_NODE_CACHE, + error); + if (query == NULL) + return FALSE; + rel_newest = xb_node_query_first_full (component, query, &error_local); +#else rel_newest = xb_node_query_first (component, "releases/release", &error_local); +#endif if (rel_newest == NULL) { g_set_error (error, FWUPD_ERROR, @@ -2207,7 +2220,11 @@ fu_engine_install (FuEngine *self, /* install each intermediate release, or install only the newest version */ if (fu_device_has_flag (device, FWUPD_DEVICE_FLAG_INSTALL_ALL_RELEASES)) { g_autoptr(GPtrArray) rels = NULL; +#if LIBXMLB_CHECK_VERSION(0,2,0) + rels = xb_node_query_full (component, query, &error_local); +#else rels = xb_node_query (component, "releases/release", 0, &error_local); +#endif if (rels == NULL) { g_set_error (error, FWUPD_ERROR, From 35ac0727d36d4fa36e4c5880a7c93a2fe45f3fa4 Mon Sep 17 00:00:00 2001 From: Richard Hughes Date: Tue, 23 Jun 2020 15:05:14 +0100 Subject: [PATCH 205/607] Use libxmlb bound parameters to speed up te device verification This means we only parse the complicated xpath query once, rather than for every GUID the device has. The code flow is also simplified and split out into two functions. --- src/fu-engine.c | 189 +++++++++++++++++++++++++++++++++--------------- 1 file changed, 129 insertions(+), 60 deletions(-) diff --git a/src/fu-engine.c b/src/fu-engine.c index 5907ac65a..724c24275 100644 --- a/src/fu-engine.c +++ b/src/fu-engine.c @@ -785,6 +785,115 @@ fu_engine_get_component_by_guids (FuEngine *self, FuDevice *device) return NULL; } +static XbNode * +fu_engine_verify_from_local_metadata (FuEngine *self, + FuDevice *device, + GError **error) +{ + g_autofree gchar *fn = NULL; + g_autofree gchar *localstatedir = NULL; + g_autofree gchar *xpath = NULL; + g_autoptr(GFile) file = NULL; + g_autoptr(XbBuilder) builder = xb_builder_new (); + g_autoptr(XbBuilderSource) source = xb_builder_source_new (); + g_autoptr(XbNode) release = NULL; + g_autoptr(XbSilo) silo = NULL; + + localstatedir = fu_common_get_path (FU_PATH_KIND_LOCALSTATEDIR_PKG); + fn = g_strdup_printf ("%s/verify/%s.xml", + localstatedir, + fu_device_get_id (device)); + file = g_file_new_for_path (fn); + if (!g_file_query_exists (file, NULL)) { + g_set_error (error, + G_IO_ERROR, + G_IO_ERROR_NOT_FOUND, + "failed to find %s", fn); + return NULL; + } + + if (!xb_builder_source_load_file (source, file, + XB_BUILDER_SOURCE_FLAG_NONE, + NULL, error)) + return NULL; + xb_builder_import_source (builder, source); + silo = xb_builder_compile (builder, + XB_BUILDER_COMPILE_FLAG_NONE, + NULL, error); + if (silo == NULL) + return NULL; + xpath = g_strdup_printf ("component/releases/release[@version='%s']", + fu_device_get_version (device)); + release = xb_silo_query_first (silo, xpath, error); + if (release == NULL) + return NULL; + + /* silo has to have same lifecyle as node */ + g_object_set_data_full (G_OBJECT (release), "XbSilo", + g_steal_pointer (&silo), + (GDestroyNotify) g_object_unref); + return g_steal_pointer (&release); +} + +static XbNode * +fu_engine_verify_from_system_metadata (FuEngine *self, + FuDevice *device, + GError **error) +{ + FwupdVersionFormat fmt = fu_device_get_version_format (device); + GPtrArray *guids = fu_device_get_guids (device); + g_autoptr(XbQuery) query = NULL; + + /* prepare query with bound GUID parameter */ + query = xb_query_new_full (self->silo, + "components/component/" + "provides/firmware[@type='flashed'][text()=?]/" + "../../releases/release", + XB_QUERY_FLAG_OPTIMIZE | + XB_QUERY_FLAG_USE_INDEXES, + error); + if (query == NULL) + return NULL; + + /* use prepared query for each GUID */ + for (guint i = 0; i < guids->len; i++) { + const gchar *guid = g_ptr_array_index (guids, i); + g_autoptr(GError) error_local = NULL; + g_autoptr(GPtrArray) releases = NULL; + + /* bind GUID and then query */ + if (!xb_query_bind_str (query, 0, guid, error)) { + g_prefix_error (error, "failed to bind string: "); + return NULL; + } + releases = xb_silo_query_full (self->silo, query, &error_local); + if (releases == NULL) { + if (g_error_matches (error_local, G_IO_ERROR, G_IO_ERROR_NOT_FOUND) || + g_error_matches (error_local, G_IO_ERROR, G_IO_ERROR_INVALID_ARGUMENT)) { + g_debug ("could not find %s: %s", + guid, error_local->message); + continue; + } + g_propagate_error (error, g_steal_pointer (&error_local)); + return NULL; + } + for (guint j = 0; j < releases->len; j++) { + XbNode *rel = g_ptr_array_index (releases, j); + const gchar *rel_ver = xb_node_get_attr (rel, "version"); + g_autofree gchar *tmp_ver = fu_common_version_parse_from_format (rel_ver, fmt); + if (fu_common_vercmp_full (tmp_ver, fu_device_get_version (device), fmt) == 0) + return g_object_ref (rel); + } + } + + /* not found */ + g_set_error_literal (error, + G_IO_ERROR, + G_IO_ERROR_NOT_FOUND, + "failed to find release"); + return NULL; +} + /** * fu_engine_verify: * @self: A #FuEngine @@ -800,15 +909,11 @@ fu_engine_verify (FuEngine *self, const gchar *device_id, GError **error) { FuPlugin *plugin; GPtrArray *checksums; - const gchar *version; - g_autofree gchar *fn = NULL; - g_autofree gchar *localstatedir = NULL; g_autoptr(FuDevice) device = NULL; - g_autoptr(GFile) file = NULL; + g_autoptr(GError) error_local = NULL; g_autoptr(GString) xpath_csum = g_string_new (NULL); g_autoptr(XbNode) csum = NULL; g_autoptr(XbNode) release = NULL; - g_autoptr(XbSilo) silo = xb_silo_new (); g_return_val_if_fail (FU_IS_ENGINE (self), FALSE); g_return_val_if_fail (device_id != NULL, FALSE); @@ -833,71 +938,34 @@ fu_engine_verify (FuEngine *self, const gchar *device_id, GError **error) return FALSE; } - /* find component in metadata */ - version = fu_device_get_version (device); - localstatedir = fu_common_get_path (FU_PATH_KIND_LOCALSTATEDIR_PKG); - fn = g_strdup_printf ("%s/verify/%s.xml", localstatedir, device_id); - file = g_file_new_for_path (fn); - if (g_file_query_exists (file, NULL)) { - g_autofree gchar *xpath = NULL; - g_autoptr(XbBuilder) builder = xb_builder_new (); - g_autoptr(XbBuilderSource) source = xb_builder_source_new (); - if (!xb_builder_source_load_file (source, file, - XB_BUILDER_SOURCE_FLAG_NONE, - NULL, error)) + /* find component in local metadata */ + release = fu_engine_verify_from_local_metadata (self, device, &error_local); + if (release == NULL) { + if (!g_error_matches (error_local, G_IO_ERROR, G_IO_ERROR_NOT_FOUND) && + !g_error_matches (error_local, G_IO_ERROR, G_IO_ERROR_INVALID_ARGUMENT)) { + g_propagate_error (error, g_steal_pointer (&error_local)); return FALSE; - xb_builder_import_source (builder, source); - silo = xb_builder_compile (builder, - XB_BUILDER_COMPILE_FLAG_NONE, - NULL, error); - if (silo == NULL) - return FALSE; - xpath = g_strdup_printf ("component/releases/release[@version='%s']", version); - release = xb_silo_query_first (silo, xpath, NULL); + } } /* try again with the system metadata */ if (release == NULL) { - GPtrArray *guids = fu_device_get_guids (device); - FwupdVersionFormat fmt = fu_device_get_version_format (device); - for (guint i = 0; i < guids->len; i++) { - const gchar *guid = g_ptr_array_index (guids, i); - g_autofree gchar *xpath2 = NULL; - g_autoptr(GError) error_local = NULL; - g_autoptr(GPtrArray) releases = NULL; - xpath2 = g_strdup_printf ("components/component/" - "provides/firmware[@type='flashed'][text()='%s']/" - "../../releases/release", - guid); - releases = xb_silo_query (self->silo, xpath2, 0, &error_local); - if (releases == NULL) { - if (g_error_matches (error_local, G_IO_ERROR, G_IO_ERROR_NOT_FOUND) || - g_error_matches (error_local, G_IO_ERROR, G_IO_ERROR_INVALID_ARGUMENT)) { - g_debug ("could not find %s: %s", - guid, error_local->message); - continue; - } - g_propagate_error (error, g_steal_pointer (&error_local)); + g_autoptr(GError) error_system = NULL; + release = fu_engine_verify_from_system_metadata (self, device, &error_system); + if (release == NULL) { + if (!g_error_matches (error_system, G_IO_ERROR, G_IO_ERROR_NOT_FOUND) && + !g_error_matches (error_system, G_IO_ERROR, G_IO_ERROR_INVALID_ARGUMENT)) { + g_propagate_error (error, g_steal_pointer (&error_system)); return FALSE; } - for (guint j = 0; j < releases->len; j++) { - XbNode *rel = g_ptr_array_index (releases, j); - const gchar *rel_ver = xb_node_get_attr (rel, "version"); - g_autofree gchar *tmp_ver = fu_common_version_parse_from_format (rel_ver, fmt); - if (fu_common_vercmp_full (tmp_ver, version, fmt) == 0) { - release = g_object_ref (rel); - break; - } - } - if (release != NULL) - break; } } if (release == NULL) { g_set_error (error, FWUPD_ERROR, FWUPD_ERROR_NOT_FOUND, - "No release found for version %s", version); + "No release found for version %s", + fu_device_get_version (device)); return FALSE; } @@ -907,7 +975,8 @@ fu_engine_verify (FuEngine *self, const gchar *device_id, GError **error) g_set_error (error, FWUPD_ERROR, FWUPD_ERROR_NOT_FOUND, - "No device checksums for %s", version); + "No device checksums for %s", + fu_device_get_version (device)); return FALSE; } @@ -938,7 +1007,7 @@ fu_engine_verify (FuEngine *self, const gchar *device_id, GError **error) FWUPD_ERROR, FWUPD_ERROR_NOT_FOUND, "No stored checksums for %s", - version); + fu_device_get_version (device)); return FALSE; } for (guint i = 0; i < csums->len; i++) { @@ -955,7 +1024,7 @@ fu_engine_verify (FuEngine *self, const gchar *device_id, GError **error) FWUPD_ERROR_NOT_FOUND, "For %s %s expected %s, got %s", fu_device_get_name (device), - version, + fu_device_get_version (device), checksums_metadata->str, checksums_device->str); return FALSE; From bfd57c6ee121dae8ffa5f8070f93933e5738f741 Mon Sep 17 00:00:00 2001 From: Mario Limonciello Date: Tue, 23 Jun 2020 14:03:38 -0500 Subject: [PATCH 206/607] trivial: modem-manager: chomp vendor string MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Reading the sysfs file seemed to have also eaten the `\n` as mentioned on a bug. ``` ├DW5821e Snapdragon X20 LTE: │ Device ID: fa707b9af86ff44bc17316b6c3e5ea82aab3ce86 │ Summary: Mobile broadband device │ Current version: T77W968.F1.0.0.4.2.GC.010 │ Vendor: Dell Inc. (USB:0x413c │ ) │ GUIDs: 64da2d58-8d1b-5e5b-b793-f88ba5a25a8f │ 761d6124-0002-5185-b767-9adf67bf1a5e │ 795e079d-093b-5503-aa59-35b832480e95 │ Device Flags: • Updatable ``` --- plugins/modem-manager/fu-mm-device.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugins/modem-manager/fu-mm-device.c b/plugins/modem-manager/fu-mm-device.c index 2ee8bc8a4..a32b5769f 100644 --- a/plugins/modem-manager/fu-mm-device.c +++ b/plugins/modem-manager/fu-mm-device.c @@ -251,7 +251,7 @@ fu_mm_device_probe_default (FuDevice *device, GError **error) if (!g_file_get_contents (path, &value, NULL, &error_local)) { g_warning ("failed to set vendor ID: %s", error_local->message); } else { - g_autofree gchar *vendor_id = g_strdup_printf ("USB:0x%s", value); + g_autofree gchar *vendor_id = g_strdup_printf ("USB:0x%s", g_strchomp (value)); fu_device_set_vendor_id (device, vendor_id); } } From 13f424088103f1b7948b445c251c9a8f86cf626d Mon Sep 17 00:00:00 2001 From: Mario Limonciello Date: Tue, 23 Jun 2020 14:17:54 -0500 Subject: [PATCH 207/607] trivial: snap: move to newer modem manager stuff Fixes: #2200 --- snap/snapcraft.yaml | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/snap/snapcraft.yaml b/snap/snapcraft.yaml index cd8536137..113e97d8e 100644 --- a/snap/snapcraft.yaml +++ b/snap/snapcraft.yaml @@ -86,10 +86,11 @@ parts: modemmanager: plugin: autotools source: https://gitlab.freedesktop.org/mobile-broadband/ModemManager.git - source-tag: 1.10.0 + source-tag: 1.14.0 # build without these; system daemon needs them build-packages: - xsltproc + - autoconf-archive configflags: - --without-mbim - --without-qmi @@ -108,7 +109,7 @@ parts: libmbim: plugin: autotools source: https://gitlab.freedesktop.org/mobile-broadband/libmbim.git - source-tag: 1.18.0 + source-tag: 1.24.0 after: [modemmanager] # build without these; system daemon needs them configflags: @@ -128,7 +129,7 @@ parts: libqmi: plugin: autotools source: https://gitlab.freedesktop.org/mobile-broadband/libqmi.git - source-tag: 1.23.1 + source-tag: 1.26.0 after: [modemmanager, libmbim] # build without these; system daemon needs them configflags: From bdc589884a8c9e71498066f25cfc39df183b5e53 Mon Sep 17 00:00:00 2001 From: Mario Limonciello Date: Tue, 23 Jun 2020 15:03:46 -0500 Subject: [PATCH 208/607] modem-manager: add support for compiling libqmi-glib 1.26.0 and later --- plugins/modem-manager/fu-qmi-pdc-updater.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/plugins/modem-manager/fu-qmi-pdc-updater.c b/plugins/modem-manager/fu-qmi-pdc-updater.c index 7ade7a173..c63e91d09 100644 --- a/plugins/modem-manager/fu-qmi-pdc-updater.c +++ b/plugins/modem-manager/fu-qmi-pdc-updater.c @@ -226,11 +226,13 @@ typedef struct { guint token; } WriteContext; +#if !QMI_CHECK_VERSION(1,26,0) #pragma clang diagnostic push #pragma clang diagnostic ignored "-Wunused-function" G_DEFINE_AUTOPTR_CLEANUP_FUNC(QmiMessagePdcLoadConfigInput, qmi_message_pdc_load_config_input_unref) G_DEFINE_AUTOPTR_CLEANUP_FUNC(QmiMessagePdcLoadConfigOutput, qmi_message_pdc_load_config_output_unref) #pragma clang diagnostic pop +#endif static void fu_qmi_pdc_updater_load_config (WriteContext *ctx); @@ -435,11 +437,13 @@ typedef struct { guint token; } ActivateContext; +#if !QMI_CHECK_VERSION(1,26,0) #pragma clang diagnostic push #pragma clang diagnostic ignored "-Wunused-function" G_DEFINE_AUTOPTR_CLEANUP_FUNC(QmiMessagePdcActivateConfigInput, qmi_message_pdc_activate_config_input_unref) G_DEFINE_AUTOPTR_CLEANUP_FUNC(QmiMessagePdcActivateConfigOutput, qmi_message_pdc_activate_config_output_unref) #pragma clang diagnostic pop +#endif static gboolean fu_qmi_pdc_updater_activate_config_timeout (gpointer user_data) @@ -540,11 +544,13 @@ fu_qmi_pdc_updater_activate_config (ActivateContext *ctx) fu_qmi_pdc_updater_activate_config_ready, ctx); } +#if !QMI_CHECK_VERSION(1,26,0) #pragma clang diagnostic push #pragma clang diagnostic ignored "-Wunused-function" G_DEFINE_AUTOPTR_CLEANUP_FUNC(QmiMessagePdcSetSelectedConfigInput, qmi_message_pdc_set_selected_config_input_unref) G_DEFINE_AUTOPTR_CLEANUP_FUNC(QmiMessagePdcSetSelectedConfigOutput, qmi_message_pdc_set_selected_config_output_unref) #pragma clang diagnostic pop +#endif static gboolean fu_qmi_pdc_updater_set_selected_config_timeout (gpointer user_data) From 58d6d329e8eed3f50b8e6d54122c183b3df77693 Mon Sep 17 00:00:00 2001 From: Mario Limonciello Date: Tue, 23 Jun 2020 23:35:50 -0500 Subject: [PATCH 209/607] trivial: thunderbolt: don't set update error for missing nvmem Trying to explain why ICL thunderbolt isn't updatable doesn't help people. It just causes fwupdmgr and fwupdtool to show the device front and center with a confusing message. Instead don't populate the message and by the default device filter it will be hidden. See #2212 for background. --- plugins/thunderbolt/fu-thunderbolt-device.c | 1 - 1 file changed, 1 deletion(-) diff --git a/plugins/thunderbolt/fu-thunderbolt-device.c b/plugins/thunderbolt/fu-thunderbolt-device.c index 6262a1f04..530921f42 100644 --- a/plugins/thunderbolt/fu-thunderbolt-device.c +++ b/plugins/thunderbolt/fu-thunderbolt-device.c @@ -316,7 +316,6 @@ fu_thunderbolt_device_setup (FuDevice *device, GError **error) fu_device_add_flag (device, FWUPD_DEVICE_FLAG_DUAL_IMAGE); } else { device_id = g_strdup ("TBT-fixed"); - fu_device_set_update_error (device, "Missing non-active nvmem"); } fu_device_add_instance_id (device, device_id); if (domain_id != NULL) From 4669dd590a9a0cc4cc962b6809c8dcd4d4cfe51c Mon Sep 17 00:00:00 2001 From: Mario Limonciello Date: Tue, 23 Jun 2020 16:50:05 -0500 Subject: [PATCH 210/607] trivial: uefi: drop secure boot check at coldplug We'll instead check this when the user tries to run an update. This allows them to sign a bootloader after the daemon starts (or remove a signed bootloader after starting) Fixes: #2219 --- plugins/uefi/fu-plugin-uefi.c | 18 +----------------- plugins/uefi/fu-uefi-device.c | 15 +++++++++++++++ 2 files changed, 16 insertions(+), 17 deletions(-) diff --git a/plugins/uefi/fu-plugin-uefi.c b/plugins/uefi/fu-plugin-uefi.c index dc5807525..d41d415c3 100644 --- a/plugins/uefi/fu-plugin-uefi.c +++ b/plugins/uefi/fu-plugin-uefi.c @@ -730,10 +730,8 @@ fu_plugin_coldplug (FuPlugin *plugin, GError **error) { FuPluginData *data = fu_plugin_get_data (plugin); const gchar *str; - g_autofree gchar *bootloader = NULL; g_autofree gchar *esrt_path = NULL; g_autofree gchar *sysfsfwdir = NULL; - g_autoptr(GError) error_bootloader = NULL; g_autoptr(GError) error_efivarfs = NULL; g_autoptr(GError) error_local = NULL; g_autoptr(GPtrArray) entries = NULL; @@ -753,14 +751,6 @@ fu_plugin_coldplug (FuPlugin *plugin, GError **error) if (!fu_plugin_uefi_ensure_efivarfs_rw (&error_efivarfs)) g_warning ("%s", error_efivarfs->message); - /* if secure boot is enabled ensure we have a signed fwupd.efi */ - bootloader = fu_uefi_get_built_app_path (&error_bootloader); - if (bootloader == NULL) { - if (fu_efivar_secure_boot_enabled ()) - g_prefix_error (&error_bootloader, "missing signed bootloader for secure boot: "); - g_warning ("%s", error_bootloader->message); - } - /* add each device */ for (guint i = 0; i < entries->len; i++) { const gchar *path = g_ptr_array_index (entries, i); @@ -773,9 +763,7 @@ fu_plugin_coldplug (FuPlugin *plugin, GError **error) fu_device_set_quirks (FU_DEVICE (dev), fu_plugin_get_quirks (plugin)); if (!fu_plugin_uefi_coldplug_device (plugin, dev, error)) return FALSE; - if (error_bootloader != NULL) { - fu_device_set_update_error (FU_DEVICE (dev), error_bootloader->message); - } else if (error_efivarfs != NULL) { + if (error_efivarfs != NULL) { fu_device_set_update_error (FU_DEVICE (dev), error_efivarfs->message); } else { fu_device_add_flag (FU_DEVICE (dev), FWUPD_DEVICE_FLAG_UPDATABLE); @@ -788,10 +776,6 @@ fu_plugin_coldplug (FuPlugin *plugin, GError **error) fu_plugin_device_add (plugin, FU_DEVICE (dev)); } - /* no devices are updatable */ - if (error_bootloader != NULL) - return TRUE; - /* for debugging problems later */ fu_plugin_uefi_test_secure_boot (plugin); if (!fu_uefi_bgrt_setup (data->bgrt, &error_local)) diff --git a/plugins/uefi/fu-uefi-device.c b/plugins/uefi/fu-uefi-device.c index 4d90fcd0f..d4a48265b 100644 --- a/plugins/uefi/fu-uefi-device.c +++ b/plugins/uefi/fu-uefi-device.c @@ -468,6 +468,19 @@ fu_uefi_device_check_esp_free (FuDevice *device, GError **error) return fu_uefi_check_esp_free_space (esp_path, sz_reqd, error); } +static gboolean +fu_uefi_check_asset (FuDevice *device, GError **error) +{ + g_autofree gchar *source_app = fu_uefi_get_built_app_path (error); + if (source_app == NULL) { + if (fu_efivar_secure_boot_enabled ()) + g_prefix_error (error, "missing signed bootloader for secure boot: "); + return FALSE; + } + + return TRUE; +} + static gboolean fu_uefi_device_cleanup_esp (FuDevice *device, GError **error) { @@ -542,6 +555,8 @@ fu_uefi_device_prepare (FuDevice *device, return FALSE; if (!fu_uefi_device_check_esp_free (device, error)) return FALSE; + if (!fu_uefi_check_asset (device, error)) + return FALSE; return TRUE; } From a11eab61e1e1cdcf8a349083dd3da9931515f235 Mon Sep 17 00:00:00 2001 From: Mario Limonciello Date: Tue, 23 Jun 2020 19:13:29 -0500 Subject: [PATCH 211/607] trivial: fu-util: show a better error for non-responsive daemon See #2212 for more context. --- src/fu-util.c | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/src/fu-util.c b/src/fu-util.c index 1c8d6b557..630d9652f 100644 --- a/src/fu-util.c +++ b/src/fu-util.c @@ -2544,6 +2544,15 @@ fu_util_check_daemon_version (FuUtilPrivate *priv, GError **error) { const gchar *daemon = fwupd_client_get_daemon_version (priv->client); + if (daemon == NULL) { + g_set_error_literal (error, + FWUPD_ERROR, + FWUPD_ERROR_NOT_SUPPORTED, + /* TRANSLATORS: error message */ + _("Unable to connect to service")); + return FALSE; + } + if (g_strcmp0 (daemon, SOURCE_VERSION) != 0) { g_set_error (error, FWUPD_ERROR, From 2ba1a853a45fc77b6cfe817d6226ad3247351bb1 Mon Sep 17 00:00:00 2001 From: Richard Hughes Date: Thu, 25 Jun 2020 16:41:02 +0100 Subject: [PATCH 212/607] Drop the automatic /usr/bin/python3 rpmbuild dependency We ship 4 *tiny* python scripts that are useful for ODMs and other people working with low level firmware blobs. These helper utilities do not warrant dragging Python onto the CoreOS image. --- contrib/fwupd.spec.in | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/contrib/fwupd.spec.in b/contrib/fwupd.spec.in index 64465edd7..109498e25 100644 --- a/contrib/fwupd.spec.in +++ b/contrib/fwupd.spec.in @@ -6,6 +6,10 @@ %global systemd_version 231 %global json_glib_version 1.1.1 +# although we ship a few tiny python files these are utilities that 99.99% +# of users do not need -- use this to avoid dragging python onto CoreOS +%global __requires_exclude ^%{python3}$ + %define alphatag #ALPHATAG# %global enable_ci 0 From b5638407533179dd4abb18c54eb317f7d2ad3ce4 Mon Sep 17 00:00:00 2001 From: Mario Limonciello Date: Thu, 25 Jun 2020 09:34:54 -0500 Subject: [PATCH 213/607] Move PCR0 reconstruction error into `security` command Now that this infrastructure is built, it's a more useful location to put the security output. --- plugins/tpm-eventlog/fu-plugin-tpm-eventlog.c | 6 +----- src/fu-util-common.c | 15 +++++++++++++++ 2 files changed, 16 insertions(+), 5 deletions(-) diff --git a/plugins/tpm-eventlog/fu-plugin-tpm-eventlog.c b/plugins/tpm-eventlog/fu-plugin-tpm-eventlog.c index 95fd3e225..eb1be1a9e 100644 --- a/plugins/tpm-eventlog/fu-plugin-tpm-eventlog.c +++ b/plugins/tpm-eventlog/fu-plugin-tpm-eventlog.c @@ -126,12 +126,8 @@ fu_plugin_device_registered_uefi (FuPlugin *plugin, FuDevice *device) } } /* check at least one reconstruction for this algorithm */ - if (!data->reconstructed) { - fu_device_set_update_message (device, - "TPM PCR0 differs from reconstruction, " - "please see https://github.com/fwupd/fwupd/wiki/TPM-PCR0-differs-from-reconstruction"); + if (!data->reconstructed) return; - } } } diff --git a/src/fu-util-common.c b/src/fu-util-common.c index 553f586f9..aec814efd 100644 --- a/src/fu-util-common.c +++ b/src/fu-util-common.c @@ -1592,6 +1592,7 @@ fu_util_security_attrs_to_string (GPtrArray *attrs) GString *str = g_string_new (NULL); gboolean low_help = FALSE; gboolean runtime_help = FALSE; + gboolean pcr0_help = FALSE; for (guint j = 1; j <= FWUPD_SECURITY_ATTR_LEVEL_LAST; j++) { gboolean has_header = FALSE; @@ -1608,6 +1609,12 @@ fu_util_security_attrs_to_string (GPtrArray *attrs) if (j < FWUPD_SECURITY_ATTR_LEVEL_IMPORTANT && !fwupd_security_attr_has_flag (attr, FWUPD_SECURITY_ATTR_FLAG_SUCCESS)) low_help = TRUE; + + /* check for PCR0 not matching */ + if (g_strcmp0 (fwupd_security_attr_get_appstream_id (attr), + FWUPD_SECURITY_ATTR_ID_TPM_RECONSTRUCTION_PCR0) == 0 && + fwupd_security_attr_get_result (attr) == FWUPD_SECURITY_ATTR_RESULT_NOT_VALID) + pcr0_help = TRUE; } } for (guint i = 0; i < attrs->len; i++) { @@ -1645,6 +1652,14 @@ fu_util_security_attrs_to_string (GPtrArray *attrs) "https://github.com/fwupd/fwupd/wiki/Host-security-ID-runtime-issues"); } + if (pcr0_help) { + g_string_append_printf (str, "\n%s\n » %s\n", + /* TRANSLATORS: this is more background on a security measurement problem */ + _("The TPM PCR0 differes from reconstruction."), + "https://github.com/fwupd/fwupd/wiki/TPM-PCR0-differs-from-reconstruction"); + + } + return g_string_free (str, FALSE); } From 28d51c036b85ebcc394407eeb12f79606118b17d Mon Sep 17 00:00:00 2001 From: Mario Limonciello Date: Thu, 25 Jun 2020 09:38:07 -0500 Subject: [PATCH 214/607] trivial: tpm-eventlog: stop showing messages about secure boot This was an overloaded use of UpdateMessage that didn't make sense. It doesn't affect the functionality of updating, just the security. Hints about why the TPM PCR0 reconstruction failed should go to the wiki page not the device. --- plugins/tpm-eventlog/fu-plugin-tpm-eventlog.c | 17 +---------------- 1 file changed, 1 insertion(+), 16 deletions(-) diff --git a/plugins/tpm-eventlog/fu-plugin-tpm-eventlog.c b/plugins/tpm-eventlog/fu-plugin-tpm-eventlog.c index eb1be1a9e..3e897faba 100644 --- a/plugins/tpm-eventlog/fu-plugin-tpm-eventlog.c +++ b/plugins/tpm-eventlog/fu-plugin-tpm-eventlog.c @@ -10,11 +10,9 @@ #include "fu-plugin-vfuncs.h" #include "fu-tpm-eventlog-device.h" -#include "fu-efivar.h" struct FuPluginData { GPtrArray *pcr0s; - gboolean secure_boot_problem; gboolean has_tpm_device; gboolean has_uefi_device; gboolean reconstructed; @@ -48,14 +46,8 @@ fu_plugin_coldplug (FuPlugin *plugin, GError **error) g_autoptr(FuTpmEventlogDevice) dev = NULL; g_autoptr(GError) error_local = NULL; - if (!g_file_get_contents (fn, (gchar **) &buf, &bufsz, &error_local)) { - if (fu_efivar_supported (NULL) && !fu_efivar_secure_boot_enabled ()) { - data->secure_boot_problem = TRUE; - return TRUE; - } - g_propagate_error (error, g_steal_pointer (&error_local)); + if (!g_file_get_contents (fn, (gchar **) &buf, &bufsz, error)) return FALSE; - } if (bufsz == 0) { g_set_error (error, FWUPD_ERROR, @@ -105,13 +97,6 @@ fu_plugin_device_registered_uefi (FuPlugin *plugin, FuDevice *device) return; data->has_uefi_device = TRUE; - if (data->secure_boot_problem) { - fu_device_set_update_message (device, - "Platform firmware measurement unavailable. Secure boot is disabled in BIOS setup, " - "enabling it may fix this issue"); - return; - } - for (guint i = 0; i < checksums->len; i++) { const gchar *checksum = g_ptr_array_index (checksums, i); data->reconstructed = FALSE; From c2721c8695ddb4bfe9d0dd9844d453528a4fbe39 Mon Sep 17 00:00:00 2001 From: Mario Limonciello Date: Thu, 25 Jun 2020 09:42:12 -0500 Subject: [PATCH 215/607] fu-util: Only show UpdateMessage when state is success This will show it only when an update was sucessful. Fixes: #2212 --- src/fu-util-common.c | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/src/fu-util-common.c b/src/fu-util-common.c index aec814efd..c0f2b243f 100644 --- a/src/fu-util-common.c +++ b/src/fu-util-common.c @@ -1210,17 +1210,20 @@ fu_util_device_to_string (FwupdDevice *dev, guint idt) /* TRANSLATORS: hardware state, e.g. "pending" */ fu_common_string_append_kv (str, idt + 1, _("Update State"), fwupd_update_state_to_string (state)); + + if (state == FWUPD_UPDATE_STATE_SUCCESS) { + tmp = fwupd_device_get_update_message (dev); + if (tmp != NULL) { + /* TRANSLATORS: helpful messages from last update */ + fu_common_string_append_kv (str, idt + 1, _("Update Message"), tmp); + } + } } tmp = fwupd_device_get_update_error (dev); if (tmp != NULL) { /* TRANSLATORS: error message from last update attempt */ fu_common_string_append_kv (str, idt + 1, _("Update Error"), tmp); } - tmp = fwupd_device_get_update_message (dev); - if (tmp != NULL) { - /* TRANSLATORS: helpful messages from last update */ - fu_common_string_append_kv (str, idt + 1, _("Update Message"), tmp); - } /* modified date: for history devices */ if (modified > 0) { From 609d0c570fab9eeaaf68faccea8c4e22df6347c8 Mon Sep 17 00:00:00 2001 From: Ryan Lee Date: Thu, 25 Jun 2020 19:20:21 +0900 Subject: [PATCH 216/607] ccgx: Add more hybrid dock support Also add HPI command retry. --- plugins/ccgx/ccgx.quirk | 15 ++- plugins/ccgx/fu-ccgx-hpi-device.c | 147 +++++++++++++++++++++++------- 2 files changed, 128 insertions(+), 34 deletions(-) diff --git a/plugins/ccgx/ccgx.quirk b/plugins/ccgx/ccgx.quirk index 02d9d0e96..2995fb792 100644 --- a/plugins/ccgx/ccgx.quirk +++ b/plugins/ccgx/ccgx.quirk @@ -12,6 +12,8 @@ GType = FuCcgxHpiDevice ImageKind = dual-asymmetric Name = ThinkPad USB-C Dock Gen2 PD Controller ParentGuid = USB\VID_17EF&PID_A391 +InstallDuration = 120 +RemoveDelay = 60000 [DeviceInstanceId=USB\VID_04B4&PID_521A&SID_1F00&APP_6D64&MODE_FW1] Summary = CCGx Power Delivery Device (Bootloader) @@ -36,11 +38,18 @@ ParentGuid = USB\VID_17EF&PID_1028 Plugin = ccgx GType = FuCcgxHpiDevice -[DeviceInstanceId=USB\VID_04B4&PID_5218&SID_1F00&APP_6462] -Name = ThinkPad USB-C Dock Hybrid PD Controller -Summary = CCGx Power Delivery Device +[DeviceInstanceId=USB\VID_04B4&PID_5218&SID_1F00&APP_6432] ImageKind = dual-symmetric +Name = ThinkPad USB-C Dock Hybrid PD Controller ParentGuid = USB\VID_17EF&PID_1028 +InstallDuration = 120 +RemoveDelay = 60000 + +[DeviceInstanceId=USB\VID_04B4&PID_5218&SID_1F00&APP_6432&MODE_FW1] +Summary = CCGx Power Delivery Device (Symmetric FW1) + +[DeviceInstanceId=USB\VID_04B4&PID_5218&SID_1F00&APP_6432&MODE_FW2] +Summary = CCGx Power Delivery Device (Symmetric FW2) # HP Adicora Dock A Type [DeviceInstanceId=USB\VID_03F0&PID_046B] diff --git a/plugins/ccgx/fu-ccgx-hpi-device.c b/plugins/ccgx/fu-ccgx-hpi-device.c index d9054cd6e..075b312a2 100644 --- a/plugins/ccgx/fu-ccgx-hpi-device.c +++ b/plugins/ccgx/fu-ccgx-hpi-device.c @@ -36,15 +36,19 @@ struct _FuCcgxHpiDevice G_DEFINE_TYPE (FuCcgxHpiDevice, fu_ccgx_hpi_device, FU_TYPE_USB_DEVICE) -#define HPI_CMD_REG_READ_WRITE_DELAY_US 10000 -#define HPI_CMD_ENTER_FLASH_MODE_DELAY_US 20000 -#define HPI_CMD_SETUP_EVENT_WAIT_TIME_MS 200 -#define HPI_CMD_SETUP_EVENT_CLEAR_TIME_MS 150 -#define HPI_CMD_COMMAND_RESPONSE_TIME_MS 500 -#define HPI_CMD_COMMAND_CLEAR_EVENT_TIME_MS 30 -#define HPI_CMD_RESET_COMPLETE_DELAY_US 150000 -#define HPI_CMD_RETRY_DELAY 30 /* ms */ -#define HPI_CMD_RESET_RETRY_CNT 3 +#define HPI_CMD_REG_READ_WRITE_DELAY_US 10000 +#define HPI_CMD_ENTER_FLASH_MODE_DELAY_US 20000 +#define HPI_CMD_SETUP_EVENT_WAIT_TIME_MS 200 +#define HPI_CMD_SETUP_EVENT_CLEAR_TIME_MS 150 +#define HPI_CMD_COMMAND_RESPONSE_TIME_MS 500 +#define HPI_CMD_COMMAND_CLEAR_EVENT_TIME_MS 30 +#define HPI_CMD_RESET_COMPLETE_DELAY_US 150000 +#define HPI_CMD_RETRY_DELAY 30 /* ms */ +#define HPI_CMD_RESET_RETRY_CNT 3 +#define HPI_CMD_ENTER_LEAVE_FLASH_MODE_RETRY_CNT 3 +#define HPI_CMD_FLASH_WRITE_RETRY_CNT 3 +#define HPI_CMD_FLASH_READ_RETRY_CNT 3 +#define HPI_CMD_VALIDATE_FW_RETRY_CNT 3 static void fu_ccgx_hpi_device_to_string (FuDevice *device, guint idt, GString *str) @@ -76,6 +80,18 @@ typedef struct { gsize bufsz; } FuCcgxHpiDeviceRetryHelper; +typedef struct { + guint16 addr; + const guint8 *buf; + gsize bufsz; +} FuCcgxHpiFlashWriteRetryHelper; + +typedef struct { + guint16 addr; + guint8 *buf; + gsize bufsz; +} FuCcgxHpiFlashReadRetryHelper; + static gboolean fu_ccgx_hpi_device_i2c_reset_cb (FuDevice *device, gpointer user_data, GError **error) { @@ -696,16 +712,21 @@ fu_ccgx_hpi_device_clear_all_events (FuCcgxHpiDevice *self, } static gboolean -fu_ccgx_hpi_validate_fw (FuCcgxHpiDevice *self, guint8 fw_index, GError **error) +fu_ccgx_hpi_validate_fw_cb (FuDevice *device, gpointer user_data, GError **error) { + FuCcgxHpiDevice *self = FU_CCGX_HPI_DEVICE (device); + guint8 *fw_index = (guint8 *) user_data; CyPDResp hpi_event = 0; + + g_return_val_if_fail (fw_index != NULL, FALSE); if (!fu_ccgx_hpi_device_clear_all_events (self, HPI_CMD_COMMAND_CLEAR_EVENT_TIME_MS, error)) return FALSE; + if (!fu_ccgx_hpi_device_reg_write (self, CY_PD_REG_VALIDATE_FW_ADDR, - &fw_index, sizeof(fw_index), + fw_index, 1, error)) { g_prefix_error (error, "validate fw error: "); return FALSE; @@ -730,8 +751,18 @@ fu_ccgx_hpi_validate_fw (FuCcgxHpiDevice *self, guint8 fw_index, GError **error) } static gboolean -fu_ccgx_hpi_enter_flash_mode (FuCcgxHpiDevice *self, GError **error) +fu_ccgx_hpi_validate_fw (FuCcgxHpiDevice *self, guint8 fw_index, GError **error) { + return fu_device_retry (FU_DEVICE (self), + fu_ccgx_hpi_validate_fw_cb, + HPI_CMD_VALIDATE_FW_RETRY_CNT, + &fw_index, error); +} + +static gboolean +fu_ccgx_hpi_enter_flash_mode_cb (FuDevice *device, gpointer user_data, GError **error) +{ + FuCcgxHpiDevice *self = FU_CCGX_HPI_DEVICE (device); CyPDResp hpi_event = 0; guint8 buf[] = { CY_PD_ENTER_FLASHING_MODE_CMD_SIG }; @@ -770,8 +801,18 @@ fu_ccgx_hpi_enter_flash_mode (FuCcgxHpiDevice *self, GError **error) } static gboolean -fu_ccgx_hpi_leave_flash_mode (FuCcgxHpiDevice *self, GError **error) +fu_ccgx_hpi_enter_flash_mode (FuCcgxHpiDevice *self, GError **error) { + return fu_device_retry (FU_DEVICE (self), + fu_ccgx_hpi_enter_flash_mode_cb, + HPI_CMD_ENTER_LEAVE_FLASH_MODE_RETRY_CNT, + NULL, error); +} + +static gboolean +fu_ccgx_hpi_leave_flash_mode_cb (FuDevice *device, gpointer user_data, GError **error) +{ + FuCcgxHpiDevice *self = FU_CCGX_HPI_DEVICE (device); CyPDResp hpi_event = 0; guint8 buf = { 0x0 }; @@ -779,6 +820,7 @@ fu_ccgx_hpi_leave_flash_mode (FuCcgxHpiDevice *self, GError **error) HPI_CMD_COMMAND_CLEAR_EVENT_TIME_MS, error)) return FALSE; + if (!fu_ccgx_hpi_device_reg_write (self, CY_PD_REG_ENTER_FLASH_MODE_ADDR, &buf, sizeof(buf), @@ -810,19 +852,26 @@ fu_ccgx_hpi_leave_flash_mode (FuCcgxHpiDevice *self, GError **error) } static gboolean -fu_ccgx_hpi_write_flash (FuCcgxHpiDevice *self, - guint16 addr, - const guint8 *buf, - guint16 bufsz, - GError **error) +fu_ccgx_hpi_leave_flash_mode (FuCcgxHpiDevice *self, GError **error) { + return fu_device_retry (FU_DEVICE (self), + fu_ccgx_hpi_leave_flash_mode_cb, + HPI_CMD_ENTER_LEAVE_FLASH_MODE_RETRY_CNT, + NULL, error); +} + +static gboolean +fu_ccgx_hpi_write_flash_cb (FuDevice *device, gpointer user_data, GError **error) +{ + FuCcgxHpiDevice *self = FU_CCGX_HPI_DEVICE (device); + FuCcgxHpiFlashWriteRetryHelper *helper = (FuCcgxHpiFlashWriteRetryHelper *) user_data; CyPDResp hpi_event = 0; guint16 addr_tmp = 0; guint8 bufhw[] = { CY_PD_FLASH_READ_WRITE_CMD_SIG, CY_PD_REG_FLASH_ROW_WRITE_CMD, - addr & 0xFF, - addr >> 8, + helper->addr & 0xFF, + helper->addr >> 8, }; if (!fu_ccgx_hpi_device_clear_all_events (self, @@ -832,7 +881,7 @@ fu_ccgx_hpi_write_flash (FuCcgxHpiDevice *self, /* write data to memory */ addr_tmp = self->hpi_addrsz > 1 ? HPI_DEV_REG_FLASH_MEM : CY_PD_REG_BOOTDATA_MEMORY_ADDR; - if (!fu_ccgx_hpi_device_reg_write (self, addr_tmp, buf, bufsz, error)) { + if (!fu_ccgx_hpi_device_reg_write (self, addr_tmp, helper->buf, helper->bufsz, error)) { g_prefix_error (error, "write buf to memory error"); return FALSE; } @@ -864,19 +913,35 @@ fu_ccgx_hpi_write_flash (FuCcgxHpiDevice *self, } static gboolean -fu_ccgx_hpi_read_flash (FuCcgxHpiDevice *self, - guint16 addr, - guint8 *buf, - guint16 bufsz, - GError **error) +fu_ccgx_hpi_write_flash (FuCcgxHpiDevice *self, + guint16 addr, + const guint8 *buf, + guint16 bufsz, + GError **error) { + FuCcgxHpiFlashWriteRetryHelper helper = { + .addr = addr, + .buf = buf, + .bufsz = bufsz, + }; + return fu_device_retry (FU_DEVICE (self), + fu_ccgx_hpi_write_flash_cb, + HPI_CMD_FLASH_WRITE_RETRY_CNT, + &helper, error); +} + +static gboolean +fu_ccgx_hpi_read_flash_cb (FuDevice *device, gpointer user_data, GError **error) +{ + FuCcgxHpiDevice *self = FU_CCGX_HPI_DEVICE (device); + FuCcgxHpiFlashReadRetryHelper *helper = (FuCcgxHpiFlashReadRetryHelper *) user_data; CyPDResp hpi_event = 0; guint16 addr_tmp; guint8 bufhw[] = { CY_PD_FLASH_READ_WRITE_CMD_SIG, CY_PD_REG_FLASH_ROW_READ_CMD, - addr & 0xFF, - addr >> 8, + helper->addr & 0xFF, + helper->addr >> 8, }; /* set address */ @@ -909,13 +974,31 @@ fu_ccgx_hpi_read_flash (FuCcgxHpiDevice *self, return FALSE; } addr_tmp = self->hpi_addrsz > 1 ? HPI_DEV_REG_FLASH_MEM : CY_PD_REG_BOOTDATA_MEMORY_ADDR; - if (!fu_ccgx_hpi_device_reg_read (self, addr_tmp, buf, bufsz, error)) { + if (!fu_ccgx_hpi_device_reg_read (self, addr_tmp, helper->buf, helper->bufsz, error)) { g_prefix_error (error, "read data from memory error"); return FALSE; } return TRUE; } +static gboolean +fu_ccgx_hpi_read_flash (FuCcgxHpiDevice *self, + guint16 addr, + guint8 *buf, + guint16 bufsz, + GError **error) +{ + FuCcgxHpiFlashReadRetryHelper helper = { + .addr = addr, + .buf = buf, + .bufsz = bufsz, + }; + return fu_device_retry (FU_DEVICE (self), + fu_ccgx_hpi_read_flash_cb, + HPI_CMD_FLASH_READ_RETRY_CNT, + &helper, error); +} + static gboolean fu_ccgx_hpi_device_detach (FuDevice *device, GError **error) { @@ -1467,6 +1550,10 @@ fu_ccgx_hpi_device_close (FuUsbDevice *device, GError **error) { FuCcgxHpiDevice *self = FU_CCGX_HPI_DEVICE (device); g_autoptr(GError) error_local = NULL; + + /* do not close handle when device restarts */ + if (fu_device_get_status (FU_DEVICE (device)) == FWUPD_STATUS_DEVICE_RESTART) + return TRUE; if (!g_usb_device_release_interface (fu_usb_device_get_dev (device), self->inf_num, G_USB_DEVICE_CLAIM_INTERFACE_BIND_KERNEL_DRIVER, @@ -1492,9 +1579,7 @@ fu_ccgx_hpi_device_init (FuCcgxHpiDevice *self) self->ep_bulk_in = PD_I2C_USB_EP_BULK_IN; self->ep_intr_in = PD_I2C_USB_EP_INTR_IN; fu_device_set_protocol (FU_DEVICE (self), "com.cypress.ccgx"); - fu_device_set_install_duration (FU_DEVICE (self), 60); fu_device_set_version_format (FU_DEVICE (self), FWUPD_VERSION_FORMAT_TRIPLET); - fu_device_set_remove_delay (FU_DEVICE (self), 120000); /* over a minute to flash offline */ fu_device_add_flag (FU_DEVICE (self), FWUPD_DEVICE_FLAG_REQUIRE_AC); fu_device_add_flag (FU_DEVICE (self), FWUPD_DEVICE_FLAG_DUAL_IMAGE); fu_device_add_flag (FU_DEVICE (self), FWUPD_DEVICE_FLAG_CAN_VERIFY_IMAGE); From 3382fb10d72321e6f77f34b1e72d38c20821adcf Mon Sep 17 00:00:00 2001 From: Richard Hughes Date: Thu, 25 Jun 2020 22:30:15 +0100 Subject: [PATCH 217/607] trivial: Correctly format the FwupdRelease:created attribute --- libfwupd/fwupd-release.c | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) diff --git a/libfwupd/fwupd-release.c b/libfwupd/fwupd-release.c index 9f8c700b7..3794ccd9c 100644 --- a/libfwupd/fwupd-release.c +++ b/libfwupd/fwupd-release.c @@ -1564,6 +1564,21 @@ fwupd_pad_kv_str (GString *str, const gchar *key, const gchar *value) g_string_append_printf (str, "%s\n", value); } +static void +fwupd_pad_kv_unx (GString *str, const gchar *key, guint64 value) +{ + g_autoptr(GDateTime) date = NULL; + g_autofree gchar *tmp = NULL; + + /* ignore */ + if (value == 0) + return; + + date = g_date_time_new_from_unix_utc ((gint64) value); + tmp = g_date_time_format (date, "%F"); + fwupd_pad_kv_str (str, key, tmp); +} + static void fwupd_pad_kv_siz (GString *str, const gchar *key, guint64 value) { @@ -1752,7 +1767,7 @@ fwupd_release_to_string (FwupdRelease *release) } fwupd_pad_kv_str (str, FWUPD_RESULT_KEY_LICENSE, priv->license); fwupd_pad_kv_siz (str, FWUPD_RESULT_KEY_SIZE, priv->size); - fwupd_pad_kv_siz (str, FWUPD_RESULT_KEY_CREATED, priv->created); + fwupd_pad_kv_unx (str, FWUPD_RESULT_KEY_CREATED, priv->created); fwupd_pad_kv_str (str, FWUPD_RESULT_KEY_URI, priv->uri); fwupd_pad_kv_str (str, FWUPD_RESULT_KEY_HOMEPAGE, priv->homepage); fwupd_pad_kv_str (str, FWUPD_RESULT_KEY_DETAILS_URL, priv->details_url); From 890dd12d7075bbedf97c067351cb030d7ca22e80 Mon Sep 17 00:00:00 2001 From: Richard Hughes Date: Thu, 25 Jun 2020 22:49:04 +0100 Subject: [PATCH 218/607] trivial: Fix GetDetails with libxmlb 0.2.x --- src/fu-engine.c | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/src/fu-engine.c b/src/fu-engine.c index 724c24275..3e0297dcf 100644 --- a/src/fu-engine.c +++ b/src/fu-engine.c @@ -3588,6 +3588,9 @@ fu_engine_get_result_from_component (FuEngine *self, XbNode *component, GError * g_autoptr(GPtrArray) provides = NULL; g_autoptr(XbNode) description = NULL; g_autoptr(XbNode) release = NULL; +#if LIBXMLB_CHECK_VERSION(0,2,0) + g_autoptr(XbQuery) query = NULL; +#endif dev = fu_device_new (); provides = xb_node_query (component, @@ -3639,9 +3642,19 @@ fu_engine_get_result_from_component (FuEngine *self, XbNode *component, GError * return NULL; /* verify trust */ +#if LIBXMLB_CHECK_VERSION(0,2,0) + query = xb_query_new_full (xb_node_get_silo (component), + "releases/release", + XB_QUERY_FLAG_FORCE_NODE_CACHE, + error); + if (query == NULL) + return NULL; + release = xb_node_query_first_full (component, query, &error_local); +#else release = xb_node_query_first (component, "releases/release", &error_local); +#endif if (release == NULL) { g_set_error (error, FWUPD_ERROR, From c5710d91bdcf593bdb5bff167bfee1d786744d06 Mon Sep 17 00:00:00 2001 From: Richard Hughes Date: Fri, 26 Jun 2020 11:08:25 +0100 Subject: [PATCH 219/607] Be more defensive when remotes are missing required keys Fixes half of https://github.com/fwupd/fwupd/issues/2223 --- src/fu-tool.c | 27 +++++++++++++++++++++------ 1 file changed, 21 insertions(+), 6 deletions(-) diff --git a/src/fu-tool.c b/src/fu-tool.c index 09455daa6..971b4fbf1 100644 --- a/src/fu-tool.c +++ b/src/fu-tool.c @@ -1846,26 +1846,41 @@ fu_util_get_history (FuUtilPrivate *priv, gchar **values, GError **error) static gboolean fu_util_refresh_remote (FuUtilPrivate *priv, FwupdRemote *remote, GError **error) { + const gchar *metadata_uri = NULL; g_autofree gchar *fn_raw = NULL; g_autofree gchar *fn_sig = NULL; g_autoptr(GBytes) bytes_raw = NULL; g_autoptr(GBytes) bytes_sig = NULL; /* payload */ - fn_raw = fu_util_get_user_cache_path (fwupd_remote_get_metadata_uri (remote)); + metadata_uri = fwupd_remote_get_metadata_uri (remote); + if (metadata_uri == NULL) { + g_set_error_literal (error, + FWUPD_ERROR, + FWUPD_ERROR_NOTHING_TO_DO, + "no metadata URI available"); + return FALSE; + } + fn_raw = fu_util_get_user_cache_path (metadata_uri); if (!fu_common_mkdir_parent (fn_raw, error)) return FALSE; - if (!fu_util_download_out_of_process (fwupd_remote_get_metadata_uri (remote), - fn_raw, error)) + if (!fu_util_download_out_of_process (metadata_uri, fn_raw, error)) return FALSE; bytes_raw = fu_common_get_contents_bytes (fn_raw, error); if (bytes_raw == NULL) return FALSE; /* signature */ - fn_sig = fu_util_get_user_cache_path (fwupd_remote_get_metadata_uri_sig (remote)); - if (!fu_util_download_out_of_process (fwupd_remote_get_metadata_uri_sig (remote), - fn_sig, error)) + metadata_uri = fwupd_remote_get_metadata_uri_sig (remote); + if (metadata_uri == NULL) { + g_set_error_literal (error, + FWUPD_ERROR, + FWUPD_ERROR_NOTHING_TO_DO, + "no metadata signature URI available"); + return FALSE; + } + fn_sig = fu_util_get_user_cache_path (metadata_uri); + if (!fu_util_download_out_of_process (metadata_uri, fn_sig, error)) return FALSE; bytes_sig = fu_common_get_contents_bytes (fn_sig, error); if (bytes_sig == NULL) From 4fd4b982ac61c2f3b8ea2d094c6fd7eeb6526abc Mon Sep 17 00:00:00 2001 From: Richard Hughes Date: Thu, 25 Jun 2020 18:58:57 +0100 Subject: [PATCH 220/607] Support LVFS::UpdateImage in GUI clients The idea here is that we can show the user both a string and an optional line-art image when the update has completed. The line art is often more well understood for non-English speakers. --- libfwupd/fwupd-device.c | 51 ++++++++++++++++++++++++++++++++++ libfwupd/fwupd-device.h | 3 ++ libfwupd/fwupd-enums-private.h | 1 + libfwupd/fwupd-release.c | 45 ++++++++++++++++++++++++++++++ libfwupd/fwupd-release.h | 3 ++ libfwupd/fwupd.map | 11 +++++++- libfwupdplugin/fu-device.c | 7 +++++ libfwupdplugin/fu-device.h | 1 + libfwupdplugin/fu-quirks.h | 1 + src/fu-engine.c | 11 +++++++- 10 files changed, 132 insertions(+), 2 deletions(-) diff --git a/libfwupd/fwupd-device.c b/libfwupd/fwupd-device.c index c2ddd9f99..3d82ba344 100644 --- a/libfwupd/fwupd-device.c +++ b/libfwupd/fwupd-device.c @@ -59,6 +59,7 @@ typedef struct { FwupdUpdateState update_state; gchar *update_error; gchar *update_message; + gchar *update_image; FwupdStatus status; GPtrArray *releases; FwupdDevice *parent; @@ -1201,6 +1202,8 @@ fwupd_device_incorporate (FwupdDevice *self, FwupdDevice *donor) fwupd_device_set_update_error (self, priv_donor->update_error); if (priv->update_message == NULL) fwupd_device_set_update_message (self, priv_donor->update_message); + if (priv->update_image == NULL) + fwupd_device_set_update_image (self, priv_donor->update_image); if (priv->version == NULL) fwupd_device_set_version (self, priv_donor->version); if (priv->version_lowest == NULL) @@ -1394,6 +1397,11 @@ fwupd_device_to_variant_full (FwupdDevice *device, FwupdDeviceFlags flags) FWUPD_RESULT_KEY_UPDATE_MESSAGE, g_variant_new_string (priv->update_message)); } + if (priv->update_image != NULL) { + g_variant_builder_add (&builder, "{sv}", + FWUPD_RESULT_KEY_UPDATE_IMAGE, + g_variant_new_string (priv->update_image)); + } if (priv->update_state != FWUPD_UPDATE_STATE_UNKNOWN) { g_variant_builder_add (&builder, "{sv}", FWUPD_RESULT_KEY_UPDATE_STATE, @@ -1578,6 +1586,10 @@ fwupd_device_from_key_value (FwupdDevice *device, const gchar *key, GVariant *va fwupd_device_set_update_message (device, g_variant_get_string (value, NULL)); return; } + if (g_strcmp0 (key, FWUPD_RESULT_KEY_UPDATE_IMAGE) == 0) { + fwupd_device_set_update_image (device, g_variant_get_string (value, NULL)); + return; + } if (g_strcmp0 (key, FWUPD_RESULT_KEY_UPDATE_STATE) == 0) { fwupd_device_set_update_state (device, g_variant_get_uint32 (value)); return; @@ -1802,6 +1814,42 @@ fwupd_device_set_update_message (FwupdDevice *device, const gchar *update_messag priv->update_message = g_strdup (update_message); } +/** + * fwupd_device_get_update_image: + * @device: A #FwupdDevice + * + * Gets the update image. + * + * Returns: the update image URL, or %NULL if unset + * + * Since: 1.4.5 + **/ +const gchar * +fwupd_device_get_update_image (FwupdDevice *device) +{ + FwupdDevicePrivate *priv = GET_PRIVATE (device); + g_return_val_if_fail (FWUPD_IS_DEVICE (device), NULL); + return priv->update_image; +} + +/** + * fwupd_device_set_update_image: + * @device: A #FwupdDevice + * @update_image: the update image URL + * + * Sets the update image. + * + * Since: 1.4.5 + **/ +void +fwupd_device_set_update_image (FwupdDevice *device, const gchar *update_image) +{ + FwupdDevicePrivate *priv = GET_PRIVATE (device); + g_return_if_fail (FWUPD_IS_DEVICE (device)); + g_free (priv->update_image); + priv->update_image = g_strdup (update_image); +} + /** * fwupd_device_get_update_error: * @device: A #FwupdDevice @@ -2042,6 +2090,7 @@ fwupd_device_to_json (FwupdDevice *device, JsonBuilder *builder) fwupd_device_json_add_int (builder, FWUPD_RESULT_KEY_STATUS, priv->status); fwupd_device_json_add_string (builder, FWUPD_RESULT_KEY_UPDATE_ERROR, priv->update_error); fwupd_device_json_add_string (builder, FWUPD_RESULT_KEY_UPDATE_MESSAGE, priv->update_message); + fwupd_device_json_add_string (builder, FWUPD_RESULT_KEY_UPDATE_IMAGE, priv->update_image); if (priv->releases->len > 0) { json_builder_set_member_name (builder, "Releases"); json_builder_begin_array (builder); @@ -2169,6 +2218,7 @@ fwupd_device_to_string (FwupdDevice *device) fwupd_pad_kv_ups (str, FWUPD_RESULT_KEY_UPDATE_STATE, priv->update_state); fwupd_pad_kv_str (str, FWUPD_RESULT_KEY_UPDATE_ERROR, priv->update_error); fwupd_pad_kv_str (str, FWUPD_RESULT_KEY_UPDATE_MESSAGE, priv->update_message); + fwupd_pad_kv_str (str, FWUPD_RESULT_KEY_UPDATE_IMAGE, priv->update_image); for (guint i = 0; i < priv->releases->len; i++) { FwupdRelease *release = g_ptr_array_index (priv->releases, i); g_autofree gchar *tmp = fwupd_release_to_string (release); @@ -2300,6 +2350,7 @@ fwupd_device_finalize (GObject *object) g_free (priv->protocol); g_free (priv->update_error); g_free (priv->update_message); + g_free (priv->update_image); g_free (priv->version); g_free (priv->version_lowest); g_free (priv->version_bootloader); diff --git a/libfwupd/fwupd-device.h b/libfwupd/fwupd-device.h index 3b92c85ff..4dfd593da 100644 --- a/libfwupd/fwupd-device.h +++ b/libfwupd/fwupd-device.h @@ -135,6 +135,9 @@ void fwupd_device_set_update_error (FwupdDevice *device, const gchar *fwupd_device_get_update_message (FwupdDevice *device); void fwupd_device_set_update_message (FwupdDevice *device, const gchar *update_message); +const gchar *fwupd_device_get_update_image (FwupdDevice *device); +void fwupd_device_set_update_image (FwupdDevice *device, + const gchar *update_image); FwupdStatus fwupd_device_get_status (FwupdDevice *self); void fwupd_device_set_status (FwupdDevice *self, FwupdStatus status); diff --git a/libfwupd/fwupd-enums-private.h b/libfwupd/fwupd-enums-private.h index 7d2bc8136..386422eea 100644 --- a/libfwupd/fwupd-enums-private.h +++ b/libfwupd/fwupd-enums-private.h @@ -47,6 +47,7 @@ G_BEGIN_DECLS #define FWUPD_RESULT_KEY_SUMMARY "Summary" /* s */ #define FWUPD_RESULT_KEY_TRUST_FLAGS "TrustFlags" /* t */ #define FWUPD_RESULT_KEY_UPDATE_MESSAGE "UpdateMessage" /* s */ +#define FWUPD_RESULT_KEY_UPDATE_IMAGE "UpdateImage" /* s */ #define FWUPD_RESULT_KEY_UPDATE_ERROR "UpdateError" /* s */ #define FWUPD_RESULT_KEY_UPDATE_STATE "UpdateState" /* u */ #define FWUPD_RESULT_KEY_URI "Uri" /* s */ diff --git a/libfwupd/fwupd-release.c b/libfwupd/fwupd-release.c index 3794ccd9c..ff224c02d 100644 --- a/libfwupd/fwupd-release.c +++ b/libfwupd/fwupd-release.c @@ -56,6 +56,7 @@ typedef struct { FwupdReleaseFlags flags; FwupdReleaseUrgency urgency; gchar *update_message; + gchar *update_image; } FwupdReleasePrivate; G_DEFINE_TYPE_WITH_PRIVATE (FwupdRelease, fwupd_release, G_TYPE_OBJECT) @@ -209,6 +210,42 @@ fwupd_release_set_update_message (FwupdRelease *release, const gchar *update_mes priv->update_message = g_strdup (update_message); } +/** + * fwupd_release_get_update_image: + * @release: A #FwupdRelease + * + * Gets the update image. + * + * Returns: the update image URL, or %NULL if unset + * + * Since: 1.4.5 + **/ +const gchar * +fwupd_release_get_update_image (FwupdRelease *release) +{ + FwupdReleasePrivate *priv = GET_PRIVATE (release); + g_return_val_if_fail (FWUPD_IS_RELEASE (release), NULL); + return priv->update_image; +} + +/** + * fwupd_release_set_update_image: + * @release: A #FwupdRelease + * @update_image: the update image URL + * + * Sets the update image. + * + * Since: 1.4.5 + **/ +void +fwupd_release_set_update_image (FwupdRelease *release, const gchar *update_image) +{ + FwupdReleasePrivate *priv = GET_PRIVATE (release); + g_return_if_fail (FWUPD_IS_RELEASE (release)); + g_free (priv->update_image); + priv->update_image = g_strdup (update_image); +} + /** * fwupd_release_get_protocol: * @release: A #FwupdRelease @@ -1545,6 +1582,10 @@ fwupd_release_from_key_value (FwupdRelease *release, const gchar *key, GVariant fwupd_release_set_update_message (release, g_variant_get_string (value, NULL)); return; } + if (g_strcmp0 (key, FWUPD_RESULT_KEY_UPDATE_IMAGE) == 0) { + fwupd_release_set_update_image (release, g_variant_get_string (value, NULL)); + return; + } if (g_strcmp0 (key, FWUPD_RESULT_KEY_METADATA) == 0) { g_hash_table_unref (priv->metadata); priv->metadata = _variant_to_hash_kv (value); @@ -1715,6 +1756,7 @@ fwupd_release_to_json (FwupdRelease *release, JsonBuilder *builder) fwupd_release_json_add_string (builder, FWUPD_RESULT_KEY_DETACH_CAPTION, priv->detach_caption); fwupd_release_json_add_string (builder, FWUPD_RESULT_KEY_DETACH_IMAGE, priv->detach_image); fwupd_release_json_add_string (builder, FWUPD_RESULT_KEY_UPDATE_MESSAGE, priv->update_message); + fwupd_release_json_add_string (builder, FWUPD_RESULT_KEY_UPDATE_IMAGE, priv->update_image); /* metadata */ keys = g_hash_table_get_keys (priv->metadata); @@ -1783,6 +1825,8 @@ fwupd_release_to_string (FwupdRelease *release) fwupd_pad_kv_str (str, FWUPD_RESULT_KEY_DETACH_IMAGE, priv->detach_image); if (priv->update_message != NULL) fwupd_pad_kv_str (str, FWUPD_RESULT_KEY_UPDATE_MESSAGE, priv->update_message); + if (priv->update_message != NULL) + fwupd_pad_kv_str (str, FWUPD_RESULT_KEY_UPDATE_IMAGE, priv->update_image); /* metadata */ keys = g_hash_table_get_keys (priv->metadata); for (GList *l = keys; l != NULL; l = l->next) { @@ -1835,6 +1879,7 @@ fwupd_release_finalize (GObject *object) g_free (priv->version); g_free (priv->remote_id); g_free (priv->update_message); + g_free (priv->update_image); g_ptr_array_unref (priv->categories); g_ptr_array_unref (priv->issues); g_ptr_array_unref (priv->checksums); diff --git a/libfwupd/fwupd-release.h b/libfwupd/fwupd-release.h index 187964c9b..d00979047 100644 --- a/libfwupd/fwupd-release.h +++ b/libfwupd/fwupd-release.h @@ -134,6 +134,9 @@ void fwupd_release_set_install_duration (FwupdRelease *release, const gchar *fwupd_release_get_update_message (FwupdRelease *release); void fwupd_release_set_update_message (FwupdRelease *release, const gchar *update_message); +const gchar *fwupd_release_get_update_image (FwupdRelease *release); +void fwupd_release_set_update_image (FwupdRelease *release, + const gchar *update_image); FwupdRelease *fwupd_release_from_variant (GVariant *value); GPtrArray *fwupd_release_array_from_variant (GVariant *value); diff --git a/libfwupd/fwupd.map b/libfwupd/fwupd.map index 08279c991..750a19681 100644 --- a/libfwupd/fwupd.map +++ b/libfwupd/fwupd.map @@ -447,6 +447,15 @@ LIBFWUPD_1.4.1 { local: *; } LIBFWUPD_1.4.0; +LIBFWUPD_1.4.5 { + global: + fwupd_device_get_update_image; + fwupd_device_set_update_image; + fwupd_release_get_update_image; + fwupd_release_set_update_image; + local: *; +} LIBFWUPD_1.4.1; + LIBFWUPD_1.5.0 { global: fwupd_client_get_host_security_attrs; @@ -484,4 +493,4 @@ LIBFWUPD_1.5.0 { fwupd_security_attr_to_string; fwupd_security_attr_to_variant; local: *; -} LIBFWUPD_1.4.1; +} LIBFWUPD_1.4.5; diff --git a/libfwupdplugin/fu-device.c b/libfwupdplugin/fu-device.c index c51f7a2b0..167a38409 100644 --- a/libfwupdplugin/fu-device.c +++ b/libfwupdplugin/fu-device.c @@ -1009,6 +1009,10 @@ fu_device_set_quirk_kv (FuDevice *self, fu_device_set_update_message (self, value); return TRUE; } + if (g_strcmp0 (key, FU_QUIRKS_UPDATE_IMAGE) == 0) { + fu_device_set_update_image (self, value); + return TRUE; + } if (g_strcmp0 (key, FU_QUIRKS_ICON) == 0) { fu_device_add_icon (self, value); return TRUE; @@ -3164,6 +3168,9 @@ fu_device_incorporate_from_component (FuDevice *self, XbNode *component) tmp = xb_node_query_text (component, "custom/value[@key='LVFS::UpdateMessage']", NULL); if (tmp != NULL) fwupd_device_set_update_message (FWUPD_DEVICE (self), tmp); + tmp = xb_node_query_text (component, "custom/value[@key='LVFS::UpdateImage']", NULL); + if (tmp != NULL) + fwupd_device_set_update_image (FWUPD_DEVICE (self), tmp); } static void diff --git a/libfwupdplugin/fu-device.h b/libfwupdplugin/fu-device.h index f2c91850f..39cc515d7 100644 --- a/libfwupdplugin/fu-device.h +++ b/libfwupdplugin/fu-device.h @@ -125,6 +125,7 @@ FuDevice *fu_device_new (void); #define fu_device_set_serial(d,v) fwupd_device_set_serial(FWUPD_DEVICE(d),v) #define fu_device_set_summary(d,v) fwupd_device_set_summary(FWUPD_DEVICE(d),v) #define fu_device_set_update_message(d,v) fwupd_device_set_update_message(FWUPD_DEVICE(d),v) +#define fu_device_set_update_image(d,v) fwupd_device_set_update_image(FWUPD_DEVICE(d),v) #define fu_device_set_update_error(d,v) fwupd_device_set_update_error(FWUPD_DEVICE(d),v) #define fu_device_set_update_state(d,v) fwupd_device_set_update_state(FWUPD_DEVICE(d),v) #define fu_device_set_vendor(d,v) fwupd_device_set_vendor(FWUPD_DEVICE(d),v) diff --git a/libfwupdplugin/fu-quirks.h b/libfwupdplugin/fu-quirks.h index 213cbf155..763c365e6 100644 --- a/libfwupdplugin/fu-quirks.h +++ b/libfwupdplugin/fu-quirks.h @@ -64,5 +64,6 @@ gboolean fu_quirks_lookup_by_id_iter (FuQuirks *self, #define FU_QUIRKS_GTYPE "GType" #define FU_QUIRKS_PROTOCOL "Protocol" #define FU_QUIRKS_UPDATE_MESSAGE "UpdateMessage" +#define FU_QUIRKS_UPDATE_IMAGE "UpdateImage" #define FU_QUIRKS_PRIORITY "Priority" #define FU_QUIRKS_REMOVE_DELAY "RemoveDelay" diff --git a/src/fu-engine.c b/src/fu-engine.c index 3e0297dcf..b8d6354d6 100644 --- a/src/fu-engine.c +++ b/src/fu-engine.c @@ -454,6 +454,9 @@ fu_engine_set_release_from_appstream (FuEngine *self, tmp = xb_node_query_text (component, "custom/value[@key='LVFS::UpdateMessage']", NULL); if (tmp != NULL) fwupd_release_set_update_message (rel, tmp); + tmp = xb_node_query_text (component, "custom/value[@key='LVFS::UpdateImage']", NULL); + if (tmp != NULL) + fwupd_release_set_update_image (rel, tmp); return TRUE; } @@ -4125,6 +4128,7 @@ fu_engine_add_releases_for_device_component (FuEngine *self, XbNode *release = g_ptr_array_index (releases_tmp, i); const gchar *remote_id; const gchar *update_message; + const gchar *update_image; gint vercmp; GPtrArray *checksums; g_autoptr(FwupdRelease) rel = fwupd_release_new (); @@ -4185,7 +4189,12 @@ fu_engine_add_releases_for_device_component (FuEngine *self, update_message = fwupd_release_get_update_message (rel); if (fwupd_device_get_update_message (FWUPD_DEVICE (device)) == NULL && update_message != NULL) { - fwupd_device_set_update_message (FWUPD_DEVICE (device), update_message); + fwupd_device_set_update_message (FWUPD_DEVICE (device), update_message); + } + update_image = fwupd_release_get_update_image (rel); + if (fwupd_device_get_update_image (FWUPD_DEVICE (device)) == NULL && + update_image != NULL) { + fwupd_device_set_update_image (FWUPD_DEVICE (device), update_image); } /* success */ g_ptr_array_add (releases, g_steal_pointer (&rel)); From df89cd566eb1cd0f94b2a49313519e8fbaf53144 Mon Sep 17 00:00:00 2001 From: Richard Hughes Date: Fri, 26 Jun 2020 20:25:18 +0100 Subject: [PATCH 221/607] Allow firmware to require specific features from front-end clients At the moment we just blindly assume the capabilities of the front-end client when installing firmware. We can somewhat work around by requiring a new enough fwupd daemon version, but the client software may be older or just incomplete. This would allow, for instance, the firmware to specify that it requries the client to be able to show a detach image. This would not be set by a command line tool using FwupdClient, but would be set by a GUI client that is capable of downloading a URL and showing a PNG image. Clients that do not register features are assumed to be dumb. --- libfwupd/fwupd-client.c | 50 ++++++++++ libfwupd/fwupd-client.h | 4 + libfwupd/fwupd-enums.c | 48 +++++++++ libfwupd/fwupd-enums.h | 20 ++++ libfwupd/fwupd.map | 3 + src/fu-engine-helper.c | 11 +- src/fu-engine-request.c | 70 +++++++++++++ src/fu-engine-request.h | 20 ++++ src/fu-engine.c | 118 ++++++++++++++++++---- src/fu-engine.h | 12 ++- src/fu-main.c | 82 +++++++++++---- src/fu-self-test.c | 183 ++++++++++++++++++++++++++++++---- src/fu-tool.c | 47 +++++++-- src/fu-util.c | 15 +++ src/meson.build | 3 + src/org.freedesktop.fwupd.xml | 20 ++++ 16 files changed, 637 insertions(+), 69 deletions(-) create mode 100644 src/fu-engine-request.c create mode 100644 src/fu-engine-request.h diff --git a/libfwupd/fwupd-client.c b/libfwupd/fwupd-client.c index 92b051826..41ef2bb51 100644 --- a/libfwupd/fwupd-client.c +++ b/libfwupd/fwupd-client.c @@ -1760,6 +1760,56 @@ fwupd_client_set_approved_firmware (FwupdClient *client, return TRUE; } +/** + * fwupd_client_set_feature_flags: + * @client: A #FwupdClient + * @feature_flags: #FwupdFeatureFlags, e.g. %FWUPD_FEATURE_FLAG_UPDATE_TEXT + * @cancellable: the #GCancellable, or %NULL + * @error: the #GError, or %NULL + * + * Sets the features the client supports. This allows firmware to depend on + * specific front-end features, for instance showing the user an image on + * how to detach the hardware. + * + * Clients can call this none or multiple times. + * + * Returns: %TRUE for success + * + * Since: 1.4.5 + **/ +gboolean +fwupd_client_set_feature_flags (FwupdClient *client, + FwupdFeatureFlags feature_flags, + GCancellable *cancellable, + GError **error) +{ + FwupdClientPrivate *priv = GET_PRIVATE (client); + g_autoptr(GVariant) val = NULL; + + g_return_val_if_fail (FWUPD_IS_CLIENT (client), FALSE); + g_return_val_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable), FALSE); + g_return_val_if_fail (error == NULL || *error == NULL, FALSE); + + /* connect */ + if (!fwupd_client_connect (client, cancellable, error)) + return FALSE; + + /* call into daemon */ + val = g_dbus_proxy_call_sync (priv->proxy, + "SetFeatureFlags", + g_variant_new ("(t)", (guint64) feature_flags), + G_DBUS_CALL_FLAGS_NONE, + -1, + cancellable, + error); + if (val == NULL) { + if (error != NULL) + fwupd_client_fixup_dbus_error (*error); + return FALSE; + } + return TRUE; +} + /** * fwupd_client_self_sign: * @client: A #FwupdClient diff --git a/libfwupd/fwupd-client.h b/libfwupd/fwupd-client.h index 80e84818d..3b3649522 100644 --- a/libfwupd/fwupd-client.h +++ b/libfwupd/fwupd-client.h @@ -162,5 +162,9 @@ gchar *fwupd_client_self_sign (FwupdClient *client, FwupdSelfSignFlags flags, GCancellable *cancellable, GError **error); +gboolean fwupd_client_set_feature_flags (FwupdClient *client, + FwupdFeatureFlags feature_flags, + GCancellable *cancellable, + GError **error); G_END_DECLS diff --git a/libfwupd/fwupd-enums.c b/libfwupd/fwupd-enums.c index 16100b8e7..16d3356da 100644 --- a/libfwupd/fwupd-enums.c +++ b/libfwupd/fwupd-enums.c @@ -398,6 +398,54 @@ fwupd_trust_flag_from_string (const gchar *trust_flag) return FWUPD_TRUST_FLAG_LAST; } +/** + * fwupd_feature_flag_to_string: + * @feature_flag: A #FwupdFeatureFlags, e.g. %FWUPD_FEATURE_FLAG_DETACH_ACTION + * + * Converts a #FwupdFeatureFlags to a string. + * + * Return value: identifier string + * + * Since: 1.4.5 + **/ +const gchar * +fwupd_feature_flag_to_string (FwupdFeatureFlags feature_flag) +{ + if (feature_flag == FWUPD_FEATURE_FLAG_NONE) + return "none"; + if (feature_flag == FWUPD_FEATURE_FLAG_CAN_REPORT) + return "can-report"; + if (feature_flag == FWUPD_FEATURE_FLAG_DETACH_ACTION) + return "detach-action"; + if (feature_flag == FWUPD_FEATURE_FLAG_UPDATE_ACTION) + return "update-action"; + return NULL; +} + +/** + * fwupd_feature_flag_from_string: + * @feature_flag: A string, e.g. `detach-action` + * + * Converts a string to a #FwupdFeatureFlags. + * + * Return value: enumerated value + * + * Since: 1.4.5 + **/ +FwupdFeatureFlags +fwupd_feature_flag_from_string (const gchar *feature_flag) +{ + if (g_strcmp0 (feature_flag, "none") == 0) + return FWUPD_FEATURE_FLAG_NONE; + if (g_strcmp0 (feature_flag, "can-report") == 0) + return FWUPD_FEATURE_FLAG_CAN_REPORT; + if (g_strcmp0 (feature_flag, "detach-action") == 0) + return FWUPD_FEATURE_FLAG_DETACH_ACTION; + if (g_strcmp0 (feature_flag, "update-action") == 0) + return FWUPD_FEATURE_FLAG_UPDATE_ACTION; + return FWUPD_FEATURE_FLAG_LAST; +} + /** * fwupd_keyring_kind_from_string: * @keyring_kind: a string, e.g. `gpg` diff --git a/libfwupd/fwupd-enums.h b/libfwupd/fwupd-enums.h index 8550a2a2c..cb39ffee7 100644 --- a/libfwupd/fwupd-enums.h +++ b/libfwupd/fwupd-enums.h @@ -64,6 +64,24 @@ typedef enum { FWUPD_TRUST_FLAG_LAST } FwupdTrustFlags; +/** + * FwupdFeatureFlags: + * @FWUPD_FEATURE_FLAG_NONE: No trust + * @FWUPD_FEATURE_FLAG_CAN_REPORT: Can upload a report of the update back to the server + * @FWUPD_FEATURE_FLAG_DETACH_ACTION: Can perform detach action, typically showing text + * @FWUPD_FEATURE_FLAG_UPDATE_ACTION: Can perform update action, typically showing text + * + * The flags to the feature capabilities of the front-end client. + **/ +typedef enum { + FWUPD_FEATURE_FLAG_NONE = 0, /* Since: 1.4.5 */ + FWUPD_FEATURE_FLAG_CAN_REPORT = 1 << 0, /* Since: 1.4.5 */ + FWUPD_FEATURE_FLAG_DETACH_ACTION = 1 << 1, /* Since: 1.4.5 */ + FWUPD_FEATURE_FLAG_UPDATE_ACTION = 1 << 2, /* Since: 1.4.5 */ + /*< private >*/ + FWUPD_FEATURE_FLAG_LAST +} FwupdFeatureFlags; + /** * FwupdDeviceFlags: * @FWUPD_DEVICE_FLAG_NONE: No flags set @@ -325,6 +343,8 @@ const gchar *fwupd_update_state_to_string (FwupdUpdateState update_state); FwupdUpdateState fwupd_update_state_from_string (const gchar *update_state); const gchar *fwupd_trust_flag_to_string (FwupdTrustFlags trust_flag); FwupdTrustFlags fwupd_trust_flag_from_string (const gchar *trust_flag); +const gchar *fwupd_feature_flag_to_string (FwupdFeatureFlags feature_flag); +FwupdFeatureFlags fwupd_feature_flag_from_string (const gchar *feature_flag); FwupdKeyringKind fwupd_keyring_kind_from_string (const gchar *keyring_kind); const gchar *fwupd_keyring_kind_to_string (FwupdKeyringKind keyring_kind); FwupdVersionFormat fwupd_version_format_from_string (const gchar *str); diff --git a/libfwupd/fwupd.map b/libfwupd/fwupd.map index 750a19681..f7b5cb62c 100644 --- a/libfwupd/fwupd.map +++ b/libfwupd/fwupd.map @@ -449,8 +449,11 @@ LIBFWUPD_1.4.1 { LIBFWUPD_1.4.5 { global: + fwupd_client_set_feature_flags; fwupd_device_get_update_image; fwupd_device_set_update_image; + fwupd_feature_flag_from_string; + fwupd_feature_flag_to_string; fwupd_release_get_update_image; fwupd_release_set_update_image; local: *; diff --git a/src/fu-engine-helper.c b/src/fu-engine-helper.c index 82ec7efed..e223508bd 100644 --- a/src/fu-engine-helper.c +++ b/src/fu-engine-helper.c @@ -17,10 +17,16 @@ gboolean fu_engine_update_motd (FuEngine *self, GError **error) { guint upgrade_count = 0; + g_autoptr(FuEngineRequest) request = fu_engine_request_new (); g_autoptr(GPtrArray) devices = NULL; g_autoptr(GString) str = NULL; g_autofree gchar *target = NULL; + /* a subset of what fwupdmgr can do */ + fu_engine_request_set_feature_flags (request, + FWUPD_FEATURE_FLAG_DETACH_ACTION | + FWUPD_FEATURE_FLAG_UPDATE_ACTION); + /* get devices from daemon, we even want to know if it's nothing */ devices = fu_engine_get_devices (self, NULL); if (devices != NULL) { @@ -30,8 +36,9 @@ fu_engine_update_motd (FuEngine *self, GError **error) /* get the releases for this device */ rels = fu_engine_get_upgrades (self, - fwupd_device_get_id (dev), - NULL); + request, + fwupd_device_get_id (dev), + NULL); if (rels == NULL) continue; upgrade_count++; diff --git a/src/fu-engine-request.c b/src/fu-engine-request.c new file mode 100644 index 000000000..becdb6596 --- /dev/null +++ b/src/fu-engine-request.c @@ -0,0 +1,70 @@ +/* + * Copyright (C) 2020 Richard Hughes + * + * SPDX-License-Identifier: LGPL-2.1+ + */ + +#define G_LOG_DOMAIN "FuEngine" + +#include "config.h" + +#include "fu-engine-request.h" + +struct _FuEngineRequest +{ + GObject parent_instance; + FwupdFeatureFlags feature_flags; + FwupdDeviceFlags device_flags; +}; + +G_DEFINE_TYPE (FuEngineRequest, fu_engine_request, G_TYPE_OBJECT) + +FwupdFeatureFlags +fu_engine_request_get_feature_flags (FuEngineRequest *self) +{ + g_return_val_if_fail (FU_IS_ENGINE_REQUEST (self), FALSE); + return self->feature_flags; +} + +void +fu_engine_request_set_feature_flags (FuEngineRequest *self, + FwupdFeatureFlags feature_flags) +{ + g_return_if_fail (FU_IS_ENGINE_REQUEST (self)); + self->feature_flags = feature_flags; +} + +FwupdDeviceFlags +fu_engine_request_get_device_flags (FuEngineRequest *self) +{ + g_return_val_if_fail (FU_IS_ENGINE_REQUEST (self), FALSE); + return self->device_flags; +} + +void +fu_engine_request_set_device_flags (FuEngineRequest *self, + FwupdDeviceFlags device_flags) +{ + g_return_if_fail (FU_IS_ENGINE_REQUEST (self)); + self->device_flags = device_flags; +} + +static void +fu_engine_request_init (FuEngineRequest *self) +{ + self->device_flags = FWUPD_DEVICE_FLAG_NONE; + self->feature_flags = FWUPD_FEATURE_FLAG_NONE; +} + +static void +fu_engine_request_class_init (FuEngineRequestClass *klass) +{ +} + +FuEngineRequest * +fu_engine_request_new (void) +{ + FuEngineRequest *self; + self = g_object_new (FU_TYPE_ENGINE_REQUEST, NULL); + return FU_ENGINE_REQUEST (self); +} diff --git a/src/fu-engine-request.h b/src/fu-engine-request.h new file mode 100644 index 000000000..7f7ec7a4a --- /dev/null +++ b/src/fu-engine-request.h @@ -0,0 +1,20 @@ +/* + * Copyright (C) 2020 Richard Hughes + * + * SPDX-License-Identifier: LGPL-2.1+ + */ + +#pragma once + +#include + +#define FU_TYPE_ENGINE_REQUEST (fu_engine_request_get_type ()) +G_DECLARE_FINAL_TYPE (FuEngineRequest, fu_engine_request, FU, ENGINE_REQUEST, GObject) + +FuEngineRequest *fu_engine_request_new (void); +FwupdFeatureFlags fu_engine_request_get_feature_flags (FuEngineRequest *self); +void fu_engine_request_set_feature_flags (FuEngineRequest *self, + FwupdFeatureFlags feature_flags); +FwupdDeviceFlags fu_engine_request_get_device_flags (FuEngineRequest *self); +void fu_engine_request_set_device_flags (FuEngineRequest *self, + FwupdDeviceFlags device_flags); diff --git a/src/fu-engine.c b/src/fu-engine.c index b8d6354d6..9dbc0d6d1 100644 --- a/src/fu-engine.c +++ b/src/fu-engine.c @@ -38,6 +38,7 @@ #include "fu-device-private.h" #include "fu-engine.h" #include "fu-engine-helper.h" +#include "fu-engine-request.h" #include "fu-hwids.h" #include "fu-idle.h" #include "fu-keyring-utils.h" @@ -1356,7 +1357,51 @@ fu_engine_check_requirement_hardware (FuEngine *self, XbNode *req, GError **erro } static gboolean -fu_engine_check_requirement (FuEngine *self, XbNode *req, FuDevice *device, GError **error) +fu_engine_check_requirement_client (FuEngine *self, + FuEngineRequest *request, + XbNode *req, + GError **error) +{ + FwupdFeatureFlags flags; + g_auto(GStrv) feature_split = NULL; + + /* split and treat as AND */ + feature_split = g_strsplit (xb_node_get_text (req), "|", -1); + flags = fu_engine_request_get_feature_flags (request); + for (guint i = 0; feature_split[i] != NULL; i++) { + FwupdFeatureFlags flag = fwupd_feature_flag_from_string (feature_split[i]); + + /* not recognised */ + if (flag == FWUPD_FEATURE_FLAG_LAST) { + g_set_error (error, + FWUPD_ERROR, + FWUPD_ERROR_NOT_FOUND, + "client requirement %s unknown", + feature_split[i]); + return FALSE; + } + + /* not supported */ + if ((flags & flag) == 0) { + g_set_error (error, + FWUPD_ERROR, + FWUPD_ERROR_NOT_SUPPORTED, + "client requirement %s not supported", + feature_split[i]); + return FALSE; + } + } + + /* success */ + return TRUE; +} + +static gboolean +fu_engine_check_requirement (FuEngine *self, + FuEngineRequest *request, + XbNode *req, + FuDevice *device, + GError **error) { /* ensure component requirement */ if (g_strcmp0 (xb_node_get_element (req), "id") == 0) @@ -1373,6 +1418,10 @@ fu_engine_check_requirement (FuEngine *self, XbNode *req, FuDevice *device, GErr if (g_strcmp0 (xb_node_get_element (req), "hardware") == 0) return fu_engine_check_requirement_hardware (self, req, error); + /* ensure client requirement */ + if (g_strcmp0 (xb_node_get_element (req), "client") == 0) + return fu_engine_check_requirement_client (self, request, req, error); + /* not supported */ g_set_error (error, FWUPD_ERROR, @@ -1383,8 +1432,11 @@ fu_engine_check_requirement (FuEngine *self, XbNode *req, FuDevice *device, GErr } gboolean -fu_engine_check_requirements (FuEngine *self, FuInstallTask *task, - FwupdInstallFlags flags, GError **error) +fu_engine_check_requirements (FuEngine *self, + FuEngineRequest *request, + FuInstallTask *task, + FwupdInstallFlags flags, + GError **error) { FuDevice *device = fu_install_task_get_device (task); g_autoptr(GError) error_local = NULL; @@ -1409,7 +1461,7 @@ fu_engine_check_requirements (FuEngine *self, FuInstallTask *task, } for (guint i = 0; i < reqs->len; i++) { XbNode *req = g_ptr_array_index (reqs, i); - if (!fu_engine_check_requirement (self, req, device, error)) + if (!fu_engine_check_requirement (self, request, req, device, error)) return FALSE; } return TRUE; @@ -1673,6 +1725,7 @@ fu_engine_composite_cleanup (FuEngine *self, GPtrArray *devices, GError **error) /** * fu_engine_install_tasks: * @self: A #FuEngine + * @request: A #FuEngineRequest * @install_tasks: (element-type FuInstallTask): A #FuDevice * @blob_cab: The #GBytes of the .cab file * @flags: The #FwupdInstallFlags, e.g. %FWUPD_DEVICE_FLAG_UPDATABLE @@ -1688,6 +1741,7 @@ fu_engine_composite_cleanup (FuEngine *self, GPtrArray *devices, GError **error) **/ gboolean fu_engine_install_tasks (FuEngine *self, + FuEngineRequest *request, GPtrArray *install_tasks, GBytes *blob_cab, FwupdInstallFlags flags, @@ -2940,9 +2994,14 @@ fu_engine_ensure_device_supported (FuEngine *self, FuDevice *device) gboolean is_supported = FALSE; g_autoptr(GError) error = NULL; g_autoptr(GPtrArray) releases = NULL; + g_autoptr(FuEngineRequest) request = fu_engine_request_new (); + + /* all flags set */ + fu_engine_request_set_feature_flags (request, ~0); /* get all releases that pass the requirements */ releases = fu_engine_get_releases_for_device (self, + request, device, &error); if (releases == NULL) { @@ -3581,7 +3640,10 @@ fu_engine_get_silo_from_blob (FuEngine *self, GBytes *blob_cab, GError **error) } static FuDevice * -fu_engine_get_result_from_component (FuEngine *self, XbNode *component, GError **error) +fu_engine_get_result_from_component (FuEngine *self, + FuEngineRequest *request, + XbNode *component, + GError **error) { FwupdReleaseFlags release_flags = FWUPD_RELEASE_FLAG_NONE; g_autoptr(FuInstallTask) task = NULL; @@ -3639,7 +3701,7 @@ fu_engine_get_result_from_component (FuEngine *self, XbNode *component, GError * /* check we can install it */ task = fu_install_task_new (NULL, component); - if (!fu_engine_check_requirements (self, task, + if (!fu_engine_check_requirements (self, request, task, FWUPD_INSTALL_FLAG_NONE, error)) return NULL; @@ -3715,6 +3777,7 @@ fu_engine_get_details_sort_cb (gconstpointer a, gconstpointer b) /** * fu_engine_get_details: * @self: A #FuEngine + * @request: A #FuEngineRequest * @fd: A file descriptor * @error: A #GError, or %NULL * @@ -3725,7 +3788,7 @@ fu_engine_get_details_sort_cb (gconstpointer a, gconstpointer b) * Returns: (transfer container) (element-type FuDevice): results **/ GPtrArray * -fu_engine_get_details (FuEngine *self, gint fd, GError **error) +fu_engine_get_details (FuEngine *self, FuEngineRequest *request, gint fd, GError **error) { const gchar *remote_id; g_autofree gchar *csum = NULL; @@ -3775,7 +3838,7 @@ fu_engine_get_details (FuEngine *self, gint fd, GError **error) for (guint i = 0; i < components->len; i++) { XbNode *component = g_ptr_array_index (components, i); FuDevice *dev; - dev = fu_engine_get_result_from_component (self, component, error); + dev = fu_engine_get_result_from_component (self, request, component, error); if (dev == NULL) return NULL; if (remote_id != NULL) { @@ -3791,7 +3854,7 @@ fu_engine_get_details (FuEngine *self, gint fd, GError **error) if (fu_device_has_flag (dev, FWUPD_DEVICE_FLAG_UPDATABLE)) { g_autoptr(FuInstallTask) task = fu_install_task_new (dev, component); g_autoptr(GError) error_req = NULL; - if (!fu_engine_check_requirements (self, task, + if (!fu_engine_check_requirements (self, request, task, FWUPD_INSTALL_FLAG_OFFLINE | FWUPD_INSTALL_FLAG_ALLOW_REINSTALL | FWUPD_INSTALL_FLAG_ALLOW_OLDER, @@ -4097,6 +4160,7 @@ fu_engine_check_release_is_approved (FuEngine *self, FwupdRelease *rel) static gboolean fu_engine_add_releases_for_device_component (FuEngine *self, + FuEngineRequest *request, FuDevice *device, XbNode *component, GPtrArray *releases, @@ -4107,7 +4171,7 @@ fu_engine_add_releases_for_device_component (FuEngine *self, g_autoptr(FuInstallTask) task = fu_install_task_new (device, component); g_autoptr(GPtrArray) releases_tmp = NULL; - if (!fu_engine_check_requirements (self, task, + if (!fu_engine_check_requirements (self, request, task, FWUPD_INSTALL_FLAG_OFFLINE | FWUPD_INSTALL_FLAG_ALLOW_REINSTALL | FWUPD_INSTALL_FLAG_ALLOW_OLDER, @@ -4205,7 +4269,10 @@ fu_engine_add_releases_for_device_component (FuEngine *self, } GPtrArray * -fu_engine_get_releases_for_device (FuEngine *self, FuDevice *device, GError **error) +fu_engine_get_releases_for_device (FuEngine *self, + FuEngineRequest *request, + FuDevice *device, + GError **error) { GPtrArray *device_guids; GPtrArray *releases; @@ -4263,6 +4330,7 @@ fu_engine_get_releases_for_device (FuEngine *self, FuDevice *device, GError **er XbNode *component = XB_NODE (g_ptr_array_index (components, i)); g_autoptr(GError) error_tmp = NULL; if (!fu_engine_add_releases_for_device_component (self, + request, device, component, releases, @@ -4296,6 +4364,7 @@ fu_engine_get_releases_for_device (FuEngine *self, FuDevice *device, GError **er /** * fu_engine_get_releases: * @self: A #FuEngine + * @request: A #FuEngineRequest * @device_id: A device ID * @error: A #GError, or %NULL * @@ -4304,7 +4373,10 @@ fu_engine_get_releases_for_device (FuEngine *self, FuDevice *device, GError **er * Returns: (transfer container) (element-type FwupdDevice): results **/ GPtrArray * -fu_engine_get_releases (FuEngine *self, const gchar *device_id, GError **error) +fu_engine_get_releases (FuEngine *self, + FuEngineRequest *request, + const gchar *device_id, + GError **error) { g_autoptr(FuDevice) device = NULL; g_autoptr(GPtrArray) releases = NULL; @@ -4319,7 +4391,7 @@ fu_engine_get_releases (FuEngine *self, const gchar *device_id, GError **error) return NULL; /* get all the releases for the device */ - releases = fu_engine_get_releases_for_device (self, device, error); + releases = fu_engine_get_releases_for_device (self, request, device, error); if (releases == NULL) return NULL; if (releases->len == 0) { @@ -4336,6 +4408,7 @@ fu_engine_get_releases (FuEngine *self, const gchar *device_id, GError **error) /** * fu_engine_get_downgrades: * @self: A #FuEngine + * @request: A #FuEngineRequest * @device_id: A device ID * @error: A #GError, or %NULL * @@ -4344,7 +4417,10 @@ fu_engine_get_releases (FuEngine *self, const gchar *device_id, GError **error) * Returns: (transfer container) (element-type FwupdDevice): results **/ GPtrArray * -fu_engine_get_downgrades (FuEngine *self, const gchar *device_id, GError **error) +fu_engine_get_downgrades (FuEngine *self, + FuEngineRequest *request, + const gchar *device_id, + GError **error) { g_autoptr(FuDevice) device = NULL; g_autoptr(GPtrArray) releases = NULL; @@ -4361,7 +4437,7 @@ fu_engine_get_downgrades (FuEngine *self, const gchar *device_id, GError **error return NULL; /* get all the releases for the device */ - releases_tmp = fu_engine_get_releases_for_device (self, device, error); + releases_tmp = fu_engine_get_releases_for_device (self, request, device, error); if (releases_tmp == NULL) return NULL; releases = g_ptr_array_new_with_free_func ((GDestroyNotify) g_object_unref); @@ -4481,6 +4557,7 @@ fu_engine_self_sign (FuEngine *self, /** * fu_engine_get_upgrades: * @self: A #FuEngine + * @request: A #FuEngineRequest * @device_id: A device ID * @error: A #GError, or %NULL * @@ -4489,7 +4566,10 @@ fu_engine_self_sign (FuEngine *self, * Returns: (transfer container) (element-type FwupdDevice): results **/ GPtrArray * -fu_engine_get_upgrades (FuEngine *self, const gchar *device_id, GError **error) +fu_engine_get_upgrades (FuEngine *self, + FuEngineRequest *request, + const gchar *device_id, + GError **error) { g_autoptr(FuDevice) device = NULL; g_autoptr(GPtrArray) releases = NULL; @@ -4515,7 +4595,7 @@ fu_engine_get_upgrades (FuEngine *self, const gchar *device_id, GError **error) } /* get all the releases for the device */ - releases_tmp = fu_engine_get_releases_for_device (self, device, error); + releases_tmp = fu_engine_get_releases_for_device (self, request, device, error); if (releases_tmp == NULL) return NULL; releases = g_ptr_array_new_with_free_func ((GDestroyNotify) g_object_unref); @@ -5487,7 +5567,9 @@ fu_engine_add_security_attrs_supported (FuEngine *self, FuSecurityAttrs *attrs) if (device == NULL) { fwupd_security_attr_set_result (attr_u, FWUPD_SECURITY_ATTR_RESULT_NOT_FOUND); } else { - releases = fu_engine_get_releases_for_device (self, device, NULL); + g_autoptr(FuEngineRequest) request = fu_engine_request_new (); + fu_engine_request_set_feature_flags (request, ~0); + releases = fu_engine_get_releases_for_device (self, request, device, NULL); if (releases == NULL) { fwupd_security_attr_set_result (attr_u, FWUPD_SECURITY_ATTR_RESULT_NOT_SUPPORTED); } else { diff --git a/src/fu-engine.h b/src/fu-engine.h index a1bd5df97..eaad096e8 100644 --- a/src/fu-engine.h +++ b/src/fu-engine.h @@ -14,6 +14,7 @@ #include "fwupd-enums.h" #include "fu-common.h" +#include "fu-engine-request.h" #include "fu-install-task.h" #include "fu-plugin.h" #include "fu-security-attrs.h" @@ -73,12 +74,15 @@ FwupdRemote *fu_engine_get_remote_by_id (FuEngine *self, GPtrArray *fu_engine_get_remotes (FuEngine *self, GError **error); GPtrArray *fu_engine_get_releases (FuEngine *self, + FuEngineRequest *request, const gchar *device_id, GError **error); GPtrArray *fu_engine_get_downgrades (FuEngine *self, + FuEngineRequest *request, const gchar *device_id, GError **error); GPtrArray *fu_engine_get_upgrades (FuEngine *self, + FuEngineRequest *request, const gchar *device_id, GError **error); FwupdDevice *fu_engine_get_results (FuEngine *self, @@ -140,11 +144,13 @@ gboolean fu_engine_install_blob (FuEngine *self, FwupdInstallFlags flags, GError **error); gboolean fu_engine_install_tasks (FuEngine *self, + FuEngineRequest *request, GPtrArray *install_tasks, GBytes *blob_cab, FwupdInstallFlags flags, GError **error); GPtrArray *fu_engine_get_details (FuEngine *self, + FuEngineRequest *request, gint fd, GError **error); gboolean fu_engine_activate (FuEngine *self, @@ -168,8 +174,9 @@ void fu_engine_md_refresh_device_from_component (FuEngine *self, FuDevice *device, XbNode *component); GPtrArray *fu_engine_get_releases_for_device (FuEngine *self, - FuDevice *device, - GError **error); + FuEngineRequest *request, + FuDevice *device, + GError **error); /* for the self tests */ void fu_engine_add_device (FuEngine *self, @@ -180,6 +187,7 @@ void fu_engine_add_runtime_version (FuEngine *self, const gchar *component_id, const gchar *version); gboolean fu_engine_check_requirements (FuEngine *self, + FuEngineRequest *request, FuInstallTask *task, FwupdInstallFlags flags, GError **error); diff --git a/src/fu-main.c b/src/fu-main.c index 363c9dacc..fe4e7316c 100644 --- a/src/fu-main.c +++ b/src/fu-main.c @@ -46,6 +46,7 @@ typedef struct { GDBusProxy *proxy_uid; GMainLoop *loop; GFileMonitor *argv0_monitor; + GHashTable *sender_features; /* sender:FwupdFeatureFlags */ #if GLIB_CHECK_VERSION(2,63,3) GMemoryMonitor *memory_monitor; #endif @@ -206,16 +207,23 @@ fu_main_engine_percentage_changed_cb (FuEngine *engine, g_variant_new_uint32 (percentage)); } -static gboolean -fu_main_get_device_flags_for_sender (FuMainPrivate *priv, const char *sender, - FwupdDeviceFlags *flags, GError **error) +static FuEngineRequest * +fu_main_create_request (FuMainPrivate *priv, const gchar *sender, GError **error) { - uid_t calling_uid; + FwupdFeatureFlags *feature_flags; + FwupdDeviceFlags device_flags = FWUPD_DEVICE_FLAG_NONE; + uid_t calling_uid = 0; + g_autoptr(FuEngineRequest) request = fu_engine_request_new (); g_autoptr(GVariant) value = NULL; - g_return_val_if_fail (sender != NULL, FALSE); - g_return_val_if_fail (flags != NULL, FALSE); + g_return_val_if_fail (sender != NULL, NULL); + /* did the client set the list of supported feature */ + feature_flags = g_hash_table_lookup (priv->sender_features, sender); + if (feature_flags != NULL) + fu_engine_request_set_feature_flags (request, *feature_flags); + + /* are we root and therefore trusted? */ value = g_dbus_proxy_call_sync (priv->proxy_uid, "GetConnectionUnixUser", g_variant_new ("(s)", sender), @@ -229,28 +237,26 @@ fu_main_get_device_flags_for_sender (FuMainPrivate *priv, const char *sender, } g_variant_get (value, "(u)", &calling_uid); if (calling_uid == 0) - *flags |= FWUPD_DEVICE_FLAG_TRUSTED; + device_flags |= FWUPD_DEVICE_FLAG_TRUSTED; + fu_engine_request_set_device_flags (request, device_flags); - return TRUE; + /* success */ + return g_steal_pointer (&request); } static GVariant * -fu_main_device_array_to_variant (FuMainPrivate *priv, const gchar *sender, +fu_main_device_array_to_variant (FuMainPrivate *priv, FuEngineRequest *request, GPtrArray *devices, GError **error) { GVariantBuilder builder; - FwupdDeviceFlags flags = FWUPD_DEVICE_FLAG_NONE; g_return_val_if_fail (devices->len > 0, NULL); g_variant_builder_init (&builder, G_VARIANT_TYPE_ARRAY); - if (!fu_main_get_device_flags_for_sender (priv, sender, &flags, error)) - return NULL; - for (guint i = 0; i < devices->len; i++) { FuDevice *device = g_ptr_array_index (devices, i); GVariant *tmp = fwupd_device_to_variant_full (FWUPD_DEVICE (device), - flags); + fu_engine_request_get_device_flags (request)); g_variant_builder_add_value (&builder, tmp); } return g_variant_new ("(aa{sv})", &builder); @@ -300,6 +306,7 @@ fu_main_result_array_to_variant (GPtrArray *results) typedef struct { GDBusMethodInvocation *invocation; + FuEngineRequest *request; PolkitSubject *subject; GPtrArray *install_tasks; GPtrArray *action_ids; @@ -323,6 +330,8 @@ fu_main_auth_helper_free (FuMainAuthHelper *helper) g_object_unref (helper->subject); if (helper->silo != NULL) g_object_unref (helper->silo); + if (helper->request != NULL) + g_object_unref (helper->request); if (helper->install_tasks != NULL) g_ptr_array_unref (helper->install_tasks); if (helper->action_ids != NULL) @@ -602,6 +611,7 @@ fu_main_authorize_install_queue (FuMainAuthHelper *helper_ref) /* all authenticated, so install all the things */ priv->update_in_progress = TRUE; ret = fu_engine_install_tasks (helper->priv->engine, + helper->request, helper->install_tasks, helper->blob_cab, helper->flags, @@ -731,6 +741,7 @@ fu_main_install_with_helper (FuMainAuthHelper *helper_ref, GError **error) /* is this component valid for the device */ task = fu_install_task_new (device, component); if (!fu_engine_check_requirements (priv->engine, + helper->request, task, helper->flags | FWUPD_INSTALL_FLAG_FORCE, &error_local)) { @@ -745,6 +756,7 @@ fu_main_install_with_helper (FuMainAuthHelper *helper_ref, GError **error) /* make a second pass using possibly updated version format now */ fu_engine_md_refresh_device_from_component (priv->engine, device, component); if (!fu_engine_check_requirements (priv->engine, + helper->request, task, helper->flags, &error_local)) { @@ -806,8 +818,16 @@ fu_main_daemon_method_call (GDBusConnection *connection, const gchar *sender, { FuMainPrivate *priv = (FuMainPrivate *) user_data; GVariant *val = NULL; + g_autoptr(FuEngineRequest) request = NULL; g_autoptr(GError) error = NULL; + /* build request */ + request = fu_main_create_request (priv, sender, &error); + if (request == NULL) { + g_dbus_method_invocation_return_gerror (invocation, error); + return; + } + /* activity */ fu_engine_idle_reset (priv->engine); @@ -819,7 +839,7 @@ fu_main_daemon_method_call (GDBusConnection *connection, const gchar *sender, g_dbus_method_invocation_return_gerror (invocation, error); return; } - val = fu_main_device_array_to_variant (priv, sender, devices, &error); + val = fu_main_device_array_to_variant (priv, request, devices, &error); if (val == NULL) { g_dbus_method_invocation_return_gerror (invocation, error); return; @@ -836,7 +856,7 @@ fu_main_daemon_method_call (GDBusConnection *connection, const gchar *sender, g_dbus_method_invocation_return_gerror (invocation, error); return; } - releases = fu_engine_get_releases (priv->engine, device_id, &error); + releases = fu_engine_get_releases (priv->engine, request, device_id, &error); if (releases == NULL) { g_dbus_method_invocation_return_gerror (invocation, error); return; @@ -897,6 +917,7 @@ fu_main_daemon_method_call (GDBusConnection *connection, const gchar *sender, fu_main_set_status (priv, FWUPD_STATUS_WAITING_FOR_AUTH); helper = g_new0 (FuMainAuthHelper, 1); helper->priv = priv; + helper->request = g_steal_pointer (&request); helper->invocation = g_object_ref (invocation); helper->checksums = g_ptr_array_new_with_free_func (g_free); for (guint i = 0; checksums[i] != NULL; i++) @@ -939,6 +960,7 @@ fu_main_daemon_method_call (GDBusConnection *connection, const gchar *sender, fu_main_set_status (priv, FWUPD_STATUS_WAITING_FOR_AUTH); helper->priv = priv; helper->value = g_steal_pointer (&value); + helper->request = g_steal_pointer (&request); helper->invocation = g_object_ref (invocation); subject = polkit_system_bus_name_new (sender); polkit_authority_check_authorization (priv->authority, subject, @@ -959,7 +981,7 @@ fu_main_daemon_method_call (GDBusConnection *connection, const gchar *sender, g_dbus_method_invocation_return_gerror (invocation, error); return; } - releases = fu_engine_get_downgrades (priv->engine, device_id, &error); + releases = fu_engine_get_downgrades (priv->engine, request, device_id, &error); if (releases == NULL) { g_dbus_method_invocation_return_gerror (invocation, error); return; @@ -977,7 +999,7 @@ fu_main_daemon_method_call (GDBusConnection *connection, const gchar *sender, g_dbus_method_invocation_return_gerror (invocation, error); return; } - releases = fu_engine_get_upgrades (priv->engine, device_id, &error); + releases = fu_engine_get_upgrades (priv->engine, request, device_id, &error); if (releases == NULL) { g_dbus_method_invocation_return_gerror (invocation, error); return; @@ -1006,7 +1028,7 @@ fu_main_daemon_method_call (GDBusConnection *connection, const gchar *sender, g_dbus_method_invocation_return_gerror (invocation, error); return; } - val = fu_main_device_array_to_variant (priv, sender, devices, &error); + val = fu_main_device_array_to_variant (priv, request, devices, &error); if (val == NULL) { g_dbus_method_invocation_return_gerror (invocation, error); return; @@ -1125,6 +1147,7 @@ fu_main_daemon_method_call (GDBusConnection *connection, const gchar *sender, fu_main_set_status (priv, FWUPD_STATUS_WAITING_FOR_AUTH); helper = g_new0 (FuMainAuthHelper, 1); helper->priv = priv; + helper->request = g_steal_pointer (&request); helper->invocation = g_object_ref (invocation); helper->device_id = g_strdup (device_id); subject = polkit_system_bus_name_new (sender); @@ -1153,6 +1176,7 @@ fu_main_daemon_method_call (GDBusConnection *connection, const gchar *sender, fu_main_set_status (priv, FWUPD_STATUS_WAITING_FOR_AUTH); helper = g_new0 (FuMainAuthHelper, 1); helper->priv = priv; + helper->request = g_steal_pointer (&request); helper->invocation = g_object_ref (invocation); helper->device_id = g_strdup (device_id); subject = polkit_system_bus_name_new (sender); @@ -1179,6 +1203,7 @@ fu_main_daemon_method_call (GDBusConnection *connection, const gchar *sender, helper->priv = priv; helper->key = g_steal_pointer (&key); helper->value = g_steal_pointer (&value); + helper->request = g_steal_pointer (&request); helper->invocation = g_object_ref (invocation); subject = polkit_system_bus_name_new (sender); polkit_authority_check_authorization (priv->authority, subject, @@ -1203,6 +1228,7 @@ fu_main_daemon_method_call (GDBusConnection *connection, const gchar *sender, /* create helper object */ helper = g_new0 (FuMainAuthHelper, 1); + helper->request = g_steal_pointer (&request); helper->invocation = g_object_ref (invocation); helper->remote_id = g_strdup (remote_id); helper->key = g_strdup (key); @@ -1236,6 +1262,7 @@ fu_main_daemon_method_call (GDBusConnection *connection, const gchar *sender, /* create helper object */ helper = g_new0 (FuMainAuthHelper, 1); + helper->request = g_steal_pointer (&request); helper->invocation = g_object_ref (invocation); helper->device_id = g_strdup (device_id); helper->priv = priv; @@ -1267,6 +1294,18 @@ fu_main_daemon_method_call (GDBusConnection *connection, const gchar *sender, g_dbus_method_invocation_return_value (invocation, NULL); return; } + if (g_strcmp0 (method_name, "SetFeatureFlags") == 0) { + guint64 feature_flags = 0; + g_variant_get (parameters, "(t)", &feature_flags); + g_debug ("Called %s(%" G_GUINT64_FORMAT ")", method_name, feature_flags); + + /* old flags for the same sender will be automatically destroyed */ + g_hash_table_insert (priv->sender_features, + g_strdup (sender), + g_memdup (&feature_flags, sizeof(feature_flags))); + g_dbus_method_invocation_return_value (invocation, NULL); + return; + } if (g_strcmp0 (method_name, "Install") == 0) { GVariant *prop_value; const gchar *device_id = NULL; @@ -1289,6 +1328,7 @@ fu_main_daemon_method_call (GDBusConnection *connection, const gchar *sender, /* create helper object */ helper = g_new0 (FuMainAuthHelper, 1); + helper->request = g_steal_pointer (&request); helper->invocation = g_object_ref (invocation); helper->device_id = g_strdup (device_id); helper->priv = priv; @@ -1381,7 +1421,7 @@ fu_main_daemon_method_call (GDBusConnection *connection, const gchar *sender, } /* get details about the file (will close the fd when done) */ - results = fu_engine_get_details (priv->engine, fd, &error); + results = fu_engine_get_details (priv->engine, request, fd, &error); if (results == NULL) { g_dbus_method_invocation_return_gerror (invocation, error); return; @@ -1559,6 +1599,7 @@ fu_main_load_introspection (const gchar *filename, GError **error) static void fu_main_private_free (FuMainPrivate *priv) { + g_hash_table_unref (priv->sender_features); if (priv->loop != NULL) g_main_loop_unref (priv->loop); if (priv->owner_id > 0) @@ -1626,6 +1667,7 @@ main (int argc, char *argv[]) /* create new objects */ priv = g_new0 (FuMainPrivate, 1); + priv->sender_features = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_free); priv->loop = g_main_loop_new (NULL, FALSE); /* load engine */ diff --git a/src/fu-self-test.c b/src/fu-self-test.c index 0991a3618..623015c61 100644 --- a/src/fu-self-test.c +++ b/src/fu-self-test.c @@ -191,6 +191,7 @@ fu_engine_requirements_missing_func (gconstpointer user_data) g_autoptr(XbNode) component = NULL; g_autoptr(XbSilo) silo = NULL; g_autoptr(FuEngine) engine = fu_engine_new (FU_APP_FLAGS_NONE); + g_autoptr(FuEngineRequest) request = fu_engine_request_new (); g_autoptr(FuInstallTask) task = NULL; g_autoptr(GError) error = NULL; const gchar *xml = @@ -213,19 +214,126 @@ fu_engine_requirements_missing_func (gconstpointer user_data) /* check this fails */ task = fu_install_task_new (NULL, component); - ret = fu_engine_check_requirements (engine, task, + ret = fu_engine_check_requirements (engine, request, task, FWUPD_INSTALL_FLAG_NONE, &error); g_assert_error (error, FWUPD_ERROR, FWUPD_ERROR_NOT_FOUND); g_assert (!ret); } +static void +fu_engine_requirements_client_fail_func (gconstpointer user_data) +{ + gboolean ret; + g_autoptr(XbNode) component = NULL; + g_autoptr(XbSilo) silo = NULL; + g_autoptr(FuEngine) engine = fu_engine_new (FU_APP_FLAGS_NONE); + g_autoptr(FuEngineRequest) request = fu_engine_request_new (); + g_autoptr(FuInstallTask) task = NULL; + g_autoptr(GError) error = NULL; + const gchar *xml = + "" + " " + " detach-action" + " " + ""; + + /* make the component require one thing */ + silo = xb_silo_new_from_xml (xml, &error); + g_assert_no_error (error); + g_assert_nonnull (silo); + component = xb_silo_query_first (silo, "component", &error); + g_assert_no_error (error); + g_assert_nonnull (component); + + /* check this fails */ + task = fu_install_task_new (NULL, component); + ret = fu_engine_check_requirements (engine, request, task, + FWUPD_INSTALL_FLAG_NONE, + &error); + g_assert_error (error, FWUPD_ERROR, FWUPD_ERROR_NOT_SUPPORTED); + g_assert (!ret); +} + +static void +fu_engine_requirements_client_invalid_func (gconstpointer user_data) +{ + gboolean ret; + g_autoptr(XbNode) component = NULL; + g_autoptr(XbSilo) silo = NULL; + g_autoptr(FuEngine) engine = fu_engine_new (FU_APP_FLAGS_NONE); + g_autoptr(FuEngineRequest) request = fu_engine_request_new (); + g_autoptr(FuInstallTask) task = NULL; + g_autoptr(GError) error = NULL; + const gchar *xml = + "" + " " + " hello-dave" + " " + ""; + + /* make the component require one thing */ + silo = xb_silo_new_from_xml (xml, &error); + g_assert_no_error (error); + g_assert_nonnull (silo); + component = xb_silo_query_first (silo, "component", &error); + g_assert_no_error (error); + g_assert_nonnull (component); + + /* check this fails */ + task = fu_install_task_new (NULL, component); + ret = fu_engine_check_requirements (engine, request, task, + FWUPD_INSTALL_FLAG_NONE, + &error); + g_assert_error (error, FWUPD_ERROR, FWUPD_ERROR_NOT_FOUND); + g_assert (!ret); +} + +static void +fu_engine_requirements_client_pass_func (gconstpointer user_data) +{ + gboolean ret; + g_autoptr(XbNode) component = NULL; + g_autoptr(XbSilo) silo = NULL; + g_autoptr(FuEngine) engine = fu_engine_new (FU_APP_FLAGS_NONE); + g_autoptr(FuEngineRequest) request = fu_engine_request_new (); + g_autoptr(FuInstallTask) task = NULL; + g_autoptr(GError) error = NULL; + const gchar *xml = + "" + " " + " detach-action" + " " + ""; + + /* set up a dummy version */ + fu_engine_request_set_feature_flags (request, + FWUPD_FEATURE_FLAG_DETACH_ACTION); + + /* make the component require one thing */ + silo = xb_silo_new_from_xml (xml, &error); + g_assert_no_error (error); + g_assert_nonnull (silo); + component = xb_silo_query_first (silo, "component", &error); + g_assert_no_error (error); + g_assert_nonnull (component); + + /* check this passes */ + task = fu_install_task_new (NULL, component); + ret = fu_engine_check_requirements (engine, request, task, + FWUPD_INSTALL_FLAG_NONE, + &error); + g_assert_no_error (error); + g_assert (ret); +} + static void fu_engine_requirements_version_require_func (gconstpointer user_data) { gboolean ret; g_autoptr(FuDevice) device = fu_device_new (); g_autoptr(FuEngine) engine = fu_engine_new (FU_APP_FLAGS_NONE); + g_autoptr(FuEngineRequest) request = fu_engine_request_new (); g_autoptr(FuInstallTask) task = NULL; g_autoptr(GError) error = NULL; g_autoptr(XbNode) component = NULL; @@ -260,7 +368,7 @@ fu_engine_requirements_version_require_func (gconstpointer user_data) /* check this fails */ task = fu_install_task_new (device, component); - ret = fu_engine_check_requirements (engine, task, + ret = fu_engine_check_requirements (engine, request, task, FWUPD_INSTALL_FLAG_NONE, &error); g_assert_error (error, FWUPD_ERROR, FWUPD_ERROR_NOT_SUPPORTED); @@ -275,6 +383,7 @@ fu_engine_requirements_unsupported_func (gconstpointer user_data) g_autoptr(XbNode) component = NULL; g_autoptr(XbSilo) silo = NULL; g_autoptr(FuEngine) engine = fu_engine_new (FU_APP_FLAGS_NONE); + g_autoptr(FuEngineRequest) request = fu_engine_request_new (); g_autoptr(FuInstallTask) task = NULL; g_autoptr(GError) error = NULL; const gchar *xml = @@ -297,7 +406,7 @@ fu_engine_requirements_unsupported_func (gconstpointer user_data) /* check this fails */ task = fu_install_task_new (NULL, component); - ret = fu_engine_check_requirements (engine, task, + ret = fu_engine_check_requirements (engine, request, task, FWUPD_INSTALL_FLAG_NONE, &error); g_assert_error (error, FWUPD_ERROR, FWUPD_ERROR_NOT_SUPPORTED); @@ -311,6 +420,7 @@ fu_engine_requirements_child_func (gconstpointer user_data) g_autoptr(FuDevice) device = fu_device_new (); g_autoptr(FuDevice) child = fu_device_new (); g_autoptr(FuEngine) engine = fu_engine_new (FU_APP_FLAGS_NONE); + g_autoptr(FuEngineRequest) request = fu_engine_request_new (); g_autoptr(FuInstallTask) task = NULL; g_autoptr(GError) error = NULL; g_autoptr(XbNode) component = NULL; @@ -351,7 +461,7 @@ fu_engine_requirements_child_func (gconstpointer user_data) /* check this passes */ task = fu_install_task_new (device, component); - ret = fu_engine_check_requirements (engine, task, + ret = fu_engine_check_requirements (engine, request, task, FWUPD_INSTALL_FLAG_NONE, &error); g_assert_no_error (error); @@ -365,6 +475,7 @@ fu_engine_requirements_child_fail_func (gconstpointer user_data) g_autoptr(FuDevice) device = fu_device_new (); g_autoptr(FuDevice) child = fu_device_new (); g_autoptr(FuEngine) engine = fu_engine_new (FU_APP_FLAGS_NONE); + g_autoptr(FuEngineRequest) request = fu_engine_request_new (); g_autoptr(FuInstallTask) task = NULL; g_autoptr(GError) error = NULL; g_autoptr(XbNode) component = NULL; @@ -405,7 +516,7 @@ fu_engine_requirements_child_fail_func (gconstpointer user_data) /* check this passes */ task = fu_install_task_new (device, component); - ret = fu_engine_check_requirements (engine, task, + ret = fu_engine_check_requirements (engine, request, task, FWUPD_INSTALL_FLAG_NONE, &error); g_assert_error (error, FWUPD_ERROR, FWUPD_ERROR_NOT_SUPPORTED); @@ -420,6 +531,7 @@ fu_engine_requirements_func (gconstpointer user_data) gboolean ret; g_autoptr(FuEngine) engine = fu_engine_new (FU_APP_FLAGS_NONE); g_autoptr(FuInstallTask) task = NULL; + g_autoptr(FuEngineRequest) request = fu_engine_request_new (); g_autoptr(GError) error = NULL; g_autoptr(XbNode) component = NULL; g_autoptr(XbSilo) silo = NULL; @@ -444,7 +556,7 @@ fu_engine_requirements_func (gconstpointer user_data) /* check this passes */ task = fu_install_task_new (NULL, component); - ret = fu_engine_check_requirements (engine, task, + ret = fu_engine_check_requirements (engine, request, task, FWUPD_INSTALL_FLAG_NONE, &error); g_assert_no_error (error); @@ -457,6 +569,7 @@ fu_engine_requirements_device_func (gconstpointer user_data) gboolean ret; g_autoptr(FuDevice) device = fu_device_new (); g_autoptr(FuEngine) engine = fu_engine_new (FU_APP_FLAGS_NONE); + g_autoptr(FuEngineRequest) request = fu_engine_request_new (); g_autoptr(FuInstallTask) task = NULL; g_autoptr(GError) error = NULL; g_autoptr(XbNode) component = NULL; @@ -500,7 +613,7 @@ fu_engine_requirements_device_func (gconstpointer user_data) /* check this passes */ task = fu_install_task_new (device, component); - ret = fu_engine_check_requirements (engine, task, + ret = fu_engine_check_requirements (engine, request, task, FWUPD_INSTALL_FLAG_NONE, &error); g_assert_no_error (error); @@ -513,6 +626,7 @@ fu_engine_requirements_device_plain_func (gconstpointer user_data) gboolean ret; g_autoptr(FuDevice) device = fu_device_new (); g_autoptr(FuEngine) engine = fu_engine_new (FU_APP_FLAGS_NONE); + g_autoptr(FuEngineRequest) request = fu_engine_request_new (); g_autoptr(FuInstallTask) task = NULL; g_autoptr(GError) error = NULL; g_autoptr(XbNode) component = NULL; @@ -546,7 +660,7 @@ fu_engine_requirements_device_plain_func (gconstpointer user_data) /* check this passes */ task = fu_install_task_new (device, component); - ret = fu_engine_check_requirements (engine, task, + ret = fu_engine_check_requirements (engine, request, task, FWUPD_INSTALL_FLAG_NONE, &error); g_assert_no_error (error); @@ -559,6 +673,7 @@ fu_engine_requirements_version_format_func (gconstpointer user_data) gboolean ret; g_autoptr(FuDevice) device = fu_device_new (); g_autoptr(FuEngine) engine = fu_engine_new (FU_APP_FLAGS_NONE); + g_autoptr(FuEngineRequest) request = fu_engine_request_new (); g_autoptr(FuInstallTask) task = NULL; g_autoptr(GError) error = NULL; g_autoptr(XbNode) component = NULL; @@ -594,7 +709,7 @@ fu_engine_requirements_version_format_func (gconstpointer user_data) /* check this fails */ task = fu_install_task_new (device, component); - ret = fu_engine_check_requirements (engine, task, + ret = fu_engine_check_requirements (engine, request, task, FWUPD_INSTALL_FLAG_NONE, &error); g_assert_error (error, FWUPD_ERROR, FWUPD_ERROR_NOT_SUPPORTED); @@ -610,6 +725,7 @@ fu_engine_requirements_other_device_func (gconstpointer user_data) g_autoptr(FuDevice) device1 = fu_device_new (); g_autoptr(FuDevice) device2 = fu_device_new (); g_autoptr(FuEngine) engine = fu_engine_new (FU_APP_FLAGS_NONE); + g_autoptr(FuEngineRequest) request = fu_engine_request_new (); g_autoptr(FuInstallTask) task = NULL; g_autoptr(GError) error = NULL; g_autoptr(XbNode) component = NULL; @@ -660,7 +776,7 @@ fu_engine_requirements_other_device_func (gconstpointer user_data) /* check this passes */ task = fu_install_task_new (device1, component); - ret = fu_engine_check_requirements (engine, task, + ret = fu_engine_check_requirements (engine, request, task, FWUPD_INSTALL_FLAG_NONE, &error); g_assert_no_error (error); @@ -673,6 +789,7 @@ fu_engine_requirements_protocol_check_func (gconstpointer user_data) g_autoptr(FuDevice) device1 = fu_device_new (); g_autoptr(FuDevice) device2 = fu_device_new (); g_autoptr(FuEngine) engine = fu_engine_new (FU_APP_FLAGS_NONE); + g_autoptr(FuEngineRequest) request = fu_engine_request_new (); g_autoptr(GPtrArray) devices = NULL; g_autoptr(FuInstallTask) task1 = NULL; g_autoptr(FuInstallTask) task2 = NULL; @@ -737,7 +854,7 @@ fu_engine_requirements_protocol_check_func (gconstpointer user_data) /* check this fails */ task1 = fu_install_task_new (device1, component); - ret = fu_engine_check_requirements (engine, task1, + ret = fu_engine_check_requirements (engine, request, task1, FWUPD_INSTALL_FLAG_NONE, &error); g_assert_error (error, FWUPD_ERROR, FWUPD_ERROR_NOT_SUPPORTED); @@ -745,7 +862,7 @@ fu_engine_requirements_protocol_check_func (gconstpointer user_data) /* check this passes */ task2 = fu_install_task_new (device2, component); - ret = fu_engine_check_requirements (engine, task2, + ret = fu_engine_check_requirements (engine, request, task2, FWUPD_INSTALL_FLAG_NONE, &error); @@ -760,6 +877,7 @@ fu_engine_requirements_parent_device_func (gconstpointer user_data) g_autoptr(FuDevice) device1 = fu_device_new (); g_autoptr(FuDevice) device2 = fu_device_new (); g_autoptr(FuEngine) engine = fu_engine_new (FU_APP_FLAGS_NONE); + g_autoptr(FuEngineRequest) request = fu_engine_request_new (); g_autoptr(FuInstallTask) task = NULL; g_autoptr(GError) error = NULL; g_autoptr(XbNode) component = NULL; @@ -813,7 +931,7 @@ fu_engine_requirements_parent_device_func (gconstpointer user_data) /* check this passes */ task = fu_install_task_new (device2, component); - ret = fu_engine_check_requirements (engine, task, + ret = fu_engine_check_requirements (engine, request, task, FWUPD_INSTALL_FLAG_NONE, &error); g_assert_no_error (error); @@ -1087,6 +1205,7 @@ fu_engine_require_hwid_func (gconstpointer user_data) g_autofree gchar *filename = NULL; g_autoptr(FuDevice) device = fu_device_new (); g_autoptr(FuEngine) engine = fu_engine_new (FU_APP_FLAGS_NONE); + g_autoptr(FuEngineRequest) request = fu_engine_request_new (); g_autoptr(FuInstallTask) task = NULL; g_autoptr(GBytes) blob_cab = NULL; g_autoptr(GError) error = NULL; @@ -1134,7 +1253,7 @@ fu_engine_require_hwid_func (gconstpointer user_data) /* check requirements */ task = fu_install_task_new (device, component); - ret = fu_engine_check_requirements (engine, task, + ret = fu_engine_check_requirements (engine, request, task, FWUPD_INSTALL_FLAG_NONE, &error); g_assert_error (error, FWUPD_ERROR, FWUPD_ERROR_INVALID_FILE); @@ -1151,6 +1270,7 @@ fu_engine_downgrade_func (gconstpointer user_data) gboolean ret; g_autoptr(FuDevice) device = fu_device_new (); g_autoptr(FuEngine) engine = fu_engine_new (FU_APP_FLAGS_NONE); + g_autoptr(FuEngineRequest) request = fu_engine_request_new (); g_autoptr(GError) error = NULL; g_autoptr(GPtrArray) devices = NULL; g_autoptr(GPtrArray) devices_pre = NULL; @@ -1269,13 +1389,19 @@ fu_engine_downgrade_func (gconstpointer user_data) g_assert (fu_device_has_flag (device, FWUPD_DEVICE_FLAG_REGISTERED)); /* get the releases for one device */ - releases = fu_engine_get_releases (engine, fu_device_get_id (device), &error); + releases = fu_engine_get_releases (engine, + request, + fu_device_get_id (device), + &error); g_assert_no_error (error); g_assert (releases != NULL); g_assert_cmpint (releases->len, ==, 4); /* no upgrades, as no firmware is approved */ - releases_up = fu_engine_get_upgrades (engine, fu_device_get_id (device), &error); + releases_up = fu_engine_get_upgrades (engine, + request, + fu_device_get_id (device), + &error); g_assert_error (error, FWUPD_ERROR, FWUPD_ERROR_NOTHING_TO_DO); g_assert_null (releases_up); g_clear_error (&error); @@ -1285,7 +1411,10 @@ fu_engine_downgrade_func (gconstpointer user_data) fu_engine_add_approved_firmware (engine, "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX"); /* upgrades */ - releases_up = fu_engine_get_upgrades (engine, fu_device_get_id (device), &error); + releases_up = fu_engine_get_upgrades (engine, + request, + fu_device_get_id (device), + &error); g_assert_no_error (error); g_assert (releases_up != NULL); g_assert_cmpint (releases_up->len, ==, 2); @@ -1297,7 +1426,10 @@ fu_engine_downgrade_func (gconstpointer user_data) g_assert_cmpstr (fwupd_release_get_version (rel), ==, "1.2.4"); /* downgrades */ - releases_dg = fu_engine_get_downgrades (engine, fu_device_get_id (device), &error); + releases_dg = fu_engine_get_downgrades (engine, + request, + fu_device_get_id (device), + &error); g_assert_no_error (error); g_assert (releases_dg != NULL); g_assert_cmpint (releases_dg->len, ==, 1); @@ -1312,6 +1444,7 @@ fu_engine_install_duration_func (gconstpointer user_data) gboolean ret; g_autoptr(FuDevice) device = fu_device_new (); g_autoptr(FuEngine) engine = fu_engine_new (FU_APP_FLAGS_NONE); + g_autoptr(FuEngineRequest) request = fu_engine_request_new (); g_autoptr(GError) error = NULL; g_autoptr(GPtrArray) devices = NULL; g_autoptr(GPtrArray) releases = NULL; @@ -1365,7 +1498,10 @@ fu_engine_install_duration_func (gconstpointer user_data) g_assert (fu_device_has_flag (device, FWUPD_DEVICE_FLAG_SUPPORTED)); /* check the release install duration */ - releases = fu_engine_get_releases (engine, fu_device_get_id (device), &error); + releases = fu_engine_get_releases (engine, + request, + fu_device_get_id (device), + &error); g_assert_no_error (error); g_assert (releases != NULL); g_assert_cmpint (releases->len, ==, 1); @@ -2654,6 +2790,7 @@ fu_plugin_composite_func (gconstpointer user_data) GError *error = NULL; gboolean ret; g_autoptr(FuEngine) engine = fu_engine_new (FU_APP_FLAGS_NONE); + g_autoptr(FuEngineRequest) request = fu_engine_request_new (); g_autoptr(GBytes) blob = NULL; g_autoptr(GPtrArray) components = NULL; g_autoptr(GPtrArray) devices = NULL; @@ -2760,6 +2897,7 @@ fu_plugin_composite_func (gconstpointer user_data) /* is this component valid for the device */ task = fu_install_task_new (device, component); if (!fu_engine_check_requirements (engine, + request, task, 0, &error_local)) { @@ -2777,6 +2915,7 @@ fu_plugin_composite_func (gconstpointer user_data) /* install the cab */ ret = fu_engine_install_tasks (engine, + request, install_tasks, blob, FWUPD_DEVICE_FLAG_NONE, @@ -3035,6 +3174,12 @@ main (int argc, char **argv) fu_engine_requirements_func); g_test_add_data_func ("/fwupd/engine{requirements-missing}", self, fu_engine_requirements_missing_func); + g_test_add_data_func ("/fwupd/engine{requirements-client-fail}", self, + fu_engine_requirements_client_fail_func); + g_test_add_data_func ("/fwupd/engine{requirements-client-invalid}", self, + fu_engine_requirements_client_invalid_func); + g_test_add_data_func ("/fwupd/engine{requirements-client-pass}", self, + fu_engine_requirements_client_pass_func); g_test_add_data_func ("/fwupd/engine{requirements-version-require}", self, fu_engine_requirements_version_require_func); g_test_add_data_func ("/fwupd/engine{requirements-parent-device}", self, diff --git a/src/fu-tool.c b/src/fu-tool.c index 971b4fbf1..b687bc69b 100644 --- a/src/fu-tool.c +++ b/src/fu-tool.c @@ -53,6 +53,7 @@ struct FuUtilPrivate { GMainLoop *loop; GOptionContext *context; FuEngine *engine; + FuEngineRequest *request; FuProgressbar *progressbar; gboolean no_reboot_check; gboolean no_safety_check; @@ -195,6 +196,8 @@ fu_util_private_free (FuUtilPrivate *priv) g_object_unref (priv->current_device); if (priv->engine != NULL) g_object_unref (priv->engine); + if (priv->request != NULL) + g_object_unref (priv->request); if (priv->loop != NULL) g_main_loop_unref (priv->loop); if (priv->cancellable != NULL) @@ -350,6 +353,7 @@ fu_util_get_updates (FuUtilPrivate *priv, gchar **values, GError **error) /* get the releases for this device and filter for validity */ rels = fu_engine_get_upgrades (priv->engine, + priv->request, fwupd_device_get_id (dev), &error_local); if (rels == NULL) { @@ -415,7 +419,7 @@ fu_util_get_details (FuUtilPrivate *priv, gchar **values, GError **error) values[0]); return FALSE; } - array = fu_engine_get_details (priv->engine, fd, error); + array = fu_engine_get_details (priv->engine, priv->request, fd, error); close (fd); if (array == NULL) @@ -916,7 +920,9 @@ fu_util_install (FuUtilPrivate *priv, gchar **values, GError **error) /* is this component valid for the device */ task = fu_install_task_new (device, component); if (!fu_engine_check_requirements (priv->engine, - task, priv->flags | FWUPD_INSTALL_FLAG_FORCE, + priv->request, + task, + priv->flags | FWUPD_INSTALL_FLAG_FORCE, &error_local)) { g_debug ("first pass requirement on %s:%s failed: %s", fu_device_get_id (device), @@ -929,7 +935,9 @@ fu_util_install (FuUtilPrivate *priv, gchar **values, GError **error) /* make a second pass using possibly updated version format now */ fu_engine_md_refresh_device_from_component (priv->engine, device, component); if (!fu_engine_check_requirements (priv->engine, - task, priv->flags, + priv->request, + task, + priv->flags, &error_local)) { g_debug ("second pass requirement on %s:%s failed: %s", fu_device_get_id (device), @@ -962,7 +970,12 @@ fu_util_install (FuUtilPrivate *priv, gchar **values, GError **error) G_CALLBACK (fu_util_update_device_changed_cb), priv); /* install all the tasks */ - if (!fu_engine_install_tasks (priv->engine, install_tasks, blob_cab, priv->flags, error)) + if (!fu_engine_install_tasks (priv->engine, + priv->request, + install_tasks, + blob_cab, + priv->flags, + error)) return FALSE; fu_util_display_current_message (priv); @@ -1061,7 +1074,10 @@ fu_util_update_all (FuUtilPrivate *priv, GError **error) continue; device_id = fu_device_get_id (dev); - rels = fu_engine_get_upgrades (priv->engine, device_id, &error_local); + rels = fu_engine_get_upgrades (priv->engine, + priv->request, + device_id, + &error_local); if (rels == NULL) { /* TRANSLATORS: message letting the user know no device upgrade available * %1 is the device name */ @@ -1103,7 +1119,10 @@ fu_util_update_by_id (FuUtilPrivate *priv, const gchar *id, GError **error) return FALSE; /* get the releases for this device and filter for validity */ - rels = fu_engine_get_upgrades (priv->engine, fu_device_get_id (dev), error); + rels = fu_engine_get_upgrades (priv->engine, + priv->request, + fu_device_get_id (dev), + error); if (rels == NULL) return FALSE; rel = g_ptr_array_index (rels, 0); @@ -1192,7 +1211,10 @@ fu_util_reinstall (FuUtilPrivate *priv, gchar **values, GError **error) return FALSE; /* try to lookup/match release from client */ - rels = fu_engine_get_releases_for_device (priv->engine, dev, error); + rels = fu_engine_get_releases_for_device (priv->engine, + priv->request, + dev, + error); if (rels == NULL) return FALSE; @@ -1813,7 +1835,10 @@ fu_util_get_history (FuUtilPrivate *priv, gchar **values, GError **error) } /* try to lookup releases from client */ - rels = fu_engine_get_releases (priv->engine, fwupd_device_get_id (dev), error); + rels = fu_engine_get_releases (priv->engine, + priv->request, + fwupd_device_get_id (dev), + error); if (rels == NULL) return FALSE; @@ -2065,6 +2090,7 @@ main (int argc, char *argv[]) /* create helper object */ priv->loop = g_main_loop_new (NULL, FALSE); priv->progressbar = fu_progressbar_new (); + priv->request = fu_engine_request_new (); /* add commands */ fu_util_cmd_array_add (cmd_array, @@ -2249,6 +2275,11 @@ main (int argc, char *argv[]) priv->no_reboot_check = TRUE; priv->no_safety_check = TRUE; fu_progressbar_set_interactive (priv->progressbar, FALSE); + } else { + /* set our implemented feature set */ + fu_engine_request_set_feature_flags (priv->request, + FWUPD_FEATURE_FLAG_DETACH_ACTION | + FWUPD_FEATURE_FLAG_UPDATE_ACTION); } /* get a list of the commands */ diff --git a/src/fu-util.c b/src/fu-util.c index 630d9652f..5c23ab307 100644 --- a/src/fu-util.c +++ b/src/fu-util.c @@ -2595,6 +2595,7 @@ main (int argc, char *argv[]) gboolean force = FALSE; gboolean allow_older = FALSE; gboolean allow_reinstall = FALSE; + gboolean is_interactive = TRUE; gboolean no_history = FALSE; gboolean offline = FALSE; gboolean ret; @@ -2877,6 +2878,7 @@ main (int argc, char *argv[]) /* non-TTY consoles cannot answer questions */ if (isatty (fileno (stdout)) == 0) { + is_interactive = FALSE; priv->no_unreported_check = TRUE; priv->no_metadata_check = TRUE; priv->no_reboot_check = TRUE; @@ -2973,6 +2975,19 @@ main (int argc, char *argv[]) return EXIT_FAILURE; } + /* send our implemented feature set */ + if (is_interactive) { + if (!fwupd_client_set_feature_flags (priv->client, + FWUPD_FEATURE_FLAG_CAN_REPORT | + FWUPD_FEATURE_FLAG_UPDATE_ACTION | + FWUPD_FEATURE_FLAG_DETACH_ACTION, + priv->cancellable, &error)) { + g_printerr ("Failed to set front-end features: %s\n", + error->message); + return EXIT_FAILURE; + } + } + /* run the specified command */ ret = fu_util_cmd_array_run (cmd_array, priv, argv[1], (gchar**) &argv[2], &error); if (!ret) { diff --git a/src/meson.build b/src/meson.build index 9a8334973..d63a52092 100644 --- a/src/meson.build +++ b/src/meson.build @@ -128,6 +128,7 @@ fwupdtool = executable( 'fu-device-list.c', 'fu-engine.c', 'fu-engine-helper.c', + 'fu-engine-request.c', 'fu-history.c', 'fu-idle.c', 'fu-install-task.c', @@ -229,6 +230,7 @@ executable( 'fu-device-list.c', 'fu-engine.c', 'fu-engine-helper.c', + 'fu-engine-request.c', 'fu-history.c', 'fu-idle.c', 'fu-install-task.c', @@ -286,6 +288,7 @@ if get_option('tests') 'fu-device-list.c', 'fu-engine.c', 'fu-engine-helper.c', + 'fu-engine-request.c', 'fu-history.c', 'fu-idle.c', 'fu-install-task.c', diff --git a/src/org.freedesktop.fwupd.xml b/src/org.freedesktop.fwupd.xml index 5f85bafdd..6bc69fba4 100644 --- a/src/org.freedesktop.fwupd.xml +++ b/src/org.freedesktop.fwupd.xml @@ -489,6 +489,26 @@ + + + + + + Sets the features the client supports. This allows firmware to depend on + specific front-end features, for instance showing the user an image on + how to detach the hardware. + + + + + + + The features the front end supports + + + + + From d9f3bec6d058c9bfbfe07ce5eb24915eb361405d Mon Sep 17 00:00:00 2001 From: Richard Hughes Date: Mon, 29 Jun 2020 15:49:14 +0100 Subject: [PATCH 222/607] trivial: Fix GtkDoc issue with FuFmapFirmware --- libfwupdplugin/fu-fmap-firmware.h | 6 +++--- plugins/cros-ec/fu-cros-ec-firmware.c | 2 +- plugins/cros-ec/fu-cros-ec-firmware.h | 2 +- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/libfwupdplugin/fu-fmap-firmware.h b/libfwupdplugin/fu-fmap-firmware.h index 70fb6b9c1..54ad5e6f5 100644 --- a/libfwupdplugin/fu-fmap-firmware.h +++ b/libfwupdplugin/fu-fmap-firmware.h @@ -8,7 +8,7 @@ #include "fu-firmware.h" -#define FMAP_STRLEN 32 /* maximum length for strings, */ +#define FU_FMAP_FIRMWARE_STRLEN 32 /* maximum length for strings, */ /* including null-terminator */ #define FU_TYPE_FMAP_FIRMWARE (fu_fmap_firmware_get_type ()) @@ -31,7 +31,7 @@ struct _FuFmapFirmwareClass typedef struct __attribute__((packed)) { guint32 offset; /* offset relative to base */ guint32 size; /* size in bytes */ - guint8 name[FMAP_STRLEN]; /* descriptive name */ + guint8 name[FU_FMAP_FIRMWARE_STRLEN]; /* descriptive name */ guint16 flags; /* flags for this area */ } FuFmapArea; @@ -41,7 +41,7 @@ typedef struct __attribute__((packed)) { guint8 ver_minor; /* minor version */ guint64 base; /* address of the firmware binary */ guint32 size; /* size of firmware binary in bytes */ - guint8 name[FMAP_STRLEN]; /* name of this firmware binary */ + guint8 name[FU_FMAP_FIRMWARE_STRLEN]; /* name of this firmware binary */ guint16 nareas; /* number of areas described by areas[] below */ FuFmapArea areas[]; diff --git a/plugins/cros-ec/fu-cros-ec-firmware.c b/plugins/cros-ec/fu-cros-ec-firmware.c index a4934ac4a..8b541d50c 100644 --- a/plugins/cros-ec/fu-cros-ec-firmware.c +++ b/plugins/cros-ec/fu-cros-ec-firmware.c @@ -82,7 +82,7 @@ fu_cros_ec_firmware_parse (FuFirmware *firmware, return FALSE; } if (!fu_memcpy_safe ((guint8 *) section->version, - FMAP_STRLEN, 0x0, + FU_FMAP_FIRMWARE_STRLEN, 0x0, g_bytes_get_data (fwid_bytes, NULL), g_bytes_get_size (fwid_bytes), 0x0, g_bytes_get_size (fwid_bytes), error)) diff --git a/plugins/cros-ec/fu-cros-ec-firmware.h b/plugins/cros-ec/fu-cros-ec-firmware.h index 54c975320..253c3c10a 100644 --- a/plugins/cros-ec/fu-cros-ec-firmware.h +++ b/plugins/cros-ec/fu-cros-ec-firmware.h @@ -33,7 +33,7 @@ typedef struct { guint32 offset; gsize size; FuCrosEcFirmwareUpgradeStatus ustatus; - gchar version[FMAP_STRLEN]; + gchar version[FU_FMAP_FIRMWARE_STRLEN]; gint32 rollback; guint32 key_version; } FuCrosEcFirmwareSection; From eaf7f0b52941818ec58d73e6cf68d42dc5eb4d5a Mon Sep 17 00:00:00 2001 From: Mario Limonciello Date: Tue, 30 Jun 2020 10:22:09 -0500 Subject: [PATCH 223/607] trivial: convert log warnings to ASCII Fixes: #2234 --- src/fu-debug.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/fu-debug.c b/src/fu-debug.c index d44c33181..10337a165 100644 --- a/src/fu-debug.c +++ b/src/fu-debug.c @@ -95,11 +95,12 @@ fu_debug_handler_cb (const gchar *log_domain, /* to file */ if (!self->console) { + g_autofree gchar *ascii_message = g_str_to_ascii (message, NULL); if (tmp != NULL) g_printerr ("%s ", tmp); if (domain != NULL) g_printerr ("%s ", domain->str); - g_printerr ("%s\n", message); + g_printerr ("%s\n", ascii_message); return; } From 4b69830e1ca388cef726164d477d8fc8b218b315 Mon Sep 17 00:00:00 2001 From: Mario Limonciello Date: Tue, 30 Jun 2020 10:23:52 -0500 Subject: [PATCH 224/607] trivial: minor optimization for no timestamp case --- src/fu-debug.c | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/src/fu-debug.c b/src/fu-debug.c index 10337a165..1773efe17 100644 --- a/src/fu-debug.c +++ b/src/fu-debug.c @@ -66,8 +66,7 @@ fu_debug_handler_cb (const gchar *log_domain, gpointer user_data) { FuDebug *self = (FuDebug *) user_data; - g_autofree gchar *tmp = NULL; - g_autoptr(GDateTime) dt = g_date_time_new_now_utc (); + g_autofree gchar *timestamp = NULL; g_autoptr(GString) domain = NULL; /* should ignore */ @@ -76,11 +75,12 @@ fu_debug_handler_cb (const gchar *log_domain, /* time header */ if (!self->no_timestamp) { - tmp = g_strdup_printf ("%02i:%02i:%02i:%04i", - g_date_time_get_hour (dt), - g_date_time_get_minute (dt), - g_date_time_get_second (dt), - g_date_time_get_microsecond (dt) / 1000); + g_autoptr(GDateTime) dt = g_date_time_new_now_utc (); + timestamp = g_strdup_printf ("%02i:%02i:%02i:%04i", + g_date_time_get_hour (dt), + g_date_time_get_minute (dt), + g_date_time_get_second (dt), + g_date_time_get_microsecond (dt) / 1000); } /* pad out domain */ @@ -96,8 +96,8 @@ fu_debug_handler_cb (const gchar *log_domain, /* to file */ if (!self->console) { g_autofree gchar *ascii_message = g_str_to_ascii (message, NULL); - if (tmp != NULL) - g_printerr ("%s ", tmp); + if (timestamp != NULL) + g_printerr ("%s ", timestamp); if (domain != NULL) g_printerr ("%s ", domain->str); g_printerr ("%s\n", ascii_message); @@ -110,16 +110,16 @@ fu_debug_handler_cb (const gchar *log_domain, case G_LOG_LEVEL_CRITICAL: case G_LOG_LEVEL_WARNING: /* critical in red */ - if (tmp != NULL) - g_printerr ("%c[%dm%s ", 0x1B, 32, tmp); + if (timestamp != NULL) + g_printerr ("%c[%dm%s ", 0x1B, 32, timestamp); if (domain != NULL) g_printerr ("%s ", domain->str); g_printerr ("%c[%dm%s\n%c[%dm", 0x1B, 31, message, 0x1B, 0); break; default: /* debug in blue */ - if (tmp != NULL) - g_printerr ("%c[%dm%s ", 0x1B, 32, tmp); + if (timestamp != NULL) + g_printerr ("%c[%dm%s ", 0x1B, 32, timestamp); if (domain != NULL) g_printerr ("%s ", domain->str); g_printerr ("%c[%dm%s\n%c[%dm", 0x1B, 34, message, 0x1B, 0); From 85226fd9d180d2fac900934faad3446ede3e7557 Mon Sep 17 00:00:00 2001 From: Richard Hughes Date: Tue, 30 Jun 2020 14:43:48 +0100 Subject: [PATCH 225/607] Remove potentially problematic language Red Hat wants to drive an initiative in correcting problematic and potentially divisive language in open source projects. These naming conventions and descriptive phrases are hurtful and offensive to many of our colleagues across the open source universe. See https://www.redhat.com/en/blog/making-open-source-more-inclusive-eradicating-problematic-language --- contrib/ci/fedora.sh | 2 +- contrib/debian/fwupd-tests.postinst | 2 +- contrib/debian/fwupd-tests.postrm | 2 +- contrib/debian/tests/ci | 2 +- data/bash-completion/fwupdtool.in | 4 +-- data/daemon.conf | 8 ++--- data/installed-tests/README.md | 2 +- libfwupd/fwupd-client.c | 2 +- plugins/csr/fu-csr-device.c | 2 +- plugins/dell-esrt/fu-plugin-dell-esrt.c | 4 +-- plugins/dell/fu-plugin-dell.c | 12 +++---- plugins/ebitdo/fu-ebitdo-device.c | 10 +++--- plugins/uefi-dbx/README.md | 2 +- src/fu-config.c | 36 +++++++++---------- src/fu-config.h | 4 +-- src/fu-engine.c | 46 ++++++++++++------------- src/fu-tool.c | 6 ++-- src/org.freedesktop.fwupd.xml | 2 +- 18 files changed, 74 insertions(+), 74 deletions(-) diff --git a/contrib/ci/fedora.sh b/contrib/ci/fedora.sh index 376870f13..32ab1c022 100755 --- a/contrib/ci/fedora.sh +++ b/contrib/ci/fedora.sh @@ -53,7 +53,7 @@ mkdir -p dist cp $HOME/rpmbuild/RPMS/*/*.rpm dist if [ "$CI" = "true" ]; then - sed "s,^BlacklistPlugins=test;invalid,BlacklistPlugins=," -i /etc/fwupd/daemon.conf + sed "s,^DisabledPlugins=test;invalid,DisabledPlugins=," -i /etc/fwupd/daemon.conf # set up enough PolicyKit and D-Bus to run the daemon mkdir -p /run/dbus diff --git a/contrib/debian/fwupd-tests.postinst b/contrib/debian/fwupd-tests.postinst index f3d686ba9..b8b61f7f5 100644 --- a/contrib/debian/fwupd-tests.postinst +++ b/contrib/debian/fwupd-tests.postinst @@ -7,7 +7,7 @@ set -e if [ "$1" = configure ] && [ -z "$2" ]; then if [ -f /etc/fwupd/daemon.conf ]; then if [ "$CI" = "true" ]; then - sed "s,^BlacklistPlugins=test;invalid,BlacklistPlugins=," -i /etc/fwupd/daemon.conf + sed "s,^DisabledPlugins=test;invalid,DisabledPlugins=," -i /etc/fwupd/daemon.conf else echo "To enable test suite, modify /etc/fwupd/daemon.conf" fi diff --git a/contrib/debian/fwupd-tests.postrm b/contrib/debian/fwupd-tests.postrm index c6fb6beaa..fc76ec2ea 100644 --- a/contrib/debian/fwupd-tests.postrm +++ b/contrib/debian/fwupd-tests.postrm @@ -6,7 +6,7 @@ set -e if [ "$1" = remove -o "$1" = purge ]; then if [ -f /etc/fwupd/daemon.conf ]; then if [ "$CI" = "true" ]; then - sed "s,^BlacklistPlugins=,BlacklistPlugins=test;invalid," -i /etc/fwupd/daemon.conf + sed "s,^DisabledPlugins=,DisabledPlugins=test;invalid," -i /etc/fwupd/daemon.conf else echo "To disable test suite, modify /etc/fwupd/daemon.conf" fi diff --git a/contrib/debian/tests/ci b/contrib/debian/tests/ci index 4c630a604..7f48ab58f 100644 --- a/contrib/debian/tests/ci +++ b/contrib/debian/tests/ci @@ -1,5 +1,5 @@ #!/bin/sh set -e -sed "s,^BlacklistPlugins=.*,BlacklistPlugins=," -i /etc/fwupd/daemon.conf +sed "s,^DisabledPlugins=.*,DisabledPlugins=," -i /etc/fwupd/daemon.conf sed "s,^VerboseDomains=.*,VerboseDomains=*," -i /etc/fwupd/daemon.conf gnome-desktop-testing-runner fwupd diff --git a/data/bash-completion/fwupdtool.in b/data/bash-completion/fwupdtool.in index 4e9ce103e..a46398f4e 100644 --- a/data/bash-completion/fwupdtool.in +++ b/data/bash-completion/fwupdtool.in @@ -38,7 +38,7 @@ _fwupdtool_opts=( '--allow-older' '--force' '--show-all-devices' - '--plugin-whitelist' + '--plugin-enable' '--prepare' '--cleanup' '--filter' @@ -82,7 +82,7 @@ _fwupdtool() command=${COMP_WORDS[1]} case $prev in - --plugin-whitelist) + --plugin-enable) _show_plugins return 0 ;; diff --git a/data/daemon.conf b/data/daemon.conf index 1cb93282c..4c9bfc82d 100644 --- a/data/daemon.conf +++ b/data/daemon.conf @@ -1,12 +1,12 @@ [fwupd] -# Allow blacklisting specific devices by their GUID +# Allow blocking specific devices by their GUID # Uses semicolons as delimiter -BlacklistDevices= +DisabledDevices= -# Allow blacklisting specific plugins +# Allow blocking specific plugins # Uses semicolons as delimiter -BlacklistPlugins=test;invalid +DisabledPlugins=test;invalid # Maximum archive size that can be loaded in Mb, with 0 for the default ArchiveSizeMax=0 diff --git a/data/installed-tests/README.md b/data/installed-tests/README.md index d48d38dd6..8eb7b1aa0 100644 --- a/data/installed-tests/README.md +++ b/data/installed-tests/README.md @@ -9,7 +9,7 @@ By default this test suite is disabled. Enabling ======= To enable the test suite: -1. Modify `/etc/fwupd/daemon.conf` to remove the `test` plugin from `BlacklistPlugins` +1. Modify `/etc/fwupd/daemon.conf` to remove the `test` plugin from `DisabledPlugins` ``` # sed "s,^Enabled=false,Enabled=true," -i /etc/fwupd/remotes.d/fwupd-tests.conf ``` diff --git a/libfwupd/fwupd-client.c b/libfwupd/fwupd-client.c index 41ef2bb51..8b371422d 100644 --- a/libfwupd/fwupd-client.c +++ b/libfwupd/fwupd-client.c @@ -802,7 +802,7 @@ fwupd_client_proxy_call_cb (GObject *source, GAsyncResult *res, gpointer user_da /** * fwupd_client_modify_config * @client: A #FwupdClient - * @key: key, e.g. `BlacklistPlugins` + * @key: key, e.g. `DisabledPlugins` * @value: value, e.g. `*` * @cancellable: the #GCancellable, or %NULL * @error: the #GError, or %NULL diff --git a/plugins/csr/fu-csr-device.c b/plugins/csr/fu-csr-device.c index def8cb83a..7e045b4a6 100644 --- a/plugins/csr/fu-csr-device.c +++ b/plugins/csr/fu-csr-device.c @@ -397,7 +397,7 @@ fu_csr_device_probe (FuUsbDevice *device, GError **error) { FuCsrDevice *self = FU_CSR_DEVICE (device); - /* devices have to be whitelisted */ + /* proxy the quirk delay */ if (fu_device_has_custom_flag (FU_DEVICE (device), FU_CSR_DEVICE_FLAG_REQUIRE_DELAY)) self->quirks = FU_CSR_DEVICE_QUIRK_REQUIRE_DELAY; diff --git a/plugins/dell-esrt/fu-plugin-dell-esrt.c b/plugins/dell-esrt/fu-plugin-dell-esrt.c index bc746d018..a6c92fcce 100644 --- a/plugins/dell-esrt/fu-plugin-dell-esrt.c +++ b/plugins/dell-esrt/fu-plugin-dell-esrt.c @@ -17,11 +17,11 @@ #include "fu-plugin-vfuncs.h" #include "fu-hash.h" -/* Whitelisted smbios class/select commands */ +/* allowed smbios class/select commands */ #define CLASS_ADMIN_PROP 10 #define SELECT_ADMIN_PROP 3 -/* whitelisted tokens */ +/* allowed tokens */ #define CAPSULE_EN_TOKEN 0x0461 #define CAPSULE_DIS_TOKEN 0x0462 diff --git a/plugins/dell/fu-plugin-dell.c b/plugins/dell/fu-plugin-dell.c index 7966fcc41..90ba57c57 100644 --- a/plugins/dell/fu-plugin-dell.c +++ b/plugins/dell/fu-plugin-dell.c @@ -93,7 +93,7 @@ struct da_structure { /** * Devices that should allow modeswitching */ -static guint16 tpm_switch_whitelist[] = {0x06F2, 0x06F3, 0x06DD, 0x06DE, 0x06DF, +static guint16 tpm_switch_allowlist[] = {0x06F2, 0x06F3, 0x06DD, 0x06DE, 0x06DF, 0x06DB, 0x06DC, 0x06BB, 0x06C6, 0x06BA, 0x06B9, 0x05CA, 0x06C7, 0x06B7, 0x06E0, 0x06E5, 0x06D9, 0x06DA, 0x06E4, 0x0704, @@ -106,7 +106,7 @@ static guint16 tpm_switch_whitelist[] = {0x06F2, 0x06F3, 0x06DD, 0x06DE, 0x06DF, /** * Dell device types to run */ -static guint8 enclosure_whitelist [] = { 0x03, /* desktop */ +static guint8 enclosure_allowlist [] = { 0x03, /* desktop */ 0x04, /* low profile desktop */ 0x06, /* mini tower */ 0x07, /* tower */ @@ -180,8 +180,8 @@ fu_dell_supported (FuPlugin *plugin) value = g_bytes_get_data (enclosure, &len); if (len == 0) return FALSE; - for (guint i = 0; i < G_N_ELEMENTS (enclosure_whitelist); i++) { - if (enclosure_whitelist[i] == value[0]) + for (guint i = 0; i < G_N_ELEMENTS (enclosure_allowlist); i++) { + if (enclosure_allowlist[i] == value[0]) return TRUE; } @@ -693,8 +693,8 @@ fu_plugin_dell_detect_tpm (FuPlugin *plugin, GError **error) else if (system_id == 0) return FALSE; - for (guint i = 0; i < G_N_ELEMENTS (tpm_switch_whitelist); i++) { - if (tpm_switch_whitelist[i] == system_id) { + for (guint i = 0; i < G_N_ELEMENTS (tpm_switch_allowlist); i++) { + if (tpm_switch_allowlist[i] == system_id) { can_switch_modes = TRUE; } } diff --git a/plugins/ebitdo/fu-ebitdo-device.c b/plugins/ebitdo/fu-ebitdo-device.c index 280afd952..4a9311910 100644 --- a/plugins/ebitdo/fu-ebitdo-device.c +++ b/plugins/ebitdo/fu-ebitdo-device.c @@ -236,7 +236,7 @@ static gboolean fu_ebitdo_device_validate (FuEbitdoDevice *self, GError **error) { const gchar *ven; - const gchar *whitelist[] = { + const gchar *allowlist[] = { "8Bitdo", "SFC30", NULL }; @@ -245,7 +245,7 @@ fu_ebitdo_device_validate (FuEbitdoDevice *self, GError **error) if (fu_usb_device_get_vid (FU_USB_DEVICE (self)) == 0x2dc8) return TRUE; - /* verify the vendor prefix against a whitelist */ + /* verify the vendor prefix against a allowlist */ ven = fu_device_get_vendor (FU_DEVICE (self)); if (ven == NULL) { g_set_error (error, @@ -254,14 +254,14 @@ fu_ebitdo_device_validate (FuEbitdoDevice *self, GError **error) "could not check vendor descriptor: "); return FALSE; } - for (guint i = 0; whitelist[i] != NULL; i++) { - if (g_str_has_prefix (ven, whitelist[i])) + for (guint i = 0; allowlist[i] != NULL; i++) { + if (g_str_has_prefix (ven, allowlist[i])) return TRUE; } g_set_error (error, G_IO_ERROR, G_IO_ERROR_INVALID_DATA, - "vendor '%s' did not match whitelist, " + "vendor '%s' did not match allowlist, " "probably not a 8Bitdo device…", ven); return FALSE; } diff --git a/plugins/uefi-dbx/README.md b/plugins/uefi-dbx/README.md index cdd07c988..297fadee7 100644 --- a/plugins/uefi-dbx/README.md +++ b/plugins/uefi-dbx/README.md @@ -4,5 +4,5 @@ UEFI dbx Support Introduction ------------ -This plugin checks if the UEFI dbx contains all the most recent blacklisted +This plugin checks if the UEFI dbx contains all the most recent revoked checksums. The result will be stored in an security attribute for HSI. diff --git a/src/fu-config.c b/src/fu-config.c index a2015f763..cf45117ba 100644 --- a/src/fu-config.c +++ b/src/fu-config.c @@ -27,8 +27,8 @@ struct _FuConfig { GObject parent_instance; GFileMonitor *monitor; - GPtrArray *blacklist_devices; /* (element-type utf-8) */ - GPtrArray *blacklist_plugins; /* (element-type utf-8) */ + GPtrArray *disabled_devices; /* (element-type utf-8) */ + GPtrArray *disabled_plugins; /* (element-type utf-8) */ GPtrArray *approved_firmware; /* (element-type utf-8) */ guint64 archive_size_max; guint idle_timeout; @@ -64,30 +64,30 @@ fu_config_reload (FuConfig *self, GError **error) G_KEY_FILE_NONE, error)) return FALSE; - /* get blacklisted devices */ - g_ptr_array_set_size (self->blacklist_devices, 0); + /* get disabled devices */ + g_ptr_array_set_size (self->disabled_devices, 0); devices = g_key_file_get_string_list (keyfile, "fwupd", - "BlacklistDevices", + "DisabledDevices", NULL, /* length */ NULL); if (devices != NULL) { for (guint i = 0; devices[i] != NULL; i++) { - g_ptr_array_add (self->blacklist_devices, + g_ptr_array_add (self->disabled_devices, g_strdup (devices[i])); } } - /* get blacklisted plugins */ - g_ptr_array_set_size (self->blacklist_plugins, 0); + /* get disabled plugins */ + g_ptr_array_set_size (self->disabled_plugins, 0); plugins = g_key_file_get_string_list (keyfile, "fwupd", - "BlacklistPlugins", + "DisabledPlugins", NULL, /* length */ NULL); if (plugins != NULL) { for (guint i = 0; plugins[i] != NULL; i++) { - g_ptr_array_add (self->blacklist_plugins, + g_ptr_array_add (self->disabled_plugins, g_strdup (plugins[i])); } } @@ -221,10 +221,10 @@ fu_config_get_idle_timeout (FuConfig *self) } GPtrArray * -fu_config_get_blacklist_devices (FuConfig *self) +fu_config_get_disabled_devices (FuConfig *self) { g_return_val_if_fail (FU_IS_CONFIG (self), NULL); - return self->blacklist_devices; + return self->disabled_devices; } guint64 @@ -235,10 +235,10 @@ fu_config_get_archive_size_max (FuConfig *self) } GPtrArray * -fu_config_get_blacklist_plugins (FuConfig *self) +fu_config_get_disabled_plugins (FuConfig *self) { g_return_val_if_fail (FU_IS_CONFIG (self), NULL); - return self->blacklist_plugins; + return self->disabled_plugins; } GPtrArray * @@ -279,8 +279,8 @@ static void fu_config_init (FuConfig *self) { self->archive_size_max = 512 * 0x100000; - self->blacklist_devices = g_ptr_array_new_with_free_func (g_free); - self->blacklist_plugins = g_ptr_array_new_with_free_func (g_free); + self->disabled_devices = g_ptr_array_new_with_free_func (g_free); + self->disabled_plugins = g_ptr_array_new_with_free_func (g_free); self->approved_firmware = g_ptr_array_new_with_free_func (g_free); } @@ -291,8 +291,8 @@ fu_config_finalize (GObject *obj) if (self->monitor != NULL) g_object_unref (self->monitor); - g_ptr_array_unref (self->blacklist_devices); - g_ptr_array_unref (self->blacklist_plugins); + g_ptr_array_unref (self->disabled_devices); + g_ptr_array_unref (self->disabled_plugins); g_ptr_array_unref (self->approved_firmware); g_free (self->config_file); diff --git a/src/fu-config.h b/src/fu-config.h index 7499f053f..72b2c28ab 100644 --- a/src/fu-config.h +++ b/src/fu-config.h @@ -23,8 +23,8 @@ gboolean fu_config_set_key_value (FuConfig *self, guint64 fu_config_get_archive_size_max (FuConfig *self); guint fu_config_get_idle_timeout (FuConfig *self); -GPtrArray *fu_config_get_blacklist_devices (FuConfig *self); -GPtrArray *fu_config_get_blacklist_plugins (FuConfig *self); +GPtrArray *fu_config_get_disabled_devices (FuConfig *self); +GPtrArray *fu_config_get_disabled_plugins (FuConfig *self); GPtrArray *fu_config_get_approved_firmware (FuConfig *self); gboolean fu_config_get_update_motd (FuConfig *self); gboolean fu_config_get_enumerate_all_devices (FuConfig *self); diff --git a/src/fu-engine.c b/src/fu-engine.c index 9dbc0d6d1..ae2b536e0 100644 --- a/src/fu-engine.c +++ b/src/fu-engine.c @@ -524,8 +524,8 @@ fu_engine_modify_config (FuEngine *self, const gchar *key, const gchar *value, G { const gchar *keys[] = { "ArchiveSizeMax", - "BlacklistDevices", - "BlacklistPlugins", + "DisabledDevices", + "DisabledPlugins", "IdleTimeout", "VerboseDomains", "UpdateMotd", @@ -4238,7 +4238,7 @@ fu_engine_add_releases_for_device_component (FuEngine *self, fwupd_release_add_flag (rel, FWUPD_RELEASE_FLAG_BLOCKED_VERSION); } - /* check if remote is whitelisting firmware */ + /* check if remote is filtering firmware */ remote_id = fwupd_release_get_remote_id (rel); if (remote_id != NULL) { FwupdRemote *remote = fu_engine_get_remote_by_id (self, remote_id, NULL); @@ -4994,7 +4994,7 @@ fu_engine_device_inherit_history (FuEngine *self, FuDevice *device) void fu_engine_add_device (FuEngine *self, FuDevice *device) { - GPtrArray *blacklisted_devices; + GPtrArray *disabled_devices; GPtrArray *device_guids; g_autoptr(XbNode) component = NULL; @@ -5007,14 +5007,14 @@ fu_engine_add_device (FuEngine *self, FuDevice *device) return; } - /* is this GUID blacklisted */ - blacklisted_devices = fu_config_get_blacklist_devices (self->config); - for (guint i = 0; i < blacklisted_devices->len; i++) { - const gchar *blacklisted_guid = g_ptr_array_index (blacklisted_devices, i); + /* is this GUID disabled */ + disabled_devices = fu_config_get_disabled_devices (self->config); + for (guint i = 0; i < disabled_devices->len; i++) { + const gchar *disabled_guid = g_ptr_array_index (disabled_devices, i); for (guint j = 0; j < device_guids->len; j++) { const gchar *device_guid = g_ptr_array_index (device_guids, j); - if (g_strcmp0 (blacklisted_guid, device_guid) == 0) { - g_debug ("%s [%s] is blacklisted [%s], ignoring from %s", + if (g_strcmp0 (disabled_guid, device_guid) == 0) { + g_debug ("%s [%s] is disabled [%s], ignoring from %s", fu_device_get_name (device), fu_device_get_id (device), device_guid, @@ -5434,11 +5434,11 @@ fu_engine_add_plugin (FuEngine *self, FuPlugin *plugin) } static gboolean -fu_engine_is_plugin_name_blacklisted (FuEngine *self, const gchar *name) +fu_engine_is_plugin_name_disabled (FuEngine *self, const gchar *name) { - GPtrArray *blacklist = fu_config_get_blacklist_plugins (self->config); - for (guint i = 0; i < blacklist->len; i++) { - const gchar *name_tmp = g_ptr_array_index (blacklist, i); + GPtrArray *disabled = fu_config_get_disabled_plugins (self->config); + for (guint i = 0; i < disabled->len; i++) { + const gchar *name_tmp = g_ptr_array_index (disabled, i); if (g_strcmp0 (name_tmp, name) == 0) return TRUE; } @@ -5446,7 +5446,7 @@ fu_engine_is_plugin_name_blacklisted (FuEngine *self, const gchar *name) } static gboolean -fu_engine_is_plugin_name_whitelisted (FuEngine *self, const gchar *name) +fu_engine_is_plugin_name_enabled (FuEngine *self, const gchar *name) { if (self->plugin_filter->len == 0) return TRUE; @@ -5511,13 +5511,13 @@ static void fu_engine_add_security_attrs_tainted (FuEngine *self, FuSecurityAttrs *attrs) { gboolean disabled_plugins = FALSE; - GPtrArray *blacklist = fu_config_get_blacklist_plugins (self->config); + GPtrArray *disabled = fu_config_get_disabled_plugins (self->config); g_autoptr(FwupdSecurityAttr) attr = fwupd_security_attr_new (FWUPD_SECURITY_ATTR_ID_FWUPD_PLUGINS); fwupd_security_attr_set_plugin (attr, "core"); fwupd_security_attr_add_flag (attr, FWUPD_SECURITY_ATTR_FLAG_RUNTIME_ISSUE); fu_security_attrs_append (attrs, attr); - for (guint i = 0; i < blacklist->len; i++) { - const gchar *name_tmp = g_ptr_array_index (blacklist, i); + for (guint i = 0; i < disabled->len; i++) { + const gchar *name_tmp = g_ptr_array_index (disabled, i); if (g_strcmp0 (name_tmp, "test") != 0 && g_strcmp0 (name_tmp, "invalid") != 0) { disabled_plugins = TRUE; @@ -5696,16 +5696,16 @@ fu_engine_load_plugins (FuEngine *self, GError **error) if (!g_str_has_suffix (fn, suffix)) continue; - /* is blacklisted */ + /* is disabled */ name = fu_plugin_guess_name_from_fn (fn); if (name == NULL) continue; - if (fu_engine_is_plugin_name_blacklisted (self, name)) { - g_debug ("plugin %s is blacklisted", name); + if (fu_engine_is_plugin_name_disabled (self, name)) { + g_debug ("plugin %s is disabled", name); continue; } - if (!fu_engine_is_plugin_name_whitelisted (self, name)) { - g_debug ("plugin %s is not whitelisted", name); + if (!fu_engine_is_plugin_name_enabled (self, name)) { + g_debug ("plugin %s is not enabled", name); continue; } diff --git a/src/fu-tool.c b/src/fu-tool.c index b687bc69b..61828c6dd 100644 --- a/src/fu-tool.c +++ b/src/fu-tool.c @@ -2047,9 +2047,9 @@ main (int argc, char *argv[]) { "show-all-devices", '\0', 0, G_OPTION_ARG_NONE, &priv->show_all_devices, /* TRANSLATORS: command line option */ _("Show devices that are not updatable"), NULL }, - { "plugin-whitelist", '\0', 0, G_OPTION_ARG_STRING_ARRAY, &plugin_glob, + { "plugin-enable", '\0', 0, G_OPTION_ARG_STRING_ARRAY, &plugin_glob, /* TRANSLATORS: command line option */ - _("Manually whitelist specific plugins"), NULL }, + _("Manually enable specific plugins"), NULL }, { "prepare", '\0', 0, G_OPTION_ARG_NONE, &priv->prepare_blob, /* TRANSLATORS: command line option */ _("Run the plugin composite prepare routine when using install-blob"), NULL }, @@ -2355,7 +2355,7 @@ main (int argc, char *argv[]) return EXIT_SUCCESS; } - /* any plugin whitelist specified */ + /* any plugin allowlist specified */ for (guint i = 0; plugin_glob != NULL && plugin_glob[i] != NULL; i++) fu_engine_add_plugin_filter (priv->engine, plugin_glob[i]); diff --git a/src/org.freedesktop.fwupd.xml b/src/org.freedesktop.fwupd.xml index 6bc69fba4..79904c793 100644 --- a/src/org.freedesktop.fwupd.xml +++ b/src/org.freedesktop.fwupd.xml @@ -580,7 +580,7 @@ - The key, e.g. 'BlacklistPlugins'. + The key, e.g. 'DisabledPlugins'. From 89a11acdaaa062172fcae65513ca15b7409d71b2 Mon Sep 17 00:00:00 2001 From: Mario Limonciello Date: Mon, 29 Jun 2020 21:27:33 -0500 Subject: [PATCH 226/607] trivial: update various symbols to 1.4.5 See https://github.com/fwupd/fwupd/pull/2235 for details --- libfwupdplugin/fu-udev-device.c | 10 +++++----- libfwupdplugin/fwupdplugin.map | 17 +++++++++++------ 2 files changed, 16 insertions(+), 11 deletions(-) diff --git a/libfwupdplugin/fu-udev-device.c b/libfwupdplugin/fu-udev-device.c index 6c40adf9a..2352bab5e 100644 --- a/libfwupdplugin/fu-udev-device.c +++ b/libfwupdplugin/fu-udev-device.c @@ -974,7 +974,7 @@ fu_udev_device_ioctl (FuUdevDevice *self, * * Returns: %TRUE for success * - * Since: 1.5.0 + * Since: 1.4.5 **/ gboolean fu_udev_device_pread_full (FuUdevDevice *self, goffset port, @@ -1020,7 +1020,7 @@ fu_udev_device_pread_full (FuUdevDevice *self, goffset port, * * Returns: %TRUE for success * - * Since: 1.5.0 + * Since: 1.4.5 **/ gboolean fu_udev_device_pwrite_full (FuUdevDevice *self, goffset port, @@ -1080,7 +1080,7 @@ fu_udev_device_pwrite (FuUdevDevice *self, goffset port, guint8 data, GError **e * * Returns: string or NULL if unset or invalid * - * Since: 1.5.0 + * Since: 1.4.5 **/ gchar * fu_udev_device_get_parent_name (FuUdevDevice *self) @@ -1108,7 +1108,7 @@ fu_udev_device_get_parent_name (FuUdevDevice *self) * * Returns: string or NULL * - * Since: 1.5.0 + * Since: 1.4.5 **/ const gchar * fu_udev_device_get_sysfs_attr (FuUdevDevice *self, const gchar *attr, @@ -1180,7 +1180,7 @@ fu_udev_device_pread (FuUdevDevice *self, goffset port, guint8 *data, GError **e * * Returns: %TRUE for success * - * Since: 1.5.0 + * Since: 1.4.5 **/ gboolean fu_udev_device_write_sysfs (FuUdevDevice *self, const gchar *attribute, diff --git a/libfwupdplugin/fwupdplugin.map b/libfwupdplugin/fwupdplugin.map index d989dfd21..29d093525 100644 --- a/libfwupdplugin/fwupdplugin.map +++ b/libfwupdplugin/fwupdplugin.map @@ -581,6 +581,16 @@ LIBFWUPDPLUGIN_1.4.1 { local: *; } LIBFWUPDPLUGIN_1.4.0; +LIBFWUPDPLUGIN_1.4.5 { + global: + fu_udev_device_get_parent_name; + fu_udev_device_get_sysfs_attr; + fu_udev_device_pread_full; + fu_udev_device_pwrite_full; + fu_udev_device_write_sysfs; + local: *; +} LIBFWUPDPLUGIN_1.4.1; + LIBFWUPDPLUGIN_1.5.0 { global: fu_common_filename_glob; @@ -599,10 +609,5 @@ LIBFWUPDPLUGIN_1.5.0 { fu_security_attrs_get_type; fu_security_attrs_new; fu_security_attrs_to_variant; - fu_udev_device_get_parent_name; - fu_udev_device_get_sysfs_attr; - fu_udev_device_pread_full; - fu_udev_device_pwrite_full; - fu_udev_device_write_sysfs; local: *; -} LIBFWUPDPLUGIN_1.4.1; +} LIBFWUPDPLUGIN_1.4.5; From 6a6029f132f684d1bf1159a667f4e3c746b9a797 Mon Sep 17 00:00:00 2001 From: Mario Limonciello Date: Tue, 30 Jun 2020 13:25:12 -0500 Subject: [PATCH 227/607] uefi: disable plugin if efivar is not supported Don't even try to coldplug the device. Fixes: #2237 --- plugins/uefi/fu-plugin-uefi.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/plugins/uefi/fu-plugin-uefi.c b/plugins/uefi/fu-plugin-uefi.c index d41d415c3..b8c4abde5 100644 --- a/plugins/uefi/fu-plugin-uefi.c +++ b/plugins/uefi/fu-plugin-uefi.c @@ -628,6 +628,10 @@ fu_plugin_startup (FuPlugin *plugin, GError **error) return FALSE; } + /* are the EFI dirs set up so we can update each device */ + if (!fu_efivar_supported (error)) + return FALSE; + /* test for invalid ESP in coldplug, and set the update-error rather * than showing no output if the plugin had self-disabled here */ return TRUE; @@ -736,10 +740,6 @@ fu_plugin_coldplug (FuPlugin *plugin, GError **error) g_autoptr(GError) error_local = NULL; g_autoptr(GPtrArray) entries = NULL; - /* are the EFI dirs set up so we can update each device */ - if (!fu_efivar_supported (error)) - return FALSE; - /* get the directory of ESRT entries */ sysfsfwdir = fu_common_get_path (FU_PATH_KIND_SYSFSDIR_FW); esrt_path = g_build_filename (sysfsfwdir, "efi", "esrt", NULL); From 7ebcd06ae45bfba34c2201919ed26cac47f35e80 Mon Sep 17 00:00:00 2001 From: Ryan Lee Date: Wed, 1 Jul 2020 21:56:53 +0900 Subject: [PATCH 228/607] ccgx: remove verify flag in plugin --- plugins/ccgx/fu-ccgx-dmc-device.c | 1 - plugins/ccgx/fu-ccgx-hpi-device.c | 1 - 2 files changed, 2 deletions(-) diff --git a/plugins/ccgx/fu-ccgx-dmc-device.c b/plugins/ccgx/fu-ccgx-dmc-device.c index 46963b688..5a8b62238 100644 --- a/plugins/ccgx/fu-ccgx-dmc-device.c +++ b/plugins/ccgx/fu-ccgx-dmc-device.c @@ -652,7 +652,6 @@ fu_ccgx_dmc_device_init (FuCcgxDmcDevice *self) fu_device_set_version_format (FU_DEVICE (self), FWUPD_VERSION_FORMAT_QUAD); fu_device_add_flag (FU_DEVICE (self), FWUPD_DEVICE_FLAG_REQUIRE_AC); fu_device_add_flag (FU_DEVICE (self), FWUPD_DEVICE_FLAG_DUAL_IMAGE); - fu_device_add_flag (FU_DEVICE (self), FWUPD_DEVICE_FLAG_CAN_VERIFY_IMAGE); fu_device_add_flag (FU_DEVICE (self), FWUPD_DEVICE_FLAG_SELF_RECOVERY); } diff --git a/plugins/ccgx/fu-ccgx-hpi-device.c b/plugins/ccgx/fu-ccgx-hpi-device.c index 075b312a2..d2137de37 100644 --- a/plugins/ccgx/fu-ccgx-hpi-device.c +++ b/plugins/ccgx/fu-ccgx-hpi-device.c @@ -1582,7 +1582,6 @@ fu_ccgx_hpi_device_init (FuCcgxHpiDevice *self) fu_device_set_version_format (FU_DEVICE (self), FWUPD_VERSION_FORMAT_TRIPLET); fu_device_add_flag (FU_DEVICE (self), FWUPD_DEVICE_FLAG_REQUIRE_AC); fu_device_add_flag (FU_DEVICE (self), FWUPD_DEVICE_FLAG_DUAL_IMAGE); - fu_device_add_flag (FU_DEVICE (self), FWUPD_DEVICE_FLAG_CAN_VERIFY_IMAGE); fu_device_add_flag (FU_DEVICE (self), FWUPD_DEVICE_FLAG_SELF_RECOVERY); fu_device_retry_set_delay (FU_DEVICE (self), HPI_CMD_RETRY_DELAY); From d09cf101c3ecbd862305cdbca73ed468db9b079d Mon Sep 17 00:00:00 2001 From: Richard Hughes Date: Wed, 1 Jul 2020 15:21:24 +0100 Subject: [PATCH 229/607] Change all instances of master/slave to initiator/target MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This makes perfect sense, because the 'initiator' starts the transaction and the 'target' is the addressee of the transaction. Even the I²C spec defines the 'master' as 'initiating' the transaction. This is the same nomenclature now used by the Glasgow project too. --- plugins/ccgx/fu-ccgx-hpi-common.h | 12 ++++++------ plugins/ccgx/fu-ccgx-hpi-device.c | 24 ++++++++++++------------ plugins/colorhug/fu-colorhug-common.c | 8 ++++---- plugins/colorhug/fu-colorhug-common.h | 4 ++-- plugins/dell-dock/fu-dell-dock-hid.c | 24 ++++++++++++------------ plugins/dell-dock/fu-dell-dock-hid.h | 2 +- plugins/dell-dock/fu-dell-dock-i2c-ec.c | 2 +- plugins/dell-dock/fu-dell-dock-i2c-mst.c | 2 +- plugins/dell-dock/fu-dell-dock-i2c-tbt.c | 2 +- plugins/rts54hid/README.md | 2 +- plugins/rts54hid/fu-rts54hid-common.h | 2 +- plugins/rts54hid/fu-rts54hid-module.c | 20 ++++++++++---------- plugins/rts54hid/rts54hid.quirk | 2 +- 13 files changed, 53 insertions(+), 53 deletions(-) diff --git a/plugins/ccgx/fu-ccgx-hpi-common.h b/plugins/ccgx/fu-ccgx-hpi-common.h index 4812f4d36..63d158d01 100644 --- a/plugins/ccgx/fu-ccgx-hpi-common.h +++ b/plugins/ccgx/fu-ccgx-hpi-common.h @@ -25,7 +25,7 @@ #define CY_I2C_ENABLE_PRECISE_TIMING 1 #define CY_I2C_EVENT_NOTIFICATION_LEN 3 -#define PD_I2C_SLAVE_ADDRESS 0x08 +#define PD_I2C_TARGET_ADDRESS 0x08 /* timeout (ms) for USB I2C communication */ #define FU_CCGX_HPI_WAIT_TIMEOUT 5000 @@ -60,11 +60,11 @@ typedef enum { * length = 16, data_out = 16 byte configuration information */ CY_I2C_WRITE_CMD, /* perform I2C write operation * value = bit0 - start, bit1 - stop, bit3 - start on idle, - * bits[14:8] - slave address, bit15 - scbIndex. length = 0 the + * bits[14:8] - target address, bit15 - scbIndex. length = 0 the * data is provided over the bulk endpoints */ CY_I2C_READ_CMD, /* rerform I2C read operation. * value = bit0 - start, bit1 - stop, bit2 - Nak last byte, - * bit3 - start on idle, bits[14:8] - slave address, bit15 - scbIndex, + * bit3 - start on idle, bits[14:8] - target address, bit15 - scbIndex, * length = 0. The data is provided over the bulk endpoints */ CY_I2C_GET_STATUS_CMD, /* retrieve the I2C bus status. * value = bit0 - 0: TX 1: RX, bit15 - scbIndex, length = 3, @@ -107,10 +107,10 @@ typedef enum { typedef struct __attribute__((packed)) { guint32 frequency; /* frequency of operation. Only valid values are 100KHz and 400KHz */ - guint8 slave_address; /* slave address to be used when in slave mode */ + guint8 target_address; /* target address to be used when in target mode */ guint8 is_msb_first; /* whether to transmit most significant bit first */ - guint8 is_master; /* whether to block is to be configured as a master*/ - guint8 s_ignore; /* ignore general call in slave mode */ + guint8 is_initiator; /* whether to block is to be configured as a initiator */ + guint8 s_ignore; /* ignore general call in target mode */ guint8 is_clock_stretch; /* whether to stretch clock in case of no FIFO availability */ guint8 is_loop_back; /* whether to loop back TX data to RX. Valid only for debug purposes */ guint8 reserved[6]; diff --git a/plugins/ccgx/fu-ccgx-hpi-device.c b/plugins/ccgx/fu-ccgx-hpi-device.c index d2137de37..87d08a684 100644 --- a/plugins/ccgx/fu-ccgx-hpi-device.c +++ b/plugins/ccgx/fu-ccgx-hpi-device.c @@ -26,7 +26,7 @@ struct _FuCcgxHpiDevice guint8 num_ports; /* max number of ports */ FWMode fw_mode; FWImageType fw_image_type; - guint8 slave_address; + guint8 target_address; guint8 ep_bulk_in; guint8 ep_bulk_out; guint8 ep_intr_in; @@ -273,19 +273,19 @@ fu_ccgx_hpi_device_i2c_read (FuCcgxHpiDevice *self, CyI2CDataConfigBits cfg_bits, GError **error) { - guint8 slave_address = 0; + guint8 target_address = 0; if (!fu_ccgx_hpi_device_check_i2c_status (self, CY_I2C_MODE_READ, error)) { g_prefix_error (error, "i2c read error: "); return FALSE; } - slave_address = (self->slave_address & 0x7F) | (self->scb_index << 7); + target_address = (self->target_address & 0x7F) | (self->scb_index << 7); if (!g_usb_device_control_transfer (fu_usb_device_get_dev (FU_USB_DEVICE (self)), G_USB_DEVICE_DIRECTION_HOST_TO_DEVICE, G_USB_DEVICE_REQUEST_TYPE_VENDOR, G_USB_DEVICE_RECIPIENT_DEVICE, CY_I2C_READ_CMD, - (((guint16) slave_address) << 8) | cfg_bits, + (((guint16) target_address) << 8) | cfg_bits, bufsz, NULL, 0x0, NULL, FU_CCGX_HPI_WAIT_TIMEOUT, NULL, error)) { @@ -316,20 +316,20 @@ fu_ccgx_hpi_device_i2c_write (FuCcgxHpiDevice *self, CyI2CDataConfigBits cfg_bits, GError **error) { - guint8 slave_address; + guint8 target_address; g_autoptr(GError) error_local = NULL; if (!fu_ccgx_hpi_device_check_i2c_status (self, CY_I2C_MODE_WRITE, error)) { g_prefix_error (error, "i2c get status error: "); return FALSE; } - slave_address = (self->slave_address & 0x7F) | (self->scb_index << 7); + target_address = (self->target_address & 0x7F) | (self->scb_index << 7); if (!g_usb_device_control_transfer (fu_usb_device_get_dev (FU_USB_DEVICE (self)), G_USB_DEVICE_DIRECTION_HOST_TO_DEVICE, G_USB_DEVICE_REQUEST_TYPE_VENDOR, G_USB_DEVICE_RECIPIENT_DEVICE, CY_I2C_WRITE_CMD, - ((guint16) slave_address << 8) | (cfg_bits & CY_I2C_DATA_CONFIG_STOP), + ((guint16) target_address << 8) | (cfg_bits & CY_I2C_DATA_CONFIG_STOP), bufsz, /* idx */ NULL, 0x0, NULL, FU_CCGX_HPI_WAIT_TIMEOUT, @@ -360,20 +360,20 @@ fu_ccgx_hpi_device_i2c_write_no_resp (FuCcgxHpiDevice *self, CyI2CDataConfigBits cfg_bits, GError **error) { - guint8 slave_address = 0; + guint8 target_address = 0; g_autoptr(GError) error_local = NULL; if (!fu_ccgx_hpi_device_check_i2c_status (self, CY_I2C_MODE_WRITE, error)) { g_prefix_error (error, "i2c write error: "); return FALSE; } - slave_address = (self->slave_address & 0x7F) | (self->scb_index << 7); + target_address = (self->target_address & 0x7F) | (self->scb_index << 7); if (!g_usb_device_control_transfer (fu_usb_device_get_dev (FU_USB_DEVICE (self)), G_USB_DEVICE_DIRECTION_HOST_TO_DEVICE, G_USB_DEVICE_REQUEST_TYPE_VENDOR, G_USB_DEVICE_RECIPIENT_DEVICE, CY_I2C_WRITE_CMD, - ((guint16) slave_address << 8) | (cfg_bits & CY_I2C_DATA_CONFIG_STOP), + ((guint16) target_address << 8) | (cfg_bits & CY_I2C_DATA_CONFIG_STOP), bufsz, NULL, 0x0, NULL, FU_CCGX_HPI_WAIT_TIMEOUT, NULL, error)) { @@ -1376,7 +1376,7 @@ fu_ccgx_hpi_device_setup (FuDevice *device, GError **error) return FALSE; } i2c_config.frequency = FU_CCGX_HPI_FREQ; - i2c_config.is_master = TRUE; + i2c_config.is_initiator = TRUE; i2c_config.is_msb_first = TRUE; if (!fu_ccgx_hpi_device_set_i2c_config (self, &i2c_config, error)) { g_prefix_error (error, "set config error: "); @@ -1574,7 +1574,7 @@ fu_ccgx_hpi_device_init (FuCcgxHpiDevice *self) self->inf_num = 0x0; self->hpi_addrsz = 1; self->num_ports = 1; - self->slave_address = PD_I2C_SLAVE_ADDRESS; + self->target_address = PD_I2C_TARGET_ADDRESS; self->ep_bulk_out = PD_I2C_USB_EP_BULK_OUT; self->ep_bulk_in = PD_I2C_USB_EP_BULK_IN; self->ep_intr_in = PD_I2C_USB_EP_INTR_IN; diff --git a/plugins/colorhug/fu-colorhug-common.c b/plugins/colorhug/fu-colorhug-common.c index b0773c758..3baa5f3d2 100644 --- a/plugins/colorhug/fu-colorhug-common.c +++ b/plugins/colorhug/fu-colorhug-common.c @@ -77,10 +77,10 @@ ch_strerror (ChError error_enum) return "Self test failed: ADC Vss"; if (error_enum == CH_ERROR_SELF_TEST_ADC_VREF) return "Self test failed: ADC Vref"; - if (error_enum == CH_ERROR_I2C_SLAVE_ADDRESS) - return "I2C set slave address failed"; - if (error_enum == CH_ERROR_I2C_SLAVE_CONFIG) - return "I2C set slave config failed"; + if (error_enum == CH_ERROR_I2C_TARGET_ADDRESS) + return "I2C set target address failed"; + if (error_enum == CH_ERROR_I2C_TARGET_CONFIG) + return "I2C set target config failed"; if (error_enum == CH_ERROR_SELF_TEST_EEPROM) return "Self test failed: EEPROM"; return NULL; diff --git a/plugins/colorhug/fu-colorhug-common.h b/plugins/colorhug/fu-colorhug-common.h index 61723a283..cef79e540 100644 --- a/plugins/colorhug/fu-colorhug-common.h +++ b/plugins/colorhug/fu-colorhug-common.h @@ -42,8 +42,8 @@ typedef enum { CH_ERROR_SELF_TEST_ADC_VDD, CH_ERROR_SELF_TEST_ADC_VSS, CH_ERROR_SELF_TEST_ADC_VREF, - CH_ERROR_I2C_SLAVE_ADDRESS, - CH_ERROR_I2C_SLAVE_CONFIG, + CH_ERROR_I2C_TARGET_ADDRESS, + CH_ERROR_I2C_TARGET_CONFIG, CH_ERROR_SELF_TEST_EEPROM, CH_ERROR_LAST } ChError; diff --git a/plugins/dell-dock/fu-dell-dock-hid.c b/plugins/dell-dock/fu-dell-dock-hid.c index 7b0b2301a..fb5be7b12 100644 --- a/plugins/dell-dock/fu-dell-dock-hid.c +++ b/plugins/dell-dock/fu-dell-dock-hid.c @@ -65,7 +65,7 @@ typedef struct __attribute__ ((packed)) { typedef struct __attribute__ ((packed)) { guint8 cmd; guint8 ext; - guint8 i2cslaveaddr; + guint8 i2ctargetaddr; guint8 i2cspeed; union { guint32 startaddress; @@ -129,7 +129,7 @@ fu_dell_dock_hid_get_hub_version (FuDevice *self, .cmd_data2 = 0, .cmd_data3 = 0, .bufferlen = GUINT16_TO_LE (12), - .parameters = {.i2cslaveaddr = 0, .regaddrlen = 0, .i2cspeed = 0}, + .parameters = {.i2ctargetaddr = 0, .regaddrlen = 0, .i2cspeed = 0}, .extended_cmdarea[0 ... 52] = 0, }; @@ -164,7 +164,7 @@ fu_dell_dock_hid_raise_mcu_clock (FuDevice *self, .cmd_data2 = 0, .cmd_data3 = 0, .bufferlen = 0, - .parameters = {.i2cslaveaddr = 0, .regaddrlen = 0, .i2cspeed = 0}, + .parameters = {.i2ctargetaddr = 0, .regaddrlen = 0, .i2cspeed = 0}, .extended_cmdarea[0 ... 52] = 0, }; @@ -193,7 +193,7 @@ fu_dell_dock_hid_get_ec_status (FuDevice *self, .cmd_data2 = 0, .cmd_data3 = 0, .bufferlen = GUINT16_TO_LE (27), - .parameters = {.i2cslaveaddr = 0, .regaddrlen = 0, .i2cspeed = 0}, + .parameters = {.i2ctargetaddr = 0, .regaddrlen = 0, .i2cspeed = 0}, .extended_cmdarea[0 ... 52] = 0, }; @@ -224,7 +224,7 @@ fu_dell_dock_hid_erase_bank (FuDevice *self, guint8 idx, GError **error) .cmd_data2 = 0, .cmd_data3 = 0, .bufferlen = 0, - .parameters = {.i2cslaveaddr = 0, .regaddrlen = 0, .i2cspeed = 0}, + .parameters = {.i2ctargetaddr = 0, .regaddrlen = 0, .i2cspeed = 0}, .extended_cmdarea[0 ... 52] = 0, }; @@ -249,7 +249,7 @@ fu_dell_dock_hid_write_flash (FuDevice *self, .ext = HUB_EXT_WRITEFLASH, .dwregaddr = GUINT32_TO_LE (dwAddr), .bufferlen = GUINT16_TO_LE (write_size), - .parameters = {.i2cslaveaddr = 0, .regaddrlen = 0, .i2cspeed = 0}, + .parameters = {.i2ctargetaddr = 0, .regaddrlen = 0, .i2cspeed = 0}, .extended_cmdarea[0 ... 52] = 0, }; @@ -280,7 +280,7 @@ fu_dell_dock_hid_verify_update (FuDevice *self, .cmd_data2 = 0, .cmd_data3 = 0, .bufferlen = GUINT16_TO_LE (1), - .parameters = {.i2cslaveaddr = 0, .regaddrlen = 0, .i2cspeed = 0}, + .parameters = {.i2ctargetaddr = 0, .regaddrlen = 0, .i2cspeed = 0}, .extended_cmdarea[0 ... 52] = 0, }; @@ -310,7 +310,7 @@ fu_dell_dock_hid_i2c_write (FuDevice *self, .ext = HUB_EXT_I2C_WRITE, .dwregaddr = 0, .bufferlen = GUINT16_TO_LE (write_size), - .parameters = {.i2cslaveaddr = parameters->i2cslaveaddr, + .parameters = {.i2ctargetaddr = parameters->i2ctargetaddr, .regaddrlen = 0, .i2cspeed = parameters->i2cspeed | 0x80}, .extended_cmdarea[0 ... 52] = 0, @@ -336,7 +336,7 @@ fu_dell_dock_hid_i2c_read (FuDevice *self, .ext = HUB_EXT_I2C_READ, .dwregaddr = GUINT32_TO_LE (cmd), .bufferlen = GUINT16_TO_LE (read_size), - .parameters = {.i2cslaveaddr = parameters->i2cslaveaddr, + .parameters = {.i2ctargetaddr = parameters->i2ctargetaddr, .regaddrlen = parameters->regaddrlen, .i2cspeed = parameters->i2cspeed | 0x80}, .extended_cmdarea[0 ... 52] = 0, @@ -365,7 +365,7 @@ fu_dell_dock_hid_tbt_wake (FuDevice *self, FuTbtCmdBuffer cmd_buffer = { .cmd = HUB_CMD_READ_DATA, /* special write command that reads status result */ .ext = HUB_EXT_WRITE_TBT_FLASH, - .i2cslaveaddr = parameters->i2cslaveaddr, + .i2ctargetaddr = parameters->i2ctargetaddr, .i2cspeed = parameters->i2cspeed, /* unlike other commands doesn't need | 0x80 */ .tbt_command = TBT_COMMAND_WAKEUP, .bufferlen = 0, @@ -408,7 +408,7 @@ fu_dell_dock_hid_tbt_write (FuDevice *self, FuTbtCmdBuffer cmd_buffer = { .cmd = HUB_CMD_READ_DATA, /* It's a special write command that reads status result */ .ext = HUB_EXT_WRITE_TBT_FLASH, - .i2cslaveaddr = parameters->i2cslaveaddr, + .i2ctargetaddr = parameters->i2ctargetaddr, .i2cspeed = parameters->i2cspeed, /* unlike other commands doesn't need | 0x80 */ .startaddress = GUINT32_TO_LE (start_addr), .bufferlen = write_size, @@ -454,7 +454,7 @@ fu_dell_dock_hid_tbt_authenticate (FuDevice *self, FuTbtCmdBuffer cmd_buffer = { .cmd = HUB_CMD_READ_DATA, /* It's a special write command that reads status result */ .ext = HUB_EXT_WRITE_TBT_FLASH, - .i2cslaveaddr = parameters->i2cslaveaddr, + .i2ctargetaddr = parameters->i2ctargetaddr, .i2cspeed = parameters->i2cspeed, /* unlike other commands doesn't need | 0x80 */ .tbt_command = GUINT32_TO_LE (TBT_COMMAND_AUTHENTICATE), .bufferlen = 0, diff --git a/plugins/dell-dock/fu-dell-dock-hid.h b/plugins/dell-dock/fu-dell-dock-hid.h index 613151283..460dfda0c 100644 --- a/plugins/dell-dock/fu-dell-dock-hid.h +++ b/plugins/dell-dock/fu-dell-dock-hid.h @@ -23,7 +23,7 @@ #include "fu-device.h" typedef struct __attribute__ ((packed)) { - guint8 i2cslaveaddr; + guint8 i2ctargetaddr; guint8 regaddrlen; guint8 i2cspeed; } FuHIDI2CParameters; diff --git a/plugins/dell-dock/fu-dell-dock-i2c-ec.c b/plugins/dell-dock/fu-dell-dock-i2c-ec.c index de8af0187..4bfb17d93 100644 --- a/plugins/dell-dock/fu-dell-dock-i2c-ec.c +++ b/plugins/dell-dock/fu-dell-dock-i2c-ec.c @@ -54,7 +54,7 @@ typedef enum { } FuDellDockECFWUpdateStatus; const FuHIDI2CParameters ec_base_settings = { - .i2cslaveaddr = I2C_EC_ADDRESS, + .i2ctargetaddr = I2C_EC_ADDRESS, .regaddrlen = 1, .i2cspeed = I2C_SPEED_250K, }; diff --git a/plugins/dell-dock/fu-dell-dock-i2c-mst.c b/plugins/dell-dock/fu-dell-dock-i2c-mst.c index ae0fd690c..96d5d89de 100644 --- a/plugins/dell-dock/fu-dell-dock-i2c-mst.c +++ b/plugins/dell-dock/fu-dell-dock-i2c-mst.c @@ -96,7 +96,7 @@ const MSTBankAttributes esm_attributes = { }; FuHIDI2CParameters mst_base_settings = { - .i2cslaveaddr = I2C_MST_ADDRESS, + .i2ctargetaddr = I2C_MST_ADDRESS, .regaddrlen = 0, .i2cspeed = I2C_SPEED_400K, }; diff --git a/plugins/dell-dock/fu-dell-dock-i2c-tbt.c b/plugins/dell-dock/fu-dell-dock-i2c-tbt.c index 485b1bca9..884a18b9a 100644 --- a/plugins/dell-dock/fu-dell-dock-i2c-tbt.c +++ b/plugins/dell-dock/fu-dell-dock-i2c-tbt.c @@ -28,7 +28,7 @@ #define I2C_TBT_ADDRESS 0xa2 const FuHIDI2CParameters tbt_base_settings = { - .i2cslaveaddr = I2C_TBT_ADDRESS, + .i2ctargetaddr = I2C_TBT_ADDRESS, .regaddrlen = 1, .i2cspeed = I2C_SPEED_400K, }; diff --git a/plugins/rts54hid/README.md b/plugins/rts54hid/README.md index 75148df39..7f5965210 100644 --- a/plugins/rts54hid/README.md +++ b/plugins/rts54hid/README.md @@ -44,6 +44,6 @@ This plugin uses the following plugin-specific quirks: | Quirk | Description | Minimum fwupd version | |------------------------|---------------------------------------------|-----------------------| -| `Rts54SlaveAddr` | The slave address of a child module. | 1.1.3 | +| `Rts54TargetAddr` | The target address of a child module. | 1.1.3 | | `Rts54I2cSpeed` | The I2C speed to operate at (0, 1, 2). | 1.1.3 | | `Rts54RegisterAddrLen` | The I2C register address length of commands | 1.1.3 | diff --git a/plugins/rts54hid/fu-rts54hid-common.h b/plugins/rts54hid/fu-rts54hid-common.h index d62e7d26a..7e8e1c2da 100644 --- a/plugins/rts54hid/fu-rts54hid-common.h +++ b/plugins/rts54hid/fu-rts54hid-common.h @@ -15,7 +15,7 @@ #define FU_RTS54HID_CMD_BUFFER_OFFSET_DATA 0x40 typedef struct __attribute__ ((packed)) { - guint8 slave_addr; + guint8 target_addr; guint8 data_sz; guint8 speed; } FuRts54HidI2cParameters; diff --git a/plugins/rts54hid/fu-rts54hid-module.c b/plugins/rts54hid/fu-rts54hid-module.c index 902a6d576..cb817a20c 100644 --- a/plugins/rts54hid/fu-rts54hid-module.c +++ b/plugins/rts54hid/fu-rts54hid-module.c @@ -17,7 +17,7 @@ struct _FuRts54HidModule { FuDevice parent_instance; - guint8 slave_addr; + guint8 target_addr; guint8 i2c_speed; guint8 register_addr_len; }; @@ -28,7 +28,7 @@ static void fu_rts54hid_module_to_string (FuDevice *module, guint idt, GString *str) { FuRts54HidModule *self = FU_RTS54HID_MODULE (module); - fu_common_string_append_kx (str, idt, "SlaveAddr", self->slave_addr); + fu_common_string_append_kx (str, idt, "TargetAddr", self->target_addr); fu_common_string_append_kx (str, idt, "I2cSpeed", self->i2c_speed); fu_common_string_append_kx (str, idt, "RegisterAddrLen", self->register_addr_len); } @@ -59,7 +59,7 @@ fu_rts54hid_module_i2c_write (FuRts54HidModule *self, .ext = FU_RTS54HID_EXT_I2C_WRITE, .dwregaddr = 0, .bufferlen = GUINT16_TO_LE (data_sz), - .parameters_i2c = {.slave_addr = self->slave_addr, + .parameters_i2c = {.target_addr = self->target_addr, .data_sz = self->register_addr_len, .speed = self->i2c_speed | 0x80}, }; @@ -83,7 +83,7 @@ fu_rts54hid_module_i2c_write (FuRts54HidModule *self, FU_RTS54HID_DEVICE_TIMEOUT * 2, FU_HID_DEVICE_FLAG_NONE, error)) { - g_prefix_error (error, "failed to write i2c @%04x: ", self->slave_addr); + g_prefix_error (error, "failed to write i2c @%04x: ", self->target_addr); return FALSE; } return TRUE; @@ -102,7 +102,7 @@ fu_rts54hid_module_i2c_read (FuRts54HidModule *self, .ext = FU_RTS54HID_EXT_I2C_READ, .dwregaddr = GUINT32_TO_LE (cmd), .bufferlen = GUINT16_TO_LE (data_sz), - .parameters_i2c = {.slave_addr = self->slave_addr, + .parameters_i2c = {.target_addr = self->target_addr, .data_sz = self->register_addr_len, .speed = self->i2c_speed | 0x80}, }; @@ -123,7 +123,7 @@ fu_rts54hid_module_i2c_read (FuRts54HidModule *self, FU_RTS54HID_DEVICE_TIMEOUT * 2, FU_HID_DEVICE_FLAG_NONE, error)) { - g_prefix_error (error, "failed to write i2c @%04x: ", self->slave_addr); + g_prefix_error (error, "failed to write i2c @%04x: ", self->target_addr); return FALSE; } if (!fu_hid_device_get_report (FU_HID_DEVICE (parent), 0x0, buf, sizeof(buf), @@ -144,17 +144,17 @@ fu_rts54hid_module_set_quirk_kv (FuDevice *device, { FuRts54HidModule *self = FU_RTS54HID_MODULE (device); - /* load slave address from quirks */ - if (g_strcmp0 (key, "Rts54SlaveAddr") == 0) { + /* load target address from quirks */ + if (g_strcmp0 (key, "Rts54TargetAddr") == 0) { guint64 tmp = fu_common_strtoull (value); if (tmp <= 0xff) { - self->slave_addr = tmp; + self->target_addr = tmp; return TRUE; } g_set_error_literal (error, G_IO_ERROR, G_IO_ERROR_INVALID_DATA, - "invalid slave address"); + "invalid target address"); return FALSE; } diff --git a/plugins/rts54hid/rts54hid.quirk b/plugins/rts54hid/rts54hid.quirk index 28d502c39..a740c5593 100644 --- a/plugins/rts54hid/rts54hid.quirk +++ b/plugins/rts54hid/rts54hid.quirk @@ -11,6 +11,6 @@ Plugin = rts54hid Name = HDMI Converter Flags = updatable FirmwareSize = 0x20000 -Rts54SlaveAddr = 0x00 +Rts54TargetAddr = 0x00 Rts54I2cSpeed = 0x00 Rts54RegisterAddrLen = 0x04 From b1cf96abe184682bb7be6aa0547274fce3595ac7 Mon Sep 17 00:00:00 2001 From: Mario Limonciello Date: Wed, 1 Jul 2020 12:56:02 -0500 Subject: [PATCH 230/607] trivial: acpi-dmar: lower missing DMAR table to debug If the system is missing a DMAR table, users can find out from `fwupdtool/fwupdmgr security`. No need to actually warn in the logs every single time. --- plugins/acpi-dmar/fu-plugin-acpi-dmar.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugins/acpi-dmar/fu-plugin-acpi-dmar.c b/plugins/acpi-dmar/fu-plugin-acpi-dmar.c index 4f637cd70..0826a0c6e 100644 --- a/plugins/acpi-dmar/fu-plugin-acpi-dmar.c +++ b/plugins/acpi-dmar/fu-plugin-acpi-dmar.c @@ -41,7 +41,7 @@ fu_plugin_add_security_attrs (FuPlugin *plugin, FuSecurityAttrs *attrs) fn = g_build_filename (path, "DMAR", NULL); blob = fu_common_get_contents_bytes (fn, &error_local); if (blob == NULL) { - g_warning ("failed to load %s: %s", fn, error_local->message); + g_debug ("failed to load %s: %s", fn, error_local->message); fwupd_security_attr_set_result (attr, FWUPD_SECURITY_ATTR_RESULT_NOT_VALID); return; } From dc805b41f1006705ac33fbba22ea3d8fd75c60b6 Mon Sep 17 00:00:00 2001 From: Richard Hughes Date: Wed, 1 Jul 2020 19:23:05 +0100 Subject: [PATCH 231/607] trivial: Remove unused variables --- libfwupd/fwupd-security-attr.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/libfwupd/fwupd-security-attr.c b/libfwupd/fwupd-security-attr.c index 9a4297b35..fe114af61 100644 --- a/libfwupd/fwupd-security-attr.c +++ b/libfwupd/fwupd-security-attr.c @@ -647,7 +647,6 @@ void fwupd_security_attr_to_json (FwupdSecurityAttr *self, JsonBuilder *builder) { FwupdSecurityAttrPrivate *priv = GET_PRIVATE (self); - g_autoptr(GList) keys = NULL; g_return_if_fail (FWUPD_IS_SECURITY_ATTR (self)); g_return_if_fail (builder != NULL); @@ -688,7 +687,6 @@ fwupd_security_attr_to_string (FwupdSecurityAttr *self) { FwupdSecurityAttrPrivate *priv = GET_PRIVATE (self); GString *str; - g_autoptr(GList) keys = NULL; g_return_val_if_fail (FWUPD_IS_SECURITY_ATTR (self), NULL); From 5c22406a18593623d38d12a2bf0bf63cfc7a1dca Mon Sep 17 00:00:00 2001 From: Richard Hughes Date: Wed, 1 Jul 2020 19:41:45 +0100 Subject: [PATCH 232/607] libfwupd: Do not export non-introspectable symbols without a version This is needed for future functionality. --- contrib/generate-version-script.py | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/contrib/generate-version-script.py b/contrib/generate-version-script.py index b506a43e4..bfecec9d3 100755 --- a/contrib/generate-version-script.py +++ b/contrib/generate-version-script.py @@ -33,9 +33,13 @@ class LdVersionScript: def _add_node(self, node): identifier = node.attrib[XMLNS_C + 'identifier'] - if 'version' not in node.attrib: + introspectable = int(node.get('introspectable', 1)) + version = node.get('version', None) + if introspectable and not version: print('No version for', identifier) sys.exit(1) + if not version: + return None version = node.attrib['version'] if version not in self.releases: self.releases[version] = [] From ec2a4b586f3dc57b2155eaf9fc7b5ecfc05d24eb Mon Sep 17 00:00:00 2001 From: Richard Hughes Date: Wed, 1 Jul 2020 19:24:50 +0100 Subject: [PATCH 233/607] trivial: Move some code for future use --- libfwupd/fwupd-common-private.h | 2 ++ libfwupd/fwupd-common.c | 33 +++++++++++++++++++++++++++++++++ libfwupd/fwupd-release.c | 31 ++----------------------------- 3 files changed, 37 insertions(+), 29 deletions(-) diff --git a/libfwupd/fwupd-common-private.h b/libfwupd/fwupd-common-private.h index 0dde0c714..d899de562 100644 --- a/libfwupd/fwupd-common-private.h +++ b/libfwupd/fwupd-common-private.h @@ -13,5 +13,7 @@ G_BEGIN_DECLS gchar *fwupd_checksum_format_for_display (const gchar *checksum); +GVariant *fwupd_hash_kv_to_variant (GHashTable *hash); +GHashTable *fwupd_variant_to_hash_kv (GVariant *dict); G_END_DECLS diff --git a/libfwupd/fwupd-common.c b/libfwupd/fwupd-common.c index 7dd42962f..dfd9cb6d5 100644 --- a/libfwupd/fwupd-common.c +++ b/libfwupd/fwupd-common.c @@ -894,3 +894,36 @@ fwupd_guid_hash_string (const gchar *str) return fwupd_guid_hash_data ((const guint8 *) str, strlen (str), FWUPD_GUID_FLAG_NONE); } + +/** + * fwupd_hash_kv_to_variant: (skip): + **/ +GVariant * +fwupd_hash_kv_to_variant (GHashTable *hash) +{ + GVariantBuilder builder; + g_autoptr(GList) keys = g_hash_table_get_keys (hash); + g_variant_builder_init (&builder, G_VARIANT_TYPE_ARRAY); + for (GList *l = keys; l != NULL; l = l->next) { + const gchar *key = l->data; + const gchar *value = g_hash_table_lookup (hash, key); + g_variant_builder_add (&builder, "{ss}", key, value); + } + return g_variant_builder_end (&builder); +} + +/** + * fwupd_variant_to_hash_kv: (skip): + **/ +GHashTable * +fwupd_variant_to_hash_kv (GVariant *dict) +{ + GHashTable *hash = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_free); + GVariantIter iter; + const gchar *key; + const gchar *value; + g_variant_iter_init (&iter, dict); + while (g_variant_iter_loop (&iter, "{ss}", &key, &value)) + g_hash_table_insert (hash, g_strdup (key), g_strdup (value)); + return hash; +} diff --git a/libfwupd/fwupd-release.c b/libfwupd/fwupd-release.c index ff224c02d..452d271a0 100644 --- a/libfwupd/fwupd-release.c +++ b/libfwupd/fwupd-release.c @@ -1274,33 +1274,6 @@ fwupd_release_set_install_duration (FwupdRelease *release, guint32 duration) priv->install_duration = duration; } -static GVariant * -_hash_kv_to_variant (GHashTable *hash) -{ - GVariantBuilder builder; - g_autoptr(GList) keys = g_hash_table_get_keys (hash); - g_variant_builder_init (&builder, G_VARIANT_TYPE_ARRAY); - for (GList *l = keys; l != NULL; l = l->next) { - const gchar *key = l->data; - const gchar *value = g_hash_table_lookup (hash, key); - g_variant_builder_add (&builder, "{ss}", key, value); - } - return g_variant_builder_end (&builder); -} - -static GHashTable * -_variant_to_hash_kv (GVariant *dict) -{ - GHashTable *hash = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_free); - GVariantIter iter; - const gchar *key; - const gchar *value; - g_variant_iter_init (&iter, dict); - while (g_variant_iter_loop (&iter, "{ss}", &key, &value)) - g_hash_table_insert (hash, g_strdup (key), g_strdup (value)); - return hash; -} - /** * fwupd_release_to_variant: * @release: A #FwupdRelease @@ -1457,7 +1430,7 @@ fwupd_release_to_variant (FwupdRelease *release) if (g_hash_table_size (priv->metadata) > 0) { g_variant_builder_add (&builder, "{sv}", FWUPD_RESULT_KEY_METADATA, - _hash_kv_to_variant (priv->metadata)); + fwupd_hash_kv_to_variant (priv->metadata)); } if (priv->install_duration > 0) { g_variant_builder_add (&builder, "{sv}", @@ -1588,7 +1561,7 @@ fwupd_release_from_key_value (FwupdRelease *release, const gchar *key, GVariant } if (g_strcmp0 (key, FWUPD_RESULT_KEY_METADATA) == 0) { g_hash_table_unref (priv->metadata); - priv->metadata = _variant_to_hash_kv (value); + priv->metadata = fwupd_variant_to_hash_kv (value); return; } } From 7b57ce226b9c908c30beb8b920985252fd176382 Mon Sep 17 00:00:00 2001 From: Richard Hughes Date: Wed, 1 Jul 2020 19:25:23 +0100 Subject: [PATCH 234/607] libfwupd: Allow storing metadata on the security attr --- libfwupd/fwupd-security-attr.c | 83 ++++++++++++++++++++++++++++++++++ libfwupd/fwupd-security-attr.h | 5 ++ libfwupd/fwupd.map | 2 + 3 files changed, 90 insertions(+) diff --git a/libfwupd/fwupd-security-attr.c b/libfwupd/fwupd-security-attr.c index fe114af61..7e3613110 100644 --- a/libfwupd/fwupd-security-attr.c +++ b/libfwupd/fwupd-security-attr.c @@ -23,6 +23,7 @@ static void fwupd_security_attr_finalize (GObject *object); typedef struct { gchar *appstream_id; GPtrArray *obsoletes; + GHashTable *metadata; /* (nullable) */ gchar *name; gchar *plugin; gchar *url; @@ -542,12 +543,70 @@ fwupd_security_attr_to_variant (FwupdSecurityAttr *self) FWUPD_RESULT_KEY_HSI_RESULT, g_variant_new_uint32 (priv->result)); } + if (priv->metadata != NULL) { + g_variant_builder_add (&builder, "{sv}", + FWUPD_RESULT_KEY_METADATA, + fwupd_hash_kv_to_variant (priv->metadata)); + } return g_variant_new ("a{sv}", &builder); } +/** + * fwupd_security_attr_get_metadata: + * @self: A #FwupdSecurityAttr + * @key: metadata key + * + * Gets private metadata from the attribute which may be used in the name. + * + * Returns: (nullable): the metadata value, or %NULL if unfound + * + * Since: 1.5.0 + **/ +const gchar * +fwupd_security_attr_get_metadata (FwupdSecurityAttr *self, const gchar *key) +{ + FwupdSecurityAttrPrivate *priv = GET_PRIVATE (self); + + g_return_val_if_fail (FWUPD_IS_SECURITY_ATTR (self), NULL); + g_return_val_if_fail (key != NULL, NULL); + + if (priv->metadata == NULL) + return NULL; + return g_hash_table_lookup (priv->metadata, key); +} + +/** + * fwupd_security_attr_add_metadata: + * @self: A #FwupdSecurityAttr + * @key: metadata key + * @value: (nullable): metadata value + * + * Adds metadata to the attribute which may be used in the name. + * + * Since: 1.5.0 + **/ +void +fwupd_security_attr_add_metadata (FwupdSecurityAttr *self, + const gchar *key, + const gchar *value) +{ + FwupdSecurityAttrPrivate *priv = GET_PRIVATE (self); + + g_return_if_fail (FWUPD_IS_SECURITY_ATTR (self)); + g_return_if_fail (key != NULL); + + if (priv->metadata == NULL) { + priv->metadata = g_hash_table_new_full (g_str_hash, g_str_equal, + g_free, g_free); + } + g_hash_table_insert (priv->metadata, g_strdup (key), g_strdup (value)); +} + static void fwupd_security_attr_from_key_value (FwupdSecurityAttr *self, const gchar *key, GVariant *value) { + FwupdSecurityAttrPrivate *priv = GET_PRIVATE (self); + if (g_strcmp0 (key, FWUPD_RESULT_KEY_APPSTREAM_ID) == 0) { fwupd_security_attr_set_appstream_id (self, g_variant_get_string (value, NULL)); return; @@ -572,6 +631,12 @@ fwupd_security_attr_from_key_value (FwupdSecurityAttr *self, const gchar *key, G fwupd_security_attr_set_result (self, g_variant_get_uint32 (value)); return; } + if (g_strcmp0 (key, FWUPD_RESULT_KEY_METADATA) == 0) { + if (priv->metadata != NULL) + g_hash_table_unref (priv->metadata); + priv->metadata = fwupd_variant_to_hash_kv (value); + return; + } } static void @@ -670,6 +735,14 @@ fwupd_security_attr_to_json (FwupdSecurityAttr *self, JsonBuilder *builder) } json_builder_end_array (builder); } + if (priv->metadata != NULL) { + g_autoptr(GList) keys = g_hash_table_get_keys (priv->metadata); + for (GList *l = keys; l != NULL; l = l->next) { + const gchar *key = l->data; + const gchar *value = g_hash_table_lookup (priv->metadata, key); + fwupd_security_attr_json_add_string (builder, key, value); + } + } } /** @@ -704,6 +777,14 @@ fwupd_security_attr_to_string (FwupdSecurityAttr *self) const gchar *appstream_id = g_ptr_array_index (priv->obsoletes, i); fwupd_pad_kv_str (str, "Obsolete", appstream_id); } + if (priv->metadata != NULL) { + g_autoptr(GList) keys = g_hash_table_get_keys (priv->metadata); + for (GList *l = keys; l != NULL; l = l->next) { + const gchar *key = l->data; + const gchar *value = g_hash_table_lookup (priv->metadata, key); + fwupd_pad_kv_str (str, key, value); + } + } return g_string_free (str, FALSE); } @@ -728,6 +809,8 @@ fwupd_security_attr_finalize (GObject *object) FwupdSecurityAttr *self = FWUPD_SECURITY_ATTR (object); FwupdSecurityAttrPrivate *priv = GET_PRIVATE (self); + if (priv->metadata != NULL) + g_hash_table_unref (priv->metadata); g_free (priv->appstream_id); g_free (priv->name); g_free (priv->plugin); diff --git a/libfwupd/fwupd-security-attr.h b/libfwupd/fwupd-security-attr.h index 9087af619..b0d038cb7 100644 --- a/libfwupd/fwupd-security-attr.h +++ b/libfwupd/fwupd-security-attr.h @@ -161,6 +161,11 @@ void fwupd_security_attr_add_obsolete (FwupdSecurityAttr *self, const gchar *appstream_id); gboolean fwupd_security_attr_has_obsolete (FwupdSecurityAttr *self, const gchar *appstream_id); +const gchar *fwupd_security_attr_get_metadata (FwupdSecurityAttr *self, + const gchar *key); +void fwupd_security_attr_add_metadata (FwupdSecurityAttr *self, + const gchar *key, + const gchar *value); FwupdSecurityAttrFlags fwupd_security_attr_get_flags (FwupdSecurityAttr *self); void fwupd_security_attr_set_flags (FwupdSecurityAttr *self, FwupdSecurityAttrFlags flags); diff --git a/libfwupd/fwupd.map b/libfwupd/fwupd.map index f7b5cb62c..09730999b 100644 --- a/libfwupd/fwupd.map +++ b/libfwupd/fwupd.map @@ -467,6 +467,7 @@ LIBFWUPD_1.5.0 { fwupd_remote_get_automatic_security_reports; fwupd_remote_get_security_report_uri; fwupd_security_attr_add_flag; + fwupd_security_attr_add_metadata; fwupd_security_attr_add_obsolete; fwupd_security_attr_array_from_variant; fwupd_security_attr_flag_to_string; @@ -475,6 +476,7 @@ LIBFWUPD_1.5.0 { fwupd_security_attr_get_appstream_id; fwupd_security_attr_get_flags; fwupd_security_attr_get_level; + fwupd_security_attr_get_metadata; fwupd_security_attr_get_name; fwupd_security_attr_get_obsoletes; fwupd_security_attr_get_plugin; From 2adeb7688a6b230bdec8f51f2a6c984ea5159053 Mon Sep 17 00:00:00 2001 From: Richard Hughes Date: Wed, 1 Jul 2020 19:25:47 +0100 Subject: [PATCH 235/607] mei: Store the family in the plugin data --- plugins/pci-mei/fu-plugin-pci-mei.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/plugins/pci-mei/fu-plugin-pci-mei.c b/plugins/pci-mei/fu-plugin-pci-mei.c index ac7cc2c54..633ea107c 100644 --- a/plugins/pci-mei/fu-plugin-pci-mei.c +++ b/plugins/pci-mei/fu-plugin-pci-mei.c @@ -14,6 +14,7 @@ struct FuPluginData { gboolean has_device; guint32 mei_cfg; + FuMeiFamily family; FuMeiVersion vers; FuMeiIssue issue; }; @@ -53,7 +54,6 @@ static gboolean fu_mei_parse_fwvers (FuPlugin *plugin, const gchar *fwvers, GError **error) { FuPluginData *priv = fu_plugin_get_data (plugin); - FuMeiFamily family; g_auto(GStrv) lines = NULL; g_auto(GStrv) sections = NULL; g_auto(GStrv) split = NULL; @@ -97,16 +97,16 @@ fu_mei_parse_fwvers (FuPlugin *plugin, const gchar *fwvers, GError **error) /* check the AMT version for issues using the data from: * https://downloadcenter.intel.com/download/28632 */ - family = fu_mei_detect_family (plugin); - if (family == FU_MEI_FAMILY_CSME) + priv->family = fu_mei_detect_family (plugin); + if (priv->family == FU_MEI_FAMILY_CSME) priv->issue = fu_mei_common_is_csme_vulnerable (&priv->vers); - else if (family == FU_MEI_FAMILY_TXE) + else if (priv->family == FU_MEI_FAMILY_TXE) priv->issue = fu_mei_common_is_txe_vulnerable (&priv->vers); - else if (family == FU_MEI_FAMILY_SPS) + else if (priv->family == FU_MEI_FAMILY_SPS) priv->issue = fu_mei_common_is_sps_vulnerable (&priv->vers); if (g_getenv ("FWUPD_MEI_VERBOSE") != NULL) { g_debug ("%s version parsed as %u.%u.%u", - fu_mei_common_family_to_string (family), + fu_mei_common_family_to_string (priv->family), priv->vers.major, priv->vers.minor, priv->vers.hotfix); } return TRUE; From 1de98dcd7205b0f7a8ae8bb2d04b399ae0997c62 Mon Sep 17 00:00:00 2001 From: Richard Hughes Date: Wed, 1 Jul 2020 19:26:26 +0100 Subject: [PATCH 236/607] mei: Add extra metadata to the security attributes --- plugins/pci-mei/fu-plugin-pci-mei.c | 19 +++++++++++++------ 1 file changed, 13 insertions(+), 6 deletions(-) diff --git a/plugins/pci-mei/fu-plugin-pci-mei.c b/plugins/pci-mei/fu-plugin-pci-mei.c index 633ea107c..5c4936feb 100644 --- a/plugins/pci-mei/fu-plugin-pci-mei.c +++ b/plugins/pci-mei/fu-plugin-pci-mei.c @@ -161,6 +161,7 @@ fu_plugin_add_security_attrs_manufacturing_mode (FuPlugin *plugin, FuSecurityAtt attr = fwupd_security_attr_new (FWUPD_SECURITY_ATTR_ID_MEI_MANUFACTURING_MODE); fwupd_security_attr_set_plugin (attr, fu_plugin_get_name (plugin)); fwupd_security_attr_set_level (attr, FWUPD_SECURITY_ATTR_LEVEL_CRITICAL); + fwupd_security_attr_add_metadata (attr, "kind", fu_mei_common_family_to_string (priv->family)); fu_security_attrs_append (attrs, attr); /* Manufacturing Mode */ @@ -184,6 +185,7 @@ fu_plugin_add_security_attrs_override_strap (FuPlugin *plugin, FuSecurityAttrs * attr = fwupd_security_attr_new (FWUPD_SECURITY_ATTR_ID_MEI_OVERRIDE_STRAP); fwupd_security_attr_set_plugin (attr, fu_plugin_get_name (plugin)); fwupd_security_attr_set_level (attr, FWUPD_SECURITY_ATTR_LEVEL_CRITICAL); + fwupd_security_attr_add_metadata (attr, "kind", fu_mei_common_family_to_string (priv->family)); fu_security_attrs_append (attrs, attr); /* Flash Descriptor Security Override Strap */ @@ -201,15 +203,18 @@ static void fu_plugin_add_security_attrs_csme_version (FuPlugin *plugin, FuSecurityAttrs *attrs) { FuPluginData *priv = fu_plugin_get_data (plugin); + g_autofree gchar *version = NULL; g_autoptr(FwupdSecurityAttr) attr = NULL; + /* format version as string */ + version = g_strdup_printf ("%u:%u.%u.%u.%u", + priv->vers.platform, + priv->vers.major, + priv->vers.minor, + priv->vers.hotfix, + priv->vers.buildno); if (priv->issue == FU_MEI_ISSUE_UNKNOWN) { - g_warning ("ME family not supported for %u:%u.%u.%u.%u", - priv->vers.platform, - priv->vers.major, - priv->vers.minor, - priv->vers.hotfix, - priv->vers.buildno); + g_warning ("ME family not supported for %s", version); return; } @@ -217,6 +222,8 @@ fu_plugin_add_security_attrs_csme_version (FuPlugin *plugin, FuSecurityAttrs *at attr = fwupd_security_attr_new (FWUPD_SECURITY_ATTR_ID_MEI_VERSION); fwupd_security_attr_set_plugin (attr, fu_plugin_get_name (plugin)); fwupd_security_attr_set_level (attr, FWUPD_SECURITY_ATTR_LEVEL_CRITICAL); + fwupd_security_attr_add_metadata (attr, "kind", fu_mei_common_family_to_string (priv->family)); + fwupd_security_attr_add_metadata (attr, "version", version); fu_security_attrs_append (attrs, attr); /* Flash Descriptor Security Override Strap */ From b99df2ef936b13d79bfe0055ca6cdba1795b1280 Mon Sep 17 00:00:00 2001 From: Richard Hughes Date: Wed, 1 Jul 2020 19:28:35 +0100 Subject: [PATCH 237/607] Use the security attributes to construct a better name Fixes https://github.com/fwupd/fwupd/issues/2184 --- src/fu-engine.c | 2 +- src/fu-security-attr.c | 70 +++++++++++++++++++++++++++--------------- src/fu-security-attr.h | 2 +- src/fu-util-common.c | 5 +-- 4 files changed, 50 insertions(+), 29 deletions(-) diff --git a/src/fu-engine.c b/src/fu-engine.c index ae2b536e0..8aea930f8 100644 --- a/src/fu-engine.c +++ b/src/fu-engine.c @@ -5638,7 +5638,7 @@ fu_engine_get_host_security_attrs (FuEngine *self) for (guint i = 0; i < items->len; i++) { FwupdSecurityAttr *attr = g_ptr_array_index (items, i); if (fwupd_security_attr_get_name (attr) == NULL) { - const gchar *name_tmp = fu_security_attr_get_name (attr); + g_autofree gchar *name_tmp = fu_security_attr_get_name (attr); if (name_tmp == NULL) { g_warning ("failed to get fallback for %s", fwupd_security_attr_get_appstream_id (attr)); diff --git a/src/fu-security-attr.c b/src/fu-security-attr.c index 2596e75f9..a2bee2d9c 100644 --- a/src/fu-security-attr.c +++ b/src/fu-security-attr.c @@ -9,105 +9,125 @@ #include "fu-security-attr.h" -const gchar * +gchar * fu_security_attr_get_name (FwupdSecurityAttr *attr) { const gchar *appstream_id = fwupd_security_attr_get_appstream_id (attr); if (g_strcmp0 (appstream_id, FWUPD_SECURITY_ATTR_ID_SPI_BIOSWE) == 0) { /* TRANSLATORS: Title: SPI refers to the flash chip in the computer */ - return _("SPI write"); + return g_strdup (_("SPI write")); } if (g_strcmp0 (appstream_id, FWUPD_SECURITY_ATTR_ID_SPI_BLE) == 0) { /* TRANSLATORS: Title: SPI refers to the flash chip in the computer */ - return _("SPI lock"); + return g_strdup (_("SPI lock")); } if (g_strcmp0 (appstream_id, FWUPD_SECURITY_ATTR_ID_SPI_SMM_BWP) == 0) { /* TRANSLATORS: Title: SPI refers to the flash chip in the computer */ - return _("SPI BIOS region"); + return g_strdup (_("SPI BIOS region")); } if (g_strcmp0 (appstream_id, FWUPD_SECURITY_ATTR_ID_ACPI_DMAR) == 0) { /* TRANSLATORS: Title: DMA as in https://en.wikipedia.org/wiki/DMA_attack */ - return _("Pre-boot DMA protection"); + return g_strdup (_("Pre-boot DMA protection")); } if (g_strcmp0 (appstream_id, FWUPD_SECURITY_ATTR_ID_INTEL_CET) == 0) { /* TRANSLATORS: Title: CET = Control-flow Enforcement Technology */ - return _("Intel CET"); + return g_strdup (_("Intel CET")); } if (g_strcmp0 (appstream_id, FWUPD_SECURITY_ATTR_ID_INTEL_SMAP) == 0) { /* TRANSLATORS: Title: SMAP = Supervisor Mode Access Prevention */ - return _("Intel SMAP"); + return g_strdup (_("Intel SMAP")); } if (g_strcmp0 (appstream_id, FWUPD_SECURITY_ATTR_ID_ENCRYPTED_RAM) == 0) { /* TRANSLATORS: Title: Memory contents are encrypted, e.g. Intel TME */ - return _("Encrypted RAM"); + return g_strdup (_("Encrypted RAM")); } if (g_strcmp0 (appstream_id, FWUPD_SECURITY_ATTR_ID_IOMMU) == 0) { /* TRANSLATORS: Title: https://en.wikipedia.org/wiki/Input%E2%80%93output_memory_management_unit */ - return _("IOMMU"); + return g_strdup (_("IOMMU")); } if (g_strcmp0 (appstream_id, FWUPD_SECURITY_ATTR_ID_KERNEL_LOCKDOWN) == 0) { /* TRANSLATORS: Title: lockdown is a security mode of the kernel */ - return _("Linux kernel lockdown"); + return g_strdup (_("Linux kernel lockdown")); } if (g_strcmp0 (appstream_id, FWUPD_SECURITY_ATTR_ID_KERNEL_TAINTED) == 0) { /* TRANSLATORS: Title: if it's tainted or not */ - return _("Linux kernel"); + return g_strdup (_("Linux kernel")); } if (g_strcmp0 (appstream_id, FWUPD_SECURITY_ATTR_ID_KERNEL_SWAP) == 0) { /* TRANSLATORS: Title: swap space or swap partition */ - return _("Linux swap"); + return g_strdup (_("Linux swap")); } if (g_strcmp0 (appstream_id, FWUPD_SECURITY_ATTR_ID_SUSPEND_TO_RAM) == 0) { /* TRANSLATORS: Title: sleep state */ - return _("Suspend-to-ram"); + return g_strdup (_("Suspend-to-ram")); } if (g_strcmp0 (appstream_id, FWUPD_SECURITY_ATTR_ID_SUSPEND_TO_IDLE) == 0) { /* TRANSLATORS: Title: a better sleep state */ - return _("Suspend-to-idle"); + return g_strdup (_("Suspend-to-idle")); } if (g_strcmp0 (appstream_id, FWUPD_SECURITY_ATTR_ID_UEFI_DBX) == 0) { /* TRANSLATORS: Title: dbx is the database with revoked hashes */ - return _("UEFI dbx"); + return g_strdup (_("UEFI dbx")); } if (g_strcmp0 (appstream_id, FWUPD_SECURITY_ATTR_ID_UEFI_SECUREBOOT) == 0) { /* TRANSLATORS: Title: SB is a way of locking down UEFI */ - return _("UEFI secure boot"); + return g_strdup (_("UEFI secure boot")); } if (g_strcmp0 (appstream_id, FWUPD_SECURITY_ATTR_ID_TPM_RECONSTRUCTION_PCR0) == 0) { /* TRANSLATORS: Title: the PCR is rebuilt from the TPM event log */ - return _("TPM PCR0 reconstruction"); + return g_strdup (_("TPM PCR0 reconstruction")); } if (g_strcmp0 (appstream_id, FWUPD_SECURITY_ATTR_ID_TPM_VERSION_20) == 0) { /* TRANSLATORS: Title: TPM = Trusted Platform Module */ - return _("TPM v2.0"); + return g_strdup (_("TPM v2.0")); } if (g_strcmp0 (appstream_id, FWUPD_SECURITY_ATTR_ID_MEI_MANUFACTURING_MODE) == 0) { + const gchar *kind = fwupd_security_attr_get_metadata (attr, "kind"); + if (kind != NULL) { + /* TRANSLATORS: Title: %s is ME kind, e.g. CSME/TXT */ + return g_strdup_printf (_("%s manufacturing mode"), kind); + } /* TRANSLATORS: Title: MEI = Intel Management Engine */ - return _("MEI manufacturing mode"); + return g_strdup (_("MEI manufacturing mode")); } if (g_strcmp0 (appstream_id, FWUPD_SECURITY_ATTR_ID_MEI_OVERRIDE_STRAP) == 0) { + const gchar *kind = fwupd_security_attr_get_metadata (attr, "kind"); + if (kind != NULL) { + /* TRANSLATORS: Title: %s is ME kind, e.g. CSME/TXT */ + return g_strdup_printf (_("%s override strap"), kind); + } /* TRANSLATORS: Title: MEI = Intel Management Engine */ - return _("MEI override strap"); + return g_strdup (_("MEI override strap")); } if (g_strcmp0 (appstream_id, FWUPD_SECURITY_ATTR_ID_MEI_VERSION) == 0) { /* TRANSLATORS: Title: MEI = Intel Management Engine */ - return _("MEI version"); + const gchar *kind = fwupd_security_attr_get_metadata (attr, "kind"); + const gchar *version = fwupd_security_attr_get_metadata (attr, "version"); + if (kind != NULL && version != NULL) { + /* TRANSLATORS: Title: %1 is ME kind, e.g. CSME/TXT, %2 is a version number */ + return g_strdup_printf (_("%s v%s"), kind, version); + } + if (kind != NULL) { + /* TRANSLATORS: Title: %s is ME kind, e.g. CSME/TXT */ + return g_strdup_printf (_("%s version"), kind); + } + return g_strdup (_("MEI version")); } if (g_strcmp0 (appstream_id, FWUPD_SECURITY_ATTR_ID_FWUPD_UPDATES) == 0) { /* TRANSLATORS: Title: if firmware updates are available */ - return _("Firmware updates"); + return g_strdup (_("Firmware updates")); } if (g_strcmp0 (appstream_id, FWUPD_SECURITY_ATTR_ID_FWUPD_ATTESTATION) == 0) { /* TRANSLATORS: Title: if we can verify the firmware checksums */ - return _("Firmware attestation"); + return g_strdup (_("Firmware attestation")); } if (g_strcmp0 (appstream_id, FWUPD_SECURITY_ATTR_ID_FWUPD_PLUGINS) == 0) { /* TRANSLATORS: Title: if the fwupd plugins are all present and correct */ - return _("fwupd plugins"); + return g_strdup (_("fwupd plugins")); } /* we should not get here */ - return fwupd_security_attr_get_name (attr); + return g_strdup (fwupd_security_attr_get_name (attr)); } const gchar * diff --git a/src/fu-security-attr.h b/src/fu-security-attr.h index d81e33ce9..9967cf27d 100644 --- a/src/fu-security-attr.h +++ b/src/fu-security-attr.h @@ -8,5 +8,5 @@ #include -const gchar *fu_security_attr_get_name (FwupdSecurityAttr *attr); +gchar *fu_security_attr_get_name (FwupdSecurityAttr *attr); const gchar *fu_security_attr_get_result (FwupdSecurityAttr *attr); diff --git a/src/fu-util-common.c b/src/fu-util-common.c index c0f2b243f..30ab1b2ef 100644 --- a/src/fu-util-common.c +++ b/src/fu-util-common.c @@ -1556,6 +1556,7 @@ fu_util_remote_to_string (FwupdRemote *remote, guint idt) static void fu_security_attr_append_str (FwupdSecurityAttr *attr, GString *str) { + g_autofree gchar *name = fu_security_attr_get_name (attr); if (fwupd_security_attr_has_flag (attr, FWUPD_SECURITY_ATTR_FLAG_OBSOLETED)) { g_string_append (str, "✦ "); } else if (fwupd_security_attr_has_flag (attr, FWUPD_SECURITY_ATTR_FLAG_SUCCESS)) { @@ -1563,8 +1564,8 @@ fu_security_attr_append_str (FwupdSecurityAttr *attr, GString *str) } else { g_string_append (str, "✘ "); } - g_string_append_printf (str, "%s:", fu_security_attr_get_name (attr)); - for (guint i = fu_common_strwidth (fu_security_attr_get_name (attr)); i < 30; i++) + g_string_append_printf (str, "%s:", name); + for (guint i = fu_common_strwidth (name); i < 30; i++) g_string_append (str, " "); if (fwupd_security_attr_has_flag (attr, FWUPD_SECURITY_ATTR_FLAG_OBSOLETED)) { g_string_append_printf (str, "\033[37m\033[1m%s\033[0m", fu_security_attr_get_result (attr)); From 2b0a329cf1e98a6fae5f3ba36dd4ea915a3395d9 Mon Sep 17 00:00:00 2001 From: Reto Kromer Date: Wed, 1 Jul 2020 22:06:55 +0200 Subject: [PATCH 238/607] fix alignment (in the code) --- plugins/rts54hid/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugins/rts54hid/README.md b/plugins/rts54hid/README.md index 7f5965210..9a5b6a679 100644 --- a/plugins/rts54hid/README.md +++ b/plugins/rts54hid/README.md @@ -44,6 +44,6 @@ This plugin uses the following plugin-specific quirks: | Quirk | Description | Minimum fwupd version | |------------------------|---------------------------------------------|-----------------------| -| `Rts54TargetAddr` | The target address of a child module. | 1.1.3 | +| `Rts54TargetAddr` | The target address of a child module. | 1.1.3 | | `Rts54I2cSpeed` | The I2C speed to operate at (0, 1, 2). | 1.1.3 | | `Rts54RegisterAddrLen` | The I2C register address length of commands | 1.1.3 | From 81a12a1b1706ec8c238b59ed93181959ee45ad07 Mon Sep 17 00:00:00 2001 From: Richard Hughes Date: Thu, 2 Jul 2020 16:15:53 +0100 Subject: [PATCH 239/607] pci-mei: Split out the HFSTS registers The register specifications have been taken as a superset of the coreboot documentation as different flags were documented in more detail on various different platforms. Having this new data allows us to add future tests and make the current tests much easier to understand. --- plugins/pci-mei/fu-mei-common.c | 237 ++++++++++++++++++++++++++++ plugins/pci-mei/fu-mei-common.h | 174 ++++++++++++++++++++ plugins/pci-mei/fu-plugin-pci-mei.c | 79 ++++++++-- 3 files changed, 480 insertions(+), 10 deletions(-) diff --git a/plugins/pci-mei/fu-mei-common.c b/plugins/pci-mei/fu-mei-common.c index 3e9b123a9..87be19179 100644 --- a/plugins/pci-mei/fu-mei-common.c +++ b/plugins/pci-mei/fu-mei-common.c @@ -146,3 +146,240 @@ fu_mei_common_is_sps_vulnerable (FuMeiVersion *vers) } return FU_MEI_ISSUE_PATCHED; } + +/* HFS1[3:0] Current Working State Values */ +static const char *me_cws_values[] = { + [ME_HFS_CWS_RESET] = "reset", + [ME_HFS_CWS_INIT] = "initializing", + [ME_HFS_CWS_REC] = "recovery", + [ME_HFS_CWS_TEST] = "test", + [ME_HFS_CWS_DISABLED] = "disabled", + [ME_HFS_CWS_NORMAL] = "normal", + [ME_HFS_CWS_WAIT] = "wait", + [ME_HFS_CWS_TRANS] = "transition", + [ME_HFS_CWS_INVALID] = "invalid", +}; + +/* HFS1[8:6] Current Operation State Values */ +static const char *me_opstate_values[] = { + [ME_HFS_STATE_PREBOOT] = "preboot", + [ME_HFS_STATE_M0_UMA] = "m0-with-uma", + [ME_HFS_STATE_M3] = "m3-without-uma", + [ME_HFS_STATE_M0] = "m0-without-uma", + [ME_HFS_STATE_BRINGUP] = "bring-up", + [ME_HFS_STATE_ERROR] = "error", +}; + +/* HFS[19:16] Current Operation Mode Values */ +static const char *me_opmode_values[] = { + [ME_HFS_MODE_NORMAL] = "normal", + [ME_HFS_MODE_DEBUG] = "debug", + [ME_HFS_MODE_DIS] = "disable", + [ME_HFS_MODE_OVER_JMPR] = "override-jumper", + [ME_HFS_MODE_OVER_MEI] = "override-mei", + [ME_HFS_MODE_UNKNOWN_6] = "unknown-6", + [ME_HFS_MODE_MAYBE_SPS] = "maybe-sps", +}; + +/* HFS[15:12] Error Code Values */ +static const char *me_error_values[] = { + [ME_HFS_ERROR_NONE] = "no-error", + [ME_HFS_ERROR_UNCAT] = "uncategorized-failure", + [ME_HFS_ERROR_DISABLED] = "disabled", + [ME_HFS_ERROR_IMAGE] = "image-failure", + [ME_HFS_ERROR_DEBUG] = "debug-failure", +}; + +void +fu_mei_hfsts1_to_string (FuMeiHfsts1 hfsts1, guint idt, GString *str) +{ + fu_common_string_append_kv (str, idt, "WorkingState", + me_cws_values[hfsts1.fields.working_state]); + fu_common_string_append_kb (str, idt, "MfgMode", + hfsts1.fields.mfg_mode); + fu_common_string_append_kb (str, idt, "FptBad", + hfsts1.fields.fpt_bad); + fu_common_string_append_kv (str, idt, "OperationState", + me_opstate_values[hfsts1.fields.operation_state]); + fu_common_string_append_kb (str, idt, "FwInitComplete", + hfsts1.fields.fw_init_complete); + fu_common_string_append_kb (str, idt, "FtBupLdFlr", + hfsts1.fields.ft_bup_ld_flr); + fu_common_string_append_kb (str, idt, "UpdateInProgress", + hfsts1.fields.update_in_progress); + fu_common_string_append_kv (str, idt, "ErrorCode", + me_error_values[hfsts1.fields.error_code]); + fu_common_string_append_kv (str, idt, "OperationMode", + me_opmode_values[hfsts1.fields.operation_mode]); + fu_common_string_append_kx (str, idt, "ResetCount", + hfsts1.fields.reset_count); + fu_common_string_append_kb (str, idt, "BootOptions_present", + hfsts1.fields.boot_options_present); + fu_common_string_append_kb (str, idt, "BistFinished", + hfsts1.fields.bist_finished); + fu_common_string_append_kb (str, idt, "BistTestState", + hfsts1.fields.bist_test_state); + fu_common_string_append_kb (str, idt, "BistResetRequest", + hfsts1.fields.bist_reset_request); + fu_common_string_append_kx (str, idt, "CurrentPowerSource", + hfsts1.fields.current_power_source); + fu_common_string_append_kb (str, idt, "D3SupportValid", + hfsts1.fields.d3_support_valid); + fu_common_string_append_kb (str, idt, "D0i3SupportValid", + hfsts1.fields.d0i3_support_valid); +} + +void +fu_mei_hfsts2_to_string (FuMeiHfsts2 hfsts2, guint idt, GString *str) +{ + fu_common_string_append_kb (str, idt, "NftpLoadFailure", + hfsts2.fields.nftp_load_failure); + fu_common_string_append_kx (str, idt, "IccProgStatus", + hfsts2.fields.icc_prog_status); + fu_common_string_append_kb (str, idt, "InvokeMebx", + hfsts2.fields.invoke_mebx); + fu_common_string_append_kb (str, idt, "CpuReplaced", + hfsts2.fields.cpu_replaced); + fu_common_string_append_kb (str, idt, "Rsvd0", + hfsts2.fields.rsvd0); + fu_common_string_append_kb (str, idt, "MfsFailure", + hfsts2.fields.mfs_failure); + fu_common_string_append_kb (str, idt, "WarmResetRqst", + hfsts2.fields.warm_reset_rqst); + fu_common_string_append_kb (str, idt, "CpuReplacedValid", + hfsts2.fields.cpu_replaced_valid); + fu_common_string_append_kb (str, idt, "LowPowerState", + hfsts2.fields.low_power_state); + fu_common_string_append_kb (str, idt, "MePowerGate", + hfsts2.fields.me_power_gate); + fu_common_string_append_kb (str, idt, "IpuNeeded", + hfsts2.fields.ipu_needed); + fu_common_string_append_kb (str, idt, "ForcedSafeBoot", + hfsts2.fields.forced_safe_boot); + fu_common_string_append_kx (str, idt, "Rsvd1", + hfsts2.fields.rsvd1); + fu_common_string_append_kb (str, idt, "ListenerChange", + hfsts2.fields.listener_change); + fu_common_string_append_kx (str, idt, "StatusData", + hfsts2.fields.status_data); + fu_common_string_append_kx (str, idt, "CurrentPmevent", + hfsts2.fields.current_pmevent); + fu_common_string_append_kx (str, idt, "Phase", + hfsts2.fields.phase); +} + +void +fu_mei_hfsts3_to_string (FuMeiHfsts3 hfsts3, guint idt, GString *str) +{ + fu_common_string_append_kx (str, idt, "Reserved0", + hfsts3.fields.reserved_0); + fu_common_string_append_kx (str, idt, "FwSku", + hfsts3.fields.fw_sku); + fu_common_string_append_kb (str, idt, "EncryptKeyCheck", + hfsts3.fields.encrypt_key_check); + fu_common_string_append_kb (str, idt, "PchConfigChange", + hfsts3.fields.pch_config_change); + fu_common_string_append_kx (str, idt, "Reserved9", + hfsts3.fields.reserved_9); + fu_common_string_append_kx (str, idt, "Reserved11", + hfsts3.fields.reserved_11); + fu_common_string_append_kx (str, idt, "Reserved14", + hfsts3.fields.reserved_14); + fu_common_string_append_kb (str, idt, "EncryptKeyOverride", + hfsts3.fields.encrypt_key_override); + fu_common_string_append_kb (str, idt, "PowerDownMitigation", + hfsts3.fields.power_down_mitigation); +} + +void +fu_mei_hfsts4_to_string (FuMeiHfsts4 hfsts4, guint idt, GString *str) +{ + fu_common_string_append_kx (str, idt, "Rsvd0", + hfsts4.fields.rsvd0); + fu_common_string_append_kb (str, idt, "EnforcementFlow", + hfsts4.fields.enforcement_flow); + fu_common_string_append_kb (str, idt, "SxResumeType", + hfsts4.fields.sx_resume_type); + fu_common_string_append_kb (str, idt, "Rsvd1", + hfsts4.fields.rsvd1); + fu_common_string_append_kb (str, idt, "TpmsDisconnected", + hfsts4.fields.tpms_disconnected); + fu_common_string_append_kb (str, idt, "Rvsd2", + hfsts4.fields.rvsd2); + fu_common_string_append_kb (str, idt, "FwstsValid", + hfsts4.fields.fwsts_valid); + fu_common_string_append_kb (str, idt, "BootGuardSelfTest", + hfsts4.fields.boot_guard_self_test); + fu_common_string_append_kx (str, idt, "Rsvd3", + hfsts4.fields.rsvd3); +} + +void +fu_mei_hfsts5_to_string (FuMeiHfsts5 hfsts5, guint idt, GString *str) +{ + fu_common_string_append_kb (str, idt, "AcmActive", + hfsts5.fields.acm_active); + fu_common_string_append_kb (str, idt, "Valid", + hfsts5.fields.valid); + fu_common_string_append_kb (str, idt, "ResultCodeSource", + hfsts5.fields.result_code_source); + fu_common_string_append_kx (str, idt, "ErrorStatusCode", + hfsts5.fields.error_status_code); + fu_common_string_append_kx (str, idt, "AcmDoneSts", + hfsts5.fields.acm_done_sts); + fu_common_string_append_kx (str, idt, "TimeoutCount", + hfsts5.fields.timeout_count); + fu_common_string_append_kb (str, idt, "ScrtmIndicator", + hfsts5.fields.scrtm_indicator); + fu_common_string_append_kx (str, idt, "IncBootGuardAcm", + hfsts5.fields.inc_boot_guard_acm); + fu_common_string_append_kx (str, idt, "IncKeyManifest", + hfsts5.fields.inc_key_manifest); + fu_common_string_append_kx (str, idt, "IncBootPolicy", + hfsts5.fields.inc_boot_policy); + fu_common_string_append_kx (str, idt, "Rsvd0", + hfsts5.fields.rsvd0); + fu_common_string_append_kb (str, idt, "StartEnforcement", + hfsts5.fields.start_enforcement); +} + +void +fu_mei_hfsts6_to_string (FuMeiHfsts6 hfsts6, guint idt, GString *str) +{ + fu_common_string_append_kb (str, idt, "ForceBootGuardAcm", + hfsts6.fields.force_boot_guard_acm); + fu_common_string_append_kb (str, idt, "CpuDebugDisable", + hfsts6.fields.cpu_debug_disable); + fu_common_string_append_kb (str, idt, "BspInitDisable", + hfsts6.fields.bsp_init_disable); + fu_common_string_append_kb (str, idt, "ProtectBiosEnv", + hfsts6.fields.protect_bios_env); + fu_common_string_append_kx (str, idt, "Rsvd0", + hfsts6.fields.rsvd0); + fu_common_string_append_kx (str, idt, "ErrorEnforcePolicy", + hfsts6.fields.error_enforce_policy); + fu_common_string_append_kb (str, idt, "MeasuredBoot", + hfsts6.fields.measured_boot); + fu_common_string_append_kb (str, idt, "VerifiedBoot", + hfsts6.fields.verified_boot); + fu_common_string_append_kx (str, idt, "BootGuardAcmsvn", + hfsts6.fields.boot_guard_acmsvn); + fu_common_string_append_kx (str, idt, "Kmsvn", + hfsts6.fields.kmsvn); + fu_common_string_append_kx (str, idt, "Bpmsvn", + hfsts6.fields.bpmsvn); + fu_common_string_append_kx (str, idt, "KeyManifestId", + hfsts6.fields.key_manifest_id); + fu_common_string_append_kb (str, idt, "BootPolicyStatus", + hfsts6.fields.boot_policy_status); + fu_common_string_append_kb (str, idt, "Error", + hfsts6.fields.error); + fu_common_string_append_kb (str, idt, "BootGuardDisable", + hfsts6.fields.boot_guard_disable); + fu_common_string_append_kb (str, idt, "FpfDisable", + hfsts6.fields.fpf_disable); + fu_common_string_append_kb (str, idt, "FpfSocLock", + hfsts6.fields.fpf_soc_lock); + fu_common_string_append_kb (str, idt, "TxtSupport", + hfsts6.fields.txt_support); +} diff --git a/plugins/pci-mei/fu-mei-common.h b/plugins/pci-mei/fu-mei-common.h index 0d990c4dc..7c62763d0 100644 --- a/plugins/pci-mei/fu-mei-common.h +++ b/plugins/pci-mei/fu-mei-common.h @@ -31,7 +31,181 @@ typedef struct { guint16 buildno; } FuMeiVersion; +/* Host Firmware Status register 1 */ +typedef union { + guint32 data; + struct { + guint32 working_state : 4; + guint32 mfg_mode : 1; + guint32 fpt_bad : 1; + guint32 operation_state : 3; + guint32 fw_init_complete : 1; + guint32 ft_bup_ld_flr : 1; + guint32 update_in_progress : 1; + guint32 error_code : 4; + guint32 operation_mode : 4; + guint32 reset_count : 4; + guint32 boot_options_present : 1; + guint32 bist_finished : 1; + guint32 bist_test_state : 1; + guint32 bist_reset_request : 1; + guint32 current_power_source : 2; + guint32 d3_support_valid : 1; + guint32 d0i3_support_valid : 1; + } __attribute__((packed)) fields; +} FuMeiHfsts1; + +/* Host Firmware Status Register 2 */ +typedef union { + guint32 data; + struct { + guint32 nftp_load_failure : 1; + guint32 icc_prog_status : 2; + guint32 invoke_mebx : 1; + guint32 cpu_replaced : 1; + guint32 rsvd0 : 1; + guint32 mfs_failure : 1; + guint32 warm_reset_rqst : 1; + guint32 cpu_replaced_valid : 1; + guint32 low_power_state : 1; + guint32 me_power_gate : 1; + guint32 ipu_needed : 1; + guint32 forced_safe_boot : 1; + guint32 rsvd1 : 2; + guint32 listener_change : 1; + guint32 status_data : 8; + guint32 current_pmevent : 4; + guint32 phase : 4; + } __attribute__((packed)) fields; +} FuMeiHfsts2; + +/* Host Firmware Status Register 3 */ +typedef union { + guint32 data; + struct { + guint32 reserved_0 : 4; + guint32 fw_sku : 3; + guint32 encrypt_key_check : 1; + guint32 pch_config_change : 1; + guint32 reserved_9 : 2; + guint32 reserved_11 : 3; + guint32 reserved_14 : 16; + guint32 encrypt_key_override : 1; + guint32 power_down_mitigation : 1; + } __attribute__((packed)) fields; +} FuMeiHfsts3; + +/* Host Firmware Status Register 4 */ +typedef union { + guint32 data; + struct { + guint32 rsvd0 : 9; + guint32 enforcement_flow : 1; + guint32 sx_resume_type : 1; + guint32 rsvd1 : 1; + guint32 tpms_disconnected : 1; + guint32 rvsd2 : 1; + guint32 fwsts_valid : 1; + guint32 boot_guard_self_test : 1; + guint32 rsvd3 : 16; + } __attribute__((packed)) fields; +} FuMeiHfsts4; + +/* Host Firmware Status Register 5 */ +typedef union { + guint32 data; + struct { + guint32 acm_active : 1; + guint32 valid : 1; + guint32 result_code_source : 1; + guint32 error_status_code : 5; + guint32 acm_done_sts : 1; + guint32 timeout_count : 7; + guint32 scrtm_indicator : 1; + guint32 inc_boot_guard_acm : 4; + guint32 inc_key_manifest : 4; + guint32 inc_boot_policy : 4; + guint32 rsvd0 : 2; + guint32 start_enforcement : 1; + } __attribute__((packed)) fields; +} FuMeiHfsts5; + +/* Host Firmware Status Register 6 */ +typedef union { + guint32 data; + struct { + guint32 force_boot_guard_acm : 1; + guint32 cpu_debug_disable : 1; + guint32 bsp_init_disable : 1; + guint32 protect_bios_env : 1; + guint32 rsvd0 : 2; + guint32 error_enforce_policy : 2; + guint32 measured_boot : 1; + guint32 verified_boot : 1; + guint32 boot_guard_acmsvn : 4; + guint32 kmsvn : 4; + guint32 bpmsvn : 4; + guint32 key_manifest_id : 4; + guint32 boot_policy_status : 1; + guint32 error : 1; + guint32 boot_guard_disable : 1; + guint32 fpf_disable : 1; + guint32 fpf_soc_lock : 1; + guint32 txt_support : 1; + } __attribute__((packed)) fields; +} FuMeiHfsts6; + +#define ME_HFS_CWS_RESET 0 +#define ME_HFS_CWS_INIT 1 +#define ME_HFS_CWS_REC 2 +#define ME_HFS_CWS_TEST 3 +#define ME_HFS_CWS_DISABLED 4 +#define ME_HFS_CWS_NORMAL 5 +#define ME_HFS_CWS_WAIT 6 +#define ME_HFS_CWS_TRANS 7 +#define ME_HFS_CWS_INVALID 8 + +#define ME_HFS_STATE_PREBOOT 0 +#define ME_HFS_STATE_M0_UMA 1 +#define ME_HFS_STATE_M3 4 +#define ME_HFS_STATE_M0 5 +#define ME_HFS_STATE_BRINGUP 6 +#define ME_HFS_STATE_ERROR 7 + +#define ME_HFS_ERROR_NONE 0 +#define ME_HFS_ERROR_UNCAT 1 +#define ME_HFS_ERROR_DISABLED 2 +#define ME_HFS_ERROR_IMAGE 3 +#define ME_HFS_ERROR_DEBUG 4 + +#define ME_HFS_MODE_NORMAL 0 +#define ME_HFS_MODE_DEBUG 2 +#define ME_HFS_MODE_DIS 3 +#define ME_HFS_MODE_OVER_JMPR 4 +#define ME_HFS_MODE_OVER_MEI 5 +#define ME_HFS_MODE_UNKNOWN_6 6 +#define ME_HFS_MODE_MAYBE_SPS 7 + const gchar *fu_mei_common_family_to_string (FuMeiFamily family); FuMeiIssue fu_mei_common_is_csme_vulnerable (FuMeiVersion *vers); FuMeiIssue fu_mei_common_is_txe_vulnerable (FuMeiVersion *vers); FuMeiIssue fu_mei_common_is_sps_vulnerable (FuMeiVersion *vers); + +void fu_mei_hfsts1_to_string (FuMeiHfsts1 hfsts1, + guint idt, + GString *str); +void fu_mei_hfsts2_to_string (FuMeiHfsts2 hfsts2, + guint idt, + GString *str); +void fu_mei_hfsts3_to_string (FuMeiHfsts3 hfsts3, + guint idt, + GString *str); +void fu_mei_hfsts4_to_string (FuMeiHfsts4 hfsts4, + guint idt, + GString *str); +void fu_mei_hfsts5_to_string (FuMeiHfsts5 hfsts5, + guint idt, + GString *str); +void fu_mei_hfsts6_to_string (FuMeiHfsts6 hfsts6, + guint idt, + GString *str); diff --git a/plugins/pci-mei/fu-plugin-pci-mei.c b/plugins/pci-mei/fu-plugin-pci-mei.c index 5c4936feb..1d88d692f 100644 --- a/plugins/pci-mei/fu-plugin-pci-mei.c +++ b/plugins/pci-mei/fu-plugin-pci-mei.c @@ -13,13 +13,41 @@ struct FuPluginData { gboolean has_device; - guint32 mei_cfg; + FuMeiHfsts1 hfsts1; + FuMeiHfsts2 hfsts2; + FuMeiHfsts3 hfsts3; + FuMeiHfsts4 hfsts4; + FuMeiHfsts5 hfsts5; + FuMeiHfsts6 hfsts6; FuMeiFamily family; FuMeiVersion vers; FuMeiIssue issue; }; #define PCI_CFG_HFS_1 0x40 +#define PCI_CFG_HFS_2 0x48 +#define PCI_CFG_HFS_3 0x60 +#define PCI_CFG_HFS_4 0x64 +#define PCI_CFG_HFS_5 0x68 +#define PCI_CFG_HFS_6 0x6c + +static void +fu_mei_hfsts_to_string (FuPlugin *plugin, guint idt, GString *str) +{ + FuPluginData *priv = fu_plugin_get_data (plugin); + fu_common_string_append_kv (str, idt, "HFSTS1", NULL); + fu_mei_hfsts1_to_string (priv->hfsts1, idt + 1, str); + fu_common_string_append_kv (str, idt, "HFSTS2", NULL); + fu_mei_hfsts2_to_string (priv->hfsts2, idt + 1, str); + fu_common_string_append_kv (str, idt, "HFSTS3", NULL); + fu_mei_hfsts3_to_string (priv->hfsts3, idt + 1, str); + fu_common_string_append_kv (str, idt, "HFSTS4", NULL); + fu_mei_hfsts4_to_string (priv->hfsts4, idt + 1, str); + fu_common_string_append_kv (str, idt, "HFSTS5", NULL); + fu_mei_hfsts5_to_string (priv->hfsts5, idt + 1, str); + fu_common_string_append_kv (str, idt, "HFSTS6", NULL); + fu_mei_hfsts6_to_string (priv->hfsts6, idt + 1, str); +} void fu_plugin_init (FuPlugin *plugin) @@ -33,11 +61,10 @@ static FuMeiFamily fu_mei_detect_family (FuPlugin *plugin) { FuPluginData *priv = fu_plugin_get_data (plugin); - guint8 operating_mode = (priv->mei_cfg >> 16) & 0xF; guint8 ver = priv->vers.major; if (ver == 1 || ver == 2) { - if (operating_mode == 0xF) + if (priv->hfsts1.fields.operation_mode == 0xf) return FU_MEI_FAMILY_SPS; return FU_MEI_FAMILY_TXE; } @@ -132,14 +159,46 @@ fu_plugin_udev_device_added (FuPlugin *plugin, FuUdevDevice *device, GError **er if (locker == NULL) return FALSE; - /* grab MEI config Register */ + /* grab MEI config registers */ if (!fu_udev_device_pread_full (device, PCI_CFG_HFS_1, buf, sizeof(buf), error)) { - g_prefix_error (error, "could not read MEI: "); + g_prefix_error (error, "could not read HFS1: "); return FALSE; } - priv->mei_cfg = fu_common_read_uint32 (buf, G_LITTLE_ENDIAN); + priv->hfsts1.data = fu_common_read_uint32 (buf, G_LITTLE_ENDIAN); + if (!fu_udev_device_pread_full (device, PCI_CFG_HFS_2, buf, sizeof(buf), error)) { + g_prefix_error (error, "could not read HFS2: "); + return FALSE; + } + priv->hfsts2.data = fu_common_read_uint32 (buf, G_LITTLE_ENDIAN); + if (!fu_udev_device_pread_full (device, PCI_CFG_HFS_3, buf, sizeof(buf), error)) { + g_prefix_error (error, "could not read HFS3: "); + return FALSE; + } + priv->hfsts3.data = fu_common_read_uint32 (buf, G_LITTLE_ENDIAN); + if (!fu_udev_device_pread_full (device, PCI_CFG_HFS_4, buf, sizeof(buf), error)) { + g_prefix_error (error, "could not read HFS4: "); + return FALSE; + } + priv->hfsts4.data = fu_common_read_uint32 (buf, G_LITTLE_ENDIAN); + if (!fu_udev_device_pread_full (device, PCI_CFG_HFS_5, buf, sizeof(buf), error)) { + g_prefix_error (error, "could not read HFS5: "); + return FALSE; + } + priv->hfsts5.data = fu_common_read_uint32 (buf, G_LITTLE_ENDIAN); + if (!fu_udev_device_pread_full (device, PCI_CFG_HFS_6, buf, sizeof(buf), error)) { + g_prefix_error (error, "could not read HFS6: "); + return FALSE; + } + priv->hfsts6.data = fu_common_read_uint32 (buf, G_LITTLE_ENDIAN); priv->has_device = TRUE; + /* dump to console */ + if (g_getenv ("FWUPD_PCI_MEI_VERBOSE") != NULL) { + g_autoptr(GString) str = g_string_new (NULL); + fu_mei_hfsts_to_string (plugin, 0, str); + g_debug ("\n%s", str->str); + } + /* check firmware version */ fwvers = fu_udev_device_get_sysfs_attr (device, "mei/mei0/fw_ver", NULL); if (fwvers != NULL) { @@ -165,7 +224,7 @@ fu_plugin_add_security_attrs_manufacturing_mode (FuPlugin *plugin, FuSecurityAtt fu_security_attrs_append (attrs, attr); /* Manufacturing Mode */ - if (((priv->mei_cfg >> 4) & 0x1) != 0) { + if (priv->hfsts1.fields.mfg_mode) { fwupd_security_attr_set_result (attr, FWUPD_SECURITY_ATTR_RESULT_NOT_LOCKED); return; } @@ -189,7 +248,7 @@ fu_plugin_add_security_attrs_override_strap (FuPlugin *plugin, FuSecurityAttrs * fu_security_attrs_append (attrs, attr); /* Flash Descriptor Security Override Strap */ - if (((priv->mei_cfg >> 16) & 0x7) != 0) { + if (priv->hfsts1.fields.operation_mode == ME_HFS_MODE_OVER_JMPR) { fwupd_security_attr_set_result (attr, FWUPD_SECURITY_ATTR_RESULT_NOT_LOCKED); return; } @@ -200,7 +259,7 @@ fu_plugin_add_security_attrs_override_strap (FuPlugin *plugin, FuSecurityAttrs * } static void -fu_plugin_add_security_attrs_csme_version (FuPlugin *plugin, FuSecurityAttrs *attrs) +fu_plugin_add_security_attrs_mei_version (FuPlugin *plugin, FuSecurityAttrs *attrs) { FuPluginData *priv = fu_plugin_get_data (plugin); g_autofree gchar *version = NULL; @@ -250,5 +309,5 @@ fu_plugin_add_security_attrs (FuPlugin *plugin, FuSecurityAttrs *attrs) fu_plugin_add_security_attrs_manufacturing_mode (plugin, attrs); fu_plugin_add_security_attrs_override_strap (plugin, attrs); - fu_plugin_add_security_attrs_csme_version (plugin, attrs); + fu_plugin_add_security_attrs_mei_version (plugin, attrs); } From 6269a839ebf770ecbef8700656426c0fe338f7bb Mon Sep 17 00:00:00 2001 From: Richard Hughes Date: Thu, 2 Jul 2020 17:18:13 +0100 Subject: [PATCH 240/607] Add a security attribute for BootGuard This information is obtained from the MEI configuration space. --- libfwupd/fwupd-security-attr.h | 1 + plugins/pci-mei/fu-mei-common.h | 4 +++ plugins/pci-mei/fu-plugin-pci-mei.c | 48 +++++++++++++++++++++++++++++ src/fu-security-attr.c | 4 +++ 4 files changed, 57 insertions(+) diff --git a/libfwupd/fwupd-security-attr.h b/libfwupd/fwupd-security-attr.h index b0d038cb7..fff2ba9d6 100644 --- a/libfwupd/fwupd-security-attr.h +++ b/libfwupd/fwupd-security-attr.h @@ -116,6 +116,7 @@ typedef enum { #define FWUPD_SECURITY_ATTR_ID_FWUPD_ATTESTATION "org.fwupd.hsi.FwupdAttestation" /* Since: 1.5.0 */ #define FWUPD_SECURITY_ATTR_ID_FWUPD_PLUGINS "org.fwupd.hsi.FwupdPlugins" /* Since: 1.5.0 */ #define FWUPD_SECURITY_ATTR_ID_FWUPD_UPDATES "org.fwupd.hsi.FwupdUpdates" /* Since: 1.5.0 */ +#define FWUPD_SECURITY_ATTR_ID_INTEL_BOOTGUARD "org.fwupd.hsi.IntelBootguard" /* Since: 1.5.0 */ #define FWUPD_SECURITY_ATTR_ID_INTEL_CET "org.fwupd.hsi.IntelCet" /* Since: 1.5.0 */ #define FWUPD_SECURITY_ATTR_ID_INTEL_SMAP "org.fwupd.hsi.IntelSmap" /* Since: 1.5.0 */ #define FWUPD_SECURITY_ATTR_ID_IOMMU "org.fwupd.hsi.Iommu" /* Since: 1.5.0 */ diff --git a/plugins/pci-mei/fu-mei-common.h b/plugins/pci-mei/fu-mei-common.h index 7c62763d0..1ad930bf9 100644 --- a/plugins/pci-mei/fu-mei-common.h +++ b/plugins/pci-mei/fu-mei-common.h @@ -186,6 +186,10 @@ typedef union { #define ME_HFS_MODE_UNKNOWN_6 6 #define ME_HFS_MODE_MAYBE_SPS 7 +#define ME_HFS_ENFORCEMENT_POLICY_NOTHING 0b00 +#define ME_HFS_ENFORCEMENT_POLICY_SHUTDOWN_TO 0b01 +#define ME_HFS_ENFORCEMENT_POLICY_SHUTDOWN_NOW 0b11 + const gchar *fu_mei_common_family_to_string (FuMeiFamily family); FuMeiIssue fu_mei_common_is_csme_vulnerable (FuMeiVersion *vers); FuMeiIssue fu_mei_common_is_txe_vulnerable (FuMeiVersion *vers); diff --git a/plugins/pci-mei/fu-plugin-pci-mei.c b/plugins/pci-mei/fu-plugin-pci-mei.c index 1d88d692f..9c8231d19 100644 --- a/plugins/pci-mei/fu-plugin-pci-mei.c +++ b/plugins/pci-mei/fu-plugin-pci-mei.c @@ -258,6 +258,53 @@ fu_plugin_add_security_attrs_override_strap (FuPlugin *plugin, FuSecurityAttrs * fwupd_security_attr_set_result (attr, FWUPD_SECURITY_ATTR_RESULT_LOCKED); } +static void +fu_plugin_add_security_attrs_bootguard (FuPlugin *plugin, FuSecurityAttrs *attrs) +{ + FuPluginData *priv = fu_plugin_get_data (plugin); + g_autoptr(FwupdSecurityAttr) attr = NULL; + + /* create attr */ + attr = fwupd_security_attr_new (FWUPD_SECURITY_ATTR_ID_INTEL_BOOTGUARD); + fwupd_security_attr_set_plugin (attr, fu_plugin_get_name (plugin)); + fwupd_security_attr_set_level (attr, FWUPD_SECURITY_ATTR_LEVEL_IMPORTANT); + fu_security_attrs_append (attrs, attr); + + /* disabled at runtime? */ + if (priv->hfsts6.fields.boot_guard_disable) { + fwupd_security_attr_set_result (attr, FWUPD_SECURITY_ATTR_RESULT_NOT_ENABLED); + return; + } + + /* measured boot is not sufficient, verified is required */ + if (!priv->hfsts6.fields.verified_boot) { + fwupd_security_attr_set_result (attr, FWUPD_SECURITY_ATTR_RESULT_NOT_VALID); + return; + } + + /* ACM protection required */ + if (!priv->hfsts6.fields.force_boot_guard_acm) { + fwupd_security_attr_set_result (attr, FWUPD_SECURITY_ATTR_RESULT_NOT_VALID); + return; + } + + /* policy must be to immediatly shutdown */ + if (priv->hfsts6.fields.error_enforce_policy != ME_HFS_ENFORCEMENT_POLICY_SHUTDOWN_NOW) { + fwupd_security_attr_set_result (attr, FWUPD_SECURITY_ATTR_RESULT_NOT_VALID); + return; + } + + /* ensure vendor set the FPF OTP fuse */ + if (!priv->hfsts6.fields.fpf_soc_lock) { + fwupd_security_attr_set_result (attr, FWUPD_SECURITY_ATTR_RESULT_NOT_VALID); + return; + } + + /* success */ + fwupd_security_attr_add_flag (attr, FWUPD_SECURITY_ATTR_FLAG_SUCCESS); + fwupd_security_attr_set_result (attr, FWUPD_SECURITY_ATTR_RESULT_LOCKED); +} + static void fu_plugin_add_security_attrs_mei_version (FuPlugin *plugin, FuSecurityAttrs *attrs) { @@ -309,5 +356,6 @@ fu_plugin_add_security_attrs (FuPlugin *plugin, FuSecurityAttrs *attrs) fu_plugin_add_security_attrs_manufacturing_mode (plugin, attrs); fu_plugin_add_security_attrs_override_strap (plugin, attrs); + fu_plugin_add_security_attrs_bootguard (plugin, attrs); fu_plugin_add_security_attrs_mei_version (plugin, attrs); } diff --git a/src/fu-security-attr.c b/src/fu-security-attr.c index a2bee2d9c..0bc0c39ad 100644 --- a/src/fu-security-attr.c +++ b/src/fu-security-attr.c @@ -29,6 +29,10 @@ fu_security_attr_get_name (FwupdSecurityAttr *attr) /* TRANSLATORS: Title: DMA as in https://en.wikipedia.org/wiki/DMA_attack */ return g_strdup (_("Pre-boot DMA protection")); } + if (g_strcmp0 (appstream_id, FWUPD_SECURITY_ATTR_ID_INTEL_BOOTGUARD) == 0) { + /* TRANSLATORS: Title: BootGuard is a trademark from Intel */ + return g_strdup (_("Intel BootGuard")); + } if (g_strcmp0 (appstream_id, FWUPD_SECURITY_ATTR_ID_INTEL_CET) == 0) { /* TRANSLATORS: Title: CET = Control-flow Enforcement Technology */ return g_strdup (_("Intel CET")); From 62618bedb680df19061a99ab07f8a638ad8bf11c Mon Sep 17 00:00:00 2001 From: Ryan Lee Date: Wed, 1 Jul 2020 13:40:14 +0900 Subject: [PATCH 241/607] ccgx: add extra 45% removal time for worst case --- plugins/ccgx/ccgx.quirk | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/plugins/ccgx/ccgx.quirk b/plugins/ccgx/ccgx.quirk index 2995fb792..34aeb629c 100644 --- a/plugins/ccgx/ccgx.quirk +++ b/plugins/ccgx/ccgx.quirk @@ -1,4 +1,4 @@ -# Lenovo Gen2 Dock +# Lenovo ThinkPad USB-C Dock Gen2 [DeviceInstanceId=USB\VID_17EF&PID_A38F] Plugin = ccgx GType = FuCcgxHidDevice @@ -23,7 +23,7 @@ Flags = is-bootloader Summary = CCGx Power Delivery Device CounterpartGuid = USB\VID_04B4&PID_521A&SID_1F00&APP_6D64&MODE_FW1 -# Lenovo Hybrid Dock +# Lenovo ThinkPad USB-C Dock Hybrid [DeviceInstanceId=USB\VID_17EF&PID_A354] Plugin = ccgx GType = FuCcgxHidDevice @@ -51,7 +51,7 @@ Summary = CCGx Power Delivery Device (Symmetric FW1) [DeviceInstanceId=USB\VID_04B4&PID_5218&SID_1F00&APP_6432&MODE_FW2] Summary = CCGx Power Delivery Device (Symmetric FW2) -# HP Adicora Dock A Type +# HP USB-C Dock G5 [DeviceInstanceId=USB\VID_03F0&PID_046B] Plugin = ccgx GType = FuCcgxDmcDevice @@ -59,10 +59,10 @@ Summary = Dock Management Controller Device ParentGuid = USB\VID_03F0&PID_0363 Name = HP USB-C Dock G5 ImageKind = dmc-composite -InstallDuration = 190 -RemoveDelay = 150000 +InstallDuration = 233 +RemoveDelay = 203000 -# HP Adicora Dock D Type +# HP USB-C/A Universal Dock G2 [DeviceInstanceId=USB\VID_03F0&PID_0A6B] Plugin = ccgx GType = FuCcgxDmcDevice @@ -70,5 +70,5 @@ Summary = Dock Management Controller Device ParentGuid = USB\VID_03F0&PID_096B Name = HP USB-C/A Universal Dock G2 ImageKind = dmc-composite -InstallDuration = 110 -RemoveDelay = 85000 +InstallDuration = 125 +RemoveDelay = 107000 From a852254d929bd8fb352ed20540144454ccfb8337 Mon Sep 17 00:00:00 2001 From: Richard Hughes Date: Fri, 3 Jul 2020 12:32:06 +0100 Subject: [PATCH 242/607] trivial: Hide the UEFI DBX parsing by default --- plugins/uefi-dbx/fu-uefi-dbx-file.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/plugins/uefi-dbx/fu-uefi-dbx-file.c b/plugins/uefi-dbx/fu-uefi-dbx-file.c index 64852d109..a56785e27 100644 --- a/plugins/uefi-dbx/fu-uefi-dbx-file.c +++ b/plugins/uefi-dbx/fu-uefi-dbx-file.c @@ -53,7 +53,8 @@ fu_uefi_dbx_file_parse_sig_item (FuUefiDbxFile *self, sig_datastr = g_string_new (NULL); for (gsize j = 0; j < sig_datasz; j++) g_string_append_printf (sig_datastr, "%02x", sig_data[j]); - g_debug ("Owner: %s, Data: %s", sig_owner, sig_datastr->str); + if (g_getenv ("FWUPD_UEFI_DBX_VERBOSE") != NULL) + g_debug ("Owner: %s, Data: %s", sig_owner, sig_datastr->str); g_ptr_array_add (self->checksums, g_string_free (sig_datastr, FALSE)); return TRUE; } From 885faa40119fdeb1efb41bb18947ad6850036f52 Mon Sep 17 00:00:00 2001 From: Richard Hughes Date: Fri, 3 Jul 2020 15:47:25 +0100 Subject: [PATCH 243/607] trivial: Require libjcat even when compiled with -Dbuild=library --- meson.build | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/meson.build b/meson.build index 1af9eb90f..ea0019c02 100644 --- a/meson.build +++ b/meson.build @@ -194,11 +194,11 @@ else gudev = dependency('', required : false) endif libxmlb = dependency('xmlb', version : '>= 0.1.13', fallback : ['libxmlb', 'libxmlb_dep']) -libjcat = dependency('jcat', version : '>= 0.1.0', fallback : ['libjcat', 'libjcat_dep']) gusb = dependency('gusb', version : '>= 0.3.3', fallback : ['gusb', 'gusb_dep']) sqlite = dependency('sqlite3') libarchive = dependency('libarchive') endif +libjcat = dependency('jcat', version : '>= 0.1.0', fallback : ['libjcat', 'libjcat_dep']) libjsonglib = dependency('json-glib-1.0', version : '>= 1.1.1') valgrind = dependency('valgrind', required: false) soup = dependency('libsoup-2.4', version : '>= 2.51.92') From eb7be16bf0e7d0ffecb32439d0d5872705a2a7c8 Mon Sep 17 00:00:00 2001 From: Mario Limonciello Date: Wed, 1 Jul 2020 15:38:47 -0500 Subject: [PATCH 244/607] fu-util/fu-tool: Group devices in `get-updates`/`update` calls Fixes: #1840 --- src/fu-tool.c | 50 ++++++++++++++++++++++++++------------------ src/fu-util-common.c | 20 ++++++++++++++++++ src/fu-util-common.h | 2 ++ src/fu-util.c | 50 ++++++++++++++++++++++++++------------------ 4 files changed, 82 insertions(+), 40 deletions(-) diff --git a/src/fu-tool.c b/src/fu-tool.c index 61828c6dd..fb7037b0c 100644 --- a/src/fu-tool.c +++ b/src/fu-tool.c @@ -320,6 +320,8 @@ fu_util_get_updates (FuUtilPrivate *priv, gchar **values, GError **error) g_autoptr(GPtrArray) devices = NULL; g_autoptr(GNode) root = g_node_new (NULL); g_autofree gchar *title = NULL; + gboolean no_updates_header = FALSE; + gboolean latest_header = FALSE; /* load engine */ if (!fu_util_start_engine (priv, FU_ENGINE_LOAD_FLAG_NONE, error)) @@ -331,6 +333,7 @@ fu_util_get_updates (FuUtilPrivate *priv, gchar **values, GError **error) if (devices == NULL) return FALSE; fwupd_device_array_ensure_parents (devices); + g_ptr_array_sort (devices, fu_util_sort_devices_by_flags_cb); for (guint i = 0; i < devices->len; i++) { FwupdDevice *dev = g_ptr_array_index (devices, i); g_autoptr(GPtrArray) rels = NULL; @@ -341,11 +344,12 @@ fu_util_get_updates (FuUtilPrivate *priv, gchar **values, GError **error) if (!fwupd_device_has_flag (dev, FWUPD_DEVICE_FLAG_UPDATABLE)) continue; if (!fwupd_device_has_flag (dev, FWUPD_DEVICE_FLAG_SUPPORTED)) { - /* TRANSLATORS: message letting the user know no device upgrade available due to missing on LVFS - * %1 is the device name */ - g_autofree gchar *tmp = g_strdup_printf (_("• %s has no available firmware updates"), - fwupd_device_get_name (dev)); - g_printerr ("%s\n", tmp); + if (!no_updates_header) { + /* TRANSLATORS: message letting the user know no device upgrade available due to missing on LVFS */ + g_printerr ("%s\n", _("Devices with no available firmware updates: ")); + no_updates_header = TRUE; + } + g_printerr (" • %s\n", fwupd_device_get_name (dev)); continue; } if (!fu_util_filter_device (priv, dev)) @@ -357,11 +361,12 @@ fu_util_get_updates (FuUtilPrivate *priv, gchar **values, GError **error) fwupd_device_get_id (dev), &error_local); if (rels == NULL) { - /* TRANSLATORS: message letting the user know no device upgrade available - * %1 is the device name */ - g_autofree gchar *tmp = g_strdup_printf (_("• %s has the latest available firmware version"), - fwupd_device_get_name (dev)); - g_printerr ("%s\n", tmp); + if (!latest_header) { + /* TRANSLATORS: message letting the user know no device upgrade available */ + g_printerr ("%s\n", _("Devices with the latest available firmware version:")); + latest_header = TRUE; + } + g_printerr (" • %s\n", fwupd_device_get_name (dev)); /* discard the actual reason from user, but leave for debugging */ g_debug ("%s", error_local->message); continue; @@ -1045,11 +1050,14 @@ static gboolean fu_util_update_all (FuUtilPrivate *priv, GError **error) { g_autoptr(GPtrArray) devices = NULL; + gboolean no_updates_header = FALSE; + gboolean latest_header = FALSE; devices = fu_engine_get_devices (priv->engine, error); if (devices == NULL) return FALSE; fwupd_device_array_ensure_parents (devices); + g_ptr_array_sort (devices, fu_util_sort_devices_by_flags_cb); for (guint i = 0; i < devices->len; i++) { FwupdDevice *dev = g_ptr_array_index (devices, i); FwupdRelease *rel; @@ -1063,11 +1071,12 @@ fu_util_update_all (FuUtilPrivate *priv, GError **error) if (!fwupd_device_has_flag (dev, FWUPD_DEVICE_FLAG_UPDATABLE)) continue; if (!fwupd_device_has_flag (dev, FWUPD_DEVICE_FLAG_SUPPORTED)) { - /* TRANSLATORS: message letting the user know no device upgrade available due to missing on LVFS - * %1 is the device name */ - g_autofree gchar *tmp = g_strdup_printf (_("• %s has no available firmware updates"), - fwupd_device_get_name (dev)); - g_printerr ("%s\n", tmp); + if (!no_updates_header) { + /* TRANSLATORS: message letting the user know no device upgrade available due to missing on LVFS */ + g_printerr ("%s\n", _("Devices with no available firmware updates: ")); + no_updates_header = TRUE; + } + g_printerr (" • %s\n", fwupd_device_get_name (dev)); continue; } if (!fu_util_filter_device (priv, dev)) @@ -1079,11 +1088,12 @@ fu_util_update_all (FuUtilPrivate *priv, GError **error) device_id, &error_local); if (rels == NULL) { - /* TRANSLATORS: message letting the user know no device upgrade available - * %1 is the device name */ - g_autofree gchar *tmp = g_strdup_printf (_("• %s has the latest available firmware version"), - fwupd_device_get_name (dev)); - g_printerr ("%s\n", tmp); + if (!latest_header) { + /* TRANSLATORS: message letting the user know no device upgrade available */ + g_printerr ("%s\n", _("Devices with the latest available firmware version:")); + latest_header = TRUE; + } + g_printerr (" • %s\n", fwupd_device_get_name (dev)); /* discard the actual reason from user, but leave for debugging */ g_debug ("%s", error_local->message); continue; diff --git a/src/fu-util-common.c b/src/fu-util-common.c index 30ab1b2ef..903d7ba06 100644 --- a/src/fu-util-common.c +++ b/src/fu-util-common.c @@ -1776,3 +1776,23 @@ fu_util_send_report (SoupSession *soup_session, /* success */ return TRUE; } + +gint +fu_util_sort_devices_by_flags_cb (gconstpointer a, gconstpointer b) +{ + FuDevice *dev_a = *((FuDevice **) a); + FuDevice *dev_b = *((FuDevice **) b); + + if ((!fu_device_has_flag (dev_a, FWUPD_DEVICE_FLAG_UPDATABLE) && + fu_device_has_flag (dev_b, FWUPD_DEVICE_FLAG_UPDATABLE)) || + (!fu_device_has_flag (dev_a, FWUPD_DEVICE_FLAG_SUPPORTED) && + fu_device_has_flag (dev_b, FWUPD_DEVICE_FLAG_SUPPORTED))) + return -1; + if ((fu_device_has_flag (dev_a, FWUPD_DEVICE_FLAG_UPDATABLE) && + !fu_device_has_flag (dev_b, FWUPD_DEVICE_FLAG_UPDATABLE)) || + (fu_device_has_flag (dev_a, FWUPD_DEVICE_FLAG_SUPPORTED) && + !fu_device_has_flag (dev_b, FWUPD_DEVICE_FLAG_SUPPORTED))) + return 1; + + return 0; +} diff --git a/src/fu-util-common.h b/src/fu-util-common.h index 31c114715..5ae35f8ea 100644 --- a/src/fu-util-common.h +++ b/src/fu-util-common.h @@ -84,3 +84,5 @@ gboolean fu_util_send_report (SoupSession *soup_session, const gchar *sig, gchar **uri, GError **error); +gint fu_util_sort_devices_by_flags_cb (gconstpointer a, + gconstpointer b); diff --git a/src/fu-util.c b/src/fu-util.c index 5c23ab307..d2f4a9110 100644 --- a/src/fu-util.c +++ b/src/fu-util.c @@ -1575,6 +1575,8 @@ fu_util_get_updates (FuUtilPrivate *priv, gchar **values, GError **error) gboolean supported = FALSE; g_autoptr(GNode) root = g_node_new (NULL); g_autofree gchar *title = fu_util_get_tree_title (priv); + gboolean no_updates_header = FALSE; + gboolean latest_header = FALSE; /* are the remotes very old */ if (!fu_util_perhaps_refresh_remotes (priv, error)) @@ -1584,6 +1586,7 @@ fu_util_get_updates (FuUtilPrivate *priv, gchar **values, GError **error) devices = fwupd_client_get_devices (priv->client, NULL, error); if (devices == NULL) return FALSE; + g_ptr_array_sort (devices, fu_util_sort_devices_by_flags_cb); for (guint i = 0; i < devices->len; i++) { FwupdDevice *dev = g_ptr_array_index (devices, i); g_autoptr(GPtrArray) rels = NULL; @@ -1594,11 +1597,12 @@ fu_util_get_updates (FuUtilPrivate *priv, gchar **values, GError **error) if (!fwupd_device_has_flag (dev, FWUPD_DEVICE_FLAG_UPDATABLE)) continue; if (!fwupd_device_has_flag (dev, FWUPD_DEVICE_FLAG_SUPPORTED)) { - /* TRANSLATORS: message letting the user know no device upgrade available due to missing on LVFS - * %1 is the device name */ - g_autofree gchar *tmp = g_strdup_printf (_("• %s has no available firmware updates"), - fwupd_device_get_name (dev)); - g_printerr ("%s\n", tmp); + if (!no_updates_header) { + /* TRANSLATORS: message letting the user know no device upgrade available due to missing on LVFS */ + g_printerr ("%s\n", _("Devices with no available firmware updates: ")); + no_updates_header = TRUE; + } + g_printerr (" • %s\n", fwupd_device_get_name (dev)); continue; } if (!fu_util_filter_device (priv, dev)) @@ -1610,11 +1614,12 @@ fu_util_get_updates (FuUtilPrivate *priv, gchar **values, GError **error) fwupd_device_get_id (dev), NULL, &error_local); if (rels == NULL) { - /* TRANSLATORS: message letting the user know no device upgrade available - * %1 is the device name */ - g_autofree gchar *tmp = g_strdup_printf (_("• %s has the latest available firmware version"), - fwupd_device_get_name (dev)); - g_printerr ("%s\n", tmp); + if (!latest_header) { + /* TRANSLATORS: message letting the user know no device upgrade available */ + g_printerr ("%s\n", _("Devices with the latest available firmware version:")); + latest_header = TRUE; + } + g_printerr (" • %s\n", fwupd_device_get_name (dev)); /* discard the actual reason from user, but leave for debugging */ g_debug ("%s", error_local->message); continue; @@ -1782,6 +1787,8 @@ fu_util_update_all (FuUtilPrivate *priv, GError **error) { g_autoptr(GPtrArray) devices = NULL; gboolean supported = FALSE; + gboolean no_updates_header = FALSE; + gboolean latest_header = FALSE; /* get devices from daemon */ devices = fwupd_client_get_devices (priv->client, NULL, error); @@ -1790,6 +1797,7 @@ fu_util_update_all (FuUtilPrivate *priv, GError **error) priv->current_operation = FU_UTIL_OPERATION_UPDATE; g_signal_connect (priv->client, "device-changed", G_CALLBACK (fu_util_update_device_changed_cb), priv); + g_ptr_array_sort (devices, fu_util_sort_devices_by_flags_cb); for (guint i = 0; i < devices->len; i++) { FwupdDevice *dev = g_ptr_array_index (devices, i); FwupdRelease *rel; @@ -1802,11 +1810,12 @@ fu_util_update_all (FuUtilPrivate *priv, GError **error) if (!fwupd_device_has_flag (dev, FWUPD_DEVICE_FLAG_UPDATABLE)) continue; if (!fwupd_device_has_flag (dev, FWUPD_DEVICE_FLAG_SUPPORTED)) { - /* TRANSLATORS: message letting the user know no device upgrade available due to missing on LVFS - * %1 is the device name */ - g_autofree gchar *tmp = g_strdup_printf (_("• %s has no available firmware updates"), - fwupd_device_get_name (dev)); - g_printerr ("%s\n", tmp); + if (!no_updates_header) { + /* TRANSLATORS: message letting the user know no device upgrade available due to missing on LVFS */ + g_printerr ("%s\n", _("Devices with no available firmware updates: ")); + no_updates_header = TRUE; + } + g_printerr (" • %s\n", fwupd_device_get_name (dev)); continue; } if (!fu_util_filter_device (priv, dev)) @@ -1818,11 +1827,12 @@ fu_util_update_all (FuUtilPrivate *priv, GError **error) fwupd_device_get_id (dev), NULL, &error_local); if (rels == NULL) { - /* TRANSLATORS: message letting the user know no device upgrade available - * %1 is the device name */ - g_autofree gchar *tmp = g_strdup_printf (_("• %s has the latest available firmware version"), - fwupd_device_get_name (dev)); - g_printerr ("%s\n", tmp); + if (!latest_header) { + /* TRANSLATORS: message letting the user know no device upgrade available */ + g_printerr ("%s\n", _("Devices with the latest available firmware version:")); + latest_header = TRUE; + } + g_printerr (" • %s\n", fwupd_device_get_name (dev)); /* discard the actual reason from user, but leave for debugging */ g_debug ("%s", error_local->message); continue; From a2431e07ff3e945ec83f3a956aecf0c9658e7c95 Mon Sep 17 00:00:00 2001 From: Mario Limonciello Date: Thu, 2 Jul 2020 16:35:23 -0500 Subject: [PATCH 245/607] trivial: fu-udev-device: add support for exporting the udev device type This is useful in some plugins that will behave differently for multiple device types. --- libfwupdplugin/fu-udev-device.c | 22 ++++++++++++++++++++++ libfwupdplugin/fu-udev-device.h | 1 + libfwupdplugin/fwupdplugin.map | 1 + 3 files changed, 24 insertions(+) diff --git a/libfwupdplugin/fu-udev-device.c b/libfwupdplugin/fu-udev-device.c index 2352bab5e..80d56cf81 100644 --- a/libfwupdplugin/fu-udev-device.c +++ b/libfwupdplugin/fu-udev-device.c @@ -1241,6 +1241,28 @@ fu_udev_device_write_sysfs (FuUdevDevice *self, const gchar *attribute, #endif } +/** + * fu_udev_device_get_devtype + * @self: A #FuUdevDevice + * + * Returns the Udev device type + * + * Returns: device type specified in the uevent + * + * Since: 1.4.5 + **/ +const gchar * +fu_udev_device_get_devtype (FuUdevDevice *self) +{ +#ifdef HAVE_GUDEV + FuUdevDevicePrivate *priv = GET_PRIVATE (self); + + return g_udev_device_get_devtype (priv->udev_device); +#else + return NULL; +#endif +} + static void fu_udev_device_get_property (GObject *object, guint prop_id, GValue *value, GParamSpec *pspec) diff --git a/libfwupdplugin/fu-udev-device.h b/libfwupdplugin/fu-udev-device.h index d181258d5..c455755ad 100644 --- a/libfwupdplugin/fu-udev-device.h +++ b/libfwupdplugin/fu-udev-device.h @@ -106,3 +106,4 @@ gboolean fu_udev_device_write_sysfs (FuUdevDevice *self, const gchar *attribute, const gchar *val, GError **error); +const gchar *fu_udev_device_get_devtype (FuUdevDevice *self); diff --git a/libfwupdplugin/fwupdplugin.map b/libfwupdplugin/fwupdplugin.map index 29d093525..addabb390 100644 --- a/libfwupdplugin/fwupdplugin.map +++ b/libfwupdplugin/fwupdplugin.map @@ -583,6 +583,7 @@ LIBFWUPDPLUGIN_1.4.1 { LIBFWUPDPLUGIN_1.4.5 { global: + fu_udev_device_get_devtype; fu_udev_device_get_parent_name; fu_udev_device_get_sysfs_attr; fu_udev_device_pread_full; From c90eca478705151793a8db7cfafae75549b5742b Mon Sep 17 00:00:00 2001 From: Mario Limonciello Date: Thu, 2 Jul 2020 16:36:33 -0500 Subject: [PATCH 246/607] thunderbolt: add support for retimers --- plugins/thunderbolt/README.md | 7 + plugins/thunderbolt/fu-thunderbolt-device.c | 154 ++++++++++++++++---- 2 files changed, 133 insertions(+), 28 deletions(-) diff --git a/plugins/thunderbolt/README.md b/plugins/thunderbolt/README.md index 914257cb3..bcc54550d 100644 --- a/plugins/thunderbolt/README.md +++ b/plugins/thunderbolt/README.md @@ -37,6 +37,13 @@ used for systems with multiple host controllers to disambiguiate between control * `TBT-$(vid)$(pid)-native-controller$(num)` +For retimers the only GUID created is as follows: +* `TBT-$(vid)$(pid)-retimer$index` + +The retimer index is oriented around the physical connection within +the machine. It is important as multiple controllers may otherwise +identify identically. + Vendor ID Security ------------------ diff --git a/plugins/thunderbolt/fu-thunderbolt-device.c b/plugins/thunderbolt/fu-thunderbolt-device.c index 530921f42..6edc946f3 100644 --- a/plugins/thunderbolt/fu-thunderbolt-device.c +++ b/plugins/thunderbolt/fu-thunderbolt-device.c @@ -21,9 +21,15 @@ #include "fu-thunderbolt-firmware.h" #include "fu-thunderbolt-firmware-update.h" +typedef enum { + FU_THUNDERBOLT_DEVICE_TYPE_DEVICE_CONTROLLER, + FU_THUNDERBOLT_DEVICE_TYPE_HOST_CONTROLLER, + FU_THUNDERBOLT_DEVICE_TYPE_RETIMER +} FuThunderboltDeviceType; + struct _FuThunderboltDevice { FuUdevDevice parent_instance; - gboolean host; + FuThunderboltDeviceType device_type; gboolean safe_mode; gboolean is_native; guint16 gen; @@ -160,7 +166,7 @@ static void fu_thunderbolt_device_check_safe_mode (FuThunderboltDevice *self) { /* failed to read, for host check for safe mode */ - if (!self->host || self->gen >= 4) + if (self->device_type != FU_THUNDERBOLT_DEVICE_TYPE_DEVICE_CONTROLLER) return; g_warning ("%s is in safe mode -- VID/DID will " "need to be set by another plugin", @@ -171,11 +177,31 @@ fu_thunderbolt_device_check_safe_mode (FuThunderboltDevice *self) fu_device_set_metadata_boolean (FU_DEVICE (self), FU_DEVICE_METADATA_TBT_IS_SAFE_MODE, TRUE); } +static const gchar* +fu_thunderbolt_device_type_to_string (FuThunderboltDevice *self) +{ + if (self->device_type == FU_THUNDERBOLT_DEVICE_TYPE_HOST_CONTROLLER) { + if (self->gen >= 4) + return "USB4 host controller"; + else + return "Thunderbolt host controller"; + } + if (self->device_type == FU_THUNDERBOLT_DEVICE_TYPE_DEVICE_CONTROLLER) { + if (self->gen >= 4) + return "USB4 device controller"; + else + return "Thunderbolt device controller"; + } + if (self->device_type == FU_THUNDERBOLT_DEVICE_TYPE_RETIMER) + return "USB4 Retimer"; + return "Unknown"; +} + static void fu_thunderbolt_device_to_string (FuDevice *device, guint idt, GString *str) { FuThunderboltDevice *self = FU_THUNDERBOLT_DEVICE (device); - fu_common_string_append_kb (str, idt, "Host Controller", self->host); + fu_common_string_append_kv (str, idt, "Device Type", fu_thunderbolt_device_type_to_string (self)); fu_common_string_append_kb (str, idt, "Safe Mode", self->safe_mode); fu_common_string_append_kb (str, idt, "Native mode", self->is_native); fu_common_string_append_ku (str, idt, "Generation", self->gen); @@ -185,16 +211,25 @@ fu_thunderbolt_device_to_string (FuDevice *device, guint idt, GString *str) static gboolean fu_thunderbolt_device_probe (FuUdevDevice *device, GError **error) { - const gchar *tmp = fu_udev_device_get_sysfs_attr (device, "unique_id", NULL); - /* most likely the domain itself, ignore */ - if (tmp == NULL) { - g_set_error_literal (error, - FWUPD_ERROR, - FWUPD_ERROR_NOT_SUPPORTED, - "thunderbolt domain not used"); + FuThunderboltDevice *self = FU_THUNDERBOLT_DEVICE (device); + const gchar *tmp = fu_udev_device_get_devtype (device); + + /* device */ + if (g_strcmp0 (tmp, "thunderbolt_device") == 0) { + tmp = fu_udev_device_get_sysfs_attr (device, "unique_id", NULL); + if (tmp != NULL) + fu_device_set_physical_id (FU_DEVICE (device), tmp); + /* retimer */ + } else if (g_strcmp0 (tmp, "thunderbolt_retimer") == 0) { + self->device_type = FU_THUNDERBOLT_DEVICE_TYPE_RETIMER; + /* domain or unsupported */ + } else { + g_set_error (error, + FWUPD_ERROR, + FWUPD_ERROR_NOT_SUPPORTED, + "%s not used", tmp); return FALSE; } - fu_device_set_physical_id (FU_DEVICE (device), tmp); return TRUE; } @@ -231,7 +266,7 @@ fu_thunderbolt_device_get_attr_uint16 (FuThunderboltDevice *self, } static gboolean -fu_thunderbolt_device_setup (FuDevice *device, GError **error) +fu_thunderbolt_device_setup_controller (FuDevice *device, GError **error) { FuThunderboltDevice *self = FU_THUNDERBOLT_DEVICE (device); const gchar *tmp = NULL; @@ -240,9 +275,6 @@ fu_thunderbolt_device_setup (FuDevice *device, GError **error) g_autoptr(GError) error_gen = NULL; g_autofree gchar *parent_name = fu_udev_device_get_parent_name (FU_UDEV_DEVICE (self)); - self->devpath = g_strdup (fu_udev_device_get_sysfs_path (FU_UDEV_DEVICE (device))); - fu_device_set_metadata (device, "sysfs-path", self->devpath); - /* these may be missing on ICL or later */ vid = fu_udev_device_get_vendor (FU_UDEV_DEVICE (self)); if (vid == 0x0) @@ -263,7 +295,7 @@ fu_thunderbolt_device_setup (FuDevice *device, GError **error) /* determine if host controller or not */ if (parent_name != NULL && g_str_has_prefix (parent_name, "domain")) { - self->host = TRUE; + self->device_type = FU_THUNDERBOLT_DEVICE_TYPE_HOST_CONTROLLER; fu_device_add_flag (device, FWUPD_DEVICE_FLAG_INTERNAL); fu_device_set_summary (device, "Unmatched performance for high-speed I/O"); } else { @@ -271,12 +303,8 @@ fu_thunderbolt_device_setup (FuDevice *device, GError **error) } /* set the controller name */ - if (tmp == NULL) { - if (self->gen == 4) - tmp = "USB4 Controller"; - else - tmp = "Thunderbolt Controller"; - } + if (tmp == NULL) + tmp = fu_thunderbolt_device_type_to_string (self); fu_device_set_name (device, tmp); /* set vendor string */ @@ -285,8 +313,7 @@ fu_thunderbolt_device_setup (FuDevice *device, GError **error) return FALSE; fu_device_set_vendor (device, tmp); - /* try to read the version */ - if (!fu_thunderbolt_device_get_version (self)) + if (fu_device_get_version (device) == NULL) fu_thunderbolt_device_check_safe_mode (self); if (self->safe_mode) { @@ -299,7 +326,8 @@ fu_thunderbolt_device_setup (FuDevice *device, GError **error) g_autofree gchar *domain = g_path_get_basename (self->devpath); /* USB4 controllers don't have a concept of legacy vs native * so don't try to read a native attribute from their NVM */ - if (self->host && self->gen < 4) { + if (self->device_type == FU_THUNDERBOLT_DEVICE_TYPE_HOST_CONTROLLER + && self->gen < 4) { domain_id = g_strdup_printf ("TBT-%04x%04x%s-controller%s", (guint) vid, (guint) did, @@ -331,14 +359,84 @@ fu_thunderbolt_device_setup (FuDevice *device, GError **error) fu_device_add_flag (device, FWUPD_DEVICE_FLAG_USABLE_DURING_UPDATE); /* forces the device to write to authenticate on disconnect attribute */ fu_device_remove_flag (device, FWUPD_DEVICE_FLAG_SKIPS_RESTART); - } else { - self->auth_method = "nvm_authenticate"; } - /* success */ return TRUE; } +static gboolean +fu_thunderbolt_device_setup_retimer (FuDevice *device, GError **error) +{ + FuThunderboltDevice *self = FU_THUNDERBOLT_DEVICE (device); + guint16 did; + guint16 vid; + g_autofree gchar *idx = g_path_get_basename (self->devpath); + g_autofree gchar *instance = NULL; + + fu_device_set_physical_id (device, idx); + /* as defined in PCIe 4.0 spec */ + fu_device_set_summary (device, "A physical layer protocol-aware, software-transparent extension device " + "that forms two separate electrical link segments"); + fu_device_set_name (device, fu_thunderbolt_device_type_to_string (self)); + fu_device_add_flag (device, FWUPD_DEVICE_FLAG_UPDATABLE); + fu_device_add_flag (device, FWUPD_DEVICE_FLAG_DUAL_IMAGE); + fu_device_add_flag (device, FWUPD_DEVICE_FLAG_INTERNAL); + vid = fu_udev_device_get_vendor (FU_UDEV_DEVICE (self)); + if (vid == 0x0) { + g_set_error_literal (error, + FWUPD_ERROR, + FWUPD_ERROR_NOT_SUPPORTED, + "missing vendor id"); + return FALSE; + } + + did = fu_udev_device_get_model (FU_UDEV_DEVICE (self)); + if (did == 0x0) { + g_set_error_literal (error, + FWUPD_ERROR, + FWUPD_ERROR_NOT_SUPPORTED, + "missing device id"); + return FALSE; + + } + + instance = g_strdup_printf ("TBT-%04x%04x-retimer%s", + (guint) vid, + (guint) did, + idx); + fu_device_add_instance_id (device, instance); + + /* hardcoded for now: + * 1. unsure if ID_VENDOR_FROM_DATABASE works in this instance + * 2. we don't recognize anyone else yet + */ + if (fu_device_get_vendor (device) == NULL) + fu_device_set_vendor (device, "Intel"); + + return TRUE; +} + +static gboolean +fu_thunderbolt_device_setup (FuDevice *device, GError **error) +{ + FuThunderboltDevice *self = FU_THUNDERBOLT_DEVICE (device); + + self->devpath = g_strdup (fu_udev_device_get_sysfs_path (FU_UDEV_DEVICE (device))); + fu_device_set_metadata (device, "sysfs-path", self->devpath); + + /* try to read the version */ + if (!fu_thunderbolt_device_get_version (self)) + g_debug ("failed to read version"); + + /* default behavior */ + self->auth_method = "nvm_authenticate"; + + /* configure differences between retimer and controller */ + if (self->device_type == FU_THUNDERBOLT_DEVICE_TYPE_RETIMER) + return fu_thunderbolt_device_setup_retimer (device, error); + return fu_thunderbolt_device_setup_controller (device, error); +} + static gboolean fu_thunderbolt_device_authenticate (FuDevice *device, GError **error) { From fb0a938f6c13dc1869531089aed0998a6c5d2f9f Mon Sep 17 00:00:00 2001 From: Richard Hughes Date: Tue, 23 Jun 2020 16:56:28 +0100 Subject: [PATCH 247/607] Cache the FuSecurityAttrs in the daemon At the moment at startup we're calculating the attrs so we can export the HSI string property on the D-Bus interface. Running `fwupdtool security` actually gets all the security attributes at least twice! --- libfwupdplugin/fu-security-attrs.c | 15 +++++ libfwupdplugin/fu-security-attrs.h | 1 + libfwupdplugin/fwupdplugin.map | 1 + src/fu-engine.c | 93 +++++++++++++++++++----------- 4 files changed, 76 insertions(+), 34 deletions(-) diff --git a/libfwupdplugin/fu-security-attrs.c b/libfwupdplugin/fu-security-attrs.c index 0ce964bd9..29603cc72 100644 --- a/libfwupdplugin/fu-security-attrs.c +++ b/libfwupdplugin/fu-security-attrs.c @@ -107,6 +107,21 @@ fu_security_attrs_get_all (FuSecurityAttrs *self) return g_ptr_array_ref (self->attrs); } +/** + * fu_security_attrs_remove_all: + * @self: A #FuSecurityAttrs + * + * Removes all the attributes in the object. + * + * Since: 1.5.0 + **/ +void +fu_security_attrs_remove_all (FuSecurityAttrs *self) +{ + g_return_if_fail (FU_IS_SECURITY_ATTRS (self)); + return g_ptr_array_set_size (self->attrs, 0); +} + /** * fu_security_attrs_calculate_hsi: * @self: A #FuSecurityAttrs diff --git a/libfwupdplugin/fu-security-attrs.h b/libfwupdplugin/fu-security-attrs.h index fbd55cb64..a65a6d7ff 100644 --- a/libfwupdplugin/fu-security-attrs.h +++ b/libfwupdplugin/fu-security-attrs.h @@ -16,3 +16,4 @@ G_DECLARE_FINAL_TYPE (FuSecurityAttrs, fu_security_attrs, FU, SECURITY_ATTRS, GO void fu_security_attrs_append (FuSecurityAttrs *self, FwupdSecurityAttr *attr); +void fu_security_attrs_remove_all (FuSecurityAttrs *self); diff --git a/libfwupdplugin/fwupdplugin.map b/libfwupdplugin/fwupdplugin.map index addabb390..7ec5a30c2 100644 --- a/libfwupdplugin/fwupdplugin.map +++ b/libfwupdplugin/fwupdplugin.map @@ -609,6 +609,7 @@ LIBFWUPDPLUGIN_1.5.0 { fu_security_attrs_get_all; fu_security_attrs_get_type; fu_security_attrs_new; + fu_security_attrs_remove_all; fu_security_attrs_to_variant; local: *; } LIBFWUPDPLUGIN_1.4.5; diff --git a/src/fu-engine.c b/src/fu-engine.c index 8aea930f8..ffed53799 100644 --- a/src/fu-engine.c +++ b/src/fu-engine.c @@ -69,6 +69,7 @@ #endif static void fu_engine_finalize (GObject *obj); +static void fu_engine_ensure_security_attrs (FuEngine *self); struct _FuEngine { @@ -107,7 +108,7 @@ struct _FuEngine JcatContext *jcat_context; gboolean loaded; gchar *host_security_id; - gboolean host_security_id_valid; + FuSecurityAttrs *host_security_attrs; }; enum { @@ -142,7 +143,8 @@ fu_engine_emit_changed (FuEngine *self) static void fu_engine_emit_device_changed (FuEngine *self, FuDevice *device) { - self->host_security_id_valid = FALSE; + /* invalidate host security attributes */ + g_clear_pointer (&self->host_security_id, g_free); g_signal_emit (self, signals[SIGNAL_DEVICE_CHANGED], 0, device); } @@ -3318,6 +3320,9 @@ fu_engine_remote_list_changed_cb (FuRemoteList *remote_list, FuEngine *self) /* set device properties from the metadata */ fu_engine_md_refresh_devices (self); + /* invalidate host security attributes */ + g_clear_pointer (&self->host_security_id, g_free); + /* make the UI update */ fu_engine_emit_changed (self); } @@ -3546,7 +3551,14 @@ fu_engine_update_metadata_bytes (FuEngine *self, const gchar *remote_id, } if (!fu_engine_load_metadata_store (self, FU_ENGINE_LOAD_FLAG_NONE, error)) return FALSE; + + /* refresh SUPPORTED flag on devices */ fu_engine_md_refresh_devices (self); + + /* invalidate host security attributes */ + g_clear_pointer (&self->host_security_id, g_free); + + /* make the UI update */ fu_engine_emit_changed (self); return TRUE; } @@ -3991,13 +4003,13 @@ fu_engine_get_devices_by_guid (FuEngine *self, const gchar *guid, GError **error static void fu_engine_get_history_set_hsi_attrs (FuEngine *self, FuDevice *device) { - g_autofree gchar *host_security_id = NULL; - g_autoptr(FuSecurityAttrs) attrs = NULL; g_autoptr(GPtrArray) vals = NULL; + /* ensure up to date */ + fu_engine_ensure_security_attrs (self); + /* add attributes */ - attrs = fu_engine_get_host_security_attrs (self); - vals = fu_security_attrs_get_all (attrs); + vals = fu_security_attrs_get_all (self->host_security_attrs); for (guint i = 0; i < vals->len; i++) { FwupdSecurityAttr *attr = g_ptr_array_index (vals, i); const gchar *tmp; @@ -4006,8 +4018,7 @@ fu_engine_get_history_set_hsi_attrs (FuEngine *self, FuDevice *device) } /* computed value */ - host_security_id = fu_security_attrs_calculate_hsi (attrs, FU_SECURITY_ATTRS_FLAG_ADD_VERSION); - fu_device_set_metadata (device, "HSI", host_security_id); + fu_device_set_metadata (device, "HSI", self->host_security_id); } /** @@ -5142,6 +5153,11 @@ static void fu_engine_plugin_security_changed_cb (FuPlugin *plugin, gpointer user_data) { FuEngine *self = FU_ENGINE (user_data); + + /* invalidate host security attributes */ + g_clear_pointer (&self->host_security_id, g_free); + + /* make UI refresh */ fu_engine_emit_changed (self); } @@ -5508,14 +5524,15 @@ fu_engine_get_host_machine_id (FuEngine *self) } static void -fu_engine_add_security_attrs_tainted (FuEngine *self, FuSecurityAttrs *attrs) +fu_engine_ensure_security_attrs_tainted (FuEngine *self) { gboolean disabled_plugins = FALSE; GPtrArray *disabled = fu_config_get_disabled_plugins (self->config); g_autoptr(FwupdSecurityAttr) attr = fwupd_security_attr_new (FWUPD_SECURITY_ATTR_ID_FWUPD_PLUGINS); fwupd_security_attr_set_plugin (attr, "core"); fwupd_security_attr_add_flag (attr, FWUPD_SECURITY_ATTR_FLAG_RUNTIME_ISSUE); - fu_security_attrs_append (attrs, attr); + + fu_security_attrs_append (self->host_security_attrs, attr); for (guint i = 0; i < disabled->len; i++) { const gchar *name_tmp = g_ptr_array_index (disabled, i); if (g_strcmp0 (name_tmp, "test") != 0 && @@ -5539,7 +5556,7 @@ fu_engine_add_security_attrs_tainted (FuEngine *self, FuSecurityAttrs *attrs) } static void -fu_engine_add_security_attrs_supported (FuEngine *self, FuSecurityAttrs *attrs) +fu_engine_ensure_security_attrs_supported (FuEngine *self) { FwupdRelease *rel_current = NULL; FwupdRelease *rel_newest = NULL; @@ -5552,11 +5569,11 @@ fu_engine_add_security_attrs_supported (FuEngine *self, FuSecurityAttrs *attrs) attr_u = fwupd_security_attr_new (FWUPD_SECURITY_ATTR_ID_FWUPD_UPDATES); fwupd_security_attr_set_plugin (attr_u, "core"); fwupd_security_attr_add_flag (attr_u, FWUPD_SECURITY_ATTR_FLAG_RUNTIME_UPDATES); - fu_security_attrs_append (attrs, attr_u); + fu_security_attrs_append (self->host_security_attrs, attr_u); attr_a = fwupd_security_attr_new (FWUPD_SECURITY_ATTR_ID_FWUPD_ATTESTATION); fwupd_security_attr_set_plugin (attr_a, "core"); fwupd_security_attr_add_flag (attr_a, FWUPD_SECURITY_ATTR_FLAG_RUNTIME_ATTESTATION); - fu_security_attrs_append (attrs, attr_a); + fu_security_attrs_append (self->host_security_attrs, attr_a); /* get device */ device = fu_device_list_get_by_guid (self->device_list, /* main-system-firmware */ @@ -5616,25 +5633,31 @@ fu_engine_add_security_attrs_supported (FuEngine *self, FuSecurityAttrs *attrs) } } -FuSecurityAttrs * -fu_engine_get_host_security_attrs (FuEngine *self) +static void +fu_engine_ensure_security_attrs (FuEngine *self) { GPtrArray *plugins = fu_plugin_list_get_all (self->plugin_list); - g_autoptr(FuSecurityAttrs) attrs = fu_security_attrs_new (); g_autoptr(GPtrArray) items = NULL; + /* already valid */ + if (self->host_security_id != NULL) + return; + + /* clear old values */ + fu_security_attrs_remove_all (self->host_security_attrs); + /* built in */ - fu_engine_add_security_attrs_tainted (self, attrs); - fu_engine_add_security_attrs_supported (self, attrs); + fu_engine_ensure_security_attrs_tainted (self); + fu_engine_ensure_security_attrs_supported (self); /* call into plugins */ for (guint j = 0; j < plugins->len; j++) { FuPlugin *plugin_tmp = g_ptr_array_index (plugins, j); - fu_plugin_runner_add_security_attrs (plugin_tmp, attrs); + fu_plugin_runner_add_security_attrs (plugin_tmp, self->host_security_attrs); } /* set the fallback names for clients without native translations */ - items = fu_security_attrs_get_all (attrs); + items = fu_security_attrs_get_all (self->host_security_attrs); for (guint i = 0; i < items->len; i++) { FwupdSecurityAttr *attr = g_ptr_array_index (items, i); if (fwupd_security_attr_get_name (attr) == NULL) { @@ -5649,30 +5672,30 @@ fu_engine_get_host_security_attrs (FuEngine *self) } /* set the obsoletes flag for each attr */ - fu_security_attrs_depsolve (attrs); + fu_security_attrs_depsolve (self->host_security_attrs); - return g_steal_pointer (&attrs); + /* distil into one simple string */ + g_free (self->host_security_id); + self->host_security_id = fu_security_attrs_calculate_hsi (self->host_security_attrs, + FU_SECURITY_ATTRS_FLAG_ADD_VERSION); } const gchar * fu_engine_get_host_security_id (FuEngine *self) { g_return_val_if_fail (FU_IS_ENGINE (self), NULL); - - /* rebuild */ - if (!self->host_security_id_valid) { - g_autoptr(FuSecurityAttrs) attrs = NULL; - g_free (self->host_security_id); - self->host_security_id = NULL; - self->host_security_id_valid = TRUE; - attrs = fu_engine_get_host_security_attrs (self); - self->host_security_id = fu_security_attrs_calculate_hsi (attrs, - FU_SECURITY_ATTRS_FLAG_ADD_VERSION); - } - + fu_engine_ensure_security_attrs (self); return self->host_security_id; } +FuSecurityAttrs * +fu_engine_get_host_security_attrs (FuEngine *self) +{ + g_return_val_if_fail (FU_IS_ENGINE (self), NULL); + fu_engine_ensure_security_attrs (self); + return g_object_ref (self->host_security_attrs); +} + gboolean fu_engine_load_plugins (FuEngine *self, GError **error) { @@ -6337,6 +6360,7 @@ fu_engine_init (FuEngine *self) self->history = fu_history_new (); self->plugin_list = fu_plugin_list_new (); self->plugin_filter = g_ptr_array_new_with_free_func (g_free); + self->host_security_attrs = fu_security_attrs_new (); self->udev_subsystems = g_ptr_array_new_with_free_func (g_free); #ifdef HAVE_GUDEV self->udev_changed_ids = g_hash_table_new_full (g_str_hash, g_str_equal, @@ -6416,6 +6440,7 @@ fu_engine_finalize (GObject *obj) g_free (self->host_machine_id); g_free (self->host_security_id); + g_object_unref (self->host_security_attrs); g_object_unref (self->idle); g_object_unref (self->config); g_object_unref (self->remote_list); From 4d2c0f804715308d9db563300fac22e09a031ad3 Mon Sep 17 00:00:00 2001 From: Richard Hughes Date: Tue, 7 Jul 2020 12:02:30 +0100 Subject: [PATCH 248/607] trivial: Fall back to the HSI ID if the name is not available This fixes a crash if you 'ninja install' with a newer fwupd version and then run fwupdtool from an older version. --- libfwupdplugin/fu-common.c | 3 +++ src/fu-util-common.c | 2 ++ 2 files changed, 5 insertions(+) diff --git a/libfwupdplugin/fu-common.c b/libfwupdplugin/fu-common.c index 071a7e5a1..67ffd9098 100644 --- a/libfwupdplugin/fu-common.c +++ b/libfwupdplugin/fu-common.c @@ -1240,6 +1240,9 @@ fu_common_strwidth (const gchar *text) { const gchar *p = text; gsize width = 0; + + g_return_val_if_fail (text != NULL, 0); + while (*p) { gunichar c = g_utf8_get_char (p); if (g_unichar_iswide (c)) diff --git a/src/fu-util-common.c b/src/fu-util-common.c index 903d7ba06..961d305fd 100644 --- a/src/fu-util-common.c +++ b/src/fu-util-common.c @@ -1557,6 +1557,8 @@ static void fu_security_attr_append_str (FwupdSecurityAttr *attr, GString *str) { g_autofree gchar *name = fu_security_attr_get_name (attr); + if (name == NULL) + name = g_strdup (fwupd_security_attr_get_appstream_id (attr)); if (fwupd_security_attr_has_flag (attr, FWUPD_SECURITY_ATTR_FLAG_OBSOLETED)) { g_string_append (str, "✦ "); } else if (fwupd_security_attr_has_flag (attr, FWUPD_SECURITY_ATTR_FLAG_SUCCESS)) { From ef7b7b0efd4b283913cb3fbc4b27d697192c8662 Mon Sep 17 00:00:00 2001 From: Ryan Lee Date: Tue, 7 Jul 2020 20:50:58 +0900 Subject: [PATCH 249/607] ccgx: modify installation time for hp g2 dock --- plugins/ccgx/ccgx.quirk | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/plugins/ccgx/ccgx.quirk b/plugins/ccgx/ccgx.quirk index 34aeb629c..b8579cc7b 100644 --- a/plugins/ccgx/ccgx.quirk +++ b/plugins/ccgx/ccgx.quirk @@ -70,5 +70,5 @@ Summary = Dock Management Controller Device ParentGuid = USB\VID_03F0&PID_096B Name = HP USB-C/A Universal Dock G2 ImageKind = dmc-composite -InstallDuration = 125 -RemoveDelay = 107000 +InstallDuration = 180 +RemoveDelay = 162000 From 72f78dc060f82a537399ded5536cb6c0cd481cff Mon Sep 17 00:00:00 2001 From: mendel5 <60322520+mendel5@users.noreply.github.com> Date: Tue, 7 Jul 2020 21:08:16 +0200 Subject: [PATCH 250/607] fix syntax in German translation file (de.po) --- po/de.po | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/po/de.po b/po/de.po index 54099fbc3..f69da6082 100644 --- a/po/de.po +++ b/po/de.po @@ -17,7 +17,7 @@ msgstr "" "Language: de\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n" -#. more than a minute +#. TRANSLATORS: more than a minute remaining #, c-format msgid "%.0f minute remaining" msgid_plural "%.0f minutes remaining" From 77d0fd31df3dff41250d032da5a53e88935caa5f Mon Sep 17 00:00:00 2001 From: Richard Hughes Date: Tue, 7 Jul 2020 16:20:42 +0100 Subject: [PATCH 251/607] fwupd: Split out two trivial helpers --- libfwupd/fwupd-client.c | 38 +++++++++++++++++++++++++++----------- 1 file changed, 27 insertions(+), 11 deletions(-) diff --git a/libfwupd/fwupd-client.c b/libfwupd/fwupd-client.c index 8b371422d..1e280ffc2 100644 --- a/libfwupd/fwupd-client.c +++ b/libfwupd/fwupd-client.c @@ -149,6 +149,29 @@ fwupd_client_set_daemon_version (FwupdClient *client, const gchar *daemon_versio g_object_notify (G_OBJECT (client), "daemon-version"); } +static void +fwupd_client_set_status (FwupdClient *client, FwupdStatus status) +{ + FwupdClientPrivate *priv = GET_PRIVATE (client); + if (priv->status == status) + return; + priv->status = status; + g_debug ("Emitting ::status-changed() [%s]", + fwupd_status_to_string (priv->status)); + g_signal_emit (client, signals[SIGNAL_STATUS_CHANGED], 0, priv->status); + g_object_notify (G_OBJECT (client), "status"); +} + +static void +fwupd_client_set_percentage (FwupdClient *client, guint percentage) +{ + FwupdClientPrivate *priv = GET_PRIVATE (client); + if (priv->percentage == percentage) + return; + priv->percentage = percentage; + g_object_notify (G_OBJECT (client), "percentage"); +} + static void fwupd_client_properties_changed_cb (GDBusProxy *proxy, GVariant *changed_properties, @@ -163,13 +186,8 @@ fwupd_client_properties_changed_cb (GDBusProxy *proxy, if (g_variant_dict_contains (dict, "Status")) { g_autoptr(GVariant) val = NULL; val = g_dbus_proxy_get_cached_property (proxy, "Status"); - if (val != NULL) { - priv->status = g_variant_get_uint32 (val); - g_debug ("Emitting ::status-changed() [%s]", - fwupd_status_to_string (priv->status)); - g_signal_emit (client, signals[SIGNAL_STATUS_CHANGED], 0, priv->status); - g_object_notify (G_OBJECT (client), "status"); - } + if (val != NULL) + fwupd_client_set_status (client, g_variant_get_uint32 (val)); } if (g_variant_dict_contains (dict, "Tainted")) { g_autoptr(GVariant) val = NULL; @@ -190,10 +208,8 @@ fwupd_client_properties_changed_cb (GDBusProxy *proxy, if (g_variant_dict_contains (dict, "Percentage")) { g_autoptr(GVariant) val = NULL; val = g_dbus_proxy_get_cached_property (proxy, "Percentage"); - if (val != NULL) { - priv->percentage = g_variant_get_uint32 (val); - g_object_notify (G_OBJECT (client), "percentage"); - } + if (val != NULL) + fwupd_client_set_percentage (client, g_variant_get_uint32 (val)); } if (g_variant_dict_contains (dict, "DaemonVersion")) { g_autoptr(GVariant) val = NULL; From 9b6d61638329789c3d6ba53e5630e82e38ba5e29 Mon Sep 17 00:00:00 2001 From: Richard Hughes Date: Tue, 7 Jul 2020 16:24:57 +0100 Subject: [PATCH 252/607] fwupd: Export fwupd_client_download_bytes() into the client library The logic here is that we can use one central session for all client actions. Also, set the user agent for the *runtime* version of fwupd -- it's the runtime version we use when checking capabilities, rather than the built-against version. This would also explain why there are so many very obsolete versions of fwupd being recorded on the LVFS... --- libfwupd/fwupd-client.c | 354 +++++++++++++++++++++++++++++++- libfwupd/fwupd-client.h | 43 ++++ libfwupd/fwupd-common-private.h | 1 + libfwupd/fwupd-common.c | 9 +- libfwupd/fwupd-common.h | 3 +- libfwupd/fwupd.map | 4 + src/fu-util-common.c | 102 ++------- src/fu-util-common.h | 3 +- src/fu-util.c | 173 +++------------- 9 files changed, 454 insertions(+), 238 deletions(-) diff --git a/libfwupd/fwupd-client.c b/libfwupd/fwupd-client.c index 1e280ffc2..3f0af25c0 100644 --- a/libfwupd/fwupd-client.c +++ b/libfwupd/fwupd-client.c @@ -8,6 +8,7 @@ #include #include +#include #ifdef HAVE_GIO_UNIX #include #endif @@ -18,7 +19,7 @@ #include #include "fwupd-client.h" -#include "fwupd-common.h" +#include "fwupd-common-private.h" #include "fwupd-deprecated.h" #include "fwupd-enums.h" #include "fwupd-error.h" @@ -49,6 +50,8 @@ typedef struct { gchar *host_security_id; GDBusConnection *conn; GDBusProxy *proxy; + SoupSession *soup_session; + gchar *user_agent; } FwupdClientPrivate; enum { @@ -66,6 +69,7 @@ enum { PROP_PERCENTAGE, PROP_DAEMON_VERSION, PROP_TAINTED, + PROP_SOUP_SESSION, PROP_HOST_PRODUCT, PROP_HOST_MACHINE_ID, PROP_HOST_SECURITY_ID, @@ -274,6 +278,75 @@ fwupd_client_signal_cb (GDBusProxy *proxy, g_debug ("Unknown signal name '%s' from %s", signal_name, sender_name); } +static gboolean +fwupd_client_ensure_networking (FwupdClient *client, GError **error) +{ + FwupdClientPrivate *priv = GET_PRIVATE (client); + const gchar *http_proxy; + g_autoptr(SoupSession) session = NULL; + + /* already exists */ + if (priv->soup_session != NULL) + return TRUE; + + /* check the user agent is sane */ + if (priv->user_agent == NULL) { + g_set_error_literal (error, + FWUPD_ERROR, + FWUPD_ERROR_INTERNAL, + "user agent unset"); + return FALSE; + } + if (g_strstr_len (priv->user_agent, -1, "fwupd/") == NULL) { + g_set_error_literal (error, + FWUPD_ERROR, + FWUPD_ERROR_INTERNAL, + "user agent unsuitable; fwupd version required"); + return FALSE; + } + + /* create the soup session */ + session = soup_session_new_with_options (SOUP_SESSION_USER_AGENT, priv->user_agent, + SOUP_SESSION_TIMEOUT, 60, + NULL); + if (session == NULL) { + g_set_error_literal (error, + FWUPD_ERROR, + FWUPD_ERROR_INTERNAL, + "failed to setup networking"); + return FALSE; + } + + /* relax the SSL checks for broken corporate proxies */ + if (g_getenv ("DISABLE_SSL_STRICT") != NULL) + g_object_set (session, SOUP_SESSION_SSL_STRICT, FALSE, NULL); + + /* set the proxy */ + http_proxy = g_getenv ("https_proxy"); + if (http_proxy == NULL) + http_proxy = g_getenv ("HTTPS_PROXY"); + if (http_proxy == NULL) + http_proxy = g_getenv ("http_proxy"); + if (http_proxy == NULL) + http_proxy = g_getenv ("HTTP_PROXY"); + if (http_proxy != NULL && strlen (http_proxy) > 0) { + g_autoptr(SoupURI) proxy_uri = soup_uri_new (http_proxy); + if (proxy_uri == NULL) { + g_set_error (error, + FWUPD_ERROR, + FWUPD_ERROR_INTERNAL, + "invalid proxy URI: %s", http_proxy); + return FALSE; + } + g_object_set (session, SOUP_SESSION_PROXY_URI, proxy_uri, NULL); + } + + /* this disables the double-compression of the firmware.xml.gz file */ + soup_session_remove_feature_by_type (session, SOUP_TYPE_CONTENT_DECODER); + priv->soup_session = g_steal_pointer (&session); + return TRUE; +} + /** * fwupd_client_connect: * @client: A #FwupdClient @@ -2055,6 +2128,265 @@ fwupd_client_get_remote_by_id (FwupdClient *client, return g_object_ref (remote); } +/** + * fwupd_client_set_user_agent: + * @client: A #FwupdClient + * @user_agent: the user agent ID, e.g. `gnome-software/3.34.1` + * + * Manually sets the user agent that is used for downloading. The user agent + * should contain the runtime version of fwupd somewhere in the provided string. + * + * Since: 1.4.5 + **/ +void +fwupd_client_set_user_agent (FwupdClient *client, const gchar *user_agent) +{ + FwupdClientPrivate *priv = GET_PRIVATE (client); + g_return_if_fail (FWUPD_IS_CLIENT (client)); + g_return_if_fail (user_agent != NULL); + g_free (priv->user_agent); + priv->user_agent = g_strdup (user_agent); +} + +/** + * fwupd_client_set_user_agent_for_package: + * @client: A #FwupdClient + * @package_name: client program name, e.g. "gnome-software" + * @package_version: client program version, e.g. "3.28.1" + * + * Builds a user-agent to use for the download. + * + * Supplying harmless details to the server means it knows more about each + * client. This allows the web service to respond in a different way, for + * instance sending a different metadata file for old versions of fwupd, or + * returning an error for Solaris machines. + * + * Before freaking out about theoretical privacy implications, much more data + * than this is sent to each and every website you visit. + * + * Since: 1.4.5 + **/ +void +fwupd_client_set_user_agent_for_package (FwupdClient *client, + const gchar *package_name, + const gchar *package_version) +{ + FwupdClientPrivate *priv = GET_PRIVATE (client); + GString *str = g_string_new (NULL); + g_autofree gchar *system = NULL; + + g_return_if_fail (FWUPD_IS_CLIENT (client)); + g_return_if_fail (package_name != NULL); + g_return_if_fail (package_version != NULL); + + /* application name and version */ + g_string_append_printf (str, "%s/%s", package_name, package_version); + + /* system information */ + system = fwupd_build_user_agent_system (); + if (system != NULL) + g_string_append_printf (str, " (%s)", system); + + /* platform, which in our case is just fwupd */ + if (g_strcmp0 (package_name, "fwupd") != 0) + g_string_append_printf (str, " fwupd/%s", priv->daemon_version); + + /* success */ + g_free (priv->user_agent); + priv->user_agent = g_string_free (str, FALSE); +} + + +static void +fwupd_client_download_chunk_cb (SoupMessage *msg, SoupBuffer *chunk, gpointer user_data) +{ + guint percentage; + goffset header_size; + goffset body_length; + FwupdClient *client = FWUPD_CLIENT (user_data); + + /* if it's returning "Found" or an error, ignore the percentage */ + if (msg->status_code != SOUP_STATUS_OK) { + g_debug ("ignoring status code %u (%s)", + msg->status_code, msg->reason_phrase); + return; + } + + /* get data */ + body_length = msg->response_body->length; + header_size = soup_message_headers_get_content_length (msg->response_headers); + if (header_size < body_length) + return; + + /* calculate percentage */ + percentage = (guint) ((100 * body_length) / header_size); + g_debug ("progress: %u%%", percentage); + fwupd_client_set_status (client, FWUPD_STATUS_DOWNLOADING); + fwupd_client_set_percentage (client, percentage); +} + +/** + * fwupd_client_download_bytes: + * @client: A #FwupdClient + * @url: the remote URL + * @flags: #FwupdClientDownloadFlags, e.g. %FWUPD_CLIENT_DOWNLOAD_FLAG_NONE + * @cancellable: the #GCancellable, or %NULL + * @error: the #GError, or %NULL + * + * Downloads data from a remote server. The fwupd_client_set_user_agent() function + * should be called before this method is used. + * + * Returns: (transfer full): downloaded data, or %NULL for error + * + * Since: 1.4.5 + **/ +GBytes * +fwupd_client_download_bytes (FwupdClient *client, + const gchar *url, + FwupdClientDownloadFlags flags, + GCancellable *cancellable, + GError **error) +{ + FwupdClientPrivate *priv = GET_PRIVATE (client); + guint status_code; + g_autoptr(SoupMessage) msg = NULL; + g_autoptr(SoupURI) uri = NULL; + + g_return_val_if_fail (FWUPD_IS_CLIENT (client), NULL); + g_return_val_if_fail (url != NULL, NULL); + g_return_val_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable), NULL); + g_return_val_if_fail (error == NULL || *error == NULL, NULL); + + /* ensure networking set up */ + if (!fwupd_client_ensure_networking (client, error)) + return NULL; + + /* download data */ + g_debug ("downloading %s", url); + uri = soup_uri_new (url); + msg = soup_message_new_from_uri (SOUP_METHOD_GET, uri); + if (msg == NULL) { + g_set_error (error, + FWUPD_ERROR, + FWUPD_ERROR_INVALID_FILE, + "Failed to parse URI %s", url); + return NULL; + } + g_signal_connect (msg, "got-chunk", + G_CALLBACK (fwupd_client_download_chunk_cb), + client); + status_code = soup_session_send_message (priv->soup_session, msg); + fwupd_client_set_status (client, FWUPD_STATUS_IDLE); + if (status_code == 429) { + g_autofree gchar *str = g_strndup (msg->response_body->data, + msg->response_body->length); + if (g_strcmp0 (str, "Too Many Requests") == 0) { + g_set_error (error, + FWUPD_ERROR, + FWUPD_ERROR_INVALID_FILE, + "Failed to download due to server limit"); + return NULL; + } + g_set_error (error, + FWUPD_ERROR, + FWUPD_ERROR_INVALID_FILE, + "Failed to download due to server limit: %s", str); + return NULL; + } + if (status_code != SOUP_STATUS_OK) { + g_set_error (error, + FWUPD_ERROR, + FWUPD_ERROR_INVALID_FILE, + "Failed to download %s: %s", + url, soup_status_get_phrase (status_code)); + return NULL; + } + + /* success */ + return g_bytes_new (msg->response_body->data, msg->response_body->length); +} + +/** + * fwupd_client_upload_bytes: + * @client: A #FwupdClient + * @url: the remote URL + * @payload: payload string + * @signature: (nullable): signature string + * @flags: #FwupdClientDownloadFlags, e.g. %FWUPD_CLIENT_DOWNLOAD_FLAG_NONE + * @cancellable: the #GCancellable, or %NULL + * @error: the #GError, or %NULL + * + * Uploads data to a remote server. The fwupd_client_set_user_agent() function + * should be called before this method is used. + * + * Returns: (transfer full): downloaded data, or %NULL for error + * + * Since: 1.4.5 + **/ +GBytes * +fwupd_client_upload_bytes (FwupdClient *client, + const gchar *url, + const gchar *payload, + const gchar *signature, + FwupdClientUploadFlags flags, + GCancellable *cancellable, + GError **error) +{ + FwupdClientPrivate *priv = GET_PRIVATE (client); + guint status_code; + g_autoptr(SoupMessage) msg = NULL; + g_autoptr(SoupURI) uri = NULL; + + g_return_val_if_fail (FWUPD_IS_CLIENT (client), NULL); + g_return_val_if_fail (url != NULL, NULL); + g_return_val_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable), NULL); + g_return_val_if_fail (error == NULL || *error == NULL, NULL); + + /* ensure networking set up */ + if (!fwupd_client_ensure_networking (client, error)) + return NULL; + + /* build message */ + if ((flags | FWUPD_CLIENT_UPLOAD_FLAG_ALWAYS_MULTIPART) > 0 || + signature != NULL) { + g_autoptr(SoupMultipart) mp = NULL; + mp = soup_multipart_new (SOUP_FORM_MIME_TYPE_MULTIPART); + soup_multipart_append_form_string (mp, "payload", payload); + if (signature != NULL) + soup_multipart_append_form_string (mp, "signature", signature); + msg = soup_form_request_new_from_multipart (url, mp); + } else { + msg = soup_message_new (SOUP_METHOD_POST, url); + soup_message_set_request (msg, "application/json; charset=utf-8", + SOUP_MEMORY_COPY, payload, strlen (payload)); + } + + /* POST request */ + if (msg == NULL) { + g_set_error (error, + FWUPD_ERROR, + FWUPD_ERROR_INVALID_FILE, + "Failed to parse URI %s", url); + return NULL; + } + g_debug ("uploading to %s", url); + status_code = soup_session_send_message (priv->soup_session, msg); + g_debug ("server returned: %s", msg->response_body->data); + + /* fall back to HTTP status codes in case the server is offline */ + if (!SOUP_STATUS_IS_SUCCESSFUL (status_code)) { + g_set_error (error, + FWUPD_ERROR, + FWUPD_ERROR_INVALID_FILE, + "Failed to upllooad to %s: %s", + url, soup_status_get_phrase (status_code)); + return NULL; + } + + /* success */ + return g_bytes_new (msg->response_body->data, msg->response_body->length); +} + static void fwupd_client_get_property (GObject *object, guint prop_id, GValue *value, GParamSpec *pspec) @@ -2069,6 +2401,9 @@ fwupd_client_get_property (GObject *object, guint prop_id, case PROP_TAINTED: g_value_set_boolean (value, priv->tainted); break; + case PROP_SOUP_SESSION: + g_value_set_object (value, priv->soup_session); + break; case PROP_PERCENTAGE: g_value_set_uint (value, priv->percentage); break; @@ -2107,6 +2442,9 @@ fwupd_client_set_property (GObject *object, guint prop_id, case PROP_PERCENTAGE: priv->percentage = g_value_get_uint (value); break; + case PROP_SOUP_SESSION: + g_set_object (&priv->soup_session, g_value_get_object (value)); + break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); break; @@ -2263,6 +2601,17 @@ fwupd_client_class_init (FwupdClientClass *klass) NULL, G_PARAM_READABLE | G_PARAM_STATIC_NAME); g_object_class_install_property (object_class, PROP_DAEMON_VERSION, pspec); + /** + * FwupdClient:soup-session: + * + * The libsoup session. + * + * Since: 1.4.5 + */ + pspec = g_param_spec_object ("soup-session", NULL, NULL, SOUP_TYPE_SESSION, + G_PARAM_READWRITE | G_PARAM_STATIC_NAME); + g_object_class_install_property (object_class, PROP_SOUP_SESSION, pspec); + /** * FwupdClient:host-product: * @@ -2308,6 +2657,7 @@ fwupd_client_finalize (GObject *object) FwupdClient *client = FWUPD_CLIENT (object); FwupdClientPrivate *priv = GET_PRIVATE (client); + g_free (priv->user_agent); g_free (priv->daemon_version); g_free (priv->host_product); g_free (priv->host_machine_id); @@ -2316,6 +2666,8 @@ fwupd_client_finalize (GObject *object) g_object_unref (priv->conn); if (priv->proxy != NULL) g_object_unref (priv->proxy); + if (priv->soup_session != NULL) + g_object_unref (priv->soup_session); G_OBJECT_CLASS (fwupd_client_parent_class)->finalize (object); } diff --git a/libfwupd/fwupd-client.h b/libfwupd/fwupd-client.h index 3b3649522..83aba76e5 100644 --- a/libfwupd/fwupd-client.h +++ b/libfwupd/fwupd-client.h @@ -40,6 +40,32 @@ struct _FwupdClientClass void (*_fwupd_reserved7) (void); }; +/** + * FwupdClientDownloadFlags: + * @FWUPD_CLIENT_DOWNLOAD_FLAG_NONE: No flags set + * + * The options to use for downloading. + **/ +typedef enum { + FWUPD_CLIENT_DOWNLOAD_FLAG_NONE = 0, /* Since: 1.4.5 */ + /*< private >*/ + FWUPD_CLIENT_DOWNLOAD_FLAG_LAST +} FwupdClientDownloadFlags; + +/** + * FwupdClientUploadFlags: + * @FWUPD_CLIENT_UPLOAD_FLAG_NONE: No flags set + * @FWUPD_CLIENT_UPLOAD_FLAG_ALWAYS_MULTIPART: Always use multipart/form-data + * + * The options to use for uploading. + **/ +typedef enum { + FWUPD_CLIENT_UPLOAD_FLAG_NONE = 0, /* Since: 1.4.5 */ + FWUPD_CLIENT_UPLOAD_FLAG_ALWAYS_MULTIPART = 1 << 0, /* Since: 1.4.5 */ + /*< private >*/ + FWUPD_CLIENT_UPLOAD_FLAG_LAST +} FwupdClientUploadFlags; + FwupdClient *fwupd_client_new (void); gboolean fwupd_client_connect (FwupdClient *client, GCancellable *cancellable, @@ -166,5 +192,22 @@ gboolean fwupd_client_set_feature_flags (FwupdClient *client, FwupdFeatureFlags feature_flags, GCancellable *cancellable, GError **error); +void fwupd_client_set_user_agent (FwupdClient *client, + const gchar *user_agent); +void fwupd_client_set_user_agent_for_package(FwupdClient *client, + const gchar *package_name, + const gchar *package_version); +GBytes *fwupd_client_download_bytes (FwupdClient *client, + const gchar *url, + FwupdClientDownloadFlags flags, + GCancellable *cancellable, + GError **error); +GBytes *fwupd_client_upload_bytes (FwupdClient *client, + const gchar *url, + const gchar *payload, + const gchar *signature, + FwupdClientUploadFlags flags, + GCancellable *cancellable, + GError **error); G_END_DECLS diff --git a/libfwupd/fwupd-common-private.h b/libfwupd/fwupd-common-private.h index d899de562..9423468b5 100644 --- a/libfwupd/fwupd-common-private.h +++ b/libfwupd/fwupd-common-private.h @@ -15,5 +15,6 @@ G_BEGIN_DECLS gchar *fwupd_checksum_format_for_display (const gchar *checksum); GVariant *fwupd_hash_kv_to_variant (GHashTable *hash); GHashTable *fwupd_variant_to_hash_kv (GVariant *dict); +gchar *fwupd_build_user_agent_system (void); G_END_DECLS diff --git a/libfwupd/fwupd-common.c b/libfwupd/fwupd-common.c index dfd9cb6d5..b938d523c 100644 --- a/libfwupd/fwupd-common.c +++ b/libfwupd/fwupd-common.c @@ -230,7 +230,10 @@ fwupd_build_user_agent_os_release (void) return g_strjoinv (" ", (gchar **) ids_os->pdata); } -static gchar * +/** + * fwupd_build_user_agent_system: (skip): + **/ +gchar * fwupd_build_user_agent_system (void) { #ifdef HAVE_UTSNAME_H @@ -288,6 +291,10 @@ fwupd_build_user_agent_system (void) * Before freaking out about theoretical privacy implications, much more data * than this is sent to each and every website you visit. * + * Rather that using this function you should use fwupd_client_set_user_agent_for_package() + * which uses the *runtime* version of the daemon rather than the *build-time* + * version. + * * Returns: a string, e.g. `foo/0.1 (Linux i386 4.14.5; en; Fedora 27) fwupd/1.0.3` * * Since: 1.0.3 diff --git a/libfwupd/fwupd-common.h b/libfwupd/fwupd-common.h index e4409ac74..055da6a5c 100644 --- a/libfwupd/fwupd-common.h +++ b/libfwupd/fwupd-common.h @@ -42,7 +42,8 @@ const gchar *fwupd_checksum_get_by_kind (GPtrArray *checksums, GChecksumType kind); GChecksumType fwupd_checksum_guess_kind (const gchar *checksum); gchar *fwupd_build_user_agent (const gchar *package_name, - const gchar *package_version); + const gchar *package_version) +G_DEPRECATED_FOR(fwupd_client_set_user_agent_for_package); gchar *fwupd_build_machine_id (const gchar *salt, GError **error); GHashTable *fwupd_get_os_release (GError **error); diff --git a/libfwupd/fwupd.map b/libfwupd/fwupd.map index 09730999b..6e793161d 100644 --- a/libfwupd/fwupd.map +++ b/libfwupd/fwupd.map @@ -449,7 +449,11 @@ LIBFWUPD_1.4.1 { LIBFWUPD_1.4.5 { global: + fwupd_client_download_bytes; fwupd_client_set_feature_flags; + fwupd_client_set_user_agent; + fwupd_client_set_user_agent_for_package; + fwupd_client_upload_bytes; fwupd_device_get_update_image; fwupd_device_set_update_image; fwupd_feature_flag_from_string; diff --git a/src/fu-util-common.c b/src/fu-util-common.c index 961d305fd..7a859c6b9 100644 --- a/src/fu-util-common.c +++ b/src/fu-util-common.c @@ -585,55 +585,6 @@ fu_util_cmd_array_to_string (GPtrArray *array) return g_string_free (string, FALSE); } -SoupSession * -fu_util_setup_networking (GError **error) -{ - const gchar *http_proxy; - g_autofree gchar *user_agent = NULL; - g_autoptr(SoupSession) session = NULL; - - /* create the soup session */ - user_agent = fwupd_build_user_agent (PACKAGE_NAME, PACKAGE_VERSION); - session = soup_session_new_with_options (SOUP_SESSION_USER_AGENT, user_agent, - SOUP_SESSION_TIMEOUT, 60, - NULL); - if (session == NULL) { - g_set_error_literal (error, - FWUPD_ERROR, - FWUPD_ERROR_INTERNAL, - "failed to setup networking"); - return NULL; - } - - /* relax the SSL checks for broken corporate proxies */ - if (g_getenv ("DISABLE_SSL_STRICT") != NULL) - g_object_set (session, SOUP_SESSION_SSL_STRICT, FALSE, NULL); - - /* set the proxy */ - http_proxy = g_getenv ("https_proxy"); - if (http_proxy == NULL) - http_proxy = g_getenv ("HTTPS_PROXY"); - if (http_proxy == NULL) - http_proxy = g_getenv ("http_proxy"); - if (http_proxy == NULL) - http_proxy = g_getenv ("HTTP_PROXY"); - if (http_proxy != NULL && strlen (http_proxy) > 0) { - g_autoptr(SoupURI) proxy_uri = soup_uri_new (http_proxy); - if (proxy_uri == NULL) { - g_set_error (error, - FWUPD_ERROR, - FWUPD_ERROR_INTERNAL, - "invalid proxy URI: %s", http_proxy); - return NULL; - } - g_object_set (session, SOUP_SESSION_PROXY_URI, proxy_uri, NULL); - } - - /* this disables the double-compression of the firmware.xml.gz file */ - soup_session_remove_feature_by_type (session, SOUP_TYPE_CONTENT_DECODER); - return g_steal_pointer (&session); -} - gchar * fu_util_release_get_name (FwupdRelease *release) { @@ -1670,7 +1621,7 @@ fu_util_security_attrs_to_string (GPtrArray *attrs) } gboolean -fu_util_send_report (SoupSession *soup_session, +fu_util_send_report (FwupdClient *client, const gchar *report_uri, const gchar *data, const gchar *sig, @@ -1678,52 +1629,39 @@ fu_util_send_report (SoupSession *soup_session, GError **error) { const gchar *server_msg = NULL; - guint status_code; JsonNode *json_root; JsonObject *json_object; + g_autofree gchar *str = NULL; + g_autoptr(GBytes) upload_response = NULL; g_autoptr(JsonParser) json_parser = NULL; - g_autoptr(SoupMessage) msg = NULL; /* POST request */ - if (sig != NULL) { - g_autoptr(SoupMultipart) mp = NULL; - mp = soup_multipart_new (SOUP_FORM_MIME_TYPE_MULTIPART); - soup_multipart_append_form_string (mp, "payload", data); - soup_multipart_append_form_string (mp, "signature", sig); - msg = soup_form_request_new_from_multipart (report_uri, mp); - } else { - msg = soup_message_new (SOUP_METHOD_POST, report_uri); - soup_message_set_request (msg, "application/json; charset=utf-8", - SOUP_MEMORY_COPY, data, strlen (data)); - } - status_code = soup_session_send_message (soup_session, msg); - g_debug ("server returned: %s", msg->response_body->data); + upload_response = fwupd_client_upload_bytes (client, report_uri, data, sig, + FWUPD_CLIENT_UPLOAD_FLAG_NONE, + NULL, error); + if (upload_response == NULL) + return FALSE; /* server returned nothing, and probably exploded in a ball of flames */ - if (msg->response_body->length == 0) { + if (g_bytes_get_size (upload_response) == 0) { g_set_error (error, FWUPD_ERROR, FWUPD_ERROR_INVALID_FILE, - "Failed to upload to %s: %s", - report_uri, soup_status_get_phrase (status_code)); + "Failed to upload to %s", + report_uri); return FALSE; } /* parse JSON reply */ json_parser = json_parser_new (); - if (!json_parser_load_from_data (json_parser, - msg->response_body->data, - msg->response_body->length, - error)) { - g_autofree gchar *str = g_strndup (msg->response_body->data, - msg->response_body->length); + str = g_strndup (g_bytes_get_data (upload_response, NULL), + g_bytes_get_size (upload_response)); + if (!json_parser_load_from_data (json_parser, str, -1, error)) { g_prefix_error (error, "Failed to parse JSON response from '%s': ", str); return FALSE; } json_root = json_parser_get_root (json_parser); if (json_root == NULL) { - g_autofree gchar *str = g_strndup (msg->response_body->data, - msg->response_body->length); g_set_error (error, FWUPD_ERROR, FWUPD_ERROR_PERMISSION_DENIED, @@ -1732,8 +1670,6 @@ fu_util_send_report (SoupSession *soup_session, } json_object = json_node_get_object (json_root); if (json_object == NULL) { - g_autofree gchar *str = g_strndup (msg->response_body->data, - msg->response_body->length); g_set_error (error, FWUPD_ERROR, FWUPD_ERROR_PERMISSION_DENIED, @@ -1765,16 +1701,6 @@ fu_util_send_report (SoupSession *soup_session, } } - /* fall back to HTTP status codes in case the server is offline */ - if (!SOUP_STATUS_IS_SUCCESSFUL (status_code)) { - g_set_error (error, - FWUPD_ERROR, - FWUPD_ERROR_INVALID_FILE, - "Failed to upload to %s: %s", - report_uri, soup_status_get_phrase (status_code)); - return FALSE; - } - /* success */ return TRUE; } diff --git a/src/fu-util-common.h b/src/fu-util-common.h index 5ae35f8ea..207206f40 100644 --- a/src/fu-util-common.h +++ b/src/fu-util-common.h @@ -32,7 +32,6 @@ gboolean fu_util_prompt_for_boolean (gboolean def); void fu_util_print_tree (GNode *n, gpointer data); gboolean fu_util_is_interesting_device (FwupdDevice *dev); gchar *fu_util_get_user_cache_path (const gchar *fn); -SoupSession *fu_util_setup_networking (GError **error); gchar *fu_util_get_versions (void); void fu_util_warning_box (const gchar *str, @@ -78,7 +77,7 @@ gchar *fu_util_release_to_string (FwupdRelease *rel, gchar *fu_util_remote_to_string (FwupdRemote *remote, guint idt); gchar *fu_util_security_attrs_to_string (GPtrArray *attrs); -gboolean fu_util_send_report (SoupSession *soup_session, +gboolean fu_util_send_report (FwupdClient *client, const gchar *report_uri, const gchar *data, const gchar *sig, diff --git a/src/fu-util.c b/src/fu-util.c index d2f4a9110..ae7c189f7 100644 --- a/src/fu-util.c +++ b/src/fu-util.c @@ -57,7 +57,6 @@ struct FuUtilPrivate { GCancellable *cancellable; GMainLoop *loop; GOptionContext *context; - SoupSession *soup_session; FwupdInstallFlags flags; FwupdClient *client; FuProgressbar *progressbar; @@ -80,7 +79,7 @@ struct FuUtilPrivate { static gboolean fu_util_report_history (FuUtilPrivate *priv, gchar **values, GError **error); static gboolean fu_util_download_file (FuUtilPrivate *priv, - SoupURI *uri, + const gchar *uri_str, const gchar *fn, const gchar *checksum_expected, GError **error); @@ -576,7 +575,7 @@ fu_util_download_if_required (FuUtilPrivate *priv, const gchar *perhapsfn, GErro filename = fu_util_get_user_cache_path (perhapsfn); if (!fu_common_mkdir_parent (filename, error)) return NULL; - if (!fu_util_download_file (priv, uri, filename, NULL, error)) + if (!fu_util_download_file (priv, perhapsfn, filename, NULL, error)) return NULL; return g_steal_pointer (&filename); } @@ -719,7 +718,7 @@ fu_util_report_history_for_remote (FuUtilPrivate *priv, } /* POST request and parse reply */ - if (!fu_util_send_report (priv->soup_session, + if (!fu_util_send_report (priv->client, fwupd_remote_get_report_uri (remote), data, sig, &uri, error)) return FALSE; @@ -745,13 +744,6 @@ fu_util_report_history (FuUtilPrivate *priv, gchar **values, GError **error) g_autoptr(GPtrArray) remotes = NULL; g_autoptr(GString) str = g_string_new (NULL); - /* set up networking */ - if (priv->soup_session == NULL) { - priv->soup_session = fu_util_setup_networking (error); - if (priv->soup_session == NULL) - return FALSE; - } - /* get all devices from the history database, then filter them, * adding to a hash map of report-ids */ devices = fwupd_client_get_history (priv->client, NULL, error); @@ -1027,48 +1019,17 @@ fu_util_file_exists_with_checksum (const gchar *fn, return g_strcmp0 (checksum_expected, checksum_actual) == 0; } -static void -fu_util_download_chunk_cb (SoupMessage *msg, SoupBuffer *chunk, gpointer user_data) -{ - guint percentage; - goffset header_size; - goffset body_length; - FuUtilPrivate *priv = (FuUtilPrivate *) user_data; - - /* if it's returning "Found" or an error, ignore the percentage */ - if (msg->status_code != SOUP_STATUS_OK) { - g_debug ("ignoring status code %u (%s)", - msg->status_code, msg->reason_phrase); - return; - } - - /* get data */ - body_length = msg->response_body->length; - header_size = soup_message_headers_get_content_length (msg->response_headers); - - /* size is not known */ - if (header_size < body_length) - return; - - /* calculate percentage */ - percentage = (guint) ((100 * body_length) / header_size); - g_debug ("progress: %u%%", percentage); - fu_progressbar_update (priv->progressbar, FWUPD_STATUS_DOWNLOADING, percentage); -} - static gboolean fu_util_download_file (FuUtilPrivate *priv, - SoupURI *uri, + const gchar *uri_str, const gchar *fn, const gchar *checksum_expected, GError **error) { GChecksumType checksum_type; - guint status_code; + g_autoptr(GBytes) blob = NULL; g_autoptr(GError) error_local = NULL; g_autofree gchar *checksum_actual = NULL; - g_autofree gchar *uri_str = NULL; - g_autoptr(SoupMessage) msg = NULL; /* check if the file already exists with the right checksum */ checksum_type = fwupd_checksum_guess_kind (checksum_expected); @@ -1077,75 +1038,33 @@ fu_util_download_file (FuUtilPrivate *priv, return TRUE; } - /* set up networking */ - if (priv->soup_session == NULL) { - priv->soup_session = fu_util_setup_networking (error); - if (priv->soup_session == NULL) - return FALSE; - } - /* download data */ - uri_str = soup_uri_to_string (uri, FALSE); - g_debug ("downloading %s to %s", uri_str, fn); - msg = soup_message_new_from_uri (SOUP_METHOD_GET, uri); - if (msg == NULL) { - g_set_error (error, - FWUPD_ERROR, - FWUPD_ERROR_INVALID_FILE, - "Failed to parse URI %s", uri_str); - return FALSE; - } if (g_str_has_suffix (uri_str, ".jcat") || g_str_has_suffix (uri_str, ".asc") || g_str_has_suffix (uri_str, ".p7b") || g_str_has_suffix (uri_str, ".p7c")) { /* TRANSLATORS: downloading new signing file */ - g_print ("%s %s\n", _("Fetching signature"), uri_str); + g_print ("%s %s", _("Fetching signature"), uri_str); } else if (g_str_has_suffix (uri_str, ".gz")) { /* TRANSLATORS: downloading new metadata file */ - g_print ("%s %s\n", _("Fetching metadata"), uri_str); + g_print ("%s %s", _("Fetching metadata"), uri_str); } else if (g_str_has_suffix (uri_str, ".cab")) { /* TRANSLATORS: downloading new firmware file */ - g_print ("%s %s\n", _("Fetching firmware"), uri_str); + g_print ("%s %s", _("Fetching firmware"), uri_str); } else { /* TRANSLATORS: downloading unknown file */ - g_print ("%s %s\n", _("Fetching file"), uri_str); + g_print ("%s %s", _("Fetching file"), uri_str); } - g_signal_connect (msg, "got-chunk", - G_CALLBACK (fu_util_download_chunk_cb), priv); - status_code = soup_session_send_message (priv->soup_session, msg); g_print ("\n"); - if (status_code == 429) { - g_autofree gchar *str = g_strndup (msg->response_body->data, - msg->response_body->length); - if (g_strcmp0 (str, "Too Many Requests") == 0) { - g_set_error (error, - FWUPD_ERROR, - FWUPD_ERROR_INVALID_FILE, - /* TRANSLATORS: the server is rate-limiting downloads */ - "%s", _("Failed to download due to server limit")); - return FALSE; - } - g_set_error (error, - FWUPD_ERROR, - FWUPD_ERROR_INVALID_FILE, - "Failed to download due to server limit: %s", str); + blob = fwupd_client_download_bytes (priv->client, uri_str, + FWUPD_CLIENT_DOWNLOAD_FLAG_NONE, + priv->cancellable, error); + if (blob == NULL) return FALSE; - } - if (status_code != SOUP_STATUS_OK) { - g_set_error (error, - FWUPD_ERROR, - FWUPD_ERROR_INVALID_FILE, - "Failed to download %s: %s", - uri_str, soup_status_get_phrase (status_code)); - return FALSE; - } /* verify checksum */ if (checksum_expected != NULL) { - checksum_actual = g_compute_checksum_for_data (checksum_type, - (guchar *) msg->response_body->data, - (gsize) msg->response_body->length); + checksum_actual = g_compute_checksum_for_bytes (checksum_type, blob); if (g_strcmp0 (checksum_expected, checksum_actual) != 0) { g_set_error (error, FWUPD_ERROR, @@ -1157,18 +1076,7 @@ fu_util_download_file (FuUtilPrivate *priv, } /* save file */ - if (!g_file_set_contents (fn, - msg->response_body->data, - msg->response_body->length, - &error_local)) { - g_set_error (error, - FWUPD_ERROR, - FWUPD_ERROR_WRITE, - "Failed to save file: %s", - error_local->message); - return FALSE; - } - return TRUE; + return fu_common_set_contents_bytes (fn, blob, error); } static gboolean @@ -1182,8 +1090,6 @@ fu_util_download_metadata_for_remote (FuUtilPrivate *priv, g_autofree gchar *basename = NULL; g_autofree gchar *filename = NULL; g_autofree gchar *filename_asc = NULL; - g_autoptr(SoupURI) uri = NULL; - g_autoptr(SoupURI) uri_sig = NULL; /* download the signature */ basename_asc = g_path_get_basename (fwupd_remote_get_filename_cache_sig (remote)); @@ -1191,8 +1097,7 @@ fu_util_download_metadata_for_remote (FuUtilPrivate *priv, filename_asc = fu_util_get_user_cache_path (basename_id_asc); if (!fu_common_mkdir_parent (filename_asc, error)) return FALSE; - uri_sig = soup_uri_new (fwupd_remote_get_metadata_uri_sig (remote)); - if (!fu_util_download_file (priv, uri_sig, filename_asc, NULL, error)) + if (!fu_util_download_file (priv, fwupd_remote_get_metadata_uri_sig (remote), filename_asc, NULL, error)) return FALSE; /* find the download URI of the metadata from the JCat file */ @@ -1203,8 +1108,7 @@ fu_util_download_metadata_for_remote (FuUtilPrivate *priv, basename = g_path_get_basename (fwupd_remote_get_filename_cache (remote)); basename_id = g_strdup_printf ("%s-%s", fwupd_remote_get_id (remote), basename); filename = fu_util_get_user_cache_path (basename_id); - uri = soup_uri_new (fwupd_remote_get_metadata_uri (remote)); - if (!fu_util_download_file (priv, uri, filename, NULL, error)) + if (!fu_util_download_file (priv, fwupd_remote_get_metadata_uri (remote), filename, NULL, error)) return FALSE; /* send all this to fwupd */ @@ -1690,7 +1594,6 @@ fu_util_update_device_with_release (FuUtilPrivate *priv, const gchar *uri_tmp; g_autofree gchar *fn = NULL; g_autofree gchar *uri_str = NULL; - g_autoptr(SoupURI) uri = NULL; if (!priv->no_safety_check && !priv->assume_yes) { if (!fu_util_prompt_warning (dev, @@ -1742,8 +1645,7 @@ fu_util_update_device_with_release (FuUtilPrivate *priv, if (!fu_common_mkdir_parent (fn, error)) return FALSE; checksums = fwupd_release_get_checksums (rel); - uri = soup_uri_new (uri_str); - if (!fu_util_download_file (priv, uri, fn, + if (!fu_util_download_file (priv, uri_str, fn, fwupd_checksum_get_best (checksums), error)) return FALSE; @@ -2306,20 +2208,18 @@ fu_util_get_remote_with_security_report_uri (FuUtilPrivate *priv, GError **error static gboolean fu_util_upload_security (FuUtilPrivate *priv, GPtrArray *attrs, GError **error) { - guint status_code; GHashTableIter iter; const gchar *key; const gchar *value; g_autofree gchar *data = NULL; g_autofree gchar *sig = NULL; g_autoptr(FwupdRemote) remote = NULL; + g_autoptr(GBytes) upload_response = NULL; g_autoptr(GError) error_local = NULL; g_autoptr(GHashTable) metadata = NULL; g_autoptr(JsonBuilder) builder = NULL; g_autoptr(JsonGenerator) json_generator = NULL; g_autoptr(JsonNode) json_root = NULL; - g_autoptr(SoupMessage) msg = NULL; - g_autoptr(SoupMultipart) mp = NULL; /* can we find a remote with a security attr */ remote = fu_util_get_remote_with_security_report_uri (priv, &error_local); @@ -2351,13 +2251,6 @@ fu_util_upload_security (FuUtilPrivate *priv, GPtrArray *attrs, GError **error) } } - /* set up networking */ - if (priv->soup_session == NULL) { - priv->soup_session = fu_util_setup_networking (error); - if (priv->soup_session == NULL) - return FALSE; - } - /* get metadata */ metadata = fwupd_client_get_report_metadata (priv->client, priv->cancellable, @@ -2439,24 +2332,13 @@ fu_util_upload_security (FuUtilPrivate *priv, GPtrArray *attrs, GError **error) } /* POST request */ - mp = soup_multipart_new (SOUP_FORM_MIME_TYPE_MULTIPART); - soup_multipart_append_form_string (mp, "payload", data); - if (sig != NULL) - soup_multipart_append_form_string (mp, "signature", sig); - msg = soup_form_request_new_from_multipart (fwupd_remote_get_security_report_uri (remote), mp); - status_code = soup_session_send_message (priv->soup_session, msg); - g_debug ("server returned: %s", msg->response_body->data); - - /* fall back to HTTP status codes in case the server is offline */ - if (!SOUP_STATUS_IS_SUCCESSFUL (status_code)) { - g_set_error (error, - FWUPD_ERROR, - FWUPD_ERROR_INVALID_FILE, - "Failed to upload to %s: %s", - fwupd_remote_get_security_report_uri (remote), - soup_status_get_phrase (status_code)); + upload_response = fwupd_client_upload_bytes (priv->client, + fwupd_remote_get_security_report_uri (remote), + data, sig, + FWUPD_CLIENT_UPLOAD_FLAG_ALWAYS_MULTIPART, + priv->cancellable, error); + if (upload_response == NULL) return FALSE; - } /* TRANSLATORS: success, so say thank you to the user */ g_print ("%s\n", "Host Security ID attributes uploaded successfully, thanks!"); @@ -2539,8 +2421,6 @@ fu_util_private_free (FuUtilPrivate *priv) g_object_unref (priv->client); if (priv->current_device != NULL) g_object_unref (priv->current_device); - if (priv->soup_session != NULL) - g_object_unref (priv->soup_session); g_free (priv->current_message); g_main_loop_unref (priv->loop); g_object_unref (priv->cancellable); @@ -2962,6 +2842,9 @@ main (int argc, char *argv[]) "is no longer supported by the upstream developers!\n"); } + /* we know the runtime daemon version now */ + fwupd_client_set_user_agent_for_package (priv->client, "fwupdmgr", PACKAGE_VERSION); + /* check that we have at least this version daemon running */ if ((priv->flags & FWUPD_INSTALL_FLAG_FORCE) == 0 && !fu_util_check_daemon_version (priv, &error)) { From 907fd15e55c82aa985227c3284635ff6e228fd71 Mon Sep 17 00:00:00 2001 From: Richard Hughes Date: Wed, 8 Jul 2020 21:08:46 +0100 Subject: [PATCH 253/607] trivial: Fix two hard to translate strings --- src/fu-security-attr.c | 9 ++++++--- src/fu-util-common.c | 2 +- 2 files changed, 7 insertions(+), 4 deletions(-) diff --git a/src/fu-security-attr.c b/src/fu-security-attr.c index 0bc0c39ad..a346feee4 100644 --- a/src/fu-security-attr.c +++ b/src/fu-security-attr.c @@ -98,10 +98,13 @@ fu_security_attr_get_name (FwupdSecurityAttr *attr) const gchar *kind = fwupd_security_attr_get_metadata (attr, "kind"); if (kind != NULL) { /* TRANSLATORS: Title: %s is ME kind, e.g. CSME/TXT */ - return g_strdup_printf (_("%s override strap"), kind); + return g_strdup_printf (_("%s override"), kind); } - /* TRANSLATORS: Title: MEI = Intel Management Engine */ - return g_strdup (_("MEI override strap")); + /* TRANSLATORS: Title: MEI = Intel Management Engine, and the + * "override" is the physical PIN that can be driven to + * logic high -- luckily it is probably not accessible to + * end users on consumer boards */ + return g_strdup (_("MEI override")); } if (g_strcmp0 (appstream_id, FWUPD_SECURITY_ATTR_ID_MEI_VERSION) == 0) { /* TRANSLATORS: Title: MEI = Intel Management Engine */ diff --git a/src/fu-util-common.c b/src/fu-util-common.c index 7a859c6b9..efb2623b1 100644 --- a/src/fu-util-common.c +++ b/src/fu-util-common.c @@ -1612,7 +1612,7 @@ fu_util_security_attrs_to_string (GPtrArray *attrs) if (pcr0_help) { g_string_append_printf (str, "\n%s\n » %s\n", /* TRANSLATORS: this is more background on a security measurement problem */ - _("The TPM PCR0 differes from reconstruction."), + _("The TPM PCR0 differs from reconstruction."), "https://github.com/fwupd/fwupd/wiki/TPM-PCR0-differs-from-reconstruction"); } From a9899758128a9a3377b4d6a030ee1105ee34d712 Mon Sep 17 00:00:00 2001 From: Benson Leung Date: Fri, 3 Jul 2020 15:36:53 -0700 Subject: [PATCH 254/607] cros-ec: Update documentation to reflect fmap The file format was added last time around, so update cros-ec's documentation to reflect that fwupd now supports fmap format blobs. --- plugins/cros-ec/README.md | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/plugins/cros-ec/README.md b/plugins/cros-ec/README.md index 3d444df2e..868483d8a 100644 --- a/plugins/cros-ec/README.md +++ b/plugins/cros-ec/README.md @@ -16,10 +16,8 @@ Information about the USB update protocol is available at [2]. Firmware Format --------------- - -The plugin at the moment does not support a firmware payload, but will -support the Google firmware format used in Chrome OS firmware -known as `flashmap`[3]. +The daemon will decompress the cabinet archive and extract a firmware blob in +the Google fmap [3] file format. GUID Generation --------------- From 6472742beabe5e347cc30564f85540170dfb9cc6 Mon Sep 17 00:00:00 2001 From: Benson Leung Date: Mon, 22 Jun 2020 15:02:03 -0700 Subject: [PATCH 255/607] cros-ec: Add prepare firmware Prepare firmware by parsing it, which will be of fu_cros_ec_firmware type. --- plugins/cros-ec/fu-cros-ec-usb-device.c | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/plugins/cros-ec/fu-cros-ec-usb-device.c b/plugins/cros-ec/fu-cros-ec-usb-device.c index 811a0898e..9cf67d040 100644 --- a/plugins/cros-ec/fu-cros-ec-usb-device.c +++ b/plugins/cros-ec/fu-cros-ec-usb-device.c @@ -10,6 +10,7 @@ #include "fu-cros-ec-usb-device.h" #include "fu-cros-ec-common.h" +#include "fu-cros-ec-firmware.h" #define USB_SUBCLASS_GOOGLE_UPDATE 0x53 #define USB_PROTOCOL_GOOGLE_UPDATE 0xff @@ -316,6 +317,20 @@ fu_cros_ec_usb_device_close (FuUsbDevice *device, GError **error) return TRUE; } +static FuFirmware * +fu_cros_ec_usb_device_prepare_firmware (FuDevice *device, + GBytes *fw, + FwupdInstallFlags flags, + GError **error) +{ + g_autoptr(FuFirmware) firmware = fu_cros_ec_firmware_new (); + + fu_device_set_status (device, FWUPD_STATUS_DECOMPRESSING); + if (!fu_firmware_parse (firmware, fw, flags, error)) + return NULL; + return g_steal_pointer (&firmware); +} + static void fu_cros_ec_usb_device_init (FuCrosEcUsbDevice *device) { @@ -353,6 +368,7 @@ fu_cros_ec_usb_device_class_init (FuCrosEcUsbDeviceClass *klass) { FuDeviceClass *klass_device = FU_DEVICE_CLASS (klass); FuUsbDeviceClass *klass_usb_device = FU_USB_DEVICE_CLASS (klass); + klass_device->prepare_firmware = fu_cros_ec_usb_device_prepare_firmware; klass_device->setup = fu_cros_ec_usb_device_setup; klass_device->to_string = fu_cros_ec_usb_device_to_string; klass_usb_device->open = fu_cros_ec_usb_device_open; From befd9a420ee31f57b5714def8d3aa8a6a2b4743e Mon Sep 17 00:00:00 2001 From: Benson Leung Date: Tue, 30 Jun 2020 14:30:18 -0700 Subject: [PATCH 256/607] cros-ec: Convert cros-ec-firmware's sections to GPtrArray --- plugins/cros-ec/fu-cros-ec-firmware.c | 32 ++++++++++++++++++++------- 1 file changed, 24 insertions(+), 8 deletions(-) diff --git a/plugins/cros-ec/fu-cros-ec-firmware.c b/plugins/cros-ec/fu-cros-ec-firmware.c index 8b541d50c..9f3612085 100644 --- a/plugins/cros-ec/fu-cros-ec-firmware.c +++ b/plugins/cros-ec/fu-cros-ec-firmware.c @@ -13,9 +13,9 @@ #define MAXSECTIONS 2 struct _FuCrosEcFirmware { - FuFmapFirmware parent_instance; - struct cros_ec_version version; - FuCrosEcFirmwareSection sections[MAXSECTIONS]; + FuFmapFirmware parent_instance; + struct cros_ec_version version; + GPtrArray *sections; }; G_DEFINE_TYPE (FuCrosEcFirmware, fu_cros_ec_firmware, FU_TYPE_FMAP_FIRMWARE) @@ -31,12 +31,9 @@ fu_cros_ec_firmware_parse (FuFirmware *firmware, FuCrosEcFirmware *self = FU_CROS_EC_FIRMWARE (firmware); FuFirmware *fmap_firmware = FU_FIRMWARE (firmware); - self->sections[0].name = "RO"; - self->sections[1].name = "RW"; - - for (gsize i = 0; i < G_N_ELEMENTS (self->sections); i++) { + for (gsize i = 0; i < self->sections->len; i++) { gboolean rw = FALSE; - FuCrosEcFirmwareSection *section = &self->sections[i]; + FuCrosEcFirmwareSection *section = g_ptr_array_index (self->sections, i); const gchar *fmap_name; const gchar *fmap_fwid_name; g_autoptr(FuFirmwareImage) img = NULL; @@ -120,13 +117,32 @@ fu_cros_ec_firmware_parse (FuFirmware *firmware, static void fu_cros_ec_firmware_init (FuCrosEcFirmware *self) { + FuCrosEcFirmwareSection *section; + + self->sections = g_ptr_array_new_with_free_func (g_free); + section = g_new0 (FuCrosEcFirmwareSection, 1); + section->name = "RO"; + g_ptr_array_add (self->sections, section); + section = g_new0 (FuCrosEcFirmwareSection, 1); + section->name = "RW"; + g_ptr_array_add (self->sections, section); +} + +static void +fu_cros_ec_firmware_finalize (GObject *object) +{ + FuCrosEcFirmware *self = FU_CROS_EC_FIRMWARE (object); + g_ptr_array_free (self->sections, TRUE); + G_OBJECT_CLASS (fu_cros_ec_firmware_parent_class)->finalize (object); } static void fu_cros_ec_firmware_class_init (FuCrosEcFirmwareClass *klass) { + GObjectClass *object_class = G_OBJECT_CLASS (klass); FuFmapFirmwareClass *klass_firmware = FU_FMAP_FIRMWARE_CLASS (klass); klass_firmware->parse = fu_cros_ec_firmware_parse; + object_class->finalize = fu_cros_ec_firmware_finalize; } FuFirmware * From d0cd862acf07a2271384a30d92837375cecbdbbd Mon Sep 17 00:00:00 2001 From: Benson Leung Date: Tue, 23 Jun 2020 14:44:33 -0700 Subject: [PATCH 257/607] cros-ec: Add fu_cros_ec_firmware_pick_sections Add this to allow the usb-device to mark which section of the firmware image is writeable by setting the section's ustatus to FU_CROS_EC_FW_NEEDED. --- plugins/cros-ec/fu-cros-ec-firmware.c | 31 +++++++++++++++++++++++++ plugins/cros-ec/fu-cros-ec-firmware.h | 3 +++ plugins/cros-ec/fu-cros-ec-usb-device.c | 15 ++++++++++++ 3 files changed, 49 insertions(+) diff --git a/plugins/cros-ec/fu-cros-ec-firmware.c b/plugins/cros-ec/fu-cros-ec-firmware.c index 9f3612085..f49629653 100644 --- a/plugins/cros-ec/fu-cros-ec-firmware.c +++ b/plugins/cros-ec/fu-cros-ec-firmware.c @@ -20,6 +20,37 @@ struct _FuCrosEcFirmware { G_DEFINE_TYPE (FuCrosEcFirmware, fu_cros_ec_firmware, FU_TYPE_FMAP_FIRMWARE) +gboolean +fu_cros_ec_firmware_pick_sections (FuCrosEcFirmware *self, + guint32 writeable_offset, + GError **error) +{ + gboolean found = FALSE; + + for (gsize i = 0; i < self->sections->len; i++) { + FuCrosEcFirmwareSection *section = g_ptr_array_index (self->sections, i); + guint32 offset = section->offset; + + if (offset != writeable_offset) + continue; + + section->ustatus = FU_CROS_EC_FW_NEEDED; + found = TRUE; + } + + if (!found) { + g_set_error (error, + G_IO_ERROR, + G_IO_ERROR_INVALID_DATA, + "no writeable section found with offset: 0x%x", + writeable_offset); + return FALSE; + } + + /* success */ + return TRUE; +} + static gboolean fu_cros_ec_firmware_parse (FuFirmware *firmware, GBytes *fw, diff --git a/plugins/cros-ec/fu-cros-ec-firmware.h b/plugins/cros-ec/fu-cros-ec-firmware.h index 253c3c10a..b0d1f6052 100644 --- a/plugins/cros-ec/fu-cros-ec-firmware.h +++ b/plugins/cros-ec/fu-cros-ec-firmware.h @@ -38,4 +38,7 @@ typedef struct { guint32 key_version; } FuCrosEcFirmwareSection; +gboolean fu_cros_ec_firmware_pick_sections (FuCrosEcFirmware *self, + guint32 writeable_offset, + GError **error); FuFirmware *fu_cros_ec_firmware_new (void); diff --git a/plugins/cros-ec/fu-cros-ec-usb-device.c b/plugins/cros-ec/fu-cros-ec-usb-device.c index 9cf67d040..ba589255d 100644 --- a/plugins/cros-ec/fu-cros-ec-usb-device.c +++ b/plugins/cros-ec/fu-cros-ec-usb-device.c @@ -27,6 +27,7 @@ struct _FuCrosEcUsbDevice { guint16 chunk_len; /* wMaxPacketSize */ struct first_response_pdu targ; + guint32 writeable_offset; guint16 protocol_version; guint16 header_type; struct cros_ec_version version; @@ -272,6 +273,7 @@ fu_cros_ec_usb_device_setup (FuDevice *device, GError **error) return FALSE; } + self->writeable_offset = GUINT32_FROM_BE (start_resp.rpdu.common.offset); if (!fu_memcpy_safe ((guint8 *) self->targ.common.version, FU_CROS_EC_STRLEN, 0x0, (const guint8 *) start_resp.rpdu.common.version, @@ -323,11 +325,22 @@ fu_cros_ec_usb_device_prepare_firmware (FuDevice *device, FwupdInstallFlags flags, GError **error) { + FuCrosEcUsbDevice *self = FU_CROS_EC_USB_DEVICE (device); + FuCrosEcFirmware *cros_ec_firmware = NULL; g_autoptr(FuFirmware) firmware = fu_cros_ec_firmware_new (); fu_device_set_status (device, FWUPD_STATUS_DECOMPRESSING); if (!fu_firmware_parse (firmware, fw, flags, error)) return NULL; + cros_ec_firmware = FU_CROS_EC_FIRMWARE (firmware); + + /* pick sections */ + if (!fu_cros_ec_firmware_pick_sections (cros_ec_firmware, + self->writeable_offset, + error)) { + g_prefix_error (error, "failed to pick sections: "); + return NULL; + } return g_steal_pointer (&firmware); } @@ -361,6 +374,8 @@ fu_cros_ec_usb_device_to_string (FuDevice *device, guint idt, GString *str) min_rollback = g_strdup_printf ("%" G_GINT32_FORMAT, self->targ.common.min_rollback); fu_common_string_append_kv (str, idt, "MinRollback", min_rollback); + fu_common_string_append_kx (str, idt, "WriteableOffset", + self->writeable_offset); } static void From 9326e1911834ccfedf40023dd7d0f655c087d377 Mon Sep 17 00:00:00 2001 From: Benson Leung Date: Tue, 30 Jun 2020 15:23:36 -0700 Subject: [PATCH 258/607] cros-ec: Give cros-ec-firmware a get_sections Add a getter for the sections. --- plugins/cros-ec/fu-cros-ec-firmware.c | 6 ++++++ plugins/cros-ec/fu-cros-ec-firmware.h | 1 + 2 files changed, 7 insertions(+) diff --git a/plugins/cros-ec/fu-cros-ec-firmware.c b/plugins/cros-ec/fu-cros-ec-firmware.c index f49629653..059711abf 100644 --- a/plugins/cros-ec/fu-cros-ec-firmware.c +++ b/plugins/cros-ec/fu-cros-ec-firmware.c @@ -51,6 +51,12 @@ fu_cros_ec_firmware_pick_sections (FuCrosEcFirmware *self, return TRUE; } +GPtrArray * +fu_cros_ec_firmware_get_sections (FuCrosEcFirmware *self) +{ + return self->sections; +} + static gboolean fu_cros_ec_firmware_parse (FuFirmware *firmware, GBytes *fw, diff --git a/plugins/cros-ec/fu-cros-ec-firmware.h b/plugins/cros-ec/fu-cros-ec-firmware.h index b0d1f6052..9bbdde5d5 100644 --- a/plugins/cros-ec/fu-cros-ec-firmware.h +++ b/plugins/cros-ec/fu-cros-ec-firmware.h @@ -41,4 +41,5 @@ typedef struct { gboolean fu_cros_ec_firmware_pick_sections (FuCrosEcFirmware *self, guint32 writeable_offset, GError **error); +GPtrArray *fu_cros_ec_firmware_get_sections (FuCrosEcFirmware *self); FuFirmware *fu_cros_ec_firmware_new (void); From 4ed2400cab9730c2b1176c70a9cceb9a68c27efb Mon Sep 17 00:00:00 2001 From: Benson Leung Date: Tue, 30 Jun 2020 15:12:23 -0700 Subject: [PATCH 259/607] cros-ec: Store image_idx in section Makes it a bit easier to retrieve the image later. --- plugins/cros-ec/fu-cros-ec-firmware.c | 1 + plugins/cros-ec/fu-cros-ec-firmware.h | 1 + 2 files changed, 2 insertions(+) diff --git a/plugins/cros-ec/fu-cros-ec-firmware.c b/plugins/cros-ec/fu-cros-ec-firmware.c index 059711abf..c50de4dc7 100644 --- a/plugins/cros-ec/fu-cros-ec-firmware.c +++ b/plugins/cros-ec/fu-cros-ec-firmware.c @@ -132,6 +132,7 @@ fu_cros_ec_firmware_parse (FuFirmware *firmware, section->offset = fu_firmware_image_get_addr (img); section->size = g_bytes_get_size (payload_bytes); fu_firmware_image_set_version (img, section->version); + section->image_idx = fu_firmware_image_get_idx (img); if (rw) { if (!fu_cros_ec_parse_version (section->version, diff --git a/plugins/cros-ec/fu-cros-ec-firmware.h b/plugins/cros-ec/fu-cros-ec-firmware.h index 9bbdde5d5..c7b09be8e 100644 --- a/plugins/cros-ec/fu-cros-ec-firmware.h +++ b/plugins/cros-ec/fu-cros-ec-firmware.h @@ -36,6 +36,7 @@ typedef struct { gchar version[FU_FMAP_FIRMWARE_STRLEN]; gint32 rollback; guint32 key_version; + guint64 image_idx; } FuCrosEcFirmwareSection; gboolean fu_cros_ec_firmware_pick_sections (FuCrosEcFirmware *self, From 8ed9f5f0a18f4622e12de5fff0269b9156690058 Mon Sep 17 00:00:00 2001 From: Benson Leung Date: Mon, 22 Jun 2020 15:32:03 -0700 Subject: [PATCH 260/607] cros-ec: Write firmware to usb target Write the firmware to the usb device, first finding which section to write to, then breaking into blocks (based on maximum pdu size), and then into chunks, which are transferred to the device using bulk transfers. --- plugins/cros-ec/fu-cros-ec-usb-device.c | 235 ++++++++++++++++++++++++ 1 file changed, 235 insertions(+) diff --git a/plugins/cros-ec/fu-cros-ec-usb-device.c b/plugins/cros-ec/fu-cros-ec-usb-device.c index ba589255d..2cf5eab7d 100644 --- a/plugins/cros-ec/fu-cros-ec-usb-device.c +++ b/plugins/cros-ec/fu-cros-ec-usb-device.c @@ -8,6 +8,7 @@ #include +#include "fu-chunk.h" #include "fu-cros-ec-usb-device.h" #include "fu-cros-ec-common.h" #include "fu-cros-ec-firmware.h" @@ -16,10 +17,13 @@ #define USB_PROTOCOL_GOOGLE_UPDATE 0xff #define SETUP_RETRY_CNT 5 +#define MAX_BLOCK_XFER_RETRIES 10 #define FLUSH_TIMEOUT_MS 10 #define BULK_SEND_TIMEOUT_MS 2000 #define BULK_RECV_TIMEOUT_MS 5000 +#define UPDATE_DONE 0xB007AB1E + struct _FuCrosEcUsbDevice { FuUsbDevice parent_instance; guint8 iface_idx; /* bInterfaceNumber */ @@ -40,6 +44,13 @@ typedef union _START_RESP { guint32 legacy_resp; } START_RESP; +typedef struct { + struct update_frame_header ufh; + GBytes *image_bytes; + gsize offset; + gsize payload_size; +} FuCrosEcUsbBlockInfo; + static gboolean fu_cros_ec_usb_device_find_interface (FuUsbDevice *device, GError **error) @@ -302,6 +313,229 @@ fu_cros_ec_usb_device_setup (FuDevice *device, GError **error) return TRUE; } +static gboolean +fu_cros_ec_usb_device_transfer_block (FuDevice *device, gpointer user_data, + GError **error) +{ + FuCrosEcUsbDevice *self = FU_CROS_EC_USB_DEVICE (device); + FuCrosEcUsbBlockInfo *block_info = (FuCrosEcUsbBlockInfo *) user_data; + gsize image_size = 0; + gsize transfer_size = 0; + guint32 reply = 0; + g_autoptr(GBytes) block_bytes = NULL; + g_autoptr(GPtrArray) chunks = NULL; + + g_return_val_if_fail (block_info != NULL, FALSE); + + image_size = g_bytes_get_size (block_info->image_bytes); + if (block_info->offset + block_info->payload_size > image_size) { + g_set_error (error, + G_IO_ERROR, + G_IO_ERROR_INVALID_DATA, + "offset %" G_GSIZE_FORMAT "plus payload_size %" + G_GSIZE_FORMAT " exceeds image size %" + G_GSIZE_FORMAT, + block_info->offset, block_info->payload_size, + image_size); + return FALSE; + } + + block_bytes = g_bytes_new_from_bytes (block_info->image_bytes, + block_info->offset, + block_info->payload_size); + chunks = fu_chunk_array_new_from_bytes (block_bytes, + 0x00, + 0x00, + self->chunk_len); + + /* first send the header */ + if (!fu_cros_ec_usb_device_do_xfer (self, (guint8 *)&block_info->ufh, + sizeof(struct update_frame_header), + NULL, + 0, FALSE, + NULL, error)) + return FALSE; + + /* send the block, chunk by chunk */ + for (guint i = 0; i < chunks->len; i++) { + FuChunk *chk = g_ptr_array_index (chunks, i); + + if (!fu_cros_ec_usb_device_do_xfer (self, + (guint8 *)chk->data, + chk->data_sz, + NULL, + 0, FALSE, + NULL, error)) { + return FALSE; + } + } + + /* get the reply */ + if (!fu_cros_ec_usb_device_do_xfer (self, NULL, 0, + (guint8 *)&reply, sizeof (reply), + TRUE, &transfer_size, error)) + return FALSE; + if (transfer_size == 0) { + g_set_error_literal (error, + G_IO_ERROR, + G_IO_ERROR_FAILED, + "zero bytes received for block reply"); + return FALSE; + } + if (reply != 0) { + g_set_error (error, + G_IO_ERROR, + G_IO_ERROR_FAILED, + "error: status 0x%#x", reply); + return FALSE; + } + + /* success */ + return TRUE; +} + +static gboolean +fu_cros_ec_usb_device_transfer_section (FuDevice *device, + FuFirmware *firmware, + FuCrosEcFirmwareSection *section, + GError **error) +{ + FuCrosEcUsbDevice *self = FU_CROS_EC_USB_DEVICE (device); + const guint8 * data_ptr = NULL; + guint32 section_addr = 0; + gsize data_len = 0; + gsize offset = 0; + g_autoptr(GBytes) img_bytes = NULL; + + g_return_val_if_fail (section != NULL, FALSE); + + section_addr = section->offset; + img_bytes = fu_firmware_get_image_by_idx_bytes (firmware, + section->image_idx, + error); + if (img_bytes == NULL) { + g_prefix_error (error, "failed to find section image: "); + return FALSE; + } + + data_ptr = (const guint8 *)g_bytes_get_data (img_bytes, &data_len); + if (data_ptr == NULL || data_len != section->size) { + g_set_error (error, + G_IO_ERROR, + G_IO_ERROR_INVALID_DATA, + "image and section sizes do not match: image = %" + G_GSIZE_FORMAT " bytes vs section size = %" + G_GSIZE_FORMAT " bytes", + data_len, section->size); + return FALSE; + } + + /* smart update: trim trailing bytes */ + while (data_len != 0 && (data_ptr[data_len - 1] == 0xff)) + data_len--; + g_debug ("trimmed %" G_GSIZE_FORMAT " trailing bytes", + section->size - data_len); + + g_debug ("sending 0x%zx bytes to %#x", data_len, section_addr); + while (data_len > 0) { + gsize payload_size; + guint32 block_base; + FuCrosEcUsbBlockInfo block_info; + + /* prepare the header to prepend to the block */ + block_info.image_bytes = img_bytes; + payload_size = MIN (data_len, + self->targ.common.maximum_pdu_size); + block_base = GUINT32_TO_BE (section_addr); + block_info.ufh.block_size = GUINT32_TO_BE (payload_size + + sizeof (struct update_frame_header)); + block_info.ufh.cmd.block_base = block_base; + block_info.ufh.cmd.block_digest = 0; + block_info.offset = offset; + block_info.payload_size = payload_size; + + if (!fu_device_retry (device, + fu_cros_ec_usb_device_transfer_block, + MAX_BLOCK_XFER_RETRIES, &block_info, + error)) { + g_prefix_error (error, + "failed to transfer block, %" + G_GSIZE_FORMAT " to go: ", data_len); + return FALSE; + } + data_len -= payload_size; + offset += payload_size; + section_addr += payload_size; + } + + /* success */ + return TRUE; +} + +static void +fu_cros_ec_usb_device_send_done (FuDevice *device) +{ + guint32 out = GUINT32_TO_BE (UPDATE_DONE); + g_autoptr(GError) error_local = NULL; + + /* send stop request, ignoring reply */ + if (!fu_cros_ec_usb_device_do_xfer (FU_CROS_EC_USB_DEVICE (device), + (guint8 *)&out, sizeof (out), + (guint8 *)&out, 1, + FALSE, NULL, &error_local)) { + g_debug ("error on transfer of done: %s", + error_local->message); + } +} + +static gboolean +fu_cros_ec_usb_device_write_firmware (FuDevice *device, + FuFirmware *firmware, + FwupdInstallFlags flags, + GError **error) +{ + GPtrArray *sections; + FuCrosEcFirmware *cros_ec_firmware = FU_CROS_EC_FIRMWARE (firmware); + gint num_txed_sections = 0; + + sections = fu_cros_ec_firmware_get_sections (cros_ec_firmware); + if (sections == NULL) { + g_set_error_literal (error, + G_IO_ERROR, + G_IO_ERROR_INVALID_DATA, + "invalid sections"); + return FALSE; + } + + fu_device_set_status (device, FWUPD_STATUS_DEVICE_WRITE); + for (guint i = 0; i < sections->len; i++) { + FuCrosEcFirmwareSection *section = g_ptr_array_index (sections, i); + + if (section->ustatus == FU_CROS_EC_FW_NEEDED) { + if (!fu_cros_ec_usb_device_transfer_section (device, + firmware, + section, + error)) { + return FALSE; + } + num_txed_sections++; + } + } + /* send done */ + fu_cros_ec_usb_device_send_done (device); + + if (num_txed_sections == 0) { + g_set_error_literal (error, + G_IO_ERROR, + G_IO_ERROR_INVALID_DATA, + "no sections transferred"); + return FALSE; + } + + /* success */ + return TRUE; +} + static gboolean fu_cros_ec_usb_device_close (FuUsbDevice *device, GError **error) { @@ -386,6 +620,7 @@ fu_cros_ec_usb_device_class_init (FuCrosEcUsbDeviceClass *klass) klass_device->prepare_firmware = fu_cros_ec_usb_device_prepare_firmware; klass_device->setup = fu_cros_ec_usb_device_setup; klass_device->to_string = fu_cros_ec_usb_device_to_string; + klass_device->write_firmware = fu_cros_ec_usb_device_write_firmware; klass_usb_device->open = fu_cros_ec_usb_device_open; klass_usb_device->probe = fu_cros_ec_usb_device_probe; klass_usb_device->close = fu_cros_ec_usb_device_close; From 852c6685ff59d29ca292a426c96ad0e75955d18f Mon Sep 17 00:00:00 2001 From: Benson Leung Date: Mon, 22 Jun 2020 14:38:07 -0700 Subject: [PATCH 261/607] cros-ec: Set protocol for cros-ec-usb-device Specify "com.google.usb.crosec" to indicate support for Google's USB endpoint updater protocol. --- plugins/cros-ec/README.md | 4 ++++ plugins/cros-ec/fu-cros-ec-usb-device.c | 1 + 2 files changed, 5 insertions(+) diff --git a/plugins/cros-ec/README.md b/plugins/cros-ec/README.md index 868483d8a..a16ac6dd0 100644 --- a/plugins/cros-ec/README.md +++ b/plugins/cros-ec/README.md @@ -19,6 +19,10 @@ Firmware Format The daemon will decompress the cabinet archive and extract a firmware blob in the Google fmap [3] file format. +This plugin supports the following protocol ID: + + * com.google.usb.crosec + GUID Generation --------------- diff --git a/plugins/cros-ec/fu-cros-ec-usb-device.c b/plugins/cros-ec/fu-cros-ec-usb-device.c index 2cf5eab7d..0308d57f9 100644 --- a/plugins/cros-ec/fu-cros-ec-usb-device.c +++ b/plugins/cros-ec/fu-cros-ec-usb-device.c @@ -581,6 +581,7 @@ fu_cros_ec_usb_device_prepare_firmware (FuDevice *device, static void fu_cros_ec_usb_device_init (FuCrosEcUsbDevice *device) { + fu_device_set_protocol (FU_DEVICE (device), "com.google.usb.crosec"); fu_device_set_version_format (FU_DEVICE (device), FWUPD_VERSION_FORMAT_TRIPLET); } From ff0dc24e543267d025cf9d47963a014298d9615b Mon Sep 17 00:00:00 2001 From: Richard Hughes Date: Mon, 1 Jun 2020 12:03:10 +0100 Subject: [PATCH 262/607] trivial: Add some documentation for the ApprovedFirmware config key --- data/daemon.conf | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/data/daemon.conf b/data/daemon.conf index 4c9bfc82d..93777595c 100644 --- a/data/daemon.conf +++ b/data/daemon.conf @@ -28,3 +28,7 @@ UpdateMotd=true # For some plugins, enumerate only devices supported by metadata EnumerateAllDevices=false + +# A list of firmware checksums that has been approved by the site admin +# If unset, all firmware is approved +ApprovedFirmware= From cc93f7c3360c204aacb1c02f74e2a9a8f7f7e546 Mon Sep 17 00:00:00 2001 From: Richard Hughes Date: Mon, 1 Jun 2020 12:04:03 +0100 Subject: [PATCH 263/607] trivial: Allow the uset to set the ApprovalRequired remote value This allows the local user with appropriate permissions to do: fwupdmgr modify-remote lvfs ApprovalRequired true --- src/fu-engine.c | 1 + 1 file changed, 1 insertion(+) diff --git a/src/fu-engine.c b/src/fu-engine.c index ffed53799..2ed45922e 100644 --- a/src/fu-engine.c +++ b/src/fu-engine.c @@ -572,6 +572,7 @@ fu_engine_modify_remote (FuEngine *self, GError **error) { const gchar *keys[] = { + "ApprovalRequired", "AutomaticReports", "AutomaticSecurityReports", "Enabled", From 17da521916953b56ad4903b4a58d392d8ec0bb3a Mon Sep 17 00:00:00 2001 From: Richard Hughes Date: Thu, 9 Jul 2020 09:45:07 +0100 Subject: [PATCH 264/607] libfwupd: Add fwupd_remote_load_signature_bytes() for when a file is not available --- libfwupd/fwupd-remote.c | 84 +++++++++++++++++++++++++++++------------ libfwupd/fwupd-remote.h | 3 ++ libfwupd/fwupd.map | 1 + 3 files changed, 63 insertions(+), 25 deletions(-) diff --git a/libfwupd/fwupd-remote.c b/libfwupd/fwupd-remote.c index c8eaeb1b1..f63a2668d 100644 --- a/libfwupd/fwupd-remote.c +++ b/libfwupd/fwupd-remote.c @@ -932,39 +932,16 @@ fwupd_remote_get_metadata_uri (FwupdRemote *self) return priv->metadata_uri; } -/** - * fwupd_remote_load_signature: - * @self: A #FwupdRemote - * @filename: A filename - * @error: the #GError, or %NULL - * - * Parses the signature, updating the metadata URI as appropriate. - * - * Returns: %TRUE for success - * - * Since: 1.4.0 - **/ -gboolean -fwupd_remote_load_signature (FwupdRemote *self, const gchar *filename, GError **error) +static gboolean +fwupd_remote_load_signature_jcat (FwupdRemote *self, JcatFile *jcat_file, GError **error) { FwupdRemotePrivate *priv = GET_PRIVATE (self); const gchar *id; g_autofree gchar *basename = NULL; g_autofree gchar *baseuri = NULL; g_autofree gchar *metadata_uri = NULL; - g_autoptr(GFile) gfile = NULL; - g_autoptr(JcatFile) jcat_file = jcat_file_new (); g_autoptr(JcatItem) jcat_item = NULL; - g_return_val_if_fail (FWUPD_IS_REMOTE (self), FALSE); - g_return_val_if_fail (filename != NULL, FALSE); - g_return_val_if_fail (error == NULL || *error == NULL, FALSE); - - /* load JCat file */ - gfile = g_file_new_for_path (filename); - if (!jcat_file_import_file (jcat_file, gfile, JCAT_IMPORT_FLAG_NONE, NULL, error)) - return FALSE; - /* this seems pointless to get the item by ID then just read the ID, * but _get_item_by_id() uses the AliasIds as a fallback */ basename = g_path_get_basename (priv->metadata_uri); @@ -998,6 +975,63 @@ fwupd_remote_load_signature (FwupdRemote *self, const gchar *filename, GError ** return TRUE; } +/** + * fwupd_remote_load_signature_bytes: + * @self: A #FwupdRemote + * @bytes: A #GBytes + * @error: the #GError, or %NULL + * + * Parses the signature, updating the metadata URI as appropriate. + * + * Returns: %TRUE for success + * + * Since: 1.4.5 + **/ +gboolean +fwupd_remote_load_signature_bytes (FwupdRemote *self, GBytes *bytes, GError **error) +{ + g_autoptr(GInputStream) istr = NULL; + g_autoptr(JcatFile) jcat_file = jcat_file_new (); + + g_return_val_if_fail (FWUPD_IS_REMOTE (self), FALSE); + g_return_val_if_fail (bytes != NULL, FALSE); + g_return_val_if_fail (error == NULL || *error == NULL, FALSE); + + istr = g_memory_input_stream_new_from_bytes (bytes); + if (!jcat_file_import_stream (jcat_file, istr, JCAT_IMPORT_FLAG_NONE, NULL, error)) + return FALSE; + return fwupd_remote_load_signature_jcat (self, jcat_file, error); +} + +/** + * fwupd_remote_load_signature: + * @self: A #FwupdRemote + * @filename: A filename + * @error: the #GError, or %NULL + * + * Parses the signature, updating the metadata URI as appropriate. + * + * Returns: %TRUE for success + * + * Since: 1.4.0 + **/ +gboolean +fwupd_remote_load_signature (FwupdRemote *self, const gchar *filename, GError **error) +{ + g_autoptr(GFile) gfile = NULL; + g_autoptr(JcatFile) jcat_file = jcat_file_new (); + + g_return_val_if_fail (FWUPD_IS_REMOTE (self), FALSE); + g_return_val_if_fail (filename != NULL, FALSE); + g_return_val_if_fail (error == NULL || *error == NULL, FALSE); + + /* load JCat file */ + gfile = g_file_new_for_path (filename); + if (!jcat_file_import_file (jcat_file, gfile, JCAT_IMPORT_FLAG_NONE, NULL, error)) + return FALSE; + return fwupd_remote_load_signature_jcat (self, jcat_file, error); +} + /** * fwupd_remote_get_metadata_uri_sig: * @self: A #FwupdRemote diff --git a/libfwupd/fwupd-remote.h b/libfwupd/fwupd-remote.h index c8da71173..1794040b6 100644 --- a/libfwupd/fwupd-remote.h +++ b/libfwupd/fwupd-remote.h @@ -77,6 +77,9 @@ gchar *fwupd_remote_build_firmware_uri (FwupdRemote *self, gboolean fwupd_remote_load_signature (FwupdRemote *self, const gchar *filename, GError **error); +gboolean fwupd_remote_load_signature_bytes (FwupdRemote *self, + GBytes *bytes, + GError **error); FwupdRemote *fwupd_remote_from_variant (GVariant *value); GPtrArray *fwupd_remote_array_from_variant (GVariant *value); diff --git a/libfwupd/fwupd.map b/libfwupd/fwupd.map index 6e793161d..edf6456ed 100644 --- a/libfwupd/fwupd.map +++ b/libfwupd/fwupd.map @@ -460,6 +460,7 @@ LIBFWUPD_1.4.5 { fwupd_feature_flag_to_string; fwupd_release_get_update_image; fwupd_release_set_update_image; + fwupd_remote_load_signature_bytes; local: *; } LIBFWUPD_1.4.1; From 9a5bd5e9d7316e1d6d4d06c28f1a6be28ca67d39 Mon Sep 17 00:00:00 2001 From: Richard Hughes Date: Thu, 9 Jul 2020 10:03:57 +0100 Subject: [PATCH 265/607] libfwupd: Split up a function for future new API --- libfwupd/fwupd-client.c | 135 ++++++++++++++++++++++------------------ 1 file changed, 76 insertions(+), 59 deletions(-) diff --git a/libfwupd/fwupd-client.c b/libfwupd/fwupd-client.c index 3f0af25c0..8601977e1 100644 --- a/libfwupd/fwupd-client.c +++ b/libfwupd/fwupd-client.c @@ -11,6 +11,7 @@ #include #ifdef HAVE_GIO_UNIX #include +#include #endif #include @@ -1604,6 +1605,71 @@ fwupd_client_get_daemon_interactive (FwupdClient *client) return priv->interactive; } +#ifdef HAVE_GIO_UNIX +static gboolean +fwupd_client_update_metadata_fds (FwupdClient *client, + const gchar *remote_id, + GUnixInputStream *metadata, + GUnixInputStream *signature, + GCancellable *cancellable, + GError **error) +{ + FwupdClientPrivate *priv = GET_PRIVATE (client); + GVariant *body; + g_autoptr(FwupdClientHelper) helper = NULL; + g_autoptr(GDBusMessage) request = NULL; + g_autoptr(GUnixFDList) fd_list = NULL; + + /* set out of band file descriptor */ + fd_list = g_unix_fd_list_new (); + g_unix_fd_list_append (fd_list, g_unix_input_stream_get_fd (metadata), NULL); + g_unix_fd_list_append (fd_list, g_unix_input_stream_get_fd (signature), NULL); + request = g_dbus_message_new_method_call (FWUPD_DBUS_SERVICE, + FWUPD_DBUS_PATH, + FWUPD_DBUS_INTERFACE, + "UpdateMetadata"); + g_dbus_message_set_unix_fd_list (request, fd_list); + + /* call into daemon */ + body = g_variant_new ("(shh)", + remote_id, + g_unix_input_stream_get_fd (metadata), + g_unix_input_stream_get_fd (signature)); + g_dbus_message_set_body (request, body); + helper = fwupd_client_helper_new (); + g_dbus_connection_send_message_with_reply (priv->conn, + request, + G_DBUS_SEND_MESSAGE_FLAGS_NONE, + -1, + NULL, + cancellable, + fwupd_client_send_message_cb, + helper); + g_main_loop_run (helper->loop); + if (!helper->ret) { + g_propagate_error (error, helper->error); + helper->error = NULL; + return FALSE; + } + return TRUE; +} + +static GUnixInputStream * +fwupd_client_input_stream_from_fn (const gchar *fn, GError **error) +{ + gint fd = open (fn, O_RDONLY); + if (fd < 0) { + g_set_error (error, + FWUPD_ERROR, + FWUPD_ERROR_INVALID_FILE, + "failed to open %s", fn); + return NULL; + } + return G_UNIX_INPUT_STREAM (g_unix_input_stream_new (fd, TRUE)); +} + +#endif + /** * fwupd_client_update_metadata: * @client: A #FwupdClient @@ -1633,13 +1699,8 @@ fwupd_client_update_metadata (FwupdClient *client, GError **error) { #ifdef HAVE_GIO_UNIX - FwupdClientPrivate *priv = GET_PRIVATE (client); - GVariant *body; - gint fd; - gint fd_sig; - g_autoptr(FwupdClientHelper) helper = NULL; - g_autoptr(GDBusMessage) request = NULL; - g_autoptr(GUnixFDList) fd_list = NULL; + GUnixInputStream *istr; + GUnixInputStream *istr_sig; g_return_val_if_fail (FWUPD_IS_CLIENT (client), FALSE); g_return_val_if_fail (remote_id != NULL, FALSE); @@ -1652,60 +1713,16 @@ fwupd_client_update_metadata (FwupdClient *client, if (!fwupd_client_connect (client, cancellable, error)) return FALSE; - /* open file */ - fd = open (metadata_fn, O_RDONLY); - if (fd < 0) { - g_set_error (error, - FWUPD_ERROR, - FWUPD_ERROR_INVALID_FILE, - "failed to open %s", - metadata_fn); + /* open files */ + istr = fwupd_client_input_stream_from_fn (metadata_fn, error); + if (istr == NULL) return FALSE; - } - fd_sig = open (signature_fn, O_RDONLY); - if (fd_sig < 0) { - close (fd); - g_set_error (error, - FWUPD_ERROR, - FWUPD_ERROR_INVALID_FILE, - "failed to open %s", - signature_fn); + istr_sig = fwupd_client_input_stream_from_fn (signature_fn, error); + if (istr_sig == NULL) return FALSE; - } - - /* set out of band file descriptor */ - fd_list = g_unix_fd_list_new (); - g_unix_fd_list_append (fd_list, fd, NULL); - g_unix_fd_list_append (fd_list, fd_sig, NULL); - request = g_dbus_message_new_method_call (FWUPD_DBUS_SERVICE, - FWUPD_DBUS_PATH, - FWUPD_DBUS_INTERFACE, - "UpdateMetadata"); - g_dbus_message_set_unix_fd_list (request, fd_list); - - /* g_unix_fd_list_append did a dup() already */ - close (fd); - close (fd_sig); - - /* call into daemon */ - body = g_variant_new ("(shh)", remote_id, fd, fd_sig); - g_dbus_message_set_body (request, body); - helper = fwupd_client_helper_new (); - g_dbus_connection_send_message_with_reply (priv->conn, - request, - G_DBUS_SEND_MESSAGE_FLAGS_NONE, - -1, - NULL, - cancellable, - fwupd_client_send_message_cb, - helper); - g_main_loop_run (helper->loop); - if (!helper->ret) { - g_propagate_error (error, helper->error); - helper->error = NULL; - return FALSE; - } - return TRUE; + return fwupd_client_update_metadata_fds (client, remote_id, + istr, istr_sig, + cancellable, error); #else g_set_error_literal (error, FWUPD_ERROR, From 71ba813a71f569f548d39e28a155e8455a46ac1e Mon Sep 17 00:00:00 2001 From: Richard Hughes Date: Thu, 9 Jul 2020 10:06:01 +0100 Subject: [PATCH 266/607] libfwupd: Add fwupd_client_update_metadata_bytes() Sometimes the data is coming from a blob of memory and not a cached file, so use a memfd to create a file descriptor that can be passed to the daemon. --- libfwupd/fwupd-client.c | 91 +++++++++++++++++++++++++++++++++++++++++ libfwupd/fwupd-client.h | 6 +++ libfwupd/fwupd.map | 1 + meson.build | 3 ++ 4 files changed, 101 insertions(+) diff --git a/libfwupd/fwupd-client.c b/libfwupd/fwupd-client.c index 8601977e1..5c2a4010d 100644 --- a/libfwupd/fwupd-client.c +++ b/libfwupd/fwupd-client.c @@ -10,11 +10,13 @@ #include #include #ifdef HAVE_GIO_UNIX +#include #include #include #endif #include +#include #include #include #include @@ -1668,6 +1670,37 @@ fwupd_client_input_stream_from_fn (const gchar *fn, GError **error) return G_UNIX_INPUT_STREAM (g_unix_input_stream_new (fd, TRUE)); } +static GUnixInputStream * +fwupd_client_input_stream_from_bytes (GBytes *bytes, GError **error) +{ + gint fd; + gssize rc; + + fd = memfd_create ("fwupd", MFD_CLOEXEC); + if (fd < 0) { + g_set_error_literal (error, + FWUPD_ERROR, + FWUPD_ERROR_INVALID_FILE, + "failed to create memfd"); + return NULL; + } + rc = write (fd, g_bytes_get_data (bytes, NULL), g_bytes_get_size (bytes)); + if (rc < 0) { + g_set_error (error, + FWUPD_ERROR, + FWUPD_ERROR_INVALID_FILE, + "failed to write %" G_GSSIZE_FORMAT, rc); + return NULL; + } + if (lseek (fd, 0, SEEK_SET) < 0) { + g_set_error (error, + FWUPD_ERROR, + FWUPD_ERROR_INVALID_FILE, + "failed to seek: %s", g_strerror (errno)); + return NULL; + } + return G_UNIX_INPUT_STREAM (g_unix_input_stream_new (fd, TRUE)); +} #endif /** @@ -1732,6 +1765,64 @@ fwupd_client_update_metadata (FwupdClient *client, #endif } +/** + * fwupd_client_update_metadata_bytes: + * @client: A #FwupdClient + * @remote_id: remote ID, e.g. `lvfs-testing` + * @metadata: XML metadata data + * @signature: signature data + * @cancellable: #GCancellable, or %NULL + * @error: the #GError, or %NULL + * + * Updates the metadata. This allows a session process to download the metadata + * and metadata signing file to be passed into the daemon to be checked and + * parsed. + * + * The @remote_id allows the firmware to be tagged so that the remote can be + * matched when the firmware is downloaded. + * + * Returns: %TRUE for success + * + * Since: 1.4.5 + **/ +gboolean +fwupd_client_update_metadata_bytes (FwupdClient *client, + const gchar *remote_id, + GBytes *metadata, + GBytes *signature, + GCancellable *cancellable, + GError **error) +{ +#ifdef HAVE_GIO_UNIX + GUnixInputStream *istr; + GUnixInputStream *istr_sig; + + g_return_val_if_fail (FWUPD_IS_CLIENT (client), FALSE); + g_return_val_if_fail (remote_id != NULL, FALSE); + g_return_val_if_fail (metadata != NULL, FALSE); + g_return_val_if_fail (signature != NULL, FALSE); + g_return_val_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable), FALSE); + g_return_val_if_fail (error == NULL || *error == NULL, FALSE); + + /* convert bytes to a readable fd */ + istr = fwupd_client_input_stream_from_bytes (metadata, error); + if (istr == NULL) + return FALSE; + istr_sig = fwupd_client_input_stream_from_bytes (signature, error); + if (istr_sig == NULL) + return FALSE; + return fwupd_client_update_metadata_fds (client, remote_id, + istr, istr_sig, + cancellable, error); +#else + g_set_error_literal (error, + FWUPD_ERROR, + FWUPD_ERROR_NOT_SUPPORTED, + "Not supported as is unavailable"); + return FALSE; +#endif +} + /** * fwupd_client_get_remotes: * @client: A #FwupdClient diff --git a/libfwupd/fwupd-client.h b/libfwupd/fwupd-client.h index 83aba76e5..cc14b0946 100644 --- a/libfwupd/fwupd-client.h +++ b/libfwupd/fwupd-client.h @@ -144,6 +144,12 @@ gboolean fwupd_client_update_metadata (FwupdClient *client, const gchar *signature_fn, GCancellable *cancellable, GError **error); +gboolean fwupd_client_update_metadata_bytes (FwupdClient *client, + const gchar *remote_id, + GBytes *metadata, + GBytes *signature, + GCancellable *cancellable, + GError **error); gboolean fwupd_client_modify_remote (FwupdClient *client, const gchar *remote_id, const gchar *key, diff --git a/libfwupd/fwupd.map b/libfwupd/fwupd.map index edf6456ed..eeec23e2e 100644 --- a/libfwupd/fwupd.map +++ b/libfwupd/fwupd.map @@ -453,6 +453,7 @@ LIBFWUPD_1.4.5 { fwupd_client_set_feature_flags; fwupd_client_set_user_agent; fwupd_client_set_user_agent_for_package; + fwupd_client_update_metadata_bytes; fwupd_client_upload_bytes; fwupd_device_get_update_image; fwupd_device_set_update_image; diff --git a/meson.build b/meson.build index ea0019c02..2db4b1162 100644 --- a/meson.build +++ b/meson.build @@ -146,6 +146,9 @@ add_project_arguments('-DFWUPD_DISABLE_DEPRECATED', language : 'c') add_project_arguments('-D_BSD_SOURCE', language : 'c') add_project_arguments('-D_XOPEN_SOURCE=700', language : 'c') +# needed for memfd_create() +add_project_arguments('-D_GNU_SOURCE', language : 'c') + # sanity check if get_option('build') == 'all' build_standalone = true From d52857197126cf01d06c240849f1561e7f2e4f25 Mon Sep 17 00:00:00 2001 From: Richard Hughes Date: Thu, 9 Jul 2020 10:22:01 +0100 Subject: [PATCH 267/607] libfwupd: Add fwupd_client_refresh_remote() This takes care of downloading the correct files and allows remotes to be refreshed from other CLI and GUI tools without copying large chunks of code. This also allows us to download the metadata without writing two temp files to the users cache directory. Although not security sensitive, it's probably not a good idea if we can avoid it. --- libfwupd/fwupd-client.c | 54 +++++++++++++++++++++++++++++++++++++++++ libfwupd/fwupd-client.h | 4 +++ libfwupd/fwupd.map | 1 + src/fu-util.c | 47 ++++------------------------------- 4 files changed, 64 insertions(+), 42 deletions(-) diff --git a/libfwupd/fwupd-client.c b/libfwupd/fwupd-client.c index 5c2a4010d..ea02837f8 100644 --- a/libfwupd/fwupd-client.c +++ b/libfwupd/fwupd-client.c @@ -1823,6 +1823,60 @@ fwupd_client_update_metadata_bytes (FwupdClient *client, #endif } +/** + * fwupd_client_refresh_remote: + * @client: A #FwupdClient + * @remote: A #FwupdRemote + * @cancellable: A #GCancellable, or %NULL + * @error: A #GError, or %NULL + * + * Refreshes a remote by downloading new metadata. + * + * Returns: %TRUE for success + * + * Since: 1.4.5 + **/ +gboolean +fwupd_client_refresh_remote (FwupdClient *client, + FwupdRemote *remote, + GCancellable *cancellable, + GError **error) +{ + g_autoptr(GBytes) metadata = NULL; + g_autoptr(GBytes) signature = NULL; + + g_return_val_if_fail (FWUPD_IS_CLIENT (client), FALSE); + g_return_val_if_fail (FWUPD_IS_REMOTE (remote), FALSE); + g_return_val_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable), FALSE); + g_return_val_if_fail (error == NULL || *error == NULL, FALSE); + + /* download the signature */ + signature = fwupd_client_download_bytes (client, + fwupd_remote_get_metadata_uri_sig (remote), + FWUPD_CLIENT_DOWNLOAD_FLAG_NONE, + cancellable, error); + if (signature == NULL) + return FALSE; + + /* find the download URI of the metadata from the JCat file */ + if (!fwupd_remote_load_signature_bytes (remote, signature, error)) + return FALSE; + + /* download the metadata */ + metadata = fwupd_client_download_bytes (client, + fwupd_remote_get_metadata_uri (remote), + FWUPD_CLIENT_DOWNLOAD_FLAG_NONE, + cancellable, error); + if (metadata == NULL) + return FALSE; + + /* send all this to fwupd */ + return fwupd_client_update_metadata_bytes (client, + fwupd_remote_get_id (remote), + metadata, signature, + cancellable, error); +} + /** * fwupd_client_get_remotes: * @client: A #FwupdClient diff --git a/libfwupd/fwupd-client.h b/libfwupd/fwupd-client.h index cc14b0946..414dca1b4 100644 --- a/libfwupd/fwupd-client.h +++ b/libfwupd/fwupd-client.h @@ -150,6 +150,10 @@ gboolean fwupd_client_update_metadata_bytes (FwupdClient *client, GBytes *signature, GCancellable *cancellable, GError **error); +gboolean fwupd_client_refresh_remote (FwupdClient *client, + FwupdRemote *remote, + GCancellable *cancellable, + GError **error); gboolean fwupd_client_modify_remote (FwupdClient *client, const gchar *remote_id, const gchar *key, diff --git a/libfwupd/fwupd.map b/libfwupd/fwupd.map index eeec23e2e..360b2d955 100644 --- a/libfwupd/fwupd.map +++ b/libfwupd/fwupd.map @@ -450,6 +450,7 @@ LIBFWUPD_1.4.1 { LIBFWUPD_1.4.5 { global: fwupd_client_download_bytes; + fwupd_client_refresh_remote; fwupd_client_set_feature_flags; fwupd_client_set_user_agent; fwupd_client_set_user_agent_for_package; diff --git a/src/fu-util.c b/src/fu-util.c index ae7c189f7..34ccc09d3 100644 --- a/src/fu-util.c +++ b/src/fu-util.c @@ -1079,46 +1079,6 @@ fu_util_download_file (FuUtilPrivate *priv, return fu_common_set_contents_bytes (fn, blob, error); } -static gboolean -fu_util_download_metadata_for_remote (FuUtilPrivate *priv, - FwupdRemote *remote, - GError **error) -{ - g_autofree gchar *basename_asc = NULL; - g_autofree gchar *basename_id_asc = NULL; - g_autofree gchar *basename_id = NULL; - g_autofree gchar *basename = NULL; - g_autofree gchar *filename = NULL; - g_autofree gchar *filename_asc = NULL; - - /* download the signature */ - basename_asc = g_path_get_basename (fwupd_remote_get_filename_cache_sig (remote)); - basename_id_asc = g_strdup_printf ("%s-%s", fwupd_remote_get_id (remote), basename_asc); - filename_asc = fu_util_get_user_cache_path (basename_id_asc); - if (!fu_common_mkdir_parent (filename_asc, error)) - return FALSE; - if (!fu_util_download_file (priv, fwupd_remote_get_metadata_uri_sig (remote), filename_asc, NULL, error)) - return FALSE; - - /* find the download URI of the metadata from the JCat file */ - if (!fwupd_remote_load_signature (remote, filename_asc, error)) - return FALSE; - - /* download the metadata */ - basename = g_path_get_basename (fwupd_remote_get_filename_cache (remote)); - basename_id = g_strdup_printf ("%s-%s", fwupd_remote_get_id (remote), basename); - filename = fu_util_get_user_cache_path (basename_id); - if (!fu_util_download_file (priv, fwupd_remote_get_metadata_uri (remote), filename, NULL, error)) - return FALSE; - - /* send all this to fwupd */ - return fwupd_client_update_metadata (priv->client, - fwupd_remote_get_id (remote), - filename, - filename_asc, - NULL, error); -} - static gboolean fu_util_download_metadata_enable_lvfs (FuUtilPrivate *priv, GError **error) { @@ -1141,7 +1101,8 @@ fu_util_download_metadata_enable_lvfs (FuUtilPrivate *priv, GError **error) return FALSE; /* refresh the newly-enabled remote */ - return fu_util_download_metadata_for_remote (priv, remote, error); + return fwupd_client_refresh_remote (priv->client, remote, + priv->cancellable, error); } static gboolean @@ -1214,7 +1175,9 @@ fu_util_download_metadata (FuUtilPrivate *priv, GError **error) if (fwupd_remote_get_kind (remote) != FWUPD_REMOTE_KIND_DOWNLOAD) continue; download_remote_enabled = TRUE; - if (!fu_util_download_metadata_for_remote (priv, remote, error)) + g_print ("%s %s\n", _("Updating"), fwupd_remote_get_id (remote)); + if (!fwupd_client_refresh_remote (priv->client, remote, + priv->cancellable, error)) return FALSE; } From 59f871deda4ffe74df2d7a05b00e6dfc64f3334f Mon Sep 17 00:00:00 2001 From: Richard Hughes Date: Thu, 9 Jul 2020 10:53:45 +0100 Subject: [PATCH 268/607] libfwupd: Move GUnixInputStream-creating functions to common code We'll need to use them from other methods soon. --- libfwupd/fwupd-client.c | 56 +++--------------------------- libfwupd/fwupd-common-private.h | 11 ++++++ libfwupd/fwupd-common.c | 60 +++++++++++++++++++++++++++++++++ 3 files changed, 75 insertions(+), 52 deletions(-) diff --git a/libfwupd/fwupd-client.c b/libfwupd/fwupd-client.c index ea02837f8..ccc45db86 100644 --- a/libfwupd/fwupd-client.c +++ b/libfwupd/fwupd-client.c @@ -10,13 +10,10 @@ #include #include #ifdef HAVE_GIO_UNIX -#include #include -#include #endif #include -#include #include #include #include @@ -1656,51 +1653,6 @@ fwupd_client_update_metadata_fds (FwupdClient *client, return TRUE; } -static GUnixInputStream * -fwupd_client_input_stream_from_fn (const gchar *fn, GError **error) -{ - gint fd = open (fn, O_RDONLY); - if (fd < 0) { - g_set_error (error, - FWUPD_ERROR, - FWUPD_ERROR_INVALID_FILE, - "failed to open %s", fn); - return NULL; - } - return G_UNIX_INPUT_STREAM (g_unix_input_stream_new (fd, TRUE)); -} - -static GUnixInputStream * -fwupd_client_input_stream_from_bytes (GBytes *bytes, GError **error) -{ - gint fd; - gssize rc; - - fd = memfd_create ("fwupd", MFD_CLOEXEC); - if (fd < 0) { - g_set_error_literal (error, - FWUPD_ERROR, - FWUPD_ERROR_INVALID_FILE, - "failed to create memfd"); - return NULL; - } - rc = write (fd, g_bytes_get_data (bytes, NULL), g_bytes_get_size (bytes)); - if (rc < 0) { - g_set_error (error, - FWUPD_ERROR, - FWUPD_ERROR_INVALID_FILE, - "failed to write %" G_GSSIZE_FORMAT, rc); - return NULL; - } - if (lseek (fd, 0, SEEK_SET) < 0) { - g_set_error (error, - FWUPD_ERROR, - FWUPD_ERROR_INVALID_FILE, - "failed to seek: %s", g_strerror (errno)); - return NULL; - } - return G_UNIX_INPUT_STREAM (g_unix_input_stream_new (fd, TRUE)); -} #endif /** @@ -1747,10 +1699,10 @@ fwupd_client_update_metadata (FwupdClient *client, return FALSE; /* open files */ - istr = fwupd_client_input_stream_from_fn (metadata_fn, error); + istr = fwupd_unix_input_stream_from_fn (metadata_fn, error); if (istr == NULL) return FALSE; - istr_sig = fwupd_client_input_stream_from_fn (signature_fn, error); + istr_sig = fwupd_unix_input_stream_from_fn (signature_fn, error); if (istr_sig == NULL) return FALSE; return fwupd_client_update_metadata_fds (client, remote_id, @@ -1805,10 +1757,10 @@ fwupd_client_update_metadata_bytes (FwupdClient *client, g_return_val_if_fail (error == NULL || *error == NULL, FALSE); /* convert bytes to a readable fd */ - istr = fwupd_client_input_stream_from_bytes (metadata, error); + istr = fwupd_unix_input_stream_from_bytes (metadata, error); if (istr == NULL) return FALSE; - istr_sig = fwupd_client_input_stream_from_bytes (signature, error); + istr_sig = fwupd_unix_input_stream_from_bytes (signature, error); if (istr_sig == NULL) return FALSE; return fwupd_client_update_metadata_fds (client, remote_id, diff --git a/libfwupd/fwupd-common-private.h b/libfwupd/fwupd-common-private.h index 9423468b5..fc1f91474 100644 --- a/libfwupd/fwupd-common-private.h +++ b/libfwupd/fwupd-common-private.h @@ -8,6 +8,10 @@ #include +#ifdef HAVE_GIO_UNIX +#include +#endif + #include "fwupd-common.h" G_BEGIN_DECLS @@ -17,4 +21,11 @@ GVariant *fwupd_hash_kv_to_variant (GHashTable *hash); GHashTable *fwupd_variant_to_hash_kv (GVariant *dict); gchar *fwupd_build_user_agent_system (void); +#ifdef HAVE_GIO_UNIX +GUnixInputStream *fwupd_unix_input_stream_from_bytes (GBytes *bytes, + GError **error); +GUnixInputStream *fwupd_unix_input_stream_from_fn (const gchar *fn, + GError **error); +#endif + G_END_DECLS diff --git a/libfwupd/fwupd-common.c b/libfwupd/fwupd-common.c index b938d523c..40bfc0387 100644 --- a/libfwupd/fwupd-common.c +++ b/libfwupd/fwupd-common.c @@ -11,6 +11,12 @@ #include "fwupd-error.h" #include "fwupd-release.h" +#ifdef HAVE_GIO_UNIX +#include +#include +#include +#endif + #include #include #ifdef HAVE_UTSNAME_H @@ -934,3 +940,57 @@ fwupd_variant_to_hash_kv (GVariant *dict) g_hash_table_insert (hash, g_strdup (key), g_strdup (value)); return hash; } + +#ifdef HAVE_GIO_UNIX +/** + * fwupd_unix_input_stream_from_bytes: (skip): + **/ +GUnixInputStream * +fwupd_unix_input_stream_from_bytes (GBytes *bytes, GError **error) +{ + gint fd; + gssize rc; + + fd = memfd_create ("fwupd", MFD_CLOEXEC); + if (fd < 0) { + g_set_error_literal (error, + FWUPD_ERROR, + FWUPD_ERROR_INVALID_FILE, + "failed to create memfd"); + return NULL; + } + rc = write (fd, g_bytes_get_data (bytes, NULL), g_bytes_get_size (bytes)); + if (rc < 0) { + g_set_error (error, + FWUPD_ERROR, + FWUPD_ERROR_INVALID_FILE, + "failed to write %" G_GSSIZE_FORMAT, rc); + return NULL; + } + if (lseek (fd, 0, SEEK_SET) < 0) { + g_set_error (error, + FWUPD_ERROR, + FWUPD_ERROR_INVALID_FILE, + "failed to seek: %s", g_strerror (errno)); + return NULL; + } + return G_UNIX_INPUT_STREAM (g_unix_input_stream_new (fd, TRUE)); +} + +/** + * fwupd_unix_input_stream_from_fn: (skip): + **/ +GUnixInputStream * +fwupd_unix_input_stream_from_fn (const gchar *fn, GError **error) +{ + gint fd = open (fn, O_RDONLY); + if (fd < 0) { + g_set_error (error, + FWUPD_ERROR, + FWUPD_ERROR_INVALID_FILE, + "failed to open %s", fn); + return NULL; + } + return G_UNIX_INPUT_STREAM (g_unix_input_stream_new (fd, TRUE)); +} +#endif From 02d94d31393cae8c2d95df89a76fb63f14f8f94e Mon Sep 17 00:00:00 2001 From: Richard Hughes Date: Thu, 9 Jul 2020 10:41:10 +0100 Subject: [PATCH 269/607] libfwupd: Add fwupd_client_install_bytes() Sometimes you do not have a filename and just a blob of memory. --- libfwupd/fwupd-client.c | 211 +++++++++++++++++++++++++--------------- libfwupd/fwupd-client.h | 6 ++ libfwupd/fwupd.map | 1 + 3 files changed, 141 insertions(+), 77 deletions(-) diff --git a/libfwupd/fwupd-client.c b/libfwupd/fwupd-client.c index ccc45db86..d1539239a 100644 --- a/libfwupd/fwupd-client.c +++ b/libfwupd/fwupd-client.c @@ -1247,6 +1247,135 @@ fwupd_client_send_message_cb (GObject *source_object, GAsyncResult *res, gpointe } #endif +#ifdef HAVE_GIO_UNIX +static gboolean +fwupd_client_install_fd (FwupdClient *client, + const gchar *device_id, + GUnixInputStream *istr, + const gchar *filename_hint, + FwupdInstallFlags install_flags, + GCancellable *cancellable, + GError **error) +{ + FwupdClientPrivate *priv = GET_PRIVATE (client); + GVariant *body; + GVariantBuilder builder; + gint retval; + g_autoptr(FwupdClientHelper) helper = NULL; + g_autoptr(GDBusMessage) request = NULL; + g_autoptr(GUnixFDList) fd_list = NULL; + + /* set options */ + g_variant_builder_init (&builder, G_VARIANT_TYPE_VARDICT); + g_variant_builder_add (&builder, "{sv}", + "reason", g_variant_new_string ("user-action")); + if (filename_hint != NULL) { + g_variant_builder_add (&builder, "{sv}", + "filename", g_variant_new_string (filename_hint)); + } + if (install_flags & FWUPD_INSTALL_FLAG_OFFLINE) { + g_variant_builder_add (&builder, "{sv}", + "offline", g_variant_new_boolean (TRUE)); + } + if (install_flags & FWUPD_INSTALL_FLAG_ALLOW_OLDER) { + g_variant_builder_add (&builder, "{sv}", + "allow-older", g_variant_new_boolean (TRUE)); + } + if (install_flags & FWUPD_INSTALL_FLAG_ALLOW_REINSTALL) { + g_variant_builder_add (&builder, "{sv}", + "allow-reinstall", g_variant_new_boolean (TRUE)); + } + if (install_flags & FWUPD_INSTALL_FLAG_FORCE) { + g_variant_builder_add (&builder, "{sv}", + "force", g_variant_new_boolean (TRUE)); + } + if (install_flags & FWUPD_INSTALL_FLAG_NO_HISTORY) { + g_variant_builder_add (&builder, "{sv}", + "no-history", g_variant_new_boolean (TRUE)); + } + + /* set out of band file descriptor */ + fd_list = g_unix_fd_list_new (); + retval = g_unix_fd_list_append (fd_list, g_unix_input_stream_get_fd (istr), NULL); + g_assert (retval != -1); + request = g_dbus_message_new_method_call (FWUPD_DBUS_SERVICE, + FWUPD_DBUS_PATH, + FWUPD_DBUS_INTERFACE, + "Install"); + g_dbus_message_set_unix_fd_list (request, fd_list); + + /* call into daemon */ + helper = fwupd_client_helper_new (); + body = g_variant_new ("(sha{sv})", device_id, g_unix_input_stream_get_fd (istr), &builder); + g_dbus_message_set_body (request, body); + g_dbus_connection_send_message_with_reply (priv->conn, + request, + G_DBUS_SEND_MESSAGE_FLAGS_NONE, + G_MAXINT, + NULL, + cancellable, + fwupd_client_send_message_cb, + helper); + g_main_loop_run (helper->loop); + if (!helper->ret) { + g_propagate_error (error, helper->error); + helper->error = NULL; + return FALSE; + } + return TRUE; +} +#endif + +/** + * fwupd_client_install_bytes: + * @client: A #FwupdClient + * @device_id: the device ID + * @bytes: #GBytes + * @install_flags: the #FwupdInstallFlags, e.g. %FWUPD_INSTALL_FLAG_ALLOW_REINSTALL + * @cancellable: the #GCancellable, or %NULL + * @error: the #GError, or %NULL + * + * Install firmware onto a specific device. + * + * Returns: %TRUE for success + * + * Since: 1.4.5 + **/ +gboolean +fwupd_client_install_bytes (FwupdClient *client, + const gchar *device_id, + GBytes *bytes, + FwupdInstallFlags install_flags, + GCancellable *cancellable, + GError **error) +{ +#ifdef HAVE_GIO_UNIX + g_autoptr(GUnixInputStream) istr = NULL; + + g_return_val_if_fail (FWUPD_IS_CLIENT (client), FALSE); + g_return_val_if_fail (device_id != NULL, FALSE); + g_return_val_if_fail (bytes != NULL, FALSE); + g_return_val_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable), FALSE); + g_return_val_if_fail (error == NULL || *error == NULL, FALSE); + + /* connect */ + if (!fwupd_client_connect (client, cancellable, error)) + return FALSE; + + istr = fwupd_unix_input_stream_from_bytes (bytes, error); + if (istr == NULL) + return FALSE; + return fwupd_client_install_fd (client, device_id, istr, NULL, + install_flags, cancellable, error); +#else + g_set_error_literal (error, + FWUPD_ERROR, + FWUPD_ERROR_NOT_SUPPORTED, + "Not supported as is unavailable"); + return FALSE; +#endif +} + /** * fwupd_client_install: * @client: A #FwupdClient @@ -1271,14 +1400,7 @@ fwupd_client_install (FwupdClient *client, GError **error) { #ifdef HAVE_GIO_UNIX - FwupdClientPrivate *priv = GET_PRIVATE (client); - GVariant *body; - GVariantBuilder builder; - gint retval; - gint fd; - g_autoptr(FwupdClientHelper) helper = NULL; - g_autoptr(GDBusMessage) request = NULL; - g_autoptr(GUnixFDList) fd_list = NULL; + g_autoptr(GUnixInputStream) istr = NULL; g_return_val_if_fail (FWUPD_IS_CLIENT (client), FALSE); g_return_val_if_fail (device_id != NULL, FALSE); @@ -1290,76 +1412,11 @@ fwupd_client_install (FwupdClient *client, if (!fwupd_client_connect (client, cancellable, error)) return FALSE; - /* set options */ - g_variant_builder_init (&builder, G_VARIANT_TYPE_VARDICT); - g_variant_builder_add (&builder, "{sv}", - "reason", g_variant_new_string ("user-action")); - g_variant_builder_add (&builder, "{sv}", - "filename", g_variant_new_string (filename)); - if (install_flags & FWUPD_INSTALL_FLAG_OFFLINE) { - g_variant_builder_add (&builder, "{sv}", - "offline", g_variant_new_boolean (TRUE)); - } - if (install_flags & FWUPD_INSTALL_FLAG_ALLOW_OLDER) { - g_variant_builder_add (&builder, "{sv}", - "allow-older", g_variant_new_boolean (TRUE)); - } - if (install_flags & FWUPD_INSTALL_FLAG_ALLOW_REINSTALL) { - g_variant_builder_add (&builder, "{sv}", - "allow-reinstall", g_variant_new_boolean (TRUE)); - } - if (install_flags & FWUPD_INSTALL_FLAG_FORCE) { - g_variant_builder_add (&builder, "{sv}", - "force", g_variant_new_boolean (TRUE)); - } - if (install_flags & FWUPD_INSTALL_FLAG_NO_HISTORY) { - g_variant_builder_add (&builder, "{sv}", - "no-history", g_variant_new_boolean (TRUE)); - } - - /* open file */ - fd = open (filename, O_RDONLY); - if (fd < 0) { - g_set_error (error, - FWUPD_ERROR, - FWUPD_ERROR_INVALID_FILE, - "failed to open %s", - filename); + istr = fwupd_unix_input_stream_from_fn (filename, error); + if (istr == NULL) return FALSE; - } - - /* set out of band file descriptor */ - fd_list = g_unix_fd_list_new (); - retval = g_unix_fd_list_append (fd_list, fd, NULL); - g_assert (retval != -1); - request = g_dbus_message_new_method_call (FWUPD_DBUS_SERVICE, - FWUPD_DBUS_PATH, - FWUPD_DBUS_INTERFACE, - "Install"); - g_dbus_message_set_unix_fd_list (request, fd_list); - - /* g_unix_fd_list_append did a dup() already */ - close (fd); - - /* call into daemon */ - helper = fwupd_client_helper_new (); - body = g_variant_new ("(sha{sv})", device_id, fd, &builder); - g_dbus_message_set_body (request, body); - g_dbus_connection_send_message_with_reply (priv->conn, - request, - G_DBUS_SEND_MESSAGE_FLAGS_NONE, - G_MAXINT, - NULL, - cancellable, - fwupd_client_send_message_cb, - helper); - g_main_loop_run (helper->loop); - if (!helper->ret) { - g_propagate_error (error, helper->error); - helper->error = NULL; - return FALSE; - } - return TRUE; + return fwupd_client_install_fd (client, device_id, istr, filename, + install_flags, cancellable, error); #else g_set_error_literal (error, FWUPD_ERROR, diff --git a/libfwupd/fwupd-client.h b/libfwupd/fwupd-client.h index 414dca1b4..8e77ed73a 100644 --- a/libfwupd/fwupd-client.h +++ b/libfwupd/fwupd-client.h @@ -138,6 +138,12 @@ gboolean fwupd_client_install (FwupdClient *client, FwupdInstallFlags install_flags, GCancellable *cancellable, GError **error); +gboolean fwupd_client_install_bytes (FwupdClient *client, + const gchar *device_id, + GBytes *bytes, + FwupdInstallFlags install_flags, + GCancellable *cancellable, + GError **error); gboolean fwupd_client_update_metadata (FwupdClient *client, const gchar *remote_id, const gchar *metadata_fn, diff --git a/libfwupd/fwupd.map b/libfwupd/fwupd.map index 360b2d955..7a3efe278 100644 --- a/libfwupd/fwupd.map +++ b/libfwupd/fwupd.map @@ -450,6 +450,7 @@ LIBFWUPD_1.4.1 { LIBFWUPD_1.4.5 { global: fwupd_client_download_bytes; + fwupd_client_install_bytes; fwupd_client_refresh_remote; fwupd_client_set_feature_flags; fwupd_client_set_user_agent; From f4c55d888e4fbafa60be6028c8c6ed76f7dd3762 Mon Sep 17 00:00:00 2001 From: Richard Hughes Date: Thu, 9 Jul 2020 10:45:31 +0100 Subject: [PATCH 270/607] libfwupd: Add fwupd_client_install_release() This allows us to remove a lot of copy-and-paste code in GNOME Software. --- libfwupd/fwupd-client.c | 95 +++++++++++++++++++++++++ libfwupd/fwupd-client.h | 6 ++ libfwupd/fwupd.map | 1 + src/fu-util.c | 153 +++------------------------------------- 4 files changed, 113 insertions(+), 142 deletions(-) diff --git a/libfwupd/fwupd-client.c b/libfwupd/fwupd-client.c index d1539239a..bc75fe081 100644 --- a/libfwupd/fwupd-client.c +++ b/libfwupd/fwupd-client.c @@ -1426,6 +1426,101 @@ fwupd_client_install (FwupdClient *client, #endif } +/** + * fwupd_client_install_release: + * @client: A #FwupdClient + * @device: A #FwupdDevice + * @release: A #FwupdRelease + * @install_flags: the #FwupdInstallFlags, e.g. %FWUPD_INSTALL_FLAG_ALLOW_REINSTALL + * @cancellable: A #GCancellable, or %NULL + * @error: A #GError, or %NULL + * + * Installs a new release on a device, downloading the firmware if required. + * + * Returns: %TRUE for success + * + * Since: 1.4.5 + **/ +gboolean +fwupd_client_install_release (FwupdClient *client, + FwupdDevice *device, + FwupdRelease *release, + FwupdInstallFlags install_flags, + GCancellable *cancellable, + GError **error) +{ + GChecksumType checksum_type; + const gchar *checksum_expected; + const gchar *remote_id; + const gchar *uri_tmp; + g_autofree gchar *checksum_actual = NULL; + g_autofree gchar *uri_str = NULL; + g_autoptr(GBytes) blob = NULL; + + /* work out what remote-specific URI fields this should use */ + uri_tmp = fwupd_release_get_uri (release); + remote_id = fwupd_release_get_remote_id (release); + if (remote_id != NULL) { + g_autoptr(FwupdRemote) remote = NULL; + g_autofree gchar *fn = NULL; + + /* if a remote-id was specified, the remote has to exist */ + remote = fwupd_client_get_remote_by_id (client, remote_id, cancellable, error); + if (remote == NULL) + return FALSE; + + /* local and directory remotes have the firmware already */ + if (fwupd_remote_get_kind (remote) == FWUPD_REMOTE_KIND_LOCAL) { + const gchar *fn_cache = fwupd_remote_get_filename_cache (remote); + g_autofree gchar *path = g_path_get_dirname (fn_cache); + + fn = g_build_filename (path, uri_tmp, NULL); + } else if (fwupd_remote_get_kind (remote) == FWUPD_REMOTE_KIND_DIRECTORY) { + fn = g_strdup (uri_tmp + 7); + } + + /* install with flags chosen by the user */ + if (fn != NULL) { + return fwupd_client_install (client, fwupd_device_get_id (device), + fn, install_flags, cancellable, error); + } + + /* remote file */ + uri_str = fwupd_remote_build_firmware_uri (remote, uri_tmp, error); + if (uri_str == NULL) + return FALSE; + } else { + uri_str = g_strdup (uri_tmp); + } + + /* download file */ + blob = fwupd_client_download_bytes (client, uri_str, + FWUPD_CLIENT_DOWNLOAD_FLAG_NONE, + cancellable, error); + if (blob == NULL) + return FALSE; + + /* verify checksum */ + checksum_expected = fwupd_checksum_get_best (fwupd_release_get_checksums (release)); + checksum_type = fwupd_checksum_guess_kind (checksum_expected); + checksum_actual = g_compute_checksum_for_bytes (checksum_type, blob); + if (g_strcmp0 (checksum_expected, checksum_actual) != 0) { + g_set_error (error, + FWUPD_ERROR, + FWUPD_ERROR_INVALID_FILE, + "Checksum invalid, expected %s got %s", + checksum_expected, checksum_actual); + return FALSE; + } + + /* if the device specifies ONLY_OFFLINE automatically set this flag */ + if (fwupd_device_has_flag (device, FWUPD_DEVICE_FLAG_ONLY_OFFLINE)) + install_flags |= FWUPD_INSTALL_FLAG_OFFLINE; + return fwupd_client_install_bytes (client, + fwupd_device_get_id (device), blob, + install_flags, NULL, error); +} + /** * fwupd_client_get_details: * @client: A #FwupdClient diff --git a/libfwupd/fwupd-client.h b/libfwupd/fwupd-client.h index 8e77ed73a..d43001b6e 100644 --- a/libfwupd/fwupd-client.h +++ b/libfwupd/fwupd-client.h @@ -144,6 +144,12 @@ gboolean fwupd_client_install_bytes (FwupdClient *client, FwupdInstallFlags install_flags, GCancellable *cancellable, GError **error); +gboolean fwupd_client_install_release (FwupdClient *client, + FwupdDevice *device, + FwupdRelease *release, + FwupdInstallFlags install_flags, + GCancellable *cancellable, + GError **error); gboolean fwupd_client_update_metadata (FwupdClient *client, const gchar *remote_id, const gchar *metadata_fn, diff --git a/libfwupd/fwupd.map b/libfwupd/fwupd.map index 7a3efe278..961023fe0 100644 --- a/libfwupd/fwupd.map +++ b/libfwupd/fwupd.map @@ -451,6 +451,7 @@ LIBFWUPD_1.4.5 { global: fwupd_client_download_bytes; fwupd_client_install_bytes; + fwupd_client_install_release; fwupd_client_refresh_remote; fwupd_client_set_feature_flags; fwupd_client_set_user_agent; diff --git a/src/fu-util.c b/src/fu-util.c index 34ccc09d3..cdf00c8e1 100644 --- a/src/fu-util.c +++ b/src/fu-util.c @@ -78,11 +78,6 @@ struct FuUtilPrivate { }; static gboolean fu_util_report_history (FuUtilPrivate *priv, gchar **values, GError **error); -static gboolean fu_util_download_file (FuUtilPrivate *priv, - const gchar *uri_str, - const gchar *fn, - const gchar *checksum_expected, - GError **error); static void fu_util_client_notify_cb (GObject *object, @@ -562,6 +557,7 @@ static gchar * fu_util_download_if_required (FuUtilPrivate *priv, const gchar *perhapsfn, GError **error) { g_autofree gchar *filename = NULL; + g_autoptr(GBytes) blob = NULL; g_autoptr(SoupURI) uri = NULL; /* a local file */ @@ -575,7 +571,14 @@ fu_util_download_if_required (FuUtilPrivate *priv, const gchar *perhapsfn, GErro filename = fu_util_get_user_cache_path (perhapsfn); if (!fu_common_mkdir_parent (filename, error)) return NULL; - if (!fu_util_download_file (priv, perhapsfn, filename, NULL, error)) + blob = fwupd_client_download_bytes (priv->client, perhapsfn, + FWUPD_CLIENT_DOWNLOAD_FLAG_NONE, + priv->cancellable, error); + if (blob == NULL) + return NULL; + + /* save file to cache */ + if (!fu_common_set_contents_bytes (filename, blob, error)) return NULL; return g_steal_pointer (&filename); } @@ -1003,82 +1006,6 @@ fu_util_verify_update (FuUtilPrivate *priv, gchar **values, GError **error) return TRUE; } -static gboolean -fu_util_file_exists_with_checksum (const gchar *fn, - const gchar *checksum_expected, - GChecksumType checksum_type) -{ - gsize len = 0; - g_autofree gchar *checksum_actual = NULL; - g_autofree gchar *data = NULL; - - if (!g_file_get_contents (fn, &data, &len, NULL)) - return FALSE; - checksum_actual = g_compute_checksum_for_data (checksum_type, - (guchar *) data, len); - return g_strcmp0 (checksum_expected, checksum_actual) == 0; -} - -static gboolean -fu_util_download_file (FuUtilPrivate *priv, - const gchar *uri_str, - const gchar *fn, - const gchar *checksum_expected, - GError **error) -{ - GChecksumType checksum_type; - g_autoptr(GBytes) blob = NULL; - g_autoptr(GError) error_local = NULL; - g_autofree gchar *checksum_actual = NULL; - - /* check if the file already exists with the right checksum */ - checksum_type = fwupd_checksum_guess_kind (checksum_expected); - if (fu_util_file_exists_with_checksum (fn, checksum_expected, checksum_type)) { - g_debug ("skpping download as file already exists"); - return TRUE; - } - - /* download data */ - if (g_str_has_suffix (uri_str, ".jcat") || - g_str_has_suffix (uri_str, ".asc") || - g_str_has_suffix (uri_str, ".p7b") || - g_str_has_suffix (uri_str, ".p7c")) { - /* TRANSLATORS: downloading new signing file */ - g_print ("%s %s", _("Fetching signature"), uri_str); - } else if (g_str_has_suffix (uri_str, ".gz")) { - /* TRANSLATORS: downloading new metadata file */ - g_print ("%s %s", _("Fetching metadata"), uri_str); - } else if (g_str_has_suffix (uri_str, ".cab")) { - /* TRANSLATORS: downloading new firmware file */ - g_print ("%s %s", _("Fetching firmware"), uri_str); - } else { - /* TRANSLATORS: downloading unknown file */ - g_print ("%s %s", _("Fetching file"), uri_str); - } - g_print ("\n"); - blob = fwupd_client_download_bytes (priv->client, uri_str, - FWUPD_CLIENT_DOWNLOAD_FLAG_NONE, - priv->cancellable, error); - if (blob == NULL) - return FALSE; - - /* verify checksum */ - if (checksum_expected != NULL) { - checksum_actual = g_compute_checksum_for_bytes (checksum_type, blob); - if (g_strcmp0 (checksum_expected, checksum_actual) != 0) { - g_set_error (error, - FWUPD_ERROR, - FWUPD_ERROR_INVALID_FILE, - "Checksum invalid, expected %s got %s", - checksum_expected, checksum_actual); - return FALSE; - } - } - - /* save file */ - return fu_common_set_contents_bytes (fn, blob, error); -} - static gboolean fu_util_download_metadata_enable_lvfs (FuUtilPrivate *priv, GError **error) { @@ -1552,72 +1479,14 @@ fu_util_update_device_with_release (FuUtilPrivate *priv, FwupdRelease *rel, GError **error) { - GPtrArray *checksums; - const gchar *remote_id; - const gchar *uri_tmp; - g_autofree gchar *fn = NULL; - g_autofree gchar *uri_str = NULL; - if (!priv->no_safety_check && !priv->assume_yes) { if (!fu_util_prompt_warning (dev, fu_util_get_tree_title (priv), error)) return FALSE; } - - /* work out what remote-specific URI fields this should use */ - uri_tmp = fwupd_release_get_uri (rel); - remote_id = fwupd_release_get_remote_id (rel); - if (remote_id != NULL) { - g_autoptr(FwupdRemote) remote = NULL; - remote = fwupd_client_get_remote_by_id (priv->client, - remote_id, - NULL, - error); - if (remote == NULL) - return FALSE; - - /* local and directory remotes have the firmware already */ - if (fwupd_remote_get_kind (remote) == FWUPD_REMOTE_KIND_LOCAL) { - const gchar *fn_cache = fwupd_remote_get_filename_cache (remote); - g_autofree gchar *path = g_path_get_dirname (fn_cache); - - fn = g_build_filename (path, uri_tmp, NULL); - } else if (fwupd_remote_get_kind (remote) == FWUPD_REMOTE_KIND_DIRECTORY) { - fn = g_strdup (uri_tmp + 7); - } - /* install with flags chosen by the user */ - if (fn != NULL) { - return fwupd_client_install (priv->client, - fwupd_device_get_id (dev), - fn, priv->flags, NULL, error); - } - - uri_str = fwupd_remote_build_firmware_uri (remote, uri_tmp, error); - if (uri_str == NULL) - return FALSE; - } else { - uri_str = g_strdup (uri_tmp); - } - - /* download file */ - g_print ("Downloading %s for %s...\n", - fwupd_release_get_version (rel), - fwupd_device_get_name (dev)); - fn = fu_util_get_user_cache_path (uri_str); - if (!fu_common_mkdir_parent (fn, error)) - return FALSE; - checksums = fwupd_release_get_checksums (rel); - if (!fu_util_download_file (priv, uri_str, fn, - fwupd_checksum_get_best (checksums), - error)) - return FALSE; - /* if the device specifies ONLY_OFFLINE automatically set this flag */ - if (fwupd_device_has_flag (dev, FWUPD_DEVICE_FLAG_ONLY_OFFLINE)) - priv->flags |= FWUPD_INSTALL_FLAG_OFFLINE; - return fwupd_client_install (priv->client, - fwupd_device_get_id (dev), fn, - priv->flags, NULL, error); + return fwupd_client_install_release (priv->client, dev, rel, priv->flags, + priv->cancellable, error); } static gboolean From ec9eb9061f4e672172cb720200db632974e011f0 Mon Sep 17 00:00:00 2001 From: Mario Limonciello Date: Fri, 10 Jul 2020 13:42:31 -0500 Subject: [PATCH 271/607] trivial: add oui quirk for samsung (Fixes: #2070) --- plugins/ata/ata.quirk | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/plugins/ata/ata.quirk b/plugins/ata/ata.quirk index 801011347..dcfccb8c6 100644 --- a/plugins/ata/ata.quirk +++ b/plugins/ata/ata.quirk @@ -38,6 +38,10 @@ VendorId = ATA:0x101C Vendor = LITE-ON VendorId = ATA:0x14A4 +[DeviceInstanceId=OUI\0024e9] +Vendor = Samsung +VendorId = ATA:0x144D + [DeviceInstanceId=OUI\002538] Vendor = Samsung VendorId = ATA:0x144D From 9a04ce8f298ff6746d8e0fd63667a11a782a2cba Mon Sep 17 00:00:00 2001 From: Richard Hughes Date: Thu, 21 May 2020 21:18:48 +0100 Subject: [PATCH 272/607] msr: Add a new plugin to detect the Intel DCI state --- contrib/ci/debian_s390x.sh | 1 + contrib/debian/lintian/fwupd | 1 + contrib/debian/rules | 4 +- contrib/fwupd.spec.in | 11 ++ libfwupd/fwupd-security-attr.h | 2 + meson.build | 4 + meson_options.txt | 1 + plugins/meson.build | 4 + plugins/msr/README.md | 14 +++ plugins/msr/fu-plugin-msr.c | 190 +++++++++++++++++++++++++++++++++ plugins/msr/fwupd-msr.conf | 1 + plugins/msr/meson.build | 31 ++++++ plugins/msr/msr.quirk | 3 + snap/hooks/install | 2 + snap/hooks/remove | 2 + src/fu-security-attr.c | 6 ++ 16 files changed, 275 insertions(+), 2 deletions(-) create mode 100644 plugins/msr/README.md create mode 100644 plugins/msr/fu-plugin-msr.c create mode 100644 plugins/msr/fwupd-msr.conf create mode 100644 plugins/msr/meson.build create mode 100644 plugins/msr/msr.quirk diff --git a/contrib/ci/debian_s390x.sh b/contrib/ci/debian_s390x.sh index 9b277ff5f..29797bb4c 100755 --- a/contrib/ci/debian_s390x.sh +++ b/contrib/ci/debian_s390x.sh @@ -20,6 +20,7 @@ meson .. \ -Dplugin_uefi=false \ -Dplugin_dell=false \ -Dplugin_modem_manager=false \ + -Dplugin_msr=false \ -Dplugin_redfish=false \ -Dintrospection=false \ -Dgtkdoc=false \ diff --git a/contrib/debian/lintian/fwupd b/contrib/debian/lintian/fwupd index 75afa4600..2cca20b92 100644 --- a/contrib/debian/lintian/fwupd +++ b/contrib/debian/lintian/fwupd @@ -12,3 +12,4 @@ fwupd: library-not-linked-against-libc usr/lib/*/fwupd-plugins-3/libfu_plugin_mo fwupd: library-not-linked-against-libc usr/lib/*/fwupd-plugins-3/libfu_plugin_pci_bcr.so fwupd: library-not-linked-against-libc usr/lib/*/fwupd-plugins-3/libfu_plugin_pci_mei.so fwupd: library-not-linked-against-libc usr/lib/*/fwupd-plugins-3/libfu_plugin_iommu.so +fwupd: library-not-linked-against-libc usr/lib/*/fwupd-plugins-3/libfu_plugin_msr.so diff --git a/contrib/debian/rules b/contrib/debian/rules index 1189ff6da..7b8b19be2 100755 --- a/contrib/debian/rules +++ b/contrib/debian/rules @@ -43,9 +43,9 @@ override_dh_auto_configure: export DELL="-Dplugin_dell=false"; \ fi; \ if pkg-config --exists efivar; then \ - export UEFI="-Dplugin_uefi=true -Dplugin_redfish=true -Dplugin_nvme=true $$DBX"; \ + export UEFI="-Dplugin_uefi=true -Dplugin_redfish=true -Dplugin_nvme=true -Dplugin_msr=true $$DBX"; \ else \ - export UEFI="-Dplugin_uefi=false -Dplugin_redfish=false -Dplugin_nvme=false"; \ + export UEFI="-Dplugin_uefi=false -Dplugin_redfish=false -Dplugin_nvme=false -Dplugin_msr=false"; \ fi; \ dh_auto_configure -- $$UEFI $$DELL $$FLASHROM $$CI -Dplugin_dummy=true -Dgtkdoc=true diff --git a/contrib/fwupd.spec.in b/contrib/fwupd.spec.in index 109498e25..b2f21d6ae 100644 --- a/contrib/fwupd.spec.in +++ b/contrib/fwupd.spec.in @@ -27,6 +27,10 @@ %global have_flashrom 1 %endif +%ifarch i686 x86_64 +%global have_msr 1 +%endif + # redfish is only available on this arch %ifarch x86_64 %global have_redfish 1 @@ -185,6 +189,11 @@ Data files for installed tests. -Dplugin_flashrom=true \ %else -Dplugin_flashrom=false \ +%endif +%if 0%{?have_msr} + -Dplugin_msr=true \ +%else + -Dplugin_msr=false \ %endif -Dplugin_thunderbolt=true \ %if 0%{?have_redfish} @@ -288,6 +297,7 @@ mkdir -p --mode=0700 $RPM_BUILD_ROOT%{_localstatedir}/lib/fwupd/gnupg %config(noreplace)%{_sysconfdir}/fwupd/remotes.d/vendor-directory.conf %config(noreplace)%{_sysconfdir}/pki/fwupd %{_sysconfdir}/pki/fwupd-metadata +%{_sysconfdir}/modules-load.d/fwupd-msr.conf %{_datadir}/dbus-1/system.d/org.freedesktop.fwupd.conf %{_datadir}/bash-completion/completions/fwupdmgr %{_datadir}/bash-completion/completions/fwupdtool @@ -367,6 +377,7 @@ mkdir -p --mode=0700 $RPM_BUILD_ROOT%{_localstatedir}/lib/fwupd/gnupg %if 0%{?have_modem_manager} %{_libdir}/fwupd-plugins-3/libfu_plugin_modem_manager.so %endif +%{_libdir}/fwupd-plugins-3/libfu_plugin_msr.so %{_libdir}/fwupd-plugins-3/libfu_plugin_nitrokey.so %if 0%{?have_uefi} %{_libdir}/fwupd-plugins-3/libfu_plugin_nvme.so diff --git a/libfwupd/fwupd-security-attr.h b/libfwupd/fwupd-security-attr.h index fff2ba9d6..7ae95816d 100644 --- a/libfwupd/fwupd-security-attr.h +++ b/libfwupd/fwupd-security-attr.h @@ -135,6 +135,8 @@ typedef enum { #define FWUPD_SECURITY_ATTR_ID_TPM_VERSION_20 "org.fwupd.hsi.TpmVersion20" /* Since: 1.5.0 */ #define FWUPD_SECURITY_ATTR_ID_UEFI_DBX "org.fwupd.hsi.UefiDbx" /* Since: 1.5.0 */ #define FWUPD_SECURITY_ATTR_ID_UEFI_SECUREBOOT "org.fwupd.hsi.UefiSecureBoot" /* Since: 1.5.0 */ +#define FWUPD_SECURITY_ATTR_ID_INTEL_DCI_ENABLED "org.fwupd.hsi.IntelDciEnabled" /* Since: 1.5.0 */ +#define FWUPD_SECURITY_ATTR_ID_INTEL_DCI_LOCKED "org.fwupd.hsi.IntelDciLocked" /* Since: 1.5.0 */ FwupdSecurityAttr *fwupd_security_attr_new (const gchar *appstream_id); gchar *fwupd_security_attr_to_string (FwupdSecurityAttr *self); diff --git a/meson.build b/meson.build index 2db4b1162..c597d40e0 100644 --- a/meson.build +++ b/meson.build @@ -265,6 +265,10 @@ if cc.has_header('fnmatch.h') endif if cc.has_header('cpuid.h') and (host_cpu == 'x86' or host_cpu == 'x86_64') conf.set('HAVE_CPUID_H', '1') +else + if get_option('plugin_msr') + error('cpuid.h is required for -Dplugin_msr=true') + endif endif if cc.has_function('getuid') conf.set('HAVE_GETUID', '1') diff --git a/meson_options.txt b/meson_options.txt index 2e8f71a4b..031f68ed0 100644 --- a/meson_options.txt +++ b/meson_options.txt @@ -19,6 +19,7 @@ option('plugin_tpm', type : 'boolean', value : true, description : 'enable TPM s option('plugin_uefi', type : 'boolean', value : true, description : 'enable UEFI support') option('plugin_nvme', type : 'boolean', value : true, description : 'enable NVMe support') option('plugin_modem_manager', type : 'boolean', value : false, description : 'enable ModemManager support') +option('plugin_msr', type : 'boolean', value : true, description : 'enable MSR support') option('plugin_flashrom', type : 'boolean', value : false, description : 'enable libflashrom support') option('plugin_coreboot', type : 'boolean', value : true, description : 'enable coreboot support') option('plugin_linux_spi_lpc', type : 'boolean', value : false, description : 'enable Linux SPI SecurityFS support') diff --git a/plugins/meson.build b/plugins/meson.build index e1ec6a612..e6735f67b 100644 --- a/plugins/meson.build +++ b/plugins/meson.build @@ -31,6 +31,10 @@ subdir('upower') subdir('wacom-usb') subdir('vli') +if get_option('plugin_msr') +subdir('msr') +endif + if get_option('plugin_linux_spi_lpc') subdir('linux-spi-lpc') endif diff --git a/plugins/msr/README.md b/plugins/msr/README.md new file mode 100644 index 000000000..a5a245160 --- /dev/null +++ b/plugins/msr/README.md @@ -0,0 +1,14 @@ +MSR +=== + +Introduction +------------ + +This plugin checks if the Model-specific registers (MSRs) indicate the +Direct Connect Interface (DCI) is enabled. + +DCI allows debugging of Intel processors using the USB3 port. DCI should +always be disabled and locked on production hardware as it allows the +attacker to disable other firmware protection methods. + +The result will be stored in a security attribute for HSI. diff --git a/plugins/msr/fu-plugin-msr.c b/plugins/msr/fu-plugin-msr.c new file mode 100644 index 000000000..3a264cc5d --- /dev/null +++ b/plugins/msr/fu-plugin-msr.c @@ -0,0 +1,190 @@ +/* + * Copyright (C) 2020 Richard Hughes + * + * SPDX-License-Identifier: LGPL-2.1+ + */ + +#include "config.h" + +#include + +#include "fu-plugin-vfuncs.h" +#include "fu-hash.h" + +typedef union { + guint32 data; + struct { + guint32 enabled : 1; + guint32 rsrvd : 29; + guint32 locked : 1; + guint32 debug_occurred : 1; + } __attribute__((packed)) fields; +} FuMsrIa32Debug; + +struct FuPluginData { + gboolean ia32_debug_supported; + FuMsrIa32Debug ia32_debug; +}; + +#define PCI_MSR_IA32_DEBUG_INTERFACE 0xc80 + +void +fu_plugin_init (FuPlugin *plugin) +{ + fu_plugin_alloc_data (plugin, sizeof (FuPluginData)); + fu_plugin_set_build_hash (plugin, FU_BUILD_HASH); + fu_plugin_add_udev_subsystem (plugin, "msr"); +} + +static gboolean +fu_plugin_msr_cpuid (guint leaf, + guint *eax, guint *ebx, + guint *ecx, guint *edx, + GError **error) +{ + guint eax_tmp = 0; + guint ebx_tmp = 0; + guint ecx_tmp = 0; + guint edx_tmp = 0; + + /* sdbg is supported: https://en.wikipedia.org/wiki/CPUID */ + if (__get_cpuid (leaf, &eax_tmp, &ebx_tmp, &ecx_tmp, &edx_tmp) == 0) { + g_set_error (error, + FWUPD_ERROR, + FWUPD_ERROR_NOT_FOUND, + "CPUID leaf 0x%x is not supported on this CPU", leaf); + return FALSE; + } + + /* success */ + if (eax != NULL) + *eax = eax_tmp; + if (ebx != NULL) + *ebx = ebx_tmp; + if (ecx != NULL) + *ecx = ecx_tmp; + if (edx != NULL) + *edx = edx_tmp; + return TRUE; +} + +gboolean +fu_plugin_startup (FuPlugin *plugin, GError **error) +{ + FuPluginData *priv = fu_plugin_get_data (plugin); + guint ecx = 0; + + /* sdbg is supported: https://en.wikipedia.org/wiki/CPUID */ + if (!fu_plugin_msr_cpuid (0x01, NULL, NULL, &ecx, NULL, error)) + return FALSE; + + priv->ia32_debug_supported = ((ecx >> 11) & 0x1) > 0; + return TRUE; +} + +gboolean +fu_plugin_udev_device_added (FuPlugin *plugin, FuUdevDevice *device, GError **error) +{ + FuPluginData *priv = fu_plugin_get_data (plugin); + guint8 buf[8] = { 0x0 }; + g_autoptr(FuDeviceLocker) locker = NULL; + g_autofree gchar *basename = NULL; + + /* interesting device? */ + if (g_strcmp0 (fu_udev_device_get_subsystem (device), "msr") != 0) + return TRUE; + + /* we only care about the first processor */ + basename = g_path_get_basename (fu_udev_device_get_sysfs_path (device)); + if (g_strcmp0 (basename, "msr0") != 0) + return TRUE; + + /* open the config */ + fu_device_set_physical_id (FU_DEVICE (device), "msr"); + locker = fu_device_locker_new (device, error); + if (locker == NULL) + return FALSE; + + /* grab MSR */ + if (priv->ia32_debug_supported) { + if (!fu_udev_device_pread_full (device, PCI_MSR_IA32_DEBUG_INTERFACE, + buf, sizeof(buf), error)) { + g_prefix_error (error, "could not read IA32_DEBUG_INTERFACE: "); + return FALSE; + } + if (!fu_common_read_uint32_safe (buf, sizeof(buf), 0x0, + &priv->ia32_debug.data, G_LITTLE_ENDIAN, + error)) + return FALSE; + g_debug ("IA32_DEBUG_INTERFACE: enabled=%i, locked=%i, debug_occurred=%i", + priv->ia32_debug.fields.enabled, + priv->ia32_debug.fields.locked, + priv->ia32_debug.fields.debug_occurred); + } + return TRUE; +} + +static void +fu_plugin_add_security_attr_dci_enabled (FuPlugin *plugin, FuSecurityAttrs *attrs) +{ + FuPluginData *priv = fu_plugin_get_data (plugin); + g_autoptr(FwupdSecurityAttr) attr = NULL; + + /* this MSR is only valid for a subset of Intel CPUs */ + if (!fu_common_is_cpu_intel ()) + return; + if (!priv->ia32_debug_supported) + return; + + /* create attr */ + attr = fwupd_security_attr_new (FWUPD_SECURITY_ATTR_ID_INTEL_DCI_ENABLED); + fwupd_security_attr_set_plugin (attr, fu_plugin_get_name (plugin)); + fwupd_security_attr_set_level (attr, FWUPD_SECURITY_ATTR_LEVEL_CRITICAL); + fu_security_attrs_append (attrs, attr); + + /* check fields */ + if (priv->ia32_debug.fields.enabled) { + fwupd_security_attr_set_result (attr, FWUPD_SECURITY_ATTR_RESULT_ENABLED); + return; + } + + /* success */ + fwupd_security_attr_add_flag (attr, FWUPD_SECURITY_ATTR_FLAG_SUCCESS); + fwupd_security_attr_set_result (attr, FWUPD_SECURITY_ATTR_RESULT_NOT_ENABLED); +} + +static void +fu_plugin_add_security_attr_dci_locked (FuPlugin *plugin, FuSecurityAttrs *attrs) +{ + FuPluginData *priv = fu_plugin_get_data (plugin); + g_autoptr(FwupdSecurityAttr) attr = NULL; + + /* this MSR is only valid for a subset of Intel CPUs */ + if (!fu_common_is_cpu_intel ()) + return; + if (!priv->ia32_debug_supported) + return; + + /* create attr */ + attr = fwupd_security_attr_new (FWUPD_SECURITY_ATTR_ID_INTEL_DCI_LOCKED); + fwupd_security_attr_set_plugin (attr, fu_plugin_get_name (plugin)); + fwupd_security_attr_set_level (attr, FWUPD_SECURITY_ATTR_LEVEL_IMPORTANT); + fu_security_attrs_append (attrs, attr); + + /* check fields */ + if (!priv->ia32_debug.fields.locked) { + fwupd_security_attr_set_result (attr, FWUPD_SECURITY_ATTR_RESULT_NOT_LOCKED); + return; + } + + /* success */ + fwupd_security_attr_add_flag (attr, FWUPD_SECURITY_ATTR_FLAG_SUCCESS); + fwupd_security_attr_set_result (attr, FWUPD_SECURITY_ATTR_RESULT_LOCKED); +} + +void +fu_plugin_add_security_attrs (FuPlugin *plugin, FuSecurityAttrs *attrs) +{ + fu_plugin_add_security_attr_dci_enabled (plugin, attrs); + fu_plugin_add_security_attr_dci_locked (plugin, attrs); +} diff --git a/plugins/msr/fwupd-msr.conf b/plugins/msr/fwupd-msr.conf new file mode 100644 index 000000000..3e5ee7fa1 --- /dev/null +++ b/plugins/msr/fwupd-msr.conf @@ -0,0 +1 @@ +msr diff --git a/plugins/msr/meson.build b/plugins/msr/meson.build new file mode 100644 index 000000000..d829e1530 --- /dev/null +++ b/plugins/msr/meson.build @@ -0,0 +1,31 @@ +cargs = ['-DG_LOG_DOMAIN="FuPluginMsr"'] + +install_data(['msr.quirk'], + install_dir: join_paths(datadir, 'fwupd', 'quirks.d') +) + +install_data(['fwupd-msr.conf'], + install_dir: join_paths(sysconfdir, 'modules-load.d') +) + +shared_module('fu_plugin_msr', + fu_hash, + sources : [ + 'fu-plugin-msr.c', + ], + include_directories : [ + root_incdir, + fwupd_incdir, + fwupdplugin_incdir, + ], + install : true, + install_dir: plugin_dir, + link_with : [ + fwupd, + fwupdplugin, + ], + c_args : cargs, + dependencies : [ + plugin_deps, + ], +) diff --git a/plugins/msr/msr.quirk b/plugins/msr/msr.quirk new file mode 100644 index 000000000..893a02c43 --- /dev/null +++ b/plugins/msr/msr.quirk @@ -0,0 +1,3 @@ +# match all devices with this udev subsystem +[DeviceInstanceId=MSR] +Plugin = msr diff --git a/snap/hooks/install b/snap/hooks/install index 419b84ecd..3302ab62e 100755 --- a/snap/hooks/install +++ b/snap/hooks/install @@ -19,3 +19,5 @@ install_if_missing etc/systemd/system/fwupd-activate.service / systemctl daemon-reload systemctl enable fwupd-activate systemctl start fwupd-activate +#msr module +install_if_missing etc/modules-load.d/fwupd-msr.conf / diff --git a/snap/hooks/remove b/snap/hooks/remove index 15f6fe5e4..350838419 100755 --- a/snap/hooks/remove +++ b/snap/hooks/remove @@ -5,3 +5,5 @@ systemctl stop fwupd-activate systemctl disable fwupd-activate rm /etc/systemd/system/fwupd-activate.service -f systemctl daemon-reload +#msr module +rm /etc/modules-load.d/fwupd-msr.conf -f diff --git a/src/fu-security-attr.c b/src/fu-security-attr.c index a346feee4..c1d3531dc 100644 --- a/src/fu-security-attr.c +++ b/src/fu-security-attr.c @@ -132,6 +132,12 @@ fu_security_attr_get_name (FwupdSecurityAttr *attr) /* TRANSLATORS: Title: if the fwupd plugins are all present and correct */ return g_strdup (_("fwupd plugins")); } + if (g_strcmp0 (appstream_id, FWUPD_SECURITY_ATTR_ID_INTEL_DCI_ENABLED) == 0 || + g_strcmp0 (appstream_id, FWUPD_SECURITY_ATTR_ID_INTEL_DCI_LOCKED) == 0) { + /* TRANSLATORS: Title: Direct Connect Interface (DCI) allows + * debugging of Intel processors using the USB3 port */ + return g_strdup (_("Intel DCI debugger")); + } /* we should not get here */ return g_strdup (fwupd_security_attr_get_name (attr)); From 474d1442f13abeb660b3de72d126fad3b45ebd13 Mon Sep 17 00:00:00 2001 From: Richard Hughes Date: Mon, 20 Jul 2020 21:00:57 +0100 Subject: [PATCH 273/607] trivial: Use proper AppStream namespacing for HSI attributes --- libfwupd/fwupd-security-attr.h | 30 +++++++++++++++--------------- 1 file changed, 15 insertions(+), 15 deletions(-) diff --git a/libfwupd/fwupd-security-attr.h b/libfwupd/fwupd-security-attr.h index 7ae95816d..54bb8cfa1 100644 --- a/libfwupd/fwupd-security-attr.h +++ b/libfwupd/fwupd-security-attr.h @@ -120,23 +120,23 @@ typedef enum { #define FWUPD_SECURITY_ATTR_ID_INTEL_CET "org.fwupd.hsi.IntelCet" /* Since: 1.5.0 */ #define FWUPD_SECURITY_ATTR_ID_INTEL_SMAP "org.fwupd.hsi.IntelSmap" /* Since: 1.5.0 */ #define FWUPD_SECURITY_ATTR_ID_IOMMU "org.fwupd.hsi.Iommu" /* Since: 1.5.0 */ -#define FWUPD_SECURITY_ATTR_ID_KERNEL_LOCKDOWN "org.fwupd.hsi.KernelLockdown" /* Since: 1.5.0 */ -#define FWUPD_SECURITY_ATTR_ID_KERNEL_SWAP "org.fwupd.hsi.KernelSwap" /* Since: 1.5.0 */ -#define FWUPD_SECURITY_ATTR_ID_KERNEL_TAINTED "org.fwupd.hsi.KernelTainted" /* Since: 1.5.0 */ -#define FWUPD_SECURITY_ATTR_ID_MEI_MANUFACTURING_MODE "org.fwupd.hsi.MeiManufacturingMode" /* Since: 1.5.0 */ -#define FWUPD_SECURITY_ATTR_ID_MEI_OVERRIDE_STRAP "org.fwupd.hsi.MeiOverrideStrap" /* Since: 1.5.0 */ -#define FWUPD_SECURITY_ATTR_ID_MEI_VERSION "org.fwupd.hsi.MeiVersion" /* Since: 1.5.0 */ -#define FWUPD_SECURITY_ATTR_ID_SPI_BIOSWE "org.fwupd.hsi.SpiBioswe" /* Since: 1.5.0 */ -#define FWUPD_SECURITY_ATTR_ID_SPI_BLE "org.fwupd.hsi.SpiBle" /* Since: 1.5.0 */ -#define FWUPD_SECURITY_ATTR_ID_SPI_SMM_BWP "org.fwupd.hsi.SpiSmmBwp" /* Since: 1.5.0 */ +#define FWUPD_SECURITY_ATTR_ID_KERNEL_LOCKDOWN "org.fwupd.hsi.Kernel.Lockdown" /* Since: 1.5.0 */ +#define FWUPD_SECURITY_ATTR_ID_KERNEL_SWAP "org.fwupd.hsi.Kernel.Swap" /* Since: 1.5.0 */ +#define FWUPD_SECURITY_ATTR_ID_KERNEL_TAINTED "org.fwupd.hsi.Kernel.Tainted" /* Since: 1.5.0 */ +#define FWUPD_SECURITY_ATTR_ID_MEI_MANUFACTURING_MODE "org.fwupd.hsi.Mei.ManufacturingMode" /* Since: 1.5.0 */ +#define FWUPD_SECURITY_ATTR_ID_MEI_OVERRIDE_STRAP "org.fwupd.hsi.Mei.OverrideStrap" /* Since: 1.5.0 */ +#define FWUPD_SECURITY_ATTR_ID_MEI_VERSION "org.fwupd.hsi.Mei.Version" /* Since: 1.5.0 */ +#define FWUPD_SECURITY_ATTR_ID_SPI_BIOSWE "org.fwupd.hsi.Spi.Bioswe" /* Since: 1.5.0 */ +#define FWUPD_SECURITY_ATTR_ID_SPI_BLE "org.fwupd.hsi.Spi.Ble" /* Since: 1.5.0 */ +#define FWUPD_SECURITY_ATTR_ID_SPI_SMM_BWP "org.fwupd.hsi.Spi.SmmBwp" /* Since: 1.5.0 */ #define FWUPD_SECURITY_ATTR_ID_SUSPEND_TO_IDLE "org.fwupd.hsi.SuspendToIdle" /* Since: 1.5.0 */ #define FWUPD_SECURITY_ATTR_ID_SUSPEND_TO_RAM "org.fwupd.hsi.SuspendToRam" /* Since: 1.5.0 */ -#define FWUPD_SECURITY_ATTR_ID_TPM_RECONSTRUCTION_PCR0 "org.fwupd.hsi.TpmReconstructionPcr0" /* Since: 1.5.0 */ -#define FWUPD_SECURITY_ATTR_ID_TPM_VERSION_20 "org.fwupd.hsi.TpmVersion20" /* Since: 1.5.0 */ -#define FWUPD_SECURITY_ATTR_ID_UEFI_DBX "org.fwupd.hsi.UefiDbx" /* Since: 1.5.0 */ -#define FWUPD_SECURITY_ATTR_ID_UEFI_SECUREBOOT "org.fwupd.hsi.UefiSecureBoot" /* Since: 1.5.0 */ -#define FWUPD_SECURITY_ATTR_ID_INTEL_DCI_ENABLED "org.fwupd.hsi.IntelDciEnabled" /* Since: 1.5.0 */ -#define FWUPD_SECURITY_ATTR_ID_INTEL_DCI_LOCKED "org.fwupd.hsi.IntelDciLocked" /* Since: 1.5.0 */ +#define FWUPD_SECURITY_ATTR_ID_TPM_RECONSTRUCTION_PCR0 "org.fwupd.hsi.Tpm.ReconstructionPcr0" /* Since: 1.5.0 */ +#define FWUPD_SECURITY_ATTR_ID_TPM_VERSION_20 "org.fwupd.hsi.Tpm.Version20" /* Since: 1.5.0 */ +#define FWUPD_SECURITY_ATTR_ID_UEFI_DBX "org.fwupd.hsi.Uefi.Dbx" /* Since: 1.5.0 */ +#define FWUPD_SECURITY_ATTR_ID_UEFI_SECUREBOOT "org.fwupd.hsi.Uefi.SecureBoot" /* Since: 1.5.0 */ +#define FWUPD_SECURITY_ATTR_ID_INTEL_DCI_ENABLED "org.fwupd.hsi.IntelDci.Enabled" /* Since: 1.5.0 */ +#define FWUPD_SECURITY_ATTR_ID_INTEL_DCI_LOCKED "org.fwupd.hsi.IntelDci.Locked" /* Since: 1.5.0 */ FwupdSecurityAttr *fwupd_security_attr_new (const gchar *appstream_id); gchar *fwupd_security_attr_to_string (FwupdSecurityAttr *self); From f8c10c2b11b5065d6bbebcd3213bbb46d5de9ca2 Mon Sep 17 00:00:00 2001 From: Richard Hughes Date: Mon, 20 Jul 2020 21:01:39 +0100 Subject: [PATCH 274/607] Use --plugins for the fwupdtool argument name This is much more obvious than --plugin-enable=foo,bar,baz ever was. --- src/fu-tool.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/fu-tool.c b/src/fu-tool.c index fb7037b0c..941266842 100644 --- a/src/fu-tool.c +++ b/src/fu-tool.c @@ -2057,7 +2057,7 @@ main (int argc, char *argv[]) { "show-all-devices", '\0', 0, G_OPTION_ARG_NONE, &priv->show_all_devices, /* TRANSLATORS: command line option */ _("Show devices that are not updatable"), NULL }, - { "plugin-enable", '\0', 0, G_OPTION_ARG_STRING_ARRAY, &plugin_glob, + { "plugins", '\0', 0, G_OPTION_ARG_STRING_ARRAY, &plugin_glob, /* TRANSLATORS: command line option */ _("Manually enable specific plugins"), NULL }, { "prepare", '\0', 0, G_OPTION_ARG_NONE, &priv->prepare_blob, From 30f7ffbdbd6d4159a0b2031a88dc342dad5d6f42 Mon Sep 17 00:00:00 2001 From: Richard Hughes Date: Mon, 20 Jul 2020 21:04:00 +0100 Subject: [PATCH 275/607] pci-mei: Split up the bootguard HSI checks into multiple entries Additionally, demote the error policy to HSI-3 and do not show the other failures if BootGuard is disabled. Fixes https://github.com/fwupd/fwupd/issues/2265 --- libfwupd/fwupd-security-attr.h | 6 +- plugins/pci-mei/fu-plugin-pci-mei.c | 100 +++++++++++++++++++++++++++- src/fu-security-attr.c | 22 +++++- 3 files changed, 123 insertions(+), 5 deletions(-) diff --git a/libfwupd/fwupd-security-attr.h b/libfwupd/fwupd-security-attr.h index 54bb8cfa1..1bde33ae9 100644 --- a/libfwupd/fwupd-security-attr.h +++ b/libfwupd/fwupd-security-attr.h @@ -116,7 +116,11 @@ typedef enum { #define FWUPD_SECURITY_ATTR_ID_FWUPD_ATTESTATION "org.fwupd.hsi.FwupdAttestation" /* Since: 1.5.0 */ #define FWUPD_SECURITY_ATTR_ID_FWUPD_PLUGINS "org.fwupd.hsi.FwupdPlugins" /* Since: 1.5.0 */ #define FWUPD_SECURITY_ATTR_ID_FWUPD_UPDATES "org.fwupd.hsi.FwupdUpdates" /* Since: 1.5.0 */ -#define FWUPD_SECURITY_ATTR_ID_INTEL_BOOTGUARD "org.fwupd.hsi.IntelBootguard" /* Since: 1.5.0 */ +#define FWUPD_SECURITY_ATTR_ID_INTEL_BOOTGUARD_ENABLED "org.fwupd.hsi.IntelBootguard.Enabled" /* Since: 1.5.0 */ +#define FWUPD_SECURITY_ATTR_ID_INTEL_BOOTGUARD_VERIFIED "org.fwupd.hsi.IntelBootguard.Verified" /* Since: 1.5.0 */ +#define FWUPD_SECURITY_ATTR_ID_INTEL_BOOTGUARD_ACM "org.fwupd.hsi.IntelBootguard.Acm" /* Since: 1.5.0 */ +#define FWUPD_SECURITY_ATTR_ID_INTEL_BOOTGUARD_POLICY "org.fwupd.hsi.IntelBootguard.Policy" /* Since: 1.5.0 */ +#define FWUPD_SECURITY_ATTR_ID_INTEL_BOOTGUARD_OTP "org.fwupd.hsi.IntelBootguard.Otp" /* Since: 1.5.0 */ #define FWUPD_SECURITY_ATTR_ID_INTEL_CET "org.fwupd.hsi.IntelCet" /* Since: 1.5.0 */ #define FWUPD_SECURITY_ATTR_ID_INTEL_SMAP "org.fwupd.hsi.IntelSmap" /* Since: 1.5.0 */ #define FWUPD_SECURITY_ATTR_ID_IOMMU "org.fwupd.hsi.Iommu" /* Since: 1.5.0 */ diff --git a/plugins/pci-mei/fu-plugin-pci-mei.c b/plugins/pci-mei/fu-plugin-pci-mei.c index 9c8231d19..579046d16 100644 --- a/plugins/pci-mei/fu-plugin-pci-mei.c +++ b/plugins/pci-mei/fu-plugin-pci-mei.c @@ -259,13 +259,13 @@ fu_plugin_add_security_attrs_override_strap (FuPlugin *plugin, FuSecurityAttrs * } static void -fu_plugin_add_security_attrs_bootguard (FuPlugin *plugin, FuSecurityAttrs *attrs) +fu_plugin_add_security_attrs_bootguard_enabled (FuPlugin *plugin, FuSecurityAttrs *attrs) { FuPluginData *priv = fu_plugin_get_data (plugin); g_autoptr(FwupdSecurityAttr) attr = NULL; /* create attr */ - attr = fwupd_security_attr_new (FWUPD_SECURITY_ATTR_ID_INTEL_BOOTGUARD); + attr = fwupd_security_attr_new (FWUPD_SECURITY_ATTR_ID_INTEL_BOOTGUARD_ENABLED); fwupd_security_attr_set_plugin (attr, fu_plugin_get_name (plugin)); fwupd_security_attr_set_level (attr, FWUPD_SECURITY_ATTR_LEVEL_IMPORTANT); fu_security_attrs_append (attrs, attr); @@ -276,24 +276,108 @@ fu_plugin_add_security_attrs_bootguard (FuPlugin *plugin, FuSecurityAttrs *attrs return; } + /* success */ + fwupd_security_attr_add_flag (attr, FWUPD_SECURITY_ATTR_FLAG_SUCCESS); + fwupd_security_attr_set_result (attr, FWUPD_SECURITY_ATTR_RESULT_ENABLED); +} + +static void +fu_plugin_add_security_attrs_bootguard_verified (FuPlugin *plugin, FuSecurityAttrs *attrs) +{ + FuPluginData *priv = fu_plugin_get_data (plugin); + g_autoptr(FwupdSecurityAttr) attr = NULL; + + /* disabled */ + if (priv->hfsts6.fields.boot_guard_disable) + return; + + /* create attr */ + attr = fwupd_security_attr_new (FWUPD_SECURITY_ATTR_ID_INTEL_BOOTGUARD_VERIFIED); + fwupd_security_attr_set_plugin (attr, fu_plugin_get_name (plugin)); + fwupd_security_attr_set_level (attr, FWUPD_SECURITY_ATTR_LEVEL_IMPORTANT); + fu_security_attrs_append (attrs, attr); + /* measured boot is not sufficient, verified is required */ if (!priv->hfsts6.fields.verified_boot) { fwupd_security_attr_set_result (attr, FWUPD_SECURITY_ATTR_RESULT_NOT_VALID); return; } + /* success */ + fwupd_security_attr_add_flag (attr, FWUPD_SECURITY_ATTR_FLAG_SUCCESS); + fwupd_security_attr_set_result (attr, FWUPD_SECURITY_ATTR_RESULT_VALID); +} + +static void +fu_plugin_add_security_attrs_bootguard_acm (FuPlugin *plugin, FuSecurityAttrs *attrs) +{ + FuPluginData *priv = fu_plugin_get_data (plugin); + g_autoptr(FwupdSecurityAttr) attr = NULL; + + /* disabled */ + if (priv->hfsts6.fields.boot_guard_disable) + return; + + /* create attr */ + attr = fwupd_security_attr_new (FWUPD_SECURITY_ATTR_ID_INTEL_BOOTGUARD_ACM); + fwupd_security_attr_set_plugin (attr, fu_plugin_get_name (plugin)); + fwupd_security_attr_set_level (attr, FWUPD_SECURITY_ATTR_LEVEL_IMPORTANT); + fu_security_attrs_append (attrs, attr); + /* ACM protection required */ if (!priv->hfsts6.fields.force_boot_guard_acm) { fwupd_security_attr_set_result (attr, FWUPD_SECURITY_ATTR_RESULT_NOT_VALID); return; } + /* success */ + fwupd_security_attr_add_flag (attr, FWUPD_SECURITY_ATTR_FLAG_SUCCESS); + fwupd_security_attr_set_result (attr, FWUPD_SECURITY_ATTR_RESULT_VALID); +} + +static void +fu_plugin_add_security_attrs_bootguard_policy (FuPlugin *plugin, FuSecurityAttrs *attrs) +{ + FuPluginData *priv = fu_plugin_get_data (plugin); + g_autoptr(FwupdSecurityAttr) attr = NULL; + + /* disabled */ + if (priv->hfsts6.fields.boot_guard_disable) + return; + + /* create attr */ + attr = fwupd_security_attr_new (FWUPD_SECURITY_ATTR_ID_INTEL_BOOTGUARD_POLICY); + fwupd_security_attr_set_plugin (attr, fu_plugin_get_name (plugin)); + fwupd_security_attr_set_level (attr, FWUPD_SECURITY_ATTR_LEVEL_THEORETICAL); + fu_security_attrs_append (attrs, attr); + /* policy must be to immediatly shutdown */ if (priv->hfsts6.fields.error_enforce_policy != ME_HFS_ENFORCEMENT_POLICY_SHUTDOWN_NOW) { fwupd_security_attr_set_result (attr, FWUPD_SECURITY_ATTR_RESULT_NOT_VALID); return; } + /* success */ + fwupd_security_attr_add_flag (attr, FWUPD_SECURITY_ATTR_FLAG_SUCCESS); + fwupd_security_attr_set_result (attr, FWUPD_SECURITY_ATTR_RESULT_VALID); +} + +static void +fu_plugin_add_security_attrs_bootguard_otp (FuPlugin *plugin, FuSecurityAttrs *attrs) +{ + FuPluginData *priv = fu_plugin_get_data (plugin); + g_autoptr(FwupdSecurityAttr) attr = NULL; + + /* disabled */ + if (priv->hfsts6.fields.boot_guard_disable) + return; + + /* create attr */ + attr = fwupd_security_attr_new (FWUPD_SECURITY_ATTR_ID_INTEL_BOOTGUARD_OTP); + fwupd_security_attr_set_plugin (attr, fu_plugin_get_name (plugin)); + fwupd_security_attr_set_level (attr, FWUPD_SECURITY_ATTR_LEVEL_IMPORTANT); + fu_security_attrs_append (attrs, attr); + /* ensure vendor set the FPF OTP fuse */ if (!priv->hfsts6.fields.fpf_soc_lock) { fwupd_security_attr_set_result (attr, FWUPD_SECURITY_ATTR_RESULT_NOT_VALID); @@ -302,7 +386,17 @@ fu_plugin_add_security_attrs_bootguard (FuPlugin *plugin, FuSecurityAttrs *attrs /* success */ fwupd_security_attr_add_flag (attr, FWUPD_SECURITY_ATTR_FLAG_SUCCESS); - fwupd_security_attr_set_result (attr, FWUPD_SECURITY_ATTR_RESULT_LOCKED); + fwupd_security_attr_set_result (attr, FWUPD_SECURITY_ATTR_RESULT_VALID); +} + +static void +fu_plugin_add_security_attrs_bootguard (FuPlugin *plugin, FuSecurityAttrs *attrs) +{ + fu_plugin_add_security_attrs_bootguard_enabled (plugin, attrs); + fu_plugin_add_security_attrs_bootguard_verified (plugin, attrs); + fu_plugin_add_security_attrs_bootguard_acm (plugin, attrs); + fu_plugin_add_security_attrs_bootguard_policy (plugin, attrs); + fu_plugin_add_security_attrs_bootguard_otp (plugin, attrs); } static void diff --git a/src/fu-security-attr.c b/src/fu-security-attr.c index c1d3531dc..3329bf0bf 100644 --- a/src/fu-security-attr.c +++ b/src/fu-security-attr.c @@ -29,10 +29,30 @@ fu_security_attr_get_name (FwupdSecurityAttr *attr) /* TRANSLATORS: Title: DMA as in https://en.wikipedia.org/wiki/DMA_attack */ return g_strdup (_("Pre-boot DMA protection")); } - if (g_strcmp0 (appstream_id, FWUPD_SECURITY_ATTR_ID_INTEL_BOOTGUARD) == 0) { + if (g_strcmp0 (appstream_id, FWUPD_SECURITY_ATTR_ID_INTEL_BOOTGUARD_ENABLED) == 0) { /* TRANSLATORS: Title: BootGuard is a trademark from Intel */ return g_strdup (_("Intel BootGuard")); } + if (g_strcmp0 (appstream_id, FWUPD_SECURITY_ATTR_ID_INTEL_BOOTGUARD_VERIFIED) == 0) { + /* TRANSLATORS: Title: BootGuard is a trademark from Intel, + * verified boot refers to the way the boot process is verified */ + return g_strdup (_("Intel BootGuard verified boot")); + } + if (g_strcmp0 (appstream_id, FWUPD_SECURITY_ATTR_ID_INTEL_BOOTGUARD_ACM) == 0) { + /* TRANSLATORS: Title: BootGuard is a trademark from Intel, + * ACM means to verify the integrity of Initial Boot Block */ + return g_strdup (_("Intel BootGuard ACM protected")); + } + if (g_strcmp0 (appstream_id, FWUPD_SECURITY_ATTR_ID_INTEL_BOOTGUARD_POLICY) == 0) { + /* TRANSLATORS: Title: BootGuard is a trademark from Intel, + * error policy is what to do on failure */ + return g_strdup (_("Intel BootGuard error policy")); + } + if (g_strcmp0 (appstream_id, FWUPD_SECURITY_ATTR_ID_INTEL_BOOTGUARD_OTP) == 0) { + /* TRANSLATORS: Title: BootGuard is a trademark from Intel, + * OTP = one time programmable */ + return g_strdup (_("Intel BootGuard OTP fuse")); + } if (g_strcmp0 (appstream_id, FWUPD_SECURITY_ATTR_ID_INTEL_CET) == 0) { /* TRANSLATORS: Title: CET = Control-flow Enforcement Technology */ return g_strdup (_("Intel CET")); From ef3924c9eac8ff3f24bd5a2e45e65eeb73e1d7b1 Mon Sep 17 00:00:00 2001 From: Richard Hughes Date: Mon, 20 Jul 2020 21:32:51 +0100 Subject: [PATCH 276/607] trivial: Fix Debian CI --- contrib/ci/debian.sh | 1 - 1 file changed, 1 deletion(-) diff --git a/contrib/ci/debian.sh b/contrib/ci/debian.sh index 8f46311c2..d7c55f11d 100755 --- a/contrib/ci/debian.sh +++ b/contrib/ci/debian.sh @@ -38,7 +38,6 @@ lintian ../*changes \ --pedantic \ --no-tag-display-limit \ --suppress-tags bad-distribution-in-changes-file \ - --suppress-tags source-contains-unsafe-symlink \ --suppress-tags debian-watch-file-in-native-package \ --suppress-tags source-nmu-has-incorrect-version-number \ --suppress-tags no-symbols-control-file \ From fa540cf539514c5b76930f8bdb40ecb62ac77c35 Mon Sep 17 00:00:00 2001 From: Richard Hughes Date: Wed, 22 Jul 2020 09:45:42 +0100 Subject: [PATCH 277/607] trivial: Fix aarch64 Fedora build --- contrib/fwupd.spec.in | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/contrib/fwupd.spec.in b/contrib/fwupd.spec.in index b2f21d6ae..eb3031bca 100644 --- a/contrib/fwupd.spec.in +++ b/contrib/fwupd.spec.in @@ -297,7 +297,9 @@ mkdir -p --mode=0700 $RPM_BUILD_ROOT%{_localstatedir}/lib/fwupd/gnupg %config(noreplace)%{_sysconfdir}/fwupd/remotes.d/vendor-directory.conf %config(noreplace)%{_sysconfdir}/pki/fwupd %{_sysconfdir}/pki/fwupd-metadata +%if 0%{?have_msr} %{_sysconfdir}/modules-load.d/fwupd-msr.conf +%endif %{_datadir}/dbus-1/system.d/org.freedesktop.fwupd.conf %{_datadir}/bash-completion/completions/fwupdmgr %{_datadir}/bash-completion/completions/fwupdtool @@ -377,7 +379,9 @@ mkdir -p --mode=0700 $RPM_BUILD_ROOT%{_localstatedir}/lib/fwupd/gnupg %if 0%{?have_modem_manager} %{_libdir}/fwupd-plugins-3/libfu_plugin_modem_manager.so %endif +%if 0%{?have_msr} %{_libdir}/fwupd-plugins-3/libfu_plugin_msr.so +%endif %{_libdir}/fwupd-plugins-3/libfu_plugin_nitrokey.so %if 0%{?have_uefi} %{_libdir}/fwupd-plugins-3/libfu_plugin_nvme.so From 4e13a790df695b83ae60c3b751654f16026afd5e Mon Sep 17 00:00:00 2001 From: Richard Hughes Date: Wed, 22 Jul 2020 12:33:21 +0100 Subject: [PATCH 278/607] vli: Rename FuVliUsbhubI2cDevice to FuVliUsbhubMsp430Device MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The I²C proxy specification is not always shared with all other devices as I originally hoped, instead there are other legacy devices that use different sets of I²C commands. Un-share various bits of code to allow for additional I²C devices to be added. No logic changes. --- plugins/vli/fu-vli-usbhub-device.c | 87 +-------- plugins/vli/fu-vli-usbhub-device.h | 21 --- plugins/vli/fu-vli-usbhub-i2c-common.h | 12 -- plugins/vli/fu-vli-usbhub-i2c-device.h | 19 -- ...device.c => fu-vli-usbhub-msp430-device.c} | 165 ++++++++++++------ plugins/vli/fu-vli-usbhub-msp430-device.h | 19 ++ plugins/vli/meson.build | 2 +- plugins/vli/vli-usbhub-lenovo.quirk | 4 +- 8 files changed, 142 insertions(+), 187 deletions(-) delete mode 100644 plugins/vli/fu-vli-usbhub-i2c-device.h rename plugins/vli/{fu-vli-usbhub-i2c-device.c => fu-vli-usbhub-msp430-device.c} (62%) create mode 100644 plugins/vli/fu-vli-usbhub-msp430-device.h diff --git a/plugins/vli/fu-vli-usbhub-device.c b/plugins/vli/fu-vli-usbhub-device.c index fecf09398..493f8f20a 100644 --- a/plugins/vli/fu-vli-usbhub-device.c +++ b/plugins/vli/fu-vli-usbhub-device.c @@ -15,7 +15,7 @@ #include "fu-vli-usbhub-common.h" #include "fu-vli-usbhub-device.h" #include "fu-vli-usbhub-firmware.h" -#include "fu-vli-usbhub-i2c-device.h" +#include "fu-vli-usbhub-msp430-device.h" #include "fu-vli-usbhub-pd-device.h" struct _FuVliUsbhubDevice @@ -45,83 +45,6 @@ fu_vli_usbhub_device_to_string (FuVliDevice *device, guint idt, GString *str) } } -gboolean -fu_vli_usbhub_device_i2c_read (FuVliUsbhubDevice *self, - guint8 cmd, guint8 *buf, gsize bufsz, - GError **error) -{ - GUsbDevice *usb_device = fu_usb_device_get_dev (FU_USB_DEVICE (self)); - guint16 value = ((guint16) FU_VLI_USBHUB_I2C_ADDR_WRITE << 8) | cmd; - guint16 index = (guint16) FU_VLI_USBHUB_I2C_ADDR_READ << 8; - if (!g_usb_device_control_transfer (usb_device, - G_USB_DEVICE_DIRECTION_DEVICE_TO_HOST, - G_USB_DEVICE_REQUEST_TYPE_VENDOR, - G_USB_DEVICE_RECIPIENT_DEVICE, - FU_VLI_USBHUB_I2C_R_VDR, value, index, - buf, bufsz, NULL, - FU_VLI_DEVICE_TIMEOUT, - NULL, error)) { - g_prefix_error (error, "failed to read I2C: "); - return FALSE; - } - if (g_getenv ("FWUPD_VLI_USBHUB_VERBOSE") != NULL) - fu_common_dump_raw (G_LOG_DOMAIN, "I2cReadData", buf, bufsz); - return TRUE; -} - -gboolean -fu_vli_usbhub_device_i2c_read_status (FuVliUsbhubDevice *self, - FuVliUsbhubI2cStatus *status, - GError **error) -{ - guint8 buf[1] = { 0xff }; - if (!fu_vli_usbhub_device_i2c_read (self, - FU_VLI_USBHUB_I2C_CMD_READ_STATUS, - buf, sizeof(buf), - error)) - return FALSE; - if (status != NULL) - *status = buf[0]; - return TRUE; -} - -gboolean -fu_vli_usbhub_device_i2c_write_data (FuVliUsbhubDevice *self, - guint8 disable_start_bit, - guint8 disable_end_bit, - const guint8 *buf, - gsize bufsz, - GError **error) -{ - GUsbDevice *usb_device = fu_usb_device_get_dev (FU_USB_DEVICE (self)); - guint16 value = (((guint16) disable_start_bit) << 8) | disable_end_bit; - if (g_getenv ("FWUPD_VLI_USBHUB_VERBOSE") != NULL) - fu_common_dump_raw (G_LOG_DOMAIN, "I2cWriteData", buf, bufsz); - if (!g_usb_device_control_transfer (usb_device, - G_USB_DEVICE_DIRECTION_HOST_TO_DEVICE, - G_USB_DEVICE_REQUEST_TYPE_VENDOR, - G_USB_DEVICE_RECIPIENT_DEVICE, - FU_VLI_USBHUB_I2C_W_VDR, value, 0x0, - (guint8 *) buf, bufsz, NULL, - FU_VLI_DEVICE_TIMEOUT, - NULL, error)) { - g_prefix_error (error, "failed to write I2C @0x%x: ", value); - return FALSE; - } - return TRUE; -} - -gboolean -fu_vli_usbhub_device_i2c_write (FuVliUsbhubDevice *self, guint8 cmd, - const guint8 *buf, gsize bufsz, GError **error) -{ - guint8 buf2[10] = { FU_VLI_USBHUB_I2C_ADDR_WRITE, cmd, 0x0 }; - if (!fu_memcpy_safe (buf2, sizeof(buf2), 0x2, - buf, bufsz, 0x0, bufsz, error)) - return FALSE; - return fu_vli_usbhub_device_i2c_write_data (self, 0x0, 0x0, buf2, bufsz + 2, error); -} - static gboolean fu_vli_usbhub_device_vdr_unlock_813 (FuVliUsbhubDevice *self, GError **error) { @@ -616,13 +539,13 @@ fu_vli_usbhub_device_pd_setup (FuVliUsbhubDevice *self, GError **error) } static gboolean -fu_vli_usbhub_device_i2c_setup (FuVliUsbhubDevice *self, GError **error) +fu_vli_usbhub_device_msp430_setup (FuVliUsbhubDevice *self, GError **error) { g_autoptr(FuDevice) dev = NULL; g_autoptr(GError) error_local = NULL; /* add child */ - dev = fu_vli_usbhub_i2c_device_new (self); + dev = fu_vli_usbhub_msp430_device_new (self); if (!fu_device_probe (dev, error)) return FALSE; if (!fu_device_setup (dev, &error_local)) { @@ -720,8 +643,8 @@ fu_vli_usbhub_device_setup (FuVliDevice *device, GError **error) /* detect the I²C child */ if (fu_usb_device_get_spec (FU_USB_DEVICE (self)) >= 0x0300 && - fu_device_has_custom_flag (FU_DEVICE (self), "has-shared-spi-i2c")) { - if (!fu_vli_usbhub_device_i2c_setup (self, error)) + fu_device_has_custom_flag (FU_DEVICE (self), "has-msp430")) { + if (!fu_vli_usbhub_device_msp430_setup (self, error)) return FALSE; } diff --git a/plugins/vli/fu-vli-usbhub-device.h b/plugins/vli/fu-vli-usbhub-device.h index 1aacd804d..7cb15f572 100644 --- a/plugins/vli/fu-vli-usbhub-device.h +++ b/plugins/vli/fu-vli-usbhub-device.h @@ -9,7 +9,6 @@ #include "fu-plugin.h" #include "fu-vli-device.h" -#include "fu-vli-usbhub-i2c-common.h" #define FU_TYPE_VLI_USBHUB_DEVICE (fu_vli_usbhub_device_get_type ()) G_DECLARE_FINAL_TYPE (FuVliUsbhubDevice, fu_vli_usbhub_device, FU, VLI_USBHUB_DEVICE, FuVliDevice) @@ -18,23 +17,3 @@ struct _FuVliUsbhubDeviceClass { FuVliDeviceClass parent_class; }; - -gboolean fu_vli_usbhub_device_i2c_read (FuVliUsbhubDevice *self, - guint8 cmd, - guint8 *buf, - gsize bufsz, - GError **error); -gboolean fu_vli_usbhub_device_i2c_read_status (FuVliUsbhubDevice *self, - FuVliUsbhubI2cStatus *status, - GError **error); -gboolean fu_vli_usbhub_device_i2c_write (FuVliUsbhubDevice *self, - guint8 cmd, - const guint8 *buf, - gsize bufsz, - GError **error); -gboolean fu_vli_usbhub_device_i2c_write_data (FuVliUsbhubDevice *self, - guint8 disable_start_bit, - guint8 disable_end_bit, - const guint8 *buf, - gsize bufsz, - GError **error); diff --git a/plugins/vli/fu-vli-usbhub-i2c-common.h b/plugins/vli/fu-vli-usbhub-i2c-common.h index e638062fe..1062d9906 100644 --- a/plugins/vli/fu-vli-usbhub-i2c-common.h +++ b/plugins/vli/fu-vli-usbhub-i2c-common.h @@ -18,17 +18,5 @@ typedef enum { FU_VLI_USBHUB_I2C_STATUS_CHECKSUM = 0x55, } FuVliUsbhubI2cStatus; -/* Texas Instruments BSL */ -#define FU_VLI_USBHUB_I2C_ADDR_WRITE 0x18 -#define FU_VLI_USBHUB_I2C_ADDR_READ 0x19 - -#define FU_VLI_USBHUB_I2C_CMD_WRITE 0x32 -#define FU_VLI_USBHUB_I2C_CMD_READ_STATUS 0x33 -#define FU_VLI_USBHUB_I2C_CMD_UPGRADE 0x34 -#define FU_VLI_USBHUB_I2C_CMD_READ_VERSIONS 0x40 - -#define FU_VLI_USBHUB_I2C_R_VDR 0xa0 /* read vendor command */ -#define FU_VLI_USBHUB_I2C_W_VDR 0xb0 /* write vendor command */ - gboolean fu_vli_usbhub_i2c_check_status (FuVliUsbhubI2cStatus status, GError **error); diff --git a/plugins/vli/fu-vli-usbhub-i2c-device.h b/plugins/vli/fu-vli-usbhub-i2c-device.h deleted file mode 100644 index 27615ed62..000000000 --- a/plugins/vli/fu-vli-usbhub-i2c-device.h +++ /dev/null @@ -1,19 +0,0 @@ -/* - * Copyright (C) 2019 Richard Hughes - * - * SPDX-License-Identifier: LGPL-2.1+ - */ - -#pragma once - -#include "fu-plugin.h" - -#define FU_TYPE_VLI_USBHUB_I2C_DEVICE (fu_vli_usbhub_i2c_device_get_type ()) -G_DECLARE_FINAL_TYPE (FuVliUsbhubI2cDevice, fu_vli_usbhub_i2c_device, FU, VLI_USBHUB_I2C_DEVICE, FuDevice) - -struct _FuVliUsbhubI2cDeviceClass -{ - FuDeviceClass parent_class; -}; - -FuDevice *fu_vli_usbhub_i2c_device_new (FuVliUsbhubDevice *parent); diff --git a/plugins/vli/fu-vli-usbhub-i2c-device.c b/plugins/vli/fu-vli-usbhub-msp430-device.c similarity index 62% rename from plugins/vli/fu-vli-usbhub-i2c-device.c rename to plugins/vli/fu-vli-usbhub-msp430-device.c index a50e7f4ec..e7597b8fd 100644 --- a/plugins/vli/fu-vli-usbhub-i2c-device.c +++ b/plugins/vli/fu-vli-usbhub-msp430-device.c @@ -1,6 +1,6 @@ /* * Copyright (C) 2017-2019 VIA Corporation - * Copyright (C) 2019 Richard Hughes + * Copyright (C) 2019-2020 Richard Hughes * * SPDX-License-Identifier: LGPL-2.1+ */ @@ -13,46 +13,113 @@ #include "fu-vli-usbhub-common.h" #include "fu-vli-usbhub-device.h" #include "fu-vli-usbhub-i2c-common.h" -#include "fu-vli-usbhub-i2c-device.h" +#include "fu-vli-usbhub-msp430-device.h" -struct _FuVliUsbhubI2cDevice +struct _FuVliUsbhubMsp430Device { FuDevice parent_instance; - FuVliDeviceKind device_kind; }; -G_DEFINE_TYPE (FuVliUsbhubI2cDevice, fu_vli_usbhub_i2c_device, FU_TYPE_DEVICE) +G_DEFINE_TYPE (FuVliUsbhubMsp430Device, fu_vli_usbhub_msp430_device, FU_TYPE_DEVICE) -static void -fu_vli_usbhub_i2c_device_to_string (FuDevice *device, guint idt, GString *str) +/* Texas Instruments BSL */ +#define I2C_ADDR_WRITE 0x18 +#define I2C_ADDR_READ 0x19 + +#define I2C_CMD_WRITE 0x32 +#define I2C_CMD_READ_STATUS 0x33 +#define I2C_CMD_UPGRADE 0x34 +#define I2C_CMD_READ_VERSIONS 0x40 + +#define I2C_R_VDR 0xa0 /* read vendor command */ +#define I2C_W_VDR 0xb0 /* write vendor command */ + +static gboolean +fu_vli_usbhub_device_i2c_read (FuVliUsbhubDevice *self, + guint8 cmd, guint8 *buf, gsize bufsz, + GError **error) { - FuVliUsbhubI2cDevice *self = FU_VLI_USBHUB_I2C_DEVICE (device); - fu_common_string_append_kv (str, idt, "DeviceKind", - fu_vli_common_device_kind_to_string (self->device_kind)); + GUsbDevice *usb_device = fu_usb_device_get_dev (FU_USB_DEVICE (self)); + guint16 value = ((guint16) I2C_ADDR_WRITE << 8) | cmd; + guint16 index = (guint16) I2C_ADDR_READ << 8; + if (!g_usb_device_control_transfer (usb_device, + G_USB_DEVICE_DIRECTION_DEVICE_TO_HOST, + G_USB_DEVICE_REQUEST_TYPE_VENDOR, + G_USB_DEVICE_RECIPIENT_DEVICE, + I2C_R_VDR, value, index, + buf, bufsz, NULL, + FU_VLI_DEVICE_TIMEOUT, + NULL, error)) { + g_prefix_error (error, "failed to read I2C: "); + return FALSE; + } + if (g_getenv ("FWUPD_VLI_USBHUB_VERBOSE") != NULL) + fu_common_dump_raw (G_LOG_DOMAIN, "I2cReadData", buf, bufsz); + return TRUE; } static gboolean -fu_vli_usbhub_i2c_device_setup (FuDevice *device, GError **error) +fu_vli_usbhub_device_i2c_read_status (FuVliUsbhubDevice *self, + FuVliUsbhubI2cStatus *status, + GError **error) +{ + guint8 buf[1] = { 0xff }; + if (!fu_vli_usbhub_device_i2c_read (self, + I2C_CMD_READ_STATUS, + buf, sizeof(buf), + error)) + return FALSE; + if (status != NULL) + *status = buf[0]; + return TRUE; +} + +static gboolean +fu_vli_usbhub_device_i2c_write_data (FuVliUsbhubDevice *self, + guint8 disable_start_bit, + guint8 disable_end_bit, + const guint8 *buf, + gsize bufsz, + GError **error) +{ + GUsbDevice *usb_device = fu_usb_device_get_dev (FU_USB_DEVICE (self)); + guint16 value = (((guint16) disable_start_bit) << 8) | disable_end_bit; + if (g_getenv ("FWUPD_VLI_USBHUB_VERBOSE") != NULL) + fu_common_dump_raw (G_LOG_DOMAIN, "I2cWriteData", buf, bufsz); + if (!g_usb_device_control_transfer (usb_device, + G_USB_DEVICE_DIRECTION_HOST_TO_DEVICE, + G_USB_DEVICE_REQUEST_TYPE_VENDOR, + G_USB_DEVICE_RECIPIENT_DEVICE, + I2C_W_VDR, value, 0x0, + (guint8 *) buf, bufsz, NULL, + FU_VLI_DEVICE_TIMEOUT, + NULL, error)) { + g_prefix_error (error, "failed to write I2C @0x%x: ", value); + return FALSE; + } + return TRUE; +} + +static gboolean +fu_vli_usbhub_msp430_device_setup (FuDevice *device, GError **error) { - FuVliUsbhubI2cDevice *self = FU_VLI_USBHUB_I2C_DEVICE (device); FuVliUsbhubDevice *parent = FU_VLI_USBHUB_DEVICE (fu_device_get_parent (device)); guint8 buf[11] = { 0x0 }; g_autofree gchar *version = NULL; /* get versions */ if (!fu_vli_usbhub_device_i2c_read (parent, - FU_VLI_USBHUB_I2C_CMD_READ_VERSIONS, + I2C_CMD_READ_VERSIONS, buf, sizeof(buf), error)) { g_prefix_error (error, "failed to read versions: "); return FALSE; } if ((buf[0] == 0x00 && buf[1] == 0x00 && buf[2] == 0x00) || (buf[0] == 0xff && buf[1] == 0xff && buf[2] == 0xff)) { - g_set_error (error, - FWUPD_ERROR, - FWUPD_ERROR_NOT_FOUND, - "no %s device detected", - fu_vli_common_device_kind_to_string (self->device_kind)); + g_set_error_literal (error, + FWUPD_ERROR, + FWUPD_ERROR_NOT_FOUND, + "no MSP430 device detected"); return FALSE; } @@ -63,14 +130,14 @@ fu_vli_usbhub_i2c_device_setup (FuDevice *device, GError **error) } static gboolean -fu_vli_usbhub_i2c_device_detach (FuDevice *device, GError **error) +fu_vli_usbhub_msp430_device_detach (FuDevice *device, GError **error) { FuVliUsbhubDevice *parent = FU_VLI_USBHUB_DEVICE (fu_device_get_parent (device)); FuVliUsbhubI2cStatus status = 0xff; g_autoptr(FuDeviceLocker) locker = NULL; const guint8 buf[] = { - FU_VLI_USBHUB_I2C_ADDR_WRITE, - FU_VLI_USBHUB_I2C_CMD_UPGRADE, + I2C_ADDR_WRITE, + I2C_CMD_UPGRADE, }; /* open device */ @@ -94,10 +161,10 @@ fu_vli_usbhub_i2c_device_detach (FuDevice *device, GError **error) } static FuFirmware * -fu_vli_usbhub_i2c_device_prepare_firmware (FuDevice *device, - GBytes *fw, - FwupdInstallFlags flags, - GError **error) +fu_vli_usbhub_msp430_device_prepare_firmware (FuDevice *device, + GBytes *fw, + FwupdInstallFlags flags, + GError **error) { g_autoptr(FuFirmware) firmware = fu_ihex_firmware_new (); fu_device_set_status (device, FWUPD_STATUS_DECOMPRESSING); @@ -114,7 +181,7 @@ typedef struct { } FuVliUsbhubDeviceRequest; static gboolean -fu_vli_usbhub_i2c_device_write_firmware_cb (FuDevice *device, gpointer user_data, GError **error) +fu_vli_usbhub_msp430_device_write_firmware_cb (FuDevice *device, gpointer user_data, GError **error) { FuVliUsbhubDeviceRequest *req = (FuVliUsbhubDeviceRequest *) user_data; FuVliUsbhubDevice *parent = FU_VLI_USBHUB_DEVICE (fu_device_get_parent (device)); @@ -157,10 +224,10 @@ fu_vli_usbhub_i2c_device_write_firmware_cb (FuDevice *device, gpointer user_data } static gboolean -fu_vli_usbhub_i2c_device_write_firmware (FuDevice *device, - FuFirmware *firmware, - FwupdInstallFlags flags, - GError **error) +fu_vli_usbhub_msp430_device_write_firmware (FuDevice *device, + FuFirmware *firmware, + FwupdInstallFlags flags, + GError **error) { FuVliUsbhubDevice *parent = FU_VLI_USBHUB_DEVICE (fu_device_get_parent (device)); GPtrArray *records = fu_ihex_firmware_get_records (FU_IHEX_FIRMWARE (firmware)); @@ -218,8 +285,8 @@ fu_vli_usbhub_i2c_device_write_firmware (FuDevice *device, } /* write each record directly to the hardware */ - req.buf[0] = FU_VLI_USBHUB_I2C_ADDR_WRITE; - req.buf[1] = FU_VLI_USBHUB_I2C_CMD_WRITE; + req.buf[0] = I2C_ADDR_WRITE; + req.buf[1] = I2C_CMD_WRITE; req.buf[2] = 0x3a; /* ':' */ req.buf[3] = req.len; req.buf[4] = fu_firmware_strparse_uint8 (line + 3); @@ -232,7 +299,7 @@ fu_vli_usbhub_i2c_device_write_firmware (FuDevice *device, /* retry this if it fails */ if (!fu_device_retry (device, - fu_vli_usbhub_i2c_device_write_firmware_cb, + fu_vli_usbhub_msp430_device_write_firmware_cb, 5, &req, error)) return FALSE; fu_device_set_progress_full (device, (gsize) j, (gsize) records->len); @@ -251,27 +318,26 @@ fu_vli_usbhub_i2c_device_write_firmware (FuDevice *device, } static gboolean -fu_vli_usbhub_i2c_device_probe (FuDevice *device, GError **error) +fu_vli_usbhub_msp430_device_probe (FuDevice *device, GError **error) { + FuVliDeviceKind device_kind = FU_VLI_DEVICE_KIND_MSP430; FuVliUsbhubDevice *parent = FU_VLI_USBHUB_DEVICE (fu_device_get_parent (device)); - FuVliUsbhubI2cDevice *self = FU_VLI_USBHUB_I2C_DEVICE (device); g_autofree gchar *instance_id = NULL; - self->device_kind = FU_VLI_DEVICE_KIND_MSP430; - fu_device_set_name (device, fu_vli_common_device_kind_to_string (self->device_kind)); + fu_device_set_name (device, fu_vli_common_device_kind_to_string (device_kind)); /* add instance ID */ instance_id = g_strdup_printf ("USB\\VID_%04X&PID_%04X&I2C_%s", fu_usb_device_get_vid (FU_USB_DEVICE (parent)), fu_usb_device_get_pid (FU_USB_DEVICE (parent)), - fu_vli_common_device_kind_to_string (self->device_kind)); + fu_vli_common_device_kind_to_string (device_kind)); fu_device_add_instance_id (device, instance_id); return TRUE; } static void -fu_vli_usbhub_i2c_device_init (FuVliUsbhubI2cDevice *self) +fu_vli_usbhub_msp430_device_init (FuVliUsbhubMsp430Device *self) { fu_device_add_icon (FU_DEVICE (self), "audio-card"); fu_device_set_protocol (FU_DEVICE (self), "com.vli.i2c"); @@ -286,22 +352,21 @@ fu_vli_usbhub_i2c_device_init (FuVliUsbhubI2cDevice *self) } static void -fu_vli_usbhub_i2c_device_class_init (FuVliUsbhubI2cDeviceClass *klass) +fu_vli_usbhub_msp430_device_class_init (FuVliUsbhubMsp430DeviceClass *klass) { FuDeviceClass *klass_device = FU_DEVICE_CLASS (klass); - klass_device->to_string = fu_vli_usbhub_i2c_device_to_string; - klass_device->probe = fu_vli_usbhub_i2c_device_probe; - klass_device->setup = fu_vli_usbhub_i2c_device_setup; - klass_device->detach = fu_vli_usbhub_i2c_device_detach; - klass_device->write_firmware = fu_vli_usbhub_i2c_device_write_firmware; - klass_device->prepare_firmware = fu_vli_usbhub_i2c_device_prepare_firmware; + klass_device->probe = fu_vli_usbhub_msp430_device_probe; + klass_device->setup = fu_vli_usbhub_msp430_device_setup; + klass_device->detach = fu_vli_usbhub_msp430_device_detach; + klass_device->write_firmware = fu_vli_usbhub_msp430_device_write_firmware; + klass_device->prepare_firmware = fu_vli_usbhub_msp430_device_prepare_firmware; } FuDevice * -fu_vli_usbhub_i2c_device_new (FuVliUsbhubDevice *parent) +fu_vli_usbhub_msp430_device_new (FuVliUsbhubDevice *parent) { - FuVliUsbhubI2cDevice *self = g_object_new (FU_TYPE_VLI_USBHUB_I2C_DEVICE, - "parent", parent, - NULL); + FuVliUsbhubMsp430Device *self = g_object_new (FU_TYPE_VLI_USBHUB_MSP430_DEVICE, + "parent", parent, + NULL); return FU_DEVICE (self); } diff --git a/plugins/vli/fu-vli-usbhub-msp430-device.h b/plugins/vli/fu-vli-usbhub-msp430-device.h new file mode 100644 index 000000000..f2097eccd --- /dev/null +++ b/plugins/vli/fu-vli-usbhub-msp430-device.h @@ -0,0 +1,19 @@ +/* + * Copyright (C) 2019-2020 Richard Hughes + * + * SPDX-License-Identifier: LGPL-2.1+ + */ + +#pragma once + +#include "fu-plugin.h" + +#define FU_TYPE_VLI_USBHUB_MSP430_DEVICE (fu_vli_usbhub_msp430_device_get_type ()) +G_DECLARE_FINAL_TYPE (FuVliUsbhubMsp430Device, fu_vli_usbhub_msp430_device, FU, VLI_USBHUB_MSP430_DEVICE, FuDevice) + +struct _FuVliUsbhubMsp430DeviceClass +{ + FuDeviceClass parent_class; +}; + +FuDevice *fu_vli_usbhub_msp430_device_new (FuVliUsbhubDevice *parent); diff --git a/plugins/vli/meson.build b/plugins/vli/meson.build index 30e10a01f..7f8fc616c 100644 --- a/plugins/vli/meson.build +++ b/plugins/vli/meson.build @@ -22,7 +22,7 @@ shared_module('fu_plugin_vli', 'fu-vli-usbhub-device.c', 'fu-vli-usbhub-firmware.c', 'fu-vli-usbhub-i2c-common.c', - 'fu-vli-usbhub-i2c-device.c', + 'fu-vli-usbhub-msp430-device.c', 'fu-vli-usbhub-pd-device.c', ], include_directories : [ diff --git a/plugins/vli/vli-usbhub-lenovo.quirk b/plugins/vli/vli-usbhub-lenovo.quirk index 4f9637584..637c1aeb2 100644 --- a/plugins/vli/vli-usbhub-lenovo.quirk +++ b/plugins/vli/vli-usbhub-lenovo.quirk @@ -32,14 +32,14 @@ ParentGuid = TBT-01081720 [DeviceInstanceId=USB\VID_17EF&PID_307F] Plugin = vli GType = FuVliUsbhubDevice -Flags = usb3,has-shared-spi-i2c +Flags = usb3,has-msp430 CounterpartGuid = USB\VID_17EF&PID_3080 [DeviceInstanceId=USB\VID_17EF&PID_307F&HUB_0006] ParentGuid = USB\VID_17EF&PID_307F&HUB_0002 [DeviceInstanceId=USB\VID_17EF&PID_3080] Plugin = vli GType = FuVliUsbhubDevice -Flags = usb2,has-shared-spi-i2c +Flags = usb2,has-msp430 [DeviceInstanceId=USB\VID_17EF&PID_3080&HUB_06] ParentGuid = USB\VID_17EF&PID_3080&HUB_20 [DeviceInstanceId=USB\VID_17EF&PID_3080&HUB_20] From 9b819e634c98200ac2381200d5c6a6bb59bcac7c Mon Sep 17 00:00:00 2001 From: Torsten Hilbrich Date: Wed, 22 Jul 2020 15:55:28 +0200 Subject: [PATCH 279/607] fu-util: Allow get-updates without download remotes If a system is configured without any downloadable remotes (e.g. with a remote pointing to a local directory) the call of fwupdmgr get-updates fails by outputting "No remotes enabled." even though the call "get-remotes" clearly shows the configured remote. I found the following commit: commit 991c95697e7f98585ec46c8cadfc1f7525e7f244 Author: Mario Limonciello Date: Wed Jun 17 15:23:13 2020 -0500 trivial: fu-util: correct an assertion when no remotes configured introduced the problem. In the call chain: fu_util_get_updates -> fu_util_perhaps_refresh_remotes -> fu_util_check_oldest_remote the function fu_util_check_oldest_remote now returns FALSE if no remote of kind FWUPD_REMOTE_KIND_DOWNLOAD is found. The function fu_util_perhaps_refresh_remotes then returns FALSE indicating failure even though without a downloadable remote the concept of refreshing is not useful. I think, we should return TRUE in this case, as no refresh is needed and the operation can continue. As the failure of fu_util_check_oldest_remote is ignored we also need to pass NULL as error pointer here. The use-case of this scenario without downloadable remote is by distributing firmware updates through software updates where the vendor directory with the capsule file is provided. --- src/fu-util.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/fu-util.c b/src/fu-util.c index cdf00c8e1..11ae78fc2 100644 --- a/src/fu-util.c +++ b/src/fu-util.c @@ -1333,8 +1333,8 @@ fu_util_perhaps_refresh_remotes (FuUtilPrivate *priv, GError **error) return TRUE; } - if (!fu_util_check_oldest_remote (priv, &age_oldest, error)) - return FALSE; + if (!fu_util_check_oldest_remote (priv, &age_oldest, NULL)) + return TRUE; /* metadata is new enough */ if (age_oldest < 60 * 60 * 24 * age_limit_days) From a99b5adfb6cc78eaeb34d2db268a5579fcb72bba Mon Sep 17 00:00:00 2001 From: Richard Hughes Date: Thu, 23 Jul 2020 07:57:11 +0100 Subject: [PATCH 280/607] trivial: Export fwupd_client_ensure_networking() This is required when the calling application needs the low-level soup-session with the user agent set correctly rather than using the helper methods like fwupd_client_download_bytes(). This is what GNOME Software needs to handle the GsApp progress completion. --- libfwupd/fwupd-client.c | 15 ++++++++++++++- libfwupd/fwupd-client.h | 2 ++ libfwupd/fwupd.map | 1 + 3 files changed, 17 insertions(+), 1 deletion(-) diff --git a/libfwupd/fwupd-client.c b/libfwupd/fwupd-client.c index bc75fe081..eef46d0d9 100644 --- a/libfwupd/fwupd-client.c +++ b/libfwupd/fwupd-client.c @@ -278,7 +278,20 @@ fwupd_client_signal_cb (GDBusProxy *proxy, g_debug ("Unknown signal name '%s' from %s", signal_name, sender_name); } -static gboolean +/** + * fwupd_client_ensure_networking: + * @client: A #FwupdClient + * @error: the #GError, or %NULL + * + * Sets up the client networking support ready for use. Most other download and + * upload methods call this automatically, and do you only need to call this if + * the session is being used outside the #FwupdClient. + * + * Returns: %TRUE for success + * + * Since: 1.4.5 + **/ +gboolean fwupd_client_ensure_networking (FwupdClient *client, GError **error) { FwupdClientPrivate *priv = GET_PRIVATE (client); diff --git a/libfwupd/fwupd-client.h b/libfwupd/fwupd-client.h index d43001b6e..43011c190 100644 --- a/libfwupd/fwupd-client.h +++ b/libfwupd/fwupd-client.h @@ -231,5 +231,7 @@ GBytes *fwupd_client_upload_bytes (FwupdClient *client, FwupdClientUploadFlags flags, GCancellable *cancellable, GError **error); +gboolean fwupd_client_ensure_networking (FwupdClient *client, + GError **error); G_END_DECLS diff --git a/libfwupd/fwupd.map b/libfwupd/fwupd.map index 961023fe0..a70b12756 100644 --- a/libfwupd/fwupd.map +++ b/libfwupd/fwupd.map @@ -450,6 +450,7 @@ LIBFWUPD_1.4.1 { LIBFWUPD_1.4.5 { global: fwupd_client_download_bytes; + fwupd_client_ensure_networking; fwupd_client_install_bytes; fwupd_client_install_release; fwupd_client_refresh_remote; From 8fe710135b726639afa028768407d3a6a4678e4b Mon Sep 17 00:00:00 2001 From: Richard Hughes Date: Thu, 23 Jul 2020 12:58:25 +0100 Subject: [PATCH 281/607] thelio-io: Add the DFU instance ID as a counterpart only This means we do not add possibly unwanted bootloader-specific quirks to the runtime device. --- plugins/thelio-io/fu-thelio-io-device.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/plugins/thelio-io/fu-thelio-io-device.c b/plugins/thelio-io/fu-thelio-io-device.c index bd0e56a01..425af941e 100644 --- a/plugins/thelio-io/fu-thelio-io-device.c +++ b/plugins/thelio-io/fu-thelio-io-device.c @@ -24,7 +24,8 @@ fu_thelio_io_device_probe (FuDevice *device, GError **error) g_autofree gchar *buf = NULL; g_autoptr(GUdevDevice) udev_device = NULL; - fu_device_add_instance_id (device, "USB\\VID_03EB&PID_2FF4"); + /* this is the atmel bootloader */ + fu_device_add_counterpart_guid (device, "USB\\VID_03EB&PID_2FF4"); /* convert GUsbDevice to GUdevDevice */ udev_device = fu_usb_device_find_udev_device (FU_USB_DEVICE (device), error); From 4f617e2eb62e91c13229d461da15196c0209f1ad Mon Sep 17 00:00:00 2001 From: Richard Hughes Date: Thu, 23 Jul 2020 12:59:19 +0100 Subject: [PATCH 282/607] thelio-io: Set the runtime version to 0.0.0 for pre-1.0.0 firmware --- plugins/thelio-io/fu-thelio-io-device.c | 17 +++++++++++++---- 1 file changed, 13 insertions(+), 4 deletions(-) diff --git a/plugins/thelio-io/fu-thelio-io-device.c b/plugins/thelio-io/fu-thelio-io-device.c index 425af941e..04e49f2c1 100644 --- a/plugins/thelio-io/fu-thelio-io-device.c +++ b/plugins/thelio-io/fu-thelio-io-device.c @@ -22,6 +22,7 @@ fu_thelio_io_device_probe (FuDevice *device, GError **error) const gchar *devpath; g_autofree gchar *fn = NULL; g_autofree gchar *buf = NULL; + g_autoptr(GError) error_local = NULL; g_autoptr(GUdevDevice) udev_device = NULL; /* this is the atmel bootloader */ @@ -40,11 +41,19 @@ fu_thelio_io_device_probe (FuDevice *device, GError **error) return FALSE; } + /* pre-1.0.0 firmware versions do not implement this */ fn = g_build_filename (devpath, "revision", NULL); - if (!g_file_get_contents(fn, &buf, NULL, error)) - return FALSE; - - fu_device_set_version (device, (const gchar *) buf); + if (!g_file_get_contents (fn, &buf, NULL, &error_local)) { + if (g_error_matches (error_local, G_FILE_ERROR, G_FILE_ERROR_FAILED)) { + g_debug ("FW revision unimplemented: %s", error_local->message); + fu_device_set_version (device, "0.0.0"); + } else { + g_propagate_error (error, g_steal_pointer (&error_local)); + return FALSE; + } + } else { + fu_device_set_version (device, (const gchar *) buf); + } return TRUE; } From 587ca9793f74884c7ebf0faba520fc7a8a2a8e52 Mon Sep 17 00:00:00 2001 From: Richard Hughes Date: Fri, 24 Jul 2020 17:02:17 +0100 Subject: [PATCH 283/607] nitrokey: Define the protocol on the runtime device This prevents a daemon warning. --- plugins/nitrokey/fu-nitrokey-device.c | 1 + 1 file changed, 1 insertion(+) diff --git a/plugins/nitrokey/fu-nitrokey-device.c b/plugins/nitrokey/fu-nitrokey-device.c index 493caf82d..f7ddc44ea 100644 --- a/plugins/nitrokey/fu-nitrokey-device.c +++ b/plugins/nitrokey/fu-nitrokey-device.c @@ -136,6 +136,7 @@ fu_nitrokey_device_init (FuNitrokeyDevice *device) fu_device_add_flag (FU_DEVICE (device), FWUPD_DEVICE_FLAG_UPDATABLE); fu_device_add_flag (FU_DEVICE (device), FWUPD_DEVICE_FLAG_ADD_COUNTERPART_GUIDS); fu_device_set_version_format (FU_DEVICE (device), FWUPD_VERSION_FORMAT_PAIR); + fu_device_set_protocol (FU_DEVICE (device), "org.usb.dfu"); fu_device_retry_set_delay (FU_DEVICE (device), 100); } From cb1e6075c5d64a2450a9ba1352e78c241f1574d5 Mon Sep 17 00:00:00 2001 From: Richard Hughes Date: Fri, 24 Jul 2020 17:03:03 +0100 Subject: [PATCH 284/607] thelio-io: Define the protocol on the runtime device This allows us to use 'protocol' in the device test JSON and also prevents a daemon warning at startup. --- plugins/thelio-io/fu-thelio-io-device.c | 1 + 1 file changed, 1 insertion(+) diff --git a/plugins/thelio-io/fu-thelio-io-device.c b/plugins/thelio-io/fu-thelio-io-device.c index 04e49f2c1..78c8b7e99 100644 --- a/plugins/thelio-io/fu-thelio-io-device.c +++ b/plugins/thelio-io/fu-thelio-io-device.c @@ -98,6 +98,7 @@ fu_thelio_io_device_init (FuThelioIoDevice *self) fu_device_add_flag (FU_DEVICE (self), FWUPD_DEVICE_FLAG_UPDATABLE); fu_device_set_remove_delay (FU_DEVICE (self), FU_DEVICE_REMOVE_DELAY_RE_ENUMERATE); fu_device_set_version_format (FU_DEVICE (self), FWUPD_VERSION_FORMAT_TRIPLET); + fu_device_set_protocol (FU_DEVICE (self), "org.usb.dfu"); } static void From fa34c319da523a426f11cb76be0875f96a8480ac Mon Sep 17 00:00:00 2001 From: Richard Hughes Date: Tue, 30 Jun 2020 20:37:21 +0100 Subject: [PATCH 285/607] trivial: Translate the FwupdSecurityAttrFlags suffix --- src/fu-util-common.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/fu-util-common.c b/src/fu-util-common.c index efb2623b1..1720b2746 100644 --- a/src/fu-util-common.c +++ b/src/fu-util-common.c @@ -1531,8 +1531,10 @@ fu_security_attr_append_str (FwupdSecurityAttr *attr, GString *str) g_string_append_printf (str, ": %s", fwupd_security_attr_get_url (attr)); } - if (fwupd_security_attr_has_flag (attr, FWUPD_SECURITY_ATTR_FLAG_OBSOLETED)) - g_string_append (str, " (obsoleted)"); + if (fwupd_security_attr_has_flag (attr, FWUPD_SECURITY_ATTR_FLAG_OBSOLETED)) { + /* TRANSLATORS: this is shown as a suffix for obsoleted tests */ + g_string_append_printf (str, " %s", _("(obsoleted)")); + } g_string_append_printf (str, "\n"); } From cad96542e28d2cdcc069a4f7ee0c0ad18810c716 Mon Sep 17 00:00:00 2001 From: Richard Hughes Date: Tue, 30 Jun 2020 19:22:31 +0100 Subject: [PATCH 286/607] Check if CET is actually being used on the runtime system With thanks to H.J. Lu for the initial code. --- contrib/debian/fwupd.install | 1 + contrib/fwupd.spec.in | 1 + libfwupd/fwupd-security-attr.h | 3 +- meson.build | 4 +++ plugins/cpu/fu-cpu-helper-cet-common.c | 29 +++++++++++++++++ plugins/cpu/fu-cpu-helper-cet-common.h | 10 ++++++ plugins/cpu/fu-cpu-helper-cet.c | 40 ++++++++++++++++++++++++ plugins/cpu/fu-plugin-cpu.c | 43 ++++++++++++++++++++++++-- plugins/cpu/meson.build | 29 +++++++++++++++++ src/fu-security-attr.c | 12 +++++-- 10 files changed, 165 insertions(+), 7 deletions(-) create mode 100644 plugins/cpu/fu-cpu-helper-cet-common.c create mode 100644 plugins/cpu/fu-cpu-helper-cet-common.h create mode 100644 plugins/cpu/fu-cpu-helper-cet.c diff --git a/contrib/debian/fwupd.install b/contrib/debian/fwupd.install index ebef528bf..825909ff8 100644 --- a/contrib/debian/fwupd.install +++ b/contrib/debian/fwupd.install @@ -9,6 +9,7 @@ usr/share/polkit-1/* usr/share/locale usr/share/metainfo/* usr/libexec/fwupd/fwupd +usr/libexec/fwupd/fwupd-detect-cet usr/libexec/fwupd/fwupdoffline usr/share/man/man1/* lib/systemd/system/* diff --git a/contrib/fwupd.spec.in b/contrib/fwupd.spec.in index eb3031bca..d01e1962c 100644 --- a/contrib/fwupd.spec.in +++ b/contrib/fwupd.spec.in @@ -275,6 +275,7 @@ mkdir -p --mode=0700 $RPM_BUILD_ROOT%{_localstatedir}/lib/fwupd/gnupg %config(noreplace)%{_sysconfdir}/fwupd/thunderbolt.conf %dir %{_libexecdir}/fwupd %{_libexecdir}/fwupd/fwupd +%{_libexecdir}/fwupd/fwupd-detect-cet %{_libexecdir}/fwupd/fwupdoffline %if 0%{?have_uefi} %{_libexecdir}/fwupd/efi/*.efi diff --git a/libfwupd/fwupd-security-attr.h b/libfwupd/fwupd-security-attr.h index 1bde33ae9..00f0004cd 100644 --- a/libfwupd/fwupd-security-attr.h +++ b/libfwupd/fwupd-security-attr.h @@ -121,7 +121,8 @@ typedef enum { #define FWUPD_SECURITY_ATTR_ID_INTEL_BOOTGUARD_ACM "org.fwupd.hsi.IntelBootguard.Acm" /* Since: 1.5.0 */ #define FWUPD_SECURITY_ATTR_ID_INTEL_BOOTGUARD_POLICY "org.fwupd.hsi.IntelBootguard.Policy" /* Since: 1.5.0 */ #define FWUPD_SECURITY_ATTR_ID_INTEL_BOOTGUARD_OTP "org.fwupd.hsi.IntelBootguard.Otp" /* Since: 1.5.0 */ -#define FWUPD_SECURITY_ATTR_ID_INTEL_CET "org.fwupd.hsi.IntelCet" /* Since: 1.5.0 */ +#define FWUPD_SECURITY_ATTR_ID_INTEL_CET_ENABLED "org.fwupd.hsi.IntelCet.Enabled" /* Since: 1.5.0 */ +#define FWUPD_SECURITY_ATTR_ID_INTEL_CET_ACTIVE "org.fwupd.hsi.IntelCet.Active" /* Since: 1.5.0 */ #define FWUPD_SECURITY_ATTR_ID_INTEL_SMAP "org.fwupd.hsi.IntelSmap" /* Since: 1.5.0 */ #define FWUPD_SECURITY_ATTR_ID_IOMMU "org.fwupd.hsi.Iommu" /* Since: 1.5.0 */ #define FWUPD_SECURITY_ATTR_ID_KERNEL_LOCKDOWN "org.fwupd.hsi.Kernel.Lockdown" /* Since: 1.5.0 */ diff --git a/meson.build b/meson.build index c597d40e0..00952236d 100644 --- a/meson.build +++ b/meson.build @@ -125,6 +125,7 @@ test_link_args = [ '-Wl,-z,relro', '-Wl,-z,defs', '-Wl,-z,now', + '-Wl,-z,ibt,-z,shstk', ] foreach arg: test_link_args if cc.has_link_argument(arg) @@ -276,6 +277,9 @@ endif if cc.has_function('realpath') conf.set('HAVE_REALPATH', '1') endif +if cc.has_function('sigaction') + conf.set('HAVE_SIGACTION', '1') +endif if cc.has_header_symbol('locale.h', 'LC_MESSAGES') conf.set('HAVE_LC_MESSAGES', '1') endif diff --git a/plugins/cpu/fu-cpu-helper-cet-common.c b/plugins/cpu/fu-cpu-helper-cet-common.c new file mode 100644 index 000000000..271ece7e8 --- /dev/null +++ b/plugins/cpu/fu-cpu-helper-cet-common.c @@ -0,0 +1,29 @@ +/* + * Copyright (C) 2020 Richard Hughes + * Copyright (C) 2020 H.J. Lu + * + * SPDX-License-Identifier: LGPL-2.1+ + */ + +#include "config.h" + +#include "fu-cpu-helper-cet-common.h" + +static void +fu_cpu_helper_cet_testfn_fptr (void) +{ +} + +static void +__attribute__ ((noinline, noclone)) +fu_cpu_helper_cet_testfn_call_fptr (void (*func) (void)) +{ + func (); +} + +void +__attribute__ ((noinline, noclone)) +fu_cpu_helper_cet_testfn1 (void) +{ + fu_cpu_helper_cet_testfn_call_fptr (fu_cpu_helper_cet_testfn_fptr); +} diff --git a/plugins/cpu/fu-cpu-helper-cet-common.h b/plugins/cpu/fu-cpu-helper-cet-common.h new file mode 100644 index 000000000..31130d6e3 --- /dev/null +++ b/plugins/cpu/fu-cpu-helper-cet-common.h @@ -0,0 +1,10 @@ +/* + * Copyright (C) 2020 Richard Hughes + * Copyright (C) 2020 H.J. Lu + * + * SPDX-License-Identifier: LGPL-2.1+ + */ + +#pragma once + +void fu_cpu_helper_cet_testfn1 (void); diff --git a/plugins/cpu/fu-cpu-helper-cet.c b/plugins/cpu/fu-cpu-helper-cet.c new file mode 100644 index 000000000..34aab2c6c --- /dev/null +++ b/plugins/cpu/fu-cpu-helper-cet.c @@ -0,0 +1,40 @@ +/* + * Copyright (C) 2020 Richard Hughes + * Copyright (C) 2020 H.J. Lu + * + * SPDX-License-Identifier: LGPL-2.1+ + */ + +#include "config.h" + +#include +#include + +#include "fu-cpu-helper-cet-common.h" + +#ifdef HAVE_SIGACTION +static void +segfault_sigaction (int signal, siginfo_t *si, void *arg) +{ + /* CET did exactly as it should to protect the system */ + exit (0); +} +#endif + +int +main (int argc, char *argv[]) +{ +#ifdef HAVE_SIGACTION + struct sigaction sa = { 0 }; + + sigemptyset (&sa.sa_mask); + sa.sa_sigaction = segfault_sigaction; + sa.sa_flags = SA_SIGINFO; + sigaction (SIGSEGV, &sa, NULL); +#endif + + fu_cpu_helper_cet_testfn1 (); + + /* this means CET did not work */ + return 1; +} diff --git a/plugins/cpu/fu-plugin-cpu.c b/plugins/cpu/fu-plugin-cpu.c index e5e83821a..dcb657a58 100644 --- a/plugins/cpu/fu-plugin-cpu.c +++ b/plugins/cpu/fu-plugin-cpu.c @@ -56,13 +56,13 @@ fu_plugin_coldplug (FuPlugin *plugin, GError **error) } static void -fu_plugin_add_security_attrs_intel_cet (FuPlugin *plugin, FuSecurityAttrs *attrs) +fu_plugin_add_security_attrs_intel_cet_enabled (FuPlugin *plugin, FuSecurityAttrs *attrs) { FuPluginData *data = fu_plugin_get_data (plugin); g_autoptr(FwupdSecurityAttr) attr = NULL; /* create attr */ - attr = fwupd_security_attr_new (FWUPD_SECURITY_ATTR_ID_INTEL_CET); + attr = fwupd_security_attr_new (FWUPD_SECURITY_ATTR_ID_INTEL_CET_ENABLED); fwupd_security_attr_set_plugin (attr, fu_plugin_get_name (plugin)); fwupd_security_attr_set_level (attr, FWUPD_SECURITY_ATTR_LEVEL_THEORETICAL); fu_security_attrs_append (attrs, attr); @@ -78,6 +78,42 @@ fu_plugin_add_security_attrs_intel_cet (FuPlugin *plugin, FuSecurityAttrs *attrs fwupd_security_attr_set_result (attr, FWUPD_SECURITY_ATTR_RESULT_ENABLED); } +static void +fu_plugin_add_security_attrs_intel_cet_active (FuPlugin *plugin, FuSecurityAttrs *attrs) +{ + FuPluginData *data = fu_plugin_get_data (plugin); + gint exit_status = 0xff; + g_autofree gchar *toolfn = NULL; + g_autoptr(FwupdSecurityAttr) attr = NULL; + g_autoptr(GError) error_local = NULL; + + /* check for CET */ + if (!data->has_cet) + return; + + /* create attr */ + attr = fwupd_security_attr_new (FWUPD_SECURITY_ATTR_ID_INTEL_CET_ACTIVE); + fwupd_security_attr_set_plugin (attr, fu_plugin_get_name (plugin)); + fwupd_security_attr_set_level (attr, FWUPD_SECURITY_ATTR_LEVEL_THEORETICAL); + fwupd_security_attr_add_flag (attr, FWUPD_SECURITY_ATTR_FLAG_RUNTIME_ISSUE); + fu_security_attrs_append (attrs, attr); + + /* check that userspace has been compiled for CET support */ + toolfn = g_build_filename (FWUPD_LIBEXECDIR, "fwupd", "fwupd-detect-cet", NULL); + if (!g_spawn_command_line_sync (toolfn, NULL, NULL, &exit_status, &error_local)) { + g_warning ("failed to test CET: %s", error_local->message); + return; + } + if (!g_spawn_check_exit_status (exit_status, &error_local)) { + g_debug ("CET does not function, not supported: %s", error_local->message); + fwupd_security_attr_set_result (attr, FWUPD_SECURITY_ATTR_RESULT_NOT_SUPPORTED); + } + + /* success */ + fwupd_security_attr_add_flag (attr, FWUPD_SECURITY_ATTR_FLAG_SUCCESS); + fwupd_security_attr_set_result (attr, FWUPD_SECURITY_ATTR_RESULT_SUPPORTED); +} + static void fu_plugin_add_security_attrs_intel_tme (FuPlugin *plugin, FuSecurityAttrs *attrs) { @@ -131,7 +167,8 @@ fu_plugin_add_security_attrs (FuPlugin *plugin, FuSecurityAttrs *attrs) if (!fu_common_is_cpu_intel ()) return; - fu_plugin_add_security_attrs_intel_cet (plugin, attrs); + fu_plugin_add_security_attrs_intel_cet_enabled (plugin, attrs); + fu_plugin_add_security_attrs_intel_cet_active (plugin, attrs); fu_plugin_add_security_attrs_intel_tme (plugin, attrs); fu_plugin_add_security_attrs_intel_smap (plugin, attrs); } diff --git a/plugins/cpu/meson.build b/plugins/cpu/meson.build index aaaed6e92..2fc6d6c68 100644 --- a/plugins/cpu/meson.build +++ b/plugins/cpu/meson.build @@ -22,3 +22,32 @@ shared_module('fu_plugin_cpu', plugin_deps, ], ) + +if cc.has_argument('-fcf-protection') + libfwupdcethelper = static_library('fwupdcethelper', + sources : [ + 'fu-cpu-helper-cet-common.c', + ], + include_directories : [ + root_incdir, + ], + c_args : ['-fcf-protection=none'], + install : false, + ) + + executable( + 'fwupd-detect-cet', + sources : [ + 'fu-cpu-helper-cet.c', + ], + include_directories : [ + root_incdir, + ], + link_with : [ + libfwupdcethelper, + ], + c_args : ['-fcf-protection=full'], + install : true, + install_dir : join_paths(libexecdir, 'fwupd') + ) +endif diff --git a/src/fu-security-attr.c b/src/fu-security-attr.c index 3329bf0bf..0b0bd949b 100644 --- a/src/fu-security-attr.c +++ b/src/fu-security-attr.c @@ -53,9 +53,15 @@ fu_security_attr_get_name (FwupdSecurityAttr *attr) * OTP = one time programmable */ return g_strdup (_("Intel BootGuard OTP fuse")); } - if (g_strcmp0 (appstream_id, FWUPD_SECURITY_ATTR_ID_INTEL_CET) == 0) { - /* TRANSLATORS: Title: CET = Control-flow Enforcement Technology */ - return g_strdup (_("Intel CET")); + if (g_strcmp0 (appstream_id, FWUPD_SECURITY_ATTR_ID_INTEL_CET_ENABLED) == 0) { + /* TRANSLATORS: Title: CET = Control-flow Enforcement Technology, + * enabled means supported by the processor */ + return g_strdup (_("Intel CET Enabled")); + } + if (g_strcmp0 (appstream_id, FWUPD_SECURITY_ATTR_ID_INTEL_CET_ACTIVE) == 0) { + /* TRANSLATORS: Title: CET = Control-flow Enforcement Technology, + * active means being used by the OS */ + return g_strdup (_("Intel CET Active")); } if (g_strcmp0 (appstream_id, FWUPD_SECURITY_ATTR_ID_INTEL_SMAP) == 0) { /* TRANSLATORS: Title: SMAP = Supervisor Mode Access Prevention */ From e031774a8b48a1ac8a142b411f968d48f3bcfda2 Mon Sep 17 00:00:00 2001 From: Richard Hughes Date: Mon, 27 Jul 2020 11:37:43 +0100 Subject: [PATCH 287/607] Split out the fwupd tutorial into a new file No content changes. --- docs/fwupd-docs.xml | 400 +------------------------------------------ docs/meson.build | 4 + docs/tutorial.xml | 402 ++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 407 insertions(+), 399 deletions(-) create mode 100644 docs/tutorial.xml diff --git a/docs/fwupd-docs.xml b/docs/fwupd-docs.xml index 129aa40f2..c2cdd5d9a 100644 --- a/docs/fwupd-docs.xml +++ b/docs/fwupd-docs.xml @@ -67,405 +67,7 @@ - - Plugin Tutorial - -
- Introduction - - At the heart of fwupd is a plugin loader that gets run at startup, - when devices get hotplugged and when updates are done. - The idea is we have lots of small plugins that each do one thing, and - are ordered by dependencies against each other at runtime. - Using plugins we can add support for new hardware or new policies - without making big changes all over the source tree. - - - There are broadly 3 types of plugin methods: - - - - - Mechanism: Upload binary data - into a specific hardware device. - - - - - Policy: Control the system when - updates are happening, e.g. preventing the user from powering-off. - - - - - Helpers: Providing more - metadata about devices, for instance handling device quirks. - - - - - In general, building things out-of-tree isn't something that we think is - a very good idea; the API and ABI internal to fwupd is still - changing and there's a huge benefit to getting plugins upstream where - they can undergo review and be ported as the API adapts. - For this reason we don't install the plugin headers onto the system, - although you can of course just install the .so binary file - manually. - - - - A plugin only needs to define the vfuncs that are required, and the - plugin name is taken automatically from the suffix of the - .so file. - - - A sample plugin - -/* - * Copyright (C) 2017 Richard Hughes - */ - -#include <fu-plugin.h> -#include <fu-plugin-vfuncs.h> - -struct FuPluginData { - gpointer proxy; -}; - -void -fu_plugin_initialize (FuPlugin *plugin) -{ - fu_plugin_add_rule (plugin, FU_PLUGIN_RULE_RUN_BEFORE, "dfu"); - fu_plugin_alloc_data (plugin, sizeof (FuPluginData)); -} - -void -fu_plugin_destroy (FuPlugin *plugin) -{ - FuPluginData *data = fu_plugin_get_data (plugin); - destroy_proxy (data->proxy); -} - -gboolean -fu_plugin_startup (FuPlugin *plugin, GError **error) -{ - FuPluginData *data = fu_plugin_get_data (plugin); - data->proxy = create_proxy (); - if (data->proxy == NULL) { - g_set_error (error, FWUPD_ERROR, FWUPD_ERROR_NOT_SUPPORTED, - "failed to create proxy"); - return FALSE; - } - return TRUE; -} - - - - - We have to define when our plugin is run in reference to other plugins, - in this case, making sure we run before the dfu plugin. - For most plugins it does not matter in what order they are run and - this information is not required. - -
- -
- Creating an abstract device - - This section shows how you would create a device which is exported - to the daemon and thus can be queried and updated by the client software. - The example here is all hardcoded, and a true plugin would have to - derive the details about the FuDevice from the hardware, - for example reading data from sysfs or /dev. - - - Example adding a custom device - -#include <fu-plugin.h> - -gboolean -fu_plugin_coldplug (FuPlugin *plugin, GError **error) -{ - g_autoptr(FuDevice) dev = NULL; - fu_device_set_id (dev, "dummy-1:2:3"); - fu_device_add_guid (dev, "2d47f29b-83a2-4f31-a2e8-63474f4d4c2e"); - fu_device_set_version (dev, "1.2.3"); - fu_device_get_version_lowest (dev, "1.2.2"); - fu_device_get_version_bootloader (dev, "0.1.2"); - fu_device_add_icon (dev, "computer"); - fu_device_add_flag (dev, FWUPD_DEVICE_FLAG_UPDATABLE); - fu_plugin_device_add (plugin, dev); - return TRUE; -} - - - - This shows a lot of the plugin architecture in action. Some notable points: - - - - - The device ID (dummy-1:2:3) has to be unique on the - system between all plugins, so including the plugin name as a - prefix is probably a good idea. - - - - - The GUID value can be generated automatically using - fu_device_add_guid(dev,"some-identifier") but is quoted - here explicitly. - The GUID value has to match the provides value in the - .metainfo.xml file for the firmware update to succeed. - - - - - Setting a display name and an icon is a good idea in case the - GUI software needs to display the device to the user. - Icons can be specified using a full path, although icon theme names - should be preferred for most devices. - - - - - The FWUPD_DEVICE_FLAG_UPDATABLE flag tells the client - code that the device is in a state where it can be updated. - If the device needs to be in a special mode (e.g. a bootloader) then - the FWUPD_DEVICE_FLAG_NEEDS_BOOTLOADER flag can also be - used. - If the update should only be allowed when there is AC power available - to the computer (i.e. not on battery) then - FWUPD_DEVICE_FLAG_REQUIRE_AC should be used as well. - There are other flags and the API documentation should be used when - choosing what flags to use for each kind of device. - - - - - Setting the lowest allows client software to refuse downgrading - the device to specific versions. - This is required in case the upgrade migrates some kind of data-store - so as to be incompatible with previous versions. - Similarly, setting the version of the bootloader (if known) allows - the firmware to depend on a specific bootloader version, for instance - allowing signed firmware to only be installable on hardware with - a bootloader new enough to deploy it - - - -
- -
- Mechanism Plugins - - Although it would be a wonderful world if we could update all hardware - using a standard shared protocol this is not the universe we live in. - Using a mechanism like DFU or UpdateCapsule means that fwupd will just - work without requiring any special code, but for the real world we need - to support vendor-specific update protocols with layers of backwards - compatibility. - - - When a plugin has created a device that is FWUPD_DEVICE_FLAG_UPDATABLE - we can ask the daemon to update the device with a suitable - .cab file. - When this is done the daemon checks the update for compatibility with - the device, and then calls the vfuncs to update the device. - - - - Updating a device - -gboolean -fu_plugin_update (FuPlugin *plugin, - FuDevice *dev, - GBytes *blob_fw, - FwupdInstallFlags flags, - GError **error) -{ - gsize sz = 0; - guint8 *buf = g_bytes_get_data (blob_fw, &sz); - /* write 'buf' of size 'sz' to the hardware */ - return TRUE; -} - - - - It's important to note that the blob_fw is the binary - firmware file (e.g. .dfu) and not - the .cab binary data. - - - If FWUPD_INSTALL_FLAG_FORCE is used then the usual checks - done by the flashing process can be relaxed (e.g. checking for quirks), - but please don't brick the users hardware even if they ask you to. - -
- -
- Policy Helpers - - For some hardware, we might want to do an action before or after - the actual firmware is squirted into the device. - This could be something as simple as checking the system battery - level is over a certain threshold, or it could be as complicated as - ensuring a vendor-specific GPIO is asserted when specific types - of hardware are updated. - - - - Running before a device update - -gboolean -fu_plugin_update_prepare (FuPlugin *plugin, FuDevice *device, GError **error) -{ - if (fu_device_has_flag (device, FWUPD_DEVICE_FLAG_REQUIRE_AC && !on_ac_power ()) { - g_set_error_literal (error, - FWUPD_ERROR, - FWUPD_ERROR_AC_POWER_REQUIRED, - "Cannot install update " - "when not on AC power"); - return FALSE; - } - return TRUE; -} - - - - Running after a device update - -gboolean -fu_plugin_update_cleanup (FuPlugin *plugin, FuDevice *device, GError **error) -{ - return g_file_set_contents ("/var/lib/fwupd/something", - fu_device_get_id (device), -1, error); -} - - -
- -
- Detaching to bootloader mode - - Some hardware can only be updated in a special bootloader mode, which - for most devices can be switched to automatically. - In some cases the user to do something manually, for instance - re-inserting the hardware with a secret button pressed. - - - Before the device update is performed the fwupd daemon runs an optional - update_detach() vfunc which switches the device to - bootloader mode. - After the update (or if the update fails) an the daemon runs an - optional update_attach() vfunc which should switch the - hardware back to runtime mode. - Finally an optional update_reload() vfunc is run to - get the new firmware version from the hardware. - - - The optional vfuncs are only run - on the plugin currently registered to handle the device ID, although - the registered plugin can change during the attach and detach phases. - - - - Running before a device update - -gboolean -fu_plugin_update_detach (FuPlugin *plugin, FuDevice *device, GError **error) -{ - if (hardware_in_bootloader) - return TRUE; - return _device_detach(device, error); -} - - - - Running after a device update - -gboolean -fu_plugin_update_attach (FuPlugin *plugin, FuDevice *device, GError **error) -{ - if (!hardware_in_bootloader) - return TRUE; - return _device_attach(device, error); -} - - - - Running after a device update on success - -gboolean -fu_plugin_update_reload (FuPlugin *plugin, FuDevice *device, GError **error) -{ - g_autofree gchar *version = _get_version(plugin, device, error); - if (version == NULL) - return FALSE; - fu_device_set_version(device, version); - return TRUE; -} - - -
- -
- The Plugin Object Cache - - The fwupd daemon provides a per-plugin cache which allows objects - to be added, removed and queried using a specified key. - Objects added to the cache must be GObjects to enable the - cache objects to be properly refcounted. - -
- -
- Debugging a Plugin - - If the fwupd daemon is started with --plugin-verbose=$plugin - then the environment variable FWUPD_$PLUGIN_VERBOSE is - set process-wide. - This allows plugins to detect when they should output detailed debugging - information that would normally be too verbose to keep in the journal. - For example, using --plugin-verbose=logitech_hidpp would set - FWUPD_LOGITECH_HID_VERBOSE=1. - -
- -
- Using existing code to develop a plugin - - It is not usually possible to share a plugin codebase with - firmware update programs designed for other operating systems. - Matching the same rationale as the Linux kernel, trying to use one - code base between projects with a compatibility shim layer in-between - is real headache to maintain. - - - The general consensus is that trying to use a abstraction layer for - hardware is a very bad idea as you're not able to take advantage of the - platform specific helpers -- for instance quirk files and the custom - GType device creation. - The time the vendor saves by creating a shim layer and - importing existing source code into fwupd will be overtaken 100x by - upstream maintenance costs longer term, which isn't fair. - - - In a similar way, using C++ rather than GObject C means expanding the - test matrix to include clang in C++ mode and GNU g++ too. - It's also doubled the runtime requirements to now include both the C - standard library as well as the C++ standard library and increases the - dependency surface. - - - Most rewritten fwupd plugins at up to x10 smaller than the standalone - code as they can take advantage of helpers provided by fwupd rather - than re-implementing error handling, device quirking and data chunking. - -
- -
-
+ API Index diff --git a/docs/meson.build b/docs/meson.build index 7169a5480..f24e07422 100644 --- a/docs/meson.build +++ b/docs/meson.build @@ -5,6 +5,10 @@ gnome.gtkdoc( join_paths(meson.source_root(), 'libfwupdplugin'), join_paths(meson.build_root(), 'libfwupd'), join_paths(meson.build_root(), 'libfwupdplugin'), + join_paths(meson.current_source_dir()), + ], + content_files : [ + 'tutorial.xml', ], main_xml : 'fwupd-docs.xml', install : true diff --git a/docs/tutorial.xml b/docs/tutorial.xml new file mode 100644 index 000000000..e1f306351 --- /dev/null +++ b/docs/tutorial.xml @@ -0,0 +1,402 @@ + + + + Plugin Tutorial + +
+ Introduction + + At the heart of fwupd is a plugin loader that gets run at startup, + when devices get hotplugged and when updates are done. + The idea is we have lots of small plugins that each do one thing, and + are ordered by dependencies against each other at runtime. + Using plugins we can add support for new hardware or new policies + without making big changes all over the source tree. + + + There are broadly 3 types of plugin methods: + + + + + Mechanism: Upload binary data + into a specific hardware device. + + + + + Policy: Control the system when + updates are happening, e.g. preventing the user from powering-off. + + + + + Helpers: Providing more + metadata about devices, for instance handling device quirks. + + + + + In general, building things out-of-tree isn't something that we think is + a very good idea; the API and ABI internal to fwupd is still + changing and there's a huge benefit to getting plugins upstream where + they can undergo review and be ported as the API adapts. + For this reason we don't install the plugin headers onto the system, + although you can of course just install the .so binary file + manually. + + + + A plugin only needs to define the vfuncs that are required, and the + plugin name is taken automatically from the suffix of the + .so file. + + + A sample plugin + +/* +* Copyright (C) 2017 Richard Hughes +*/ + +#include <fu-plugin.h> +#include <fu-plugin-vfuncs.h> + +struct FuPluginData { +gpointer proxy; +}; + +void +fu_plugin_initialize (FuPlugin *plugin) +{ +fu_plugin_add_rule (plugin, FU_PLUGIN_RULE_RUN_BEFORE, "dfu"); +fu_plugin_alloc_data (plugin, sizeof (FuPluginData)); +} + +void +fu_plugin_destroy (FuPlugin *plugin) +{ +FuPluginData *data = fu_plugin_get_data (plugin); +destroy_proxy (data->proxy); +} + +gboolean +fu_plugin_startup (FuPlugin *plugin, GError **error) +{ +FuPluginData *data = fu_plugin_get_data (plugin); +data->proxy = create_proxy (); +if (data->proxy == NULL) { + g_set_error (error, FWUPD_ERROR, FWUPD_ERROR_NOT_SUPPORTED, + "failed to create proxy"); + return FALSE; +} +return TRUE; +} + + + + + We have to define when our plugin is run in reference to other plugins, + in this case, making sure we run before the dfu plugin. + For most plugins it does not matter in what order they are run and + this information is not required. + +
+ +
+ Creating an abstract device + + This section shows how you would create a device which is exported + to the daemon and thus can be queried and updated by the client software. + The example here is all hardcoded, and a true plugin would have to + derive the details about the FuDevice from the hardware, + for example reading data from sysfs or /dev. + + + Example adding a custom device + +#include <fu-plugin.h> + +gboolean +fu_plugin_coldplug (FuPlugin *plugin, GError **error) +{ +g_autoptr(FuDevice) dev = NULL; +fu_device_set_id (dev, "dummy-1:2:3"); +fu_device_add_guid (dev, "2d47f29b-83a2-4f31-a2e8-63474f4d4c2e"); +fu_device_set_version (dev, "1.2.3"); +fu_device_get_version_lowest (dev, "1.2.2"); +fu_device_get_version_bootloader (dev, "0.1.2"); +fu_device_add_icon (dev, "computer"); +fu_device_add_flag (dev, FWUPD_DEVICE_FLAG_UPDATABLE); +fu_plugin_device_add (plugin, dev); +return TRUE; +} + + + + This shows a lot of the plugin architecture in action. Some notable points: + + + + + The device ID (dummy-1:2:3) has to be unique on the + system between all plugins, so including the plugin name as a + prefix is probably a good idea. + + + + + The GUID value can be generated automatically using + fu_device_add_guid(dev,"some-identifier") but is quoted + here explicitly. + The GUID value has to match the provides value in the + .metainfo.xml file for the firmware update to succeed. + + + + + Setting a display name and an icon is a good idea in case the + GUI software needs to display the device to the user. + Icons can be specified using a full path, although icon theme names + should be preferred for most devices. + + + + + The FWUPD_DEVICE_FLAG_UPDATABLE flag tells the client + code that the device is in a state where it can be updated. + If the device needs to be in a special mode (e.g. a bootloader) then + the FWUPD_DEVICE_FLAG_NEEDS_BOOTLOADER flag can also be + used. + If the update should only be allowed when there is AC power available + to the computer (i.e. not on battery) then + FWUPD_DEVICE_FLAG_REQUIRE_AC should be used as well. + There are other flags and the API documentation should be used when + choosing what flags to use for each kind of device. + + + + + Setting the lowest allows client software to refuse downgrading + the device to specific versions. + This is required in case the upgrade migrates some kind of data-store + so as to be incompatible with previous versions. + Similarly, setting the version of the bootloader (if known) allows + the firmware to depend on a specific bootloader version, for instance + allowing signed firmware to only be installable on hardware with + a bootloader new enough to deploy it + + + +
+ +
+ Mechanism Plugins + + Although it would be a wonderful world if we could update all hardware + using a standard shared protocol this is not the universe we live in. + Using a mechanism like DFU or UpdateCapsule means that fwupd will just + work without requiring any special code, but for the real world we need + to support vendor-specific update protocols with layers of backwards + compatibility. + + + When a plugin has created a device that is FWUPD_DEVICE_FLAG_UPDATABLE + we can ask the daemon to update the device with a suitable + .cab file. + When this is done the daemon checks the update for compatibility with + the device, and then calls the vfuncs to update the device. + + + + Updating a device + +gboolean +fu_plugin_update (FuPlugin *plugin, + FuDevice *dev, + GBytes *blob_fw, + FwupdInstallFlags flags, + GError **error) +{ +gsize sz = 0; +guint8 *buf = g_bytes_get_data (blob_fw, &sz); +/* write 'buf' of size 'sz' to the hardware */ +return TRUE; +} + + + + It's important to note that the blob_fw is the binary + firmware file (e.g. .dfu) and not + the .cab binary data. + + + If FWUPD_INSTALL_FLAG_FORCE is used then the usual checks + done by the flashing process can be relaxed (e.g. checking for quirks), + but please don't brick the users hardware even if they ask you to. + +
+ +
+ Policy Helpers + + For some hardware, we might want to do an action before or after + the actual firmware is squirted into the device. + This could be something as simple as checking the system battery + level is over a certain threshold, or it could be as complicated as + ensuring a vendor-specific GPIO is asserted when specific types + of hardware are updated. + + + + Running before a device update + +gboolean +fu_plugin_update_prepare (FuPlugin *plugin, FuDevice *device, GError **error) +{ +if (fu_device_has_flag (device, FWUPD_DEVICE_FLAG_REQUIRE_AC && !on_ac_power ()) { + g_set_error_literal (error, + FWUPD_ERROR, + FWUPD_ERROR_AC_POWER_REQUIRED, + "Cannot install update " + "when not on AC power"); + return FALSE; +} +return TRUE; +} + + + + Running after a device update + +gboolean +fu_plugin_update_cleanup (FuPlugin *plugin, FuDevice *device, GError **error) +{ +return g_file_set_contents ("/var/lib/fwupd/something", + fu_device_get_id (device), -1, error); +} + + +
+ +
+ Detaching to bootloader mode + + Some hardware can only be updated in a special bootloader mode, which + for most devices can be switched to automatically. + In some cases the user to do something manually, for instance + re-inserting the hardware with a secret button pressed. + + + Before the device update is performed the fwupd daemon runs an optional + update_detach() vfunc which switches the device to + bootloader mode. + After the update (or if the update fails) an the daemon runs an + optional update_attach() vfunc which should switch the + hardware back to runtime mode. + Finally an optional update_reload() vfunc is run to + get the new firmware version from the hardware. + + + The optional vfuncs are only run + on the plugin currently registered to handle the device ID, although + the registered plugin can change during the attach and detach phases. + + + + Running before a device update + +gboolean +fu_plugin_update_detach (FuPlugin *plugin, FuDevice *device, GError **error) +{ +if (hardware_in_bootloader) + return TRUE; +return _device_detach(device, error); +} + + + + Running after a device update + +gboolean +fu_plugin_update_attach (FuPlugin *plugin, FuDevice *device, GError **error) +{ +if (!hardware_in_bootloader) + return TRUE; +return _device_attach(device, error); +} + + + + Running after a device update on success + +gboolean +fu_plugin_update_reload (FuPlugin *plugin, FuDevice *device, GError **error) +{ +g_autofree gchar *version = _get_version(plugin, device, error); +if (version == NULL) + return FALSE; +fu_device_set_version(device, version); +return TRUE; +} + + +
+ +
+ The Plugin Object Cache + + The fwupd daemon provides a per-plugin cache which allows objects + to be added, removed and queried using a specified key. + Objects added to the cache must be GObjects to enable the + cache objects to be properly refcounted. + +
+ +
+ Debugging a Plugin + + If the fwupd daemon is started with --plugin-verbose=$plugin + then the environment variable FWUPD_$PLUGIN_VERBOSE is + set process-wide. + This allows plugins to detect when they should output detailed debugging + information that would normally be too verbose to keep in the journal. + For example, using --plugin-verbose=logitech_hidpp would set + FWUPD_LOGITECH_HID_VERBOSE=1. + +
+ +
+ Using existing code to develop a plugin + + It is not usually possible to share a plugin codebase with + firmware update programs designed for other operating systems. + Matching the same rationale as the Linux kernel, trying to use one + code base between projects with a compatibility shim layer in-between + is real headache to maintain. + + + The general consensus is that trying to use a abstraction layer for + hardware is a very bad idea as you're not able to take advantage of the + platform specific helpers -- for instance quirk files and the custom + GType device creation. + The time the vendor saves by creating a shim layer and + importing existing source code into fwupd will be overtaken 100x by + upstream maintenance costs longer term, which isn't fair. + + + In a similar way, using C++ rather than GObject C means expanding the + test matrix to include clang in C++ mode and GNU g++ too. + It's also doubled the runtime requirements to now include both the C + standard library as well as the C++ standard library and increases the + dependency surface. + + + Most rewritten fwupd plugins at up to x10 smaller than the standalone + code as they can take advantage of helpers provided by fwupd rather + than re-implementing error handling, device quirking and data chunking. + +
+ +
+
From 070084e0d818ffe5a0d96f82975cf23345467e4f Mon Sep 17 00:00:00 2001 From: Richard Hughes Date: Thu, 23 Jul 2020 11:42:42 +0100 Subject: [PATCH 288/607] libfwupdplugin: Set the physical device ID for i2c devices --- libfwupdplugin/fu-udev-device.c | 1 + 1 file changed, 1 insertion(+) diff --git a/libfwupdplugin/fu-udev-device.c b/libfwupdplugin/fu-udev-device.c index 80d56cf81..c4edd615c 100644 --- a/libfwupdplugin/fu-udev-device.c +++ b/libfwupdplugin/fu-udev-device.c @@ -700,6 +700,7 @@ fu_udev_device_set_physical_id (FuUdevDevice *self, const gchar *subsystems, GEr physical_id = g_strdup_printf ("PCI_SLOT_NAME=%s", tmp); } else if (g_strcmp0 (subsystem, "usb") == 0 || g_strcmp0 (subsystem, "mmc") == 0 || + g_strcmp0 (subsystem, "i2c") == 0 || g_strcmp0 (subsystem, "scsi") == 0) { tmp = g_udev_device_get_property (udev_device, "DEVPATH"); if (tmp == NULL) { From 8edaa89076509901a0ee3979bf76408ae8221e85 Mon Sep 17 00:00:00 2001 From: Richard Hughes Date: Thu, 23 Jul 2020 11:43:04 +0100 Subject: [PATCH 289/607] libfwupdplugin: Allow opening i2c devices with O_NONBLOCK --- libfwupdplugin/fu-udev-device.c | 4 ++++ libfwupdplugin/fu-udev-device.h | 1 + 2 files changed, 5 insertions(+) diff --git a/libfwupdplugin/fu-udev-device.c b/libfwupdplugin/fu-udev-device.c index c4edd615c..3444b8a83 100644 --- a/libfwupdplugin/fu-udev-device.c +++ b/libfwupdplugin/fu-udev-device.c @@ -859,6 +859,10 @@ fu_udev_device_open (FuDevice *device, GError **error) } else { flags = O_RDONLY; } +#ifdef O_NONBLOCK + if (priv->flags & FU_UDEV_DEVICE_FLAG_OPEN_NONBLOCK) + flags |= O_NONBLOCK; +#endif priv->fd = g_open (priv->device_file, flags, 0); if (priv->fd < 0) { g_set_error (error, diff --git a/libfwupdplugin/fu-udev-device.h b/libfwupdplugin/fu-udev-device.h index c455755ad..f0aa9af5c 100644 --- a/libfwupdplugin/fu-udev-device.h +++ b/libfwupdplugin/fu-udev-device.h @@ -48,6 +48,7 @@ typedef enum { FU_UDEV_DEVICE_FLAG_OPEN_WRITE = 1 << 1, FU_UDEV_DEVICE_FLAG_VENDOR_FROM_PARENT = 1 << 2, FU_UDEV_DEVICE_FLAG_USE_CONFIG = 1 << 3, + FU_UDEV_DEVICE_FLAG_OPEN_NONBLOCK = 1 << 4, /*< private >*/ FU_UDEV_DEVICE_FLAG_LAST } FuUdevDeviceFlags; From 5bfa7bf808f3d355fb8b0a106b302dfa5e748255 Mon Sep 17 00:00:00 2001 From: Richard Hughes Date: Tue, 28 Jul 2020 15:55:06 +0100 Subject: [PATCH 290/607] trivial: Add a device test for the Thelio Io device --- .../device-tests/devices/system76-thelio.json | 21 +++++++++++++++++++ 1 file changed, 21 insertions(+) create mode 100644 data/device-tests/devices/system76-thelio.json diff --git a/data/device-tests/devices/system76-thelio.json b/data/device-tests/devices/system76-thelio.json new file mode 100644 index 000000000..12e72dc24 --- /dev/null +++ b/data/device-tests/devices/system76-thelio.json @@ -0,0 +1,21 @@ +{ + "name": "System76 Thelio Io", + "guids": [ + "fdac0b40-51c6-591b-a049-e9cfc05e9271" + ], + "protocol": "org.usb.dfu", + "releases": [ + { + "version": "0.0.0", + "file": "ed423e586cdd35d41f0dd708ea8e5b5b97c54d48eef7e23a02d9a088b231b3fd-thelio-io_0.0.0.cab" + }, + { + "version": "1.0.0", + "file": "1be9bcfa7b5f0db2bca927505f82d8829be5882ca295e33af492d0e1fdacc162-thelio-io_1.0.0.cab" + }, + { + "version": "1.0.2", + "file": "63d4a480162b729fc57ff7c92c1e2254540f43d6-thelio-io_1.0.2.cab" + } + ] +} From 92f8e92daacf135b9e1b69e47c252c978f50d190 Mon Sep 17 00:00:00 2001 From: mendel5 <60322520+mendel5@users.noreply.github.com> Date: Tue, 28 Jul 2020 21:15:06 +0200 Subject: [PATCH 291/607] pull_request_template.md: replace github.com/hughsie with github.com/fwupd --- .github/pull_request_template.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/pull_request_template.md b/.github/pull_request_template.md index b478bac1d..a3f4e1ba4 100644 --- a/.github/pull_request_template.md +++ b/.github/pull_request_template.md @@ -1,5 +1,5 @@ Type of pull request: -- [ ] New plugin (Please include [new plugin checklist](https://github.com/hughsie/fwupd/wiki/New-plugin-checklist)) +- [ ] New plugin (Please include [new plugin checklist](https://github.com/fwupd/fwupd/wiki/New-plugin-checklist)) - [ ] Code fix - [ ] Feature - [ ] Documentation From db2906d49cb9fcc5674f737a7961384efc7204f8 Mon Sep 17 00:00:00 2001 From: mendel5 <60322520+mendel5@users.noreply.github.com> Date: Tue, 28 Jul 2020 21:17:41 +0200 Subject: [PATCH 292/607] fu-plugin-synaptics-mst.c: replace github.com/hughsie with github.com/fwupd --- plugins/synaptics-mst/fu-plugin-synaptics-mst.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugins/synaptics-mst/fu-plugin-synaptics-mst.c b/plugins/synaptics-mst/fu-plugin-synaptics-mst.c index a9c516023..39d7b958f 100644 --- a/plugins/synaptics-mst/fu-plugin-synaptics-mst.c +++ b/plugins/synaptics-mst/fu-plugin-synaptics-mst.c @@ -21,7 +21,7 @@ struct FuPluginData { guint drm_changed_id; }; -/* see https://github.com/hughsie/fwupd/issues/1121 for more details */ +/* see https://github.com/fwupd/fwupd/issues/1121 for more details */ static gboolean fu_synaptics_mst_check_amdgpu_safe (GError **error) { From b700783bf6d78971a353dcbe169b79c8dce9f0ea Mon Sep 17 00:00:00 2001 From: Emily Miller Date: Fri, 10 Jul 2020 17:01:40 +0800 Subject: [PATCH 293/607] vli: Add dual-image feature for VL103 backup firmware --- plugins/vli/fu-vli-pd-device.c | 64 ++++++++++++++++++++++++++++++++++ plugins/vli/vli-pd.quirk | 2 ++ 2 files changed, 66 insertions(+) diff --git a/plugins/vli/fu-vli-pd-device.c b/plugins/vli/fu-vli-pd-device.c index 2e39e01a7..024f71596 100644 --- a/plugins/vli/fu-vli-pd-device.c +++ b/plugins/vli/fu-vli-pd-device.c @@ -392,6 +392,65 @@ fu_vli_pd_device_write_gpios (FuVliPdDevice *self, GError **error) return TRUE; } +static gboolean +fu_vli_pd_device_write_dual_firmware (FuVliPdDevice *self, GBytes *fw, GError **error) +{ + const guint8 *buf = NULL; + const guint8 *sbuf = NULL; + gsize bufsz = 0; + gsize sbufsz = 0; + guint16 crc_actual; + guint16 crc_file = 0x0; + guint32 sec_addr = 0x28000; + g_autoptr(GBytes) spi_fw = NULL; + + /* check spi fw1 crc16 */ + fu_device_set_status (FU_DEVICE (self), FWUPD_STATUS_DEVICE_VERIFY); + spi_fw = fu_vli_device_spi_read (FU_VLI_DEVICE (self), + fu_vli_device_get_offset (FU_VLI_DEVICE (self)), + fu_device_get_firmware_size_max (FU_DEVICE (self)), + error); + if (spi_fw == NULL) + return FALSE; + sbuf = g_bytes_get_data (spi_fw, &sbufsz); + if (sbufsz != 0x8000) + sec_addr = 0x30000; + if (!fu_common_read_uint16_safe (sbuf, sbufsz, sbufsz - 2, &crc_file, + G_LITTLE_ENDIAN, error)) { + g_prefix_error (error, "failed to read file CRC: "); + return FALSE; + } + crc_actual = fu_vli_common_crc16 (sbuf, sbufsz - 2); + fu_device_set_status (FU_DEVICE (self), FWUPD_STATUS_DEVICE_WRITE); + + /* update fw2 first if fw1 correct */ + buf = g_bytes_get_data (fw, &bufsz); + if (crc_actual == crc_file) { + if (!fu_vli_device_spi_write (FU_VLI_DEVICE (self), + sec_addr, + buf, bufsz, error)) + return FALSE; + if (!fu_vli_device_spi_write (FU_VLI_DEVICE (self), + fu_vli_device_get_offset (FU_VLI_DEVICE (self)), + buf, bufsz, error)) + return FALSE; + + /* else update fw1 first */ + } else { + if (!fu_vli_device_spi_write (FU_VLI_DEVICE (self), + fu_vli_device_get_offset (FU_VLI_DEVICE (self)), + buf, bufsz, error)) + return FALSE; + if (!fu_vli_device_spi_write (FU_VLI_DEVICE (self), + sec_addr, + buf, bufsz, error)) + return FALSE; + } + + /* success */ + return TRUE; +} + static gboolean fu_vli_pd_device_write_firmware (FuDevice *device, FuFirmware *firmware, @@ -419,6 +478,11 @@ fu_vli_pd_device_write_firmware (FuDevice *device, if (!fu_vli_pd_device_write_reg (self, 0x0003, tmp | 0x44, error)) return FALSE; + /* dual image on VL103 */ + if (fu_vli_device_get_kind (FU_VLI_DEVICE (device)) == FU_VLI_DEVICE_KIND_VL103 && + fu_device_has_flag (device, FWUPD_DEVICE_FLAG_DUAL_IMAGE)) + return fu_vli_pd_device_write_dual_firmware (self, fw, error); + /* erase */ fu_device_set_status (FU_DEVICE (self), FWUPD_STATUS_DEVICE_ERASE); if (!fu_vli_device_spi_erase_all (FU_VLI_DEVICE (self), error)) diff --git a/plugins/vli/vli-pd.quirk b/plugins/vli/vli-pd.quirk index 586c6aeda..2c8a39e61 100644 --- a/plugins/vli/vli-pd.quirk +++ b/plugins/vli/vli-pd.quirk @@ -18,6 +18,7 @@ DeviceKind = VL102 [DeviceInstanceId=USB\VID_2109&PID_0103] Plugin = vli GType = FuVliPdDevice +Flags = dual-image DeviceKind = VL103 [DeviceInstanceId=USB\VID_2109&PID_0104] Plugin = vli @@ -52,6 +53,7 @@ GType = FuVliPdDevice [DeviceInstanceId=USB\VID_17EF&PID_7212] Plugin = vli GType = FuVliPdDevice +Flag = dual-image # Lenovo [DeviceInstanceId=USB\VID_17EF&PID_7215] From 0b5ed33b239c39c33369dd79b6eb07e1f02af74d Mon Sep 17 00:00:00 2001 From: Ryan Lee Date: Tue, 28 Jul 2020 09:33:17 +0900 Subject: [PATCH 294/607] ccgx: Modify readme to remove customer info --- plugins/ccgx/README.md | 39 +++++++++++++++++---------------------- 1 file changed, 17 insertions(+), 22 deletions(-) diff --git a/plugins/ccgx/README.md b/plugins/ccgx/README.md index 508ba2373..8be26bdf8 100644 --- a/plugins/ccgx/README.md +++ b/plugins/ccgx/README.md @@ -3,15 +3,17 @@ Cypress support Introduction ------------ + This plugin can flash firmware on Cypress CCGx USB-C controller family of -devices used in dock solutions. +devices used in docks. -Supported devices: +Supported Protocols +------------------- - * Lenovo Gen2 Dock - * Lenovo Hybrid Dock - * HP USB-C Dock G5 - * HP USB-C/A Universal Dock G2 +This plugin supports the following protocol IDs: + + * com.cypress.ccgx + * com.cypress.ccgx.dmc Device Flash ============ @@ -52,12 +54,11 @@ The `CY_PD_JUMP_TO_ALT_FW_CMD_SIG` command is allowed only in asymmetric FW, but `CY_PD_DEVICE_RESET_CMD_SIG` is allowed in both asymmetric FW and symmetric FW. DMC(Dock Management Controller) Composite Firmware ---------------------------------------------------- +-------------------------------------------------- In composite firmware topology, a single firmware image contains metadata and firmware images of multiple devices including DMC itself in a dock system. - Firmware Format =============== @@ -71,34 +72,28 @@ blobs in cyacd file format. See https://community.cypress.com/docs/DOC-10562 for more details. DMC composite firmware format ------------------------------- +----------------------------- The daemon will decompress the cabinet archive and extract several firmware blobs in a combined image file format. See 4.4.1 Single Composite (Combined) Dock Image at https://www.cypress.com/file/387471/download for more details. -This plugin supports the following protocol ID: - - * com.cypress.ccgx - GUID Generation --------------- These devices use the standard USB DeviceInstanceId values, e.g. - * `USB\VID_17EF&PID_A38F` - * `USB\VID_03F0&PID_046B` + * `USB\VID_1234&PID_5678` -For cyacd firmware device, - They additionally add other instance IDs which corresponds to the silicon ID, - application ID and device mode, e.g. +Devices also have additional instance IDs which corresponds to the silicon ID, +application ID and device mode, e.g. - * `USB\VID_17EF&PID_A38F&SID_1234` - * `USB\VID_17EF&PID_A38F&SID_1234&APP_5678` - * `USB\VID_17EF&PID_A38F&SID_1234&APP_5678&MODE_FW2` + * `USB\VID_1234&PID_5678&SID_9ABC` + * `USB\VID_1234&PID_5678&SID_9ABC&APP_DEF1` + * `USB\VID_1234&PID_5678&SID_9ABC&APP_DEF1&MODE_FW2` Vendor ID Security ------------------ -The vendor ID is set from the USB vendor, for example set to `USB:0x17EF` +The vendor ID is set from the USB vendor, for example set to `USB:0x04B4` From c7edf611c33f28f2f7b847805c52f46a7d6abc16 Mon Sep 17 00:00:00 2001 From: Sean Rhodes Date: Wed, 29 Jul 2020 12:46:04 +0100 Subject: [PATCH 295/607] Added quirk for LabTop Mk IV --- plugins/superio/superio.quirk | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/plugins/superio/superio.quirk b/plugins/superio/superio.quirk index ab71c5220..bfa1f1188 100644 --- a/plugins/superio/superio.quirk +++ b/plugins/superio/superio.quirk @@ -6,6 +6,11 @@ SuperioChipsets=IT8587 [HwId=f00d8c4e-dce2-51c3-89d6-6cbc5fc5cdbb] SuperioChipsets=IT8587 +# Star LabTop Mk IV +[HwID=6ed215ec-75d5-54e9-9c60-7708b325b904] +SuperioChipsets=IT8987 +InstallDuration=20 + # Star LabTop Mk3 [HwId=3dc52d2c-9e9b-5ba5-b10d-9ba1eb11dacc] SuperioChipsets=IT8987 From 45adc67c82d5ab0fbda8ddb1c153d1472889c416 Mon Sep 17 00:00:00 2001 From: Richard Hughes Date: Wed, 29 Jul 2020 13:43:13 +0100 Subject: [PATCH 296/607] trivial: Fix aarch64 Fedora build --- contrib/fwupd.spec.in | 2 ++ 1 file changed, 2 insertions(+) diff --git a/contrib/fwupd.spec.in b/contrib/fwupd.spec.in index d01e1962c..29660b37e 100644 --- a/contrib/fwupd.spec.in +++ b/contrib/fwupd.spec.in @@ -275,7 +275,9 @@ mkdir -p --mode=0700 $RPM_BUILD_ROOT%{_localstatedir}/lib/fwupd/gnupg %config(noreplace)%{_sysconfdir}/fwupd/thunderbolt.conf %dir %{_libexecdir}/fwupd %{_libexecdir}/fwupd/fwupd +%ifarch i686 x86_64 %{_libexecdir}/fwupd/fwupd-detect-cet +%endif %{_libexecdir}/fwupd/fwupdoffline %if 0%{?have_uefi} %{_libexecdir}/fwupd/efi/*.efi From b76b4f8deb6066262fdc684389a184628520dae5 Mon Sep 17 00:00:00 2001 From: Richard Hughes Date: Wed, 29 Jul 2020 14:19:56 +0100 Subject: [PATCH 297/607] trivial: Make the bash completion script reflect reality --- data/bash-completion/fwupdtool.in | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/data/bash-completion/fwupdtool.in b/data/bash-completion/fwupdtool.in index a46398f4e..c239877a4 100644 --- a/data/bash-completion/fwupdtool.in +++ b/data/bash-completion/fwupdtool.in @@ -38,7 +38,7 @@ _fwupdtool_opts=( '--allow-older' '--force' '--show-all-devices' - '--plugin-enable' + '--plugins' '--prepare' '--cleanup' '--filter' @@ -82,7 +82,7 @@ _fwupdtool() command=${COMP_WORDS[1]} case $prev in - --plugin-enable) + --plugins) _show_plugins return 0 ;; From 4a0d14b0973a041d5c2b49792000f3efadd6405b Mon Sep 17 00:00:00 2001 From: Richard Hughes Date: Thu, 30 Jul 2020 15:13:00 +0100 Subject: [PATCH 298/607] trivial: Fix the quirk entry for the Star LabTop Mk IV --- plugins/superio/superio.quirk | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugins/superio/superio.quirk b/plugins/superio/superio.quirk index bfa1f1188..13194972c 100644 --- a/plugins/superio/superio.quirk +++ b/plugins/superio/superio.quirk @@ -7,7 +7,7 @@ SuperioChipsets=IT8587 SuperioChipsets=IT8587 # Star LabTop Mk IV -[HwID=6ed215ec-75d5-54e9-9c60-7708b325b904] +[HwId=6ed215ec-75d5-54e9-9c60-7708b325b904] SuperioChipsets=IT8987 InstallDuration=20 From 27c49542ef7f51d6f70020d42179fb60c13a83ac Mon Sep 17 00:00:00 2001 From: Mario Limonciello Date: Thu, 30 Jul 2020 11:12:03 -0500 Subject: [PATCH 299/607] trivial: try to fix circleci news generation script --- .circleci/config.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.circleci/config.yml b/.circleci/config.yml index 719e29198..ea07268b1 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -167,7 +167,7 @@ jobs: go get github.com/tcnksm/ghr VERSION=$(cat dist/VERSION) BODY=$(cat dist/news.txt) - ghr -t ${GITHUB_TOKEN} -u ${CIRCLE_PROJECT_USERNAME} -r ${CIRCLE_PROJECT_REPONAME} -c ${CIRCLE_SHA1} -b ${BODY} ${VERSION} ./dist/setup/ + ghr -t ${GITHUB_TOKEN} -u ${CIRCLE_PROJECT_USERNAME} -r ${CIRCLE_PROJECT_REPONAME} -c ${CIRCLE_SHA1} -b "${BODY}" ${VERSION} ./dist/setup/ workflows: version: 2 main: From 8b9f9ab47ad1a9945d7e8387975757c2741d1dc6 Mon Sep 17 00:00:00 2001 From: Benson Leung Date: Sat, 1 Aug 2020 13:10:24 -0700 Subject: [PATCH 300/607] Save custom flags on device replace New instances of a device may be interested in custom flags. Copy them over on fu_device_list_replace. fixes #2298 --- src/fu-device-list.c | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/src/fu-device-list.c b/src/fu-device-list.c index 9f503596e..fc154442d 100644 --- a/src/fu-device-list.c +++ b/src/fu-device-list.c @@ -516,6 +516,8 @@ fu_device_list_item_set_device (FuDeviceItem *item, FuDevice *device) static void fu_device_list_replace (FuDeviceList *self, FuDeviceItem *item, FuDevice *device) { + const gchar *custom_flags; + /* clear timeout if scheduled */ if (item->remove_id != 0) { g_source_remove (item->remove_id); @@ -533,6 +535,13 @@ fu_device_list_replace (FuDeviceList *self, FuDeviceItem *item, FuDevice *device fu_device_set_vendor_id (device, vendor_id); } + /* copy over custom flags */ + custom_flags = fu_device_get_custom_flags (item->device); + if (custom_flags != NULL) { + g_debug ("copying old custom flags %s to new device", custom_flags); + fu_device_set_custom_flags (device, custom_flags); + } + /* copy over the version strings if not set */ if (fu_device_get_version (item->device) != NULL && fu_device_get_version (device) == NULL) { From 1a58062be983f50e99bd5c1e00a5de9606955ffd Mon Sep 17 00:00:00 2001 From: Richard Hughes Date: Mon, 3 Aug 2020 10:02:25 +0100 Subject: [PATCH 301/607] Refresh the handle to device before testing ANOTHER_WRITE_REQUIRED fu_engine_install_blob may result in the device being reset during attach or detach and needing to be replugged. The device handle we're holding may be stale, but it is still used by the do while loop itself for the ANOTHER_WRITE_REQUIRED test. Similar to the other functions in the loop, let's get the device handle by id in case that happened. Original patch by Benson Leung , many thanks. Fixes https://github.com/fwupd/fwupd/issues/2297 --- src/fu-engine.c | 18 ++++++++++++++---- 1 file changed, 14 insertions(+), 4 deletions(-) diff --git a/src/fu-engine.c b/src/fu-engine.c index 2ed45922e..b1ad92377 100644 --- a/src/fu-engine.c +++ b/src/fu-engine.c @@ -2487,6 +2487,10 @@ fu_engine_update_prepare (FuEngine *self, device = fu_engine_get_device_by_id (self, device_id, error); if (device == NULL) return FALSE; + + /* don't rely on a plugin clearing this */ + fu_device_remove_flag (device, FWUPD_DEVICE_FLAG_ANOTHER_WRITE_REQUIRED); + str = fu_device_to_string (device); g_debug ("performing prepare on %s", str); if (!fu_engine_device_prepare (self, device, flags, error)) @@ -2792,6 +2796,8 @@ fu_engine_install_blob (FuEngine *self, * must return TRUE rather than an error */ device_id = g_strdup (fu_device_get_id (device)); do { + g_autoptr(FuDevice) device_tmp = NULL; + /* check for a loop */ if (++retries > 5) { g_set_error_literal (error, @@ -2801,9 +2807,6 @@ fu_engine_install_blob (FuEngine *self, return FALSE; } - /* don't rely on a plugin clearing this */ - fu_device_remove_flag (device, FWUPD_DEVICE_FLAG_ANOTHER_WRITE_REQUIRED); - /* signal to all the plugins the update is about to happen */ if (!fu_engine_update_prepare (self, flags, device_id, error)) return FALSE; @@ -2820,7 +2823,14 @@ fu_engine_install_blob (FuEngine *self, if (!fu_engine_update_attach (self, device_id, error)) return FALSE; - } while (fu_device_has_flag (device, FWUPD_DEVICE_FLAG_ANOTHER_WRITE_REQUIRED)); + /* the device and plugin both may have changed */ + device_tmp = fu_engine_get_device_by_id (self, device_id, error); + if (device_tmp == NULL) + return FALSE; + if (!fu_device_has_flag (device_tmp, FWUPD_DEVICE_FLAG_ANOTHER_WRITE_REQUIRED)) + break; + + } while (TRUE); /* get the new version number */ if (!fu_engine_update_reload (self, device_id, error)) From fc974c724034af0347fccf29557728e57c08ad93 Mon Sep 17 00:00:00 2001 From: Simon McVittie Date: Wed, 5 Aug 2020 22:11:55 +0100 Subject: [PATCH 302/607] trivial: Don't skip methods on plain structs This resulted in losing g_usb_source_set_callback@LIBGUSB_0.1.0 which causes a build failure when building gusb as a subproject, and also the little-used fu_chunk_to_string() from libfwupdplugin. Signed-off-by: Richard Hughes --- contrib/generate-version-script.py | 7 ++++--- libfwupdplugin/fwupdplugin.map | 1 + 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/contrib/generate-version-script.py b/contrib/generate-version-script.py index bfecec9d3..e2df3b0e2 100755 --- a/contrib/generate-version-script.py +++ b/contrib/generate-version-script.py @@ -56,9 +56,6 @@ class LdVersionScript: # choose the lowest version method for the _get_type symbol version_lowest = None - if '{http://www.gtk.org/introspection/glib/1.0}get-type' not in cls.attrib: - return - type_name = cls.attrib['{http://www.gtk.org/introspection/glib/1.0}get-type'] # add all class methods for node in cls.findall(XMLNS + 'method'): @@ -78,6 +75,10 @@ class LdVersionScript: ): version_lowest = version_tmp + if '{http://www.gtk.org/introspection/glib/1.0}get-type' not in cls.attrib: + return + type_name = cls.attrib['{http://www.gtk.org/introspection/glib/1.0}get-type'] + # finally add the get_type symbol if version_lowest: self.releases[version_lowest].append(type_name) diff --git a/libfwupdplugin/fwupdplugin.map b/libfwupdplugin/fwupdplugin.map index 7ec5a30c2..e40f98918 100644 --- a/libfwupdplugin/fwupdplugin.map +++ b/libfwupdplugin/fwupdplugin.map @@ -277,6 +277,7 @@ LIBFWUPDPLUGIN_1.1.2 { fu_chunk_array_new; fu_chunk_array_new_from_bytes; fu_chunk_new; + fu_chunk_to_string; fu_common_find_program_in_path; fu_common_strstrip; fu_common_strtoull; From ced2fa1ca4b04f0bacd2537d2c16f8c271af3b32 Mon Sep 17 00:00:00 2001 From: Richard Hughes Date: Thu, 6 Aug 2020 07:59:16 +0100 Subject: [PATCH 303/607] trivial: Fix the Fedora CI --- contrib/ci/Dockerfile-fedora.in | 1 + contrib/fwupd.spec.in | 5 ++++- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/contrib/ci/Dockerfile-fedora.in b/contrib/ci/Dockerfile-fedora.in index b8e18b6ec..29eb03faf 100644 --- a/contrib/ci/Dockerfile-fedora.in +++ b/contrib/ci/Dockerfile-fedora.in @@ -5,6 +5,7 @@ ENV LANGUAGE en_US:en ENV LC_ALL en_US.UTF-8 RUN echo fubar > /etc/machine-id RUN dnf -y update +RUN dnf -y install https://kojipkgs.fedoraproject.org//packages/pesign/113/12.fc31/x86_64/pesign-113-12.fc31.x86_64.rpm RUN echo fubar > /etc/machine-id %%%INSTALL_DEPENDENCIES_COMMAND%%% RUN dnf -y update glib2 glib2-devel --releasever=32 diff --git a/contrib/fwupd.spec.in b/contrib/fwupd.spec.in index 29660b37e..222aa0ca3 100644 --- a/contrib/fwupd.spec.in +++ b/contrib/fwupd.spec.in @@ -243,7 +243,10 @@ Data files for installed tests. %global efiarch aa64 %endif %global fwup_efi_fn $RPM_BUILD_ROOT%{_libexecdir}/fwupd/efi/fwupd%{efiarch}.efi -%pesign -s -i %{fwup_efi_fn} -o %{fwup_efi_fn}.signed +%pesign -s -i %{fwup_efi_fn} -o %{fwup_efi_fn}.tmp +%define __pesign_client_cert fwupd-signer +%pesign -s -i %{fwup_efi_fn}.tmp -o %{fwup_efi_fn}.signed +rm -vf %{fwup_efi_fn}.tmp %endif mkdir -p --mode=0700 $RPM_BUILD_ROOT%{_localstatedir}/lib/fwupd/gnupg From f79680bfd196a36db6edf5b977a0946e41ca0c5f Mon Sep 17 00:00:00 2001 From: Mario Limonciello Date: Mon, 10 Aug 2020 09:01:53 -0500 Subject: [PATCH 304/607] trivial: move ubuntu ci to clang 10 --- contrib/ci/Dockerfile-ubuntu.in | 2 +- contrib/ci/dependencies.xml | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/contrib/ci/Dockerfile-ubuntu.in b/contrib/ci/Dockerfile-ubuntu.in index 5a4e47e78..694ae2471 100644 --- a/contrib/ci/Dockerfile-ubuntu.in +++ b/contrib/ci/Dockerfile-ubuntu.in @@ -1,6 +1,6 @@ FROM ubuntu:devel %%%OS%%% -ENV CC clang-6.0 +ENV CC clang RUN echo fubar > /etc/machine-id %%%ARCH_SPECIFIC_COMMAND%%% %%%INSTALL_DEPENDENCIES_COMMAND%%% diff --git a/contrib/ci/dependencies.xml b/contrib/ci/dependencies.xml index 6f03a9dab..1c3db8cf7 100644 --- a/contrib/ci/dependencies.xml +++ b/contrib/ci/dependencies.xml @@ -66,12 +66,12 @@ - + - + From 2c553829442b6ff3681c53d1c1ab579a0915ada1 Mon Sep 17 00:00:00 2001 From: Mario Limonciello Date: Mon, 10 Aug 2020 09:30:09 -0500 Subject: [PATCH 305/607] trivial: cpu: add noreturn attribute --- plugins/cpu/fu-cpu-helper-cet.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugins/cpu/fu-cpu-helper-cet.c b/plugins/cpu/fu-cpu-helper-cet.c index 34aab2c6c..56ca9a573 100644 --- a/plugins/cpu/fu-cpu-helper-cet.c +++ b/plugins/cpu/fu-cpu-helper-cet.c @@ -13,7 +13,7 @@ #include "fu-cpu-helper-cet-common.h" #ifdef HAVE_SIGACTION -static void +static __attribute__((noreturn))void segfault_sigaction (int signal, siginfo_t *si, void *arg) { /* CET did exactly as it should to protect the system */ From 0ebddc9fcffb44827a4399b9e0f7d4b40df22416 Mon Sep 17 00:00:00 2001 From: Mario Limonciello Date: Mon, 10 Aug 2020 09:30:18 -0500 Subject: [PATCH 306/607] trivial: fix some unused variables found by clang-10 --- plugins/ccgx/fu-ccgx-hpi-device.c | 1 - plugins/thunderbolt/fu-self-test.c | 1 - plugins/thunderbolt/fu-thunderbolt-device.c | 1 - plugins/tpm-eventlog/fu-plugin-tpm-eventlog.c | 1 - plugins/uefi/fu-plugin-uefi.c | 1 - src/fu-engine.c | 2 -- 6 files changed, 7 deletions(-) diff --git a/plugins/ccgx/fu-ccgx-hpi-device.c b/plugins/ccgx/fu-ccgx-hpi-device.c index 87d08a684..606a7a7e5 100644 --- a/plugins/ccgx/fu-ccgx-hpi-device.c +++ b/plugins/ccgx/fu-ccgx-hpi-device.c @@ -317,7 +317,6 @@ fu_ccgx_hpi_device_i2c_write (FuCcgxHpiDevice *self, GError **error) { guint8 target_address; - g_autoptr(GError) error_local = NULL; if (!fu_ccgx_hpi_device_check_i2c_status (self, CY_I2C_MODE_WRITE, error)) { g_prefix_error (error, "i2c get status error: "); diff --git a/plugins/thunderbolt/fu-self-test.c b/plugins/thunderbolt/fu-self-test.c index 12175ebfa..90c147efd 100644 --- a/plugins/thunderbolt/fu-self-test.c +++ b/plugins/thunderbolt/fu-self-test.c @@ -1004,7 +1004,6 @@ test_tree (ThunderboltTest *tt, gconstpointer user_data) const MockTree *found; gboolean ret; g_autoptr(MockTree) tree = NULL; - g_autoptr(GError) error = NULL; tree = mock_tree_init (&root_one); g_assert_nonnull (tree); diff --git a/plugins/thunderbolt/fu-thunderbolt-device.c b/plugins/thunderbolt/fu-thunderbolt-device.c index 6edc946f3..ab24a907e 100644 --- a/plugins/thunderbolt/fu-thunderbolt-device.c +++ b/plugins/thunderbolt/fu-thunderbolt-device.c @@ -563,7 +563,6 @@ fu_thunderbolt_device_prepare_firmware (FuDevice *device, g_autoptr(FuThunderboltFirmwareUpdate) firmware = fu_thunderbolt_firmware_update_new (); g_autoptr(FuThunderboltFirmware) firmware_old = fu_thunderbolt_firmware_new (); g_autoptr(GBytes) controller_fw = NULL; - g_autoptr(GError) error_local = NULL; g_autoptr(GFile) nvmem = NULL; /* parse */ diff --git a/plugins/tpm-eventlog/fu-plugin-tpm-eventlog.c b/plugins/tpm-eventlog/fu-plugin-tpm-eventlog.c index 3e897faba..2699dede0 100644 --- a/plugins/tpm-eventlog/fu-plugin-tpm-eventlog.c +++ b/plugins/tpm-eventlog/fu-plugin-tpm-eventlog.c @@ -44,7 +44,6 @@ fu_plugin_coldplug (FuPlugin *plugin, GError **error) g_autofree gchar *str = NULL; g_autofree guint8 *buf = NULL; g_autoptr(FuTpmEventlogDevice) dev = NULL; - g_autoptr(GError) error_local = NULL; if (!g_file_get_contents (fn, (gchar **) &buf, &bufsz, error)) return FALSE; diff --git a/plugins/uefi/fu-plugin-uefi.c b/plugins/uefi/fu-plugin-uefi.c index b8c4abde5..5b8c56c15 100644 --- a/plugins/uefi/fu-plugin-uefi.c +++ b/plugins/uefi/fu-plugin-uefi.c @@ -414,7 +414,6 @@ fu_plugin_uefi_load_config (FuPlugin *plugin, FuDevice *device, GError **error) gboolean disable_shim; guint64 sz_reqd = FU_UEFI_COMMON_REQUIRED_ESP_FREE_SPACE; g_autofree gchar *require_esp_free_space = NULL; - g_autofree gchar *require_shim_for_sb = NULL; g_autofree gchar *esp_path = NULL; /* parse free space needed for ESP */ diff --git a/src/fu-engine.c b/src/fu-engine.c index b1ad92377..d0f7c5975 100644 --- a/src/fu-engine.c +++ b/src/fu-engine.c @@ -3469,8 +3469,6 @@ fu_engine_update_metadata_bytes (FuEngine *self, const gchar *remote_id, { FwupdKeyringKind keyring_kind; FwupdRemote *remote; - g_autofree gchar *pki_dir = NULL; - g_autofree gchar *sysconfdir = NULL; g_return_val_if_fail (FU_IS_ENGINE (self), FALSE); g_return_val_if_fail (remote_id != NULL, FALSE); From abfc72d6c06388d2b36a6af43eb5bf0ae2e16a21 Mon Sep 17 00:00:00 2001 From: Mario Limonciello Date: Mon, 10 Aug 2020 10:05:54 -0500 Subject: [PATCH 307/607] trivial: add a missing assertion in self test --- src/fu-self-test.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/fu-self-test.c b/src/fu-self-test.c index 623015c61..1f9abbabf 100644 --- a/src/fu-self-test.c +++ b/src/fu-self-test.c @@ -175,6 +175,7 @@ fu_plugin_hash_func (gconstpointer user_data) "libfu_plugin_invalid." G_MODULE_SUFFIX, NULL); ret = fu_plugin_open (plugin, pluginfn, &error); + g_assert_true (ret); g_assert_no_error (error); /* make sure it tainted now */ @@ -858,6 +859,7 @@ fu_engine_requirements_protocol_check_func (gconstpointer user_data) FWUPD_INSTALL_FLAG_NONE, &error); g_assert_error (error, FWUPD_ERROR, FWUPD_ERROR_NOT_SUPPORTED); + g_assert_false (ret); g_clear_error (&error); /* check this passes */ From 27fd95ae881b4cf8a6db538aaeb79d659835bceb Mon Sep 17 00:00:00 2001 From: Mario Limonciello Date: Mon, 10 Aug 2020 10:02:24 -0500 Subject: [PATCH 308/607] trivial: fu-config: stop setting local variable archive_size_max --- src/fu-config.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/fu-config.c b/src/fu-config.c index cf45117ba..b5bdf24ed 100644 --- a/src/fu-config.c +++ b/src/fu-config.c @@ -112,7 +112,7 @@ fu_config_reload (FuConfig *self, GError **error) "ArchiveSizeMax", NULL); if (archive_size_max > 0) - self->archive_size_max = archive_size_max *= 0x100000; + self->archive_size_max = archive_size_max * 0x100000; /* get idle timeout */ idle_timeout = g_key_file_get_uint64 (keyfile, From 3120683143b1fa8068cea59bc420ce0dbf7f44cc Mon Sep 17 00:00:00 2001 From: Richard Hughes Date: Mon, 27 Jul 2020 15:31:11 +0100 Subject: [PATCH 309/607] Allow blocking specific firmware releases by checksum Fixes https://github.com/fwupd/fwupd/issues/2280 --- data/bash-completion/fwupdmgr.in | 3 + data/daemon.conf | 4 + libfwupd/fwupd-client.c | 92 ++++++++++++++++ libfwupd/fwupd-client.h | 7 ++ libfwupd/fwupd.map | 9 +- src/fu-config.c | 25 +++++ src/fu-config.h | 1 + src/fu-engine.c | 104 ++++++++++++++++-- src/fu-engine.h | 8 ++ src/fu-history.c | 163 ++++++++++++++++++++++++++++- src/fu-history.h | 7 ++ src/fu-main.c | 66 ++++++++++++ src/fu-util.c | 174 +++++++++++++++++++++++++++++++ src/org.freedesktop.fwupd.xml | 36 +++++++ 14 files changed, 688 insertions(+), 11 deletions(-) diff --git a/data/bash-completion/fwupdmgr.in b/data/bash-completion/fwupdmgr.in index ccdd89c55..623a75917 100644 --- a/data/bash-completion/fwupdmgr.in +++ b/data/bash-completion/fwupdmgr.in @@ -1,5 +1,6 @@ _fwupdmgr_cmd_list=( 'activate' + 'block-firmware' 'clear-history' 'clear-offline' 'clear-results' @@ -7,6 +8,7 @@ _fwupdmgr_cmd_list=( 'downgrade' 'enable-remote' 'get-approved-firmware' + 'get-blocked-firmware' 'get-details' 'get-devices' 'get-history' @@ -25,6 +27,7 @@ _fwupdmgr_cmd_list=( 'security' 'set-approved-firmware' 'unlock' + 'unblock-firmware' 'update' 'upgrade' 'verify' diff --git a/data/daemon.conf b/data/daemon.conf index 93777595c..6a576cfd5 100644 --- a/data/daemon.conf +++ b/data/daemon.conf @@ -32,3 +32,7 @@ EnumerateAllDevices=false # A list of firmware checksums that has been approved by the site admin # If unset, all firmware is approved ApprovedFirmware= + +# Allow blocking specific devices by their checksum, either SHA1 or SHA256 +# Uses semicolons as delimiter +BlockedFirmware= diff --git a/libfwupd/fwupd-client.c b/libfwupd/fwupd-client.c index eef46d0d9..bf96ec381 100644 --- a/libfwupd/fwupd-client.c +++ b/libfwupd/fwupd-client.c @@ -2128,6 +2128,98 @@ fwupd_client_set_approved_firmware (FwupdClient *client, return TRUE; } +/** + * fwupd_client_get_blocked_firmware: + * @client: A #FwupdClient + * @cancellable: the #GCancellable, or %NULL + * @error: the #GError, or %NULL + * + * Gets the list of blocked firmware. + * + * Returns: (transfer full): list of checksums, or %NULL + * + * Since: 1.4.6 + **/ +gchar ** +fwupd_client_get_blocked_firmware (FwupdClient *client, + GCancellable *cancellable, + GError **error) +{ + FwupdClientPrivate *priv = GET_PRIVATE (client); + g_autoptr(GVariant) val = NULL; + gchar **retval = NULL; + + g_return_val_if_fail (FWUPD_IS_CLIENT (client), NULL); + g_return_val_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable), NULL); + g_return_val_if_fail (error == NULL || *error == NULL, NULL); + + /* connect */ + if (!fwupd_client_connect (client, cancellable, error)) + return NULL; + + /* call into daemon */ + val = g_dbus_proxy_call_sync (priv->proxy, + "GetBlockedFirmware", + NULL, + G_DBUS_CALL_FLAGS_NONE, + -1, + cancellable, + error); + if (val == NULL) { + if (error != NULL) + fwupd_client_fixup_dbus_error (*error); + return NULL; + } + g_variant_get (val, "(^as)", &retval); + return retval; +} + +/** + * fwupd_client_set_blocked_firmware: + * @client: A #FwupdClient + * @checksums: Array of checksums + * @cancellable: the #GCancellable, or %NULL + * @error: the #GError, or %NULL + * + * Sets the list of blocked firmware. + * + * Returns: %TRUE for success + * + * Since: 1.4.6 + **/ +gboolean +fwupd_client_set_blocked_firmware (FwupdClient *client, + gchar **checksums, + GCancellable *cancellable, + GError **error) +{ + FwupdClientPrivate *priv = GET_PRIVATE (client); + g_autoptr(GVariant) val = NULL; + + g_return_val_if_fail (FWUPD_IS_CLIENT (client), FALSE); + g_return_val_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable), FALSE); + g_return_val_if_fail (error == NULL || *error == NULL, FALSE); + + /* connect */ + if (!fwupd_client_connect (client, cancellable, error)) + return FALSE; + + /* call into daemon */ + val = g_dbus_proxy_call_sync (priv->proxy, + "SetBlockedFirmware", + g_variant_new ("(^as)", checksums), + G_DBUS_CALL_FLAGS_NONE, + -1, + cancellable, + error); + if (val == NULL) { + if (error != NULL) + fwupd_client_fixup_dbus_error (*error); + return FALSE; + } + return TRUE; +} + /** * fwupd_client_set_feature_flags: * @client: A #FwupdClient diff --git a/libfwupd/fwupd-client.h b/libfwupd/fwupd-client.h index 43011c190..235568e68 100644 --- a/libfwupd/fwupd-client.h +++ b/libfwupd/fwupd-client.h @@ -205,6 +205,13 @@ gboolean fwupd_client_set_approved_firmware (FwupdClient *client, gchar **checksums, GCancellable *cancellable, GError **error); +gchar **fwupd_client_get_blocked_firmware (FwupdClient *client, + GCancellable *cancellable, + GError **error); +gboolean fwupd_client_set_blocked_firmware (FwupdClient *client, + gchar **checksums, + GCancellable *cancellable, + GError **error); gchar *fwupd_client_self_sign (FwupdClient *client, const gchar *value, FwupdSelfSignFlags flags, diff --git a/libfwupd/fwupd.map b/libfwupd/fwupd.map index a70b12756..1b669fe8a 100644 --- a/libfwupd/fwupd.map +++ b/libfwupd/fwupd.map @@ -469,6 +469,13 @@ LIBFWUPD_1.4.5 { local: *; } LIBFWUPD_1.4.1; +LIBFWUPD_1.4.6 { + global: + fwupd_client_get_blocked_firmware; + fwupd_client_set_blocked_firmware; + local: *; +} LIBFWUPD_1.4.5; + LIBFWUPD_1.5.0 { global: fwupd_client_get_host_security_attrs; @@ -508,4 +515,4 @@ LIBFWUPD_1.5.0 { fwupd_security_attr_to_string; fwupd_security_attr_to_variant; local: *; -} LIBFWUPD_1.4.5; +} LIBFWUPD_1.4.6; diff --git a/src/fu-config.c b/src/fu-config.c index b5bdf24ed..646940c03 100644 --- a/src/fu-config.c +++ b/src/fu-config.c @@ -30,6 +30,7 @@ struct _FuConfig GPtrArray *disabled_devices; /* (element-type utf-8) */ GPtrArray *disabled_plugins; /* (element-type utf-8) */ GPtrArray *approved_firmware; /* (element-type utf-8) */ + GPtrArray *blocked_firmware; /* (element-type utf-8) */ guint64 archive_size_max; guint idle_timeout; gchar *config_file; @@ -52,6 +53,7 @@ fu_config_reload (FuConfig *self, GError **error) guint64 archive_size_max; guint idle_timeout; g_auto(GStrv) approved_firmware = NULL; + g_auto(GStrv) blocked_firmware = NULL; g_auto(GStrv) devices = NULL; g_auto(GStrv) plugins = NULL; g_autofree gchar *domains = NULL; @@ -106,6 +108,20 @@ fu_config_reload (FuConfig *self, GError **error) } } + /* get blocked firmware */ + g_ptr_array_set_size (self->blocked_firmware, 0); + blocked_firmware = g_key_file_get_string_list (keyfile, + "fwupd", + "BlockedFirmware", + NULL, /* length */ + NULL); + if (blocked_firmware != NULL) { + for (guint i = 0; blocked_firmware[i] != NULL; i++) { + g_ptr_array_add (self->blocked_firmware, + g_strdup (blocked_firmware[i])); + } + } + /* get maximum archive size, defaulting to something sane */ archive_size_max = g_key_file_get_uint64 (keyfile, "fwupd", @@ -227,6 +243,13 @@ fu_config_get_disabled_devices (FuConfig *self) return self->disabled_devices; } +GPtrArray * +fu_config_get_blocked_firmware (FuConfig *self) +{ + g_return_val_if_fail (FU_IS_CONFIG (self), NULL); + return self->blocked_firmware; +} + guint64 fu_config_get_archive_size_max (FuConfig *self) { @@ -282,6 +305,7 @@ fu_config_init (FuConfig *self) self->disabled_devices = g_ptr_array_new_with_free_func (g_free); self->disabled_plugins = g_ptr_array_new_with_free_func (g_free); self->approved_firmware = g_ptr_array_new_with_free_func (g_free); + self->blocked_firmware = g_ptr_array_new_with_free_func (g_free); } static void @@ -294,6 +318,7 @@ fu_config_finalize (GObject *obj) g_ptr_array_unref (self->disabled_devices); g_ptr_array_unref (self->disabled_plugins); g_ptr_array_unref (self->approved_firmware); + g_ptr_array_unref (self->blocked_firmware); g_free (self->config_file); G_OBJECT_CLASS (fu_config_parent_class)->finalize (obj); diff --git a/src/fu-config.h b/src/fu-config.h index 72b2c28ab..6c8d6e340 100644 --- a/src/fu-config.h +++ b/src/fu-config.h @@ -26,5 +26,6 @@ guint fu_config_get_idle_timeout (FuConfig *self); GPtrArray *fu_config_get_disabled_devices (FuConfig *self); GPtrArray *fu_config_get_disabled_plugins (FuConfig *self); GPtrArray *fu_config_get_approved_firmware (FuConfig *self); +GPtrArray *fu_config_get_blocked_firmware (FuConfig *self); gboolean fu_config_get_update_motd (FuConfig *self); gboolean fu_config_get_enumerate_all_devices (FuConfig *self); diff --git a/src/fu-engine.c b/src/fu-engine.c index d0f7c5975..a87a9ce22 100644 --- a/src/fu-engine.c +++ b/src/fu-engine.c @@ -103,6 +103,7 @@ struct _FuEngine GHashTable *runtime_versions; GHashTable *compile_versions; GHashTable *approved_firmware; /* (nullable) */ + GHashTable *blocked_firmware; /* (nullable) */ GHashTable *firmware_gtypes; gchar *host_machine_id; JcatContext *jcat_context; @@ -527,6 +528,7 @@ fu_engine_modify_config (FuEngine *self, const gchar *key, const gchar *value, G const gchar *keys[] = { "ArchiveSizeMax", "DisabledDevices", + "BlockedFirmware", "DisabledPlugins", "IdleTimeout", "VerboseDomains", @@ -4178,6 +4180,21 @@ fu_engine_check_release_is_approved (FuEngine *self, FwupdRelease *rel) return FALSE; } +static gboolean +fu_engine_check_release_is_blocked (FuEngine *self, FwupdRelease *rel) +{ + GPtrArray *csums = fwupd_release_get_checksums (rel); + if (self->blocked_firmware == NULL) + return FALSE; + for (guint i = 0; i < csums->len; i++) { + const gchar *csum = g_ptr_array_index (csums, i); + g_debug ("checking %s against blocked list", csum); + if (g_hash_table_lookup (self->blocked_firmware, csum) != NULL) + return TRUE; + } + return FALSE; +} + static gboolean fu_engine_add_releases_for_device_component (FuEngine *self, FuEngineRequest *request, @@ -4258,6 +4275,10 @@ fu_engine_add_releases_for_device_component (FuEngine *self, fwupd_release_add_flag (rel, FWUPD_RELEASE_FLAG_BLOCKED_VERSION); } + /* manually blocked */ + if (fu_engine_check_release_is_blocked (self, rel)) + fwupd_release_add_flag (rel, FWUPD_RELEASE_FLAG_BLOCKED_APPROVAL); + /* check if remote is filtering firmware */ remote_id = fwupd_release_get_remote_id (rel); if (remote_id != NULL) { @@ -4545,6 +4566,56 @@ fu_engine_add_approved_firmware (FuEngine *self, const gchar *checksum) g_hash_table_add (self->approved_firmware, g_strdup (checksum)); } +GPtrArray * +fu_engine_get_blocked_firmware (FuEngine *self) +{ + GPtrArray *checksums = g_ptr_array_new_with_free_func (g_free); + if (self->blocked_firmware != NULL) { + g_autoptr(GList) keys = g_hash_table_get_keys (self->blocked_firmware); + for (GList *l = keys; l != NULL; l = l->next) { + const gchar *csum = l->data; + g_ptr_array_add (checksums, g_strdup (csum)); + } + } + return checksums; +} + +void +fu_engine_add_blocked_firmware (FuEngine *self, const gchar *checksum) +{ + if (self->blocked_firmware == NULL) { + self->blocked_firmware = g_hash_table_new_full (g_str_hash, + g_str_equal, + g_free, + NULL); + } + g_hash_table_add (self->blocked_firmware, g_strdup (checksum)); +} + +gboolean +fu_engine_set_blocked_firmware (FuEngine *self, GPtrArray *checksums, GError **error) +{ + /* update in-memory hash */ + if (self->blocked_firmware != NULL) { + g_hash_table_unref (self->blocked_firmware); + self->blocked_firmware = NULL; + } + for (guint i = 0; i < checksums->len; i++) { + const gchar *csum = g_ptr_array_index (checksums, i); + fu_engine_add_blocked_firmware (self, csum); + } + + /* save database */ + if (!fu_history_clear_blocked_firmware (self->history, error)) + return FALSE; + for (guint i = 0; i < checksums->len; i++) { + const gchar *csum = g_ptr_array_index (checksums, i); + if (!fu_history_add_blocked_firmware (self->history, csum, error)) + return FALSE; + } + return TRUE; +} + gchar * fu_engine_self_sign (FuEngine *self, const gchar *value, @@ -6123,7 +6194,8 @@ fu_engine_load (FuEngine *self, FuEngineLoadFlags flags, GError **error) { FuRemoteListLoadFlags remote_list_flags = FU_REMOTE_LIST_LOAD_FLAG_NONE; FuQuirksLoadFlags quirks_flags = FU_QUIRKS_LOAD_FLAG_NONE; - g_autoptr(GPtrArray) checksums = NULL; + g_autoptr(GPtrArray) checksums_approved = NULL; + g_autoptr(GPtrArray) checksums_blocked = NULL; #ifndef _WIN32 g_autoptr(GError) error_local = NULL; #endif @@ -6159,21 +6231,33 @@ fu_engine_load (FuEngine *self, FuEngineLoadFlags flags, GError **error) /* create client certificate */ fu_engine_ensure_client_certificate (self); - /* get hardcoded approved firmware */ - checksums = fu_config_get_approved_firmware (self->config); - for (guint i = 0; i < checksums->len; i++) { - const gchar *csum = g_ptr_array_index (checksums, i); + /* get hardcoded approved and blocked firmware */ + checksums_approved = fu_config_get_approved_firmware (self->config); + for (guint i = 0; i < checksums_approved->len; i++) { + const gchar *csum = g_ptr_array_index (checksums_approved, i); fu_engine_add_approved_firmware (self, csum); } + checksums_blocked = fu_config_get_blocked_firmware (self->config); + for (guint i = 0; i < checksums_blocked->len; i++) { + const gchar *csum = g_ptr_array_index (checksums_blocked, i); + fu_engine_add_blocked_firmware (self, csum); + } /* get extra firmware saved to the database */ - checksums = fu_history_get_approved_firmware (self->history, error); - if (checksums == NULL) + checksums_approved = fu_history_get_approved_firmware (self->history, error); + if (checksums_approved == NULL) return FALSE; - for (guint i = 0; i < checksums->len; i++) { - const gchar *csum = g_ptr_array_index (checksums, i); + for (guint i = 0; i < checksums_approved->len; i++) { + const gchar *csum = g_ptr_array_index (checksums_approved, i); fu_engine_add_approved_firmware (self, csum); } + checksums_blocked = fu_history_get_blocked_firmware (self->history, error); + if (checksums_blocked == NULL) + return FALSE; + for (guint i = 0; i < checksums_blocked->len; i++) { + const gchar *csum = g_ptr_array_index (checksums_blocked, i); + fu_engine_add_blocked_firmware (self, csum); + } /* set up idle exit */ if ((self->app_flags & FU_APP_FLAGS_NO_IDLE_SOURCES) == 0) @@ -6446,6 +6530,8 @@ fu_engine_finalize (GObject *obj) g_source_remove (self->coldplug_id); if (self->approved_firmware != NULL) g_hash_table_unref (self->approved_firmware); + if (self->blocked_firmware != NULL) + g_hash_table_unref (self->blocked_firmware); g_free (self->host_machine_id); g_free (self->host_security_id); diff --git a/src/fu-engine.h b/src/fu-engine.h index eaad096e8..08462198b 100644 --- a/src/fu-engine.h +++ b/src/fu-engine.h @@ -159,6 +159,14 @@ gboolean fu_engine_activate (FuEngine *self, GPtrArray *fu_engine_get_approved_firmware (FuEngine *self); void fu_engine_add_approved_firmware (FuEngine *self, const gchar *checksum); +void fu_engine_set_approved_firmware (FuEngine *self, + GPtrArray *checksums); +GPtrArray *fu_engine_get_blocked_firmware (FuEngine *self); +void fu_engine_add_blocked_firmware (FuEngine *self, + const gchar *checksum); +gboolean fu_engine_set_blocked_firmware (FuEngine *self, + GPtrArray *checksums, + GError **error); gchar *fu_engine_self_sign (FuEngine *self, const gchar *value, JcatSignFlags flags, diff --git a/src/fu-history.c b/src/fu-history.c index 96db6bd91..6de1970d5 100644 --- a/src/fu-history.c +++ b/src/fu-history.c @@ -20,7 +20,7 @@ #include "fu-history.h" #include "fu-mutex.h" -#define FU_HISTORY_CURRENT_SCHEMA_VERSION 5 +#define FU_HISTORY_CURRENT_SCHEMA_VERSION 6 static void fu_history_finalize (GObject *object); @@ -181,6 +181,8 @@ fu_history_create_database (FuHistory *self, GError **error) "protocol TEXT DEFAULT NULL);" "CREATE TABLE IF NOT EXISTS approved_firmware (" "checksum TEXT);" + "CREATE TABLE IF NOT EXISTS blocked_firmware (" + "checksum TEXT);" "COMMIT;", NULL, NULL, NULL); if (rc != SQLITE_OK) { g_set_error (error, FWUPD_ERROR, FWUPD_ERROR_INTERNAL, @@ -269,6 +271,22 @@ fu_history_migrate_database_v4 (FuHistory *self, GError **error) return TRUE; } +static gboolean +fu_history_migrate_database_v5 (FuHistory *self, GError **error) +{ + gint rc; + rc = sqlite3_exec (self->db, + "CREATE TABLE IF NOT EXISTS blocked_firmware (checksum TEXT);", + NULL, NULL, NULL); + if (rc != SQLITE_OK) { + g_set_error (error, FWUPD_ERROR, FWUPD_ERROR_INTERNAL, + "Failed to create table: %s", + sqlite3_errmsg (self->db)); + return FALSE; + } + return TRUE; +} + /* returns 0 if database is not initialised */ static guint fu_history_get_schema_version (FuHistory *self) @@ -315,16 +333,26 @@ fu_history_create_or_migrate (FuHistory *self, guint schema_ver, GError **error) return FALSE; if (!fu_history_migrate_database_v4 (self, error)) return FALSE; + if (!fu_history_migrate_database_v5 (self, error)) + return FALSE; } else if (schema_ver == 3) { g_debug ("migrating v%u database by altering", schema_ver); if (!fu_history_migrate_database_v3 (self, error)) return FALSE; if (!fu_history_migrate_database_v4 (self, error)) return FALSE; + if (!fu_history_migrate_database_v5 (self, error)) + return FALSE; } else if (schema_ver == 4) { g_debug ("migrating v%u database by altering", schema_ver); if (!fu_history_migrate_database_v4 (self, error)) return FALSE; + if (!fu_history_migrate_database_v5 (self, error)) + return FALSE; + } else if (schema_ver == 5) { + g_debug ("migrating v%u database by altering", schema_ver); + if (!fu_history_migrate_database_v5 (self, error)) + return FALSE; } else { /* this is probably okay, but return an error if we ever delete * or rename columns */ @@ -1066,6 +1094,139 @@ fu_history_add_approved_firmware (FuHistory *self, sqlite3_bind_text (stmt, 1, checksum, -1, SQLITE_STATIC); return fu_history_stmt_exec (self, stmt, NULL, error); } +/** + * fu_history_get_blocked_firmware: + * @self: A #FuHistory + * @error: A #GError or NULL + * + * Returns blocked firmware records. + * + * Returns: (transfer full) (element-type gchar *): records + * + * Since: 1.4.6 + **/ +GPtrArray * +fu_history_get_blocked_firmware (FuHistory *self, GError **error) +{ + gint rc; + g_autoptr(GRWLockReaderLocker) locker = NULL; + g_autoptr(GPtrArray) array = NULL; + g_autoptr(sqlite3_stmt) stmt = NULL; + + g_return_val_if_fail (FU_IS_HISTORY (self), NULL); + + /* lazy load */ + if (self->db == NULL) { + if (!fu_history_load (self, error)) + return NULL; + } + + /* get all the blocked firmware */ + locker = g_rw_lock_reader_locker_new (&self->db_mutex); + g_return_val_if_fail (locker != NULL, NULL); + rc = sqlite3_prepare_v2 (self->db, + "SELECT checksum FROM blocked_firmware;", + -1, &stmt, NULL); + if (rc != SQLITE_OK) { + g_set_error (error, FWUPD_ERROR, FWUPD_ERROR_INTERNAL, + "Failed to prepare SQL to get checksum: %s", + sqlite3_errmsg (self->db)); + return NULL; + } + array = g_ptr_array_new_with_free_func (g_free); + while ((rc = sqlite3_step (stmt)) == SQLITE_ROW) { + const gchar *tmp = (const gchar *) sqlite3_column_text (stmt, 0); + g_ptr_array_add (array, g_strdup (tmp)); + } + if (rc != SQLITE_DONE) { + g_set_error (error, FWUPD_ERROR, FWUPD_ERROR_WRITE, + "failed to execute prepared statement: %s", + sqlite3_errmsg (self->db)); + return NULL; + } + return g_steal_pointer (&array); +} + +/** + * fu_history_clear_blocked_firmware: + * @self: A #FuHistory + * @error: A #GError or NULL + * + * Clear all blocked firmware records + * + * Returns: #TRUE for success, #FALSE for failure + * + * Since: 1.4.6 + **/ +gboolean +fu_history_clear_blocked_firmware (FuHistory *self, GError **error) +{ + gint rc; + g_autoptr(sqlite3_stmt) stmt = NULL; + g_autoptr(GRWLockWriterLocker) locker = NULL; + + g_return_val_if_fail (FU_IS_HISTORY (self), FALSE); + + /* lazy load */ + if (!fu_history_load (self, error)) + return FALSE; + + /* remove entries */ + locker = g_rw_lock_writer_locker_new (&self->db_mutex); + g_return_val_if_fail (locker != NULL, FALSE); + rc = sqlite3_prepare_v2 (self->db, + "DELETE FROM blocked_firmware;", + -1, &stmt, NULL); + if (rc != SQLITE_OK) { + g_set_error (error, FWUPD_ERROR, FWUPD_ERROR_INTERNAL, + "Failed to prepare SQL to delete blocked firmware: %s", + sqlite3_errmsg (self->db)); + return FALSE; + } + return fu_history_stmt_exec (self, stmt, NULL, error); +} + +/** + * fu_history_add_blocked_firmware: + * @self: A #FuHistory + * @checksum: a string + * @error: A #GError or NULL + * + * Add an blocked firmware record to the database + * + * Returns: #TRUE for success, #FALSE for failure + * + * Since: 1.4.6 + **/ +gboolean +fu_history_add_blocked_firmware (FuHistory *self, const gchar *checksum, GError **error) +{ + gint rc; + g_autoptr(sqlite3_stmt) stmt = NULL; + g_autoptr(GRWLockWriterLocker) locker = NULL; + + g_return_val_if_fail (FU_IS_HISTORY (self), FALSE); + g_return_val_if_fail (checksum != NULL, FALSE); + + /* lazy load */ + if (!fu_history_load (self, error)) + return FALSE; + + /* add */ + locker = g_rw_lock_writer_locker_new (&self->db_mutex); + g_return_val_if_fail (locker != NULL, FALSE); + rc = sqlite3_prepare_v2 (self->db, + "INSERT INTO blocked_firmware (checksum) " + "VALUES (?1)", -1, &stmt, NULL); + if (rc != SQLITE_OK) { + g_set_error (error, FWUPD_ERROR, FWUPD_ERROR_INTERNAL, + "Failed to prepare SQL to insert checksum: %s", + sqlite3_errmsg (self->db)); + return FALSE; + } + sqlite3_bind_text (stmt, 1, checksum, -1, SQLITE_STATIC); + return fu_history_stmt_exec (self, stmt, NULL, error); +} static void fu_history_class_init (FuHistoryClass *klass) diff --git a/src/fu-history.h b/src/fu-history.h index f5b92fa12..84e4ae935 100644 --- a/src/fu-history.h +++ b/src/fu-history.h @@ -47,3 +47,10 @@ gboolean fu_history_add_approved_firmware (FuHistory *self, GError **error); GPtrArray *fu_history_get_approved_firmware (FuHistory *self, GError **error); +gboolean fu_history_clear_blocked_firmware (FuHistory *self, + GError **error); +gboolean fu_history_add_blocked_firmware (FuHistory *self, + const gchar *checksum, + GError **error); +GPtrArray *fu_history_get_blocked_firmware (FuHistory *self, + GError **error); diff --git a/src/fu-main.c b/src/fu-main.c index fe4e7316c..3f5cce94b 100644 --- a/src/fu-main.c +++ b/src/fu-main.c @@ -430,6 +430,30 @@ fu_main_authorize_set_approved_firmware_cb (GObject *source, GAsyncResult *res, g_dbus_method_invocation_return_value (helper->invocation, NULL); } +static void +fu_main_authorize_set_blocked_firmware_cb (GObject *source, GAsyncResult *res, gpointer user_data) +{ + g_autoptr(FuMainAuthHelper) helper = (FuMainAuthHelper *) user_data; + g_autoptr(GError) error = NULL; + g_autoptr(PolkitAuthorizationResult) auth = NULL; + + /* get result */ + fu_main_set_status (helper->priv, FWUPD_STATUS_IDLE); + auth = polkit_authority_check_authorization_finish (POLKIT_AUTHORITY (source), + res, &error); + if (!fu_main_authorization_is_valid (auth, &error)) { + g_dbus_method_invocation_return_gerror (helper->invocation, error); + return; + } + + /* success */ + if (!fu_engine_set_blocked_firmware (helper->priv->engine, helper->checksums, &error)) { + g_dbus_method_invocation_return_gerror (helper->invocation, error); + return; + } + g_dbus_method_invocation_return_value (helper->invocation, NULL); +} + static void fu_main_authorize_self_sign_cb (GObject *source, GAsyncResult *res, gpointer user_data) { @@ -878,6 +902,19 @@ fu_main_daemon_method_call (GDBusConnection *connection, const gchar *sender, g_variant_new_tuple (&val, 1)); return; } + if (g_strcmp0 (method_name, "GetBlockedFirmware") == 0) { + GVariantBuilder builder; + GPtrArray *checksums = fu_engine_get_blocked_firmware (priv->engine); + g_variant_builder_init (&builder, G_VARIANT_TYPE ("as")); + for (guint i = 0; i < checksums->len; i++) { + const gchar *checksum = g_ptr_array_index (checksums, i); + g_variant_builder_add_value (&builder, g_variant_new_string (checksum)); + } + val = g_variant_builder_end (&builder); + g_dbus_method_invocation_return_value (invocation, + g_variant_new_tuple (&val, 1)); + return; + } if (g_strcmp0 (method_name, "GetReportMetadata") == 0) { GHashTableIter iter; GVariantBuilder builder; @@ -932,6 +969,35 @@ fu_main_daemon_method_call (GDBusConnection *connection, const gchar *sender, g_steal_pointer (&helper)); return; } + if (g_strcmp0 (method_name, "SetBlockedFirmware") == 0) { + g_autofree gchar *checksums_str = NULL; + g_auto(GStrv) checksums = NULL; + g_autoptr(FuMainAuthHelper) helper = NULL; + g_autoptr(PolkitSubject) subject = NULL; + + g_variant_get (parameters, "(^as)", &checksums); + checksums_str = g_strjoinv (",", checksums); + g_debug ("Called %s(%s)", method_name, checksums_str); + + /* authenticate */ + fu_main_set_status (priv, FWUPD_STATUS_WAITING_FOR_AUTH); + helper = g_new0 (FuMainAuthHelper, 1); + helper->priv = priv; + helper->request = g_steal_pointer (&request); + helper->invocation = g_object_ref (invocation); + helper->checksums = g_ptr_array_new_with_free_func (g_free); + for (guint i = 0; checksums[i] != NULL; i++) + g_ptr_array_add (helper->checksums, g_strdup (checksums[i])); + subject = polkit_system_bus_name_new (sender); + polkit_authority_check_authorization (priv->authority, subject, + "org.freedesktop.fwupd.set-approved-firmware", + NULL, + POLKIT_CHECK_AUTHORIZATION_FLAGS_ALLOW_USER_INTERACTION, + NULL, + fu_main_authorize_set_blocked_firmware_cb, + g_steal_pointer (&helper)); + return; + } if (g_strcmp0 (method_name, "SelfSign") == 0) { GVariant *prop_value; gchar *prop_key; diff --git a/src/fu-util.c b/src/fu-util.c index 11ae78fc2..bff5163a1 100644 --- a/src/fu-util.c +++ b/src/fu-util.c @@ -2311,6 +2311,162 @@ fu_util_check_polkit_actions (GError **error) G_DEFINE_AUTOPTR_CLEANUP_FUNC(FuUtilPrivate, fu_util_private_free) #pragma clang diagnostic pop +static gchar * +fu_util_get_history_checksum (FuUtilPrivate *priv, GError **error) +{ + const gchar *csum; + g_autoptr(FwupdDevice) device = NULL; + g_autoptr(FwupdRelease) release = NULL; + g_autoptr(GPtrArray) devices = NULL; + + devices = fwupd_client_get_history (priv->client, NULL, error); + if (devices == NULL) + return NULL; + device = fu_util_prompt_for_device (priv, devices, error); + if (device == NULL) + return NULL; + release = fu_util_prompt_for_release (priv, fwupd_device_get_releases (device), error); + if (release == NULL) + return NULL; + csum = fwupd_checksum_get_best (fwupd_release_get_checksums (release)); + if (csum == NULL) { + g_set_error_literal (error, + FWUPD_ERROR, + FWUPD_ERROR_NOTHING_TO_DO, + "No suitable checksums"); + return NULL; + } + return g_strdup (csum); +} + +static gboolean +fu_util_block_firmware (FuUtilPrivate *priv, gchar **values, GError **error) +{ + guint idx = 0; + g_autofree gchar *csum = NULL; + g_auto(GStrv) csums_new = NULL; + g_auto(GStrv) csums = NULL; + + /* get existing checksums */ + csums = fwupd_client_get_blocked_firmware (priv->client, priv->cancellable, error); + if (csums == NULL) + return FALSE; + + /* get new value */ + if (g_strv_length (values) == 0) { + csum = fu_util_get_history_checksum (priv, error); + if (csum == NULL) + return FALSE; + } else { + csum = g_strdup (values[0]); + } + + /* ensure it's not already there */ + if (g_strv_contains ((const gchar * const *) csums, csum)) { + g_set_error_literal (error, + FWUPD_ERROR, + FWUPD_ERROR_NOTHING_TO_DO, + /* TRANSLATORS: user selected something not possible */ + _("Firmware is already blocked")); + return FALSE; + } + + /* TRANSLATORS: we will not offer this firmware to the user */ + g_print ("%s %s\n", _("Blocking firmware:"), csum); + + /* remove it from the new list */ + csums_new = g_new0 (gchar *, g_strv_length (csums) + 2); + for (guint i = 0; csums[i] != NULL; i++) { + if (g_strcmp0 (csums[i], csum) != 0) + csums_new[idx++] = g_strdup (csums[i]); + } + csums_new[idx] = g_strdup (csum); + return fwupd_client_set_blocked_firmware (priv->client, csums_new, + priv->cancellable, error); +} + +static gboolean +fu_util_unblock_firmware (FuUtilPrivate *priv, gchar **values, GError **error) +{ + guint idx = 0; + g_auto(GStrv) csums = NULL; + g_auto(GStrv) csums_new = NULL; + g_autofree gchar *csum = NULL; + + /* get existing checksums */ + csums = fwupd_client_get_blocked_firmware (priv->client, priv->cancellable, error); + if (csums == NULL) + return FALSE; + + /* empty list */ + if (g_strv_length (csums) == 0) { + g_set_error_literal (error, + FWUPD_ERROR, + FWUPD_ERROR_NOTHING_TO_DO, + /* TRANSLATORS: nothing to show */ + _("There are no blocked firmware files")); + return FALSE; + } + + /* get new value */ + if (g_strv_length (values) == 0) { + csum = fu_util_get_history_checksum (priv, error); + if (csum == NULL) + return FALSE; + } else { + csum = g_strdup (values[0]); + } + + /* ensure it's there */ + if (!g_strv_contains ((const gchar * const *) csums, csum)) { + g_set_error_literal (error, + FWUPD_ERROR, + FWUPD_ERROR_NOTHING_TO_DO, + /* TRANSLATORS: user selected something not possible */ + _("Firmware is not already blocked")); + return FALSE; + } + + /* TRANSLATORS: we will not offer this firmware to the user */ + g_print ("%s %s\n", _("Unblocking firmware:"), csum); + + /* remove it from the new list */ + csums_new = g_new0 (gchar *, g_strv_length (csums)); + for (guint i = 0; csums[i] != NULL; i++) { + if (g_strcmp0 (csums[i], csum) != 0) + csums_new[idx++] = g_strdup (csums[i]); + } + return fwupd_client_set_blocked_firmware (priv->client, csums_new, + priv->cancellable, error); +} + +static gboolean +fu_util_get_blocked_firmware (FuUtilPrivate *priv, gchar **values, GError **error) +{ + g_auto(GStrv) csums = NULL; + + /* get checksums */ + csums = fwupd_client_get_blocked_firmware (priv->client, priv->cancellable, error); + if (csums == NULL) + return FALSE; + + /* empty list */ + if (g_strv_length (csums) == 0) { + /* TRANSLATORS: nothing to show */ + g_print ("%s\n", _("There are no blocked firmware files")); + return TRUE; + } + + /* TRANSLATORS: there follows a list of hashes */ + g_print ("%s\n", _("Blocked firmware files:")); + for (guint i = 0; csums[i] != NULL; i++) { + g_print ("%u.\t%s\n", i + 1, csums[i]); + } + + /* success */ + return TRUE; +} + int main (int argc, char *argv[]) { @@ -2557,6 +2713,24 @@ main (int argc, char *argv[]) /* TRANSLATORS: command description */ _("Gets the host security attributes."), fu_util_security); + fu_util_cmd_array_add (cmd_array, + "block-firmware", + "[CHECKSUM]", + /* TRANSLATORS: command description */ + _("Blocks a specific firmware from being installed."), + fu_util_block_firmware); + fu_util_cmd_array_add (cmd_array, + "unblock-firmware", + "[CHECKSUM]", + /* TRANSLATORS: command description */ + _("Blocks a specific firmware from being installed."), + fu_util_unblock_firmware); + fu_util_cmd_array_add (cmd_array, + "get-blocked-firmware", + NULL, + /* TRANSLATORS: command description */ + _("Gets the list of blocked firmware."), + fu_util_get_blocked_firmware); /* do stuff on ctrl+c */ priv->cancellable = g_cancellable_new (); diff --git a/src/org.freedesktop.fwupd.xml b/src/org.freedesktop.fwupd.xml index 79904c793..6b0f7448e 100644 --- a/src/org.freedesktop.fwupd.xml +++ b/src/org.freedesktop.fwupd.xml @@ -489,6 +489,42 @@
+ + + + + + Gets the list of blocked firmware. + + + + + + + The checksums of the archives + + + + + + + + + + + Sets the list of blocked firmware that can be applied to devices. + + + + + + + The checksums of the archives + + + + + From 8131fceb6bbf01817e5f4d405a0c65662439f9e4 Mon Sep 17 00:00:00 2001 From: Mario Limonciello Date: Mon, 10 Aug 2020 09:12:34 -0500 Subject: [PATCH 310/607] trivial: adjust migration code to remove duplication --- src/fu-history.c | 45 ++++++++++++++++++++------------------------- 1 file changed, 20 insertions(+), 25 deletions(-) diff --git a/src/fu-history.c b/src/fu-history.c index 6de1970d5..2903fbebd 100644 --- a/src/fu-history.c +++ b/src/fu-history.c @@ -198,6 +198,7 @@ fu_history_migrate_database_v1 (FuHistory *self, GError **error) { gint rc; + g_debug ("migrating v1 database by recreating table"); /* rename the table to something out the way */ rc = sqlite3_exec (self->db, "ALTER TABLE history RENAME TO history_old;", @@ -316,44 +317,38 @@ fu_history_create_or_migrate (FuHistory *self, guint schema_ver, GError **error) gint rc; g_autoptr(sqlite3_stmt) stmt = NULL; - /* create initial up-to-date database or migrate */ - if (schema_ver == 0) { + if (schema_ver == 0) g_debug ("building initial database"); + else if (schema_ver > 1) + g_debug ("migrating v%u database by altering", schema_ver); + + switch (schema_ver) { + /* create initial up-to-date database or migrate */ + case 0: if (!fu_history_create_database (self, error)) return FALSE; - } else if (schema_ver == 1) { - g_debug ("migrating v%u database by recreating table", schema_ver); + break; + case 1: if (!fu_history_migrate_database_v1 (self, error)) return FALSE; - } else if (schema_ver == 2) { - g_debug ("migrating v%u database by altering", schema_ver); + break; + case 2: if (!fu_history_migrate_database_v2 (self, error)) return FALSE; + /* fall through */ + case 3: if (!fu_history_migrate_database_v3 (self, error)) return FALSE; + /* fall through */ + case 4: if (!fu_history_migrate_database_v4 (self, error)) return FALSE; + /* fall through */ + case 5: if (!fu_history_migrate_database_v5 (self, error)) return FALSE; - } else if (schema_ver == 3) { - g_debug ("migrating v%u database by altering", schema_ver); - if (!fu_history_migrate_database_v3 (self, error)) - return FALSE; - if (!fu_history_migrate_database_v4 (self, error)) - return FALSE; - if (!fu_history_migrate_database_v5 (self, error)) - return FALSE; - } else if (schema_ver == 4) { - g_debug ("migrating v%u database by altering", schema_ver); - if (!fu_history_migrate_database_v4 (self, error)) - return FALSE; - if (!fu_history_migrate_database_v5 (self, error)) - return FALSE; - } else if (schema_ver == 5) { - g_debug ("migrating v%u database by altering", schema_ver); - if (!fu_history_migrate_database_v5 (self, error)) - return FALSE; - } else { + break; + default: /* this is probably okay, but return an error if we ever delete * or rename columns */ g_warning ("schema version %u is unknown", schema_ver); From 334a4d9f30eff723084f7a451f391210469d6efa Mon Sep 17 00:00:00 2001 From: Vincent Huang Date: Wed, 12 Aug 2020 16:28:55 +0800 Subject: [PATCH 311/607] synaptics-prometheus: generate new guid with configid and add pids to quirk file --- plugins/synaptics-prometheus/README.md | 2 ++ .../synaptics-prometheus/fu-synaprom-config.c | 20 ++++++++++++++----- .../synaptics-prometheus.quirk | 8 ++++++++ 3 files changed, 25 insertions(+), 5 deletions(-) diff --git a/plugins/synaptics-prometheus/README.md b/plugins/synaptics-prometheus/README.md index d5d93b7d6..c448680eb 100644 --- a/plugins/synaptics-prometheus/README.md +++ b/plugins/synaptics-prometheus/README.md @@ -24,6 +24,8 @@ These devices use the standard USB DeviceInstanceId values, e.g. * `USB\VID_06CB&PID_00A9&REV_0001` * `USB\VID_06CB&PID_00A9` + * `USB\VID_06CB&PID_00A9-cfg` + * `USB\VID_06CB&PID_00A9&CFG1_3483&CFG2_500` Vendor ID Security ------------------ diff --git a/plugins/synaptics-prometheus/fu-synaprom-config.c b/plugins/synaptics-prometheus/fu-synaprom-config.c index 1068d6bc4..371d8d809 100644 --- a/plugins/synaptics-prometheus/fu-synaprom-config.c +++ b/plugins/synaptics-prometheus/fu-synaprom-config.c @@ -67,6 +67,7 @@ fu_synaprom_config_setup (FuDevice *device, GError **error) g_autofree gchar *version = NULL; g_autoptr(GByteArray) reply = NULL; g_autoptr(GByteArray) request = NULL; + g_autofree gchar *devid = NULL; /* get IOTA */ cmd.itype = GUINT16_TO_LE((guint16)FU_SYNAPROM_IOTA_ITYPE_CONFIG_VERSION); @@ -103,6 +104,13 @@ fu_synaprom_config_setup (FuDevice *device, GError **error) self->configid1, self->configid2, GUINT16_FROM_LE(cfg.version)); + /* append the configid to the generated GUID */ + devid = g_strdup_printf ("USB\\VID_%04X&PID_%04X&CFG1_%u&CFG2_%u", + fu_usb_device_get_vid (FU_USB_DEVICE (parent)), + fu_usb_device_get_pid (FU_USB_DEVICE (parent)), + self->configid1, self->configid2); + fu_device_add_instance_id (FU_DEVICE (self), devid); + /* no downgrades are allowed */ version = g_strdup_printf ("%04u", GUINT16_FROM_LE(cfg.version)); fu_device_set_version (FU_DEVICE (self), version); @@ -122,6 +130,7 @@ fu_synaprom_config_prepare_firmware (FuDevice *device, g_autoptr(FuFirmware) firmware = fu_synaprom_firmware_new (); guint32 product; guint32 id1; + guint32 id2; /* parse the firmware */ fu_device_set_status (device, FWUPD_STATUS_DECOMPRESSING); @@ -157,18 +166,19 @@ fu_synaprom_config_prepare_firmware (FuDevice *device, } } id1 = GUINT32_FROM_LE(hdr.id1); - if (id1 != self->configid1) { + id2 = GUINT32_FROM_LE(hdr.id2); + if (id1 != self->configid1 || id2 != self->configid2) { if (flags & FWUPD_INSTALL_FLAG_FORCE) { g_warning ("CFG version not compatible, " - "got %u expected %u", - id1, self->configid1); + "got %u:%u expected %u:%u", + id1, id2, self->configid1, self->configid2); } else { g_set_error (error, G_IO_ERROR, G_IO_ERROR_NOT_SUPPORTED, "CFG version not compatible, " - "got %u expected %u", - id1, self->configid1); + "got %u:%u expected %u:%u", + id1, id2, self->configid1, self->configid2); return NULL; } } diff --git a/plugins/synaptics-prometheus/synaptics-prometheus.quirk b/plugins/synaptics-prometheus/synaptics-prometheus.quirk index 2fe394f23..95170f9ee 100644 --- a/plugins/synaptics-prometheus/synaptics-prometheus.quirk +++ b/plugins/synaptics-prometheus/synaptics-prometheus.quirk @@ -5,3 +5,11 @@ InstallDuration = 2 [DeviceInstanceId=USB\VID_06CB&PID_00BD] Plugin = synaptics_prometheus InstallDuration = 2 + +[DeviceInstanceId=USB\VID_06CB&PID_00DF] +Plugin = synaptics_prometheus +InstallDuration = 2 + +[DeviceInstanceId=USB\VID_06CB&PID_00E9] +Plugin = synaptics_prometheus +InstallDuration = 2 From 0031b474bcf169da8ed9b66ae09bd122e253d296 Mon Sep 17 00:00:00 2001 From: Richard Hughes Date: Wed, 12 Aug 2020 12:22:25 +0100 Subject: [PATCH 312/607] Fix a critical warning if constructing a FuDeviceLocker using the GType --- libfwupdplugin/fu-device-locker.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/libfwupdplugin/fu-device-locker.c b/libfwupdplugin/fu-device-locker.c index 0ccdb270f..d2373971b 100644 --- a/libfwupdplugin/fu-device-locker.c +++ b/libfwupdplugin/fu-device-locker.c @@ -46,8 +46,8 @@ fu_device_locker_finalize (GObject *obj) if (!self->close_func (self->device, &error)) g_warning ("failed to close device: %s", error->message); } - - g_object_unref (self->device); + if (self->device != NULL) + g_object_unref (self->device); G_OBJECT_CLASS (fu_device_locker_parent_class)->finalize (obj); } From 99dda53cc29111d64e3ca7804660828b67ba350c Mon Sep 17 00:00:00 2001 From: Richard Hughes Date: Wed, 12 Aug 2020 15:03:50 +0100 Subject: [PATCH 313/607] trivial: Define one more EFI GUID --- libfwupdplugin/fu-efivar.h | 1 + plugins/uefi-dbx/fu-plugin-uefi-dbx.c | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/libfwupdplugin/fu-efivar.h b/libfwupdplugin/fu-efivar.h index c966c109e..7f639d7ed 100644 --- a/libfwupdplugin/fu-efivar.h +++ b/libfwupdplugin/fu-efivar.h @@ -12,6 +12,7 @@ #define FU_EFIVAR_GUID_EFI_GLOBAL "8be4df61-93ca-11d2-aa0d-00e098032b8c" #define FU_EFIVAR_GUID_FWUPDATE "0abba7dc-e516-4167-bbf5-4d9d1c739416" #define FU_EFIVAR_GUID_UX_CAPSULE "3b8c8162-188c-46a4-aec9-be43f1d65697" +#define FU_EFIVAR_GUID_SECURITY_DATABASE "d719b2cb-3d3a-4596-a3bc-dad00e67656f" #define FU_EFIVAR_ATTR_NON_VOLATILE (1 << 0) #define FU_EFIVAR_ATTR_BOOTSERVICE_ACCESS (1 << 1) diff --git a/plugins/uefi-dbx/fu-plugin-uefi-dbx.c b/plugins/uefi-dbx/fu-plugin-uefi-dbx.c index 4aed0eb48..9692b957b 100644 --- a/plugins/uefi-dbx/fu-plugin-uefi-dbx.c +++ b/plugins/uefi-dbx/fu-plugin-uefi-dbx.c @@ -84,7 +84,7 @@ fu_plugin_add_security_attrs (FuPlugin *plugin, FuSecurityAttrs *attrs) } /* get system dbx */ - if (!fu_efivar_get_data ("d719b2cb-3d3a-4596-a3bc-dad00e67656f", "dbx", + if (!fu_efivar_get_data (FU_EFIVAR_GUID_SECURITY_DATABASE, "dbx", &buf_system, &bufsz, NULL, &error_local)) { g_warning ("failed to load EFI dbx: %s", error_local->message); fwupd_security_attr_set_result (attr, FWUPD_SECURITY_ATTR_RESULT_NOT_VALID); From 8f0b2d1708a73c2bacb5b996d0a4be6745d693e8 Mon Sep 17 00:00:00 2001 From: Richard Hughes Date: Wed, 12 Aug 2020 12:41:53 +0100 Subject: [PATCH 314/607] libfwupdplugin: Add FuVolume to interact with the ESP This allows us to rip out a lot of legacy code and make interacting with the ESP possible from more than one plugin. --- libfwupdplugin/fu-common.c | 200 ++++++++++++++++++++ libfwupdplugin/fu-common.h | 7 + libfwupdplugin/fu-volume-private.h | 15 ++ libfwupdplugin/fu-volume.c | 282 +++++++++++++++++++++++++++++ libfwupdplugin/fu-volume.h | 31 ++++ libfwupdplugin/fwupdplugin.h | 1 + libfwupdplugin/fwupdplugin.map | 18 +- libfwupdplugin/meson.build | 2 + 8 files changed, 555 insertions(+), 1 deletion(-) create mode 100644 libfwupdplugin/fu-volume-private.h create mode 100644 libfwupdplugin/fu-volume.c create mode 100644 libfwupdplugin/fu-volume.h diff --git a/libfwupdplugin/fu-common.c b/libfwupdplugin/fu-common.c index 67ffd9098..14cf814bd 100644 --- a/libfwupdplugin/fu-common.c +++ b/libfwupdplugin/fu-common.c @@ -33,6 +33,13 @@ #include "fwupd-error.h" #include "fu-common.h" +#include "fu-volume-private.h" + +#define UDISKS_DBUS_SERVICE "org.freedesktop.UDisks2" +#define UDISKS_DBUS_PATH "/org/freedesktop/UDisks2/Manager" +#define UDISKS_DBUS_MANAGER_INTERFACE "org.freedesktop.UDisks2.Manager" +#define UDISKS_DBUS_PART_INTERFACE "org.freedesktop.UDisks2.Partition" +#define UDISKS_DBUS_FILE_INTERFACE "org.freedesktop.UDisks2.Filesystem" /** * SECTION:fu-common @@ -2069,3 +2076,196 @@ fu_common_is_cpu_intel (void) #endif return FALSE; } + +static GPtrArray * +fu_common_get_block_devices (GDBusConnection *connection, GError **error) +{ + GVariantBuilder builder; + GVariant *input; + const gchar *obj; + g_autoptr(GVariant) output = NULL; + g_autoptr(GDBusProxy) proxy = NULL; + g_autoptr(GPtrArray) devices = NULL; + g_autoptr(GVariantIter) iter = NULL; + + proxy = g_dbus_proxy_new_sync (connection, + G_DBUS_PROXY_FLAGS_NONE, NULL, + UDISKS_DBUS_SERVICE, + UDISKS_DBUS_PATH, + UDISKS_DBUS_MANAGER_INTERFACE, + NULL, error); + if (proxy == NULL) { + g_prefix_error (error, "failed to find %s: ", UDISKS_DBUS_SERVICE); + return NULL; + } + g_variant_builder_init (&builder, G_VARIANT_TYPE_VARDICT); + input = g_variant_new ("(a{sv})", &builder); + output = g_dbus_proxy_call_sync (proxy, + "GetBlockDevices", g_variant_ref (input), + G_DBUS_CALL_FLAGS_NONE, + -1, NULL, error); + if (output == NULL) + return NULL; + devices = g_ptr_array_new_with_free_func (g_free); + g_variant_get (output, "(ao)", &iter); + while (g_variant_iter_next (iter, "o", &obj)) + g_ptr_array_add (devices, g_strdup (obj)); + + return g_steal_pointer (&devices); +} + +/** + * fu_common_get_volumes_by_kind: + * @kind: A volume kind, typically a GUID + * @error: A #GError or NULL + * + * Call into the plugin's get results routine + * + * Finds all volumes of a specific type + * + * Returns: (transfer container) (element-type FuVolume): a #GPtrArray, or %NULL if the kind was not found + * + * Since: 1.4.6 + **/ +GPtrArray * +fu_common_get_volumes_by_kind (const gchar *kind, GError **error) +{ + g_autoptr(GDBusConnection) connection = NULL; + g_autoptr(GPtrArray) devices = NULL; + g_autoptr(GPtrArray) volumes = NULL; + + connection = g_bus_get_sync (G_BUS_TYPE_SYSTEM, NULL, error); + if (connection == NULL) { + g_prefix_error (error, "failed to get system bus: "); + return NULL; + } + devices = fu_common_get_block_devices (connection, error); + if (devices == NULL) + return FALSE; + volumes = g_ptr_array_new_with_free_func ((GDestroyNotify) g_object_unref); + for (guint i = 0; i < devices->len; i++) { + const gchar *obj = g_ptr_array_index (devices, i); + const gchar *type_str; + g_autoptr(GDBusProxy) proxy_part = NULL; + g_autoptr(GDBusProxy) proxy_file = NULL; + g_autoptr(GError) error_local = NULL; + g_autoptr(GVariant) val = NULL; + + proxy_part = g_dbus_proxy_new_sync (connection, + G_DBUS_PROXY_FLAGS_NONE, NULL, + UDISKS_DBUS_SERVICE, + obj, + UDISKS_DBUS_PART_INTERFACE, + NULL, error); + if (proxy_part == NULL) { + g_prefix_error (error, "failed to initialize d-bus proxy %s: ", obj); + return FALSE; + } + val = g_dbus_proxy_get_cached_property (proxy_part, "Type"); + if (val == NULL) + continue; + + g_variant_get (val, "s", &type_str); + g_debug ("device %s, type: %s", obj, type_str); + if (g_strcmp0 (type_str, kind) != 0) + continue; + proxy_file = g_dbus_proxy_new_sync (connection, + G_DBUS_PROXY_FLAGS_NONE, NULL, + UDISKS_DBUS_SERVICE, + obj, + UDISKS_DBUS_FILE_INTERFACE, + NULL, error); + if (proxy_file == NULL) { + g_prefix_error (error, "failed to initialize d-bus proxy %s: ", obj); + return FALSE; + } + g_ptr_array_add (volumes, fu_volume_new_from_proxy (proxy_file)); + } + if (volumes->len == 0) { + g_set_error (error, + G_IO_ERROR, + G_IO_ERROR_NOT_FOUND, + "no volumes of type %s", kind); + return NULL; + } + return g_steal_pointer (&volumes); +} + +/** + * fu_common_get_esp_default: + * @error: A #GError or NULL + * + * Gets the platform default ESP + * + * Returns: (transfer full): a #FuVolume, or %NULL if the ESP was not found + * + * Since: 1.4.6 + **/ +FuVolume * +fu_common_get_esp_default (GError **error) +{ + const gchar *path_tmp; + g_autoptr(GPtrArray) volumes_fstab = g_ptr_array_new (); + g_autoptr(GPtrArray) volumes_mtab = g_ptr_array_new (); + g_autoptr(GPtrArray) volumes = NULL; + + /* for the test suite use local directory for ESP */ + path_tmp = g_getenv ("FWUPD_UEFI_ESP_PATH"); + if (path_tmp != NULL) + return fu_volume_new_from_mount_path (path_tmp); + + volumes = fu_common_get_volumes_by_kind (FU_VOLUME_KIND_ESP, error); + if (volumes == NULL) + return FALSE; + for (guint i = 0; i < volumes->len; i++) { + FuVolume *vol = g_ptr_array_index (volumes, i); + g_ptr_array_add (fu_volume_is_mounted (vol) ? volumes_mtab : volumes_fstab, vol); + } + if (volumes_mtab->len == 1) { + FuVolume *vol = g_ptr_array_index (volumes_mtab, 0); + return g_object_ref (vol); + } + if (volumes_mtab->len == 0 && volumes_fstab->len == 1) { + FuVolume *vol = g_ptr_array_index (volumes_fstab, 0); + return g_object_ref (vol); + } + g_set_error (error, + G_IO_ERROR, + G_IO_ERROR_INVALID_FILENAME, + "More than one available ESP"); + return NULL; +} + +/** + * fu_common_get_esp_for_path: + * @esp_path: A path to the ESP + * @error: A #GError or NULL + * + * Gets the platform ESP using a UNIX or UDisks path + * + * Returns: (transfer full): a #FuVolume, or %NULL if the ESP was not found + * + * Since: 1.4.6 + **/ +FuVolume * +fu_common_get_esp_for_path (const gchar *esp_path, GError **error) +{ + g_autofree gchar *basename = g_path_get_basename (esp_path); + g_autoptr(GPtrArray) volumes = NULL; + + volumes = fu_common_get_volumes_by_kind (FU_VOLUME_KIND_ESP, error); + if (volumes == NULL) + return FALSE; + for (guint i = 0; i < volumes->len; i++) { + FuVolume *vol = g_ptr_array_index (volumes, i); + g_autofree gchar *vol_basename = g_path_get_basename (fu_volume_get_id (vol)); + if (g_strcmp0 (basename, vol_basename) == 0) + return g_object_ref (vol); + } + g_set_error (error, + G_IO_ERROR, + G_IO_ERROR_INVALID_FILENAME, + "No ESP with path %s", + esp_path); + return NULL; +} diff --git a/libfwupdplugin/fu-common.h b/libfwupdplugin/fu-common.h index 1ba975978..4482b7a5a 100644 --- a/libfwupdplugin/fu-common.h +++ b/libfwupdplugin/fu-common.h @@ -8,6 +8,8 @@ #include +#include "fu-volume.h" + /** * FuAppFlags: * @FU_APP_FLAGS_NONE: No flags set @@ -227,3 +229,8 @@ gchar **fu_common_strnsplit (const gchar *str, gint max_tokens); gboolean fu_common_kernel_locked_down (void); gboolean fu_common_is_cpu_intel (void); +GPtrArray *fu_common_get_volumes_by_kind (const gchar *kind, + GError **error); +FuVolume *fu_common_get_esp_for_path (const gchar *esp_path, + GError **error); +FuVolume *fu_common_get_esp_default (GError **error); diff --git a/libfwupdplugin/fu-volume-private.h b/libfwupdplugin/fu-volume-private.h new file mode 100644 index 000000000..88d6f6699 --- /dev/null +++ b/libfwupdplugin/fu-volume-private.h @@ -0,0 +1,15 @@ +/* + * Copyright (C) 2018-2020 Richard Hughes + * Copyright (C) 2019 Mario Limonciello + * + * SPDX-License-Identifier: LGPL-2.1+ + */ + +#pragma once + +#include + +#include "fu-volume.h" + +FuVolume *fu_volume_new_from_proxy (GDBusProxy *proxy); +FuVolume *fu_volume_new_from_mount_path (const gchar *mount_path); diff --git a/libfwupdplugin/fu-volume.c b/libfwupdplugin/fu-volume.c new file mode 100644 index 000000000..889173186 --- /dev/null +++ b/libfwupdplugin/fu-volume.c @@ -0,0 +1,282 @@ +/* + * Copyright (C) 2018-2020 Richard Hughes + * Copyright (C) 2019 Mario Limonciello + * + * SPDX-License-Identifier: LGPL-2.1+ + */ + +#define G_LOG_DOMAIN "FuVolume" + +#include "config.h" + +#include + +#include "fwupd-error.h" + +#include "fu-volume-private.h" + +/** + * SECTION:fu-volume + * @title: FuVolume + * @short_description: Volume abstraction that uses UDisks + */ + +struct _FuVolume { + GObject parent_instance; + GDBusProxy *proxy; + gchar *mount_path; /* only when mounted ourselves */ +}; + +G_DEFINE_TYPE (FuVolume, fu_volume, G_TYPE_OBJECT) + +static void +fu_volume_finalize (GObject *obj) +{ + FuVolume *self = FU_VOLUME (obj); + g_free (self->mount_path); + if (self->proxy != NULL) + g_object_unref (self->proxy); + G_OBJECT_CLASS (fu_volume_parent_class)->finalize (obj); +} + +static void +fu_volume_class_init (FuVolumeClass *klass) +{ + GObjectClass *object_class = G_OBJECT_CLASS (klass); + object_class->finalize = fu_volume_finalize; +} + +static void +fu_volume_init (FuVolume *self) +{ +} + +/** + * fu_volume_get_id: + * @self: a @FuVolume + * + * Gets the D-Bus path of the mount point. + * + * Returns: string ID, or %NULL + * + * Since: 1.4.6 + **/ +const gchar * +fu_volume_get_id (FuVolume *self) +{ + g_return_val_if_fail (FU_IS_VOLUME (self), NULL); + return g_dbus_proxy_get_object_path (self->proxy); +} + +/** + * fu_volume_get_mount_point: + * @self: a @FuVolume + * + * Gets the location of the volume mount point. + * + * Returns: UNIX path, or %NULL + * + * Since: 1.4.6 + **/ +gchar * +fu_volume_get_mount_point (FuVolume *self) +{ + const gchar **mountpoints = NULL; + g_autoptr(GVariant) val = NULL; + g_autoptr(GError) error_local = NULL; + + g_return_val_if_fail (FU_IS_VOLUME (self), NULL); + + /* we mounted it */ + if (self->mount_path != NULL) + return g_strdup (self->mount_path); + + /* something else mounted it */ + val = g_dbus_proxy_get_cached_property (self->proxy, "MountPoints"); + if (val == NULL) + return NULL; + mountpoints = g_variant_get_bytestring_array (val, NULL); + return g_strdup (mountpoints[0]); +} + +/** + * fu_volume_check_free_space: + * @self: a @FuVolume + * @required: size in bytes + * @error: A #GError, or %NULL + * + * Checks the volume for required space. + * + * Returns: %TRUE for success + * + * Since: 1.4.6 + **/ +gboolean +fu_volume_check_free_space (FuVolume *self, guint64 required, GError **error) +{ + guint64 fs_free; + g_autofree gchar *path = NULL; + g_autoptr(GFile) file = NULL; + g_autoptr(GFileInfo) info = NULL; + + g_return_val_if_fail (FU_IS_VOLUME (self), FALSE); + + /* skip the checks for unmounted disks */ + path = fu_volume_get_mount_point (self); + if (path == NULL) + return TRUE; + + file = g_file_new_for_path (path); + info = g_file_query_filesystem_info (file, + G_FILE_ATTRIBUTE_FILESYSTEM_FREE, + NULL, error); + if (info == NULL) + return FALSE; + fs_free = g_file_info_get_attribute_uint64 (info, G_FILE_ATTRIBUTE_FILESYSTEM_FREE); + if (fs_free < required) { + g_autofree gchar *str_free = g_format_size (fs_free); + g_autofree gchar *str_reqd = g_format_size (required); + g_set_error (error, + FWUPD_ERROR, + FWUPD_ERROR_NOT_SUPPORTED, + "%s does not have sufficient space, required %s, got %s", + path, str_reqd, str_free); + return FALSE; + } + return TRUE; +} + +/** + * fu_volume_is_mounted: + * @self: a @FuVolume + * + * Checks if the VOLUME is already mounted. + * + * Returns: %TRUE for success + * + * Since: 1.4.6 + **/ +gboolean +fu_volume_is_mounted (FuVolume *self) +{ + g_autofree gchar *mount_point = NULL; + g_return_val_if_fail (FU_IS_VOLUME (self), FALSE); + mount_point = fu_volume_get_mount_point (self); + return mount_point != NULL; +} + +/** + * fu_volume_mount: + * @self: a @FuVolume + * @error: A #GError, or %NULL + * + * Mounts the VOLUME ready for use. + * + * Returns: %TRUE for success + * + * Since: 1.4.6 + **/ +gboolean +fu_volume_mount (FuVolume *self, GError **error) +{ + GVariantBuilder builder; + g_autoptr(GVariant) val = NULL; + + g_return_val_if_fail (FU_IS_VOLUME (self), FALSE); + + /* device from the self tests */ + if (self->proxy == NULL) + return TRUE; + + g_debug ("mounting %s", fu_volume_get_id (self)); + g_variant_builder_init (&builder, G_VARIANT_TYPE_VARDICT); + val = g_dbus_proxy_call_sync (self->proxy, + "Mount", g_variant_new ("(a{sv})", &builder), + G_DBUS_CALL_FLAGS_NONE, + -1, NULL, error); + if (val == NULL) + return FALSE; + g_variant_get (val, "(s)", &self->mount_path); + return TRUE; +} + +/** + * fu_volume_unmount: + * @self: a @FuVolume + * @error: A #GError, or %NULL + * + * Unmounts the volume after use. + * + * Returns: %TRUE for success + * + * Since: 1.4.6 + **/ +gboolean +fu_volume_unmount (FuVolume *self, GError **error) +{ + GVariantBuilder builder; + g_autoptr(GVariant) val = NULL; + + g_return_val_if_fail (FU_IS_VOLUME (self), FALSE); + + /* device from the self tests */ + if (self->proxy == NULL) + return TRUE; + + g_debug ("unmounting %s", fu_volume_get_id (self)); + g_variant_builder_init (&builder, G_VARIANT_TYPE_VARDICT); + val = g_dbus_proxy_call_sync (self->proxy, + "Unmount", + g_variant_new ("(a{sv})", &builder), + G_DBUS_CALL_FLAGS_NONE, + -1, NULL, error); + if (val == NULL) + return FALSE; + g_free (self->mount_path); + self->mount_path = NULL; + return TRUE; +} + +/** + * fu_volume_locker: + * @self: a @FuVolume + * @error: A #GError, or %NULL + * + * Locks the volume, mounting it and unmounting it as required. If the volume is + * already mounted then it is is _not_ unmounted when the locker is closed. + * + * Returns: (transfer full): a #FuDeviceLocker for success, or %NULL + * + * Since: 1.4.6 + **/ +FuDeviceLocker * +fu_volume_locker (FuVolume *self, GError **error) +{ + /* already open, so NOP */ + if (fu_volume_is_mounted (self)) + return g_object_new (FU_TYPE_DEVICE_LOCKER, NULL); + return fu_device_locker_new_full (self, + (FuDeviceLockerFunc) fu_volume_mount, + (FuDeviceLockerFunc) fu_volume_unmount, + error); +} + +/* private */ +FuVolume * +fu_volume_new_from_proxy (GDBusProxy *proxy) +{ + g_autoptr(FuVolume) self = g_object_new (FU_TYPE_VOLUME, NULL); + g_return_val_if_fail (proxy != NULL, NULL); + g_set_object (&self->proxy, proxy); + return g_steal_pointer (&self); +} + +/* private */ +FuVolume * +fu_volume_new_from_mount_path (const gchar *mount_path) +{ + g_autoptr(FuVolume) self = g_object_new (FU_TYPE_VOLUME, NULL); + g_return_val_if_fail (mount_path != NULL, NULL); + self->mount_path = g_strdup (mount_path); + return g_steal_pointer (&self); +} diff --git a/libfwupdplugin/fu-volume.h b/libfwupdplugin/fu-volume.h new file mode 100644 index 000000000..5d1340799 --- /dev/null +++ b/libfwupdplugin/fu-volume.h @@ -0,0 +1,31 @@ +/* + * Copyright (C) 2018-2020 Richard Hughes + * Copyright (C) 2019 Mario Limonciello + * + * SPDX-License-Identifier: LGPL-2.1+ + */ + +#pragma once + +#include + +#include "fu-device-locker.h" + +#define FU_TYPE_VOLUME (fu_volume_get_type ()) + +G_DECLARE_FINAL_TYPE (FuVolume, fu_volume, FU, VOLUME, GObject) + +#define FU_VOLUME_KIND_ESP "c12a7328-f81f-11d2-ba4b-00a0c93ec93b" + +const gchar *fu_volume_get_id (FuVolume *self); +gboolean fu_volume_check_free_space (FuVolume *self, + guint64 required, + GError **error); +gboolean fu_volume_is_mounted (FuVolume *self); +gchar *fu_volume_get_mount_point (FuVolume *self); +gboolean fu_volume_mount (FuVolume *self, + GError **error); +gboolean fu_volume_unmount (FuVolume *self, + GError **error); +FuDeviceLocker *fu_volume_locker (FuVolume *self, + GError **error); diff --git a/libfwupdplugin/fwupdplugin.h b/libfwupdplugin/fwupdplugin.h index b35ce5968..41be7e17c 100644 --- a/libfwupdplugin/fwupdplugin.h +++ b/libfwupdplugin/fwupdplugin.h @@ -38,6 +38,7 @@ #include #include #include +#include #ifndef FWUPD_DISABLE_DEPRECATED #include diff --git a/libfwupdplugin/fwupdplugin.map b/libfwupdplugin/fwupdplugin.map index e40f98918..c22a94194 100644 --- a/libfwupdplugin/fwupdplugin.map +++ b/libfwupdplugin/fwupdplugin.map @@ -593,6 +593,22 @@ LIBFWUPDPLUGIN_1.4.5 { local: *; } LIBFWUPDPLUGIN_1.4.1; +LIBFWUPDPLUGIN_1.4.6 { + global: + fu_common_get_esp_default; + fu_common_get_esp_for_path; + fu_common_get_volumes_by_kind; + fu_volume_check_free_space; + fu_volume_get_id; + fu_volume_get_mount_point; + fu_volume_get_type; + fu_volume_is_mounted; + fu_volume_locker; + fu_volume_mount; + fu_volume_unmount; + local: *; +} LIBFWUPDPLUGIN_1.4.5; + LIBFWUPDPLUGIN_1.5.0 { global: fu_common_filename_glob; @@ -613,4 +629,4 @@ LIBFWUPDPLUGIN_1.5.0 { fu_security_attrs_remove_all; fu_security_attrs_to_variant; local: *; -} LIBFWUPDPLUGIN_1.4.5; +} LIBFWUPDPLUGIN_1.4.6; diff --git a/libfwupdplugin/meson.build b/libfwupdplugin/meson.build index 8793938e0..935735ed0 100644 --- a/libfwupdplugin/meson.build +++ b/libfwupdplugin/meson.build @@ -9,6 +9,7 @@ fwupdplugin_src = [ 'fu-device-locker.c', 'fu-device.c', 'fu-dfu-firmware.c', + 'fu-volume.c', 'fu-firmware.c', 'fu-firmware-common.c', 'fu-firmware-image.c', @@ -39,6 +40,7 @@ fwupdplugin_headers = [ 'fu-device-metadata.h', 'fu-device-locker.h', 'fu-dfu-firmware.h', + 'fu-volume.h', 'fu-firmware.h', 'fu-firmware-common.h', 'fu-firmware-image.h', From a83deb42b5c9b9feb1572ee904a18b71563b0815 Mon Sep 17 00:00:00 2001 From: Richard Hughes Date: Wed, 12 Aug 2020 12:45:36 +0100 Subject: [PATCH 315/607] Add commands to fwupdtool for interacting with the ESP --- data/bash-completion/fwupdtool.in | 3 + src/fu-tool.c | 100 ++++++++++++++++++++++++++++++ 2 files changed, 103 insertions(+) diff --git a/data/bash-completion/fwupdtool.in b/data/bash-completion/fwupdtool.in index c239877a4..7cac716b4 100644 --- a/data/bash-completion/fwupdtool.in +++ b/data/bash-completion/fwupdtool.in @@ -1,6 +1,9 @@ _fwupdtool_cmd_list=( 'activate' 'build-firmware' + 'esp-list' + 'esp-mount' + 'esp-unmount' 'firmware-convert' 'firmware-parse' 'get-updates' diff --git a/src/fu-tool.c b/src/fu-tool.c index 941266842..8cf93c2c5 100644 --- a/src/fu-tool.c +++ b/src/fu-tool.c @@ -2020,6 +2020,88 @@ fu_util_security (FuUtilPrivate *priv, gchar **values, GError **error) return TRUE; } +static FuVolume * +fu_util_prompt_for_volume (GError **error) +{ + FuVolume *volume; + guint idx; + g_autoptr(GPtrArray) volumes = NULL; + + /* exactly one */ + volumes = fu_common_get_volumes_by_kind (FU_VOLUME_KIND_ESP, error); + if (volumes->len == 1) { + volume = g_ptr_array_index (volumes, 0); + /* TRANSLATORS: Volume has been chosen by the the user */ + g_print ("%s: %s\n", _("Selected volume"), fu_volume_get_id (volume)); + return g_object_ref (volume); + } + + /* TRANSLATORS: get interactive prompt */ + g_print ("%s\n", _("Choose a volume:")); + /* TRANSLATORS: this is to abort the interactive prompt */ + g_print ("0.\t%s\n", _("Cancel")); + for (guint i = 0; i < volumes->len; i++) { + volume = g_ptr_array_index (volumes, i); + g_print ("%u.\t%s\n", i + 1, fu_volume_get_id (volume)); + } + idx = fu_util_prompt_for_number (volumes->len); + if (idx == 0) { + g_set_error_literal (error, + FWUPD_ERROR, + FWUPD_ERROR_NOTHING_TO_DO, + "Request canceled"); + return NULL; + } + volume = g_ptr_array_index (volumes, idx - 1); + return g_object_ref (volume); + +} + +static gboolean +fu_util_esp_mount (FuUtilPrivate *priv, gchar **values, GError **error) +{ + g_autoptr(FuVolume) volume = NULL; + volume = fu_util_prompt_for_volume (error); + if (volume == NULL) + return FALSE; + return fu_volume_mount (volume, error); +} + +static gboolean +fu_util_esp_unmount (FuUtilPrivate *priv, gchar **values, GError **error) +{ + g_autoptr(FuVolume) volume = NULL; + volume = fu_util_prompt_for_volume (error); + if (volume == NULL) + return FALSE; + return fu_volume_unmount (volume, error); +} + +static gboolean +fu_util_esp_list (FuUtilPrivate *priv, gchar **values, GError **error) +{ + g_autofree gchar *mount_point = NULL; + g_autoptr(FuDeviceLocker) locker = NULL; + g_autoptr(FuVolume) volume = NULL; + g_autoptr(GPtrArray) files = NULL; + + volume = fu_util_prompt_for_volume (error); + if (volume == NULL) + return FALSE; + locker = fu_volume_locker (volume, error); + if (locker == NULL) + return FALSE; + mount_point = fu_volume_get_mount_point (volume); + files = fu_common_get_files_recursive (mount_point, error); + if (files == NULL) + return FALSE; + for (guint i = 0; i < files->len; i++) { + const gchar *fn = g_ptr_array_index (files, i); + g_print ("%s\n", fn); + } + return TRUE; +} + int main (int argc, char *argv[]) { @@ -2266,6 +2348,24 @@ main (int argc, char *argv[]) /* TRANSLATORS: command description */ _("Gets the host security attributes."), fu_util_security); + fu_util_cmd_array_add (cmd_array, + "esp-mount", + NULL, + /* TRANSLATORS: command description */ + _("Mounts the ESP."), + fu_util_esp_mount); + fu_util_cmd_array_add (cmd_array, + "esp-unmount", + NULL, + /* TRANSLATORS: command description */ + _("Unmounts the ESP."), + fu_util_esp_unmount); + fu_util_cmd_array_add (cmd_array, + "esp-list", + NULL, + /* TRANSLATORS: command description */ + _("Lists files on the ESP."), + fu_util_esp_list); /* do stuff on ctrl+c */ priv->cancellable = g_cancellable_new (); From d3f60abe6d64b4f7af70ff1d00daba232c201d80 Mon Sep 17 00:00:00 2001 From: Richard Hughes Date: Wed, 12 Aug 2020 12:49:50 +0100 Subject: [PATCH 316/607] uefi: Port the plugin to use FuVolume --- plugins/uefi/fu-plugin-uefi.c | 58 +++++------ plugins/uefi/fu-uefi-common.c | 157 ---------------------------- plugins/uefi/fu-uefi-common.h | 6 -- plugins/uefi/fu-uefi-device.c | 113 ++++++-------------- plugins/uefi/fu-uefi-device.h | 2 + plugins/uefi/fu-uefi-tool.c | 13 ++- plugins/uefi/fu-uefi-udisks.c | 190 ---------------------------------- plugins/uefi/fu-uefi-udisks.h | 16 --- plugins/uefi/meson.build | 3 - 9 files changed, 73 insertions(+), 485 deletions(-) delete mode 100644 plugins/uefi/fu-uefi-udisks.c delete mode 100644 plugins/uefi/fu-uefi-udisks.h diff --git a/plugins/uefi/fu-plugin-uefi.c b/plugins/uefi/fu-plugin-uefi.c index 5b8c56c15..7ea48c741 100644 --- a/plugins/uefi/fu-plugin-uefi.c +++ b/plugins/uefi/fu-plugin-uefi.c @@ -29,6 +29,7 @@ G_DEFINE_AUTOPTR_CLEANUP_FUNC(GUnixMountEntry, g_unix_mount_free) struct FuPluginData { FuUefiBgrt *bgrt; + FuVolume *esp; }; void @@ -200,7 +201,6 @@ fu_plugin_uefi_write_splash_data (FuPlugin *plugin, GError **error) { FuPluginData *data = fu_plugin_get_data (plugin); - const gchar *esp_path = fu_device_get_metadata (device, "EspPath"); guint32 screen_x, screen_y; gsize buf_size = g_bytes_get_size (blob); gssize size; @@ -213,6 +213,7 @@ fu_plugin_uefi_write_splash_data (FuPlugin *plugin, .header_size = sizeof(efi_capsule_header_t), .capsule_image_size = 0 }; + g_autofree gchar *esp_path = NULL; g_autofree gchar *fn = NULL; g_autofree gchar *directory = NULL; g_autofree gchar *basename = NULL; @@ -229,6 +230,7 @@ fu_plugin_uefi_write_splash_data (FuPlugin *plugin, } /* save to a predicatable filename */ + esp_path = fu_volume_get_mount_point (data->esp); directory = fu_uefi_get_esp_path_for_os (esp_path); basename = g_strdup_printf ("fwupd-%s.cap", FU_EFIVAR_GUID_UX_CAPSULE); fn = g_build_filename (directory, "fw", basename, NULL); @@ -408,13 +410,12 @@ fu_plugin_update (FuPlugin *plugin, return fu_device_write_firmware (device, blob_fw, flags, error); } -static gboolean -fu_plugin_uefi_load_config (FuPlugin *plugin, FuDevice *device, GError **error) +static void +fu_plugin_uefi_load_config (FuPlugin *plugin, FuDevice *device) { gboolean disable_shim; guint64 sz_reqd = FU_UEFI_COMMON_REQUIRED_ESP_FREE_SPACE; g_autofree gchar *require_esp_free_space = NULL; - g_autofree gchar *esp_path = NULL; /* parse free space needed for ESP */ require_esp_free_space = fu_plugin_get_config_value (plugin, "RequireESPFreeSpace"); @@ -427,36 +428,17 @@ fu_plugin_uefi_load_config (FuPlugin *plugin, FuDevice *device, GError **error) fu_device_set_metadata_boolean (device, "RequireShimForSecureBoot", !disable_shim); - - /* load ESP from file */ - esp_path = fu_plugin_get_config_value (plugin, "OverrideESPMountPoint"); - if (esp_path != NULL) { - g_autoptr(GError) error_local = NULL; - if (!fu_uefi_check_esp_path (esp_path, &error_local)) { - g_set_error (error, - G_IO_ERROR, - G_IO_ERROR_INVALID_FILENAME, - "invalid OverrideESPMountPoint=%s specified in config: %s", - esp_path, error_local->message); - return FALSE; - } - fu_device_set_metadata (device, "EspPath", esp_path); - } - - /* success */ - return TRUE; } static void fu_plugin_uefi_register_proxy_device (FuPlugin *plugin, FuDevice *device) { + FuPluginData *data = fu_plugin_get_data (plugin); g_autoptr(FuUefiDevice) dev = fu_uefi_device_new_from_dev (device); - g_autoptr(GError) error_local = NULL; /* load all configuration variables */ - if (!fu_plugin_uefi_load_config (plugin, FU_DEVICE (dev), &error_local)) - g_warning ("%s", error_local->message); - + fu_plugin_uefi_load_config (plugin, FU_DEVICE (dev)); + fu_uefi_device_set_esp (dev, data->esp); fu_plugin_device_add (plugin, FU_DEVICE (dev)); } @@ -607,6 +589,8 @@ fu_plugin_uefi_smbios_enabled (FuPlugin *plugin, GError **error) gboolean fu_plugin_startup (FuPlugin *plugin, GError **error) { + FuPluginData *data = fu_plugin_get_data (plugin); + g_autofree gchar *esp_path = NULL; g_autoptr(GError) error_local = NULL; /* some platforms have broken SMBIOS data */ @@ -631,6 +615,23 @@ fu_plugin_startup (FuPlugin *plugin, GError **error) if (!fu_efivar_supported (error)) return FALSE; + /* override the default ESP path */ + esp_path = fu_plugin_get_config_value (plugin, "OverrideESPMountPoint"); + if (esp_path != NULL) { + data->esp = fu_common_get_esp_for_path (esp_path, error); + if (data->esp == NULL) { + g_prefix_error (error, "invalid OverrideESPMountPoint=%s " + "specified in config: ", esp_path); + return FALSE; + } + } else { + data->esp = fu_common_get_esp_default (error); + if (data->esp == NULL) { + g_prefix_error (error, "cannot find default ESP: "); + return FALSE; + } + } + /* test for invalid ESP in coldplug, and set the update-error rather * than showing no output if the plugin had self-disabled here */ return TRUE; @@ -760,6 +761,7 @@ fu_plugin_coldplug (FuPlugin *plugin, GError **error) continue; } fu_device_set_quirks (FU_DEVICE (dev), fu_plugin_get_quirks (plugin)); + fu_uefi_device_set_esp (FU_UEFI_DEVICE (dev), data->esp); if (!fu_plugin_uefi_coldplug_device (plugin, dev, error)) return FALSE; if (error_efivarfs != NULL) { @@ -769,9 +771,7 @@ fu_plugin_coldplug (FuPlugin *plugin, GError **error) fu_device_add_flag (FU_DEVICE (dev), FWUPD_DEVICE_FLAG_USABLE_DURING_UPDATE); } /* load all configuration variables */ - if (!fu_plugin_uefi_load_config (plugin, FU_DEVICE (dev), error)) - return FALSE; - + fu_plugin_uefi_load_config (plugin, FU_DEVICE (dev)); fu_plugin_device_add (plugin, FU_DEVICE (dev)); } diff --git a/plugins/uefi/fu-uefi-common.c b/plugins/uefi/fu-uefi-common.c index 70e0c93c6..6cd556726 100644 --- a/plugins/uefi/fu-uefi-common.c +++ b/plugins/uefi/fu-uefi-common.c @@ -8,23 +8,14 @@ #include "config.h" #include -#include #include "fu-common.h" #include "fu-uefi-common.h" #include "fu-efivar.h" -#include "fu-uefi-udisks.h" #include "fwupd-common.h" #include "fwupd-error.h" -#ifndef HAVE_GIO_2_55_0 -#pragma clang diagnostic push -#pragma clang diagnostic ignored "-Wunused-function" -G_DEFINE_AUTOPTR_CLEANUP_FUNC(GUnixMountEntry, g_unix_mount_free) -#pragma clang diagnostic pop -#endif - static const gchar * fu_uefi_bootmgr_get_suffix (GError **error) { @@ -273,154 +264,6 @@ fu_uefi_read_file_as_uint64 (const gchar *path, const gchar *attr_name) return fu_common_strtoull (data); } -gboolean -fu_uefi_check_esp_free_space (const gchar *path, guint64 required, GError **error) -{ - guint64 fs_free; - g_autoptr(GFile) file = NULL; - g_autoptr(GFileInfo) info = NULL; - - /* skip the checks for unmounted disks */ - if (fu_uefi_udisks_objpath (path)) - return TRUE; - - file = g_file_new_for_path (path); - info = g_file_query_filesystem_info (file, - G_FILE_ATTRIBUTE_FILESYSTEM_FREE, - NULL, error); - if (info == NULL) - return FALSE; - fs_free = g_file_info_get_attribute_uint64 (info, G_FILE_ATTRIBUTE_FILESYSTEM_FREE); - if (fs_free < required) { - g_autofree gchar *str_free = g_format_size (fs_free); - g_autofree gchar *str_reqd = g_format_size (required); - g_set_error (error, - FWUPD_ERROR, - FWUPD_ERROR_NOT_SUPPORTED, - "%s does not have sufficient space, required %s, got %s", - path, str_reqd, str_free); - return FALSE; - } - return TRUE; -} - -gboolean -fu_uefi_check_esp_path (const gchar *path, GError **error) -{ - const gchar *fs_types[] = { "vfat", "ntfs", "exfat", "autofs", NULL }; - g_autoptr(GUnixMountEntry) mount = g_unix_mount_at (path, NULL); - if (mount == NULL) { - g_set_error (error, - FWUPD_ERROR, - FWUPD_ERROR_NOT_FOUND, - "%s was not mounted", path); - return FALSE; - } - - /* /boot is a special case because systemd sandboxing marks - * it read-only, but we need to write to /boot/EFI - */ - if (g_strcmp0 (path, "/boot") == 0) { - if (!g_file_test ("/boot/EFI", G_FILE_TEST_IS_DIR)) { - g_set_error (error, - FWUPD_ERROR, - FWUPD_ERROR_NOT_SUPPORTED, - "%s/EFI does not exist", path); - return FALSE; - } - /* /efi is a special case because systemd sandboxing marks - * it read-only, but we need to write to /efi/EFI - */ - } else if (g_strcmp0 (path, "/efi") == 0) { - if (!g_file_test ("/efi/EFI", G_FILE_TEST_IS_DIR)) { - g_set_error (error, - FWUPD_ERROR, - FWUPD_ERROR_NOT_SUPPORTED, - "%s/EFI does not exist", path); - return FALSE; - } - } else if (g_unix_mount_is_readonly (mount)) { - g_set_error (error, - FWUPD_ERROR, - FWUPD_ERROR_NOT_SUPPORTED, - "%s is read only", path); - return FALSE; - } - if (!g_strv_contains (fs_types, g_unix_mount_get_fs_type (mount))) { - g_autofree gchar *supported = g_strjoinv ("|", (gchar **) fs_types); - g_set_error (error, - FWUPD_ERROR, - FWUPD_ERROR_NOT_SUPPORTED, - "%s has an invalid type, expected %s", - path, supported); - return FALSE; - } - return TRUE; -} - -static gchar * -fu_uefi_probe_udisks_esp (GError **error) -{ - g_autoptr(GPtrArray) devices = NULL; - g_autofree gchar *found_esp = NULL; - - devices = fu_uefi_udisks_get_block_devices (error); - if (devices == NULL) - return NULL; - for (guint i = 0; i < devices->len; i++) { - const gchar *obj = g_ptr_array_index (devices, i); - gboolean esp = fu_uefi_udisks_objpath_is_esp (obj); - g_debug ("block device %s, is_esp: %d", obj, esp); - if (!esp) - continue; - if (found_esp != NULL) { - g_set_error_literal (error, - G_IO_ERROR, - G_IO_ERROR_INVALID_FILENAME, - "Multiple EFI system partitions found, " - "See https://github.com/fwupd/fwupd/wiki/Determining-EFI-system-partition-location"); - return NULL; - } - found_esp = g_strdup (obj); - } - if (found_esp == NULL) { - g_set_error_literal (error, - G_IO_ERROR, - G_IO_ERROR_INVALID_FILENAME, - "Unable to determine EFI system partition location, " - "See https://github.com/fwupd/fwupd/wiki/Determining-EFI-system-partition-location"); - return NULL; - } - - g_debug ("Udisks detected objpath %s", found_esp); - return g_steal_pointer (&found_esp); -} - -gchar * -fu_uefi_guess_esp_path (GError **error) -{ - const gchar *paths[] = {"/boot/efi", "/boot", "/efi", NULL}; - const gchar *path_tmp; - - /* for the test suite use local directory for ESP */ - path_tmp = g_getenv ("FWUPD_UEFI_ESP_PATH"); - if (path_tmp != NULL) - return g_strdup (path_tmp); - - /* try to use known paths */ - for (guint i = 0; paths[i] != NULL; i++) { - g_autoptr(GError) error_local = NULL; - if (!fu_uefi_check_esp_path (paths[i], &error_local)) { - g_debug ("ignoring ESP path: %s", error_local->message); - continue; - } - return g_strdup (paths[i]); - } - - /* probe using udisks2 */ - return fu_uefi_probe_udisks_esp (error); -} - void fu_uefi_print_efivar_errors (void) { diff --git a/plugins/uefi/fu-uefi-common.h b/plugins/uefi/fu-uefi-common.h index b329812c8..cf7381169 100644 --- a/plugins/uefi/fu-uefi-common.h +++ b/plugins/uefi/fu-uefi-common.h @@ -69,12 +69,6 @@ gboolean fu_uefi_get_bitmap_size (const guint8 *buf, gboolean fu_uefi_get_framebuffer_size (guint32 *width, guint32 *height, GError **error); -gchar *fu_uefi_guess_esp_path (GError **error); -gboolean fu_uefi_check_esp_path (const gchar *path, - GError **error); -gboolean fu_uefi_check_esp_free_space (const gchar *path, - guint64 required, - GError **error); gchar *fu_uefi_get_esp_path_for_os (const gchar *esp_path); GPtrArray *fu_uefi_get_esrt_entry_paths (const gchar *esrt_path, GError **error); diff --git a/plugins/uefi/fu-uefi-device.c b/plugins/uefi/fu-uefi-device.c index d4a48265b..ed1d17206 100644 --- a/plugins/uefi/fu-uefi-device.c +++ b/plugins/uefi/fu-uefi-device.c @@ -21,10 +21,11 @@ #include "fu-uefi-bootmgr.h" #include "fu-uefi-pcrs.h" #include "fu-efivar.h" -#include "fu-uefi-udisks.h" struct _FuUefiDevice { FuDevice parent_instance; + FuVolume *esp; + FuDeviceLocker *esp_locker; gchar *fw_class; FuUefiDeviceKind kind; guint32 capsule_flags; @@ -40,6 +41,14 @@ struct _FuUefiDevice { G_DEFINE_TYPE (FuUefiDevice, fu_uefi_device, FU_TYPE_DEVICE) +void +fu_uefi_device_set_esp (FuUefiDevice *self, FuVolume *esp) +{ + g_return_if_fail (FU_IS_UEFI_DEVICE (self)); + g_return_if_fail (FU_IS_VOLUME (esp)); + g_set_object (&self->esp, esp); +} + const gchar * fu_uefi_device_kind_to_string (FuUefiDeviceKind kind) { @@ -108,8 +117,10 @@ fu_uefi_device_to_string (FuDevice *device, guint idt, GString *str) fu_common_string_append_kv (str, idt, "LastAttemptStatus", fu_uefi_device_status_to_string (self->last_attempt_status)); fu_common_string_append_kx (str, idt, "LastAttemptVersion", self->last_attempt_version); - fu_common_string_append_kv (str, idt, "EspPath", - fu_device_get_metadata (device, "EspPath")); + if (self->esp != NULL) { + fu_common_string_append_kv (str, idt, "EspId", + fu_volume_get_id (self->esp)); + } fu_common_string_append_ku (str, idt, "RequireESPFreeSpace", fu_device_get_metadata_integer (device, "RequireESPFreeSpace")); fu_common_string_append_kb (str, idt, "RequireShimForSecureBoot", @@ -129,7 +140,7 @@ fu_uefi_device_report_metadata_pre (FuDevice *device, GHashTable *metadata) /* where the ESP was mounted during installation */ g_hash_table_insert (metadata, g_strdup ("EspPath"), - g_strdup (fu_device_get_metadata (device, "EspPath"))); + fu_volume_get_mount_point (self->esp)); } static void @@ -424,48 +435,16 @@ fu_uefi_device_write_update_info (FuUefiDevice *self, return TRUE; } -static gboolean -fu_uefi_device_is_esp_mounted (FuDevice *device, GError **error) -{ - const gchar *esp_path = fu_device_get_metadata (device, "EspPath"); - g_autofree gchar *contents = NULL; - g_auto(GStrv) lines = NULL; - gsize length; - - if (esp_path == NULL) { - g_set_error_literal (error, - FWUPD_ERROR, - FWUPD_ERROR_NOT_SUPPORTED, - "EFI System partition is not defined"); - return FALSE; - } - - if (!g_file_get_contents ("/proc/mounts", &contents, &length, error)) - return FALSE; - lines = g_strsplit (contents, "\n", 0); - - for (guint i = 0; lines[i] != NULL; i++) { - if (lines[i] != NULL && g_strrstr (lines[i], esp_path)) - return TRUE; - } - g_set_error (error, - FWUPD_ERROR, - FWUPD_ERROR_NOT_SUPPORTED, - "EFI System partition %s is not mounted", - esp_path); - return FALSE; -} - static gboolean fu_uefi_device_check_esp_free (FuDevice *device, GError **error) { - const gchar *esp_path = fu_device_get_metadata (device, "EspPath"); + FuUefiDevice *self = FU_UEFI_DEVICE (device); guint64 sz_reqd = fu_device_get_metadata_integer (device, "RequireESPFreeSpace"); if (sz_reqd == G_MAXUINT) { g_debug ("maximum size is not configured"); return TRUE; } - return fu_uefi_check_esp_free_space (esp_path, sz_reqd, error); + return fu_volume_check_free_space (self->esp, sz_reqd, error); } static gboolean @@ -484,7 +463,8 @@ fu_uefi_check_asset (FuDevice *device, GError **error) static gboolean fu_uefi_device_cleanup_esp (FuDevice *device, GError **error) { - const gchar *esp_path = fu_device_get_metadata (device, "EspPath"); + FuUefiDevice *self = FU_UEFI_DEVICE (device); + g_autofree gchar *esp_path = fu_volume_get_mount_point (self->esp); g_autofree gchar *pattern = NULL; g_autoptr(GPtrArray) files = NULL; @@ -519,38 +499,14 @@ fu_uefi_device_prepare (FuDevice *device, FwupdInstallFlags flags, GError **error) { - /* not set in conf, figure it out */ - if (fu_device_get_metadata (device, "EspPath") == NULL) { - g_autofree gchar *guessed = NULL; - g_autofree gchar *detected_esp = NULL; - guessed = fu_uefi_guess_esp_path (error); - if (guessed == NULL) - return FALSE; + FuUefiDevice *self = FU_UEFI_DEVICE (device); - /* udisks objpath */ - if (fu_uefi_udisks_objpath (guessed)) { - FuUefiDevice *self = FU_UEFI_DEVICE (device); - detected_esp = fu_uefi_udisks_objpath_is_mounted (guessed); - if (detected_esp != NULL) { - g_debug ("ESP already mounted @ %s", detected_esp); - /* not mounted */ - } else { - g_debug ("Mounting ESP @ %s", guessed); - detected_esp = fu_uefi_udisks_objpath_mount (guessed, error); - if (detected_esp == NULL) - return FALSE; - self->automounted_esp = TRUE; - } - /* already mounted */ - } else { - detected_esp = g_steal_pointer (&guessed); - } - fu_device_set_metadata (device, "EspPath", detected_esp); - } + /* mount if required */ + self->esp_locker = fu_volume_locker (self->esp, error); + if (self->esp_locker == NULL) + return FALSE; /* sanity checks */ - if (!fu_uefi_device_is_esp_mounted (device, error)) - return FALSE; if (!fu_uefi_device_cleanup_esp (device, error)) return FALSE; if (!fu_uefi_device_check_esp_free (device, error)) @@ -567,18 +523,11 @@ fu_uefi_device_cleanup (FuDevice *device, GError **error) { FuUefiDevice *self = FU_UEFI_DEVICE (device); - if (self->automounted_esp) { - g_autofree gchar *guessed = NULL; - guessed = fu_uefi_guess_esp_path (error); - if (guessed == NULL) - return FALSE; - g_debug ("Unmounting ESP @ %s", guessed); - if (!fu_uefi_udisks_objpath_umount (guessed, error)) - return FALSE; - self->automounted_esp = FALSE; - /* we will detect again if necessary */ - fu_device_remove_metadata (device, "EspPath"); - } + + /* unmount ESP if we opened it */ + if (!fu_device_locker_close (self->esp_locker, error)) + return FALSE; + g_clear_object (&self->esp_locker); return TRUE; } @@ -592,8 +541,8 @@ fu_uefi_device_write_firmware (FuDevice *device, FuUefiDevice *self = FU_UEFI_DEVICE (device); FuUefiBootmgrFlags flags = FU_UEFI_BOOTMGR_FLAG_NONE; const gchar *bootmgr_desc = "Linux Firmware Updater"; - const gchar *esp_path = fu_device_get_metadata (device, "EspPath"); efi_guid_t guid; + g_autofree gchar *esp_path = fu_volume_get_mount_point (self->esp); g_autoptr(GBytes) fixed_fw = NULL; g_autoptr(GBytes) fw = NULL; g_autofree gchar *basename = NULL; @@ -781,6 +730,8 @@ fu_uefi_device_finalize (GObject *object) FuUefiDevice *self = FU_UEFI_DEVICE (object); g_free (self->fw_class); + if (self->esp_locker != NULL) + g_object_unref (self->esp_locker); G_OBJECT_CLASS (fu_uefi_device_parent_class)->finalize (object); } diff --git a/plugins/uefi/fu-uefi-device.h b/plugins/uefi/fu-uefi-device.h index d9e7ffd98..ce60b338e 100644 --- a/plugins/uefi/fu-uefi-device.h +++ b/plugins/uefi/fu-uefi-device.h @@ -40,6 +40,8 @@ FuUefiDevice *fu_uefi_device_new_from_guid (const gchar *guid); FuUefiDevice *fu_uefi_device_new_from_entry (const gchar *entry_path, GError **error); FuUefiDevice *fu_uefi_device_new_from_dev (FuDevice *dev); +void fu_uefi_device_set_esp (FuUefiDevice *self, + FuVolume *esp); gboolean fu_uefi_device_clear_status (FuUefiDevice *self, GError **error); FuUefiDeviceKind fu_uefi_device_get_kind (FuUefiDevice *self); diff --git a/plugins/uefi/fu-uefi-tool.c b/plugins/uefi/fu-uefi-tool.c index bb5345c24..82463c57a 100644 --- a/plugins/uefi/fu-uefi-tool.c +++ b/plugins/uefi/fu-uefi-tool.c @@ -66,6 +66,7 @@ main (int argc, char *argv[]) g_autoptr(FuUtilPrivate) priv = g_new0 (FuUtilPrivate, 1); g_autoptr(GError) error = NULL; g_autoptr(GPtrArray) devices = NULL; + g_autoptr(FuVolume) esp = NULL; const GOptionEntry options[] = { { "verbose", 'v', 0, G_OPTION_ARG_NONE, &verbose, /* TRANSLATORS: command line option */ @@ -159,12 +160,19 @@ main (int argc, char *argv[]) /* override the default ESP path */ if (esp_path != NULL) { - if (!fu_uefi_check_esp_path (esp_path, &error)) { + esp = fu_common_get_esp_for_path (esp_path, &error); + if (esp == NULL) { /* TRANSLATORS: ESP is EFI System Partition */ g_print ("%s: %s\n", _("ESP specified was not valid"), error->message); return EXIT_FAILURE; } + } else { + esp = fu_common_get_esp_default (&error); + if (esp == NULL) { + g_printerr ("failed: %s\n", error->message); + return EXIT_FAILURE; + } } /* show the debug action_log from the last attempted update */ @@ -213,8 +221,7 @@ main (int argc, char *argv[]) path, error_parse->message); continue; } - if (esp_path != NULL) - fu_device_set_metadata (FU_DEVICE (dev), "EspPath", esp_path); + fu_uefi_device_set_esp (dev, esp); g_ptr_array_add (devices, g_object_ref (dev)); } } diff --git a/plugins/uefi/fu-uefi-udisks.c b/plugins/uefi/fu-uefi-udisks.c deleted file mode 100644 index 7eb02e383..000000000 --- a/plugins/uefi/fu-uefi-udisks.c +++ /dev/null @@ -1,190 +0,0 @@ -/* - * Copyright (C) 2019 Mario Limonciello - * - * SPDX-License-Identifier: LGPL-2.1+ - */ - -#include "config.h" - -#include - -#include "fu-uefi-udisks.h" -#include "fwupd-common.h" -#include "fwupd-error.h" - -#define UDISKS_DBUS_SERVICE "org.freedesktop.UDisks2" -#define UDISKS_DBUS_PATH "/org/freedesktop/UDisks2/Manager" -#define UDISKS_DBUS_MANAGER_INTERFACE "org.freedesktop.UDisks2.Manager" -#define UDISKS_DBUS_PART_INTERFACE "org.freedesktop.UDisks2.Partition" -#define UDISKS_DBUS_FILE_INTERFACE "org.freedesktop.UDisks2.Filesystem" -#define ESP_DISK_TYPE "c12a7328-f81f-11d2-ba4b-00a0c93ec93b" - -gboolean -fu_uefi_udisks_objpath (const gchar *path) -{ - return g_str_has_prefix (path, "/org/freedesktop/UDisks2/"); -} - -static GDBusProxy * -fu_uefi_udisks_get_dbus_proxy (const gchar *path, const gchar *interface, - GError **error) -{ - g_autoptr(GDBusConnection) connection = NULL; - g_autoptr(GDBusProxy) proxy = NULL; - - connection = g_bus_get_sync (G_BUS_TYPE_SYSTEM, NULL, error); - if (connection == NULL) { - g_prefix_error (error, "failed to get bus: "); - return NULL; - } - proxy = g_dbus_proxy_new_sync (connection, - G_DBUS_PROXY_FLAGS_NONE, NULL, - UDISKS_DBUS_SERVICE, - path, - interface, - NULL, error); - if (proxy == NULL) { - g_prefix_error (error, "failed to find %s: ", UDISKS_DBUS_SERVICE); - return NULL; - } - return g_steal_pointer (&proxy); -} - - -GPtrArray * -fu_uefi_udisks_get_block_devices (GError **error) -{ - g_autoptr(GVariant) output = NULL; - g_autoptr(GDBusProxy) proxy = NULL; - g_autoptr(GPtrArray) devices = NULL; - g_autoptr(GVariantIter) iter = NULL; - GVariant *input; - GVariantBuilder builder; - const gchar *obj; - - proxy = fu_uefi_udisks_get_dbus_proxy (UDISKS_DBUS_PATH, - UDISKS_DBUS_MANAGER_INTERFACE, - error); - if (proxy == NULL) - return NULL; - g_variant_builder_init (&builder, G_VARIANT_TYPE_VARDICT); - input = g_variant_new ("(a{sv})", &builder); - output = g_dbus_proxy_call_sync (proxy, - "GetBlockDevices", g_variant_ref (input), - G_DBUS_CALL_FLAGS_NONE, - -1, NULL, error); - if (output == NULL) - return NULL; - devices = g_ptr_array_new_with_free_func (g_free); - g_variant_get (output, "(ao)", &iter); - while (g_variant_iter_next (iter, "o", &obj)) - g_ptr_array_add (devices, g_strdup (obj)); - - return g_steal_pointer (&devices); -} - -gboolean -fu_uefi_udisks_objpath_is_esp (const gchar *obj) -{ - g_autoptr(GDBusProxy) proxy = NULL; - g_autoptr(GError) error_local = NULL; - g_autoptr(GVariant) val = NULL; - const gchar *str; - - proxy = fu_uefi_udisks_get_dbus_proxy (obj, - UDISKS_DBUS_PART_INTERFACE, - &error_local); - if (proxy == NULL) { - g_warning ("Failed to initialize d-bus proxy: %s", - error_local->message); - return FALSE; - } - val = g_dbus_proxy_get_cached_property (proxy, "Type"); - if (val == NULL) - return FALSE; - - g_variant_get (val, "s", &str); - return g_strcmp0 (str, ESP_DISK_TYPE) == 0; -} - -gboolean -fu_uefi_udisks_objpath_umount (const gchar *path, GError **error) -{ - GVariant *input; - GVariantBuilder builder; - g_autoptr(GDBusProxy) proxy = NULL; - g_autoptr(GVariant) val = NULL; - - g_return_val_if_fail (fu_uefi_udisks_objpath (path), FALSE); - - proxy = fu_uefi_udisks_get_dbus_proxy (path, - UDISKS_DBUS_FILE_INTERFACE, - error); - if (proxy == NULL) - return FALSE; - - g_variant_builder_init (&builder, G_VARIANT_TYPE_VARDICT); - input = g_variant_new ("(a{sv})", &builder); - val = g_dbus_proxy_call_sync (proxy, - "Unmount", input, - G_DBUS_CALL_FLAGS_NONE, - -1, NULL, error); - if (val == NULL) - return FALSE; - return TRUE; -} - -gchar * -fu_uefi_udisks_objpath_mount (const gchar *path, GError **error) -{ - GVariant *input; - GVariantBuilder builder; - const gchar *str; - g_autoptr(GDBusProxy) proxy = NULL; - g_autoptr(GVariant) val = NULL; - - g_return_val_if_fail (fu_uefi_udisks_objpath (path), NULL); - - proxy = fu_uefi_udisks_get_dbus_proxy (path, - UDISKS_DBUS_FILE_INTERFACE, - error); - if (proxy == NULL) - return NULL; - - g_variant_builder_init (&builder, G_VARIANT_TYPE_VARDICT); - input = g_variant_new ("(a{sv})", &builder); - val = g_dbus_proxy_call_sync (proxy, - "Mount", input, - G_DBUS_CALL_FLAGS_NONE, - -1, NULL, error); - if (val == NULL) - return NULL; - g_variant_get (val, "(s)", &str); - - return g_strdup (str); -} - -gchar * -fu_uefi_udisks_objpath_is_mounted (const gchar *path) -{ - const gchar **mountpoints = NULL; - g_autoptr(GDBusProxy) proxy = NULL; - g_autoptr(GVariant) val = NULL; - g_autoptr(GError) error_local = NULL; - - g_return_val_if_fail (fu_uefi_udisks_objpath (path), NULL); - - proxy = fu_uefi_udisks_get_dbus_proxy (path, - UDISKS_DBUS_FILE_INTERFACE, - &error_local); - if (proxy == NULL) { - g_warning ("%s", error_local->message); - return NULL; - } - val = g_dbus_proxy_get_cached_property (proxy, "MountPoints"); - if (val == NULL) - return NULL; - mountpoints = g_variant_get_bytestring_array (val, NULL); - - return g_strdup (mountpoints[0]); -} diff --git a/plugins/uefi/fu-uefi-udisks.h b/plugins/uefi/fu-uefi-udisks.h deleted file mode 100644 index 58018ecc4..000000000 --- a/plugins/uefi/fu-uefi-udisks.h +++ /dev/null @@ -1,16 +0,0 @@ -/* - * Copyright (C) 2019 Mario Limonciello - * - * SPDX-License-Identifier: LGPL-2.1+ - */ - -#pragma once - -GPtrArray *fu_uefi_udisks_get_block_devices (GError **error); -gboolean fu_uefi_udisks_objpath (const gchar *path); -gboolean fu_uefi_udisks_objpath_is_esp (const gchar *obj); -gchar *fu_uefi_udisks_objpath_mount (const gchar *path, - GError **error); -gboolean fu_uefi_udisks_objpath_umount (const gchar *path, - GError **error); -gchar *fu_uefi_udisks_objpath_is_mounted (const gchar *path); diff --git a/plugins/uefi/meson.build b/plugins/uefi/meson.build index 5838cecc2..3f13f4c75 100644 --- a/plugins/uefi/meson.build +++ b/plugins/uefi/meson.build @@ -22,7 +22,6 @@ shared_module('fu_plugin_uefi', 'fu-uefi-devpath.c', 'fu-uefi-pcrs.c', 'fu-uefi-update-info.c', - 'fu-uefi-udisks.c', ], include_directories : [ root_incdir, @@ -58,7 +57,6 @@ fwupdate = executable( 'fu-uefi-devpath.c', 'fu-uefi-pcrs.c', 'fu-uefi-update-info.c', - 'fu-uefi-udisks.c', ], include_directories : [ root_incdir, @@ -119,7 +117,6 @@ if get_option('tests') 'fu-uefi-devpath.c', 'fu-uefi-pcrs.c', 'fu-uefi-update-info.c', - 'fu-uefi-udisks.c', 'fu-ucs2.c', ], include_directories : [ From 722f53278157eac00599266fbe435d2a67cab316 Mon Sep 17 00:00:00 2001 From: Daniel Campello Date: Wed, 12 Aug 2020 11:27:38 -0600 Subject: [PATCH 317/607] fwupd-remote: Download remote firmware on local remote This changes allows for downloading firmware from a remote server pointed from a local remote manifest.xml.gz file Change-Id: Id00870f9c2817d48d6d301d2b6d229ba1ca6045a --- libfwupd/fwupd-client.c | 6 ++++-- src/fu-tool.c | 6 ++++-- 2 files changed, 8 insertions(+), 4 deletions(-) diff --git a/libfwupd/fwupd-client.c b/libfwupd/fwupd-client.c index bf96ec381..5e5796745 100644 --- a/libfwupd/fwupd-client.c +++ b/libfwupd/fwupd-client.c @@ -1469,9 +1469,11 @@ fwupd_client_install_release (FwupdClient *client, g_autofree gchar *checksum_actual = NULL; g_autofree gchar *uri_str = NULL; g_autoptr(GBytes) blob = NULL; + g_autoptr(SoupURI) uri = NULL; /* work out what remote-specific URI fields this should use */ uri_tmp = fwupd_release_get_uri (release); + uri = soup_uri_new (uri_tmp); remote_id = fwupd_release_get_remote_id (release); if (remote_id != NULL) { g_autoptr(FwupdRemote) remote = NULL; @@ -1482,8 +1484,8 @@ fwupd_client_install_release (FwupdClient *client, if (remote == NULL) return FALSE; - /* local and directory remotes have the firmware already */ - if (fwupd_remote_get_kind (remote) == FWUPD_REMOTE_KIND_LOCAL) { + /* local and directory remotes may have the firmware already */ + if (fwupd_remote_get_kind (remote) == FWUPD_REMOTE_KIND_LOCAL && uri == NULL) { const gchar *fn_cache = fwupd_remote_get_filename_cache (remote); g_autofree gchar *path = g_path_get_dirname (fn_cache); diff --git a/src/fu-tool.c b/src/fu-tool.c index 8cf93c2c5..04b6476cc 100644 --- a/src/fu-tool.c +++ b/src/fu-tool.c @@ -1006,6 +1006,7 @@ fu_util_install_release (FuUtilPrivate *priv, FwupdRelease *rel, GError **error) const gchar *remote_id; const gchar *uri_tmp; g_auto(GStrv) argv = NULL; + g_autoptr(SoupURI) uri = NULL; uri_tmp = fwupd_release_get_uri (rel); if (uri_tmp == NULL) { @@ -1032,8 +1033,9 @@ fu_util_install_release (FuUtilPrivate *priv, FwupdRelease *rel, GError **error) return FALSE; argv = g_new0 (gchar *, 2); - /* local remotes have the firmware already */ - if (fwupd_remote_get_kind (remote) == FWUPD_REMOTE_KIND_LOCAL) { + /* local remotes may have the firmware already */ + uri = soup_uri_new (uri_tmp); + if (fwupd_remote_get_kind (remote) == FWUPD_REMOTE_KIND_LOCAL && uri == NULL) { const gchar *fn_cache = fwupd_remote_get_filename_cache (remote); g_autofree gchar *path = g_path_get_dirname (fn_cache); argv[0] = g_build_filename (path, uri_tmp, NULL); From 12f21b89ecdb009819978bf2a576c8fdf5fe44c1 Mon Sep 17 00:00:00 2001 From: Richard Hughes Date: Thu, 13 Aug 2020 11:13:40 +0100 Subject: [PATCH 318/607] trivial: Fix CI -Werror=null-dereference false positive --- plugins/thunderbolt/fu-self-test.c | 1 + 1 file changed, 1 insertion(+) diff --git a/plugins/thunderbolt/fu-self-test.c b/plugins/thunderbolt/fu-self-test.c index 90c147efd..c3414c436 100644 --- a/plugins/thunderbolt/fu-self-test.c +++ b/plugins/thunderbolt/fu-self-test.c @@ -888,6 +888,7 @@ fu_thunderbolt_gudev_uevent_cb (GUdevClient *gudev_client, if (g_strcmp0 (action, "change") == 0) { const gchar *uuid = g_udev_device_get_sysfs_attr (udev_device, "unique_id"); MockTree *target = (MockTree *) mock_tree_find_uuid (tt->tree, uuid); + g_assert_nonnull (target); fu_plugin_runner_udev_device_changed (tt->plugin, FU_UDEV_DEVICE (target->fu_device), &error_local); return; From 891de60df5b011fb282607723240a596a1db441f Mon Sep 17 00:00:00 2001 From: Richard Hughes Date: Thu, 13 Aug 2020 12:36:28 +0100 Subject: [PATCH 319/607] trivial: Disable -Wnull-dereference It just doesn't work correctly. --- meson.build | 1 - 1 file changed, 1 deletion(-) diff --git a/meson.build b/meson.build index 00952236d..d780f24ab 100644 --- a/meson.build +++ b/meson.build @@ -92,7 +92,6 @@ warning_flags = [ '-Wno-strict-aliasing', '-Wno-suggest-attribute=format', '-Wno-unused-parameter', - '-Wnull-dereference', '-Wold-style-definition', '-Woverride-init', '-Wpointer-arith', From b53661676c976d249188386442f46a7fefeb6d8b Mon Sep 17 00:00:00 2001 From: Richard Hughes Date: Thu, 13 Aug 2020 12:55:51 +0100 Subject: [PATCH 320/607] trivial: Use O_APPEND for FU_EFIVAR_ATTR_APPEND_WRITE --- libfwupdplugin/fu-efivar.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/libfwupdplugin/fu-efivar.c b/libfwupdplugin/fu-efivar.c index 7579b383a..0bde17fd6 100644 --- a/libfwupdplugin/fu-efivar.c +++ b/libfwupdplugin/fu-efivar.c @@ -349,6 +349,7 @@ fu_efivar_set_data (const gchar *guid, const gchar *name, const guint8 *data, { #ifndef _WIN32 int fd; + int open_wflags; gboolean was_immutable; g_autofree gchar *fn = fu_efivar_get_filename (guid, name); g_autofree guint8 *buf = g_malloc0 (sizeof(guint32) + sz); @@ -374,8 +375,11 @@ fu_efivar_set_data (const gchar *guid, const gchar *name, const guint8 *data, return FALSE; } - /* open file for writing */ - fd = open (fn, O_WRONLY); + /* open file for writing, optionally append */ + open_wflags = O_WRONLY; + if (attr & FU_EFIVAR_ATTR_APPEND_WRITE) + open_wflags |= O_APPEND; + fd = open (fn, open_wflags); if (fd < 0) { g_set_error (error, G_IO_ERROR, From da1e4a38e7dc7b70137917630525ab26d26f39ff Mon Sep 17 00:00:00 2001 From: Richard Hughes Date: Thu, 13 Aug 2020 13:34:02 +0100 Subject: [PATCH 321/607] trivial: Fix the define of ATTR_TIME_BASED_AUTHENTICATED_WRITE_ACCESS --- libfwupdplugin/fu-efivar.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libfwupdplugin/fu-efivar.h b/libfwupdplugin/fu-efivar.h index 7f639d7ed..6bea1768c 100644 --- a/libfwupdplugin/fu-efivar.h +++ b/libfwupdplugin/fu-efivar.h @@ -19,7 +19,7 @@ #define FU_EFIVAR_ATTR_RUNTIME_ACCESS (1 << 2) #define FU_EFIVAR_ATTR_HARDWARE_ERROR_RECORD (1 << 3) #define FU_EFIVAR_ATTR_AUTHENTICATED_WRITE_ACCESS (1 << 4) -#define FU_EFIVAR_ATTR_TIME_BASED_AUTHENTICATED_WRITE_ACCESS (5 << 0) +#define FU_EFIVAR_ATTR_TIME_BASED_AUTHENTICATED_WRITE_ACCESS (1 << 5) #define FU_EFIVAR_ATTR_APPEND_WRITE (1 << 6) gboolean fu_efivar_supported (GError **error); From 361114784b9a93d87dd37cdbf1cf0bf4bcfcd8b1 Mon Sep 17 00:00:00 2001 From: Richard Hughes Date: Wed, 12 Aug 2020 15:04:24 +0100 Subject: [PATCH 322/607] Add a compatible re-implementation of the rhboot dbxtool --- libfwupdplugin/fu-common.c | 34 +++ libfwupdplugin/fu-common.h | 1 + libfwupdplugin/fwupdplugin.map | 1 + plugins/uefi-dbx/fu-dbxtool.c | 238 ++++++++++++++++++ plugins/uefi-dbx/fu-efi-signature-list.c | 91 +++++++ plugins/uefi-dbx/fu-efi-signature-list.h | 23 ++ ...i-dbx-file.c => fu-efi-signature-parser.c} | 140 +++++------ plugins/uefi-dbx/fu-efi-signature-parser.h | 23 ++ plugins/uefi-dbx/fu-efi-signature.c | 99 ++++++++ plugins/uefi-dbx/fu-efi-signature.h | 28 +++ plugins/uefi-dbx/fu-fuzzer.c | 17 +- plugins/uefi-dbx/fu-plugin-uefi-dbx.c | 31 +-- plugins/uefi-dbx/fu-self-test.c | 25 +- plugins/uefi-dbx/fu-uefi-dbx-file.h | 26 -- plugins/uefi-dbx/meson.build | 36 ++- 15 files changed, 673 insertions(+), 140 deletions(-) create mode 100644 plugins/uefi-dbx/fu-dbxtool.c create mode 100644 plugins/uefi-dbx/fu-efi-signature-list.c create mode 100644 plugins/uefi-dbx/fu-efi-signature-list.h rename plugins/uefi-dbx/{fu-uefi-dbx-file.c => fu-efi-signature-parser.c} (57%) create mode 100644 plugins/uefi-dbx/fu-efi-signature-parser.h create mode 100644 plugins/uefi-dbx/fu-efi-signature.c create mode 100644 plugins/uefi-dbx/fu-efi-signature.h delete mode 100644 plugins/uefi-dbx/fu-uefi-dbx-file.h diff --git a/libfwupdplugin/fu-common.c b/libfwupdplugin/fu-common.c index 14cf814bd..bd66931e7 100644 --- a/libfwupdplugin/fu-common.c +++ b/libfwupdplugin/fu-common.c @@ -2077,6 +2077,40 @@ fu_common_is_cpu_intel (void) return FALSE; } +/** + * fu_common_is_live_media: + * + * Checks if the user is running from a live media using various heuristics. + * + * Returns: %TRUE if live + * + * Since: 1.4.6 + **/ +gboolean +fu_common_is_live_media (void) +{ + gsize bufsz = 0; + g_autofree gchar *buf = NULL; + g_auto(GStrv) tokens = NULL; + const gchar *args[] = { + "rd.live.image", + "boot=live", + NULL, /* last entry */ + }; + if (g_file_test ("/cdrom/.disk/info", G_FILE_TEST_EXISTS)) + return TRUE; + if (!g_file_get_contents ("/proc/cmdline", &buf, &bufsz, NULL)) + return FALSE; + if (bufsz == 0) + return FALSE; + tokens = fu_common_strnsplit (buf, bufsz - 1, " ", -1); + for (guint i = 0; args[i] != NULL; i++) { + if (g_strv_contains ((const gchar * const *) tokens, args[i])) + return TRUE; + } + return FALSE; +} + static GPtrArray * fu_common_get_block_devices (GDBusConnection *connection, GError **error) { diff --git a/libfwupdplugin/fu-common.h b/libfwupdplugin/fu-common.h index 4482b7a5a..836cc60a8 100644 --- a/libfwupdplugin/fu-common.h +++ b/libfwupdplugin/fu-common.h @@ -229,6 +229,7 @@ gchar **fu_common_strnsplit (const gchar *str, gint max_tokens); gboolean fu_common_kernel_locked_down (void); gboolean fu_common_is_cpu_intel (void); +gboolean fu_common_is_live_media (void); GPtrArray *fu_common_get_volumes_by_kind (const gchar *kind, GError **error); FuVolume *fu_common_get_esp_for_path (const gchar *esp_path, diff --git a/libfwupdplugin/fwupdplugin.map b/libfwupdplugin/fwupdplugin.map index c22a94194..3e9077485 100644 --- a/libfwupdplugin/fwupdplugin.map +++ b/libfwupdplugin/fwupdplugin.map @@ -598,6 +598,7 @@ LIBFWUPDPLUGIN_1.4.6 { fu_common_get_esp_default; fu_common_get_esp_for_path; fu_common_get_volumes_by_kind; + fu_common_is_live_media; fu_volume_check_free_space; fu_volume_get_id; fu_volume_get_mount_point; diff --git a/plugins/uefi-dbx/fu-dbxtool.c b/plugins/uefi-dbx/fu-dbxtool.c new file mode 100644 index 000000000..1b93b5c66 --- /dev/null +++ b/plugins/uefi-dbx/fu-dbxtool.c @@ -0,0 +1,238 @@ +/* + * Copyright (C) 2020 Richard Hughes + * + * SPDX-License-Identifier: LGPL-2.1+ + */ + +#include "config.h" + +#include +#include +#include +#include +#include +#include + +#include "fu-common.h" +#include "fu-efivar.h" +#include "fu-uefi-dbx-common.h" +#include "fu-efi-signature-parser.h" + +/* custom return code */ +#define EXIT_NOTHING_TO_DO 2 + +static void +fu_util_ignore_cb (const gchar *log_domain, GLogLevelFlags log_level, + const gchar *message, gpointer user_data) +{ +} + +static const gchar * +fu_dbxtool_convert_guid (const gchar *guid) +{ + if (g_strcmp0 (guid, "77fa9abd-0359-4d32-bd60-28f4e78f784b") == 0) + return "microsoft"; + return guid; +} + +static FuEfiSignatureList * +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)) + return FALSE; + return fu_efi_signature_parser_one (buf, bufsz, + FU_EFI_SIGNATURE_PARSER_FLAGS_NONE, + error); +} + +static FuEfiSignatureList * +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)) + return FALSE; + return fu_efi_signature_parser_one (buf, bufsz, + FU_EFI_SIGNATURE_PARSER_FLAGS_IGNORE_HEADER, + error); +} + +int +main (int argc, char *argv[]) +{ + gboolean action_apply = FALSE; + gboolean action_list = FALSE; + gboolean force = FALSE; + gboolean verbose = FALSE; + g_autofree gchar *dbxfile = NULL; + g_autoptr(GError) error = NULL; + g_autoptr(GOptionContext) context = NULL; + g_autofree gchar *tmp = NULL; + const GOptionEntry options[] = { + { "verbose", 'v', 0, G_OPTION_ARG_NONE, &verbose, + /* TRANSLATORS: command line option */ + _("Show extra debugging information"), NULL }, + { "list", 'l', 0, G_OPTION_ARG_NONE, &action_list, + /* TRANSLATORS: command line option */ + _("List entries in dbx"), NULL }, + { "apply", 'a', 0, G_OPTION_ARG_NONE, &action_apply, + /* TRANSLATORS: command line option */ + _("Apply update files"), NULL }, + { "dbx", 'd', 0, G_OPTION_ARG_STRING, &dbxfile, + /* TRANSLATORS: command line option */ + _("Specify the dbx database file"), "FILENAME" }, + { "force", 'f', 0, G_OPTION_ARG_NONE, &force, + /* TRANSLATORS: command line option */ + _("Apply update even when not advised"), NULL }, + { NULL} + }; + + setlocale (LC_ALL, ""); + + bindtextdomain (GETTEXT_PACKAGE, FWUPD_LOCALEDIR); + bind_textdomain_codeset (GETTEXT_PACKAGE, "UTF-8"); + textdomain (GETTEXT_PACKAGE); + + /* get a action_list of the commands */ + context = g_option_context_new (NULL); + g_option_context_set_description (context, + /* TRANSLATORS: description of dbxtool */ + _("This tool allows an administrator to apply UEFI dbx updates.")); + + /* TRANSLATORS: program name */ + g_set_application_name (_("UEFI dbx Utility")); + g_option_context_add_main_entries (context, options, NULL); + if (!g_option_context_parse (context, &argc, &argv, &error)) { + /* TRANSLATORS: the user didn't read the man page */ + g_print ("%s: %s\n", _("Failed to parse arguments"), + error->message); + return EXIT_FAILURE; + } + + /* set verbose? */ + if (verbose) { + g_setenv ("G_MESSAGES_DEBUG", "all", FALSE); + } else { + g_log_set_handler (G_LOG_DOMAIN, G_LOG_LEVEL_DEBUG, + fu_util_ignore_cb, NULL); + } + + /* list contents, either of the existing system, or an update */ + if (action_list) { + GPtrArray *sigs; + g_autoptr(FuEfiSignatureList) dbx = NULL; + if (dbxfile != NULL) { + dbx = fu_dbxtool_get_siglist_local (dbxfile, &error); + if (dbx == NULL) { + /* TRANSLATORS: could not read existing system data */ + g_printerr ("%s: %s\n", _("Failed to load local dbx"), error->message); + return EXIT_FAILURE; + } + } else { + dbx = fu_dbxtool_get_siglist_system (&error); + if (dbx == NULL) { + /* TRANSLATORS: could not read existing system data */ + g_printerr ("%s: %s\n", _("Failed to load system dbx"), error->message); + return EXIT_FAILURE; + } + } + sigs = fu_efi_signature_list_get_all (dbx); + for (guint i = 0; i < sigs->len; i++) { + FuEfiSignature *sig = g_ptr_array_index (sigs, i); + g_print ("%4u: {%s} {%s} %s\n", i + 1, + fu_dbxtool_convert_guid (fu_efi_signature_get_owner (sig)), + fu_efi_signature_kind_to_string (fu_efi_signature_list_get_kind (dbx)), + fu_efi_signature_get_checksum (sig)); + } + return EXIT_SUCCESS; + } + +#ifdef HAVE_GETUID + /* ensure root user */ + if (getuid () != 0 || geteuid () != 0) { + /* TRANSLATORS: we're poking around as a power user */ + g_printerr ("%s\n", _("This program may only work correctly as root")); + } +#endif + + /* apply update */ + if (action_apply) { + gsize bufsz = 0; + g_autofree guint8 *buf = NULL; + g_autoptr(FuEfiSignatureList) dbx_system = NULL; + g_autoptr(FuEfiSignatureList) dbx_update = NULL; + + if (dbxfile == NULL) { + /* TRANSLATORS: user did not include a filename parameter */ + g_printerr ("%s\n", _("Filename required")); + return EXIT_FAILURE; + } + + /* TRANSLATORS: reading existing dbx from the system */ + g_print ("%s\n", _("Parsing system dbx…")); + dbx_system = fu_dbxtool_get_siglist_system (&error); + if (dbx_system == NULL) { + /* TRANSLATORS: could not read existing system data */ + g_printerr ("%s: %s\n", _("Failed to load system dbx"), error->message); + return EXIT_FAILURE; + } + + /* TRANSLATORS: reading new dbx from the update */ + g_print ("%s\n", _("Parsing dbx update…")); + if (!g_file_get_contents (dbxfile, (gchar **) &buf, &bufsz, &error)) { + /* 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_one (buf, bufsz, + FU_EFI_SIGNATURE_PARSER_FLAGS_IGNORE_HEADER, + &error); + if (dbx_update == NULL) { + /* TRANSLATORS: could not parse file */ + g_printerr ("%s: %s\n", _("Failed to parse local dbx"), error->message); + return EXIT_FAILURE; + } + + /* check this is a newer dbx update */ + if (!force && fu_efi_signature_list_are_inclusive (dbx_system, dbx_update)) { + /* TRANSLATORS: same or newer update already applied */ + g_printerr ("%s\n", _("Cannot apply update as this dbx update has already been applied.")); + return EXIT_FAILURE; + } + + /* check if on live media */ + if (fu_common_is_live_media () && !force) { + /* TRANSLATORS: the user is using a LiveCD or LiveUSB install disk */ + g_printerr ("%s\n", _("Cannot apply updates on live media")); + return EXIT_FAILURE; + } + + /* 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)) { + /* TRANSLATORS: dbx file failed to be applied as an update */ + g_printerr ("%s: %s\n", _("Failed to apply update"), error->message); + return EXIT_FAILURE; + } + + /* TRANSLATORS: success */ + g_print ("%s\n", _("Done!")); + return EXIT_SUCCESS; + } + + /* nothing specified */ + tmp = g_option_context_get_help (context, TRUE, NULL); + /* TRANSLATORS: user did not tell the tool what to do */ + g_printerr ("%s\n\n%s", _("No action specified!"), tmp); + return EXIT_FAILURE; +} diff --git a/plugins/uefi-dbx/fu-efi-signature-list.c b/plugins/uefi-dbx/fu-efi-signature-list.c new file mode 100644 index 000000000..19fec96a8 --- /dev/null +++ b/plugins/uefi-dbx/fu-efi-signature-list.c @@ -0,0 +1,91 @@ +/* + * Copyright (C) 2020 Richard Hughes + * + * SPDX-License-Identifier: LGPL-2.1+ + */ + +#include "config.h" + +#include "fu-efi-signature-list.h" + +struct _FuEfiSignatureList { + GObject parent_instance; + FuEfiSignatureKind kind; + GPtrArray *items; /* element-type: FuEfiSignature */ +}; + +G_DEFINE_TYPE (FuEfiSignatureList, fu_efi_signature_list, G_TYPE_OBJECT) + +FuEfiSignatureList * +fu_efi_signature_list_new (FuEfiSignatureKind kind) +{ + g_autoptr(FuEfiSignatureList) self = g_object_new (FU_TYPE_EFI_SIGNATURE_LIST, NULL); + self->kind = kind; + return g_steal_pointer (&self); +} + +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; + } + return FALSE; +} + +gboolean +fu_efi_signature_list_are_inclusive (FuEfiSignatureList *self, FuEfiSignatureList *other) +{ + g_return_val_if_fail (FU_IS_EFI_SIGNATURE_LIST (self), FALSE); + for (guint i = 0; i < other->items->len; i++) { + FuEfiSignature *sig = g_ptr_array_index (other->items, i); + if (!fu_efi_signature_list_has_checksum (self, fu_efi_signature_get_checksum (sig))) + return FALSE; + } + return TRUE; +} + +static void +fu_efi_signature_list_finalize (GObject *obj) +{ + FuEfiSignatureList *self = FU_EFI_SIGNATURE_LIST (obj); + g_ptr_array_unref (self->items); + G_OBJECT_CLASS (fu_efi_signature_list_parent_class)->finalize (obj); +} + +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; +} + +static void +fu_efi_signature_list_init (FuEfiSignatureList *self) +{ + self->items = g_ptr_array_new_with_free_func ((GDestroyNotify) g_object_unref); +} diff --git a/plugins/uefi-dbx/fu-efi-signature-list.h b/plugins/uefi-dbx/fu-efi-signature-list.h new file mode 100644 index 000000000..75582ecc1 --- /dev/null +++ b/plugins/uefi-dbx/fu-efi-signature-list.h @@ -0,0 +1,23 @@ +/* + * Copyright (C) 2020 Richard Hughes + * + * SPDX-License-Identifier: LGPL-2.1+ + */ + +#pragma once + +#include "fu-efi-signature.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) + + +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); +gboolean fu_efi_signature_list_are_inclusive (FuEfiSignatureList *self, + FuEfiSignatureList *other); diff --git a/plugins/uefi-dbx/fu-uefi-dbx-file.c b/plugins/uefi-dbx/fu-efi-signature-parser.c similarity index 57% rename from plugins/uefi-dbx/fu-uefi-dbx-file.c rename to plugins/uefi-dbx/fu-efi-signature-parser.c index a56785e27..df8571bab 100644 --- a/plugins/uefi-dbx/fu-uefi-dbx-file.c +++ b/plugins/uefi-dbx/fu-efi-signature-parser.c @@ -10,29 +10,22 @@ #include #include "fu-common.h" -#include "fu-uefi-dbx-common.h" -#include "fu-uefi-dbx-file.h" - -struct _FuUefiDbxFile { - GObject parent_instance; - GPtrArray *checksums; -}; - -G_DEFINE_TYPE (FuUefiDbxFile, fu_uefi_dbx_file, G_TYPE_OBJECT) +#include "fu-efi-signature-parser.h" static gboolean -fu_uefi_dbx_file_parse_sig_item (FuUefiDbxFile *self, - const guint8 *buf, - gsize bufsz, - gsize offset, - guint32 sig_size, - GError **error) +fu_efi_signature_list_parse_item (FuEfiSignatureList *siglist, + const guint8 *buf, + gsize bufsz, + gsize offset, + guint32 sig_size, + GError **error) { - GString *sig_datastr; 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 */ @@ -48,23 +41,20 @@ fu_uefi_dbx_file_parse_sig_item (FuUefiDbxFile *self, return FALSE; } - /* we don't care about the owner, so just store the checksum */ + /* create item */ sig_owner = fwupd_guid_to_string (&guid, FWUPD_GUID_FLAG_MIXED_ENDIAN); - sig_datastr = g_string_new (NULL); - for (gsize j = 0; j < sig_datasz; j++) - g_string_append_printf (sig_datastr, "%02x", sig_data[j]); - if (g_getenv ("FWUPD_UEFI_DBX_VERBOSE") != NULL) - g_debug ("Owner: %s, Data: %s", sig_owner, sig_datastr->str); - g_ptr_array_add (self->checksums, g_string_free (sig_datastr, FALSE)); + 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_uefi_dbx_file_parse_sig_list (FuUefiDbxFile *self, - const guint8 *buf, - gsize bufsz, - gsize *offset, - GError **error) +fu_efi_signature_list_parse_list (GPtrArray *siglists, + const guint8 *buf, + gsize bufsz, + gsize *offset, + GError **error) { fwupd_guid_t guid; gsize offset_tmp; @@ -72,6 +62,7 @@ fu_uefi_dbx_file_parse_sig_list (FuUefiDbxFile *self, 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 */ @@ -81,12 +72,16 @@ fu_uefi_dbx_file_parse_sig_list (FuUefiDbxFile *self, 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) + if (g_strcmp0 (sig_type, "c1c41626-504c-4092-aca9-41f936934328") == 0) { g_debug ("EFI_SIGNATURE_LIST SHA256"); - else if (g_strcmp0 (sig_type, "a5c059a1-94e4-4aa7-87b5-ab155c2bf072") == 0) + siglist = fu_efi_signature_list_new (FU_EFI_SIGNATURE_KIND_SHA256); + } else if (g_strcmp0 (sig_type, "a5c059a1-94e4-4aa7-87b5-ab155c2bf072") == 0) { g_debug ("EFI_SIGNATURE_LIST X509"); - else + siglist = fu_efi_signature_list_new (FU_EFI_SIGNATURE_KIND_X509); + } else { g_debug ("EFI_SIGNATURE_LIST unknown: %s", sig_type); + 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; @@ -121,27 +116,28 @@ fu_uefi_dbx_file_parse_sig_list (FuUefiDbxFile *self, /* 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_uefi_dbx_file_parse_sig_item (self, buf, bufsz, - offset_tmp, sig_size, - error)) + 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; } -FuUefiDbxFile * -fu_uefi_dbx_file_new (const guint8 *buf, gsize bufsz, - FuUefiDbxFileParseFlags flags, - GError **error) +GPtrArray * +fu_efi_signature_parser_all (const guint8 *buf, gsize bufsz, + FuEfiSignatureParserFlags flags, + GError **error) { gsize offset_fs = 0; - g_autoptr(FuUefiDbxFile) self = g_object_new (FU_TYPE_UEFI_DBX_FILE, NULL); + 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_UEFI_DBX_FILE_PARSE_FLAGS_IGNORE_HEADER) { + if (flags & FU_EFI_SIGNATURE_PARSER_FLAGS_IGNORE_HEADER) { 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); @@ -152,51 +148,39 @@ fu_uefi_dbx_file_new (const guint8 *buf, gsize bufsz, } /* 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_uefi_dbx_file_parse_sig_list (self, buf, bufsz, &offset, error)) + if (!fu_efi_signature_list_parse_list (siglists, buf, bufsz, &offset, error)) return NULL; } /* success */ - return g_steal_pointer (&self); + return g_steal_pointer (&siglists); } -gboolean -fu_uefi_dbx_file_has_checksum (FuUefiDbxFile *self, const gchar *checksum) +FuEfiSignatureList * +fu_efi_signature_parser_one (const guint8 *buf, gsize bufsz, + FuEfiSignatureParserFlags flags, + GError **error) { - g_return_val_if_fail (FU_IS_UEFI_DBX_FILE (self), FALSE); - for (guint i = 0; i < self->checksums->len; i++) { - const gchar *checksums_tmp = g_ptr_array_index (self->checksums, i); - if (g_strcmp0 (checksums_tmp, checksum) == 0) - return TRUE; + g_autoptr(GPtrArray) siglists = NULL; + + siglists = fu_efi_signature_parser_all (buf, bufsz, flags, error); + if (siglists == NULL) + return FALSE; + if (siglists->len == 0) { + g_set_error (error, + G_IO_ERROR, + G_IO_ERROR_FAILED, + "no EFI_SIGNATURE_LIST items"); + return FALSE; } - return FALSE; -} - -GPtrArray * -fu_uefi_dbx_file_get_checksums (FuUefiDbxFile *self) -{ - g_return_val_if_fail (FU_IS_UEFI_DBX_FILE (self), FALSE); - return self->checksums; -} - -static void -fu_uefi_dbx_file_finalize (GObject *obj) -{ - FuUefiDbxFile *self = FU_UEFI_DBX_FILE (obj); - g_ptr_array_unref (self->checksums); - G_OBJECT_CLASS (fu_uefi_dbx_file_parent_class)->finalize (obj); -} - -static void -fu_uefi_dbx_file_class_init (FuUefiDbxFileClass *klass) -{ - GObjectClass *object_class = G_OBJECT_CLASS (klass); - object_class->finalize = fu_uefi_dbx_file_finalize; -} - -static void -fu_uefi_dbx_file_init (FuUefiDbxFile *self) -{ - self->checksums = g_ptr_array_new_with_free_func (g_free); + if (siglists->len > 1) { + g_set_error (error, + G_IO_ERROR, + G_IO_ERROR_FAILED, + "more than one EFI_SIGNATURE_LIST items"); + return FALSE; + } + return g_object_ref (g_ptr_array_index (siglists, 0)); } diff --git a/plugins/uefi-dbx/fu-efi-signature-parser.h b/plugins/uefi-dbx/fu-efi-signature-parser.h new file mode 100644 index 000000000..956088a69 --- /dev/null +++ b/plugins/uefi-dbx/fu-efi-signature-parser.h @@ -0,0 +1,23 @@ +/* + * Copyright (C) 2020 Richard Hughes + * + * 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_all (const guint8 *buf, + gsize bufsz, + FuEfiSignatureParserFlags flags, + GError **error); +FuEfiSignatureList* fu_efi_signature_parser_one (const guint8 *buf, + gsize bufsz, + FuEfiSignatureParserFlags flags, + GError **error); diff --git a/plugins/uefi-dbx/fu-efi-signature.c b/plugins/uefi-dbx/fu-efi-signature.c new file mode 100644 index 000000000..e2e8494c5 --- /dev/null +++ b/plugins/uefi-dbx/fu-efi-signature.c @@ -0,0 +1,99 @@ +/* + * Copyright (C) 2020 Richard Hughes + * + * SPDX-License-Identifier: LGPL-2.1+ + */ + +#include "config.h" + +#include "fu-efi-signature.h" + +struct _FuEfiSignature { + GObject parent_instance; + FuEfiSignatureKind kind; + gchar *owner; + gchar *checksum; /* (nullable) */ + GBytes *data; +}; + +G_DEFINE_TYPE (FuEfiSignature, fu_efi_signature, G_TYPE_OBJECT) + + +const gchar * +fu_efi_signature_kind_to_string (FuEfiSignatureKind kind) +{ + if (kind == FU_EFI_SIGNATURE_KIND_SHA256) + return "sha256"; + if (kind == FU_EFI_SIGNATURE_KIND_X509) + return "x509"; + return "unknown"; +} + +FuEfiSignature * +fu_efi_signature_new (FuEfiSignatureKind kind, const gchar *owner, GBytes *data) +{ + 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); +} + +const gchar * +fu_efi_signature_get_owner (FuEfiSignature *self) +{ + g_return_val_if_fail (FU_IS_EFI_SIGNATURE (self), NULL); + return self->owner; +} + +GBytes * +fu_efi_signature_get_data (FuEfiSignature *self) +{ + g_return_val_if_fail (FU_IS_EFI_SIGNATURE (self), NULL); + return self->data; +} + +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); + } + } + return self->checksum; +} + +static void +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); +} + +static void +fu_efi_signature_class_init (FuEfiSignatureClass *klass) +{ + GObjectClass *object_class = G_OBJECT_CLASS (klass); + object_class->finalize = fu_efi_signature_finalize; +} + +static void +fu_efi_signature_init (FuEfiSignature *self) +{ +} diff --git a/plugins/uefi-dbx/fu-efi-signature.h b/plugins/uefi-dbx/fu-efi-signature.h new file mode 100644 index 000000000..14926de74 --- /dev/null +++ b/plugins/uefi-dbx/fu-efi-signature.h @@ -0,0 +1,28 @@ +/* + * Copyright (C) 2020 Richard Hughes + * + * SPDX-License-Identifier: LGPL-2.1+ + */ + +#pragma once + +#include + +#define FU_TYPE_EFI_SIGNATURE (fu_efi_signature_get_type ()) +G_DECLARE_FINAL_TYPE (FuEfiSignature, fu_efi_signature, FU, EFI_SIGNATURE, GObject) + +typedef enum { + FU_EFI_SIGNATURE_KIND_UNKNOWN, + FU_EFI_SIGNATURE_KIND_SHA256, + FU_EFI_SIGNATURE_KIND_X509, + FU_EFI_SIGNATURE_KIND_LAST +} FuEfiSignatureKind; + +const gchar *fu_efi_signature_kind_to_string (FuEfiSignatureKind kind); + +FuEfiSignature *fu_efi_signature_new (FuEfiSignatureKind kind, + const gchar *owner, + GBytes *data); +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); diff --git a/plugins/uefi-dbx/fu-fuzzer.c b/plugins/uefi-dbx/fu-fuzzer.c index ee8b392b5..374d6e2cc 100644 --- a/plugins/uefi-dbx/fu-fuzzer.c +++ b/plugins/uefi-dbx/fu-fuzzer.c @@ -8,15 +8,15 @@ #include -#include "fu-uefi-dbx-file.h" +#include "fu-efi-signature-parser.h" int main (int argc, char *argv[]) { gsize bufsz = 0; g_autofree guint8 *buf = NULL; - g_autoptr(FuUefiDbxFile) uefi_dbx_file = NULL; g_autoptr(GError) error = NULL; + g_autoptr(GPtrArray) siglists = NULL; if (argc < 2) { g_printerr ("Not enough arguments, expected 'foo.bin'\n"); @@ -26,13 +26,16 @@ main (int argc, char *argv[]) g_printerr ("Failed to load %s: %s\n", argv[1], error->message); return EXIT_FAILURE; } - uefi_dbx_file = fu_uefi_dbx_file_new (buf, bufsz, - FU_UEFI_DBX_FILE_PARSE_FLAGS_IGNORE_HEADER, - &error); - if (uefi_dbx_file == NULL) { + siglists = fu_efi_signature_parser_all (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; } - g_print ("%u checksums\n", fu_uefi_dbx_file_get_checksums(uefi_dbx_file)->len); + 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; } diff --git a/plugins/uefi-dbx/fu-plugin-uefi-dbx.c b/plugins/uefi-dbx/fu-plugin-uefi-dbx.c index 9692b957b..15444df90 100644 --- a/plugins/uefi-dbx/fu-plugin-uefi-dbx.c +++ b/plugins/uefi-dbx/fu-plugin-uefi-dbx.c @@ -10,7 +10,7 @@ #include "fu-efivar.h" #include "fu-hash.h" #include "fu-uefi-dbx-common.h" -#include "fu-uefi-dbx-file.h" +#include "fu-efi-signature-parser.h" struct FuPluginData { gchar *fn; @@ -45,13 +45,13 @@ void fu_plugin_add_security_attrs (FuPlugin *plugin, FuSecurityAttrs *attrs) { FuPluginData *data = fu_plugin_get_data (plugin); - GPtrArray *checksums; + GPtrArray *items; gsize bufsz = 0; guint missing_cnt = 0; g_autofree guint8 *buf_system = NULL; g_autofree guint8 *buf_update = NULL; - g_autoptr(FuUefiDbxFile) dbx_system = NULL; - g_autoptr(FuUefiDbxFile) dbx_update = NULL; + g_autoptr(FuEfiSignatureList) dbx_system = NULL; + g_autoptr(FuEfiSignatureList) dbx_update = NULL; g_autoptr(FwupdSecurityAttr) attr = NULL; g_autoptr(GError) error_local = NULL; @@ -74,9 +74,9 @@ fu_plugin_add_security_attrs (FuPlugin *plugin, FuSecurityAttrs *attrs) fwupd_security_attr_set_result (attr, FWUPD_SECURITY_ATTR_RESULT_NOT_VALID); return; } - dbx_update = fu_uefi_dbx_file_new (buf_update, bufsz, - FU_UEFI_DBX_FILE_PARSE_FLAGS_IGNORE_HEADER, - &error_local); + dbx_update = fu_efi_signature_parser_one (buf_update, bufsz, + FU_EFI_SIGNATURE_PARSER_FLAGS_IGNORE_HEADER, + &error_local); if (dbx_update == NULL) { g_warning ("failed to parse %s: %s", data->fn, error_local->message); fwupd_security_attr_set_result (attr, FWUPD_SECURITY_ATTR_RESULT_NOT_VALID); @@ -90,9 +90,9 @@ fu_plugin_add_security_attrs (FuPlugin *plugin, FuSecurityAttrs *attrs) fwupd_security_attr_set_result (attr, FWUPD_SECURITY_ATTR_RESULT_NOT_VALID); return; } - dbx_system = fu_uefi_dbx_file_new (buf_system, bufsz, - FU_UEFI_DBX_FILE_PARSE_FLAGS_NONE, - &error_local); + dbx_system = fu_efi_signature_parser_one (buf_system, bufsz, + FU_EFI_SIGNATURE_PARSER_FLAGS_NONE, + &error_local); if (dbx_system == NULL) { g_warning ("failed to parse EFI dbx: %s", error_local->message); fwupd_security_attr_set_result (attr, FWUPD_SECURITY_ATTR_RESULT_NOT_VALID); @@ -100,11 +100,12 @@ fu_plugin_add_security_attrs (FuPlugin *plugin, FuSecurityAttrs *attrs) } /* look for each checksum in the update in the system version */ - checksums = fu_uefi_dbx_file_get_checksums (dbx_update); - for (guint i = 0; i < checksums->len; i++) { - const gchar *checksum = g_ptr_array_index (checksums, i); - if (!fu_uefi_dbx_file_has_checksum (dbx_system, checksum)) { - g_debug ("%s missing from the system DBX", checksum); + items = fu_efi_signature_list_get_all (dbx_update); + for (guint i = 0; i < items->len; i++) { + FuEfiSignature *item = g_ptr_array_index (items, i); + if (!fu_efi_signature_list_has_checksum (dbx_system, fu_efi_signature_get_checksum (item))) { + g_debug ("%s missing from the system DBX", + fu_efi_signature_get_checksum (item)); missing_cnt += 1; } } diff --git a/plugins/uefi-dbx/fu-self-test.c b/plugins/uefi-dbx/fu-self-test.c index 706e0d988..4a98c42b8 100644 --- a/plugins/uefi-dbx/fu-self-test.c +++ b/plugins/uefi-dbx/fu-self-test.c @@ -9,16 +9,17 @@ #include #include "fu-uefi-dbx-common.h" -#include "fu-uefi-dbx-file.h" +#include "fu-efi-signature-parser.h" static void -fu_uefi_dbx_file_parse_func (void) +fu_efi_signature_list_parse_func (void) { + FuEfiSignatureList *siglist; gboolean ret; gsize bufsz = 0; g_autofree gchar *fn = NULL; g_autofree guint8 *buf = NULL; - g_autoptr(FuUefiDbxFile) uefi_dbx_file = NULL; + g_autoptr(GPtrArray) siglists = NULL; g_autoptr(GError) error = NULL; /* load file */ @@ -32,14 +33,16 @@ fu_uefi_dbx_file_parse_func (void) g_assert_true (ret); /* parse the update */ - uefi_dbx_file = fu_uefi_dbx_file_new (buf, bufsz, - FU_UEFI_DBX_FILE_PARSE_FLAGS_IGNORE_HEADER, - &error); + siglists = fu_efi_signature_parser_all (buf, bufsz, + FU_EFI_SIGNATURE_PARSER_FLAGS_IGNORE_HEADER, + &error); g_assert_no_error (error); - g_assert_nonnull (uefi_dbx_file); - g_assert_cmpint (fu_uefi_dbx_file_get_checksums(uefi_dbx_file)->len, ==, 77); - g_assert_true (fu_uefi_dbx_file_has_checksum (uefi_dbx_file, "72e0bd1867cf5d9d56ab158adf3bddbc82bf32a8d8aa1d8c5e2f6df29428d6d8")); - g_assert_false (fu_uefi_dbx_file_has_checksum (uefi_dbx_file, "dave")); + g_assert_nonnull (siglists); + g_assert_cmpint (siglists->len, ==, 1); + siglist = g_ptr_array_index (siglists, 0); + g_assert_cmpint (fu_efi_signature_list_get_all(siglist)->len, ==, 77); + g_assert_true (fu_efi_signature_list_has_checksum (siglist, "72e0bd1867cf5d9d56ab158adf3bddbc82bf32a8d8aa1d8c5e2f6df29428d6d8")); + g_assert_false (fu_efi_signature_list_has_checksum (siglist, "dave")); } int @@ -52,6 +55,6 @@ main (int argc, char **argv) g_setenv ("G_MESSAGES_DEBUG", "all", TRUE); /* tests go here */ - g_test_add_func ("/uefi-dbx/file-parse", fu_uefi_dbx_file_parse_func); + g_test_add_func ("/uefi-dbx/file-parse", fu_efi_signature_list_parse_func); return g_test_run (); } diff --git a/plugins/uefi-dbx/fu-uefi-dbx-file.h b/plugins/uefi-dbx/fu-uefi-dbx-file.h deleted file mode 100644 index 4a3b2c693..000000000 --- a/plugins/uefi-dbx/fu-uefi-dbx-file.h +++ /dev/null @@ -1,26 +0,0 @@ -/* - * Copyright (C) 2020 Richard Hughes - * - * SPDX-License-Identifier: LGPL-2.1+ - */ - -#pragma once - -#include - -#define FU_TYPE_UEFI_DBX_FILE (fu_uefi_dbx_file_get_type ()) -G_DECLARE_FINAL_TYPE (FuUefiDbxFile, fu_uefi_dbx_file, FU, UEFI_DBX_FILE, GObject) - - -typedef enum { - FU_UEFI_DBX_FILE_PARSE_FLAGS_NONE = 0, - FU_UEFI_DBX_FILE_PARSE_FLAGS_IGNORE_HEADER = 1 << 0, -} FuUefiDbxFileParseFlags; - -FuUefiDbxFile *fu_uefi_dbx_file_new (const guint8 *buf, - gsize bufsz, - FuUefiDbxFileParseFlags flags, - GError **error); -GPtrArray *fu_uefi_dbx_file_get_checksums (FuUefiDbxFile *self); -gboolean fu_uefi_dbx_file_has_checksum (FuUefiDbxFile *self, - const gchar *checksum); diff --git a/plugins/uefi-dbx/meson.build b/plugins/uefi-dbx/meson.build index e64a55a85..14d66d635 100644 --- a/plugins/uefi-dbx/meson.build +++ b/plugins/uefi-dbx/meson.build @@ -5,7 +5,9 @@ shared_module('fu_plugin_uefi_dbx', sources : [ 'fu-plugin-uefi-dbx.c', 'fu-uefi-dbx-common.c', - 'fu-uefi-dbx-file.c', + 'fu-efi-signature.c', + 'fu-efi-signature-list.c', + 'fu-efi-signature-parser.c', ], include_directories : [ root_incdir, @@ -31,7 +33,9 @@ if get_option('tests') sources : [ 'fu-self-test.c', 'fu-uefi-dbx-common.c', - 'fu-uefi-dbx-file.c', + 'fu-efi-signature.c', + 'fu-efi-signature-list.c', + 'fu-efi-signature-parser.c', ], include_directories : [ root_incdir, @@ -53,7 +57,9 @@ uefi_dbx_fuzzer = executable( 'uefi-dbx-fuzzer', sources : [ 'fu-fuzzer.c', - 'fu-uefi-dbx-file.c', + 'fu-efi-signature.c', + 'fu-efi-signature-list.c', + 'fu-efi-signature-parser.c', ], include_directories : [ root_incdir, @@ -69,6 +75,30 @@ uefi_dbx_fuzzer = executable( ], ) +dbxtool = executable( + 'dbxtool', + sources : [ + 'fu-dbxtool.c', + 'fu-uefi-dbx-common.c', + 'fu-efi-signature.c', + 'fu-efi-signature-list.c', + 'fu-efi-signature-parser.c', + ], + include_directories : [ + root_incdir, + fwupd_incdir, + fwupdplugin_incdir, + ], + dependencies : [ + plugin_deps, + ], + link_with : [ + fwupd, + fwupdplugin, + ], + c_args : cargs, +) + run_target('fuzz-efidbx', command: [ join_paths(meson.source_root(), 'contrib/afl-fuzz.py'), From edc34323389db76204ffbc7e40a3fe3d89406572 Mon Sep 17 00:00:00 2001 From: Richard Hughes Date: Thu, 13 Aug 2020 20:46:05 +0100 Subject: [PATCH 323/607] dbxtool: List the checksums correctly for multiple EFI_SIGNATURE_LISTs Fixes https://github.com/fwupd/fwupd/issues/2319 --- plugins/uefi-dbx/fu-dbxtool.c | 46 +++++++++++++--------- plugins/uefi-dbx/fu-efi-signature-common.c | 37 +++++++++++++++++ plugins/uefi-dbx/fu-efi-signature-common.h | 12 ++++++ plugins/uefi-dbx/fu-efi-signature-list.c | 12 ------ plugins/uefi-dbx/fu-efi-signature-list.h | 2 - plugins/uefi-dbx/fu-efi-signature-parser.c | 29 +------------- plugins/uefi-dbx/fu-efi-signature-parser.h | 6 +-- plugins/uefi-dbx/fu-efi-signature.c | 9 ++++- plugins/uefi-dbx/fu-efi-signature.h | 1 + plugins/uefi-dbx/fu-fuzzer.c | 2 +- plugins/uefi-dbx/fu-plugin-uefi-dbx.c | 24 +++-------- plugins/uefi-dbx/fu-self-test.c | 2 +- plugins/uefi-dbx/meson.build | 4 ++ 13 files changed, 100 insertions(+), 86 deletions(-) create mode 100644 plugins/uefi-dbx/fu-efi-signature-common.c create mode 100644 plugins/uefi-dbx/fu-efi-signature-common.h diff --git a/plugins/uefi-dbx/fu-dbxtool.c b/plugins/uefi-dbx/fu-dbxtool.c index 1b93b5c66..819c47a6c 100644 --- a/plugins/uefi-dbx/fu-dbxtool.c +++ b/plugins/uefi-dbx/fu-dbxtool.c @@ -16,6 +16,7 @@ #include "fu-common.h" #include "fu-efivar.h" #include "fu-uefi-dbx-common.h" +#include "fu-efi-signature-common.h" #include "fu-efi-signature-parser.h" /* custom return code */ @@ -35,7 +36,7 @@ fu_dbxtool_convert_guid (const gchar *guid) return guid; } -static FuEfiSignatureList * +static GPtrArray * fu_dbxtool_get_siglist_system (GError **error) { gsize bufsz = 0; @@ -43,19 +44,19 @@ fu_dbxtool_get_siglist_system (GError **error) if (!fu_efivar_get_data (FU_EFIVAR_GUID_SECURITY_DATABASE, "dbx", &buf, &bufsz, NULL, error)) return FALSE; - return fu_efi_signature_parser_one (buf, bufsz, + return fu_efi_signature_parser_new (buf, bufsz, FU_EFI_SIGNATURE_PARSER_FLAGS_NONE, error); } -static FuEfiSignatureList * +static GPtrArray * 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)) return FALSE; - return fu_efi_signature_parser_one (buf, bufsz, + return fu_efi_signature_parser_new (buf, bufsz, FU_EFI_SIGNATURE_PARSER_FLAGS_IGNORE_HEADER, error); } @@ -122,8 +123,8 @@ main (int argc, char *argv[]) /* list contents, either of the existing system, or an update */ if (action_list) { - GPtrArray *sigs; - g_autoptr(FuEfiSignatureList) dbx = NULL; + guint cnt = 1; + g_autoptr(GPtrArray) dbx = NULL; if (dbxfile != NULL) { dbx = fu_dbxtool_get_siglist_local (dbxfile, &error); if (dbx == NULL) { @@ -139,13 +140,17 @@ main (int argc, char *argv[]) return EXIT_FAILURE; } } - sigs = fu_efi_signature_list_get_all (dbx); - for (guint i = 0; i < sigs->len; i++) { - FuEfiSignature *sig = g_ptr_array_index (sigs, i); - g_print ("%4u: {%s} {%s} %s\n", i + 1, - fu_dbxtool_convert_guid (fu_efi_signature_get_owner (sig)), - fu_efi_signature_kind_to_string (fu_efi_signature_list_get_kind (dbx)), - fu_efi_signature_get_checksum (sig)); + 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_dbxtool_convert_guid (fu_efi_signature_get_owner (sig)), + fu_efi_signature_kind_to_string (fu_efi_signature_get_kind (sig)), + fu_efi_signature_get_checksum (sig)); + } } return EXIT_SUCCESS; } @@ -162,8 +167,8 @@ main (int argc, char *argv[]) if (action_apply) { gsize bufsz = 0; g_autofree guint8 *buf = NULL; - g_autoptr(FuEfiSignatureList) dbx_system = NULL; - g_autoptr(FuEfiSignatureList) dbx_update = NULL; + g_autoptr(GPtrArray) dbx_system = NULL; + g_autoptr(GPtrArray) dbx_update = NULL; if (dbxfile == NULL) { /* TRANSLATORS: user did not include a filename parameter */ @@ -187,7 +192,7 @@ main (int argc, char *argv[]) g_printerr ("%s: %s\n", _("Failed to load local dbx"), error->message); return EXIT_FAILURE; } - dbx_update = fu_efi_signature_parser_one (buf, bufsz, + dbx_update = fu_efi_signature_parser_new (buf, bufsz, FU_EFI_SIGNATURE_PARSER_FLAGS_IGNORE_HEADER, &error); if (dbx_update == NULL) { @@ -195,11 +200,16 @@ main (int argc, char *argv[]) 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_are_inclusive (dbx_system, dbx_update)) { + if (!force && fu_efi_signature_list_array_inclusive (dbx_system, dbx_update)) { /* TRANSLATORS: same or newer update already applied */ - g_printerr ("%s\n", _("Cannot apply update as this dbx update has already been applied.")); + g_printerr ("%s\n", _("Cannot apply as dbx update has already been applied.")); return EXIT_FAILURE; } diff --git a/plugins/uefi-dbx/fu-efi-signature-common.c b/plugins/uefi-dbx/fu-efi-signature-common.c new file mode 100644 index 000000000..1c70d7ea5 --- /dev/null +++ b/plugins/uefi-dbx/fu-efi-signature-common.c @@ -0,0 +1,37 @@ +/* + * Copyright (C) 2020 Richard Hughes + * + * SPDX-License-Identifier: LGPL-2.1+ + */ + +#include "config.h" + +#include "fu-efi-signature-common.h" +#include "fu-efi-signature-list.h" + +static gboolean +fu_efi_signature_list_array_has_checksum (GPtrArray *siglists, 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; +} + +gboolean +fu_efi_signature_list_array_inclusive (GPtrArray *outer, GPtrArray *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; + } + } + return TRUE; +} diff --git a/plugins/uefi-dbx/fu-efi-signature-common.h b/plugins/uefi-dbx/fu-efi-signature-common.h new file mode 100644 index 000000000..b9761110e --- /dev/null +++ b/plugins/uefi-dbx/fu-efi-signature-common.h @@ -0,0 +1,12 @@ +/* + * Copyright (C) 2020 Richard Hughes + * + * SPDX-License-Identifier: LGPL-2.1+ + */ + +#pragma once + +#include "fu-efi-signature.h" + +gboolean fu_efi_signature_list_array_inclusive (GPtrArray *outer, + GPtrArray *inner); diff --git a/plugins/uefi-dbx/fu-efi-signature-list.c b/plugins/uefi-dbx/fu-efi-signature-list.c index 19fec96a8..422a0010e 100644 --- a/plugins/uefi-dbx/fu-efi-signature-list.c +++ b/plugins/uefi-dbx/fu-efi-signature-list.c @@ -57,18 +57,6 @@ fu_efi_signature_list_has_checksum (FuEfiSignatureList *self, const gchar *check return FALSE; } -gboolean -fu_efi_signature_list_are_inclusive (FuEfiSignatureList *self, FuEfiSignatureList *other) -{ - g_return_val_if_fail (FU_IS_EFI_SIGNATURE_LIST (self), FALSE); - for (guint i = 0; i < other->items->len; i++) { - FuEfiSignature *sig = g_ptr_array_index (other->items, i); - if (!fu_efi_signature_list_has_checksum (self, fu_efi_signature_get_checksum (sig))) - return FALSE; - } - return TRUE; -} - static void fu_efi_signature_list_finalize (GObject *obj) { diff --git a/plugins/uefi-dbx/fu-efi-signature-list.h b/plugins/uefi-dbx/fu-efi-signature-list.h index 75582ecc1..688f2ee84 100644 --- a/plugins/uefi-dbx/fu-efi-signature-list.h +++ b/plugins/uefi-dbx/fu-efi-signature-list.h @@ -19,5 +19,3 @@ void fu_efi_signature_list_add (FuEfiSignatureList *self, GPtrArray *fu_efi_signature_list_get_all (FuEfiSignatureList *self); gboolean fu_efi_signature_list_has_checksum (FuEfiSignatureList *self, const gchar *checksum); -gboolean fu_efi_signature_list_are_inclusive (FuEfiSignatureList *self, - FuEfiSignatureList *other); diff --git a/plugins/uefi-dbx/fu-efi-signature-parser.c b/plugins/uefi-dbx/fu-efi-signature-parser.c index df8571bab..3754064c8 100644 --- a/plugins/uefi-dbx/fu-efi-signature-parser.c +++ b/plugins/uefi-dbx/fu-efi-signature-parser.c @@ -128,7 +128,7 @@ fu_efi_signature_list_parse_list (GPtrArray *siglists, } GPtrArray * -fu_efi_signature_parser_all (const guint8 *buf, gsize bufsz, +fu_efi_signature_parser_new (const guint8 *buf, gsize bufsz, FuEfiSignatureParserFlags flags, GError **error) { @@ -157,30 +157,3 @@ fu_efi_signature_parser_all (const guint8 *buf, gsize bufsz, /* success */ return g_steal_pointer (&siglists); } - -FuEfiSignatureList * -fu_efi_signature_parser_one (const guint8 *buf, gsize bufsz, - FuEfiSignatureParserFlags flags, - GError **error) -{ - g_autoptr(GPtrArray) siglists = NULL; - - siglists = fu_efi_signature_parser_all (buf, bufsz, flags, error); - if (siglists == NULL) - return FALSE; - if (siglists->len == 0) { - g_set_error (error, - G_IO_ERROR, - G_IO_ERROR_FAILED, - "no EFI_SIGNATURE_LIST items"); - return FALSE; - } - if (siglists->len > 1) { - g_set_error (error, - G_IO_ERROR, - G_IO_ERROR_FAILED, - "more than one EFI_SIGNATURE_LIST items"); - return FALSE; - } - return g_object_ref (g_ptr_array_index (siglists, 0)); -} diff --git a/plugins/uefi-dbx/fu-efi-signature-parser.h b/plugins/uefi-dbx/fu-efi-signature-parser.h index 956088a69..d5a138c06 100644 --- a/plugins/uefi-dbx/fu-efi-signature-parser.h +++ b/plugins/uefi-dbx/fu-efi-signature-parser.h @@ -13,11 +13,7 @@ typedef enum { FU_EFI_SIGNATURE_PARSER_FLAGS_IGNORE_HEADER = 1 << 0, } FuEfiSignatureParserFlags; -GPtrArray *fu_efi_signature_parser_all (const guint8 *buf, - gsize bufsz, - FuEfiSignatureParserFlags flags, - GError **error); -FuEfiSignatureList* fu_efi_signature_parser_one (const guint8 *buf, +GPtrArray *fu_efi_signature_parser_new (const guint8 *buf, gsize bufsz, FuEfiSignatureParserFlags flags, GError **error); diff --git a/plugins/uefi-dbx/fu-efi-signature.c b/plugins/uefi-dbx/fu-efi-signature.c index e2e8494c5..bc33bbc0d 100644 --- a/plugins/uefi-dbx/fu-efi-signature.c +++ b/plugins/uefi-dbx/fu-efi-signature.c @@ -25,7 +25,7 @@ fu_efi_signature_kind_to_string (FuEfiSignatureKind kind) if (kind == FU_EFI_SIGNATURE_KIND_SHA256) return "sha256"; if (kind == FU_EFI_SIGNATURE_KIND_X509) - return "x509"; + return "x509_cert"; return "unknown"; } @@ -39,6 +39,13 @@ fu_efi_signature_new (FuEfiSignatureKind kind, const gchar *owner, GBytes *data) return g_steal_pointer (&self); } +FuEfiSignatureKind +fu_efi_signature_get_kind (FuEfiSignature *self) +{ + g_return_val_if_fail (FU_IS_EFI_SIGNATURE (self), 0); + return self->kind; +} + const gchar * fu_efi_signature_get_owner (FuEfiSignature *self) { diff --git a/plugins/uefi-dbx/fu-efi-signature.h b/plugins/uefi-dbx/fu-efi-signature.h index 14926de74..9aebf0abd 100644 --- a/plugins/uefi-dbx/fu-efi-signature.h +++ b/plugins/uefi-dbx/fu-efi-signature.h @@ -23,6 +23,7 @@ const gchar *fu_efi_signature_kind_to_string (FuEfiSignatureKind kind); FuEfiSignature *fu_efi_signature_new (FuEfiSignatureKind kind, const gchar *owner, GBytes *data); +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); diff --git a/plugins/uefi-dbx/fu-fuzzer.c b/plugins/uefi-dbx/fu-fuzzer.c index 374d6e2cc..a147c6a7d 100644 --- a/plugins/uefi-dbx/fu-fuzzer.c +++ b/plugins/uefi-dbx/fu-fuzzer.c @@ -26,7 +26,7 @@ main (int argc, char *argv[]) g_printerr ("Failed to load %s: %s\n", argv[1], error->message); return EXIT_FAILURE; } - siglists = fu_efi_signature_parser_all (buf, bufsz, + siglists = fu_efi_signature_parser_new (buf, bufsz, FU_EFI_SIGNATURE_PARSER_FLAGS_IGNORE_HEADER, &error); if (siglists == NULL) { diff --git a/plugins/uefi-dbx/fu-plugin-uefi-dbx.c b/plugins/uefi-dbx/fu-plugin-uefi-dbx.c index 15444df90..9217a1602 100644 --- a/plugins/uefi-dbx/fu-plugin-uefi-dbx.c +++ b/plugins/uefi-dbx/fu-plugin-uefi-dbx.c @@ -10,6 +10,7 @@ #include "fu-efivar.h" #include "fu-hash.h" #include "fu-uefi-dbx-common.h" +#include "fu-efi-signature-common.h" #include "fu-efi-signature-parser.h" struct FuPluginData { @@ -45,13 +46,11 @@ void fu_plugin_add_security_attrs (FuPlugin *plugin, FuSecurityAttrs *attrs) { FuPluginData *data = fu_plugin_get_data (plugin); - GPtrArray *items; gsize bufsz = 0; - guint missing_cnt = 0; g_autofree guint8 *buf_system = NULL; g_autofree guint8 *buf_update = NULL; - g_autoptr(FuEfiSignatureList) dbx_system = NULL; - g_autoptr(FuEfiSignatureList) dbx_update = NULL; + g_autoptr(GPtrArray) dbx_system = NULL; + g_autoptr(GPtrArray) dbx_update = NULL; g_autoptr(FwupdSecurityAttr) attr = NULL; g_autoptr(GError) error_local = NULL; @@ -74,7 +73,7 @@ fu_plugin_add_security_attrs (FuPlugin *plugin, FuSecurityAttrs *attrs) fwupd_security_attr_set_result (attr, FWUPD_SECURITY_ATTR_RESULT_NOT_VALID); return; } - dbx_update = fu_efi_signature_parser_one (buf_update, bufsz, + dbx_update = fu_efi_signature_parser_new (buf_update, bufsz, FU_EFI_SIGNATURE_PARSER_FLAGS_IGNORE_HEADER, &error_local); if (dbx_update == NULL) { @@ -90,7 +89,7 @@ fu_plugin_add_security_attrs (FuPlugin *plugin, FuSecurityAttrs *attrs) fwupd_security_attr_set_result (attr, FWUPD_SECURITY_ATTR_RESULT_NOT_VALID); return; } - dbx_system = fu_efi_signature_parser_one (buf_system, bufsz, + dbx_system = fu_efi_signature_parser_new (buf_system, bufsz, FU_EFI_SIGNATURE_PARSER_FLAGS_NONE, &error_local); if (dbx_system == NULL) { @@ -100,18 +99,7 @@ fu_plugin_add_security_attrs (FuPlugin *plugin, FuSecurityAttrs *attrs) } /* look for each checksum in the update in the system version */ - items = fu_efi_signature_list_get_all (dbx_update); - for (guint i = 0; i < items->len; i++) { - FuEfiSignature *item = g_ptr_array_index (items, i); - if (!fu_efi_signature_list_has_checksum (dbx_system, fu_efi_signature_get_checksum (item))) { - g_debug ("%s missing from the system DBX", - fu_efi_signature_get_checksum (item)); - missing_cnt += 1; - } - } - - /* add security attribute */ - if (missing_cnt > 0) { + if (!fu_efi_signature_list_array_inclusive (dbx_system, dbx_update)) { fwupd_security_attr_set_result (attr, FWUPD_SECURITY_ATTR_RESULT_NOT_FOUND); return; } diff --git a/plugins/uefi-dbx/fu-self-test.c b/plugins/uefi-dbx/fu-self-test.c index 4a98c42b8..de8657b55 100644 --- a/plugins/uefi-dbx/fu-self-test.c +++ b/plugins/uefi-dbx/fu-self-test.c @@ -33,7 +33,7 @@ fu_efi_signature_list_parse_func (void) g_assert_true (ret); /* parse the update */ - siglists = fu_efi_signature_parser_all (buf, bufsz, + siglists = fu_efi_signature_parser_new (buf, bufsz, FU_EFI_SIGNATURE_PARSER_FLAGS_IGNORE_HEADER, &error); g_assert_no_error (error); diff --git a/plugins/uefi-dbx/meson.build b/plugins/uefi-dbx/meson.build index 14d66d635..8a8eb07a5 100644 --- a/plugins/uefi-dbx/meson.build +++ b/plugins/uefi-dbx/meson.build @@ -6,6 +6,7 @@ shared_module('fu_plugin_uefi_dbx', 'fu-plugin-uefi-dbx.c', 'fu-uefi-dbx-common.c', 'fu-efi-signature.c', + 'fu-efi-signature-common.c', 'fu-efi-signature-list.c', 'fu-efi-signature-parser.c', ], @@ -34,6 +35,7 @@ if get_option('tests') 'fu-self-test.c', 'fu-uefi-dbx-common.c', 'fu-efi-signature.c', + 'fu-efi-signature-common.c', 'fu-efi-signature-list.c', 'fu-efi-signature-parser.c', ], @@ -58,6 +60,7 @@ uefi_dbx_fuzzer = executable( sources : [ 'fu-fuzzer.c', 'fu-efi-signature.c', + 'fu-efi-signature-common.c', 'fu-efi-signature-list.c', 'fu-efi-signature-parser.c', ], @@ -81,6 +84,7 @@ dbxtool = executable( 'fu-dbxtool.c', 'fu-uefi-dbx-common.c', 'fu-efi-signature.c', + 'fu-efi-signature-common.c', 'fu-efi-signature-list.c', 'fu-efi-signature-parser.c', ], From 01d5779597ba0a43af6aa5ab654988ad4cb29597 Mon Sep 17 00:00:00 2001 From: Richard Hughes Date: Thu, 13 Aug 2020 17:42:19 +0100 Subject: [PATCH 324/607] uefi-dbx: Allow updating the dbx using the LVFS The GUID is built using the SHA256 of the certificates in the KEK. --- plugins/uefi-dbx/README.md | 35 ++++- plugins/uefi-dbx/fu-dbxtool.c | 21 +-- plugins/uefi-dbx/fu-efi-signature-common.c | 22 +++ plugins/uefi-dbx/fu-efi-signature-common.h | 1 + plugins/uefi-dbx/fu-efi-signature.c | 12 ++ plugins/uefi-dbx/fu-efi-signature.h | 5 + plugins/uefi-dbx/fu-plugin-uefi-dbx.c | 41 +++--- plugins/uefi-dbx/fu-uefi-dbx-device.c | 148 +++++++++++++++++++++ plugins/uefi-dbx/fu-uefi-dbx-device.h | 14 ++ plugins/uefi-dbx/meson.build | 1 + 10 files changed, 267 insertions(+), 33 deletions(-) create mode 100644 plugins/uefi-dbx/fu-uefi-dbx-device.c create mode 100644 plugins/uefi-dbx/fu-uefi-dbx-device.h diff --git a/plugins/uefi-dbx/README.md b/plugins/uefi-dbx/README.md index 297fadee7..3607a8d19 100644 --- a/plugins/uefi-dbx/README.md +++ b/plugins/uefi-dbx/README.md @@ -4,5 +4,38 @@ UEFI dbx Support Introduction ------------ -This plugin checks if the UEFI dbx contains all the most recent revoked +Updating the UEFI revocation database prevents starting EFI binaries with known +security issues, and is typically no longer done from a firmware update due to +the risk of the machine being "bricked" if the bootloader is not updated first. + +This plugin also checks if the UEFI dbx contains all the most recent revoked checksums. The result will be stored in an security attribute for HSI. + +Firmware Format +--------------- + +The daemon will decompress the cabinet archive and extract a firmware blob in +EFI_SIGNATURE_LIST format. + +See https://www.uefi.org/sites/default/files/resources/UEFI%20Spec%202_6.pdf +for details. + +This plugin supports the following protocol ID: + + * org.uefi.dbx + +GUID Generation +--------------- + +These devices use the GUID constructed of the uppercase SHA256 of the X509 +certificates found in the system KEK and optionally the EFI architecture. e.g. + + * `UEFI\CRT_{sha256}` + * `UEFI\CRT_{sha256}&ARCH_{arch}` + +...where `arch` is typically one of `IA32`, `X64`, `ARM` or `AA64` + +Vendor ID Security +------------------ + +The vendor ID is hardcoded to `UEFI:Microsoft` for all devices. diff --git a/plugins/uefi-dbx/fu-dbxtool.c b/plugins/uefi-dbx/fu-dbxtool.c index 819c47a6c..a77d633a5 100644 --- a/plugins/uefi-dbx/fu-dbxtool.c +++ b/plugins/uefi-dbx/fu-dbxtool.c @@ -28,14 +28,6 @@ fu_util_ignore_cb (const gchar *log_domain, GLogLevelFlags log_level, { } -static const gchar * -fu_dbxtool_convert_guid (const gchar *guid) -{ - if (g_strcmp0 (guid, "77fa9abd-0359-4d32-bd60-28f4e78f784b") == 0) - return "microsoft"; - return guid; -} - static GPtrArray * fu_dbxtool_get_siglist_system (GError **error) { @@ -66,6 +58,7 @@ main (int argc, char *argv[]) { gboolean action_apply = FALSE; gboolean action_list = FALSE; + gboolean action_version = FALSE; gboolean force = FALSE; gboolean verbose = FALSE; g_autofree gchar *dbxfile = NULL; @@ -76,6 +69,9 @@ main (int argc, char *argv[]) { "verbose", 'v', 0, G_OPTION_ARG_NONE, &verbose, /* TRANSLATORS: command line option */ _("Show extra debugging information"), NULL }, + { "version", '\0', 0, G_OPTION_ARG_NONE, &action_version, + /* TRANSLATORS: command line option */ + _("Show the calculated version of the dbx"), NULL }, { "list", 'l', 0, G_OPTION_ARG_NONE, &action_list, /* TRANSLATORS: command line option */ _("List entries in dbx"), NULL }, @@ -122,7 +118,7 @@ main (int argc, char *argv[]) } /* list contents, either of the existing system, or an update */ - if (action_list) { + if (action_list || action_version) { guint cnt = 1; g_autoptr(GPtrArray) dbx = NULL; if (dbxfile != NULL) { @@ -140,6 +136,11 @@ main (int argc, char *argv[]) return EXIT_FAILURE; } } + if (action_version) { + /* TRANSLATORS: the detected version number of the dbx */ + g_print ("%s: %u\n", _("Version"), fu_efi_signature_list_array_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); @@ -147,7 +148,7 @@ main (int argc, char *argv[]) FuEfiSignature *sig = g_ptr_array_index (sigs, i); g_print ("%4u: {%s} {%s} %s\n", cnt++, - fu_dbxtool_convert_guid (fu_efi_signature_get_owner (sig)), + 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)); } diff --git a/plugins/uefi-dbx/fu-efi-signature-common.c b/plugins/uefi-dbx/fu-efi-signature-common.c index 1c70d7ea5..00d43fe7f 100644 --- a/plugins/uefi-dbx/fu-efi-signature-common.c +++ b/plugins/uefi-dbx/fu-efi-signature-common.c @@ -35,3 +35,25 @@ fu_efi_signature_list_array_inclusive (GPtrArray *outer, GPtrArray *inner) } 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; +} diff --git a/plugins/uefi-dbx/fu-efi-signature-common.h b/plugins/uefi-dbx/fu-efi-signature-common.h index b9761110e..48a89c64b 100644 --- a/plugins/uefi-dbx/fu-efi-signature-common.h +++ b/plugins/uefi-dbx/fu-efi-signature-common.h @@ -10,3 +10,4 @@ gboolean fu_efi_signature_list_array_inclusive (GPtrArray *outer, GPtrArray *inner); +guint fu_efi_signature_list_array_version (GPtrArray *siglists); diff --git a/plugins/uefi-dbx/fu-efi-signature.c b/plugins/uefi-dbx/fu-efi-signature.c index bc33bbc0d..3987d3d49 100644 --- a/plugins/uefi-dbx/fu-efi-signature.c +++ b/plugins/uefi-dbx/fu-efi-signature.c @@ -29,6 +29,18 @@ fu_efi_signature_kind_to_string (FuEfiSignatureKind kind) return "unknown"; } +const gchar * +fu_efi_signature_guid_to_string (const gchar *guid) +{ + if (g_strcmp0 (guid, FU_EFI_SIGNATURE_GUID_ZERO) == 0) + return "zero"; + if (g_strcmp0 (guid, FU_EFI_SIGNATURE_GUID_MICROSOFT) == 0) + return "microsoft"; + if (g_strcmp0 (guid, FU_EFI_SIGNATURE_GUID_OVMF) == 0) + return "ovmf"; + return guid; +} + FuEfiSignature * fu_efi_signature_new (FuEfiSignatureKind kind, const gchar *owner, GBytes *data) { diff --git a/plugins/uefi-dbx/fu-efi-signature.h b/plugins/uefi-dbx/fu-efi-signature.h index 9aebf0abd..352e1fc05 100644 --- a/plugins/uefi-dbx/fu-efi-signature.h +++ b/plugins/uefi-dbx/fu-efi-signature.h @@ -18,7 +18,12 @@ typedef enum { FU_EFI_SIGNATURE_KIND_LAST } FuEfiSignatureKind; +#define FU_EFI_SIGNATURE_GUID_ZERO "00000000-0000-0000-0000-000000000000" +#define FU_EFI_SIGNATURE_GUID_MICROSOFT "77fa9abd-0359-4d32-bd60-28f4e78f784b" +#define FU_EFI_SIGNATURE_GUID_OVMF "a0baa8a3-041d-48a8-bc87-c36d121b5e3d" + 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, diff --git a/plugins/uefi-dbx/fu-plugin-uefi-dbx.c b/plugins/uefi-dbx/fu-plugin-uefi-dbx.c index 9217a1602..1d3d689e8 100644 --- a/plugins/uefi-dbx/fu-plugin-uefi-dbx.c +++ b/plugins/uefi-dbx/fu-plugin-uefi-dbx.c @@ -9,43 +9,32 @@ #include "fu-plugin-vfuncs.h" #include "fu-efivar.h" #include "fu-hash.h" -#include "fu-uefi-dbx-common.h" #include "fu-efi-signature-common.h" #include "fu-efi-signature-parser.h" - -struct FuPluginData { - gchar *fn; -}; +#include "fu-uefi-dbx-common.h" +#include "fu-uefi-dbx-device.h" void fu_plugin_init (FuPlugin *plugin) { - fu_plugin_alloc_data (plugin, sizeof (FuPluginData)); fu_plugin_set_build_hash (plugin, FU_BUILD_HASH); } -void -fu_plugin_destroy (FuPlugin *plugin) -{ - FuPluginData *data = fu_plugin_get_data (plugin); - g_free (data->fn); -} - gboolean -fu_plugin_startup (FuPlugin *plugin, GError **error) +fu_plugin_coldplug (FuPlugin *plugin, GError **error) { - FuPluginData *data = fu_plugin_get_data (plugin); - data->fn = fu_uefi_dbx_get_dbxupdate (error); - if (data->fn == NULL) + g_autoptr(FuUefiDbxDevice) device = fu_uefi_dbx_device_new (); + if (!fu_device_probe (FU_DEVICE (device), error)) return FALSE; - g_debug ("using %s", data->fn); + if (!fu_device_setup (FU_DEVICE (device), error)) + return FALSE; + fu_plugin_device_add (plugin, FU_DEVICE (device)); return TRUE; } void fu_plugin_add_security_attrs (FuPlugin *plugin, FuSecurityAttrs *attrs) { - FuPluginData *data = fu_plugin_get_data (plugin); gsize bufsz = 0; g_autofree guint8 *buf_system = NULL; g_autofree guint8 *buf_update = NULL; @@ -53,6 +42,14 @@ fu_plugin_add_security_attrs (FuPlugin *plugin, FuSecurityAttrs *attrs) g_autoptr(GPtrArray) dbx_update = NULL; g_autoptr(FwupdSecurityAttr) attr = NULL; g_autoptr(GError) error_local = NULL; + g_autofree gchar *fn = NULL; + + /* find the latest DBX on the system */ + fn = fu_uefi_dbx_get_dbxupdate (&error_local); + if (fn == NULL) { + g_warning ("cannot find any updates: %s", error_local->message); + return; + } /* create attr */ attr = fwupd_security_attr_new (FWUPD_SECURITY_ATTR_ID_UEFI_DBX); @@ -68,8 +65,8 @@ fu_plugin_add_security_attrs (FuPlugin *plugin, FuSecurityAttrs *attrs) } /* get update dbx */ - if (!g_file_get_contents (data->fn, (gchar **) &buf_update, &bufsz, &error_local)) { - g_warning ("failed to load %s: %s", data->fn, error_local->message); + if (!g_file_get_contents (fn, (gchar **) &buf_update, &bufsz, &error_local)) { + g_warning ("failed to load %s: %s", fn, error_local->message); fwupd_security_attr_set_result (attr, FWUPD_SECURITY_ATTR_RESULT_NOT_VALID); return; } @@ -77,7 +74,7 @@ fu_plugin_add_security_attrs (FuPlugin *plugin, FuSecurityAttrs *attrs) FU_EFI_SIGNATURE_PARSER_FLAGS_IGNORE_HEADER, &error_local); if (dbx_update == NULL) { - g_warning ("failed to parse %s: %s", data->fn, error_local->message); + g_warning ("failed to parse %s: %s", fn, error_local->message); fwupd_security_attr_set_result (attr, FWUPD_SECURITY_ATTR_RESULT_NOT_VALID); return; } diff --git a/plugins/uefi-dbx/fu-uefi-dbx-device.c b/plugins/uefi-dbx/fu-uefi-dbx-device.c new file mode 100644 index 000000000..92e4c6d42 --- /dev/null +++ b/plugins/uefi-dbx/fu-uefi-dbx-device.c @@ -0,0 +1,148 @@ +/* + * Copyright (C) 2020 Richard Hughes + * + * SPDX-License-Identifier: LGPL-2.1+ + */ + +#include "config.h" + +#include "fu-efivar.h" + +#include "fu-efi-signature-common.h" +#include "fu-efi-signature-parser.h" +#include "fu-uefi-dbx-device.h" + +struct _FuUefiDbxDevice { + FuDevice parent_instance; +}; + +G_DEFINE_TYPE (FuUefiDbxDevice, fu_uefi_dbx_device, FU_TYPE_DEVICE) + +static gboolean +fu_uefi_dbx_device_write_firmware (FuDevice *device, + FuFirmware *firmware, + FwupdInstallFlags install_flags, + GError **error) +{ + const guint8 *buf; + gsize bufsz = 0; + g_autoptr(GBytes) fw = NULL; + + /* get default image */ + fw = fu_firmware_get_image_default_bytes (firmware, error); + if (fw == NULL) + return FALSE; + + /* write entire chunk to efivarfs */ + fu_device_set_status (device, FWUPD_STATUS_DEVICE_WRITE); + buf = g_bytes_get_data (fw, &bufsz); + 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)) { + return FALSE; + } + + /* success! */ + return TRUE; +} + +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; + + /* 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)) + return FALSE; + dbx = fu_efi_signature_parser_new (buf, bufsz, + FU_EFI_SIGNATURE_PARSER_FLAGS_NONE, + error); + if (dbx == NULL) + 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); + return TRUE; +} + +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; + + /* 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)) + return FALSE; + kek = fu_efi_signature_parser_new (buf, bufsz, + FU_EFI_SIGNATURE_PARSER_FLAGS_NONE, + error); + if (kek == NULL) + 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; + + 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); + } + } + return fu_uefi_dbx_device_set_version_number (device, error); +} + +static void +fu_uefi_dbx_device_init (FuUefiDbxDevice *self) +{ + fu_device_set_physical_id (FU_DEVICE (self), "dbx"); + fu_device_set_name (FU_DEVICE (self), "UEFI dbx"); + fu_device_set_summary (FU_DEVICE (self), "UEFI Revocation Database"); + fu_device_set_vendor_id (FU_DEVICE (self), "UEFI:Linux Foundation"); + fu_device_set_protocol (FU_DEVICE (self), "org.uefi.dbx"); + fu_device_set_version_format (FU_DEVICE (self), FWUPD_VERSION_FORMAT_NUMBER); + fu_device_set_install_duration (FU_DEVICE (self), 1); + fu_device_add_icon (FU_DEVICE (self), "computer"); + fu_device_add_flag (FU_DEVICE (self), FWUPD_DEVICE_FLAG_INTERNAL); + fu_device_add_flag (FU_DEVICE (self), FWUPD_DEVICE_FLAG_NEEDS_REBOOT); + fu_device_add_parent_guid (FU_DEVICE (self), "main-system-firmware"); + if (!fu_common_is_live_media ()) + fu_device_add_flag (FU_DEVICE (self), FWUPD_DEVICE_FLAG_UPDATABLE); +} + +static void +fu_uefi_dbx_device_class_init (FuUefiDbxDeviceClass *klass) +{ + FuDeviceClass *klass_device = FU_DEVICE_CLASS (klass); + klass_device->probe = fu_uefi_dbx_device_probe; + klass_device->write_firmware = fu_uefi_dbx_device_write_firmware; +} + +FuUefiDbxDevice * +fu_uefi_dbx_device_new (void) +{ + FuUefiDbxDevice *self; + self = g_object_new (FU_TYPE_UEFI_DBX_DEVICE, NULL); + return self; +} diff --git a/plugins/uefi-dbx/fu-uefi-dbx-device.h b/plugins/uefi-dbx/fu-uefi-dbx-device.h new file mode 100644 index 000000000..48d71ecd7 --- /dev/null +++ b/plugins/uefi-dbx/fu-uefi-dbx-device.h @@ -0,0 +1,14 @@ +/* + * Copyright (C) 2020 Richard Hughes + * + * SPDX-License-Identifier: LGPL-2.1+ + */ + +#pragma once + +#include "fu-plugin.h" + +#define FU_TYPE_UEFI_DBX_DEVICE (fu_uefi_dbx_device_get_type ()) +G_DECLARE_FINAL_TYPE (FuUefiDbxDevice, fu_uefi_dbx_device, FU, UEFI_DBX_DEVICE, FuDevice) + +FuUefiDbxDevice *fu_uefi_dbx_device_new (void); diff --git a/plugins/uefi-dbx/meson.build b/plugins/uefi-dbx/meson.build index 8a8eb07a5..a257c6bdd 100644 --- a/plugins/uefi-dbx/meson.build +++ b/plugins/uefi-dbx/meson.build @@ -5,6 +5,7 @@ shared_module('fu_plugin_uefi_dbx', sources : [ 'fu-plugin-uefi-dbx.c', 'fu-uefi-dbx-common.c', + 'fu-uefi-dbx-device.c', 'fu-efi-signature.c', 'fu-efi-signature-common.c', 'fu-efi-signature-list.c', From 4e2768057bb649ab0037d0565d9e62d476112777 Mon Sep 17 00:00:00 2001 From: Darkovian Date: Fri, 14 Aug 2020 14:56:44 -0500 Subject: [PATCH 325/607] Update ata.quirk Added OUI\030302 to ata.quirk --- plugins/ata/ata.quirk | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/plugins/ata/ata.quirk b/plugins/ata/ata.quirk index dcfccb8c6..21a95cc0f 100644 --- a/plugins/ata/ata.quirk +++ b/plugins/ata/ata.quirk @@ -54,6 +54,10 @@ VendorId = ATA:0x2646 Vendor = Micron VendorId = ATA:0x1344 +[DeviceInstanceId=OUI\030302] +Vendor = SK hynix +VendorId = ATA:0x1C5C + [DeviceInstanceId=OUI\550380] Vendor = Kingston VendorId = ATA:0x2646 From 377cf823f359389863b0c959cd5640c34cff2294 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Piotr=20Dr=C4=85g?= Date: Sat, 15 Aug 2020 10:29:15 +0200 Subject: [PATCH 326/607] Update POTFILES.in --- po/POTFILES.in | 1 + 1 file changed, 1 insertion(+) diff --git a/po/POTFILES.in b/po/POTFILES.in index 95ac721db..3b44e8c43 100644 --- a/po/POTFILES.in +++ b/po/POTFILES.in @@ -3,6 +3,7 @@ data/remotes.d/lvfs-testing.metainfo.xml policy/org.freedesktop.fwupd.policy.in plugins/dfu/dfu-tool.c plugins/tpm-eventlog/fu-tpm-eventlog.c +plugins/uefi-dbx/fu-dbxtool.c plugins/uefi/fu-plugin-uefi.c plugins/uefi/fu-uefi-tool.c src/fu-agent.c From b81140de758c1a0c5f0346e17cc88e6da7459aa2 Mon Sep 17 00:00:00 2001 From: Richard Hughes Date: Mon, 17 Aug 2020 14:47:17 +0100 Subject: [PATCH 327/607] libfwupdplugin: Fix some NULL/FALSE confusion --- libfwupdplugin/fu-common.c | 10 +++++----- libfwupdplugin/fu-udev-device.c | 6 +++--- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/libfwupdplugin/fu-common.c b/libfwupdplugin/fu-common.c index bd66931e7..887a2c7d7 100644 --- a/libfwupdplugin/fu-common.c +++ b/libfwupdplugin/fu-common.c @@ -2175,7 +2175,7 @@ fu_common_get_volumes_by_kind (const gchar *kind, GError **error) } devices = fu_common_get_block_devices (connection, error); if (devices == NULL) - return FALSE; + return NULL; volumes = g_ptr_array_new_with_free_func ((GDestroyNotify) g_object_unref); for (guint i = 0; i < devices->len; i++) { const gchar *obj = g_ptr_array_index (devices, i); @@ -2193,7 +2193,7 @@ fu_common_get_volumes_by_kind (const gchar *kind, GError **error) NULL, error); if (proxy_part == NULL) { g_prefix_error (error, "failed to initialize d-bus proxy %s: ", obj); - return FALSE; + return NULL; } val = g_dbus_proxy_get_cached_property (proxy_part, "Type"); if (val == NULL) @@ -2211,7 +2211,7 @@ fu_common_get_volumes_by_kind (const gchar *kind, GError **error) NULL, error); if (proxy_file == NULL) { g_prefix_error (error, "failed to initialize d-bus proxy %s: ", obj); - return FALSE; + return NULL; } g_ptr_array_add (volumes, fu_volume_new_from_proxy (proxy_file)); } @@ -2250,7 +2250,7 @@ fu_common_get_esp_default (GError **error) volumes = fu_common_get_volumes_by_kind (FU_VOLUME_KIND_ESP, error); if (volumes == NULL) - return FALSE; + return NULL; for (guint i = 0; i < volumes->len; i++) { FuVolume *vol = g_ptr_array_index (volumes, i); g_ptr_array_add (fu_volume_is_mounted (vol) ? volumes_mtab : volumes_fstab, vol); @@ -2289,7 +2289,7 @@ fu_common_get_esp_for_path (const gchar *esp_path, GError **error) volumes = fu_common_get_volumes_by_kind (FU_VOLUME_KIND_ESP, error); if (volumes == NULL) - return FALSE; + return NULL; for (guint i = 0; i < volumes->len; i++) { FuVolume *vol = g_ptr_array_index (volumes, i); g_autofree gchar *vol_basename = g_path_get_basename (fu_volume_get_id (vol)); diff --git a/libfwupdplugin/fu-udev-device.c b/libfwupdplugin/fu-udev-device.c index 3444b8a83..a6a46af4f 100644 --- a/libfwupdplugin/fu-udev-device.c +++ b/libfwupdplugin/fu-udev-device.c @@ -1123,8 +1123,8 @@ fu_udev_device_get_sysfs_attr (FuUdevDevice *self, const gchar *attr, FuUdevDevicePrivate *priv = GET_PRIVATE (self); const gchar *result; - g_return_val_if_fail (FU_IS_UDEV_DEVICE (self), FALSE); - g_return_val_if_fail (attr != NULL, FALSE); + g_return_val_if_fail (FU_IS_UDEV_DEVICE (self), NULL); + g_return_val_if_fail (attr != NULL, NULL); /* nothing to do */ if (priv->udev_device == NULL) { @@ -1141,7 +1141,7 @@ fu_udev_device_get_sysfs_attr (FuUdevDevice *self, const gchar *attr, G_IO_ERROR_NOT_FOUND, "attribute %s returned no data", attr); - return FALSE; + return NULL; } return result; From 7bca1b27b4e0b7e8b98227368cc3bc99224ce1d7 Mon Sep 17 00:00:00 2001 From: Richard Hughes Date: Mon, 17 Aug 2020 14:47:30 +0100 Subject: [PATCH 328/607] acpi-dmar: Fix some NULL/FALSE confusion --- plugins/acpi-dmar/fu-acpi-dmar.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/plugins/acpi-dmar/fu-acpi-dmar.c b/plugins/acpi-dmar/fu-acpi-dmar.c index 582544c26..29c2fc8f0 100644 --- a/plugins/acpi-dmar/fu-acpi-dmar.c +++ b/plugins/acpi-dmar/fu-acpi-dmar.c @@ -35,29 +35,29 @@ fu_acpi_dmar_new (GBytes *blob, GError **error) if (!fu_memcpy_safe ((guint8 *) signature, sizeof(signature), 0x0, /* dst */ buf, bufsz, 0x00, /* src */ sizeof(signature) - 1, error)) - return FALSE; + return NULL; if (strcmp (signature, "DMAR") != 0) { g_set_error (error, G_IO_ERROR, G_IO_ERROR_NOT_SUPPORTED, "Not a DMAR table, got %s", signature); - return FALSE; + return NULL; } if (!fu_memcpy_safe ((guint8 *) oem_table_id, sizeof(oem_table_id), 0x0,/* dst */ buf, bufsz, 0x10, /* src */ sizeof(oem_table_id) - 1, error)) - return FALSE; + return NULL; g_debug ("OemTableId: %s", oem_table_id); if (!fu_memcpy_safe ((guint8 *) creator_id, sizeof(creator_id), 0x0, /* dst */ buf, bufsz, 0x1c, /* src */ sizeof(creator_id) - 1, error)) - return FALSE; + return NULL; g_debug ("CreatorId: %s", creator_id); if (!fu_memcpy_safe (&flags, sizeof(flags), 0x0, /* dst */ buf, bufsz, 0x25, /* src */ sizeof(flags), error)) - return FALSE; + return NULL; g_debug ("Flags: 0x%02x", flags); self->opt_in = (flags & DMAR_DMA_CTRL_PLATFORM_OPT_IN_FLAG) > 0; return self; From 1411b8056b0f60a6d03d0e3edeff65a90e16db3f Mon Sep 17 00:00:00 2001 From: Richard Hughes Date: Mon, 17 Aug 2020 14:47:42 +0100 Subject: [PATCH 329/607] acpi-facp: Fix some NULL/FALSE confusion --- plugins/acpi-facp/fu-acpi-facp.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugins/acpi-facp/fu-acpi-facp.c b/plugins/acpi-facp/fu-acpi-facp.c index 0adc47271..9aa776f51 100644 --- a/plugins/acpi-facp/fu-acpi-facp.c +++ b/plugins/acpi-facp/fu-acpi-facp.c @@ -30,7 +30,7 @@ fu_acpi_facp_new (GBytes *blob, GError **error) /* parse table */ if (!fu_common_read_uint32_safe (buf, bufsz, 0x70, &flags, G_LITTLE_ENDIAN, error)) - return FALSE; + return NULL; g_debug ("Flags: 0x%04x", flags); self->get_s2i = (flags & LOW_POWER_S0_IDLE_CAPABLE) > 0; return self; From 0e7102c4f815977ba7e17f832afec77dd45b0ac1 Mon Sep 17 00:00:00 2001 From: Richard Hughes Date: Mon, 17 Aug 2020 14:47:58 +0100 Subject: [PATCH 330/607] uefi-dbx: Fix some NULL/FALSE confusion --- plugins/uefi-dbx/fu-dbxtool.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/plugins/uefi-dbx/fu-dbxtool.c b/plugins/uefi-dbx/fu-dbxtool.c index a77d633a5..a18665a7f 100644 --- a/plugins/uefi-dbx/fu-dbxtool.c +++ b/plugins/uefi-dbx/fu-dbxtool.c @@ -35,7 +35,7 @@ fu_dbxtool_get_siglist_system (GError **error) g_autofree guint8 *buf = NULL; if (!fu_efivar_get_data (FU_EFIVAR_GUID_SECURITY_DATABASE, "dbx", &buf, &bufsz, NULL, error)) - return FALSE; + return NULL; return fu_efi_signature_parser_new (buf, bufsz, FU_EFI_SIGNATURE_PARSER_FLAGS_NONE, error); @@ -47,7 +47,7 @@ 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)) - return FALSE; + return NULL; return fu_efi_signature_parser_new (buf, bufsz, FU_EFI_SIGNATURE_PARSER_FLAGS_IGNORE_HEADER, error); From bfe6c7754948ea3e3e3ad8b9db56461e15ac9d92 Mon Sep 17 00:00:00 2001 From: Richard Hughes Date: Mon, 17 Aug 2020 14:48:23 +0100 Subject: [PATCH 331/607] trivial: Fix some NULL/FALSE confusion in the daemon --- src/fu-main.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/fu-main.c b/src/fu-main.c index 3f5cce94b..c19edba38 100644 --- a/src/fu-main.c +++ b/src/fu-main.c @@ -233,7 +233,7 @@ fu_main_create_request (FuMainPrivate *priv, const gchar *sender, GError **error error); if (value == NULL) { g_prefix_error (error, "failed to read user id of caller: "); - return FALSE; + return NULL; } g_variant_get (value, "(u)", &calling_uid); if (calling_uid == 0) From adabe53e2b57644907de97e17531a0ebc5881426 Mon Sep 17 00:00:00 2001 From: Richard Hughes Date: Mon, 17 Aug 2020 14:48:30 +0100 Subject: [PATCH 332/607] trivial: Fix some NULL/FALSE confusion when getting the HSI --- src/fu-util.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/fu-util.c b/src/fu-util.c index bff5163a1..615a827b9 100644 --- a/src/fu-util.c +++ b/src/fu-util.c @@ -2034,7 +2034,7 @@ fu_util_get_remote_with_security_report_uri (FuUtilPrivate *priv, GError **error FWUPD_ERROR, FWUPD_ERROR_NOT_SUPPORTED, "No remotes specified SecurityReportURI"); - return FALSE; + return NULL; } static gboolean From 1abb32c623d14581452c3e11bf238b498347b25f Mon Sep 17 00:00:00 2001 From: Richard Hughes Date: Mon, 17 Aug 2020 14:13:54 +0100 Subject: [PATCH 333/607] uefi-dbx: Validate the dbx update is safe to apply To do this mount all ESP partitions and check all the binaries there to see if they match any entries in the new dbx. If we applied the update when a hash matched, we would unintentially 'brick' the users machine, as the grub and shim binaries *have* to be updated first. This functionality does reimplement the PE hashing functionality found in sbsigntools and pesign. This was done for 4 main reasons: * There were some memory safety issues found when fuzzing random binaries * Executing the tools hundreds of times was a lot of overhead * Operating from a blob of immutable mmap'd memory is much faster * We only need a very small amount of functionality from both tools --- plugins/uefi-dbx/fu-dbxtool.c | 12 + plugins/uefi-dbx/fu-efi-image.c | 332 +++++++++++++++++++++ plugins/uefi-dbx/fu-efi-image.h | 16 + plugins/uefi-dbx/fu-efi-signature-common.c | 2 +- plugins/uefi-dbx/fu-efi-signature-common.h | 2 + plugins/uefi-dbx/fu-self-test.c | 33 ++ plugins/uefi-dbx/fu-uefi-dbx-common.c | 86 ++++++ plugins/uefi-dbx/fu-uefi-dbx-common.h | 6 +- plugins/uefi-dbx/fu-uefi-dbx-device.c | 36 +++ plugins/uefi-dbx/meson.build | 8 + plugins/uefi-dbx/tests/fwupdx64.efi | Bin 0 -> 65640 bytes 11 files changed, 531 insertions(+), 2 deletions(-) create mode 100644 plugins/uefi-dbx/fu-efi-image.c create mode 100644 plugins/uefi-dbx/fu-efi-image.h create mode 100755 plugins/uefi-dbx/tests/fwupdx64.efi diff --git a/plugins/uefi-dbx/fu-dbxtool.c b/plugins/uefi-dbx/fu-dbxtool.c index a18665a7f..2a9601e79 100644 --- a/plugins/uefi-dbx/fu-dbxtool.c +++ b/plugins/uefi-dbx/fu-dbxtool.c @@ -221,6 +221,18 @@ main (int argc, char *argv[]) return EXIT_FAILURE; } + /* validate this is safe to apply */ + 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)) { + /* 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); + return EXIT_FAILURE; + } + } + /* TRANSLATORS: actually sending the update to the hardware */ g_print ("%s\n", _("Applying update…")); if (!fu_efivar_set_data (FU_EFIVAR_GUID_SECURITY_DATABASE, diff --git a/plugins/uefi-dbx/fu-efi-image.c b/plugins/uefi-dbx/fu-efi-image.c new file mode 100644 index 000000000..31229316b --- /dev/null +++ b/plugins/uefi-dbx/fu-efi-image.c @@ -0,0 +1,332 @@ +/* + * Copyright (C) 2020 Richard Hughes + * + * SPDX-License-Identifier: LGPL-2.1+ + */ + +#include "config.h" + +#include "fu-common.h" +#include "fu-efi-image.h" + +struct _FuEfiImage { + GObject parent_instance; + gchar *checksum; +}; + +typedef struct { + gsize offset; + gsize size; + gchar *name; +} FuEfiImageRegion; + +typedef struct __attribute__((packed)) { + guint32 addr; + guint32 size; +} FuEfiImageDataDirEntry; + +G_DEFINE_TYPE (FuEfiImage, fu_efi_image, G_TYPE_OBJECT) + +#define _DOS_OFFSET_SIGNATURE 0x00 +#define _DOS_OFFSET_TO_PE_HEADER 0x3c + +#define _PEI_OFFSET_SIGNATURE 0x00 +#define _PEI_OFFSET_MACHINE 0x04 +#define _PEI_OFFSET_NUMBER_OF_SECTIONS 0x06 +#define _PEI_OFFSET_OPTIONAL_HEADER_SIZE 0x14 +#define _PEI_HEADER_SIZE 0x18 + +#define _PE_OFFSET_SIZE_OF_HEADERS 0x54 +#define _PE_OFFSET_CHECKSUM 0x58 +#define _PE_OFFSET_DEBUG_TABLE_OFFSET 0x98 + +#define _PEP_OFFSET_SIZE_OF_HEADERS 0x54 +#define _PEP_OFFSET_CHECKSUM 0x58 +#define _PEP_OFFSET_DEBUG_TABLE_OFFSET 0xa8 + +#define _SECTION_HEADER_OFFSET_NAME 0x0 +#define _SECTION_HEADER_OFFSET_SIZE 0x10 +#define _SECTION_HEADER_OFFSET_PTR 0x14 +#define _SECTION_HEADER_SIZE 0x28 + +#define IMAGE_FILE_MACHINE_AMD64 0x8664 +#define IMAGE_FILE_MACHINE_I386 0x014c +#define IMAGE_FILE_MACHINE_THUMB 0x01c2 +#define IMAGE_FILE_MACHINE_AARCH64 0xaa64 + +static gint +fu_efi_image_region_sort_cb (gconstpointer a, gconstpointer b) +{ + const FuEfiImageRegion *r1 = *((const FuEfiImageRegion **) a); + const FuEfiImageRegion *r2 = *((const FuEfiImageRegion **) b); + if (r1->offset < r2->offset) + return -1; + if (r1->offset > r2->offset) + return 1; + return 0; +} + +static FuEfiImageRegion * +fu_efi_image_add_region (GPtrArray *checksum_regions, + const gchar *name, + gsize offset_start, + gsize offset_end) +{ + FuEfiImageRegion *r = g_new0 (FuEfiImageRegion, 1); + r->name = g_strdup (name); + r->offset = offset_start; + r->size = offset_end - offset_start; + g_ptr_array_add (checksum_regions, r); + return r; +} + +static void +fu_efi_image_region_free (FuEfiImageRegion *r) +{ + g_free (r->name); + g_free (r); +} + +FuEfiImage * +fu_efi_image_new (GBytes *data, GError **error) +{ + FuEfiImageRegion *r; + const guint8 *buf; + gsize bufsz; + gsize image_bytes = 0; + gsize checksum_offset; + gsize data_dir_debug_offset; + gsize offset_tmp; + guint16 dos_sig = 0; + guint16 machine = 0; + guint16 opthdrsz; + guint16 sections; + guint32 baseaddr = 0; + guint32 cert_table_size; + guint32 header_size; + guint32 nt_sig = 0; + g_autoptr(FuEfiImage) self = g_object_new (FU_TYPE_EFI_IMAGE, NULL); + g_autoptr(GChecksum) checksum = g_checksum_new (G_CHECKSUM_SHA256); + g_autoptr(GPtrArray) checksum_regions = NULL; + + /* verify this is a DOS file */ + buf = g_bytes_get_data (data, &bufsz); + if (!fu_common_read_uint16_safe (buf, bufsz, + _DOS_OFFSET_SIGNATURE, + &dos_sig, G_LITTLE_ENDIAN, error)) + return NULL; + if (dos_sig != 0x5a4d) { + g_set_error (error, + G_IO_ERROR, + G_IO_ERROR_NOT_SUPPORTED, + "Invalid DOS header magic %04x", dos_sig); + return NULL; + } + + /* verify the PE signature */ + if (!fu_common_read_uint32_safe (buf, bufsz, + _DOS_OFFSET_TO_PE_HEADER, + &baseaddr, G_LITTLE_ENDIAN, error)) + return NULL; + if (!fu_common_read_uint32_safe (buf, bufsz, + baseaddr + _PEI_OFFSET_SIGNATURE, + &nt_sig, G_LITTLE_ENDIAN, error)) + return NULL; + if (nt_sig != 0x4550) { + g_set_error (error, + G_IO_ERROR, + G_IO_ERROR_NOT_SUPPORTED, + "Invalid PE header signature %08x", nt_sig); + return NULL; + } + + /* which machine type are we reading */ + if (!fu_common_read_uint16_safe (buf, bufsz, + baseaddr + _PEI_OFFSET_MACHINE, + &machine, G_LITTLE_ENDIAN, error)) + return NULL; + if (machine == IMAGE_FILE_MACHINE_AMD64 || + machine == IMAGE_FILE_MACHINE_AARCH64) { + + /* a.out header directly follows PE header */ + if (!fu_common_read_uint16_safe (buf, bufsz, + baseaddr + _PEI_HEADER_SIZE, + &machine, G_LITTLE_ENDIAN, error)) + return NULL; + if (machine != 0x020b) { + g_set_error (error, + G_IO_ERROR, + G_IO_ERROR_NOT_SUPPORTED, + "Invalid a.out machine type %04x", machine); + return NULL; + } + if (!fu_common_read_uint32_safe (buf, bufsz, + baseaddr + _PEP_OFFSET_SIZE_OF_HEADERS, + &header_size, G_LITTLE_ENDIAN, error)) + return NULL; + + checksum_offset = baseaddr + _PEP_OFFSET_CHECKSUM; + + /* now, this is odd. sbsigntools seems to think that we're + * skipping the CertificateTable -- but we actually seems to be + * ignoring Debug instead */ + data_dir_debug_offset = baseaddr + _PEP_OFFSET_DEBUG_TABLE_OFFSET; + + } else if (machine == IMAGE_FILE_MACHINE_I386 || + machine == IMAGE_FILE_MACHINE_THUMB) { + + /* a.out header directly follows PE header */ + if (!fu_common_read_uint16_safe (buf, bufsz, + baseaddr + _PEI_HEADER_SIZE, + &machine, G_LITTLE_ENDIAN, error)) + return NULL; + if (machine != 0x010b) { + g_set_error (error, + G_IO_ERROR, + G_IO_ERROR_NOT_SUPPORTED, + "Invalid a.out machine type %04x", machine); + return NULL; + } + if (!fu_common_read_uint32_safe (buf, bufsz, + baseaddr + _PE_OFFSET_SIZE_OF_HEADERS, + &header_size, G_LITTLE_ENDIAN, error)) + return NULL; + + checksum_offset = baseaddr + _PE_OFFSET_CHECKSUM; + data_dir_debug_offset = baseaddr + _PE_OFFSET_DEBUG_TABLE_OFFSET; + + } else { + g_set_error (error, + G_IO_ERROR, + G_IO_ERROR_NOT_SUPPORTED, + "Invalid PE header machine %04x", machine); + return NULL; + } + + /* get sections */ + if (!fu_common_read_uint32_safe (buf, bufsz, + data_dir_debug_offset + sizeof(guint32), + &cert_table_size, G_LITTLE_ENDIAN, error)) + return NULL; + if (!fu_common_read_uint16_safe (buf, bufsz, + baseaddr + _PEI_OFFSET_NUMBER_OF_SECTIONS, + §ions, G_LITTLE_ENDIAN, error)) + return NULL; + g_debug ("number_of_sections: %u", sections); + + /* get header size */ + if (!fu_common_read_uint16_safe (buf, bufsz, + baseaddr + _PEI_OFFSET_OPTIONAL_HEADER_SIZE, + &opthdrsz, G_LITTLE_ENDIAN, error)) + return NULL; + g_debug ("optional_header_size: 0x%x", opthdrsz); + + /* first region: beginning to checksum_offset field */ + checksum_regions = g_ptr_array_new_with_free_func ((GDestroyNotify) fu_efi_image_region_free); + r = fu_efi_image_add_region (checksum_regions, "begin->cksum", 0x0, checksum_offset); + image_bytes += r->size + sizeof(guint32); + + /* second region: end of checksum_offset to certificate table entry */ + r = fu_efi_image_add_region (checksum_regions, "cksum->datadir[DEBUG]", + checksum_offset + sizeof(guint32), + data_dir_debug_offset); + image_bytes += r->size + sizeof(FuEfiImageDataDirEntry); + + /* third region: end of checksum_offset to end of headers */ + r = fu_efi_image_add_region (checksum_regions, "datadir[DEBUG]->headers", + data_dir_debug_offset + sizeof(FuEfiImageDataDirEntry), + header_size); + image_bytes += r->size; + + /* add COFF sections */ + offset_tmp = baseaddr + _PEI_HEADER_SIZE + opthdrsz; + for (guint i = 0; i < sections; i++) { + guint32 file_offset = 0; + guint32 file_size = 0; + gchar name[9] = { '\0' }; + + if (!fu_common_read_uint32_safe (buf, bufsz, + offset_tmp + _SECTION_HEADER_OFFSET_PTR, + &file_offset, G_LITTLE_ENDIAN, error)) + return NULL; + if (!fu_common_read_uint32_safe (buf, bufsz, + offset_tmp + _SECTION_HEADER_OFFSET_SIZE, + &file_size, G_LITTLE_ENDIAN, error)) + return NULL; + if (file_size == 0) + continue; + if (!fu_memcpy_safe ((guint8 *) name, sizeof(name), 0x0, /* dst */ + buf, bufsz, + offset_tmp + _SECTION_HEADER_OFFSET_NAME, /* src */ + sizeof(name) - 1, error)) + return NULL; + r = fu_efi_image_add_region (checksum_regions, name, file_offset, file_offset + file_size); + image_bytes += r->size; + + if (file_offset + r->size > bufsz) { + g_set_error (error, + G_IO_ERROR, + G_IO_ERROR_INVALID_DATA, + "file-aligned section %s extends beyond end of file", + r->name); + return NULL; + } + offset_tmp += _SECTION_HEADER_SIZE; + } + + /* make sure in order */ + g_ptr_array_sort (checksum_regions, fu_efi_image_region_sort_cb); + + /* for the data at the end of the image */ + if (image_bytes + cert_table_size < bufsz) { + fu_efi_image_add_region (checksum_regions, "endjunk", + image_bytes, bufsz - cert_table_size); + } else if (image_bytes + cert_table_size > bufsz) { + g_set_error (error, + G_IO_ERROR, + G_IO_ERROR_INVALID_DATA, + "checksum_offset areas outside image size"); + return NULL; + } + + /* calculate the checksum we would find in the dbx */ + for (guint i = 0; i < checksum_regions->len; i++) { + r = g_ptr_array_index (checksum_regions, i); + g_debug ("region %s: 0x%04x -> 0x%04x [0x%04x]", + r->name, + (guint) r->offset, + (guint) (r->offset + r->size - 1), + (guint) r->size); + g_checksum_update (checksum, + (const guchar *) buf + r->offset, + (gssize) r->size); + } + self->checksum = g_strdup (g_checksum_get_string (checksum)); + return g_steal_pointer (&self); +} + +const gchar * +fu_efi_image_get_checksum (FuEfiImage *self) +{ + return self->checksum; +} + +static void +fu_efi_image_finalize (GObject *obj) +{ + FuEfiImage *self = FU_EFI_IMAGE (obj); + g_free (self->checksum); + G_OBJECT_CLASS (fu_efi_image_parent_class)->finalize (obj); +} + +static void +fu_efi_image_class_init (FuEfiImageClass *klass) +{ + GObjectClass *object_class = G_OBJECT_CLASS (klass); + object_class->finalize = fu_efi_image_finalize; +} + +static void +fu_efi_image_init (FuEfiImage *self) +{ +} diff --git a/plugins/uefi-dbx/fu-efi-image.h b/plugins/uefi-dbx/fu-efi-image.h new file mode 100644 index 000000000..64aebad42 --- /dev/null +++ b/plugins/uefi-dbx/fu-efi-image.h @@ -0,0 +1,16 @@ +/* + * Copyright (C) 2020 Richard Hughes + * + * SPDX-License-Identifier: LGPL-2.1+ + */ + +#pragma once + +#include + +#define FU_TYPE_EFI_IMAGE (fu_efi_image_get_type ()) +G_DECLARE_FINAL_TYPE (FuEfiImage, fu_efi_image, FU, EFI_IMAGE, GObject) + +FuEfiImage *fu_efi_image_new (GBytes *data, + GError **error); +const gchar *fu_efi_image_get_checksum (FuEfiImage *self); diff --git a/plugins/uefi-dbx/fu-efi-signature-common.c b/plugins/uefi-dbx/fu-efi-signature-common.c index 00d43fe7f..825ac3266 100644 --- a/plugins/uefi-dbx/fu-efi-signature-common.c +++ b/plugins/uefi-dbx/fu-efi-signature-common.c @@ -9,7 +9,7 @@ #include "fu-efi-signature-common.h" #include "fu-efi-signature-list.h" -static gboolean +gboolean fu_efi_signature_list_array_has_checksum (GPtrArray *siglists, const gchar *checksum) { for (guint i = 0; i < siglists->len; i++) { diff --git a/plugins/uefi-dbx/fu-efi-signature-common.h b/plugins/uefi-dbx/fu-efi-signature-common.h index 48a89c64b..fe9511d1d 100644 --- a/plugins/uefi-dbx/fu-efi-signature-common.h +++ b/plugins/uefi-dbx/fu-efi-signature-common.h @@ -11,3 +11,5 @@ 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); diff --git a/plugins/uefi-dbx/fu-self-test.c b/plugins/uefi-dbx/fu-self-test.c index de8657b55..fb310e30f 100644 --- a/plugins/uefi-dbx/fu-self-test.c +++ b/plugins/uefi-dbx/fu-self-test.c @@ -8,9 +8,41 @@ #include +#include "fu-common.h" #include "fu-uefi-dbx-common.h" +#include "fu-efi-image.h" #include "fu-efi-signature-parser.h" +static gchar * +fu_test_get_filename (const gchar *filename) +{ + g_autofree gchar *path = NULL; + path = g_build_filename (TESTDATADIR, filename, NULL); + return fu_common_realpath (path, NULL); +} + +static void +fu_efi_image_func (void) +{ + const gchar *csum = NULL; + g_autofree gchar *fn = NULL; + g_autoptr(FuEfiImage) img = NULL; + g_autoptr(GBytes) bytes = NULL; + g_autoptr(GError) error = NULL; + + fn = fu_test_get_filename ("fwupdx64.efi"); + g_assert_nonnull (fn); + bytes = fu_common_get_contents_bytes (fn, &error); + g_assert_no_error (error); + g_assert_nonnull (bytes); + + img = fu_efi_image_new (bytes, &error); + g_assert_no_error (error); + g_assert_nonnull (img); + csum = fu_efi_image_get_checksum (img); + g_assert_cmpstr (csum, ==, "e99707d4378140c01eb3f867240d5cc9e237b126d3db0c3b4bbcd3da1720ddff"); +} + static void fu_efi_signature_list_parse_func (void) { @@ -55,6 +87,7 @@ main (int argc, char **argv) g_setenv ("G_MESSAGES_DEBUG", "all", TRUE); /* tests go here */ + g_test_add_func ("/uefi-dbx/image", fu_efi_image_func); g_test_add_func ("/uefi-dbx/file-parse", fu_efi_signature_list_parse_func); return g_test_run (); } diff --git a/plugins/uefi-dbx/fu-uefi-dbx-common.c b/plugins/uefi-dbx/fu-uefi-dbx-common.c index 2971e81a6..bdcd0a44a 100644 --- a/plugins/uefi-dbx/fu-uefi-dbx-common.c +++ b/plugins/uefi-dbx/fu-uefi-dbx-common.c @@ -7,6 +7,10 @@ #include "config.h" #include "fu-common.h" +#include "fu-efi-image.h" +#include "fu-efi-signature-common.h" +#include "fu-volume.h" + #include "fu-uefi-dbx-common.h" gchar * @@ -26,3 +30,85 @@ fu_uefi_dbx_get_dbxupdate (GError **error) return NULL; return g_strdup (g_ptr_array_index (files, 0)); } + +gchar * +fu_uefi_dbx_get_authenticode_hash (const gchar *fn, GError **error) +{ + g_autoptr(FuEfiImage) img = NULL; + g_autoptr(GBytes) bytes = NULL; + g_autoptr(GMappedFile) mmap = NULL; + + g_debug ("getting Authenticode hash of %s", fn); + mmap = g_mapped_file_new (fn, FALSE, error); + if (mmap == NULL) + return NULL; + bytes = g_mapped_file_get_bytes (mmap); + + img = fu_efi_image_new (bytes, error); + if (img == NULL) + return NULL; + g_debug ("SHA256 was %s", fu_efi_image_get_checksum (img)); + return g_strdup (fu_efi_image_get_checksum (img)); +} + +static gboolean +fu_uefi_dbx_signature_list_validate_volume (GPtrArray *siglists, FuVolume *esp, GError **error) +{ + g_autofree gchar *esp_path = NULL; + g_autoptr(GPtrArray) files = NULL; + + /* get list of files contained in the ESP */ + esp_path = fu_volume_get_mount_point (esp); + if (esp_path == NULL) + return TRUE; + files = fu_common_get_files_recursive (esp_path, error); + if (files == NULL) + return FALSE; + + /* verify each file does not exist in the ESP */ + for (guint i = 0; i < files->len; i++) { + const gchar *fn = g_ptr_array_index (files, i); + g_autofree gchar *checksum = NULL; + g_autoptr(GError) error_local = NULL; + + /* get checksum of file */ + checksum = fu_uefi_dbx_get_authenticode_hash (fn, &error_local); + if (checksum == NULL) { + g_debug ("failed to get checksum for %s: %s", fn, error_local->message); + continue; + } + + /* Authenticode signature is present in dbx! */ + g_debug ("fn=%s, checksum=%s", fn, checksum); + if (fu_efi_signature_list_array_has_checksum (siglists, checksum)) { + g_set_error (error, + G_IO_ERROR, + G_IO_ERROR_INVALID_DATA, + "%s Authenticode checksum [%s] is present in dbx", + fn, checksum); + return FALSE; + } + } + + /* success */ + return TRUE; +} + +gboolean +fu_uefi_dbx_signature_list_validate (GPtrArray *siglists, GError **error) +{ + g_autoptr(GPtrArray) volumes = NULL; + volumes = fu_common_get_volumes_by_kind (FU_VOLUME_KIND_ESP, error); + if (volumes == NULL) + return FALSE; + for (guint i = 0; i < volumes->len; i++) { + FuVolume *esp = g_ptr_array_index (volumes, i); + g_autoptr(FuDeviceLocker) locker = NULL; + locker = fu_volume_locker (esp, error); + if (locker == NULL) + return FALSE; + if (!fu_uefi_dbx_signature_list_validate_volume (siglists, esp, error)) + return FALSE; + } + return TRUE; +} diff --git a/plugins/uefi-dbx/fu-uefi-dbx-common.h b/plugins/uefi-dbx/fu-uefi-dbx-common.h index fd4243217..de33f8805 100644 --- a/plugins/uefi-dbx/fu-uefi-dbx-common.h +++ b/plugins/uefi-dbx/fu-uefi-dbx-common.h @@ -8,4 +8,8 @@ #include -gchar *fu_uefi_dbx_get_dbxupdate (GError **error); +gchar *fu_uefi_dbx_get_dbxupdate (GError **error); +gchar *fu_uefi_dbx_get_authenticode_hash (const gchar *fn, + GError **error); +gboolean fu_uefi_dbx_signature_list_validate (GPtrArray *siglists, + GError **error); diff --git a/plugins/uefi-dbx/fu-uefi-dbx-device.c b/plugins/uefi-dbx/fu-uefi-dbx-device.c index 92e4c6d42..3236a1be2 100644 --- a/plugins/uefi-dbx/fu-uefi-dbx-device.c +++ b/plugins/uefi-dbx/fu-uefi-dbx-device.c @@ -10,6 +10,7 @@ #include "fu-efi-signature-common.h" #include "fu-efi-signature-parser.h" +#include "fu-uefi-dbx-common.h" #include "fu-uefi-dbx-device.h" struct _FuUefiDbxDevice { @@ -75,6 +76,40 @@ fu_uefi_dbx_device_set_version_number (FuDevice *device, GError **error) return TRUE; } +static FuFirmware * +fu_uefi_dbx_prepare_firmware (FuDevice *device, + GBytes *fw, + FwupdInstallFlags flags, + GError **error) +{ + const guint8 *buf; + gsize bufsz = 0; + g_autoptr(GPtrArray) siglists = NULL; + + /* parse dbx */ + fu_device_set_status (device, FWUPD_STATUS_DECOMPRESSING); + 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) + 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)) { + g_prefix_error (error, + "Blocked executable in the ESP, " + "ensure grub and shim are up to date: "); + return NULL; + } + } + + /* default blob */ + return fu_firmware_new_from_bytes (fw); +} + static gboolean fu_uefi_dbx_device_probe (FuDevice *device, GError **error) { @@ -137,6 +172,7 @@ fu_uefi_dbx_device_class_init (FuUefiDbxDeviceClass *klass) FuDeviceClass *klass_device = FU_DEVICE_CLASS (klass); klass_device->probe = fu_uefi_dbx_device_probe; klass_device->write_firmware = fu_uefi_dbx_device_write_firmware; + klass_device->prepare_firmware = fu_uefi_dbx_prepare_firmware; } FuUefiDbxDevice * diff --git a/plugins/uefi-dbx/meson.build b/plugins/uefi-dbx/meson.build index a257c6bdd..6961dfab2 100644 --- a/plugins/uefi-dbx/meson.build +++ b/plugins/uefi-dbx/meson.build @@ -6,6 +6,7 @@ shared_module('fu_plugin_uefi_dbx', 'fu-plugin-uefi-dbx.c', 'fu-uefi-dbx-common.c', 'fu-uefi-dbx-device.c', + 'fu-efi-image.c', 'fu-efi-signature.c', 'fu-efi-signature-common.c', 'fu-efi-signature-list.c', @@ -29,12 +30,15 @@ shared_module('fu_plugin_uefi_dbx', ) if get_option('tests') + testdatadir = join_paths(meson.current_source_dir(), 'tests') + cargs += '-DTESTDATADIR="' + testdatadir + '"' e = executable( 'uefi-dbx-self-test', fu_hash, sources : [ 'fu-self-test.c', 'fu-uefi-dbx-common.c', + 'fu-efi-image.c', 'fu-efi-signature.c', 'fu-efi-signature-common.c', 'fu-efi-signature-list.c', @@ -52,6 +56,7 @@ if get_option('tests') fwupd, fwupdplugin, ], + c_args : cargs, ) test('uefi-dbx-self-test', e) endif @@ -60,10 +65,12 @@ 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, @@ -84,6 +91,7 @@ dbxtool = executable( sources : [ 'fu-dbxtool.c', 'fu-uefi-dbx-common.c', + 'fu-efi-image.c', 'fu-efi-signature.c', 'fu-efi-signature-common.c', 'fu-efi-signature-list.c', diff --git a/plugins/uefi-dbx/tests/fwupdx64.efi b/plugins/uefi-dbx/tests/fwupdx64.efi new file mode 100755 index 0000000000000000000000000000000000000000..8d38a5e8ede05b4e81f69b8749fcb3f44cfec933 GIT binary patch literal 65640 zcmeFadtg-6)i->SOdwoOP|&DY$9AYe5fUVtNYELQz!{i8G~5)GAP_;hq%Z@)8-tT5 zr{nm>)>>*?#i!bOt5R#jMa2X#0jn+G4ZH@taK=GJsoYfZ{eFAzGdI9K-}CnS>w5-f z&e^xM*IIk6wbx#IpOea~o3t!V(;WDAc52#MT={W}-yi-7qPX`t>w9a@b$jjHwHdzG z&YduO&LU^s!UZ=hoIcMvWBUC03;fROXE_%J<~!%icb1Q@cFtQcbJpNqy}G*;=&A}$ zn|WtfnR->z#$;&PeyvMpkIc*;YqulYP!-*{@@s!`ag%8$lCA{+0AkvIl%aJ`%Ko8S zg8Fx#x^Fb?Fafq`|82Pc4rX%sVE?RoKQnH_*Nrb}=b$8goLW`Q;Dxj1E|{TkXh9)) za7R)l+`6^gk%MPW_fN-t{)PD2hVNi}8}Lo~xV4&=!84c6pFVHS3^&-OY4{<$XOk-7 z)~&f)*e~JL^~O&w>XB*B;hXe9J@=4dG9wR{I*b9~)oo6ygj?2Qzl)a6(+moq6ZJ^z zmgDQC=KOE!Kg|Inv@hq1D~-sA121)U8j+%XFKOCUS6^|ZRd%bUO}ox|594WsHs@@b zXqca%a)A-a&RdPVa8-^G)(o@4GR%qljrNKTqK4~E45rpzL7CG~`S}-E8UO1HBXZkL zBU1T>5kVvLYeXh?T!|Z}*F54iw;1L|Bhu@p{{utx7P>3|?88PF-^P~u?zrhNLWeW_ zHGp}84bu&n0SPk|-dBVd>37dF#G%&^!rYb)bCC@*Fy|%WY{mL%T5P(!{}A`#ifxT8 zf$^Y)#S-J}zu%*2Rls4>vCdAf+3JgAA3@H#K9F;C7(h?p;{CV?IKrG-4*(c?&y6{n zVi`?aH?1RYV%f$@Bct629m~3Xu--g6Q*WM})w(CA+csmyHlyUNTV2M$w~UPKdh_X_ zJRRuh59eKN9vk&#u$-JqaYdqI_uJcUWB-uWaY=1@ecq~GQMMKyl20~%@ z6Z9Bsm9;-+?KfrZZL)SoYVB`MMeScEv(ago-+Ik&jP`OD&6$QPAfhMS_0<}3Qj{Evh_Yx@`Z0jad@UH&l~#g68%o#p?OjJJ4kb}e&-sITs91a z7wPxxMyfL6cfIN}KegWa9zzV-?_F8)uUor$OWO1X2MK_rdnQ$RCdh$$l8moGI}FsJ zyLl;EyE26h{Xv)*>9u4HK0&6E*~tO#K?aRMDd0RK;nbzVdE*om#$m+P%l<{X@v_|# z*{(RX-S1M{-Qk&V<1pFwa`rh{wjD0pe)sDX+-uktgP-U(dO0M&(!4FN(wvnW2G>1i zMUG*9Xgzxq7;9FL^ZxE@0aT0j6-x4;hIuLad1{Ye^dXhq*dCmU zZikvzLk^7avOH^u8)f0))_J_5%X4s@DlB8N*c5wBsAk|XBbo6n%Xl#>T3{)+ zyre;NtW!=WvYRO-4QFClJR8s(t>;=!giwx#HEfBy%C%GwU!9-fY3a zEZL+tJSimGeFzEvI-~L3`cq(RTR`32P;G1P5Qui6nvwDtmtnG^3LFs}%OU zrlau?Z@40_-CaP98gC9dR2f;E5gh@PeCC(dt5Do%0TRaZwj5P9e(pbwWvfvZ>xr4? zF`ro=%v)vS$Nn55ynO_5$80uhXIwe2-IRb4dlTdk#$3Y45{bRmZ$+yQt+IfoagI)w z#2T-843ZdZuW0%4)N%LMwpVPvY9@Z$cJwjU-czEj+B#?9a0up>_KMZ_&Y#>3MbBM6 z55LW*U{VbJZ16HY*?V2!&fmc3`3vGfM$E-^&~R z5jADv`C!@wP{8*fdh1#Q%znlS!QXYiOyTdm-l%%DwAvrAcAKnyrmP)iZR9A)xg53G z!F{fT5HtV{I1_@qu~EUBF=>u5o+obj1dZ@*tBl4@f3{Uq%6jPx*PBOTDjt*7x;v-a z7EaL{jnJkHy*V?~v8;5Ne|4!N@E%|~0&lftE^8Z^(b+aK)6q6E3u^GCHE$r%prx5X z)Zame(6ecG@lv$y7b&PW^nw`woZOVt@Y0dqP-nmmCF*X&6&YoyC z7p92VKO-B88D;`#(Aj*iZ2nu>yk~0j7Br`Q_L*OZu73~uOEdfWtMfGP5sHPN}_H;*XoF=I%9m+PrGDQL{bm^_e zZzXY!ElZoE@GpiPUe`;4zFvZkVdhO@*IfV|`!j|u6Cj>mPd-|?;EBHGwx@lO1>bo? z-*;I&)Mv&*A7up2_b&gQ)8>+MjnJ2w)|;@vUb78i0;=mAKJzo5dC1yP42Z)k%_vB_ zll`9~``;51q;Xx5)PGk&nr#!JPBEKhZ+HfE1wXea@A*@8t1Cx3_pS2kkfgyV94#A6QsXc!S)<&N|YtXvd2zzp90B(c~?Q?q8 zp&_Qm{d7LI(PQDl42GQ?xSEiMOUSoM$l0lQJPgQ~XaTOO()=F5_{gSO`tR@kgqPEb#~5qx|Mun&wgs=a(JdM#j2FNooyw&AY_nsG7*;g{xS`Cfw74cGmqF6~&yHCzv$B zm3w2RUhLp_ema4;X8+*cmKL?Bk^S zok{nvR)??4H8KtukurzD`M=$Y(HB7<=e3n(NZAzh#kywp%`!qQ8CZ(wiw~@*&JcZ0 z-IN6F>tuhTKrV=|t~5*^kOe36i41R?_D!C+36BO#>xYq}`PNx95L^&-ReV61AMD1` zDBoJaDTIZe5fa%)!4ra?>kIo_#Z)?P=*U_6oo}HAgeZRngy=mhFB1*?sSOTi12Q^;qn&*!Yd38K+ngKZi@sSlvT6Fv4yU^`# zWw(Q6xBrBKC8^$wa&X2I`mxF&QYk z!yDS1fyL~yC3WK?gFc0uOeXkmG{VJnx)vjDlxKvE-14v+@t>m4e~%t_akPY|zO+>| zfW4^pg|Vp4ejjtyy1f$9GbE-r!h|F-t=gHdnc5UklR(yno z^v>C9q&~xF-RrP+cNLkd1)i0tA+3@cm5VS(8m)UA<0GY?8d>lhF~z{Cv|#Wb^M)_C zPEV|rN@!>}h`y3pTNd94jJ(9iBQg5btpfl1p(07kH%{NN-+9AbX}&t^dUn=1jIg)$V}~zm)@pCN1NwqAj2FiYLVw80SAH6d<>~OKHXGrI zTi`;0VYjWdezOnjE;XOK*x^;O!=UVNd1{A`qOa&`z*SPh8FMyU&62Ig$W~+7ih?I> zueAWTvBA=3&{(@h*6uHBpPkx=hqcGQhbuRCR?Uv}d?~nTYldZ_W$ZPY+2>i0!a-?<4Q{tep$)Oqk`|%66Zi4S_jFV` zej$}`f5pnx2;H_;^Y<2<{B$s&$`$M(YZnrnx|i3&6=wJn;hb-SBfdg-P74&iIGQM- zc;i*LMvP+~(=yC=phUY-0fFoD!6oZ{atUGTsn>35%U;8lsL&!SbYq2uV9bkMkstf3 z-kjb1sHSaluNd((uhNc*o~sx)J&5_uW4`7y+kKejM6fSk0Bmptd4;=>YaoK>RE`6z zy7fsV3m9zhUlbfM31GE=yYX|q;VImOzR%Pf;Tobw8xTGR_{hP&{0fK&3@^zDH`=)a znG2PN*=g~aUzO9n{S-A?<29CyBP>Qd{HIBnFUQMbRiN=yRKGNywUb#`=YMJao{j*n zwHG3%uWb56yxwZmBc~0Nf|*rQuazNJkoB(r3ziIKyN^ZS>T`cDLh8?)ERplB9|QNH z)g3tuXFNL-A~!*>HP0Yl{{=;p@zY55qmQ5qx<+opb~HgS>|eR7)G)thgj&Yyp@^43 zm;>?pQz#(GZOY*?l)^nV5Iv5E9#qH}1Z?84BnQjg=S1c4R1o7+oixKFTfqO^| zGh~Z@;vOvyqhV5ur_e$uQZ&FxGqevO^{t@cFMqIUo+5TV zlIScxE{F(M>$bJvnb&;FOIfT~ZO>DHbVD4H;+{_~{x&Cpq?fLnei*TdUUkTEj#_!9Rknqk(D%wY^Ng&JS*YK z{MBc6T4$dR@qZkBGY1QiPOArUs0M$Xjw^selsPJ`pY>e+X{WAf{_G9lnr38t4Tg_< z7_S=C*>sroSw`cS%V4y5lmHF$@Bj&NtpI6HWZ3cgW)%S! zqCUpY=gRj*9GPN~y$-On&PnjGH#;$I^*!XW12j#=z6v)2#*ho=vCBxm`I7aAQn~Q= zqn(|?fW_Kvd;PtY1slmRfKBRddtcWAB$wldz|3_cCCIZR$h%WP)&pd0O9I*_K;UH1 z9w)T1654BWmq2meu`&qAhcFYB8J)551{M)w4f`5$yWqMbv@;4zm3}`3A;t{H9S8?@b~GU)DhM2xQ`iDB_ahPAI|{YW38D=da4)iA zA0*O$Vfr75^fIP5B+|Dq{d6L|l<5ZnsGK*ys;wQYp95QhkA4o|PjZNkpG0AFJ~}>0 zIkAY2JFYyen%A>p~XLEs;Gu(GdhDc$)BRJC@anKf6Ou@Mi6-?x4wF@Hf@L+g%xp z=VB!0XNp082aUX;&$F!n8gc=0LE*c;NYQJ^R`R1aPdFP9#)I%^&;lC)))-XvmBbc) zqBl=;HS7qCn2It%1JHXEExAh_b)lAij+^`oAP@X{v5N-Odm=yfKtcpjJ_qFjy!B-n z3Rfo)P}^k7R~0Hn|B3RXQo`4p$7SoyiU*go(i5x{7jYvzNh+3yW%r~5K>IEbH8%>4 z@Hp&KkAiDkL^zBXXTemS$0EIA8#KBKtrPN$dX=+p|G)_GGq-^ePvP%dt%D zSB=}??G6@RBMOUV$wERtI1)Guxe$5)9e^C$lYokqfDq)V*G7K}(2%R;N3*)atko<(nuBX#wyb5|O z9|0r_`BgH%V;S<-sqqV=5>)3(01A)IY1|sPC0vbJ!|nooJ_GZ1ZL|;-FkVEWCz?bT zL)IamMTJO6?b8XOI;U|*0A8$UkK%=BT-X9kzw*S}-;VyH7qh*D_eZ9G%Cz|knp}b= z65@+!1Eiui+Iodj5hoGa{t!x23|>N>ULnL~C{L3oN`a6$B?`~6-elB^>w}WDmsxOG zIsnR}1M-+H)a!ZHIg@qb@@VVhzm&o2T@Is{5j>Ku-*sjNWv1vduuE^=jw#}PBV&JO zhm?zQ6NiI}z5qZBMY}tWPldi_t}9b$?e{3GX#6}-5XIiPjjsm^+@BG$Ba9)CD?*7I z0l`!9zJAZ$sEVmN@HRtUf@wFRD7M9(B4od($$rPPC?e!k=Ko0MUxIu&2R5bTL$0*w z)fk!t{j$8LY}a`?$}deRS9bAQU@L5jFeY!K9$6A8%0k0(vsGf+!sg#%CQced&jje& zIjE)h+XcELRM~$H3XVc>N*(^br5Q*R-AsOGGtbb=xA`J7$fvJt*@Bl~U56f!cLPG0 zT+%%R{}tXs;7rUpSUr9@6=koZKIe;zP!)Qn@c;cSwp~99`APUeJ_bU*f=4p^eS=3b z{fJZ)bpQm6z*m=1{>SAB(YYIW(GQUmpT||fuUXKB0x1`I^H$G<3cVTAYxACoZoT;} z?As!}9h0fwHM_i9s|RPQP+0D&<4-YCt)J%T&2wD^dh<0dXL+|h<=xsug&O=`!Ua9)PxjtBep_CMoVTUpy>KOoJ#i(8J#Zz7-Ek#}-AE!A@3o;@GE4nf%5I*Get}cQQe|+1r9`)AU>wH< z$cX+VMITu|UOt}X+^bILvjq9+Vquqtpd4Kf2XPk)8pq;b-=aaJv4AuV0dA!6Qd~)6 z39h8E7+2DG39h8^Vq8gM5w4_h7_Ox8B3w!1P+Uo4A!$4+Vz(r$Mq=^!aFSJh0Wc7% zbj7XkJMKef^l+-J;QW>%j~>+I#B0@}Hi$qUW4i$i3Fturx}%qTRDumI6TKAe!?6?5 zku{WU)>P+8>G>EkBc*4fl%BueVpr^jiosh>p`^6QOvsUocafrxc!4oO2YW6R%*^gy z=ICD5rF&Ude>E!H8t-qTC?5+csutdL^VqIL5$;S;qXcU`gen~V{{H&Je4DvM4gYeK zVts<*z-}}=wR>6L?q&VDmz~zV?DXzsdELv-=w5cFzb$4eKOjRw1!|+wGFn18;QYS( zW}C7h%s)3pK28c)ZS6p!r-icaNv0akz%^+Tn<%08^uM3p4`^oAc3 zj1cS^KmvA;OE3_a>eJQWok=)n0M1Q-gDQ8TN;C>-Xu@z88{zDin}`IW4*i~70b7qS zT)y1&hPhvh0mPtqkq0goZ%VS}wM{82X84ci@i@~o%(@PjM_+S|D^narJ%}mDm+=vf z&&*q&k%>vPw>`faq0ch>s9Bb2nC}}IoAl-i;d(9$eBw2~tQ@#Ecw2@HHb5+Pdd+LG zm3A2i(`R-hEqqZI^Ht%&!cH{tnMbV#Ogk~0minZkurv02LSHdi6n-q0_fEsa4wn&` z%gx_wTsg5Ejx%>Y47ot(KytR*hwhxJJ46!?$GT&l)7MmGVg;)==c>cGUj*xM&d4$b z9>$KUW0Osv2lMb@gh65S|4lo~7nzNf#+TN*)3|Ks*+7495jjA(pxrufI_KaHOeUUd zHzm;{j{V}4stUE{OR5@isODlAa4(`1_}_Ri&?|Zt(oHAB+c&VqhxsbE@LjY0bxc?AV}6H%r!q;k3|5ua?E;@ z>Ch%@cmu^lRxRv4quao;*@)coou~)#|GE*T@Nw1+qsP$Z{3H>wt{`2&B!;!}A*;+z zy^$*KIHv=V=IL9wu&|X_OfJs!Ms9al8KeY*=0j-SXMW9~J;rS~dehfbK)iw3m+j@* z+OkfEW|a%@Ut*lCU2G>MT8ysex}@=C0VMWX4801*C!qs5^h^?G{0{NV1BC1w>a+E0 zHy}ppd2Yn|Ekf>6n)HScxV6>+o_Qm;x_E8|NY(PJfhSVo@L*B_Ar%gz)yiQa%UTA^ zpqt3|v^yNcn_E6^*o$AmZx&Vp7Gr4x$KWezFJ3|yNPP-Mz+`ZL|7wf{#0E^Uz7)7n zpNef!Cb0==hCP`?eIYSCbqn3?rsOYUzrLmpDtAbjsmYGe?kr>AD@Nm1cp66&YWTKL z!|m21r;=>3MFN-f1Ba6!CRp2f5F<{vIkAbEn?=tUmWIAK?iJm2Xdp& zfGxByC({$(zz!d`@}W{aeyE;7U8-}8jg($yHQ{hHY#q2wN+E0i1kn((Sf2z(^)-`0 z@7sxo2)^KnyMU#y8J*cSIwJ#u3L(IA2-Yvq7-D8gF+(u%TBw1Yhz>*Kn|NV;!G|@z z!|1#YSu-FD=FcH*^nOKh%jqAg0+~Y)Uy@-1@<~4eD)Q0Pn8LrMDd#$Gq0X&bM z5K*5vPXoj8M=U(mln8GHOo6mRY^@Ivjh6<>m(f8swQ0-9r8aj4pzxaMkk>4lSj-`u zK$FaClMtIf-32hxqH}E)Is1NO0LL8b{a(4Fg!?x zC3BbXqQg_y+nlX{Y0(>)bfsn#eohMSTP`RxVy7wl8omgG<#Gc-hy)#x{aCbe3jN4v z{RE+b>?*Wjpb}?;CgkT(4dvi_u8sb!faa~7qtRTUBPdhZg*G34eI0@_nExD}a3vSS z#jMa9HwC=ug`0fd^u&#mH$8BZ$D8iB$>mKq+~n{k2jdIhbqu;<---{(;?4f$V^HxK z+I(|;6a1cPANM-;P4TvqY0wcE7WyP^A7(;>;^!9mxG`8iHZ*Pza0n3-1Z7LeOFZotif#xqPd^gq; z_5glb$u+Km#pkl`;z|>G@tG0sxf57_2pg6#q;F8q#HlQu_~%C<=La6!lg5K~Tdehg8MB|NU9D5>B-mo?Bn#XJv$8A_) z@VUlwXx-&-{>E9)a<3b-AwaH`wU%CPIE#%NM5GnxmHmPHj+d;s#(O z_yXd^vpv4>H8Mt68NM>lQ*tT}>geTd;u#@W`pe)wk z;d;s~v>>6VKcSF1O_93WYBBbGHCEH1eRZ(B zv*0Rn(wVX@7ah@C#+)&MHVtNw$INEq2m;0-AArI9dBR7CG`LoY+GH|B!p$Klj#W$h zi4e89Ju)&!3`@9g?@DOPywKqx`d#N@EJGV{27Eud$j3oiAn-AQx3Ee+a|h2!H3b1z zo>r*8mQw}>I6riB$l}N3h+?xP)PiWvDeSR;kWV!tc;FlG3b?iIh97`u_ruu{fJNY? zv&so6sPmcoZ9TO86GIVU(8l6ey^QOk!GBBo=$(S>Rb&B2KQUObTG$7g0<(=HB*v%jP)LW~ z0Cz|OP5NEeK=vYaIJocV&Lv^!81gQoJhtRv=2HVW8Tk0Z-9anlv9oCf8q2kMeT@)C zHG;nsRPnU{X~K9W`IR!NPbB!AeFQUgTqf%==_^lB+FM0h@^B@QNO`vGIi zlH&{a?GBQbOph2KvFA|ofI~S&kY~$hJrM|F6_+4Sis!T>@%*D0TdEjD^EfG8CrFR& zmBK17(OzgS@}u8jUX}B%XL8{Vxc39F@RLyo5jT;(B8`8-U)=LAw8o*N3gs`3fS}O( zg-{AV@i0vP2R{=|js=-v#5q0%EiLA>&PQAdmTZ%J6kY??XxY{oSjH#j0O`lZ_j?H( zY^y0?4SX}zO z!3)@N1N%cHq~AqgC1&(E3)O@jc26*~7op4=iqW)2h^GidSoM@5G>Bw}*{&peCNBP= zz_B=W!D`!8D~l~rjAd|PC+b9Z48vvz=I;?t&LW_quj|ms?;XTK1c!DoCW<32PckGj z3o03VnEb?>7a|Vq6C9yw=?#0*n&DpYvrb=0Yv2IS*D!j#!+&PsRw-|Af*ifeS2(cz zYsErid*F+t)wCQRtkAOq@M6Nf!axE3tYArJl^a8_7A#EOOTc;u6&R9-!NSnjRhkP~d>Qs26g{sn?GGU~RL*UkiwPG2G!^-!C9G-ym?6 z40n_d>j(iCTNj@rDpeB0f(d>OR=|cn>UHa8b`#G217HZNV#q!dRwYQ9piICmz!#SQ zA-fR#<8e;R{}edBc7v_+lUNpg7dnwN1L@5>q874jdlvmRwLE$j&`GLKYTppnULKk$ zFyJhM>}*6v{ns1ovxywf{qjMal5PHJ)PwVZL_s`o6J!P3UyggK24AHR?m;lyLBJz$ z%80#;+3~oYT0bRD7Mpnd172zNQdDKL?yMiqz7ffAui$(&oQ&lOQK-LLDL0n~{yT|M zQsBsjFW2+l7i~I7F9Pr8YYafH&nM=z2-r#x>v_497un(L{cz;My}F=hJisVB)mQu$ zP54d@11EO%h6n+Kv)kzMnMZN>QmmKpBp(f@yR!=Nh!v2p#PSa&9If$Tz6Scm`s0$q_B?FM40<4TA6qa<2ovwb*{asAF;i-PSu?V?u(8=(vQl z$BNz%SJ=wwz{!T5wO#QmSODC2^Tc{M`}IXqphKGt44@t7W{`+BC>v0`=62bVu9H(8 zt*_$AE$o3N;m`VS0-C7LXw47Rmy@&yk9bFls%}DH3a7avBQk5yN>Nl`<%m@?qy@ec(^=@r2yM)y4J!`!$_ES~Wb#QbImjHW0-x@k2{GMn@wG{E@27A_ z6QiXQHE#M$5VZg*L)5Wg&9^P-KuLd;WIND}qCV2^PdAc%Ga(#Y7GmDLavGU8g)0ce z|1lR!%SZ#-3pq&0Tx=3wJX5LDtD_ymleD&i0l{RT>~svQj@5g$K{&s2_zgcxgg z>&>0fy%&J6bAq5#6X`XHG(@G4UPP#VHij&O8X}^tCV8>K$%&nn?5}5Mi24kJPMN*< za=dt~&WH@+Azg&Avy6-{teuvy7=hOT{0%w(3<@tC{2Xh{x>~>h2{!il3Arz>U zL?V+9kI^RKc`;1y5-Y=ell~uEQ$}zxA!px!PNdHvUL-(+>ZA6-Gnj(TDzH7@gAwO) z63QU_a4m39JeR#G*HhBA1dG+-bS_V)KlX)H{1eoJ#Ve87ffztEd>-fp)C=sH2uC0G zTIYNKLa{IS_QxEKq(VG7oRg9fA0JNK*y7li-+2Yk4bxc>cwrw$>XGs{Uc)};+mot| z<@;7)O!R@nT>8LUUAg7@Kp0*8!cO3q!9;!FHLfcBB3z8$xvo0=KIaOe6>eS-%WLbc zb2$nVb47Rwi`fdSZ@0rQ%`*nJdP}w$`siI;>Kl>1XCYMTu|7Qrg2ENKM%J~ciEqiK zMYHJQQ2onI#}qvu2;~DIo}42n z|4qLC7f{vU5Su+m#_mtEKa|clDF?6qCmCdfugbCh;sld2c4Fb1;Vr?t1Qt$>Q;Ds7 zSm6I#N;wHe&w{pc-p<|%^1b0wmlunvTyP!a0i zFYz#KE^neW!qKr8r3^{m!&dI03A2JVPDVVXrfwrLzz1E{| zxCRfcueh$$Is@(;_xoV)cU6{r>OWuj=lf&b*sfOJFa@%W*$Z=Gt$Fn^xGaIsyaU_D zMCJw%6|I#j?TqV1+IV5b)r||INWUNRQqr#9*J6~st>3p1@8OH|yO4%VC2`1fQ&TnE zKTO#qB|O?)Yvvl^$x!kCvjTW`POgVy6&Plj8;awkLF6&qZ+Mb{DrLO{o}dOoM`crt za43j2lqW1p!)y<__yprkRa83!bp&6;^APAMbga97Xe}HtbZdl08;pV@#DK)`(Z!3X z&3WvP*XU%ydxF>2_ri}r^90QnK7*hJ9wRGtSuTNEsS92o&>8KH-6!YG;N?)v$)Iv{ zj{nqJJdWbXM8`M^G&+Z7ya@*>93zu+()cU=9eL&|{7e&&Av4-5gtQpph=m-)UE}eB z+L8K(zD_Tk8}w0;Q;Vg{062EOlHLAugN%jUqM)YtT_Nv;%l*JsWG6OMESy86sV z3Dp<=a|bSZbK_B5DoZ}mL!1*)%4}{|Y{u0$TvXOWYgh@}-=|8tWxV6h1hg0qUYYwP zCvIy^ac_jmZ2n`YhnE#E#ISwHCf0k9B43GUw`7Y#p|WJ(qN#+fGv2{Ciok5~XfW?@ zhXI!GYdsiYyLX|=lv$Zk5&c*#1OorNv2Vh+(DHAJwY67cuk{i6XC z)6EHhF6vKv>n+*5xLPuJVs2m^FdH;7wwCkFhgJ?ci@hWHvQEmAfP6fD53u?!9!Nz` zvAZFU!57JWEr4*D;Jf1YLRUf|<-CW6tI$xsc|eTG;`az;y%Wua0G|N&h1+6n5-*PD zeNa~4aKU>$bQcm)9^#Va8zkN*=Bs{(Nj(P&XDi&rE1-n_!C>`>UW~mk38%el0q{xq z|B&x>Sr{|E0YmPQV$&A9_PMg#%3WPE>AE-YwI?1%9^Tehyo=`Cgu#1eX7U_EOv1&o zctdvnDSpcvnS?>N zG6H$t$SB8#K`4QzeKAT9J{7O+fT7&VC?v9bvw0hBBihKFUhY3jd$WGhMET+AsDU_d zx8FGQ8Gl<3Uv3P{q?N9kW?IkHne5dR+yuXMSHV? zy8~Pv%Uf@AxHS=H2i% zM62^(!-QPMi3;&?Y_eX{D(hU`q7T`!xT`)nyJdo=9nf?8Z4uY2HtK_0Z|riyg{0*$pzze}&~b%YT~S z2jQp+gSM$!TW*d5rNGCu)rAM~f2&W#5yb!2j!e(MR@BTk%)Txx-SstiT)p2NSBNJV;00Q5V+9Um5w~g*9j@<* zPGY~Ieu(~LTAY)ny~oV{D>U}t6>^GggAi&pF~6H%)xuS9N2=b%vHI#Ir|WBWcxO!bmFCO%taDF7-TI%Qw}%q@EUk5hT#Rc5(ds{3;ycO_X+0U z6-Riuwc%9wg<@~>V+2^tjo1$|va0hgAioW?Iyb7SgZdp&caw8G7S2@%*+74u4|?G9Z@@Bl+huHk`t@ zR`!AY-iotvwdn5{imXpRwMTTO0PTh!BlSIaG{ZQf#RzrqF^XKnl!kLHk*-C8;tdw@ zdH2uJQn2U<@{&=JqTTof%B3tTu0%h_Ya#4$W)Lm8krB?sxkidkE!ISr)?(2s&1ZBY zS|#kO-Tv<5=*LEG_MKzojDRzgJ8&+2qty8zAlUv-lIrS>4}mH{!m@N|Gfs&;MgekhgnfCrTcbJi!7q)}w%PZnQsclstLl0=1kA=@U5k`W-{X zdE*bQ(0)OyJ9;iMlJE^DS@EIKOreS881bb1=s6-c2!^KSj~0gL1o>jXj?aHs22V4i8mW|w zTLB;?<5gggECHA>kD^XW*3jr+disg6;XEf6MRp8i`M#BqBzj8w$q85ku6}(=$$d!E zbAoH@)(19712ph%;U?+>?{gKPOdt3=ms?yPaaD=yQ?43uea=-Ut}nQPxboE~Kgpgp z87t3z@ZZ>NJgBSuw+2@Wa=C5h-mnsAU zk1+?>td=F)7;wWWuKN_&yG1vhZ}E8d6=Es}8(5VmG+!5DAggejcH8ls1IF18!$-wy z9IM2x)TJ15&kH1P?Ku3b8&6#9eBOj$v&Nauq0S>z#R$udk27zfKdfB{h9S_EswQa0`{8QZ_$k_mqf1b<}2 z2z>z;|80X$lJ#`Scl$(o4UDp{HhSS=DPm0l#vDQh)v)GCAP>D1yRhcJ#6u_CgJmSp zYkoq077Coj%i1VCy}klmtEYg4P-$qhQy`ZHPpopyL!f?}AQ8KM+&;usE5u8@e-7$! z38U&&464^Krd~%a2%@?^P>PE_@F~|Sk$z4LJmcyuNXJE(Pv2pWmlWnQAHcDq?KK`4 zsznw!iqf71D7B^tImiM}iPO|%jB#E=P`!MgCE#!)9J|kM;*5yL-{nQr{FUX%j3upZ726}ur36bF!m_vFHrv5 z2c*O=o)W}t1lks1lgGM8*fDT_`DWrPLix$V>DIt_mU!_-EeghekP1qkxrc=8M+c-K zk2DAo1RX$eHN7B73*RzD^i!zvVL6_V%8hX2q*O{`5U#;Ihy8K$kWe7;B%o5Ri9UHi z0@Uq9r{d%exoAnb4Lq9K>xQ;g0B%JtRn{PJQ@o*Lo&KIUMUSO|I9&`;-)p`6 zC2(54naJAfY;l$Xje#{xZ2=S)8WH<*iaLt%VCgS5m7aiAm>w(BcZTz~-UX{0cp!0R@2Q z8EBZWXL3ZjnG9k5&zgx7Q>o~B@=8fp9=HwbpP=hz>X=Pelae@$hZnE7fNA&-nzICc zyLgTnn$}- z^^?H*n(gkEPPXgRn@fkgSKJQc)gIcb8=<3JRZeEP`K3oMhfC6y>NM*;EGPIFEm&F(E`wzSMn=?EvVRFq2(|=xwqI}Dn=nl&))(`O&wR6@a7T0} zYAC;XL`k9#oaM4^W)GOVu3HbL5{F8ZTle)4_hq84H3@ZO-$W($^Mr^*pGRaWN#ON0 zT@mLD42TVu>r_OtYjG6yd_F>p6D9bz;rm$zgP}N_xFhg^IGI4Au~qmDst?2;ZAt9U zh+TMkcgy#2j{CnosL%`8#&_NS$NTNXN?{9jsQqWe)7**< zmUhMY8R;J-JFnz7p7_=`^lsSUAH0_08p~602H7s(geT1 zutnT8=^MH>v;8iT_-ZnT)$=p*C~}UzMmHh>>^R{)g7c4I zXA@)|zFcqE23nR}20(hlH@HRS`Fi8)yu;z6AIY~eSbv36g-zYYkC2b2lF{@wEavwV zZjC+3aYUo3dgFt#k=}3zZeWLVn#_&0C0qO@?34Wg*%7FEt$!wdFT{I()?_hnlE|y7 zEqP_hKTvh} z?G@Gy(&V@iSUBj%lRw97eWjALjqb#G$3yb@f{5c1*1-ezf-fvzF_{N(0{?=5qWup4 zSrALRz24lj%Zi>tRdHT5us@ku90#Fifm34V$Khd9yt_ldt;K12HQniJx(w5t-pVqzLWA@(NkSZ zfL9f6jmuXn;f)78oL3w#s2fY_MuEDn*e?bDd#FxFX@UI)&nIMTF(Uo3LT%- zo;FiBDTr~iuLAmyllUi|##1c(8t&;SeAks*6T*-40p?NjaLZ>79N~-f{YAu4mEJ#2 zcD#*mXT*WhjW~UPGYLI#kfF5$Zm4?JDs3gD z4gHz6czc{9E0C+BbtGS@W-ZxYV%hL`2SDQ@ICg@-bacu)>cyS`S(dz1!a z-s$e2ir-#-sO;e!{}BA1vv{kwxgYm`L{_B8#@_WG(0t4T2_ejP|@K$>Kk>qXS zA=)||i>h}=a~aJ5cf&>F+&~{zxe)Q~OK~6TXO9PtQ>*viz-AjIIe{;tk7KtzF0Vjs zX(8s~gLt9mD*U|^GHfdz$Xcgm%C~T!Pd-W!;^P}4O3p}1IJ+E3@vobLQ>922A<0K? zN^aFpxgv**@P^;bu#Cg;}q(A;XA^8W9Q7wCqheIOXc!Bc* zkI)w2`4KEL;r8%_4GdN|*C9JtxC59-2ecmNO0pkgODtRryoyM?L?4enhny^Nsp0g5P(p$+2mK6UZ&!7J2Y z;7RQ+$fxyZ{GFo>!TVQ2mJV6`ld4=4o&h{xa8tgh5D4H1g}`6;JDrcmzR1PiAob?8 zPHXB`VTVsFZ9Ff+mpu3vVxGt;+yOSjfjfUe-&yJG_4KKM7Q|+BP$2h0qc++nVt^pN#PvSpM(5G+NCHPfHwB$ zia3n26bLeP^7c+}aXL<4Nq7>kg`$U9=<8DSF%w;+!nAvrCCAf43hIFEiRek@eKHLb z(ZU`Rr*E}o%B&rUz{Mu~A=#%v~8?}fjArkBP+G5;u#MsmE(1-`6axrSmz|{#l zWIs;eQHy_zkW1;19N;*x4W*d5m%)x7q)}?N_g{e@5DGHODyG;pHZk2Kn-%?L^V!?Zynmyq4wN3eW@)I zoVK}U>&J=dr?g27D3!b;^%B2o+>t9YAkj7@<;Y9OVU@sQw&Kwu*gyWWKPRqB>7~`6 z4D&iO-ulGtXy0ff$WK}{$gdW?xXJ3^9dr~L)e=e?9 z0wX_qT!?<`zU(%mP+!g+95HH@)Kv?9AbYb8qZW&P1W+`5lKkliQy#1 zQCif6LQbSaOFc-2O>D5x0*xoOJjr#_txZB#ZQVK%U6j&UfS+!;$W!985cXiYux1I$ zlJy}O1Bva4=}z>s7!=RN$ffISLdTM85ati#ov_39$etKeyWa8qqzy`*pA!~M+9b*v zeUyaFAC7yL(RMEte4=D0YdGhP8<4}fLgI4+YK&5Hd7?7XIU7CA&~A!L^k~?sD$y^s ziqcz+NP0LHqigZc%$8+#x{7=Yna!MTM1bgrD3FVfdcuk8c` z`eC#%_NZ}$IVae>Nv0zqVZ`V}^2s@!Hi(oYw{#+pGdle+_OMW_oaVzfPOfG1QO<}b zf^T~g$*rjIiBYxTpBTTB`*U{R979UJ-BUFro$zNtb5lRUAD&)UH+Si@8Pn?)1?J9@ zcHXWf$`{S@Pm`|nv_<~u{=lL{B~?Cs;f&eSYUj+ImC|lO-K_a3xtjF9r_Y>e!&9Bw z&18Aqg1W$5IPP|(IrD4r1iko({?g0+)33LChTlJJ-t;;1;{elc{=5D~`nrT8;t>*V z`#p1@1GK%ijM19PH4Wutfs(((Y<8}YmI2Tc>BaMRx|XjEjL)xJhs$|zGWxnw8;99r z9Q++A4U1HJd9}%+p3?th@6^7;?0vkqWm^c&)U+J-dWRH9A4$_rwvM_GjO9A&MDl!c z|1QyEGM6Nt$zI?86mCLKMhn^}fwE*8Y8pqN%_+jPG5pGk0z}7C?VtY8J8lb4F1@anD1~5 z2XkH-u4Ry24^k7s`Rj2VC&mZyOff>712|5Lk*gu5zCg#&DsS)Xbm05( zZJnJiT!-OXj&EOlY2R&aN%WqN@v8@fdIbR?XF#J}O_U6Z*Gb&5zlj1fKWcKtF$&mE z#Cl_bpg2)B0CaQZhlebWt3|JZB?BO5vIgN63S0^?PZo*0q2kxZkp7{Zj~N}2tAk`* zNvDnHT+ns0dr1L#n&2RP?-@uFqXKOxT5D)eEH#0H7kT63oS7o>{PrLu1ncJ@n3@9Nhp~wB!l=dpR=>n87UD4^j+dU2yI7V#B6R9XvInc zlIx5H&a@qbMhMAeQnm|3K5Z5I`tSWx-ldnwC>1|;TF(BoqaMt3TsL!ukhXmd68( zITvu0{FrG9#P}uds{orTU|Bv9b!s6&l+gL$GJV@6_?6?y{u#-l6i_dnN{2}?*X^|O zGvxYp6U6?X}9V_!!?L+ z73kaYEDko|o1^Hq>#z8W#HSc#%xh8UJk*{G{yA21Qo<$LYyI zy&RP$29!>FwIemx2kDh71F46!cJf21=StDu8L|ByM))LdQlnBM#GI|=XQYBV5s+L5&e~C?L=BJdfD>siI8q7DQabJE9j*E(eA9Dn{xc#%o~E_|TKG`D zSSt4nDB1Sj4}GqMpi{%J#R`UXDTPghxO&ojNP&f-dI^$@6;{E z@3?oDI&P^YiMdx|kggB5bq;{999?O}IU`G&I4{ftP8=`xSB`od1N$=>_sRPlsk4(4 z^AY!D>x8etHtF@L33j~1iBXX8q=Y}0UO!nsj<0<@{C}^XHYFMMP0IDO7gLg2)sxrO zjOx(Jo@^emGxz=QPp)5n_wc*(9vSuY)(vG}y*26A@BQid?x%fngXj5gDu3U9(S4_- zw#F+l(lXNP_q=N2d8G@Ej(qTuKdhfn`p$qQgZp{kIdkUdHUD+HbZP%vw+{Sp*QFU1ku}E(m6>}ldcDu@=V&?Y%MU!1zv%qda}Mw5vwo~B ze`{60Kkp0wbIhtm+s@v5`-Lldv_E}I$K=Jnd+r+YV17=hY*x)5KRn|(;B%qGr+Rd2 z$A%+2`aIB6rkBq?e8&a(Z}fTLHZ9m*x?*|ZbNh^i-?mgd{^Ng5Ip*l`=A_)aU%dFC zedWJ+?2i{MTfX$pgTs3E559iXv&#GPZFA48ed2@1M>f6plj1S=e|z%>+k#izSoQKB zj{I%e>wTVI1^nhL9A472e*agquN(QqvRzLcIqQyxR~77>bo1?r^4u9CdVjnC>E*Kj zXRn)o$;Sn+_gVjmOyB$3iv6Qj?dWsQND1%mo34KAlb`Lce7xKK9lyEY>c?Myd-S`@ zkAc1-NzX6mPwsa4Jk&3d^?#9;-ahZCQ@1U8qtEJ_v?sI|=k0y)lrR2r@jJ^s_a1gU z@{3Dq|J3+w>+pU*zhlf3FIC=l>bFB@6}K1MbnhSD=<~pE34f?J@8w6|eRtHO>tF5h z&hPpbbzXDxjk~P6@$26SJXtW{AAJWcxjA?Do2WlZ)_<~aRbJV1XI4Ji(zDx7fArAL zp1-|r$eCkMUM$PCXTR~So&Biq!F|tOc6n9i1Iw4bKlHo{F&<$_|7)Jc-4hQj8vl#P z%+jAPeRklvuUzZ8<=fZ${GSX-U)HCav+|!xjPJUkD<2+^lwR=90nfkjReZd^U-nw# z*(3fHPgnNYbmKFd8o;ko3Gd#5eUp5@Li%!<{_)gt_g^(L!Oy4f>ECbAvO%LCoUk(g zjPW5e@Qjr*^PjV*g_d7<^(wDud9_>0@;B;d8Cr5`Rl zYwGn${h#~5)@;3f$C#f_EBf%FvTuImysRNSborG=)2kED95-fJ|9jKMclw7PhhO>S zjy_NH(mGaVU2ylZ42SrGtNi1ojx^iCq?1pe{J^KvPG`wQi*CspN zTc(54RQW0LT4Se`t83HmQ1sQ+%6bk(pIg;;DEi{{6@5;-T+yegbhd(5bDe~@Or@(- zTIMEx&wI9g^!b}1ual*G|1>QQ^Z>e;XDnG2!9jd&yCHoDk z@-tO>n<^iq(yLT@m`b;(bg4?OR_St;u2b-;RJul`XRCCTN(WVX|5p-^`&GI_r5{o0 zZ7RK5rCU^bvr0Fq^bVC?t1`^l%uVoXl~(31nESb`*i+TdS7~ML zf|shaZO$gCw65yksM5JAeWyzIQRxR&`V^IZPNh#(={A+_tI{1R-A|>pFXWAKpo6(8 zeYz_DsY)wz94uAoGgNtvN}s9HO)7nsN^e$ayz-8p;7*l3N2R}3X{So(ekpIxRq0}t zR^zSJsI(eytx2WTcxx>xt;Sp1uhJ6S|Nj1e#Q`Osaqu?(?Tl}ZbuQrjPL*L#r&@s= zS*3q)q-5HTR6VZ-Ug?vj3LuH;=)daNmV*6MyF0owUmu1qWa*6Mmo zcuK$H{VBBn_i_>r1l2f@n`+2J&DqK?w)t!Ouk~s9wjaA9E#LNMSEl9Le%fPc`L=(% zHZ9-wbGM}BS6wd&+L@MLpz^J>eB1v$oR)9xzI4$4y!*i71Ve{Yi$7hSz$7}KUw(UpMr{&xJ#EP_h+pk!emT&tP zkEP|?e#Y9geB0mHl9q4#9Xr$VZU4hc%eVcI!)f`pKa%sUlp~uDwqKH$mT&tf`DyvK zpHiHbZ~H4oTE6YKOi9bP{g>Hk`L-WZpO$a?Gb_^aZNFw^TE6YyJeHPk`#EdV@@;=- zOIp6|_v}o|xBVY0E#LNo4yWbY{!orukJCq zN?N|{Kg~|dxBaO4w0zs2T9KA-`&BE`^5gzhnmx4RA@*A)g{B3HTxiT$3zHUy-U!~S%kEP|?>+02M`7H|m+O&Lo-QALw z-=ykqNz1p_<=fKogR1_{w0wKr-jSAHr|Mg2`S!Yge_DQxs(&~w-(L4?hg0oLm8zeU zmT$)ea?|qNs(xNtz8yDkrsWr?`uS=3c3hz#E#Il?7pLXhaR+x=ey*x-q~+UjiK?`G zP1T>0mT$)`YSQxUIL7R>d^@gDmzHnGIqK8$?YKuUEx$v_=Zds^J1)|cmT$*NR;K0K zag$YP`7O5mr{&vmmDOqacARBxTD~23X-Uhs<1ky&^6j|HwzPaZPO~#D-;UdKq~!+{ z{#IJP9oN~PmT$*-4yWbYaUbnSs{Gq=pq#XPJ1+G9w0Gv=O;vdxzg;McEESMNwg3WU zvD_|f0@9sEy2K_epg@`?w%utOH){yvY#;6EFs|*Zg>kme_CgqE`)*BP zobAKC8OGVZTyq#NR`c?aFwXYvTEe(Rl|LEA*}h(D7#CIfb77qA`w3y|&lEOKgmJbn z7#qe-s(ha?&h`!C!Z_PMR7Tx@|Noy_11ai$1MTCmy`TToy7+Io|62q9t~KyH0t??8 zrdXf80*}GwVRwAOezu6D^!=Je;IY`vZB(B>mAis)2i}nUy>k?jr`|ZKa>r~1j8OT= zE7-}${aDx$QdB|pB@wS=|9n_H)+^ZgjVgasjVDR9bN3bG532HA=PH6zAV)vmE68`p zJ&LDzw=5<+qPz%ORQb3IDo|hg*^*3bj9cM1kXn_9bGu9cvlmufG-fsF}+3t*ZP+InM7d3X2ua{+}uH zOZ(><)y}+Gie!{($Bawr&q6b^@c;WYUaEG7P=q-AQW2wscvnSvd5tJ!o9Id>2?hcz z&<8Ff@vCSN8HiuMiD?lTgJ0^9iX9>o@LK^DT`L3REsn@ljt^dSEhl7Raj9!jGp^!f zR)AcGkEe8*M?um#@)Af3r?nrXkt5Ww@1TKoJ70jLa5ASrmf@ovsOmC#cy;ziUUXL&nh8aUDf(m2NG{cVsGltOPE8j~iDw1CX*$9y47;qN4alImJNgV0g^ zI-$SqImg-Q26B=k*MeBk(V(oBJszZ(BU3?yK}H!Xh>0UEkQ9yt$PP#7Te)gELf`sT zk2=(2eh7r>P>*K|NE1i?1k%Eh{U8m4jau)M7DtYg7Dv7X5r!DG&Vh&=X@}4(9O(hF ziX$eF)}cl_Ng%P;8A%$5$dQ{tEF75&;^)Y1AkD*!c4|pxxRKls(!`M`Nd^;r1d4~Z z_}M`(ql}~pq!u!CLy*3C#fE{BWQM+G(z4_ zkYx+=ZVmap>3;m}xt|e>HPe=AvlSHI%m`_?UD#$cy-mRfPx&wAZtrTRZ4l=cz z_q8DS<90(^YzAq7rqVj8A)lKx@ki|jndiutiIpOwq)d*wxWp)P5HiK+hg41UD+phL zv|PtXMn${xffvfqR$ojQDW{0c{16hU1 zNAF`3K$;dANj^yI^~^G9m4NuQnC%&}^HOuoUH{J6I~KrI?;6w}lC7IE56c-M7WX2zg%uttPE! zmP_SM3@^cyVU$?`8T_*;wUtThVUQM+kvvB-=o@;3`#>xSMsgfvl~zA?H69VmPDKmt z<;{`2f`x0HpP^MenE5IQQL9ScrYfdI@pNntnMxz+0V0+f$pDa(*D*V=Vs+n+Q@J!> z!BD^>c^yKNM(h|o`4u4{R*R5)je(sOZM-8RQ9=@8H7$~vMlxEhQp_YJauJ##LzzDc z@=*f3d!6Nehj^PY<^_;x%48%fAW0UV&r__CTcm(5S1K23HA3Dipe3Sj=xwo#d~vO_ z9)xBP#XD*J354b*oxBO+*J_?*4ugoAOsYCm8WtLT{Q#L1Ed6!wQ5{e}(~M*YNGsQZ zV?a{49zGeQL93r?HP_X0^-~I&RYgY2A&@V*a@CU^EoLgkIuKDZYCR5OnPMb=0x8C< zr_=`JLi!OkLRb4BBXGWsgQRH0EZ0wJ2>%3Dt&Pkqa|WGvnZns=Bkx)cN6+-8m-~fP zUZzF9euYdk*A}rI1;M2GBAEmbTBYbMI1QwklPLlbwOS>ug(Sn(Pd!MJ$!KRINJG#V zPb0`G%`!%b9|J|eKc7-diV03GeJxkd2T4n0GUWX@NV7Jhq3o0Zgko+qeG8dbJbUXs z>KsTDSJL*KK)6zj25HDLYE1-bp3I1xNf2fWH!3qAQ>)2Pgcgui&X*meiL1j!AT3;b z-2>uJX1>VI7LaBwClJ{QQmfS=k@rDNoUctXxIDHB@gAtOslk7}1l1(6DqLI8zWUP@igVg32 z$#IZIEsv#H$u_)m>y4A7#nsObASN#6*v=S(T8~m%x!j+^^`Cx_vE&=Q4+m-F>UlcJ zaF*wSG>56tWt;)wy;VoDV1^;+2P9d7D!_nvy5>;DM6^! z`WVV3TdLJcN_IYlRxIcJEJ!ogUXfj3S&N6XhJ(a%#6pCNXD&!Hm&5M>DdxN{2kCP? z>rrwZ!!kET8_O&mHo6VvlGpQsCSzASbW<6Vp$H#W^Tnes4IMFqrmJ{QeCT->k4cXBfMYF%1&4D&`QZQdY=m7 z=SndbM9}(}#ca!jf>5lj*~m@+GI1tm*{;sHmRZcQ(!>2VtF#_&$;!c(yJ5uL%w)*U z3fO7p=D5w|os0P;lHnpe0^)ZW?R*8&!1axbAWfQg^3|~$ymRw=50I8ItP~_O1f&5` zM&NxE0U;Tr)?}2ikW7wI#z!(*jhWTPFllW;c4{FbYHdnn9cg7SJ7{IMJj41JDROw+ zuH3YO=9?HHtu4?>(R>kk6U0<#l%YMO7Oiij`}{RDyc@XD-2xebtFiMS#i)6`?A>B9 z;|bw4@bU{YE=4lVz^#2SHL`N3V^~K^nE1XXgl> z?yks0QXzyNAalN#k#xQqy}YlH3TT4z88XFp z7|E?5XEpD3$r}ow58_xcxfDu-0mwY7S*DolLGJBul=&UVG>$w1a+D*RLAnkwYV8DJ zJAsjc9S7c3BNNkpI@O`#y@`_{@9$hfj&p<#lnjs^{3v$ps$rebyT3sz&VTVDjatRm zkDMKni9uWG5fbTs2^qu@JC28UkRW~(%XUdYacYiId|eMMi;2lh!Bu=f@;KuC9-KN8 zcA`98)2Z|JGIUkJZZECyI_>uOiK?LA9;9bLSu5<^O-)u*ZigRpDIbHW35`>PRA=%L znD$aUtzBMMIU-Xk_lIi20voR=1SS0pPt8Z7a!)_UQ@fL-+@X^Z%Y1%&xzD9KcFvca z3uRX73)m~F*|DOE{AEu5)J!G|y0j9bTuGNZd{om(&?|U??7^iT?vL?{;~4FzVae-K z?r3cyAODZ93MkW+4R+MZr>c}sJk)$8>Eem{TTauSAyrx&q4}9!m)VP+jZJoev9w?i z|7n-GlFRL&ElQu$=h0{uj!-278c5G5$j7%csCKQ?UD-t;4V-lAOj~+(d@_PlWz61E zx7VHKK(QGr47j!TxejNl%N5YB&58Ni`@&#}_C6tLQnGfD6C9yh#y1mqp!*959 z8ZOd($WT6yN7B7vqQWMuX4m3$Is$r}7N>404?U{TyU^>a!U4N#(TdQPKHXS0bTb0( zN=aZ(er8MM_;`0P;J`;4Oo^EBB3YP0Mrk4m3fB3O$7A+}q(G^|DQV4txw%5J`S1uH z??)}enmL%`b2>cA{Ac#MLvBppw@W$h5(`eMMOVkyw7N_58!n+Nv((M*$x#OKE2Tid z?b6&(2m<~UWyqHyIo&vnlT4)Jkj{`MlIIJ#OKUPKk?VyV>wI@9RO>E-|q|H8CmIcvQlOs;0xeU+UobXQ48#zVCcc9d^hTbdZpQ) zY?T6ZndbJoFoHCBxU_~U@JrjDw4Mc^8q{k_8ps z5U%7XY4^*9x#coJ$t9r%4}`gwivr&n6(|Nd709^FN2@Lj^VE`{&r^X=eAr7j6jHaB zJUCZr4BN#)_C*QO=4R=w_=~AeOog+&% zCWZ2fj6ki20*5;&*(^C!HMx$EbH3gLL7_nF28CX?6Qe}yzJk?V?nnLzE2XZS74Vg3 zBQfBxbJCXRhF6ME_7=)S=p2t&P_AtTWxdm5^enC0;~LRuHbc+`t5 zFniXJFQDZLp-689xTTJ0tqF#ta_WwPJkZn8UE~tW^`saK%Odiaa0gL;tXy(5xl+g> zcSTvV$d(|A7EeV`zDFub*VBD+$|NAGXyVg7z7mIr6+^?>j^O-DG0a&zE)K9(jlTI3qFI8(hrw`SK;Eu}ev z615i>u39+ih4eIuOD*N;Wnd#h$gS|ue8GmA(nge9&HOMcbX_s8Q%$Smi3@}{jh4%% zOoW9PqyW0F&EfXsm(sAy54bRl3qs)&9yQh_nM^ic;^bVa?ZWC+nO&50mR5sNyU^+` z^Wt=RtW>C8v{}pM(}vn5X^&PJNGegJW1(JMJI8Enpsq|RAi>Bjd35F4;LV=`J1g(D5ZmHY(PnJN`{g^71 zw?O)5nU#J11i`E-t*etaZkA>SwIQXq1$RqM)$)`AgNFGz)$5XJ0cJBp_uyNVCe%yX zRbPj(t_rh-Zgu7$16b$Mz)!lS+8I*cVZ#-n$hlQrUEnf9J`-Q-Ss63 SJ0x0gAccE1z|`n(RTIBV>cA}OPW zl+KA~hEjJ~ML_A$@`3wBWsY=@BN$|{%B7(39zMmZBSE4bqIJ{h0f&FS+Zn`i5__o3 zhFlPRl`qh>HrLXs?F!4>%Vb-@Dt{%0rp=;|BhWjYd|%M}hMMx!HMyZ>s6QcCE>f7G z^|vy0)8N$Y8rw;!LTWWUpZMfQ96^1CQWP%9e}-k1Hk9OSiPn*yjaV4UsGFEf5Wg1R5VeA)Zp1Y!iw%X_} z?FK13Hu&NMuUoO824oMDp$(s{36YV4Sl{VnOvh2n zvzPzWC8B*~Lw%=DfIfH{^*q zVs8WKCU(Rhr#3`yimVmHgfQJ`(>H6|e>kBorD@=fb7j|cne*0(3EPGrI@)>ijNOMm z?QJ@Kv7x@hSg}4Dzfrv#q9P+ABRdK|ebVmOg@+y*Ovcm@Bd$Uql?hjg9b=*jqhoqR z7FrW}i9P9}Lys=G7@iL2e0(uXC=^WSF2)jX-=kx?qr5~;a!j^Uk1hq0%arX1jWLT#{gO*W(}Q#uw8c<{wjgDE{#9N4={LZUc9oRlyrAu&1m7F;G7F2&IQ zeO!aZK}uYGE)$phh$+@b3^7&^S}LkOq8nN^qElpjM1-*C?(Zwc*qUxW24wS$2)--=l|r;GKnQKCgc1vlC|$kH%~ZtT{2KN7mq2%Rj~MsJ&s`+V7@zT{vOWz_E~*xv?TwRY@?;+D8RRfQ+TakKW^_3#s;H+lVkJU)Kx zd*;^{ycdaX8S!}CUa{^~aR4fFK-cJA(LKl2zBlgUg_BEfPx-vm-GBGFpmqBcxvmEc zjqW4%s_ogK;k#MFfync-?&!WVYS{Y4dEd|NFLopSZV?d|quWJAwZB-aXbdBbm<|{m z?b@}EiqZx}r>F?IpAP5|9f@PZrzyi}`MI=+F42j-MCxI3&yqWt+?Xcp;Fzx1()=($ zD@O=-?A_S*;qklj&TL8kY**#V+!0o5o#U*l>BhFqcFCbxU7tR3u3Gwd@n4_6rs;6r z4gbj4aBjlLC0}(MTU!6vn@6r`IQimOUscTbS0n1~@aMOl{Ul<^+I4GYpU5A+`+;>f+o#vHeR9{DW#%z+BYywMwJm**eeTe(NY~}j%b-4#0+!Ph_OvD4{U;VIh*^jG# zSTS_N6ASuuXi3;Jer3;Xqmw2*_V#ywj=#R=@RD_lS5KNBSGs%D!7)F)UXu28f&XY^ z_SlHS*Si0B)r;rrj((q9{K%_^{xagX5BHgzy}S11cKhr*5{IXn=AI0t)?`%gtp7Uy z$@`l3Pp$uG{~LE5zA)s2og=Dt{qoUk+y1(F!tCIoH|~FE{f1LTo$sE~yzws&C%(Gu zc*DZ^{SuCt=5Os~-hR`{ZVR?#pPSt}^1yvIU)MRSzuIuRqPn@mH8ZOtpI$rQsgpOI z>VEjvC3lzZ%WHq8@u#AO(xH9N#hw1<*>|_z`Pc)09`M4pedpDru|ll7%aAlKn-eHO z|I?&#m7Fx9qcN-fs$`HJat0Bj@FET~W`#bzdTCi9Rh@m5EN>Y5=+E-lU)HDR{uZzA zqc*U06-yO9k&C>SGElEkcSO1)Ce}3<) z7nbb{WW;oRbLrfHZQbLSUugTaU-sT5pYEL<`EKq%Y*VwP;2e+d!C~h!ns0dIwYeQ) z_H=)0#Pk(u2ZszRo7sEj(WRePpV_`_>ww*FSyH-oUNmjcqn+FTk|134%?_R2dUn!R}H1Gb&6rZ)UXJx%@!^lyCu*Z&{qdh z37xf>0t+g!zkaJ-Lbu*s5=C)*f|!t;I5BzRE#g@HZgj$sXjA)lS3DkfY*^FiMO((d z_3MK-&zacn`owARKdqeSN*sUx`Z{9*#F8Ky|1{&C!}o7E&xD+AA3w;i2k z4}HJIzG(Qx{SVyJZ|UY4Wyhk=48G}&W96gf%{w*n+hosg#$ zbh1CA`(ac0f#mV2C!$)nlfW+<$99+q(0UdR%zxf^A9Of@M2a+&%uo5lN<#RV&wDz4>n$PnGvQ zb>C-qTmSyE#e62_rj+eNnwy{h>Y17@pT4lmG0$^slDBpCtbTL%9~l1j+p8Ob-TJ>W zcH-Hszr=Ov7y06$7uSt_YT_S2l3sXbd3D{cPu9=bz5S6f$EGfM^Yt~&Q?d?B`d!iu KBfp?eSN{hcgPmLe literal 0 HcmV?d00001 From 04afb39f761cddf31dbb7c7ccff40ad8473c39e3 Mon Sep 17 00:00:00 2001 From: Richard Hughes Date: Mon, 17 Aug 2020 16:20:24 +0100 Subject: [PATCH 334/607] Add X-Configuration to use for dbx updates This would fall back to X-System. --- src/fu-util-common.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/fu-util-common.c b/src/fu-util-common.c index 1720b2746..70d3aa70d 100644 --- a/src/fu-util-common.c +++ b/src/fu-util-common.c @@ -598,6 +598,11 @@ fu_util_release_get_name (FwupdRelease *release) * the first %s is the device name, e.g. 'Unifying Receiver` */ return g_strdup_printf (_("%s Device Update"), name); } + if (g_strcmp0 (cat, "X-Configuration") == 0) { + /* TRANSLATORS: a specific part of hardware, + * the first %s is the device name, e.g. 'Secure Boot` */ + return g_strdup_printf (_("%s Configuration Update"), name); + } if (g_strcmp0 (cat, "X-System") == 0) { /* TRANSLATORS: the entire system, e.g. all internal devices, * the first %s is the device name, e.g. 'ThinkPad P50` */ From 13b3343aafa555c040225ad8de9420aad7a549de Mon Sep 17 00:00:00 2001 From: Richard Hughes Date: Wed, 22 Jul 2020 17:36:46 +0100 Subject: [PATCH 335/607] =?UTF-8?q?vli:=20Add=20support=20for=20the=20Real?= =?UTF-8?q?tek=20RTD21XX=20I=C2=B2C=20protocol?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- plugins/vli/fu-vli-common.c | 4 + plugins/vli/fu-vli-common.h | 1 + plugins/vli/fu-vli-usbhub-device.c | 30 ++ plugins/vli/fu-vli-usbhub-rtd21xx-device.c | 524 +++++++++++++++++++++ plugins/vli/fu-vli-usbhub-rtd21xx-device.h | 19 + plugins/vli/meson.build | 1 + plugins/vli/vli-usbhub-lenovo.quirk | 7 + 7 files changed, 586 insertions(+) create mode 100644 plugins/vli/fu-vli-usbhub-rtd21xx-device.c create mode 100644 plugins/vli/fu-vli-usbhub-rtd21xx-device.h diff --git a/plugins/vli/fu-vli-common.c b/plugins/vli/fu-vli-common.c index 67cd57ea8..8c6904af9 100644 --- a/plugins/vli/fu-vli-common.c +++ b/plugins/vli/fu-vli-common.c @@ -94,6 +94,8 @@ fu_vli_common_device_kind_to_string (FuVliDeviceKind device_kind) return "MSP430"; if (device_kind == FU_VLI_DEVICE_KIND_PS186) return "PS186"; + if (device_kind == FU_VLI_DEVICE_KIND_RTD21XX) + return "RTD21XX"; return NULL; } @@ -150,6 +152,8 @@ fu_vli_common_device_kind_from_string (const gchar *device_kind) return FU_VLI_DEVICE_KIND_MSP430; if (g_strcmp0 (device_kind, "PS186") == 0) return FU_VLI_DEVICE_KIND_PS186; + if (g_strcmp0 (device_kind, "RTD21XX") == 0) + return FU_VLI_DEVICE_KIND_RTD21XX; return FU_VLI_DEVICE_KIND_UNKNOWN; } diff --git a/plugins/vli/fu-vli-common.h b/plugins/vli/fu-vli-common.h index 8035f7fd8..cc652f427 100644 --- a/plugins/vli/fu-vli-common.h +++ b/plugins/vli/fu-vli-common.h @@ -36,6 +36,7 @@ typedef enum { FU_VLI_DEVICE_KIND_VL820Q8 = 0xb820, FU_VLI_DEVICE_KIND_MSP430 = 0xf430, /* guessed */ FU_VLI_DEVICE_KIND_PS186 = 0xf186, /* guessed */ + FU_VLI_DEVICE_KIND_RTD21XX = 0xff00, /* guessed */ } FuVliDeviceKind; const gchar *fu_vli_common_device_kind_to_string (FuVliDeviceKind device_kind); diff --git a/plugins/vli/fu-vli-usbhub-device.c b/plugins/vli/fu-vli-usbhub-device.c index 493f8f20a..9502d2d97 100644 --- a/plugins/vli/fu-vli-usbhub-device.c +++ b/plugins/vli/fu-vli-usbhub-device.c @@ -16,6 +16,7 @@ #include "fu-vli-usbhub-device.h" #include "fu-vli-usbhub-firmware.h" #include "fu-vli-usbhub-msp430-device.h" +#include "fu-vli-usbhub-rtd21xx-device.h" #include "fu-vli-usbhub-pd-device.h" struct _FuVliUsbhubDevice @@ -563,6 +564,31 @@ fu_vli_usbhub_device_msp430_setup (FuVliUsbhubDevice *self, GError **error) return TRUE; } +static gboolean +fu_vli_usbhub_device_rtd21xx_setup (FuVliUsbhubDevice *self, GError **error) +{ + g_autoptr(FuDevice) dev = NULL; + g_autoptr(GError) error_local = NULL; + + /* add child */ + dev = fu_vli_usbhub_rtd21xx_device_new (self); + if (!fu_device_probe (dev, error)) + return FALSE; + if (!fu_device_setup (dev, &error_local)) { + if (g_error_matches (error_local, + FWUPD_ERROR, + FWUPD_ERROR_NOT_FOUND)) { + g_debug ("%s", error_local->message); + } else { + g_warning ("cannot create I²C device: %s", + error_local->message); + } + return TRUE; + } + fu_device_add_child (FU_DEVICE (self), dev); + return TRUE; +} + static gboolean fu_vli_usbhub_device_setup (FuVliDevice *device, GError **error) { @@ -647,6 +673,10 @@ fu_vli_usbhub_device_setup (FuVliDevice *device, GError **error) if (!fu_vli_usbhub_device_msp430_setup (self, error)) return FALSE; } + if (fu_device_has_custom_flag (FU_DEVICE (self), "has-rtd21xx")) { + if (!fu_vli_usbhub_device_rtd21xx_setup (self, error)) + return FALSE; + } /* success */ return TRUE; diff --git a/plugins/vli/fu-vli-usbhub-rtd21xx-device.c b/plugins/vli/fu-vli-usbhub-rtd21xx-device.c new file mode 100644 index 000000000..269ebfa85 --- /dev/null +++ b/plugins/vli/fu-vli-usbhub-rtd21xx-device.c @@ -0,0 +1,524 @@ +/* + * Copyright (C) 2017-2019 VIA Corporation + * Copyright (C) 2019-2020 Richard Hughes + * + * SPDX-License-Identifier: LGPL-2.1+ + */ + +#include "config.h" + +#include "fu-chunk.h" + +#include "fu-vli-usbhub-device.h" +#include "fu-vli-usbhub-rtd21xx-device.h" + +struct _FuVliUsbhubRtd21xxDevice +{ + FuDevice parent_instance; +}; + +G_DEFINE_TYPE (FuVliUsbhubRtd21xxDevice, fu_vli_usbhub_rtd21xx_device, FU_TYPE_DEVICE) + +#define I2C_WRITE_REQUEST 0xB2 +#define I2C_READ_REQUEST 0xA5 + +#define I2C_DELAY_AFTER_SEND 5000 /* us */ + +#define UC_FOREGROUND_SLAVE_ADDR 0x3A +#define UC_FOREGROUND_STATUS 0x31 +#define UC_FOREGROUND_OPCODE 0x33 +#define UC_FOREGROUND_ISP_DATA_OPCODE 0x34 + +#define ISP_DATA_BLOCKSIZE 30 +#define ISP_PACKET_SIZE 32 + +typedef enum { + ISP_STATUS_BUSY = 0xBB, /* host must wait for device */ + ISP_STATUS_IDLE_SUCCESS = 0x11, /* previous command was OK */ + ISP_STATUS_IDLE_FAILURE = 0x12, /* previous command failed */ +} IspStatus; + +typedef enum { + ISP_CMD_ENTER_FW_UPDATE = 0x01, + ISP_CMD_GET_PROJECT_ID_ADDR = 0x02, + ISP_CMD_SYNC_IDENTIFY_CODE = 0x03, + ISP_CMD_GET_FW_INFO = 0x04, + ISP_CMD_FW_UPDATE_START = 0x05, + ISP_CMD_FW_UPDATE_ISP_DONE = 0x06, + ISP_CMD_FW_UPDATE_EXIT = 0x07, + ISP_CMD_FW_UPDATE_RESET = 0x08, +} IspCmd; + +static gboolean +fu_vli_usbhub_device_i2c_write (FuVliUsbhubDevice *self, + guint8 slave_addr, guint8 sub_addr, + guint8 *data, gsize datasz, + GError **error) +{ + GUsbDevice *usb_device = fu_usb_device_get_dev (FU_USB_DEVICE (self)); + g_autofree guint8 *buf = g_malloc0 (datasz + 2); + + buf[0] = slave_addr; + buf[1] = sub_addr; + memcpy (buf + 2, data, datasz); + + if (g_getenv ("FWUPD_VLI_USBHUB_VERBOSE") != NULL) + fu_common_dump_raw (G_LOG_DOMAIN, "I2cWriteData", buf, datasz + 2); + if (!g_usb_device_control_transfer (usb_device, + G_USB_DEVICE_DIRECTION_HOST_TO_DEVICE, + G_USB_DEVICE_REQUEST_TYPE_VENDOR, + G_USB_DEVICE_RECIPIENT_DEVICE, + I2C_WRITE_REQUEST, 0x0000, 0x0000, + buf, datasz + 2, NULL, + FU_VLI_DEVICE_TIMEOUT, + NULL, error)) { + g_prefix_error (error, + "failed to write I2C @0x%02x:%02x: ", + slave_addr, sub_addr); + return FALSE; + } + g_usleep (I2C_DELAY_AFTER_SEND); + return TRUE; +} + +static gboolean +fu_vli_usbhub_device_i2c_read (FuVliUsbhubDevice *self, + guint8 slave_addr, guint8 sub_addr, + guint8 *data, gsize datasz, + GError **error) +{ + GUsbDevice *usb_device = fu_usb_device_get_dev (FU_USB_DEVICE (self)); + if (!g_usb_device_control_transfer (usb_device, + G_USB_DEVICE_DIRECTION_DEVICE_TO_HOST, + G_USB_DEVICE_REQUEST_TYPE_VENDOR, + G_USB_DEVICE_RECIPIENT_DEVICE, + I2C_READ_REQUEST, 0x0000, + ((guint16) sub_addr << 8) + slave_addr, + data, datasz, NULL, + FU_VLI_DEVICE_TIMEOUT, + NULL, error)) { + g_prefix_error (error, "failed to read I2C: "); + return FALSE; + } + if (g_getenv ("FWUPD_VLI_USBHUB_VERBOSE") != NULL) + fu_common_dump_raw (G_LOG_DOMAIN, "I2cReadData", data, datasz); + return TRUE; + +} + +static gboolean +fu_vli_usbhub_device_rtd21xx_read_status_raw (FuVliUsbhubRtd21xxDevice *self, + guint8 *status, + GError **error) +{ + FuVliUsbhubDevice *parent = FU_VLI_USBHUB_DEVICE (fu_device_get_parent (FU_DEVICE (self))); + guint8 buf[] = { 0x00 }; + if (!fu_vli_usbhub_device_i2c_read (parent, + UC_FOREGROUND_SLAVE_ADDR, + UC_FOREGROUND_STATUS, + buf, sizeof(buf), + error)) + return FALSE; + if (status != NULL) + *status = buf[0]; + return TRUE; +} + +static gboolean +fu_vli_usbhub_device_rtd21xx_read_status_cb (FuDevice *device, + gpointer user_data, + GError **error) +{ + FuVliUsbhubRtd21xxDevice *self = FU_VLI_USBHUB_RTD21XX_DEVICE (device); + guint8 status = 0xfd; + if (!fu_vli_usbhub_device_rtd21xx_read_status_raw (self, &status, error)) + return FALSE; + if (status == ISP_STATUS_BUSY) { + g_set_error (error, + FWUPD_ERROR, + FWUPD_ERROR_INTERNAL, + "status was 0x%02x", status); + return FALSE; + } + return TRUE; +} + +static gboolean +fu_vli_usbhub_device_rtd21xx_read_status (FuVliUsbhubRtd21xxDevice *self, + guint8 *status, + GError **error) +{ + return fu_device_retry (FU_DEVICE (self), + fu_vli_usbhub_device_rtd21xx_read_status_cb, + 4200, status, error); +} + +static gboolean +fu_vli_usbhub_rtd21xx_ensure_version_unlocked (FuVliUsbhubRtd21xxDevice *self, + GError **error) +{ + FuVliUsbhubDevice *parent = FU_VLI_USBHUB_DEVICE (fu_device_get_parent (FU_DEVICE (self))); + guint8 buf_rep[7] = { 0x00 }; + guint8 buf_req[] = { ISP_CMD_GET_FW_INFO }; + g_autofree gchar *version = NULL; + + if (!fu_vli_usbhub_device_i2c_write (parent, + UC_FOREGROUND_SLAVE_ADDR, + UC_FOREGROUND_OPCODE, + buf_req, sizeof(buf_req), + error)) { + g_prefix_error (error, "failed to get version number: "); + return FALSE; + } + + /* wait for device ready */ + g_usleep (300000); + if (!fu_vli_usbhub_device_i2c_read (parent, + UC_FOREGROUND_SLAVE_ADDR, + 0x00, + buf_rep, sizeof(buf_rep), + error)) { + g_prefix_error (error, "failed to get version number: "); + return FALSE; + } + + /* set version */ + version = g_strdup_printf ("%u.%u", buf_rep[1], buf_rep[2]); + fu_device_set_version (FU_DEVICE (self), version); + return TRUE; +} + +static gboolean +fu_vli_usbhub_rtd21xx_device_setup (FuDevice *device, GError **error) +{ + FuVliUsbhubRtd21xxDevice *self = FU_VLI_USBHUB_RTD21XX_DEVICE (device); + g_autoptr(FuDeviceLocker) locker = NULL; + + /* get version */ + locker = fu_device_locker_new_full (device, + (FuDeviceLockerFunc) fu_device_detach, + (FuDeviceLockerFunc) fu_device_attach, + error); + if (locker == NULL) + return FALSE; + if (!fu_vli_usbhub_rtd21xx_ensure_version_unlocked (self, error)) + return FALSE; + + /* success */ + return TRUE; +} + +static gboolean +fu_vli_usbhub_device_rtd21xx_detach_raw (FuVliUsbhubRtd21xxDevice *self, GError **error) +{ + FuVliUsbhubDevice *parent = FU_VLI_USBHUB_DEVICE (fu_device_get_parent (FU_DEVICE (self))); + guint8 buf[] = { 0x03 }; + if (!fu_vli_usbhub_device_i2c_write (parent, 0x6A, 0x31, buf, sizeof(buf), error)) { + g_prefix_error (error, "failed to detach: "); + return FALSE; + } + return TRUE; +} + +static gboolean +fu_vli_usbhub_device_rtd21xx_detach_cb (FuDevice *device, + gpointer user_data, + GError **error) +{ + FuVliUsbhubRtd21xxDevice *self = FU_VLI_USBHUB_RTD21XX_DEVICE (device); + guint8 status = 0xfe; + if (!fu_vli_usbhub_device_rtd21xx_detach_raw (self, error)) + return FALSE; + if (!fu_vli_usbhub_device_rtd21xx_read_status_raw (self, &status, error)) + return FALSE; + if (status != ISP_STATUS_IDLE_SUCCESS) { + g_set_error (error, + FWUPD_ERROR, + FWUPD_ERROR_INTERNAL, + "detach status was 0x%02x", status); + return FALSE; + } + return TRUE; +} + +static gboolean +fu_vli_usbhub_rtd21xx_device_detach (FuDevice *device, GError **error) +{ + FuVliUsbhubDevice *parent = FU_VLI_USBHUB_DEVICE (fu_device_get_parent (device)); + g_autoptr(FuDeviceLocker) locker = NULL; + + /* open device */ + locker = fu_device_locker_new (parent, error); + if (locker == NULL) + return FALSE; + if (!fu_device_retry (device, + fu_vli_usbhub_device_rtd21xx_detach_cb, + 100, NULL, error)) + return FALSE; + + /* success */ + fu_device_add_flag (device, FWUPD_DEVICE_FLAG_IS_BOOTLOADER); + return TRUE; +} + +static gboolean +fu_vli_usbhub_rtd21xx_device_attach (FuDevice *device, GError **error) +{ + FuVliUsbhubDevice *parent = FU_VLI_USBHUB_DEVICE (fu_device_get_parent (device)); + guint8 buf[] = { ISP_CMD_FW_UPDATE_RESET }; + g_autoptr(FuDeviceLocker) locker = NULL; + + /* open device */ + locker = fu_device_locker_new (parent, error); + if (locker == NULL) + return FALSE; + if (!fu_vli_usbhub_device_i2c_write (parent, + UC_FOREGROUND_SLAVE_ADDR, + UC_FOREGROUND_OPCODE, + buf, sizeof(buf), + error)) { + g_prefix_error (error, "failed to attach: "); + return FALSE; + } + + /* success */ + fu_device_remove_flag (device, FWUPD_DEVICE_FLAG_IS_BOOTLOADER); + return TRUE; +} + +static gboolean +fu_vli_usbhub_rtd21xx_device_write_firmware (FuDevice *device, + FuFirmware *firmware, + FwupdInstallFlags flags, + GError **error) +{ + FuVliUsbhubDevice *parent = FU_VLI_USBHUB_DEVICE (fu_device_get_parent (device)); + FuVliUsbhubRtd21xxDevice *self = FU_VLI_USBHUB_RTD21XX_DEVICE (device); + const guint8 *fwbuf; + gsize fwbufsz = 0; + guint32 project_addr; + guint8 project_id_count; + guint8 read_buf[10] = { 0 }; + guint8 write_buf[ISP_PACKET_SIZE] = {0}; + g_autoptr(FuDeviceLocker) locker = NULL; + g_autoptr(GBytes) fw = NULL; + g_autoptr(GPtrArray) chunks = NULL; + + /* open device */ + locker = fu_device_locker_new (parent, error); + if (locker == NULL) + return FALSE; + + /* simple image */ + fw = fu_firmware_get_image_default_bytes (firmware, error); + if (fw == NULL) + return FALSE; + fwbuf = g_bytes_get_data (fw, &fwbufsz); + + /* enable ISP high priority */ + write_buf[0] = ISP_CMD_ENTER_FW_UPDATE; + write_buf[1] = 0x01; + fu_device_set_status (device, FWUPD_STATUS_DEVICE_BUSY); + if (!fu_vli_usbhub_device_i2c_write (parent, + UC_FOREGROUND_SLAVE_ADDR, + UC_FOREGROUND_OPCODE, + write_buf, + 2, + error)) { + g_prefix_error (error, "failed to enable ISP: "); + return FALSE; + } + if (!fu_vli_usbhub_device_rtd21xx_read_status (self, NULL, error)) + return FALSE; + + /* get project ID address */ + write_buf[0] = ISP_CMD_GET_PROJECT_ID_ADDR; + fu_device_set_status (device, FWUPD_STATUS_DEVICE_READ); + if (!fu_vli_usbhub_device_i2c_write (parent, + UC_FOREGROUND_SLAVE_ADDR, + UC_FOREGROUND_OPCODE, + write_buf, 1, + error)) { + g_prefix_error (error, "failed to get project ID address: "); + return FALSE; + } + + /* read back 6 bytes data */ + g_usleep (I2C_DELAY_AFTER_SEND * 40); + if (!fu_vli_usbhub_device_i2c_read (parent, + UC_FOREGROUND_SLAVE_ADDR, + UC_FOREGROUND_STATUS, + read_buf, 6, + error)) { + g_prefix_error (error, "failed to read project ID: "); + return FALSE; + } + if (read_buf[0] != ISP_STATUS_IDLE_SUCCESS) { + g_prefix_error (error, "failed project ID with error 0x%02x", read_buf[0]); + return FALSE; + } + + /* verify project ID */ + project_addr = fu_common_read_uint32 (read_buf + 1, G_BIG_ENDIAN); + project_id_count = read_buf[5]; + write_buf[0] = ISP_CMD_SYNC_IDENTIFY_CODE; + if (!fu_memcpy_safe (write_buf, sizeof(write_buf), 0x1, /* dst */ + fwbuf, fwbufsz, project_addr, /* src */ + project_id_count, error)) { + g_prefix_error (error, "failed to write project ID from 0x%04x: ", project_addr); + return FALSE; + } + fu_device_set_status (device, FWUPD_STATUS_DEVICE_BUSY); + if (!fu_vli_usbhub_device_i2c_write (parent, + UC_FOREGROUND_SLAVE_ADDR, + UC_FOREGROUND_OPCODE, + write_buf, + project_id_count + 1, + error)) { + g_prefix_error (error, "failed to send fw update start cmd: "); + return FALSE; + } + if (!fu_vli_usbhub_device_rtd21xx_read_status (self, NULL, error)) + return FALSE; + + /* background FW update start command */ + write_buf[0] = ISP_CMD_FW_UPDATE_START; + fu_common_write_uint16 (write_buf + 1, ISP_DATA_BLOCKSIZE, G_BIG_ENDIAN); + if (!fu_vli_usbhub_device_i2c_write (parent, + UC_FOREGROUND_SLAVE_ADDR, + UC_FOREGROUND_OPCODE, + write_buf, 3, + error)) { + g_prefix_error (error, "failed to send fw update start cmd: "); + return FALSE; + } + + /* send data */ + fu_device_set_status (device, FWUPD_STATUS_DEVICE_WRITE); + chunks = fu_chunk_array_new_from_bytes (fw, + 0x00, /* start addr */ + 0x00, /* page_sz */ + ISP_DATA_BLOCKSIZE); + for (guint i = 0; i < chunks->len; i++) { + FuChunk *chk = g_ptr_array_index (chunks, i); + if (!fu_vli_usbhub_device_rtd21xx_read_status (self, NULL, error)) + return FALSE; + if (!fu_vli_usbhub_device_i2c_write (parent, + UC_FOREGROUND_SLAVE_ADDR, + UC_FOREGROUND_ISP_DATA_OPCODE, + (guint8 *) chk->data, + chk->data_sz, + error)) { + g_prefix_error (error, "failed to write @0x%04x: ", chk->address); + return FALSE; + } + + /* update progress */ + fu_device_set_progress_full (device, (gsize) i, (gsize) chunks->len); + } + + /* update finish command */ + fu_device_set_status (device, FWUPD_STATUS_DEVICE_BUSY); + if (!fu_vli_usbhub_device_rtd21xx_read_status (self, NULL, error)) + return FALSE; + write_buf[0] = ISP_CMD_FW_UPDATE_ISP_DONE; + if (!fu_vli_usbhub_device_i2c_write (parent, + UC_FOREGROUND_SLAVE_ADDR, + UC_FOREGROUND_OPCODE, + write_buf, 1, + error)) { + g_prefix_error (error, "failed update finish cmd: "); + return FALSE; + } + + /* exit background-fw mode */ + fu_device_set_status (device, FWUPD_STATUS_DEVICE_RESTART); + fu_device_set_progress (device, 0); + if (!fu_vli_usbhub_device_rtd21xx_read_status (self, NULL, error)) + return FALSE; + write_buf[0] = ISP_CMD_FW_UPDATE_EXIT; + if (!fu_vli_usbhub_device_i2c_write (parent, + UC_FOREGROUND_SLAVE_ADDR, + UC_FOREGROUND_OPCODE, + write_buf, 1, + error)) { + g_prefix_error (error, "FwUpdate exit: "); + return FALSE; + } + + /* the device needs some time to restart with the new firmware before + * it can be queried again */ + for (guint i = 0; i < 100; i++) { + g_usleep (200000); + fu_device_set_progress (device, i); + } + + /* success */ + return TRUE; +} + +static gboolean +fu_vli_usbhub_rtd21xx_device_reload (FuDevice *device, GError **error) +{ + FuVliUsbhubDevice *parent = FU_VLI_USBHUB_DEVICE (fu_device_get_parent (device)); + g_autoptr(FuDeviceLocker) locker = NULL; + + /* open parent device */ + locker = fu_device_locker_new (parent, error); + if (locker == NULL) + return FALSE; + return fu_vli_usbhub_rtd21xx_device_setup (device, error); +} + +static gboolean +fu_vli_usbhub_rtd21xx_device_probe (FuDevice *device, GError **error) +{ + FuVliDeviceKind device_kind = FU_VLI_DEVICE_KIND_RTD21XX; + FuVliUsbhubDevice *parent = FU_VLI_USBHUB_DEVICE (fu_device_get_parent (device)); + g_autofree gchar *instance_id = NULL; + + fu_device_set_name (device, fu_vli_common_device_kind_to_string (device_kind)); + + /* add instance ID */ + instance_id = g_strdup_printf ("USB\\VID_%04X&PID_%04X&I2C_%s", + fu_usb_device_get_vid (FU_USB_DEVICE (parent)), + fu_usb_device_get_pid (FU_USB_DEVICE (parent)), + fu_vli_common_device_kind_to_string (device_kind)); + fu_device_add_instance_id (device, instance_id); + return TRUE; +} + +static void +fu_vli_usbhub_rtd21xx_device_init (FuVliUsbhubRtd21xxDevice *self) +{ + fu_device_add_icon (FU_DEVICE (self), "video-display"); + fu_device_set_protocol (FU_DEVICE (self), "com.vli.i2c"); + fu_device_add_flag (FU_DEVICE (self), FWUPD_DEVICE_FLAG_UPDATABLE); + fu_device_add_flag (FU_DEVICE (self), FWUPD_DEVICE_FLAG_NO_GUID_MATCHING); + fu_device_add_flag (FU_DEVICE (self), FWUPD_DEVICE_FLAG_DUAL_IMAGE); + fu_device_set_version_format (FU_DEVICE (self), FWUPD_VERSION_FORMAT_PAIR); + fu_device_set_install_duration (FU_DEVICE (self), 100); /* seconds */ + fu_device_set_logical_id (FU_DEVICE (self), "I2C"); + fu_device_retry_set_delay (FU_DEVICE (self), 30); /* ms */ +} + +static void +fu_vli_usbhub_rtd21xx_device_class_init (FuVliUsbhubRtd21xxDeviceClass *klass) +{ + FuDeviceClass *klass_device = FU_DEVICE_CLASS (klass); + klass_device->probe = fu_vli_usbhub_rtd21xx_device_probe; + klass_device->setup = fu_vli_usbhub_rtd21xx_device_setup; + klass_device->reload = fu_vli_usbhub_rtd21xx_device_reload; + klass_device->attach = fu_vli_usbhub_rtd21xx_device_attach; + klass_device->detach = fu_vli_usbhub_rtd21xx_device_detach; + klass_device->write_firmware = fu_vli_usbhub_rtd21xx_device_write_firmware; +} + +FuDevice * +fu_vli_usbhub_rtd21xx_device_new (FuVliUsbhubDevice *parent) +{ + FuVliUsbhubRtd21xxDevice *self = g_object_new (FU_TYPE_VLI_USBHUB_RTD21XX_DEVICE, + "parent", parent, + NULL); + return FU_DEVICE (self); +} diff --git a/plugins/vli/fu-vli-usbhub-rtd21xx-device.h b/plugins/vli/fu-vli-usbhub-rtd21xx-device.h new file mode 100644 index 000000000..174934d8b --- /dev/null +++ b/plugins/vli/fu-vli-usbhub-rtd21xx-device.h @@ -0,0 +1,19 @@ +/* + * Copyright (C) 2019-2020 Richard Hughes + * + * SPDX-License-Identifier: LGPL-2.1+ + */ + +#pragma once + +#include "fu-plugin.h" + +#define FU_TYPE_VLI_USBHUB_RTD21XX_DEVICE (fu_vli_usbhub_rtd21xx_device_get_type ()) +G_DECLARE_FINAL_TYPE (FuVliUsbhubRtd21xxDevice, fu_vli_usbhub_rtd21xx_device, FU, VLI_USBHUB_RTD21XX_DEVICE, FuDevice) + +struct _FuVliUsbhubRtd21xxDeviceClass +{ + FuDeviceClass parent_class; +}; + +FuDevice *fu_vli_usbhub_rtd21xx_device_new (FuVliUsbhubDevice *parent); diff --git a/plugins/vli/meson.build b/plugins/vli/meson.build index 7f8fc616c..8c3deb891 100644 --- a/plugins/vli/meson.build +++ b/plugins/vli/meson.build @@ -24,6 +24,7 @@ shared_module('fu_plugin_vli', 'fu-vli-usbhub-i2c-common.c', 'fu-vli-usbhub-msp430-device.c', 'fu-vli-usbhub-pd-device.c', + 'fu-vli-usbhub-rtd21xx-device.c', ], include_directories : [ root_incdir, diff --git a/plugins/vli/vli-usbhub-lenovo.quirk b/plugins/vli/vli-usbhub-lenovo.quirk index 637c1aeb2..e35fc5a9c 100644 --- a/plugins/vli/vli-usbhub-lenovo.quirk +++ b/plugins/vli/vli-usbhub-lenovo.quirk @@ -174,6 +174,13 @@ Plugin = vli GType = FuVliUsbhubDevice Flags = usb2 ParentGuid = USB\VID_17EF&PID_3094 +[DeviceInstanceId=USB\VID_17EF&PID_3093] +Plugin = vli +GType = FuVliUsbhubDevice +Flags = has-rtd21xx +ParentGuid = USB\VID_17EF&PID_3094 +[DeviceInstanceId=USB\VID_17EF&PID_3093&I2C_REALTEK] +Name = RTD2181S [DeviceInstanceId=USB\VID_17EF&PID_721C&APP_26] ProxyGuid = USB\VID_17EF&PID_3094 FirmwareSize = 0x8000 From fd0ee5153edc6515480b50fbd4c4aa219e5aa7ea Mon Sep 17 00:00:00 2001 From: Richard Hughes Date: Mon, 27 Jul 2020 15:17:39 +0100 Subject: [PATCH 336/607] Add some of the HSI specification to the generated documentation --- docs/fwupd-docs.xml | 1 + docs/hsi.xml | 872 ++++++++++++++++++++++++++++ docs/meson.build | 1 + libfwupd/fwupd-security-attr.h | 6 +- libfwupdplugin/fu-security-attrs.c | 18 + libfwupdplugin/fu-self-test.c | 7 + plugins/pci-mei/fu-plugin-pci-mei.c | 4 + 7 files changed, 906 insertions(+), 3 deletions(-) create mode 100644 docs/hsi.xml diff --git a/docs/fwupd-docs.xml b/docs/fwupd-docs.xml index c2cdd5d9a..3250d6fda 100644 --- a/docs/fwupd-docs.xml +++ b/docs/fwupd-docs.xml @@ -68,6 +68,7 @@ + API Index diff --git a/docs/hsi.xml b/docs/hsi.xml new file mode 100644 index 000000000..288450519 --- /dev/null +++ b/docs/hsi.xml @@ -0,0 +1,872 @@ + + + + Host Security ID Specification + + + This specification is still in active development: it is incomplete, + subject to change, and may have errors; use this at your own risk. + It is based on publicly available information. + + + + + + + + + Introduction + + Not all system vendors prioritize building a secure platform. + The truth is that security costs money. + Vendors have to choose between saving a few cents on a bill-of-materials + by sharing a SPI chip, or correctly implementing BootGuard. + Discovering security vulnerabilities often takes an external researcher + filing a disclosure. + These disclosures are often technical in nature and difficult for an + average consumer to decipher. + + + The Linux Vendor Firmware Service (LVFS) could provide some + easy-to-understand information to + people buying hardware. + The service already knows a huge amount of information about machines + from signed reports uploaded to the LVFS and from analyzing firmware binaries. + However this information alone does not explain firmware security to the + user in a way they can actually interpret. + + + + + Other Tools + + Traditionally, figuring out the true security of your hardware and firmware + requires sifting through the marketing documentation provided by the + OEM and in many cases just “trusting” they did it right. + Tools such as Chipsec can check the hardware configuration, but they do + not work out of the box and use technical jargon that an average user + cannot interpret. + Unfortunately, running a tool like Chipsec requires that you actively + turn off some security layers such as UEFI Secure Boot, and allow 3rd + party unsigned kernel modules to be loaded. + + + + + Verifying Host Firmware Security + + To start out some core protections must be assigned a relative importance. + Then an evaluation must be done to determine how each vendor is conforming + to the model. + For instance, a user might say that for home use any hardware the bare + minimum security level (HSI:1) is good enough. + For a work laptop the company IT department might restrict the choice of + models to anything meeting the criteria of level HSI:2 or + above. + A journalist or a security researcher would only buy level HSI:3 + and above. + The reality is that HSI:4 is going to be more expensive + than some unbranded hardware that is rated HSI:0. + + + To be trusted, this rating information should be distributed in a + centralized agnostic database such as the LVFS. + + + Of course, tools need to detect implementation errors, and to verify that + the model that is measured does indeed match the HSI level advertised by + the LVFS. + Some existing compliance solutions place the burden on the OEM to define + what firmware security has been implemented, which is easy to get wrong + and in some cases impossible to verify. + + + For this reason HSI will only measure security protections that can be + verified by the end user without requiring any extra hardware to be + connected, additional software to be installed, or disabling any existing + security layers to measure. + + + + + Runtime Behavior + + Orthogonal to the security features provided by the firmware there are + other security considerations related to the firmware which may require + internet access to discover or that runtime OS changes directly affect + the security of the firmware. + It would not make sense to have have updates on the LVFS + as a requirement for a specific security level as this would mean + offline the platform might be a higher level initially but as soon as + it is brought online it is downgraded which would be really confusing to + users. + The core security level will not change at + Operating System runtime, but the suffix may. + + + + + HSI:0 (Insecure) + + The lowest security level with little or no detected firmware protections. + This is the default security level if no tests can be run or some tests + in the next security level have failed. + + + + + HSI:1 (Critical) + + This security level corresponds to the most basic of security protections + considered essential by security professionals. + Any failures at this level would have critical security impact. + + + + + HSI:3 (Theoretical) + + This security level corresponds to firmware security issues that pose a + theoretical concern or where any exploit would be difficult or + impractical to use. + At this level various technologies may be employed to protect the boot + process from modification by an attacker with local access to the machine. + + + + + HSI:4 (System Protection) + + This security level corresponds to out-of-band protection of the system + firmware perhaps including recovery. + + + + + HSI:5 (System Attestation) + + This security level corresponds to out-of-band attestation of the system + firmware. + There are currently no tests implemented for HSI:5 and so this security + level cannot yet be obtained. + + + + + HSI Runtime Suffix <code>U</code> + + Updates available on the + Linux Vendor Firmware Service which are less than 12 months old. + + + + + HSI Runtime Suffix <code>A</code> + + Attestation data is available to verify the current system firmware. + For most UEFI platforms, this is usually the Trusted Platform Module (TPM) + PCR0 hash, but other attestation checksums could be used. + + + + + HSI Runtime Suffix <code>!</code> + + A runtime security issue detected. + + + + + UEFI + Secure Boot has been turned off. v1.5.0 + + + + + The kernel is + tainted due to a non-free module or critical firmware issue. v1.5.0 + + + + + The kernel is not not + locked down. v1.5.0 + + + + + Unencrypted + swap partition. v1.5.0 + + + + + The installed fwupd is running with + custom or modified plugins. v1.5.0 + + + + + + + Tests included in fwupd + + The set of tests is currently x86 UEFI-centric, but will be expanded + in the future for various ARM or RISC-V firmware protections as required. + Where the requirement is architecture or processor specific it has been noted. + + + + + BIOS Write Enable (BWE) + + Intel hardware provides this mechanism to protect the SPI ROM chip + located on the motherboard from being overwritten by the operating system. + + + + + For HSI-1 the ``BIOSWE`` bit must be unset. v1.5.0 + + + + + + See also: + + + + Intel C200 Datasheet + + + + + + + + + BIOS Lock Enable (BLE) + + If the lock bit is set then System Management Interrupts (SMIs) are + raised when setting BIOS Write Enable. + The BLE` bit must be enabled in the PCH otherwise + BIOSWE can easily be unset. + + + + + For HSI-1 this should be set. v1.5.0 + + + + + + See also: + + + + Intel C200 Datasheet + + + + + + + + + SMM Bios Write Protect (SMM_BWP) + + This bit set defines when the BIOS region can be written by the host. + The SMM_BWP bit must be set to make the BIOS region + non-writable unless all processors are in system management mode. + + + + + For HSI-1 this should be set v1.5.0 + + + + + + See also: + + + + Intel C200 Datasheet + + + + + + + + + UEFI Secure Boot Revocation database (dbx) + + The UEFI Secure boot Revocation database is a list of banned hashes that + must not be allowed to execute when Secure Boot is turned on. + Vulnerabilities like the Kaspersky signed bootloader remove all + protections of SecureBoot and this is why an up-to-date dbx is + considered such an important part of firmware security. + + + The dbx list is updated infrequently and is normally part of the system + firmware updates issued by system manufacturers or operating system vendors. + + + + + For HSI-1 this should be provided v1.5.0 + + + + + + See also: + + + + Microsoft Windows Secure Boot Guidance + + + + + + + + + TPM 2.0 Present + + A TPM securely stores platform specific secrets that can only be divulged + to trusted consumers in a secure environment. + + + + + For HSI-1 this should be available for use by the OS or applications v1.5.0 + + + + + + See also: + + + + Wikipedia TPM Article + + + + + + + + + ME not in manufacturing mode + + There have been some unfortunate cases of the ME being distributed in + manufacturing mode. + In manufacturing mode many features from the ME can be interacted with + that decrease the platform’s security. + + + + + For HSI-1 this should be unset v1.5.0 + + + + + + See also: + + + + ME Manufacturing Mode: obscured dangers + + + + + Intel security advisory SA-00086 + + + + + + + + + ME Flash Descriptor Override + + The Flash Descriptor Security Override Strap is not accessible to end + users on consumer boards and Intel stresses that this is for debugging only. + + + + + For HSI-1 this should be unset v1.5.0 + + + + + + See also: + + + + Chromium documentation for Intel ME + + + + + + + + + CSME Version + + Converged Security and Manageability Engine is a standalone management + module that can manage and control some local devices without the host + CPU involvement. + The CSME lives in the PCH and can only be updated by the OEM vendor. + The version of the CSME module can be checked to detect the most common + and serious vulnerabilities. + + + + + For HSI-1 this should not be vulnerable to CVE-2017-5705, CVE-2017-5708, + CVE-2017-5711, CVE-2017-5712, CVE-2017-5711, CVE-2017-5712, CVE-2017-5706, + CVE-2017-5709, CVE-2017-5707 or CVE-2017-5710 v1.5.0 + + + + + + See also: + + + + Intel CSME Security Review Cumulative Update + + + + + + + + + Intel DCI + + Newer Intel CPUs support debugging over USB3 via a proprietary Direct + Connection Interface (DCI) with the use of off-the-shelf hardware. + DCI should always be disabled and locked on production hardware. + + + + + For HSI-1 this should be disabled. v1.5.0 + + + + + For HSI-2 this should be locked. v1.5.0 + + + + + + See also: + + + + Intel Direct Connect Interface + + + + + Chipsec 4xxlp register definitions + + + + + RISC-V EDK PCH register definitions + + + + + + + + + PCR0 TPM Event Log Reconstruction + + The TPM event log records which events are registered for the PCR0 hash. + When reconstructed the event log values should always match the TPM PCR0. + If extra events are included in the event log, or some are missing, + the reconstitution will fail. + + + + + For HSI-2 this should match the TPM-provided PCR0 v1.5.0 + + + + + + See also: + + + + Linux Kernel TPM Documentation + + + + + + + + Pre-boot DMA protection + + The IOMMU on modern systems is used to mitigate against DMA attacks. + All I/O for devices capable of DMA is mapped into a private virtual + memory region. + The ACPI DMAR table is used to set up pre-boot DMA protection which + eliminates some firmware attacks. + + + + + For HSI-2 this should be available v1.5.0 + + + + + + See also: + + + + Wikipedia IOMMU article + + + + + + + + + Intel BootGuard + + BootGuard is a processor feature that prevents the machine from running + firmware images not released by the system manufacturer. + It forms a root-of-trust by fusing in cryptographic keys into the processor + itself that are used to verify the Authenticated Code Modules found in + the SPI flash. + + + + + For HSI-1 verified boot must be enabled with ACM protection. v1.5.0 + + + + + For HSI-2 the error enforcement policy must be set to “immediate shutdown”. v1.5.0 + + + + + + See also: + + + + Coreboot documentation + + + + + + + + + Suspend to RAM disabled + + Suspend to Ram (S3) keeps the raw contents of the DRAM refreshed when + the system is asleep. + This means that the memory modules can be physically removed and the + contents recovered, or a cold boot attack can be performed with a USB device. + + + + + For HSI-3 the firmware should be configured to prefer using suspend + to idle instead of suspend to ram or to not offer suspend to + RAM. v1.5.0 + + + + + + See also: + + + + Wikipedia article on cold boot attacks + + + + + + + + + Intel CET Available + + Control enforcement technology is available on new Intel platforms and + prevents exploits from hijacking the control-flow transfer instructions + for both forward-edge (indirect call/jmp) and back-edge transfer (ret). + + + + + For HSI-3 this should be available and enabled v1.5.0 + + + + + + See also: + + + + Intel CET Technology Preview + + + + + + + + + DRAM total memory encryption (TME) + + Total memory encryption technology is used by the firmware on supported + SOCs to encrypt all data on external memory buses. + It mitigates against an attacker being able to capture memory data while + the system is running or to capture memory by removing a DRAM chip. + + + + + For HSI-4 this should be supported and enabled v1.5.0 + + + + + + See also: + + + + Intel TME Press Release + + 0 + + + + + + Supervisor Mode Access Prevention + + Without Supervisor Mode Access Prevention, the supervisor code usually + has full read and write access to user-space memory mappings. + This can make exploits easier to write, as it allows the kernel to + access user-space memory when it did not intend to. + + + + + For HSI-4 the SMAP and SMEP features should be available on the CPU. v1.5.0 + + + + + + See also: + + + + Wikipedia SMAP Article + + + + + + + + + Kernel DMA protection + + The IOMMU on modern systems is used to mitigate against DMA attacks. + All I/O for devices capable of DMA is mapped into a private virtual + memory region. + Common implementations are Intel VT-d and AMD-Vi. + + + + + For HSI-2 this should be available for use. v1.5.0 + + + + + + See also: + + + + Wikipedia IOMMU article + + + + + + + + + Suspend-to-Idle + + The platform should be set up with Suspend-to-Idle as the default S3 + sleep state. + + + + + For HSI-3 this should be set v1.5.0 + + + + + + + Conclusion + + Any system with a Host Security ID of 0 can easily be + modified from userspace. + PCs with confidential documents should have a HSI:3 or + higher level of protection. + In a graphical tool that would show details about the computer (such as + GNOME Control Center’s details tab) the OS could display a field + indicating Host Security ID. + The ID should be shown with an alert color if the security is not at + least HSI:1 or the suffix is !. + + + On Linux fwupd is used to enumerate and update firmware. + It exports a property HostSecurityId and a + GetHostSecurityAttrs() method. + The attributes are supposed to represent the system as a whole + but individual (internal) devices are able to make a claim that they + worsened the state of the security of the system. + Certain attributes can “obsolete” other attributes. + An example is BIOSGuard will set obsoletes to org.intel.prx. + + + A plugin method gets called on each plugin which adds attributes directly + from the hardware or kernel. + Several attributes may be dependent upon the kernel performing measurements + and it will take time for these to be upstreamed. + In some cases security level measurements will only be possible on systems + with a newer kernel. + + + The long term goal is to increase the HSI:x level of systems + being sold to consumers. + By making some of the HSI:x attributes part of the LVFS + uploaded report we can allow users to compare vendors and models before + purchasing hardware. + + + + + Intentional Omissions + + + Intel SGX + + This is not widely used as it has several high severity security issues. + + + + Intel MPX + + MPX support was removed from GCC and the Linux kernel in 2019 and it is + now considered obsolete. + + + + + Further Work + + More internal and external devices should be factored into the security + equation. + For now the focus for further tests should be around internal device + firmware as it is what can be most directly controlled by fwupd and the + hardware manufacturer. + + + Security conscious manufacturers are actively participating in the + development of future initiatives in the Trusted Computing Group (TCG). + As those become ratified standards that are available in hardware, + there are opportunities for synergy with this specification. + + + + + diff --git a/docs/meson.build b/docs/meson.build index f24e07422..de07c3bf8 100644 --- a/docs/meson.build +++ b/docs/meson.build @@ -9,6 +9,7 @@ gnome.gtkdoc( ], content_files : [ 'tutorial.xml', + 'hsi.xml', ], main_xml : 'fwupd-docs.xml', install : true diff --git a/libfwupd/fwupd-security-attr.h b/libfwupd/fwupd-security-attr.h index 00f0004cd..343e67647 100644 --- a/libfwupd/fwupd-security-attr.h +++ b/libfwupd/fwupd-security-attr.h @@ -113,9 +113,9 @@ typedef enum { #define FWUPD_SECURITY_ATTR_ID_ACPI_DMAR "org.fwupd.hsi.AcpiDmar" /* Since: 1.5.0 */ #define FWUPD_SECURITY_ATTR_ID_ENCRYPTED_RAM "org.fwupd.hsi.EncryptedRam" /* Since: 1.5.0 */ -#define FWUPD_SECURITY_ATTR_ID_FWUPD_ATTESTATION "org.fwupd.hsi.FwupdAttestation" /* Since: 1.5.0 */ -#define FWUPD_SECURITY_ATTR_ID_FWUPD_PLUGINS "org.fwupd.hsi.FwupdPlugins" /* Since: 1.5.0 */ -#define FWUPD_SECURITY_ATTR_ID_FWUPD_UPDATES "org.fwupd.hsi.FwupdUpdates" /* Since: 1.5.0 */ +#define FWUPD_SECURITY_ATTR_ID_FWUPD_ATTESTATION "org.fwupd.hsi.Fwupd.Attestation" /* Since: 1.5.0 */ +#define FWUPD_SECURITY_ATTR_ID_FWUPD_PLUGINS "org.fwupd.hsi.Fwupd.Plugins" /* Since: 1.5.0 */ +#define FWUPD_SECURITY_ATTR_ID_FWUPD_UPDATES "org.fwupd.hsi.Fwupd.Updates" /* Since: 1.5.0 */ #define FWUPD_SECURITY_ATTR_ID_INTEL_BOOTGUARD_ENABLED "org.fwupd.hsi.IntelBootguard.Enabled" /* Since: 1.5.0 */ #define FWUPD_SECURITY_ATTR_ID_INTEL_BOOTGUARD_VERIFIED "org.fwupd.hsi.IntelBootguard.Verified" /* Since: 1.5.0 */ #define FWUPD_SECURITY_ATTR_ID_INTEL_BOOTGUARD_ACM "org.fwupd.hsi.IntelBootguard.Acm" /* Since: 1.5.0 */ diff --git a/libfwupdplugin/fu-security-attrs.c b/libfwupdplugin/fu-security-attrs.c index 29603cc72..e7a1c17bb 100644 --- a/libfwupdplugin/fu-security-attrs.c +++ b/libfwupdplugin/fu-security-attrs.c @@ -17,6 +17,9 @@ struct _FuSecurityAttrs { GPtrArray *attrs; }; +/* probaly sane to *not* make this part of the ABI */ +#define FWUPD_SECURITY_ATTR_ID_DOC_URL "https://fwupd.github.io/hsi.html" + G_DEFINE_TYPE (FuSecurityAttrs, fu_security_attrs, G_TYPE_OBJECT) static void @@ -60,6 +63,21 @@ fu_security_attrs_append (FuSecurityAttrs *self, FwupdSecurityAttr *attr) g_warning ("%s has no plugin set", fwupd_security_attr_get_appstream_id (attr)); } + + /* sanity check, and correctly prefix the URLs with the current mirror */ + if (fwupd_security_attr_get_url (attr) == NULL) { + g_autofree gchar *url = NULL; + url = g_strdup_printf ("%s%s", + FWUPD_SECURITY_ATTR_ID_DOC_URL, + fwupd_security_attr_get_appstream_id (attr)); + fwupd_security_attr_set_url (attr, url); + } else if (g_str_has_prefix (fwupd_security_attr_get_url (attr), "#")) { + g_autofree gchar *url = NULL; + url = g_strdup_printf ("%s%s", + FWUPD_SECURITY_ATTR_ID_DOC_URL, + fwupd_security_attr_get_url (attr)); + fwupd_security_attr_set_url (attr, url); + } g_ptr_array_add (self->attrs, g_object_ref (attr)); } diff --git a/libfwupdplugin/fu-self-test.c b/libfwupdplugin/fu-self-test.c index 245a69232..ca4c8575a 100644 --- a/libfwupdplugin/fu-self-test.c +++ b/libfwupdplugin/fu-self-test.c @@ -1807,6 +1807,7 @@ fu_security_attrs_hsi_func (void) fwupd_security_attr_set_plugin (attr, "test"); fwupd_security_attr_set_level (attr, FWUPD_SECURITY_ATTR_LEVEL_CRITICAL); fwupd_security_attr_add_flag (attr, FWUPD_SECURITY_ATTR_FLAG_SUCCESS); + fwupd_security_attr_set_url (attr, "http://test"); fu_security_attrs_append (attrs, attr); hsi2 = fu_security_attrs_calculate_hsi (attrs, FU_SECURITY_ATTRS_FLAG_NONE); g_assert_cmpstr (hsi2, ==, "HSI:1"); @@ -1816,6 +1817,7 @@ fu_security_attrs_hsi_func (void) attr = fwupd_security_attr_new ("org.fwupd.hsi.PRX"); fwupd_security_attr_set_plugin (attr, "test"); fwupd_security_attr_set_level (attr, FWUPD_SECURITY_ATTR_LEVEL_IMPORTANT); + fwupd_security_attr_set_url (attr, "http://test"); fu_security_attrs_append (attrs, attr); hsi3 = fu_security_attrs_calculate_hsi (attrs, FU_SECURITY_ATTRS_FLAG_NONE); g_assert_cmpstr (hsi3, ==, "HSI:1"); @@ -1827,6 +1829,7 @@ fu_security_attrs_hsi_func (void) fwupd_security_attr_set_level (attr, FWUPD_SECURITY_ATTR_LEVEL_THEORETICAL); fwupd_security_attr_add_flag (attr, FWUPD_SECURITY_ATTR_FLAG_SUCCESS); fwupd_security_attr_add_obsolete (attr, "org.fwupd.hsi.PRX"); + fwupd_security_attr_set_url (attr, "http://test"); fu_security_attrs_append (attrs, attr); fu_security_attrs_depsolve (attrs); hsi4 = fu_security_attrs_calculate_hsi (attrs, FU_SECURITY_ATTRS_FLAG_NONE); @@ -1838,6 +1841,7 @@ fu_security_attrs_hsi_func (void) fwupd_security_attr_set_plugin (attr, "test"); fwupd_security_attr_add_flag (attr, FWUPD_SECURITY_ATTR_FLAG_SUCCESS); fwupd_security_attr_add_flag (attr, FWUPD_SECURITY_ATTR_FLAG_RUNTIME_ISSUE); + fwupd_security_attr_set_url (attr, "http://test"); fu_security_attrs_append (attrs, attr); hsi5 = fu_security_attrs_calculate_hsi (attrs, FU_SECURITY_ATTRS_FLAG_NONE); g_assert_cmpstr (hsi5, ==, "HSI:3"); @@ -1849,6 +1853,7 @@ fu_security_attrs_hsi_func (void) fwupd_security_attr_add_flag (attr, FWUPD_SECURITY_ATTR_FLAG_RUNTIME_UPDATES); fwupd_security_attr_add_flag (attr, FWUPD_SECURITY_ATTR_FLAG_RUNTIME_ATTESTATION); fwupd_security_attr_add_flag (attr, FWUPD_SECURITY_ATTR_FLAG_SUCCESS); + fwupd_security_attr_set_url (attr, "http://test"); fu_security_attrs_append (attrs, attr); hsi6 = fu_security_attrs_calculate_hsi (attrs, FU_SECURITY_ATTRS_FLAG_NONE); g_assert_cmpstr (hsi6, ==, "HSI:3+UA"); @@ -1858,6 +1863,7 @@ fu_security_attrs_hsi_func (void) attr = fwupd_security_attr_new (FWUPD_SECURITY_ATTR_ID_KERNEL_SWAP); fwupd_security_attr_set_plugin (attr, "test"); fwupd_security_attr_add_flag (attr, FWUPD_SECURITY_ATTR_FLAG_RUNTIME_ISSUE); + fwupd_security_attr_set_url (attr, "http://test"); fu_security_attrs_append (attrs, attr); hsi7 = fu_security_attrs_calculate_hsi (attrs, FU_SECURITY_ATTRS_FLAG_NONE); g_assert_cmpstr (hsi7, ==, "HSI:3+UA!"); @@ -1867,6 +1873,7 @@ fu_security_attrs_hsi_func (void) attr = fwupd_security_attr_new (FWUPD_SECURITY_ATTR_ID_KERNEL_SWAP); fwupd_security_attr_set_plugin (attr, "test"); fwupd_security_attr_add_flag (attr, FWUPD_SECURITY_ATTR_FLAG_RUNTIME_ISSUE); + fwupd_security_attr_set_url (attr, "http://test"); fu_security_attrs_append (attrs, attr); hsi8 = fu_security_attrs_calculate_hsi (attrs, FU_SECURITY_ATTRS_FLAG_ADD_VERSION); expected_hsi8 = g_strdup_printf ("HSI:3+UA! (v%d.%d.%d)", diff --git a/plugins/pci-mei/fu-plugin-pci-mei.c b/plugins/pci-mei/fu-plugin-pci-mei.c index 579046d16..3c24c3ce5 100644 --- a/plugins/pci-mei/fu-plugin-pci-mei.c +++ b/plugins/pci-mei/fu-plugin-pci-mei.c @@ -268,6 +268,7 @@ fu_plugin_add_security_attrs_bootguard_enabled (FuPlugin *plugin, FuSecurityAttr attr = fwupd_security_attr_new (FWUPD_SECURITY_ATTR_ID_INTEL_BOOTGUARD_ENABLED); fwupd_security_attr_set_plugin (attr, fu_plugin_get_name (plugin)); fwupd_security_attr_set_level (attr, FWUPD_SECURITY_ATTR_LEVEL_IMPORTANT); + fwupd_security_attr_set_url (attr, "#org.fwupd.hsi.Kernel.IntelBootguard"); fu_security_attrs_append (attrs, attr); /* disabled at runtime? */ @@ -295,6 +296,7 @@ fu_plugin_add_security_attrs_bootguard_verified (FuPlugin *plugin, FuSecurityAtt attr = fwupd_security_attr_new (FWUPD_SECURITY_ATTR_ID_INTEL_BOOTGUARD_VERIFIED); fwupd_security_attr_set_plugin (attr, fu_plugin_get_name (plugin)); fwupd_security_attr_set_level (attr, FWUPD_SECURITY_ATTR_LEVEL_IMPORTANT); + fwupd_security_attr_set_url (attr, "#org.fwupd.hsi.Kernel.IntelBootguard"); fu_security_attrs_append (attrs, attr); /* measured boot is not sufficient, verified is required */ @@ -349,6 +351,7 @@ fu_plugin_add_security_attrs_bootguard_policy (FuPlugin *plugin, FuSecurityAttrs attr = fwupd_security_attr_new (FWUPD_SECURITY_ATTR_ID_INTEL_BOOTGUARD_POLICY); fwupd_security_attr_set_plugin (attr, fu_plugin_get_name (plugin)); fwupd_security_attr_set_level (attr, FWUPD_SECURITY_ATTR_LEVEL_THEORETICAL); + fwupd_security_attr_set_url (attr, "#org.fwupd.hsi.Kernel.IntelBootguard"); fu_security_attrs_append (attrs, attr); /* policy must be to immediatly shutdown */ @@ -376,6 +379,7 @@ fu_plugin_add_security_attrs_bootguard_otp (FuPlugin *plugin, FuSecurityAttrs *a attr = fwupd_security_attr_new (FWUPD_SECURITY_ATTR_ID_INTEL_BOOTGUARD_OTP); fwupd_security_attr_set_plugin (attr, fu_plugin_get_name (plugin)); fwupd_security_attr_set_level (attr, FWUPD_SECURITY_ATTR_LEVEL_IMPORTANT); + fwupd_security_attr_set_url (attr, "#org.fwupd.hsi.Kernel.IntelBootguard"); fu_security_attrs_append (attrs, attr); /* ensure vendor set the FPF OTP fuse */ From 58ba785915a7be75b9caa41830acfa6191e8e6a7 Mon Sep 17 00:00:00 2001 From: Richard Hughes Date: Mon, 17 Aug 2020 15:00:49 +0100 Subject: [PATCH 337/607] Install the new dbx utility as fwupdbxtool --- contrib/fwupd.spec.in | 5 +++++ contrib/snap/dbxtool.wrapper | 2 ++ plugins/uefi-dbx/dbxtool.h2m | 7 +++++++ plugins/uefi-dbx/fu-dbxtool.c | 1 + plugins/uefi-dbx/meson.build | 22 ++++++++++++++++++++++ snap/snapcraft.yaml | 3 +++ 6 files changed, 40 insertions(+) create mode 100644 contrib/snap/dbxtool.wrapper create mode 100644 plugins/uefi-dbx/dbxtool.h2m diff --git a/contrib/fwupd.spec.in b/contrib/fwupd.spec.in index 222aa0ca3..28923ebea 100644 --- a/contrib/fwupd.spec.in +++ b/contrib/fwupd.spec.in @@ -137,6 +137,9 @@ Obsoletes: libebitdo < 0.7.5-3 Obsoletes: libdfu < 1.0.0 Obsoletes: fwupd-labels < 1.1.0-1 +Obsoletes: dbxtool < 9 +Provides: dbxtool + %if 0%{?rhel} > 7 Obsoletes: fwupdate < 11-4 Obsoletes: fwupdate-efi < 11-4 @@ -289,6 +292,7 @@ mkdir -p --mode=0700 $RPM_BUILD_ROOT%{_localstatedir}/lib/fwupd/gnupg %{_bindir}/fwupdtpmevlog %endif %{_bindir}/dfu-tool +%{_bindir}/dbxtool %{_bindir}/fwupdmgr %{_bindir}/fwupdtool %{_bindir}/fwupdagent @@ -323,6 +327,7 @@ mkdir -p --mode=0700 $RPM_BUILD_ROOT%{_localstatedir}/lib/fwupd/gnupg %{_datadir}/man/man1/fwupdtool.1.gz %{_datadir}/man/man1/fwupdagent.1.gz %{_datadir}/man/man1/dfu-tool.1.gz +%{_datadir}/man/man1/dbxtool.1.gz %{_datadir}/man/man1/fwupdmgr.1.gz %if 0%{?have_uefi} %{_datadir}/man/man1/fwupdate.1.gz diff --git a/contrib/snap/dbxtool.wrapper b/contrib/snap/dbxtool.wrapper new file mode 100644 index 000000000..d29ab9901 --- /dev/null +++ b/contrib/snap/dbxtool.wrapper @@ -0,0 +1,2 @@ +#!/bin/sh +exec "$SNAP/fwupd-command" $SNAP/bin/dbxtool $@ diff --git a/plugins/uefi-dbx/dbxtool.h2m b/plugins/uefi-dbx/dbxtool.h2m new file mode 100644 index 000000000..069b08e2d --- /dev/null +++ b/plugins/uefi-dbx/dbxtool.h2m @@ -0,0 +1,7 @@ +[DESCRIPTION] +.PP +This manual page documents briefly the \fBdbxtool\fR command. +.PP +\fBdbxtool\fR allows a user to operate on the UEFI dbx revokation list. +This tool can be used to list the current dbx contents or update it to a newer +version. diff --git a/plugins/uefi-dbx/fu-dbxtool.c b/plugins/uefi-dbx/fu-dbxtool.c index 2a9601e79..0da139314 100644 --- a/plugins/uefi-dbx/fu-dbxtool.c +++ b/plugins/uefi-dbx/fu-dbxtool.c @@ -1,4 +1,5 @@ /* + * Copyright (C) 2015-2017 Peter Jones * Copyright (C) 2020 Richard Hughes * * SPDX-License-Identifier: LGPL-2.1+ diff --git a/plugins/uefi-dbx/meson.build b/plugins/uefi-dbx/meson.build index 6961dfab2..cca0c6ceb 100644 --- a/plugins/uefi-dbx/meson.build +++ b/plugins/uefi-dbx/meson.build @@ -109,9 +109,31 @@ dbxtool = executable( fwupd, fwupdplugin, ], + install : true, + install_dir : bindir, c_args : cargs, ) +if get_option('man') + help2man = find_program('help2man') + extra = join_paths(meson.current_source_dir(), 'dbxtool.h2m') + custom_target('dbxtool-man', + input : dbxtool, + output : 'dbxtool.1', + command : [ + help2man, '@INPUT@', + '--no-info', + '--output', '@OUTPUT@', + '--name', 'dbxtool', + '--manual', 'User Commands', + '--version-string', fwupd_version, + '--include', extra, + ], + install : true, + install_dir : join_paths(mandir, 'man1'), + ) +endif + run_target('fuzz-efidbx', command: [ join_paths(meson.source_root(), 'contrib/afl-fuzz.py'), diff --git a/snap/snapcraft.yaml b/snap/snapcraft.yaml index 113e97d8e..5f1044aff 100644 --- a/snap/snapcraft.yaml +++ b/snap/snapcraft.yaml @@ -16,6 +16,8 @@ architectures: apps: dfu-tool: command: dfu-tool.wrapper + dbxtool: + command: dbxtool.wrapper fwupdtool: command: fwupdtool.wrapper completer: @@ -299,6 +301,7 @@ parts: source: contrib/snap stage: - dfu-tool.wrapper + - dbxtool.wrapper - fwupd-command - fwupdtool.wrapper - fwupd.wrapper From 82c3e3471d5f106ef6d75defac8030e2fde0e6af Mon Sep 17 00:00:00 2001 From: Mario Limonciello Date: Tue, 18 Aug 2020 19:48:05 -0500 Subject: [PATCH 338/607] Remove support for UEFI dbx security attribute This is no longer relevant as fwupd is providing dbxtool now. --- contrib/debian/rules | 3 +- contrib/fwupd.spec.in | 1 - docs/hsi.xml | 34 ------------ libfwupd/fwupd-security-attr.h | 1 - libfwupdplugin/fu-common.c | 14 ----- libfwupdplugin/fu-common.h | 2 - meson.build | 13 ----- meson_options.txt | 1 - plugins/uefi-dbx/fu-plugin-uefi-dbx.c | 74 --------------------------- plugins/uefi-dbx/fu-self-test.c | 35 ------------- plugins/uefi-dbx/fu-uefi-dbx-common.c | 18 ------- plugins/uefi-dbx/fu-uefi-dbx-common.h | 1 - src/fu-security-attr.c | 4 -- 13 files changed, 1 insertion(+), 200 deletions(-) diff --git a/contrib/debian/rules b/contrib/debian/rules index 7b8b19be2..e41695cae 100755 --- a/contrib/debian/rules +++ b/contrib/debian/rules @@ -20,7 +20,6 @@ ifeq (yes,$(shell dpkg-vendor --derives-from Ubuntu && echo yes)) SB_STYLE := ubuntu tar_name := fwupd_$(deb_version)_$(DEB_HOST_ARCH).tar.gz export FLASHROM=-Dplugin_flashrom=false - export DBX=-Defi_dbxdir=/usr/share/secureboot/updates/dbx else TMPLDIR := debian/fwupd-$(DEB_HOST_ARCH)-signed-template/usr/share/code-signing/fwupd-$(DEB_HOST_ARCH)-signed-template export FLASHROM=-Dplugin_flashrom=true @@ -43,7 +42,7 @@ override_dh_auto_configure: export DELL="-Dplugin_dell=false"; \ fi; \ if pkg-config --exists efivar; then \ - export UEFI="-Dplugin_uefi=true -Dplugin_redfish=true -Dplugin_nvme=true -Dplugin_msr=true $$DBX"; \ + export UEFI="-Dplugin_uefi=true -Dplugin_redfish=true -Dplugin_nvme=true -Dplugin_msr=true"; \ else \ export UEFI="-Dplugin_uefi=false -Dplugin_redfish=false -Dplugin_nvme=false -Dplugin_msr=false"; \ fi; \ diff --git a/contrib/fwupd.spec.in b/contrib/fwupd.spec.in index 28923ebea..fb8d43798 100644 --- a/contrib/fwupd.spec.in +++ b/contrib/fwupd.spec.in @@ -177,7 +177,6 @@ Data files for installed tests. --werror \ %endif -Dgtkdoc=true \ - -Defi_dbxdir=%{_datadir}/dbxtool \ %if 0%{?enable_tests} -Dtests=true \ %else diff --git a/docs/hsi.xml b/docs/hsi.xml index 288450519..522c2dce5 100644 --- a/docs/hsi.xml +++ b/docs/hsi.xml @@ -343,40 +343,6 @@ - - UEFI Secure Boot Revocation database (dbx) - - The UEFI Secure boot Revocation database is a list of banned hashes that - must not be allowed to execute when Secure Boot is turned on. - Vulnerabilities like the Kaspersky signed bootloader remove all - protections of SecureBoot and this is why an up-to-date dbx is - considered such an important part of firmware security. - - - The dbx list is updated infrequently and is normally part of the system - firmware updates issued by system manufacturers or operating system vendors. - - - - - For HSI-1 this should be provided v1.5.0 - - - - - - See also: - - - - Microsoft Windows Secure Boot Guidance - - - - - - - TPM 2.0 Present diff --git a/libfwupd/fwupd-security-attr.h b/libfwupd/fwupd-security-attr.h index 343e67647..fd8c533d3 100644 --- a/libfwupd/fwupd-security-attr.h +++ b/libfwupd/fwupd-security-attr.h @@ -138,7 +138,6 @@ typedef enum { #define FWUPD_SECURITY_ATTR_ID_SUSPEND_TO_RAM "org.fwupd.hsi.SuspendToRam" /* Since: 1.5.0 */ #define FWUPD_SECURITY_ATTR_ID_TPM_RECONSTRUCTION_PCR0 "org.fwupd.hsi.Tpm.ReconstructionPcr0" /* Since: 1.5.0 */ #define FWUPD_SECURITY_ATTR_ID_TPM_VERSION_20 "org.fwupd.hsi.Tpm.Version20" /* Since: 1.5.0 */ -#define FWUPD_SECURITY_ATTR_ID_UEFI_DBX "org.fwupd.hsi.Uefi.Dbx" /* Since: 1.5.0 */ #define FWUPD_SECURITY_ATTR_ID_UEFI_SECUREBOOT "org.fwupd.hsi.Uefi.SecureBoot" /* Since: 1.5.0 */ #define FWUPD_SECURITY_ATTR_ID_INTEL_DCI_ENABLED "org.fwupd.hsi.IntelDci.Enabled" /* Since: 1.5.0 */ #define FWUPD_SECURITY_ATTR_ID_INTEL_DCI_LOCKED "org.fwupd.hsi.IntelDci.Locked" /* Since: 1.5.0 */ diff --git a/libfwupdplugin/fu-common.c b/libfwupdplugin/fu-common.c index 887a2c7d7..4822fc9d0 100644 --- a/libfwupdplugin/fu-common.c +++ b/libfwupdplugin/fu-common.c @@ -1112,20 +1112,6 @@ fu_common_get_path (FuPathKind path_kind) return g_strdup (EFI_APP_LOCATION); #else return NULL; -#endif - /* /usr/share/fwupd/dbx */ - case FU_PATH_KIND_EFIDBXDIR: - tmp = g_getenv ("FWUPD_EFIDBXDIR"); - if (tmp != NULL) - return g_strdup (tmp); -#ifdef FWUPD_EFI_DBXDIR - tmp = g_getenv ("SNAP"); - if (tmp != NULL) - return g_build_filename (tmp, FWUPD_EFI_DBXDIR, NULL); - return g_strdup (FWUPD_EFI_DBXDIR); -#else - basedir = fu_common_get_path (FU_PATH_KIND_LOCALSTATEDIR_PKG); - return g_build_filename (basedir, "dbx", NULL); #endif /* /etc/fwupd */ case FU_PATH_KIND_SYSCONFDIR_PKG: diff --git a/libfwupdplugin/fu-common.h b/libfwupdplugin/fu-common.h index 836cc60a8..d8ac00ce2 100644 --- a/libfwupdplugin/fu-common.h +++ b/libfwupdplugin/fu-common.h @@ -59,7 +59,6 @@ typedef guint FuEndianType; * @FU_PATH_KIND_POLKIT_ACTIONS: The directory for policy kit actions (IE /usr/share/polkit-1/actions/) * @FU_PATH_KIND_OFFLINE_TRIGGER: The file for the offline trigger (IE /system-update) * @FU_PATH_KIND_SYSFSDIR_SECURITY: The sysfs security location (IE /sys/kernel/security) - * @FU_PATH_KIND_EFIDBXDIR: The location of the EFI dbx files * @FU_PATH_KIND_ACPI_TABLES: The location of the ACPI tables * * Path types to use when dynamically determining a path at runtime @@ -80,7 +79,6 @@ typedef enum { FU_PATH_KIND_POLKIT_ACTIONS, FU_PATH_KIND_OFFLINE_TRIGGER, FU_PATH_KIND_SYSFSDIR_SECURITY, - FU_PATH_KIND_EFIDBXDIR, FU_PATH_KIND_ACPI_TABLES, /*< private >*/ FU_PATH_KIND_LAST diff --git a/meson.build b/meson.build index d780f24ab..8cf660d7c 100644 --- a/meson.build +++ b/meson.build @@ -304,19 +304,6 @@ if build_standalone and get_option('plugin_uefi') efi_app_location = join_paths(libexecdir, 'fwupd', 'efi') conf.set_quoted ('EFI_APP_LOCATION', efi_app_location) - efi_dbxdir = get_option('efi_dbxdir') - if efi_dbxdir == '' - foreach dir : ['/usr/share/secureboot/updates/dbx', '/usr/share/dbxtool'] - if run_command('[', '-d', dir, ']').returncode() == 0 - efi_dbxdir = dir - endif - endforeach - endif - if efi_dbxdir != '' - message('efi-dbxdir: "@0@"'.format(efi_dbxdir)) - conf.set_quoted ('FWUPD_EFI_DBXDIR', efi_dbxdir) - endif - if host_cpu == 'x86' EFI_MACHINE_TYPE_NAME = 'ia32' gnu_efi_arch = 'ia32' diff --git a/meson_options.txt b/meson_options.txt index 031f68ed0..c2fb1f720 100644 --- a/meson_options.txt +++ b/meson_options.txt @@ -28,7 +28,6 @@ option('systemd_root_prefix', type: 'string', value: '', description: 'Directory option('elogind', type : 'boolean', value : false, description : 'enable elogind support') option('tests', type : 'boolean', value : true, description : 'enable tests') option('udevdir', type: 'string', value: '', description: 'Directory for udev rules') -option('efi_dbxdir', type: 'string', value: '', description: 'Directory for UEFI dbx files') option('efi-cc', type : 'string', value : 'gcc', description : 'the compiler to use for EFI modules') option('efi-ld', type : 'string', value : 'ld', description : 'the linker to use for EFI modules') option('efi-libdir', type : 'string', description : 'path to the EFI lib directory') diff --git a/plugins/uefi-dbx/fu-plugin-uefi-dbx.c b/plugins/uefi-dbx/fu-plugin-uefi-dbx.c index 1d3d689e8..9b9315eb2 100644 --- a/plugins/uefi-dbx/fu-plugin-uefi-dbx.c +++ b/plugins/uefi-dbx/fu-plugin-uefi-dbx.c @@ -31,77 +31,3 @@ fu_plugin_coldplug (FuPlugin *plugin, GError **error) fu_plugin_device_add (plugin, FU_DEVICE (device)); return TRUE; } - -void -fu_plugin_add_security_attrs (FuPlugin *plugin, FuSecurityAttrs *attrs) -{ - gsize bufsz = 0; - g_autofree guint8 *buf_system = NULL; - g_autofree guint8 *buf_update = NULL; - g_autoptr(GPtrArray) dbx_system = NULL; - g_autoptr(GPtrArray) dbx_update = NULL; - g_autoptr(FwupdSecurityAttr) attr = NULL; - g_autoptr(GError) error_local = NULL; - g_autofree gchar *fn = NULL; - - /* find the latest DBX on the system */ - fn = fu_uefi_dbx_get_dbxupdate (&error_local); - if (fn == NULL) { - g_warning ("cannot find any updates: %s", error_local->message); - return; - } - - /* create attr */ - attr = fwupd_security_attr_new (FWUPD_SECURITY_ATTR_ID_UEFI_DBX); - fwupd_security_attr_set_plugin (attr, fu_plugin_get_name (plugin)); - fwupd_security_attr_set_level (attr, FWUPD_SECURITY_ATTR_LEVEL_CRITICAL); - fu_security_attrs_append (attrs, attr); - - /* no binary blob */ - if (!fu_plugin_get_enabled (plugin)) { - fwupd_security_attr_set_result (attr, FWUPD_SECURITY_ATTR_RESULT_NOT_FOUND); - fwupd_security_attr_set_url (attr, "https://github.com/fwupd/fwupd/wiki/Missingdbx"); - return; - } - - /* get update dbx */ - if (!g_file_get_contents (fn, (gchar **) &buf_update, &bufsz, &error_local)) { - g_warning ("failed to load %s: %s", fn, error_local->message); - fwupd_security_attr_set_result (attr, FWUPD_SECURITY_ATTR_RESULT_NOT_VALID); - return; - } - dbx_update = fu_efi_signature_parser_new (buf_update, bufsz, - FU_EFI_SIGNATURE_PARSER_FLAGS_IGNORE_HEADER, - &error_local); - if (dbx_update == NULL) { - g_warning ("failed to parse %s: %s", fn, error_local->message); - fwupd_security_attr_set_result (attr, FWUPD_SECURITY_ATTR_RESULT_NOT_VALID); - return; - } - - /* get system dbx */ - if (!fu_efivar_get_data (FU_EFIVAR_GUID_SECURITY_DATABASE, "dbx", - &buf_system, &bufsz, NULL, &error_local)) { - g_warning ("failed to load EFI dbx: %s", error_local->message); - fwupd_security_attr_set_result (attr, FWUPD_SECURITY_ATTR_RESULT_NOT_VALID); - return; - } - dbx_system = fu_efi_signature_parser_new (buf_system, bufsz, - FU_EFI_SIGNATURE_PARSER_FLAGS_NONE, - &error_local); - if (dbx_system == NULL) { - g_warning ("failed to parse EFI dbx: %s", error_local->message); - fwupd_security_attr_set_result (attr, FWUPD_SECURITY_ATTR_RESULT_NOT_VALID); - return; - } - - /* look for each checksum in the update in the system version */ - if (!fu_efi_signature_list_array_inclusive (dbx_system, dbx_update)) { - fwupd_security_attr_set_result (attr, FWUPD_SECURITY_ATTR_RESULT_NOT_FOUND); - return; - } - - /* success */ - fwupd_security_attr_add_flag (attr, FWUPD_SECURITY_ATTR_FLAG_SUCCESS); - fwupd_security_attr_set_result (attr, FWUPD_SECURITY_ATTR_RESULT_FOUND); -} diff --git a/plugins/uefi-dbx/fu-self-test.c b/plugins/uefi-dbx/fu-self-test.c index fb310e30f..b50a98cf4 100644 --- a/plugins/uefi-dbx/fu-self-test.c +++ b/plugins/uefi-dbx/fu-self-test.c @@ -43,40 +43,6 @@ fu_efi_image_func (void) g_assert_cmpstr (csum, ==, "e99707d4378140c01eb3f867240d5cc9e237b126d3db0c3b4bbcd3da1720ddff"); } -static void -fu_efi_signature_list_parse_func (void) -{ - FuEfiSignatureList *siglist; - gboolean ret; - gsize bufsz = 0; - g_autofree gchar *fn = NULL; - g_autofree guint8 *buf = NULL; - g_autoptr(GPtrArray) siglists = NULL; - g_autoptr(GError) error = NULL; - - /* load file */ - fn = fu_uefi_dbx_get_dbxupdate (NULL); - if (fn == NULL) { - g_test_skip ("no dbx file, use -Defi_dbxdir="); - return; - } - ret = g_file_get_contents (fn, (gchar **) &buf, &bufsz, &error); - g_assert_no_error (error); - g_assert_true (ret); - - /* parse the update */ - siglists = fu_efi_signature_parser_new (buf, bufsz, - FU_EFI_SIGNATURE_PARSER_FLAGS_IGNORE_HEADER, - &error); - g_assert_no_error (error); - g_assert_nonnull (siglists); - g_assert_cmpint (siglists->len, ==, 1); - siglist = g_ptr_array_index (siglists, 0); - g_assert_cmpint (fu_efi_signature_list_get_all(siglist)->len, ==, 77); - g_assert_true (fu_efi_signature_list_has_checksum (siglist, "72e0bd1867cf5d9d56ab158adf3bddbc82bf32a8d8aa1d8c5e2f6df29428d6d8")); - g_assert_false (fu_efi_signature_list_has_checksum (siglist, "dave")); -} - int main (int argc, char **argv) { @@ -88,6 +54,5 @@ main (int argc, char **argv) /* tests go here */ g_test_add_func ("/uefi-dbx/image", fu_efi_image_func); - g_test_add_func ("/uefi-dbx/file-parse", fu_efi_signature_list_parse_func); return g_test_run (); } diff --git a/plugins/uefi-dbx/fu-uefi-dbx-common.c b/plugins/uefi-dbx/fu-uefi-dbx-common.c index bdcd0a44a..5a00a6cdd 100644 --- a/plugins/uefi-dbx/fu-uefi-dbx-common.c +++ b/plugins/uefi-dbx/fu-uefi-dbx-common.c @@ -13,24 +13,6 @@ #include "fu-uefi-dbx-common.h" -gchar * -fu_uefi_dbx_get_dbxupdate (GError **error) -{ - g_autofree gchar *dbxdir = NULL; - g_autofree gchar *glob = NULL; - g_autoptr(GPtrArray) files = NULL; - - /* get the newest files from dbxtool, prefer the per-arch ones first */ - dbxdir = fu_common_get_path (FU_PATH_KIND_EFIDBXDIR); - glob = g_strdup_printf ("*%s*.bin", EFI_MACHINE_TYPE_NAME); - files = fu_common_filename_glob (dbxdir, glob, NULL); - if (files == NULL) - files = fu_common_filename_glob (dbxdir, "*.bin", error); - if (files == NULL) - return NULL; - return g_strdup (g_ptr_array_index (files, 0)); -} - gchar * fu_uefi_dbx_get_authenticode_hash (const gchar *fn, GError **error) { diff --git a/plugins/uefi-dbx/fu-uefi-dbx-common.h b/plugins/uefi-dbx/fu-uefi-dbx-common.h index de33f8805..ff6b97654 100644 --- a/plugins/uefi-dbx/fu-uefi-dbx-common.h +++ b/plugins/uefi-dbx/fu-uefi-dbx-common.h @@ -8,7 +8,6 @@ #include -gchar *fu_uefi_dbx_get_dbxupdate (GError **error); gchar *fu_uefi_dbx_get_authenticode_hash (const gchar *fn, GError **error); gboolean fu_uefi_dbx_signature_list_validate (GPtrArray *siglists, diff --git a/src/fu-security-attr.c b/src/fu-security-attr.c index 0b0bd949b..ffdbd0e64 100644 --- a/src/fu-security-attr.c +++ b/src/fu-security-attr.c @@ -95,10 +95,6 @@ fu_security_attr_get_name (FwupdSecurityAttr *attr) /* TRANSLATORS: Title: a better sleep state */ return g_strdup (_("Suspend-to-idle")); } - if (g_strcmp0 (appstream_id, FWUPD_SECURITY_ATTR_ID_UEFI_DBX) == 0) { - /* TRANSLATORS: Title: dbx is the database with revoked hashes */ - return g_strdup (_("UEFI dbx")); - } if (g_strcmp0 (appstream_id, FWUPD_SECURITY_ATTR_ID_UEFI_SECUREBOOT) == 0) { /* TRANSLATORS: Title: SB is a way of locking down UEFI */ return g_strdup (_("UEFI secure boot")); From 5976125e25cd872f264777d232aebec199a0049a Mon Sep 17 00:00:00 2001 From: Richard Hughes Date: Thu, 20 Aug 2020 07:51:36 +0100 Subject: [PATCH 339/607] trivial: Fix two translator comment typos --- src/fu-tool.c | 2 +- src/fu-util.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/fu-tool.c b/src/fu-tool.c index 04b6476cc..6d1de3795 100644 --- a/src/fu-tool.c +++ b/src/fu-tool.c @@ -2033,7 +2033,7 @@ fu_util_prompt_for_volume (GError **error) volumes = fu_common_get_volumes_by_kind (FU_VOLUME_KIND_ESP, error); if (volumes->len == 1) { volume = g_ptr_array_index (volumes, 0); - /* TRANSLATORS: Volume has been chosen by the the user */ + /* TRANSLATORS: Volume has been chosen by the user */ g_print ("%s: %s\n", _("Selected volume"), fu_volume_get_id (volume)); return g_object_ref (volume); } diff --git a/src/fu-util.c b/src/fu-util.c index 615a827b9..d9f29c042 100644 --- a/src/fu-util.c +++ b/src/fu-util.c @@ -2427,7 +2427,7 @@ fu_util_unblock_firmware (FuUtilPrivate *priv, gchar **values, GError **error) return FALSE; } - /* TRANSLATORS: we will not offer this firmware to the user */ + /* TRANSLATORS: we will now offer this firmware to the user */ g_print ("%s %s\n", _("Unblocking firmware:"), csum); /* remove it from the new list */ From bd1dc2a1e2a8914b85ba84c7c643dabab3ec86d7 Mon Sep 17 00:00:00 2001 From: Richard Hughes Date: Thu, 20 Aug 2020 15:35:28 +0100 Subject: [PATCH 340/607] pcb-bcr: Use the correct BCR register for Bay Trail CPUs Fixes https://github.com/fwupd/fwupd/issues/2328 --- libfwupdplugin/fu-common.c | 57 ++++++++++++++++++++++++++--- libfwupdplugin/fu-common.h | 6 +++ libfwupdplugin/fwupdplugin.map | 1 + plugins/cpu/README.md | 9 +++++ plugins/cpu/cpu.quirk | 3 ++ plugins/cpu/fu-cpu-device.c | 49 +++++++++++++++++++++++++ plugins/cpu/fu-plugin-cpu.c | 3 ++ plugins/cpu/meson.build | 4 ++ plugins/pci-bcr/fu-plugin-pci-bcr.c | 23 ++++++++++-- 9 files changed, 147 insertions(+), 8 deletions(-) create mode 100644 plugins/cpu/cpu.quirk diff --git a/libfwupdplugin/fu-common.c b/libfwupdplugin/fu-common.c index 4822fc9d0..846ab8310 100644 --- a/libfwupdplugin/fu-common.c +++ b/libfwupdplugin/fu-common.c @@ -2033,6 +2033,55 @@ fu_common_kernel_locked_down (void) #endif } +/** + * fu_common_cpuid: + * @leaf: The CPUID level, now called the 'leaf' by Intel + * @eax: (out) (nullable): EAX register + * @ebx: (out) (nullable): EBX register + * @ecx: (out) (nullable): ECX register + * @edx: (out) (nullable): EDX register + * @error: A #GError or NULL + * + * Calls CPUID and returns the registers for the given leaf. + * + * Return value: %TRUE if the registers are set. + * + * Since: 1.5.0 + **/ +gboolean +fu_common_cpuid (guint32 leaf, + guint32 *eax, + guint32 *ebx, + guint32 *ecx, + guint32 *edx, + GError **error) +{ +#ifdef HAVE_CPUID_H + guint eax_tmp = 0; + guint ebx_tmp = 0; + guint ecx_tmp = 0; + guint edx_tmp = 0; + + /* get vendor */ + __get_cpuid(leaf, &eax_tmp, &ebx_tmp, &ecx_tmp, &edx_tmp); + if (eax != NULL) + *eax = eax_tmp; + if (ebx != NULL) + *ebx = ebx_tmp; + if (ecx != NULL) + *ecx = ecx_tmp; + if (edx != NULL) + *edx = edx_tmp; + return TRUE; +#else + g_set_error_literal (error, + G_IO_ERROR, + G_IO_ERROR_NOT_SUPPORTED, + "no support"); + return FALSE; +#endif +} + /** * fu_common_is_cpu_intel: * @@ -2045,15 +2094,13 @@ fu_common_kernel_locked_down (void) gboolean fu_common_is_cpu_intel (void) { -#ifdef HAVE_CPUID_H - guint eax = 0; guint ebx = 0; guint ecx = 0; guint edx = 0; - guint level = 0; - /* get vendor */ - __get_cpuid(level, &eax, &ebx, &ecx, &edx); + if (!fu_common_cpuid (0x0, NULL, &ebx, &ecx, &edx, NULL)) + return FALSE; +#ifdef HAVE_CPUID_H if (ebx == signature_INTEL_ebx && edx == signature_INTEL_edx && ecx == signature_INTEL_ecx) { diff --git a/libfwupdplugin/fu-common.h b/libfwupdplugin/fu-common.h index d8ac00ce2..0b99ac43f 100644 --- a/libfwupdplugin/fu-common.h +++ b/libfwupdplugin/fu-common.h @@ -226,6 +226,12 @@ gchar **fu_common_strnsplit (const gchar *str, const gchar *delimiter, gint max_tokens); gboolean fu_common_kernel_locked_down (void); +gboolean fu_common_cpuid (guint32 leaf, + guint32 *eax, + guint32 *ebx, + guint32 *ecx, + guint32 *edx, + GError **error); gboolean fu_common_is_cpu_intel (void); gboolean fu_common_is_live_media (void); GPtrArray *fu_common_get_volumes_by_kind (const gchar *kind, diff --git a/libfwupdplugin/fwupdplugin.map b/libfwupdplugin/fwupdplugin.map index 3e9077485..ec78769c2 100644 --- a/libfwupdplugin/fwupdplugin.map +++ b/libfwupdplugin/fwupdplugin.map @@ -612,6 +612,7 @@ LIBFWUPDPLUGIN_1.4.6 { LIBFWUPDPLUGIN_1.5.0 { global: + fu_common_cpuid; fu_common_filename_glob; fu_common_is_cpu_intel; fu_device_report_metadata_post; diff --git a/plugins/cpu/README.md b/plugins/cpu/README.md index 832f43a62..941e50305 100644 --- a/plugins/cpu/README.md +++ b/plugins/cpu/README.md @@ -7,3 +7,12 @@ Introduction This plugin reads the sysfs attributes associated with CPU microcode. It displays a read-only value of the CPU microcode version loaded onto the physical CPU at fwupd startup. + +GUID Generation +--------------- + +These devices add extra instance IDs from the CPUID values, e.g. + + * `CPUID\PRO_0&FAM_6` + * `CPUID\PRO_0&FAM_6&MOD_E` + * `CPUID\PRO_0&FAM_6&MOD_E&STP_3` diff --git a/plugins/cpu/cpu.quirk b/plugins/cpu/cpu.quirk new file mode 100644 index 000000000..b49ad3941 --- /dev/null +++ b/plugins/cpu/cpu.quirk @@ -0,0 +1,3 @@ +# Intel Atom Bay Trail [Silvermont] +[DeviceInstanceId=CPUID\PRO_0&FAM_6&MOD_7] +BcrAddr = 0x54 diff --git a/plugins/cpu/fu-cpu-device.c b/plugins/cpu/fu-cpu-device.c index 9a54218d0..09146ee98 100644 --- a/plugins/cpu/fu-cpu-device.c +++ b/plugins/cpu/fu-cpu-device.c @@ -94,11 +94,60 @@ fu_cpu_device_init (FuCpuDevice *self) fu_device_set_version_format (FU_DEVICE (self), FWUPD_VERSION_FORMAT_HEX); } +static gboolean +fu_cpu_device_probe (FuDevice *device, GError **error) +{ + guint32 eax = 0; + g_autofree gchar *devid1 = NULL; + g_autofree gchar *devid2 = NULL; + g_autofree gchar *devid3 = NULL; + + /* add GUIDs */ + if (!fu_common_cpuid (0x1, &eax, NULL, NULL, NULL, error)) + return FALSE; + devid1 = g_strdup_printf ("CPUID\\PRO_%01X&FAM_%01X", + (eax >> 12) & 0x3, + (eax >> 8) & 0xf); + fu_device_add_instance_id (device, devid1); + devid2 = g_strdup_printf ("CPUID\\PRO_%01X&FAM_%01X&MOD_%01X", + (eax >> 12) & 0x3, + (eax >> 8) & 0xf, + (eax >> 4) & 0xf); + fu_device_add_instance_id (device, devid2); + devid3 = g_strdup_printf ("CPUID\\PRO_%01X&FAM_%01X&MOD_%01X&STP_%01X", + (eax >> 12) & 0x3, + (eax >> 8) & 0xf, + (eax >> 4) & 0xf, + eax & 0xf); + fu_device_add_instance_id (device, devid3); + return TRUE; +} + +static gboolean +fu_cpu_device_set_quirk_kv (FuDevice *device, + const gchar *key, + const gchar *value, + GError **error) +{ + if (g_strcmp0 (key, "BcrAddr") == 0) { + guint64 tmp = fu_common_strtoull (value); + fu_device_set_metadata_integer (device, "BcrAddr", tmp); + return TRUE; + } + g_set_error_literal (error, + G_IO_ERROR, + G_IO_ERROR_NOT_SUPPORTED, + "no supported"); + return FALSE; +} + static void fu_cpu_device_class_init (FuCpuDeviceClass *klass) { FuDeviceClass *klass_device = FU_DEVICE_CLASS (klass); klass_device->to_string = fu_cpu_device_to_string; + klass_device->probe = fu_cpu_device_probe; + klass_device->set_quirk_kv = fu_cpu_device_set_quirk_kv; } FuCpuDevice * diff --git a/plugins/cpu/fu-plugin-cpu.c b/plugins/cpu/fu-plugin-cpu.c index dcb657a58..d60547094 100644 --- a/plugins/cpu/fu-plugin-cpu.c +++ b/plugins/cpu/fu-plugin-cpu.c @@ -40,6 +40,9 @@ fu_plugin_coldplug (FuPlugin *plugin, GError **error) if (strlen (lines[i]) == 0) continue; dev = fu_cpu_device_new (lines[i]); + fu_device_set_quirks (FU_DEVICE (dev), fu_plugin_get_quirks (plugin)); + if (!fu_device_probe (FU_DEVICE (dev), error)) + return FALSE; if (!fu_device_setup (FU_DEVICE (dev), error)) return FALSE; if (fu_cpu_device_has_flag (dev, FU_CPU_DEVICE_FLAG_SHSTK) && diff --git a/plugins/cpu/meson.build b/plugins/cpu/meson.build index 2fc6d6c68..09f762953 100644 --- a/plugins/cpu/meson.build +++ b/plugins/cpu/meson.build @@ -1,5 +1,9 @@ cargs = ['-DG_LOG_DOMAIN="FuPluginCpu"'] +install_data(['cpu.quirk'], + install_dir: join_paths(datadir, 'fwupd', 'quirks.d') +) + shared_module('fu_plugin_cpu', fu_hash, sources : [ diff --git a/plugins/pci-bcr/fu-plugin-pci-bcr.c b/plugins/pci-bcr/fu-plugin-pci-bcr.c index e2fc1e9f4..dbebe9dd6 100644 --- a/plugins/pci-bcr/fu-plugin-pci-bcr.c +++ b/plugins/pci-bcr/fu-plugin-pci-bcr.c @@ -11,10 +11,10 @@ struct FuPluginData { gboolean has_device; + guint8 bcr_addr; guint8 bcr; }; -#define BCR 0xdc #define BCR_WPD (1 << 0) #define BCR_BLE (1 << 1) #define BCR_SMM_BWP (1 << 5) @@ -22,9 +22,26 @@ struct FuPluginData { void fu_plugin_init (FuPlugin *plugin) { - fu_plugin_alloc_data (plugin, sizeof (FuPluginData)); + FuPluginData *priv = fu_plugin_alloc_data (plugin, sizeof (FuPluginData)); fu_plugin_set_build_hash (plugin, FU_BUILD_HASH); fu_plugin_add_udev_subsystem (plugin, "pci"); + + /* this is true except for some Atoms */ + priv->bcr_addr = 0xdc; +} + +void +fu_plugin_device_registered (FuPlugin *plugin, FuDevice *dev) +{ + FuPluginData *priv = fu_plugin_get_data (plugin); + if (g_strcmp0 (fu_device_get_plugin (dev), "cpu") == 0) { + guint tmp = fu_device_get_metadata_integer (dev, "BcrAddr"); + if (tmp != G_MAXUINT && priv->bcr_addr != tmp) { + g_debug ("overriding BCR addr from 0x%02x to 0x%02x", + priv->bcr_addr, tmp); + priv->bcr_addr = tmp; + } + } } static void @@ -132,7 +149,7 @@ fu_plugin_udev_device_added (FuPlugin *plugin, FuUdevDevice *device, GError **er return FALSE; /* grab BIOS Control Register */ - if (!fu_udev_device_pread (device, BCR, &priv->bcr, error)) { + if (!fu_udev_device_pread (device, priv->bcr_addr, &priv->bcr, error)) { g_prefix_error (error, "could not read BCR"); return FALSE; } From 7c4a64b833f793b26d4b9984e22978c3db058f33 Mon Sep 17 00:00:00 2001 From: Richard Hughes Date: Sun, 23 Aug 2020 21:20:58 +0100 Subject: [PATCH 341/607] trivial: Ensure EAX is set to 0x0 when calling CPUID This fixes getting the 'Extended Features' from the CPU. --- libfwupdplugin/fu-common.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libfwupdplugin/fu-common.c b/libfwupdplugin/fu-common.c index 846ab8310..fbc9ff2aa 100644 --- a/libfwupdplugin/fu-common.c +++ b/libfwupdplugin/fu-common.c @@ -2063,7 +2063,7 @@ fu_common_cpuid (guint32 leaf, guint edx_tmp = 0; /* get vendor */ - __get_cpuid(leaf, &eax_tmp, &ebx_tmp, &ecx_tmp, &edx_tmp); + __get_cpuid_count (leaf, 0x0, &eax_tmp, &ebx_tmp, &ecx_tmp, &edx_tmp); if (eax != NULL) *eax = eax_tmp; if (ebx != NULL) From 8667c7e816161e0d6c3b7f617e54a1627f911d24 Mon Sep 17 00:00:00 2001 From: Richard Hughes Date: Sun, 23 Aug 2020 21:27:48 +0100 Subject: [PATCH 342/607] cpu: Use the proper vendor name rather than the signature --- plugins/cpu/fu-cpu-device.c | 60 ++++++++++++++++++++++++++++++++++++- 1 file changed, 59 insertions(+), 1 deletion(-) diff --git a/plugins/cpu/fu-cpu-device.c b/plugins/cpu/fu-cpu-device.c index 09146ee98..58c0e623b 100644 --- a/plugins/cpu/fu-cpu-device.c +++ b/plugins/cpu/fu-cpu-device.c @@ -35,6 +35,64 @@ fu_cpu_device_to_string (FuDevice *device, guint idt, GString *str) fu_cpu_device_has_flag (self, FU_CPU_DEVICE_FLAG_SMAP)); } +static const gchar * +fu_cpu_device_convert_vendor (const gchar *vendor) +{ + if (g_strcmp0 (vendor, "GenuineIntel") == 0) + return "Intel"; + if (g_strcmp0 (vendor, "AuthenticAMD") == 0 || + g_strcmp0 (vendor, "AMDisbetter!") == 0) + return "AMD"; + if (g_strcmp0 (vendor, "CentaurHauls") == 0) + return "IDT"; + if (g_strcmp0 (vendor, "CyrixInstead") == 0) + return "Cyrix"; + if (g_strcmp0 (vendor, "TransmetaCPU") == 0 || + g_strcmp0 (vendor, "GenuineTMx86") == 0) + return "Transmeta"; + if (g_strcmp0 (vendor, "Geode by NSC") == 0) + return "National Semiconductor"; + if (g_strcmp0 (vendor, "NexGenDriven") == 0) + return "NexGen"; + if (g_strcmp0 (vendor, "RiseRiseRise") == 0) + return "Rise"; + if (g_strcmp0 (vendor, "SiS SiS SiS ") == 0) + return "SiS"; + if (g_strcmp0 (vendor, "UMC UMC UMC ") == 0) + return "UMC"; + if (g_strcmp0 (vendor, "VIA VIA VIA ") == 0) + return "VIA"; + if (g_strcmp0 (vendor, "Vortex86 SoC") == 0) + return "Vortex"; + if (g_strcmp0 (vendor, " Shanghai ") == 0) + return "Zhaoxin"; + if (g_strcmp0 (vendor, "HygonGenuine") == 0) + return "Hygon"; + if (g_strcmp0 (vendor, "E2K MACHINE") == 0) + return "MCST"; + if (g_strcmp0 (vendor, "bhyve bhyve ") == 0) + return "bhyve"; + if (g_strcmp0 (vendor, " KVMKVMKVM ") == 0) + return "KVM"; + if (g_strcmp0 (vendor, "TCGTCGTCGTCG") == 0) + return "QEMU"; + if (g_strcmp0 (vendor, "Microsoft Hv") == 0) + return "Microsoft"; + if (g_strcmp0 (vendor, " lrpepyh vr") == 0) + return "Parallels"; + if (g_strcmp0 (vendor, "VMwareVMware") == 0) + return "VMware"; + if (g_strcmp0 (vendor, "XenVMMXenVMM") == 0) + return "Xen"; + if (g_strcmp0 (vendor, "ACRNACRNACRN") == 0) + return "ACRN"; + if (g_strcmp0 (vendor, " QNXQVMBSQG ") == 0) + return "QNX"; + if (g_strcmp0 (vendor, "VirtualApple") == 0) + return "Apple"; + return vendor; +} + static void fu_cpu_device_parse_flags (FuCpuDevice *self, const gchar *data) { @@ -62,7 +120,7 @@ fu_cpu_device_parse_section (FuDevice *dev, const gchar *data) if (g_str_has_prefix (lines[i], "vendor_id")) { g_auto(GStrv) fields = g_strsplit (lines[i], ":", -1); if (fields[1] != NULL) - fu_device_set_vendor (dev, g_strchug (fields[1])); + fu_device_set_vendor (dev, fu_cpu_device_convert_vendor (fields[1] + 1)); } else if (g_str_has_prefix (lines[i], "model name")) { g_auto(GStrv) fields = g_strsplit (lines[i], ":", -1); if (fields[1] != NULL) From 3a095cdadf3dd0ddeab8dd63c1708c0c73e0e8ea Mon Sep 17 00:00:00 2001 From: Richard Hughes Date: Sun, 23 Aug 2020 21:47:42 +0100 Subject: [PATCH 343/607] cpu: Use the extended IDs where required --- plugins/cpu/README.md | 6 ++-- plugins/cpu/cpu.quirk | 2 +- plugins/cpu/fu-cpu-device.c | 55 +++++++++++++++++++++++++++---------- 3 files changed, 45 insertions(+), 18 deletions(-) diff --git a/plugins/cpu/README.md b/plugins/cpu/README.md index 941e50305..5ef8b88c5 100644 --- a/plugins/cpu/README.md +++ b/plugins/cpu/README.md @@ -13,6 +13,6 @@ GUID Generation These devices add extra instance IDs from the CPUID values, e.g. - * `CPUID\PRO_0&FAM_6` - * `CPUID\PRO_0&FAM_6&MOD_E` - * `CPUID\PRO_0&FAM_6&MOD_E&STP_3` + * `CPUID\PRO_0&FAM_06` + * `CPUID\PRO_0&FAM_06&MOD_0E` + * `CPUID\PRO_0&FAM_06&MOD_0E&STP_3` diff --git a/plugins/cpu/cpu.quirk b/plugins/cpu/cpu.quirk index b49ad3941..dace03cfe 100644 --- a/plugins/cpu/cpu.quirk +++ b/plugins/cpu/cpu.quirk @@ -1,3 +1,3 @@ # Intel Atom Bay Trail [Silvermont] -[DeviceInstanceId=CPUID\PRO_0&FAM_6&MOD_7] +[DeviceInstanceId=CPUID\PRO_0&FAM_06&MOD_07] BcrAddr = 0x54 diff --git a/plugins/cpu/fu-cpu-device.c b/plugins/cpu/fu-cpu-device.c index 58c0e623b..681c1ac48 100644 --- a/plugins/cpu/fu-cpu-device.c +++ b/plugins/cpu/fu-cpu-device.c @@ -153,34 +153,61 @@ fu_cpu_device_init (FuCpuDevice *self) } static gboolean -fu_cpu_device_probe (FuDevice *device, GError **error) +fu_cpu_device_add_instance_ids (FuDevice *device, GError **error) { guint32 eax = 0; + guint32 family_id; + guint32 family_id_ext; + guint32 model_id; + guint32 model_id_ext; + guint32 processor_id; + guint32 stepping_id; g_autofree gchar *devid1 = NULL; g_autofree gchar *devid2 = NULL; g_autofree gchar *devid3 = NULL; - /* add GUIDs */ + /* decode according to https://en.wikipedia.org/wiki/CPUID */ if (!fu_common_cpuid (0x1, &eax, NULL, NULL, NULL, error)) return FALSE; - devid1 = g_strdup_printf ("CPUID\\PRO_%01X&FAM_%01X", - (eax >> 12) & 0x3, - (eax >> 8) & 0xf); + processor_id = (eax >> 12) & 0x3; + model_id = (eax >> 4) & 0xf; + family_id = (eax >> 8) & 0xf; + model_id_ext = (eax >> 16) & 0xf; + family_id_ext = (eax >> 20) & 0xff; + stepping_id = eax & 0xf; + + /* use extended IDs where required */ + if (family_id == 6 || family_id == 15) + model_id |= model_id_ext << 4; + if (family_id == 15) + family_id += family_id_ext; + + devid1 = g_strdup_printf ("CPUID\\PRO_%01X&FAM_%02X", + processor_id, + family_id); fu_device_add_instance_id (device, devid1); - devid2 = g_strdup_printf ("CPUID\\PRO_%01X&FAM_%01X&MOD_%01X", - (eax >> 12) & 0x3, - (eax >> 8) & 0xf, - (eax >> 4) & 0xf); + devid2 = g_strdup_printf ("CPUID\\PRO_%01X&FAM_%02X&MOD_%02X", + processor_id, + family_id, + model_id); fu_device_add_instance_id (device, devid2); - devid3 = g_strdup_printf ("CPUID\\PRO_%01X&FAM_%01X&MOD_%01X&STP_%01X", - (eax >> 12) & 0x3, - (eax >> 8) & 0xf, - (eax >> 4) & 0xf, - eax & 0xf); + devid3 = g_strdup_printf ("CPUID\\PRO_%01X&FAM_%02X&MOD_%02X&STP_%01X", + processor_id, + family_id, + model_id, + stepping_id); fu_device_add_instance_id (device, devid3); return TRUE; } +static gboolean +fu_cpu_device_probe (FuDevice *device, GError **error) +{ + if (!fu_cpu_device_add_instance_ids (device, error)) + return FALSE; + return TRUE; +} + static gboolean fu_cpu_device_set_quirk_kv (FuDevice *device, const gchar *key, From f779a0cfaa858b7679d3a2fd1b5bb15b55f8d97f Mon Sep 17 00:00:00 2001 From: Richard Hughes Date: Sun, 23 Aug 2020 22:07:25 +0100 Subject: [PATCH 344/607] msr: Use the new fu_common_cpuid() functionality --- plugins/msr/fu-plugin-msr.c | 35 +---------------------------------- 1 file changed, 1 insertion(+), 34 deletions(-) diff --git a/plugins/msr/fu-plugin-msr.c b/plugins/msr/fu-plugin-msr.c index 3a264cc5d..5c0d90b55 100644 --- a/plugins/msr/fu-plugin-msr.c +++ b/plugins/msr/fu-plugin-msr.c @@ -36,38 +36,6 @@ fu_plugin_init (FuPlugin *plugin) fu_plugin_add_udev_subsystem (plugin, "msr"); } -static gboolean -fu_plugin_msr_cpuid (guint leaf, - guint *eax, guint *ebx, - guint *ecx, guint *edx, - GError **error) -{ - guint eax_tmp = 0; - guint ebx_tmp = 0; - guint ecx_tmp = 0; - guint edx_tmp = 0; - - /* sdbg is supported: https://en.wikipedia.org/wiki/CPUID */ - if (__get_cpuid (leaf, &eax_tmp, &ebx_tmp, &ecx_tmp, &edx_tmp) == 0) { - g_set_error (error, - FWUPD_ERROR, - FWUPD_ERROR_NOT_FOUND, - "CPUID leaf 0x%x is not supported on this CPU", leaf); - return FALSE; - } - - /* success */ - if (eax != NULL) - *eax = eax_tmp; - if (ebx != NULL) - *ebx = ebx_tmp; - if (ecx != NULL) - *ecx = ecx_tmp; - if (edx != NULL) - *edx = edx_tmp; - return TRUE; -} - gboolean fu_plugin_startup (FuPlugin *plugin, GError **error) { @@ -75,9 +43,8 @@ fu_plugin_startup (FuPlugin *plugin, GError **error) guint ecx = 0; /* sdbg is supported: https://en.wikipedia.org/wiki/CPUID */ - if (!fu_plugin_msr_cpuid (0x01, NULL, NULL, &ecx, NULL, error)) + if (!fu_common_cpuid (0x01, NULL, NULL, &ecx, NULL, error)) return FALSE; - priv->ia32_debug_supported = ((ecx >> 11) & 0x1) > 0; return TRUE; } From 8307bd603ea7764e17142c67aa637edaf0de6adb Mon Sep 17 00:00:00 2001 From: Richard Hughes Date: Sun, 23 Aug 2020 21:54:50 +0100 Subject: [PATCH 345/607] cpu: Directly probe the CPUID data to improve startup speed This is much more efficient than parsing hundreds of lines of /proc/cpuinfo and also causes hundreds of thousands less allocations at startup. For systems with dozens of virtual CPUs the deduplication of device objects was increasing start up time considerably. Use the msr plugin to read the microcode version as this is not obtained using CPUID, as it is instead being provided in an MSR. --- plugins/cpu/fu-cpu-device.c | 138 ++++++++++++++++++++++-------------- plugins/cpu/fu-cpu-device.h | 2 +- plugins/cpu/fu-plugin-cpu.c | 61 +++++----------- plugins/msr/fu-plugin-msr.c | 36 ++++++++++ 4 files changed, 141 insertions(+), 96 deletions(-) diff --git a/plugins/cpu/fu-cpu-device.c b/plugins/cpu/fu-cpu-device.c index 681c1ac48..a97191b55 100644 --- a/plugins/cpu/fu-cpu-device.c +++ b/plugins/cpu/fu-cpu-device.c @@ -93,56 +93,6 @@ fu_cpu_device_convert_vendor (const gchar *vendor) return vendor; } -static void -fu_cpu_device_parse_flags (FuCpuDevice *self, const gchar *data) -{ - g_auto(GStrv) flags = g_strsplit (data, " ", -1); - for (guint i = 0; flags[i] != NULL; i++) { - if (g_strcmp0 (flags[i], "shstk") == 0) - self->flags |= FU_CPU_DEVICE_FLAG_SHSTK; - if (g_strcmp0 (flags[i], "ibt") == 0) - self->flags |= FU_CPU_DEVICE_FLAG_IBT; - if (g_strcmp0 (flags[i], "tme") == 0) - self->flags |= FU_CPU_DEVICE_FLAG_TME; - if (g_strcmp0 (flags[i], "smap") == 0) - self->flags |= FU_CPU_DEVICE_FLAG_SMAP; - } -} - -static void -fu_cpu_device_parse_section (FuDevice *dev, const gchar *data) -{ - g_auto(GStrv) lines = NULL; - FuCpuDevice *self = FU_CPU_DEVICE (dev); - - lines = g_strsplit (data, "\n", 0); - for (guint i = 0; lines[i] != NULL; i++) { - if (g_str_has_prefix (lines[i], "vendor_id")) { - g_auto(GStrv) fields = g_strsplit (lines[i], ":", -1); - if (fields[1] != NULL) - fu_device_set_vendor (dev, fu_cpu_device_convert_vendor (fields[1] + 1)); - } else if (g_str_has_prefix (lines[i], "model name")) { - g_auto(GStrv) fields = g_strsplit (lines[i], ":", -1); - if (fields[1] != NULL) - fu_device_set_name (dev, g_strchug (fields[1])); - } else if (g_str_has_prefix (lines[i], "microcode")) { - g_auto(GStrv) fields = g_strsplit (lines[i], ":", -1); - if (fields[1] != NULL) - fu_device_set_version (dev, g_strchug (fields[1])); - } else if (g_str_has_prefix (lines[i], "physical id")) { - g_auto(GStrv) fields = g_strsplit (lines[i], ":", -1); - if (fields[1] != NULL) { - g_autofree gchar *tmp = g_strdup_printf ("cpu:%s", g_strchug (fields[1])); - fu_device_set_physical_id (dev, tmp); - } - } else if (g_str_has_prefix (lines[i], "flags")) { - g_auto(GStrv) fields = g_strsplit (lines[i], ":", -1); - if (fields[1] != NULL) - fu_cpu_device_parse_flags (self, fields[1]); - } - } -} - static void fu_cpu_device_init (FuCpuDevice *self) { @@ -150,6 +100,7 @@ fu_cpu_device_init (FuCpuDevice *self) fu_device_add_flag (FU_DEVICE (self), FWUPD_DEVICE_FLAG_INTERNAL); fu_device_add_icon (FU_DEVICE (self), "computer"); fu_device_set_version_format (FU_DEVICE (self), FWUPD_VERSION_FORMAT_HEX); + fu_device_set_physical_id (FU_DEVICE (self), "cpu:0"); } static gboolean @@ -200,9 +151,93 @@ fu_cpu_device_add_instance_ids (FuDevice *device, GError **error) return TRUE; } +static gboolean +fu_cpu_device_probe_manufacturer_id (FuDevice *device, GError **error) +{ + guint32 ebx = 0; + guint32 ecx = 0; + guint32 edx = 0; + gchar str[13] = { '\0' }; + if (!fu_common_cpuid (0x0, NULL, &ebx, &ecx, &edx, error)) + return FALSE; + if (!fu_memcpy_safe ((guint8 *) str, sizeof(str), 0x0, /* dst */ + (const guint8 *) &ebx, sizeof(ebx), 0x0, /* src */ + sizeof(guint32), error)) + return FALSE; + if (!fu_memcpy_safe ((guint8 *) str, sizeof(str), 0x4, /* dst */ + (const guint8 *) &edx, sizeof(edx), 0x0, /* src */ + sizeof(guint32), error)) + return FALSE; + if (!fu_memcpy_safe ((guint8 *) str, sizeof(str), 0x8, /* dst */ + (const guint8 *) &ecx, sizeof(ecx), 0x0, /* src */ + sizeof(guint32), error)) + return FALSE; + fu_device_set_vendor (device, fu_cpu_device_convert_vendor (str)); + return TRUE; +} + +static gboolean +fu_cpu_device_probe_model (FuDevice *device, GError **error) +{ + guint32 eax = 0; + guint32 ebx = 0; + guint32 ecx = 0; + guint32 edx = 0; + gchar str[49] = { '\0' }; + + for (guint32 i = 0; i < 3; i++) { + if (!fu_common_cpuid (0x80000002 + i, &eax, &ebx, &ecx, &edx, error)) + return FALSE; + if (!fu_memcpy_safe ((guint8 *) str, sizeof(str), (16 * i) + 0x0, /* dst */ + (const guint8 *) &eax, sizeof(eax), 0x0, /* src */ + sizeof(guint32), error)) + return FALSE; + if (!fu_memcpy_safe ((guint8 *) str, sizeof(str), (16 * i) + 0x4, /* dst */ + (const guint8 *) &ebx, sizeof(ebx), 0x0, /* src */ + sizeof(guint32), error)) + return FALSE; + if (!fu_memcpy_safe ((guint8 *) str, sizeof(str), (16 * i) + 0x8, /* dst */ + (const guint8 *) &ecx, sizeof(ecx), 0x0, /* src */ + sizeof(guint32), error)) + return FALSE; + if (!fu_memcpy_safe ((guint8 *) str, sizeof(str), (16 * i) + 0xc, /* dst */ + (const guint8 *) &edx, sizeof(edx), 0x0, /* src */ + sizeof(guint32), error)) + return FALSE; + } + fu_device_set_name (device, str); + return TRUE; +} + +static gboolean +fu_cpu_device_probe_extended_features (FuDevice *device, GError **error) +{ + FuCpuDevice *self = FU_CPU_DEVICE (device); + guint32 ebx = 0; + guint32 ecx = 0; + + if (!fu_common_cpuid (0x7, NULL, &ebx, &ecx, NULL, error)) + return FALSE; + if ((ebx >> 20) & 0x1) + self->flags |= FU_CPU_DEVICE_FLAG_SMAP; + if ((ecx >> 7) & 0x1) + self->flags |= FU_CPU_DEVICE_FLAG_SHSTK; + if ((ecx >> 13) & 0x1) + self->flags |= FU_CPU_DEVICE_FLAG_TME; + if ((ecx >> 20) & 0x1) + self->flags |= FU_CPU_DEVICE_FLAG_IBT; + return TRUE; +} + static gboolean fu_cpu_device_probe (FuDevice *device, GError **error) { + if (!fu_cpu_device_probe_manufacturer_id (device, error)) + return FALSE; + if (!fu_cpu_device_probe_model (device, error)) + return FALSE; + if (!fu_cpu_device_probe_extended_features (device, error)) + return FALSE; if (!fu_cpu_device_add_instance_ids (device, error)) return FALSE; return TRUE; @@ -236,10 +271,9 @@ fu_cpu_device_class_init (FuCpuDeviceClass *klass) } FuCpuDevice * -fu_cpu_device_new (const gchar *section) +fu_cpu_device_new (void) { FuCpuDevice *device = NULL; device = g_object_new (FU_TYPE_CPU_DEVICE, NULL); - fu_cpu_device_parse_section (FU_DEVICE (device), section); return device; } diff --git a/plugins/cpu/fu-cpu-device.h b/plugins/cpu/fu-cpu-device.h index 50d50d154..0115916a2 100644 --- a/plugins/cpu/fu-cpu-device.h +++ b/plugins/cpu/fu-cpu-device.h @@ -19,6 +19,6 @@ typedef enum { FU_CPU_DEVICE_FLAG_SMAP = 1 << 3, } FuCpuDeviceFlag; -FuCpuDevice *fu_cpu_device_new (const gchar *section); +FuCpuDevice *fu_cpu_device_new (void); gboolean fu_cpu_device_has_flag (FuCpuDevice *self, FuCpuDeviceFlag flag); diff --git a/plugins/cpu/fu-plugin-cpu.c b/plugins/cpu/fu-plugin-cpu.c index d60547094..52015c4bd 100644 --- a/plugins/cpu/fu-plugin-cpu.c +++ b/plugins/cpu/fu-plugin-cpu.c @@ -10,58 +10,31 @@ #include "fu-hash.h" #include "fu-cpu-device.h" -struct FuPluginData { - gboolean has_cet; - gboolean has_smap; - gboolean has_tme; -}; - void fu_plugin_init (FuPlugin *plugin) { fu_plugin_set_build_hash (plugin, FU_BUILD_HASH); - fu_plugin_alloc_data (plugin, sizeof (FuPluginData)); + fu_plugin_add_rule (plugin, FU_PLUGIN_RULE_RUN_BEFORE, "msr"); } gboolean fu_plugin_coldplug (FuPlugin *plugin, GError **error) { - FuPluginData *data = fu_plugin_get_data (plugin); - gsize length; - g_autofree gchar *buf = NULL; - g_auto(GStrv) lines = NULL; - - if (!g_file_get_contents ("/proc/cpuinfo", &buf, &length, error)) + g_autoptr(FuCpuDevice) dev = fu_cpu_device_new (); + fu_device_set_quirks (FU_DEVICE (dev), fu_plugin_get_quirks (plugin)); + if (!fu_device_probe (FU_DEVICE (dev), error)) return FALSE; - - lines = g_strsplit (buf, "\n\n", 0); - for (guint i = 0; lines[i] != NULL; i++) { - g_autoptr(FuCpuDevice) dev = NULL; - if (strlen (lines[i]) == 0) - continue; - dev = fu_cpu_device_new (lines[i]); - fu_device_set_quirks (FU_DEVICE (dev), fu_plugin_get_quirks (plugin)); - if (!fu_device_probe (FU_DEVICE (dev), error)) - return FALSE; - if (!fu_device_setup (FU_DEVICE (dev), error)) - return FALSE; - if (fu_cpu_device_has_flag (dev, FU_CPU_DEVICE_FLAG_SHSTK) && - fu_cpu_device_has_flag (dev, FU_CPU_DEVICE_FLAG_IBT)) - data->has_cet = TRUE; - if (fu_cpu_device_has_flag (dev, FU_CPU_DEVICE_FLAG_TME)) - data->has_tme = TRUE; - if (fu_cpu_device_has_flag (dev, FU_CPU_DEVICE_FLAG_SMAP)) - data->has_smap = TRUE; - fu_plugin_device_add (plugin, FU_DEVICE (dev)); - } - + if (!fu_device_setup (FU_DEVICE (dev), error)) + return FALSE; + fu_plugin_cache_add (plugin, "cpu", dev); + fu_plugin_device_add (plugin, FU_DEVICE (dev)); return TRUE; } static void fu_plugin_add_security_attrs_intel_cet_enabled (FuPlugin *plugin, FuSecurityAttrs *attrs) { - FuPluginData *data = fu_plugin_get_data (plugin); + FuCpuDevice *device = fu_plugin_cache_lookup (plugin, "cpu"); g_autoptr(FwupdSecurityAttr) attr = NULL; /* create attr */ @@ -71,7 +44,8 @@ fu_plugin_add_security_attrs_intel_cet_enabled (FuPlugin *plugin, FuSecurityAttr fu_security_attrs_append (attrs, attr); /* check for CET */ - if (!data->has_cet) { + if (!fu_cpu_device_has_flag (device, FU_CPU_DEVICE_FLAG_SHSTK) || + !fu_cpu_device_has_flag (device, FU_CPU_DEVICE_FLAG_IBT)) { fwupd_security_attr_set_result (attr, FWUPD_SECURITY_ATTR_RESULT_NOT_SUPPORTED); return; } @@ -84,14 +58,15 @@ fu_plugin_add_security_attrs_intel_cet_enabled (FuPlugin *plugin, FuSecurityAttr static void fu_plugin_add_security_attrs_intel_cet_active (FuPlugin *plugin, FuSecurityAttrs *attrs) { - FuPluginData *data = fu_plugin_get_data (plugin); + FuCpuDevice *device = fu_plugin_cache_lookup (plugin, "cpu"); gint exit_status = 0xff; g_autofree gchar *toolfn = NULL; g_autoptr(FwupdSecurityAttr) attr = NULL; g_autoptr(GError) error_local = NULL; /* check for CET */ - if (!data->has_cet) + if (!fu_cpu_device_has_flag (device, FU_CPU_DEVICE_FLAG_SHSTK) || + !fu_cpu_device_has_flag (device, FU_CPU_DEVICE_FLAG_IBT)) return; /* create attr */ @@ -120,7 +95,7 @@ fu_plugin_add_security_attrs_intel_cet_active (FuPlugin *plugin, FuSecurityAttrs static void fu_plugin_add_security_attrs_intel_tme (FuPlugin *plugin, FuSecurityAttrs *attrs) { - FuPluginData *data = fu_plugin_get_data (plugin); + FuCpuDevice *device = fu_plugin_cache_lookup (plugin, "cpu"); g_autoptr(FwupdSecurityAttr) attr = NULL; /* create attr */ @@ -130,7 +105,7 @@ fu_plugin_add_security_attrs_intel_tme (FuPlugin *plugin, FuSecurityAttrs *attrs fu_security_attrs_append (attrs, attr); /* check for TME */ - if (!data->has_tme) { + if (!fu_cpu_device_has_flag (device, FU_CPU_DEVICE_FLAG_TME)) { fwupd_security_attr_set_result (attr, FWUPD_SECURITY_ATTR_RESULT_NOT_SUPPORTED); return; } @@ -143,7 +118,7 @@ fu_plugin_add_security_attrs_intel_tme (FuPlugin *plugin, FuSecurityAttrs *attrs static void fu_plugin_add_security_attrs_intel_smap (FuPlugin *plugin, FuSecurityAttrs *attrs) { - FuPluginData *data = fu_plugin_get_data (plugin); + FuCpuDevice *device = fu_plugin_cache_lookup (plugin, "cpu"); g_autoptr(FwupdSecurityAttr) attr = NULL; /* create attr */ @@ -153,7 +128,7 @@ fu_plugin_add_security_attrs_intel_smap (FuPlugin *plugin, FuSecurityAttrs *attr fu_security_attrs_append (attrs, attr); /* check for SMEP and SMAP */ - if (!data->has_smap) { + if (!fu_cpu_device_has_flag (device, FU_CPU_DEVICE_FLAG_SMAP)) { fwupd_security_attr_set_result (attr, FWUPD_SECURITY_ATTR_RESULT_NOT_SUPPORTED); return; } diff --git a/plugins/msr/fu-plugin-msr.c b/plugins/msr/fu-plugin-msr.c index 5c0d90b55..cf529321a 100644 --- a/plugins/msr/fu-plugin-msr.c +++ b/plugins/msr/fu-plugin-msr.c @@ -27,6 +27,7 @@ struct FuPluginData { }; #define PCI_MSR_IA32_DEBUG_INTERFACE 0xc80 +#define PCI_MSR_IA32_BIOS_SIGN_ID 0x8b void fu_plugin_init (FuPlugin *plugin) @@ -52,6 +53,7 @@ fu_plugin_startup (FuPlugin *plugin, GError **error) gboolean fu_plugin_udev_device_added (FuPlugin *plugin, FuUdevDevice *device, GError **error) { + FuDevice *device_cpu = fu_plugin_cache_lookup (plugin, "cpu"); FuPluginData *priv = fu_plugin_get_data (plugin); guint8 buf[8] = { 0x0 }; g_autoptr(FuDeviceLocker) locker = NULL; @@ -88,9 +90,43 @@ fu_plugin_udev_device_added (FuPlugin *plugin, FuUdevDevice *device, GError **er priv->ia32_debug.fields.locked, priv->ia32_debug.fields.debug_occurred); } + + /* get microcode version */ + if (device_cpu != NULL) { + guint32 ver_raw; + if (!fu_udev_device_pread_full (device, PCI_MSR_IA32_BIOS_SIGN_ID, + buf, sizeof(buf), error)) { + g_prefix_error (error, "could not read IA32_BIOS_SIGN_ID: "); + return FALSE; + } + fu_common_dump_raw (G_LOG_DOMAIN, "IA32_BIOS_SIGN_ID", buf, sizeof(buf)); + if (!fu_common_read_uint32_safe (buf, sizeof(buf), 0x4, + &ver_raw, G_LITTLE_ENDIAN, + error)) + return FALSE; + if (ver_raw != 0) { + FwupdVersionFormat verfmt = fu_device_get_version_format (device_cpu); + g_autofree gchar *ver_str = NULL; + ver_str = fu_common_version_from_uint32 (ver_raw, verfmt); + g_debug ("setting microcode version to %s", ver_str); + fu_device_set_version (device_cpu, ver_str); + fu_device_set_version_raw (device_cpu, ver_raw); + } + } + + /* success */ return TRUE; } +void +fu_plugin_device_registered (FuPlugin *plugin, FuDevice *dev) +{ + if (g_strcmp0 (fu_device_get_plugin (dev), "cpu") == 0) { + fu_plugin_cache_add (plugin, "cpu", dev); + return; + } +} + static void fu_plugin_add_security_attr_dci_enabled (FuPlugin *plugin, FuSecurityAttrs *attrs) { From 7818067c33f28b5e67411a56eaa909158b67a45d Mon Sep 17 00:00:00 2001 From: Richard Hughes Date: Wed, 26 Aug 2020 09:38:35 +0100 Subject: [PATCH 346/607] trivial: Construct the HSI auto-URL correctly --- libfwupdplugin/fu-security-attrs.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libfwupdplugin/fu-security-attrs.c b/libfwupdplugin/fu-security-attrs.c index e7a1c17bb..d6df40ca8 100644 --- a/libfwupdplugin/fu-security-attrs.c +++ b/libfwupdplugin/fu-security-attrs.c @@ -67,7 +67,7 @@ fu_security_attrs_append (FuSecurityAttrs *self, FwupdSecurityAttr *attr) /* sanity check, and correctly prefix the URLs with the current mirror */ if (fwupd_security_attr_get_url (attr) == NULL) { g_autofree gchar *url = NULL; - url = g_strdup_printf ("%s%s", + url = g_strdup_printf ("%s#%s", FWUPD_SECURITY_ATTR_ID_DOC_URL, fwupd_security_attr_get_appstream_id (attr)); fwupd_security_attr_set_url (attr, url); From fc9cb560ebbe71336052cf54b671a72c9c1310df Mon Sep 17 00:00:00 2001 From: Mario Limonciello Date: Wed, 26 Aug 2020 09:22:40 -0500 Subject: [PATCH 347/607] trivial: debian: don't fail CI for subprojects --- contrib/debian/rules | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/contrib/debian/rules b/contrib/debian/rules index e41695cae..3f7e96f88 100755 --- a/contrib/debian/rules +++ b/contrib/debian/rules @@ -56,7 +56,9 @@ override_dh_install: if [ -d debian/tmp/usr/libexec/fwupd/efi/ ]; then \ dh_install -pfwupd usr/libexec/fwupd/efi ;\ fi - dh_missing -a --fail-missing + if [ -z "$$CI" ]; then \ + dh_missing -a --fail-missing; \ + fi #this is placed in fwupd-tests rm -f debian/fwupd/usr/lib/*/fwupd-plugins-3/libfu_plugin_test.so From 8819ee54f3994d1555fb5fdc4476b0c4c64876c0 Mon Sep 17 00:00:00 2001 From: Richard Hughes Date: Wed, 26 Aug 2020 16:19:34 +0100 Subject: [PATCH 348/607] trivial: Update the CI to Fedora 32 and drop various workarounds --- contrib/ci/Dockerfile-fedora.in | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/contrib/ci/Dockerfile-fedora.in b/contrib/ci/Dockerfile-fedora.in index 29eb03faf..a9255d458 100644 --- a/contrib/ci/Dockerfile-fedora.in +++ b/contrib/ci/Dockerfile-fedora.in @@ -1,14 +1,12 @@ -FROM fedora:31 +FROM fedora:32 %%%OS%%% ENV LANG en_US.UTF-8 ENV LANGUAGE en_US:en ENV LC_ALL en_US.UTF-8 RUN echo fubar > /etc/machine-id RUN dnf -y update -RUN dnf -y install https://kojipkgs.fedoraproject.org//packages/pesign/113/12.fc31/x86_64/pesign-113-12.fc31.x86_64.rpm RUN echo fubar > /etc/machine-id %%%INSTALL_DEPENDENCIES_COMMAND%%% -RUN dnf -y update glib2 glib2-devel --releasever=32 RUN mkdir /build WORKDIR /build COPY . . From 93ba041ce2fa8913359bbab2063b19b1d6d90813 Mon Sep 17 00:00:00 2001 From: Richard Hughes Date: Tue, 25 Aug 2020 14:54:46 +0100 Subject: [PATCH 349/607] trivial: Use @self in FwupdClient to modernize the object --- libfwupd/fwupd-client.c | 568 ++++++++++++++++++++-------------------- libfwupd/fwupd-client.h | 94 +++---- 2 files changed, 331 insertions(+), 331 deletions(-) diff --git a/libfwupd/fwupd-client.c b/libfwupd/fwupd-client.c index 5e5796745..9db14a3cc 100644 --- a/libfwupd/fwupd-client.c +++ b/libfwupd/fwupd-client.c @@ -118,71 +118,71 @@ G_DEFINE_AUTOPTR_CLEANUP_FUNC(FwupdClientHelper, fwupd_client_helper_free) #pragma clang diagnostic pop static void -fwupd_client_set_host_product (FwupdClient *client, const gchar *host_product) +fwupd_client_set_host_product (FwupdClient *self, const gchar *host_product) { - FwupdClientPrivate *priv = GET_PRIVATE (client); + FwupdClientPrivate *priv = GET_PRIVATE (self); g_free (priv->host_product); priv->host_product = g_strdup (host_product); - g_object_notify (G_OBJECT (client), "host-product"); + g_object_notify (G_OBJECT (self), "host-product"); } static void -fwupd_client_set_host_machine_id (FwupdClient *client, const gchar *host_machine_id) +fwupd_client_set_host_machine_id (FwupdClient *self, const gchar *host_machine_id) { - FwupdClientPrivate *priv = GET_PRIVATE (client); + FwupdClientPrivate *priv = GET_PRIVATE (self); g_free (priv->host_machine_id); priv->host_machine_id = g_strdup (host_machine_id); - g_object_notify (G_OBJECT (client), "host-machine-id"); + g_object_notify (G_OBJECT (self), "host-machine-id"); } static void -fwupd_client_set_host_security_id (FwupdClient *client, const gchar *host_security_id) +fwupd_client_set_host_security_id (FwupdClient *self, const gchar *host_security_id) { - FwupdClientPrivate *priv = GET_PRIVATE (client); + FwupdClientPrivate *priv = GET_PRIVATE (self); g_free (priv->host_security_id); priv->host_security_id = g_strdup (host_security_id); - g_object_notify (G_OBJECT (client), "host-security-id"); + g_object_notify (G_OBJECT (self), "host-security-id"); } static void -fwupd_client_set_daemon_version (FwupdClient *client, const gchar *daemon_version) +fwupd_client_set_daemon_version (FwupdClient *self, const gchar *daemon_version) { - FwupdClientPrivate *priv = GET_PRIVATE (client); + FwupdClientPrivate *priv = GET_PRIVATE (self); g_free (priv->daemon_version); priv->daemon_version = g_strdup (daemon_version); - g_object_notify (G_OBJECT (client), "daemon-version"); + g_object_notify (G_OBJECT (self), "daemon-version"); } static void -fwupd_client_set_status (FwupdClient *client, FwupdStatus status) +fwupd_client_set_status (FwupdClient *self, FwupdStatus status) { - FwupdClientPrivate *priv = GET_PRIVATE (client); + FwupdClientPrivate *priv = GET_PRIVATE (self); if (priv->status == status) return; priv->status = status; g_debug ("Emitting ::status-changed() [%s]", fwupd_status_to_string (priv->status)); - g_signal_emit (client, signals[SIGNAL_STATUS_CHANGED], 0, priv->status); - g_object_notify (G_OBJECT (client), "status"); + g_signal_emit (self, signals[SIGNAL_STATUS_CHANGED], 0, priv->status); + g_object_notify (G_OBJECT (self), "status"); } static void -fwupd_client_set_percentage (FwupdClient *client, guint percentage) +fwupd_client_set_percentage (FwupdClient *self, guint percentage) { - FwupdClientPrivate *priv = GET_PRIVATE (client); + FwupdClientPrivate *priv = GET_PRIVATE (self); if (priv->percentage == percentage) return; priv->percentage = percentage; - g_object_notify (G_OBJECT (client), "percentage"); + g_object_notify (G_OBJECT (self), "percentage"); } static void fwupd_client_properties_changed_cb (GDBusProxy *proxy, GVariant *changed_properties, GStrv invalidated_properties, - FwupdClient *client) + FwupdClient *self) { - FwupdClientPrivate *priv = GET_PRIVATE (client); + FwupdClientPrivate *priv = GET_PRIVATE (self); g_autoptr(GVariantDict) dict = NULL; /* print to the console */ @@ -191,14 +191,14 @@ fwupd_client_properties_changed_cb (GDBusProxy *proxy, g_autoptr(GVariant) val = NULL; val = g_dbus_proxy_get_cached_property (proxy, "Status"); if (val != NULL) - fwupd_client_set_status (client, g_variant_get_uint32 (val)); + fwupd_client_set_status (self, g_variant_get_uint32 (val)); } if (g_variant_dict_contains (dict, "Tainted")) { g_autoptr(GVariant) val = NULL; val = g_dbus_proxy_get_cached_property (proxy, "Tainted"); if (val != NULL) { priv->tainted = g_variant_get_boolean (val); - g_object_notify (G_OBJECT (client), "tainted"); + g_object_notify (G_OBJECT (self), "tainted"); } } if (g_variant_dict_contains (dict, "Interactive")) { @@ -206,38 +206,38 @@ fwupd_client_properties_changed_cb (GDBusProxy *proxy, val = g_dbus_proxy_get_cached_property (proxy, "Interactive"); if (val != NULL) { priv->interactive = g_variant_get_boolean (val); - g_object_notify (G_OBJECT (client), "interactive"); + g_object_notify (G_OBJECT (self), "interactive"); } } if (g_variant_dict_contains (dict, "Percentage")) { g_autoptr(GVariant) val = NULL; val = g_dbus_proxy_get_cached_property (proxy, "Percentage"); if (val != NULL) - fwupd_client_set_percentage (client, g_variant_get_uint32 (val)); + fwupd_client_set_percentage (self, g_variant_get_uint32 (val)); } if (g_variant_dict_contains (dict, "DaemonVersion")) { g_autoptr(GVariant) val = NULL; val = g_dbus_proxy_get_cached_property (proxy, "DaemonVersion"); if (val != NULL) - fwupd_client_set_daemon_version (client, g_variant_get_string (val, NULL)); + fwupd_client_set_daemon_version (self, g_variant_get_string (val, NULL)); } if (g_variant_dict_contains (dict, "HostProduct")) { g_autoptr(GVariant) val = NULL; val = g_dbus_proxy_get_cached_property (proxy, "HostProduct"); if (val != NULL) - fwupd_client_set_host_product (client, g_variant_get_string (val, NULL)); + fwupd_client_set_host_product (self, g_variant_get_string (val, NULL)); } if (g_variant_dict_contains (dict, "HostMachineId")) { g_autoptr(GVariant) val = NULL; val = g_dbus_proxy_get_cached_property (proxy, "HostMachineId"); if (val != NULL) - fwupd_client_set_host_machine_id (client, g_variant_get_string (val, NULL)); + fwupd_client_set_host_machine_id (self, g_variant_get_string (val, NULL)); } if (g_variant_dict_contains (dict, "HostSecurityId")) { g_autoptr(GVariant) val = NULL; val = g_dbus_proxy_get_cached_property (proxy, "HostSecurityId"); if (val != NULL) - fwupd_client_set_host_security_id (client, g_variant_get_string (val, NULL)); + fwupd_client_set_host_security_id (self, g_variant_get_string (val, NULL)); } } @@ -246,31 +246,31 @@ fwupd_client_signal_cb (GDBusProxy *proxy, const gchar *sender_name, const gchar *signal_name, GVariant *parameters, - FwupdClient *client) + FwupdClient *self) { g_autoptr(FwupdDevice) dev = NULL; if (g_strcmp0 (signal_name, "Changed") == 0) { g_debug ("Emitting ::changed()"); - g_signal_emit (client, signals[SIGNAL_CHANGED], 0); + g_signal_emit (self, signals[SIGNAL_CHANGED], 0); return; } if (g_strcmp0 (signal_name, "DeviceAdded") == 0) { dev = fwupd_device_from_variant (parameters); g_debug ("Emitting ::device-added(%s)", fwupd_device_get_id (dev)); - g_signal_emit (client, signals[SIGNAL_DEVICE_ADDED], 0, dev); + g_signal_emit (self, signals[SIGNAL_DEVICE_ADDED], 0, dev); return; } if (g_strcmp0 (signal_name, "DeviceRemoved") == 0) { dev = fwupd_device_from_variant (parameters); - g_signal_emit (client, signals[SIGNAL_DEVICE_REMOVED], 0, dev); + g_signal_emit (self, signals[SIGNAL_DEVICE_REMOVED], 0, dev); g_debug ("Emitting ::device-removed(%s)", fwupd_device_get_id (dev)); return; } if (g_strcmp0 (signal_name, "DeviceChanged") == 0) { dev = fwupd_device_from_variant (parameters); - g_signal_emit (client, signals[SIGNAL_DEVICE_CHANGED], 0, dev); + g_signal_emit (self, signals[SIGNAL_DEVICE_CHANGED], 0, dev); g_debug ("Emitting ::device-changed(%s)", fwupd_device_get_id (dev)); return; @@ -280,7 +280,7 @@ fwupd_client_signal_cb (GDBusProxy *proxy, /** * fwupd_client_ensure_networking: - * @client: A #FwupdClient + * @self: A #FwupdClient * @error: the #GError, or %NULL * * Sets up the client networking support ready for use. Most other download and @@ -292,9 +292,9 @@ fwupd_client_signal_cb (GDBusProxy *proxy, * Since: 1.4.5 **/ gboolean -fwupd_client_ensure_networking (FwupdClient *client, GError **error) +fwupd_client_ensure_networking (FwupdClient *self, GError **error) { - FwupdClientPrivate *priv = GET_PRIVATE (client); + FwupdClientPrivate *priv = GET_PRIVATE (self); const gchar *http_proxy; g_autoptr(SoupSession) session = NULL; @@ -362,7 +362,7 @@ fwupd_client_ensure_networking (FwupdClient *client, GError **error) /** * fwupd_client_connect: - * @client: A #FwupdClient + * @self: A #FwupdClient * @cancellable: the #GCancellable, or %NULL * @error: the #GError, or %NULL * @@ -375,13 +375,13 @@ fwupd_client_ensure_networking (FwupdClient *client, GError **error) * Since: 0.7.1 **/ gboolean -fwupd_client_connect (FwupdClient *client, GCancellable *cancellable, GError **error) +fwupd_client_connect (FwupdClient *self, GCancellable *cancellable, GError **error) { - FwupdClientPrivate *priv = GET_PRIVATE (client); + FwupdClientPrivate *priv = GET_PRIVATE (self); g_autoptr(GVariant) val = NULL; g_autoptr(GVariant) val2 = NULL; - g_return_val_if_fail (FWUPD_IS_CLIENT (client), FALSE); + g_return_val_if_fail (FWUPD_IS_CLIENT (self), FALSE); g_return_val_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable), FALSE); g_return_val_if_fail (error == NULL || *error == NULL, FALSE); @@ -406,12 +406,12 @@ fwupd_client_connect (FwupdClient *client, GCancellable *cancellable, GError **e if (priv->proxy == NULL) return FALSE; g_signal_connect (priv->proxy, "g-properties-changed", - G_CALLBACK (fwupd_client_properties_changed_cb), client); + G_CALLBACK (fwupd_client_properties_changed_cb), self); g_signal_connect (priv->proxy, "g-signal", - G_CALLBACK (fwupd_client_signal_cb), client); + G_CALLBACK (fwupd_client_signal_cb), self); val = g_dbus_proxy_get_cached_property (priv->proxy, "DaemonVersion"); if (val != NULL) - fwupd_client_set_daemon_version (client, g_variant_get_string (val, NULL)); + fwupd_client_set_daemon_version (self, g_variant_get_string (val, NULL)); val2 = g_dbus_proxy_get_cached_property (priv->proxy, "Tainted"); if (val2 != NULL) priv->tainted = g_variant_get_boolean (val2); @@ -420,13 +420,13 @@ fwupd_client_connect (FwupdClient *client, GCancellable *cancellable, GError **e priv->interactive = g_variant_get_boolean (val2); val = g_dbus_proxy_get_cached_property (priv->proxy, "HostProduct"); if (val != NULL) - fwupd_client_set_host_product (client, g_variant_get_string (val, NULL)); + fwupd_client_set_host_product (self, g_variant_get_string (val, NULL)); val = g_dbus_proxy_get_cached_property (priv->proxy, "HostMachineId"); if (val != NULL) - fwupd_client_set_host_machine_id (client, g_variant_get_string (val, NULL)); + fwupd_client_set_host_machine_id (self, g_variant_get_string (val, NULL)); val = g_dbus_proxy_get_cached_property (priv->proxy, "HostSecurityId"); if (val != NULL) - fwupd_client_set_host_security_id (client, g_variant_get_string (val, NULL)); + fwupd_client_set_host_security_id (self, g_variant_get_string (val, NULL)); return TRUE; } @@ -466,7 +466,7 @@ fwupd_client_fixup_dbus_error (GError *error) /** * fwupd_client_get_host_security_attrs: - * @client: A #FwupdClient + * @self: A #FwupdClient * @cancellable: the #GCancellable, or %NULL * @error: the #GError, or %NULL * @@ -477,17 +477,17 @@ fwupd_client_fixup_dbus_error (GError *error) * Since: 1.5.0 **/ GPtrArray * -fwupd_client_get_host_security_attrs (FwupdClient *client, GCancellable *cancellable, GError **error) +fwupd_client_get_host_security_attrs (FwupdClient *self, GCancellable *cancellable, GError **error) { - FwupdClientPrivate *priv = GET_PRIVATE (client); + FwupdClientPrivate *priv = GET_PRIVATE (self); g_autoptr(GVariant) val = NULL; - g_return_val_if_fail (FWUPD_IS_CLIENT (client), NULL); + g_return_val_if_fail (FWUPD_IS_CLIENT (self), NULL); g_return_val_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable), NULL); g_return_val_if_fail (error == NULL || *error == NULL, NULL); /* connect */ - if (!fwupd_client_connect (client, cancellable, error)) + if (!fwupd_client_connect (self, cancellable, error)) return NULL; /* call into daemon */ @@ -529,7 +529,7 @@ fwupd_report_metadata_hash_from_variant (GVariant *value) /** * fwupd_client_get_report_metadata: - * @client: A #FwupdClient + * @self: A #FwupdClient * @cancellable: the #GCancellable, or %NULL * @error: the #GError, or %NULL * @@ -540,19 +540,19 @@ fwupd_report_metadata_hash_from_variant (GVariant *value) * Since: 1.5.0 **/ GHashTable * -fwupd_client_get_report_metadata (FwupdClient *client, +fwupd_client_get_report_metadata (FwupdClient *self, GCancellable *cancellable, GError **error) { - FwupdClientPrivate *priv = GET_PRIVATE (client); + FwupdClientPrivate *priv = GET_PRIVATE (self); g_autoptr(GVariant) val = NULL; - g_return_val_if_fail (FWUPD_IS_CLIENT (client), NULL); + g_return_val_if_fail (FWUPD_IS_CLIENT (self), NULL); g_return_val_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable), NULL); g_return_val_if_fail (error == NULL || *error == NULL, NULL); /* connect */ - if (!fwupd_client_connect (client, cancellable, error)) + if (!fwupd_client_connect (self, cancellable, error)) return NULL; /* call into daemon */ @@ -573,7 +573,7 @@ fwupd_client_get_report_metadata (FwupdClient *client, /** * fwupd_client_get_devices: - * @client: A #FwupdClient + * @self: A #FwupdClient * @cancellable: the #GCancellable, or %NULL * @error: the #GError, or %NULL * @@ -584,17 +584,17 @@ fwupd_client_get_report_metadata (FwupdClient *client, * Since: 0.9.2 **/ GPtrArray * -fwupd_client_get_devices (FwupdClient *client, GCancellable *cancellable, GError **error) +fwupd_client_get_devices (FwupdClient *self, GCancellable *cancellable, GError **error) { - FwupdClientPrivate *priv = GET_PRIVATE (client); + FwupdClientPrivate *priv = GET_PRIVATE (self); g_autoptr(GVariant) val = NULL; - g_return_val_if_fail (FWUPD_IS_CLIENT (client), NULL); + g_return_val_if_fail (FWUPD_IS_CLIENT (self), NULL); g_return_val_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable), NULL); g_return_val_if_fail (error == NULL || *error == NULL, NULL); /* connect */ - if (!fwupd_client_connect (client, cancellable, error)) + if (!fwupd_client_connect (self, cancellable, error)) return NULL; /* call into daemon */ @@ -615,7 +615,7 @@ fwupd_client_get_devices (FwupdClient *client, GCancellable *cancellable, GError /** * fwupd_client_get_history: - * @client: A #FwupdClient + * @self: A #FwupdClient * @cancellable: the #GCancellable, or %NULL * @error: the #GError, or %NULL * @@ -626,17 +626,17 @@ fwupd_client_get_devices (FwupdClient *client, GCancellable *cancellable, GError * Since: 1.0.4 **/ GPtrArray * -fwupd_client_get_history (FwupdClient *client, GCancellable *cancellable, GError **error) +fwupd_client_get_history (FwupdClient *self, GCancellable *cancellable, GError **error) { - FwupdClientPrivate *priv = GET_PRIVATE (client); + FwupdClientPrivate *priv = GET_PRIVATE (self); g_autoptr(GVariant) val = NULL; - g_return_val_if_fail (FWUPD_IS_CLIENT (client), NULL); + g_return_val_if_fail (FWUPD_IS_CLIENT (self), NULL); g_return_val_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable), NULL); g_return_val_if_fail (error == NULL || *error == NULL, NULL); /* connect */ - if (!fwupd_client_connect (client, cancellable, error)) + if (!fwupd_client_connect (self, cancellable, error)) return NULL; /* call into daemon */ @@ -657,7 +657,7 @@ fwupd_client_get_history (FwupdClient *client, GCancellable *cancellable, GError /** * fwupd_client_get_device_by_id: - * @client: A #FwupdClient + * @self: A #FwupdClient * @device_id: the device ID, e.g. `usb:00:01:03:03` * @cancellable: the #GCancellable, or %NULL * @error: the #GError, or %NULL @@ -669,20 +669,20 @@ fwupd_client_get_history (FwupdClient *client, GCancellable *cancellable, GError * Since: 0.9.3 **/ FwupdDevice * -fwupd_client_get_device_by_id (FwupdClient *client, +fwupd_client_get_device_by_id (FwupdClient *self, const gchar *device_id, GCancellable *cancellable, GError **error) { g_autoptr(GPtrArray) devices = NULL; - g_return_val_if_fail (FWUPD_IS_CLIENT (client), NULL); + g_return_val_if_fail (FWUPD_IS_CLIENT (self), NULL); g_return_val_if_fail (device_id != NULL, NULL); g_return_val_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable), NULL); g_return_val_if_fail (error == NULL || *error == NULL, NULL); /* get all the devices */ - devices = fwupd_client_get_devices (client, cancellable, error); + devices = fwupd_client_get_devices (self, cancellable, error); if (devices == NULL) return NULL; @@ -701,7 +701,7 @@ fwupd_client_get_device_by_id (FwupdClient *client, /** * fwupd_client_get_devices_by_guid: - * @client: A #FwupdClient + * @self: A #FwupdClient * @guid: the GUID, e.g. `e22c4520-43dc-5bb3-8245-5787fead9b63` * @cancellable: the #GCancellable, or %NULL * @error: the #GError, or %NULL @@ -714,7 +714,7 @@ fwupd_client_get_device_by_id (FwupdClient *client, * Since: 1.4.1 **/ GPtrArray * -fwupd_client_get_devices_by_guid (FwupdClient *client, +fwupd_client_get_devices_by_guid (FwupdClient *self, const gchar *guid, GCancellable *cancellable, GError **error) @@ -722,13 +722,13 @@ fwupd_client_get_devices_by_guid (FwupdClient *client, g_autoptr(GPtrArray) devices = NULL; g_autoptr(GPtrArray) devices_tmp = NULL; - g_return_val_if_fail (FWUPD_IS_CLIENT (client), NULL); + g_return_val_if_fail (FWUPD_IS_CLIENT (self), NULL); g_return_val_if_fail (guid != NULL, NULL); g_return_val_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable), NULL); g_return_val_if_fail (error == NULL || *error == NULL, NULL); /* get all the devices */ - devices_tmp = fwupd_client_get_devices (client, cancellable, error); + devices_tmp = fwupd_client_get_devices (self, cancellable, error); if (devices_tmp == NULL) return NULL; @@ -755,7 +755,7 @@ fwupd_client_get_devices_by_guid (FwupdClient *client, /** * fwupd_client_get_releases: - * @client: A #FwupdClient + * @self: A #FwupdClient * @device_id: the device ID * @cancellable: the #GCancellable, or %NULL * @error: the #GError, or %NULL @@ -767,19 +767,19 @@ fwupd_client_get_devices_by_guid (FwupdClient *client, * Since: 0.9.3 **/ GPtrArray * -fwupd_client_get_releases (FwupdClient *client, const gchar *device_id, +fwupd_client_get_releases (FwupdClient *self, const gchar *device_id, GCancellable *cancellable, GError **error) { - FwupdClientPrivate *priv = GET_PRIVATE (client); + FwupdClientPrivate *priv = GET_PRIVATE (self); g_autoptr(GVariant) val = NULL; - g_return_val_if_fail (FWUPD_IS_CLIENT (client), NULL); + g_return_val_if_fail (FWUPD_IS_CLIENT (self), NULL); g_return_val_if_fail (device_id != NULL, NULL); g_return_val_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable), NULL); g_return_val_if_fail (error == NULL || *error == NULL, NULL); /* connect */ - if (!fwupd_client_connect (client, cancellable, error)) + if (!fwupd_client_connect (self, cancellable, error)) return NULL; /* call into daemon */ @@ -800,7 +800,7 @@ fwupd_client_get_releases (FwupdClient *client, const gchar *device_id, /** * fwupd_client_get_downgrades: - * @client: A #FwupdClient + * @self: A #FwupdClient * @device_id: the device ID * @cancellable: the #GCancellable, or %NULL * @error: the #GError, or %NULL @@ -812,19 +812,19 @@ fwupd_client_get_releases (FwupdClient *client, const gchar *device_id, * Since: 0.9.8 **/ GPtrArray * -fwupd_client_get_downgrades (FwupdClient *client, const gchar *device_id, +fwupd_client_get_downgrades (FwupdClient *self, const gchar *device_id, GCancellable *cancellable, GError **error) { - FwupdClientPrivate *priv = GET_PRIVATE (client); + FwupdClientPrivate *priv = GET_PRIVATE (self); g_autoptr(GVariant) val = NULL; - g_return_val_if_fail (FWUPD_IS_CLIENT (client), NULL); + g_return_val_if_fail (FWUPD_IS_CLIENT (self), NULL); g_return_val_if_fail (device_id != NULL, NULL); g_return_val_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable), NULL); g_return_val_if_fail (error == NULL || *error == NULL, NULL); /* connect */ - if (!fwupd_client_connect (client, cancellable, error)) + if (!fwupd_client_connect (self, cancellable, error)) return NULL; /* call into daemon */ @@ -845,7 +845,7 @@ fwupd_client_get_downgrades (FwupdClient *client, const gchar *device_id, /** * fwupd_client_get_upgrades: - * @client: A #FwupdClient + * @self: A #FwupdClient * @device_id: the device ID * @cancellable: the #GCancellable, or %NULL * @error: the #GError, or %NULL @@ -857,19 +857,19 @@ fwupd_client_get_downgrades (FwupdClient *client, const gchar *device_id, * Since: 0.9.8 **/ GPtrArray * -fwupd_client_get_upgrades (FwupdClient *client, const gchar *device_id, +fwupd_client_get_upgrades (FwupdClient *self, const gchar *device_id, GCancellable *cancellable, GError **error) { - FwupdClientPrivate *priv = GET_PRIVATE (client); + FwupdClientPrivate *priv = GET_PRIVATE (self); g_autoptr(GVariant) val = NULL; - g_return_val_if_fail (FWUPD_IS_CLIENT (client), NULL); + g_return_val_if_fail (FWUPD_IS_CLIENT (self), NULL); g_return_val_if_fail (device_id != NULL, NULL); g_return_val_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable), NULL); g_return_val_if_fail (error == NULL || *error == NULL, NULL); /* connect */ - if (!fwupd_client_connect (client, cancellable, error)) + if (!fwupd_client_connect (self, cancellable, error)) return NULL; /* call into daemon */ @@ -903,7 +903,7 @@ fwupd_client_proxy_call_cb (GObject *source, GAsyncResult *res, gpointer user_da /** * fwupd_client_modify_config - * @client: A #FwupdClient + * @self: A #FwupdClient * @key: key, e.g. `DisabledPlugins` * @value: value, e.g. `*` * @cancellable: the #GCancellable, or %NULL @@ -917,18 +917,18 @@ fwupd_client_proxy_call_cb (GObject *source, GAsyncResult *res, gpointer user_da * Since: 1.2.8 **/ gboolean -fwupd_client_modify_config (FwupdClient *client, const gchar *key, const gchar *value, +fwupd_client_modify_config (FwupdClient *self, const gchar *key, const gchar *value, GCancellable *cancellable, GError **error) { - FwupdClientPrivate *priv = GET_PRIVATE (client); + FwupdClientPrivate *priv = GET_PRIVATE (self); g_autoptr(FwupdClientHelper) helper = NULL; - g_return_val_if_fail (FWUPD_IS_CLIENT (client), FALSE); + g_return_val_if_fail (FWUPD_IS_CLIENT (self), FALSE); g_return_val_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable), FALSE); g_return_val_if_fail (error == NULL || *error == NULL, FALSE); /* connect */ - if (!fwupd_client_connect (client, cancellable, error)) + if (!fwupd_client_connect (self, cancellable, error)) return FALSE; /* call into daemon */ @@ -952,7 +952,7 @@ fwupd_client_modify_config (FwupdClient *client, const gchar *key, const gchar * /** * fwupd_client_activate: - * @client: A #FwupdClient + * @self: A #FwupdClient * @cancellable: the #GCancellable, or %NULL * @device_id: a device * @error: the #GError, or %NULL @@ -965,19 +965,19 @@ fwupd_client_modify_config (FwupdClient *client, const gchar *key, const gchar * * Since: 1.2.6 **/ gboolean -fwupd_client_activate (FwupdClient *client, GCancellable *cancellable, +fwupd_client_activate (FwupdClient *self, GCancellable *cancellable, const gchar *device_id, GError **error) { - FwupdClientPrivate *priv = GET_PRIVATE (client); + FwupdClientPrivate *priv = GET_PRIVATE (self); g_autoptr(FwupdClientHelper) helper = NULL; - g_return_val_if_fail (FWUPD_IS_CLIENT (client), FALSE); + g_return_val_if_fail (FWUPD_IS_CLIENT (self), FALSE); g_return_val_if_fail (device_id != NULL, FALSE); g_return_val_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable), FALSE); g_return_val_if_fail (error == NULL || *error == NULL, FALSE); /* connect */ - if (!fwupd_client_connect (client, cancellable, error)) + if (!fwupd_client_connect (self, cancellable, error)) return FALSE; /* call into daemon */ @@ -1001,7 +1001,7 @@ fwupd_client_activate (FwupdClient *client, GCancellable *cancellable, /** * fwupd_client_verify: - * @client: A #FwupdClient + * @self: A #FwupdClient * @device_id: the device ID * @cancellable: the #GCancellable, or %NULL * @error: the #GError, or %NULL @@ -1013,19 +1013,19 @@ fwupd_client_activate (FwupdClient *client, GCancellable *cancellable, * Since: 0.7.0 **/ gboolean -fwupd_client_verify (FwupdClient *client, const gchar *device_id, +fwupd_client_verify (FwupdClient *self, const gchar *device_id, GCancellable *cancellable, GError **error) { - FwupdClientPrivate *priv = GET_PRIVATE (client); + FwupdClientPrivate *priv = GET_PRIVATE (self); g_autoptr(FwupdClientHelper) helper = NULL; - g_return_val_if_fail (FWUPD_IS_CLIENT (client), FALSE); + g_return_val_if_fail (FWUPD_IS_CLIENT (self), FALSE); g_return_val_if_fail (device_id != NULL, FALSE); g_return_val_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable), FALSE); g_return_val_if_fail (error == NULL || *error == NULL, FALSE); /* connect */ - if (!fwupd_client_connect (client, cancellable, error)) + if (!fwupd_client_connect (self, cancellable, error)) return FALSE; /* call into daemon */ @@ -1049,7 +1049,7 @@ fwupd_client_verify (FwupdClient *client, const gchar *device_id, /** * fwupd_client_verify_update: - * @client: A #FwupdClient + * @self: A #FwupdClient * @device_id: the device ID * @cancellable: the #GCancellable, or %NULL * @error: the #GError, or %NULL @@ -1061,19 +1061,19 @@ fwupd_client_verify (FwupdClient *client, const gchar *device_id, * Since: 0.8.0 **/ gboolean -fwupd_client_verify_update (FwupdClient *client, const gchar *device_id, +fwupd_client_verify_update (FwupdClient *self, const gchar *device_id, GCancellable *cancellable, GError **error) { - FwupdClientPrivate *priv = GET_PRIVATE (client); + FwupdClientPrivate *priv = GET_PRIVATE (self); g_autoptr(FwupdClientHelper) helper = NULL; - g_return_val_if_fail (FWUPD_IS_CLIENT (client), FALSE); + g_return_val_if_fail (FWUPD_IS_CLIENT (self), FALSE); g_return_val_if_fail (device_id != NULL, FALSE); g_return_val_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable), FALSE); g_return_val_if_fail (error == NULL || *error == NULL, FALSE); /* connect */ - if (!fwupd_client_connect (client, cancellable, error)) + if (!fwupd_client_connect (self, cancellable, error)) return FALSE; /* call into daemon */ @@ -1097,7 +1097,7 @@ fwupd_client_verify_update (FwupdClient *client, const gchar *device_id, /** * fwupd_client_unlock: - * @client: A #FwupdClient + * @self: A #FwupdClient * @device_id: the device ID * @cancellable: the #GCancellable, or %NULL * @error: the #GError, or %NULL @@ -1109,19 +1109,19 @@ fwupd_client_verify_update (FwupdClient *client, const gchar *device_id, * Since: 0.7.0 **/ gboolean -fwupd_client_unlock (FwupdClient *client, const gchar *device_id, +fwupd_client_unlock (FwupdClient *self, const gchar *device_id, GCancellable *cancellable, GError **error) { - FwupdClientPrivate *priv = GET_PRIVATE (client); + FwupdClientPrivate *priv = GET_PRIVATE (self); g_autoptr(FwupdClientHelper) helper = NULL; - g_return_val_if_fail (FWUPD_IS_CLIENT (client), FALSE); + g_return_val_if_fail (FWUPD_IS_CLIENT (self), FALSE); g_return_val_if_fail (device_id != NULL, FALSE); g_return_val_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable), FALSE); g_return_val_if_fail (error == NULL || *error == NULL, FALSE); /* connect */ - if (!fwupd_client_connect (client, cancellable, error)) + if (!fwupd_client_connect (self, cancellable, error)) return FALSE; /* call into daemon */ @@ -1145,7 +1145,7 @@ fwupd_client_unlock (FwupdClient *client, const gchar *device_id, /** * fwupd_client_clear_results: - * @client: A #FwupdClient + * @self: A #FwupdClient * @device_id: the device ID * @cancellable: the #GCancellable, or %NULL * @error: the #GError, or %NULL @@ -1157,19 +1157,19 @@ fwupd_client_unlock (FwupdClient *client, const gchar *device_id, * Since: 0.7.0 **/ gboolean -fwupd_client_clear_results (FwupdClient *client, const gchar *device_id, +fwupd_client_clear_results (FwupdClient *self, const gchar *device_id, GCancellable *cancellable, GError **error) { - FwupdClientPrivate *priv = GET_PRIVATE (client); + FwupdClientPrivate *priv = GET_PRIVATE (self); g_autoptr(FwupdClientHelper) helper = NULL; - g_return_val_if_fail (FWUPD_IS_CLIENT (client), FALSE); + g_return_val_if_fail (FWUPD_IS_CLIENT (self), FALSE); g_return_val_if_fail (device_id != NULL, FALSE); g_return_val_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable), FALSE); g_return_val_if_fail (error == NULL || *error == NULL, FALSE); /* connect */ - if (!fwupd_client_connect (client, cancellable, error)) + if (!fwupd_client_connect (self, cancellable, error)) return FALSE; /* call into daemon */ @@ -1193,7 +1193,7 @@ fwupd_client_clear_results (FwupdClient *client, const gchar *device_id, /** * fwupd_client_get_results: - * @client: A #FwupdClient + * @self: A #FwupdClient * @device_id: the device ID * @cancellable: the #GCancellable, or %NULL * @error: the #GError, or %NULL @@ -1205,19 +1205,19 @@ fwupd_client_clear_results (FwupdClient *client, const gchar *device_id, * Since: 0.7.0 **/ FwupdDevice * -fwupd_client_get_results (FwupdClient *client, const gchar *device_id, +fwupd_client_get_results (FwupdClient *self, const gchar *device_id, GCancellable *cancellable, GError **error) { - FwupdClientPrivate *priv = GET_PRIVATE (client); + FwupdClientPrivate *priv = GET_PRIVATE (self); g_autoptr(FwupdClientHelper) helper = NULL; - g_return_val_if_fail (FWUPD_IS_CLIENT (client), NULL); + g_return_val_if_fail (FWUPD_IS_CLIENT (self), NULL); g_return_val_if_fail (device_id != NULL, NULL); g_return_val_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable), NULL); g_return_val_if_fail (error == NULL || *error == NULL, NULL); /* connect */ - if (!fwupd_client_connect (client, cancellable, error)) + if (!fwupd_client_connect (self, cancellable, error)) return NULL; /* call into daemon */ @@ -1262,7 +1262,7 @@ fwupd_client_send_message_cb (GObject *source_object, GAsyncResult *res, gpointe #ifdef HAVE_GIO_UNIX static gboolean -fwupd_client_install_fd (FwupdClient *client, +fwupd_client_install_fd (FwupdClient *self, const gchar *device_id, GUnixInputStream *istr, const gchar *filename_hint, @@ -1270,7 +1270,7 @@ fwupd_client_install_fd (FwupdClient *client, GCancellable *cancellable, GError **error) { - FwupdClientPrivate *priv = GET_PRIVATE (client); + FwupdClientPrivate *priv = GET_PRIVATE (self); GVariant *body; GVariantBuilder builder; gint retval; @@ -1341,7 +1341,7 @@ fwupd_client_install_fd (FwupdClient *client, /** * fwupd_client_install_bytes: - * @client: A #FwupdClient + * @self: A #FwupdClient * @device_id: the device ID * @bytes: #GBytes * @install_flags: the #FwupdInstallFlags, e.g. %FWUPD_INSTALL_FLAG_ALLOW_REINSTALL @@ -1355,7 +1355,7 @@ fwupd_client_install_fd (FwupdClient *client, * Since: 1.4.5 **/ gboolean -fwupd_client_install_bytes (FwupdClient *client, +fwupd_client_install_bytes (FwupdClient *self, const gchar *device_id, GBytes *bytes, FwupdInstallFlags install_flags, @@ -1365,20 +1365,20 @@ fwupd_client_install_bytes (FwupdClient *client, #ifdef HAVE_GIO_UNIX g_autoptr(GUnixInputStream) istr = NULL; - g_return_val_if_fail (FWUPD_IS_CLIENT (client), FALSE); + g_return_val_if_fail (FWUPD_IS_CLIENT (self), FALSE); g_return_val_if_fail (device_id != NULL, FALSE); g_return_val_if_fail (bytes != NULL, FALSE); g_return_val_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable), FALSE); g_return_val_if_fail (error == NULL || *error == NULL, FALSE); /* connect */ - if (!fwupd_client_connect (client, cancellable, error)) + if (!fwupd_client_connect (self, cancellable, error)) return FALSE; istr = fwupd_unix_input_stream_from_bytes (bytes, error); if (istr == NULL) return FALSE; - return fwupd_client_install_fd (client, device_id, istr, NULL, + return fwupd_client_install_fd (self, device_id, istr, NULL, install_flags, cancellable, error); #else g_set_error_literal (error, @@ -1391,7 +1391,7 @@ fwupd_client_install_bytes (FwupdClient *client, /** * fwupd_client_install: - * @client: A #FwupdClient + * @self: A #FwupdClient * @device_id: the device ID * @filename: the filename to install * @install_flags: the #FwupdInstallFlags, e.g. %FWUPD_INSTALL_FLAG_ALLOW_REINSTALL @@ -1405,7 +1405,7 @@ fwupd_client_install_bytes (FwupdClient *client, * Since: 0.7.0 **/ gboolean -fwupd_client_install (FwupdClient *client, +fwupd_client_install (FwupdClient *self, const gchar *device_id, const gchar *filename, FwupdInstallFlags install_flags, @@ -1415,20 +1415,20 @@ fwupd_client_install (FwupdClient *client, #ifdef HAVE_GIO_UNIX g_autoptr(GUnixInputStream) istr = NULL; - g_return_val_if_fail (FWUPD_IS_CLIENT (client), FALSE); + g_return_val_if_fail (FWUPD_IS_CLIENT (self), FALSE); g_return_val_if_fail (device_id != NULL, FALSE); g_return_val_if_fail (filename != NULL, FALSE); g_return_val_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable), FALSE); g_return_val_if_fail (error == NULL || *error == NULL, FALSE); /* connect */ - if (!fwupd_client_connect (client, cancellable, error)) + if (!fwupd_client_connect (self, cancellable, error)) return FALSE; istr = fwupd_unix_input_stream_from_fn (filename, error); if (istr == NULL) return FALSE; - return fwupd_client_install_fd (client, device_id, istr, filename, + return fwupd_client_install_fd (self, device_id, istr, filename, install_flags, cancellable, error); #else g_set_error_literal (error, @@ -1441,7 +1441,7 @@ fwupd_client_install (FwupdClient *client, /** * fwupd_client_install_release: - * @client: A #FwupdClient + * @self: A #FwupdClient * @device: A #FwupdDevice * @release: A #FwupdRelease * @install_flags: the #FwupdInstallFlags, e.g. %FWUPD_INSTALL_FLAG_ALLOW_REINSTALL @@ -1455,7 +1455,7 @@ fwupd_client_install (FwupdClient *client, * Since: 1.4.5 **/ gboolean -fwupd_client_install_release (FwupdClient *client, +fwupd_client_install_release (FwupdClient *self, FwupdDevice *device, FwupdRelease *release, FwupdInstallFlags install_flags, @@ -1480,7 +1480,7 @@ fwupd_client_install_release (FwupdClient *client, g_autofree gchar *fn = NULL; /* if a remote-id was specified, the remote has to exist */ - remote = fwupd_client_get_remote_by_id (client, remote_id, cancellable, error); + remote = fwupd_client_get_remote_by_id (self, remote_id, cancellable, error); if (remote == NULL) return FALSE; @@ -1496,7 +1496,7 @@ fwupd_client_install_release (FwupdClient *client, /* install with flags chosen by the user */ if (fn != NULL) { - return fwupd_client_install (client, fwupd_device_get_id (device), + return fwupd_client_install (self, fwupd_device_get_id (device), fn, install_flags, cancellable, error); } @@ -1509,7 +1509,7 @@ fwupd_client_install_release (FwupdClient *client, } /* download file */ - blob = fwupd_client_download_bytes (client, uri_str, + blob = fwupd_client_download_bytes (self, uri_str, FWUPD_CLIENT_DOWNLOAD_FLAG_NONE, cancellable, error); if (blob == NULL) @@ -1531,14 +1531,14 @@ fwupd_client_install_release (FwupdClient *client, /* if the device specifies ONLY_OFFLINE automatically set this flag */ if (fwupd_device_has_flag (device, FWUPD_DEVICE_FLAG_ONLY_OFFLINE)) install_flags |= FWUPD_INSTALL_FLAG_OFFLINE; - return fwupd_client_install_bytes (client, + return fwupd_client_install_bytes (self, fwupd_device_get_id (device), blob, install_flags, NULL, error); } /** * fwupd_client_get_details: - * @client: A #FwupdClient + * @self: A #FwupdClient * @filename: the firmware filename, e.g. `firmware.cab` * @cancellable: the #GCancellable, or %NULL * @error: the #GError, or %NULL @@ -1550,11 +1550,11 @@ fwupd_client_install_release (FwupdClient *client, * Since: 1.0.0 **/ GPtrArray * -fwupd_client_get_details (FwupdClient *client, const gchar *filename, +fwupd_client_get_details (FwupdClient *self, const gchar *filename, GCancellable *cancellable, GError **error) { #ifdef HAVE_GIO_UNIX - FwupdClientPrivate *priv = GET_PRIVATE (client); + FwupdClientPrivate *priv = GET_PRIVATE (self); GVariant *body; gint fd; gint retval; @@ -1562,13 +1562,13 @@ fwupd_client_get_details (FwupdClient *client, const gchar *filename, g_autoptr(GDBusMessage) request = NULL; g_autoptr(GUnixFDList) fd_list = NULL; - g_return_val_if_fail (FWUPD_IS_CLIENT (client), NULL); + g_return_val_if_fail (FWUPD_IS_CLIENT (self), NULL); g_return_val_if_fail (filename != NULL, NULL); g_return_val_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable), NULL); g_return_val_if_fail (error == NULL || *error == NULL, NULL); /* connect */ - if (!fwupd_client_connect (client, cancellable, error)) + if (!fwupd_client_connect (self, cancellable, error)) return NULL; /* open file */ @@ -1628,7 +1628,7 @@ fwupd_client_get_details (FwupdClient *client, const gchar *filename, /** * fwupd_client_get_percentage: - * @client: A #FwupdClient + * @self: A #FwupdClient * * Gets the last returned percentage value. * @@ -1637,16 +1637,16 @@ fwupd_client_get_details (FwupdClient *client, const gchar *filename, * Since: 0.7.3 **/ guint -fwupd_client_get_percentage (FwupdClient *client) +fwupd_client_get_percentage (FwupdClient *self) { - FwupdClientPrivate *priv = GET_PRIVATE (client); - g_return_val_if_fail (FWUPD_IS_CLIENT (client), 0); + FwupdClientPrivate *priv = GET_PRIVATE (self); + g_return_val_if_fail (FWUPD_IS_CLIENT (self), 0); return priv->percentage; } /** * fwupd_client_get_daemon_version: - * @client: A #FwupdClient + * @self: A #FwupdClient * * Gets the daemon version number. * @@ -1655,16 +1655,16 @@ fwupd_client_get_percentage (FwupdClient *client) * Since: 0.9.6 **/ const gchar * -fwupd_client_get_daemon_version (FwupdClient *client) +fwupd_client_get_daemon_version (FwupdClient *self) { - FwupdClientPrivate *priv = GET_PRIVATE (client); - g_return_val_if_fail (FWUPD_IS_CLIENT (client), NULL); + FwupdClientPrivate *priv = GET_PRIVATE (self); + g_return_val_if_fail (FWUPD_IS_CLIENT (self), NULL); return priv->daemon_version; } /** * fwupd_client_get_host_product: - * @client: A #FwupdClient + * @self: A #FwupdClient * * Gets the string that represents the host running fwupd * @@ -1673,16 +1673,16 @@ fwupd_client_get_daemon_version (FwupdClient *client) * Since: 1.3.1 **/ const gchar * -fwupd_client_get_host_product (FwupdClient *client) +fwupd_client_get_host_product (FwupdClient *self) { - FwupdClientPrivate *priv = GET_PRIVATE (client); - g_return_val_if_fail (FWUPD_IS_CLIENT (client), NULL); + FwupdClientPrivate *priv = GET_PRIVATE (self); + g_return_val_if_fail (FWUPD_IS_CLIENT (self), NULL); return priv->host_product; } /** * fwupd_client_get_host_machine_id: - * @client: A #FwupdClient + * @self: A #FwupdClient * * Gets the string that represents the host machine ID * @@ -1691,16 +1691,16 @@ fwupd_client_get_host_product (FwupdClient *client) * Since: 1.3.2 **/ const gchar * -fwupd_client_get_host_machine_id (FwupdClient *client) +fwupd_client_get_host_machine_id (FwupdClient *self) { - FwupdClientPrivate *priv = GET_PRIVATE (client); - g_return_val_if_fail (FWUPD_IS_CLIENT (client), NULL); + FwupdClientPrivate *priv = GET_PRIVATE (self); + g_return_val_if_fail (FWUPD_IS_CLIENT (self), NULL); return priv->host_machine_id; } /** * fwupd_client_get_host_security_id: - * @client: A #FwupdClient + * @self: A #FwupdClient * * Gets the string that represents the host machine ID * @@ -1709,16 +1709,16 @@ fwupd_client_get_host_machine_id (FwupdClient *client) * Since: 1.5.0 **/ const gchar * -fwupd_client_get_host_security_id (FwupdClient *client) +fwupd_client_get_host_security_id (FwupdClient *self) { - FwupdClientPrivate *priv = GET_PRIVATE (client); - g_return_val_if_fail (FWUPD_IS_CLIENT (client), NULL); + FwupdClientPrivate *priv = GET_PRIVATE (self); + g_return_val_if_fail (FWUPD_IS_CLIENT (self), NULL); return priv->host_security_id; } /** * fwupd_client_get_status: - * @client: A #FwupdClient + * @self: A #FwupdClient * * Gets the last returned status value. * @@ -1727,16 +1727,16 @@ fwupd_client_get_host_security_id (FwupdClient *client) * Since: 0.7.3 **/ FwupdStatus -fwupd_client_get_status (FwupdClient *client) +fwupd_client_get_status (FwupdClient *self) { - FwupdClientPrivate *priv = GET_PRIVATE (client); - g_return_val_if_fail (FWUPD_IS_CLIENT (client), FWUPD_STATUS_UNKNOWN); + FwupdClientPrivate *priv = GET_PRIVATE (self); + g_return_val_if_fail (FWUPD_IS_CLIENT (self), FWUPD_STATUS_UNKNOWN); return priv->status; } /** * fwupd_client_get_tainted: - * @client: A #FwupdClient + * @self: A #FwupdClient * * Gets if the daemon has been tainted by 3rd party code. * @@ -1745,17 +1745,17 @@ fwupd_client_get_status (FwupdClient *client) * Since: 1.2.4 **/ gboolean -fwupd_client_get_tainted (FwupdClient *client) +fwupd_client_get_tainted (FwupdClient *self) { - FwupdClientPrivate *priv = GET_PRIVATE (client); - g_return_val_if_fail (FWUPD_IS_CLIENT (client), FALSE); + FwupdClientPrivate *priv = GET_PRIVATE (self); + g_return_val_if_fail (FWUPD_IS_CLIENT (self), FALSE); return priv->tainted; } /** * fwupd_client_get_daemon_interactive: - * @client: A #FwupdClient + * @self: A #FwupdClient * * Gets if the daemon is running in an interactive terminal. * @@ -1764,23 +1764,23 @@ fwupd_client_get_tainted (FwupdClient *client) * Since: 1.3.4 **/ gboolean -fwupd_client_get_daemon_interactive (FwupdClient *client) +fwupd_client_get_daemon_interactive (FwupdClient *self) { - FwupdClientPrivate *priv = GET_PRIVATE (client); - g_return_val_if_fail (FWUPD_IS_CLIENT (client), FALSE); + FwupdClientPrivate *priv = GET_PRIVATE (self); + g_return_val_if_fail (FWUPD_IS_CLIENT (self), FALSE); return priv->interactive; } #ifdef HAVE_GIO_UNIX static gboolean -fwupd_client_update_metadata_fds (FwupdClient *client, +fwupd_client_update_metadata_fds (FwupdClient *self, const gchar *remote_id, GUnixInputStream *metadata, GUnixInputStream *signature, GCancellable *cancellable, GError **error) { - FwupdClientPrivate *priv = GET_PRIVATE (client); + FwupdClientPrivate *priv = GET_PRIVATE (self); GVariant *body; g_autoptr(FwupdClientHelper) helper = NULL; g_autoptr(GDBusMessage) request = NULL; @@ -1824,7 +1824,7 @@ fwupd_client_update_metadata_fds (FwupdClient *client, /** * fwupd_client_update_metadata: - * @client: A #FwupdClient + * @self: A #FwupdClient * @remote_id: the remote ID, e.g. `lvfs-testing` * @metadata_fn: the XML metadata filename * @signature_fn: the GPG signature file @@ -1843,7 +1843,7 @@ fwupd_client_update_metadata_fds (FwupdClient *client, * Since: 1.0.0 **/ gboolean -fwupd_client_update_metadata (FwupdClient *client, +fwupd_client_update_metadata (FwupdClient *self, const gchar *remote_id, const gchar *metadata_fn, const gchar *signature_fn, @@ -1854,7 +1854,7 @@ fwupd_client_update_metadata (FwupdClient *client, GUnixInputStream *istr; GUnixInputStream *istr_sig; - g_return_val_if_fail (FWUPD_IS_CLIENT (client), FALSE); + g_return_val_if_fail (FWUPD_IS_CLIENT (self), FALSE); g_return_val_if_fail (remote_id != NULL, FALSE); g_return_val_if_fail (metadata_fn != NULL, FALSE); g_return_val_if_fail (signature_fn != NULL, FALSE); @@ -1862,7 +1862,7 @@ fwupd_client_update_metadata (FwupdClient *client, g_return_val_if_fail (error == NULL || *error == NULL, FALSE); /* connect */ - if (!fwupd_client_connect (client, cancellable, error)) + if (!fwupd_client_connect (self, cancellable, error)) return FALSE; /* open files */ @@ -1872,7 +1872,7 @@ fwupd_client_update_metadata (FwupdClient *client, istr_sig = fwupd_unix_input_stream_from_fn (signature_fn, error); if (istr_sig == NULL) return FALSE; - return fwupd_client_update_metadata_fds (client, remote_id, + return fwupd_client_update_metadata_fds (self, remote_id, istr, istr_sig, cancellable, error); #else @@ -1886,7 +1886,7 @@ fwupd_client_update_metadata (FwupdClient *client, /** * fwupd_client_update_metadata_bytes: - * @client: A #FwupdClient + * @self: A #FwupdClient * @remote_id: remote ID, e.g. `lvfs-testing` * @metadata: XML metadata data * @signature: signature data @@ -1905,7 +1905,7 @@ fwupd_client_update_metadata (FwupdClient *client, * Since: 1.4.5 **/ gboolean -fwupd_client_update_metadata_bytes (FwupdClient *client, +fwupd_client_update_metadata_bytes (FwupdClient *self, const gchar *remote_id, GBytes *metadata, GBytes *signature, @@ -1916,7 +1916,7 @@ fwupd_client_update_metadata_bytes (FwupdClient *client, GUnixInputStream *istr; GUnixInputStream *istr_sig; - g_return_val_if_fail (FWUPD_IS_CLIENT (client), FALSE); + g_return_val_if_fail (FWUPD_IS_CLIENT (self), FALSE); g_return_val_if_fail (remote_id != NULL, FALSE); g_return_val_if_fail (metadata != NULL, FALSE); g_return_val_if_fail (signature != NULL, FALSE); @@ -1930,7 +1930,7 @@ fwupd_client_update_metadata_bytes (FwupdClient *client, istr_sig = fwupd_unix_input_stream_from_bytes (signature, error); if (istr_sig == NULL) return FALSE; - return fwupd_client_update_metadata_fds (client, remote_id, + return fwupd_client_update_metadata_fds (self, remote_id, istr, istr_sig, cancellable, error); #else @@ -1944,7 +1944,7 @@ fwupd_client_update_metadata_bytes (FwupdClient *client, /** * fwupd_client_refresh_remote: - * @client: A #FwupdClient + * @self: A #FwupdClient * @remote: A #FwupdRemote * @cancellable: A #GCancellable, or %NULL * @error: A #GError, or %NULL @@ -1956,7 +1956,7 @@ fwupd_client_update_metadata_bytes (FwupdClient *client, * Since: 1.4.5 **/ gboolean -fwupd_client_refresh_remote (FwupdClient *client, +fwupd_client_refresh_remote (FwupdClient *self, FwupdRemote *remote, GCancellable *cancellable, GError **error) @@ -1964,13 +1964,13 @@ fwupd_client_refresh_remote (FwupdClient *client, g_autoptr(GBytes) metadata = NULL; g_autoptr(GBytes) signature = NULL; - g_return_val_if_fail (FWUPD_IS_CLIENT (client), FALSE); + g_return_val_if_fail (FWUPD_IS_CLIENT (self), FALSE); g_return_val_if_fail (FWUPD_IS_REMOTE (remote), FALSE); g_return_val_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable), FALSE); g_return_val_if_fail (error == NULL || *error == NULL, FALSE); /* download the signature */ - signature = fwupd_client_download_bytes (client, + signature = fwupd_client_download_bytes (self, fwupd_remote_get_metadata_uri_sig (remote), FWUPD_CLIENT_DOWNLOAD_FLAG_NONE, cancellable, error); @@ -1982,7 +1982,7 @@ fwupd_client_refresh_remote (FwupdClient *client, return FALSE; /* download the metadata */ - metadata = fwupd_client_download_bytes (client, + metadata = fwupd_client_download_bytes (self, fwupd_remote_get_metadata_uri (remote), FWUPD_CLIENT_DOWNLOAD_FLAG_NONE, cancellable, error); @@ -1990,7 +1990,7 @@ fwupd_client_refresh_remote (FwupdClient *client, return FALSE; /* send all this to fwupd */ - return fwupd_client_update_metadata_bytes (client, + return fwupd_client_update_metadata_bytes (self, fwupd_remote_get_id (remote), metadata, signature, cancellable, error); @@ -1998,7 +1998,7 @@ fwupd_client_refresh_remote (FwupdClient *client, /** * fwupd_client_get_remotes: - * @client: A #FwupdClient + * @self: A #FwupdClient * @cancellable: the #GCancellable, or %NULL * @error: the #GError, or %NULL * @@ -2009,17 +2009,17 @@ fwupd_client_refresh_remote (FwupdClient *client, * Since: 0.9.3 **/ GPtrArray * -fwupd_client_get_remotes (FwupdClient *client, GCancellable *cancellable, GError **error) +fwupd_client_get_remotes (FwupdClient *self, GCancellable *cancellable, GError **error) { - FwupdClientPrivate *priv = GET_PRIVATE (client); + FwupdClientPrivate *priv = GET_PRIVATE (self); g_autoptr(GVariant) val = NULL; - g_return_val_if_fail (FWUPD_IS_CLIENT (client), NULL); + g_return_val_if_fail (FWUPD_IS_CLIENT (self), NULL); g_return_val_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable), NULL); g_return_val_if_fail (error == NULL || *error == NULL, NULL); /* connect */ - if (!fwupd_client_connect (client, cancellable, error)) + if (!fwupd_client_connect (self, cancellable, error)) return NULL; /* call into daemon */ @@ -2040,7 +2040,7 @@ fwupd_client_get_remotes (FwupdClient *client, GCancellable *cancellable, GError /** * fwupd_client_get_approved_firmware: - * @client: A #FwupdClient + * @self: A #FwupdClient * @cancellable: the #GCancellable, or %NULL * @error: the #GError, or %NULL * @@ -2051,20 +2051,20 @@ fwupd_client_get_remotes (FwupdClient *client, GCancellable *cancellable, GError * Since: 1.2.6 **/ gchar ** -fwupd_client_get_approved_firmware (FwupdClient *client, +fwupd_client_get_approved_firmware (FwupdClient *self, GCancellable *cancellable, GError **error) { - FwupdClientPrivate *priv = GET_PRIVATE (client); + FwupdClientPrivate *priv = GET_PRIVATE (self); g_autoptr(GVariant) val = NULL; gchar **retval = NULL; - g_return_val_if_fail (FWUPD_IS_CLIENT (client), NULL); + g_return_val_if_fail (FWUPD_IS_CLIENT (self), NULL); g_return_val_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable), NULL); g_return_val_if_fail (error == NULL || *error == NULL, NULL); /* connect */ - if (!fwupd_client_connect (client, cancellable, error)) + if (!fwupd_client_connect (self, cancellable, error)) return NULL; /* call into daemon */ @@ -2086,7 +2086,7 @@ fwupd_client_get_approved_firmware (FwupdClient *client, /** * fwupd_client_set_approved_firmware: - * @client: A #FwupdClient + * @self: A #FwupdClient * @checksums: Array of checksums * @cancellable: the #GCancellable, or %NULL * @error: the #GError, or %NULL @@ -2098,20 +2098,20 @@ fwupd_client_get_approved_firmware (FwupdClient *client, * Since: 1.2.6 **/ gboolean -fwupd_client_set_approved_firmware (FwupdClient *client, +fwupd_client_set_approved_firmware (FwupdClient *self, gchar **checksums, GCancellable *cancellable, GError **error) { - FwupdClientPrivate *priv = GET_PRIVATE (client); + FwupdClientPrivate *priv = GET_PRIVATE (self); g_autoptr(GVariant) val = NULL; - g_return_val_if_fail (FWUPD_IS_CLIENT (client), FALSE); + g_return_val_if_fail (FWUPD_IS_CLIENT (self), FALSE); g_return_val_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable), FALSE); g_return_val_if_fail (error == NULL || *error == NULL, FALSE); /* connect */ - if (!fwupd_client_connect (client, cancellable, error)) + if (!fwupd_client_connect (self, cancellable, error)) return FALSE; /* call into daemon */ @@ -2132,7 +2132,7 @@ fwupd_client_set_approved_firmware (FwupdClient *client, /** * fwupd_client_get_blocked_firmware: - * @client: A #FwupdClient + * @self: A #FwupdClient * @cancellable: the #GCancellable, or %NULL * @error: the #GError, or %NULL * @@ -2143,20 +2143,20 @@ fwupd_client_set_approved_firmware (FwupdClient *client, * Since: 1.4.6 **/ gchar ** -fwupd_client_get_blocked_firmware (FwupdClient *client, +fwupd_client_get_blocked_firmware (FwupdClient *self, GCancellable *cancellable, GError **error) { - FwupdClientPrivate *priv = GET_PRIVATE (client); + FwupdClientPrivate *priv = GET_PRIVATE (self); g_autoptr(GVariant) val = NULL; gchar **retval = NULL; - g_return_val_if_fail (FWUPD_IS_CLIENT (client), NULL); + g_return_val_if_fail (FWUPD_IS_CLIENT (self), NULL); g_return_val_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable), NULL); g_return_val_if_fail (error == NULL || *error == NULL, NULL); /* connect */ - if (!fwupd_client_connect (client, cancellable, error)) + if (!fwupd_client_connect (self, cancellable, error)) return NULL; /* call into daemon */ @@ -2178,7 +2178,7 @@ fwupd_client_get_blocked_firmware (FwupdClient *client, /** * fwupd_client_set_blocked_firmware: - * @client: A #FwupdClient + * @self: A #FwupdClient * @checksums: Array of checksums * @cancellable: the #GCancellable, or %NULL * @error: the #GError, or %NULL @@ -2190,20 +2190,20 @@ fwupd_client_get_blocked_firmware (FwupdClient *client, * Since: 1.4.6 **/ gboolean -fwupd_client_set_blocked_firmware (FwupdClient *client, +fwupd_client_set_blocked_firmware (FwupdClient *self, gchar **checksums, GCancellable *cancellable, GError **error) { - FwupdClientPrivate *priv = GET_PRIVATE (client); + FwupdClientPrivate *priv = GET_PRIVATE (self); g_autoptr(GVariant) val = NULL; - g_return_val_if_fail (FWUPD_IS_CLIENT (client), FALSE); + g_return_val_if_fail (FWUPD_IS_CLIENT (self), FALSE); g_return_val_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable), FALSE); g_return_val_if_fail (error == NULL || *error == NULL, FALSE); /* connect */ - if (!fwupd_client_connect (client, cancellable, error)) + if (!fwupd_client_connect (self, cancellable, error)) return FALSE; /* call into daemon */ @@ -2224,7 +2224,7 @@ fwupd_client_set_blocked_firmware (FwupdClient *client, /** * fwupd_client_set_feature_flags: - * @client: A #FwupdClient + * @self: A #FwupdClient * @feature_flags: #FwupdFeatureFlags, e.g. %FWUPD_FEATURE_FLAG_UPDATE_TEXT * @cancellable: the #GCancellable, or %NULL * @error: the #GError, or %NULL @@ -2240,20 +2240,20 @@ fwupd_client_set_blocked_firmware (FwupdClient *client, * Since: 1.4.5 **/ gboolean -fwupd_client_set_feature_flags (FwupdClient *client, +fwupd_client_set_feature_flags (FwupdClient *self, FwupdFeatureFlags feature_flags, GCancellable *cancellable, GError **error) { - FwupdClientPrivate *priv = GET_PRIVATE (client); + FwupdClientPrivate *priv = GET_PRIVATE (self); g_autoptr(GVariant) val = NULL; - g_return_val_if_fail (FWUPD_IS_CLIENT (client), FALSE); + g_return_val_if_fail (FWUPD_IS_CLIENT (self), FALSE); g_return_val_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable), FALSE); g_return_val_if_fail (error == NULL || *error == NULL, FALSE); /* connect */ - if (!fwupd_client_connect (client, cancellable, error)) + if (!fwupd_client_connect (self, cancellable, error)) return FALSE; /* call into daemon */ @@ -2274,7 +2274,7 @@ fwupd_client_set_feature_flags (FwupdClient *client, /** * fwupd_client_self_sign: - * @client: A #FwupdClient + * @self: A #FwupdClient * @value: A string to sign, typically a JSON blob * @flags: #FwupdSelfSignFlags, e.g. %FWUPD_SELF_SIGN_FLAG_ADD_TIMESTAMP * @cancellable: the #GCancellable, or %NULL @@ -2287,23 +2287,23 @@ fwupd_client_set_feature_flags (FwupdClient *client, * Since: 1.2.6 **/ gchar * -fwupd_client_self_sign (FwupdClient *client, +fwupd_client_self_sign (FwupdClient *self, const gchar *value, FwupdSelfSignFlags flags, GCancellable *cancellable, GError **error) { - FwupdClientPrivate *priv = GET_PRIVATE (client); + FwupdClientPrivate *priv = GET_PRIVATE (self); GVariantBuilder builder; g_autoptr(GVariant) val = NULL; gchar *retval = NULL; - g_return_val_if_fail (FWUPD_IS_CLIENT (client), NULL); + g_return_val_if_fail (FWUPD_IS_CLIENT (self), NULL); g_return_val_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable), NULL); g_return_val_if_fail (error == NULL || *error == NULL, NULL); /* connect */ - if (!fwupd_client_connect (client, cancellable, error)) + if (!fwupd_client_connect (self, cancellable, error)) return NULL; /* set options */ @@ -2336,7 +2336,7 @@ fwupd_client_self_sign (FwupdClient *client, /** * fwupd_client_modify_remote: - * @client: A #FwupdClient + * @self: A #FwupdClient * @remote_id: the remote ID, e.g. `lvfs-testing` * @key: the key, e.g. `Enabled` * @value: the key, e.g. `true` @@ -2352,17 +2352,17 @@ fwupd_client_self_sign (FwupdClient *client, * Since: 0.9.8 **/ gboolean -fwupd_client_modify_remote (FwupdClient *client, +fwupd_client_modify_remote (FwupdClient *self, const gchar *remote_id, const gchar *key, const gchar *value, GCancellable *cancellable, GError **error) { - FwupdClientPrivate *priv = GET_PRIVATE (client); + FwupdClientPrivate *priv = GET_PRIVATE (self); g_autoptr(GVariant) val = NULL; - g_return_val_if_fail (FWUPD_IS_CLIENT (client), FALSE); + g_return_val_if_fail (FWUPD_IS_CLIENT (self), FALSE); g_return_val_if_fail (remote_id != NULL, FALSE); g_return_val_if_fail (key != NULL, FALSE); g_return_val_if_fail (value != NULL, FALSE); @@ -2370,7 +2370,7 @@ fwupd_client_modify_remote (FwupdClient *client, g_return_val_if_fail (error == NULL || *error == NULL, FALSE); /* connect */ - if (!fwupd_client_connect (client, cancellable, error)) + if (!fwupd_client_connect (self, cancellable, error)) return FALSE; /* call into daemon */ @@ -2391,7 +2391,7 @@ fwupd_client_modify_remote (FwupdClient *client, /** * fwupd_client_modify_device: - * @client: A #FwupdClient + * @self: A #FwupdClient * @device_id: the device ID * @key: the key, e.g. `Flags` * @value: the key, e.g. `reported` @@ -2408,17 +2408,17 @@ fwupd_client_modify_remote (FwupdClient *client, * Since: 1.0.4 **/ gboolean -fwupd_client_modify_device (FwupdClient *client, +fwupd_client_modify_device (FwupdClient *self, const gchar *remote_id, const gchar *key, const gchar *value, GCancellable *cancellable, GError **error) { - FwupdClientPrivate *priv = GET_PRIVATE (client); + FwupdClientPrivate *priv = GET_PRIVATE (self); g_autoptr(GVariant) val = NULL; - g_return_val_if_fail (FWUPD_IS_CLIENT (client), FALSE); + g_return_val_if_fail (FWUPD_IS_CLIENT (self), FALSE); g_return_val_if_fail (remote_id != NULL, FALSE); g_return_val_if_fail (key != NULL, FALSE); g_return_val_if_fail (value != NULL, FALSE); @@ -2426,7 +2426,7 @@ fwupd_client_modify_device (FwupdClient *client, g_return_val_if_fail (error == NULL || *error == NULL, FALSE); /* connect */ - if (!fwupd_client_connect (client, cancellable, error)) + if (!fwupd_client_connect (self, cancellable, error)) return FALSE; /* call into daemon */ @@ -2458,7 +2458,7 @@ fwupd_client_get_remote_by_id_noref (GPtrArray *remotes, const gchar *remote_id) /** * fwupd_client_get_remote_by_id: - * @client: A #FwupdClient + * @self: A #FwupdClient * @remote_id: the remote ID, e.g. `lvfs-testing` * @cancellable: the #GCancellable, or %NULL * @error: the #GError, or %NULL @@ -2470,7 +2470,7 @@ fwupd_client_get_remote_by_id_noref (GPtrArray *remotes, const gchar *remote_id) * Since: 0.9.3 **/ FwupdRemote * -fwupd_client_get_remote_by_id (FwupdClient *client, +fwupd_client_get_remote_by_id (FwupdClient *self, const gchar *remote_id, GCancellable *cancellable, GError **error) @@ -2478,13 +2478,13 @@ fwupd_client_get_remote_by_id (FwupdClient *client, FwupdRemote *remote; g_autoptr(GPtrArray) remotes = NULL; - g_return_val_if_fail (FWUPD_IS_CLIENT (client), NULL); + g_return_val_if_fail (FWUPD_IS_CLIENT (self), NULL); g_return_val_if_fail (remote_id != NULL, NULL); g_return_val_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable), NULL); g_return_val_if_fail (error == NULL || *error == NULL, NULL); /* find remote in list */ - remotes = fwupd_client_get_remotes (client, cancellable, error); + remotes = fwupd_client_get_remotes (self, cancellable, error); if (remotes == NULL) return NULL; remote = fwupd_client_get_remote_by_id_noref (remotes, remote_id); @@ -2503,7 +2503,7 @@ fwupd_client_get_remote_by_id (FwupdClient *client, /** * fwupd_client_set_user_agent: - * @client: A #FwupdClient + * @self: A #FwupdClient * @user_agent: the user agent ID, e.g. `gnome-software/3.34.1` * * Manually sets the user agent that is used for downloading. The user agent @@ -2512,10 +2512,10 @@ fwupd_client_get_remote_by_id (FwupdClient *client, * Since: 1.4.5 **/ void -fwupd_client_set_user_agent (FwupdClient *client, const gchar *user_agent) +fwupd_client_set_user_agent (FwupdClient *self, const gchar *user_agent) { - FwupdClientPrivate *priv = GET_PRIVATE (client); - g_return_if_fail (FWUPD_IS_CLIENT (client)); + FwupdClientPrivate *priv = GET_PRIVATE (self); + g_return_if_fail (FWUPD_IS_CLIENT (self)); g_return_if_fail (user_agent != NULL); g_free (priv->user_agent); priv->user_agent = g_strdup (user_agent); @@ -2523,7 +2523,7 @@ fwupd_client_set_user_agent (FwupdClient *client, const gchar *user_agent) /** * fwupd_client_set_user_agent_for_package: - * @client: A #FwupdClient + * @self: A #FwupdClient * @package_name: client program name, e.g. "gnome-software" * @package_version: client program version, e.g. "3.28.1" * @@ -2540,15 +2540,15 @@ fwupd_client_set_user_agent (FwupdClient *client, const gchar *user_agent) * Since: 1.4.5 **/ void -fwupd_client_set_user_agent_for_package (FwupdClient *client, +fwupd_client_set_user_agent_for_package (FwupdClient *self, const gchar *package_name, const gchar *package_version) { - FwupdClientPrivate *priv = GET_PRIVATE (client); + FwupdClientPrivate *priv = GET_PRIVATE (self); GString *str = g_string_new (NULL); g_autofree gchar *system = NULL; - g_return_if_fail (FWUPD_IS_CLIENT (client)); + g_return_if_fail (FWUPD_IS_CLIENT (self)); g_return_if_fail (package_name != NULL); g_return_if_fail (package_version != NULL); @@ -2576,7 +2576,7 @@ fwupd_client_download_chunk_cb (SoupMessage *msg, SoupBuffer *chunk, gpointer us guint percentage; goffset header_size; goffset body_length; - FwupdClient *client = FWUPD_CLIENT (user_data); + FwupdClient *self = FWUPD_CLIENT (user_data); /* if it's returning "Found" or an error, ignore the percentage */ if (msg->status_code != SOUP_STATUS_OK) { @@ -2594,13 +2594,13 @@ fwupd_client_download_chunk_cb (SoupMessage *msg, SoupBuffer *chunk, gpointer us /* calculate percentage */ percentage = (guint) ((100 * body_length) / header_size); g_debug ("progress: %u%%", percentage); - fwupd_client_set_status (client, FWUPD_STATUS_DOWNLOADING); - fwupd_client_set_percentage (client, percentage); + fwupd_client_set_status (self, FWUPD_STATUS_DOWNLOADING); + fwupd_client_set_percentage (self, percentage); } /** * fwupd_client_download_bytes: - * @client: A #FwupdClient + * @self: A #FwupdClient * @url: the remote URL * @flags: #FwupdClientDownloadFlags, e.g. %FWUPD_CLIENT_DOWNLOAD_FLAG_NONE * @cancellable: the #GCancellable, or %NULL @@ -2614,24 +2614,24 @@ fwupd_client_download_chunk_cb (SoupMessage *msg, SoupBuffer *chunk, gpointer us * Since: 1.4.5 **/ GBytes * -fwupd_client_download_bytes (FwupdClient *client, +fwupd_client_download_bytes (FwupdClient *self, const gchar *url, FwupdClientDownloadFlags flags, GCancellable *cancellable, GError **error) { - FwupdClientPrivate *priv = GET_PRIVATE (client); + FwupdClientPrivate *priv = GET_PRIVATE (self); guint status_code; g_autoptr(SoupMessage) msg = NULL; g_autoptr(SoupURI) uri = NULL; - g_return_val_if_fail (FWUPD_IS_CLIENT (client), NULL); + g_return_val_if_fail (FWUPD_IS_CLIENT (self), NULL); g_return_val_if_fail (url != NULL, NULL); g_return_val_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable), NULL); g_return_val_if_fail (error == NULL || *error == NULL, NULL); /* ensure networking set up */ - if (!fwupd_client_ensure_networking (client, error)) + if (!fwupd_client_ensure_networking (self, error)) return NULL; /* download data */ @@ -2647,9 +2647,9 @@ fwupd_client_download_bytes (FwupdClient *client, } g_signal_connect (msg, "got-chunk", G_CALLBACK (fwupd_client_download_chunk_cb), - client); + self); status_code = soup_session_send_message (priv->soup_session, msg); - fwupd_client_set_status (client, FWUPD_STATUS_IDLE); + fwupd_client_set_status (self, FWUPD_STATUS_IDLE); if (status_code == 429) { g_autofree gchar *str = g_strndup (msg->response_body->data, msg->response_body->length); @@ -2681,7 +2681,7 @@ fwupd_client_download_bytes (FwupdClient *client, /** * fwupd_client_upload_bytes: - * @client: A #FwupdClient + * @self: A #FwupdClient * @url: the remote URL * @payload: payload string * @signature: (nullable): signature string @@ -2697,7 +2697,7 @@ fwupd_client_download_bytes (FwupdClient *client, * Since: 1.4.5 **/ GBytes * -fwupd_client_upload_bytes (FwupdClient *client, +fwupd_client_upload_bytes (FwupdClient *self, const gchar *url, const gchar *payload, const gchar *signature, @@ -2705,18 +2705,18 @@ fwupd_client_upload_bytes (FwupdClient *client, GCancellable *cancellable, GError **error) { - FwupdClientPrivate *priv = GET_PRIVATE (client); + FwupdClientPrivate *priv = GET_PRIVATE (self); guint status_code; g_autoptr(SoupMessage) msg = NULL; g_autoptr(SoupURI) uri = NULL; - g_return_val_if_fail (FWUPD_IS_CLIENT (client), NULL); + g_return_val_if_fail (FWUPD_IS_CLIENT (self), NULL); g_return_val_if_fail (url != NULL, NULL); g_return_val_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable), NULL); g_return_val_if_fail (error == NULL || *error == NULL, NULL); /* ensure networking set up */ - if (!fwupd_client_ensure_networking (client, error)) + if (!fwupd_client_ensure_networking (self, error)) return NULL; /* build message */ @@ -2764,8 +2764,8 @@ static void fwupd_client_get_property (GObject *object, guint prop_id, GValue *value, GParamSpec *pspec) { - FwupdClient *client = FWUPD_CLIENT (object); - FwupdClientPrivate *priv = GET_PRIVATE (client); + FwupdClient *self = FWUPD_CLIENT (object); + FwupdClientPrivate *priv = GET_PRIVATE (self); switch (prop_id) { case PROP_STATUS: @@ -2805,8 +2805,8 @@ static void fwupd_client_set_property (GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec) { - FwupdClient *client = FWUPD_CLIENT (object); - FwupdClientPrivate *priv = GET_PRIVATE (client); + FwupdClient *self = FWUPD_CLIENT (object); + FwupdClientPrivate *priv = GET_PRIVATE (self); switch (prop_id) { case PROP_STATUS: @@ -2835,7 +2835,7 @@ fwupd_client_class_init (FwupdClientClass *klass) /** * FwupdClient::changed: - * @client: the #FwupdClient instance that emitted the signal + * @self: the #FwupdClient instance that emitted the signal * * The ::changed signal is emitted when the daemon internal has * changed, for instance when a device has been added or removed. @@ -2851,7 +2851,7 @@ fwupd_client_class_init (FwupdClientClass *klass) /** * FwupdClient::state-changed: - * @client: the #FwupdClient instance that emitted the signal + * @self: the #FwupdClient instance that emitted the signal * @status: the #FwupdStatus * * The ::state-changed signal is emitted when the daemon status has @@ -2868,7 +2868,7 @@ fwupd_client_class_init (FwupdClientClass *klass) /** * FwupdClient::device-added: - * @client: the #FwupdClient instance that emitted the signal + * @self: the #FwupdClient instance that emitted the signal * @result: the #FwupdDevice * * The ::device-added signal is emitted when a device has been @@ -2885,7 +2885,7 @@ fwupd_client_class_init (FwupdClientClass *klass) /** * FwupdClient::device-removed: - * @client: the #FwupdClient instance that emitted the signal + * @self: the #FwupdClient instance that emitted the signal * @result: the #FwupdDevice * * The ::device-removed signal is emitted when a device has been @@ -2902,7 +2902,7 @@ fwupd_client_class_init (FwupdClientClass *klass) /** * FwupdClient::device-changed: - * @client: the #FwupdClient instance that emitted the signal + * @self: the #FwupdClient instance that emitted the signal * @result: the #FwupdDevice * * The ::device-changed signal is emitted when a device has been @@ -3020,15 +3020,15 @@ fwupd_client_class_init (FwupdClientClass *klass) } static void -fwupd_client_init (FwupdClient *client) +fwupd_client_init (FwupdClient *self) { } static void fwupd_client_finalize (GObject *object) { - FwupdClient *client = FWUPD_CLIENT (object); - FwupdClientPrivate *priv = GET_PRIVATE (client); + FwupdClient *self = FWUPD_CLIENT (object); + FwupdClientPrivate *priv = GET_PRIVATE (self); g_free (priv->user_agent); g_free (priv->daemon_version); @@ -3057,7 +3057,7 @@ fwupd_client_finalize (GObject *object) FwupdClient * fwupd_client_new (void) { - FwupdClient *client; - client = g_object_new (FWUPD_TYPE_CLIENT, NULL); - return FWUPD_CLIENT (client); + FwupdClient *self; + self = g_object_new (FWUPD_TYPE_CLIENT, NULL); + return FWUPD_CLIENT (self); } diff --git a/libfwupd/fwupd-client.h b/libfwupd/fwupd-client.h index 235568e68..d7b796f67 100644 --- a/libfwupd/fwupd-client.h +++ b/libfwupd/fwupd-client.h @@ -67,178 +67,178 @@ typedef enum { } FwupdClientUploadFlags; FwupdClient *fwupd_client_new (void); -gboolean fwupd_client_connect (FwupdClient *client, +gboolean fwupd_client_connect (FwupdClient *self, GCancellable *cancellable, GError **error); -GPtrArray *fwupd_client_get_devices (FwupdClient *client, +GPtrArray *fwupd_client_get_devices (FwupdClient *self, GCancellable *cancellable, GError **error); -GPtrArray *fwupd_client_get_history (FwupdClient *client, +GPtrArray *fwupd_client_get_history (FwupdClient *self, GCancellable *cancellable, GError **error); -GPtrArray *fwupd_client_get_releases (FwupdClient *client, +GPtrArray *fwupd_client_get_releases (FwupdClient *self, const gchar *device_id, GCancellable *cancellable, GError **error); -GPtrArray *fwupd_client_get_downgrades (FwupdClient *client, +GPtrArray *fwupd_client_get_downgrades (FwupdClient *self, const gchar *device_id, GCancellable *cancellable, GError **error); -GPtrArray *fwupd_client_get_upgrades (FwupdClient *client, +GPtrArray *fwupd_client_get_upgrades (FwupdClient *self, const gchar *device_id, GCancellable *cancellable, GError **error); -GPtrArray *fwupd_client_get_details (FwupdClient *client, +GPtrArray *fwupd_client_get_details (FwupdClient *self, const gchar *filename, GCancellable *cancellable, GError **error); -gboolean fwupd_client_verify (FwupdClient *client, +gboolean fwupd_client_verify (FwupdClient *self, const gchar *device_id, GCancellable *cancellable, GError **error); -gboolean fwupd_client_verify_update (FwupdClient *client, +gboolean fwupd_client_verify_update (FwupdClient *self, const gchar *device_id, GCancellable *cancellable, GError **error); -gboolean fwupd_client_unlock (FwupdClient *client, +gboolean fwupd_client_unlock (FwupdClient *self, const gchar *device_id, GCancellable *cancellable, GError **error); -gboolean fwupd_client_modify_config (FwupdClient *client, +gboolean fwupd_client_modify_config (FwupdClient *self, const gchar *key, const gchar *value, GCancellable *cancellable, GError **error); -gboolean fwupd_client_activate (FwupdClient *client, +gboolean fwupd_client_activate (FwupdClient *self, GCancellable *cancellable, const gchar *device_id, GError **error); -gboolean fwupd_client_clear_results (FwupdClient *client, +gboolean fwupd_client_clear_results (FwupdClient *self, const gchar *device_id, GCancellable *cancellable, GError **error); -FwupdDevice *fwupd_client_get_results (FwupdClient *client, +FwupdDevice *fwupd_client_get_results (FwupdClient *self, const gchar *device_id, GCancellable *cancellable, GError **error); -GPtrArray *fwupd_client_get_host_security_attrs (FwupdClient *client, +GPtrArray *fwupd_client_get_host_security_attrs (FwupdClient *self, GCancellable *cancellable, GError **error); -FwupdDevice *fwupd_client_get_device_by_id (FwupdClient *client, +FwupdDevice *fwupd_client_get_device_by_id (FwupdClient *self, const gchar *device_id, GCancellable *cancellable, GError **error); -GPtrArray *fwupd_client_get_devices_by_guid (FwupdClient *client, +GPtrArray *fwupd_client_get_devices_by_guid (FwupdClient *self, const gchar *guid, GCancellable *cancellable, GError **error); -gboolean fwupd_client_install (FwupdClient *client, +gboolean fwupd_client_install (FwupdClient *self, const gchar *device_id, const gchar *filename, FwupdInstallFlags install_flags, GCancellable *cancellable, GError **error); -gboolean fwupd_client_install_bytes (FwupdClient *client, +gboolean fwupd_client_install_bytes (FwupdClient *self, const gchar *device_id, GBytes *bytes, FwupdInstallFlags install_flags, GCancellable *cancellable, GError **error); -gboolean fwupd_client_install_release (FwupdClient *client, +gboolean fwupd_client_install_release (FwupdClient *self, FwupdDevice *device, FwupdRelease *release, FwupdInstallFlags install_flags, GCancellable *cancellable, GError **error); -gboolean fwupd_client_update_metadata (FwupdClient *client, +gboolean fwupd_client_update_metadata (FwupdClient *self, const gchar *remote_id, const gchar *metadata_fn, const gchar *signature_fn, GCancellable *cancellable, GError **error); -gboolean fwupd_client_update_metadata_bytes (FwupdClient *client, +gboolean fwupd_client_update_metadata_bytes (FwupdClient *self, const gchar *remote_id, GBytes *metadata, GBytes *signature, GCancellable *cancellable, GError **error); -gboolean fwupd_client_refresh_remote (FwupdClient *client, +gboolean fwupd_client_refresh_remote (FwupdClient *self, FwupdRemote *remote, GCancellable *cancellable, GError **error); -gboolean fwupd_client_modify_remote (FwupdClient *client, +gboolean fwupd_client_modify_remote (FwupdClient *self, const gchar *remote_id, const gchar *key, const gchar *value, GCancellable *cancellable, GError **error); -gboolean fwupd_client_modify_device (FwupdClient *client, +gboolean fwupd_client_modify_device (FwupdClient *self, const gchar *device_id, const gchar *key, const gchar *value, GCancellable *cancellable, GError **error); -GHashTable *fwupd_client_get_report_metadata (FwupdClient *client, +GHashTable *fwupd_client_get_report_metadata (FwupdClient *self, GCancellable *cancellable, GError **error); -FwupdStatus fwupd_client_get_status (FwupdClient *client); -gboolean fwupd_client_get_tainted (FwupdClient *client); -gboolean fwupd_client_get_daemon_interactive (FwupdClient *client); -guint fwupd_client_get_percentage (FwupdClient *client); -const gchar *fwupd_client_get_daemon_version (FwupdClient *client); -const gchar *fwupd_client_get_host_product (FwupdClient *client); -const gchar *fwupd_client_get_host_machine_id (FwupdClient *client); -const gchar *fwupd_client_get_host_security_id (FwupdClient *client); +FwupdStatus fwupd_client_get_status (FwupdClient *self); +gboolean fwupd_client_get_tainted (FwupdClient *self); +gboolean fwupd_client_get_daemon_interactive (FwupdClient *self); +guint fwupd_client_get_percentage (FwupdClient *self); +const gchar *fwupd_client_get_daemon_version (FwupdClient *self); +const gchar *fwupd_client_get_host_product (FwupdClient *self); +const gchar *fwupd_client_get_host_machine_id (FwupdClient *self); +const gchar *fwupd_client_get_host_security_id (FwupdClient *self); -GPtrArray *fwupd_client_get_remotes (FwupdClient *client, +GPtrArray *fwupd_client_get_remotes (FwupdClient *self, GCancellable *cancellable, GError **error); -FwupdRemote *fwupd_client_get_remote_by_id (FwupdClient *client, +FwupdRemote *fwupd_client_get_remote_by_id (FwupdClient *self, const gchar *remote_id, GCancellable *cancellable, GError **error); -gchar **fwupd_client_get_approved_firmware (FwupdClient *client, +gchar **fwupd_client_get_approved_firmware (FwupdClient *self, GCancellable *cancellable, GError **error); -gboolean fwupd_client_set_approved_firmware (FwupdClient *client, +gboolean fwupd_client_set_approved_firmware (FwupdClient *self, gchar **checksums, GCancellable *cancellable, GError **error); -gchar **fwupd_client_get_blocked_firmware (FwupdClient *client, +gchar **fwupd_client_get_blocked_firmware (FwupdClient *self, GCancellable *cancellable, GError **error); -gboolean fwupd_client_set_blocked_firmware (FwupdClient *client, +gboolean fwupd_client_set_blocked_firmware (FwupdClient *self, gchar **checksums, GCancellable *cancellable, GError **error); -gchar *fwupd_client_self_sign (FwupdClient *client, +gchar *fwupd_client_self_sign (FwupdClient *self, const gchar *value, FwupdSelfSignFlags flags, GCancellable *cancellable, GError **error); -gboolean fwupd_client_set_feature_flags (FwupdClient *client, +gboolean fwupd_client_set_feature_flags (FwupdClient *self, FwupdFeatureFlags feature_flags, GCancellable *cancellable, GError **error); -void fwupd_client_set_user_agent (FwupdClient *client, +void fwupd_client_set_user_agent (FwupdClient *self, const gchar *user_agent); -void fwupd_client_set_user_agent_for_package(FwupdClient *client, +void fwupd_client_set_user_agent_for_package(FwupdClient *self, const gchar *package_name, const gchar *package_version); -GBytes *fwupd_client_download_bytes (FwupdClient *client, +GBytes *fwupd_client_download_bytes (FwupdClient *self, const gchar *url, FwupdClientDownloadFlags flags, GCancellable *cancellable, GError **error); -GBytes *fwupd_client_upload_bytes (FwupdClient *client, +GBytes *fwupd_client_upload_bytes (FwupdClient *self, const gchar *url, const gchar *payload, const gchar *signature, FwupdClientUploadFlags flags, GCancellable *cancellable, GError **error); -gboolean fwupd_client_ensure_networking (FwupdClient *client, +gboolean fwupd_client_ensure_networking (FwupdClient *self, GError **error); G_END_DECLS From f9902f1cdd89c6ee48a1fad4fa62eaff88db4be4 Mon Sep 17 00:00:00 2001 From: Richard Hughes Date: Thu, 27 Aug 2020 16:10:08 +0100 Subject: [PATCH 350/607] Fix building GUsb as a subproject with introspection enabled --- libfwupdplugin/meson.build | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/libfwupdplugin/meson.build b/libfwupdplugin/meson.build index 935735ed0..ba8e6bc4d 100644 --- a/libfwupdplugin/meson.build +++ b/libfwupdplugin/meson.build @@ -156,6 +156,11 @@ fwupdplugin_pkgg.generate( if get_option('introspection') gir_dep = declare_dependency(sources: fwupd_gir) + if gusb.type_name() == 'internal' + libgusb_girtarget = subproject('gusb').get_variable('libgusb_girtarget')[0] + else + libgusb_girtarget = 'GUsb-1.0' + endif fwupdplugin_gir = gnome.generate_gir(fwupd, sources : [ fwupdplugin_src, @@ -180,7 +185,7 @@ if get_option('introspection') includes : [ 'Gio-2.0', 'GObject-2.0', - 'GUsb-1.0', + libgusb_girtarget, fwupd_gir[0], ], install : true From e89ce1a935f80c1a9759977fe607267eacc3a78c Mon Sep 17 00:00:00 2001 From: Mario Limonciello Date: Thu, 27 Aug 2020 21:00:48 -0500 Subject: [PATCH 351/607] trivial: dell-dock: check for valid dock type on open Only add instance ID if it actually probes properly. Otherwise this makes an invalid assumption that the device is a WD19 EC just because it had the correct hub in front. Instead check the first time it's opened that the correct device is identified (`EXPECTED_DOCK_TYPE`) --- plugins/dell-dock/fu-dell-dock-i2c-ec.c | 41 ++++++++++++++----------- 1 file changed, 23 insertions(+), 18 deletions(-) diff --git a/plugins/dell-dock/fu-dell-dock-i2c-ec.c b/plugins/dell-dock/fu-dell-dock-i2c-ec.c index 4bfb17d93..e61476cdf 100644 --- a/plugins/dell-dock/fu-dell-dock-i2c-ec.c +++ b/plugins/dell-dock/fu-dell-dock-i2c-ec.c @@ -301,8 +301,9 @@ fu_dell_dock_ec_write (FuDevice *device, gsize length, guint8 *data, GError **er static gboolean fu_dell_dock_is_valid_dock (FuDevice *device, GError **error) { - g_autoptr(GBytes) data = NULL; const guint8 *result = NULL; + gsize sz = 0; + g_autoptr(GBytes) data = NULL; g_return_val_if_fail (device != NULL, FALSE); @@ -310,14 +311,25 @@ fu_dell_dock_is_valid_dock (FuDevice *device, GError **error) g_prefix_error (error, "Failed to query dock type: "); return FALSE; } - result = g_bytes_get_data (data, NULL); - - if (result == NULL || *result != EXPECTED_DOCK_TYPE) { - g_set_error_literal (error, FWUPD_ERROR, FWUPD_ERROR_NOT_FOUND, + result = g_bytes_get_data (data, &sz); + if (sz != 1) { + g_set_error_literal (error, FWUPD_ERROR, FWUPD_ERROR_NOT_SUPPORTED, "No valid dock was found"); return FALSE; } - return TRUE; + + /* this will trigger setting up all the quirks */ + if (result[0] == EXPECTED_DOCK_TYPE) { + fu_device_add_instance_id (device, DELL_DOCK_EC_INSTANCE_ID); + return TRUE; + } + + g_set_error (error, + FWUPD_ERROR, + FWUPD_ERROR_NOT_SUPPORTED, + "Invalid dock type: %x", + *result); + return FALSE; } static gboolean @@ -919,15 +931,6 @@ fu_dell_dock_ec_set_quirk_kv (FuDevice *device, return FALSE; } -static gboolean -fu_dell_dock_ec_probe (FuDevice *device, GError **error) -{ - /* this will trigger setting up all the quirks */ - fu_device_add_instance_id (device, DELL_DOCK_EC_INSTANCE_ID); - - return TRUE; -} - static gboolean fu_dell_dock_ec_query (FuDevice *device, GError **error) { @@ -976,10 +979,13 @@ fu_dell_dock_ec_setup (FuDevice *device, GError **error) static gboolean fu_dell_dock_ec_open (FuDevice *device, GError **error) { + FuDellDockEc *self = FU_DELL_DOCK_EC (device); + if (!fu_device_open (fu_device_get_proxy (device), error)) return FALSE; - - return fu_dell_dock_is_valid_dock (device, error); + if (!self->data->dock_type) + return fu_dell_dock_is_valid_dock (device, error); + return TRUE; } static gboolean @@ -1017,7 +1023,6 @@ fu_dell_dock_ec_class_init (FuDellDockEcClass *klass) object_class->finalize = fu_dell_dock_ec_finalize; klass_device->activate = fu_dell_dock_ec_activate; klass_device->to_string = fu_dell_dock_ec_to_string; - klass_device->probe = fu_dell_dock_ec_probe; klass_device->setup = fu_dell_dock_ec_setup; klass_device->open = fu_dell_dock_ec_open; klass_device->close = fu_dell_dock_ec_close; From 5de5dd35828c37bdeb968072678af02e7f2d37f8 Mon Sep 17 00:00:00 2001 From: Mario Limonciello Date: Fri, 28 Aug 2020 09:53:30 -0500 Subject: [PATCH 352/607] Install the installed tests Move binaries out of fwupd tree to https://github.com/fwupd/fwupd-test-firmware Fixes some of https://github.com/fwupd/fwupd/issues/1956 --- .gitignore | 9 ++++++ contrib/ci/Dockerfile-arch.in | 1 + contrib/ci/Dockerfile-debian.in | 1 + contrib/ci/Dockerfile-ubuntu.in | 1 + contrib/ci/arch.sh | 6 ++++ contrib/ci/centos.sh | 7 +++++ contrib/ci/debian.sh | 6 ++++ contrib/ci/get_test_firmware.sh | 8 ++++++ contrib/ci/trust.sh | 6 ++++ contrib/ci/ubuntu.sh | 6 ++++ contrib/debian/fwupd-tests.install | 2 ++ contrib/debian/tests/ci | 4 ++- contrib/fwupd.spec.in | 5 +++- data/installed-tests/fwupd.sh | 27 ++++++++++++++++++ data/installed-tests/fwupd.test.in | 3 ++ data/installed-tests/meson.build | 17 +++++++++-- meson.build | 4 +++ plugins/acpi-dmar/fu-self-test.c | 14 +++++++-- plugins/acpi-dmar/meson.build | 10 ++++--- plugins/acpi-dmar/tests/DMAR | Bin 168 -> 0 bytes plugins/acpi-dmar/tests/DMAR-OPTOUT | Bin 168 -> 0 bytes plugins/acpi-facp/fu-self-test.c | 14 +++++++-- plugins/acpi-facp/meson.build | 10 ++++--- plugins/acpi-facp/tests/FACP | Bin 244 -> 0 bytes plugins/acpi-facp/tests/FACP-S2I | Bin 276 -> 0 bytes plugins/ata/fu-self-test.c | 14 +++++++-- plugins/ata/meson.build | 10 ++++--- .../ata/tests/Samsung SSD 860 EVO 500GB.bin | Bin 512 -> 0 bytes plugins/ata/tests/StarDrive-SBFM61.2.bin | Bin 512 -> 0 bytes plugins/dfu/dfu-self-test.c | 22 +++++++------- plugins/dfu/meson.build | 10 ++++--- plugins/dfu/tests/dev_VRBRAIN.dfu | Bin 92690 -> 0 bytes plugins/dfu/tests/example.bin | 1 - plugins/dfu/tests/example.dfu | Bin 28 -> 0 bytes plugins/dfu/tests/example.xdfu | Bin 28 -> 0 bytes plugins/dfu/tests/kiibohd.dfu.bin | Bin 36548 -> 0 bytes plugins/dfu/tests/metadata.dfu | Bin 35 -> 0 bytes plugins/linux-swap/meson.build | 4 ++- plugins/nitrokey/meson.build | 4 ++- plugins/nvme/fu-self-test.c | 10 +++++-- plugins/nvme/meson.build | 10 ++++--- plugins/nvme/tests/.gitignore | 1 - plugins/nvme/tests/TOSHIBA_THNSN5512GPU7.bin | Bin 4096 -> 0 bytes plugins/optionrom/fu-self-test.c | 4 +-- plugins/optionrom/meson.build | 12 ++++---- plugins/redfish/meson.build | 6 ++-- plugins/synaptics-mst/fu-self-test.c | 22 +++++++++++--- plugins/synaptics-mst/meson.build | 11 ++++--- .../tests/no_devices/drm_dp_aux0 | Bin 128000 -> 0 bytes .../tests/no_devices/drm_dp_aux1 | 0 .../tests/no_devices/drm_dp_aux2 | 0 .../synaptics-mst/tests/tb16_dock/drm_dp_aux0 | Bin 128000 -> 0 bytes .../synaptics-mst/tests/tb16_dock/drm_dp_aux1 | Bin 320000 -> 0 bytes .../synaptics-mst/tests/tb16_dock/drm_dp_aux2 | Bin 320000 -> 0 bytes .../tests/tb16_dock/remote/drm_dp_aux0 | Bin 256000 -> 0 bytes .../tests/tb16_dock/remote/drm_dp_aux1 | Bin 128000 -> 0 bytes .../tests/tb16_dock/remote/drm_dp_aux1_eeprom | 1 - .../tests/tb16_dock/remote/drm_dp_aux2 | Bin 256000 -> 0 bytes .../tests/tb16_dock/remote/drm_dp_aux2_eeprom | 1 - plugins/synaptics-prometheus/data/test.pkg | Bin 294 -> 0 bytes plugins/synaptics-prometheus/fu-self-test.c | 7 ++++- plugins/synaptics-prometheus/meson.build | 11 ++++--- plugins/tpm-eventlog/fu-self-test.c | 14 +++++++-- plugins/tpm-eventlog/meson.build | 7 +++-- .../tests/binary_bios_measurements-v1 | Bin 10436 -> 0 bytes .../tests/binary_bios_measurements-v2 | Bin 40311 -> 0 bytes plugins/uefi-dbx/fu-self-test.c | 15 ++++------ plugins/uefi-dbx/meson.build | 9 ++++-- plugins/uefi-dbx/tests/fwupdx64.efi | Bin 65640 -> 0 bytes plugins/vli/meson.build | 8 +++--- plugins/wacom-usb/fu-self-test.c | 2 +- plugins/wacom-usb/meson.build | 11 ++++--- 72 files changed, 292 insertions(+), 96 deletions(-) create mode 100755 contrib/ci/get_test_firmware.sh create mode 100755 data/installed-tests/fwupd.sh create mode 100644 data/installed-tests/fwupd.test.in delete mode 100644 plugins/acpi-dmar/tests/DMAR delete mode 100644 plugins/acpi-dmar/tests/DMAR-OPTOUT delete mode 100644 plugins/acpi-facp/tests/FACP delete mode 100644 plugins/acpi-facp/tests/FACP-S2I delete mode 100644 plugins/ata/tests/Samsung SSD 860 EVO 500GB.bin delete mode 100644 plugins/ata/tests/StarDrive-SBFM61.2.bin delete mode 100644 plugins/dfu/tests/dev_VRBRAIN.dfu delete mode 100644 plugins/dfu/tests/example.bin delete mode 100644 plugins/dfu/tests/example.dfu delete mode 100644 plugins/dfu/tests/example.xdfu delete mode 100644 plugins/dfu/tests/kiibohd.dfu.bin delete mode 100644 plugins/dfu/tests/metadata.dfu delete mode 100644 plugins/nvme/tests/.gitignore delete mode 100644 plugins/nvme/tests/TOSHIBA_THNSN5512GPU7.bin delete mode 100644 plugins/synaptics-mst/tests/no_devices/drm_dp_aux0 delete mode 100644 plugins/synaptics-mst/tests/no_devices/drm_dp_aux1 delete mode 100644 plugins/synaptics-mst/tests/no_devices/drm_dp_aux2 delete mode 100644 plugins/synaptics-mst/tests/tb16_dock/drm_dp_aux0 delete mode 100644 plugins/synaptics-mst/tests/tb16_dock/drm_dp_aux1 delete mode 100644 plugins/synaptics-mst/tests/tb16_dock/drm_dp_aux2 delete mode 100644 plugins/synaptics-mst/tests/tb16_dock/remote/drm_dp_aux0 delete mode 100644 plugins/synaptics-mst/tests/tb16_dock/remote/drm_dp_aux1 delete mode 100644 plugins/synaptics-mst/tests/tb16_dock/remote/drm_dp_aux1_eeprom delete mode 100644 plugins/synaptics-mst/tests/tb16_dock/remote/drm_dp_aux2 delete mode 100644 plugins/synaptics-mst/tests/tb16_dock/remote/drm_dp_aux2_eeprom delete mode 100644 plugins/synaptics-prometheus/data/test.pkg delete mode 100644 plugins/tpm-eventlog/tests/binary_bios_measurements-v1 delete mode 100644 plugins/tpm-eventlog/tests/binary_bios_measurements-v2 delete mode 100755 plugins/uefi-dbx/tests/fwupdx64.efi diff --git a/.gitignore b/.gitignore index d5a589422..18fdd8a78 100644 --- a/.gitignore +++ b/.gitignore @@ -21,3 +21,12 @@ /*.xz /*.gz __pycache__ +plugins/acpi-dmar/tests/ +plugins/acpi-facp/tests/ +plugins/ata/tests/ +plugins/dfu/tests/ +plugins/nvme/tests/ +plugins/synaptics-mst/tests/ +plugins/synaptics-prometheus/tests/ +plugins/tpm-eventlog/tests/ +plugins/uefi-dbx/tests/ diff --git a/contrib/ci/Dockerfile-arch.in b/contrib/ci/Dockerfile-arch.in index 57194602c..e47aaf467 100644 --- a/contrib/ci/Dockerfile-arch.in +++ b/contrib/ci/Dockerfile-arch.in @@ -2,6 +2,7 @@ FROM archlinux/base %%%OS%%% ENV LANG en_US.UTF-8 ENV LC_ALL en_US.UTF-8 +ENV CI_NETWORK true RUN echo fubar > /etc/machine-id RUN rm /usr/share/libalpm/hooks/package-cleanup.hook RUN echo fubar > /etc/machine-id diff --git a/contrib/ci/Dockerfile-debian.in b/contrib/ci/Dockerfile-debian.in index b82e11abb..2af6cfa4e 100644 --- a/contrib/ci/Dockerfile-debian.in +++ b/contrib/ci/Dockerfile-debian.in @@ -1,5 +1,6 @@ FROM %%%ARCH_PREFIX%%%debian:testing %%%OS%%% +ENV CI_NETWORK true RUN echo "deb http://ftp.us.debian.org/debian unstable main contrib non-free" >> /etc/apt/sources.list RUN echo 'Package: *\n\ Pin: release a=testing\n\ diff --git a/contrib/ci/Dockerfile-ubuntu.in b/contrib/ci/Dockerfile-ubuntu.in index 694ae2471..921ecbcaf 100644 --- a/contrib/ci/Dockerfile-ubuntu.in +++ b/contrib/ci/Dockerfile-ubuntu.in @@ -1,5 +1,6 @@ FROM ubuntu:devel %%%OS%%% +ENV CI_NETWORK true ENV CC clang RUN echo fubar > /etc/machine-id %%%ARCH_SPECIFIC_COMMAND%%% diff --git a/contrib/ci/arch.sh b/contrib/ci/arch.sh index 5a08166ff..f4d0ce0fd 100755 --- a/contrib/ci/arch.sh +++ b/contrib/ci/arch.sh @@ -3,6 +3,12 @@ set -e set -x shopt -s extglob +#clone test firmware +if [ "$CI_NETWORK" = "true" ]; then + ./contrib/ci/get_test_firmware.sh + export G_TEST_SRCDIR=`pwd`/fwupd-test-firmware/installed-tests +fi + # prepare the build tree rm -rf build mkdir build && pushd build diff --git a/contrib/ci/centos.sh b/contrib/ci/centos.sh index 990ada1b7..7005fb596 100755 --- a/contrib/ci/centos.sh +++ b/contrib/ci/centos.sh @@ -2,6 +2,13 @@ set -e set -x +#clone test firmware +if [ "$CI_NETWORK" = "true" ]; then + ./contrib/ci/get_test_firmware.sh + export G_TEST_SRCDIR=`pwd`/fwupd-test-firmware/installed-tests +fi + +#build rm -rf build mkdir -p build cd build diff --git a/contrib/ci/debian.sh b/contrib/ci/debian.sh index d7c55f11d..0853b3a96 100755 --- a/contrib/ci/debian.sh +++ b/contrib/ci/debian.sh @@ -23,6 +23,12 @@ sed s/quilt/native/ debian/source/format -i #generate control file ./contrib/ci/generate_debian.py +#clone test firmware +if [ "$CI_NETWORK" = "true" ]; then + ./contrib/ci/get_test_firmware.sh + export G_TEST_SRCDIR=`pwd`/fwupd-test-firmware/installed-tests +fi + #disable unit tests if fwupd is already installed (may cause problems) if [ -x /usr/lib/fwupd/fwupd ]; then export DEB_BUILD_OPTIONS=nocheck diff --git a/contrib/ci/get_test_firmware.sh b/contrib/ci/get_test_firmware.sh new file mode 100755 index 000000000..486fc4f70 --- /dev/null +++ b/contrib/ci/get_test_firmware.sh @@ -0,0 +1,8 @@ +#!/bin/sh + +#clone fwupd-test-firmware +rm -rf fwupd-test-firmware +git clone https://github.com/fwupd/fwupd-test-firmware +#set up build tests to work +cp fwupd-test-firmware/ci-tests/* . -R +export G_TEST_SRCDIR=`pwd`/fwupd-test-firmware/installed-tests diff --git a/contrib/ci/trust.sh b/contrib/ci/trust.sh index d32404dfa..78f1964c8 100755 --- a/contrib/ci/trust.sh +++ b/contrib/ci/trust.sh @@ -2,6 +2,12 @@ set -e set -x +#clone test firmware +if [ "$CI_NETWORK" = "true" ]; then + ./contrib/ci/get_test_firmware.sh + export G_TEST_SRCDIR=`pwd`/fwupd-test-firmware/installed-tests +fi + # Builds using GPG and PKCS7 turned off to make # sure no assumptions of a trust backend rm -rf build diff --git a/contrib/ci/ubuntu.sh b/contrib/ci/ubuntu.sh index ca92888dc..a80464160 100755 --- a/contrib/ci/ubuntu.sh +++ b/contrib/ci/ubuntu.sh @@ -2,6 +2,12 @@ set -e set -x +#clone test firmware +if [ "$CI_NETWORK" = "true" ]; then + ./contrib/ci/get_test_firmware.sh + export G_TEST_SRCDIR=`pwd`/fwupd-test-firmware/installed-tests +fi + #evaluate using Ubuntu's buildflags eval "$(dpkg-buildflags --export=sh)" #filter out -Bsymbolic-functions diff --git a/contrib/debian/fwupd-tests.install b/contrib/debian/fwupd-tests.install index 12dc15b43..5c837a649 100644 --- a/contrib/debian/fwupd-tests.install +++ b/contrib/debian/fwupd-tests.install @@ -3,6 +3,8 @@ #find them. for more information see: #https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=872458 usr/share/installed-tests/* +usr/libexec/installed-tests/fwupd/fwupd.sh +usr/libexec/installed-tests/fwupd/*-self-test usr/lib/*/fwupd-plugins-3/libfu_plugin_test.so usr/lib/*/fwupd-plugins-3/libfu_plugin_invalid.so debian/lintian/fwupd-tests usr/share/lintian/overrides diff --git a/contrib/debian/tests/ci b/contrib/debian/tests/ci index 7f48ab58f..ac847e768 100644 --- a/contrib/debian/tests/ci +++ b/contrib/debian/tests/ci @@ -2,4 +2,6 @@ set -e sed "s,^DisabledPlugins=.*,DisabledPlugins=," -i /etc/fwupd/daemon.conf sed "s,^VerboseDomains=.*,VerboseDomains=*," -i /etc/fwupd/daemon.conf -gnome-desktop-testing-runner fwupd +git clone https://github.com/fwupd/fwupd-test-firmware +export G_TEST_SRCDIR=`pwd`/fwupd-test-firmware/installed-tests +CI_NETWORK=true gnome-desktop-testing-runner fwupd diff --git a/contrib/fwupd.spec.in b/contrib/fwupd.spec.in index fb8d43798..7eb632ab5 100644 --- a/contrib/fwupd.spec.in +++ b/contrib/fwupd.spec.in @@ -162,7 +162,6 @@ Files for development with %{name}. %package tests Summary: Data files for installed tests -BuildArch: noarch %description tests Data files for installed tests. @@ -229,6 +228,9 @@ Data files for installed tests. %meson_build %if 0%{?enable_tests} +%if 0%{?enable_ci} + ./contrib/ci/get_test_firmware.sh +%endif %check %meson_test %endif @@ -453,6 +455,7 @@ mkdir -p --mode=0700 $RPM_BUILD_ROOT%{_localstatedir}/lib/fwupd/gnupg %{_datadir}/installed-tests/fwupd/*.test %{_datadir}/installed-tests/fwupd/*.cab %{_datadir}/installed-tests/fwupd/*.sh +%{_libexecdir}/installed-tests/fwupd/* %dir %{_sysconfdir}/fwupd/remotes.d %config(noreplace)%{_sysconfdir}/fwupd/remotes.d/fwupd-tests.conf diff --git a/data/installed-tests/fwupd.sh b/data/installed-tests/fwupd.sh new file mode 100755 index 000000000..0a6e7eb30 --- /dev/null +++ b/data/installed-tests/fwupd.sh @@ -0,0 +1,27 @@ +#!/bin/bash + +exec 2>&1 +dirname=`dirname $0` + +run_test() +{ + $dirname/$1 + rc=$?; if [[ $rc != 0 ]]; then exit $rc; fi +} + +run_test acpi-dmar-self-test +run_test acpi-facp-self-test +run_test ata-self-test +run_test nitrokey-self-test +run_test linux-swap-self-test +run_test nvme-self-test +run_test wacom-usb-self-test +run_test redfish-self-test +run_test optionrom-self-test +run_test vli-self-test +run_test uefi-dbx-self-test +run_test synaptics-prometheus-self-test +run_test dfu-self-test + +# success! +exit 0 diff --git a/data/installed-tests/fwupd.test.in b/data/installed-tests/fwupd.test.in new file mode 100644 index 000000000..eda783638 --- /dev/null +++ b/data/installed-tests/fwupd.test.in @@ -0,0 +1,3 @@ +[Test] +Type=session +Exec=sh -c "@installedtestsbindir@/fwupd.sh" diff --git a/data/installed-tests/meson.build b/data/installed-tests/meson.build index 40918bcbc..adadbcdde 100644 --- a/data/installed-tests/meson.build +++ b/data/installed-tests/meson.build @@ -1,7 +1,6 @@ -installed_test_datadir = join_paths(datadir, 'installed-tests', 'fwupd') - con2 = configuration_data() con2.set('installedtestsdir', installed_test_datadir) +con2.set('installedtestsbindir', installed_test_bindir) con2.set('bindir', bindir) configure_file( @@ -12,6 +11,14 @@ configure_file( install_dir: installed_test_datadir, ) +configure_file( + input : 'fwupd.test.in', + output : 'fwupd.test', + configuration : con2, + install: true, + install_dir: installed_test_datadir, +) + install_data([ 'fwupdmgr.sh', 'fwupd-tests.xml', @@ -19,6 +26,12 @@ install_data([ install_dir : installed_test_datadir, ) +install_data([ + 'fwupd.sh', + ], + install_dir : installed_test_bindir, +) + custom_target('installed-cab123', input : [ 'fakedevice123.bin', diff --git a/meson.build b/meson.build index 8cf660d7c..9dc2c601f 100644 --- a/meson.build +++ b/meson.build @@ -171,10 +171,14 @@ if host_machine.system() == 'windows' sysconfdir = get_option('sysconfdir') localstatedir = get_option('localstatedir') datadir = get_option('datadir') + installed_test_bindir = get_option('libexecdir') + installed_test_datadir = get_option('datadir') else datadir = join_paths(prefix, get_option('datadir')) sysconfdir = join_paths(prefix, get_option('sysconfdir')) localstatedir = join_paths(prefix, get_option('localstatedir')) + installed_test_bindir = join_paths(libexecdir, 'installed-tests', meson.project_name()) + installed_test_datadir = join_paths(datadir, 'installed-tests', meson.project_name()) endif mandir = join_paths(prefix, get_option('mandir')) localedir = join_paths(prefix, get_option('localedir')) diff --git a/plugins/acpi-dmar/fu-self-test.c b/plugins/acpi-dmar/fu-self-test.c index aa9bf7f2a..0c8871f69 100644 --- a/plugins/acpi-dmar/fu-self-test.c +++ b/plugins/acpi-dmar/fu-self-test.c @@ -15,12 +15,17 @@ static void fu_acpi_dmar_opt_in_func (void) { + const gchar *ci = g_getenv ("CI_NETWORK"); g_autoptr(FuAcpiDmar) dmar = NULL; g_autoptr(GError) error = NULL; g_autoptr(GBytes) blob = NULL; g_autofree gchar *fn = NULL; - fn = g_build_filename (TESTDATADIR, "DMAR", NULL); + fn = g_test_build_filename (G_TEST_DIST, "tests", "DMAR", NULL); + if (!g_file_test (fn, G_FILE_TEST_EXISTS) && ci == NULL) { + g_test_skip ("Missing DMAR"); + return; + } blob = fu_common_get_contents_bytes (fn, &error); g_assert_no_error (error); g_assert_nonnull (blob); @@ -33,12 +38,17 @@ fu_acpi_dmar_opt_in_func (void) static void fu_acpi_dmar_opt_out_func (void) { + const gchar *ci = g_getenv ("CI_NETWORK"); g_autoptr(FuAcpiDmar) dmar = NULL; g_autoptr(GError) error = NULL; g_autoptr(GBytes) blob = NULL; g_autofree gchar *fn = NULL; - fn = g_build_filename (TESTDATADIR, "DMAR-OPTOUT", NULL); + fn = g_test_build_filename (G_TEST_DIST, "tests", "DMAR-OPTOUT", NULL); + if (!g_file_test (fn, G_FILE_TEST_EXISTS) && ci == NULL) { + g_test_skip ("Missing DMAR-OPTOUT"); + return; + } blob = fu_common_get_contents_bytes (fn, &error); g_assert_no_error (error); g_assert_nonnull (blob); diff --git a/plugins/acpi-dmar/meson.build b/plugins/acpi-dmar/meson.build index 95df341ee..ae1400b02 100644 --- a/plugins/acpi-dmar/meson.build +++ b/plugins/acpi-dmar/meson.build @@ -24,8 +24,9 @@ shared_module('fu_plugin_acpi_dmar', ) if get_option('tests') - testdatadir = join_paths(meson.current_source_dir(), 'tests') - cargs += '-DTESTDATADIR="' + testdatadir + '"' + testdatadirs = environment() + testdatadirs.set('G_TEST_SRCDIR', meson.current_source_dir()) + testdatadirs.set('G_TEST_BUILDDIR', meson.current_build_dir()) e = executable( 'acpi-dmar-self-test', fu_hash, @@ -45,7 +46,8 @@ if get_option('tests') fwupd, fwupdplugin, ], - c_args : cargs, + install : true, + install_dir : installed_test_bindir, ) - test('acpi-dmar-self-test', e) + test('acpi-dmar-self-test', e, env : testdatadirs) # added to installed-tests endif diff --git a/plugins/acpi-dmar/tests/DMAR b/plugins/acpi-dmar/tests/DMAR deleted file mode 100644 index 9f37918eee5c7e8926d9ca46a92c188424e650b9..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 168 zcmZ?qbqrd;z`(%x$I~yw)knc4H77^GGcTD5D5d}e!aylCRv-rsB%rLD|3C~z4iE`e z&AZ9P2nvVF7e;@`U2Z#i# z2ATl`0uXU#pg0qQ96JkGUXG2CK>;Moz!2aU52F722Y_jaei5Kv1&}ZZWP^zR|LgNX HG|YSenmQ5z diff --git a/plugins/acpi-facp/fu-self-test.c b/plugins/acpi-facp/fu-self-test.c index 2fd4ca43e..e00248760 100644 --- a/plugins/acpi-facp/fu-self-test.c +++ b/plugins/acpi-facp/fu-self-test.c @@ -15,12 +15,17 @@ static void fu_acpi_facp_s2i_disabled_func (void) { + const gchar *ci = g_getenv ("CI_NETWORK"); g_autofree gchar *fn = NULL; g_autoptr(FuAcpiFacp) facp = NULL; g_autoptr(GBytes) blob = NULL; g_autoptr(GError) error = NULL; - fn = g_build_filename (TESTDATADIR, "FACP", NULL); + fn = g_test_build_filename (G_TEST_DIST, "tests", "FACP", NULL); + if (!g_file_test (fn, G_FILE_TEST_EXISTS) && ci == NULL) { + g_test_skip ("Missing FACP"); + return; + } blob = fu_common_get_contents_bytes (fn, &error); g_assert_no_error (error); g_assert_nonnull (blob); @@ -33,12 +38,17 @@ fu_acpi_facp_s2i_disabled_func (void) static void fu_acpi_facp_s2i_enabled_func (void) { + const gchar *ci = g_getenv ("CI_NETWORK"); g_autofree gchar *fn = NULL; g_autoptr(FuAcpiFacp) facp = NULL; g_autoptr(GBytes) blob = NULL; g_autoptr(GError) error = NULL; - fn = g_build_filename (TESTDATADIR, "FACP-S2I", NULL); + fn = g_test_build_filename (G_TEST_DIST, "tests", "FACP-S2I", NULL); + if (!g_file_test (fn, G_FILE_TEST_EXISTS) && ci == NULL) { + g_test_skip ("Missing FACP-S2I"); + return; + } blob = fu_common_get_contents_bytes (fn, &error); g_assert_no_error (error); g_assert_nonnull (blob); diff --git a/plugins/acpi-facp/meson.build b/plugins/acpi-facp/meson.build index 9a3c96a25..71ec8f0ab 100644 --- a/plugins/acpi-facp/meson.build +++ b/plugins/acpi-facp/meson.build @@ -24,8 +24,9 @@ shared_module('fu_plugin_acpi_facp', ) if get_option('tests') - testdatadir = join_paths(meson.current_source_dir(), 'tests') - cargs += '-DTESTDATADIR="' + testdatadir + '"' + testdatadirs = environment() + testdatadirs.set('G_TEST_SRCDIR', meson.current_source_dir()) + testdatadirs.set('G_TEST_BUILDDIR', meson.current_build_dir()) e = executable( 'acpi-facp-self-test', fu_hash, @@ -45,7 +46,8 @@ if get_option('tests') fwupd, fwupdplugin, ], - c_args : cargs, + install : true, + install_dir : installed_test_bindir, ) - test('acpi-facp-self-test', e) + test('acpi-facp-self-test', e, env : testdatadirs) # added to installed-tests endif diff --git a/plugins/acpi-facp/tests/FACP b/plugins/acpi-facp/tests/FACP deleted file mode 100644 index e438f978c5fb2596ebb7421e28c67b315ea044d7..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 244 zcmZ>BbPo8!z`($I!^hRnKg>TQK-bUERY75bC<8-4h^sRbP>!MDhd)EZUw;NBPKHfD z?uU<`7#Ji#5)2G1P&xoea{zGzOq_|4MS($}HI?BdGe{jHGcSV?BLl;$m500R@uJ`{1Fc_912Y7`ilLGA#vfkwgH15^)0 G5C8ya=@|h4 diff --git a/plugins/acpi-facp/tests/FACP-S2I b/plugins/acpi-facp/tests/FACP-S2I deleted file mode 100644 index 6ee6211d2f801c1b62492bbb4510dd6588ac969c..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 276 zcmY*TF$%&!5S+aW5(^=PsO91l{DBw+;fnk~LDB^qzn~uy>@0mizG0^+t(;A~fCG0s z?9R^YX1OZH0u1i?It10ctSa3e4}z(lFCom6iK1?Hs6RWnA+7*k?*^EW5Xr9=tSR3< z_MIe(3?-i4bmB)?Fz5DAND46@!-=Dg@wW^@6fXL6=&Wau3@+yV_33B%tw!PPj+S#J S-a~z#!+hWSkjJcU3-|&8^BMsF diff --git a/plugins/ata/fu-self-test.c b/plugins/ata/fu-self-test.c index 038dd585c..bbc1b0f5f 100644 --- a/plugins/ata/fu-self-test.c +++ b/plugins/ata/fu-self-test.c @@ -16,12 +16,17 @@ fu_ata_id_func (void) { gboolean ret; gsize sz; + const gchar *ci = g_getenv ("CI_NETWORK"); g_autofree gchar *data = NULL; g_autofree gchar *path = NULL; g_autoptr(FuAtaDevice) dev = NULL; g_autoptr(GError) error = NULL; - path = g_build_filename (TESTDATADIR, "StarDrive-SBFM61.2.bin", NULL); + path = g_test_build_filename (G_TEST_DIST, "tests", "StarDrive-SBFM61.2.bin", NULL); + if (!g_file_test (path, G_FILE_TEST_EXISTS) && ci == NULL) { + g_test_skip ("Missing StarDrive-SBFM61.2.bin"); + return; + } ret = g_file_get_contents (path, &data, &sz, &error); g_assert_no_error (error); g_assert (ret); @@ -40,13 +45,18 @@ fu_ata_oui_func (void) { gboolean ret; gsize sz; + const gchar *ci = g_getenv ("CI_NETWORK"); g_autofree gchar *data = NULL; g_autofree gchar *path = NULL; g_autofree gchar *str = NULL; g_autoptr(FuAtaDevice) dev = NULL; g_autoptr(GError) error = NULL; - path = g_build_filename (TESTDATADIR, "Samsung SSD 860 EVO 500GB.bin", NULL); + path = g_test_build_filename (G_TEST_DIST, "tests", "Samsung SSD 860 EVO 500GB.bin", NULL); + if (!g_file_test (path, G_FILE_TEST_EXISTS) && ci == NULL) { + g_test_skip ("Missing Samsung SSD 860 EVO 500GB.bin"); + return; + } ret = g_file_get_contents (path, &data, &sz, &error); g_assert_no_error (error); g_assert (ret); diff --git a/plugins/ata/meson.build b/plugins/ata/meson.build index 8444bb8a7..f32b97fe3 100644 --- a/plugins/ata/meson.build +++ b/plugins/ata/meson.build @@ -37,8 +37,9 @@ shared_module('fu_plugin_ata', ) if get_option('tests') - testdatadir = join_paths(meson.current_source_dir(), 'tests') - cargs += '-DTESTDATADIR="' + testdatadir + '"' + testdatadirs = environment() + testdatadirs.set('G_TEST_SRCDIR', meson.current_source_dir()) + testdatadirs.set('G_TEST_BUILDDIR', meson.current_build_dir()) e = executable( 'ata-self-test', fu_hash, @@ -58,7 +59,8 @@ if get_option('tests') fwupd, fwupdplugin, ], - c_args : cargs + install : true, + install_dir : installed_test_bindir, ) - test('ata-self-test', e) + test('ata-self-test', e, env : testdatadirs) # added to installed-tests endif diff --git a/plugins/ata/tests/Samsung SSD 860 EVO 500GB.bin b/plugins/ata/tests/Samsung SSD 860 EVO 500GB.bin deleted file mode 100644 index cc6a339bf543213f5a9bc0324ae42a3f0c4c6826..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 512 zcmZ=@_-}81LVy7T?7<`hgK@B7l#`#gftiJ+k%f^$gaQyiq{4y>LYxc(%@Tu)bMs0S z(u0E)T+A#K48mL${0&Uq4HTR}Y7v03fzg3MpTU8FiGhh7Xp;cY4uLme9vP&3ilN~cl822PQ)+;bEumDy3`;Sl! zVi_b@SV2TM7=ZRMFa`7lr#obygowdNIR_b_95T>E=1_sn%)rP1^FO7=*+L9(KsARE X&aH<;8=Q~C00sgIa6sX~IZG1&k?t@7 diff --git a/plugins/ata/tests/StarDrive-SBFM61.2.bin b/plugins/ata/tests/StarDrive-SBFM61.2.bin deleted file mode 100644 index 201cceca295cd57a8d3e4d840d5527291e4a1352..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 512 zcmZ=@_-}81LVy7T?7<`hgNdV~skwopg{7gHg@J*&iK&^T0Yu6v*w@X_%t+5M*fAtn z!6jIM01#+kaA42}Vjy4#+9Uw9L*UPE1_8$Z|NrxY#F!Z>ppZcxVh4znXW(mPWAI^c zVfX=5m0iMEo9vib!nh~dvEG4;K@OSwT88@ALeg z-}C+B3(wBpXYYOX*=Oyw)?T-LObPDJn+pc}=ArL*c9!7)2K*_#53@|cEQW9Wl2H!pWt0o= zWt8#A6Oa;-2D|<1_b$|pyi=coeDs@)vIY14f0-_Q^RMyWM7b5|y*qX9iHvd_(*J$_ z)F7jrjWiEwsBJXnJ5;9pvws_R;^F^n`}cnTZ_4xTJY&_J@s|DD^Z);iQ_zwyFQG(l zPp>+>VnEM&8Qln9SRdmZCJam0I)(|F^s-8|z@S`kRwaJfpKaGw#mu{~LY2mbI40A^ z=Ih)AXPGu7$M9+-tQrzmsGu@ZL5s0O=d3htyQI#1@?ys|MvR_$cWz;N`keWN6LLl{ z!*n`_N<7{_T}ZY~k34OtwQ5d8b5ti)6*R+X7Ye9SID<& zZM-AhH%Z7tNu?8fIf4PDSe@CIB}_(1rkm}XAWTGw)7|6C5OPprb<=$5LN-dgBi}bx z$U-R^Gtkl-+OmD6x7-d^RP-{t#Kh z;(C+3y|HUiyxuHcWPC~KD$`osVnxdCjY@AOi+=bDV7(IzbCnynYA}|_+55Y{1 z1ML&DWnP)N&CjUhK7F>bO=kWx%164VxwPg)^KgkxeX+;De9#n= zqq?Z@*Qg}_cdi?Ld3mRQysOc_&h=yGq^!HVsBww@b>)M17^a_Ziph-h*Pil!SN^nr zLisxXE3Rq&C|7r<*2#$-+??zw-ZJOJY|hK&v+4Bgq&7C6%V*NrnM_)u#Ks#6=&7=c zstkFEWp8(SZr5*{(iUqjy;Z*{#T@W6uIMbqrH<~na^-XyJnf=@4Q>0X)%pSlGw3n9+{AAA13bV4|G!dIp6_n2?u^^ zW7_^J0=H;fT?;cAQ9_jE>!sQh^^`^SC^1Glmvh^zIr|6nu^WI-$Q>;z@n$GX&{ky$ zrMFxg8$&%ksm=)&g?J;(iaVuoLW+Hypha3NrD?_q3UgEF=8X)re}nPAZA!N;l60D4 z51Y>Q%5Lh7T>DtGeHmt_h@BkIip5f$C$(ghknS91SuCY%6yis~MNY5urU)sP)F&Ce zy6us)N7EGI>F@~5dT)4yFsdp}RP?8rIY95wnncUlYmP#Nc%sb-oSFnsoWZ;^6%4-u zWx0`678>K3AnN`(n^mUgvC0o(7(Nr%<54Eq7?6KAg;koO7=8-M1ubg3!pxf!#Hk^A zN~ZnnwSvL~aoQPdL@hCxg*D8k0e{8E!cn*?3afaPxG}`=XRj#>RbuTKrtM*j<3QTh zBF8uhA!TL;_~h8)Z&t+E6HLWUR+O<^ma>hX@y!x8U#ai$GUFaznQX~L@9y4A4?ESC zLgmihWKSZVkq{o`Q%>ym@@7WdGoV3@GR)}Wty+`(wf)kLG?gi)c-ab0Qjen1Zs1ul zmc5eNz`mvsM~CH&L^B6iyx%;`3G+IFRDySS8*oszu;L#=tU=u-v&aBVWnnmQ>0PGn zB>G%NBA%hZT>jK6H?v}OFv|RFYZhkk@jw<A3H3@6y(Ei>@Rb_|w1=Nj{dz`l&q?J-q{gPQ7!YUe?A=mG^|Fl!~mf6ni8y zJ`v-NcT8vuA9XwWAj<%N!0PkXCRr72o4&ol@g;YA5cd2lW6QG zNDhVgRFF5Hy`}+N!hp*>^dASlwG=4>N!dbo6%Me#h{Om+%oreyu=fsOMD^)kU7ZpNONu_j74&DNs z{Hg!j2(O{%crniHyNP!Y?$-vDt-QtH6U1+WOvZTgIJ47}<6(26ya{3s@QL#! zh?zl!d1Nt0o01^52mPI~6BU<|Eb6pD>OOOp%~5`pAS77wgLm;+cr&8;#7c5Q0D z?b;^4qy{vo?v=ADOO`p$tPo%9R|q=kE*s%~C%qr$lm;AlFq7fuB7X>JJ5oUlVfU=y zxh8w7+&o+uZjp7FWNGGR$&A@3#3%ccb8dPI&Ss+5KctbFa&zogd>UOP2NT3kC53?g z@|PtuQ*c&pNydx|Fpt$|Ej+{5WBgZ;YRBmGnQf|c*%(cW+AO;~k!K|~cBwHOsOn>M zG6!$goHeve?B<@?-Pq_atY*^G>2kB|c!KDaTKwm#JG%9*9>1pd)3yTtgz5tSI@Dyk zGErV{KI=bUtx8Y!Ysz+A|IX3S^_>H>8D=KF(Z=g0>g;CX0}0~aB{nnKYtZeLh8gxs zaY*q7wU5hG{9B#eC(D$#4fa_dd3wD>bMQ#Af)AUr&9c{M{r@2`x;6LnW+m3MTB5ov zQ-Zil;?2>GXMg0LF#z6=4wubf7?6G&#sqsyzG=JGGbJ@+O{GF(O81-?e zf1~d}w_HWF=TN&GwMx{!*cant(xOp%p>LcAJDoj!y+S|dO1@)%Bq$!0z zC+ELl{K@+yc;3Bf38GqJG9PL;jl!ym?}WF5qQZgWA!Y)tY*NP7q6Z|oyAV%ONV92w zK`91z+~ds^Mwt%a{Ura#u9N=GYFhEhSMYBCQ8WHx`esFTa+}hxsmH3%P-G_nuAC^7 zMMcF7d&!>Yi1Fdq9fjW=-Apy-J8G{)KHEGRvmen%YlM9Scq$cz1BSL_i_FJPdv3DF z3x12X!TO75oA66879L z0Mn+agFN>d$~TdcaqR$(%b$7B@?go%#&F=3&`ON)8Ggfodj?i-ULmZourtP+2PJ{` zLSN#|Z~F@)nEz0F@)TxVQa4xK0w@w>7PYfe7h0Bdv-JnMnffog+3GCJ@RbnJ3$=6q z5HR{5Lydk5a3dTj9bnCKQS*H0w*OrHU=Jg%_oB!8NRRu_V-{+5(inGo%)s?l^eB$> zn1~*Cqh=G0apx(yxZZ#s_DGLW=rI{Jt3&FE@*a)+m^a6=ew0Ei3o+u4{n;f7Gwp#X zo-FiP5Ry98<_Z6{i;{#y(o<20cF|4A@)Nbvj@(2OZ>?S-lQcPOt}^SUm&q87-CbF@ z9`8FTlsa#eWz{l;m=(%QVba2ZxdSPHr_?*NGT0A5m-1(b50d;xJbEhDf_OCT2fwCu zK_dQ0bU}Ne6W6pyRwJkVvkp1Q4#$ww`u+(y?WbbPo<=z^q+#I0CT3!VcbmnHed~1Z zl5XyomCM08Wtq3&tuFRr{Z#Vf;lQ4L*8Bu&{*D?pQsYL=Ce(b?i`9(OJb{`=P;(YF zgMA)B%?8w*>>Y&d-@F~&c9&fs*_|YICjEp_)}xUPyPVi9FI(I#D@*K#Q6=xU{$1ry z_>bL@*;iUV>t@S8!wmO=*1~}`y-bGkb)6}(JKELJ{VUh6gr%0oK?;mu-o>_LvwRBh zr&pbG-Mh&081}M-(Cswhq=ACg1%k|^F)-=pGPSED?-sO`6wA@Z50DJ0IK!uDMEL-d z`AEBYlmU>69mp|9n@zOl3x>58S?2i+<}7n>lSYijXuMf2P8gVl9ZVt4?k(}LQ-0{w zi1q#EF|m`P&6cltGmZCEzrwu0GiOvLuzG87GWMV7k-GskHiPlW!B42qC+K6j)2BQ* z9(|$`E4vjccFJJ;>3?f43y!(d9`#H6iT>o)F~FlQg9$#?5Dr*^cL}l_j56Zs?r2qy zHyLeASmqmvJz61l1!EdT;MY0e#aiH37xEq?!X?sAY^b}9Yt{eg?s*6KDI~%lIdG2f zQFR9wNe+oeIUR}ca|IIQ&$;WM)j!=>XEwI7x?fwWBnC6u9bAh!>1drCWX9?2 ze=xpsVTM3$%T}tz<^gurb78 z#-u}%oJ_jbd#L{iiPn656zq8@-$07Tx>~YFddsSsZXbFy(W~A3Znnl-D}9jhQ#MwO zQG201>lYM8S!<0!Z#y*of;Lz`=2F5hbl*7Td3hZ66@__F`(5RUnoo3Q?PD^3Zhtye zZZVkFq`JXHf9iCcB_2ljrfdlZ-V1A5ReX$iqz{&>;$+e$S8GH~UyXDwgUjC8#-zJZ z!c|h~tsNB{^mg|4<&AQSMjQw!f$KC5J)h(}!qG{V8i`-#R)jjS&6wX?9e47JIG!~bzVJ)0Bi zaerOpe!8Cc!_B#JJa^lG#>3<=;@Ry!t8bphzR>O~*D#cer>s>w|Y@$ z&*gQyq=$1K!S9o~di*|>n}*+QxjOv1a|>^j6djXlkpE^AGoGCwPcIdfF{QW8JGivM z8(%$mOxlmOr;2t-i_>;VOOWp0cT94!yQJ!bW72b9?~=}~Jtmc}Iwt)F=@Fy{kd`8q zt=c86M0yZu#l~IIcI3|>{R!o_kT)V7Kze@TF{u#Gn1R_Eb9YHc5`f2>N^gCgdrUGR z&1doa#R~pI>1DKxSa?h_qt|aydwuap)E-X&y(JuzEV-|3FT8PbapBM5jkd=d9>1S2 z6*HB`BrC?KPsr1aN%J{M#aQ)3{+LvPx&^skSEOySZQ3Or#Ekxk^af`0=BhuT=JzQ5 z<*{AT`;U!x?37sdPKk4W|F~}BPDydDR7_Iul%me>9sor!*OL2KSmZi-e;{-y-SO zF0$;DOpX-YPH7JI%m3;xy=B?-vg9(HN6p_2rMC{Qd0A>V6yCU$|FU!ev;3`Xr}PAp z6Ju?5?3A{m{CSNIoN-&l%hFRkaA@_*lA9kbMe#eOojiLtaAKiy(#z5gjl4%CzwTwh z6~5#vrGFs(H_})9+VrE+|KiSr6-Ol>pNXq)_)>A}qW7hL^6yL6_;}Qa{88x!(k&i% zS8*PtpHWI$bX2;?9F=;Njs-cSQUhf3~3lVNFCuw^4mKe(}?N8ledeu!8!(;1xNeV+;E`xY^1cCY0J5@ zH$?RILn*U<&fGfdUeyz`7^b1{UbGPn6U`G96AiPlaM%A*u8Yt=)fcqLOPF!Im$=k7^j7+%vdTpR7L$zHA{O;v(^h^raNg5m{e!_{AOGZA}0reCQ#?mv!E zJfV*6;V$`MvJ;EYf%@@0544o`(KAl$3wCtJVlJ^RpFi3~x?8`$(=`$!GWvJgWVh8t z4f#5o2KyX6JLk#gW-$$FbA!5h4xXyQ6I~a&S=R*Ep}iQd6EJJOVDSO&xbs}HWiy5r+ArdYKV31*{DNmvj@--U zJ3XUKOh(R>``r*{Lxb&ccq1xxOqT_^ao2xsG~b zg;b|pueqcWVoQ?k%k67yJb2_iVI{2DNN%N&T6Glu9sQ<)vqQd;^Vs`#B3;B@$YCrs z%9_DBS>j5Vw3J107D`E`ltm2B+g8~cY_TOtCN6)l9D}l4KUn5^lDKbSPuD~-{5k9q zNf^t3^eoC2j6Fl>=$`3Xx_O56(iVcpDgRto-R9kZC|UiXxw}vcpTk^NezDg^^*aFZ zp`Mei$y=#*JZd972k(E1`bA+h>U+v>ELRS6OP+{V;ep1dFhY2N3lDz6J!&@ft6wS;SP{il4h>3CtGHkhlz*!MhbN{79-6V zcs|&WE7zZI+a)#3MmcTqs02aPo>0tn895dy!M?xheMzOcygkOJwkFu$m!dRvqZcAq zX%hFyw#%T^5bY9Ot4pEFXxKuMZ&}d9kMmjOH%Me3Pl@1~-kUs+*KMdwhOfkJEUO$@ z(g4lGD=qNw<0n-%*eBo$b~xBn)Z*LHBbB^8t`zzKY(GD=$Ceb>|3^}~ai@8FrCL0L zeue1wlJs!p<<3$uYyiL7PIFOo;*Js_*;K6bc5%w z$(RGz)C_wt9QdZ+W?yelwC39rZL^7oXcLNg`##`JmR(~7CvnZzuJiA9CD@1-X$50p z`;HZw!MS5WDO|*VAjg^!eK?StFpp#;;tlWMdMgsG@kwgCv0zP|QFgWAwz{yPz%f@Q z)EVDtW9Z62GE!q}I6PhuTSnVC`0g~(NltxAg84yblqip4^P=DmtBdi>}csA7o ziCDIrxzeP89$=V}Xu8s*(sJ21zGBk18&#LI9}|#mcb~Cv1l#NgxIvG47tS8QOzojq3c zh4%`zz))7NfK`0T_UJD-y`sGVEuV*(%pbk~+nF&@-5zyOHIWhP-NW$vd-pY8_C!^C z&O~MVx4x$$o`iGtbjIB9YIxRX`BI&W_4jxmg5QWn|`?>%|~>c(!W4Ru1JlP6Z_{0OSj+Ui=GtSuAG$M zCF+dnw+I)v$NH!&>z{oixd@V8#nPh2(2bk3t+m_PyBS^fMCkgqnT}Q7Syp{}EY!;{9qpOM4QDSjalTYmCW@SZ+GpFQ%{0us(v)b*u_idLG#xVLd2@u( zPIh8UJ2x@Mn+?zYp*;!i%X{>|?hIdt^n$xiiZ#T-x-iCAjR+O@i}qA`Nj*3rr6nDjh{#y8BG=%n3g z*{B4E+WLrYUg2F1V4qGVva+YXCSEecUv`3aPJuu6A<;gTiKIay{#b>& zDWJWQs6iSezdr3vv{xNK`vD=v$)qc@m>WyBcU)sdl_Fu}xcmj{A7fU-mcXSed|H@Z z3&lCxwN5rq>nQwM25qiNNJfhFJq?SM*0D=aIg_2)pdgilGie<=gwc+iueZU{rFA^@ zf7-SRqupb^b{0pW?TP=>_Bi%eu1hiQ&8C*y%r^GoXt&Hq(F_{|t>aO`Z#Vb#dP}*L zb&hamnf}_uI&w`3j`hW=s*kf@XtP^(En)NaH>uofiesww84JZOcXax(P9>hS0#K|p zGU7Mxr4c&$U%b`QNL`_L(ft5QQF?2;{353x-Y(NmZU4+STz`MNL0>5T)xAj2ZeAp4 zva8wtO7jxycSy4 zP4MaU-u$hM{^9mHLiR5!Uxbxk>6>9)yg3nTDr-;Nd~r;Xv1s-TP%xuk;GJguqGFye zPq^$FF0!1gz24;=V>Mc5=M}3Qs#ZhsCl$5QWIi9znc>S6^5&PV&vVzW&z)zyp}8}Y z$(VyOG6#=Tct$6rZq+yESFP2jU&^jh>B!?gLD<)n;*M!*&Pu-e((RKKT6dD~86(%D z<}{bnEW;)FiqT7Wwx56XW|?z% zYsyx(Rl6y5OJb|a6As8j&kB3zX`Q8_A`bWy8W@P{dM@tsE-tPTR=wR=ORjb|tenrq zF}kO%PZ!rM?T{Ai*foFYf|`)jb7&#<8CB){4ykZ|RET93OEHcIC6#Tyq+;4qu@YNr zLVbOT@dc(LDTb*D{VXbB4{};k7I1ZAd!OxNGi6;|>^O=0`v`NC_l+J-{m$*p+v?i> zCNUa0Jn|oUA1QrgUWZimqEZw>GwnyZf8#o*RYWv`IW9!0RDX>9_e1Q+N^xfBAIJ-A zxBTZL`oYpRNbjzw6V&>U!0eAc!R|kZ-Cg}R*!O}_^~;N+>(=Ukvo}=kW!4(tZlb#$ zKEKK4*w$EgqWk{h2SA}r_Py;iuEDOgpC?&T>#&!KoD%Y6_9@8dWpB-d2fGlgoBTe35(7Xi`zc#k|g$t~3pxkVe1Tk0hZ|2|}w4$06k+{2|; zOYpx2A**H2!hXky?d}=>BwqWQs6m`19Q^>eNqqJm#EaMnw^3JvYaYqHeqHzl z;^JKJ?bX>+B_&@6>zT&nZlZAue?FDRG{KM4XS8NY3WnkU73tj62c)Fb1e<)K{P4D0 z8{Y~CesktfH&Z`VNC708gFg2(p(b?WM$Me#Z8c_X)!5!DDZaN#OlYby#$A0L@7B?6 zh{QqNnMZYviTWHxyqaFPA~6e6?eBLfVwb|o_I59mIr~QKaQ14Ak@XcBYmJ|_F*;V) z(VbqMKA)rsy!UB9A1mBNJ8Rgda8(G2d>GF@|Ii-7}wEGAke${|_nzp=JMt4M1V%h0?15E?2U5C}WT zvLLS=!p~eYVV>4}=e|#f`+X)Qof`<;3{MTl0;iWYb#(78JNyd{eu3w1vJ)0wMZXH$ zkoNe6maq`x&LBM8X>ti$iV4nydxV38fB(O*Z)nyw;Mg_L2IdDpuKe)Q#Tx`wIu}yp zNAOFp1%53zZ@cx_TeYx7<$2aZ$6K3Dw)i#H1b4G^(Ev{jUk{A3!Gddp<@cO69Qb39 z_Fg9QR9m63&bTcw_5`Z~H!&=OWOF|xMnvYE{uRmj8|%y?J?!L|_9|b6bFt81$1ae# z4ATDB!L7aqJ9e0T&9)z*Ef4!P3z6|4R%GBEHc)a;3j9}>aN!?@{!=p^-rv3^KY)2?<++A^U#tz+v}uf za~b`&-ka;`uI2XT+XqX(x?~V!>6cesM5Nu_zH+A?UMD3pG{c&pjMw}0>skGA9I^Ribjl=85fcdg=DIh}qL=aXYzTL&23Cfj1r0pU8~baG!fO!|I=4uIc82Sg); z_jQm5B7744$nG+vZxg?^!1gvoLnJR(*hdO%UWILhb-(mtn$=SViS|O1BCQFriEP() zc9FKs5iQn*?sy&}pH|=HIQ#^nb5<*uT3Ro^DvqvQ)47t5n}34HI*vj_!C^<>FoO0@>}{ zum>Ur#$`a>gt%0?R*MB;^5<7JY2_y9)h9O{Zc1({INOIvPfcmw!JCv13b)Wn4+Rvqac>l!PdzKrUV-5-O}M+r*) zNcSig$tOp;Q(a^|JP8}}(A^^i>UE@h1bFdo*MV+Lq(?`0qAO7#PVqJ@gVclW8we~6 zC40!zA{Uuc6a!9tk?fm=*h5vlCQulx1o*U@J8zgGQ&Us3*pKNGfF)ibc8mhZ$n zegL=>oONIKZ93ZJ+w_bv>I##|UMA6B$dJJBeYfkM527Yw0VL|Z8}K8E|9g~S*Bz1#tc>rUWw#dHD&z8_^hqIk0@oww{_1^B z_?;!SszZ8g$J&flMa$vgzIm(oo|l{0*TR7%12c1Wmy})FEr9nynqv$U!?O$em1RGk z7~wlRgjBU=43qUn`wQj4Dc1HdJs)~6wPOaN_zM^+PUtHt85$8V_yRjCFk?r{H+ z?oHKCW88!2%fs)X7GLi>i0jv&a|~V|?R!n)7}{5punU{o*I8(Gih)z`i>|c};>}!w z24Pt_qucF&x_pf9l(afw5c~esmTsmtM%VKoK>_ceB}fs330i=0`8PkZ|>Jgf`sCElS_q$V|@l&#|zOP;2{(U|sv9&nP6j7vOs0!0)B4urb}& zPH-bm2Dnt;Q$jqCpm99%w&w<_aNU9P4Tu(uK$5$NC=a*JrxyRzmnV?qHpuVC_BGyK zwe5IY>8(``%!_aU_vx{p&~8xHcNe6Yt-tW}!5u--$HOY7FtGY`VVF1F+7gsANmX20 z5;R{Kzb_>A>}fjWPH?ln6IJ!@>?*ChysFGiv1SxQDDIX6rwR8@0k2;G{yzphCmMJb ziSYj=MSJ=26U}^r>)-w5@q1_=`04FN(+9YgkVrl_iCk{Q4sTm* ztF_5sv8LphOY}svL^OrC&QjXDqs8Bb&cL3{H8e|1<7v?B4s8s0Qwr9|eB;&OuruB8 zZ*Q5OY|95mn`)a&j&z@_KUvz*eX{x_^!9>E($N<;H(3tATML;{!`VB!8&&K~Pv~Zk zl6cYpYz>^sG{~KZAAO|aY;NcfYSDt&8@=s3B*^?Kc4of2060uq25A-)w{>SszN7mE z)eH04nN7cNxQA8o(9Z@(8P^xzTitsGk?*J4{?^09o{p40>4Ag}9qF=pELw*~R*U0d zW%#mtm|sRzP4Fwq z{;K`XKh71CJ3Q-RH&a&EmS{sV*O>(yE2^qav0ce{R#yLMr$?=YkD$l+5NFybUr z3hXwsU0NIMO@p*8`PbJI=Y$`8(Z~MR>Sq-9`+ukhR;lFToPHIeF{k%^*&XL1eHCx7 zD)6tXCd?r2M6kzGfFBEb6=`lzy{=C$e?;4t&PZQkUU=*@B0dQGU$!uEe-mUPWm#{p-g+&5IvEdnPfAb`eZy-oY5N&C!wrF z`V{?dAT^*}JrE9miKIro4|O;ZXFuP?C>vbq#p&~Tof46-uu|QbYf~Rq%f>%Bx_Gn| zEe3;4E*|fDc^g?T3^u^oS^)SGAJy9l(nq@Qib$Hq8}cZ^6xiZ^9%CZk@}uJO?7{R& zxWB5;pv5^uSlRWqkFkHSJS^@!$;^ld`rSV_b&Qxx{!P?&^&j`diYtQq;4Ng}Elis5yLlVd zSKeZZHmpkF*;&!z+~7zt9DUP^_M#1ya&byuJnn1l=fv7Di_!_iFv|F7@xCCV+ioqq z@xKcXE#mSs^pf`}VH=$!D z`lEam$dkjI&w<>END;=?AE@uwcpkCH#W-BM9sPm*{mB^V2s;qS3Ze&Qum^9Z5Eu3R zTHtZ&^C2tx%}&6Z)R`|zNrvU~Dn(v)9;Fn_(kIc|xqo@PixR!vb?*bXS6hiY@s2XY zT89HK1zGW{NNiJoU}?XymC-4EN<3{*Ka(l7-?TIN$!)BT<@ds8(;t|NNL6Yr>Sugd zX_002!bVFqGy3Udy?TS`ZnM0-BtzL z68ajd+6H?C`u0j%%!0ukJ$)yo=g@nEK`ZQ)QkiDN-MlF!8@S^t@vsyv;=BrcZ)-Ly z^fGTE@Zvly`NQet9r6U>JiI6g@CB4@VnuDRuajw`b8fU3l3q+cVG%m(f+&XHJ`d-p zEKDK!ii!58pzZ~{z5~2~_yO&=ipZK_rpBX^HUsmE|1aME48$U zNtD&lY;>MgLh9z&R&Ek`GCL%jr$c&n`^=!iv9dU-OBNH|wVOF4u?B{v@s|nLA9QP% zz<$ZqYD|FoBDuI4qgo(xbUiru_RY8XZOX5>Nip6t&~ygt*6O*dj1IjFOC>q~BuN9( zA>gJgq?AgpA5SiX@2SbdO-gE)AHIq>v8$50@%`Jq6)_>DxTS~-sq(?qH*%p^t~S(j z6WY%WrSFO}7I$!7qj{#8^~vfNn{$iFK5j2F6vNJTZsQ8F*Twg`gB{YjM#a8QyJFZ5 z>78>+q}Uo}-x5i!*<)f3?J>cY4!ipC8mci#v6>N544yAJKz$xZ!w_@JX2=BmdrgfLO>)o97 zLe*tAbRXDG)&lyseLB!yppJw>x)O?{RHDQLQY3qU_Sr@P4eEF^-)a1cp`p?Fx zK@M>8HJpL&FuC|X(_eudH(X03mEoYo0uy7zbHh38PwG%ipNY82^&dxpW`+a4=j38( zP$y9B*Go;3tOjEk0ONC|KZh$)V@R5N5394Rs6*OWqZO7&G5iuq)?kui8ulcpyKMI? zGC7|7dV$K6BrGUmr>VQ(ewci1(ZAsR3v?pJ?u$h-%?70rJJSNJoyL*?~vH@?{Q?ZzF~zro3~ZyZ&|H`-ty zGoQTu^|mpWtBf7p@3@p#nQZPVM$3-&Ei&TNQZ~+I>E%>IT6?wJx14HGK3`ph6K!%| zqkls+>m!M~qx(cX;lX&b=wE-LLz0?+`vz5{_a`TA!y=aLpKxN!Lmk~mVI%nDgfb$@ zeRARuXrEdn|F!DN=G4|h-~x>Pk@kAU|)@UKCWFrm^6556p_&P|Q>;1dy>8%<4A}{!x0bYRZ;0&H$xYnb}F1d`m3c3CC zC|_(>6nCV1rE8HBGBY&66^KY&p=E0Uk!+Hk>771?6#Rt$6W6Q$Jt~>_eV9EAdx?tf zq>(PbHpI9N5wDMU5J{t%fRTiV#(C7^^k1(w;9QmHF9&?r1HPHCxiEB22NtrqDj8Ne z(po(Wa(knFsmTl|N<8I~|laJTGMw{+YPAUvpwD zlR4$I|L>|5MX`_{*Cy~Jx)G**$ zuvOAN!7+>o5j>vGU2enryIrYO6T73H0e0hg>p}DD{jb&&-E)&Vq$xX`rHF~FRw42x z1AIr$tMbc=2v>=EGkq0;^C6@9_)}#ZC_bB0lVQ4 zr)mZ+1G?2mx|g{kKHTo5prNH&s*^*WndU!V59~c5?^4RL{876ItQz;xX|VVhOG#fgfZjydg2{&SZOR~3 zbadZ?S=^%~T9k?Efgk*;>H=69V#P6`X^4b&Rbc)5?-pdBhCx~=ed|bfel_`&Cl}|H ztn*hzJcC1gP$quU4^7#{yQyUYwA(??;o$0j+5bOivqjqY|I_vn+BjE(dxF2JIt4z| z^VRfpU>N3gs{ibdQP23?(8ekUX^H5FXz1VfGKR4jhw#4Uz0IH-7ih*+WCI->0Ii%v z`b~uH4x;{G5&4&hX2?%ZdmhnFGH7Wj%J^;r?8_A%CLO*Ze6xb}Xl!%t*vs*&B61R5KThv zCcCZMyvMxX%#7=5T0CdO1qNTgD4H|uf=W;!qDM1fhsbkft1RYel~LmIUUte8mHy6q z_$cxIUUuqt^i7oABzMzyaFi_?_!%|A{?>Zu4tTdtw?g8_cXhN?!$?zv)YTXGY`}JB z)-~@ecjmWpd^nBHyU@2ATHBOoNzNx;L^iY^@&2^m{{`}V6!RB>?8}#*tugLujK9)& zyZ6yrXu0DV-udJOS^L@~>R?hg=X8hS&E9o3f(sK#>gDcXQeT$6y zn`))sE~v#xfm%=_x1UL4e=n<5nNL6}XWY4v=g)VkWwIML#}wZ9e%iZpWEThbAmSdq zo4D)_>A;Sh_Hmxq;f4ROOD1DP@P{wT3E(cl1wLN|k)q^$WPUDq7Tn0{A7V*0*i}+-|(2~4EG7kA|I=b(VcsR%_87p3w27OUfE)Sjz za=w!|TMwD#I(VR#Y-hv=dH=)UNLAp2?ud^CUPzn)(99q@*STqTS>xtFCC@|iX2c`z zdrR&U?whZz(%BPD_gZzfL?@e%I7>%VdUNPTfD4VBMmqgmFEqWHh_y;oDr-Yh=x<%J z*aGukB?i`&BYjIvC?SeU65UO#`1^1@SyJ3Am!;P_CWwl@@*6`BBlRch;a{OVg(K7#GXk&}u#;w%v! z5$k*1ndliC(atxZG%8{rk%=q&QiaswR2(y}*D~3fEA}lZ)}^gAjwI`X^~9mvBF_+) zTCge>wl5Z6mE!PKngm!7m$!m%*!luZeFl$W$Ua{x6Q{oO%hm6gHW%hSWFsJ6MEtD* ziQqx!J2@fQR3q)cq3<^$XCJ{+W-BrO-F+R>%WhpMlR3?sUJ_+i!1lu!t~J%oZMfl2 zhh=o}{-%0kRof_Gba7Q%v-BLRvZo4(g^XTynVq=?(hHj}>)NGG#Me4T0d#AsWTplr zA5vbfoE=KGJH++w7R(yq$Gx&qRjc(OZBwA z=P-9#-+Qo5GKO)JU4+XtwB%c(+7pv5 z*VdGg46yRaNyQ}JlMk(BK{C1U)k6fI1zef-Z{_n|6v=9iouxy zabKU>$BJ)cw)OkO_!rxXv(bIPK}TP}5!wq(nc2Q~{@#*<(&q-^N{GGW_8CWA?T~VI z)JZIV+S4LEmo~%ga-Vj;Ew%H#?t{|b`9u?)1vq4sUkwLF!lOc`z@Nmfhf!@qkwD5RtE_lI}Qjv*C@GbhqbF~0otHrjrB{Qs5 zb0YSB#60iB*N|eUZj+}lLcu0sxw8ms^?Yt3qFsL<;(V>}{{(4nh9pEdzvrH5UF@ti zzwe2R)T(nngm3eO13N;`O9v1e#E6Z6r5XBRq4>I6=X?_RtB7Q(2p#pMJAaj(?42C3 zGh)sTk}zKAReJgY%lhS@@Za`oJXwgV!kH;tJ=!aReHbDeV~=Cfnxa{O-J`5=DXJ85nk z&ZIjZ&CbTGpA60P5$zHWDg@oq_u__lwgcBAkccl8ASeBZ>`X(pO_F&YLEQ?Zl}HTI zvuFn#(zKpLK;|j^XYD%Y@AY!;o;x;Hx$jlI95&@=VE5HI&*(XC^Ik4r=KC}3uqe%J z-WB6}7qy!rwP*3QLzHH2+Qs4|A#fV@cfv-371L{Je%$)Fkl@_tdAzvTxy*yLXR!7O zRYt|t6lY4S!;;|0%aFU5Z(Zzp1n|jjeFU%@-db+WOM^ExUFj=FZJy`X)g5azm-&_Yv#xtIyn=4y0 zaPDK@Mx5iYBiVAS-YVqo9E?qg@g3a=zOtY%UN4YQaa4+>CDx<{4$EY+mEqaz;UI6?(`E zv@a4a5groW%|O`$oEpNjpHWYE8IdVaPdWkl%g7%_a)kkH7oo$GuZ-}s4rxtAofK_I z_3Xg2k=#6HMrXl()&7lZo4{nxZ{HS)ceh@83Vsy^ew8{&#k)M0H#6CDamHt}<m1ikHj}G zjNle=ZCO{5tf{LgUVD{zewCzZWI;w z-*Z5ip-t&ih?Sw;M)?J*j|FGF4(n`h;B5aIpANokTl)tRQ?t^SjW1)$^~(nRXTy@y z7cs0($?I$(d`B_a!-^ira8@t+@YrKedo@x^amTa%t@c7#;ReZ^gkuzcNO-gp`9$pT6r)b~NBC5L6gi6ryds<<-bi{Y@yr^+KX{;+ z1vHaW;nz!NM&R<)c1AZ7UcArx!+`*N9HBsU_}F|Vv!MN$bzc?RGe>r~sal_8en~iL z&AE6KU$ap7-Ual=wvXHnB4je5J6g`J@ze?p??T@i<-ZURRuw_ViP2=X)4s&7AnF&&@dx zzZAvKQylX7w*5_rvS3!5SU%bDjk^%%((*hN)?~*8yun86U+5R!Xr)Q#!vL-klr0+zS zTBJhk{l+v-oY(JjNBfoutE-+59!yBJvmu#o4J4DT;EAQeWv8k&b+g`M6&70)sxDWl zOqW6Np}={38;JJixx(em;PyD_!iX=sQ@0Q%H@L|*T1*@O>bDcyHxRoh<|FUx)9fJQHLvHs}qj$qp=SCMzdJ8i=Kw7>$T4w;>d`4gL8m z?`U6gM82DKOY{0bAT}HhsL$ZbsJ=nD=t2|2FCK$$7VY09otqL0%t7oxW*S>R5NIC= z2Od51%ec_h=v{XL22+reUb+NjIr#53;nGc-z18;W|_o&=GN$JuIpp&=YOt4r&E^Y8Euy9-0`|3?WL5Ba-UUo*bO zA-5h~#7#-g`3a}o2fv3y-&T}bmX$1<2akHGqU(Jb&o6fl`s>d;9tvzkya1~^^Z1(0 zBlRix=INT0FaGTtZ=CnclWWe5^J((q|0c|zWP18qJY&VKqnXO)otvn2bb9@rcS-ra zIaZ9U*a2$(2fS?WfFpd<&Ww9}PRHeY=j+)qrZuMczp+#4?pvLMGoRYepBd#_y?L5Y zP@E{`F-iwTxUaM`6aDRsuF}|b`Tef<+4AJvQsNYIVPASGd0&;sy?=AlMmFEyx#rHE zmTl#|X+C`Q*2!kwx|9j*s*Zed%uin&bNvjP?gVITumj;L5s{{JB}1Nw7)`R~79szx zGY;?0rX}kW9vcZs?3?8M!3&ywp5c~7Qu{+6E_g4wrfUD@>W#y!Rqh05bUvHw&?h*$ zyd+~KK1ScP2?wU)TfW5Wzg#%@y``6d1KW}6?q`*5VP@mRpT_=M_irxSN117Oh&SFx8ViE`RiD9mrOAe5Y$ZF1qiZJddNDt{a?=m zKIkqstr(>ME>{|(F3Eva8cnpgE37l$=+vC0d6%4G{#>#DV!`pY%qTk zQG|oh1h9Isd$eowII*#}!Tmb)1~yA^@s0U!%%d}wv%ICgSA`SSi&d`(`-5NdE2>6U zQEc%dqb$S?9Qy_G-(Q$SC!?+-x~e>?314+CAKwJaRypd*@%1;?3-ig&g)cpqk#CMx z={w|z!9uGH@n+GeV}FS|12=MwmxepoyuWvDa_%ijZEXRb>)bKEodR)svY-xf`v-b? zcll;^#)YPl+02d1?ez899TsITcSBQXICCMYuxAYXZ$G|>y=i~Fw6n2Q;v8G>ZM?jJ z(*K9GH;-?s%=gF7mZcj_7qCqWW+}Ba1=AL=Qq(jFhqfuQIq-_sZKU_eWIC`y;}!{W80kq`fr87TL$N zK!eP7{l3;U25>wKEYyPEVX$#f8fY4n2H%F3tIk^DV0^nLApyJ}%_Nrw8fNqS?h4M@ z9)DEtERr({^5t|xYAF8I6z8l+x}h+V@vjYY_)9uxinswIQjmnJD}vO*q$j^{t%rV1x&! zhCp+^H&Tx_u)S*(p4tT#6Yh9YkYIyL1M7h+aRx}5e!}p&DxYZZ zk+i&S_z{=em$l{O@fYO(vA!VxLYF3S$u+L*fZqQ?q&@_`9cx8v${^SK-@VMZA`>v+ zeI)a=PAVMN(7GS8vA=Kv9=jqrQ=B-_eOhNqXt|Oz%RdRLtD?2Y^y|SZBPq~hCOMJw z3Z>FvE>;06GJPBLTE+niVBU=UT=!{a>(iW$J0!XaEAl?j*|~%o^H)-V5e)OO~XP#fAE{G{r32Cw?xta>G|a{aJ2ft z(dw7k;wxQD&TqwHNYo#iv*a9BUm;RlX#^f<){6Im$SG;gd;YfpAvUS7I5u9uDD zroY?;i6T%snGVuPPIH6i1I+;%|FJ#tH0BPS!!&>B?3CKroMVIiSD&@B=c^o%E++T0 z7V-;&qu`k zud;B6y_;8sj`Wtn$HR9EA8+aY{NVz=qo9^GL0`6Mb-@GB$T7KKQ($Sq9RUXJ$*zqB zs{>r;nu3%-Ti4?ST%fj~C~&MRp;w4k{QUS(fZwix@e zG@=fj=v~S$w=Y-xx+rmyL1MbO1U+4Z~Y{5u3oFj*^7abK^rO$I4&_q!f&q zLZjiV=wY!O>5Ss(xz4UQWu|gug96-#kP_;+paBexC;5b?O;aHp)p|4)i)FzQ=VA9p z!;_=@v3q2p2YTg^meNuBaVL`7R7csplulj2?`L1ZP6e(J(kLJ(>3JpnUsp3)mS6@3 zvPd^UKASK^mGg=jB5h@p`5yr)` ziLq&!tDC$&z_qlFLP!rCT+pQY)FAXr0;(sCaNG5}>`9f->If|&X~0M)Lq|+JbYrq! zS4-TyiOvj*N@lD0AZt$X@~~XO7Q>>*DR5C5K1X?fr?%le*_GA?3P#FruWni|h!qTD zPOLn%Kqxj?29T54A6Fh<5nrh?$4Nhv<6Ifli7j!JCb!nK{BiEs7>rEqW71jM)Ca&5 zy_02V4@km0tSr>(+Tz;*ai3yLgfr252g04v9KhU-Pp4|GTrgKItwsBNnYG4BSVa-a zx&>p3`w*-N+##%Co!tRufxENT$Jn}`(`9aEC04L?*Bkb_mu_aHWZ^5MSjYz5hY+(> z$bnC%(^YqFwjq5mC1VRC@hH)0Tv)wqOVbusx=}d7e#$tz_cD&|g(-WhgVijxtYfS% zXiVr^QeC<>8bRvuGXuKHG!HAD(I=OuxXZ5ii}u@jcan>=Y3jY81XLzlE-X<8#|&a4csoKnV0 z$*g(`_QOPN=l`xul@krO*tj0eO=*>O+34kpb(U_x*=DagFWJR)CM(!hqC-iik}5Nt zDYckKg<7&y!LTi3b4fZy^-jc7iHF*e16Mic;a1>*&c|AspOh}GEd_W|@K}q*EvzLm zIIfb%JkuC?Xq6(ZJG?Og7z1ckf@Te7e>`RhG#VCZB}X(iOSCStn`Q`=KUOEzLG$F$ zgN&k6mGv-MtPiJfZQh^m`y18}ZJUoL)+Ys31?5vKPRMSfM#>$@YiEJogGv+pPaMfB*Gjj`x^@A+2?|#}#bvaZ z%Qez+@YZV)9wvt3r8_^B@h^njfRM#X$PJK^&3<+u{KfDD*ZVETRz=2K z;s$l8skoi!z^C*V+(=@aQon&b$k(`okUTHlNrr#~+yGxZ0!@8co( z;R4`>2ETtcZZ^cjw02B?UxEwz7}oBGK2M@Lq83mJ|3ch{TZVA+Ax<6I8JUja;>9*b z+B%2IxBd8)W2r;yf_BUe(6f+cIF8G;Mv^6=Je0Pi%`lnCVZf{M&XC}Y zHwe<8%-;56@ND0FNJ73DO{{oM{&^W|Hi>)f{CToJVsb`;+REo-ADiZFYE@S*b?AK0 z$y<$!9RkLf+D+a&}+-VZ{wknHrg~53$Qwq zJO$1ieIlrykAc61`s5q*$saJ*iNJq&+s3=b&&%@UEA(;Wr)hUupgke2>dBVXH3#P& z#<;;|l}A^ut4MQN+=mgyn2X(_?z!zZH_&ngcKTBFr%AaFa;byk~tUs+imv;FUiK z+)?X%tjn#cAYcMB^k8f|xiF#n)`&`Xa#@1&gjh*a)!jq5{jq(1C$rg_L9P?x2QGzDS z??cw%eQ^K0FPB(Px}S8Hx)Vbum(l!TiwV;kZ%8(>CaQ55I3I3?daAltPz$~3!q)z$ z-atQC+0s}^x5_-K;SIa=Q}9o+l~;og&tF?r;$Jh5$+H1FqZe!LBq;%C>H6Z>)%Ujw zIKx{Ov@ET5wk%+b0^|k0h184Ma?hQAkk=}*sb2@#JVWsBsDj zpmP2!e-ZRkSGZ1~rcB=n`Qemh_bd^8b@N9-}8F1W8ei2%pDcZ`Z5}hT)^a_&2ir=ZMK%bDzB|(djyb-!TwQ8_f6PTMEzXEs);C_u%az-)ne#6mLg;>_K21 zaf=y~-z3>hqO;cH*^70@;74nj=wr=zY*^E@E{Q(&8Pc4_^FE$2S{Z|IqRajZ>!+km zQ>m%ay7tL;VGqR(ZqDSogL74``|AjrC{fNrqJPl-cL`;9+h)0DRb^of6aULvaOIsT zCLN_SUAL64zzT+2(fDMBxUa?JiFY&R>32?YGNzYhuW`IMt+MFO#^sHR3-4@POmjsF z?$~%U;jdcqVB2k?zg70KdHM|BJ$T!|w#ttg^Ylx72mRaijlKlXfeHgAkFnfTab9nR zCh`fLrfb|fjQNJjckgXnp5FR9a1vz9TfX?O_x=w04sWQ^D>eNPObewbwElPR{rKMG z$^s`hS?{zs4-8)IS6g0^y=7N|L`5D5&l>=|tL!+?MTMDZxy;)&>2-9LXx+uEg^LLO)@5(>t;q=59e~mUr58 zifx*bHuXG%Df zp=At1uzQXn3F-bAorijlMwx=Rs>F`l4MzBmM9m(?lqc%fLr)9d_k)5>8YRFJ0h}n+ z1A9bB_gM!p>2NzcU^mW_u^G6Z(Ri{ir-jA{(E6ZN^m6Nqb|GNBCmP-at7Kv5h#$41 zmaGFc@R4W)7)^#DK4s=6HiwymNp*!cOE@jASMzI$*Gu*|_2zBMO$mr2OqTY+R2g`L5#;_O9n!8!phMIfl+G zxm6b8O?87(?gsoHF|_n~de)ddL@g|v7d2+!>*J+&!2!b=EVv>3KEmc?v~cE!y+^%# z4((RIj(A#lg#!3Mw&kvY@PDF=VwYgzrZ?Wjgr%qw%nyQ9?o9q)tI`M z@Y4m*#|Oec2Ys9{Py^vZ5nYQGY1rvlpQ!7(NM6h8?08fDT?t6fO`kOX$?K@STrg2d zn`9OYv6?r7@}BNWF*V-xa`p@IF_z|J8c%#gk7XZ4%W4px=t?)~?>dqF=&_qKj~ugRl#}SC}T{Z=19369Q?Bt zKM((;4n99AXv+h}f@7}S@JyXN*RXtjom|djtQQbJu0zPz!1_TQX7d7D#(EXPgbr2y z(cpf$T(=*opR;Ff)?6&JWv*YCjodn{tM$L?+Ge*&-|xg4us#lY;YdAmC1YC+-fVdL zqi+u0-rqT~(+=0aGojN4_m!Pxpb-9TC#{jSBY^9q*Z=H5_@bRogr8Bu?;Y`0vVhDP z>Cb6_2j9>Lwy zAuO)VcI@Bm>^>tb#=j$d@fK%yU3!)4B7ASBXTrzkEW>|UP7op6a#FVJgYWGeXE!%} z`IF9W`}9WqZ=bGz3L#EC(s1d^@oslE;(xpI68_(D>YqmVlI8ffFKK-GQ@Gogpw1=5 zF2;~q%Znd<@gTlGYr6;EU%2z;^4*u$!9Tt}r}JUB@6}~=u7&$t-9v~s?o^?F-Wtvw z?Vm@6Cy%~)h9L`GOA@M#6nyIunWTgzp{UOZig#f=23=sXbbS-ln*(x5f8^m{pg{F9OY*YF$R{s!(uxXo}g;XVa-Jlq%HrVLRS(}UH_l%SX65dJj6 zRdBb$W#RrD?(kqeZh)YcppV(1dDr@QU6)(K4$FKU<@C2a7G)YLFsD$tq7Wrl>p^cjI4jXnc z=(|nMAI&X{rstAXA(h26>SL291}LTex-x!BsXS`(A)!hTQvOI zz?;3=WU?@^C-~T98vP{D2K!s+tE1ub14m{0^1s2QFaHQGefg;Y19;1K%k|ccm;tK2 z?No;NSisoX-peL?0`0v*vQ7H6kG%=sKTs+%FDw8oTnV^v>8Ovp$tbFTxnD3a7FUYc z3izG^_icLeBPe5h@>4rL@N z2Wz}hR4XCb1F^iZT(GgH_yyCLKT+|kuK9(5vHH{qn;GJOi$hx^s=*~r3n^a~p)VV2 zQ_nRYppKgW%SU1{$cYwx7Kx<aP_=K(f zx4!YaFLg#}#~S$UmpY8nELc{9K7;!>SWoMY(Ej>MC4Aa|&XrQt3B4+(B08LikXect zJlL-zZv3B#B#xe!fk^!5+eeW&*NxzhqjjUeeVF_IZ)>LtYv;WxHR>LM%nPm3Ka%VV z+}9#+D`n+;NwMEWI=}}8d%}@FyZV$p=BvnCF2+0`&`zAVsgIess-Kmn{5+N!vgdt zohBSyI!#986A?O12H?_Z@}vA_giezy@&V;E`4}#pChxc&t-hvJhOL*fC$}0cIwr8EY^a_Q}L;@hq&CVsDo#l-U3&0p$Lr^1n~{ ze?*>*at{KMjfP*9x8wh1)PXYyFfGmsIT}8I$1f9CqAobobq3lN&R`Fi39NaYtnukL zG6i?^hmXRtryDojlW(FmTl;@FT7Z;HGo?;!$wypXxdq(2#K{{8j|X4a-%sX_o{<-i zvW7^wYXH4+(l{FSx1)wpzI9l8I++E@Mkar2|JkFgsc|EE_T&w&m9M0X=v-=0X88f_wgnNIvsWC=p@P<-5?wBd}SuL~#Sr z#c-bqjm^^rAFKu3GZH=#ov*mZqIW9pAEJO95dI2o=ihYE_$13C;lD*Is@&@%;oAVK zeIAX#HseV6-DthM3%Y4OiXM@F2KO&;m%=>*cRAb+xV3Ok!rj6y2$fXnpcn3&sC)BB zcr(hFh_ZG-s}Gg29xbOb{sS(Ru^TRx@eEulqYmyCxLczIn2l67lam8kes((Sbs~Hr z`s2soq|iusOLUSFt}UoT%#XqJP#V&|j`W%ME_V7zxHOueK%OIEF$!(#uqO_S)^L9l z9f2*gVqiPy4vLxgCOab<-u-3_BL`f^=vaLdj^6k$JQAKxjLr2r)@e-lVjTT;{?ono zS2}c}cdi!CiSI*-zBtW=6W_nByuIIX?EA8K@7!bGyYa7WD+Ay4&x|CKt#3asFHK>l zJQhf8g}h<@Z(y~CEY}>5EHxgFEHAtj(ox^+BE1eCXyGC)4y0!h^ja^;LdOGJOxpFDu^5@&4@47+{oS{uOqYug*UyL~j)SW0ymDL9Ss+uL z>e037-BTdXu?!YA_IWP3Z>l`xhP{ny@-2!maj5ZX0A%{XYK&M+79AX zyR_rR%0oL4vJ)XY_xT%lW`mphB7FP&%b(F#W>ol*+^MqqexNH2rj|nq(hBha<+n#O8x|!S(X_7bZde7;u>iyL-0gz^sBfZyF#ro zENOR#gQ@Ed;bzzae5toB?as8S^m%i!&OeV@al(gy+ssq6QTIewdpye9*U>~5Ae8XA zXoBMYcQjscKa3XFnjf=x4!a-nTqdej2i+$+F)!$DF?O#Y*of>N3ZhvAKTZO1S#Z!) z9qwA1ML1t-vsR=p_}_MVC*BX?D0q^=&mmN>`-j6*My}`kxE~Vhq+jtJNa{`y6Ppqm z?ep-S@DMPS0%YM~J=?R}{=~W40Fj&lc3A_<#{})1iq6g;d#LSEO8Joc7SNdm*c(a1 z*_;xZq1=m?TuNx%*P{@yQ51Rj7L3*(ODk0XqKDwC2n!&dCKP$ zK;J!UAnkI{Gl&0=(f6+`Wwm>jvD$y(y#jMXf=k>^yXRSIxzgRo)UYD-QaxD_(lAq* z1j6C47;zkuM%62bz3&_3rtqivs?)b8Pgr1%JVmTubII>}Orf!-PJb^pFF<3C$ zFidbGa3^pJ;I1A1Pw-uyh)iQhJOAS0QqM&}`^n4L`%cJftf%#-`;w4qF2a|q)E7!U zSt{Kp&5z<9I-Cft2M;5z0wp~PcMe=H+_K@Gt`iX}-ex1D2yO}7>2RmRoe9?pw*+nh z+*xq*M%yr3X+z2|n@cujevLIL^oTq=^LS)7lom%ymp+xZ6GUm7*o*l@Dt4Xa<{b840zfdSnv>+UI7k|5y?KLoWd9j+!#LV5fO-i7`5j;?HnQ z3TciCuL3_4KQRQ}GsY&_&?@f`#V2#>CVMxpJKdUqxH}L>SesQtFUlEk?}eKUcll7# z)SfLqY`+ON{Nr(ZT~8` z7NydOTQbBqig4)-F zR|w;^NER~Zcl-JK2I}OR7L1fCc`DagF0op5$X6Jha-gFec74hvUc24?P0)t@<-{N} z`8DyVsFiq@n=&E5Pnj5Cr_2nJE@4%0)v{FfzJcunyTz#?d?AficRWVm&>(6{Fo!5r zQh@q~*HKJ5Qc;*DNPS57P&cTj+Xu&mkir_v`{ba~mpb6R2gk}6@P+fc4{A@MUN)Hv zlAh}a2OkHwT57-VE_I+?UZeXjtmlvPs{QQb1*()!gq|I&GGCcvk%vQa2L2hy>oH|= z8beh4-XK3CMHT-^{A(Oio_zG8>@l3zm&xg~!Pgs_+`>*3f~teShYvD2`p`p@P#)+a z=)Z|J%#XMh!c4NIKYjwuyUMpNku8iCXKT@5LNA+ebk2{Te%U4TX7ELxB4}jUK>xZ{ z`nPhX1md8F6dhq8^n-i>I1F=&Jd}C`qsKk4HKIliy%R3-q&Ybgc*?C~xuBB(dA>%T znF_pf!zId_eJ!srnpe1%SGX?kmjjo(ZmLM|G-8Ko$NutPk$aVW=YIe-6nT!jO)gW# z2KPDrK3$~)vPgsif1ZA{VSf4i3LbK8Wk1${ zOY&@o?aG&SnhCDTk2^kX6+krwSGiOO?FqOMgxH+80Hu z78cM0!H>JF-aBE-GTl^MUOZnb{b{J!RSeC)T<>G-H${!^Wo}42`U_o{|GwGo%dKo_ zvL#oMV%CoSlCvfn)6>)QrvMMzY(JsEvFRbtX2+zZ_N8UXA;M~aH(1gAL0WhjXnl~w zk3=A~2)6;81%N|MFWJ%@rEYe5O2Nm$j4JTjx>@Oehd8s_UF=oChAP1@v@eDLd+Y{` zL9om(;QkuV>v&G$c^?nmJASj1WoVAj9HM=d_E5TKjqRxf&k#JM1S4!oSGxeerRArPlS&Bm4kHEVmVcsnrW_A5WC!0#IV<^3GP4<*7QE3J z?rbrN)zTM@=5YaVuUNvtW4%$H`WL(<9e#Wx=YmzjI!YD7ZIH9Y!4KXT!}7Xl_wpsi-6d5(4_Kh6k3ZRr$u=wEvF`qnIuv3$t?y3Flac+=FRLBz~h}*a6{0koV;z( zym8TRYxG@(gXfRrqORAX-{6$|eRNHWwjiAA_)>0v;J%<@;tY?w5&TntOus#ar;je6YyFfV($2 zG?JGToFYa|hg&u1pBo3MoEn$}iiRJEqQ4c+C+Z8O-`ZGM9cMOZk#cZ=(kxL@E>!;S zjDohxIBujK1eONv3pBR&g$L{7RX62nbU z-$58Z{6!S}@B^&0Y|yTZLj2^YfxV4nB*sfol^o0y(duv&dKG-m0VZc<2)YEo38{q^ zm`~OhyMgaST(QzWY?OVY_AYjYFf|-}5w)|Hui_YnC!{dief32+T6R_p^}_aNP*N48DkONt0}l%N24Gb0&tSh_51EK%I>p zT+XYLCyT|N6-vp+f;zN`Sr5B_xNT*0FgfZ_o=9`zJNSEo|LRHrFAZ?I?RhkcXix75b}s?D7jF23q5s{8=UUula9p#qRacqEuLcv9es~`8 z&QFXOvWZWqZ7)J+X`IiqP|uo1~lWustZ}Q%QUVFd8k{Dx}QMZHv}^bg&42L zMj$VeGb0pRJEi!3h*6_v>qs7A|8}iCIiWO3oy-SbFc=ZOY$Q|3eb>lo=**&3H)&)+ z%MkLVEBTIJYwHieSo}DY{9#}iDR{IxYqZr~wAy=$c#C6wMQz{OwgK%-5-)0)-p_nO z9&-g&55EEAtUhP^B|}z8-V4Pk-#=jl95ZPB*^oyhdfFnT^)G@VgSn&wpP!*AjKxLL)XSaV#rEnd+7oYb)IL21!)_13HIH-7m|DpNc*+2A=%JEE*DXoQ$squ^&y1Z zhzxlm%wq=Sek%>ohz()Xum{W5Df8+~5P7*=f$8fO<-> z`=iG<080_Q%Uouvm!}oIX0DfSE~=M{4U6zL!DOnbm#wh*P-v}&zX)$P6ur}@!FvYM zXBMR;rjDzZvrJ!l>Sg_COg3UBj>g<*`Vu8fD%xOVQEGZ>y*xhk%T?~$Tg76u?9AZ( z>lvfFHXiTqjcQ?&Pn}tN$WENBNn&aMysv-_YTNTgZ>_r5%2J;+57G&Mo}YnTH0SCn z2G~`Di2VpMYq~amJz|Q_tfDW!6!o1vfUi0r-%P!1y1|tSeSLYs1Gr5ckZY`|0&eT8 z4#*E!^^ODbgI4%V$u5($)!t~I5Fp-?1M&_716ec9eL&uB&>>Zw0X~C4+G;zkr(Il! z{Sb2r57TkiYtg7!wgf!2QRpS$-NcPM9_tBHeeV`rVSZG4Lzu45ZkEA~!5 z&dHpha5b`#F=f_Pv>e*pxj7DUZcKH?X4bKEGv18zWKJg(>GJtr9sjQ&lY5V>UNE)A zpq%@jsJ1-;t5^Vr>Pis3IGKl>$AoR#mLx;k7YF3o=%Z3A&DGjBwrpb<&an6~`|Ax`fB*@2QZW-56R;um|f1V^`K^#OT-w-hBW^ulL8Am8CTAm8r2 zyIY%gG@u@2hO|AYH$3P(X+LuQ)2!prIm%dm6R`bwbv-P^U7Y{p)hCYI_jK^NTrQx2 zT&@^;&)J)y^?!BsKdX(ae!nU;$mBnR8t+A$@6*wIU@;$7>f%x3Jv#VIt5!8J&=Qq@ z2P|!J)8=p$`jRLm`c8aV(_4i(M)Eu&}ILFs=mMOqt z%>oW+F|8Wo3f2--|N$=bDg03_uOrKUbeawOmp7%!N2rr zHM5;PnggXQ`gMo9IS;Oj^=^0*3;*Jft{s49)M;Eq;f&D&x#+lqN^ki0hJLteS9-lG!Pf^p)v zK3Jni2;{$O4%j2-mb8<85H`4ct*Kq#@Vs3*w{-3JP`db=+B?`k+w(j|G4VXG?@>p# zAZ7&EywF99XGP6H`)B8V%=#YOebv!_xtY9A0!+^Yomxs(TReHyPq5aR#m21*#_#bh@AYXWs6*&O!+U*vt_e9O zIO;GSme5##Pa0lua;Ë!;2zM*#4g9`4&gbukCpqZ0@)axaCIJygM$=$>xHw zIRn`^d&&9R0okySQCnTZ&VW3`d3GAxN&Ux7j_rbPj#yjDvj2$@Fb3M}Jwd69!q=fC z(eV7}EA4l;n`{2*UYz;jkPa;zZ8(uddl?`&eV^CX3wRyY|*7v z>@DASU0VCUS^rq|Pq)ECcSQY&q1x>E+Bd(uJVV=S)jFK3F$?LdG|E58kw|3;wKrP? zaUAZFD=kcroyko8ox8a9MoUHK=!r9Oe>IKZN{cP<`x=9>1o$6jGPuMB^F*x?kc?H^ z!>A|7>}-Q&W~afj2eOi&*G+vaP*VHPJV*@~O1#=BLdQPl95k8mEIWmh5;-k2o9cKW zpIj|JxFL2r7LB-%zf^N>3+=FrH0v%@*L<|)Q+3rRkcPmSTRPZ`mfdVQCaQZ`^?wHC zuA43Iq19&t(=3Yu&)Q4RO#&9cS8BPlZ>3%0IoO#woh`HLoH&Yy`wp152{3WySrwJXaIj?%|L?5UGrOf^9o=?Y1ZV4CD?zw%1)l6>^;VF zt1&xO=VD`>I1K2g9s502MS7qtTNj{k(iU-K*n>5-JX;lj+|RWYHADPI7vW0iW_e>9 zyH|LHdCmrWb~@TsIKWRD|7lV=BxQA+7zg~L*2^9Q9uhhZ?4Z0aXkiO9LH3mzrFcqxHf_|KTI(jD1!03MWm%&FLnLqYYXXxudFA*h2}> z195O9{#Uwora;@FHcXJRlhx9V8hfC;MSzTq>J?!3qjM##CjM8}mUW@aThgSI-eZ7HCWX72v%iZ+Ark6K;y~+I;NfOYlJRD)o zFF*116S?g(N(N2AsyEhu51pT}n%;@zRUh8^<<=N1VA`7I zShe+!Zh{1Q+_1c3{bTjJ&}MVgXBE}B?UJ+wVdG*z-AdWoGiJmcyPieOivm--P{Wugo>a_eN*McQ4M@ zOVRiV!L)W`&9ZhTRE>F+j{9m}`(e+Qp8fWxFJ5*(8Dc@psm#7BV6LgI=G%?chc~ZK zCw*cRU#eLs=aeq3Wz8eumvA;YgNHYpq1*WIdhBw?s%w^_W$z4X+c`r?=)Uf|@|d1@ zwJFd94X#Zx%V>MzInvn;E$rG`p*O@Kg4b~WMKk*!uhxBX_?rJ09C9omK8bUa!_7po0yDy?gi=DTS9(e2PS!=o|)_~X;zlE~D{)YqD zwOg>((m%Z?n|IEhnz=FIbL^K#8PHY|S>S%4jpUxJjE;2@qdM%l-^~^ucJs%qr)Ygf z!*9q;-aPaYFBv!vI0`0T4E*1HIWz=~nb-Q#;Q0cha%)5_`c6(>+p~q*)U)BT$Fk{g zLstAln=UsT-E{fMo=xVOqfeZ{iJg^bc|0q=`-z7h9|?C2(fohq@t((N-dmpVJn_fJ zzJH8*lD;dpe;7QczVX_k;nxW_eTrlgsinV<8rq3(;Ab+^ZgAsH)%MF{9A+K+9Q#U& z$nEE`HaADPM%Z1tM5la0h&?F0`Vf61VCkztrip88w1awfa6IW{83gXO4R(xcv&AdG zd^6IQz=%ShG3*}_^@XfXY+0{ZSHE?cJE1}{Y{PEC7!SEM#!R=?)e329jSIL1;3MdM zSC749B?Ejw2)oO7Oz8CA)-okiWBgFta4X}Cz(Zk8M6lPfc#j)>_u-wV_h56wX~>4k zz$K3pZxETB!>uQ=V;0^+n7hxwhx20>K@U<{EdHR9!ZAmEE)UQK`2V9;U{0?pd%d^K ze+)M^GmD*`%N1ZTFwP2_fD2$b5RcZ)NN+~9ug>oeEiRL@Z_6)dqzq_5>e0+!Pr>5orv>Z@1qr2Q`&CSTn&mLcar( zb!@N~90fe1JEf$>IPFCq=ri$*<&T|opW&n)2TL%%qJq+NwIt;f>WLq7HD&SJBCJnP_JydVie+db!eehO_Bf zcoz>^74H%%FS)&QhoY?Ehd;mmcbYQ-GoS*dP0Bh+|3iPep)$kuoQIVXSz!tv(Bc_i znGqUaIU%&bv(TgK_a!gzq<5rLCRY+Z6m#`TLPdq=?LM~bbe~_x7TO&Z42A05s!DCe zKF>RSd}_l=z2`%l9yOy)C7g}sER)mEFsWM@7vAS%-g`M++Zow!n1}u)s6y{%OpWeL zk5Q^$Z|wIKX1dEOmchUC7<^a_m)y)gb|2FA`#`gV-9Hc4&lIuym`1h;F^&3mrm^*E z^Sa((mM5)$)Q;tTwh2080@GcM9#cQVHM*x)o{{SfRHJW|-fay{bLk((`y&0CY2ceI zBO9CUMo%LiJ8aR!+~!4%?!3z7ZY9?SJ=$cbY+wgJ$#L1PsH!vF`#ol0efPt4NF3Zu zSCa=8f_SYZ5`4Q0G*vW*^=u?o&wk1EN7#Kn~6Lw1#iF-k-Jhdf$ps zA7cb{5d4ld&`+m~_>49aU`sPAnMYWqjteNaxt4SXP;F^#HAu^VJ_KAcaOF4hG%D)z zoMjwgA`r80U>t5V^yZ4hjlOvY1iZ15k7cD*BcSBr%jrB}rpylRl~W2iNKysl>BfL; zfcF2Ci*MJS)3Z}fBSb)WPD+CFw476D5HH|;Un?X1UY-&P$R!J5ALd7XaKg{-ZGX`o zcRnD`E+nY22z5U%pOt4QGQ_p%31S?_!c~{y(5?fszAL!)Z5A zi7Py*$ny=xah&3Q>WNp}tQxiAuBhQ+@ikOpb1gLLh^J5!W5HSL>-IDGq$N8xBhdnb zL3}8*8+~Ate(R&Yut_fh=b2jg3*hh7(pEJi{nBR;>*ciSLX6V~n04S?jE;kz1YkOp z)$b2A)Xuq+ol@xC3hZktRw@UKP+Xuk#7uDqSn#sf%eoZWi_$`6?VOT_La3y-M&^eO z;GLb~0u%!dtC7OmvACB;%0eId+59EIEK;c|lzJytr*PH3J_UQll!|f4iYkps^+u4Gq%3HbRp$r20ZC)2cponhPaCPHANPwYm~Jsl+7kn4LwPw0juDCg3d&&iz)w z=0Ltr*}n+BXvW_BD?A7Al(b{s%PB@8=|{1tvGMn zowd9C>@-S$zEu~v={!Ge0rtXFBbT2S;PcCamHx)|d(|m{OpMI?gGr%SoE~wr5Xa=- z8eFE!I17#kfO%GI~W_!J&u099D-A%kP&rK#Lf7MbUQese|}lYg+)6yw6(M;&(Hk zOL8SMRSvGsUcsdK61=?Gc!!m17}i(^e=K0_f-`t7U)b1P@<7feXkrgdp6xmco)9^3P^%f=ge+=IB z`Efp!B$6dL-{W)_(B@4FCRdqj%>A~F=4xY2l4Ei;e3HzY;S!`X$&pKM{XSq(NDhHw zIVCoh3bP&UA-TZV^~H2eozre_=OcTJ42HraT{meY-Geigg6(U#(1 zS7A0V+O{;;L2&q?cXf2LxsP<&>(WExMnioJg)Tv;kBJM#BQ$~1DxnpWmSK!!d61Fp z?IbhBEWy2GDV~*J?QPp}Ob~bai{^W<8!*x-nLC*8vAS}lJJd4;NMVF$Cf+#kjPm6# z`;300#Dbe4F0s*W^d)sJW{!dHuBkNcEs{v#2sh)61ezw8ac9Cdbfk_KQF*e9eYbhE5_AvQ~lvOv%jX{HGfm9 zGQK{u-`u}#HO-JLA>NUdnC56|HT&`#jy5Q7+lZHqU{})H3GJ4})bDjZv}6On&9MzV z~r{aHd*BJaBv-tXIpaQy$D;fxZ_TnkTaDMOF2Ayyh;+3nZm zU#;X{J(j-?Ul8At>0m=(`sNmhZJxP^k`uMa9 zD|ydlo5Q`wbGC1LPWnA&Xq&2cH{j-FFI=?pyzLC_H>i8;UbPqZD(o{4#kD{`L&((4 zFd3_%dr6_uP;F1m!dH~$=D9Y zxt6cPt!=~d2T_9ZeV4BLzRuY96|gqmwc??SQ5#H3T?k`c2d~9zq1Q0B=6nkXBi#gk zK;MGcnuGjt$F+58qgWrs+OAutO6cPV#fntcDJUnf5Q;vxvQXfGP~Z^~{G4CcR^>N4 z_Tc##Phx}FQH5s@o{t;2{<1}82dx3#SGU{T&nPpmt}bC0za1lN=6w!do$ri~Rzcmi zGut#~{-@arEFP@_+qG5TYaor3+kRRn{mf#T&&=Yn`OG(DUh5HSo3JMbx@>d6{wCC` zb_;u6Z=EdlsgAVfJ94CW;!a3&BL2lzqeE54)>}`-a_FwhF&U@Fk=CiIsYy9fv*46; z!W>YMk+T^3gHoDW_q6hL0&-?o^8UT{rqLg1yVzM{Q$&1fh; z<^ozVOI|+BkzBdgj&n-MBLwI)if;f-*unc;o-?Zw{QM3z#*h#2SADBV+J5&IekW_L zLmy!r7>t9Cu>n(8?4W&|deK+6;o54){z3is(=Ng={GMz6dT$%Qr{2%)PV(RBH%S}0 zR3SAn-|=iiY!{p1c)b-^N5{B%uh@^Y@&VOV-~F%H#|8h|aOW;FC_xs-v-k!9Zqlw9 zj+}nmW3RUsIO=^|-7b%PHD8Z24(+4*bg}WP=l5*)qlZynPXE_V8WqA=I=fXlS;Dgo zS&5ErRoXm1{imVMeXU1YF>6Na9glj=p!Q>LMEv|8J072C+wGr&5lq@;>bI@3ckkfl z?V|st)_twpeY-qD-FCFXO7k_=jHv>o--4r!w@)|f#X3mn&4VOCmUPE}g*f3yKJ zSZRY9r{|2(Hkg$*EV6g2QmGB9)Uh_y*S+(9wjnlC(FSWXm$U09s>+2N%=vs7iv&P++#ooDCpV!iCi~0X8O&!7rTA?+&U0Jic^WQ|nK)*;XrSR0;j}I%DbU>gtsAV>QRp$3kQ2seZXFNgU^Y4SFms4T5+( zxSA734C1$bPz7wzV9+5<(}2PYZpv$6Z+B>?waMz!nmyUUoBDm5?hx)s)YR|Xt=jXS zt*^J{N`30d{f7HR%%nN!iKf;wmo6AM+LX=Y6fRRG}g>~3bs07OYLdP-LX`RxtuG`^Q*S#3KAsaf=H;!*c zDEb{M{<<@mcDG&I8&bM?W*_E%%C-IM14l!va+dG<5T~}a4ZFqSBoTYX_PB7|C$Rwh5+GhfPNPjoC|_A$#GkRt0{V{Reb9jk+_b6rYv1Jg?S=s#eJ3K8DN16ovt z;@B}?GOu^+Yc&Dp!Rphowz>udrunzMnqZx``?Lzgfipi1+<`g3oUw=PbhlxHunDJ} zsXA-AmG}JAJ1pP=z)08nBrYDd7j2&^=L=>aa|_N|T@|}uCGrMdIyh+Yu(S0w?7p-B z3#vx{CAN{Uu`FR!tJRg6HK2UV;sWfU4>a-x%CQwXqKL9nmc%pGwzIVlw=+H48NN6m z2NpExOd_mD1QtTKN}ii7lDlx{0}h8TLac3{jyNFach@ljI0ec;>0pb0?9w`Qr&yDO zR&DpPQ|3!H?u>W4FA>-f-YWq20leqNGd|ADZ+Lsde5u(H2aG`?;?%LY)n|NW*V`NT ztIVo7wOsWXHz#I-YVij<+iOsBy#l8_$6nPv$X>Npr`&&cH9Ngfl)8jkoEEF>)v%T^ zp1qk`gN*_G1H1 zrA0q>@mJlePs@qGt4hjVD%eWe_$@4M_47duTOcRioD-x?+&f_j*iC%_e&Fw*zd3B%j|6%UkQQ3lz$wR+KbpL)#R})l0!8p%mK6CET=BT>_|7kQG5)1X)lNP*i9E z1+@l2!Ru}U;&NTOqC``hO(~^m(>Cw-JZX`2cYnY4^LhVy3zKJ_dCtt7IdkTI<{Zhj z@;t9vvco*4;cPjb-4R55KwCYhT9igBxKYu?H^)UQgw%g1k5O+a6?qSL{7|l`K3gst z0?7od($1Q-fbQe$^9YADx0fw$`TLBa+B~mqMrljmygsF0pmw))Ag7y5(ocBX(m^=L zoY%^Cl+)fvt|W*B?M0j{#~wL2Wt$nR`w8@xbo(thpX0V0FnZBk&eF0zn%i=soZB94 zk(nZir|u!1dR7|bsTm!_Q^I+fo%rgv_$tKz&v;+<#Jl@<@lKS>kDM*%hAeJ*c-i8X zzbxaO1}~e&H-uoNVgpr2qJ%>bM-J>Cte_dFO_+tAgv`{|3Y8B1N=1CRrG-u-sI8np zI}eNi*IK4nPLxkEPqD}gUa)*x^$N6TtF(rj*60_oiZxF&U{nY-Y=J}yV#%2;3p?rH z2khL7D*71X%gb86f&Zky6A4Zc=8|6ru9e$x#%tp(EfM@fbGFSn4*Et&EG+}_!0}6= zzh(-(FUI>xpM1(mpK^*yL%TFn0`$8mkW>MgXkZs@nPzzb>+`dgIaOQq5og4(_{(K( zu24Z&(mRmkEcR~FsZd8MO91u?eswYJop4hZ{x7&tTG=lPwGap3uAfN<{2nrdmQwD^ z0>lB#4ha}0s@RS*_8i;UR&Nz z9QNHt&{ZM&w(858vX(6dOUo;$2ir6QR-anX{X&Jpa1k{^b5=^14djL<8Idj*O!wJ; zOSeEsS5&dM^MxFosl3tKf!Vz0c)2H&zTOPe<%1arCiyEthjc z8(uEo8OM$Pz<=u&y?+n+Xt{k}%O94fTRyAmQ^loAoUHL_NleAN6$>obn?;Dsky$IQ z;0DioMAji`9c?Hp6+)fjiZ{xCluWnhc-fR3uWd?96>EG-oZ}VeyiuVsJ7LFbjMG^j zRkafF4+=;n^lg%bOS;cEr{yzg z4}_U*OR}864KwI!2QF*)mnsw$l@^0njG8+MU9jVwCdjIdbBHPwRS!PGX*lf6@P?Ao z%m&n>fV;Llxq`j)uR7eeGHxs{gzeO_7OAW!4=b=Rhc;vz5ynrnAXoKh?ET`a1Yaiq zKKJPh6%}(V0w#=b&@YTesp+&oGS+Q2E;3zDZi> zR*GKhGew{DO%|Q>O~-RqG&k~R?1)1^e*P*rk3kC-q~;ruDfcT&;(VCAHt!_%t!3^+J~f+AiT- z$y)z)U34%$&Y6*dxQ|`z=Q;5mDO?IsSWP%@|CewMm34&jN=Ys=NLpvD$cZyqnD#64 z28+p>JA>Md+^(?1U^cx{*pI)7I9ZUR5aJA)XOOl&_vq?4Zg8>nsTp6H6&7g9v6uvS zivWKa@V@_7IB^4?vj*`xj(u}zdHuhZgAKeC(i^89^LpF{z}R4EQA9_UhZ?A+Nslwt z^;4ZB5hwqFsQq*&$!WGZj<+1wv6Sh;S<9jBK}MVLHJZ05Nbg#{BNq2Z?sd%WSnpRG zA405s-4f%^GWEG-3%TSS<{zrw#_nc(#RZ&oo@j~Ux5t0!tI6Dld(3K_E%liLOH?|&77jx{h(Yt zCZstf72UgxYm9>k-w?`!d0)5117n=z+O!q3JD&B&RXqHNxN!rY z+!5NkxuS{NT;5a{X6U2)S(bRN+!4MujujX;D5UZo=To3%{lkIFJr{_zI4r* z`0s^t>@1S!Zx$&j{p}US?pKxD>q_&6Tmak@z~QV~dnWo2U^U<4T>IgKmvEBY$0$Jz zg56)IHkR~QpX~8;!guylRKTKa@;na6a`kzY< zQWN3Yifxct!%msyA*;(D|1JJ|P$an6iA61xmE<%sjK{?N&e2!1{~FrT6<}xbi&D_b zYjgnTAnk&+a?=(?)cXkG(qKN2 zJW&SrH_%Q)CX@Z7bYfE-i=x^#fWhMlKcRe7gWMkb})&oaZ$|_ROFS zwbA|THxTYSG60e+l2pDK{j?*_JgOma63v21N5C*gJhT$wCePwHliZ$U)|AJWzo6$) zqD-s0p^qu1_&NKhSjBzX2tCi{e&r6|ucHt7?#|euUtcG_5SQB&uQA_?F?UF=#>_PP z>+Uv(6mgmn)}-9k7(udy{`DQ;v=8nm++nzn;o5;?){zvgVxkCrzrs}OtBFpi5F1m_ zJAH>da4HO$252qHfL>)t70|r47ICPI)+3=+(O$DeiksJi9qOSP=eIS5RrR$A($I5i zlcr#Mxe6RW_0_-NhnlXovVg21(UedSZ%#C&8vB{M+8zzCz#p0$rLcIey8*OJv}pAO)p`M7>~6vpPvG z+l;g+eWIfk_Pa=%04!up98w-~EY8{&k}kiF4lAPC9aR2`zOGJmp?~fm^Oy0Wh7ENi zg!+{g4KW96b|UJ8%1ZT0^+|P0b=vKs^EC!5abX2pV{2e%URm(agJdzT)uqS}EkHlS z*XWPhA;X;(xYco>tL?K+I!n9NcJxCAI&}iS%kwxn)*9-pvB+ZrW02FUp?TMFBM1$-QIeo8fxq;6=!l|b%Ers;+pHA`;L@`FKzx3Jtt{eIu$fjd=+g}A3?#1plTf4@XVcgSdM(9a| zc0*6M4jO{H+lKptvXS9}WFtv6ra*QiHY3A`(}B0%^(AHm5Q!k4DYB6z5@-kgh|X4UXTAp3h3evM=wY!x_yy{V^zZ3z{4z?F z&!aw`^Q(_>VLaKJ7FA^>axke+` ze8iG~J7YF&gw*XuUmRRKxHQ3x@=$Dp?5!-LYzs8|;)@0@2{E;ZnFfu&-O%k#8n2;; z7AMyvxjU$bJBJC}nUSFbcZPsFM}a#BLM}H2E)^V_4(=R@JSscr<^g2t@uYM%c0>r0 z|ELe}CD|*YGqpSU^NEiCzwu}0hlJzr`SYvW{Mi~4Lav*5Xxn|y^am1R-nqy0acsZ z>3f*a3fkLsx4)D9pX1P=>0K>FOSsg2yiQrGwnFRUeSf9-Ai_}($hWs$P?>t$1^K18 zTddBAFHcziT5I(Z6G;SExA?s+wElQ8oT+)?J9JIC2;WMixAOQyq!6tu1E* z6Kx_uMfXS!z;aS>6D?aK)0xre4yoXN{z*Gpa( zlfqw#xjPOmmRc>de~$Pu=-HnT|PK=(dN|qu%FN1w*l?t=SfVK)Zh9HT*9_gKen+x|1%8t4yE_So{tG-#a z(~D>N6uJ!u69 z&2l+3)`x8TS;^4uGSKeSXos874mWkRRd-AFZN<0&y~Q2ecIxXz+hx>_(ar{DWSQ8u zgsOLa>P=P+OOrK9CFt{27#GxJNmw3IjP=pcW@SVgWZUFkS!!yk3N8*ViK)@%yW5^> zR~rk!9Zz(`H3UNr^@Kd$q3Q|o+=h|$gbc<=NUQQd~o}y z?R2*d?x1@Da?D?Fa);hYj2=mfo=JgTN}18!_CN<|rC`hlnW^~vgo%l;e7!|Jsxd5y;@z+YPw5W8o)(pv${Xabw&JV41-3X7xGXNDQ7%p#guCZs zc9*j)(Bxp;V60niE+@@AsA&c6WDE{!^ktM@Uf1+|k>JyHO+zX?!tUvsoX-T`m@YnPB6_v1 zwh>*WE0flfQq}UcTxKp=rM0r;>W5dx1yXVUnDJh( zsGv&j9B&$ryAw&z*0px5GGDm2(9$qxWmIh#ZYtWeNh{-PW8EBVXxOy>kjl=nq%j47 zw&8&>CbFxV*YJu|elBxTX2D3@@f--IOlxrQ~! zHLpLBTKj2ZP85e-(9N8zVNl`qCkhSWbQ7eMZUbmxix)RU!y&QQu(@vcv(QT4HNX_n zkRXjX*B{@OCdOM!pN%ct3|LNc4X2x=CnnZp@C{=8=)|GVJOAu@{Ru^FACxHAhf_Ox z4o(8=Zd6Z1OiAI;!5YDZ-knLH1!3GNHLCtqQ5lFg!aMtyN_n_7YI@*^VX#-w&g zGccu*?2*US(tV;E0iP=iw+ck%wC14u1)}opw|$px`)I{0CrR(5@9Jn&7?`mZc4;}j z4f^QL)=Bd-pp&qsCq#tZ--cMa!}N}slOKn(qAjyQqf9#w?ZZ{GBPp* zE)*_|@f!508XjE68dPXE-EA|ES|`x`Bb93%u2D>hOq8WD9rx}!Vs7It%4tOc=-QCejTS9fHWU5ig4?! zznXcoyKxf*dXqTled1Mg3pD}Ogg0gPH^KgI^%mH8CHui!pd-Eu@BBX4`c1_sffyn+ zY2_f>!<%4x*i{W3VyYl4C%^_Fm4KA|4pL(zI7$yNpoJoXbbocU{nbbJgk#bE-ciw9 zB9J4mh4lyQ^Vp{0)QZNWjG6hU3tdp-8t#O2j#PKH{nV*3Mhd0*61}Ba@O{=b7hleI z^7{g9&jb|7gRwhGy(g9V{Vt02mGG@9P~R?B*S9NF_3g@xnA{hzQdSuI=WfF@+8Etx zn;nrGa^*hQ;^gjKbJK<$y-Uz)z{zQb$>c~)6NP(x8@m+Ay{WGgQr|A5Uhr?JzY!ly z{Z{;MsejrilgX|Ox+DFI&~!v;OFf$kuQq9_H4~3|u24Y7s7Pl`F9ac zGTF}@ye~ftI+1LaE?5NmP>maY?He&}lh(ScBqeOYo&g(;QSqa83F`8KpEQ+Sl5yWL z^-Pl7whY6!1MMFH{&YLjgeMUnxP_Qv<6wN-+0Lc^?A+mt1mCN`qfx~B;AXLwMv!-f zHWA&!w-mBNm`Cz}?DJb_3vpzOsT|tkMi|@CFOl9f!i3rp(m>ilon*mx9`Dp1!g{{r zmO0`MLG1Rn$(V~sgZD16#v}R!X%S;2{YwGthQy>tJ0#~N=`jvPy2>%@n5yApJZXPH zX5}?N8 z-Q!z;RHW^6hg2j$Wh3;TJ`PZU4$5&1-Y@wo@x2B05NPvaeQmR3AoQ;S)UN_mI^MtV zCE|O70Ch!xqI&#DfVv<+Y4LsptA#+@x4u~XekDNlL+CyM>XZN#hxgZg@%a9sV43Fw z0V)QeF9}eG1Sl2WpZC$7(!JmXtO*4u1wz*dP`j|>0i7d0nJE+Ul*`OgaJ>{)A?!N+mu{Sg%zEP?$HOfMJU>;kA zbjL`M?*7ejhDMoaK+&hr>vZK8F=DX!8Z+YNy&pfnQ6&4YQLK2RQ4)$0?FW|g?=rES z@#Q#w+4Z_#mdE=QGvoHoVs8jM2>59@QRE=qtOAsc#$D9!Z!jwZ`GCo} z17=YVOo&NQm{1c{{(7S*3HoGln?0ds4J`UP!gOu}b_-Z*hdCB|0Se?914m`*MA@h; zSx3SrhWC^qUnm1~BqE=%o-%~=ltI!{hR(LkKyU{0nSdXqNAsNSwj@B9^UV`GF&poX z6n^azp$+D@bDEO;&bHV9^#M6}djN0If!6^+r^nrG=ex=UDt(9XBgI;rKLsgp0czy~ z0Br(vXZIU``%HlTvY~0@~e8&~iZQ0R2<<9zeeAsy+?q~${z>lvjQ|` zu9{JR{%iL>K))X(rG@8Eumv_l>3#uj4|T!@%b1DeXYgnDltBt>SNtHz9bhLY#mK+KV|P|* z-slU13%73cMd(nTF2w5j+SxXvi*y}{lRDdWbcNuVVtljp{OC?_8}%4_y2SfB+s1b% z;d~7D!j^Qlt?H)RKy=1{JPdTUfM+Sr6Eaea(I)X0G3KXqz7UI?j&$9Pc)+<^t)&%& z7^??~4%7oSGHYks;LZWR3-5$&u#li$T+F%X?hozn^zQDHhAD7O{XxtNvX1DWTJ3n9 z+N#dytm*=8pwc>^0AKMNY8ISnKta59K%v^Cw5qIIYg9McsxWBN?Bh(Rxgb$~2i>F7 z;_~^L%@Y0`cTc-BvSDp4(e;O}=zJyi|1S+Bim6=dVLtPu;lyu$1nG$vXT&1sKnbJ4E#wz`v$ zmf@sh9dz3)c#}qJ3#J;;wLyrxzAy^fSk{|P)UGd#tcpAKY(Yp>U`V8s%CZjM$h!C{ zSh9K+GV06{X^X3RBA+$QvVyS`S9^9@>o5d`f$Xg74W9q4?-q&D`W)t)8Q2n!HJ zNgL=pv_hwo1Ygj3Amm+bQ1Ze8%(k!qlB!t|MSBdSE1ujs|tXCYiV z+qA%RL{&-M3;KJU%0ezP+B&vDCLMh)4PlcLwGLH5NcnnbNxM{c2I(ZN8Cf+Gx>=K* zvt5|ufVb+wSJb|#y?+8nZJyf4XK>VBsQpu$i82kr3B;v3?V3oGg{7^!IsQN<$uQo$ z=RlY#yfC3^Gu8ndbU}nULj?{D73xYM^f{evfAfb3p|m?kc~G8|59Lq!QhtOF@i||4 zyh0^teT8gbrLHnMp7gYnB%jF0Rq87y&$?L7;l_brXCW#ccTj03#kQam_vdyk(1Cky zK%-Z?Lq#`_vLq?t*foNdY>6x^EJTuzwNpM1hkNeWQ|)X!EZCu=`w1+U=~zBo4E9w1 zkMXGeZvC(E1{@h|8jM{?)Xvh2=6G16+iE6>l!1lYEJ`DO=hE2x7k_XJ{si-QjAR%; z!ZJwPe0av|&@aY`FrsCIo{PiIu?+k_u0#BmE-A-{y*bQXer~@e3q2>(MCB`x(lC6p zY4PpeaD2Pio=p2%890N*^S7O?&bBK)E}!;a%&|<}fU($o7vxyr7s`z>DdWfx(~vvx z9$Z*r84TQ?KDf;iW*h{(gR_Smtp0FrjPg(a58U6rjl1%k_#L%27g)t&2b;=pvAu7; z2KYYP-YBE5I^k<%PYJ(n4;Q{xw-5Rs_&*8!=^n{DJ@}vQ1G`d@z@O?2^NCeG_zwZz zLxA@-OSmxwSfd_R5aw6R{VW&*Y4s<}ep)+zPx-pr*oOkY_ zWMTM5^9(9mBzEzsYzx{WgzpLMgZ~Hi{RQgNy77y?LHeJL2L8nJ#Bad=|4#qlEN*p& zTEPFc|G@v>sUM^-agZDsCiGDMD_@ZMwjS!sgs;jT{6F$d_^w#MIBR7(#V8wzk^3m9Mpo{j>@wrKzjFrxSB=ly*@5{;fo zVSLTJdZl3{d%?EgpOs{@f^_^~=41>tPFb=V;m%6ig3aXt%*lIaP-_?Tt9iHXEveWT zb?!uEeC^hn<8_-RC>yrdoT$jDxKy`c`iY8@uxo?UlV*`WQhU;pD(!b}cjcVQE&6E3 z>lM2eIA?XXP3;Qyhm}~-v^!p}gtXr67`x|48mN?mm(UoS)0HNZp4+vc_~wJqtVe6* z`vsdEw6}Z|YhCI$$X^FPwL$XZ-i5%=K=}(w>maH2d2I;MB0I?QgU<1jzuE&fiw^38kfiOeKfCqSMEi zo!*xTwnIAG4*3QZ72kx?0i0Hf22npur>(+TO*mgbkBn61*b9_v6iI$zS1?5InGhB# z_>Ax=l9VW2PJl}$o)+{)VZ9@r3|hfa8rQoOI5$)q{cXbnq+Q;I`r3*!7n{1X?Fl@K zy|&4nuxp({5Z%F*A?eI0zIhz6zwI&z?Oc?^3F{PLoKVwh(vNeuApNSe4;o}i(2C&2 zd2!}iedh)11k&C0pdrxKY$y5&j#(j_wn49S$O`2XW6Dp>8V1dIhavqahoufKGsX;k zZNh#T$tjXNo6_Vx(yyH2L^u?Mp_5|DPtO`F#IdcSI5Fm^^0#pxk;`mCOfU45dg~L% z;(iNUBG%HHln5u)k-`d%V~Rp+NzHoe#j3BY@hcTeN>&yw*}iha62dGCbq~#~cAO)X z(+PS|i@bG$kPgzqz76bEg+Mkl)FCfeKZ{3tXdBpX1r|y1X5wK==gz#NdSpP&NL$?F zp9R1ChyprT#h6iu^Th@Jwm_#SpU&%57EV3_ZXC*u8A_2DBen)L@-NJ7F*mVO_*8uV zef+CE@yqaS>3@m;w>#pm!uLDV{`8J->+vnf-@U(#u_G#26OJ#`dYNI1e(k}yD~Fl` z#o|jD9-Sgs^W``t{|5GPM2t(>(Zm#2VC5LM*;7ItyP$WI^M2Clc3o`>RdC)ZJ$7(7 zZ&7CtFTWqm)lJzbrZrs{l^N-+bB{IV=hHSeNkbzXwK_Q zzJ1v-?BQ~-;?v0xzc(MwyRTcL6`4K2es{NgyU5(=+5|q|1)9A>bn_1S$O`;nKYEgY zKkROsQHF2*FaJjwPImoP2Jr?f%20rk9mRMw+Ia+JZT6@-JkCFx{i zcHqrXnRxGs_Dv?Ft7A#D!(Ez)QgLCB&kPmHVTVp(=6%B^-=2UPDH5;^mg&XYWuknM z*EY&adpp-zPENZLl%rgGDfiqR`99Mg%$0$LVvh1=>7P3mViiOFZ(LL}oVUFbXSgZl zj@F*C)Hs7BY=V~8H9hs{f`9zYCk}|U5C1N|>38He>2`j6`t2OOf3i_+6$z!RK`B|< z^N#h%oA~1+A>GLbj(Cm>bX?V1c!1O9{w|NCJMu_uA5}$Z<9slEl;a)~qc`J-~UV zbtM7sr5Gz99|NxEy(t|+skj#%r_kPrZ}$<;lA%!M4Fm%JnlL~}lO^@0`2D$CXi?=j zQKi0v_de?**@3)YRVL2+iXb^O?N?PAY$~G`jyofJIN&4KzsFj1N31{I5vxC9y@_*E zDg)ua(*-Wybto?%YJOt&fQyHkm9wpvsn5FFR8@V@GhZREr}5=Ds7#^35c2J8TB5kx zw4|D)p0}gt>w#sd$8Y?}hF)%cmgl&FsI2x3UQayFyq|aNY?@bnwP{{9Tp|3~a5zby zSAu5=o;V$!SBYok&mLL!K98vIny04l4UfF!M^8-&jeS3PYO1w2S3yTpgy>C=yb`DD z*)C5_<#mso@~GVFnNT^%gK33FR{e!1W&J7e#m^Xf2;axxf6TMD2TwIHyV|6Whf9S6 zCi+x3dRD>#D?KpO11rG+D}A-gqe-Qde(4^clMRPlHNZl6mf(rp zHNZx2$bAiReH}E}i`)hyx4k8AdIneiTF)2gJs#6}QNaEls z+&+}p3+%>vn4-Zmulg?6rHC)bUy3Nu(HJlPS7erWRdKd4a$xENDE?smo<-~V>%edU_hGcO_@o`)_Xt_m_H;G~>d%tW$|5Ff-|MokqC^fDdn z92Q4jt^}(pZ5DksB6HT(}QIDx(J%izkJVYstgyx+< zaiSw9{>wh&hG;Ic)PhR{133%yUwt|_?>+6@&@2Z(bf|+3)giT^DC5xT43A8aA*6V< zDHW7WRj~AZJ$dYG8l?EqwX;c!TxgZVdE<^zE=fqG1=rZ zhT@mmLHFas>OaaP`UmUbORSQFKO4fRUhF@9-S;>g*5}>{pmWJ+FPlKE75+ltQ5o$R z-^=~-Aa|-&3Z|m5wDVMOiR?v5Y;{$x3 zt6^ zt6BQ-8-H89vuTv#8yDS0yn3l8uL;ci^+zoIV|yETZ=J`cpsycZ+}Hfa2TR;?`8`hR zS!}@Vpo{R_?-+1}rC+=R97^`OK4|`Pam+=+FXWQH56u84bck+{Cd7~Q%)4$il>z;6 zdL+SDKJS9`q~b-qe|V8c{92D*@w7{dFM~W%h0P`LY^o$G*gVOKm97tQOMKPMM-R{( zaH$LMl_LR9m^^}hlIBTmfmOoXmob~^Xe*1b-MD}C>?UzFwb;epyEu$C>whgQcK>|; z7cG6|tM1#B7oMB%{o@o}%lOqU&_&ns;%dw*$Gq0cINo^G*SU6Q(>1i^YuQ)f@GOKY zfxqyo@5hrr6kl!nL9w&xhj=_wH?vK-kll*kikb6c=wpC)>Kf0W)B=@o1HRR!;c_4I zoG#%2Q|4JyIRbJ;eKGot^_*4=^6aTr-&|$h>yc)wAu+0KanhSSjkW5y^u=wqv%ftqu(s^>@GQoKG)?Lh-Y5)Ui2$xnpoirO)Pt?C%Kxa zh55UJazPG!usy2m3+CF!(B zJtr#Xd3II0JgX}o^{gd$<5I31zwNSyN5+6u`9#P;os`(~dq6)XJ8lUob)jm)0S= zmbYzn&Ce7+etEH@4z1vimsyg^*gMid!V5L_Bx>(T^wdwH2A@oYAHDUHsKqByi%*t} z0XBm?&s3sb(9bjU)N2HO^LmWHVt4i6;K&1NB!NoTQhx;1ANA-f-@urGJ`laQ3>4pk zvEwwTU_>bmi1SS4GbqJlo_U~-3%$^M1@%ACxwxYkas0;1HtK~^z_qIDJZ^oSXyz4t zuVWA1chi_ zQgsS?V2sv^Uw%5%2Rn1zAG33y)gV6i1Xh0e6S4La=Rw2Y39QSK++v|V#(K)CKW%=Q zqcxg52lf|0U)*QYpOEwgW`A&vD_F0WUtV={#sSLlCS>9$x4)gg+BEidZgoE)FBO-x z;5zjZRK}}K36)oyhNBl9UIGUUbtOme?I)!EKAw9pmYPwEgD}R<2fZ6S5{zu~G1f|{ zW^Z#0aps$zXF$Kx)xTV4-X{a)t|gx(vhNQ)%=FFE?wc`k!F`h58}8fx_S^S;u<+7- z+g^zqe-v%MIP1~zyH4&H!|;6W6Z`1cr6a~OxT23nWQM!19GP)weU>G3%ttgH%9w5Z zS2qfljC(sPGZ4Vkko7f~^{n z(w;)xc~=gjFE6=dHD2JtVx7R$^YesDM{*Bng3iL$JH>K|323b@3(iOy__>t!Dxt=U40W zB=blzj$+6=z^~Aoao+~`S&M(?ai4i#9PJWeQ-KOv303Qi* zm>Hf43O0-=NjMz2*o$#5zB>JW7s3A6hx!_D`m}5D^0a?m+1WG#{5PTmGaB@gvJxve z9nb3TJx^DU2K{=We~gbyPrpp59rTnbPP?eq23M<4YyD8hb(M7c@3#`J6Y6cLOQf9! zO2mN@ae&%W9fVqU2Q7k-4`aR(4LqXJN0cehYbsWN_j~bpu4hl;8s-Q#%*h;ZhTPF( zZ4m_qj9Z4ubFg;8yL|W4!=7qS8t(uPGWbW1*f@|lk$S#5aE|qG#+k}PEbZP)b?8@$ z-Pfk1pG9luu>&J=%AiR^ly9HOSn~a8(p|Az_59_8_@`p~c8C@&E8CbvEg(^w&6Eh@@r)JP-ZvEIgVHbKIdcyJnALg9NVtJCF?>Kh?zmd78 zPz%Aiz|Sr&DKhsHl&uFx%s=vHr(f*ZAIfHFW(Qh7xO)V8-x1)D5$GjGfLlg@o+B_e zyn!)oFy_X4u`U=~N%P{ts1tQ?J%TmDIvNYA|Loa=5mTqIP6(#f52^J-YWq17%RcI9P>hDN zPPhe5YW47yO)g-7cV?gT_X+RbS{^ati5puEV{2rrCG`Cd(XZV5$}6wj$5{S&l1rrB zn!g`>vuN%P(F>yHz}?e*$+mvRv;Fh!(fux|wC-!mAmj3vO9md6>DL(J8gXHG%a>5} z5c^%(Ut)8)jQF>t&{c%>WZK*IJr7=OdQp%{7BzFCeRh&bUaSA-uUs{0B5QKetgqNz z6WZ@m{652b&p(k4#mxAuCzK;N}TLG7Mq90s2_VuSt{rw%EzY-$tdl0+=q(m)m@vU#jo+%-^PKdCg|&|3$N$%|ahx=wO&jB2Ih}-r_Km z`U0mMk+}%>hTx6c#9_Z?=oNfPW$DDJ2u;rTHn?w1la83|F`mIbczGW03IWefE=_YhxacnY?$ zA*-Vf-KZz3kKPhLrl~ zKZF%ZHKhw(mc!R#RHb>Z{L1kC#JPt+^^baCUscvpuA&_@u7BlX!}BgZo;d97t4&y; z{65{kga=_?`4lN0#>kskJrH}O^Q*tas*wwyeVyMn%QqN0XJTyfY<@FI$Xt0(*|<)G zHr9_DFVAK}+8zAnGuOFSuQr8Mv-H(Y(T-u;hHs}E9I3dOvED^|IM@hIECDA@u19T( zs!t#%zIuymc~2X;b37B@9?!IgX#Bx04aS{577y;jelL+I>*)N9;A2s~%bqW8<8pDN6 zKK5*ld>qYN;Xa`=vYky_D2+qGHtbvFJwp4XCtDPgcin*Iz9DN5zDlL4E_R=Nbi`#g zr1;Xk`IzauMdBF4V24f)pX@G!(t&f#^ynd4==3gv?oXYYQ^wfYV64$6jKnF>Dd{-l z_mC|w#n_PnJ6$+4>4YRLtis)6ggiROyc0WfepQ8%MzhQziYv9Pw#7c@6oiBVHb?m8 zb?v$ljr&xA5ufTJ^}jd@R7iJv&at(9ZhM<-^UnvkS4~ z63Cp7*0{6D6c3jQmyNk?JRJE8@yx~(^AA%Yp5Oyh39aQz68CzzRN8rb9V>X+d88dj ztgUbFIQH%~&hrea%y!&YFurg*i_0B@c8V2y$)CY9(Yb6W?u%jWIA2&_4ZM_vJza)< zsH;t*E3Jr!zOwoz`U~oh-nxSQDQ~H7IIxeqyt~yQdR3o#89Rs7SUF=JKDe4`X^u;` zm|k+x4oX%%<%ag8pk6tvUW1sSm)kt@YD$-4@Q5*AxDWM&D}b=m=y65bM`;#RZAG7f zeY2VKTG~GM;k(zroulK2cqT3aU**3zuF|DnQAI#?}`t>7a&E^!Eu2At*?7%lL^|yqpj+(CyJ4V zK}$W+4>b*m4CY;b4D;tnYjFE~0Hmy=aN3M9=ua%I!@&ma(YKv>Gj5?==9e6s3>^XT z?XZ)T!e0_O79}Pd(~TZiKG~!C6JwAu7Hs4Ba2|y_z|asZa(pxEv*}!By9=7^az(~1 zdf21Et>O;Iq>wx#>`je=j>@zS=Qp#y0~|~5aH{IRtmBQa9dl1Y?FM~2WTt@S5Wgc9 zPmwX&$EC4UzcV(T%R)GdfUHG-$XaaC_jPElem4K~|YdYdyom#}9V!j`blI3j{P zt{C>pp+zz+7A+#9p0HO{Wz{n67qe1o&&_&T--^_IF6c=%W?w4IL_S9!^|Q#SIoUqzx6@S5zHN%=D^Qm@{Lj z+^GiiRrX-Y6lYnLO3RPp8_=fh3N0J1B>SR;821W4^tZILK_Y+L+ZjgW5DH7E2NPh+ zm~&*@8`_ZI6@?}^KEfJ-?*2azTI?Mg`gNm3vO}-B_yuy*6Cq2(OXXJ@4i~MXd zH%QQ&GKOgJch|B+rIQUW_9lsh{4gpq9o@f5#a#gJ^D@X_=xe35mj01+qyBlqO|Csi zHZh+kzQ{NdZ4?*MO?VY7KqZ08Gjy<=YbUz%Ce9dJ4hfQ@On8Tu%fw{J-^xcThi2K8 z$!w_9IR4T`{k>;3ro{4C$i%!>8(KayA^f}0G|`1n^Ea{IP9D(k9JHp*Dd%C$+*Dp_ zRvK~F+*nZli>nXxt0f%Ez=%88r#274T!49#e1=5M*vIi%;y`ftQ+kCn*(`1jW!ipf z%p6a~hdN61KTNjPXBaK<%o~dP&>p8!n~D7;lF2NB3|Br}))8qDBo2*oqt=X?M4G%) zTP~_iGiTM0BAKDW=BGDR*7i%$7>3ttFw8oxM4;xLz#n3umeAAX#4O?tZGvh=Z;qVzc zBrOl+gg3m|td@iWic3X!XNtYZ%PZ;I@z^Pi*Os8K%#)o1--KUoX39S{GPbCZ<1p_U zkZ=|w!T{yj0{Lur1}k=tQ;Lyau{(EaRI4q*=G|t)oxftaeYShDa&j|cIgR2eIc^D; zQ9s*Vq}1i)ARX9~89-S6;(Wo28_agj2u*7pt6R`lW$tbc#rUP>l^2yGiq^Rx?dl9EahchZohqwinC4kju&B~sy*ds?MeFf*$1Hwzs7lGkgXgrtN zSKqWna-+C=C%LFTW9?L{AQBwO==03paQHwut#qJSs zymf#*%Dc+2#k;C_wbwkwI$<+%h_TaqFc0%`!dHV*sHr_b^Qaus^2i;zDjI%!2j}MT z=Yrf?+=JO{_Y1Se-@N=@F*Ie)c3)P;+C?LKpM2wGoKUDmtV7hP?x4C5b?e;Ws43KV z?x)w8-HJQ{%A%VM3liOt)BD*I-O)2%bSooXf@9u)_|kLHj-(oQ(G;z_Xc{mX9V^f) z2lZw^4Q4rZ`T4&Rp8xdoKS?nwXz+`E!n^dJe$oA}qMWhzNm%c_(Hs!J-^y0aZPhIo zpPB8R6uvOW*eI3i-KR7;?io{x-Jh#zQ;pQ%7js4@+hQFxY2{&L6&W&R&`)x7JVNS8?HJ-JCV{hpjrQ9FfhH$hb_gO2YA#gY1i4hNb zuN~svctRZN7ycbyO?ljy?KM$rAgu7bp+>$8`P~_hT1f=tN|;fH79VWk zayvJ!&5`4laxV$AMK6l)Q<P{9hf36Etet98>6q-!ky7m$ zq)sQ%jq(Pan6;k1NMXM&&PZS5(EgMWyc4xOCfZ4HB~G-FF^K|%;&$AeJK7hhF1%H7 zIDhy*^3-168;ue%@(-tWNBuDK)}RL$Wnx`9BhMWjZE#1GqSYkjxg-1Jxm9J*ZZs$y zxbA>{{g?H*&0S(KxQIV9Q(o*I$-f_8hWp_`fALM53iJE)_Z#`}6^)|sB>VgED~vj~ zlJ&s;E_~Mi2!Hi|gkNSe+|uw^oXbmqS>F}KZfW0Q_eqh#J#|^J`vlrwVj?7-P!FL_ ztc-=82NW)P-$h~QlMT4VbDO)z-#YN#kwy`EH{h$hvv0T7qr8(QVQh-|pS->4dLD4u zc%5pP>Ps%vGTkqtHwD$+s8u&d9iaMKbu;+@)o!|r-lSBUqsQOudXK`AT)*+fs+*s` zhd1%6n_&mQ36fPe8{dnZIm=N({rLv{4GXjjKT|MVT4AnL%swDcM$QF zO5!pl^{KotYSXTV3VVAL@}QmUBy7^B+t1&%*nQ2a^KuNb(miPjTsIE3@erR<{GM%}6vlx$M(7JLmKrhdwsS`UZ6DzFQofzi=jtc=!!0BKska{Th)Tt+$W2t{uVn-4^3Ga=y6E%w6pK7u9 zqZMHsCf?Oze5KQ#Z!kvAnI@x}&Fqg_=+^0O>Oeb6QzyKkEl*(fWydOyFIqgY&l`SL03;ne?ZUE2#!(ER}aa64dI5og*iXixZ0c*=tf z!Abz<8ar*+7fPe^^ght(5n*JoX|i7bz=gVwH7%yvlbBgxtZD;IZtT$AWx)7#Yl!j# z*b~oGa{j0%_Q9H!asu=7kV^@D2T&p&RCnb$yNhcw~fCCJ+U5^pBgsk70~q;5B`cX#$Yy2GeXSXBdik+ zb*%N#&a}?^lx>5aKf6ZHZv4ZBz3HT%T~Wt4Eo}6)9_e`c2H87aicdp({s(?< z^GGH0M?R)^%O)uO+>H)Q(?8bguwh`Ke^tG-Z4Z&IITvyK=z#AAf)Af>$#`wV<(9f?N1X-Ow>uUX8 z-vGls$UQcauz?+@9Hn30vOy1iFg55Az+2s7~g!v+4H;kovBgIjLc{E?a2pvQB5Sbj5v`nis6d6EvfSAHS7Q7Hl?MvgwSEidx|e|Kr_R~W$%>qdw_ zD$`y!!7Z8)>gU^!<;gGH)u@z#8kq@aj^)K&;IrrFf*N^m`Wg2n^aVXnb1sqMti+LO zRJ-OFIoCbL7?-p|e(M>1>zT^_Oxwp5Z~Vy>YTV_DG=A;cWUO%+jC!NO#b-}*@pli; z9fvs=ab=8=Y?87x12}OSabnv8wWnb(NZld5#dXM9_zv04{@_Jft48@gcrlH5asDpw zB6Q}17Y~6K#|ZUi^WL%@0)MrD7YF6uiU)MdyTpqYSi8E-iy_2|V{BNz5HDW6&5Oi= zLC)KtFFX(KyTyi0boO%I_X6kr1_KTpco=s(4|hBT4t&BHk}ycQw~mA5saxJur4)9j zK&>2^pWRpw{tJm?Xe<1g_29pgHnZ_r)cdU)@778EQIWtcPv+;_4xpW+Q#nT1pfP_h zaNB}%=-t@yxs6$GO9|q63hN%MiEbX!B^rv|G5H$IsJIR(I6=~S$nWbMZjk#EGw%f_ zJk@~}fLKMeq1SwO^p-cT&wu3eM&^<`~nArLGr+cA&vrcaTzzc7SzB>&O0EK3KlvLP3ex zZ}w8ZQ6xi4D9vN|8ge1AQLLo4kbR~!FH2|(Z{(hAR4Ng#+mD=3r zTu1Y^U*PW@ocoGPWc&xX@wAK2(&T1?2gMSxL@tSdBVR!KazH_UDJcs4OA-9WfIieuldN*99la z;p9@dzHt5F2EnDmVGodH;yD)XUN{4s5pE*fWVjh{7Pz@^m2gYo9*27x?oV*9!tH}Q z0CxoL1l+f97vU)FC-39rtKl9}F!??_--UZAg2_L{^DDSlvoW38p~8@=x$Q z1y=_DIXo}IJq>s%(s0B7u#(ARK_eyH3ZyvzPfGt@_~~iH`y{yg;r;+u2DcE7%9k-> zWag;RW5#CPoufD8<{2mC7ZjR`CQd4zJZ0*%=`-$s;K7GV*!@%WODz?P)P|x0^`m7= zmsKoYq#ijebA-BZ#RB!n4E!H4T0LAnA~QQ-y(ianb-_r3I&bMx0X%tbI*?s7uVTJ>Sw*#g0ikMnv|`cx zVZ(;8FvZleIg1xB?|GfLV%c)_oHDg#(Mt8=rE|-csu#~w=j2VFO5{XD!-}O#%N8wH zTb3=Wn7?Qtyue7vD_fnnNFWW!qP8wrF<%YBPMADRJ+ETvvgL>>d`31xpcM%$FJHQN z#r$$$(fbwUoL6R9zG7(^74$c1-w{}_=uyjpiraANMV5tS!4z^UmQnt5fscR)JYkBW zGNGhG4KG|gw+D1;*|M_bRAlw?#USxK%ZdfdmjzSlE#Sh6s zrBV9-DM8 z9K(M`Hr;x(bOT!4Y4M)b+6w9LU&&{r&(VFz0bVS+cC5(0m$x$` z3D_&6{>-LKb|T{*xARHmYdrdhbo#hMIeLq`Bb(doPGClFE{^gj4<%CQ(9uL*MoEvF z8lD(*uB1qJgZ_t1#p&FqC_5*l0%<#^2bY_GmaK78Ur!wc*Vdsbg<>}CRwZyl)j-rm zNAq>zY${b3N)}_Ib?fa36ma6gcuO5Rq7KtBlPqp_$3_#eO`zcZi6W)4cAWh9f=i=!c79}xCnA=aOd=64xRdcoH|CZ*j{@B}F3`PM6{wv;QaWQblqgOl z5*c?R<~$DT%}iOFPf5xYb_foYnl$0FfgG@3}|7O8YN zyEAA0hP5<*L(>`aH#D|3_RbtQSvHYdezT;*<)jvE&8k(C66s;f9?vG@b|#jfbTXcg z;XA`iMX{IyV^5a#WJdC16V-Vfua$Vhjt`+l&2bB3PeyPwIWkI_#8@$Jr<&ttOgU$s z9ae54ZRPD^f(nWJc(xp59#a`Tgpn#@*-peQJD;XF7NC6E+LTPCtilBMI}J}*cB(j< zO~tKvlFfOkwPK@o-o~n)r$TnPh}@HQ${MoA;<~gl*Jvd(@M5h0re#x^9my3eUVMm^ zQVtv#8=ABVLv}&M*ki>k$8t+hR(?_^D&!KIiutj$Rj`ZJ5Edbt!DKVma4IpG%jSzz zOr#R&1V+umIyRofg~6m|T1eZ+ad9ieYz$gVUo>U}vctpdSYv+asb4 zWigT#&zTv7nm;ob%q0RWTvdxO=Yho~8e0cKwibp~UB=;wBW7UI!a|lxVCZ70WX4wZ z=`5zQ1+PnB!B54BYiOl%!&-@@bHmm!{3M$%6YxCE=oF{%}mkLj5K$qvGn7AC8bir{{&E+8c&eA>H;;a2y?rB?Yss zP^6J$dI&RqIAxC%l+$3$opFT^O>Rbu_3Fj3ADt0$%EiQ@LfS?z>k(n!L$%VnV3n&1 zDu*7j;aEj`$l@&^sZb`HEF_e(sbFl_8plj=bhwZ%nrjwAXATc5hmI%8-pi{@E(@q7 zhP7l#gD>k?tfFPL6rZ=WLB<}Jc-C|@YdUr!2TzG7#|p%pOt*qHioU^=S0vUe3;|Yu zGlb#e1cg*Wd@d)Qk`#%2d73A+$XOU%1o%70%QbZV#-fhzoRz{xf{nGrM5ZwMMmU}vPjC<&n;v2p))zWv@?$(kCY6k12{8$^ zroyj`WXcb5Va#!^`QoT*#!$+RZ5ql>s<~%j3qUiOcp{Tc^A^w9_E@~Na)V$m<*PjG zGn?GQ&{9eGFz=Ue?c}=vcg)!HfYaM)y^Aq7*lL5JFM$*vL;Z5tVie`>WGt^Xbhsw) zz8ssF47RnnOMutn-Uh{{iT55(^@uCM)j9=B6-x+qG~>R44Bd?=u8O|?5pP)F&k8x- z=I}-{hW(eiULZRjGPQ+st8Q=_t@gw;k|>_a8$Z26)|V_Ue=LC(sZBoV4gKN>+AOWdU~T4jI9ojpCVmhpT{2_q(Cql3|o)oF!&eLd9e@%ba3?kK*7tRU1_DSPiL%5UE_wZ)jXHFW^N5*RP=7uE7=5 z?O%_=tpTpV`elk6q+mxhIJioQZoelQDrtk{@r6TvPhS@-{XVO)sln>#Krg7!X$@9q zR}Za=q9r=3UhX0*8njf~sk7hX?+AvtJrNY>?~*`AKRPJD&nEJCMlk`L3tR^9Ga-IH zv<={Rezvg)`l-Nb;GYQNO(hND9X!V`K9Oh|9P4KZ=Yl?GrMCM8eoAIn7150~MDG@E zJ2|xaSS-$KW{b1#tL-3)8GWBX)C6 z!dVA|w*aqzLs#PXj_y;s$3=e;?p23di@zSbO4sFea4^SFU!r4$d&A(C3in6hIPaC< z*#1uj*D2gf;JAKlcc!HMvytC9!aZT6O$qm;aI=wii*QdFX|ERUU&67E?G)}!gZqwf z`;D{@3HKm4&i?^mA2`nA2jI9pa~BakFWe6$Z5}@PvZQ^$$glb|-G2{Bemw5S3iq(V zoh;ms49+XuBa&Yo(nf{5PB?ZHOStO|E-Bm>4XyyL682vL=SSaAyV2mT67D90 zy9pe({bq1HZmi!44uWn0$FdrDP`I7Kad}UG9EzlW0UL$8 zTkM$63-<%zt^&6m9JlQrNy}}!N$f_%j`O=sxKZJ_+;0n)G`PEj`>?^?FWe@Bds4WR z!96Ej+Ti{Gj_a2J$9>1^OE+Ir#M3y#~s`E^U$ zdt}^JgC7LPefDeNs-P!@`;Bny&mRScYSHh&u|1CI(?!C)D0a+UEot9}avlHsvT(;q zojLs-;CSro4embS8Vqh9IGE8ggZqte#|wwoAM`ij#-&erEJ^%o(&*>Ig_|(A@U?t>z@eQ!@s*Tb+!xV*vjOWMtnme=waIBxI9gyS;u!c7_67U8xU z+&1AZ2FK}+0zLyiVv>pRoap>C|5;6PD8(z3to7H+`c?h?*6xCeymGq}fv8#K6Q zg&Q)sKL{5zxW5ax-r(L6E@p7E)@a{#%UH6X9u1D$vA`JfC1Q6HI9~7BZk2G04X#_# zo+xSA_oKp{VU&Bea8ZN1OxC({3@$EqK7-pNT*Tncle8NRE-!X#4Q^7neuKMS(pm<$ zMeO_rw^g`x2DeSP4;kF$!r{EQ8_ieO#vQ_)WpLLE7dN<@g$oYHI9}II2lpZ}<}t6uyFBLF4Q{@0UW2O_ zt`i*0@q_S0ZQytg_6o=O_`yMt>CXegy$ky=o^Ng-Dcs=(cl_~j_3?Ctqx^n~oEKHF z|4_hHdl4kkyXQhWpKlG-xGL$d)inJcQ7h@KqeXS$ zie1vQ@=&Q7Pt#RwYBp0Tc1csyp;DcuE7-_IRm@@^#T(jZ_`C79XJY)fdGPya^q$XC zMFlN?c?yH}jTboK>r%R*V3tl zM0Z2yd#cI`tVVIFbSY7#LsdFdtwYs_$A2|CRHH-4rR}w<<%~V7OL)&g!Ya|P&dM= zzHO2QvRsy=e)(!d%cBsk0KXLyD}(yr z7K#2E#kmm3qe43VRY>;dUBWMe_FN z+`)L$rma#BXq6VSBGl;hL6^(5EVYT#O5P6d$WmRzhNdKMXYG-a4w^UT>7+ZLyi)#% zS328@J?+tJfKxvemN@1})`*h5tSL^IWhqbCt27{{+77-_{!eu;<;P{Ke575H_sn=b zH=Vjq?a_0wR5zKMP8j#sYA!qBlD(6+V?U!EM)`Z715UjhS;~*oar~5cfwJT;o?4e1 zbHjFf@7u@N*+=NYZk;R!^d9I!v*Tlu+hz%!_%KR5uX9zaJpAHNUT^#s>-h5LfA3`RQL5m=O-E4S)L(TyUTL^ikT zp1F3N?js)0FG6R@eRwl;mb{m^9Xd-Mi#wpRgOjffqNpYF`Fk2dd6S`M`Xj z7k~0Sk&5HDA)w^bd~!`45oz(-g~TvkxQ`ZbrmY+o$3cpgg$0~snN9jU-STF{hw!2Y z2O;npq-A0J)P-?QlaGa!u?iT6KVZSpc){kp?h=OIn=e&w!de<87f!MfzYcBeX<0bN zfzn9?BW#=)09)TsUpCDrhLvGM3pKR(gFV=rH!O@VjSfaj;hDi1Au}L4JRC3N(}@iY z8`;~n-l%oFii_AqMaQyu@#NU(fEeLLWU@FG$GaM&R_{EOHiGkW89oLumMihPczFLWx1oQaFmrB_2Hili0W1E0wMUFCr;$_x^wwNJgLrS z^tux`i=o$E?RN>nWT0w3*K_^BHEovRTNWLuDGzpD-W42kHAO9TM?Cwj(aGb<0 zxFa}0m&(RA&F*!V63Gk6mPU{~a?Uy0mL?Fs^6YMInoTXb>>6GR|FuHZOWnftg2(#H zOE8^j=w}&vOmtpfQ-(ff=vy3nES?uRIu_5%9UY73HKOy{e3PMn)6n-q$0naENRO~y zSLv$3;{24@)L;RB!O&ka^nW@!7WTKbu5L?bV~o&1rOz|;6Ab-SLtky^KIo_qe(ZoK z%z8EQLCIf>CtmF6Xyg^F^W6XjW*_?x+Wnl!yAk&Q z@EGt6aKe(4>swk^uQ|PK!^V$&oH)4D2v2?D{0p{T_{obd{?xWhwqJVLr!T+aGyi$z zXRo??$2DL3ukD||?Yiqf@TD7W{PIm-x%rlzw|@0&w|#xr?cez3?r(kjj{pA7cfWV% z_wU-X_wIY{{lR@dy#Ij*AA0ylkNo&2k3RO($M^m0i6@`>`7eI?^fS-?>Jag-N&I!a z0q1?VoJFsQnXke#He9bJgXHF0*hxAIJf10RAL9{{eDZKnv+4T0|Gq zr*sDG0VFsuw%6rzok45KUlBNen#@q=RM%AZRL_)$y!fNZQW&|~`8Ooh#$vt;BPL<= zd6gM*u>-dRD$WKFFf#1GK1Lpz>API~Bk!S$t8`dTB#W5W8z$GYz!-jl1 zq&I>C7`P-J(x5w{POh>+GM3Nc0Amd2^)ks=f%uB9KFb@tW}t)Cb%am|AD36Ek2fbc zahE_dG3-PS+p%n67z$1qvY^68@Pwc(C2yR&!>98d#G{9Ly>bm)UwS38xNg*1LD5!p)GeJ{y`62|1;RU;Gui|0=qXo z^h%|dT4sCcg1KJggyXH2}Y}>HsbWJiyz)nLrG<6?hi-9&jIE z19t!m04}=)@B#tgr@(VS4d4To0)GUs1gUy_2J(FX=YJgVCkfvU$@TsUa60fJa6W(z zS9RxnxO{HoR^Si7wLlIy3D^x-z!re(e;RNF@Pz2xPZ7~yh2*rH52v{V_&&h>xftME ziT4Aq16Kpn0Jk5@F6{t#ul_P{DsTkA>CXaq|DOgpEz1=E*XJhykHy0P_XGD`5azv;$n1Y2Ybf3J3rNfZN;%)Ci7-`~P4fZWb!F@KyuSzbJM=BKLk5#FOdu7iBE zfmeO-o2T#iaJ*Yr^#AXB-!N_*D=>KXPJi5mYRtilka@LKDQ^K9*;#q9I~HR@KbnTkMZk&W^(mJ8q}iTX#{d4a@?Xfxmy9 zYM%j)fxZxM60_tCoJ>#&s;lUr3K#8ds)L)jDxg*`z@P4}UVxW3RSPOAsu$FdYgYC7 zm9;cohhM6xn2kiUs$CWBEIz@4-gum99|PV4AV_n5O0^sJQSI}PK7cv?tbzV>o?)u( z`T^M5H>oxV+z0dn7Xthugr|&WKh*|+^MLihHNf|Qp958ubyY{AIxuX%psIZUji}&< z&i_E%Yrq@8G~jxRYTtx>i**=3Du1{U>LEYp+1MohA3i%=gFP_#P^>u0MX74V*mgE diff --git a/plugins/dfu/tests/kiibohd.dfu.bin b/plugins/dfu/tests/kiibohd.dfu.bin deleted file mode 100644 index d11909cc9f3e5fcea129be49b15cba4ed3a00cd6..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 36548 zcmd443wTu3)jzz?Ig?~^pIm@s65z}X!H@}INI=6yOeV=N$s`0rP(Y{&A&@ALLlShb zwhR~B@m5iMTP|(2T3giGl3=WE|E)8V080D5 z&;R?r=lLT0?E7u)wbov1?Y&1PGVzjuvC>q=YT$Ojy$;8vF?K2CYBvw*I9>6GpdP*7HV*S&UW2%6%DLyY6^q<;oTNm+Fcx^k=v-s`lE2-lSt3 zWAVH%rex2j>eTQ5Q=NKfA7kYIm}esUm<0;pgp%kI9m=N%SU}&SlVgH{td0nBnZnDh zicTH~w!g&7cPT7)#J?7y zvNDQ0!Q>Rh(qhy?35w2@)$)OE0IAW+nSR!{bR%PP(7(P%9r}w3JV7giud%+(YZ=q` z#2|Jy6z$?n87(^bX*CM*zlC&FQ7&VH{^(Ye$^V=Mw(ez2$A+U45Z3p^p^PsS8>w@@ zsz>~-P)sDgLydMGJ)#=F z@QcUmN29+zp{PiIm8ve%-?v`-AX1*j%a;p|y>{M*)y*32mlhj(m<22EduR2p>$##! z{f48`;`WykTnUxNmIS~owq@;0m7MN`>*A8x57@nZT+tgB7T9g3?S$WB3$00UkItbE{aKB|_modkC_$&vMH}UXg}1)EKQy!?^7)&>Wh!Ez6t9Xn*~R6FYd9_>|0G=uIOO5#bfq<w9 zjd$^=v-YK7&EBR6oYVVwGiPR&Ovm%~8OJNTxETh2qxZ>{`@6XX74-+Zc~eqg zEY1{e4_3+)6=?8gD1!8p7EkvL^&7kaZ^n|oZcjIN!?y{eL}8E>?)Dt)ez%{? zo9s`iO0}d(DXvU+iYz8)I(XlUn3XP&=6(WjIc$lS;v%s5bx04`aN^N3$}XmT`Ea<8 z=1ub>7=-62m+o^IU55{6d7~T?9mx*<5Hr1GenHXM)FE@|jOAfPZ+lpYZOC^FWPabC z_5Q<3bP0DzFfp?_v{}vQ4O(9or=?OS|K^efyM$dX;f)QZs@n6J z9cc~A8bsH9v_j@pTRi4fl4v$=$;OVx)*2h)MGj+2u&6_e)C{V5-h&-x5^|qvH#ST} z3KPR=dee&*9$1&Bra03zsBcmY+RW6U7Bvp-#7E}17ju*V-#=^!?=$R4T?vPEW*@RZ zy_{T9f_ORnUn2hoz#+o_M-nXI(Wpa8DBPYpvxlgsV z=SM?(7lz7L0KF!u2&8hp<(C; z!SFb#Z#TyJI2`fcE64HqFpcBv@YpzJd}$ni86F$Qi{sc`V2U%{v zpZH0}==pvf(HC}k#soJwhV}ZBr_Tto5SKd1JabA_nK!N6?%wZyz!()Uj>qE44@l-f znRjBP-5p=9^iOaJgM0WtyGz|%QKNCMeZQpmQv=CYq?*dZsWAa&(N~qajpba?9_ynh z7v(%-5u|CBGAYbOh({ehx?EAG*27Kh;hyE6;{mgJl>^M;kLcu2hdDqgfgv4Ga%$<% zW0rr>(i0=;3$^qtr2B_G-7JvdctJ^G!Xb6&LE!TmMK_|(=;(XQ1XUDpkDbK;=b!tJc=m__q4psK?hb7R|_kg1$S3L>$ z2kaRc9YkX>)kGzN{Cggls8=>`S*@Xf-A$VllNT`G)S<%Luixe=8hKH z8{X)~zQm4w5hJE?Y+$GPF~$#i?77wag~!ag8I_nfCks)@=9z3-6$?zOs#7cmZkleG z$@((8VqwLBdP>QO(o)Ki0)7ilo#o1M^VS*uw3aei6s83-sHTlG^C&0S6R;a|V%8OP zO=lSk*Y=`zJjR^cb;us8)#nB5$Y@6p(i*rxS_5`+aH(|gT^*br?)QMF0lw5TvvQ_W zkbfGQiMfBK#DbUWvwb zYOFvFalD4^iW=)xJ!(us*`rD(zQ0m9lT*~mH(g3a?1%y$?ntkRneNQIrHomAmdObf4^?G&QapUX=!HJ!xgWX$%ej4c*T`vQ&SSM_E8=1Y;`mHu zf^DgrnaVVneG>X-cdg9yG3M>Ad&=I+n9|$0&9p^lYTR;fWr~u)xB(|u>E<3QIm?OI z_xGwp?}SX=7Zv^(cYqzNy{LZE*|nttSUbD+?COM!zWsGSMqX^-Jkk;dxrExYH**<% zl;*E%+NQHs_@CNl+4jajJb%1fuo^X}cG^$@c{7fT6E+HEuI+d%&LNJ%apWbw1kokvfyKJFia8QRX7PU%ejR@2WE* zsYbB(+E4yxB7wnh7H zRwq@)3eweXH+>+fAn{EQalFnRA|V8oUBHJpB*3M_~JfjTaq69liK_{%Ds;EPeRhFw7V7^~(<%kIQ-j!9TU(NxmIgt- zGn9xvT0)S`UZB34LIL2(W6-q)c}-}!GL3O_c=?Wz*!+L`;C3qfV@RJ2pVnXwd|Hzd__P*w_*HOqaI{{ucC=16 z^l;C$0!sbEY0k8obinh6!L%w4x+m@F%dBxe{$#l|%9j{eXXSkzaC&g9G$|eYkP|~gvFh1=HvNn4SL}0-PXXTE*@abs94W}}1__pnwHkK?367<~ zU1lCFu5>%IS4dPUvz)vBEor}-o4sG!dxFPT719n{>S9rF5 zm!+xf>@6%0`R23rzwIaeHDOep+J`ZpgCqRsHivO=dk>dK`f3d0{Z;5UDp&=cVDZ*o z3~ga~mA+L|9<-Z1KTu*sosXOSpk41TbLj$tWmTEoW%dx&wg+x90~+BBSK2o@vu-ssA}4ce|ixctXa&XfyGt_u<-{}!aHpWr1vu=N z*dtyej(qd0tnYD@ISCi<9qLJTteo=nh3#eccaJQX=$PjzuF+YOwOu$qHYQ47EmA|^ zko2{{8EJJOcgw0k%a&r#t${nYtu)SZWtKao1zu*Y^;=!HxmBy+vsR_L57=Y;&$(x~ z&bXH;g|->na;x?&zEjJ!Xt~9{iG%9(wQ{roDPg)*GF30>`p7K+eowjoF6r|0eNRjA zfMAoB#+lbjW;dl;G`LQ5WqCPh!iCTR$l~&_n&6B^Oday7g^oC9EB3)%st&fLiCs@g zA4y!mEHz2R<6KxcEFVn;Y_j3TB6TEW4ABTEO)qit0xnmqGFX(61pr5mRgchc| zpLXjI(-j~!XQG8ObBAUFe>FRZ_>7bzK{Hzle1@fMR*3TQFs8iFabSU9J8Dnzh1XZW z`c4gTa}x&zMivd|ZlTY+|Itq)rt#8fX^b?Uj-JHoPc+Q>31L>j-!ursx}K3Ty$9Wx zzkxJC^b0s#2>t}JXIK}Zx_OvOM^AEfvsQn)o3rQ&n!*q?W7NP$vJ`>(Ea9XsjJ9?6? zF?ON}f>;a_w0@rf)S@sJn!)4aGobO4eR=}cQ;?P63BAM{&kyTeq9Ysd^{e3#G-My^ zR)-!!@5M(O(eG|JT2tc9#XS=oI)?%EP7ZT3d4Cc@?+zzn=uu zAxvuy%GZf4z=9~O5VQRRGv$`TCV=rz4GQ4e`a!4T?QX&nYv`xa-?8f8m%C{0Q#GBC zm;2NS7@K>TEGElFbh%SNm(Z_b;*wGs59mJ|ngHm37D^37A*NT80($s%H7)>aX3Ie@ zzlVP|PUOumfCs5VKZ$6|VOeV?@MGquUo0lr=euYXjP4&Oxzb;hd=Ex$h;~fGx-b?! zjT66X$Jj9+z6A4XARIs7Sm4VzH8p}=k1K3XgVZ~yOD4|O;?P4+&cQsNA1!gr)9Bz= z!QCj+EFAzOj@X4$DZq`KEb35V+|gIiYZK8C(JLsJXqMdkQmuO|aH4Mu@uD*{}>gl!&m-EIL9%deD>3s?MceAv;flJV!85dX_9%QVDD0v?b0t5-+EyHLl50Vpp{*TdH=|R2y4r zYHDg>DTPgytf*vLEjgEFepB(ysy(05{-*NYEQjkqVOy;|e{=h)hH_U$Ri-yKE=9_8 z-z=3?l~o$tdI?99l`Kw=v{IMdnJJ~ZSGAW`O@vItU+~m&(x_dLIQz%#J> zxrXP~4m1p`wYjW~JBzGMvs^}xara8k%H1n>th_J3vQ6GD#5csRwYoA}N@an|Y}kp` zb1Qel8YRNU&t34`953Zm=8uOhuo`=2XJUpPQ)WY<1gn1ucy(VF==zB*umyuQ#^f$K ze`E%}gx|qRVxEL;*rzLb2XJNxccXk9r5%QapB$A#+yJ)_^|JS{66Rqg0_rk^X&uwy zXTT*OJs#x*II=g>*@@1P(Z%J)_-}>YajOf~2G7)CFSJ$C$D;!EwEhaSL@Cp3b*`Nx zr4?p4x)qP%{%&stlOOYh!*6%(G_Nf)lvgb|tmV~Ad415sz0e(3{-okr`o!uYx7yv& zMcOYoqEd=h7c0>LkI7r{6v_wubOv%`%>?xFtV6KAsmTI-LPli~Y*!>l*_2-nP84pp z-(IQ@P#Vck(-m%3LLYw}yAGq1%C&UT)Qrl+Sps%Y8uPq>epc<--9qe1!Hl>VJ0S3o zq_*5D-3$u_8%vA2(@om?v)N_`*>L(sGtt@yU9joNU#KmbT;^8Nv>q~$_Nf{>u$!CY zs&W@QmMLZ%Killsw>YCK0h*nFUW%YK-gJJ$FOpIAU3D#FQf1fmfd53ePS6ak3CT?) zGZDQlN7`z*wQwzPo8f#|Z=z?ZrwO}6w!_}L7Jgn=BjlOX-V8VF2cg?t4OLk!DJ}c$ z>Ap9=h+`$^)Gc0nlAjmT8gTwNVsV%CuE6f2T6I|8EO&eta5Mov)@AuSKKkc^k zKCawnW7blCS>Wa+H1do7rLM{DrLHJhipp}opx5_tIj?lpU@n_rJIHnL@;TLo*m|-g zxOsU1b_`y=T_sJ5hef0Uu@&kf^zym!^KLftPrj$z^Ia_O_r6TX_nGAx(p&BuE4lf4 z=>TMVocwFDyHVn9?C&qe2o`kF8gxM)CVQ$n^t0EBFrNIY#`9*^EcB8S8P9XDPw?`T z$atPsEr?B0F)#2~UOuRbh$pM2D@KGo!vq(b@wRU-4&UtA8Rff_UE&_)TMb5MYBV

ibRiTP zDyNe98N*FIr|nT<`4KuuA=eQbuxB09O><3TOQkwUKnBfc)1+AL3kJ9#0<~a9(1o9 zmQz@c&cW?DUl%?v;pInBk4`RD`nLAEtO*zv>biZ{b4eI@TW~nCwoNTp zyUPN+Jb~lM!n`>?vsH zygX6U?XmtioyYozn8i>v!MT6M4%mPRGSQ(_dido8G2%?W1SZFyEqw!1qQnU zFZ+Yh=;=?e56~$pFOLAe3$eD;PR>@6ndzh}$1w({AW2_1t>E&bebv^<8k`;u{iZt| zaJfJ9+wOR@_R}DJe;g!wd^Z@2@DGDFoVN0?h(x=-ww%s$`TP@pk|wC1D)h4vu9h+J zT4UU`F+Phi7DUF_fqK`f)2!85J6`7z)UieC>_Z*eU#!m4if<2`C$BbdiM7UB z&C8WRE5_>x(mIv}p^=EZ{8q38v4z1L=)JDt9OPdgEJjLEko0L@ep#Doex!64tOuZf z#BM>|=d_ll!0x~y^=Yl8Nx=zdY5Fj=krI@&HomL15f^FW5v>g&h;sv2ZIm)z{#FF< z^{^=toU-8C$X8G2Xw9<^uO-2JHx+9A(q2?x*dE zr*3iyv}+b|rhUj=9^~dMME+Z&A4C6|yY@tRqvITd-|(P~aY=>Acn zqi>B8>`siPA?z8Qg6}u9ly^px5Wagf3tyc7Pa`~&Mrq&MH2P#WFTXlU^t54gqDvU~ zwZP5E*v8Ar2M_Lo&9`J{6!hHwfKY>@h4F3#V z#@&o9hO2_xx0^AgC$FZ!%glSbkJw|6=T>utx&gaxj>1>(wx9QNW}K6mE!EepPPV7_ zU3Zq_=9QW1&AnT)XLu%8nv{vmw7Ru-ZC4&{62%`^gtio zS=)&6;d0ShxnI7L(rb`|$yAcd<^3GAk*z5C_;|T+drzZ10d0p%@g{X>t=3-Gm&!eY za@=@19m*}y%Kb?zN1AIi#u$V1bh2P#{k8IDe`+->-RPfc%vG(BD9kw5d90huGkfAs z(OHu|VDWMba9hS|@$jc`Hx751sE!VGs4aCUv#otJT<^+SeK4l+1e2!5M`YP}yqzL=r#$mh5nXII6& z`GrR~P%+7uV9ItaDchfUaOHzt&U>D;C%qec&qMb3cN>kuzz()dG1;1Z^@56nc~72nSk6l+IN>zZX#Cq&zgqM%Z($nyPg=Pdp+{EMF)LZ-_5{} z(d}X0LOAmo7)JlRIi8#=J~Yj=HjoB*C(>O!O|TTbA*Z`vB6)F~-esd*NndoMUGR zKgE2co>Wkh&XLwT*u~Gt_PM6;*36T)Pc+^MWacY<-M#3muzlwFm))?J_xU{Sw zgDc!3G1H6EjC$ND(_|}O1RlgghK}po8afo?b5Bvd_#s}5SL~@uv##2BRsEHjKDpk4LKsW*N0SRnL$>WZV%@d#M1$T zn>)yjKyMi2;+MN`AAWEIvcP`b!OZfN6`dal2aPSz#9~*K^N&?IHdMyCD=WTsYJDYt z5GR*n)MIQUHpS?kdjvPne8RhYUber%nHAsU4V_8fde+sfEuM5Nuak5}^%L2XwN5=K-}h zy4u~{y<8a5Ho#TfxBBL6!JIn6QV*_%<}mZ7^Yy>@r2h}Ai;n2?hoA`+1k5orPPDsI zoS9^WM@kIE0<*m*L|}L8vCAvfoOfc620e#Zm+^O+_L&R zy-tG%^U9Wn-&9{Ku`n3f`(gx-_= zsNH{f;5|jx6VW1+4 zx7;c1?dAhq;qmUj^>ee|?mpFDXd zt_&2>NS6W<$JoGcgjcT^>9Iic@kL5n;JX#qkB_uK8|hs3v&cw`x&)lPkBxIEJkDbn z=R=u}#)=8Plp0|mD(Qz9Wl2SxKhya`g$t}%gE7X&hQ}DVPYRE)UmKx88zDiux}S7f z!d=p1iRao8CO%KHJn?wa>H2`nB*PINlMF}rUZsX*Ig;a8&Q#AVhYjoXoZWtEmTOj3 z8g4OQww~}9giHLuuJ}wvUqZKbvev{7=sBDeKPv3~nC^bW2?sv_L=IGB`M3dHlF1dj zhCi@OnSE@j8*Dj1fl4ufXjhRk!EjHuMVVyy@9w|%M@8tE zWK){Y7~PT%vM&P>h0t!E!3j7AZ5Q|5Z%_a}VAj;EXU9emq?jV zFd3@VIoP@Hd8%t_z)=Xx*(Fzb)PP4{<>dBq@}y8DMv@-Fi3{#1R3My0w-aoW-Q4sO zy=90;hZf;>Q7lHiEL4JcD2Sby?q$h4LpLIR5%GPHsKWPFIQj0^<~Z1NK=R4cihS5e z^97VPhKf)&5JVh$?WFXd2id_7z$J}nb@y( z*Jo|Jh!+Lf&`&}aP= zo1?{MsGme+Gu(N=-UcU)`K0%h0pE$XD&UCD=*)qGwi|`-++Y-JV|2TjlN%$tW%Yx2 z$2BlkZkkrkbVa$ENV#^DyAkc(&=c?C_RtCaWQWzQua2_DpX8p?Bucq*m>o#NsiFlp zPc70vF;3f28qe4rN{j=tH||hMbcd4GPQ*!&;b!Dx$*%=@+~ps$fze#l z8MYn)8Wl&UfB`xKwDcwd_idQV+pjV?C~(#|SFAq{yL^RQ5|txmLXYG8nI7BGRId?V z*0(1z*Pp}RgEvw)Y3-6O34IXodFEAV@euOkGPkq^sgC9^E6=L)m(F8OufesB^wY4J+brLodlQakDlLl0?|I)4mi zZ@}!UUX7}@xUG190r=n@5ZTBKN4H1%S7*>`pUX9hQDgS2(KS}+ijX^T9t``unlF*9 zVc&QiDFW+t&KCmf(0UF|kJV_bSwXxnH4uh&lK*Qiep?=xPPY|u{bT{fnq25fB5BDDAfDpi~y_=!a?v?{Oepq+j=uR)ohOSammFAAJa;K`D zoq?8o-N}{NDNDRE&RB<0BzEpsH`=qYdF|C(j2oY6WryvqnQx+@n8{d zF1F;wo-C{^bRAs%!0KErPp3saHz-sX<&r^&mipPvtUsq&}2zST!(LW-M@MIW1dw{W~ z?|{!d!q{W*+u;}855AA|>mLs5#`+!xn;34DVBh^n3BPtYiZ^);DDxT08lZ#H8A(-d z3g|4#8g; z1HXyhiFK74VsUpGT7E%7pZB`AuKSkEMK3p^{e8Xf!KnhP5xjKCj(CA>eiZiup zsbVQf?=8X1`2fM8w1J?I91x&cMw$OsZ;W2!t~#)q-mFI9&8h-!MQ=3$mw-_6#m>>biSWnPk8D#vcV)Xj?rw<5I`IPV z=J~Fl!O{X*NSM(@uk#=~_NqfC)I(oMW%Bvp6D}S08J(;rD-=&>Y{IS|x}E?=9PgeG zTYL7gm=bx_PTj!ogjFr|$_=(Rzt|;k3lgmCT=mY=XVPSulYvr~|I3Yp6IoizcWUZd ztPOWGJY03KyIi?Je5m$e;5aw^$b~1{<~5iaf7CcpV)8RPtS66L*s-0-^LH3d?!*XY z?1(<;v6je>?$}vvk{YG|`0&UD&-P>T{X4chTRto~#})3i$D>Zkc8@%3$5R&$dF75ZuIJnhOXx-5dKYW~QuGCndrH85&cstIckM_xiQeicJbwpH@U?yy?Rd_; z+Ex6a{oIeVzUJ@n6w-JKk$$Ty|HGm?GNXkP(jEF@CVz8Of4!sPf}c%4>^QBgd-N8_ za=BeTMfW6wy?Uub>9531!Yb&@)sMP5PvO*gco2X)bJ`Jvrmow@1z9mQ3}uEO#njiwH=RN$pisy+KHeU6XG zhSB0K-GD=*ESsxbDYiui_CqQ|h;c>tBgEv;h*QQn5z4*E>upOLCRUXzMPhUSUq)ra z<(#lBMK6;9lJWnF91mXN<)2?nPQP!bCH~Q;3F$eu<`SZ*c~qY2r6TSI>L()|Qh$ zs6N1c;3AwlxcWd$>xt>ohQRY)LEg^m^H%=3)yrnw;y=J1ccqmZ-Dcdys0lpgoHbs; zsgPp7C<_2O+o2vOhf`bKk(?7gjc-@fXC@GlJH`h^;Lwlh* z6c@ZJE5BUum&{D@&vgiat8+(2DVIYo@4wBpuwjaaGp};32&}5HdV&AkgE*sS7T@Y+ zl`F7E#aJ)-RV*`tvu!N|GV1vPFm$DGC18Nzt?FO4EU|%w~<(aMpwZDW#2cC_%a zo_~5!&pyXFkjk;V+kof48qTY9(pBA9f5 zCf<~o@E+W>a`{BiN~-rV_udd#wMNK`(P*!^nP@K>w5JPDIo$Fv3+7eJZv~DM?j8eP zp9lWtJsOq|s)4^Hz|F^@w>KdFapV)u6CIEaFoyg4kWTnZxDEa*rY2YveZKjKMTySF zZx&=1RpNd1hnR^ityh~z;A={b!P!vYT7p@Ty&$gKg0loBn}-cudYjY`9mpkEGwh9p zMpzZ5yQWvsi1mGG4qAh0EV~PVL@`5}>Qr%qh$;GoeCK4yDwADL5T`*MIzh;Zjyf^Hm53A%xKc^}lQGdJNb(`> z3J75?A4c;hVq6B4pz>q#0nstRfM}R_1i_~hFnAA+_`^x~1XC~ELvXv{h!-%+Wb85f zm-;gFMMo~|-d@^p5%0fo<4L>2l;OfnCcNjKSjnPC-kach124WZBz#L!lQOm%?@Fyw zVIN6r=M`yTyt_;;5#psJ7bh}vhO|rBC<=-pA>JintZ@XThB$59q!ZGZ=nhnZDW>H6 z7|Yn0E%<#19qujZkxuu~E6(koyC1uBeD8jzC9ofmn1XvUbVu~A5g|AE6nEo)xKjOT zfh_0_9Bjeo`X3`%P;N*b^y$R`NO6lU!HST3))yZzx(mBF^MjDp0J%~o4;>vD`j+~i z{r5rhI1p_-ai8m3OR{kGa33h_Q=CcTU97x0v*lw<0G8 z4zcXJw>IkgetKh~JLzCb-RT_&p805$zh@@x^2-e+s{t0$Cll z(2|oSc)Q4@K%R}Nbeflyy#?#x@0Z$1YVF$t9w&Z?dqys&`Ay@Ik#negiAls{DN^!ykvi*-I_bpmclb45!3)N+^iCTsMm5=*>?`oz6j zi?u=TibA_D^v{v#%obO}`r0slDKf`S_#{^q_mECWmV)Pd6RJ%uv%6g0C^6oH_W+l2 z8j6pqL#Zm~5WAvq`b+2E-{{rRskmmd7;BH(;ef+$zQX$c_!z@mHN3WzUmelm+lw!0 zxlDfX6~ddbyG2y~d6fSzlqdejrqP|Yr|k<*iOBik$W-lA8aMk!rXc>^5q8~z?(8K8 z*ktYn<1Mg#u3Tw4lIg_n{J5CBX@pW%tYq@;kz<3240o`Umj_vLj4$1(A59mnBEP0WFD_q@Y_I`$4=B!hgQFg-zq|@i$-V`3$$Wsc z&(OZpVUJ+4Mf-|40cY}L?Q0w{B0Nd^rjKOeo^wVElm9r95edCDGBFZ*b7X=R3d8zU z4c3Dg?;OB0;Bnl~gxd%A65L7Pn{}_6Z10c2AH`M_uwm zgS{=GA*}%#uD14Oti1Oyv)<@4)iB6((a**__gTF()2pHgD>O)Y<=W#3|BfV=);cfYo#r~8wuMZ7t`3ojS`2#(73 zCc1QwbNJ#71HMU>QG1iBl7K_5Vf|s^j=5O(jaYNS16q5U&qJ`|tC$b>UB>i;X|2O#bVoc$6YXZP7S8(Uu?W>_EGt@b5vK`dINj z##ZfPjBt|HgiaW8vG+4;rSH00Hm%q}uj)qu;R5wZ$8?89gR$ilxNL0l@cmz$R=kG~ zu-dbN@r{AFxZ42RWlEf3M;8OU4-6OgQVMC2NNpgx8aodUXfXfpe(<*BbZ7-hPAjP6 zax05W#>r<=MUG@uc!d>I6t`(_B1z|55cL<=*8JC$49*% zZ`_Mrf-Ayp307j>}YQZ=2lEsmSH(~Lo)>eHj z+qas7q_gkR#qPDpi@#Llkoy~*(*w4X`n>6W&N>B9w@OxbeeKgYX@1(XyfSW0Twapn zAO0!jq8X=HfVc@|YP6LZP?n*UGfEw>Rsq(2^fJF-sh0Cs<NA~FB+?+V^@e%nV8<|*Q(9US% zW^g{dWC$?G*PJOu%5pD&F0c-gz&~AHnp9S= z2fxqOrNfJb%OyxQ8vE^rp$gL~6)IY&k=$WbGPB3n^?_Jgobs=~+JoX_kS?2lirha_PGj8668cG9!z z&?hQ)C^U3xG<;fgMGNPnM$*y3Qnc_ieq$=Wi+7yskFTfNdPt+asNV|z?`jKZt2a_# z0xx88a#ZZhhx%@qZkyheJ-3|29_&tB&iS&@KcAQ2)8)nC#!j-|ZT@}zN7?+GA9vf# z2fO2zM+YDi9bb`coAyrqu5P6tQf57kmTukeL~n86dBjJlza9UgKk7|4$O)JGi$i~U zx*-(lFQMFKeoBf$U&3*l_?Gr-a#!|LGv1S5>!~`@lL4?bz;0{q!Yv2a<95Mu(U+!h z35ezI!L82>H|_yStQ)^f*TXsDa=7Vn4&*J^+hw)lRV&^{)PVac^6LJI)AV~8oyB}9bHmWX-bS^&c^n2qN8!^ z#!i#CtjvD9)3K~>zQ}5tH?_5I6KfhbH*RQ#)^fQ(S-5~!xTdC*3fs4K{HqdnhgM>F z2b#G?8I^6Xt5{Z1FV@$J)wQMN6?NO0%FYDYt?jLy&0=SpxS{o~=FMVz^M=-rP7Fk% zb~-v6+dEq~Zx9>` zu>pi{L3sZp#=bx}0pYjN&M3lfqwYMUU-?(p+_+8~!8PVnz{*=Y8rN>b#M;((-rd-a zK+D$7b!~TVE?`-=&0bJ6cT;(Vefi?7+iaV}nPPcqeJP->XNpxQh>VDCW(!k z#pcbOK!Ww{ZJP=T3c@{pr5<_|mz281b2Yk75{Y~Ujj{OXJ_*!Ny81yqMd-gb{i0BW&~VU19C~liu%Y{ ziwZYYE^*XGV6m)u^E%)cKy|Oksw>KGZ)yW1+BV+a)F?HsZQa<~xh;27+q&lb#!YQo zH+SZ@ZeG{yp21oRo9ddI?joOBU;uqtXZuF->y`p>DX@%imjZ;B$QdJ02Zzjo81ynOKe12(#CC+H#@wn zz$1;S8$se@Re^o6vCBJ}#e1*oAO_MQVY$Y0JH)$NJ6q6HM`xS#?>a6J|F>clRIm$o-GU*Bjj{dW?kFel!L!8Yq~14rqM0Bnzx|>zbvu_D*qAGwpF2r~Jxr zsB~n&*BbHC_U5}<+px1m%3Y(CWwb&|wr*P6+^$WWExfaN+oJgkrSYl+`9%wxwzjv^ zx@ikRG~CpQT@7ms-hpWA=BpB@qfIt9o6oR;u`r@&>kO^+lb9WD;il0B-S-= zY;Npmj-*G{1?iQW?`qtL--3-S#+Nalu?crD_A&O@36mk@BRmssF#F0~lCfV(c*6wu z4jg_dgnb0}8Qev7JyZ3ToMzZ3hm3HLD&eiG?N z^Rd4pya{feg|TY*ufUy}#@Ma!FTve76ZR7LM^N`sl)3V+zHP$>(C_lny85!V&6|l0 zU8dOrc4a!P?p6pE5pZ3(W0!7j#X5rYu8E9e4PPccG2HF7np#@1q#WD5NJ7)hMG?gP zvJ_CJAwXDYLziNBH)Rm#G$HC*?Ut3=t1HT!6=g25uA;1>@|FrLX}I83lv52kj5zR> zGjAH>ZsGQs*4;JgURj5*cxwksj4KD3f#KJ0lbYwpUXE9;(_+Lo#)I167v2a4AFi#H zh}EXqf$%KUj;(WtQ|rTic;;8v(H7{cNiA#c)MSQr;juJ==t=Nh)X(M=jqBW1t5 z67_9u;-;=d5)!Q%(7wXnB9tW(zbON67T2}5 z0~3jrj|*F%<*OyZC2gIM-`cirXc4imG`C~V)zEii<2I6pH=~^n5;C-nxOv?ezrR{S zy7qWzQfpf`5E?Y132kemxvj@Wi@w^lO*t%bVu06fV{A?YhjF+>B+W4@xq2*>>*`24 z=;(}O|4T597rZ8%zT9ZVW^AfqN#uWS_=>{+tH#6I(Aa#g!nw+Ikxl9{?61m?$e`k~ zZJV1w0uUO;V0pEyTG!kW!QLy$i)`_phV!^kpraVmG{}PbY zV3^XVrFyrc(orkgh%ZFKvni}Go3fVXraRd<qtWF)=p__XCzX&nZgkaF59$jELgsF!&ndy8VgoKu#S|ixg4y!99-7f!HADRy1WYt zlEy5r1l|}w(}Yh=%oee)U0LGGn;WG*aVrD`lHogA+O}?lHU`}mx@c=tD+xrcn<4w6vnI$B=zzoh zGHmR#5Ws!?gm{Wz|6U0hL5EHGL@~}W;0Ggq&OF%c5q}{PzYo5E_%=tl+>MJ7!QYOE z-xcxw$fv(g;8XoikWN0AfP3-@OW^(n_aXI;2;*)-EDkOa&H`6Li4*CAU&cw84R;qs z>JTt%KoTJa&TJ2hNn$hX7cf3x8)$5TS_D}i3PFKbz7={&6Nt1!Y#~*5D^$q!t(#$= zSlf&QNS^JQ%TSOtw6j;6-pM?EkOT-jor5wXl`Y{BDn z){2g`y_`19YZP>a)4sf`tl!w!(L(w`Sdm$WeT0-Npc4(PdE-Vh%K+szX=V(-psn!= zi@?>K3q&J+r9A*@HsJ*}sdn+sjT?y!F6)Zd+L5apw*eb33r}M^*_XI!c!v)cu4c3# z*OYH+v{m{aS_>Ci+TPX#shMU>5V>Z*k^aDJSowU>MN*Dv6+1fDIks+Ys%ey91BbMq zi?t_$nW3pTq`->dio|`XVbP&cF$BJ9(se6gom2rkP+pp}%nx?6Vel6HGHn(A)2{Vf^ zNNDqkEbv!qkI7nKOF%tzH-`HEvScUW=@@-{nFow*;>7Jql*C2=+rozCS;Py*2KN7? z^1qq~nUl2D(zFGPk7V4|P143@GK>6s)8ppGjcptLZ)=YM@N(w`VtosykAICYn{EKB z4x{PS_@=E2I&GH5@~>h_S1le9b+a2&zn3ilPhQ#SVwtvJjB3*$*fX zu?{eeh%`1D4r)~|QxFOP8aHnfn_7t0G--(hr73Xp;R4iJ z4t=V%KJdYj1u`a6S}g)5I6b3=H5n~DBiRm7%@RcMn3w$q3*nV5H5Wh<|;=&x`o^5r0<1w?zEu5g*5UT01on zKRjj*9VbL1Nz1cG{PKuDKjPmQ@n@5tK-gJDgIi7?qEq^P75d#Kb_-yKdzs{g<1qwW^fTi=`?K7WumUW znpDGl2sBzqGN>(VDV_~x1j&cgJ59>T7w3r8kZ8i2X$M9&1MYgbkKl^nuq=$Lq0d6Z zNJT*yzcCc?QzAYAjneg+&q3v5oTkS_(kZVh6230t&(M4>RnysRxb)&UA zCE|;k&)on|OP?5yQ??dQBtO9pM=Y7Ko3yxwU{rvsppV8(Z0w19K$pPl3x)WtIfUQ% zHs}cm)rIg<(8cQuK=TOS4*dTo!fzn_8{qrog`i1E9Mj!Q^~TMG9v+$U5Fz-HVs`hfVTTq%`nU!F_&E_@i1<1|7Eb7(II|R&FSCj#*>pg&h%%?ut>2%PwJ48R?*O)JVpb$Wh|* zSuUv0u=8S!3HbE@JQLy)7Qt21h(NK7gH3}@Qn&;FnC6j1^MJzy8f?wD^^f;5=MEXn<67y}M=?uf6U*g583W zrO=`Zs(@;W+D0W+Dz#OmCQ>T+L8Y|f2P&% z3=VLvTnpZL0=@x9NDGf2fk(s*;GY$N5H=#Ejrz8j8o3mNydE$e2BF0>_5Sy;0=ub3*g&NFc;ts(&ONZq$j|4(%&T5 zV%+x#24p`74jU}{OwwMy%p)AI3l12Nh(~WTMyytffxBWS|`>3(?dpe9i>RxMjaUy%mb+R{9ZXKqv|KWHnY?ZIG-P z(~yjhhXt|yXfcLZ(QU~ZN}IA~g8L1Yy+MmzAWfG&DEYGItmbwg3SdZW-UQqsWwpH2 zc3)ePqFBhIi-=TFCA8+J6(?#c%SSu>JXRoxsQqMkc@BBVtd+CnlCj*$rN&^njFKZ) z8i&U_4~>i+)_I%^`FU9*Tt?$37BKAd5K;nU z#O$Z&blLpgw%qH?RL)}#;fQrJggaI;>eVS3n;yK0UtxM=*Ru|A&McRbxaVaH`J87O zyVT4mg{565Ggan-Bpyq4#umEMaycLaGo0(L^cCyMQWMc27@?qy(}~gRbR}UR_(r>t${rOq zG7N(Q(t+%Za0~}SRY#M!3RFru3cHNp#M|!VYgtaIPbMb4azPWCObD3}Hh~|6)Zr=< znoYRcgwL38jR`F#Y&2n$37bvu`u%@nBrU*6;sKNL6tt*jnwo+%`k@t}aL3A13 zla%vIl-IppoKyE-lovfol!M<;UUUuqL%BM{b37^!bW8nZneJB$?|yvCF-`ZYZsKnF zfO?JcqQ9tZ0d;tp9#roUPicBk6+Aj;UpMbX3fc07{U;fN#BJg~GI1aAK2yd|yw%VH z#Ghq6Qa(t0!qA(DJBA)2UNZ48@gpX_f%sQVT@g+mAS42(UnchA7YHeKH#3LJH1feTPmfwUTz1PLl0^gq!rXYj;NNhi!ARi= z@tqWrHGxMRtn3y?>dLurzxt9xWfA>uavcXSEwE_GJ9E}v6KJ8~=E{8DTdway;V6~M zGjfTClRG{4jq2xlxo=qZ5=R*mZ{qgVm+MH@Ql=u;oAc#|^Ee6OrsI0ax~>TwY6$l| z3SjiEW-IwT?x5qv2eJO+lv>0l&!ou7RpJn%kxE`45uN5HSKX7ZRK7Xd+|wrRzUlsbSF4+{TrU`xE2yzq=E~8AV)yQI44*4$vQI0yj)b16o=hs0 z?(LoK>P_UQrh2BkI#(vCgIuqT zAv`Eps$sN4ubV_Ho{Gj}(Ri9uq%W21OQK-LdSbCl>I~Ftg>uEMb$2FPo^l3C`2{p5 zmSJ}xgY#Iw>08F}d9U_hy@+XNb%&1IBS%}pi6{FKu|AHt+hc^abq*6J1S%VjENE#tF8h2s3G_GA%fXA-d- zFJPpPm8Mf(D?_7`mlT5uE4BPWbT;XgaizqXVxI2i72%M?)Umvl(%pDAGuNi?*CXyV za@(l9B$6p{$sTdsqqJ@Qp-L7$i@4qbZSp!q#A|bMu84OTE-foPYw598KirpJ?X-;# zn0|5NiY^Y96whn#@8#0UeMds+*Dx?CZ1>c~jCjrzbIgtQ>OtJ-3t7!Ig?wpVSVa%+ zGSMdfk}Li>cnOG?AnrnVdw4gqnUW|Vi=N0!jKHJf44j;GzxnzNk0VRCA!J)%M0VdM z5q@U|+nrpcJU=gzhP$Z>zRc`d^Q`E4rg>denQP>NxR%rv|EWl2MHKN_bQL4{YVt~i za-|Ijg-Aa2I}^uT(Sr^I)qTXKr&)b*IVCq_h^yipcb^QC5^@JBPpH^)o>S_pIOFJ=_qBt45}Vx`^7wtugP@WLQ_cfAFso|7_=>I)+B{(`<&97DOzIe#hKG z!W>!7;X5Tp0nZ@7A)Bep@#SO_^s(1zFeh`9=hcV|Z~ow-TrJD(sLLcwzPc+vhl^tg zbz1MI<<}5ahFM@=BgN5C#pbDRM8z=+H&gLmVuctEnR-6m?;BDP-kEgc?bciThPh>1 zK5LV;*;aPQ4%-{-t9;65`TV|sFX(HsE!(#EM?BcT(3yT2!KQK>e%Zj)JFz99J3X@t z+aER@bsT#lic>RiEpRi?3bX@BU^kEhNfX9KSfbRf50L}nE z2QC1w0%>en7r}o5-UQw_!JQiL4)6gGg4P0r8em`x-~b1J3E(JsIY~3_8u)SG-;XI? z)TR#50&D>spbdxtY2YZ314=**xJaFsz$dVkJqeryhOvWJSJ^Mav22|fut z54-^U1UL(vC+}t872tP3jPLgb_-_JV!^UX^tZ?wO^@LTomI8s$Rx1*C#;*I8tY>^s zLf5GsR-kF?n~}E~Ht7zN_DABR?Io)rrHY2y75P5YCPVe=o{F4VQ}=A-uU_2?bnZXR zP0tSL-U)>1-f7sRn^J1;9ai1HWaY1=P;X<9PwO=HyPY5V>Km5);aE5xPJ~kp`+`Ta z!`8GS2^91gRL^JOS2<=he(ZKo%E+Rn=sv7d{O8MLD-D ze|XzQ%vIa(R84_~kE_YBUt6!NfXR52jK_Ta$_ia2MjtB}_GAB&NT5}bSrs-p3e8cS%^Pi6bCS#I}Z_*Hh z3Cbwd29uE@<4LK(3fQLwY*`7tSOK$i0albf)9_J-g}JV=<9I!^WH*A8-6v&I)*ip? zmow+=a9Xlcn1<`2M(~1^IDgL8Y5zH2pm{^ucI%T#pv4pHPn-6v>l z2sASc>j_`Ig$zsWJY@%(w_3NI;-}{>up)!3K$(?XZ$&m)@+_zNH{N{kEcP}2MP1+j zv}eZkj*cIibmPo9GXTlR~-M{cYF!%72@0(MEQ*A&onu4ZVmdNCizT~lCm*qG5#dT>u&reA0b4% S>Fmavxyar-+!C8iefGbnvPgsg diff --git a/plugins/dfu/tests/metadata.dfu b/plugins/dfu/tests/metadata.dfu deleted file mode 100644 index 11421a4f8a0d3c72a3045c57f09123e4365494f3..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 35 ncmYeyP0Yzm^mSom&Q7glElbQPP5loB42+>}F0v6v?g;?^0`U)N diff --git a/plugins/linux-swap/meson.build b/plugins/linux-swap/meson.build index e5abe2fa4..099ff53d0 100644 --- a/plugins/linux-swap/meson.build +++ b/plugins/linux-swap/meson.build @@ -43,6 +43,8 @@ if get_option('tests') fwupd, fwupdplugin, ], + install : true, + install_dir : installed_test_bindir, ) - test('linux-swap-self-test', e) + test('linux-swap-self-test', e) # added to installed-tests endif diff --git a/plugins/nitrokey/meson.build b/plugins/nitrokey/meson.build index 6b9991fa8..1152cdd65 100644 --- a/plugins/nitrokey/meson.build +++ b/plugins/nitrokey/meson.build @@ -47,6 +47,8 @@ if get_option('tests') link_with : [ fwupdplugin, ], + install : true, + install_dir : installed_test_bindir, ) - test('nitrokey-self-test', e) + test('nitrokey-self-test', e) # added to installed-tests endif diff --git a/plugins/nvme/fu-self-test.c b/plugins/nvme/fu-self-test.c index 9b872bb0b..b1b9ae560 100644 --- a/plugins/nvme/fu-self-test.c +++ b/plugins/nvme/fu-self-test.c @@ -16,12 +16,18 @@ fu_nvme_cns_func (void) { gboolean ret; gsize sz; + const gchar *ci = g_getenv ("CI_NETWORK"); g_autofree gchar *data = NULL; g_autofree gchar *path = NULL; g_autoptr(FuNvmeDevice) dev = NULL; g_autoptr(GError) error = NULL; - path = g_build_filename (TESTDATADIR, "TOSHIBA_THNSN5512GPU7.bin", NULL); + path = g_test_build_filename (G_TEST_DIST, "tests", "TOSHIBA_THNSN5512GPU7.bin", NULL); + + if (!g_file_test (path, G_FILE_TEST_EXISTS) && ci == NULL) { + g_test_skip ("Missing TOSHIBA_THNSN5512GPU7.bin"); + return; + } ret = g_file_get_contents (path, &data, &sz, &error); g_assert_no_error (error); g_assert (ret); @@ -43,7 +49,7 @@ fu_nvme_cns_all_func (void) g_autoptr(GDir) dir = NULL; /* may or may not exist */ - path = g_build_filename (TESTDATADIR, "blobs", NULL); + path = g_test_build_filename (G_TEST_DIST, "tests", "blobs", NULL); if (!g_file_test (path, G_FILE_TEST_EXISTS)) return; dir = g_dir_open (path, 0, NULL); diff --git a/plugins/nvme/meson.build b/plugins/nvme/meson.build index d0db9f434..a2f005ac6 100644 --- a/plugins/nvme/meson.build +++ b/plugins/nvme/meson.build @@ -34,8 +34,9 @@ shared_module('fu_plugin_nvme', ) if get_option('tests') - testdatadir = join_paths(meson.current_source_dir(), 'tests') - cargs += '-DTESTDATADIR="' + testdatadir + '"' + testdatadirs = environment() + testdatadirs.set('G_TEST_SRCDIR', meson.current_source_dir()) + testdatadirs.set('G_TEST_BUILDDIR', meson.current_build_dir()) e = executable( 'nvme-self-test', fu_hash, @@ -56,7 +57,8 @@ if get_option('tests') fwupd, fwupdplugin, ], - c_args : cargs + install : true, + install_dir : installed_test_bindir, ) - test('nvme-self-test', e) + test('nvme-self-test', e, env : testdatadirs) # added to installed-tests endif diff --git a/plugins/nvme/tests/.gitignore b/plugins/nvme/tests/.gitignore deleted file mode 100644 index 76234851f..000000000 --- a/plugins/nvme/tests/.gitignore +++ /dev/null @@ -1 +0,0 @@ -blobs diff --git a/plugins/nvme/tests/TOSHIBA_THNSN5512GPU7.bin b/plugins/nvme/tests/TOSHIBA_THNSN5512GPU7.bin deleted file mode 100644 index 8048a0df8289ab63694de02e7aa51389aec6fc76..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 4096 zcmb;vtQ1s$0%P-_U>8?M7bjO&w-67%U_Vn+LnHTqP;-S4|6mVKCr6k- z$B~hNgO_0l0(J&wW+sMuRtCm+#$?7J=m83yoaVy70P?mR$Q;K16q+`weKZ6{Ltr!n zMnhnzgn$AwewVf()rpKifUf!kk^mDBAaTLW4J-`IFMxJ{Ff$OK%U1w}JA@e+1k@QA wSbzXs-UcYY0O*K-!wd|pK!7ek${!7Z(GVC70cZ$dlux4}Ga3S;A%Hss0HviGMF0Q* diff --git a/plugins/optionrom/fu-self-test.c b/plugins/optionrom/fu-self-test.c index d3aa79326..59f050123 100644 --- a/plugins/optionrom/fu-self-test.c +++ b/plugins/optionrom/fu-self-test.c @@ -61,7 +61,7 @@ fu_rom_func (void) g_assert (rom != NULL); /* load file */ - filename = g_build_filename (TESTDATADIR, data[i].fn, NULL); + filename = g_test_build_filename (G_TEST_DIST, "tests", data[i].fn, NULL); if (!g_file_test (filename, G_FILE_TEST_EXISTS)) continue; g_print ("\nparsing %s...", filename); @@ -83,7 +83,7 @@ fu_rom_all_func (void) g_autofree gchar *path = NULL; /* may or may not exist */ - path = g_build_filename (TESTDATADIR, "roms", NULL); + path = g_test_build_filename (G_TEST_DIST, "tests", "roms", NULL); if (!g_file_test (path, G_FILE_TEST_EXISTS)) return; g_print ("\n"); diff --git a/plugins/optionrom/meson.build b/plugins/optionrom/meson.build index 10901ff5e..56013ad56 100644 --- a/plugins/optionrom/meson.build +++ b/plugins/optionrom/meson.build @@ -52,9 +52,9 @@ executable( ) if get_option('tests') - cargs += '-DPLUGINBUILDDIR="' + meson.current_build_dir() + '"' - testdatadir = join_paths(meson.current_source_dir(), 'tests') - cargs += '-DTESTDATADIR="' + testdatadir + '"' + testdatadirs = environment() + testdatadirs.set('G_TEST_SRCDIR', meson.current_source_dir()) + testdatadirs.set('G_TEST_BUILDDIR', meson.current_build_dir()) e = executable( 'optionrom-self-test', fu_hash, @@ -74,7 +74,9 @@ if get_option('tests') fwupd, fwupdplugin, ], - c_args : cargs + c_args : cargs, + install : true, + install_dir : installed_test_bindir, ) - test('optionrom-self-test', e) + test('optionrom-self-test', e, env : testdatadirs) # added to installed-tests endif diff --git a/plugins/redfish/meson.build b/plugins/redfish/meson.build index 25fc5c7d3..49d77ab71 100644 --- a/plugins/redfish/meson.build +++ b/plugins/redfish/meson.build @@ -53,7 +53,9 @@ if get_option('tests') fwupd, fwupdplugin, ], - c_args : cargs + c_args : cargs, + install : true, + install_dir : installed_test_bindir, ) - test('redfish-self-test', e) + test('redfish-self-test', e) # added to installed-tests endif diff --git a/plugins/synaptics-mst/fu-self-test.c b/plugins/synaptics-mst/fu-self-test.c index 100ab6474..12e55a9a0 100644 --- a/plugins/synaptics-mst/fu-self-test.c +++ b/plugins/synaptics-mst/fu-self-test.c @@ -53,15 +53,17 @@ static void fu_plugin_synaptics_mst_none_func (void) { gboolean ret; + const gchar *ci = g_getenv ("CI_NETWORK"); g_autoptr(FuPlugin) plugin = fu_plugin_new (); g_autoptr(GError) error = NULL; g_autoptr(GPtrArray) devices = g_ptr_array_new_with_free_func ((GDestroyNotify) g_object_unref); g_autofree gchar *pluginfn = NULL; + g_autofree gchar *filename = NULL; g_signal_connect (plugin, "device-added", G_CALLBACK (_plugin_device_added_cb), &devices); - pluginfn = g_build_filename (PLUGINBUILDDIR, + pluginfn = g_test_build_filename (G_TEST_BUILT, "libfu_plugin_synaptics_mst." G_MODULE_SUFFIX, NULL); ret = fu_plugin_open (plugin, pluginfn, &error); @@ -75,7 +77,12 @@ fu_plugin_synaptics_mst_none_func (void) g_assert_no_error (error); g_assert (ret); - _test_add_fake_devices_from_dir (plugin, SOURCEDIR "/tests/no_devices"); + filename = g_test_build_filename (G_TEST_DIST, "tests", "no_devices", NULL); + if (!g_file_test (filename, G_FILE_TEST_EXISTS) && ci == NULL) { + g_test_skip ("Missing no_devices"); + return; + } + _test_add_fake_devices_from_dir (plugin, filename); g_assert_cmpint (devices->len, ==, 0); } @@ -84,15 +91,17 @@ static void fu_plugin_synaptics_mst_tb16_func (void) { gboolean ret; + const gchar *ci = g_getenv ("CI_NETWORK"); g_autoptr(FuPlugin) plugin = fu_plugin_new (); g_autoptr(GError) error = NULL; g_autoptr(GPtrArray) devices = g_ptr_array_new_with_free_func ((GDestroyNotify) g_object_unref); g_autofree gchar *pluginfn = NULL; + g_autofree gchar *filename = NULL; g_signal_connect (plugin, "device-added", G_CALLBACK (_plugin_device_added_cb), &devices); - pluginfn = g_build_filename (PLUGINBUILDDIR, + pluginfn = g_test_build_filename (G_TEST_BUILT, "libfu_plugin_synaptics_mst." G_MODULE_SUFFIX, NULL); ret = fu_plugin_open (plugin, pluginfn, &error); @@ -106,7 +115,12 @@ fu_plugin_synaptics_mst_tb16_func (void) g_assert_no_error (error); g_assert (ret); - _test_add_fake_devices_from_dir (plugin, SOURCEDIR "/tests/tb16_dock"); + filename = g_test_build_filename (G_TEST_DIST, "tests", "tb16_dock", NULL); + if (!g_file_test (filename, G_FILE_TEST_EXISTS) && ci == NULL) { + g_test_skip ("Missing tb16_dock"); + return; + } + _test_add_fake_devices_from_dir (plugin, filename); for (guint i = 0; i < devices->len; i++) { FuDevice *device = g_ptr_array_index (devices, i); g_autofree gchar *tmp = fu_device_to_string (device); diff --git a/plugins/synaptics-mst/meson.build b/plugins/synaptics-mst/meson.build index 120f405fc..faeb070c1 100644 --- a/plugins/synaptics-mst/meson.build +++ b/plugins/synaptics-mst/meson.build @@ -32,8 +32,10 @@ shared_module('fu_plugin_synaptics_mst', ) if get_option('tests') - cargs += '-DPLUGINBUILDDIR="' + meson.current_build_dir() + '"' - cargs += '-DSOURCEDIR="' + meson.current_source_dir() + '"' + testdatadirs = environment() + testdatadirs.set('G_TEST_SRCDIR', meson.current_source_dir()) + testdatadirs.set('G_TEST_BUILDDIR', meson.current_build_dir()) + testdatadirs.set('FWUPD_LOCALSTATEDIR', '/tmp/fwupd-self-test/var') e = executable( 'synaptics-mst-self-test', fu_hash, @@ -60,7 +62,8 @@ if get_option('tests') c_args : [ cargs, ], + install : true, + install_dir : installed_test_bindir, ) - test('synaptics-mst-self-test', e, - env: ['FWUPD_LOCALSTATEDIR=/tmp/fwupd-self-test/var']) + test('synaptics-mst-self-test', e, env: testdatadirs) endif diff --git a/plugins/synaptics-mst/tests/no_devices/drm_dp_aux0 b/plugins/synaptics-mst/tests/no_devices/drm_dp_aux0 deleted file mode 100644 index ffc2b1e8036b42350d5f89ff12fdd418f0138972..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 128000 zcmeIyu?>JA5Cu@c3hbOnhj12GaBOW@fP@6`(cCrv!aWkUl8#W%TAO|~_8Z+axulTu zn;h+4P0KWdVz@$#XG2ni0D-Ry{Po|f@0RYpwkiPv1PBlyK!5-N0t5&UAV7cs0RjXF z5FkKcDuHFHZ7f58009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7 z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+ z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7 R2oNAZfB*pk1PF{I@Bpub0w@3g diff --git a/plugins/synaptics-mst/tests/no_devices/drm_dp_aux1 b/plugins/synaptics-mst/tests/no_devices/drm_dp_aux1 deleted file mode 100644 index e69de29bb..000000000 diff --git a/plugins/synaptics-mst/tests/no_devices/drm_dp_aux2 b/plugins/synaptics-mst/tests/no_devices/drm_dp_aux2 deleted file mode 100644 index e69de29bb..000000000 diff --git a/plugins/synaptics-mst/tests/tb16_dock/drm_dp_aux0 b/plugins/synaptics-mst/tests/tb16_dock/drm_dp_aux0 deleted file mode 100644 index ffc2b1e8036b42350d5f89ff12fdd418f0138972..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 128000 zcmeIyu?>JA5Cu@c3hbOnhj12GaBOW@fP@6`(cCrv!aWkUl8#W%TAO|~_8Z+axulTu zn;h+4P0KWdVz@$#XG2ni0D-Ry{Po|f@0RYpwkiPv1PBlyK!5-N0t5&UAV7cs0RjXF z5FkKcDuHFHZ7f58009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7 z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+ z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7 R2oNAZfB*pk1PF{I@Bpub0w@3g diff --git a/plugins/synaptics-mst/tests/tb16_dock/drm_dp_aux1 b/plugins/synaptics-mst/tests/tb16_dock/drm_dp_aux1 deleted file mode 100644 index e132d259e0ce9f845d3c461be4c7db103a33ccb2..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 320000 zcmeI%ziPrj901^pp@^aoidz?ljx7{?fa1`tsGv&+UqQ#Ng_h2JC`TWmk0PbUa6^kr z(2$gVH{8G6{qC19Bug#_n-DIN*H*|&Q6IXoN@AyIpQl&7d@8m-ua+P6`+zlxtB%cS9f$s-Ghf~ZwchRGVg5KylPo6j7CUEZKepHNr^$G9m!;h! zU%xY*(%dkA{rzvQtjq`yAV7cs0RjXF5FpSjf$U~E%*#HjU6`y_x3kr(8)v>k(LId! zYj&T_N?tYu2oNAZfB*pk1PGKA@CT?QnB@cr5FkK+009C72oNAZfB*pk1PBlyK!5-N z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+ z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7 z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+ z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7 z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+ z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U lAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!8BS0^iK36VU(w diff --git a/plugins/synaptics-mst/tests/tb16_dock/drm_dp_aux2 b/plugins/synaptics-mst/tests/tb16_dock/drm_dp_aux2 deleted file mode 100644 index 1c60857e39b3f3da8bb993eb9a64f2b77fe5ec0e..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 320000 zcmeI%v1-Cl6adh~P>Mw%h+7v2KS1yUB!jq=I@qQE(m}9va`2NnIQmf%!y8&$Z1PB? zC&Rlp3Gcp}6Y`df#>XUiNO!%YJgV`Mh9M0}6+hO`gYr^{KkwdtHXQbEpA>V(W6a_) zYAWlyZ0t5&UAV7cs0Rr6;$XDO_tZZrDt-f?afB*pk1PBlyK!89D0e^sE zsH#bT009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7 z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+ z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7 z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+ z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7 z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+ z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly OK!5-N0t5*BUEmC8`V0vG diff --git a/plugins/synaptics-mst/tests/tb16_dock/remote/drm_dp_aux0 b/plugins/synaptics-mst/tests/tb16_dock/remote/drm_dp_aux0 deleted file mode 100644 index 13b878fe4945503f6e4b538e0b78cb5551983778..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 256000 zcmeIyu?>JA5Cu@c3hbOnhj12GaBOW@fP_Tw(cCrv!aWkUl8#W%TAO|~_8Z+axulTu zoBZ0nnwDt@#c+if&xWK30Rp27{Po|f@0RYpwkiPv1PBlyK!5-N0t5&UAV7cs0RjXF z5FkKcDuHFHZ7f58009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7 z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+ z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7 z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+ z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7 z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXFj3n>? D4!r^> diff --git a/plugins/synaptics-mst/tests/tb16_dock/remote/drm_dp_aux1 b/plugins/synaptics-mst/tests/tb16_dock/remote/drm_dp_aux1 deleted file mode 100644 index ea7ff51db45f9a73247d89f1eb3f5853f270e989..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 128000 zcmeI%J4(br7y#gjQDhevg6sh-tVBWZ0J4RJAj?9uu<#1&6&4h0k0N*lv9hxED2wYR zVG2creS{GFrkMF>lKE%y<tRQq^S`t0V?h`}%&cQw+uS`_aXFyi_@% diff --git a/plugins/synaptics-mst/tests/tb16_dock/remote/drm_dp_aux1_eeprom b/plugins/synaptics-mst/tests/tb16_dock/remote/drm_dp_aux1_eeprom deleted file mode 100644 index 45d72a52c..000000000 --- a/plugins/synaptics-mst/tests/tb16_dock/remote/drm_dp_aux1_eeprom +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/plugins/synaptics-mst/tests/tb16_dock/remote/drm_dp_aux2 b/plugins/synaptics-mst/tests/tb16_dock/remote/drm_dp_aux2 deleted file mode 100644 index 87e4ad5d75ea883e01a5152237e73177b3925378..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 256000 zcmeI%J4(br7y#gjQN+bSkUhW_mTRL2kS#0(S%T4G3$L(VK~Stcir^J2J%UGB#7)8! zip@Sk2!2z{{4>e?Gx_ppax{DoVJ~^y2~}z8I*e5kgQh*r#)s8VY=0hIy_aPNt50fk z#(ta0+sJ*sQPN+xccWZgOisI4^dGJH@I37FYHu#et4W&VaT8C;TOC%cHM!n(gaXYtwHMy*VM009C72oNAZfWQ_6`~lhmq7(!O5FkK+009C7 z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+ z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7 z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+ z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7 z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+ i009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7e?1_IwT-AY@<&^7uc(0RUZh0}ucJ diff --git a/plugins/synaptics-prometheus/fu-self-test.c b/plugins/synaptics-prometheus/fu-self-test.c index a9b4df72d..67fe99bf1 100644 --- a/plugins/synaptics-prometheus/fu-self-test.c +++ b/plugins/synaptics-prometheus/fu-self-test.c @@ -16,6 +16,7 @@ static void fu_test_synaprom_firmware_func (void) { + const gchar *ci = g_getenv ("CI_NETWORK"); const guint8 *buf; gboolean ret; gsize sz = 0; @@ -28,7 +29,11 @@ fu_test_synaprom_firmware_func (void) g_autoptr(FuFirmware) firmware2 = NULL; g_autoptr(FuFirmware) firmware = fu_synaprom_firmware_new (); - filename = g_build_filename (TESTDATADIR, "test.pkg", NULL); + filename = g_test_build_filename (G_TEST_DIST, "tests", "test.pkg", NULL); + if (!g_file_test (filename, G_FILE_TEST_EXISTS) && ci == NULL) { + g_test_skip ("Missing test.pkg"); + return; + } fw = fu_common_get_contents_bytes (filename, &error); g_assert_no_error (error); g_assert_nonnull (fw); diff --git a/plugins/synaptics-prometheus/meson.build b/plugins/synaptics-prometheus/meson.build index 7e2f72fad..b7b5d0a65 100644 --- a/plugins/synaptics-prometheus/meson.build +++ b/plugins/synaptics-prometheus/meson.build @@ -31,8 +31,9 @@ shared_module('fu_plugin_synaptics_prometheus', ) if get_option('tests') - testdatadir = join_paths(meson.current_source_dir(), 'data') - cargs += '-DTESTDATADIR="' + testdatadir + '"' + testdatadirs = environment() + testdatadirs.set('G_TEST_SRCDIR', meson.current_source_dir()) + testdatadirs.set('G_TEST_BUILDDIR', meson.current_build_dir()) e = executable( 'synaptics-prometheus-self-test', fu_hash, @@ -55,9 +56,11 @@ if get_option('tests') fwupd, fwupdplugin, ], - c_args : cargs + c_args : cargs, + install : true, + install_dir : installed_test_bindir, ) - test('synaptics-prometheus-self-test', e) + test('synaptics-prometheus-self-test', e, env : testdatadirs) # added to installed-tests # for fuzzing executable( diff --git a/plugins/tpm-eventlog/fu-self-test.c b/plugins/tpm-eventlog/fu-self-test.c index 73fcaff48..f0d9ed25f 100644 --- a/plugins/tpm-eventlog/fu-self-test.c +++ b/plugins/tpm-eventlog/fu-self-test.c @@ -14,6 +14,7 @@ static void fu_test_tpm_eventlog_parse_v1_func (void) { + const gchar *ci = g_getenv ("CI_NETWORK"); const gchar *tmp; gboolean ret; gsize bufsz = 0; @@ -24,7 +25,11 @@ fu_test_tpm_eventlog_parse_v1_func (void) g_autoptr(GError) error = NULL; g_autoptr(GPtrArray) pcr0s = NULL; - fn = g_build_filename (TESTDATADIR, "binary_bios_measurements-v1", NULL); + fn = g_test_build_filename (G_TEST_DIST, "tests", "binary_bios_measurements-v1", NULL); + if (!g_file_test (fn, G_FILE_TEST_EXISTS) && ci == NULL) { + g_test_skip ("Missing binary_bios_measurements-v1"); + return; + } ret = g_file_get_contents (fn, (gchar **) &buf, &bufsz, &error); g_assert_no_error (error); g_assert_true (ret); @@ -48,6 +53,7 @@ fu_test_tpm_eventlog_parse_v1_func (void) static void fu_test_tpm_eventlog_parse_v2_func (void) { + const gchar *ci = g_getenv ("CI_NETWORK"); const gchar *tmp; gboolean ret; gsize bufsz = 0; @@ -58,7 +64,11 @@ fu_test_tpm_eventlog_parse_v2_func (void) g_autoptr(GError) error = NULL; g_autoptr(GPtrArray) pcr0s = NULL; - fn = g_build_filename (TESTDATADIR, "binary_bios_measurements-v2", NULL); + fn = g_test_build_filename (G_TEST_DIST, "tests", "binary_bios_measurements-v2", NULL); + if (!g_file_test (fn, G_FILE_TEST_EXISTS) && ci == NULL) { + g_test_skip ("Missing binary_bios_measurements-v2"); + return; + } ret = g_file_get_contents (fn, (gchar **) &buf, &bufsz, &error); g_assert_no_error (error); g_assert_true (ret); diff --git a/plugins/tpm-eventlog/meson.build b/plugins/tpm-eventlog/meson.build index 6f155a463..3f7e7aa76 100644 --- a/plugins/tpm-eventlog/meson.build +++ b/plugins/tpm-eventlog/meson.build @@ -27,8 +27,9 @@ shared_module('fu_plugin_tpm_eventlog', ) if get_option('tests') - testdatadir = join_paths(meson.current_source_dir(), 'tests') - cargs += '-DTESTDATADIR="' + testdatadir + '"' + testdatadirs = environment() + testdatadirs.set('G_TEST_SRCDIR', meson.current_source_dir()) + testdatadirs.set('G_TEST_BUILDDIR', meson.current_build_dir()) e = executable( 'tpm-eventlog-self-test', fu_hash, @@ -53,7 +54,7 @@ if get_option('tests') ], c_args : cargs ) - test('tpm-eventlog-self-test', e) + test('tpm-eventlog-self-test', e, env : testdatadirs) # added to installed-tests endif fwupdtpmevlog = executable( diff --git a/plugins/tpm-eventlog/tests/binary_bios_measurements-v1 b/plugins/tpm-eventlog/tests/binary_bios_measurements-v1 deleted file mode 100644 index 0618456e968779145ef4e5aeaab9ffe04a393643..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 10436 zcmdT}2V4``^Iw_@r=qBUg1Vj!Jp&1$DnWXY5{hC0jZ3l#QIcQ^0v13lU;$A?ggZgy zEMUP-5!5^71P%*$hYhTNilxTO6vP#LrXx0p6*3b+!5F*%Ph5>Ui~UQdPo z+3L!&H@hDAiJ~d_#ZG)f;sH=gLRdgYX;`^L+)f~{IFg} zh5~qqD-gjECL%$E;OT@2z(5MY+Z$Rx<)G0 z5AjmS$ZT7EzPDr6s)+JYoT{|d*W2T^&KlQ^j85~VGQ7Y-bxH|-+m;h`Rrmd6szC)c zqd;#$&fPmuld2;_>n79EU3Zl6Of&Mu({nbhDM9~z3 zc~FzCGP-I4WkeBDGy(NSZe>)ntB#4k$l1s~;QTKE+a8GEIJ_V__&Y9OWZ1lWi|h`Z zNY`vFZ13audwvep8_XFZ8$BSMgEqW(UXx^hYW5zCeE)J%QQO+wX+>_x+~sxhe+=gvRw|UTiKeLHTU=>KQ zQ2m}^^?ROlTI&eiJ^g;nlEcSxdn;p6CNqkHTvpN97i^8_8>Z{b6t%|?SPoLG`Eo

?8RXHWL{L^tQK4Y^o);Npr>V2$C?)wiptS(tCtUKqQvl?P$#5|S8hE~t) zDq>!GHF$E?v{QMT!Uh#fo-1SR8s4ANG~JeS*QDm!m44INqT!gOvRw{lJ;PF;S-SN8 zh2`|(K2MfEFClT1vFe`{*RDU3e9viItz%I6V~$(eJv9RBaa3Cc8altkqL|ZVkx&tu`}3*@s9EefYfv=WT=jk1lIW@-?uV z?^+=i+#un`>TNKn9l3sYLwth$OIu!Iwnl1Y{6sKuvfO9lYsY%mV**mG#o0@EUzvF? zWKVCfq4L3Y8VSD6;LAtY2p8cXYKlwl4>d3bhY3LVko|&$aEcfQ8;g`g&h`K2DK!j< zbF#Bvk+kYbR_&<4OVj63_-}uyTUiUtNQpbUlishwd-u>QO^&rcdBRc+uXWM~qU_1e za>WIODq7XEfL?|r<0Kpj-Ke;T3FuZxOFY!nr7o7S{3{PaBG}{O?mJ|if7RRbm2tNH zjCGoq&u{jwibf%{42DAbsU?wAJ1|op**JdcSsw)b#}`h)_yxrz&R>1&WUXzCx>q4( zfyQrirWukG8m57{t_4_LPYfY5xa5_b4(d7!1fq~YGynx?C^8H&LX45&$OvR4f+~<~ zo9Z?%_&Xr|)l=r9yj#;!7|*U5g#b0XBK461Ad_S!$dSkh{7{HlG3c$hAmCXb>=z>< zfFh?t5g!BtGZ;t&s1=Ori9{(wa&)DVQE9!>wR+GPSyt=raQepCp2@ zDDZUxq2z+l!E+kGa0Wdh4OxQN65hjze$gD@kq}F8XMqn1u>dlyfz2df4HJAQ;4d~p zMa%&@70g-yDhohi3wV|R1dPCgJsfNopdRv7CND}Yc-yOV`H;M-^0monKesZM%-#(- zy7X>x-$#Nuc**UR`kqY44+Z|g0kQ!21_LzEzr<3>nH_o&yhW73jV6#{-_S0ye37Q*Ol*uaODwZ)oS!?ppKeT5V<=4^T4<2Uwr7 z!j8~G)d~vm7u41SnSlfX`%q$45JW>~3{qngb!vs~e4hmUGht7oYl2rt=%we)iSjrR ze)Xr?;srC5JsLQF=~2d5-qFI_KC`yAyiI5g+c=&78C~Rki?T;4VAbK(sf!zk5En4g zoi>8jAv+Vv$DQ{UvIc0ojqp^~X8XAD&TNkthp*VuwM(zhd4Hg=++ZP)^C{2BE2XM7 zwuEOUfVY?+5dAoaJgCXokNkod58Y;d-P`wIX3mL6$%VNpq2@=MO`^XR_}&rUI=w*5 zG1s}%lGbxo9J{Cj)BbBzQB(HH7RlQiJ05;V_aATD|Jcr_ZYDS0&0q8xuQ-A^c&U2D zNv4V;$XG`ZFCN4inFG4+6iPi5Iy=ZE+i_3PNP5!5f;TF@sgxKT4o;nv?3fe%bjX|0 z>cdY_xAj~h=WZ3Eex*X1${sp7Y|fh#x56j?QxbptRqWr_z0(4=^jsmAZWa1e^mO%* zhO$EC`^@@oc^&q&neq}fSoJK!ep`)Q&lPg*Rw2q)dPrSaA;UVg1-s%j4Xjfxu6n#f zkCVzD9N6&2iR$Hvau0$OOo7#=^t7d=BdB=7~B+M1*shn3yZzqimsohdK!a zVw4^M2LLHisXq6@3pIt+>~l1-m*UUTz?%OhIdJ|Xe{fcQ zXkiGsvF!BapQoHO;#PS*00u$d`8ftmhn-vqprunv_J9Yma`1UbZ#%Jxe-D3vD_Qot zsam@@Ul`_;nD0Bs@WA9u=o@&&$-cdf%b5@xUM8Z6XGgxR8CdLvz4n&I@lGzkw>YwNt^4i;_UuX*L`jm z5f3SDhx=}LUiGhEynkl)%FjLLys}Z7dcliM@2J1%Z+PiD=OSbO_TnWmIN~A2?U))O z@2&n-9lF{dJ>z}gf}uq|d$X?Ac}M(n1aXk!cIZlD?Oz24!eEYoyo@`LDJ(saX^{VL zZd&rflEPHS8)KdGz?@-0sVl_Hi0(Y;gumCq8@SZf`XZMdHHZU8H8l_`!-+ehVK6|N zCw=;pK>p5-NRXuiX_7=H4Q_CfN_pc63SrmSf~gWqY)Sf7t$ySrYrlLS5`VNG>{x~ zBhOuVJgdf(Y%*qSoFx!qW>7HBk3{Dxq*b_2F&Wmd zqjud+Tgob0(V3zS%39cDC{zd+U@QjY`I1nD$d*K}#%G5k6Q?+Z)t2^pnOjZYr`2Cs zWH73vz-1#UYua^t-?n%2rl#3<^ioe;eBMWy8v1~RvoT4ym}ZGlFe--IuxwdW3riad zTdE~y&7_#K$xLgEX-y_sno>NL-czc7Mu|zW=oxqqXx(YrCq67Z-9fl!QgBS;~mXI^bw zr&s+~8Z$ZNd-96p-?LLcL*Z#b=AwoDP-RrOmSQds2cQg*I654sL6a4ri@ewNi_^a}c?PzY>WSKL z$|T$lgHQ0&EEQ~8BdpI;q9*pysTw-3?Uk#QZdKCFVajY=zKADap}xZSB|+KMTe@kVO$mq=PTBu&$20Rti6&_ zY4bDM69SHMc4bE0{$$p6*0F-uzYDT#v5AigNBCXbYMOH8bm~6%e*`5}KUs1lB3x+7 zWOI~~YGRzv*t68OpBRS2_TD77-b)R75i?X-oNN<_z=UE3D2xjAdDaq3%{|9Gr`LFn z_A{MA%cMA5Q>h6uMm$Pvu3-A67<}aDaj#(kT_<|Lrifbp;~76TOeF^?t0=-TAu|jm zk@x}nH@@HT9C}yEL)O=C7DXH#Y5R73ft0} zO18wzZP}eQ@0%Snyx6w!e1*E}uBVfKbx6J2>=>kR6rQOo7D(n8HrDCPZ}Ll1WX{6C z!eUwj|M}Z}Nf)iR`>UbwwMPN;6@G!62Wms1l1Vm}=1z)rD%x{iza}~E=^-J_efp7& z8)omeM^aQpE4mBDLR`qlf!oC*!p*c9Gdx{rY%7cn`U?sP!&w-~0y8%!*_yLLNo*Ti zTQ-havDlUrR471&xJbgor99>s#R|vCmLzK%CYfYmg;|qAt=X2KEx}kUTa0DJw6H*h zVVqEOk%S9&1ckZ>e3tn>+d|FMvpd*YlBC{?QPJ+Jl1eg{hlYzl^efnwPuuG`);L>j zdCr_ge`tjy^?5R!3lE4D4(vi7dN=B3e0+;u$JMn9A6*NJT=M*CXxA1}^wllondQ;* z@U#H!#22%4>*JmwPu$X1sq8uO7E+;aM9uVjj}t2PpB(tOIrLcGj-Y0j#xigQpwL&* z2%$4UO%f~?Ne>i!Fg|RCQ4?^?V8+5D%|tBBd;-V}Ca9Jobg_(9{#zgdQy_B$q6ncN z6c>_kHkU+kCcBU*6dPxBiH>%cJwY)5LRv=~?$t2eXye0JWY|laj|T*76!eH=z{-my zLYxs1j)~aQ&4dj&ezdKK^OmZX-y(Qc2X!;Afm}3fd#}MQ2nE^ zPz<&+Vl147g)zBO6;V`SppG^kF2Z}FfD$X4tE0^f!?=97c);bvTZ9jnDHMnVY_XXW z@QWGDIUa|-*c2$IvrMtN?Y*rHCNij z|Cc(*{U0XwC1>5qnOa!j`gk+x&_IveQx3`r)ESV0(IPR={|#@-#=Mcy9Jx+75ltt$fhx)A3Xot-kfZ-c|Lu& zN+BQ;Jd(@81&Sc}rb4jfWXnsZ2#vj$Y_rs!*^wBxdT1t*UTRk+-HkvupQ z^NE*K>0a|cRdW#duU>ct5wfd!e@xPnU{=!=+erwg<tFQPOm&T?)| zeaPQkJO2ikkJhayxUBJEd35>LoPfl+CnIs5$(<)4)B~l%{@Br6?vQ!tid7V4fxqsN z3;X3xl-6T-5CZhT|Id0-ewxFHDA{%?ExIz(h&s4xN6h&-bJ#B& vAVx4AXz{u~xG?4NIEs~Onh+axO6$JWn(SPioWTyy!v?+2|9GW52@vEz%Vs0w diff --git a/plugins/tpm-eventlog/tests/binary_bios_measurements-v2 b/plugins/tpm-eventlog/tests/binary_bios_measurements-v2 deleted file mode 100644 index 5aacd4197a15cee3c201acbe77bfc98d00411e40..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 40311 zcmeFa2S60dvM{{luw)QH(keMGIU_meobv)JVab9DNJbDPsw9abAW0M@N)i-Qq7noI z5fn)x2nY)NvjmmZbFb&UbMAZp`_91ZY|qwIbyrt)RdpH=2n50a&R-qOz)gJ*m_0;Q z0ix&!bN7J??17>!e7zEk7hXY*pZc=w$B3HhN*LOGK1vT7C@-;XqIRXrt zFSP0q_PpjZ-mH3!}$ zw=zfJhnw)Cyfd`(Dp9C=Xboa<5yqvy+A1N z;CkWrch0%{Cl~XALB8EZ$)zR9wsrPb{8Ejq&y_m|QV0Kr@nen1*vdt@r>>9v zc5Vbz1oY)j?BccAueXWs`t%*|W1YG1qzCz%9$xu^U!5ZSFvoOXf9fsMCyXkH2sR+;l- z^kJi0g*n^?g9B`%zOyR#kKEa!33_efd7tKwL2B=~wkTY|(j&^)a(AYYjQ= z0#gMq`uT<2;*(vipqI%f5(048j!(sQCiRgP6M`nLVQ^kNsJsIu(Fegm_8?!77jTsW zA%H(05ZYnl1FzgaS>Z+8X}e7R;zi%XjW4EXD_{^uIJ)7%exXu4$L zDM;p|O3RP4f^zSF1lW#B{6OQM?N^BoNF9`8+H_+o`KDS_)vY5IoJ(E@zug94x-^YE zzNWp=iujs*MRjn>0vd{u2@OS$$i_fNLq{jk$!Um)d3Uc~hP%`MS)X$bln@(_BT^-D zoe&KTj0J)^@qwXu*cgVG*yQMj`g}xC0%QW00LuX8Z|luR4kbmVaR~7B5WemX5Iuyw z3m+Mj1bGvm08att>IzYHx98zwfYKrFVGvM$y9d#6we@jCc)3B;VF6J3qlA3IP+=$^ zKa?K|6)`(XD8RRu6o5j7&Hi&42}L{cBNNcDKp3HD#2{!W8a{d`8XD*}L|i6%&dG$4 zOo0HhaIaW_`encHXp@_|Nr)C#(FyaNW~vIFwhXqw;jb4xCRuNacGVW&WI_*aDZ>vh z6S)f-`}DD2Us%SE+RuS?jO8T0VssAZL-M-|bf4It`-@asy%hU!2NY*?sWF64;M%J2 zk^XCSVx6ojPOs&+#qeJ-Wj14?$Lb}%t9(9u6Z$&hJsWEvNW4P4OC&~|H`jtG+ylR^m*PfG&POEo(3L2OHf zN~PQPZT^pp2BZyOG#W^6?OwoChgU_8DxA6NsKu#v{%$m%m?3s}Gw3VXJ0+V0y)y!Y ztqjh=-qfO%Wv%&(PRk#OqMSZ>9vgP{EN_&#=YGwUUJsmc<&hpMtt)-s1;MZ@rW}(( z!J9oSqcy`vL@q>)Za~>i>o0GQ@L0dUN3dK~7#k^*MWqdCR1?IWR>Gub%8xK9J~l696Tg`s zog9Zhq#oDmdh}}O@vny)jw-{O@z>W|%Xm7iJFP>+iq`B;egcE+Z!nXqe`%4!x=7?A z7oZ(WN5M^wo|cvu!|&DB$r#@T1)3<-hU1_K$KP+h)Io~BXgZen!3KWabhH3XNAZ5s z!J1yG*JydGQbYK(+^4ycXDF5VpVQbMn+|?KQK0GI7uat)_ytAGpe}z=8^#DdzSo8w z``(5DO&3Jb-`?5Q-3hkaj{UplqbDv?;)X1{hFomPhcrj-41t)5u4Piy)j<2n_=>ml zJ7c4cP;+qH<ykU?w_m_hWhO(8PWmg8h)?x!|g7tmkISMf;1 zEEM)pGqof7RC(hP-^!Z9r4SnI9RK=Ue@Ix8)+gLNC^qqG+HkW#M6oQWvtV;9g-uCs1(dV-l;DX{9z01Sw zkCs-+Jna@V$CiuAwqwoiwh)iie{A?fi+1KgQT|G*kU$Yk@-!Pkb2gUD^5CZsVYJJf zV%7Cuu<>ymcZy_tDXes{M{WlMH19PZj!=i+Xg)wt24s`Mh)D&dJpbzk1Zh?F+7}$0 zPbnnN2hVnoU9+#+mbCH8p7lZz$=&t^5(U9pvtS;SuR<82cPB{czG`}!R-c@EF}Ks| zV`CuZ7!j!}Rn#j-O*a@DlXq?n!?4;DZ8^?ridXVvt8ZvVW9}Ergiq0Dtg%lIkNPQ_ zmCu_;or5<$o}~TCO_W(BrzooH0lHFpO>NA3Hbl2v`3z5Zxz}@{sW{OH~UI=f5qYp$L;pKtwvh{%jPe?$;b~TQi|Chf*44mOWV5MX0 z|1EjufU@o7 z`S`E%tgfgIk(Y(=L;3gspWKBItci9`5OZQ6(9Z3XeX z+uVF`%^Nd&{&S>9wTa$)@o$KA|{e%I$*ON_{g(Xnhag`NpoivA= zy1|blv@b&XYGVGExdo$^-2Gfoj6#&W|Dbp8*AhFLyB9ZlZ+SQJnrYyY0j5T zXKYfo3^qS`KJ$=wI(3mL7GpkcId-;H?Tb7q891m)Inj0WE#`%}RRPR75;P9a>5VXQ z$sJ}qUS~h0om%Y&qotl4CdFTf`U0e;(qR%$**UVldYR_Vl_h>y6Cyv~jy^wS{WR0> z*$4Z?=JEiU@PMe`H+qFLnP+j}myhf<7NKa`0H@ReuM&?F8x0dJROAR6;BlaVe()~r zzREw#md=0TMAm0MY*=#k>Ae_hDD}4oD9|wp=OMMpjP*Fh$vjRRWO84YnI#7~?mgjyhO*z2wX-!N)t!BO zJj8i)`@N-sSc1LOA%^`*`yLVgblFAi99u0zwPOsx=@CP;THK zD#QbTLT#{dfr4UT;h>>m8bI}+ItOVedZfZWq0^^N|B4XI>o+L)pr|iKD8S6;;nAxU z$yDf_9Fku+5@`trvwJ_z=s6ZH=2rQhi3b&P=lhw>2HdX^Ii-7+#9{5V!!o+lgY`lh z|AyMGXcGs50prKidDd71Bkeu#E){kD`*W6k(AB2Z>RNxCJkIU(5kaHy`OwZXS!Rz6 zm-pN8#DiBDrr#wqRB{l+sqe6{lbl^2Ja?nluLkRJzyfi6Vn)mMI3mcE`0Vp$#W6wM zD`LdcRz^cqSXVyb6v*AlKD~uYz3gf9G%J!ZKk7-rmPycaxYLn@ppfNY@@c}@7|E#c zxi?)6^3$c<;YpWHahjb|*wiZydCW~)H=#EUBK@2u)ofGoTA(T~x)(-`f9ze!x%}qP zC@s<3yo7BOQHZTLo_eu+@7}gfOg&=_|Bx*Afju@}Nme3+#%X9n-W2wPuzm}asQt-T z;${)kR~=cIfC+AG{8Oxc?s^MX;AhK;*Q2m{6kAI5DMA>&KrxF&gl%7{!D$4CoEHYr zyIqqB`nz3E1eD%hs>jGxvMG9q({eoYht2Po#0du*Pw3fM))lqHlY1XQ)G9yH@ z-Xv_s1YB!{6W!0Fg_42TRF|C_b_Q#wN!w)R#SI;&BPk4NQJNTt#v9)g$Xg4}QUn)j6>>u0

5y*bf4$P?~a>aJj!5lMf_ z(ZN8epQ7iLV0K|DRh3f8Y_Qp#iM!{g;@I;@MJNSpKR5DbzOv{S@#7Zo$y@1Q!NHa@ zOCO=DDE^54uDHjvv$kQ{g4r?Qau4b7iQbRhlnvK)jqXehy2@1)kHQ!7ES~As5Z-QV zA3=Y+s;3gA%P^6%e!>59)1&jGIc5PFk_)7#D6&^NeGA>UZtH#`+seq7fbW?Pp#41T zYXU9)kACF^0wTpgaew-nqd{gpMyGCip0u9(!Lrx~-z-{J@Vtxt3X9ax!*fe^%peLy z=yv_eW2a{~)6X+expm;K#+!mNf|}n`V$3XNr4GF>?KJqfgHBH)Nij5BY$`P4GL5sD zLVxwL8JR678lmHQwC+8^%SKwwA1Jj#)1Hw$y>02D*M=U2&r+m4pR{7_c~6WX_i5CV z`SIuz>k{c68e+YV#;gfmJ~Z{al>d%TUorZ;Ys=SZKeULzj4s;HXU2ig#&3+7hUxhv zzEV|F?YzsI90!S=UQM)jS(!kSu5zh(eCqD!DOS9|h}dkrs!}R`eaZ2((9x-+lycsp zOsZn&vj;BrGZw5O^1;1*)HE!#nzQ~m(+H-44x5{>^%M8$*=cE}pXH^ z*^2#609B{o?CbQSU+eT8K&R99b^3&fCPTzo!+MR^Z}_dl-FeEfXCzYw6; zyE?s_-y@w zsyI3>!O8=S5hi@rgkk5%ogD)Hgt-z`vGTGFmf2b))V*Nt-T?-yW;Yq z>0KLMqJ;ql2fcCZQSYJ<>*t1HV8V*b)HG6`QJ#oYGYX0Ko+&i7+GrFE!=Z2sr=T<+ z;?L=XR-~_{Dn-K-brPP6wi`a_Ylws}kJ>|nmd&-=2dd6DvA-tBk(h2jBVp=Fd% zscJ0I66}PQHJ613(bF`ky`{CHjQfQPXYu@res1!UvNtL`3viEgm6BO+{3R+rrn%m_ z+7)DWIy~UWt=6*`3@#)MC^ERK;y68{@XTVy%T7$6Zg=}-s`e7h7x&}m2f6nahv~!I z(M+rgUoH*4TbK3A{`^HfYwN}+WuFcGeJ4?6@VNXIJzm-6E!!A~_M20};&P77Hke1x z7fUuP7$?MAbYsvGRW+mUeo{t!w{X{jT*-Y>T;)e@ZP*@TfYLY2OV#K z3kZBD#e8CLei1vYt_>1CyxtePB3f}Pzm)r&T>#e38?}>|LJ*HP58t^=WHbr;zK`J> zi}RQs6{+%3y2552Wy8qTII4WZXHc}vnkd@snhr)hM4?hb zv-=fE+5RVaCoR!WY0kqLnAt3Zcedn@;3rQ|-|Zf6A)9P5XI*6VhsK(7;JKW*pl?IT z)#Oa4Upue5l4*M}!Wqw7!7?z{fO9Nh{YbZvr7JC`MOS?WV=ThGie*@syj6REwXB9; zLN<}>^`mE}XNnE9)-Ax8QLwx6RE3ojZq%pe&6qY-Fb<+dd7$+?`7fi!B6f7KOOy|< z`ag@`xUQY{`kZ08{$CR{zF0GQa(O1#!p^x@DmmVKuq%z~A=C({W*}@QFJAlu+`o(zDZZZb z)V&eV;$HbdOuAlDkJz2_Bni3qcA;~RN`ate%oQw_MLwl?+kk-`Q65E?PfgQo)i3ET z$Bf_&9($yLFYI{g;yleDW_%&l(fst9Nf~}&zlY6c?Tu5IO|z8!C9TdM>`KNATy>x( z1#{=NlW%HW`ZRwo(%ZO2@3^<1*-BoF(PPY)ICu-6W8ZXr3c6Ibv<8mB{c^H{&MR2I zdhUV!#2YC-SVhS6a>+Bw{4A-$+vzQGJ@Mhz26Q_YW^3t`;}I3!TC!O(S=Q4z9F?RA z-Z977mbzYfi&;zGvap#S#~>-}$9w;2?MlSGVBKg(W$L)x3Non>4ri>>bqN}FXYV!R zJgPktC5SZI26S@Fh7ND7B(klXW%giSc=aKoMs5>3lm{(;!qc zAhT}K2=PxY>b6zm@|LfMdgk~&-&xq zX))(^6i&un=C5Q?Df6vb?9iZBqYj!1O{4Qatw~VPutwZZ*v)a38)HJz0?`N>6Rd7VvE%feC{t!T#KQ3{@2)y|5th%g>dC|pijHj z{Rm1)oK1w-mH7Qw&wU`1WtF2*D|QPJRWT(uTzPLISU?F5Ew(HTeR)1i7W?vDx@C-- zm1CAPA9dn4?ihy4vC%>rD$8^!+L}tPrW~h@A0hsF`g)3YLUd4K6o4s;}XcQsrde|9a{;Ts!@7keuLGVeF%^mmxAu zchZ=BS)X-a7^Q?QxYpJYmEHdI6*KrL2&Lv{CCFiKBL_>bxoKvBvB=eX_^A}17 zG0UC|$(Uw`_oisrC7d|sLw8Y1nMk2vsv=!b==SD4{X(vg`Ft$T$C=f&Gc*d0Q_2QJ zmyCk%WKmwLjO=lij%TdmwYsbm5!W6UYAu`diHC3^wa?Xe>K?r6c;qHd@7knh@5@rI z)B5zx{34HB^}JFdD?SR@o}yl@lnBu=D&Xhd&b_c97s*Oxm=oG*mi`%f&48jn`3f`d zW0on|18;{eB$=-*>@P&9C_>X@k*^A!U5_FZ-|6g?Jzu# z6nyAm&CWIzvH2{TTs`6M@wrwbGAem(q6}Se5!P}qF9=TQi<6kXT2OBqW^%Zv@%ml5 z9QkKLJl(Qoi2V33CtqAM)C7Z;8dckK`(JzD1T#2BS-RF#7K=h`I@_A=DLR5{%$rO! zkNn)zxZmLbVg-If9>|_X|DXCA)Ay}a@cwlVcJC7!itPdo#neBrRs^T0cYpZVTK(?| zT7U^Nz{nO<5W3f6A+(niLMEXBe~XPe=pZFO_T5H(i&^$;6ZGG9UNi;NiQir#4zDhC z;P9pN?y19BlP1ihn7Wv|q$Ty)8|s2j^u0?Qq95b1XAZtC^CLawj!PuZJUe_0{aw0(*n#5d=P-=lez zcq>>`>21s-Z@8Z!{EEiZ(30R>?QMoG_MnH_ndC=qk<)mY*crLTgycD#zNQ3Y&kUou zp@EwnHps}ZVm*%F>V8Q%MC66ZHsm7xnf&&-+@k^7L8IbRnI5bzjU!*_AK?r&Jpd=s zvrTxr^%=Zp(`apVF(aUFA&-UHk82H@2AzYJ7* zwTohKaJxP+QC*t`?W_z0(23OlHAd(EOrR2yiHxowm?0_9kVI(6(ROZ{`=ukm=eh3{%1DNgS1hNIW zf~-M0z??r<5FD5V7yzX7f%$*7zzGAn0jE3gjR!)9;_vPbx$(#rL{?!Vmd;0PN^~B5 z-?2F*){^Ye>X6(zWK>3QM{}X?{eLC|e2QXk#VF<+KgJ#~L&lUAxzNMYFB7tgV=aJfU@23ze%o$KQ)S&< zR#}g>j;6&}yfD=$>3RDrmO>lf$hvvEf+adk#c}DI;l1VxjP}gJrx9i5qbFWaFrJbP z?vX1P`M`V@^G)9s5j*Vi&osoB?uez;U04;up3XOKy?9;3TE90>WGi2LhK9(+Z>suo zMa%4#?>d+4{fxZV^jOC`uv60n$eU>Rvu$5c6QUH-e~P4$g+p^ zkc(FyMD^=w0?W2XuhEG`+@mbs(AH+aNOtIJQhQ zG;oVvU>p4%i<_8WAj%51Tb~5@kw?WH*G9 zC~?VBOsf*MGjzdH=)Ya~S9N+_VG?$xHt*L&+$DRZ&VMpKp{5tfCI3ct!5mbaPl zWgwB*i;Zby3PVw_&pZN$$weY1u*99F>kKM<+wf3M zNj=f{%rtQp6@Gx_ND$pA&)8R>or+2Utim;)Q0G}x?Jt@NV8_t?*~tp(NU ze{|q(4BQcD&*K=2%(5ZhrsUz`|M+Cu4HcffeNOMLqC2-~+sqDj>U}a_Im*Q3MNdpxg$7&WE>w-aS zwoT>s0?A8B$fND_qtDP?l4lCSs!8=ke}aG8UTETgxc#9$0Ari&HYFMZqtkZc+XtM& zsn>VJdak3w5}2j``5UU^@K2Q-NT5Cdy|FmO7zz=O^0Q$pu&UeH`D)H?-oo4f6P8bJ+?$Kfw)a7WC!k6a^W$C-z9rRzoo_$xX(rZP@hMTs!iLDz zWw7DGMO1h~!UvrQ_W5jtz_CEDsc3aFyx==3*Tgv}vIkFUlTZ-<1mCgpCH2a2mDbKM zVSe8@>E~bLz#yC&bH2BFmpPu9e?^5SL6ppP&u?i#C44@e&pv-`vgbT!65`S$pRVI8 zl#$LEsPIR%#KGqB?FBe>{W98Eg7i||Vs=hl$)Br;co>UbCK8~+Qwa#N?_k+2WL?FO zCRG_-oaTPOqv~crQq?{1*rBiYr~GrKcC*OwByI~^H>$T1vf{d4f31E7v7_*X*Ciee zo+^flpR(!5}YCn*1dHZZc;JaBBt}GGH&PRDPpWF?62X} zE&mA~>d3Zfa2jgNR;#8I_^wCvjKM0r-!H4n%6I-kU)+%-RQ$rY3$?4I#IpGmIj7Gw z@|IgUVF)@|wWeCZg+i|r6!)RRi^}#L7mhm;HfVv5{`RXPK6i2I8QHrYucvo; ze`;@CqYaefUYJfM=~lBexmGuR;7l$R5*3Q_>P`C0)7wdkiXTD2w&U3`LiD1Xf#+=F zlUokwT3}{Y`&*&HdoIT#`c9|@8RRM1-D0}>^)U(LH1R6A^ZPf$jZe1h zeNo}PT%_+AV4i}me3nYT(uJ|+@xBnd*CPhQ^DXzoOfJUepWr7NsGPbjGmUN?i5Zs| zs}F7DFB~eSyJ*Ghww%m1FoX*4&sv@;%(c1X8CW`XyKzE3rq{FCY^+7)zWL|QeD%sU zRQQm>8dzO;f0RoydyzrN(-eKG?qUkEA>7A#5?ca0OH-)up(7Gqch_*`yE3n~_C`HR zH}tf?(N4Oc=i1FV%3#lxk0(U!hIcZbicgLwQc9Jh z!p97#n0`#DT8%3&P6nT{bt)M+6YYLkDaqle*YP$}#Tr!j*iV9YuY;bhA3@K37LN;i zf;KN9l`SdsK*xIg>uT_$e74R!hFde+t2T4d z^9%Dk>2^xHnPZ zZ?5p_#A#J*m!{zcZD{q@;?G;YUH^bsD&S0dFm9{y zXK*iIWnfr;e4*}EB|%!_=jc4VVaRk2J(f*mFk5376}~>Iz&;;6lM_0p8Bb^ZC|ME&(+cYb@}PWSJE#% zA~sP`CVh4h3uKPzqwa2KsQKCMuH^6KNmX}KvE=e}@`|~kXBu8=Q9$oYd4d5ajp8Ty z={!njs}>hTMw^s;v1i+`KQ&~d_gIlTh9bVK9&1axIVyg`nsmZxsrqddv!X{L-6!u+ zevnGotV%6DcZ+)ArhQc{D*Wj&YT`V?=p8Ewv}5>h>Fx0R3CO|vR!^edE=9+HU3gL9 zA4}dAJ5idtYU88iJ0|ipd9>7w;Yooq@1h{7=djpJI4ZmZdX&C2L2J+au|mctOGUE9 zLtaM$dLO2q=k9GS5Uwslg-=Rb{It5MJ1HR3x;z!H(iQEccWP^0ul43i-g14GjVda< zgR%KAnSUA&MXAx6AcJ1H%V&ZO1(3g~@B1Y!ZihidRCvWlkIQ`VyX#cGis%J8kc~NL zmJKCHK8s=M(2RgPjbB1`$|6_i?ya4Thj;qFQ^aS}^_HiR)@y6gOP%rtgT_zVUc)Tn z9g#7n=6)zOs4{yxW>l|U_2LW`QxiosDfPkXUS!WI!8cr#)FB&;WU$_k4;huab##Nm z@B=KtAlppis@UM=II@@9PWH!|vEE?UbreU4$e5;}u|_BnIYNNvcPB^5BitR~PQH69 z0)WMY$Q6UTs{hv}^Plx2p{=FarB=QM9U4e^yX&D#cpw5qXgX^)?*vak2!e%#~R zJuq~Q_RSouwEBv$JU^EQ?VqP}BVV|Djpp+6XX0%=qh)V9ZKyi;W z7xE@>VB%1KI4gXUY&484HE0bBQaw+LU}95%SUQh|&ax+|hGm%sHy!tg3*N!peGriG z{XCuQZ}t)kqP9LItAf8Ih<|MuPhkKIYJz#_ceDtwC06<`HscYLxCpermwVNSkqX5p zEwuJz5C>?YF0TXXZTC1>fqk$LSQ}Ut>;QBFdV#QZ^$S=$3BY~NK}mrMjn@2G17p3W zEBXD**|~4v_rRc|=#BlV8kBGIJ=uEtO@`bYe1+B*38D=!Y#;Rs%1;s%060){a6s8_ zFC*WUB11vQKcQW^cDoB8e0Mt~eE~R3G>$!19y|<^*?l??G&kLF=ZxH?9AkUe64yKE z=$M#-APZp0pb|(GxFVNP9AL2kd4rsR&QCXButgXo2;u=s>jA!N)X=dKHbQele6*(I< za_x)60l)W3E4W)KACNJS4|jn72+(ODmymBffq*oDE?RfsblR<(KgS8BA2^}8+wJQG zQ1Av$N1(IU;u{qUfJ=MJ!QB8ljzAs`^Tt?JOF`RMe>bnlg;oB*DF-Z1Q2=QJS2cj! z@*o3{6zD8SY*&VCL81VM`GIa`ZlFHxfqM?XH$k8TB0vpu1EsMC{`i1zjvxU5&JOq# z1pXX=Qv|>v1Pa`(T_nqp>+q5K`Ewn;n2v80_pmfRrkC4Br0wog!;E^)U50sb> z_!9t9g1~Q3pxh834QL!10jNh7V|Vc@8X7hTlMeX_v`i&kn;W zfEIF7sozplVr2fxVqHor{HCP5-VF2bSdL<`l*-MC=Twsbjz8jjCGZ>aILO_ecJS?% z*bW%NKx&8YE>D$!?_Piop9Z7|xsd?`s22}Fa`px?yZ{`3hBN=Qw!&gpM|^kbqP8VS zP66kByNxIJm45YJbDeErZ_xwpt2ft%rX0W^D<9bOb$aVJ8F_9NDe-EeNp<8zj3dI# z=NvX+N2!;sWdI!V15xw&b5-g&(#ZZJ zbzYBjf+rCiWs~ihMgp~L01kOuS65(NBm}u-g{+5%D{?|Aa+ar~7s3s)yK9WL2l560 zx~r#vlmOTNo?nJ62{QkG1+G0De+@3=!2Ms9FC?D73Kvo~{wiF^w&t(Gh4j@YKnF4y zYvLH80S?U^cFGz42+B(&lx0l>gEZAHarux-G&CKfoLwHNdf{6>C%if|-ffdMAs>I8 z=e-J$p+8!xg`CKTJdhJ8P~!+-io`z?`jFG}{=_ooe>LX{kU6S$hDb1`dJf$~SD{v6*9^D;cLB=05AP1Dx8z`eaKxHo~u>CE1 zKjJ`sFPCa34h#2Ez7!w@A5spSa?DdRr*xOsh`#9`*U;0k2_o5}yFvet-zLM8KJF;Z&G@FdEMuzb6`@J) zRRKof+@WFs2bE36Zl4sy3Rv_0!x6Lp{qKl3|7%gz;Sw`YF}=&o3+8$~dCgTR=`$|G z=g2A;1Zz0|+KyQzaZI}-wo!d*SU4hG{B!mE?8?b3U!^bDZ`pq+;U9jr0Vd0OP=jy| zyQfr^_o&Y(++Kdic8yihso`!0ATcT)0} z(wx0&pCgcKom-YRN)sUYTlb`fNXB9rkp)2>qWfR;_q&~d8M}hO8WY;RS-W_k8d;`n zDy~E)lqq+Im+vXd@lovVSO#on2UhiVg+UOGz#cN+cc~%3Q9$@QxdNNq9fcl2I(+y9 zMDn)o2zMY-bA@R5IPmZR^KEw*Y7lT9{sF+_?E~}r^-{y#RffA;((nPRjD`4sRVBMS z)Bvg7fmf0?38kID>dgZk;7R0S#M_kh6rh-e_9T)q>mVxyt zsr#^@l$gPsjKuA_$q2!K&h@j6wPzlaa8n1CnsygFf3HRSvP^GQ<9d8odn%!p6U^Uo zqxXfVn%bGmNg2V%@*+mMHe=UYa*uPT8^{Wg7?a1j*0W>ls0GcY7CGOPc!Wd4e?6Nz ziYTDYIh8voNpE^>t|NVebD`QpBafWe%77^e6^Dvu3ug;P^8YY@)&4*vcQ>2yhS>vK%yQcS3thS0c7>4J-gbA5 z;Ng88cb7At3|#ZOaVP99=b0Wiy<-?*56N!oWGE*-ZAv~J+E-?LClzy*U%cIr4rhd{ z$Y^uuxgTV1s#SL+%_1Z5B$fBeGx+oqXe3B{F^<;0 z4M9Jj?4hA_Ke)DNbTtJ z7MoZ!@>h?s;TKLgbTr9YnV3p25pq(JB&Vuh#RuZy1#^V^OC7L5kewGPg}V$u z4r=|tV;g9xwXSyls9x&;?1ReWQr3IrQ(#axA;Y+pgVc-(6}VaZ)oY<-En5r7_>NHz zYyU@U0L~-Pm zvR#}V0~o~rHP~{d>BcCSKIk4^C*RGWJIaP)uZPbl%8%yMRJt0o{sv7)?_ZGH0riDY zh+X`ct;e67JRsgRcX>Gt=tK8Ih!&}`Zl|AZp21rZmOg!nq8)7pv^mRqjK{bCt32m# zkhAv+@bE$Wf~4bpmi7VlX1xC7m=v~E^x5R3OTbQ%N}r?Kc!g^>?s41H$6?Ez;!`U% zBmR6!-mZw2nJi~K1L$*!6=^lTVV<$FiPj-fFvDnhzC3t@6^)re1E6E?bwD8p76|tmBV#O46D|?z#P4j_r2`cpc$@3I1hH zzNye*DH5P4ePv95Ry32IdF@`Je{N#xyHH>TW<9I$VDvq4Vu{NaYv7rZ?esXsca$VC z7!^N0%4^JBqyMAwexq`@fVw@!ZzfIBI6he5zbkvU>C@(fHwgwg4vZhaL}zFAq@vLL z6-C_J@)hi$dE4!-x40h~*aH~5c@7oO9K!AW$3=s=`#~&Gq_r~WfnmgDzN_gDW^xKu zR_>c4nq^=RkDTCR-LYleik%LjMYk4L5%kxhoa!fZL&ME9@C29QBfd`Ycz z(rfe0Hsx#RT*OzZDtT{Fz`-CQ@uL$DFUbvNX&&)=w;t6&%9ui80>f%$p^!*ti5-JM z4i(KC<^yrI^@CX>*$0r2^6~P8q0mv3T6CS^93m=AAHp?eD!UrKLren(eXhwmeN8NW z=DdnS=c|Mj+p2pu1TA5_b7i0XOJWuJf{?pKeU}kegsp=$vIvJ|;6K8ryYJIw`o>1b zoo9;WuTza#)jrwj0E7B!*u&nQ+DW~}J6&!#vB4VH^f@Y3@by^`MG%9m(b4ON^KTA; zNJ034dOj>&Shb3rOW@#WEVetA=1h>$X&7_H35;OJ*O%mTfkt z&vHS$&(PAXh;se{HQ!IDJqa2a&!sis&=%3kV)Cni9z3e}0tR)3FxAr#*ArAdQx>?G z{piK2f?Gh6yMj1`?#k`Nn+-7JF52I@4&)j&$G$QN5Jk?qMd+=`3*}d(pAAlYZ~=qF zNiWDWviO1mSA;L#dv3Api{Ouw_IJVC_(Cn|Rk%FRdWVOO+I)n10 z)9v&y#Dn)U`B6C;V_=Y?voOPb6B@pJZU?g}K`3v{x?E|o$o;L?ddDr{lcryggEv2B z+dlwcH}HX)`vyI{X#zYL@z>RsUXIuq)*$)wj9?Jn$3V?5>Q_J7DcN%!zg=>ixx<1Y zI(2axJFAXHP}q_*A zfwv1SbU}9VDqvQZ>O=^xO9X_X2cl1CBw6vl;M6;hqwMlkr{9exGQ^7c5Gj~HuoI>a zOeUgQ;;GIhycS$u>mPuD$j*i@wVLX!4=h=b)dm^dh_|Y+g%D3M?!8K zwoPrDaYp+0tyKnh=(4Ns3xiw^mk6nQPLBR=0KcSceSHupBrZ>1cO00f4u>cQGp#4Q zXaA`GS^*65W4Sf-z(=lS+E-XjI^~JDgubLnd0jqwU&F2O&z9_ukn3#^GtJr$?f^qY z{`ZQLX;;5|h0XnOgUz$Kx*wtfWNhfCz@R~L{Z-*hmCbBe@rfa9SJQ{x3rFZLhNzzO z_ZOA$yCrd$J8*YzfHM$aX!e%{Xbqm~QoB<8R3fNDAR8(*PP^Ro6lktZOxf$3SNW=? zM{v&IMHrbZ<6Rt!f9&=|$JI0MD2*0!3GsLC?2`cM0O?ktu%ExY#L&rBQDckJA+Xz` zjpZsPVL2FNN@MqG_F{)dVAB&cTz(Dx!FLy!(^FWKz)26YCS+^rg$@xw*03uA=%avH zJHWku>5ud7{fONGvRMv2w8wZ zC0?s*jL*ID7(9+}a*W;~nW%2|y1K*6j+>sBD?)LL_b`D2_Q8C7VE(9~j3}+1(|JaD zyI^~`xBDfsEs@6&dBB@bq#kE05Xrl+T+sUR5R2F6!HK48^O&-V*(M&AnLS)I$lm1d z^>g6tS|faYJbZVRkeB$WF`B+-CzKRti62#Twzkqa0dsNJ4$s& zI37{CajR2*-29P;gTPac>8#dGARs}jtG5^tyTN?3b0*o$SGL*O?7Y*)7vbXm&AL&0 z>(;~7{R1f}K2%?U&=}X?f|*&yq-A@H4h!o=?ql{&z{`8iy-eAPNVw2L`KaY7Mop8E z*EPipQ|GVKb-jfRuy+R{_fJ92WVtJG;{xDSli4%kcD1*K5W zZ%~#s*LQBW8$gCHKVcHjhYg8v|I4k(h77xG;ldnJa5h;i`?aft|X zp>mhInY^uH)6-FW1R{{T}Y#Y2m{Ny_CC& zg{j8%b^1d`uT|!pc{Ot4|ZOB7Q6)_tKp|PW>O02xf zK0-7P2Cehi)@3AEu(5@UFvP;Viv3hnudbm_>V1?*rynpN%@#qy&HYD#sH6XG4Y|U- zeRzEQeSUH;3BY|NAwKs!{Mxnzzg%3g|8NWkn1OtT&6Jwuj&{JySJa}`Ctr}*QM3rj zD81jVbS5X{tb9;|oK5<@XwIjB+0FLOe-JOC=0E_2xh~yBwOP}p9VrwX{W$85GTco! z3&5Z}w~2sD6(z|73oA}O83YS97UqeA>S27m$>dCetE$svhjL&J_|DLu%I19a4C}C@ z6`SySo2H%S^UI4(YryQ?Wz~1KH{bY@d@fl{kZV4wpdp@9Z|0fyZuTCbgeM*q{^7QD z*E+!6ef_Ng^Jl&5gSfz89w=qVTwK~z&@vs&zGQ37Y!}V)ZhLG43_39(%S>OTHOKG4 zWNcb29ov8Zj6+~e^u3VVvtQvh#fp$aW!U$eff-gm5JRC8IA9a0hVSUsbYE*pcIfiB zbW07egfodocy(u8tdNtC)9%Ka-ThHekj#S>Ipqf!trY_gozshfe!}my_02Vh81DA> zLAbf?fguBL$X@r~x1^K1FZXU{e!TPTJFvMhGJ=2rP`g0f-f%Y$R~Ywib?KeO$Mb^O zBfK0OZQ-u?c)OAEuJ?tHx9{jdm=5y+AMe15o`EBPgd@Zp;?J~OC}8{iy;t%8;gdhi z9bzc~@o@&O`w#d74@ev&T+bjpkV!}QH-sL*PW;wDALzFmfQ{z=M!^wg>jU&oTOSay z-s{1%2Hp?gvmdYRk;BJ>?DuX0d~ru`JGvq~JOY64j^5n6eVyFgfG9~JJ2N4_)$fUq z2Xpm?{TZ~s!+Lx?WYKqdi?`R=>F0(_o#7VZ5#RwfbQj}xg1N)I;P$)yu2P1EstQuS zgBSpZKsS{5hWj`} zG?3a1LFFy$H#PdRI>+>l(DzUt!um}KQ3-MXse-UV0L46{nTJ&Kk9G5~a{eXSd4Te} zdLG=_)6WAUe?me3dJWxI(LaIscT@?e1EiAT!R(z8c&r*gJdd1o`)f&p@bK`k0k#00e24+5dA&bwKyG zT8Dq9REO-^fmHvu4BLUC{G&Smld5wdBoKE5Qaq7<-ML#;jRJC4w{N5G^~_g&rZD>l^C{s%j;dpLX1Ow@)X*SqeS0( zpATLNu)C!Nu)fOH30N4#25fY}>j3lPb@y|F0q<1w;A8(bigSAZ&1VNAsRx6j2yfsG z%62d>X$v%7xe+iMkgk(}EdUUYMEJk0}?{-<%hHZnX;%n(M6Vp;d~<}0_f z600ZB!5~_ruxs5sYMHCizIB6{I};}JiVwg(y1Yfyx!Zwv3-FE~8Zk%qsUDuxgRDc; z0mK4((~0qh!FTvi``V^>2nSxc19K|FQpFdX#IKWGvJ4k735h6kD=iQz?xwxX=x%;w zN$c%{!_x!JA$-tZ&M>gRzw!Yy<3pi3Cw>B0IGhPoJ_^h*7}Lh%#`^yz@@W5}roR;( zdI>^5U&Vx7*&G`e8f_pJ>^*mC>Jp69s&f8+ibrK9WK1wWQUX=d% z+v=5?`irCz9^KmL7qH^63Fwd^#55^z&3_v9H5|#M#U=Ts~@0fdS)nO}9 zy{EIv7D?T#ZuS8#Pv*$Ea%nNo9FFEM{Vso8!hCLhZH$oIIN_rD=C!A`E%W{fIw1|k z;wr2bE9fSY<0kRrS*fpYWi1xC#UizO&ovM054^x_CHrFqmZTl{ULi4)YcBtt6Tfs^ z6L(FTs2jg$uGhiGQVhRQmsJ9T8JIZ}bBm!9#AvB%#)Y&W|1Y@hI&HC$O`>OC{mZq> zHMtp<*0I%TnX+GREo!O)m6DJp5NL+)I#|&9 z?<VMtT)b#@VQz)#ro>J$m)-I8sgGKL#c`F= z&+K(>wI4oZmOj{DCUR}3=41nz)LqY3#H1QLN!X9Rq(`?3b1na*xM#C#x{ge)+2?-s zL~!7Z%q=gj1Gfn19AYou)oXn`I!!V8@ao3}CcfV5#IMJ1-RsaRziroj&<+|zaw`UH z{s3)ZL4*%l=!`BY#HWjO2PZ-&p#cUd^yq1{>aJKGZt;Vkbed(ih(r)(29b@N>Ke|i^Y~8 z$F295wpDhr$1f2!zFR+vDCG^rsGqNOm9KW z&`49!Xr}AFaJ}(?u5^YE7boT3zv&LqM2pgcEjN+zf#W-v79_%u908KU1E)YrQ-yx#tGyhcmXZ zr++-w&X{Q!j*?m-E7ySS3IeOsh*_e7=6T(NrHp)T(xz{8+KdW6h_O^{KM7nmz3lff z{kNrSZC)(-WT5n6H4|sNYDlX8@( zIb1QC^y};KH;-1Pm`r>wnOFwgzG&Kdwz9N#k#G5<-(2qv-Lm#B=rQ1@{jy0^shjV90aE$MM_G&> zWr2Ry#pqEM19y}K>gM8=+uSQTKKlwRf+w4t(p#2VzIt-spp!3q$;kAm3Rd#jL_Vr=@dX_dfuP*M`4m<{o zo8bnFZFY6*TGPJG+ty{ZTWx=@yeK*7=pFx6QSWY@kJ};*+U)OIky!#cD>gW_s4O!% zwHSClei?A@AL!s%R7>1LUGJW(xW4~_*{?HodNb-hBSOdwoOP|&DY$9AYe5fUVtNYELQz!{i8G~5)GAP_;hq%Z@)8-tT5 zr{nm>)>>*?#i!bOt5R#jMa2X#0jn+G4ZH@taK=GJsoYfZ{eFAzGdI9K-}CnS>w5-f z&e^xM*IIk6wbx#IpOea~o3t!V(;WDAc52#MT={W}-yi-7qPX`t>w9a@b$jjHwHdzG z&YduO&LU^s!UZ=hoIcMvWBUC03;fROXE_%J<~!%icb1Q@cFtQcbJpNqy}G*;=&A}$ zn|WtfnR->z#$;&PeyvMpkIc*;YqulYP!-*{@@s!`ag%8$lCA{+0AkvIl%aJ`%Ko8S zg8Fx#x^Fb?Fafq`|82Pc4rX%sVE?RoKQnH_*Nrb}=b$8goLW`Q;Dxj1E|{TkXh9)) za7R)l+`6^gk%MPW_fN-t{)PD2hVNi}8}Lo~xV4&=!84c6pFVHS3^&-OY4{<$XOk-7 z)~&f)*e~JL^~O&w>XB*B;hXe9J@=4dG9wR{I*b9~)oo6ygj?2Qzl)a6(+moq6ZJ^z zmgDQC=KOE!Kg|Inv@hq1D~-sA121)U8j+%XFKOCUS6^|ZRd%bUO}ox|594WsHs@@b zXqca%a)A-a&RdPVa8-^G)(o@4GR%qljrNKTqK4~E45rpzL7CG~`S}-E8UO1HBXZkL zBU1T>5kVvLYeXh?T!|Z}*F54iw;1L|Bhu@p{{utx7P>3|?88PF-^P~u?zrhNLWeW_ zHGp}84bu&n0SPk|-dBVd>37dF#G%&^!rYb)bCC@*Fy|%WY{mL%T5P(!{}A`#ifxT8 zf$^Y)#S-J}zu%*2Rls4>vCdAf+3JgAA3@H#K9F;C7(h?p;{CV?IKrG-4*(c?&y6{n zVi`?aH?1RYV%f$@Bct629m~3Xu--g6Q*WM})w(CA+csmyHlyUNTV2M$w~UPKdh_X_ zJRRuh59eKN9vk&#u$-JqaYdqI_uJcUWB-uWaY=1@ecq~GQMMKyl20~%@ z6Z9Bsm9;-+?KfrZZL)SoYVB`MMeScEv(ago-+Ik&jP`OD&6$QPAfhMS_0<}3Qj{Evh_Yx@`Z0jad@UH&l~#g68%o#p?OjJJ4kb}e&-sITs91a z7wPxxMyfL6cfIN}KegWa9zzV-?_F8)uUor$OWO1X2MK_rdnQ$RCdh$$l8moGI}FsJ zyLl;EyE26h{Xv)*>9u4HK0&6E*~tO#K?aRMDd0RK;nbzVdE*om#$m+P%l<{X@v_|# z*{(RX-S1M{-Qk&V<1pFwa`rh{wjD0pe)sDX+-uktgP-U(dO0M&(!4FN(wvnW2G>1i zMUG*9Xgzxq7;9FL^ZxE@0aT0j6-x4;hIuLad1{Ye^dXhq*dCmU zZikvzLk^7avOH^u8)f0))_J_5%X4s@DlB8N*c5wBsAk|XBbo6n%Xl#>T3{)+ zyre;NtW!=WvYRO-4QFClJR8s(t>;=!giwx#HEfBy%C%GwU!9-fY3a zEZL+tJSimGeFzEvI-~L3`cq(RTR`32P;G1P5Qui6nvwDtmtnG^3LFs}%OU zrlau?Z@40_-CaP98gC9dR2f;E5gh@PeCC(dt5Do%0TRaZwj5P9e(pbwWvfvZ>xr4? zF`ro=%v)vS$Nn55ynO_5$80uhXIwe2-IRb4dlTdk#$3Y45{bRmZ$+yQt+IfoagI)w z#2T-843ZdZuW0%4)N%LMwpVPvY9@Z$cJwjU-czEj+B#?9a0up>_KMZ_&Y#>3MbBM6 z55LW*U{VbJZ16HY*?V2!&fmc3`3vGfM$E-^&~R z5jADv`C!@wP{8*fdh1#Q%znlS!QXYiOyTdm-l%%DwAvrAcAKnyrmP)iZR9A)xg53G z!F{fT5HtV{I1_@qu~EUBF=>u5o+obj1dZ@*tBl4@f3{Uq%6jPx*PBOTDjt*7x;v-a z7EaL{jnJkHy*V?~v8;5Ne|4!N@E%|~0&lftE^8Z^(b+aK)6q6E3u^GCHE$r%prx5X z)Zame(6ecG@lv$y7b&PW^nw`woZOVt@Y0dqP-nmmCF*X&6&YoyC z7p92VKO-B88D;`#(Aj*iZ2nu>yk~0j7Br`Q_L*OZu73~uOEdfWtMfGP5sHPN}_H;*XoF=I%9m+PrGDQL{bm^_e zZzXY!ElZoE@GpiPUe`;4zFvZkVdhO@*IfV|`!j|u6Cj>mPd-|?;EBHGwx@lO1>bo? z-*;I&)Mv&*A7up2_b&gQ)8>+MjnJ2w)|;@vUb78i0;=mAKJzo5dC1yP42Z)k%_vB_ zll`9~``;51q;Xx5)PGk&nr#!JPBEKhZ+HfE1wXea@A*@8t1Cx3_pS2kkfgyV94#A6QsXc!S)<&N|YtXvd2zzp90B(c~?Q?q8 zp&_Qm{d7LI(PQDl42GQ?xSEiMOUSoM$l0lQJPgQ~XaTOO()=F5_{gSO`tR@kgqPEb#~5qx|Mun&wgs=a(JdM#j2FNooyw&AY_nsG7*;g{xS`Cfw74cGmqF6~&yHCzv$B zm3w2RUhLp_ema4;X8+*cmKL?Bk^S zok{nvR)??4H8KtukurzD`M=$Y(HB7<=e3n(NZAzh#kywp%`!qQ8CZ(wiw~@*&JcZ0 z-IN6F>tuhTKrV=|t~5*^kOe36i41R?_D!C+36BO#>xYq}`PNx95L^&-ReV61AMD1` zDBoJaDTIZe5fa%)!4ra?>kIo_#Z)?P=*U_6oo}HAgeZRngy=mhFB1*?sSOTi12Q^;qn&*!Yd38K+ngKZi@sSlvT6Fv4yU^`# zWw(Q6xBrBKC8^$wa&X2I`mxF&QYk z!yDS1fyL~yC3WK?gFc0uOeXkmG{VJnx)vjDlxKvE-14v+@t>m4e~%t_akPY|zO+>| zfW4^pg|Vp4ejjtyy1f$9GbE-r!h|F-t=gHdnc5UklR(yno z^v>C9q&~xF-RrP+cNLkd1)i0tA+3@cm5VS(8m)UA<0GY?8d>lhF~z{Cv|#Wb^M)_C zPEV|rN@!>}h`y3pTNd94jJ(9iBQg5btpfl1p(07kH%{NN-+9AbX}&t^dUn=1jIg)$V}~zm)@pCN1NwqAj2FiYLVw80SAH6d<>~OKHXGrI zTi`;0VYjWdezOnjE;XOK*x^;O!=UVNd1{A`qOa&`z*SPh8FMyU&62Ig$W~+7ih?I> zueAWTvBA=3&{(@h*6uHBpPkx=hqcGQhbuRCR?Uv}d?~nTYldZ_W$ZPY+2>i0!a-?<4Q{tep$)Oqk`|%66Zi4S_jFV` zej$}`f5pnx2;H_;^Y<2<{B$s&$`$M(YZnrnx|i3&6=wJn;hb-SBfdg-P74&iIGQM- zc;i*LMvP+~(=yC=phUY-0fFoD!6oZ{atUGTsn>35%U;8lsL&!SbYq2uV9bkMkstf3 z-kjb1sHSaluNd((uhNc*o~sx)J&5_uW4`7y+kKejM6fSk0Bmptd4;=>YaoK>RE`6z zy7fsV3m9zhUlbfM31GE=yYX|q;VImOzR%Pf;Tobw8xTGR_{hP&{0fK&3@^zDH`=)a znG2PN*=g~aUzO9n{S-A?<29CyBP>Qd{HIBnFUQMbRiN=yRKGNywUb#`=YMJao{j*n zwHG3%uWb56yxwZmBc~0Nf|*rQuazNJkoB(r3ziIKyN^ZS>T`cDLh8?)ERplB9|QNH z)g3tuXFNL-A~!*>HP0Yl{{=;p@zY55qmQ5qx<+opb~HgS>|eR7)G)thgj&Yyp@^43 zm;>?pQz#(GZOY*?l)^nV5Iv5E9#qH}1Z?84BnQjg=S1c4R1o7+oixKFTfqO^| zGh~Z@;vOvyqhV5ur_e$uQZ&FxGqevO^{t@cFMqIUo+5TV zlIScxE{F(M>$bJvnb&;FOIfT~ZO>DHbVD4H;+{_~{x&Cpq?fLnei*TdUUkTEj#_!9Rknqk(D%wY^Ng&JS*YK z{MBc6T4$dR@qZkBGY1QiPOArUs0M$Xjw^selsPJ`pY>e+X{WAf{_G9lnr38t4Tg_< z7_S=C*>sroSw`cS%V4y5lmHF$@Bj&NtpI6HWZ3cgW)%S! zqCUpY=gRj*9GPN~y$-On&PnjGH#;$I^*!XW12j#=z6v)2#*ho=vCBxm`I7aAQn~Q= zqn(|?fW_Kvd;PtY1slmRfKBRddtcWAB$wldz|3_cCCIZR$h%WP)&pd0O9I*_K;UH1 z9w)T1654BWmq2meu`&qAhcFYB8J)551{M)w4f`5$yWqMbv@;4zm3}`3A;t{H9S8?@b~GU)DhM2xQ`iDB_ahPAI|{YW38D=da4)iA zA0*O$Vfr75^fIP5B+|Dq{d6L|l<5ZnsGK*ys;wQYp95QhkA4o|PjZNkpG0AFJ~}>0 zIkAY2JFYyen%A>p~XLEs;Gu(GdhDc$)BRJC@anKf6Ou@Mi6-?x4wF@Hf@L+g%xp z=VB!0XNp082aUX;&$F!n8gc=0LE*c;NYQJ^R`R1aPdFP9#)I%^&;lC)))-XvmBbc) zqBl=;HS7qCn2It%1JHXEExAh_b)lAij+^`oAP@X{v5N-Odm=yfKtcpjJ_qFjy!B-n z3Rfo)P}^k7R~0Hn|B3RXQo`4p$7SoyiU*go(i5x{7jYvzNh+3yW%r~5K>IEbH8%>4 z@Hp&KkAiDkL^zBXXTemS$0EIA8#KBKtrPN$dX=+p|G)_GGq-^ePvP%dt%D zSB=}??G6@RBMOUV$wERtI1)Guxe$5)9e^C$lYokqfDq)V*G7K}(2%R;N3*)atko<(nuBX#wyb5|O z9|0r_`BgH%V;S<-sqqV=5>)3(01A)IY1|sPC0vbJ!|nooJ_GZ1ZL|;-FkVEWCz?bT zL)IamMTJO6?b8XOI;U|*0A8$UkK%=BT-X9kzw*S}-;VyH7qh*D_eZ9G%Cz|knp}b= z65@+!1Eiui+Iodj5hoGa{t!x23|>N>ULnL~C{L3oN`a6$B?`~6-elB^>w}WDmsxOG zIsnR}1M-+H)a!ZHIg@qb@@VVhzm&o2T@Is{5j>Ku-*sjNWv1vduuE^=jw#}PBV&JO zhm?zQ6NiI}z5qZBMY}tWPldi_t}9b$?e{3GX#6}-5XIiPjjsm^+@BG$Ba9)CD?*7I z0l`!9zJAZ$sEVmN@HRtUf@wFRD7M9(B4od($$rPPC?e!k=Ko0MUxIu&2R5bTL$0*w z)fk!t{j$8LY}a`?$}deRS9bAQU@L5jFeY!K9$6A8%0k0(vsGf+!sg#%CQced&jje& zIjE)h+XcELRM~$H3XVc>N*(^br5Q*R-AsOGGtbb=xA`J7$fvJt*@Bl~U56f!cLPG0 zT+%%R{}tXs;7rUpSUr9@6=koZKIe;zP!)Qn@c;cSwp~99`APUeJ_bU*f=4p^eS=3b z{fJZ)bpQm6z*m=1{>SAB(YYIW(GQUmpT||fuUXKB0x1`I^H$G<3cVTAYxACoZoT;} z?As!}9h0fwHM_i9s|RPQP+0D&<4-YCt)J%T&2wD^dh<0dXL+|h<=xsug&O=`!Ua9)PxjtBep_CMoVTUpy>KOoJ#i(8J#Zz7-Ek#}-AE!A@3o;@GE4nf%5I*Get}cQQe|+1r9`)AU>wH< z$cX+VMITu|UOt}X+^bILvjq9+Vquqtpd4Kf2XPk)8pq;b-=aaJv4AuV0dA!6Qd~)6 z39h8E7+2DG39h8^Vq8gM5w4_h7_Ox8B3w!1P+Uo4A!$4+Vz(r$Mq=^!aFSJh0Wc7% zbj7XkJMKef^l+-J;QW>%j~>+I#B0@}Hi$qUW4i$i3Fturx}%qTRDumI6TKAe!?6?5 zku{WU)>P+8>G>EkBc*4fl%BueVpr^jiosh>p`^6QOvsUocafrxc!4oO2YW6R%*^gy z=ICD5rF&Ude>E!H8t-qTC?5+csutdL^VqIL5$;S;qXcU`gen~V{{H&Je4DvM4gYeK zVts<*z-}}=wR>6L?q&VDmz~zV?DXzsdELv-=w5cFzb$4eKOjRw1!|+wGFn18;QYS( zW}C7h%s)3pK28c)ZS6p!r-icaNv0akz%^+Tn<%08^uM3p4`^oAc3 zj1cS^KmvA;OE3_a>eJQWok=)n0M1Q-gDQ8TN;C>-Xu@z88{zDin}`IW4*i~70b7qS zT)y1&hPhvh0mPtqkq0goZ%VS}wM{82X84ci@i@~o%(@PjM_+S|D^narJ%}mDm+=vf z&&*q&k%>vPw>`faq0ch>s9Bb2nC}}IoAl-i;d(9$eBw2~tQ@#Ecw2@HHb5+Pdd+LG zm3A2i(`R-hEqqZI^Ht%&!cH{tnMbV#Ogk~0minZkurv02LSHdi6n-q0_fEsa4wn&` z%gx_wTsg5Ejx%>Y47ot(KytR*hwhxJJ46!?$GT&l)7MmGVg;)==c>cGUj*xM&d4$b z9>$KUW0Osv2lMb@gh65S|4lo~7nzNf#+TN*)3|Ks*+7495jjA(pxrufI_KaHOeUUd zHzm;{j{V}4stUE{OR5@isODlAa4(`1_}_Ri&?|Zt(oHAB+c&VqhxsbE@LjY0bxc?AV}6H%r!q;k3|5ua?E;@ z>Ch%@cmu^lRxRv4quao;*@)coou~)#|GE*T@Nw1+qsP$Z{3H>wt{`2&B!;!}A*;+z zy^$*KIHv=V=IL9wu&|X_OfJs!Ms9al8KeY*=0j-SXMW9~J;rS~dehfbK)iw3m+j@* z+OkfEW|a%@Ut*lCU2G>MT8ysex}@=C0VMWX4801*C!qs5^h^?G{0{NV1BC1w>a+E0 zHy}ppd2Yn|Ekf>6n)HScxV6>+o_Qm;x_E8|NY(PJfhSVo@L*B_Ar%gz)yiQa%UTA^ zpqt3|v^yNcn_E6^*o$AmZx&Vp7Gr4x$KWezFJ3|yNPP-Mz+`ZL|7wf{#0E^Uz7)7n zpNef!Cb0==hCP`?eIYSCbqn3?rsOYUzrLmpDtAbjsmYGe?kr>AD@Nm1cp66&YWTKL z!|m21r;=>3MFN-f1Ba6!CRp2f5F<{vIkAbEn?=tUmWIAK?iJm2Xdp& zfGxByC({$(zz!d`@}W{aeyE;7U8-}8jg($yHQ{hHY#q2wN+E0i1kn((Sf2z(^)-`0 z@7sxo2)^KnyMU#y8J*cSIwJ#u3L(IA2-Yvq7-D8gF+(u%TBw1Yhz>*Kn|NV;!G|@z z!|1#YSu-FD=FcH*^nOKh%jqAg0+~Y)Uy@-1@<~4eD)Q0Pn8LrMDd#$Gq0X&bM z5K*5vPXoj8M=U(mln8GHOo6mRY^@Ivjh6<>m(f8swQ0-9r8aj4pzxaMkk>4lSj-`u zK$FaClMtIf-32hxqH}E)Is1NO0LL8b{a(4Fg!?x zC3BbXqQg_y+nlX{Y0(>)bfsn#eohMSTP`RxVy7wl8omgG<#Gc-hy)#x{aCbe3jN4v z{RE+b>?*Wjpb}?;CgkT(4dvi_u8sb!faa~7qtRTUBPdhZg*G34eI0@_nExD}a3vSS z#jMa9HwC=ug`0fd^u&#mH$8BZ$D8iB$>mKq+~n{k2jdIhbqu;<---{(;?4f$V^HxK z+I(|;6a1cPANM-;P4TvqY0wcE7WyP^A7(;>;^!9mxG`8iHZ*Pza0n3-1Z7LeOFZotif#xqPd^gq; z_5glb$u+Km#pkl`;z|>G@tG0sxf57_2pg6#q;F8q#HlQu_~%C<=La6!lg5K~Tdehg8MB|NU9D5>B-mo?Bn#XJv$8A_) z@VUlwXx-&-{>E9)a<3b-AwaH`wU%CPIE#%NM5GnxmHmPHj+d;s#(O z_yXd^vpv4>H8Mt68NM>lQ*tT}>geTd;u#@W`pe)wk z;d;s~v>>6VKcSF1O_93WYBBbGHCEH1eRZ(B zv*0Rn(wVX@7ah@C#+)&MHVtNw$INEq2m;0-AArI9dBR7CG`LoY+GH|B!p$Klj#W$h zi4e89Ju)&!3`@9g?@DOPywKqx`d#N@EJGV{27Eud$j3oiAn-AQx3Ee+a|h2!H3b1z zo>r*8mQw}>I6riB$l}N3h+?xP)PiWvDeSR;kWV!tc;FlG3b?iIh97`u_ruu{fJNY? zv&so6sPmcoZ9TO86GIVU(8l6ey^QOk!GBBo=$(S>Rb&B2KQUObTG$7g0<(=HB*v%jP)LW~ z0Cz|OP5NEeK=vYaIJocV&Lv^!81gQoJhtRv=2HVW8Tk0Z-9anlv9oCf8q2kMeT@)C zHG;nsRPnU{X~K9W`IR!NPbB!AeFQUgTqf%==_^lB+FM0h@^B@QNO`vGIi zlH&{a?GBQbOph2KvFA|ofI~S&kY~$hJrM|F6_+4Sis!T>@%*D0TdEjD^EfG8CrFR& zmBK17(OzgS@}u8jUX}B%XL8{Vxc39F@RLyo5jT;(B8`8-U)=LAw8o*N3gs`3fS}O( zg-{AV@i0vP2R{=|js=-v#5q0%EiLA>&PQAdmTZ%J6kY??XxY{oSjH#j0O`lZ_j?H( zY^y0?4SX}zO z!3)@N1N%cHq~AqgC1&(E3)O@jc26*~7op4=iqW)2h^GidSoM@5G>Bw}*{&peCNBP= zz_B=W!D`!8D~l~rjAd|PC+b9Z48vvz=I;?t&LW_quj|ms?;XTK1c!DoCW<32PckGj z3o03VnEb?>7a|Vq6C9yw=?#0*n&DpYvrb=0Yv2IS*D!j#!+&PsRw-|Af*ifeS2(cz zYsErid*F+t)wCQRtkAOq@M6Nf!axE3tYArJl^a8_7A#EOOTc;u6&R9-!NSnjRhkP~d>Qs26g{sn?GGU~RL*UkiwPG2G!^-!C9G-ym?6 z40n_d>j(iCTNj@rDpeB0f(d>OR=|cn>UHa8b`#G217HZNV#q!dRwYQ9piICmz!#SQ zA-fR#<8e;R{}edBc7v_+lUNpg7dnwN1L@5>q874jdlvmRwLE$j&`GLKYTppnULKk$ zFyJhM>}*6v{ns1ovxywf{qjMal5PHJ)PwVZL_s`o6J!P3UyggK24AHR?m;lyLBJz$ z%80#;+3~oYT0bRD7Mpnd172zNQdDKL?yMiqz7ffAui$(&oQ&lOQK-LLDL0n~{yT|M zQsBsjFW2+l7i~I7F9Pr8YYafH&nM=z2-r#x>v_497un(L{cz;My}F=hJisVB)mQu$ zP54d@11EO%h6n+Kv)kzMnMZN>QmmKpBp(f@yR!=Nh!v2p#PSa&9If$Tz6Scm`s0$q_B?FM40<4TA6qa<2ovwb*{asAF;i-PSu?V?u(8=(vQl z$BNz%SJ=wwz{!T5wO#QmSODC2^Tc{M`}IXqphKGt44@t7W{`+BC>v0`=62bVu9H(8 zt*_$AE$o3N;m`VS0-C7LXw47Rmy@&yk9bFls%}DH3a7avBQk5yN>Nl`<%m@?qy@ec(^=@r2yM)y4J!`!$_ES~Wb#QbImjHW0-x@k2{GMn@wG{E@27A_ z6QiXQHE#M$5VZg*L)5Wg&9^P-KuLd;WIND}qCV2^PdAc%Ga(#Y7GmDLavGU8g)0ce z|1lR!%SZ#-3pq&0Tx=3wJX5LDtD_ymleD&i0l{RT>~svQj@5g$K{&s2_zgcxgg z>&>0fy%&J6bAq5#6X`XHG(@G4UPP#VHij&O8X}^tCV8>K$%&nn?5}5Mi24kJPMN*< za=dt~&WH@+Azg&Avy6-{teuvy7=hOT{0%w(3<@tC{2Xh{x>~>h2{!il3Arz>U zL?V+9kI^RKc`;1y5-Y=ell~uEQ$}zxA!px!PNdHvUL-(+>ZA6-Gnj(TDzH7@gAwO) z63QU_a4m39JeR#G*HhBA1dG+-bS_V)KlX)H{1eoJ#Ve87ffztEd>-fp)C=sH2uC0G zTIYNKLa{IS_QxEKq(VG7oRg9fA0JNK*y7li-+2Yk4bxc>cwrw$>XGs{Uc)};+mot| z<@;7)O!R@nT>8LUUAg7@Kp0*8!cO3q!9;!FHLfcBB3z8$xvo0=KIaOe6>eS-%WLbc zb2$nVb47Rwi`fdSZ@0rQ%`*nJdP}w$`siI;>Kl>1XCYMTu|7Qrg2ENKM%J~ciEqiK zMYHJQQ2onI#}qvu2;~DIo}42n z|4qLC7f{vU5Su+m#_mtEKa|clDF?6qCmCdfugbCh;sld2c4Fb1;Vr?t1Qt$>Q;Ds7 zSm6I#N;wHe&w{pc-p<|%^1b0wmlunvTyP!a0i zFYz#KE^neW!qKr8r3^{m!&dI03A2JVPDVVXrfwrLzz1E{| zxCRfcueh$$Is@(;_xoV)cU6{r>OWuj=lf&b*sfOJFa@%W*$Z=Gt$Fn^xGaIsyaU_D zMCJw%6|I#j?TqV1+IV5b)r||INWUNRQqr#9*J6~st>3p1@8OH|yO4%VC2`1fQ&TnE zKTO#qB|O?)Yvvl^$x!kCvjTW`POgVy6&Plj8;awkLF6&qZ+Mb{DrLO{o}dOoM`crt za43j2lqW1p!)y<__yprkRa83!bp&6;^APAMbga97Xe}HtbZdl08;pV@#DK)`(Z!3X z&3WvP*XU%ydxF>2_ri}r^90QnK7*hJ9wRGtSuTNEsS92o&>8KH-6!YG;N?)v$)Iv{ zj{nqJJdWbXM8`M^G&+Z7ya@*>93zu+()cU=9eL&|{7e&&Av4-5gtQpph=m-)UE}eB z+L8K(zD_Tk8}w0;Q;Vg{062EOlHLAugN%jUqM)YtT_Nv;%l*JsWG6OMESy86sV z3Dp<=a|bSZbK_B5DoZ}mL!1*)%4}{|Y{u0$TvXOWYgh@}-=|8tWxV6h1hg0qUYYwP zCvIy^ac_jmZ2n`YhnE#E#ISwHCf0k9B43GUw`7Y#p|WJ(qN#+fGv2{Ciok5~XfW?@ zhXI!GYdsiYyLX|=lv$Zk5&c*#1OorNv2Vh+(DHAJwY67cuk{i6XC z)6EHhF6vKv>n+*5xLPuJVs2m^FdH;7wwCkFhgJ?ci@hWHvQEmAfP6fD53u?!9!Nz` zvAZFU!57JWEr4*D;Jf1YLRUf|<-CW6tI$xsc|eTG;`az;y%Wua0G|N&h1+6n5-*PD zeNa~4aKU>$bQcm)9^#Va8zkN*=Bs{(Nj(P&XDi&rE1-n_!C>`>UW~mk38%el0q{xq z|B&x>Sr{|E0YmPQV$&A9_PMg#%3WPE>AE-YwI?1%9^Tehyo=`Cgu#1eX7U_EOv1&o zctdvnDSpcvnS?>N zG6H$t$SB8#K`4QzeKAT9J{7O+fT7&VC?v9bvw0hBBihKFUhY3jd$WGhMET+AsDU_d zx8FGQ8Gl<3Uv3P{q?N9kW?IkHne5dR+yuXMSHV? zy8~Pv%Uf@AxHS=H2i% zM62^(!-QPMi3;&?Y_eX{D(hU`q7T`!xT`)nyJdo=9nf?8Z4uY2HtK_0Z|riyg{0*$pzze}&~b%YT~S z2jQp+gSM$!TW*d5rNGCu)rAM~f2&W#5yb!2j!e(MR@BTk%)Txx-SstiT)p2NSBNJV;00Q5V+9Um5w~g*9j@<* zPGY~Ieu(~LTAY)ny~oV{D>U}t6>^GggAi&pF~6H%)xuS9N2=b%vHI#Ir|WBWcxO!bmFCO%taDF7-TI%Qw}%q@EUk5hT#Rc5(ds{3;ycO_X+0U z6-Riuwc%9wg<@~>V+2^tjo1$|va0hgAioW?Iyb7SgZdp&caw8G7S2@%*+74u4|?G9Z@@Bl+huHk`t@ zR`!AY-iotvwdn5{imXpRwMTTO0PTh!BlSIaG{ZQf#RzrqF^XKnl!kLHk*-C8;tdw@ zdH2uJQn2U<@{&=JqTTof%B3tTu0%h_Ya#4$W)Lm8krB?sxkidkE!ISr)?(2s&1ZBY zS|#kO-Tv<5=*LEG_MKzojDRzgJ8&+2qty8zAlUv-lIrS>4}mH{!m@N|Gfs&;MgekhgnfCrTcbJi!7q)}w%PZnQsclstLl0=1kA=@U5k`W-{X zdE*bQ(0)OyJ9;iMlJE^DS@EIKOreS881bb1=s6-c2!^KSj~0gL1o>jXj?aHs22V4i8mW|w zTLB;?<5gggECHA>kD^XW*3jr+disg6;XEf6MRp8i`M#BqBzj8w$q85ku6}(=$$d!E zbAoH@)(19712ph%;U?+>?{gKPOdt3=ms?yPaaD=yQ?43uea=-Ut}nQPxboE~Kgpgp z87t3z@ZZ>NJgBSuw+2@Wa=C5h-mnsAU zk1+?>td=F)7;wWWuKN_&yG1vhZ}E8d6=Es}8(5VmG+!5DAggejcH8ls1IF18!$-wy z9IM2x)TJ15&kH1P?Ku3b8&6#9eBOj$v&Nauq0S>z#R$udk27zfKdfB{h9S_EswQa0`{8QZ_$k_mqf1b<}2 z2z>z;|80X$lJ#`Scl$(o4UDp{HhSS=DPm0l#vDQh)v)GCAP>D1yRhcJ#6u_CgJmSp zYkoq077Coj%i1VCy}klmtEYg4P-$qhQy`ZHPpopyL!f?}AQ8KM+&;usE5u8@e-7$! z38U&&464^Krd~%a2%@?^P>PE_@F~|Sk$z4LJmcyuNXJE(Pv2pWmlWnQAHcDq?KK`4 zsznw!iqf71D7B^tImiM}iPO|%jB#E=P`!MgCE#!)9J|kM;*5yL-{nQr{FUX%j3upZ726}ur36bF!m_vFHrv5 z2c*O=o)W}t1lks1lgGM8*fDT_`DWrPLix$V>DIt_mU!_-EeghekP1qkxrc=8M+c-K zk2DAo1RX$eHN7B73*RzD^i!zvVL6_V%8hX2q*O{`5U#;Ihy8K$kWe7;B%o5Ri9UHi z0@Uq9r{d%exoAnb4Lq9K>xQ;g0B%JtRn{PJQ@o*Lo&KIUMUSO|I9&`;-)p`6 zC2(54naJAfY;l$Xje#{xZ2=S)8WH<*iaLt%VCgS5m7aiAm>w(BcZTz~-UX{0cp!0R@2Q z8EBZWXL3ZjnG9k5&zgx7Q>o~B@=8fp9=HwbpP=hz>X=Pelae@$hZnE7fNA&-nzICc zyLgTnn$}- z^^?H*n(gkEPPXgRn@fkgSKJQc)gIcb8=<3JRZeEP`K3oMhfC6y>NM*;EGPIFEm&F(E`wzSMn=?EvVRFq2(|=xwqI}Dn=nl&))(`O&wR6@a7T0} zYAC;XL`k9#oaM4^W)GOVu3HbL5{F8ZTle)4_hq84H3@ZO-$W($^Mr^*pGRaWN#ON0 zT@mLD42TVu>r_OtYjG6yd_F>p6D9bz;rm$zgP}N_xFhg^IGI4Au~qmDst?2;ZAt9U zh+TMkcgy#2j{CnosL%`8#&_NS$NTNXN?{9jsQqWe)7**< zmUhMY8R;J-JFnz7p7_=`^lsSUAH0_08p~602H7s(geT1 zutnT8=^MH>v;8iT_-ZnT)$=p*C~}UzMmHh>>^R{)g7c4I zXA@)|zFcqE23nR}20(hlH@HRS`Fi8)yu;z6AIY~eSbv36g-zYYkC2b2lF{@wEavwV zZjC+3aYUo3dgFt#k=}3zZeWLVn#_&0C0qO@?34Wg*%7FEt$!wdFT{I()?_hnlE|y7 zEqP_hKTvh} z?G@Gy(&V@iSUBj%lRw97eWjALjqb#G$3yb@f{5c1*1-ezf-fvzF_{N(0{?=5qWup4 zSrALRz24lj%Zi>tRdHT5us@ku90#Fifm34V$Khd9yt_ldt;K12HQniJx(w5t-pVqzLWA@(NkSZ zfL9f6jmuXn;f)78oL3w#s2fY_MuEDn*e?bDd#FxFX@UI)&nIMTF(Uo3LT%- zo;FiBDTr~iuLAmyllUi|##1c(8t&;SeAks*6T*-40p?NjaLZ>79N~-f{YAu4mEJ#2 zcD#*mXT*WhjW~UPGYLI#kfF5$Zm4?JDs3gD z4gHz6czc{9E0C+BbtGS@W-ZxYV%hL`2SDQ@ICg@-bacu)>cyS`S(dz1!a z-s$e2ir-#-sO;e!{}BA1vv{kwxgYm`L{_B8#@_WG(0t4T2_ejP|@K$>Kk>qXS zA=)||i>h}=a~aJ5cf&>F+&~{zxe)Q~OK~6TXO9PtQ>*viz-AjIIe{;tk7KtzF0Vjs zX(8s~gLt9mD*U|^GHfdz$Xcgm%C~T!Pd-W!;^P}4O3p}1IJ+E3@vobLQ>922A<0K? zN^aFpxgv**@P^;bu#Cg;}q(A;XA^8W9Q7wCqheIOXc!Bc* zkI)w2`4KEL;r8%_4GdN|*C9JtxC59-2ecmNO0pkgODtRryoyM?L?4enhny^Nsp0g5P(p$+2mK6UZ&!7J2Y z;7RQ+$fxyZ{GFo>!TVQ2mJV6`ld4=4o&h{xa8tgh5D4H1g}`6;JDrcmzR1PiAob?8 zPHXB`VTVsFZ9Ff+mpu3vVxGt;+yOSjfjfUe-&yJG_4KKM7Q|+BP$2h0qc++nVt^pN#PvSpM(5G+NCHPfHwB$ zia3n26bLeP^7c+}aXL<4Nq7>kg`$U9=<8DSF%w;+!nAvrCCAf43hIFEiRek@eKHLb z(ZU`Rr*E}o%B&rUz{Mu~A=#%v~8?}fjArkBP+G5;u#MsmE(1-`6axrSmz|{#l zWIs;eQHy_zkW1;19N;*x4W*d5m%)x7q)}?N_g{e@5DGHODyG;pHZk2Kn-%?L^V!?Zynmyq4wN3eW@)I zoVK}U>&J=dr?g27D3!b;^%B2o+>t9YAkj7@<;Y9OVU@sQw&Kwu*gyWWKPRqB>7~`6 z4D&iO-ulGtXy0ff$WK}{$gdW?xXJ3^9dr~L)e=e?9 z0wX_qT!?<`zU(%mP+!g+95HH@)Kv?9AbYb8qZW&P1W+`5lKkliQy#1 zQCif6LQbSaOFc-2O>D5x0*xoOJjr#_txZB#ZQVK%U6j&UfS+!;$W!985cXiYux1I$ zlJy}O1Bva4=}z>s7!=RN$ffISLdTM85ati#ov_39$etKeyWa8qqzy`*pA!~M+9b*v zeUyaFAC7yL(RMEte4=D0YdGhP8<4}fLgI4+YK&5Hd7?7XIU7CA&~A!L^k~?sD$y^s ziqcz+NP0LHqigZc%$8+#x{7=Yna!MTM1bgrD3FVfdcuk8c` z`eC#%_NZ}$IVae>Nv0zqVZ`V}^2s@!Hi(oYw{#+pGdle+_OMW_oaVzfPOfG1QO<}b zf^T~g$*rjIiBYxTpBTTB`*U{R979UJ-BUFro$zNtb5lRUAD&)UH+Si@8Pn?)1?J9@ zcHXWf$`{S@Pm`|nv_<~u{=lL{B~?Cs;f&eSYUj+ImC|lO-K_a3xtjF9r_Y>e!&9Bw z&18Aqg1W$5IPP|(IrD4r1iko({?g0+)33LChTlJJ-t;;1;{elc{=5D~`nrT8;t>*V z`#p1@1GK%ijM19PH4Wutfs(((Y<8}YmI2Tc>BaMRx|XjEjL)xJhs$|zGWxnw8;99r z9Q++A4U1HJd9}%+p3?th@6^7;?0vkqWm^c&)U+J-dWRH9A4$_rwvM_GjO9A&MDl!c z|1QyEGM6Nt$zI?86mCLKMhn^}fwE*8Y8pqN%_+jPG5pGk0z}7C?VtY8J8lb4F1@anD1~5 z2XkH-u4Ry24^k7s`Rj2VC&mZyOff>712|5Lk*gu5zCg#&DsS)Xbm05( zZJnJiT!-OXj&EOlY2R&aN%WqN@v8@fdIbR?XF#J}O_U6Z*Gb&5zlj1fKWcKtF$&mE z#Cl_bpg2)B0CaQZhlebWt3|JZB?BO5vIgN63S0^?PZo*0q2kxZkp7{Zj~N}2tAk`* zNvDnHT+ns0dr1L#n&2RP?-@uFqXKOxT5D)eEH#0H7kT63oS7o>{PrLu1ncJ@n3@9Nhp~wB!l=dpR=>n87UD4^j+dU2yI7V#B6R9XvInc zlIx5H&a@qbMhMAeQnm|3K5Z5I`tSWx-ldnwC>1|;TF(BoqaMt3TsL!ukhXmd68( zITvu0{FrG9#P}uds{orTU|Bv9b!s6&l+gL$GJV@6_?6?y{u#-l6i_dnN{2}?*X^|O zGvxYp6U6?X}9V_!!?L+ z73kaYEDko|o1^Hq>#z8W#HSc#%xh8UJk*{G{yA21Qo<$LYyI zy&RP$29!>FwIemx2kDh71F46!cJf21=StDu8L|ByM))LdQlnBM#GI|=XQYBV5s+L5&e~C?L=BJdfD>siI8q7DQabJE9j*E(eA9Dn{xc#%o~E_|TKG`D zSSt4nDB1Sj4}GqMpi{%J#R`UXDTPghxO&ojNP&f-dI^$@6;{E z@3?oDI&P^YiMdx|kggB5bq;{999?O}IU`G&I4{ftP8=`xSB`od1N$=>_sRPlsk4(4 z^AY!D>x8etHtF@L33j~1iBXX8q=Y}0UO!nsj<0<@{C}^XHYFMMP0IDO7gLg2)sxrO zjOx(Jo@^emGxz=QPp)5n_wc*(9vSuY)(vG}y*26A@BQid?x%fngXj5gDu3U9(S4_- zw#F+l(lXNP_q=N2d8G@Ej(qTuKdhfn`p$qQgZp{kIdkUdHUD+HbZP%vw+{Sp*QFU1ku}E(m6>}ldcDu@=V&?Y%MU!1zv%qda}Mw5vwo~B ze`{60Kkp0wbIhtm+s@v5`-Lldv_E}I$K=Jnd+r+YV17=hY*x)5KRn|(;B%qGr+Rd2 z$A%+2`aIB6rkBq?e8&a(Z}fTLHZ9m*x?*|ZbNh^i-?mgd{^Ng5Ip*l`=A_)aU%dFC zedWJ+?2i{MTfX$pgTs3E559iXv&#GPZFA48ed2@1M>f6plj1S=e|z%>+k#izSoQKB zj{I%e>wTVI1^nhL9A472e*agquN(QqvRzLcIqQyxR~77>bo1?r^4u9CdVjnC>E*Kj zXRn)o$;Sn+_gVjmOyB$3iv6Qj?dWsQND1%mo34KAlb`Lce7xKK9lyEY>c?Myd-S`@ zkAc1-NzX6mPwsa4Jk&3d^?#9;-ahZCQ@1U8qtEJ_v?sI|=k0y)lrR2r@jJ^s_a1gU z@{3Dq|J3+w>+pU*zhlf3FIC=l>bFB@6}K1MbnhSD=<~pE34f?J@8w6|eRtHO>tF5h z&hPpbbzXDxjk~P6@$26SJXtW{AAJWcxjA?Do2WlZ)_<~aRbJV1XI4Ji(zDx7fArAL zp1-|r$eCkMUM$PCXTR~So&Biq!F|tOc6n9i1Iw4bKlHo{F&<$_|7)Jc-4hQj8vl#P z%+jAPeRklvuUzZ8<=fZ${GSX-U)HCav+|!xjPJUkD<2+^lwR=90nfkjReZd^U-nw# z*(3fHPgnNYbmKFd8o;ko3Gd#5eUp5@Li%!<{_)gt_g^(L!Oy4f>ECbAvO%LCoUk(g zjPW5e@Qjr*^PjV*g_d7<^(wDud9_>0@;B;d8Cr5`Rl zYwGn${h#~5)@;3f$C#f_EBf%FvTuImysRNSborG=)2kED95-fJ|9jKMclw7PhhO>S zjy_NH(mGaVU2ylZ42SrGtNi1ojx^iCq?1pe{J^KvPG`wQi*CspN zTc(54RQW0LT4Se`t83HmQ1sQ+%6bk(pIg;;DEi{{6@5;-T+yegbhd(5bDe~@Or@(- zTIMEx&wI9g^!b}1ual*G|1>QQ^Z>e;XDnG2!9jd&yCHoDk z@-tO>n<^iq(yLT@m`b;(bg4?OR_St;u2b-;RJul`XRCCTN(WVX|5p-^`&GI_r5{o0 zZ7RK5rCU^bvr0Fq^bVC?t1`^l%uVoXl~(31nESb`*i+TdS7~ML zf|shaZO$gCw65yksM5JAeWyzIQRxR&`V^IZPNh#(={A+_tI{1R-A|>pFXWAKpo6(8 zeYz_DsY)wz94uAoGgNtvN}s9HO)7nsN^e$ayz-8p;7*l3N2R}3X{So(ekpIxRq0}t zR^zSJsI(eytx2WTcxx>xt;Sp1uhJ6S|Nj1e#Q`Osaqu?(?Tl}ZbuQrjPL*L#r&@s= zS*3q)q-5HTR6VZ-Ug?vj3LuH;=)daNmV*6MyF0owUmu1qWa*6Mmo zcuK$H{VBBn_i_>r1l2f@n`+2J&DqK?w)t!Ouk~s9wjaA9E#LNMSEl9Le%fPc`L=(% zHZ9-wbGM}BS6wd&+L@MLpz^J>eB1v$oR)9xzI4$4y!*i71Ve{Yi$7hSz$7}KUw(UpMr{&xJ#EP_h+pk!emT&tP zkEP|?e#Y9geB0mHl9q4#9Xr$VZU4hc%eVcI!)f`pKa%sUlp~uDwqKH$mT&tf`DyvK zpHiHbZ~H4oTE6YKOi9bP{g>Hk`L-WZpO$a?Gb_^aZNFw^TE6YyJeHPk`#EdV@@;=- zOIp6|_v}o|xBVY0E#LNo4yWbY{!orukJCq zN?N|{Kg~|dxBaO4w0zs2T9KA-`&BE`^5gzhnmx4RA@*A)g{B3HTxiT$3zHUy-U!~S%kEP|?>+02M`7H|m+O&Lo-QALw z-=ykqNz1p_<=fKogR1_{w0wKr-jSAHr|Mg2`S!Yge_DQxs(&~w-(L4?hg0oLm8zeU zmT$)ea?|qNs(xNtz8yDkrsWr?`uS=3c3hz#E#Il?7pLXhaR+x=ey*x-q~+UjiK?`G zP1T>0mT$)`YSQxUIL7R>d^@gDmzHnGIqK8$?YKuUEx$v_=Zds^J1)|cmT$*NR;K0K zag$YP`7O5mr{&vmmDOqacARBxTD~23X-Uhs<1ky&^6j|HwzPaZPO~#D-;UdKq~!+{ z{#IJP9oN~PmT$*-4yWbYaUbnSs{Gq=pq#XPJ1+G9w0Gv=O;vdxzg;McEESMNwg3WU zvD_|f0@9sEy2K_epg@`?w%utOH){yvY#;6EFs|*Zg>kme_CgqE`)*BP zobAKC8OGVZTyq#NR`c?aFwXYvTEe(Rl|LEA*}h(D7#CIfb77qA`w3y|&lEOKgmJbn z7#qe-s(ha?&h`!C!Z_PMR7Tx@|Noy_11ai$1MTCmy`TToy7+Io|62q9t~KyH0t??8 zrdXf80*}GwVRwAOezu6D^!=Je;IY`vZB(B>mAis)2i}nUy>k?jr`|ZKa>r~1j8OT= zE7-}${aDx$QdB|pB@wS=|9n_H)+^ZgjVgasjVDR9bN3bG532HA=PH6zAV)vmE68`p zJ&LDzw=5<+qPz%ORQb3IDo|hg*^*3bj9cM1kXn_9bGu9cvlmufG-fsF}+3t*ZP+InM7d3X2ua{+}uH zOZ(><)y}+Gie!{($Bawr&q6b^@c;WYUaEG7P=q-AQW2wscvnSvd5tJ!o9Id>2?hcz z&<8Ff@vCSN8HiuMiD?lTgJ0^9iX9>o@LK^DT`L3REsn@ljt^dSEhl7Raj9!jGp^!f zR)AcGkEe8*M?um#@)Af3r?nrXkt5Ww@1TKoJ70jLa5ASrmf@ovsOmC#cy;ziUUXL&nh8aUDf(m2NG{cVsGltOPE8j~iDw1CX*$9y47;qN4alImJNgV0g^ zI-$SqImg-Q26B=k*MeBk(V(oBJszZ(BU3?yK}H!Xh>0UEkQ9yt$PP#7Te)gELf`sT zk2=(2eh7r>P>*K|NE1i?1k%Eh{U8m4jau)M7DtYg7Dv7X5r!DG&Vh&=X@}4(9O(hF ziX$eF)}cl_Ng%P;8A%$5$dQ{tEF75&;^)Y1AkD*!c4|pxxRKls(!`M`Nd^;r1d4~Z z_}M`(ql}~pq!u!CLy*3C#fE{BWQM+G(z4_ zkYx+=ZVmap>3;m}xt|e>HPe=AvlSHI%m`_?UD#$cy-mRfPx&wAZtrTRZ4l=cz z_q8DS<90(^YzAq7rqVj8A)lKx@ki|jndiutiIpOwq)d*wxWp)P5HiK+hg41UD+phL zv|PtXMn${xffvfqR$ojQDW{0c{16hU1 zNAF`3K$;dANj^yI^~^G9m4NuQnC%&}^HOuoUH{J6I~KrI?;6w}lC7IE56c-M7WX2zg%uttPE! zmP_SM3@^cyVU$?`8T_*;wUtThVUQM+kvvB-=o@;3`#>xSMsgfvl~zA?H69VmPDKmt z<;{`2f`x0HpP^MenE5IQQL9ScrYfdI@pNntnMxz+0V0+f$pDa(*D*V=Vs+n+Q@J!> z!BD^>c^yKNM(h|o`4u4{R*R5)je(sOZM-8RQ9=@8H7$~vMlxEhQp_YJauJ##LzzDc z@=*f3d!6Nehj^PY<^_;x%48%fAW0UV&r__CTcm(5S1K23HA3Dipe3Sj=xwo#d~vO_ z9)xBP#XD*J354b*oxBO+*J_?*4ugoAOsYCm8WtLT{Q#L1Ed6!wQ5{e}(~M*YNGsQZ zV?a{49zGeQL93r?HP_X0^-~I&RYgY2A&@V*a@CU^EoLgkIuKDZYCR5OnPMb=0x8C< zr_=`JLi!OkLRb4BBXGWsgQRH0EZ0wJ2>%3Dt&Pkqa|WGvnZns=Bkx)cN6+-8m-~fP zUZzF9euYdk*A}rI1;M2GBAEmbTBYbMI1QwklPLlbwOS>ug(Sn(Pd!MJ$!KRINJG#V zPb0`G%`!%b9|J|eKc7-diV03GeJxkd2T4n0GUWX@NV7Jhq3o0Zgko+qeG8dbJbUXs z>KsTDSJL*KK)6zj25HDLYE1-bp3I1xNf2fWH!3qAQ>)2Pgcgui&X*meiL1j!AT3;b z-2>uJX1>VI7LaBwClJ{QQmfS=k@rDNoUctXxIDHB@gAtOslk7}1l1(6DqLI8zWUP@igVg32 z$#IZIEsv#H$u_)m>y4A7#nsObASN#6*v=S(T8~m%x!j+^^`Cx_vE&=Q4+m-F>UlcJ zaF*wSG>56tWt;)wy;VoDV1^;+2P9d7D!_nvy5>;DM6^! z`WVV3TdLJcN_IYlRxIcJEJ!ogUXfj3S&N6XhJ(a%#6pCNXD&!Hm&5M>DdxN{2kCP? z>rrwZ!!kET8_O&mHo6VvlGpQsCSzASbW<6Vp$H#W^Tnes4IMFqrmJ{QeCT->k4cXBfMYF%1&4D&`QZQdY=m7 z=SndbM9}(}#ca!jf>5lj*~m@+GI1tm*{;sHmRZcQ(!>2VtF#_&$;!c(yJ5uL%w)*U z3fO7p=D5w|os0P;lHnpe0^)ZW?R*8&!1axbAWfQg^3|~$ymRw=50I8ItP~_O1f&5` zM&NxE0U;Tr)?}2ikW7wI#z!(*jhWTPFllW;c4{FbYHdnn9cg7SJ7{IMJj41JDROw+ zuH3YO=9?HHtu4?>(R>kk6U0<#l%YMO7Oiij`}{RDyc@XD-2xebtFiMS#i)6`?A>B9 z;|bw4@bU{YE=4lVz^#2SHL`N3V^~K^nE1XXgl> z?yks0QXzyNAalN#k#xQqy}YlH3TT4z88XFp z7|E?5XEpD3$r}ow58_xcxfDu-0mwY7S*DolLGJBul=&UVG>$w1a+D*RLAnkwYV8DJ zJAsjc9S7c3BNNkpI@O`#y@`_{@9$hfj&p<#lnjs^{3v$ps$rebyT3sz&VTVDjatRm zkDMKni9uWG5fbTs2^qu@JC28UkRW~(%XUdYacYiId|eMMi;2lh!Bu=f@;KuC9-KN8 zcA`98)2Z|JGIUkJZZECyI_>uOiK?LA9;9bLSu5<^O-)u*ZigRpDIbHW35`>PRA=%L znD$aUtzBMMIU-Xk_lIi20voR=1SS0pPt8Z7a!)_UQ@fL-+@X^Z%Y1%&xzD9KcFvca z3uRX73)m~F*|DOE{AEu5)J!G|y0j9bTuGNZd{om(&?|U??7^iT?vL?{;~4FzVae-K z?r3cyAODZ93MkW+4R+MZr>c}sJk)$8>Eem{TTauSAyrx&q4}9!m)VP+jZJoev9w?i z|7n-GlFRL&ElQu$=h0{uj!-278c5G5$j7%csCKQ?UD-t;4V-lAOj~+(d@_PlWz61E zx7VHKK(QGr47j!TxejNl%N5YB&58Ni`@&#}_C6tLQnGfD6C9yh#y1mqp!*959 z8ZOd($WT6yN7B7vqQWMuX4m3$Is$r}7N>404?U{TyU^>a!U4N#(TdQPKHXS0bTb0( zN=aZ(er8MM_;`0P;J`;4Oo^EBB3YP0Mrk4m3fB3O$7A+}q(G^|DQV4txw%5J`S1uH z??)}enmL%`b2>cA{Ac#MLvBppw@W$h5(`eMMOVkyw7N_58!n+Nv((M*$x#OKE2Tid z?b6&(2m<~UWyqHyIo&vnlT4)Jkj{`MlIIJ#OKUPKk?VyV>wI@9RO>E-|q|H8CmIcvQlOs;0xeU+UobXQ48#zVCcc9d^hTbdZpQ) zY?T6ZndbJoFoHCBxU_~U@JrjDw4Mc^8q{k_8ps z5U%7XY4^*9x#coJ$t9r%4}`gwivr&n6(|Nd709^FN2@Lj^VE`{&r^X=eAr7j6jHaB zJUCZr4BN#)_C*QO=4R=w_=~AeOog+&% zCWZ2fj6ki20*5;&*(^C!HMx$EbH3gLL7_nF28CX?6Qe}yzJk?V?nnLzE2XZS74Vg3 zBQfBxbJCXRhF6ME_7=)S=p2t&P_AtTWxdm5^enC0;~LRuHbc+`t5 zFniXJFQDZLp-689xTTJ0tqF#ta_WwPJkZn8UE~tW^`saK%Odiaa0gL;tXy(5xl+g> zcSTvV$d(|A7EeV`zDFub*VBD+$|NAGXyVg7z7mIr6+^?>j^O-DG0a&zE)K9(jlTI3qFI8(hrw`SK;Eu}ev z615i>u39+ih4eIuOD*N;Wnd#h$gS|ue8GmA(nge9&HOMcbX_s8Q%$Smi3@}{jh4%% zOoW9PqyW0F&EfXsm(sAy54bRl3qs)&9yQh_nM^ic;^bVa?ZWC+nO&50mR5sNyU^+` z^Wt=RtW>C8v{}pM(}vn5X^&PJNGegJW1(JMJI8Enpsq|RAi>Bjd35F4;LV=`J1g(D5ZmHY(PnJN`{g^71 zw?O)5nU#J11i`E-t*etaZkA>SwIQXq1$RqM)$)`AgNFGz)$5XJ0cJBp_uyNVCe%yX zRbPj(t_rh-Zgu7$16b$Mz)!lS+8I*cVZ#-n$hlQrUEnf9J`-Q-Ss63 SJ0x0gAccE1z|`n(RTIBV>cA}OPW zl+KA~hEjJ~ML_A$@`3wBWsY=@BN$|{%B7(39zMmZBSE4bqIJ{h0f&FS+Zn`i5__o3 zhFlPRl`qh>HrLXs?F!4>%Vb-@Dt{%0rp=;|BhWjYd|%M}hMMx!HMyZ>s6QcCE>f7G z^|vy0)8N$Y8rw;!LTWWUpZMfQ96^1CQWP%9e}-k1Hk9OSiPn*yjaV4UsGFEf5Wg1R5VeA)Zp1Y!iw%X_} z?FK13Hu&NMuUoO824oMDp$(s{36YV4Sl{VnOvh2n zvzPzWC8B*~Lw%=DfIfH{^*q zVs8WKCU(Rhr#3`yimVmHgfQJ`(>H6|e>kBorD@=fb7j|cne*0(3EPGrI@)>ijNOMm z?QJ@Kv7x@hSg}4Dzfrv#q9P+ABRdK|ebVmOg@+y*Ovcm@Bd$Uql?hjg9b=*jqhoqR z7FrW}i9P9}Lys=G7@iL2e0(uXC=^WSF2)jX-=kx?qr5~;a!j^Uk1hq0%arX1jWLT#{gO*W(}Q#uw8c<{wjgDE{#9N4={LZUc9oRlyrAu&1m7F;G7F2&IQ zeO!aZK}uYGE)$phh$+@b3^7&^S}LkOq8nN^qElpjM1-*C?(Zwc*qUxW24wS$2)--=l|r;GKnQKCgc1vlC|$kH%~ZtT{2KN7mq2%Rj~MsJ&s`+V7@zT{vOWz_E~*xv?TwRY@?;+D8RRfQ+TakKW^_3#s;H+lVkJU)Kx zd*;^{ycdaX8S!}CUa{^~aR4fFK-cJA(LKl2zBlgUg_BEfPx-vm-GBGFpmqBcxvmEc zjqW4%s_ogK;k#MFfync-?&!WVYS{Y4dEd|NFLopSZV?d|quWJAwZB-aXbdBbm<|{m z?b@}EiqZx}r>F?IpAP5|9f@PZrzyi}`MI=+F42j-MCxI3&yqWt+?Xcp;Fzx1()=($ zD@O=-?A_S*;qklj&TL8kY**#V+!0o5o#U*l>BhFqcFCbxU7tR3u3Gwd@n4_6rs;6r z4gbj4aBjlLC0}(MTU!6vn@6r`IQimOUscTbS0n1~@aMOl{Ul<^+I4GYpU5A+`+;>f+o#vHeR9{DW#%z+BYywMwJm**eeTe(NY~}j%b-4#0+!Ph_OvD4{U;VIh*^jG# zSTS_N6ASuuXi3;Jer3;Xqmw2*_V#ywj=#R=@RD_lS5KNBSGs%D!7)F)UXu28f&XY^ z_SlHS*Si0B)r;rrj((q9{K%_^{xagX5BHgzy}S11cKhr*5{IXn=AI0t)?`%gtp7Uy z$@`l3Pp$uG{~LE5zA)s2og=Dt{qoUk+y1(F!tCIoH|~FE{f1LTo$sE~yzws&C%(Gu zc*DZ^{SuCt=5Os~-hR`{ZVR?#pPSt}^1yvIU)MRSzuIuRqPn@mH8ZOtpI$rQsgpOI z>VEjvC3lzZ%WHq8@u#AO(xH9N#hw1<*>|_z`Pc)09`M4pedpDru|ll7%aAlKn-eHO z|I?&#m7Fx9qcN-fs$`HJat0Bj@FET~W`#bzdTCi9Rh@m5EN>Y5=+E-lU)HDR{uZzA zqc*U06-yO9k&C>SGElEkcSO1)Ce}3<) z7nbb{WW;oRbLrfHZQbLSUugTaU-sT5pYEL<`EKq%Y*VwP;2e+d!C~h!ns0dIwYeQ) z_H=)0#Pk(u2ZszRo7sEj(WRePpV_`_>ww*FSyH-oUNmjcqn+FTk|134%?_R2dUn!R}H1Gb&6rZ)UXJx%@!^lyCu*Z&{qdh z37xf>0t+g!zkaJ-Lbu*s5=C)*f|!t;I5BzRE#g@HZgj$sXjA)lS3DkfY*^FiMO((d z_3MK-&zacn`owARKdqeSN*sUx`Z{9*#F8Ky|1{&C!}o7E&xD+AA3w;i2k z4}HJIzG(Qx{SVyJZ|UY4Wyhk=48G}&W96gf%{w*n+hosg#$ zbh1CA`(ac0f#mV2C!$)nlfW+<$99+q(0UdR%zxf^A9Of@M2a+&%uo5lN<#RV&wDz4>n$PnGvQ zb>C-qTmSyE#e62_rj+eNnwy{h>Y17@pT4lmG0$^slDBpCtbTL%9~l1j+p8Ob-TJ>W zcH-Hszr=Ov7y06$7uSt_YT_S2l3sXbd3D{cPu9=bz5S6f$EGfM^Yt~&Q?d?B`d!iu KBfp?eSN{hcgPmLe diff --git a/plugins/vli/meson.build b/plugins/vli/meson.build index 8c3deb891..7db82864b 100644 --- a/plugins/vli/meson.build +++ b/plugins/vli/meson.build @@ -44,8 +44,6 @@ shared_module('fu_plugin_vli', ) if get_option('tests') - testdatadir = join_paths(meson.current_source_dir(), 'data') - cargs += '-DTESTDATADIR="' + testdatadir + '"' e = executable( 'vli-self-test', fu_hash, @@ -65,7 +63,9 @@ if get_option('tests') fwupd, fwupdplugin, ], - c_args : cargs + c_args : cargs, + install : true, + install_dir : installed_test_bindir, ) - test('vli-self-test', e) + test('vli-self-test', e) # added to installed-tests endif diff --git a/plugins/wacom-usb/fu-self-test.c b/plugins/wacom-usb/fu-self-test.c index eb5d27ed3..78de13a3a 100644 --- a/plugins/wacom-usb/fu-self-test.c +++ b/plugins/wacom-usb/fu-self-test.c @@ -27,7 +27,7 @@ fu_wac_firmware_parse_func (void) g_autoptr(GError) error = NULL; /* parse the test file */ - fn = g_build_filename (TESTDATADIR, "test.wac", NULL); + fn = g_test_build_filename (G_TEST_DIST, "tests", "test.wac", NULL); if (!g_file_test (fn, G_FILE_TEST_EXISTS)) { g_test_skip ("no data file found"); return; diff --git a/plugins/wacom-usb/meson.build b/plugins/wacom-usb/meson.build index 6a861254e..e8c5c8af6 100644 --- a/plugins/wacom-usb/meson.build +++ b/plugins/wacom-usb/meson.build @@ -33,8 +33,9 @@ shared_module('fu_plugin_wacom_usb', ) if get_option('tests') - testdatadir = join_paths(meson.current_source_dir(), 'tests') - cargs += '-DTESTDATADIR="' + testdatadir + '"' + testdatadirs = environment() + testdatadirs.set('G_TEST_SRCDIR', meson.current_source_dir()) + testdatadirs.set('G_TEST_BUILDDIR', meson.current_build_dir()) e = executable( 'wacom-usb-self-test', fu_hash, @@ -59,7 +60,9 @@ if get_option('tests') fwupd, fwupdplugin, ], - c_args : cargs + c_args : cargs, + install : true, + install_dir : installed_test_bindir, ) - test('wacom-usb-self-test', e) + test('wacom-usb-self-test', e, env : testdatadirs) # added to installed-tests endif From c76775641bb3ab31cb78867360f181d2d9464647 Mon Sep 17 00:00:00 2001 From: Mario Limonciello Date: Fri, 28 Aug 2020 10:13:25 -0500 Subject: [PATCH 353/607] Revert "trivial: debian: don't fail CI for subprojects" This reverts commit fc9cb560ebbe71336052cf54b671a72c9c1310df. --- contrib/debian/rules | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/contrib/debian/rules b/contrib/debian/rules index 3f7e96f88..e41695cae 100755 --- a/contrib/debian/rules +++ b/contrib/debian/rules @@ -56,9 +56,7 @@ override_dh_install: if [ -d debian/tmp/usr/libexec/fwupd/efi/ ]; then \ dh_install -pfwupd usr/libexec/fwupd/efi ;\ fi - if [ -z "$$CI" ]; then \ - dh_missing -a --fail-missing; \ - fi + dh_missing -a --fail-missing #this is placed in fwupd-tests rm -f debian/fwupd/usr/lib/*/fwupd-plugins-3/libfu_plugin_test.so From ac4444b52873b827dae5eed351f707a414efc66a Mon Sep 17 00:00:00 2001 From: Mario Limonciello Date: Fri, 28 Aug 2020 10:16:38 -0500 Subject: [PATCH 354/607] trivial: debian ci: don't use packaging when subproject active This prevents carrying hacks in the packaging specific to CI things that will never actually land in Debian. This will keep CI availability high while new packages are not yet actually landed into Debian. --- contrib/ci/debian.sh | 8 ++++++++ contrib/ci/ubuntu.sh | 1 + 2 files changed, 9 insertions(+) diff --git a/contrib/ci/debian.sh b/contrib/ci/debian.sh index 0853b3a96..64d77c6ae 100755 --- a/contrib/ci/debian.sh +++ b/contrib/ci/debian.sh @@ -23,6 +23,14 @@ sed s/quilt/native/ debian/source/format -i #generate control file ./contrib/ci/generate_debian.py +#check if we have all deps available +#if some are missing, we're going to use subproject instead and +#packaging CI will fail +if ! dpkg-checkbuilddeps; then + ./contrib/ci/ubuntu.sh + exit 0 +fi + #clone test firmware if [ "$CI_NETWORK" = "true" ]; then ./contrib/ci/get_test_firmware.sh diff --git a/contrib/ci/ubuntu.sh b/contrib/ci/ubuntu.sh index a80464160..d5e8a191b 100755 --- a/contrib/ci/ubuntu.sh +++ b/contrib/ci/ubuntu.sh @@ -9,6 +9,7 @@ if [ "$CI_NETWORK" = "true" ]; then fi #evaluate using Ubuntu's buildflags +#evaluate using Debian/Ubuntu's buildflags eval "$(dpkg-buildflags --export=sh)" #filter out -Bsymbolic-functions export LDFLAGS=$(dpkg-buildflags --get LDFLAGS | sed "s/-Wl,-Bsymbolic-functions\s//") From 439945c71c7cf3d557189f565d77cdc8916e8e55 Mon Sep 17 00:00:00 2001 From: Richard Hughes Date: Fri, 28 Aug 2020 16:52:05 +0100 Subject: [PATCH 355/607] trivial: Do not require and obsolete dbxtool --- contrib/fwupd.spec.in | 4 ---- 1 file changed, 4 deletions(-) diff --git a/contrib/fwupd.spec.in b/contrib/fwupd.spec.in index 7eb632ab5..d527e828b 100644 --- a/contrib/fwupd.spec.in +++ b/contrib/fwupd.spec.in @@ -124,10 +124,6 @@ Requires: libsoup%{?_isa} >= %{libsoup_version} Requires: bubblewrap Requires: shared-mime-info -%if 0%{?have_uefi} -Requires: dbxtool -%endif - %if 0%{?rhel} > 7 || 0%{?fedora} > 28 Recommends: python3 %endif From 019c096fccb75c2eb4a3d037da52e928adaf7d8d Mon Sep 17 00:00:00 2001 From: Richard Hughes Date: Fri, 28 Aug 2020 16:52:27 +0100 Subject: [PATCH 356/607] trivial: Fix Fedora s390x build --- contrib/fwupd.spec.in | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/contrib/fwupd.spec.in b/contrib/fwupd.spec.in index d527e828b..365f07437 100644 --- a/contrib/fwupd.spec.in +++ b/contrib/fwupd.spec.in @@ -289,7 +289,9 @@ mkdir -p --mode=0700 $RPM_BUILD_ROOT%{_localstatedir}/lib/fwupd/gnupg %{_bindir}/fwupdtpmevlog %endif %{_bindir}/dfu-tool +%if 0%{?have_uefi} %{_bindir}/dbxtool +%endif %{_bindir}/fwupdmgr %{_bindir}/fwupdtool %{_bindir}/fwupdagent @@ -324,7 +326,9 @@ mkdir -p --mode=0700 $RPM_BUILD_ROOT%{_localstatedir}/lib/fwupd/gnupg %{_datadir}/man/man1/fwupdtool.1.gz %{_datadir}/man/man1/fwupdagent.1.gz %{_datadir}/man/man1/dfu-tool.1.gz +%if 0%{?have_uefi} %{_datadir}/man/man1/dbxtool.1.gz +%endif %{_datadir}/man/man1/fwupdmgr.1.gz %if 0%{?have_uefi} %{_datadir}/man/man1/fwupdate.1.gz From 024b37fcee2f8a075226665702843a699df52551 Mon Sep 17 00:00:00 2001 From: Richard Hughes Date: Thu, 27 Aug 2020 22:53:37 +0100 Subject: [PATCH 357/607] trivial: Fix segfault when xmlb cache cannot be written --- plugins/dfu/dfu-tool.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/plugins/dfu/dfu-tool.c b/plugins/dfu/dfu-tool.c index 222d1fe82..9a99ef3e4 100644 --- a/plugins/dfu/dfu-tool.c +++ b/plugins/dfu/dfu-tool.c @@ -47,7 +47,8 @@ dfu_tool_private_free (DfuToolPrivate *priv) if (priv == NULL) return; g_free (priv->device_vid_pid); - g_object_unref (priv->cancellable); + if (priv->cancellable != NULL) + g_object_unref (priv->cancellable); g_object_unref (priv->quirks); if (priv->cmd_array != NULL) g_ptr_array_unref (priv->cmd_array); From 6f4b72cea5bc96027bd625e95330dc9bc410de0b Mon Sep 17 00:00:00 2001 From: Mario Limonciello Date: Fri, 28 Aug 2020 11:51:23 -0500 Subject: [PATCH 358/607] trivial: disable gusb self tests for ubuntu --- contrib/ci/ubuntu.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/contrib/ci/ubuntu.sh b/contrib/ci/ubuntu.sh index d5e8a191b..3de520790 100755 --- a/contrib/ci/ubuntu.sh +++ b/contrib/ci/ubuntu.sh @@ -15,7 +15,7 @@ eval "$(dpkg-buildflags --export=sh)" export LDFLAGS=$(dpkg-buildflags --get LDFLAGS | sed "s/-Wl,-Bsymbolic-functions\s//") rm -rf build -meson build -Dman=false -Dgtkdoc=true +meson build -Dman=false -Dgtkdoc=true -Dgusb:tests=false #build with clang ninja -C build test -v From 58eeeff9a8d06641d31d69a41976212825daeee4 Mon Sep 17 00:00:00 2001 From: Mario Limonciello Date: Fri, 28 Aug 2020 12:12:23 -0500 Subject: [PATCH 359/607] trivial: only run scan-build if compiler is clang --- contrib/ci/ubuntu.sh | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/contrib/ci/ubuntu.sh b/contrib/ci/ubuntu.sh index 3de520790..38ac943b5 100755 --- a/contrib/ci/ubuntu.sh +++ b/contrib/ci/ubuntu.sh @@ -25,4 +25,6 @@ mkdir -p dist/docs cp build/docs/* dist/docs -R #run static analysis (these mostly won't be critical) -ninja -C build scan-build -v +if [ "$CC" = "clang" ]; then + ninja -C build scan-build -v +fi From 879b8149c77df90190938a3134caef96caeacef9 Mon Sep 17 00:00:00 2001 From: Benson Leung Date: Tue, 25 Aug 2020 14:02:59 -0700 Subject: [PATCH 360/607] cros-ec: Set FWUPD_DEVICE_FLAG_UPDATABLE --- plugins/cros-ec/fu-cros-ec-usb-device.c | 1 + 1 file changed, 1 insertion(+) diff --git a/plugins/cros-ec/fu-cros-ec-usb-device.c b/plugins/cros-ec/fu-cros-ec-usb-device.c index 0308d57f9..061f93cf3 100644 --- a/plugins/cros-ec/fu-cros-ec-usb-device.c +++ b/plugins/cros-ec/fu-cros-ec-usb-device.c @@ -582,6 +582,7 @@ static void fu_cros_ec_usb_device_init (FuCrosEcUsbDevice *device) { fu_device_set_protocol (FU_DEVICE (device), "com.google.usb.crosec"); + fu_device_add_flag (FU_DEVICE (device), FWUPD_DEVICE_FLAG_UPDATABLE); fu_device_set_version_format (FU_DEVICE (device), FWUPD_VERSION_FORMAT_TRIPLET); } From 9832b4138cb36d98b3450b461ad425622a9cb3f3 Mon Sep 17 00:00:00 2001 From: Benson Leung Date: Tue, 28 Jul 2020 15:50:20 -0700 Subject: [PATCH 361/607] cros-ec: Restart to RO on detach and to RW on attach Add external command support and functions to reset to RO and RW. This will now jump to the RO no matter what, and update the RW, then jump to RW. --- plugins/cros-ec/fu-cros-ec-usb-device.c | 149 ++++++++++++++++++++++++ 1 file changed, 149 insertions(+) diff --git a/plugins/cros-ec/fu-cros-ec-usb-device.c b/plugins/cros-ec/fu-cros-ec-usb-device.c index 061f93cf3..bafed3414 100644 --- a/plugins/cros-ec/fu-cros-ec-usb-device.c +++ b/plugins/cros-ec/fu-cros-ec-usb-device.c @@ -23,6 +23,21 @@ #define BULK_RECV_TIMEOUT_MS 5000 #define UPDATE_DONE 0xB007AB1E +#define UPDATE_EXTRA_CMD 0xB007AB1F + +enum update_extra_command { + UPDATE_EXTRA_CMD_IMMEDIATE_RESET = 0, + UPDATE_EXTRA_CMD_JUMP_TO_RW = 1, + UPDATE_EXTRA_CMD_STAY_IN_RO = 2, + UPDATE_EXTRA_CMD_UNLOCK_RW = 3, + UPDATE_EXTRA_CMD_UNLOCK_ROLLBACK = 4, + UPDATE_EXTRA_CMD_INJECT_ENTROPY = 5, + UPDATE_EXTRA_CMD_PAIR_CHALLENGE = 6, + UPDATE_EXTRA_CMD_TOUCHPAD_INFO = 7, + UPDATE_EXTRA_CMD_TOUCHPAD_DEBUG = 8, + UPDATE_EXTRA_CMD_CONSOLE_READ_INIT = 9, + UPDATE_EXTRA_CMD_CONSOLE_READ_NEXT = 10, +}; struct _FuCrosEcUsbDevice { FuUsbDevice parent_instance; @@ -211,6 +226,44 @@ fu_cros_ec_usb_device_flush (FuDevice *device, gpointer user_data, return TRUE; } +/* + * Channel TPM extension/vendor command over USB. The payload of the USB frame + * in this case consists of the 2 byte subcommand code concatenated with the + * command body. The caller needs to indicate if a response is expected, and + * if it is - of what maximum size. + */ +static gboolean +fu_cros_ec_usb_ext_cmd (FuDevice *device, guint16 subcommand, + gpointer cmd_body, gsize body_size, + gpointer resp, gsize *resp_size, + gboolean allow_less, GError **error) +{ + FuCrosEcUsbDevice *self = FU_CROS_EC_USB_DEVICE (device); + guint16 *frame_ptr; + gsize usb_msg_size = sizeof (struct update_frame_header) + + sizeof (subcommand) + body_size; + g_autofree struct update_frame_header *ufh = g_malloc0 (usb_msg_size); + + ufh->block_size = GUINT32_TO_BE (usb_msg_size); + ufh->cmd.block_digest = 0; + ufh->cmd.block_base = GUINT32_TO_BE (UPDATE_EXTRA_CMD); + frame_ptr = (guint16 *)(ufh + 1); + *frame_ptr = GUINT16_TO_BE (subcommand); + + if (body_size != 0) { + gsize offset = sizeof (struct update_frame_header) + sizeof (subcommand); + if (!fu_memcpy_safe ((guint8 *) ufh, usb_msg_size, offset, + (const guint8 *) cmd_body, body_size, + 0x0, body_size, error)) + return FALSE; + } + + return fu_cros_ec_usb_device_do_xfer (self, (guint8 *)ufh, usb_msg_size, + (guint8 *)resp, + resp_size != NULL ? *resp_size : 0, + TRUE, NULL, error); +} + static gboolean fu_cros_ec_usb_device_start_request (FuDevice *device, gpointer user_data, GError **error) @@ -488,6 +541,73 @@ fu_cros_ec_usb_device_send_done (FuDevice *device) } } +static gboolean +fu_cros_ec_usb_device_send_subcommand (FuDevice *device, guint16 subcommand, + gpointer cmd_body, gsize body_size, + gpointer resp, gsize *resp_size, + gboolean allow_less, GError **error) +{ + fu_cros_ec_usb_device_send_done (device); + + if (!fu_cros_ec_usb_ext_cmd (device, subcommand, + cmd_body, body_size, + resp, resp_size, FALSE, error)) { + g_prefix_error (error, + "failed to send subcommand %" G_GUINT16_FORMAT ": ", + subcommand); + return FALSE; + } + + /* success */ + return TRUE; +} + +static gboolean +fu_cros_ec_usb_device_reset_to_ro (FuDevice *device, GError **error) +{ + guint8 response; + guint16 subcommand = UPDATE_EXTRA_CMD_STAY_IN_RO; + guint8 command_body[2]; /* Max command body size. */ + gsize command_body_size = 0; + gsize response_size = 1; + + /* send subcommand to remain in RO */ + if (!fu_cros_ec_usb_device_send_subcommand (device, subcommand, command_body, + command_body_size, &response, + &response_size, FALSE, error)) + return FALSE; + + response_size = 1; + subcommand = UPDATE_EXTRA_CMD_IMMEDIATE_RESET; + if (!fu_cros_ec_usb_device_send_subcommand (device, subcommand, command_body, + command_body_size, &response, + &response_size, FALSE, error)) { + /* failure here is ok */ + g_clear_error (error); + return TRUE; + } + + /* success */ + return TRUE; +} + +static gboolean +fu_cros_ec_usb_device_jump_to_rw (FuDevice *device) +{ + guint8 response; + guint16 subcommand = UPDATE_EXTRA_CMD_JUMP_TO_RW; + guint8 command_body[2]; /* Max command body size. */ + gsize command_body_size = 0; + gsize response_size = 1; + + fu_cros_ec_usb_device_send_subcommand (device, subcommand, command_body, + command_body_size, &response, + &response_size, FALSE, NULL); + + /* success */ + return TRUE; +} + static gboolean fu_cros_ec_usb_device_write_firmware (FuDevice *device, FuFirmware *firmware, @@ -578,6 +698,33 @@ fu_cros_ec_usb_device_prepare_firmware (FuDevice *device, return g_steal_pointer (&firmware); } +static gboolean +fu_cros_ec_usb_device_attach (FuDevice *self, GError **error) +{ + fu_device_set_remove_delay (self, FU_DEVICE_REMOVE_DELAY_RE_ENUMERATE); + fu_cros_ec_usb_device_jump_to_rw (self); + + fu_device_set_status (self, FWUPD_STATUS_DEVICE_RESTART); + fu_device_add_flag (self, FWUPD_DEVICE_FLAG_WAIT_FOR_REPLUG); + + /* success */ + return TRUE; +} + +static gboolean +fu_cros_ec_usb_device_detach (FuDevice *self, GError **error) +{ + fu_device_set_remove_delay (self, FU_DEVICE_REMOVE_DELAY_RE_ENUMERATE); + if (!fu_cros_ec_usb_device_reset_to_ro (self, error)) + return FALSE; + + fu_device_set_status (self, FWUPD_STATUS_DEVICE_RESTART); + fu_device_add_flag (self, FWUPD_DEVICE_FLAG_WAIT_FOR_REPLUG); + + /* success */ + return TRUE; +} + static void fu_cros_ec_usb_device_init (FuCrosEcUsbDevice *device) { @@ -619,6 +766,8 @@ fu_cros_ec_usb_device_class_init (FuCrosEcUsbDeviceClass *klass) { FuDeviceClass *klass_device = FU_DEVICE_CLASS (klass); FuUsbDeviceClass *klass_usb_device = FU_USB_DEVICE_CLASS (klass); + klass_device->attach = fu_cros_ec_usb_device_attach; + klass_device->detach = fu_cros_ec_usb_device_detach; klass_device->prepare_firmware = fu_cros_ec_usb_device_prepare_firmware; klass_device->setup = fu_cros_ec_usb_device_setup; klass_device->to_string = fu_cros_ec_usb_device_to_string; From 96bad357adabec2b16bc928bccbed1f89fd790b7 Mon Sep 17 00:00:00 2001 From: Benson Leung Date: Fri, 31 Jul 2020 16:49:25 -0700 Subject: [PATCH 362/607] Require libgusb 0.3.5 Newer version of libgusb has g_usb_device_get_configuration_index which will be used by cros-ec plugin. Skip bumping this dependency on Debian and Ubuntu as of this commit date, they don't know about 0.3.5 yet. --- contrib/fwupd.spec.in | 2 +- meson.build | 2 +- subprojects/gusb.wrap | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/contrib/fwupd.spec.in b/contrib/fwupd.spec.in index 365f07437..4e5195e47 100644 --- a/contrib/fwupd.spec.in +++ b/contrib/fwupd.spec.in @@ -1,6 +1,6 @@ %global glib2_version 2.45.8 %global libxmlb_version 0.1.3 -%global libgusb_version 0.3.3 +%global libgusb_version 0.3.5 %global libsoup_version 2.51.92 %global libjcat_version 0.1.0 %global systemd_version 231 diff --git a/meson.build b/meson.build index 9dc2c601f..2622f7c9b 100644 --- a/meson.build +++ b/meson.build @@ -201,7 +201,7 @@ else gudev = dependency('', required : false) endif libxmlb = dependency('xmlb', version : '>= 0.1.13', fallback : ['libxmlb', 'libxmlb_dep']) -gusb = dependency('gusb', version : '>= 0.3.3', fallback : ['gusb', 'gusb_dep']) +gusb = dependency('gusb', version : '>= 0.3.5', fallback : ['gusb', 'gusb_dep']) sqlite = dependency('sqlite3') libarchive = dependency('libarchive') endif diff --git a/subprojects/gusb.wrap b/subprojects/gusb.wrap index d0ce92146..539253671 100644 --- a/subprojects/gusb.wrap +++ b/subprojects/gusb.wrap @@ -1,4 +1,4 @@ [wrap-git] directory = gusb url = https://github.com/hughsie/libgusb.git -revision = 0.3.3 +revision = 0.3.5 From 7f3095d9ff4d5e5e6c5e1db43f3c35f0238c1889 Mon Sep 17 00:00:00 2001 From: Benson Leung Date: Wed, 29 Jul 2020 17:22:15 -0700 Subject: [PATCH 363/607] cros-ec: Use iConfiguration to determine RO versus RW versions This requires an API upgrade. libgusb 0.3.5 is required for iConfiguration. --- plugins/cros-ec/fu-cros-ec-usb-device.c | 79 ++++++++++++++++++++++++- 1 file changed, 77 insertions(+), 2 deletions(-) diff --git a/plugins/cros-ec/fu-cros-ec-usb-device.c b/plugins/cros-ec/fu-cros-ec-usb-device.c index bafed3414..adb6035a2 100644 --- a/plugins/cros-ec/fu-cros-ec-usb-device.c +++ b/plugins/cros-ec/fu-cros-ec-usb-device.c @@ -49,7 +49,10 @@ struct _FuCrosEcUsbDevice { guint32 writeable_offset; guint16 protocol_version; guint16 header_type; - struct cros_ec_version version; + struct cros_ec_version version; /* version of other region */ + struct cros_ec_version active_version; /* version of active region */ + gchar configuration[FU_CROS_EC_STRLEN]; + gboolean in_bootloader; }; G_DEFINE_TYPE (FuCrosEcUsbDevice, fu_cros_ec_usb_device, FU_TYPE_USB_DEVICE) @@ -66,6 +69,41 @@ typedef struct { gsize payload_size; } FuCrosEcUsbBlockInfo; +static gboolean +fu_cros_ec_usb_device_get_configuration (FuCrosEcUsbDevice *self, + GError **error) +{ + GUsbDevice *usb_device = fu_usb_device_get_dev (FU_USB_DEVICE (self)); + guint8 index; + g_autofree gchar *configuration = NULL; + +#if G_USB_CHECK_VERSION(0,3,5) + index = g_usb_device_get_configuration_index (usb_device); +#else + g_set_error_literal (error, + FWUPD_ERROR, + FWUPD_ERROR_NOT_SUPPORTED, + "this version of GUsb is not supported"); + return FALSE; +#endif + configuration = g_usb_device_get_string_descriptor (usb_device, + index, + error); + if (configuration == NULL) + return FALSE; + + if (g_strlcpy (self->configuration, configuration, FU_CROS_EC_STRLEN) == 0) { + g_set_error_literal (error, + FWUPD_ERROR, + FWUPD_ERROR_INTERNAL, + "empty iConfiguration"); + return FALSE; + } + + /* success */ + return TRUE; +} + static gboolean fu_cros_ec_usb_device_find_interface (FuUsbDevice *device, GError **error) @@ -301,6 +339,7 @@ fu_cros_ec_usb_device_setup (FuDevice *device, GError **error) FuCrosEcUsbDevice *self = FU_CROS_EC_USB_DEVICE (device); guint32 error_code; START_RESP start_resp; + g_auto(GStrv) config_split = NULL; /* flush all data from endpoint to recover in case of error */ if (!fu_device_retry (device, fu_cros_ec_usb_device_flush, @@ -351,6 +390,32 @@ fu_cros_ec_usb_device_setup (FuDevice *device, GError **error) self->targ.common.min_rollback = GINT32_FROM_BE (start_resp.rpdu.common.min_rollback); self->targ.common.key_version = GUINT32_FROM_BE (start_resp.rpdu.common.key_version); + /* get active version string and running region from iConfiguration */ + if (!fu_cros_ec_usb_device_get_configuration (self, error)) + return FALSE; + config_split = g_strsplit (self->configuration, ":", 2); + if (g_strv_length (config_split) < 2) { + /* no prefix found so fall back to offset */ + self->in_bootloader = self->writeable_offset != 0x0; + if (!fu_cros_ec_parse_version (self->configuration, + &self->active_version, error)) { + g_prefix_error (error, + "failed parsing device's version: %32s: ", + self->configuration); + return FALSE; + } + } else { + self->in_bootloader = g_strcmp0 ("RO", config_split[0]) == 0; + if (!fu_cros_ec_parse_version (config_split[1], + &self->active_version, error)) { + g_prefix_error (error, + "failed parsing device's version: %32s: ", + config_split[1]); + return FALSE; + } + } + + /* get the other region's version string from targ */ if (!fu_cros_ec_parse_version (self->targ.common.version, &self->version, error)) { g_prefix_error (error, @@ -359,7 +424,17 @@ fu_cros_ec_usb_device_setup (FuDevice *device, GError **error) return FALSE; } - fu_device_set_version (FU_DEVICE (device), self->version.triplet); + if (self->in_bootloader) { + fu_device_add_flag (device, FWUPD_DEVICE_FLAG_IS_BOOTLOADER); + fu_device_set_version (FU_DEVICE (device), self->version.triplet); + fu_device_set_version_bootloader (FU_DEVICE (device), + self->active_version.triplet); + } else { + fu_device_remove_flag (device, FWUPD_DEVICE_FLAG_IS_BOOTLOADER); + fu_device_set_version (FU_DEVICE (device), self->active_version.triplet); + fu_device_set_version_bootloader (FU_DEVICE (device), + self->version.triplet); + } fu_device_add_instance_id (FU_DEVICE (device), self->version.boardname); /* success */ From 24f0570e1b1cbcd7f36e51f97a662db7a23c1ecb Mon Sep 17 00:00:00 2001 From: Benson Leung Date: Fri, 31 Jul 2020 17:16:44 -0700 Subject: [PATCH 364/607] cros-ec: Set FWUPD_DEVICE_FLAG_DUAL_IMAGE --- plugins/cros-ec/fu-cros-ec-usb-device.c | 1 + 1 file changed, 1 insertion(+) diff --git a/plugins/cros-ec/fu-cros-ec-usb-device.c b/plugins/cros-ec/fu-cros-ec-usb-device.c index adb6035a2..d98441abf 100644 --- a/plugins/cros-ec/fu-cros-ec-usb-device.c +++ b/plugins/cros-ec/fu-cros-ec-usb-device.c @@ -806,6 +806,7 @@ fu_cros_ec_usb_device_init (FuCrosEcUsbDevice *device) fu_device_set_protocol (FU_DEVICE (device), "com.google.usb.crosec"); fu_device_add_flag (FU_DEVICE (device), FWUPD_DEVICE_FLAG_UPDATABLE); fu_device_set_version_format (FU_DEVICE (device), FWUPD_VERSION_FORMAT_TRIPLET); + fu_device_add_flag (FU_DEVICE (device), FWUPD_DEVICE_FLAG_DUAL_IMAGE); } static void From a5487d48483be01a3d90b32abdd0b9214ad31054 Mon Sep 17 00:00:00 2001 From: Benson Leung Date: Sat, 1 Aug 2020 13:10:24 -0700 Subject: [PATCH 365/607] cros-ec: Do RO write as ANOTHER WRITE using custom flags This implements the following simple state machine: 1. Reboot to RO, Update RW first, set ANOTHER_WRITE_REQUIRED 2. Second time around, don't reboot into RO. Stay in RW. 3. Update RO. 4. Done. --- plugins/cros-ec/fu-cros-ec-usb-device.c | 32 +++++++++++++++++++++---- 1 file changed, 27 insertions(+), 5 deletions(-) diff --git a/plugins/cros-ec/fu-cros-ec-usb-device.c b/plugins/cros-ec/fu-cros-ec-usb-device.c index d98441abf..6910081dc 100644 --- a/plugins/cros-ec/fu-cros-ec-usb-device.c +++ b/plugins/cros-ec/fu-cros-ec-usb-device.c @@ -689,6 +689,7 @@ fu_cros_ec_usb_device_write_firmware (FuDevice *device, FwupdInstallFlags flags, GError **error) { + FuCrosEcUsbDevice *self = FU_CROS_EC_USB_DEVICE (device); GPtrArray *sections; FuCrosEcFirmware *cros_ec_firmware = FU_CROS_EC_FIRMWARE (firmware); gint num_txed_sections = 0; @@ -727,6 +728,16 @@ fu_cros_ec_usb_device_write_firmware (FuDevice *device, return FALSE; } + if (self->in_bootloader) + fu_device_set_custom_flags (device, "rw-written"); + else if (fu_device_has_custom_flag (device, "rw-written")) + fu_device_set_custom_flags (device, "ro-written,rw-written"); + else + fu_device_set_custom_flags (device, "ro-written"); + + if (fu_device_has_custom_flag (device, "rw-written") && + !fu_device_has_custom_flag (device, "ro-written")) + fu_device_add_flag (device, FWUPD_DEVICE_FLAG_ANOTHER_WRITE_REQUIRED); /* success */ return TRUE; } @@ -774,13 +785,20 @@ fu_cros_ec_usb_device_prepare_firmware (FuDevice *device, } static gboolean -fu_cros_ec_usb_device_attach (FuDevice *self, GError **error) +fu_cros_ec_usb_device_attach (FuDevice *device, GError **error) { - fu_device_set_remove_delay (self, FU_DEVICE_REMOVE_DELAY_RE_ENUMERATE); - fu_cros_ec_usb_device_jump_to_rw (self); + FuCrosEcUsbDevice *self = FU_CROS_EC_USB_DEVICE (device); - fu_device_set_status (self, FWUPD_STATUS_DEVICE_RESTART); - fu_device_add_flag (self, FWUPD_DEVICE_FLAG_WAIT_FOR_REPLUG); + if (!self->in_bootloader) { + /* already in rw, so skip jump to rw */ + return TRUE; + } + + fu_device_set_remove_delay (device, FU_DEVICE_REMOVE_DELAY_RE_ENUMERATE); + fu_cros_ec_usb_device_jump_to_rw (device); + + fu_device_set_status (device, FWUPD_STATUS_DEVICE_RESTART); + fu_device_add_flag (device, FWUPD_DEVICE_FLAG_WAIT_FOR_REPLUG); /* success */ return TRUE; @@ -789,6 +807,10 @@ fu_cros_ec_usb_device_attach (FuDevice *self, GError **error) static gboolean fu_cros_ec_usb_device_detach (FuDevice *self, GError **error) { + if (fu_device_has_custom_flag (self, "rw-written") && + !fu_device_has_custom_flag (self, "ro-written")) + return TRUE; + fu_device_set_remove_delay (self, FU_DEVICE_REMOVE_DELAY_RE_ENUMERATE); if (!fu_cros_ec_usb_device_reset_to_ro (self, error)) return FALSE; From 72aea1f8ed8259b5a4c7a7859b85e2bcfc0020ab Mon Sep 17 00:00:00 2001 From: Benson Leung Date: Sat, 1 Aug 2020 14:07:34 -0700 Subject: [PATCH 366/607] cros-ec: Save new firmware version on successful write --- plugins/cros-ec/fu-cros-ec-firmware.c | 17 +++++++++++++---- plugins/cros-ec/fu-cros-ec-firmware.h | 4 +++- plugins/cros-ec/fu-cros-ec-usb-device.c | 8 ++++++++ 3 files changed, 24 insertions(+), 5 deletions(-) diff --git a/plugins/cros-ec/fu-cros-ec-firmware.c b/plugins/cros-ec/fu-cros-ec-firmware.c index c50de4dc7..12001174c 100644 --- a/plugins/cros-ec/fu-cros-ec-firmware.c +++ b/plugins/cros-ec/fu-cros-ec-firmware.c @@ -115,7 +115,7 @@ fu_cros_ec_firmware_parse (FuFirmware *firmware, fmap_fwid_name); return FALSE; } - if (!fu_memcpy_safe ((guint8 *) section->version, + if (!fu_memcpy_safe ((guint8 *) section->raw_version, FU_FMAP_FIRMWARE_STRLEN, 0x0, g_bytes_get_data (fwid_bytes, NULL), g_bytes_get_size (fwid_bytes), 0x0, @@ -131,16 +131,25 @@ fu_cros_ec_firmware_parse (FuFirmware *firmware, } section->offset = fu_firmware_image_get_addr (img); section->size = g_bytes_get_size (payload_bytes); - fu_firmware_image_set_version (img, section->version); + fu_firmware_image_set_version (img, section->raw_version); section->image_idx = fu_firmware_image_get_idx (img); + if (!fu_cros_ec_parse_version (section->raw_version, + §ion->version, + error)) { + g_prefix_error (error, + "failed parsing firmware's version: %32s: ", + section->raw_version); + return FALSE; + } + if (rw) { - if (!fu_cros_ec_parse_version (section->version, + if (!fu_cros_ec_parse_version (section->raw_version, &self->version, error)) { g_prefix_error (error, "failed parsing firmware's version: %32s: ", - section->version); + section->raw_version); return FALSE; } fu_firmware_set_version (firmware, diff --git a/plugins/cros-ec/fu-cros-ec-firmware.h b/plugins/cros-ec/fu-cros-ec-firmware.h index c7b09be8e..e6aaebef2 100644 --- a/plugins/cros-ec/fu-cros-ec-firmware.h +++ b/plugins/cros-ec/fu-cros-ec-firmware.h @@ -8,6 +8,7 @@ #include "fu-firmware.h" #include "fu-fmap-firmware.h" +#include "fu-cros-ec-common.h" #define FU_TYPE_CROS_EC_FIRMWARE (fu_cros_ec_firmware_get_type ()) G_DECLARE_FINAL_TYPE (FuCrosEcFirmware, fu_cros_ec_firmware, FU, CROS_EC_FIRMWARE, FuFmapFirmware) @@ -33,7 +34,8 @@ typedef struct { guint32 offset; gsize size; FuCrosEcFirmwareUpgradeStatus ustatus; - gchar version[FU_FMAP_FIRMWARE_STRLEN]; + gchar raw_version[FU_FMAP_FIRMWARE_STRLEN]; + struct cros_ec_version version; gint32 rollback; guint32 key_version; guint64 image_idx; diff --git a/plugins/cros-ec/fu-cros-ec-usb-device.c b/plugins/cros-ec/fu-cros-ec-usb-device.c index 6910081dc..97b187f65 100644 --- a/plugins/cros-ec/fu-cros-ec-usb-device.c +++ b/plugins/cros-ec/fu-cros-ec-usb-device.c @@ -715,6 +715,14 @@ fu_cros_ec_usb_device_write_firmware (FuDevice *device, return FALSE; } num_txed_sections++; + + if (self->in_bootloader) { + fu_device_set_version (FU_DEVICE (device), + section->version.triplet); + } else { + fu_device_set_version_bootloader (FU_DEVICE (device), + section->version.triplet); + } } } /* send done */ From 40efe471c441a5c3f88244b6790a8bdf2233ea27 Mon Sep 17 00:00:00 2001 From: Benson Leung Date: Fri, 21 Aug 2020 17:12:58 -0700 Subject: [PATCH 367/607] Disable gusb:tests --- contrib/ci/fedora.sh | 1 + contrib/ci/trust.sh | 1 + 2 files changed, 2 insertions(+) diff --git a/contrib/ci/fedora.sh b/contrib/ci/fedora.sh index 32ab1c022..dcc6590b0 100755 --- a/contrib/ci/fedora.sh +++ b/contrib/ci/fedora.sh @@ -10,6 +10,7 @@ meson .. \ -Dgtkdoc=true \ -Dman=true \ -Dtests=true \ + -Dgusb:tests=false \ -Dplugin_dummy=true \ -Dplugin_flashrom=true \ -Dplugin_modem_manager=false \ diff --git a/contrib/ci/trust.sh b/contrib/ci/trust.sh index 78f1964c8..d1ebc5c3a 100755 --- a/contrib/ci/trust.sh +++ b/contrib/ci/trust.sh @@ -14,6 +14,7 @@ rm -rf build meson build \ -Dman=false \ -Ddaemon=false \ + -Dgusb:tests=false \ -Dplugin_tpm=false \ -Dplugin_modem_manager=false \ -Dplugin_flashrom=false \ From c0fcd64b4a93b64117066001ac67a02f39d407ce Mon Sep 17 00:00:00 2001 From: Benson Leung Date: Fri, 28 Aug 2020 09:22:05 -0700 Subject: [PATCH 368/607] Bump libgusb-devel version to 0.3.5 for debian --- contrib/ci/dependencies.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/contrib/ci/dependencies.xml b/contrib/ci/dependencies.xml index 1c3db8cf7..8c9fc8d6a 100644 --- a/contrib/ci/dependencies.xml +++ b/contrib/ci/dependencies.xml @@ -766,7 +766,7 @@ - (>= 0.3.3) + (>= 0.3.5) libgusb-dev:s390x From 783bc5c8a8d3f47206588c48f0f58113ef611b95 Mon Sep 17 00:00:00 2001 From: Jerry Zhang Date: Fri, 28 Aug 2020 22:27:00 -0500 Subject: [PATCH 369/607] dfu: Support download of large DFU firmware The nr_chunks is defined as an unsigned short, the max value is 65536. Assume the transfer_size reported by device is 4096, the maximum size of DFU firmware supported is 65536 * 4096 = 256MB. To support larger DFU firmware, we can change the guint16 to guint32. --- plugins/dfu/dfu-target.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/plugins/dfu/dfu-target.c b/plugins/dfu/dfu-target.c index 5ada4f21a..ac5e9f683 100644 --- a/plugins/dfu/dfu-target.c +++ b/plugins/dfu/dfu-target.c @@ -1106,7 +1106,7 @@ dfu_target_download_element_dfu (DfuTarget *target, { DfuTargetPrivate *priv = GET_PRIVATE (target); GBytes *bytes; - guint16 nr_chunks; + guint32 nr_chunks; guint16 transfer_size = dfu_device_get_transfer_size (priv->device); /* round up as we have to transfer incomplete blocks */ @@ -1121,7 +1121,7 @@ dfu_target_download_element_dfu (DfuTarget *target, return FALSE; } dfu_target_set_action (target, FWUPD_STATUS_DEVICE_WRITE); - for (guint16 i = 0; i < nr_chunks + 1; i++) { + for (guint32 i = 0; i < nr_chunks + 1; i++) { gsize length; guint32 offset; g_autoptr(GBytes) bytes_tmp = NULL; From 3e82beeddac31292c50229e59e2404865edee5ad Mon Sep 17 00:00:00 2001 From: Jan Tojnar Date: Sun, 30 Aug 2020 12:24:54 +0200 Subject: [PATCH 370/607] build: fix systemd_root_prefix for systemd 246 systemd 246 replaced the variable names (https://github.com/systemd/systemd/commit/4908de44b0a0409f84a7cdc5641b114d6ce8ba03). The old ones are kept for backwards compatibility but some of them interpolate new variable names so redefining them breaks. Curiously, only systemdshutdowndir is affected by that here. --- meson.build | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/meson.build b/meson.build index 2622f7c9b..473015489 100644 --- a/meson.build +++ b/meson.build @@ -378,7 +378,7 @@ if build_standalone and get_option('systemd') else systemdunitdir = systemd.get_pkgconfig_variable('systemdsystemunitdir', define_variable: ['rootprefix', systemd_root_prefix]) systemdsystempresetdir = systemd.get_pkgconfig_variable('systemdsystempresetdir', define_variable: ['rootprefix', systemd_root_prefix]) - systemd_shutdown_dir = systemd.get_pkgconfig_variable('systemdshutdowndir', define_variable: ['rootprefix', systemd_root_prefix]) + systemd_shutdown_dir = systemd.get_pkgconfig_variable('systemdshutdowndir', define_variable: [systemd.version().version_compare('>= 246') ? 'root_prefix' : 'rootprefix', systemd_root_prefix]) endif endif From 840e84bcf2a8e77453849016ca1e2e269cc22990 Mon Sep 17 00:00:00 2001 From: Richard Hughes Date: Tue, 21 Jul 2020 15:20:21 +0100 Subject: [PATCH 371/607] elantp: Add a plugin to update Elan Touchpads using HID --- contrib/fwupd.spec.in | 1 + plugins/elantp/README.md | 48 +++ plugins/elantp/elantp.quirk | 24 ++ plugins/elantp/fu-elantp-common.c | 18 + plugins/elantp/fu-elantp-common.h | 40 +++ plugins/elantp/fu-elantp-firmware.c | 98 +++++ plugins/elantp/fu-elantp-firmware.h | 16 + plugins/elantp/fu-elantp-hid-device.c | 494 ++++++++++++++++++++++++++ plugins/elantp/fu-elantp-hid-device.h | 12 + plugins/elantp/fu-plugin-elantp.c | 22 ++ plugins/elantp/meson.build | 35 ++ plugins/meson.build | 1 + 12 files changed, 809 insertions(+) create mode 100644 plugins/elantp/README.md create mode 100644 plugins/elantp/elantp.quirk create mode 100644 plugins/elantp/fu-elantp-common.c create mode 100644 plugins/elantp/fu-elantp-common.h create mode 100644 plugins/elantp/fu-elantp-firmware.c create mode 100644 plugins/elantp/fu-elantp-firmware.h create mode 100644 plugins/elantp/fu-elantp-hid-device.c create mode 100644 plugins/elantp/fu-elantp-hid-device.h create mode 100644 plugins/elantp/fu-plugin-elantp.c create mode 100644 plugins/elantp/meson.build diff --git a/contrib/fwupd.spec.in b/contrib/fwupd.spec.in index 4e5195e47..49e26f837 100644 --- a/contrib/fwupd.spec.in +++ b/contrib/fwupd.spec.in @@ -375,6 +375,7 @@ mkdir -p --mode=0700 $RPM_BUILD_ROOT%{_localstatedir}/lib/fwupd/gnupg %{_libdir}/fwupd-plugins-3/libfu_plugin_dell_dock.so %{_libdir}/fwupd-plugins-3/libfu_plugin_dfu.so %{_libdir}/fwupd-plugins-3/libfu_plugin_ebitdo.so +%{_libdir}/fwupd-plugins-3/libfu_plugin_elantp.so %{_libdir}/fwupd-plugins-3/libfu_plugin_emmc.so %{_libdir}/fwupd-plugins-3/libfu_plugin_ep963x.so %{_libdir}/fwupd-plugins-3/libfu_plugin_fastboot.so diff --git a/plugins/elantp/README.md b/plugins/elantp/README.md new file mode 100644 index 000000000..cd1bbc37d --- /dev/null +++ b/plugins/elantp/README.md @@ -0,0 +1,48 @@ +Elan TouchPad +============= + +Introduction +------------ + +This plugin allows updating Touchpad devices from Elan. Devices are enumerated +using HID. + +Firmware Format +--------------- + +The daemon will decompress the cabinet archive and extract a firmware blob in +an unspecified binary file format. + +This plugin supports the following protocol ID: + + * tw.com.emc.elantp + +GUID Generation +--------------- + +These device uses the standard DeviceInstanceId values, e.g. + + * `HIDRAW\VEN_04F3&DEV_3010` + +Additionally another instance ID is added which corresponds to the module ID: + + * `HIDRAW\VEN_04F3&DEV_3010&MOD_1234` + +These devices also use custom GUID values for the IC configuration, e.g. + + * `ELANTP\ICTYPE_09` + +Vendor ID Security +------------------ + +The vendor ID is set from the HID vendor, for example set to `HIDRAW:0x17EF` + +Quirk use +--------- + +This plugin uses the following plugin-specific quirks: + +| Quirk | Description | Minimum fwupd version | +|------------------------|-------------------------------------------|-----------------------| +| `ElantpIcPageCount` | The IC page count | 1.4.6 | +| `ElantpIapPassword` | The IAP password | 1.4.6 | diff --git a/plugins/elantp/elantp.quirk b/plugins/elantp/elantp.quirk new file mode 100644 index 000000000..7d3fcca80 --- /dev/null +++ b/plugins/elantp/elantp.quirk @@ -0,0 +1,24 @@ +[DeviceInstanceId=HIDRAW\VEN_04F3&DEV_3010] +Plugin = elantp +GType = FuElantpHidDevice + +[DeviceInstanceId=HIDRAW\VEN_04F3&DEV_30C5] +Plugin = elantp +GType = FuElantpHidDevice + +[DeviceInstanceId=ELANTP\ICTYPE_0A] +ElantpIcPageCount = 768 +ElantpIapPassword = 0xE15A + +[DeviceInstanceId=ELANTP\ICTYPE_09] +ElantpIcPageCount = 768 +ElantpIapPassword = 0x1EA5 + +[DeviceInstanceId=ELANTP\ICTYPE_0D] +ElantpIcPageCount = 896 +ElantpIapPassword = 0x1EA5 + +[DeviceInstanceId=ELANTP\ICTYPE_10] +ElantpIcPageCount = 1024 +ElantpIapPassword = 0x1EA5 +Flags = iap-version-2 diff --git a/plugins/elantp/fu-elantp-common.c b/plugins/elantp/fu-elantp-common.c new file mode 100644 index 000000000..538421752 --- /dev/null +++ b/plugins/elantp/fu-elantp-common.c @@ -0,0 +1,18 @@ +/* + * Copyright (C) 2020 Richard Hughes + * + * SPDX-License-Identifier: LGPL-2.1+ + */ + +#include "config.h" + +#include "fu-elantp-common.h" + +guint16 +fu_elantp_calc_checksum (const guint8 *data, gsize length) +{ + guint16 checksum = 0; + for (gsize i = 0; i < length; i += 2) + checksum += ((guint16) (data[i+1]) << 8) | (data[i]); + return checksum; +} diff --git a/plugins/elantp/fu-elantp-common.h b/plugins/elantp/fu-elantp-common.h new file mode 100644 index 000000000..94d60e1a5 --- /dev/null +++ b/plugins/elantp/fu-elantp-common.h @@ -0,0 +1,40 @@ +/* + * Copyright (C) 2020 Richard Hughes + * + * SPDX-License-Identifier: LGPL-2.1+ + */ + +#pragma once + +#include + +#define FW_PAGE_SIZE 64 + +#define ETP_CMD_GET_HARDWARE_ID 0x0100 +#define ETP_CMD_GET_MODULE_ID 0x0101 +#define ETP_CMD_I2C_FW_CHECKSUM 0x030F +#define ETP_CMD_I2C_FW_VERSION 0x0102 +#define ETP_CMD_I2C_IAP 0x0311 +#define ETP_CMD_I2C_IAP_CHECKSUM 0x0315 +#define ETP_CMD_I2C_IAP_CTRL 0x0310 +#define ETP_CMD_I2C_IAP_ICBODY 0x0110 +#define ETP_CMD_I2C_IAP_RESET 0x0314 +#define ETP_CMD_I2C_IAP_VERSION 0x0111 +#define ETP_CMD_I2C_IAP_VERSION_2 0x0110 +#define ETP_CMD_I2C_OSM_VERSION 0x0103 + +#define ETP_I2C_ENABLE_REPORT 0x0800 + +#define ETP_I2C_IAP_RESET 0xF0F0 +#define ETP_I2C_MAIN_MODE_ON (1 << 9) + +#define ETP_I2C_IAP_REG_L 0x01 +#define ETP_I2C_IAP_REG_H 0x06 + +#define ETP_FW_IAP_INTF_ERR (1 << 4) +#define ETP_FW_IAP_PAGE_ERR (1 << 5) +#define ETP_FW_IAP_CHECK_PW (1 << 7) +#define ETP_FW_IAP_LAST_FIT (1 << 9) + +guint16 fu_elantp_calc_checksum (const guint8 *data, + gsize length); diff --git a/plugins/elantp/fu-elantp-firmware.c b/plugins/elantp/fu-elantp-firmware.c new file mode 100644 index 000000000..bd9288b3f --- /dev/null +++ b/plugins/elantp/fu-elantp-firmware.c @@ -0,0 +1,98 @@ +/* + * Copyright (C) 2020 Richard Hughes + * + * SPDX-License-Identifier: LGPL-2.1+ + */ + +#include "config.h" + +#include "fu-common.h" + +#include "fu-elantp-common.h" +#include "fu-elantp-firmware.h" + +struct _FuElantpFirmware { + FuFirmwareClass parent_instance; + guint16 module_id; + guint16 iap_addr; +}; + +G_DEFINE_TYPE (FuElantpFirmware, fu_elantp_firmware, FU_TYPE_FIRMWARE) + +/* firmware block update */ +#define ETP_IAP_START_ADDR 0x0083 + +guint16 +fu_elantp_firmware_get_module_id (FuElantpFirmware *self) +{ + g_return_val_if_fail (FU_IS_ELANTP_FIRMWARE (self), 0); + return self->module_id; +} + +guint16 +fu_elantp_firmware_get_iap_addr (FuElantpFirmware *self) +{ + g_return_val_if_fail (FU_IS_ELANTP_FIRMWARE (self), 0); + return self->iap_addr; +} + +static void +fu_elantp_firmware_to_string (FuFirmware *firmware, guint idt, GString *str) +{ + FuElantpFirmware *self = FU_ELANTP_FIRMWARE (firmware); + fu_common_string_append_kx (str, idt, "IapAddr", self->iap_addr); + fu_common_string_append_kx (str, idt, "ModuleId", self->module_id); +} + +static gboolean +fu_elantp_firmware_parse (FuFirmware *firmware, + GBytes *fw, + guint64 addr_start, + guint64 addr_end, + FwupdInstallFlags flags, + GError **error) +{ + FuElantpFirmware *self = FU_ELANTP_FIRMWARE (firmware); + gsize bufsz = 0; + guint16 iap_addr_wrds; + guint16 module_id_wrds; + const guint8 *buf = g_bytes_get_data (fw, &bufsz); + g_autoptr(FuFirmwareImage) img = fu_firmware_image_new (fw); + + /* presumably in words */ + if (!fu_common_read_uint16_safe (buf, bufsz, ETP_IAP_START_ADDR * 2, + &iap_addr_wrds, G_LITTLE_ENDIAN, error)) + return FALSE; + self->iap_addr = iap_addr_wrds * 2; + + /* read module ID */ + if (!fu_common_read_uint16_safe (buf, bufsz, self->iap_addr, + &module_id_wrds, G_LITTLE_ENDIAN, error)) + return FALSE; + if (!fu_common_read_uint16_safe (buf, bufsz, module_id_wrds * 2, + &self->module_id, G_LITTLE_ENDIAN, error)) + return FALSE; + + /* whole image */ + fu_firmware_add_image (firmware, img); + return TRUE; +} + +static void +fu_elantp_firmware_init (FuElantpFirmware *self) +{ +} + +static void +fu_elantp_firmware_class_init (FuElantpFirmwareClass *klass) +{ + FuFirmwareClass *klass_firmware = FU_FIRMWARE_CLASS (klass); + klass_firmware->parse = fu_elantp_firmware_parse; + klass_firmware->to_string = fu_elantp_firmware_to_string; +} + +FuFirmware * +fu_elantp_firmware_new (void) +{ + return FU_FIRMWARE (g_object_new (FU_TYPE_ELANTP_FIRMWARE, NULL)); +} diff --git a/plugins/elantp/fu-elantp-firmware.h b/plugins/elantp/fu-elantp-firmware.h new file mode 100644 index 000000000..1881b9794 --- /dev/null +++ b/plugins/elantp/fu-elantp-firmware.h @@ -0,0 +1,16 @@ +/* + * Copyright (C) 2020 Richard Hughes + * + * SPDX-License-Identifier: LGPL-2.1+ + */ + +#pragma once + +#include "fu-firmware.h" + +#define FU_TYPE_ELANTP_FIRMWARE (fu_elantp_firmware_get_type ()) +G_DECLARE_FINAL_TYPE (FuElantpFirmware, fu_elantp_firmware, FU, ELANTP_FIRMWARE, FuFirmware) + +FuFirmware *fu_elantp_firmware_new (void); +guint16 fu_elantp_firmware_get_module_id (FuElantpFirmware *self); +guint16 fu_elantp_firmware_get_iap_addr (FuElantpFirmware *self); diff --git a/plugins/elantp/fu-elantp-hid-device.c b/plugins/elantp/fu-elantp-hid-device.c new file mode 100644 index 000000000..e6cb76ffe --- /dev/null +++ b/plugins/elantp/fu-elantp-hid-device.c @@ -0,0 +1,494 @@ +/* + * Copyright (C) 2020 Richard Hughes + * + * SPDX-License-Identifier: LGPL-2.1+ + */ + +#include "config.h" + +#include +#include + +#include "fu-elantp-common.h" +#include "fu-elantp-firmware.h" +#include "fu-elantp-hid-device.h" + +#include "fu-chunk.h" + +struct _FuElantpHidDevice { + FuUdevDevice parent_instance; + guint16 ic_page_count; + guint16 iap_ctrl; + guint16 iap_password; + guint16 module_id; +}; + +#define ELANTP_DELAY_COMPLETE 1200 /* ms */ +#define ELANTP_DELAY_RESET 30 /* ms */ +#define ELANTP_DELAY_UNLOCK 100 /* ms */ +#define ELANTP_DELAY_WRITE_BLOCK 35 /* ms */ + +G_DEFINE_TYPE (FuElantpHidDevice, fu_elantp_hid_device, FU_TYPE_UDEV_DEVICE) + +static void +fu_elantp_hid_device_to_string (FuDevice *device, guint idt, GString *str) +{ + FuElantpHidDevice *self = FU_ELANTP_HID_DEVICE (device); + fu_common_string_append_kx (str, idt, "ModuleId", self->module_id); + fu_common_string_append_kx (str, idt, "IcPageCount", self->ic_page_count); + fu_common_string_append_kx (str, idt, "EapCtrl", self->iap_ctrl); +} + +static gboolean +fu_elantp_hid_device_probe (FuUdevDevice *device, GError **error) +{ + /* check is valid */ + if (g_strcmp0 (fu_udev_device_get_subsystem (device), "hidraw") != 0) { + g_set_error (error, + FWUPD_ERROR, + FWUPD_ERROR_NOT_SUPPORTED, + "is not correct subsystem=%s, expected hidraw", + fu_udev_device_get_subsystem (device)); + return FALSE; + } + + /* set the physical ID */ + return fu_udev_device_set_physical_id (device, "hid", error); +} + +static gboolean +fu_elantp_hid_device_send_cmd (FuElantpHidDevice *self, + guint8 *tx, gsize txsz, + guint8 *rx, gsize rxsz, + GError **error) +{ + g_autofree guint8 *buf = NULL; + + if (!fu_udev_device_ioctl (FU_UDEV_DEVICE (self), + HIDIOCSFEATURE(txsz), tx, + NULL, error)) + return FALSE; + if (rxsz == 0) + return TRUE; + + /* GetFeature */ + buf = g_malloc0 (rxsz + 1); + buf[0] = tx[0]; /* report number */ + if (!fu_udev_device_ioctl (FU_UDEV_DEVICE (self), + HIDIOCGFEATURE(rxsz + 3), buf, + NULL, error)) + return FALSE; + + /* success */ + memcpy (rx, buf + 0x3, rxsz); + return TRUE; +} + +static gboolean +fu_elantp_hid_device_read_cmd (FuElantpHidDevice *self, guint16 reg, + guint8 *rx, gsize rxsz, GError **error) +{ + guint8 buf[5] = { 0x0d, 0x05, 0x03 }; + fu_common_write_uint16 (buf + 0x3, reg, G_LITTLE_ENDIAN); + if (g_getenv ("FWUPD_ELANTP_VERBOSE") != NULL) + fu_common_dump_raw (G_LOG_DOMAIN, "ReadCmd", buf, sizeof(buf)); + return fu_elantp_hid_device_send_cmd (self, buf, sizeof(buf), rx, rxsz, error); +} + +static gint +fu_elantp_hid_device_write_cmd (FuElantpHidDevice *self, + guint16 reg, guint16 cmd, + GError **error) +{ + guint8 buf[5] = { 0x0d }; + fu_common_write_uint16 (buf + 0x1, reg, G_LITTLE_ENDIAN); + fu_common_write_uint16 (buf + 0x3, cmd, G_LITTLE_ENDIAN); + if (g_getenv ("FWUPD_ELANTP_VERBOSE") != NULL) + fu_common_dump_raw (G_LOG_DOMAIN, "WriteCmd", buf, sizeof(buf)); + + return fu_elantp_hid_device_send_cmd (self, buf, sizeof(buf), NULL, 0, error); +} + +static gboolean +fu_elantp_hid_device_ensure_iap_ctrl (FuElantpHidDevice *self, GError **error) +{ + guint8 buf[2] = { 0x0 }; + if (!fu_elantp_hid_device_read_cmd (self, ETP_CMD_I2C_IAP_CTRL, buf, sizeof(buf), error)) { + g_prefix_error (error, "failed to read IAPControl: "); + return FALSE; + } + self->iap_ctrl = fu_common_read_uint16 (buf, G_LITTLE_ENDIAN); + + /* in bootloader mode? */ + if ((self->iap_ctrl & ETP_I2C_MAIN_MODE_ON) == 0) + fu_device_add_flag (FU_DEVICE (self), FWUPD_DEVICE_FLAG_IS_BOOTLOADER); + else + fu_device_remove_flag (FU_DEVICE (self), FWUPD_DEVICE_FLAG_IS_BOOTLOADER); + + return TRUE; +} + +static gboolean +fu_elantp_hid_device_setup (FuDevice *device, GError **error) +{ + FuElantpHidDevice *self = FU_ELANTP_HID_DEVICE (device); + FuUdevDevice *udev_device = FU_UDEV_DEVICE (device); + gboolean is_new_pattern; + guint16 fwver; + guint16 tmp; + guint8 buf[2] = { 0x0 }; + guint8 ic_type; + g_autofree gchar *instance_id1 = NULL; + g_autofree gchar *instance_id_ic_type = NULL; + g_autofree gchar *version_bl = NULL; + g_autofree gchar *version = NULL; + + /* get current firmware version */ + if (!fu_elantp_hid_device_read_cmd (self, + ETP_CMD_I2C_FW_VERSION, + buf, sizeof(buf), error)) { + g_prefix_error (error, "failed to read fw version: "); + return FALSE; + } + fwver = fu_common_read_uint16 (buf, G_LITTLE_ENDIAN); + version = fu_common_version_from_uint16 (fwver, FWUPD_VERSION_FORMAT_HEX); + fu_device_set_version (device, version); + + /* get EAP firmware version */ + is_new_pattern = fu_device_has_custom_flag (FU_DEVICE (self), "iap-version-2"); + if (!fu_elantp_hid_device_read_cmd (self, + is_new_pattern ? ETP_CMD_I2C_IAP_VERSION_2 : ETP_CMD_I2C_IAP_VERSION, + buf, sizeof(buf), error)) { + g_prefix_error (error, "failed to read bootloader version: "); + return FALSE; + } + fwver = fu_common_read_uint16 (buf, G_LITTLE_ENDIAN); + version_bl = fu_common_version_from_uint16 (fwver, FWUPD_VERSION_FORMAT_HEX); + fu_device_set_version_bootloader (device, version_bl); + + /* get module ID */ + if (!fu_elantp_hid_device_read_cmd (self, + ETP_CMD_GET_MODULE_ID, + buf, sizeof(buf), error)) { + g_prefix_error (error, "failed to read module ID: "); + return FALSE; + } + self->module_id = fu_common_read_uint16 (buf, G_LITTLE_ENDIAN); + + /* define the extra instance IDs */ + instance_id1 = g_strdup_printf ("HIDRAW\\VEN_%04X&DEV_%04X&MOD_%04X", + fu_udev_device_get_vendor (udev_device), + fu_udev_device_get_model (udev_device), + self->module_id); + fu_device_add_instance_id (device, instance_id1); + + /* get OSM version */ + if (!fu_elantp_hid_device_read_cmd (self, ETP_CMD_I2C_OSM_VERSION, buf, sizeof(buf), error)) { + g_prefix_error (error, "failed to read OSM version: "); + return FALSE; + } + tmp = fu_common_read_uint16 (buf, G_LITTLE_ENDIAN); + if (tmp == ETP_CMD_I2C_OSM_VERSION || tmp == 0xFFFF) { + if (!fu_elantp_hid_device_read_cmd (self, ETP_CMD_I2C_IAP_ICBODY, buf, sizeof(buf), error)) { + g_prefix_error (error, "failed to read IC body: "); + return FALSE; + } + ic_type = fu_common_read_uint16 (buf, G_LITTLE_ENDIAN) & 0xFF; + } else { + ic_type = (tmp >> 8) & 0xFF; + } + instance_id_ic_type = g_strdup_printf ("ELANTP\\ICTYPE_%02X", ic_type); + fu_device_add_instance_id (device, instance_id_ic_type); + + /* no quirk entry */ + if (self->ic_page_count == 0x0) { + g_set_error (error, + FWUPD_ERROR, + FWUPD_ERROR_NOT_SUPPORTED, + "no page count for ELANTP\\ICTYPE_%02X", + ic_type); + return FALSE; + } + fu_device_set_firmware_size (device, self->ic_page_count * FW_PAGE_SIZE); + + /* is in bootloader mode */ + if (!fu_elantp_hid_device_ensure_iap_ctrl (self, error)) + return FALSE; + + /* success */ + return TRUE; +} + +static FuFirmware * +fu_elantp_hid_device_prepare_firmware (FuDevice *device, + GBytes *fw, + FwupdInstallFlags flags, + GError **error) +{ + FuElantpHidDevice *self = FU_ELANTP_HID_DEVICE (device); + guint16 module_id; + g_autoptr(FuFirmware) firmware = fu_elantp_firmware_new (); + + /* check size */ + if (g_bytes_get_size (fw) < fu_device_get_firmware_size_min (device)) { + g_set_error (error, + FWUPD_ERROR, + FWUPD_ERROR_INVALID_FILE, + "firmware too small, got 0x%x, expected >= 0x%x", + (guint) g_bytes_get_size (fw), + (guint) fu_device_get_firmware_size_min (device)); + return NULL; + } + if (g_bytes_get_size (fw) > fu_device_get_firmware_size_max (device)) { + g_set_error (error, + FWUPD_ERROR, + FWUPD_ERROR_INVALID_FILE, + "firmware too large, got 0x%x, expected <= 0x%x", + (guint) g_bytes_get_size (fw), + (guint) fu_device_get_firmware_size_max (device)); + return NULL; + } + + /* check is compatible with hardware */ + fu_device_set_status (device, FWUPD_STATUS_DECOMPRESSING); + if (!fu_firmware_parse (firmware, fw, flags, error)) + return NULL; + module_id = fu_elantp_firmware_get_module_id (FU_ELANTP_FIRMWARE (firmware)); + if (self->module_id != module_id) { + g_set_error (error, + FWUPD_ERROR, + FWUPD_ERROR_INVALID_FILE, + "firmware incompatible, got 0x%04x, expected 0x%04x", + module_id, self->module_id); + return NULL; + } + + /* success */ + return g_steal_pointer (&firmware); +} + +static gboolean +fu_elantp_hid_device_write_firmware (FuDevice *device, + FuFirmware *firmware, + FwupdInstallFlags flags, + GError **error) +{ + FuElantpHidDevice *self = FU_ELANTP_HID_DEVICE (device); + FuElantpFirmware *firmware_elantp = FU_ELANTP_FIRMWARE (firmware); + gsize bufsz = 0; + guint16 checksum = 0; + guint16 checksum_device = 0; + guint16 iap_addr; + const guint8 *buf; + guint8 csum_buf[2] = { 0x0 }; + g_autoptr(GBytes) fw = NULL; + g_autoptr(GPtrArray) chunks = NULL; + + /* simple image */ + fw = fu_firmware_get_image_default_bytes (firmware, error); + if (fw == NULL) + return FALSE; + + /* write each block */ + fu_device_set_status (device, FWUPD_STATUS_DEVICE_WRITE); + buf = g_bytes_get_data (fw, &bufsz); + iap_addr = fu_elantp_firmware_get_iap_addr (firmware_elantp); + chunks = fu_chunk_array_new (buf + iap_addr, bufsz - iap_addr, 0x0, 0x0, FW_PAGE_SIZE); + for (guint i = 0; i < chunks->len; i++) { + FuChunk *chk = g_ptr_array_index (chunks, i); + guint16 csum_tmp = fu_elantp_calc_checksum (chk->data, chk->data_sz); + guint8 blk[FW_PAGE_SIZE + 3]; + + /* write block */ + blk[0] = 0x0B; /* report ID */ + memcpy (blk + 1, chk->data, chk->data_sz); + fu_common_write_uint16 (blk + chk->data_sz + 1, csum_tmp, G_LITTLE_ENDIAN); + + if (!fu_elantp_hid_device_send_cmd (self, blk, sizeof (blk), NULL, 0, error)) + return FALSE; + g_usleep (ELANTP_DELAY_WRITE_BLOCK * 1000); + if (!fu_elantp_hid_device_ensure_iap_ctrl (self, error)) + return FALSE; + if (self->iap_ctrl & (ETP_FW_IAP_PAGE_ERR | ETP_FW_IAP_INTF_ERR)) { + g_set_error (error, + FWUPD_ERROR, + FWUPD_ERROR_WRITE, + "bootloader reports failed write: 0x%x", + self->iap_ctrl); + return FALSE; + } + + /* update progress */ + checksum += csum_tmp; + fu_device_set_progress_full (device, (gsize) i, (gsize) chunks->len); + } + + /* verify the written checksum */ + fu_device_set_status (device, FWUPD_STATUS_DEVICE_VERIFY); + if (!fu_elantp_hid_device_read_cmd (self, ETP_CMD_I2C_IAP_CHECKSUM, + csum_buf, sizeof(csum_buf), error)) + return FALSE; + checksum_device = fu_common_read_uint16 (csum_buf, G_LITTLE_ENDIAN); + if (checksum != checksum_device) { + g_set_error (error, + FWUPD_ERROR, + FWUPD_ERROR_WRITE, + "checksum failed 0x%04x != 0x%04x", + checksum, checksum_device); + return FALSE; + } + + /* wait for a reset */ + fu_device_set_progress (device, 0); + fu_device_set_status (device, FWUPD_STATUS_DEVICE_RESTART); + g_usleep (ELANTP_DELAY_COMPLETE * 1000); + return TRUE; +} + +static gboolean +fu_elantp_hid_device_detach (FuDevice *device, GError **error) +{ + FuElantpHidDevice *self = FU_ELANTP_HID_DEVICE (device); + + /* sanity check */ + if (fu_device_has_flag (device, FWUPD_DEVICE_FLAG_IS_BOOTLOADER)) { + g_debug ("already in bootloader mode, skipping"); + return TRUE; + } + + g_debug ("in bootloader mode, reset IC"); + fu_device_set_status (device, FWUPD_STATUS_DEVICE_RESTART); + if (!fu_elantp_hid_device_write_cmd (self, + ETP_CMD_I2C_IAP_RESET, + ETP_I2C_IAP_RESET, + error)) + return FALSE; + g_usleep (ELANTP_DELAY_RESET * 1000); + if (!fu_elantp_hid_device_write_cmd (self, + ETP_CMD_I2C_IAP, + self->iap_password, + error)) + return FALSE; + g_usleep (ELANTP_DELAY_UNLOCK * 1000); + if (!fu_elantp_hid_device_ensure_iap_ctrl (self, error)) + return FALSE; + if ((self->iap_ctrl & ETP_FW_IAP_CHECK_PW) == 0) { + g_set_error_literal (error, + FWUPD_ERROR, + FWUPD_ERROR_WRITE, + "unexpected bootloader password"); + return FALSE; + } + + /* success */ + return TRUE; +} + +static gboolean +fu_elantp_hid_device_attach (FuDevice *device, GError **error) +{ + FuElantpHidDevice *self = FU_ELANTP_HID_DEVICE (device); + + /* sanity check */ + if (!fu_device_has_flag (device, FWUPD_DEVICE_FLAG_IS_BOOTLOADER)) { + g_debug ("already in runtime mode, skipping"); + return TRUE; + } + + /* reset back to runtime */ + fu_device_set_status (device, FWUPD_STATUS_DEVICE_RESTART); + if (!fu_elantp_hid_device_write_cmd (self, ETP_CMD_I2C_IAP_RESET, ETP_I2C_IAP_RESET, error)) + return FALSE; + g_usleep (ELANTP_DELAY_RESET * 1000); + if (!fu_elantp_hid_device_write_cmd (self, ETP_CMD_I2C_IAP_RESET, ETP_I2C_ENABLE_REPORT, error)) { + g_prefix_error (error, "cannot enable TP report: "); + return FALSE; + } + if (!fu_elantp_hid_device_write_cmd (self, 0x0306, 0x003, error)) { + g_prefix_error (error, "cannot switch to TP PTP mode: "); + return FALSE; + } + if (!fu_elantp_hid_device_ensure_iap_ctrl (self, error)) + return FALSE; + + /* success */ + return TRUE; +} + +static gboolean +fu_elantp_hid_device_set_quirk_kv (FuDevice *device, + const gchar *key, + const gchar *value, + GError **error) +{ + FuElantpHidDevice *self = FU_ELANTP_HID_DEVICE (device); + if (g_strcmp0 (key, "ElantpIcPageCount") == 0) { + guint64 tmp = fu_common_strtoull (value); + if (tmp > 0xffff) { + g_set_error_literal (error, + G_IO_ERROR, + G_IO_ERROR_NOT_SUPPORTED, + "ElantpIcPageCount only supports " + "values <= 0xffff"); + return FALSE; + } + self->ic_page_count = (guint16) tmp; + return TRUE; + } + if (g_strcmp0 (key, "ElantpIapPassword") == 0) { + guint64 tmp = fu_common_strtoull (value); + if (tmp > 0xffff) { + g_set_error_literal (error, + G_IO_ERROR, + G_IO_ERROR_NOT_SUPPORTED, + "ElantpIapPassword only supports " + "values <= 0xffff"); + return FALSE; + } + self->iap_password = (guint16) tmp; + return TRUE; + } + g_set_error_literal (error, + G_IO_ERROR, + G_IO_ERROR_NOT_SUPPORTED, + "quirk key not supported"); + return FALSE; +} + +static void +fu_elantp_hid_device_init (FuElantpHidDevice *self) +{ + fu_device_add_flag (FU_DEVICE (self), FWUPD_DEVICE_FLAG_INTERNAL); + fu_device_add_flag (FU_DEVICE (self), FWUPD_DEVICE_FLAG_UPDATABLE); + fu_device_set_summary (FU_DEVICE (self), "Elan Touchpad"); + fu_device_add_icon (FU_DEVICE (self), "input-touchpad"); + fu_device_set_protocol (FU_DEVICE (self), "tw.com.emc.elantp"); + fu_device_set_version_format (FU_DEVICE (self), FWUPD_VERSION_FORMAT_HEX); + fu_udev_device_set_flags (FU_UDEV_DEVICE (self), + FU_UDEV_DEVICE_FLAG_OPEN_READ | + FU_UDEV_DEVICE_FLAG_OPEN_WRITE | + FU_UDEV_DEVICE_FLAG_OPEN_NONBLOCK); +} + +static void +fu_elantp_hid_device_finalize (GObject *object) +{ + G_OBJECT_CLASS (fu_elantp_hid_device_parent_class)->finalize (object); +} + +static void +fu_elantp_hid_device_class_init (FuElantpHidDeviceClass *klass) +{ + GObjectClass *object_class = G_OBJECT_CLASS (klass); + FuDeviceClass *klass_device = FU_DEVICE_CLASS (klass); + FuUdevDeviceClass *klass_udev_device = FU_UDEV_DEVICE_CLASS (klass); + object_class->finalize = fu_elantp_hid_device_finalize; + klass_device->to_string = fu_elantp_hid_device_to_string; + klass_device->attach = fu_elantp_hid_device_attach; + klass_device->detach = fu_elantp_hid_device_detach; + klass_device->set_quirk_kv = fu_elantp_hid_device_set_quirk_kv; + klass_device->setup = fu_elantp_hid_device_setup; + klass_device->write_firmware = fu_elantp_hid_device_write_firmware; + klass_device->prepare_firmware = fu_elantp_hid_device_prepare_firmware; + klass_udev_device->probe = fu_elantp_hid_device_probe; +} diff --git a/plugins/elantp/fu-elantp-hid-device.h b/plugins/elantp/fu-elantp-hid-device.h new file mode 100644 index 000000000..06d058ca1 --- /dev/null +++ b/plugins/elantp/fu-elantp-hid-device.h @@ -0,0 +1,12 @@ +/* + * Copyright (C) 2020 Richard Hughes + * + * SPDX-License-Identifier: LGPL-2.1+ + */ + +#pragma once + +#include "fu-plugin.h" + +#define FU_TYPE_ELANTP_HID_DEVICE (fu_elantp_hid_device_get_type ()) +G_DECLARE_FINAL_TYPE (FuElantpHidDevice, fu_elantp_hid_device, FU, ELANTP_HID_DEVICE, FuUdevDevice) diff --git a/plugins/elantp/fu-plugin-elantp.c b/plugins/elantp/fu-plugin-elantp.c new file mode 100644 index 000000000..5bd05ed37 --- /dev/null +++ b/plugins/elantp/fu-plugin-elantp.c @@ -0,0 +1,22 @@ +/* + * Copyright (C) 2020 Richard Hughes + * + * SPDX-License-Identifier: LGPL-2.1+ + */ + +#include "config.h" + +#include "fu-plugin-vfuncs.h" +#include "fu-hash.h" + +#include "fu-elantp-firmware.h" +#include "fu-elantp-hid-device.h" + +void +fu_plugin_init (FuPlugin *plugin) +{ + fu_plugin_set_build_hash (plugin, FU_BUILD_HASH); + fu_plugin_add_udev_subsystem (plugin, "hidraw"); + fu_plugin_add_firmware_gtype (plugin, "elantp", FU_TYPE_ELANTP_FIRMWARE); + fu_plugin_set_device_gtype (plugin, FU_TYPE_ELANTP_HID_DEVICE); +} diff --git a/plugins/elantp/meson.build b/plugins/elantp/meson.build new file mode 100644 index 000000000..97527e9d9 --- /dev/null +++ b/plugins/elantp/meson.build @@ -0,0 +1,35 @@ +cargs = ['-DG_LOG_DOMAIN="FuPluginElantp"'] + +install_data([ + 'elantp.quirk', + ], + install_dir: join_paths(datadir, 'fwupd', 'quirks.d') +) + +shared_module('fu_plugin_elantp', + fu_hash, + sources : [ + 'fu-plugin-elantp.c', + 'fu-elantp-common.c', + 'fu-elantp-firmware.c', + 'fu-elantp-hid-device.c', + ], + include_directories : [ + root_incdir, + fwupd_incdir, + fwupdplugin_incdir, + ], + install : true, + install_dir: plugin_dir, + c_args : [ + cargs, + '-DLOCALSTATEDIR="' + localstatedir + '"', + ], + link_with : [ + fwupd, + fwupdplugin, + ], + dependencies : [ + plugin_deps, + ], +) diff --git a/plugins/meson.build b/plugins/meson.build index e6735f67b..6ecd99578 100644 --- a/plugins/meson.build +++ b/plugins/meson.build @@ -41,6 +41,7 @@ endif if get_option('gudev') subdir('ata') +subdir('elantp') subdir('logitech-hidpp') subdir('optionrom') subdir('superio') From ec2fbb054cb14867d4d3cb464ea4dbc3dd4f804a Mon Sep 17 00:00:00 2001 From: Richard Hughes Date: Tue, 1 Sep 2020 13:49:05 +0100 Subject: [PATCH 372/607] trivial: Fix a copy paste mistake spotted by Coverity --- libfwupd/fwupd-release.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libfwupd/fwupd-release.c b/libfwupd/fwupd-release.c index 452d271a0..875b4e518 100644 --- a/libfwupd/fwupd-release.c +++ b/libfwupd/fwupd-release.c @@ -1798,7 +1798,7 @@ fwupd_release_to_string (FwupdRelease *release) fwupd_pad_kv_str (str, FWUPD_RESULT_KEY_DETACH_IMAGE, priv->detach_image); if (priv->update_message != NULL) fwupd_pad_kv_str (str, FWUPD_RESULT_KEY_UPDATE_MESSAGE, priv->update_message); - if (priv->update_message != NULL) + if (priv->update_image != NULL) fwupd_pad_kv_str (str, FWUPD_RESULT_KEY_UPDATE_IMAGE, priv->update_image); /* metadata */ keys = g_hash_table_get_keys (priv->metadata); From 241bdbb0f58fef481d1094e0f1f2ffc93c65a381 Mon Sep 17 00:00:00 2001 From: Richard Hughes Date: Tue, 1 Sep 2020 14:12:27 +0100 Subject: [PATCH 373/607] trivial: Fix some dead code as-seen by Coverity --- libfwupdplugin/fu-udev-device.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/libfwupdplugin/fu-udev-device.c b/libfwupdplugin/fu-udev-device.c index a6a46af4f..038f80739 100644 --- a/libfwupdplugin/fu-udev-device.c +++ b/libfwupdplugin/fu-udev-device.c @@ -1145,13 +1145,13 @@ fu_udev_device_get_sysfs_attr (FuUdevDevice *self, const gchar *attr, } return result; -#endif +#else g_set_error_literal (error, G_IO_ERROR, G_IO_ERROR_FAILED, "not supported"); return NULL; - +#endif } /** From f0735f458359f54d6569eab61f3d7fd102c1fcb1 Mon Sep 17 00:00:00 2001 From: Richard Hughes Date: Tue, 1 Sep 2020 14:14:02 +0100 Subject: [PATCH 374/607] trivial: Fix a logic thinko spotted by Coverity --- libfwupd/fwupd-client.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libfwupd/fwupd-client.c b/libfwupd/fwupd-client.c index 9db14a3cc..35904db1c 100644 --- a/libfwupd/fwupd-client.c +++ b/libfwupd/fwupd-client.c @@ -2720,7 +2720,7 @@ fwupd_client_upload_bytes (FwupdClient *self, return NULL; /* build message */ - if ((flags | FWUPD_CLIENT_UPLOAD_FLAG_ALWAYS_MULTIPART) > 0 || + if ((flags & FWUPD_CLIENT_UPLOAD_FLAG_ALWAYS_MULTIPART) > 0 || signature != NULL) { g_autoptr(SoupMultipart) mp = NULL; mp = soup_multipart_new (SOUP_FORM_MIME_TYPE_MULTIPART); From 728695177198151386fd6fb8067f073b7af3847f Mon Sep 17 00:00:00 2001 From: Richard Hughes Date: Tue, 1 Sep 2020 15:07:20 +0100 Subject: [PATCH 375/607] Use newer libxmlb features to properly display more AppStream markup --- src/fu-util-common.c | 99 ++++++++++++++++++++++++++++++-------------- 1 file changed, 67 insertions(+), 32 deletions(-) diff --git a/src/fu-util-common.c b/src/fu-util-common.c index 70d3aa70d..5d8c9ae92 100644 --- a/src/fu-util-common.c +++ b/src/fu-util-common.c @@ -811,51 +811,86 @@ fu_util_parse_filter_flags (const gchar *filter, FwupdDeviceFlags *include, return TRUE; } +typedef struct { + guint cnt; + GString *str; +} FuUtilConvertHelper; + +static gboolean +fu_util_convert_description_head_cb (XbNode *n, gpointer user_data) +{ + FuUtilConvertHelper *helper = (FuUtilConvertHelper *) user_data; + helper->cnt++; + + /* start */ + if (g_strcmp0 (xb_node_get_element (n), "em") == 0) { + g_string_append (helper->str, "\033[3m"); + } else if (g_strcmp0 (xb_node_get_element (n), "strong") == 0) { + g_string_append (helper->str, "\033[1m"); + } else if (g_strcmp0 (xb_node_get_element (n), "code") == 0) { + g_string_append (helper->str, "`"); + } else if (g_strcmp0 (xb_node_get_element (n), "li") == 0) { + g_string_append (helper->str, "• "); + } else if (g_strcmp0 (xb_node_get_element (n), "p") == 0 || + g_strcmp0 (xb_node_get_element (n), "ul") == 0 || + g_strcmp0 (xb_node_get_element (n), "ol") == 0) { + g_string_append (helper->str, "\n"); + } + + /* text */ + if (xb_node_get_text (n) != NULL) + g_string_append (helper->str, xb_node_get_text (n)); + + return FALSE; +} + +static gboolean +fu_util_convert_description_tail_cb (XbNode *n, gpointer user_data) +{ + FuUtilConvertHelper *helper = (FuUtilConvertHelper *) user_data; + helper->cnt++; + + /* end */ + if (g_strcmp0 (xb_node_get_element (n), "em") == 0 || + g_strcmp0 (xb_node_get_element (n), "strong") == 0) { + g_string_append (helper->str, "\033[0m"); + } else if (g_strcmp0 (xb_node_get_element (n), "code") == 0) { + g_string_append (helper->str, "`"); + } else if (g_strcmp0 (xb_node_get_element (n), "li") == 0) { + g_string_append (helper->str, "\n"); + } else if (g_strcmp0 (xb_node_get_element (n), "p") == 0) { + g_string_append (helper->str, "\n"); + } + + /* tail */ + if (xb_node_get_tail (n) != NULL) + g_string_append (helper->str, xb_node_get_tail (n)); + + return FALSE; +} + gchar * fu_util_convert_description (const gchar *xml, GError **error) { g_autoptr(GString) str = g_string_new (NULL); g_autoptr(XbNode) n = NULL; g_autoptr(XbSilo) silo = NULL; + FuUtilConvertHelper helper = { + .cnt = 0, + .str = str, + }; /* parse XML */ silo = xb_silo_new_from_xml (xml, error); if (silo == NULL) return NULL; + /* convert to something we can show on the console */ n = xb_silo_get_root (silo); - while (n != NULL) { - g_autoptr(XbNode) n2 = NULL; - - /* support

,

    ,
      and
    1. , ignore all else */ - if (g_strcmp0 (xb_node_get_element (n), "p") == 0) { - g_string_append_printf (str, "%s\n\n", xb_node_get_text (n)); - } else if (g_strcmp0 (xb_node_get_element (n), "ul") == 0) { - g_autoptr(GPtrArray) children = xb_node_get_children (n); - for (guint i = 0; i < children->len; i++) { - XbNode *nc = g_ptr_array_index (children, i); - if (g_strcmp0 (xb_node_get_element (nc), "li") == 0) { - g_string_append_printf (str, " • %s\n", - xb_node_get_text (nc)); - } - } - g_string_append (str, "\n"); - } else if (g_strcmp0 (xb_node_get_element (n), "ol") == 0) { - g_autoptr(GPtrArray) children = xb_node_get_children (n); - for (guint i = 0; i < children->len; i++) { - XbNode *nc = g_ptr_array_index (children, i); - if (g_strcmp0 (xb_node_get_element (nc), "li") == 0) { - g_string_append_printf (str, " %u. %s\n", - i + 1, - xb_node_get_text (nc)); - } - } - g_string_append (str, "\n"); - } - - n2 = xb_node_get_next (n); - g_set_object (&n, n2); - } + xb_node_transmogrify (n, + fu_util_convert_description_head_cb, + fu_util_convert_description_tail_cb, + &helper); /* success */ return fu_common_strstrip (str->str); From 409a2c958c14364e710616797b372a24ffb6acb7 Mon Sep 17 00:00:00 2001 From: Jerry Zhang Date: Mon, 31 Aug 2020 12:33:24 -0500 Subject: [PATCH 376/607] dfu: Support polling the status from device in dfuManifest state Some devices may accumulate the firmware image and perform the entire reprogramming operation at one time. In this case, the device enters dfuMANIFEST-SYNC or dfuMANIFEST state after dfuDNLOAD-IDLE. The fwupd shall be able to poll the status from the device via DFU_GETSTATUS until the device completes the reprogramming or reports an error. For details, please refer to Section 7. Manifestation Phase and A.1 Interface State Transition Diagram in the USB DFU protocol. https://www.usb.org/sites/default/files/DFU_1.1.pdf For not affecting the other DFU capable devices, introduce a quirk "manifest-poll" to limit the logic. --- plugins/dfu/dfu-device.c | 1 + plugins/dfu/dfu-target.c | 47 ++++++++++++++++++++++++++++++++++++++++ plugins/dfu/dfu.quirk | 40 ++++++++++++++++++++++++++++++++++ 3 files changed, 88 insertions(+) diff --git a/plugins/dfu/dfu-device.c b/plugins/dfu/dfu-device.c index 2138f5a46..792f12f43 100644 --- a/plugins/dfu/dfu-device.c +++ b/plugins/dfu/dfu-device.c @@ -44,6 +44,7 @@ * * `legacy-protocol`: Use a legacy protocol version * * `detach-for-attach`: Requires a DFU_REQUEST_DETACH to attach * * `absent-sector-size`: In absence of sector size, assume byte + * * `manifest-poll`: Requires polling via GetStatus in dfuManifest state * * Default value: `none` * diff --git a/plugins/dfu/dfu-target.c b/plugins/dfu/dfu-target.c index ac5e9f683..e9d13d856 100644 --- a/plugins/dfu/dfu-target.c +++ b/plugins/dfu/dfu-target.c @@ -30,6 +30,8 @@ #include "fwupd-error.h" +#define DFU_TARGET_MANIFEST_MAX_POLLING_TRIES 200 + static void dfu_target_finalize (GObject *object); typedef struct { @@ -472,6 +474,46 @@ dfu_target_status_to_error_msg (DfuStatus status) return NULL; } +static gboolean +dfu_target_manifest_wait (DfuTarget *target, GError **error) +{ + DfuTargetPrivate *priv = GET_PRIVATE (target); + guint polling_count = 0; + + /* get the status */ + if (!dfu_device_refresh (priv->device, error)) + return FALSE; + + /* wait for DFU_STATE_DFU_MANIFEST to not be set */ + while (dfu_device_get_state (priv->device) == DFU_STATE_DFU_MANIFEST_SYNC || + dfu_device_get_state (priv->device) == DFU_STATE_DFU_MANIFEST) { + g_debug ("waiting for DFU_STATE_DFU_MANIFEST to clear"); + + if (polling_count++ > DFU_TARGET_MANIFEST_MAX_POLLING_TRIES) { + g_set_error_literal (error, + FWUPD_ERROR, + FWUPD_ERROR_INTERNAL, + "reach to max polling tries"); + return FALSE; + } + + g_usleep ((dfu_device_get_download_timeout (priv->device) + 1000) * 1000); + if (!dfu_device_refresh (priv->device, error)) + return FALSE; + } + + /* in an error state */ + if (dfu_device_get_state (priv->device) == DFU_STATE_DFU_ERROR) { + g_set_error_literal (error, + FWUPD_ERROR, + FWUPD_ERROR_INTERNAL, + dfu_target_status_to_error_msg (dfu_device_get_status (priv->device))); + return FALSE; + } + + return TRUE; +} + gboolean dfu_target_check_status (DfuTarget *target, GError **error) { @@ -1285,6 +1327,11 @@ dfu_target_download (DfuTarget *target, DfuImage *image, return FALSE; } + if (fu_device_has_custom_flag (FU_DEVICE (dfu_target_get_device (target)), "manifest-poll") && + dfu_device_has_attribute (priv->device, DFU_DEVICE_ATTRIBUTE_MANIFEST_TOL)) + if (!dfu_target_manifest_wait (target, error)) + return FALSE; + /* success */ return TRUE; } diff --git a/plugins/dfu/dfu.quirk b/plugins/dfu/dfu.quirk index bbf172a72..5639c7cd0 100644 --- a/plugins/dfu/dfu.quirk +++ b/plugins/dfu/dfu.quirk @@ -329,3 +329,43 @@ Flags = absent-sector-size Plugin = dfu DfuForceVersion = 011a DfuForceTimeout = 5000 + +# Poly Studio +[DeviceInstanceId=USB\VID_095D&PID_9217] +Plugin = dfu +Flags = manifest-poll +[DeviceInstanceId=USB\VID_095D&PID_9218] +Plugin = dfu +Flags = manifest-poll + +# Poly Eagle Eye Cube +[DeviceInstanceId=USB\VID_095D&PID_9212] +Plugin = dfu +Flags = manifest-poll +[DeviceInstanceId=USB\VID_095D&PID_9213] +Plugin = dfu +Flags = manifest-poll + +# Poly P30 +[DeviceInstanceId=USB\VID_095D&PID_9290] +Plugin = dfu +Flags = manifest-poll +[DeviceInstanceId=USB\VID_095D&PID_9291] +Plugin = dfu +Flags = manifest-poll + +# Poly ULCC +[DeviceInstanceId=USB\VID_095D&PID_9160] +Plugin = dfu +Flags = manifest-poll +[DeviceInstanceId=USB\VID_095D&PID_927B] +Plugin = dfu +Flags = manifest-poll + +# Poly Eagle Eye Mini +[DeviceInstanceId=USB\VID_095D&PID_3001] +Plugin = dfu +Flags = manifest-poll +[DeviceInstanceId=USB\VID_095D&PID_3002] +Plugin = dfu +Flags = manifest-poll From 0b6f58394ba5edaa8c2c024c5e891de9476d0d40 Mon Sep 17 00:00:00 2001 From: Richard Hughes Date: Tue, 1 Sep 2020 20:15:02 +0100 Subject: [PATCH 377/607] Cancel the file monitor before disposal to avoid a potential deadlock Fixes https://github.com/fwupd/fwupd/issues/2350 --- plugins/linux-lockdown/fu-plugin-linux-lockdown.c | 4 +++- plugins/linux-swap/fu-plugin-linux-swap.c | 4 +++- plugins/linux-tainted/fu-plugin-linux-tainted.c | 4 +++- plugins/thunderbolt/fu-self-test.c | 2 ++ src/fu-config.c | 4 +++- src/fu-main.c | 4 +++- src/fu-remote-list.c | 9 ++++++++- 7 files changed, 25 insertions(+), 6 deletions(-) diff --git a/plugins/linux-lockdown/fu-plugin-linux-lockdown.c b/plugins/linux-lockdown/fu-plugin-linux-lockdown.c index ccfdefe40..633feec2c 100644 --- a/plugins/linux-lockdown/fu-plugin-linux-lockdown.c +++ b/plugins/linux-lockdown/fu-plugin-linux-lockdown.c @@ -27,8 +27,10 @@ fu_plugin_destroy (FuPlugin *plugin) FuPluginData *data = fu_plugin_get_data (plugin); if (data->file != NULL) g_object_unref (data->file); - if (data->monitor != NULL) + if (data->monitor != NULL) { + g_file_monitor_cancel (data->monitor); g_object_unref (data->monitor); + } } static void diff --git a/plugins/linux-swap/fu-plugin-linux-swap.c b/plugins/linux-swap/fu-plugin-linux-swap.c index a92d86de2..b0f11edca 100644 --- a/plugins/linux-swap/fu-plugin-linux-swap.c +++ b/plugins/linux-swap/fu-plugin-linux-swap.c @@ -28,8 +28,10 @@ fu_plugin_destroy (FuPlugin *plugin) FuPluginData *data = fu_plugin_get_data (plugin); if (data->file != NULL) g_object_unref (data->file); - if (data->monitor != NULL) + if (data->monitor != NULL) { + g_file_monitor_cancel (data->monitor); g_object_unref (data->monitor); + } } static void diff --git a/plugins/linux-tainted/fu-plugin-linux-tainted.c b/plugins/linux-tainted/fu-plugin-linux-tainted.c index 86c69655e..6100edef4 100644 --- a/plugins/linux-tainted/fu-plugin-linux-tainted.c +++ b/plugins/linux-tainted/fu-plugin-linux-tainted.c @@ -27,8 +27,10 @@ fu_plugin_destroy (FuPlugin *plugin) FuPluginData *data = fu_plugin_get_data (plugin); if (data->file != NULL) g_object_unref (data->file); - if (data->monitor != NULL) + if (data->monitor != NULL) { + g_file_monitor_cancel (data->monitor); g_object_unref (data->monitor); + } } static void diff --git a/plugins/thunderbolt/fu-self-test.c b/plugins/thunderbolt/fu-self-test.c index c3414c436..90d2105f8 100644 --- a/plugins/thunderbolt/fu-self-test.c +++ b/plugins/thunderbolt/fu-self-test.c @@ -672,6 +672,8 @@ update_context_free (UpdateContext *ctx) if (ctx == NULL) return; + g_file_monitor_cancel (ctx->monitor); + g_object_unref (ctx->bed); g_object_unref (ctx->plugin); g_object_unref (ctx->monitor); diff --git a/src/fu-config.c b/src/fu-config.c index 646940c03..07114402e 100644 --- a/src/fu-config.c +++ b/src/fu-config.c @@ -313,8 +313,10 @@ fu_config_finalize (GObject *obj) { FuConfig *self = FU_CONFIG (obj); - if (self->monitor != NULL) + if (self->monitor != NULL) { + g_file_monitor_cancel (self->monitor); g_object_unref (self->monitor); + } g_ptr_array_unref (self->disabled_devices); g_ptr_array_unref (self->disabled_plugins); g_ptr_array_unref (self->approved_firmware); diff --git a/src/fu-main.c b/src/fu-main.c index c19edba38..cb2ccf5e6 100644 --- a/src/fu-main.c +++ b/src/fu-main.c @@ -1678,8 +1678,10 @@ fu_main_private_free (FuMainPrivate *priv) g_object_unref (priv->connection); if (priv->authority != NULL) g_object_unref (priv->authority); - if (priv->argv0_monitor != NULL) + if (priv->argv0_monitor != NULL) { + g_file_monitor_cancel (priv->argv0_monitor); g_object_unref (priv->argv0_monitor); + } if (priv->introspection_daemon != NULL) g_dbus_node_info_unref (priv->introspection_daemon); #if GLIB_CHECK_VERSION(2,63,3) diff --git a/src/fu-remote-list.c b/src/fu-remote-list.c index 4fbb15d5e..1646bde3a 100644 --- a/src/fu-remote-list.c +++ b/src/fu-remote-list.c @@ -475,11 +475,18 @@ fu_remote_list_class_init (FuRemoteListClass *klass) G_TYPE_NONE, 0); } +static void +fu_remote_list_monitor_unref (GFileMonitor *monitor) +{ + g_file_monitor_cancel (monitor); + g_object_unref (monitor); +} + static void fu_remote_list_init (FuRemoteList *self) { self->array = g_ptr_array_new_with_free_func ((GDestroyNotify) g_object_unref); - self->monitors = g_ptr_array_new_with_free_func ((GDestroyNotify) g_object_unref); + self->monitors = g_ptr_array_new_with_free_func ((GDestroyNotify) fu_remote_list_monitor_unref); } static void From a018b3cbb4951980fa74d40b6891f6ce16393e62 Mon Sep 17 00:00:00 2001 From: Richard Hughes Date: Fri, 28 Aug 2020 17:08:19 +0100 Subject: [PATCH 378/607] Do not return HSI attributes when running in a VM or container --- src/fu-main.c | 45 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 45 insertions(+) diff --git a/src/fu-main.c b/src/fu-main.c index cb2ccf5e6..b93f57c98 100644 --- a/src/fu-main.c +++ b/src/fu-main.c @@ -40,6 +40,12 @@ G_DEFINE_AUTOPTR_CLEANUP_FUNC(PolkitSubject, g_object_unref) #pragma clang diagnostic pop #endif +typedef enum { + FU_MAIN_MACHINE_KIND_PHYSICAL, + FU_MAIN_MACHINE_KIND_VIRTUAL, + FU_MAIN_MACHINE_KIND_CONTAINER, +} FuMainMachineKind; + typedef struct { GDBusConnection *connection; GDBusNodeInfo *introspection_daemon; @@ -55,6 +61,7 @@ typedef struct { FuEngine *engine; gboolean update_in_progress; gboolean pending_sigterm; + FuMainMachineKind machine_kind; } FuMainPrivate; static gboolean @@ -1105,6 +1112,13 @@ fu_main_daemon_method_call (GDBusConnection *connection, const gchar *sender, if (g_strcmp0 (method_name, "GetHostSecurityAttrs") == 0) { g_autoptr(FuSecurityAttrs) attrs = NULL; g_debug ("Called %s()", method_name); + if (priv->machine_kind != FU_MAIN_MACHINE_KIND_PHYSICAL) { + g_dbus_method_invocation_return_error_literal (invocation, + FWUPD_ERROR, + FWUPD_ERROR_NOT_SUPPORTED, + "HSI unavailable for hypervisor"); + return; + } attrs = fu_engine_get_host_security_attrs (priv->engine); val = fu_security_attrs_to_variant (attrs); g_dbus_method_invocation_return_value (invocation, val); @@ -1662,6 +1676,30 @@ fu_main_load_introspection (const gchar *filename, GError **error) return g_dbus_node_info_new_for_xml (g_bytes_get_data (data, NULL), error); } +static gboolean +fu_main_is_hypervisor (void) +{ + g_autofree gchar *buf = NULL; + gsize bufsz = 0; + if (!g_file_get_contents ("/proc/cpuinfo", &buf, &bufsz, NULL)) + return FALSE; + return g_strstr_len (buf, (gssize) bufsz, "hypervisor") != NULL; +} + +static gboolean +fu_main_is_container (void) +{ + g_autofree gchar *buf = NULL; + gsize bufsz = 0; + if (!g_file_get_contents ("/proc/1/cgroup", &buf, &bufsz, NULL)) + return FALSE; + if (g_strstr_len (buf, (gssize) bufsz, "docker") != NULL) + return TRUE; + if (g_strstr_len (buf, (gssize) bufsz, "lxc") != NULL) + return TRUE; + return FALSE; +} + static void fu_main_private_free (FuMainPrivate *priv) { @@ -1795,6 +1833,13 @@ main (int argc, char *argv[]) return EXIT_FAILURE; } + /* are we a VM? */ + if (fu_main_is_hypervisor ()) { + priv->machine_kind = FU_MAIN_MACHINE_KIND_VIRTUAL; + } else if (fu_main_is_container ()) { + priv->machine_kind = FU_MAIN_MACHINE_KIND_CONTAINER; + } + /* own the object */ priv->owner_id = g_bus_own_name (G_BUS_TYPE_SYSTEM, FWUPD_DBUS_SERVICE, From 9f31bc22df4056e6f985252ab2f8a7526abf1aa3 Mon Sep 17 00:00:00 2001 From: Jerry Zhang Date: Mon, 31 Aug 2020 17:36:34 -0500 Subject: [PATCH 379/607] dfu: Specify "RemoveDelay" for Poly USB Cameras in dfu.quirk For some Poly USB Cameras, it takes a longer time than the default (FU_DEVICE_REMOVE_DELAY_RE_ENUMERATE) for being detached to DFU or attached to normal mode. Need to specify the timeout in "RemoveDelay" quirk key. Also replace the hard-coded timeout with fu_device_get_remove_delay() in dfu-tool.c. --- plugins/dfu/dfu-tool.c | 9 ++++----- plugins/dfu/dfu.quirk | 10 ++++++++++ 2 files changed, 14 insertions(+), 5 deletions(-) diff --git a/plugins/dfu/dfu-tool.c b/plugins/dfu/dfu-tool.c index 9a99ef3e4..f5f221a93 100644 --- a/plugins/dfu/dfu-tool.c +++ b/plugins/dfu/dfu-tool.c @@ -278,7 +278,7 @@ dfu_device_wait_for_replug (DfuToolPrivate *priv, DfuDevice *device, guint timeo /* watch the device disappear and re-appear */ usb_device2 = g_usb_context_wait_for_replug (usb_context, usb_device, - FU_DEVICE_REMOVE_DELAY_RE_ENUMERATE, + timeout, error); if (usb_device2 == NULL) return FALSE; @@ -918,10 +918,9 @@ dfu_tool_write (DfuToolPrivate *priv, gchar **values, GError **error) if (!fu_device_detach (FU_DEVICE (device), error)) return FALSE; if (!dfu_device_wait_for_replug (priv, device, - FU_DEVICE_REMOVE_DELAY_RE_ENUMERATE, - error)) { + fu_device_get_remove_delay (FU_DEVICE (device)), + error)) return FALSE; - } } /* allow wildcards */ @@ -941,7 +940,7 @@ dfu_tool_write (DfuToolPrivate *priv, gchar **values, GError **error) return FALSE; if (dfu_device_has_attribute (device, DFU_DEVICE_ATTRIBUTE_MANIFEST_TOL)) { - if (!dfu_device_wait_for_replug (priv, device, FU_DEVICE_REMOVE_DELAY_RE_ENUMERATE, error)) + if (!dfu_device_wait_for_replug (priv, device, fu_device_get_remove_delay (FU_DEVICE (device)), error)) return FALSE; } diff --git a/plugins/dfu/dfu.quirk b/plugins/dfu/dfu.quirk index 5639c7cd0..73908e34d 100644 --- a/plugins/dfu/dfu.quirk +++ b/plugins/dfu/dfu.quirk @@ -334,38 +334,48 @@ DfuForceTimeout = 5000 [DeviceInstanceId=USB\VID_095D&PID_9217] Plugin = dfu Flags = manifest-poll +RemoveDelay = 40000 [DeviceInstanceId=USB\VID_095D&PID_9218] Plugin = dfu Flags = manifest-poll +RemoveDelay = 40000 # Poly Eagle Eye Cube [DeviceInstanceId=USB\VID_095D&PID_9212] Plugin = dfu Flags = manifest-poll +RemoveDelay = 30000 [DeviceInstanceId=USB\VID_095D&PID_9213] Plugin = dfu Flags = manifest-poll +RemoveDelay = 30000 # Poly P30 [DeviceInstanceId=USB\VID_095D&PID_9290] Plugin = dfu Flags = manifest-poll +RemoveDelay = 40000 [DeviceInstanceId=USB\VID_095D&PID_9291] Plugin = dfu Flags = manifest-poll +RemoveDelay = 40000 # Poly ULCC [DeviceInstanceId=USB\VID_095D&PID_9160] Plugin = dfu Flags = manifest-poll +RemoveDelay = 50000 [DeviceInstanceId=USB\VID_095D&PID_927B] Plugin = dfu Flags = manifest-poll +RemoveDelay = 50000 # Poly Eagle Eye Mini [DeviceInstanceId=USB\VID_095D&PID_3001] Plugin = dfu Flags = manifest-poll +RemoveDelay = 9000 [DeviceInstanceId=USB\VID_095D&PID_3002] Plugin = dfu Flags = manifest-poll +RemoveDelay = 9000 From 7c8a83065924a7dff86c128b0b6625c0ab205cc6 Mon Sep 17 00:00:00 2001 From: Richard Hughes Date: Tue, 25 Aug 2020 16:00:26 +0100 Subject: [PATCH 380/607] libfwupd: Add async versions of the library for GUI tools Rather than force the GUI to interact with fwupd using threads, provide async versions so thay can be run without blocking the UI thread. --- docs/fwupd-docs.xml | 1 + libfwupd/fwupd-client-private.h | 36 + libfwupd/fwupd-client-sync.c | 2009 +++++++++++++++ libfwupd/fwupd-client-sync.h | 170 ++ libfwupd/fwupd-client.c | 4146 ++++++++++++++++++++----------- libfwupd/fwupd-client.h | 234 +- libfwupd/fwupd-common-private.h | 10 +- libfwupd/fwupd-common.c | 90 + libfwupd/fwupd-device.c | 1 - libfwupd/fwupd-self-test.c | 1 + libfwupd/fwupd.h | 1 + libfwupd/fwupd.map | 71 + libfwupd/meson.build | 4 + 13 files changed, 5334 insertions(+), 1440 deletions(-) create mode 100644 libfwupd/fwupd-client-private.h create mode 100644 libfwupd/fwupd-client-sync.c create mode 100644 libfwupd/fwupd-client-sync.h diff --git a/docs/fwupd-docs.xml b/docs/fwupd-docs.xml index 3250d6fda..cae03b8fa 100644 --- a/docs/fwupd-docs.xml +++ b/docs/fwupd-docs.xml @@ -26,6 +26,7 @@ + diff --git a/libfwupd/fwupd-client-private.h b/libfwupd/fwupd-client-private.h new file mode 100644 index 000000000..9ed55a449 --- /dev/null +++ b/libfwupd/fwupd-client-private.h @@ -0,0 +1,36 @@ +/* + * Copyright (C) 2016-2020 Richard Hughes + * + * SPDX-License-Identifier: LGPL-2.1+ + */ + +#pragma once + +#include "fwupd-client.h" + +#ifdef HAVE_GIO_UNIX +#include +#endif + +#ifdef HAVE_GIO_UNIX +void fwupd_client_get_details_stream_async (FwupdClient *self, + GUnixInputStream *istr, + GCancellable *cancellable, + GAsyncReadyCallback callback, + gpointer callback_data); +void fwupd_client_install_stream_async (FwupdClient *self, + const gchar *device_id, + GUnixInputStream *istr, + const gchar *filename_hint, + FwupdInstallFlags install_flags, + GCancellable *cancellable, + GAsyncReadyCallback callback, + gpointer callback_data); +void fwupd_client_update_metadata_stream_async(FwupdClient *self, + const gchar *remote_id, + GUnixInputStream *istr, + GUnixInputStream *istr_sig, + GCancellable *cancellable, + GAsyncReadyCallback callback, + gpointer callback_data); +#endif diff --git a/libfwupd/fwupd-client-sync.c b/libfwupd/fwupd-client-sync.c new file mode 100644 index 000000000..e122b376b --- /dev/null +++ b/libfwupd/fwupd-client-sync.c @@ -0,0 +1,2009 @@ +/* + * Copyright (C) 2016-2020 Richard Hughes + * + * SPDX-License-Identifier: LGPL-2.1+ + */ + +#include "config.h" + +#ifdef HAVE_GIO_UNIX +#include +#endif + +#include "fwupd-client.h" +#include "fwupd-client-private.h" +#include "fwupd-client-sync.h" +#include "fwupd-common-private.h" +#include "fwupd-error.h" + +typedef struct { + gboolean ret; + gchar *str; + GError *error; + GPtrArray *array; + GMainLoop *loop; + GVariant *val; + GHashTable *hash; + GBytes *bytes; + FwupdDevice *device; +} FwupdClientHelper; + +static void +fwupd_client_helper_free (FwupdClientHelper *helper) +{ + if (helper->val != NULL) + g_variant_unref (helper->val); + if (helper->error != NULL) + g_error_free (helper->error); + if (helper->array != NULL) + g_ptr_array_unref (helper->array); + if (helper->hash != NULL) + g_hash_table_unref (helper->hash); + if (helper->bytes != NULL) + g_bytes_unref (helper->bytes); + if (helper->device != NULL) + g_object_unref (helper->device); + g_free (helper->str); + g_main_loop_unref (helper->loop); + g_free (helper); +} + +static FwupdClientHelper * +fwupd_client_helper_new (void) +{ + FwupdClientHelper *helper; + helper = g_new0 (FwupdClientHelper, 1); + helper->loop = g_main_loop_new (NULL, FALSE); + return helper; +} + +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wunused-function" +G_DEFINE_AUTOPTR_CLEANUP_FUNC(FwupdClientHelper, fwupd_client_helper_free) +#pragma clang diagnostic pop + +static void +fwupd_client_connect_cb (GObject *source, GAsyncResult *res, gpointer user_data) +{ + FwupdClientHelper *helper = (FwupdClientHelper *) user_data; + helper->ret = fwupd_client_connect_finish (FWUPD_CLIENT (source), res, &helper->error); + g_main_loop_quit (helper->loop); +} + +/** + * fwupd_client_connect: + * @self: A #FwupdClient + * @cancellable: the #GCancellable, or %NULL + * @error: the #GError, or %NULL + * + * Sets up the client ready for use. Most other methods call this + * for you, and do you only need to call this if you are just watching + * the client. + * + * Returns: %TRUE for success + * + * Since: 0.7.1 + **/ +gboolean +fwupd_client_connect (FwupdClient *self, GCancellable *cancellable, GError **error) +{ + g_autoptr(FwupdClientHelper) helper = fwupd_client_helper_new (); + + g_return_val_if_fail (FWUPD_IS_CLIENT (self), FALSE); + g_return_val_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable), FALSE); + g_return_val_if_fail (error == NULL || *error == NULL, FALSE); + + /* call async version and run loop until complete */ + fwupd_client_connect_async (self, cancellable, fwupd_client_connect_cb, helper); + g_main_loop_run (helper->loop); + if (!helper->ret) { + g_propagate_error (error, g_steal_pointer (&helper->error)); + return FALSE; + } + return TRUE; +} + +static void +fwupd_client_get_devices_cb (GObject *source, GAsyncResult *res, gpointer user_data) +{ + FwupdClientHelper *helper = (FwupdClientHelper *) user_data; + helper->array = fwupd_client_get_devices_finish (FWUPD_CLIENT (source), res, &helper->error); + g_main_loop_quit (helper->loop); +} + +/** + * fwupd_client_get_devices: + * @self: A #FwupdClient + * @cancellable: the #GCancellable, or %NULL + * @error: the #GError, or %NULL + * + * Gets all the devices registered with the daemon. + * + * Returns: (element-type FwupdDevice) (transfer container): results + * + * Since: 0.9.2 + **/ +GPtrArray * +fwupd_client_get_devices (FwupdClient *self, GCancellable *cancellable, GError **error) +{ + g_autoptr(FwupdClientHelper) helper = fwupd_client_helper_new (); + + g_return_val_if_fail (FWUPD_IS_CLIENT (self), NULL); + g_return_val_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable), NULL); + g_return_val_if_fail (error == NULL || *error == NULL, NULL); + + /* connect */ + if (!fwupd_client_connect (self, cancellable, error)) + return NULL; + + /* call async version and run loop until complete */ + fwupd_client_get_devices_async (self, cancellable, + fwupd_client_get_devices_cb, helper); + g_main_loop_run (helper->loop); + if (helper->array == NULL) { + g_propagate_error (error, g_steal_pointer (&helper->error)); + return NULL; + } + return g_steal_pointer (&helper->array); +} +static void +fwupd_client_get_history_cb (GObject *source, GAsyncResult *res, gpointer user_data) +{ + FwupdClientHelper *helper = (FwupdClientHelper *) user_data; + helper->array = fwupd_client_get_history_finish (FWUPD_CLIENT (source), res, &helper->error); + g_main_loop_quit (helper->loop); +} + +/** + * fwupd_client_get_history: + * @self: A #FwupdClient + * @cancellable: the #GCancellable, or %NULL + * @error: the #GError, or %NULL + * + * Gets all the history. + * + * Returns: (element-type FwupdDevice) (transfer container): results + * + * Since: 1.0.4 + **/ +GPtrArray * +fwupd_client_get_history (FwupdClient *self, GCancellable *cancellable, GError **error) +{ + g_autoptr(FwupdClientHelper) helper = fwupd_client_helper_new (); + + g_return_val_if_fail (FWUPD_IS_CLIENT (self), NULL); + g_return_val_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable), NULL); + g_return_val_if_fail (error == NULL || *error == NULL, NULL); + + /* connect */ + if (!fwupd_client_connect (self, cancellable, error)) + return NULL; + + /* call async version and run loop until complete */ + fwupd_client_get_history_async (self, cancellable, + fwupd_client_get_history_cb, helper); + g_main_loop_run (helper->loop); + if (helper->array == NULL) { + g_propagate_error (error, g_steal_pointer (&helper->error)); + return NULL; + } + return g_steal_pointer (&helper->array); +} + +static void +fwupd_client_get_releases_cb (GObject *source, GAsyncResult *res, gpointer user_data) +{ + FwupdClientHelper *helper = (FwupdClientHelper *) user_data; + helper->array = fwupd_client_get_releases_finish (FWUPD_CLIENT (source), res, &helper->error); + g_main_loop_quit (helper->loop); +} + +/** + * fwupd_client_get_releases: + * @self: A #FwupdClient + * @device_id: the device ID + * @cancellable: the #GCancellable, or %NULL + * @error: the #GError, or %NULL + * + * Gets all the releases for a specific device + * + * Returns: (element-type FwupdRelease) (transfer container): results + * + * Since: 0.9.3 + **/ +GPtrArray * +fwupd_client_get_releases (FwupdClient *self, const gchar *device_id, + GCancellable *cancellable, GError **error) +{ + g_autoptr(FwupdClientHelper) helper = fwupd_client_helper_new (); + + g_return_val_if_fail (FWUPD_IS_CLIENT (self), NULL); + g_return_val_if_fail (device_id != NULL, NULL); + g_return_val_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable), NULL); + g_return_val_if_fail (error == NULL || *error == NULL, NULL); + + /* connect */ + if (!fwupd_client_connect (self, cancellable, error)) + return NULL; + + /* call async version and run loop until complete */ + fwupd_client_get_releases_async (self, device_id, cancellable, + fwupd_client_get_releases_cb, helper); + g_main_loop_run (helper->loop); + if (helper->array == NULL) { + g_propagate_error (error, g_steal_pointer (&helper->error)); + return NULL; + } + return g_steal_pointer (&helper->array); +} + +static void +fwupd_client_get_downgrades_cb (GObject *source, GAsyncResult *res, gpointer user_data) +{ + FwupdClientHelper *helper = (FwupdClientHelper *) user_data; + helper->array = fwupd_client_get_downgrades_finish (FWUPD_CLIENT (source), res, &helper->error); + g_main_loop_quit (helper->loop); +} + +/** + * fwupd_client_get_downgrades: + * @self: A #FwupdClient + * @device_id: the device ID + * @cancellable: the #GCancellable, or %NULL + * @error: the #GError, or %NULL + * + * Gets all the downgrades for a specific device. + * + * Returns: (element-type FwupdRelease) (transfer container): results + * + * Since: 0.9.8 + **/ +GPtrArray * +fwupd_client_get_downgrades (FwupdClient *self, const gchar *device_id, + GCancellable *cancellable, GError **error) +{ + g_autoptr(FwupdClientHelper) helper = fwupd_client_helper_new (); + + g_return_val_if_fail (FWUPD_IS_CLIENT (self), NULL); + g_return_val_if_fail (device_id != NULL, NULL); + g_return_val_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable), NULL); + g_return_val_if_fail (error == NULL || *error == NULL, NULL); + + /* connect */ + if (!fwupd_client_connect (self, cancellable, error)) + return NULL; + + /* call async version and run loop until complete */ + fwupd_client_get_downgrades_async (self, device_id, cancellable, + fwupd_client_get_downgrades_cb, helper); + g_main_loop_run (helper->loop); + if (helper->array == NULL) { + g_propagate_error (error, g_steal_pointer (&helper->error)); + return NULL; + } + return g_steal_pointer (&helper->array); +} + +static void +fwupd_client_get_upgrades_cb (GObject *source, GAsyncResult *res, gpointer user_data) +{ + FwupdClientHelper *helper = (FwupdClientHelper *) user_data; + helper->array = fwupd_client_get_upgrades_finish (FWUPD_CLIENT (source), res, &helper->error); + g_main_loop_quit (helper->loop); +} + +/** + * fwupd_client_get_upgrades: + * @self: A #FwupdClient + * @device_id: the device ID + * @cancellable: the #GCancellable, or %NULL + * @error: the #GError, or %NULL + * + * Gets all the upgrades for a specific device. + * + * Returns: (element-type FwupdRelease) (transfer container): results + * + * Since: 0.9.8 + **/ +GPtrArray * +fwupd_client_get_upgrades (FwupdClient *self, const gchar *device_id, + GCancellable *cancellable, GError **error) +{ + g_autoptr(FwupdClientHelper) helper = fwupd_client_helper_new (); + + g_return_val_if_fail (FWUPD_IS_CLIENT (self), NULL); + g_return_val_if_fail (device_id != NULL, NULL); + g_return_val_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable), NULL); + g_return_val_if_fail (error == NULL || *error == NULL, NULL); + + /* connect */ + if (!fwupd_client_connect (self, cancellable, error)) + return NULL; + + /* call async version and run loop until complete */ + fwupd_client_get_upgrades_async (self, device_id, cancellable, + fwupd_client_get_upgrades_cb, helper); + g_main_loop_run (helper->loop); + if (helper->array == NULL) { + g_propagate_error (error, g_steal_pointer (&helper->error)); + return NULL; + } + return g_steal_pointer (&helper->array); +} + +static void +fwupd_client_get_details_bytes_cb (GObject *source, GAsyncResult *res, gpointer user_data) +{ + FwupdClientHelper *helper = (FwupdClientHelper *) user_data; + helper->array = fwupd_client_get_details_bytes_finish (FWUPD_CLIENT (source), res, &helper->error); + g_main_loop_quit (helper->loop); +} + +/** + * fwupd_client_get_details_bytes: + * @self: A #FwupdClient + * @bytes: the firmware blob, e.g. the contents of `firmware.cab` + * @cancellable: the #GCancellable, or %NULL + * @error: the #GError, or %NULL + * + * Gets details about a specific firmware file. + * + * Returns: (transfer container) (element-type FwupdDevice): an array of results + * + * Since: 1.5.0 + **/ +GPtrArray * +fwupd_client_get_details_bytes (FwupdClient *self, + GBytes *bytes, + GCancellable *cancellable, + GError **error) +{ + g_autoptr(FwupdClientHelper) helper = fwupd_client_helper_new (); + + g_return_val_if_fail (FWUPD_IS_CLIENT (self), NULL); + g_return_val_if_fail (bytes != NULL, NULL); + g_return_val_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable), NULL); + g_return_val_if_fail (error == NULL || *error == NULL, NULL); + + /* connect */ + if (!fwupd_client_connect (self, cancellable, error)) + return NULL; + + /* call async version and run loop until complete */ + fwupd_client_get_details_bytes_async (self, bytes, + cancellable, + fwupd_client_get_details_bytes_cb, + helper); + g_main_loop_run (helper->loop); + if (helper->array == NULL) { + g_propagate_error (error, g_steal_pointer (&helper->error)); + return NULL; + } + return g_steal_pointer (&helper->array); +} + +#ifdef HAVE_GIO_UNIX +static void +fwupd_client_get_details_cb (GObject *source, GAsyncResult *res, gpointer user_data) +{ + FwupdClientHelper *helper = (FwupdClientHelper *) user_data; + helper->array = fwupd_client_get_details_bytes_finish (FWUPD_CLIENT (source), res, &helper->error); + g_main_loop_quit (helper->loop); +} +#endif + +/** + * fwupd_client_get_details: + * @self: A #FwupdClient + * @filename: the firmware filename, e.g. `firmware.cab` + * @cancellable: the #GCancellable, or %NULL + * @error: the #GError, or %NULL + * + * Gets details about a specific firmware file. + * + * Returns: (transfer container) (element-type FwupdDevice): an array of results + * + * Since: 1.0.0 + **/ +GPtrArray * +fwupd_client_get_details (FwupdClient *self, + const gchar *filename, + GCancellable *cancellable, + GError **error) +{ +#ifdef HAVE_GIO_UNIX + g_autoptr(GUnixInputStream) istr = NULL; + g_autoptr(FwupdClientHelper) helper = fwupd_client_helper_new (); + + g_return_val_if_fail (FWUPD_IS_CLIENT (self), NULL); + g_return_val_if_fail (filename != NULL, NULL); + g_return_val_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable), NULL); + g_return_val_if_fail (error == NULL || *error == NULL, NULL); + + /* connect */ + if (!fwupd_client_connect (self, cancellable, error)) + return NULL; + + /* call async version and run loop until complete */ + istr = fwupd_unix_input_stream_from_fn (filename, error); + if (istr == NULL) + return NULL; + fwupd_client_get_details_stream_async (self, istr, cancellable, + fwupd_client_get_details_cb, + helper); + g_main_loop_run (helper->loop); + if (helper->array == NULL) { + g_propagate_error (error, g_steal_pointer (&helper->error)); + return NULL; + } + return g_steal_pointer (&helper->array); +#else + g_set_error_literal (error, + FWUPD_ERROR, + FWUPD_ERROR_NOT_SUPPORTED, + "Not supported as is unavailable"); + return NULL; +#endif +} + +static void +fwupd_client_verify_cb (GObject *source, GAsyncResult *res, gpointer user_data) +{ + FwupdClientHelper *helper = (FwupdClientHelper *) user_data; + helper->ret = fwupd_client_verify_finish (FWUPD_CLIENT (source), res, &helper->error); + g_main_loop_quit (helper->loop); +} + +/** + * fwupd_client_verify: + * @self: A #FwupdClient + * @device_id: the device ID + * @cancellable: the #GCancellable, or %NULL + * @error: the #GError, or %NULL + * + * Verify a specific device. + * + * Returns: %TRUE for verification success + * + * Since: 0.7.0 + **/ +gboolean +fwupd_client_verify (FwupdClient *self, + const gchar *device_id, + GCancellable *cancellable, + GError **error) +{ + g_autoptr(FwupdClientHelper) helper = fwupd_client_helper_new (); + + g_return_val_if_fail (FWUPD_IS_CLIENT (self), FALSE); + g_return_val_if_fail (device_id != NULL, FALSE); + g_return_val_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable), FALSE); + g_return_val_if_fail (error == NULL || *error == NULL, FALSE); + + /* connect */ + if (!fwupd_client_connect (self, cancellable, error)) + return FALSE; + + /* call async version and run loop until complete */ + fwupd_client_verify_async (self, device_id, cancellable, + fwupd_client_verify_cb, + helper); + g_main_loop_run (helper->loop); + if (!helper->ret) { + g_propagate_error (error, g_steal_pointer (&helper->error)); + return FALSE; + } + return TRUE; +} + +static void +fwupd_client_verify_update_cb (GObject *source, GAsyncResult *res, gpointer user_data) +{ + FwupdClientHelper *helper = (FwupdClientHelper *) user_data; + helper->ret = fwupd_client_verify_update_finish (FWUPD_CLIENT (source), res, &helper->error); + g_main_loop_quit (helper->loop); +} + +/** + * fwupd_client_verify_update: + * @self: A #FwupdClient + * @device_id: the device ID + * @cancellable: the #GCancellable, or %NULL + * @error: the #GError, or %NULL + * + * Update the verification record for a specific device. + * + * Returns: %TRUE for verification success + * + * Since: 0.8.0 + **/ +gboolean +fwupd_client_verify_update (FwupdClient *self, + const gchar *device_id, + GCancellable *cancellable, + GError **error) +{ + g_autoptr(FwupdClientHelper) helper = fwupd_client_helper_new (); + + g_return_val_if_fail (FWUPD_IS_CLIENT (self), FALSE); + g_return_val_if_fail (device_id != NULL, FALSE); + g_return_val_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable), FALSE); + g_return_val_if_fail (error == NULL || *error == NULL, FALSE); + + /* connect */ + if (!fwupd_client_connect (self, cancellable, error)) + return FALSE; + + /* call async version and run loop until complete */ + fwupd_client_verify_update_async (self, device_id, cancellable, + fwupd_client_verify_update_cb, + helper); + g_main_loop_run (helper->loop); + if (!helper->ret) { + g_propagate_error (error, g_steal_pointer (&helper->error)); + return FALSE; + } + return TRUE; +} + +static void +fwupd_client_unlock_cb (GObject *source, GAsyncResult *res, gpointer user_data) +{ + FwupdClientHelper *helper = (FwupdClientHelper *) user_data; + helper->ret = fwupd_client_unlock_finish (FWUPD_CLIENT (source), res, &helper->error); + g_main_loop_quit (helper->loop); +} + +/** + * fwupd_client_unlock: + * @self: A #FwupdClient + * @device_id: the device ID + * @cancellable: the #GCancellable, or %NULL + * @error: the #GError, or %NULL + * + * Unlocks a specific device so firmware can be read or wrote. + * + * Returns: %TRUE for success + * + * Since: 0.7.0 + **/ +gboolean +fwupd_client_unlock (FwupdClient *self, + const gchar *device_id, + GCancellable *cancellable, + GError **error) +{ + g_autoptr(FwupdClientHelper) helper = fwupd_client_helper_new (); + + g_return_val_if_fail (FWUPD_IS_CLIENT (self), FALSE); + g_return_val_if_fail (device_id != NULL, FALSE); + g_return_val_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable), FALSE); + g_return_val_if_fail (error == NULL || *error == NULL, FALSE); + + /* connect */ + if (!fwupd_client_connect (self, cancellable, error)) + return FALSE; + + /* call async version and run loop until complete */ + fwupd_client_unlock_async (self, device_id, cancellable, + fwupd_client_unlock_cb, + helper); + g_main_loop_run (helper->loop); + if (!helper->ret) { + g_propagate_error (error, g_steal_pointer (&helper->error)); + return FALSE; + } + return TRUE; +} +static void +fwupd_client_modify_config_cb (GObject *source, GAsyncResult *res, gpointer user_data) +{ + FwupdClientHelper *helper = (FwupdClientHelper *) user_data; + helper->ret = fwupd_client_modify_config_finish (FWUPD_CLIENT (source), res, &helper->error); + g_main_loop_quit (helper->loop); +} + +/** + * fwupd_client_modify_config + * @self: A #FwupdClient + * @key: key, e.g. `DisabledPlugins` + * @value: value, e.g. `*` + * @cancellable: the #GCancellable, or %NULL + * @error: the #GError, or %NULL + * + * Modifies a daemon config option. + * The daemon will only respond to this request with proper permissions + * + * Returns: %TRUE for success + * + * Since: 1.2.8 + **/ +gboolean +fwupd_client_modify_config (FwupdClient *self, + const gchar *key, + const gchar *value, + GCancellable *cancellable, + GError **error) +{ + g_autoptr(FwupdClientHelper) helper = fwupd_client_helper_new (); + + g_return_val_if_fail (FWUPD_IS_CLIENT (self), FALSE); + g_return_val_if_fail (key != NULL, FALSE); + g_return_val_if_fail (value != NULL, FALSE); + g_return_val_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable), FALSE); + g_return_val_if_fail (error == NULL || *error == NULL, FALSE); + + /* connect */ + if (!fwupd_client_connect (self, cancellable, error)) + return FALSE; + + /* call async version and run loop until complete */ + fwupd_client_modify_config_async (self, key, value, + cancellable, + fwupd_client_modify_config_cb, + helper); + g_main_loop_run (helper->loop); + if (!helper->ret) { + g_propagate_error (error, g_steal_pointer (&helper->error)); + return FALSE; + } + return TRUE; +} + +static void +fwupd_client_activate_cb (GObject *source, GAsyncResult *res, gpointer user_data) +{ + FwupdClientHelper *helper = (FwupdClientHelper *) user_data; + helper->ret = fwupd_client_activate_finish (FWUPD_CLIENT (source), res, &helper->error); + g_main_loop_quit (helper->loop); +} + +/** + * fwupd_client_activate: + * @self: A #FwupdClient + * @cancellable: the #GCancellable, or %NULL + * @device_id: a device + * @error: the #GError, or %NULL + * + * Activates up a device, which normally means the device switches to a new + * firmware version. This should only be called when data loss cannot occur. + * + * Returns: %TRUE for success + * + * Since: 1.2.6 + **/ +gboolean +fwupd_client_activate (FwupdClient *self, + GCancellable *cancellable, + const gchar *device_id, /* yes, this is the wrong way around :/ */ + GError **error) +{ + g_autoptr(FwupdClientHelper) helper = fwupd_client_helper_new (); + + g_return_val_if_fail (FWUPD_IS_CLIENT (self), FALSE); + g_return_val_if_fail (device_id != NULL, FALSE); + g_return_val_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable), FALSE); + g_return_val_if_fail (error == NULL || *error == NULL, FALSE); + + /* connect */ + if (!fwupd_client_connect (self, cancellable, error)) + return FALSE; + + /* call async version and run loop until complete */ + fwupd_client_activate_async (self, device_id, + cancellable, + fwupd_client_activate_cb, + helper); + g_main_loop_run (helper->loop); + if (!helper->ret) { + g_propagate_error (error, g_steal_pointer (&helper->error)); + return FALSE; + } + return TRUE; +} + +static void +fwupd_client_clear_results_cb (GObject *source, GAsyncResult *res, gpointer user_data) +{ + FwupdClientHelper *helper = (FwupdClientHelper *) user_data; + helper->ret = fwupd_client_clear_results_finish (FWUPD_CLIENT (source), res, &helper->error); + g_main_loop_quit (helper->loop); +} + +/** + * fwupd_client_clear_results: + * @self: A #FwupdClient + * @device_id: the device ID + * @cancellable: the #GCancellable, or %NULL + * @error: the #GError, or %NULL + * + * Clears the results for a specific device. + * + * Returns: %TRUE for success + * + * Since: 0.7.0 + **/ +gboolean +fwupd_client_clear_results (FwupdClient *self, + const gchar *device_id, + GCancellable *cancellable, + GError **error) +{ + g_autoptr(FwupdClientHelper) helper = fwupd_client_helper_new (); + + g_return_val_if_fail (FWUPD_IS_CLIENT (self), FALSE); + g_return_val_if_fail (device_id != NULL, FALSE); + g_return_val_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable), FALSE); + g_return_val_if_fail (error == NULL || *error == NULL, FALSE); + + /* connect */ + if (!fwupd_client_connect (self, cancellable, error)) + return FALSE; + + /* call async version and run loop until complete */ + fwupd_client_clear_results_async (self, device_id, + cancellable, + fwupd_client_clear_results_cb, + helper); + g_main_loop_run (helper->loop); + if (!helper->ret) { + g_propagate_error (error, g_steal_pointer (&helper->error)); + return FALSE; + } + return TRUE; +} + +static void +fwupd_client_get_results_cb (GObject *source, GAsyncResult *res, gpointer user_data) +{ + FwupdClientHelper *helper = (FwupdClientHelper *) user_data; + helper->device = fwupd_client_get_results_finish (FWUPD_CLIENT (source), res, &helper->error); + g_main_loop_quit (helper->loop); +} + +/** + * fwupd_client_get_results: + * @self: A #FwupdClient + * @device_id: the device ID + * @cancellable: the #GCancellable, or %NULL + * @error: the #GError, or %NULL + * + * Gets the results of a previous firmware update for a specific device. + * + * Returns: (transfer full): a #FwupdDevice, or %NULL for failure + * + * Since: 0.7.0 + **/ +FwupdDevice * +fwupd_client_get_results (FwupdClient *self, const gchar *device_id, + GCancellable *cancellable, GError **error) +{ + g_autoptr(FwupdClientHelper) helper = fwupd_client_helper_new (); + + g_return_val_if_fail (FWUPD_IS_CLIENT (self), NULL); + g_return_val_if_fail (device_id != NULL, NULL); + g_return_val_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable), NULL); + g_return_val_if_fail (error == NULL || *error == NULL, NULL); + + /* connect */ + if (!fwupd_client_connect (self, cancellable, error)) + return NULL; + + /* call async version and run loop until complete */ + fwupd_client_get_results_async (self, device_id, cancellable, + fwupd_client_get_results_cb, helper); + g_main_loop_run (helper->loop); + if (helper->device == NULL) { + g_propagate_error (error, g_steal_pointer (&helper->error)); + return NULL; + } + return g_steal_pointer (&helper->device); +} + +static void +fwupd_client_get_host_security_attrs_cb (GObject *source, GAsyncResult *res, gpointer user_data) +{ + FwupdClientHelper *helper = (FwupdClientHelper *) user_data; + helper->array = fwupd_client_get_host_security_attrs_finish (FWUPD_CLIENT (source), res, &helper->error); + g_main_loop_quit (helper->loop); +} + +/** + * fwupd_client_get_host_security_attrs: + * @self: A #FwupdClient + * @cancellable: the #GCancellable, or %NULL + * @error: the #GError, or %NULL + * + * Gets all the host security attributes from the daemon. + * + * Returns: (element-type FwupdSecurityAttr) (transfer container): attributes + * + * Since: 1.5.0 + **/ +GPtrArray * +fwupd_client_get_host_security_attrs (FwupdClient *self, + GCancellable *cancellable, + GError **error) +{ + g_autoptr(FwupdClientHelper) helper = fwupd_client_helper_new (); + + g_return_val_if_fail (FWUPD_IS_CLIENT (self), NULL); + g_return_val_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable), NULL); + g_return_val_if_fail (error == NULL || *error == NULL, NULL); + + /* connect */ + if (!fwupd_client_connect (self, cancellable, error)) + return NULL; + + /* call async version and run loop until complete */ + fwupd_client_get_host_security_attrs_async (self, cancellable, + fwupd_client_get_host_security_attrs_cb, + helper); + g_main_loop_run (helper->loop); + if (helper->array == NULL) { + g_propagate_error (error, g_steal_pointer (&helper->error)); + return NULL; + } + return g_steal_pointer (&helper->array); +} + +static void +fwupd_client_get_device_by_id_cb (GObject *source, GAsyncResult *res, gpointer user_data) +{ + FwupdClientHelper *helper = (FwupdClientHelper *) user_data; + helper->device = fwupd_client_get_device_by_id_finish (FWUPD_CLIENT (source), res, &helper->error); + g_main_loop_quit (helper->loop); +} + +/** + * fwupd_client_get_device_by_id: + * @self: A #FwupdClient + * @device_id: the device ID, e.g. `usb:00:01:03:03` + * @cancellable: the #GCancellable, or %NULL + * @error: the #GError, or %NULL + * + * Gets a device by it's device ID. + * + * Returns: (transfer full): a #FwupdDevice or %NULL + * + * Since: 0.9.3 + **/ +FwupdDevice * +fwupd_client_get_device_by_id (FwupdClient *self, + const gchar *device_id, + GCancellable *cancellable, + GError **error) +{ + g_autoptr(FwupdClientHelper) helper = fwupd_client_helper_new (); + + g_return_val_if_fail (FWUPD_IS_CLIENT (self), NULL); + g_return_val_if_fail (device_id != NULL, NULL); + g_return_val_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable), NULL); + g_return_val_if_fail (error == NULL || *error == NULL, NULL); + + /* connect */ + if (!fwupd_client_connect (self, cancellable, error)) + return NULL; + + /* call async version and run loop until complete */ + fwupd_client_get_device_by_id_async (self, device_id, cancellable, + fwupd_client_get_device_by_id_cb, + helper); + g_main_loop_run (helper->loop); + if (helper->device == NULL) { + g_propagate_error (error, g_steal_pointer (&helper->error)); + return NULL; + } + return g_steal_pointer (&helper->device); +} + +static void +fwupd_client_get_devices_by_guid_cb (GObject *source, GAsyncResult *res, gpointer user_data) +{ + FwupdClientHelper *helper = (FwupdClientHelper *) user_data; + helper->array = fwupd_client_get_devices_by_guid_finish (FWUPD_CLIENT (source), res, &helper->error); + g_main_loop_quit (helper->loop); +} + +/** + * fwupd_client_get_devices_by_guid: + * @self: A #FwupdClient + * @guid: the GUID, e.g. `e22c4520-43dc-5bb3-8245-5787fead9b63` + * @cancellable: the #GCancellable, or %NULL + * @error: the #GError, or %NULL + * + * Gets any devices that provide a specific GUID. An error is returned if no + * devices contains this GUID. + * + * Returns: (element-type FwupdDevice) (transfer container): devices or %NULL + * + * Since: 1.4.1 + **/ +GPtrArray * +fwupd_client_get_devices_by_guid (FwupdClient *self, const gchar *guid, + GCancellable *cancellable, GError **error) +{ + g_autoptr(FwupdClientHelper) helper = fwupd_client_helper_new (); + + g_return_val_if_fail (FWUPD_IS_CLIENT (self), NULL); + g_return_val_if_fail (guid != NULL, NULL); + g_return_val_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable), NULL); + g_return_val_if_fail (error == NULL || *error == NULL, NULL); + + /* connect */ + if (!fwupd_client_connect (self, cancellable, error)) + return NULL; + + /* call async version and run loop until complete */ + fwupd_client_get_devices_by_guid_async (self, guid, cancellable, + fwupd_client_get_devices_by_guid_cb, + helper); + g_main_loop_run (helper->loop); + if (helper->array == NULL) { + g_propagate_error (error, g_steal_pointer (&helper->error)); + return NULL; + } + return g_steal_pointer (&helper->array); +} + +#ifdef HAVE_GIO_UNIX +static void +fwupd_client_install_fd_cb (GObject *source, GAsyncResult *res, gpointer user_data) +{ + FwupdClientHelper *helper = (FwupdClientHelper *) user_data; + helper->ret = fwupd_client_install_bytes_finish (FWUPD_CLIENT (source), res, &helper->error); + g_main_loop_quit (helper->loop); +} +#endif + +/** + * fwupd_client_install: + * @self: A #FwupdClient + * @device_id: the device ID + * @filename: the filename to install + * @install_flags: the #FwupdInstallFlags, e.g. %FWUPD_INSTALL_FLAG_ALLOW_REINSTALL + * @cancellable: the #GCancellable, or %NULL + * @error: the #GError, or %NULL + * + * Install a file onto a specific device. + * + * Returns: %TRUE for success + * + * Since: 0.7.0 + **/ +gboolean +fwupd_client_install (FwupdClient *self, + const gchar *device_id, + const gchar *filename, + FwupdInstallFlags install_flags, + GCancellable *cancellable, + GError **error) +{ +#ifdef HAVE_GIO_UNIX + g_autoptr(GUnixInputStream) istr = NULL; + g_autoptr(FwupdClientHelper) helper = fwupd_client_helper_new (); + + g_return_val_if_fail (FWUPD_IS_CLIENT (self), FALSE); + g_return_val_if_fail (device_id != NULL, FALSE); + g_return_val_if_fail (filename != NULL, FALSE); + g_return_val_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable), FALSE); + g_return_val_if_fail (error == NULL || *error == NULL, FALSE); + + /* connect */ + if (!fwupd_client_connect (self, cancellable, error)) + return FALSE; + + /* move to a thread if this ever takes more than a few ms */ + istr = fwupd_unix_input_stream_from_fn (filename, error); + if (istr == NULL) + return FALSE; + + /* call async version and run loop until complete */ + fwupd_client_install_stream_async (self, device_id, istr, filename, + install_flags, cancellable, + fwupd_client_install_fd_cb, + helper); + g_main_loop_run (helper->loop); + if (!helper->ret) { + g_propagate_error (error, g_steal_pointer (&helper->error)); + return FALSE; + } + return TRUE; +#else + g_set_error_literal (error, + FWUPD_ERROR, + FWUPD_ERROR_NOT_SUPPORTED, + "Not supported as is unavailable"); + return FALSE; +#endif +} + +static void +fwupd_client_install_bytes_cb (GObject *source, GAsyncResult *res, gpointer user_data) +{ + FwupdClientHelper *helper = (FwupdClientHelper *) user_data; + helper->ret = fwupd_client_install_bytes_finish (FWUPD_CLIENT (source), res, &helper->error); + g_main_loop_quit (helper->loop); +} + +/** + * fwupd_client_install_bytes: + * @self: A #FwupdClient + * @device_id: the device ID + * @bytes: #GBytes + * @install_flags: the #FwupdInstallFlags, e.g. %FWUPD_INSTALL_FLAG_ALLOW_REINSTALL + * @cancellable: the #GCancellable, or %NULL + * @error: the #GError, or %NULL + * + * Install firmware onto a specific device. + * + * Returns: %TRUE for success + * + * Since: 1.4.5 + **/ +gboolean +fwupd_client_install_bytes (FwupdClient *self, + const gchar *device_id, + GBytes *bytes, + FwupdInstallFlags install_flags, + GCancellable *cancellable, + GError **error) +{ + g_autoptr(FwupdClientHelper) helper = fwupd_client_helper_new (); + + g_return_val_if_fail (FWUPD_IS_CLIENT (self), FALSE); + g_return_val_if_fail (device_id != NULL, FALSE); + g_return_val_if_fail (bytes != NULL, FALSE); + g_return_val_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable), FALSE); + g_return_val_if_fail (error == NULL || *error == NULL, FALSE); + + /* connect */ + if (!fwupd_client_connect (self, cancellable, error)) + return FALSE; + + /* call async version and run loop until complete */ + fwupd_client_install_bytes_async (self, device_id, bytes, install_flags, + cancellable, + fwupd_client_install_bytes_cb, + helper); + g_main_loop_run (helper->loop); + if (!helper->ret) { + g_propagate_error (error, g_steal_pointer (&helper->error)); + return FALSE; + } + return TRUE; +} +static void +fwupd_client_install_release_cb (GObject *source, GAsyncResult *res, gpointer user_data) +{ + FwupdClientHelper *helper = (FwupdClientHelper *) user_data; + helper->ret = fwupd_client_install_release_finish (FWUPD_CLIENT (source), res, &helper->error); + g_main_loop_quit (helper->loop); +} + +/** + * fwupd_client_install_release: + * @self: A #FwupdClient + * @device: A #FwupdDevice + * @release: A #FwupdRelease + * @install_flags: the #FwupdInstallFlags, e.g. %FWUPD_INSTALL_FLAG_ALLOW_REINSTALL + * @cancellable: the #GCancellable, or %NULL + * @error: the #GError, or %NULL + * + * Installs a new release on a device, downloading the firmware if required. + * + * Returns: %TRUE for success + * + * Since: 1.4.5 + **/ +gboolean +fwupd_client_install_release (FwupdClient *self, + FwupdDevice *device, + FwupdRelease *release, + FwupdInstallFlags install_flags, + GCancellable *cancellable, + GError **error) +{ + g_autoptr(FwupdClientHelper) helper = fwupd_client_helper_new (); + + g_return_val_if_fail (FWUPD_IS_CLIENT (self), FALSE); + g_return_val_if_fail (FWUPD_IS_DEVICE (device), FALSE); + g_return_val_if_fail (FWUPD_IS_RELEASE (release), FALSE); + g_return_val_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable), FALSE); + g_return_val_if_fail (error == NULL || *error == NULL, FALSE); + + /* connect */ + if (!fwupd_client_connect (self, cancellable, error)) + return FALSE; + + /* call async version and run loop until complete */ + fwupd_client_install_release_async (self, device, release, + install_flags, cancellable, + fwupd_client_install_release_cb, + helper); + g_main_loop_run (helper->loop); + if (!helper->ret) { + g_propagate_error (error, g_steal_pointer (&helper->error)); + return FALSE; + } + return TRUE; +} + +#ifdef HAVE_GIO_UNIX +static void +fwupd_client_update_metadata_cb (GObject *source, GAsyncResult *res, gpointer user_data) +{ + FwupdClientHelper *helper = (FwupdClientHelper *) user_data; + helper->ret = fwupd_client_update_metadata_bytes_finish (FWUPD_CLIENT (source), res, &helper->error); + g_main_loop_quit (helper->loop); +} +#endif + +/** + * fwupd_client_update_metadata: + * @self: A #FwupdClient + * @remote_id: the remote ID, e.g. `lvfs-testing` + * @metadata_fn: the XML metadata filename + * @signature_fn: the GPG signature file + * @cancellable: the #GCancellable, or %NULL + * @error: the #GError, or %NULL + * + * Updates the metadata. This allows a session process to download the metadata + * and metadata signing file to be passed into the daemon to be checked and + * parsed. + * + * The @remote_id allows the firmware to be tagged so that the remote can be + * matched when the firmware is downloaded. + * + * Returns: %TRUE for success + * + * Since: 1.0.0 + **/ +gboolean +fwupd_client_update_metadata (FwupdClient *self, + const gchar *remote_id, + const gchar *metadata_fn, + const gchar *signature_fn, + GCancellable *cancellable, + GError **error) +{ +#ifdef HAVE_GIO_UNIX + g_autoptr(GUnixInputStream) istr = NULL; + g_autoptr(GUnixInputStream) istr_sig = NULL; + g_autoptr(FwupdClientHelper) helper = fwupd_client_helper_new (); + + g_return_val_if_fail (FWUPD_IS_CLIENT (self), FALSE); + g_return_val_if_fail (remote_id != NULL, FALSE); + g_return_val_if_fail (metadata_fn != NULL, FALSE); + g_return_val_if_fail (signature_fn != NULL, FALSE); + g_return_val_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable), FALSE); + g_return_val_if_fail (error == NULL || *error == NULL, FALSE); + + /* connect */ + if (!fwupd_client_connect (self, cancellable, error)) + return FALSE; + + istr = fwupd_unix_input_stream_from_fn (metadata_fn, error); + if (istr == NULL) + return FALSE; + istr_sig = fwupd_unix_input_stream_from_fn (signature_fn, error); + if (istr_sig == NULL) + return FALSE; + + /* call async version and run loop until complete */ + fwupd_client_update_metadata_stream_async (self, remote_id, istr, istr_sig, cancellable, + fwupd_client_update_metadata_cb, + helper); + g_main_loop_run (helper->loop); + if (!helper->ret) { + g_propagate_error (error, g_steal_pointer (&helper->error)); + return FALSE; + } + return TRUE; +#else + g_set_error_literal (error, + FWUPD_ERROR, + FWUPD_ERROR_NOT_SUPPORTED, + "Not supported as is unavailable"); + return FALSE; +#endif +} + +static void +fwupd_client_update_metadata_bytes_cb (GObject *source, GAsyncResult *res, gpointer user_data) +{ + FwupdClientHelper *helper = (FwupdClientHelper *) user_data; + helper->ret = fwupd_client_update_metadata_bytes_finish (FWUPD_CLIENT (source), res, &helper->error); + g_main_loop_quit (helper->loop); +} + +/** + * fwupd_client_update_metadata_bytes: + * @self: A #FwupdClient + * @remote_id: remote ID, e.g. `lvfs-testing` + * @metadata: XML metadata data + * @signature: signature data + * @cancellable: #GCancellable, or %NULL + * @error: the #GError, or %NULL + * + * Updates the metadata. This allows a session process to download the metadata + * and metadata signing file to be passed into the daemon to be checked and + * parsed. + * + * The @remote_id allows the firmware to be tagged so that the remote can be + * matched when the firmware is downloaded. + * + * Returns: %TRUE for success + * + * Since: 1.4.5 + **/ +gboolean +fwupd_client_update_metadata_bytes (FwupdClient *self, + const gchar *remote_id, + GBytes *metadata, + GBytes *signature, + GCancellable *cancellable, + GError **error) +{ + g_autoptr(FwupdClientHelper) helper = fwupd_client_helper_new (); + + g_return_val_if_fail (FWUPD_IS_CLIENT (self), FALSE); + g_return_val_if_fail (remote_id != NULL, FALSE); + g_return_val_if_fail (metadata != NULL, FALSE); + g_return_val_if_fail (signature != NULL, FALSE); + g_return_val_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable), FALSE); + g_return_val_if_fail (error == NULL || *error == NULL, FALSE); + + /* connect */ + if (!fwupd_client_connect (self, cancellable, error)) + return FALSE; + + /* call async version and run loop until complete */ + fwupd_client_update_metadata_bytes_async (self, remote_id, metadata, signature, + cancellable, + fwupd_client_update_metadata_bytes_cb, + helper); + g_main_loop_run (helper->loop); + if (!helper->ret) { + g_propagate_error (error, g_steal_pointer (&helper->error)); + return FALSE; + } + return TRUE; +} + +static void +fwupd_client_refresh_remote_cb (GObject *source, + GAsyncResult *res, + gpointer user_data) +{ + FwupdClientHelper *helper = (FwupdClientHelper *) user_data; + helper->ret = fwupd_client_refresh_remote_finish (FWUPD_CLIENT (source), + res, &helper->error); + g_main_loop_quit (helper->loop); +} + +/** + * fwupd_client_refresh_remote: + * @self: A #FwupdClient + * @remote: A #FwupdRemote + * @cancellable: A #GCancellable, or %NULL + * @error: A #GError, or %NULL + * + * Refreshes a remote by downloading new metadata. + * + * Returns: %TRUE for success + * + * Since: 1.4.5 + **/ +gboolean +fwupd_client_refresh_remote (FwupdClient *self, + FwupdRemote *remote, + GCancellable *cancellable, + GError **error) +{ + g_autoptr(FwupdClientHelper) helper = fwupd_client_helper_new (); + + g_return_val_if_fail (FWUPD_IS_CLIENT (self), FALSE); + g_return_val_if_fail (FWUPD_IS_REMOTE (remote), FALSE); + g_return_val_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable), FALSE); + g_return_val_if_fail (error == NULL || *error == NULL, FALSE); + + fwupd_client_refresh_remote_async (self, remote, cancellable, + fwupd_client_refresh_remote_cb, + helper); + g_main_loop_run (helper->loop); + if (!helper->ret) { + g_propagate_error (error, g_steal_pointer (&helper->error)); + return FALSE; + } + return TRUE; +} + +static void +fwupd_client_modify_remote_cb (GObject *source, GAsyncResult *res, gpointer user_data) +{ + FwupdClientHelper *helper = (FwupdClientHelper *) user_data; + helper->ret = fwupd_client_modify_remote_finish (FWUPD_CLIENT (source), res, &helper->error); + g_main_loop_quit (helper->loop); +} + +/** + * fwupd_client_modify_remote: + * @self: A #FwupdClient + * @remote_id: the remote ID, e.g. `lvfs-testing` + * @key: the key, e.g. `Enabled` + * @value: the key, e.g. `true` + * @cancellable: the #GCancellable, or %NULL + * @error: the #GError, or %NULL + * + * Modifies a system remote in a specific way. + * + * NOTE: User authentication may be required to complete this action. + * + * Returns: %TRUE for success + * + * Since: 0.9.8 + **/ +gboolean +fwupd_client_modify_remote (FwupdClient *self, + const gchar *remote_id, + const gchar *key, + const gchar *value, + GCancellable *cancellable, + GError **error) +{ + g_autoptr(FwupdClientHelper) helper = fwupd_client_helper_new (); + + g_return_val_if_fail (FWUPD_IS_CLIENT (self), FALSE); + g_return_val_if_fail (remote_id != NULL, FALSE); + g_return_val_if_fail (key != NULL, FALSE); + g_return_val_if_fail (value != NULL, FALSE); + g_return_val_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable), FALSE); + g_return_val_if_fail (error == NULL || *error == NULL, FALSE); + + /* connect */ + if (!fwupd_client_connect (self, cancellable, error)) + return FALSE; + + /* call async version and run loop until complete */ + fwupd_client_modify_remote_async (self, remote_id, key, value, + cancellable, + fwupd_client_modify_remote_cb, + helper); + g_main_loop_run (helper->loop); + if (!helper->ret) { + g_propagate_error (error, g_steal_pointer (&helper->error)); + return FALSE; + } + return TRUE; +} + +static void +fwupd_client_get_report_metadata_cb (GObject *source, GAsyncResult *res, gpointer user_data) +{ + FwupdClientHelper *helper = (FwupdClientHelper *) user_data; + helper->hash = fwupd_client_get_report_metadata_finish (FWUPD_CLIENT (source), res, &helper->error); + g_main_loop_quit (helper->loop); +} + +/** + * fwupd_client_get_report_metadata: + * @self: A #FwupdClient + * @cancellable: the #GCancellable, or %NULL + * @error: the #GError, or %NULL + * + * Gets all the report metadata from the daemon. + * + * Returns: (transfer container): attributes + * + * Since: 1.5.0 + **/ +GHashTable * +fwupd_client_get_report_metadata (FwupdClient *self, + GCancellable *cancellable, + GError **error) +{ + g_autoptr(FwupdClientHelper) helper = fwupd_client_helper_new (); + + g_return_val_if_fail (FWUPD_IS_CLIENT (self), NULL); + g_return_val_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable), NULL); + g_return_val_if_fail (error == NULL || *error == NULL, NULL); + + /* connect */ + if (!fwupd_client_connect (self, cancellable, error)) + return NULL; + + /* call async version and run loop until complete */ + fwupd_client_get_report_metadata_async (self, cancellable, + fwupd_client_get_report_metadata_cb, + helper); + g_main_loop_run (helper->loop); + if (helper->hash == NULL) { + g_propagate_error (error, g_steal_pointer (&helper->error)); + return NULL; + } + return g_steal_pointer (&helper->hash); +} + +static void +fwupd_client_modify_device_cb (GObject *source, GAsyncResult *res, gpointer user_data) +{ + FwupdClientHelper *helper = (FwupdClientHelper *) user_data; + helper->ret = fwupd_client_modify_device_finish (FWUPD_CLIENT (source), res, &helper->error); + g_main_loop_quit (helper->loop); +} + +/** + * fwupd_client_modify_device: + * @self: A #FwupdClient + * @device_id: the device ID + * @key: the key, e.g. `Flags` + * @value: the key, e.g. `reported` + * @cancellable: the #GCancellable, or %NULL + * @error: the #GError, or %NULL + * + * Modifies a device in a specific way. Not all properties on the #FwupdDevice + * are settable by the client, and some may have other restrictions on @value. + * + * NOTE: User authentication may be required to complete this action. + * + * Returns: %TRUE for success + * + * Since: 1.0.4 + **/ +gboolean +fwupd_client_modify_device (FwupdClient *self, + const gchar *device_id, + const gchar *key, + const gchar *value, + GCancellable *cancellable, + GError **error) +{ + g_autoptr(FwupdClientHelper) helper = fwupd_client_helper_new (); + + g_return_val_if_fail (FWUPD_IS_CLIENT (self), FALSE); + g_return_val_if_fail (device_id != NULL, FALSE); + g_return_val_if_fail (key != NULL, FALSE); + g_return_val_if_fail (value != NULL, FALSE); + g_return_val_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable), FALSE); + g_return_val_if_fail (error == NULL || *error == NULL, FALSE); + + /* connect */ + if (!fwupd_client_connect (self, cancellable, error)) + return FALSE; + + /* call async version and run loop until complete */ + fwupd_client_modify_device_async (self, device_id, key, value, + cancellable, + fwupd_client_modify_device_cb, + helper); + g_main_loop_run (helper->loop); + if (!helper->ret) { + g_propagate_error (error, g_steal_pointer (&helper->error)); + return FALSE; + } + return TRUE; +} + +static void +fwupd_client_get_remotes_cb (GObject *source, GAsyncResult *res, gpointer user_data) +{ + FwupdClientHelper *helper = (FwupdClientHelper *) user_data; + helper->array = fwupd_client_get_remotes_finish (FWUPD_CLIENT (source), res, &helper->error); + g_main_loop_quit (helper->loop); +} + +/** + * fwupd_client_get_remotes: + * @self: A #FwupdClient + * @cancellable: the #GCancellable, or %NULL + * @error: the #GError, or %NULL + * + * Gets the list of remotes that have been configured for the system. + * + * Returns: (element-type FwupdRemote) (transfer container): list of remotes, or %NULL + * + * Since: 0.9.3 + **/ +GPtrArray * +fwupd_client_get_remotes (FwupdClient *self, GCancellable *cancellable, GError **error) +{ + g_autoptr(FwupdClientHelper) helper = fwupd_client_helper_new (); + + g_return_val_if_fail (FWUPD_IS_CLIENT (self), NULL); + g_return_val_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable), NULL); + g_return_val_if_fail (error == NULL || *error == NULL, NULL); + + /* connect */ + if (!fwupd_client_connect (self, cancellable, error)) + return NULL; + + /* call async version and run loop until complete */ + fwupd_client_get_remotes_async (self, cancellable, + fwupd_client_get_remotes_cb, helper); + g_main_loop_run (helper->loop); + if (helper->array == NULL) { + g_propagate_error (error, g_steal_pointer (&helper->error)); + return NULL; + } + return g_steal_pointer (&helper->array); +} + +static FwupdRemote * +fwupd_client_get_remote_by_id_noref (GPtrArray *remotes, const gchar *remote_id) +{ + for (guint i = 0; i < remotes->len; i++) { + FwupdRemote *remote = g_ptr_array_index (remotes, i); + if (g_strcmp0 (remote_id, fwupd_remote_get_id (remote)) == 0) + return remote; + } + return NULL; +} + +/** + * fwupd_client_get_remote_by_id: + * @self: A #FwupdClient + * @remote_id: the remote ID, e.g. `lvfs-testing` + * @cancellable: the #GCancellable, or %NULL + * @error: the #GError, or %NULL + * + * Gets a specific remote that has been configured for the system. + * + * Returns: (transfer full): a #FwupdRemote, or %NULL if not found + * + * Since: 0.9.3 + **/ +FwupdRemote * +fwupd_client_get_remote_by_id (FwupdClient *self, + const gchar *remote_id, + GCancellable *cancellable, + GError **error) +{ + FwupdRemote *remote; + g_autoptr(GPtrArray) remotes = NULL; + + g_return_val_if_fail (FWUPD_IS_CLIENT (self), NULL); + g_return_val_if_fail (remote_id != NULL, NULL); + g_return_val_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable), NULL); + g_return_val_if_fail (error == NULL || *error == NULL, NULL); + + /* find remote in list */ + remotes = fwupd_client_get_remotes (self, cancellable, error); + if (remotes == NULL) + return NULL; + remote = fwupd_client_get_remote_by_id_noref (remotes, remote_id); + if (remote == NULL) { + g_set_error (error, + FWUPD_ERROR, + FWUPD_ERROR_NOT_FOUND, + "No remote '%s' found in search paths", + remote_id); + return NULL; + } + + /* success */ + return g_object_ref (remote); +} + +static void +fwupd_client_get_approved_firmware_cb (GObject *source, GAsyncResult *res, gpointer user_data) +{ + FwupdClientHelper *helper = (FwupdClientHelper *) user_data; + helper->array = fwupd_client_get_approved_firmware_finish (FWUPD_CLIENT (source), res, &helper->error); + g_main_loop_quit (helper->loop); +} + +/** + * fwupd_client_get_approved_firmware: + * @self: A #FwupdClient + * @cancellable: the #GCancellable, or %NULL + * @error: the #GError, or %NULL + * + * Gets the list of approved firmware. + * + * Returns: (transfer full): checksums, or %NULL for error + * + * Since: 1.2.6 + **/ +gchar ** +fwupd_client_get_approved_firmware (FwupdClient *self, + GCancellable *cancellable, + GError **error) +{ + g_autoptr(FwupdClientHelper) helper = fwupd_client_helper_new (); + gchar **argv; + + g_return_val_if_fail (FWUPD_IS_CLIENT (self), NULL); + g_return_val_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable), NULL); + g_return_val_if_fail (error == NULL || *error == NULL, NULL); + + /* connect */ + if (!fwupd_client_connect (self, cancellable, error)) + return NULL; + + /* call async version and run loop until complete */ + fwupd_client_get_approved_firmware_async (self, cancellable, + fwupd_client_get_approved_firmware_cb, + helper); + g_main_loop_run (helper->loop); + if (helper->array == NULL) { + g_propagate_error (error, g_steal_pointer (&helper->error)); + return NULL; + } + argv = g_new0 (gchar *, helper->array->len + 1); + for (guint i = 0; i < helper->array->len; i++) { + const gchar *tmp = g_ptr_array_index (helper->array, i); + argv[i] = g_strdup (tmp); + } + return argv; +} + +static void +fwupd_client_set_approved_firmware_cb (GObject *source, GAsyncResult *res, gpointer user_data) +{ + FwupdClientHelper *helper = (FwupdClientHelper *) user_data; + helper->ret = fwupd_client_set_approved_firmware_finish (FWUPD_CLIENT (source), res, &helper->error); + g_main_loop_quit (helper->loop); +} + +/** + * fwupd_client_set_approved_firmware: + * @self: A #FwupdClient + * @checksums: Array of checksums + * @cancellable: the #GCancellable, or %NULL + * @error: the #GError, or %NULL + * + * Sets the list of approved firmware. + * + * Returns: %TRUE for success + * + * Since: 1.2.6 + **/ +gboolean +fwupd_client_set_approved_firmware (FwupdClient *self, + gchar **checksums, + GCancellable *cancellable, + GError **error) +{ + g_autoptr(FwupdClientHelper) helper = fwupd_client_helper_new (); + g_autoptr(GPtrArray) array = g_ptr_array_new_with_free_func (g_free); + + /* connect */ + if (!fwupd_client_connect (self, cancellable, error)) + return FALSE; + + /* convert */ + for (guint i = 0; checksums[i] != NULL; i++) + g_ptr_array_add (array, g_strdup (checksums[i])); + + /* call async version and run loop until complete */ + fwupd_client_set_approved_firmware_async (self, array, cancellable, + fwupd_client_set_approved_firmware_cb, + helper); + g_main_loop_run (helper->loop); + if (!helper->ret) { + g_propagate_error (error, g_steal_pointer (&helper->error)); + return FALSE; + } + return TRUE; +} + +static void +fwupd_client_get_blocked_firmware_cb (GObject *source, GAsyncResult *res, gpointer user_data) +{ + FwupdClientHelper *helper = (FwupdClientHelper *) user_data; + helper->array = fwupd_client_get_blocked_firmware_finish (FWUPD_CLIENT (source), res, &helper->error); + g_main_loop_quit (helper->loop); +} + +/** + * fwupd_client_get_blocked_firmware: + * @self: A #FwupdClient + * @cancellable: the #GCancellable, or %NULL + * @error: the #GError, or %NULL + * + * Gets the list of blocked firmware. + * + * Returns: (transfer full): checksums, or %NULL for error + * + * Since: 1.4.6 + **/ +gchar ** +fwupd_client_get_blocked_firmware (FwupdClient *self, + GCancellable *cancellable, + GError **error) +{ + g_autoptr(FwupdClientHelper) helper = fwupd_client_helper_new (); + gchar **argv; + + g_return_val_if_fail (FWUPD_IS_CLIENT (self), NULL); + g_return_val_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable), NULL); + g_return_val_if_fail (error == NULL || *error == NULL, NULL); + + /* connect */ + if (!fwupd_client_connect (self, cancellable, error)) + return NULL; + + /* call async version and run loop until complete */ + fwupd_client_get_blocked_firmware_async (self, cancellable, + fwupd_client_get_blocked_firmware_cb, + helper); + g_main_loop_run (helper->loop); + if (helper->array == NULL) { + g_propagate_error (error, g_steal_pointer (&helper->error)); + return NULL; + } + argv = g_new0 (gchar *, helper->array->len + 1); + for (guint i = 0; i < helper->array->len; i++) { + const gchar *tmp = g_ptr_array_index (helper->array, i); + argv[i] = g_strdup (tmp); + } + return argv; +} + +static void +fwupd_client_set_blocked_firmware_cb (GObject *source, GAsyncResult *res, gpointer user_data) +{ + FwupdClientHelper *helper = (FwupdClientHelper *) user_data; + helper->ret = fwupd_client_set_blocked_firmware_finish (FWUPD_CLIENT (source), res, &helper->error); + g_main_loop_quit (helper->loop); +} + +/** + * fwupd_client_set_blocked_firmware: + * @self: A #FwupdClient + * @checksums: Array of checksums + * @cancellable: the #GCancellable, or %NULL + * @error: the #GError, or %NULL + * + * Sets the list of approved firmware. + * + * Returns: %TRUE for success + * + * Since: 1.4.6 + **/ +gboolean +fwupd_client_set_blocked_firmware (FwupdClient *self, + gchar **checksums, + GCancellable *cancellable, + GError **error) +{ + g_autoptr(FwupdClientHelper) helper = fwupd_client_helper_new (); + g_autoptr(GPtrArray) array = g_ptr_array_new_with_free_func (g_free); + + g_return_val_if_fail (FWUPD_IS_CLIENT (self), FALSE); + g_return_val_if_fail (checksums != NULL, FALSE); + g_return_val_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable), FALSE); + g_return_val_if_fail (error == NULL || *error == NULL, FALSE); + + /* connect */ + if (!fwupd_client_connect (self, cancellable, error)) + return FALSE; + + for (guint i = 0; checksums[i] != NULL; i++) + g_ptr_array_add (array, g_strdup (checksums[i])); + + /* call async version and run loop until complete */ + fwupd_client_set_blocked_firmware_async (self, array, cancellable, + fwupd_client_set_blocked_firmware_cb, + helper); + g_main_loop_run (helper->loop); + if (!helper->ret) { + g_propagate_error (error, g_steal_pointer (&helper->error)); + return FALSE; + } + return TRUE; +} + +static void +fwupd_client_set_feature_flags_cb (GObject *source, GAsyncResult *res, gpointer user_data) +{ + FwupdClientHelper *helper = (FwupdClientHelper *) user_data; + helper->ret = fwupd_client_set_feature_flags_finish (FWUPD_CLIENT (source), res, &helper->error); + g_main_loop_quit (helper->loop); +} + +/** + * fwupd_client_set_feature_flags: + * @self: A #FwupdClient + * @feature_flags: #FwupdFeatureFlags, e.g. %FWUPD_FEATURE_FLAG_UPDATE_TEXT + * @cancellable: the #GCancellable, or %NULL + * @error: the #GError, or %NULL + * + * Sets the features the client supports. This allows firmware to depend on + * specific front-end features, for instance showing the user an image on + * how to detach the hardware. + * + * Clients can call this none or multiple times. + * + * Returns: %TRUE for success + * + * Since: 1.4.5 + **/ +gboolean +fwupd_client_set_feature_flags (FwupdClient *self, + FwupdFeatureFlags feature_flags, + GCancellable *cancellable, + GError **error) +{ + g_autoptr(FwupdClientHelper) helper = fwupd_client_helper_new (); + + g_return_val_if_fail (FWUPD_IS_CLIENT (self), FALSE); + g_return_val_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable), FALSE); + g_return_val_if_fail (error == NULL || *error == NULL, FALSE); + + /* connect */ + if (!fwupd_client_connect (self, cancellable, error)) + return FALSE; + + /* call async version and run loop until complete */ + fwupd_client_set_feature_flags_async (self, feature_flags, cancellable, + fwupd_client_set_feature_flags_cb, + helper); + g_main_loop_run (helper->loop); + if (!helper->ret) { + g_propagate_error (error, g_steal_pointer (&helper->error)); + return FALSE; + } + return TRUE; +} + +static void +fwupd_client_self_sign_cb (GObject *source, GAsyncResult *res, gpointer user_data) +{ + FwupdClientHelper *helper = (FwupdClientHelper *) user_data; + helper->str = fwupd_client_self_sign_finish (FWUPD_CLIENT (source), res, &helper->error); + g_main_loop_quit (helper->loop); +} + +/** + * fwupd_client_self_sign: + * @self: A #FwupdClient + * @value: A string to sign, typically a JSON blob + * @flags: #FwupdSelfSignFlags, e.g. %FWUPD_SELF_SIGN_FLAG_ADD_TIMESTAMP + * @cancellable: the #GCancellable, or %NULL + * @error: the #GError, or %NULL + * + * Signs the data using the client self-signed certificate. + * + * Returns: a signature, or %NULL for failure + * + * Since: 1.2.6 + **/ +gchar * +fwupd_client_self_sign (FwupdClient *self, + const gchar *value, + FwupdSelfSignFlags flags, + GCancellable *cancellable, + GError **error) +{ + g_autoptr(FwupdClientHelper) helper = fwupd_client_helper_new (); + + g_return_val_if_fail (FWUPD_IS_CLIENT (self), NULL); + g_return_val_if_fail (value != NULL, NULL); + g_return_val_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable), NULL); + g_return_val_if_fail (error == NULL || *error == NULL, NULL); + + /* connect */ + if (!fwupd_client_connect (self, cancellable, error)) + return NULL; + + /* call async version and run loop until complete */ + fwupd_client_self_sign_async (self, value, flags, cancellable, + fwupd_client_self_sign_cb, + helper); + g_main_loop_run (helper->loop); + if (helper->str == NULL) { + g_propagate_error (error, g_steal_pointer (&helper->error)); + return NULL; + } + return g_steal_pointer (&helper->str); +} + +static void +fwupd_client_download_bytes_cb (GObject *source, GAsyncResult *res, gpointer user_data) +{ + FwupdClientHelper *helper = (FwupdClientHelper *) user_data; + helper->bytes = fwupd_client_download_bytes_finish (FWUPD_CLIENT (source), res, &helper->error); + g_main_loop_quit (helper->loop); +} + +/** + * fwupd_client_download_bytes: + * @self: A #FwupdClient + * @url: the remote URL + * @flags: #FwupdClientDownloadFlags, e.g. %FWUPD_CLIENT_DOWNLOAD_FLAG_NONE + * @cancellable: the #GCancellable, or %NULL + * @error: the #GError, or %NULL + * + * Downloads data from a remote server. The fwupd_client_set_user_agent() function + * should be called before this method is used. + * + * Returns: (transfer full): downloaded data, or %NULL for error + * + * Since: 1.4.5 + **/ +GBytes * +fwupd_client_download_bytes (FwupdClient *self, + const gchar *url, + FwupdClientDownloadFlags flags, + GCancellable *cancellable, + GError **error) +{ + g_autoptr(FwupdClientHelper) helper = fwupd_client_helper_new (); + + g_return_val_if_fail (FWUPD_IS_CLIENT (self), NULL); + g_return_val_if_fail (url != NULL, NULL); + g_return_val_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable), NULL); + g_return_val_if_fail (error == NULL || *error == NULL, NULL); + + /* connect */ + if (!fwupd_client_connect (self, cancellable, error)) + return NULL; + + /* call async version and run loop until complete */ + fwupd_client_download_bytes_async (self, url, flags, cancellable, + fwupd_client_download_bytes_cb, helper); + g_main_loop_run (helper->loop); + if (helper->bytes == NULL) { + g_propagate_error (error, g_steal_pointer (&helper->error)); + return NULL; + } + return g_steal_pointer (&helper->bytes); +} + +static void +fwupd_client_upload_bytes_cb (GObject *source, GAsyncResult *res, gpointer user_data) +{ + FwupdClientHelper *helper = (FwupdClientHelper *) user_data; + helper->bytes = fwupd_client_upload_bytes_finish (FWUPD_CLIENT (source), res, &helper->error); + g_main_loop_quit (helper->loop); +} + +/** + * fwupd_client_upload_bytes: + * @self: A #FwupdClient + * @url: the remote URL + * @payload: payload string + * @signature: (nullable): signature string + * @flags: #FwupdClientDownloadFlags, e.g. %FWUPD_CLIENT_DOWNLOAD_FLAG_NONE + * @cancellable: the #GCancellable, or %NULL + * @error: the #GError, or %NULL + * + * Uploads data to a remote server. The fwupd_client_set_user_agent() function + * should be called before this method is used. + * + * Returns: (transfer full): response data, or %NULL for error + * + * Since: 1.4.5 + **/ +GBytes * +fwupd_client_upload_bytes (FwupdClient *self, + const gchar *url, + const gchar *payload, + const gchar *signature, + FwupdClientUploadFlags flags, + GCancellable *cancellable, + GError **error) +{ + g_autoptr(FwupdClientHelper) helper = fwupd_client_helper_new (); + + g_return_val_if_fail (FWUPD_IS_CLIENT (self), NULL); + g_return_val_if_fail (url != NULL, NULL); + g_return_val_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable), NULL); + g_return_val_if_fail (error == NULL || *error == NULL, NULL); + + /* connect */ + if (!fwupd_client_connect (self, cancellable, error)) + return NULL; + + /* call async version and run loop until complete */ + fwupd_client_upload_bytes_async (self, url, payload, signature, flags, cancellable, + fwupd_client_upload_bytes_cb, helper); + g_main_loop_run (helper->loop); + if (helper->bytes == NULL) { + g_propagate_error (error, g_steal_pointer (&helper->error)); + return NULL; + } + return g_steal_pointer (&helper->bytes); +} diff --git a/libfwupd/fwupd-client-sync.h b/libfwupd/fwupd-client-sync.h new file mode 100644 index 000000000..947ddab05 --- /dev/null +++ b/libfwupd/fwupd-client-sync.h @@ -0,0 +1,170 @@ +/* + * Copyright (C) 2016-2020 Richard Hughes + * + * SPDX-License-Identifier: LGPL-2.1+ + */ + +#pragma once + +#include "fwupd-client.h" + +gboolean fwupd_client_connect (FwupdClient *self, + GCancellable *cancellable, + GError **error); +GPtrArray *fwupd_client_get_devices (FwupdClient *self, + GCancellable *cancellable, + GError **error); +GPtrArray *fwupd_client_get_history (FwupdClient *self, + GCancellable *cancellable, + GError **error); +GPtrArray *fwupd_client_get_releases (FwupdClient *self, + const gchar *device_id, + GCancellable *cancellable, + GError **error); +GPtrArray *fwupd_client_get_downgrades (FwupdClient *self, + const gchar *device_id, + GCancellable *cancellable, + GError **error); +GPtrArray *fwupd_client_get_upgrades (FwupdClient *self, + const gchar *device_id, + GCancellable *cancellable, + GError **error); +GPtrArray *fwupd_client_get_details (FwupdClient *self, + const gchar *filename, + GCancellable *cancellable, + GError **error); +GPtrArray *fwupd_client_get_details_bytes (FwupdClient *self, + GBytes *bytes, + GCancellable *cancellable, + GError **error); +gboolean fwupd_client_verify (FwupdClient *self, + const gchar *device_id, + GCancellable *cancellable, + GError **error); +gboolean fwupd_client_verify_update (FwupdClient *self, + const gchar *device_id, + GCancellable *cancellable, + GError **error); +gboolean fwupd_client_unlock (FwupdClient *self, + const gchar *device_id, + GCancellable *cancellable, + GError **error); +gboolean fwupd_client_modify_config (FwupdClient *self, + const gchar *key, + const gchar *value, + GCancellable *cancellable, + GError **error); +gboolean fwupd_client_activate (FwupdClient *self, + GCancellable *cancellable, + const gchar *device_id, + GError **error); +gboolean fwupd_client_clear_results (FwupdClient *self, + const gchar *device_id, + GCancellable *cancellable, + GError **error); +FwupdDevice *fwupd_client_get_results (FwupdClient *self, + const gchar *device_id, + GCancellable *cancellable, + GError **error); +GPtrArray *fwupd_client_get_host_security_attrs (FwupdClient *self, + GCancellable *cancellable, + GError **error); +FwupdDevice *fwupd_client_get_device_by_id (FwupdClient *self, + const gchar *device_id, + GCancellable *cancellable, + GError **error); +GPtrArray *fwupd_client_get_devices_by_guid (FwupdClient *self, + const gchar *guid, + GCancellable *cancellable, + GError **error); +gboolean fwupd_client_install (FwupdClient *self, + const gchar *device_id, + const gchar *filename, + FwupdInstallFlags install_flags, + GCancellable *cancellable, + GError **error); +gboolean fwupd_client_install_bytes (FwupdClient *self, + const gchar *device_id, + GBytes *bytes, + FwupdInstallFlags install_flags, + GCancellable *cancellable, + GError **error); +gboolean fwupd_client_install_release (FwupdClient *self, + FwupdDevice *device, + FwupdRelease *release, + FwupdInstallFlags install_flags, + GCancellable *cancellable, + GError **error); +gboolean fwupd_client_update_metadata (FwupdClient *self, + const gchar *remote_id, + const gchar *metadata_fn, + const gchar *signature_fn, + GCancellable *cancellable, + GError **error); +gboolean fwupd_client_update_metadata_bytes (FwupdClient *self, + const gchar *remote_id, + GBytes *metadata, + GBytes *signature, + GCancellable *cancellable, + GError **error); +gboolean fwupd_client_refresh_remote (FwupdClient *self, + FwupdRemote *remote, + GCancellable *cancellable, + GError **error); +gboolean fwupd_client_modify_remote (FwupdClient *self, + const gchar *remote_id, + const gchar *key, + const gchar *value, + GCancellable *cancellable, + GError **error); +gboolean fwupd_client_modify_device (FwupdClient *self, + const gchar *device_id, + const gchar *key, + const gchar *value, + GCancellable *cancellable, + GError **error); +GHashTable *fwupd_client_get_report_metadata (FwupdClient *self, + GCancellable *cancellable, + GError **error); +GPtrArray *fwupd_client_get_remotes (FwupdClient *self, + GCancellable *cancellable, + GError **error); +FwupdRemote *fwupd_client_get_remote_by_id (FwupdClient *self, + const gchar *remote_id, + GCancellable *cancellable, + GError **error); +gchar **fwupd_client_get_approved_firmware (FwupdClient *self, + GCancellable *cancellable, + GError **error); +gboolean fwupd_client_set_approved_firmware (FwupdClient *self, + gchar **checksums, + GCancellable *cancellable, + GError **error); +gchar **fwupd_client_get_blocked_firmware (FwupdClient *self, + GCancellable *cancellable, + GError **error); +gboolean fwupd_client_set_blocked_firmware (FwupdClient *self, + gchar **checksums, + GCancellable *cancellable, + GError **error); +gchar *fwupd_client_self_sign (FwupdClient *self, + const gchar *value, + FwupdSelfSignFlags flags, + GCancellable *cancellable, + GError **error); +gboolean fwupd_client_set_feature_flags (FwupdClient *self, + FwupdFeatureFlags feature_flags, + GCancellable *cancellable, + GError **error); +GBytes *fwupd_client_download_bytes (FwupdClient *self, + const gchar *url, + FwupdClientDownloadFlags flags, + GCancellable *cancellable, + GError **error); +GBytes *fwupd_client_upload_bytes (FwupdClient *self, + const gchar *url, + const gchar *payload, + const gchar *signature, + FwupdClientUploadFlags flags, + GCancellable *cancellable, + GError **error); diff --git a/libfwupd/fwupd-client.c b/libfwupd/fwupd-client.c index 35904db1c..00a4417bc 100644 --- a/libfwupd/fwupd-client.c +++ b/libfwupd/fwupd-client.c @@ -18,7 +18,8 @@ #include #include -#include "fwupd-client.h" +#include "fwupd-client-private.h" +#include "fwupd-client-sync.h" #include "fwupd-common-private.h" #include "fwupd-deprecated.h" #include "fwupd-enums.h" @@ -82,41 +83,6 @@ static guint signals [SIGNAL_LAST] = { 0 }; G_DEFINE_TYPE_WITH_PRIVATE (FwupdClient, fwupd_client, G_TYPE_OBJECT) #define GET_PRIVATE(o) (fwupd_client_get_instance_private (o)) -typedef struct { - gboolean ret; - GError *error; - GMainLoop *loop; - GVariant *val; - GDBusMessage *message; -} FwupdClientHelper; - -static void -fwupd_client_helper_free (FwupdClientHelper *helper) -{ - if (helper->message != NULL) - g_object_unref (helper->message); - if (helper->val != NULL) - g_variant_unref (helper->val); - if (helper->error != NULL) - g_error_free (helper->error); - g_main_loop_unref (helper->loop); - g_free (helper); -} - -static FwupdClientHelper * -fwupd_client_helper_new (void) -{ - FwupdClientHelper *helper; - helper = g_new0 (FwupdClientHelper, 1); - helper->loop = g_main_loop_new (NULL, FALSE); - return helper; -} - -#pragma clang diagnostic push -#pragma clang diagnostic ignored "-Wunused-function" -G_DEFINE_AUTOPTR_CLEANUP_FUNC(FwupdClientHelper, fwupd_client_helper_free) -#pragma clang diagnostic pop - static void fwupd_client_set_host_product (FwupdClient *self, const gchar *host_product) { @@ -360,51 +326,23 @@ fwupd_client_ensure_networking (FwupdClient *self, GError **error) return TRUE; } -/** - * fwupd_client_connect: - * @self: A #FwupdClient - * @cancellable: the #GCancellable, or %NULL - * @error: the #GError, or %NULL - * - * Sets up the client ready for use. Most other methods call this - * for you, and do you only need to call this if you are just watching - * the client. - * - * Returns: %TRUE for success - * - * Since: 0.7.1 - **/ -gboolean -fwupd_client_connect (FwupdClient *self, GCancellable *cancellable, GError **error) +static void +fwupd_client_connect_get_proxy_cb (GObject *source, + GAsyncResult *res, + gpointer user_data) { + g_autoptr(GTask) task = G_TASK (user_data); + FwupdClient *self = g_task_get_source_object (task); FwupdClientPrivate *priv = GET_PRIVATE (self); + g_autoptr(GError) error = NULL; g_autoptr(GVariant) val = NULL; g_autoptr(GVariant) val2 = NULL; - g_return_val_if_fail (FWUPD_IS_CLIENT (self), FALSE); - g_return_val_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable), FALSE); - g_return_val_if_fail (error == NULL || *error == NULL, FALSE); - - /* nothing to do */ - if (priv->proxy != NULL) - return TRUE; - - /* connect to the daemon */ - priv->conn = g_bus_get_sync (G_BUS_TYPE_SYSTEM, NULL, error); - if (priv->conn == NULL) { - g_prefix_error (error, "Failed to connect to system D-Bus: "); - return FALSE; + priv->proxy = g_dbus_proxy_new_finish (res, &error); + if (priv->proxy == NULL) { + g_task_return_error (task, g_steal_pointer (&error)); + return; } - priv->proxy = g_dbus_proxy_new_sync (priv->conn, - G_DBUS_PROXY_FLAGS_NONE, - NULL, - FWUPD_DBUS_SERVICE, - FWUPD_DBUS_PATH, - FWUPD_DBUS_INTERFACE, - NULL, - error); - if (priv->proxy == NULL) - return FALSE; g_signal_connect (priv->proxy, "g-properties-changed", G_CALLBACK (fwupd_client_properties_changed_cb), self); g_signal_connect (priv->proxy, "g-signal", @@ -428,7 +366,93 @@ fwupd_client_connect (FwupdClient *self, GCancellable *cancellable, GError **err if (val != NULL) fwupd_client_set_host_security_id (self, g_variant_get_string (val, NULL)); - return TRUE; + /* success */ + g_task_return_boolean (task, TRUE); +} + +static void +fwupd_client_connect_get_bus_cb (GObject *source, + GAsyncResult *res, + gpointer user_data) +{ + g_autoptr(GTask) task = G_TASK (user_data); + FwupdClient *self = g_task_get_source_object (task); + FwupdClientPrivate *priv = GET_PRIVATE (self); + g_autoptr(GError) error = NULL; + + priv->conn = g_bus_get_finish (res, &error); + if (priv->conn == NULL) { + g_prefix_error (&error, "Failed to connect to system D-Bus: "); + g_task_return_error (task, g_steal_pointer (&error)); + return; + } + g_dbus_proxy_new (priv->conn, + G_DBUS_PROXY_FLAGS_NONE, + NULL, + FWUPD_DBUS_SERVICE, + FWUPD_DBUS_PATH, + FWUPD_DBUS_INTERFACE, + g_task_get_cancellable (task), + fwupd_client_connect_get_proxy_cb, + g_object_ref (task)); +} + +/** + * fwupd_client_connect_async: + * @self: A #FwupdClient + * @cancellable: the #GCancellable, or %NULL + * @callback: the function to run on completion + * @callback_data: the data to pass to @callback + * + * Sets up the client ready for use. This is probably the first method you call + * when wanting to use libfwupd in an asynchronous manner. + * + * Other methods such as fwupd_client_get_devices_async() should only be called + * after fwupd_client_connect_finish() has been called without an error. + * + * Since: 1.5.0 + **/ +void +fwupd_client_connect_async (FwupdClient *self, GCancellable *cancellable, + GAsyncReadyCallback callback, gpointer callback_data) +{ + FwupdClientPrivate *priv = GET_PRIVATE (self); + g_autoptr(GTask) task = g_task_new (self, cancellable, callback, callback_data); + + g_return_if_fail (FWUPD_IS_CLIENT (self)); + g_return_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable)); + + /* nothing to do */ + if (priv->proxy != NULL) { + g_task_return_boolean (task, TRUE); + return; + } + + g_bus_get (G_BUS_TYPE_SYSTEM, cancellable, + fwupd_client_connect_get_bus_cb, + g_steal_pointer (&task)); + +} + +/** + * fwupd_client_connect_finish: + * @self: A #FwupdClient + * @res: the #GAsyncResult + * @error: the #GError, or %NULL + * + * Gets the result of fwupd_client_connect_async(). + * + * Returns: %TRUE for success + * + * Since: 1.5.0 + **/ +gboolean +fwupd_client_connect_finish (FwupdClient *self, GAsyncResult *res, GError **error) +{ + g_return_val_if_fail (FWUPD_IS_CLIENT (self), FALSE); + g_return_val_if_fail (g_task_is_valid (res, self), FALSE); + g_return_val_if_fail (error == NULL || *error == NULL, FALSE); + return g_task_propagate_boolean (G_TASK(res), error); } static void @@ -464,46 +488,84 @@ fwupd_client_fixup_dbus_error (GError *error) g_dbus_error_strip_remote_error (error); } +static void +fwupd_client_get_host_security_attrs_cb (GObject *source, + GAsyncResult *res, + gpointer user_data) +{ + g_autoptr(GTask) task = G_TASK (user_data); + g_autoptr(GError) error = NULL; + g_autoptr(GVariant) val = NULL; + + val = g_dbus_proxy_call_finish (G_DBUS_PROXY (source), res, &error); + if (val == NULL) { + fwupd_client_fixup_dbus_error (error); + g_task_return_error (task, g_steal_pointer (&error)); + return; + } + + /* success */ + g_task_return_pointer (task, + fwupd_security_attr_array_from_variant (val), + (GDestroyNotify) g_ptr_array_unref); +} + /** - * fwupd_client_get_host_security_attrs: + * fwupd_client_get_host_security_attrs_async: * @self: A #FwupdClient * @cancellable: the #GCancellable, or %NULL - * @error: the #GError, or %NULL + * @callback: the function to run on completion + * @callback_data: the data to pass to @callback * * Gets all the host security attributes from the daemon. * + * You must have called fwupd_client_connect_async() on @self before using + * this method. + * + * Since: 1.5.0 + **/ +void +fwupd_client_get_host_security_attrs_async (FwupdClient *self, + GCancellable *cancellable, + GAsyncReadyCallback callback, + gpointer callback_data) +{ + FwupdClientPrivate *priv = GET_PRIVATE (self); + g_autoptr(GTask) task = NULL; + + g_return_if_fail (FWUPD_IS_CLIENT (self)); + g_return_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable)); + g_return_if_fail (priv->proxy != NULL); + + /* call into daemon */ + task = g_task_new (self, cancellable, callback, callback_data); + g_dbus_proxy_call (priv->proxy, "GetHostSecurityAttrs", + NULL, + G_DBUS_CALL_FLAGS_NONE, + -1, cancellable, + fwupd_client_get_host_security_attrs_cb, + g_steal_pointer (&task)); +} + +/** + * fwupd_client_get_host_security_attrs_finish: + * @self: A #FwupdClient + * @res: the #GAsyncResult + * @error: the #GError, or %NULL + * + * Gets the result of fwupd_client_get_host_security_attrs_async(). + * * Returns: (element-type FwupdSecurityAttr) (transfer container): attributes * * Since: 1.5.0 **/ GPtrArray * -fwupd_client_get_host_security_attrs (FwupdClient *self, GCancellable *cancellable, GError **error) +fwupd_client_get_host_security_attrs_finish (FwupdClient *self, GAsyncResult *res, GError **error) { - FwupdClientPrivate *priv = GET_PRIVATE (self); - g_autoptr(GVariant) val = NULL; - g_return_val_if_fail (FWUPD_IS_CLIENT (self), NULL); - g_return_val_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable), NULL); + g_return_val_if_fail (g_task_is_valid (res, self), NULL); g_return_val_if_fail (error == NULL || *error == NULL, NULL); - - /* connect */ - if (!fwupd_client_connect (self, cancellable, error)) - return NULL; - - /* call into daemon */ - val = g_dbus_proxy_call_sync (priv->proxy, - "GetHostSecurityAttrs", - NULL, - G_DBUS_CALL_FLAGS_NONE, - -1, - cancellable, - error); - if (val == NULL) { - if (error != NULL) - fwupd_client_fixup_dbus_error (*error); - return NULL; - } - return fwupd_security_attr_array_from_variant (val); + return g_task_propagate_pointer (G_TASK(res), error); } static GHashTable * @@ -527,210 +589,350 @@ fwupd_report_metadata_hash_from_variant (GVariant *value) return hash; } +static void +fwupd_client_get_report_metadata_cb (GObject *source, + GAsyncResult *res, + gpointer user_data) +{ + g_autoptr(GTask) task = G_TASK (user_data); + g_autoptr(GError) error = NULL; + g_autoptr(GVariant) val = NULL; + + val = g_dbus_proxy_call_finish (G_DBUS_PROXY (source), res, &error); + if (val == NULL) { + fwupd_client_fixup_dbus_error (error); + g_task_return_error (task, g_steal_pointer (&error)); + return; + } + + /* success */ + g_task_return_pointer (task, + fwupd_report_metadata_hash_from_variant (val), + (GDestroyNotify) g_hash_table_unref); +} + /** - * fwupd_client_get_report_metadata: + * fwupd_client_get_report_metadata_async: * @self: A #FwupdClient * @cancellable: the #GCancellable, or %NULL - * @error: the #GError, or %NULL + * @callback: the function to run on completion + * @callback_data: the data to pass to @callback * * Gets all the report metadata from the daemon. * + * You must have called fwupd_client_connect_async() on @self before using + * this method. + * + * Since: 1.5.0 + **/ +void +fwupd_client_get_report_metadata_async (FwupdClient *self, + GCancellable *cancellable, + GAsyncReadyCallback callback, + gpointer callback_data) +{ + FwupdClientPrivate *priv = GET_PRIVATE (self); + g_autoptr(GTask) task = NULL; + + g_return_if_fail (FWUPD_IS_CLIENT (self)); + g_return_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable)); + g_return_if_fail (priv->proxy != NULL); + + /* call into daemon */ + task = g_task_new (self, cancellable, callback, callback_data); + g_dbus_proxy_call (priv->proxy, "GetReportMetadata", + NULL, + G_DBUS_CALL_FLAGS_NONE, + -1, cancellable, + fwupd_client_get_report_metadata_cb, + g_steal_pointer (&task)); +} + +/** + * fwupd_client_get_report_metadata_finish: + * @self: A #FwupdClient + * @res: the #GAsyncResult + * @error: the #GError, or %NULL + * + * Gets the result of fwupd_client_get_report_metadata_async(). + * * Returns: (transfer container): attributes * * Since: 1.5.0 **/ GHashTable * -fwupd_client_get_report_metadata (FwupdClient *self, - GCancellable *cancellable, - GError **error) +fwupd_client_get_report_metadata_finish (FwupdClient *self, GAsyncResult *res, GError **error) { - FwupdClientPrivate *priv = GET_PRIVATE (self); + g_return_val_if_fail (FWUPD_IS_CLIENT (self), NULL); + g_return_val_if_fail (g_task_is_valid (res, self), NULL); + g_return_val_if_fail (error == NULL || *error == NULL, NULL); + return g_task_propagate_pointer (G_TASK(res), error); +} + +static void +fwupd_client_get_devices_cb (GObject *source, + GAsyncResult *res, + gpointer user_data) +{ + g_autoptr(GTask) task = G_TASK (user_data); + g_autoptr(GError) error = NULL; g_autoptr(GVariant) val = NULL; - g_return_val_if_fail (FWUPD_IS_CLIENT (self), NULL); - g_return_val_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable), NULL); - g_return_val_if_fail (error == NULL || *error == NULL, NULL); - - /* connect */ - if (!fwupd_client_connect (self, cancellable, error)) - return NULL; - - /* call into daemon */ - val = g_dbus_proxy_call_sync (priv->proxy, - "GetReportMetadata", - NULL, - G_DBUS_CALL_FLAGS_NONE, - -1, - cancellable, - error); + val = g_dbus_proxy_call_finish (G_DBUS_PROXY (source), res, &error); if (val == NULL) { - if (error != NULL) - fwupd_client_fixup_dbus_error (*error); - return NULL; + fwupd_client_fixup_dbus_error (error); + g_task_return_error (task, g_steal_pointer (&error)); + return; } - return fwupd_report_metadata_hash_from_variant (val); + + /* success */ + g_task_return_pointer (task, + fwupd_device_array_from_variant (val), + (GDestroyNotify) g_ptr_array_unref); } /** - * fwupd_client_get_devices: + * fwupd_client_get_devices_async: * @self: A #FwupdClient * @cancellable: the #GCancellable, or %NULL - * @error: the #GError, or %NULL + * @callback: the function to run on completion + * @callback_data: the data to pass to @callback * * Gets all the devices registered with the daemon. * - * Returns: (element-type FwupdDevice) (transfer container): results + * You must have called fwupd_client_connect_async() on @self before using + * this method. * - * Since: 0.9.2 + * Since: 1.5.0 **/ -GPtrArray * -fwupd_client_get_devices (FwupdClient *self, GCancellable *cancellable, GError **error) +void +fwupd_client_get_devices_async (FwupdClient *self, GCancellable *cancellable, + GAsyncReadyCallback callback, gpointer callback_data) { FwupdClientPrivate *priv = GET_PRIVATE (self); - g_autoptr(GVariant) val = NULL; + g_autoptr(GTask) task = NULL; - g_return_val_if_fail (FWUPD_IS_CLIENT (self), NULL); - g_return_val_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable), NULL); - g_return_val_if_fail (error == NULL || *error == NULL, NULL); - - /* connect */ - if (!fwupd_client_connect (self, cancellable, error)) - return NULL; + g_return_if_fail (FWUPD_IS_CLIENT (self)); + g_return_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable)); + g_return_if_fail (priv->proxy != NULL); /* call into daemon */ - val = g_dbus_proxy_call_sync (priv->proxy, - "GetDevices", - NULL, - G_DBUS_CALL_FLAGS_NONE, - -1, - cancellable, - error); - if (val == NULL) { - if (error != NULL) - fwupd_client_fixup_dbus_error (*error); - return NULL; - } - return fwupd_device_array_from_variant (val); + task = g_task_new (self, cancellable, callback, callback_data); + g_dbus_proxy_call (priv->proxy, "GetDevices", + NULL, G_DBUS_CALL_FLAGS_NONE, + -1, cancellable, + fwupd_client_get_devices_cb, + g_steal_pointer (&task)); } /** - * fwupd_client_get_history: + * fwupd_client_get_devices_finish: + * @self: A #FwupdClient + * @res: the #GAsyncResult + * @error: the #GError, or %NULL + * + * Gets the result of fwupd_client_get_devices_async(). + * + * Returns: (element-type FwupdDevice) (transfer container): results + * + * Since: 1.5.0 + **/ +GPtrArray * +fwupd_client_get_devices_finish (FwupdClient *self, GAsyncResult *res, GError **error) +{ + g_return_val_if_fail (FWUPD_IS_CLIENT (self), NULL); + g_return_val_if_fail (g_task_is_valid (res, self), NULL); + g_return_val_if_fail (error == NULL || *error == NULL, NULL); + return g_task_propagate_pointer (G_TASK(res), error); +} + +static void +fwupd_client_get_history_cb (GObject *source, + GAsyncResult *res, + gpointer user_data) +{ + g_autoptr(GTask) task = G_TASK (user_data); + g_autoptr(GError) error = NULL; + g_autoptr(GVariant) val = NULL; + + val = g_dbus_proxy_call_finish (G_DBUS_PROXY (source), res, &error); + if (val == NULL) { + fwupd_client_fixup_dbus_error (error); + g_task_return_error (task, g_steal_pointer (&error)); + return; + } + + /* success */ + g_task_return_pointer (task, + fwupd_device_array_from_variant (val), + (GDestroyNotify) g_ptr_array_unref); +} + +/** + * fwupd_client_get_history_async: * @self: A #FwupdClient * @cancellable: the #GCancellable, or %NULL - * @error: the #GError, or %NULL + * @callback: the function to run on completion + * @callback_data: the data to pass to @callback * * Gets all the history. * - * Returns: (element-type FwupdDevice) (transfer container): results + * You must have called fwupd_client_connect_async() on @self before using + * this method. * - * Since: 1.0.4 + * Since: 1.5.0 **/ -GPtrArray * -fwupd_client_get_history (FwupdClient *self, GCancellable *cancellable, GError **error) +void +fwupd_client_get_history_async (FwupdClient *self, GCancellable *cancellable, + GAsyncReadyCallback callback, gpointer callback_data) { FwupdClientPrivate *priv = GET_PRIVATE (self); - g_autoptr(GVariant) val = NULL; + g_autoptr(GTask) task = NULL; - g_return_val_if_fail (FWUPD_IS_CLIENT (self), NULL); - g_return_val_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable), NULL); - g_return_val_if_fail (error == NULL || *error == NULL, NULL); - - /* connect */ - if (!fwupd_client_connect (self, cancellable, error)) - return NULL; + g_return_if_fail (FWUPD_IS_CLIENT (self)); + g_return_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable)); + g_return_if_fail (priv->proxy != NULL); /* call into daemon */ - val = g_dbus_proxy_call_sync (priv->proxy, - "GetHistory", - NULL, - G_DBUS_CALL_FLAGS_NONE, - -1, - cancellable, - error); - if (val == NULL) { - if (error != NULL) - fwupd_client_fixup_dbus_error (*error); - return NULL; - } - return fwupd_device_array_from_variant (val); + task = g_task_new (self, cancellable, callback, callback_data); + g_dbus_proxy_call (priv->proxy, "GetHistory", + NULL, G_DBUS_CALL_FLAGS_NONE, + -1, cancellable, + fwupd_client_get_history_cb, + g_steal_pointer (&task)); } /** - * fwupd_client_get_device_by_id: + * fwupd_client_get_history_finish: * @self: A #FwupdClient - * @device_id: the device ID, e.g. `usb:00:01:03:03` - * @cancellable: the #GCancellable, or %NULL + * @res: the #GAsyncResult * @error: the #GError, or %NULL * - * Gets a device by it's device ID. + * Gets the result of fwupd_client_get_history_async(). * - * Returns: (transfer full): a #FwupdDevice or %NULL + * Returns: (element-type FwupdDevice) (transfer container): results * - * Since: 0.9.3 + * Since: 1.5.0 **/ -FwupdDevice * -fwupd_client_get_device_by_id (FwupdClient *self, - const gchar *device_id, - GCancellable *cancellable, - GError **error) +GPtrArray * +fwupd_client_get_history_finish (FwupdClient *self, GAsyncResult *res, GError **error) { - g_autoptr(GPtrArray) devices = NULL; - g_return_val_if_fail (FWUPD_IS_CLIENT (self), NULL); - g_return_val_if_fail (device_id != NULL, NULL); - g_return_val_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable), NULL); + g_return_val_if_fail (g_task_is_valid (res, self), NULL); g_return_val_if_fail (error == NULL || *error == NULL, NULL); + return g_task_propagate_pointer (G_TASK(res), error); +} - /* get all the devices */ - devices = fwupd_client_get_devices (self, cancellable, error); - if (devices == NULL) - return NULL; +static void +fwupd_client_get_device_by_id_cb (GObject *source, + GAsyncResult *res, + gpointer user_data) +{ + g_autoptr(GTask) task = G_TASK (user_data); + g_autoptr(GError) error = NULL; + g_autoptr(GPtrArray) devices = NULL; + g_autoptr(FwupdDevice) device = NULL; + const gchar *device_id = g_task_get_task_data (task); + + devices = fwupd_client_get_devices_finish (FWUPD_CLIENT (source), res, &error); + if (devices == NULL) { + g_task_return_error (task, g_steal_pointer (&error)); + return; + } /* find the device by ID (client side) */ for (guint i = 0; i < devices->len; i++) { FwupdDevice *dev = g_ptr_array_index (devices, i); - if (g_strcmp0 (fwupd_device_get_id (dev), device_id) == 0) - return g_object_ref (dev); + if (g_strcmp0 (fwupd_device_get_id (dev), device_id) == 0) { + g_task_return_pointer (task, + g_object_ref (dev), + (GDestroyNotify) g_object_unref); + return; + } } - g_set_error (error, - FWUPD_ERROR, - FWUPD_ERROR_NOT_FOUND, - "failed to find %s", device_id); - return NULL; + + /* failed */ + g_task_return_new_error (task, + FWUPD_ERROR, + FWUPD_ERROR_NOT_FOUND, + "failed to find %s", device_id); } /** - * fwupd_client_get_devices_by_guid: + * fwupd_client_get_device_by_id_async: * @self: A #FwupdClient - * @guid: the GUID, e.g. `e22c4520-43dc-5bb3-8245-5787fead9b63` + * @device_id: the device ID * @cancellable: the #GCancellable, or %NULL + * @callback: the function to run on completion + * @callback_data: the data to pass to @callback + * + * Gets a device by it's device ID. + * + * You must have called fwupd_client_connect_async() on @self before using + * this method. + * + * Since: 1.5.0 + **/ +void +fwupd_client_get_device_by_id_async (FwupdClient *self, const gchar *device_id, + GCancellable *cancellable, + GAsyncReadyCallback callback, + gpointer callback_data) +{ + FwupdClientPrivate *priv = GET_PRIVATE (self); + g_autoptr(GTask) task = NULL; + + g_return_if_fail (FWUPD_IS_CLIENT (self)); + g_return_if_fail (device_id != NULL); + g_return_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable)); + g_return_if_fail (priv->proxy != NULL); + + /* call into daemon */ + task = g_task_new (self, cancellable, callback, callback_data); + g_task_set_task_data (task, g_strdup (device_id), g_free); + fwupd_client_get_devices_async (self, cancellable, + fwupd_client_get_device_by_id_cb, + g_steal_pointer (&task)); +} + +/** + * fwupd_client_get_device_by_id_finish: + * @self: A #FwupdClient + * @res: the #GAsyncResult * @error: the #GError, or %NULL * - * Gets any devices that provide a specific GUID. An error is returned if no - * devices contains this GUID. + * Gets the result of fwupd_client_get_device_by_id_async(). * - * Returns: (element-type FwupdDevice) (transfer container): devices or %NULL + * Returns: (transfer full): a #FwupdDevice, or %NULL for failure * - * Since: 1.4.1 + * Since: 1.5.0 **/ -GPtrArray * -fwupd_client_get_devices_by_guid (FwupdClient *self, - const gchar *guid, - GCancellable *cancellable, - GError **error) +FwupdDevice * +fwupd_client_get_device_by_id_finish (FwupdClient *self, GAsyncResult *res, GError **error) { + g_return_val_if_fail (FWUPD_IS_CLIENT (self), NULL); + g_return_val_if_fail (g_task_is_valid (res, self), NULL); + g_return_val_if_fail (error == NULL || *error == NULL, NULL); + return g_task_propagate_pointer (G_TASK(res), error); +} + +static void +fwupd_client_get_devices_by_guid_cb (GObject *source, + GAsyncResult *res, + gpointer user_data) +{ + g_autoptr(GTask) task = G_TASK (user_data); + g_autoptr(GError) error = NULL; g_autoptr(GPtrArray) devices = NULL; g_autoptr(GPtrArray) devices_tmp = NULL; - - g_return_val_if_fail (FWUPD_IS_CLIENT (self), NULL); - g_return_val_if_fail (guid != NULL, NULL); - g_return_val_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable), NULL); - g_return_val_if_fail (error == NULL || *error == NULL, NULL); + const gchar *guid = g_task_get_task_data (task); /* get all the devices */ - devices_tmp = fwupd_client_get_devices (self, cancellable, error); - if (devices_tmp == NULL) - return NULL; + devices_tmp = fwupd_client_get_devices_finish (FWUPD_CLIENT (source), res, &error); + if (devices_tmp == NULL) { + g_task_return_error (task, g_steal_pointer (&error)); + return; + } /* find the devices by GUID (client side) */ devices = g_ptr_array_new_with_free_func ((GDestroyNotify) g_object_unref); @@ -742,541 +944,920 @@ fwupd_client_get_devices_by_guid (FwupdClient *self, /* nothing */ if (devices->len == 0) { - g_set_error (error, - FWUPD_ERROR, - FWUPD_ERROR_NOT_FOUND, - "failed to find any device providing %s", guid); - return NULL; + g_task_return_new_error (task, + FWUPD_ERROR, + FWUPD_ERROR_NOT_FOUND, + "failed to find any device providing %s", guid); + return; } /* success */ - return g_steal_pointer (&devices); + g_task_return_pointer (task, + g_steal_pointer (&devices), + (GDestroyNotify) g_ptr_array_unref); } /** - * fwupd_client_get_releases: + * fwupd_client_get_devices_by_guid_async: * @self: A #FwupdClient - * @device_id: the device ID + * @guid: the GUID, e.g. `e22c4520-43dc-5bb3-8245-5787fead9b63` * @cancellable: the #GCancellable, or %NULL - * @error: the #GError, or %NULL + * @callback: the function to run on completion + * @callback_data: the data to pass to @callback * - * Gets all the releases for a specific device + * Gets any devices that provide a specific GUID. An error is returned if no + * devices contains this GUID. * - * Returns: (element-type FwupdRelease) (transfer container): results + * You must have called fwupd_client_connect_async() on @self before using + * this method. * - * Since: 0.9.3 + * Since: 1.5.0 **/ -GPtrArray * -fwupd_client_get_releases (FwupdClient *self, const gchar *device_id, - GCancellable *cancellable, GError **error) +void +fwupd_client_get_devices_by_guid_async (FwupdClient *self, const gchar *guid, + GCancellable *cancellable, + GAsyncReadyCallback callback, + gpointer callback_data) { FwupdClientPrivate *priv = GET_PRIVATE (self); - g_autoptr(GVariant) val = NULL; + g_autoptr(GTask) task = NULL; - g_return_val_if_fail (FWUPD_IS_CLIENT (self), NULL); - g_return_val_if_fail (device_id != NULL, NULL); - g_return_val_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable), NULL); - g_return_val_if_fail (error == NULL || *error == NULL, NULL); - - /* connect */ - if (!fwupd_client_connect (self, cancellable, error)) - return NULL; + g_return_if_fail (FWUPD_IS_CLIENT (self)); + g_return_if_fail (guid != NULL); + g_return_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable)); + g_return_if_fail (priv->proxy != NULL); /* call into daemon */ - val = g_dbus_proxy_call_sync (priv->proxy, - "GetReleases", - g_variant_new ("(s)", device_id), - G_DBUS_CALL_FLAGS_NONE, - -1, - cancellable, - error); - if (val == NULL) { - if (error != NULL) - fwupd_client_fixup_dbus_error (*error); - return NULL; - } - return fwupd_release_array_from_variant (val); + task = g_task_new (self, cancellable, callback, callback_data); + g_task_set_task_data (task, g_strdup (guid), g_free); + fwupd_client_get_devices_async (self, cancellable, + fwupd_client_get_devices_by_guid_cb, + g_steal_pointer (&task)); } /** - * fwupd_client_get_downgrades: + * fwupd_client_get_devices_by_guid_finish: * @self: A #FwupdClient - * @device_id: the device ID - * @cancellable: the #GCancellable, or %NULL + * @res: the #GAsyncResult * @error: the #GError, or %NULL * - * Gets all the downgrades for a specific device. + * Gets the result of fwupd_client_get_devices_by_guid_async(). * * Returns: (element-type FwupdRelease) (transfer container): results * - * Since: 0.9.8 + * Since: 1.5.0 **/ GPtrArray * -fwupd_client_get_downgrades (FwupdClient *self, const gchar *device_id, - GCancellable *cancellable, GError **error) +fwupd_client_get_devices_by_guid_finish (FwupdClient *self, GAsyncResult *res, GError **error) { - FwupdClientPrivate *priv = GET_PRIVATE (self); - g_autoptr(GVariant) val = NULL; - g_return_val_if_fail (FWUPD_IS_CLIENT (self), NULL); - g_return_val_if_fail (device_id != NULL, NULL); - g_return_val_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable), NULL); + g_return_val_if_fail (g_task_is_valid (res, self), NULL); g_return_val_if_fail (error == NULL || *error == NULL, NULL); - - /* connect */ - if (!fwupd_client_connect (self, cancellable, error)) - return NULL; - - /* call into daemon */ - val = g_dbus_proxy_call_sync (priv->proxy, - "GetDowngrades", - g_variant_new ("(s)", device_id), - G_DBUS_CALL_FLAGS_NONE, - -1, - cancellable, - error); - if (val == NULL) { - if (error != NULL) - fwupd_client_fixup_dbus_error (*error); - return NULL; - } - return fwupd_release_array_from_variant (val); -} - -/** - * fwupd_client_get_upgrades: - * @self: A #FwupdClient - * @device_id: the device ID - * @cancellable: the #GCancellable, or %NULL - * @error: the #GError, or %NULL - * - * Gets all the upgrades for a specific device. - * - * Returns: (element-type FwupdRelease) (transfer container): results - * - * Since: 0.9.8 - **/ -GPtrArray * -fwupd_client_get_upgrades (FwupdClient *self, const gchar *device_id, - GCancellable *cancellable, GError **error) -{ - FwupdClientPrivate *priv = GET_PRIVATE (self); - g_autoptr(GVariant) val = NULL; - - g_return_val_if_fail (FWUPD_IS_CLIENT (self), NULL); - g_return_val_if_fail (device_id != NULL, NULL); - g_return_val_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable), NULL); - g_return_val_if_fail (error == NULL || *error == NULL, NULL); - - /* connect */ - if (!fwupd_client_connect (self, cancellable, error)) - return NULL; - - /* call into daemon */ - val = g_dbus_proxy_call_sync (priv->proxy, - "GetUpgrades", - g_variant_new ("(s)", device_id), - G_DBUS_CALL_FLAGS_NONE, - -1, - cancellable, - error); - if (val == NULL) { - if (error != NULL) - fwupd_client_fixup_dbus_error (*error); - return NULL; - } - return fwupd_release_array_from_variant (val); + return g_task_propagate_pointer (G_TASK(res), error); } static void -fwupd_client_proxy_call_cb (GObject *source, GAsyncResult *res, gpointer user_data) +fwupd_client_get_releases_cb (GObject *source, + GAsyncResult *res, + gpointer user_data) { - FwupdClientHelper *helper = (FwupdClientHelper *) user_data; - helper->val = g_dbus_proxy_call_finish (G_DBUS_PROXY (source), - res, &helper->error); - if (helper->val != NULL) - helper->ret = TRUE; - if (helper->error != NULL) - fwupd_client_fixup_dbus_error (helper->error); - g_main_loop_quit (helper->loop); + g_autoptr(GTask) task = G_TASK (user_data); + g_autoptr(GError) error = NULL; + g_autoptr(GVariant) val = NULL; + + val = g_dbus_proxy_call_finish (G_DBUS_PROXY (source), res, &error); + if (val == NULL) { + fwupd_client_fixup_dbus_error (error); + g_task_return_error (task, g_steal_pointer (&error)); + return; + } + + /* success */ + g_task_return_pointer (task, + fwupd_release_array_from_variant (val), + (GDestroyNotify) g_ptr_array_unref); } /** - * fwupd_client_modify_config + * fwupd_client_get_releases_async: + * @self: A #FwupdClient + * @device_id: the device ID + * @cancellable: the #GCancellable, or %NULL + * @callback: the function to run on completion + * @callback_data: the data to pass to @callback + * + * Gets all the releases for a specific device + * + * You must have called fwupd_client_connect_async() on @self before using + * this method. + * + * Since: 1.5.0 + **/ +void +fwupd_client_get_releases_async (FwupdClient *self, const gchar *device_id, + GCancellable *cancellable, + GAsyncReadyCallback callback, + gpointer callback_data) +{ + FwupdClientPrivate *priv = GET_PRIVATE (self); + g_autoptr(GTask) task = NULL; + + g_return_if_fail (FWUPD_IS_CLIENT (self)); + g_return_if_fail (device_id != NULL); + g_return_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable)); + g_return_if_fail (priv->proxy != NULL); + + /* call into daemon */ + task = g_task_new (self, cancellable, callback, callback_data); + g_dbus_proxy_call (priv->proxy, "GetReleases", + g_variant_new ("(s)", device_id), + G_DBUS_CALL_FLAGS_NONE, + -1, cancellable, + fwupd_client_get_releases_cb, + g_steal_pointer (&task)); +} + +/** + * fwupd_client_get_releases_finish: + * @self: A #FwupdClient + * @res: the #GAsyncResult + * @error: the #GError, or %NULL + * + * Gets the result of fwupd_client_get_releases_async(). + * + * Returns: (element-type FwupdRelease) (transfer container): results + * + * Since: 1.5.0 + **/ +GPtrArray * +fwupd_client_get_releases_finish (FwupdClient *self, GAsyncResult *res, GError **error) +{ + g_return_val_if_fail (FWUPD_IS_CLIENT (self), NULL); + g_return_val_if_fail (g_task_is_valid (res, self), NULL); + g_return_val_if_fail (error == NULL || *error == NULL, NULL); + return g_task_propagate_pointer (G_TASK(res), error); +} + +static void +fwupd_client_get_downgrades_cb (GObject *source, + GAsyncResult *res, + gpointer user_data) +{ + g_autoptr(GTask) task = G_TASK (user_data); + g_autoptr(GError) error = NULL; + g_autoptr(GVariant) val = NULL; + + val = g_dbus_proxy_call_finish (G_DBUS_PROXY (source), res, &error); + if (val == NULL) { + fwupd_client_fixup_dbus_error (error); + g_task_return_error (task, g_steal_pointer (&error)); + return; + } + + /* success */ + g_task_return_pointer (task, + fwupd_release_array_from_variant (val), + (GDestroyNotify) g_ptr_array_unref); +} + +/** + * fwupd_client_get_downgrades_async: + * @self: A #FwupdClient + * @device_id: the device ID + * @cancellable: the #GCancellable, or %NULL + * @callback: the function to run on completion + * @callback_data: the data to pass to @callback + * + * Gets all the downgrades for a specific device. + * + * You must have called fwupd_client_connect_async() on @self before using + * this method. + * + * Since: 1.5.0 + **/ +void +fwupd_client_get_downgrades_async (FwupdClient *self, const gchar *device_id, + GCancellable *cancellable, + GAsyncReadyCallback callback, + gpointer callback_data) +{ + FwupdClientPrivate *priv = GET_PRIVATE (self); + g_autoptr(GTask) task = NULL; + + g_return_if_fail (FWUPD_IS_CLIENT (self)); + g_return_if_fail (device_id != NULL); + g_return_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable)); + g_return_if_fail (priv->proxy != NULL); + + /* call into daemon */ + task = g_task_new (self, cancellable, callback, callback_data); + g_dbus_proxy_call (priv->proxy, "GetDowngrades", + g_variant_new ("(s)", device_id), + G_DBUS_CALL_FLAGS_NONE, + -1, cancellable, + fwupd_client_get_downgrades_cb, + g_steal_pointer (&task)); +} + +/** + * fwupd_client_get_downgrades_finish: + * @self: A #FwupdClient + * @res: the #GAsyncResult + * @error: the #GError, or %NULL + * + * Gets the result of fwupd_client_get_downgrades_async(). + * + * Returns: (element-type FwupdRelease) (transfer container): results + * + * Since: 1.5.0 + **/ +GPtrArray * +fwupd_client_get_downgrades_finish (FwupdClient *self, GAsyncResult *res, GError **error) +{ + g_return_val_if_fail (FWUPD_IS_CLIENT (self), NULL); + g_return_val_if_fail (g_task_is_valid (res, self), NULL); + g_return_val_if_fail (error == NULL || *error == NULL, NULL); + return g_task_propagate_pointer (G_TASK(res), error); +} + +static void +fwupd_client_get_upgrades_cb (GObject *source, + GAsyncResult *res, + gpointer user_data) +{ + g_autoptr(GTask) task = G_TASK (user_data); + g_autoptr(GError) error = NULL; + g_autoptr(GVariant) val = NULL; + + val = g_dbus_proxy_call_finish (G_DBUS_PROXY (source), res, &error); + if (val == NULL) { + fwupd_client_fixup_dbus_error (error); + g_task_return_error (task, g_steal_pointer (&error)); + return; + } + + /* success */ + g_task_return_pointer (task, + fwupd_release_array_from_variant (val), + (GDestroyNotify) g_ptr_array_unref); +} + +/** + * fwupd_client_get_upgrades_async: + * @self: A #FwupdClient + * @device_id: the device ID + * @cancellable: the #GCancellable, or %NULL + * @callback: the function to run on completion + * @callback_data: the data to pass to @callback + * + * Gets all the upgrades for a specific device. + * + * You must have called fwupd_client_connect_async() on @self before using + * this method. + * + * Since: 1.5.0 + **/ +void +fwupd_client_get_upgrades_async (FwupdClient *self, const gchar *device_id, + GCancellable *cancellable, + GAsyncReadyCallback callback, + gpointer callback_data) +{ + FwupdClientPrivate *priv = GET_PRIVATE (self); + g_autoptr(GTask) task = NULL; + + g_return_if_fail (FWUPD_IS_CLIENT (self)); + g_return_if_fail (device_id != NULL); + g_return_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable)); + g_return_if_fail (priv->proxy != NULL); + + /* call into daemon */ + task = g_task_new (self, cancellable, callback, callback_data); + g_dbus_proxy_call (priv->proxy, "GetUpgrades", + g_variant_new ("(s)", device_id), + G_DBUS_CALL_FLAGS_NONE, + -1, cancellable, + fwupd_client_get_upgrades_cb, + g_steal_pointer (&task)); +} + +/** + * fwupd_client_get_upgrades_finish: + * @self: A #FwupdClient + * @res: the #GAsyncResult + * @error: the #GError, or %NULL + * + * Gets the result of fwupd_client_get_upgrades_async(). + * + * Returns: (element-type FwupdRelease) (transfer container): results + * + * Since: 1.5.0 + **/ +GPtrArray * +fwupd_client_get_upgrades_finish (FwupdClient *self, GAsyncResult *res, GError **error) +{ + g_return_val_if_fail (FWUPD_IS_CLIENT (self), NULL); + g_return_val_if_fail (g_task_is_valid (res, self), NULL); + g_return_val_if_fail (error == NULL || *error == NULL, NULL); + return g_task_propagate_pointer (G_TASK(res), error); +} + +static void +fwupd_client_modify_config_cb (GObject *source, + GAsyncResult *res, + gpointer user_data) +{ + g_autoptr(GTask) task = G_TASK (user_data); + g_autoptr(GError) error = NULL; + g_autoptr(GVariant) val = NULL; + + val = g_dbus_proxy_call_finish (G_DBUS_PROXY (source), res, &error); + if (val == NULL) { + fwupd_client_fixup_dbus_error (error); + g_task_return_error (task, g_steal_pointer (&error)); + return; + } + + /* success */ + g_task_return_boolean (task, TRUE); +} + +/** + * fwupd_client_modify_config_async: * @self: A #FwupdClient * @key: key, e.g. `DisabledPlugins` * @value: value, e.g. `*` * @cancellable: the #GCancellable, or %NULL - * @error: the #GError, or %NULL + * @callback: the function to run on completion + * @callback_data: the data to pass to @callback * * Modifies a daemon config option. * The daemon will only respond to this request with proper permissions * - * Returns: %TRUE for success - * - * Since: 1.2.8 + * Since: 1.5.0 **/ -gboolean -fwupd_client_modify_config (FwupdClient *self, const gchar *key, const gchar *value, - GCancellable *cancellable, GError **error) +void +fwupd_client_modify_config_async (FwupdClient *self, + const gchar *key, + const gchar *value, + GCancellable *cancellable, + GAsyncReadyCallback callback, + gpointer callback_data) { FwupdClientPrivate *priv = GET_PRIVATE (self); - g_autoptr(FwupdClientHelper) helper = NULL; + g_autoptr(GTask) task = NULL; - g_return_val_if_fail (FWUPD_IS_CLIENT (self), FALSE); - g_return_val_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable), FALSE); - g_return_val_if_fail (error == NULL || *error == NULL, FALSE); - - /* connect */ - if (!fwupd_client_connect (self, cancellable, error)) - return FALSE; + g_return_if_fail (FWUPD_IS_CLIENT (self)); + g_return_if_fail (key != NULL); + g_return_if_fail (value != NULL); + g_return_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable)); + g_return_if_fail (priv->proxy != NULL); /* call into daemon */ - helper = fwupd_client_helper_new (); - g_dbus_proxy_call (priv->proxy, - "ModifyConfig", + task = g_task_new (self, cancellable, callback, callback_data); + g_dbus_proxy_call (priv->proxy, "ModifyConfig", g_variant_new ("(ss)", key, value), - G_DBUS_CALL_FLAGS_NONE, - -1, + G_DBUS_CALL_FLAGS_NONE, -1, cancellable, - fwupd_client_proxy_call_cb, - helper); - g_main_loop_run (helper->loop); - if (!helper->ret) { - g_propagate_error (error, helper->error); - helper->error = NULL; - return FALSE; - } - return TRUE; + fwupd_client_modify_config_cb, + g_steal_pointer (&task)); } /** - * fwupd_client_activate: + * fwupd_client_modify_config_finish: * @self: A #FwupdClient - * @cancellable: the #GCancellable, or %NULL - * @device_id: a device + * @res: the #GAsyncResult * @error: the #GError, or %NULL * + * Gets the result of fwupd_client_modify_config_async(). + * + * Returns: %TRUE for success + * + * Since: 1.5.0 + **/ +gboolean +fwupd_client_modify_config_finish (FwupdClient *self, GAsyncResult *res, GError **error) +{ + g_return_val_if_fail (FWUPD_IS_CLIENT (self), FALSE); + g_return_val_if_fail (g_task_is_valid (res, self), FALSE); + g_return_val_if_fail (error == NULL || *error == NULL, FALSE); + return g_task_propagate_boolean (G_TASK(res), error); +} + +static void +fwupd_client_activate_cb (GObject *source, + GAsyncResult *res, + gpointer user_data) +{ + g_autoptr(GTask) task = G_TASK (user_data); + g_autoptr(GError) error = NULL; + g_autoptr(GVariant) val = NULL; + + val = g_dbus_proxy_call_finish (G_DBUS_PROXY (source), res, &error); + if (val == NULL) { + fwupd_client_fixup_dbus_error (error); + g_task_return_error (task, g_steal_pointer (&error)); + return; + } + + /* success */ + g_task_return_boolean (task, TRUE); +} + +/** + * fwupd_client_activate_async: + * @self: A #FwupdClient + * @device_id: a device + * @cancellable: the #GCancellable, or %NULL + * @callback: the function to run on completion + * @callback_data: the data to pass to @callback + * * Activates up a device, which normally means the device switches to a new * firmware version. This should only be called when data loss cannot occur. * - * Returns: %TRUE for success - * - * Since: 1.2.6 + * Since: 1.5.0 **/ -gboolean -fwupd_client_activate (FwupdClient *self, GCancellable *cancellable, - const gchar *device_id, GError **error) +void +fwupd_client_activate_async (FwupdClient *self, + const gchar *device_id, + GCancellable *cancellable, + GAsyncReadyCallback callback, + gpointer callback_data) { FwupdClientPrivate *priv = GET_PRIVATE (self); - g_autoptr(FwupdClientHelper) helper = NULL; + g_autoptr(GTask) task = NULL; - g_return_val_if_fail (FWUPD_IS_CLIENT (self), FALSE); - g_return_val_if_fail (device_id != NULL, FALSE); - g_return_val_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable), FALSE); - g_return_val_if_fail (error == NULL || *error == NULL, FALSE); - - /* connect */ - if (!fwupd_client_connect (self, cancellable, error)) - return FALSE; + g_return_if_fail (FWUPD_IS_CLIENT (self)); + g_return_if_fail (device_id != NULL); + g_return_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable)); + g_return_if_fail (priv->proxy != NULL); /* call into daemon */ - helper = fwupd_client_helper_new (); - g_dbus_proxy_call (priv->proxy, - "Activate", + task = g_task_new (self, cancellable, callback, callback_data); + g_dbus_proxy_call (priv->proxy, "Activate", g_variant_new ("(s)", device_id), - G_DBUS_CALL_FLAGS_NONE, - -1, + G_DBUS_CALL_FLAGS_NONE, -1, cancellable, - fwupd_client_proxy_call_cb, - helper); - g_main_loop_run (helper->loop); - if (!helper->ret) { - g_propagate_error (error, helper->error); - helper->error = NULL; - return FALSE; - } - return TRUE; + fwupd_client_activate_cb, + g_steal_pointer (&task)); } /** - * fwupd_client_verify: + * fwupd_client_activate_finish: + * @self: A #FwupdClient + * @res: the #GAsyncResult + * @error: the #GError, or %NULL + * + * Gets the result of fwupd_client_activate_async(). + * + * Returns: %TRUE for success + * + * Since: 1.5.0 + **/ +gboolean +fwupd_client_activate_finish (FwupdClient *self, GAsyncResult *res, GError **error) +{ + g_return_val_if_fail (FWUPD_IS_CLIENT (self), FALSE); + g_return_val_if_fail (g_task_is_valid (res, self), FALSE); + g_return_val_if_fail (error == NULL || *error == NULL, FALSE); + return g_task_propagate_boolean (G_TASK(res), error); +} + +static void +fwupd_client_verify_cb (GObject *source, + GAsyncResult *res, + gpointer user_data) +{ + g_autoptr(GTask) task = G_TASK (user_data); + g_autoptr(GError) error = NULL; + g_autoptr(GVariant) val = NULL; + + val = g_dbus_proxy_call_finish (G_DBUS_PROXY (source), res, &error); + if (val == NULL) { + fwupd_client_fixup_dbus_error (error); + g_task_return_error (task, g_steal_pointer (&error)); + return; + } + + /* success */ + g_task_return_boolean (task, TRUE); +} + +/** + * fwupd_client_verify_async: * @self: A #FwupdClient * @device_id: the device ID * @cancellable: the #GCancellable, or %NULL - * @error: the #GError, or %NULL + * @callback: the function to run on completion + * @callback_data: the data to pass to @callback * * Verify a specific device. * - * Returns: %TRUE for verification success - * - * Since: 0.7.0 + * Since: 1.5.0 **/ -gboolean -fwupd_client_verify (FwupdClient *self, const gchar *device_id, - GCancellable *cancellable, GError **error) +void +fwupd_client_verify_async (FwupdClient *self, + const gchar *device_id, + GCancellable *cancellable, + GAsyncReadyCallback callback, + gpointer callback_data) { FwupdClientPrivate *priv = GET_PRIVATE (self); - g_autoptr(FwupdClientHelper) helper = NULL; + g_autoptr(GTask) task = NULL; - g_return_val_if_fail (FWUPD_IS_CLIENT (self), FALSE); - g_return_val_if_fail (device_id != NULL, FALSE); - g_return_val_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable), FALSE); - g_return_val_if_fail (error == NULL || *error == NULL, FALSE); - - /* connect */ - if (!fwupd_client_connect (self, cancellable, error)) - return FALSE; + g_return_if_fail (FWUPD_IS_CLIENT (self)); + g_return_if_fail (device_id != NULL); + g_return_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable)); + g_return_if_fail (priv->proxy != NULL); /* call into daemon */ - helper = fwupd_client_helper_new (); - g_dbus_proxy_call (priv->proxy, - "Verify", + task = g_task_new (self, cancellable, callback, callback_data); + g_dbus_proxy_call (priv->proxy, "Verify", g_variant_new ("(s)", device_id), - G_DBUS_CALL_FLAGS_NONE, - -1, + G_DBUS_CALL_FLAGS_NONE, -1, cancellable, - fwupd_client_proxy_call_cb, - helper); - g_main_loop_run (helper->loop); - if (!helper->ret) { - g_propagate_error (error, helper->error); - helper->error = NULL; - return FALSE; - } - return TRUE; + fwupd_client_verify_cb, + g_steal_pointer (&task)); } /** - * fwupd_client_verify_update: + * fwupd_client_verify_finish: + * @self: A #FwupdClient + * @res: the #GAsyncResult + * @error: the #GError, or %NULL + * + * Gets the result of fwupd_client_verify_async(). + * + * Returns: %TRUE for success + * + * Since: 1.5.0 + **/ +gboolean +fwupd_client_verify_finish (FwupdClient *self, GAsyncResult *res, GError **error) +{ + g_return_val_if_fail (FWUPD_IS_CLIENT (self), FALSE); + g_return_val_if_fail (g_task_is_valid (res, self), FALSE); + g_return_val_if_fail (error == NULL || *error == NULL, FALSE); + return g_task_propagate_boolean (G_TASK(res), error); +} + +static void +fwupd_client_verify_update_cb (GObject *source, + GAsyncResult *res, + gpointer user_data) +{ + g_autoptr(GTask) task = G_TASK (user_data); + g_autoptr(GError) error = NULL; + g_autoptr(GVariant) val = NULL; + + val = g_dbus_proxy_call_finish (G_DBUS_PROXY (source), res, &error); + if (val == NULL) { + fwupd_client_fixup_dbus_error (error); + g_task_return_error (task, g_steal_pointer (&error)); + return; + } + + /* success */ + g_task_return_boolean (task, TRUE); +} + +/** + * fwupd_client_verify_update_async: * @self: A #FwupdClient * @device_id: the device ID * @cancellable: the #GCancellable, or %NULL - * @error: the #GError, or %NULL + * @callback: the function to run on completion + * @callback_data: the data to pass to @callback * * Update the verification record for a specific device. * - * Returns: %TRUE for verification success - * - * Since: 0.8.0 + * Since: 1.5.0 **/ -gboolean -fwupd_client_verify_update (FwupdClient *self, const gchar *device_id, - GCancellable *cancellable, GError **error) +void +fwupd_client_verify_update_async (FwupdClient *self, + const gchar *device_id, + GCancellable *cancellable, + GAsyncReadyCallback callback, + gpointer callback_data) { FwupdClientPrivate *priv = GET_PRIVATE (self); - g_autoptr(FwupdClientHelper) helper = NULL; + g_autoptr(GTask) task = NULL; - g_return_val_if_fail (FWUPD_IS_CLIENT (self), FALSE); - g_return_val_if_fail (device_id != NULL, FALSE); - g_return_val_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable), FALSE); - g_return_val_if_fail (error == NULL || *error == NULL, FALSE); - - /* connect */ - if (!fwupd_client_connect (self, cancellable, error)) - return FALSE; + g_return_if_fail (FWUPD_IS_CLIENT (self)); + g_return_if_fail (device_id != NULL); + g_return_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable)); + g_return_if_fail (priv->proxy != NULL); /* call into daemon */ - helper = fwupd_client_helper_new (); - g_dbus_proxy_call (priv->proxy, - "VerifyUpdate", + task = g_task_new (self, cancellable, callback, callback_data); + g_dbus_proxy_call (priv->proxy, "VerifyUpdate", g_variant_new ("(s)", device_id), - G_DBUS_CALL_FLAGS_NONE, - -1, + G_DBUS_CALL_FLAGS_NONE, -1, cancellable, - fwupd_client_proxy_call_cb, - helper); - g_main_loop_run (helper->loop); - if (!helper->ret) { - g_propagate_error (error, helper->error); - helper->error = NULL; - return FALSE; - } - return TRUE; + fwupd_client_verify_update_cb, + g_steal_pointer (&task)); } /** - * fwupd_client_unlock: + * fwupd_client_verify_update_finish: + * @self: A #FwupdClient + * @res: the #GAsyncResult + * @error: the #GError, or %NULL + * + * Gets the result of fwupd_client_verify_update_async(). + * + * Returns: %TRUE for success + * + * Since: 1.5.0 + **/ +gboolean +fwupd_client_verify_update_finish (FwupdClient *self, GAsyncResult *res, GError **error) +{ + g_return_val_if_fail (FWUPD_IS_CLIENT (self), FALSE); + g_return_val_if_fail (g_task_is_valid (res, self), FALSE); + g_return_val_if_fail (error == NULL || *error == NULL, FALSE); + return g_task_propagate_boolean (G_TASK(res), error); +} + +static void +fwupd_client_unlock_cb (GObject *source, + GAsyncResult *res, + gpointer user_data) +{ + g_autoptr(GTask) task = G_TASK (user_data); + g_autoptr(GError) error = NULL; + g_autoptr(GVariant) val = NULL; + + val = g_dbus_proxy_call_finish (G_DBUS_PROXY (source), res, &error); + if (val == NULL) { + fwupd_client_fixup_dbus_error (error); + g_task_return_error (task, g_steal_pointer (&error)); + return; + } + + /* success */ + g_task_return_boolean (task, TRUE); +} + +/** + * fwupd_client_unlock_async: * @self: A #FwupdClient * @device_id: the device ID * @cancellable: the #GCancellable, or %NULL - * @error: the #GError, or %NULL + * @callback: the function to run on completion + * @callback_data: the data to pass to @callback * * Unlocks a specific device so firmware can be read or wrote. * - * Returns: %TRUE for success - * - * Since: 0.7.0 + * Since: 1.5.0 **/ -gboolean -fwupd_client_unlock (FwupdClient *self, const gchar *device_id, - GCancellable *cancellable, GError **error) +void +fwupd_client_unlock_async (FwupdClient *self, + const gchar *device_id, + GCancellable *cancellable, + GAsyncReadyCallback callback, + gpointer callback_data) { FwupdClientPrivate *priv = GET_PRIVATE (self); - g_autoptr(FwupdClientHelper) helper = NULL; + g_autoptr(GTask) task = NULL; - g_return_val_if_fail (FWUPD_IS_CLIENT (self), FALSE); - g_return_val_if_fail (device_id != NULL, FALSE); - g_return_val_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable), FALSE); - g_return_val_if_fail (error == NULL || *error == NULL, FALSE); - - /* connect */ - if (!fwupd_client_connect (self, cancellable, error)) - return FALSE; + g_return_if_fail (FWUPD_IS_CLIENT (self)); + g_return_if_fail (device_id != NULL); + g_return_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable)); + g_return_if_fail (priv->proxy != NULL); /* call into daemon */ - helper = fwupd_client_helper_new (); - g_dbus_proxy_call (priv->proxy, - "Unlock", + task = g_task_new (self, cancellable, callback, callback_data); + g_dbus_proxy_call (priv->proxy, "Unlock", g_variant_new ("(s)", device_id), - G_DBUS_CALL_FLAGS_NONE, - -1, + G_DBUS_CALL_FLAGS_NONE, -1, cancellable, - fwupd_client_proxy_call_cb, - helper); - g_main_loop_run (helper->loop); - if (!helper->ret) { - g_propagate_error (error, helper->error); - helper->error = NULL; - return FALSE; - } - return TRUE; + fwupd_client_unlock_cb, + g_steal_pointer (&task)); } /** - * fwupd_client_clear_results: + * fwupd_client_unlock_finish: * @self: A #FwupdClient - * @device_id: the device ID - * @cancellable: the #GCancellable, or %NULL + * @res: the #GAsyncResult * @error: the #GError, or %NULL * + * Gets the result of fwupd_client_unlock_async(). + * + * Returns: %TRUE for success + * + * Since: 1.5.0 + **/ +gboolean +fwupd_client_unlock_finish (FwupdClient *self, GAsyncResult *res, GError **error) +{ + g_return_val_if_fail (FWUPD_IS_CLIENT (self), FALSE); + g_return_val_if_fail (g_task_is_valid (res, self), FALSE); + g_return_val_if_fail (error == NULL || *error == NULL, FALSE); + return g_task_propagate_boolean (G_TASK(res), error); +} + +static void +fwupd_client_clear_results_cb (GObject *source, + GAsyncResult *res, + gpointer user_data) +{ + g_autoptr(GTask) task = G_TASK (user_data); + g_autoptr(GError) error = NULL; + g_autoptr(GVariant) val = NULL; + + val = g_dbus_proxy_call_finish (G_DBUS_PROXY (source), res, &error); + if (val == NULL) { + fwupd_client_fixup_dbus_error (error); + g_task_return_error (task, g_steal_pointer (&error)); + return; + } + + /* success */ + g_task_return_boolean (task, TRUE); +} + +/** + * fwupd_client_clear_results_async: + * @self: A #FwupdClient + * @device_id: a device + * @cancellable: the #GCancellable, or %NULL + * @callback: the function to run on completion + * @callback_data: the data to pass to @callback + * * Clears the results for a specific device. * - * Returns: %TRUE for success - * - * Since: 0.7.0 + * Since: 1.5.0 **/ -gboolean -fwupd_client_clear_results (FwupdClient *self, const gchar *device_id, - GCancellable *cancellable, GError **error) +void +fwupd_client_clear_results_async (FwupdClient *self, + const gchar *device_id, + GCancellable *cancellable, + GAsyncReadyCallback callback, + gpointer callback_data) { FwupdClientPrivate *priv = GET_PRIVATE (self); - g_autoptr(FwupdClientHelper) helper = NULL; + g_autoptr(GTask) task = NULL; - g_return_val_if_fail (FWUPD_IS_CLIENT (self), FALSE); - g_return_val_if_fail (device_id != NULL, FALSE); - g_return_val_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable), FALSE); - g_return_val_if_fail (error == NULL || *error == NULL, FALSE); - - /* connect */ - if (!fwupd_client_connect (self, cancellable, error)) - return FALSE; + g_return_if_fail (FWUPD_IS_CLIENT (self)); + g_return_if_fail (device_id != NULL); + g_return_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable)); + g_return_if_fail (priv->proxy != NULL); /* call into daemon */ - helper = fwupd_client_helper_new (); - g_dbus_proxy_call (priv->proxy, - "ClearResults", + task = g_task_new (self, cancellable, callback, callback_data); + g_dbus_proxy_call (priv->proxy, "ClearResults", g_variant_new ("(s)", device_id), - G_DBUS_CALL_FLAGS_NONE, - -1, + G_DBUS_CALL_FLAGS_NONE, -1, cancellable, - fwupd_client_proxy_call_cb, - helper); - g_main_loop_run (helper->loop); - if (!helper->ret) { - g_propagate_error (error, helper->error); - helper->error = NULL; - return FALSE; - } - return TRUE; + fwupd_client_clear_results_cb, + g_steal_pointer (&task)); } /** - * fwupd_client_get_results: + * fwupd_client_clear_results_finish: + * @self: A #FwupdClient + * @res: the #GAsyncResult + * @error: the #GError, or %NULL + * + * Gets the result of fwupd_client_clear_results_async(). + * + * Returns: %TRUE for success + * + * Since: 1.5.0 + **/ +gboolean +fwupd_client_clear_results_finish (FwupdClient *self, GAsyncResult *res, GError **error) +{ + g_return_val_if_fail (FWUPD_IS_CLIENT (self), FALSE); + g_return_val_if_fail (g_task_is_valid (res, self), FALSE); + g_return_val_if_fail (error == NULL || *error == NULL, FALSE); + return g_task_propagate_boolean (G_TASK(res), error); +} + +static void +fwupd_client_get_results_cb (GObject *source, + GAsyncResult *res, + gpointer user_data) +{ + g_autoptr(GTask) task = G_TASK (user_data); + g_autoptr(GError) error = NULL; + g_autoptr(GVariant) val = NULL; + + val = g_dbus_proxy_call_finish (G_DBUS_PROXY (source), res, &error); + if (val == NULL) { + fwupd_client_fixup_dbus_error (error); + g_task_return_error (task, g_steal_pointer (&error)); + return; + } + + /* success */ + g_task_return_pointer (task, + fwupd_device_from_variant (val), + (GDestroyNotify) g_ptr_array_unref); +} + +/** + * fwupd_client_get_results_async: * @self: A #FwupdClient * @device_id: the device ID * @cancellable: the #GCancellable, or %NULL - * @error: the #GError, or %NULL + * @callback: the function to run on completion + * @callback_data: the data to pass to @callback * * Gets the results of a previous firmware update for a specific device. * - * Returns: (transfer full): a #FwupdDevice, or %NULL for failure + * You must have called fwupd_client_connect_async() on @self before using + * this method. * - * Since: 0.7.0 + * Since: 1.5.0 **/ -FwupdDevice * -fwupd_client_get_results (FwupdClient *self, const gchar *device_id, - GCancellable *cancellable, GError **error) +void +fwupd_client_get_results_async (FwupdClient *self, const gchar *device_id, + GCancellable *cancellable, + GAsyncReadyCallback callback, + gpointer callback_data) { FwupdClientPrivate *priv = GET_PRIVATE (self); - g_autoptr(FwupdClientHelper) helper = NULL; + g_autoptr(GTask) task = NULL; - g_return_val_if_fail (FWUPD_IS_CLIENT (self), NULL); - g_return_val_if_fail (device_id != NULL, NULL); - g_return_val_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable), NULL); - g_return_val_if_fail (error == NULL || *error == NULL, NULL); - - /* connect */ - if (!fwupd_client_connect (self, cancellable, error)) - return NULL; + g_return_if_fail (FWUPD_IS_CLIENT (self)); + g_return_if_fail (device_id != NULL); + g_return_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable)); + g_return_if_fail (priv->proxy != NULL); /* call into daemon */ - helper = fwupd_client_helper_new (); - g_dbus_proxy_call (priv->proxy, - "GetResults", + task = g_task_new (self, cancellable, callback, callback_data); + g_dbus_proxy_call (priv->proxy, "GetResults", g_variant_new ("(s)", device_id), G_DBUS_CALL_FLAGS_NONE, - -1, - cancellable, - fwupd_client_proxy_call_cb, - helper); - g_main_loop_run (helper->loop); - if (!helper->ret) { - g_propagate_error (error, helper->error); - helper->error = NULL; - return NULL; - } - return fwupd_device_from_variant (helper->val); + -1, cancellable, + fwupd_client_get_results_cb, + g_steal_pointer (&task)); } -#ifdef HAVE_GIO_UNIX -static void -fwupd_client_send_message_cb (GObject *source_object, GAsyncResult *res, gpointer user_data) +/** + * fwupd_client_get_results_finish: + * @self: A #FwupdClient + * @res: the #GAsyncResult + * @error: the #GError, or %NULL + * + * Gets the result of fwupd_client_get_results_async(). + * + * Returns: (transfer full): a #FwupdDevice, or %NULL for failure + * + * Since: 1.5.0 + **/ +FwupdDevice * +fwupd_client_get_results_finish (FwupdClient *self, GAsyncResult *res, GError **error) { - FwupdClientHelper *helper = (FwupdClientHelper *) user_data; - GDBusConnection *con = G_DBUS_CONNECTION (source_object); - helper->message = g_dbus_connection_send_message_with_reply_finish (con, res, - &helper->error); - if (helper->message && - !g_dbus_message_to_gerror (helper->message, &helper->error)) { - helper->ret = TRUE; - helper->val = g_dbus_message_get_body (helper->message); - if (helper->val != NULL) - g_variant_ref (helper->val); - } - if (helper->error != NULL) - fwupd_client_fixup_dbus_error (helper->error); - g_main_loop_quit (helper->loop); + g_return_val_if_fail (FWUPD_IS_CLIENT (self), NULL); + g_return_val_if_fail (g_task_is_valid (res, self), NULL); + g_return_val_if_fail (error == NULL || *error == NULL, NULL); + return g_task_propagate_pointer (G_TASK(res), error); } -#endif #ifdef HAVE_GIO_UNIX -static gboolean -fwupd_client_install_fd (FwupdClient *self, - const gchar *device_id, - GUnixInputStream *istr, - const gchar *filename_hint, - FwupdInstallFlags install_flags, - GCancellable *cancellable, - GError **error) + +static void +fwupd_client_install_stream_cb (GObject *source, GAsyncResult *res, gpointer user_data) +{ + g_autoptr(GDBusMessage) msg = NULL; + g_autoptr(GError) error = NULL; + g_autoptr(GTask) task = G_TASK (user_data); + + msg = g_dbus_connection_send_message_with_reply_finish (G_DBUS_CONNECTION (source), + res, &error); + if (msg == NULL) { + fwupd_client_fixup_dbus_error (error); + g_task_return_error (task, g_steal_pointer (&error)); + return; + } + if (g_dbus_message_to_gerror (msg, &error)) { + fwupd_client_fixup_dbus_error (error); + g_task_return_error (task, g_steal_pointer (&error)); + return; + } + + /* success */ + g_task_return_boolean (task, TRUE); +} + +void +fwupd_client_install_stream_async (FwupdClient *self, + const gchar *device_id, + GUnixInputStream *istr, + const gchar *filename_hint, + FwupdInstallFlags install_flags, + GCancellable *cancellable, + GAsyncReadyCallback callback, + gpointer callback_data) { FwupdClientPrivate *priv = GET_PRIVATE (self); - GVariant *body; GVariantBuilder builder; - gint retval; - g_autoptr(FwupdClientHelper) helper = NULL; g_autoptr(GDBusMessage) request = NULL; g_autoptr(GUnixFDList) fd_list = NULL; + g_autoptr(GTask) task = g_task_new (self, cancellable, callback, callback_data); /* set options */ g_variant_builder_init (&builder, G_VARIANT_TYPE_VARDICT); @@ -1309,8 +1890,7 @@ fwupd_client_install_fd (FwupdClient *self, /* set out of band file descriptor */ fd_list = g_unix_fd_list_new (); - retval = g_unix_fd_list_append (fd_list, g_unix_input_stream_get_fd (istr), NULL); - g_assert (retval != -1); + g_unix_fd_list_append (fd_list, g_unix_input_stream_get_fd (istr), NULL); request = g_dbus_message_new_method_call (FWUPD_DBUS_SERVICE, FWUPD_DBUS_PATH, FWUPD_DBUS_INTERFACE, @@ -1318,314 +1898,527 @@ fwupd_client_install_fd (FwupdClient *self, g_dbus_message_set_unix_fd_list (request, fd_list); /* call into daemon */ - helper = fwupd_client_helper_new (); - body = g_variant_new ("(sha{sv})", device_id, g_unix_input_stream_get_fd (istr), &builder); - g_dbus_message_set_body (request, body); + g_dbus_message_set_body (request, g_variant_new ("(sha{sv})", + device_id, + g_unix_input_stream_get_fd (istr), + &builder)); g_dbus_connection_send_message_with_reply (priv->conn, request, G_DBUS_SEND_MESSAGE_FLAGS_NONE, G_MAXINT, NULL, cancellable, - fwupd_client_send_message_cb, - helper); - g_main_loop_run (helper->loop); - if (!helper->ret) { - g_propagate_error (error, helper->error); - helper->error = NULL; - return FALSE; - } - return TRUE; + fwupd_client_install_stream_cb, + g_steal_pointer (&task)); } #endif /** - * fwupd_client_install_bytes: + * fwupd_client_install_bytes_async: * @self: A #FwupdClient * @device_id: the device ID * @bytes: #GBytes * @install_flags: the #FwupdInstallFlags, e.g. %FWUPD_INSTALL_FLAG_ALLOW_REINSTALL * @cancellable: the #GCancellable, or %NULL - * @error: the #GError, or %NULL + * @callback: the function to run on completion + * @callback_data: the data to pass to @callback * * Install firmware onto a specific device. * - * Returns: %TRUE for success - * - * Since: 1.4.5 + * Since: 1.5.0 **/ -gboolean -fwupd_client_install_bytes (FwupdClient *self, - const gchar *device_id, - GBytes *bytes, - FwupdInstallFlags install_flags, - GCancellable *cancellable, - GError **error) +void +fwupd_client_install_bytes_async (FwupdClient *self, + const gchar *device_id, + GBytes *bytes, + FwupdInstallFlags install_flags, + GCancellable *cancellable, + GAsyncReadyCallback callback, + gpointer callback_data) { #ifdef HAVE_GIO_UNIX + FwupdClientPrivate *priv = GET_PRIVATE (self); + g_autoptr(GError) error = NULL; g_autoptr(GUnixInputStream) istr = NULL; - g_return_val_if_fail (FWUPD_IS_CLIENT (self), FALSE); - g_return_val_if_fail (device_id != NULL, FALSE); - g_return_val_if_fail (bytes != NULL, FALSE); - g_return_val_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable), FALSE); - g_return_val_if_fail (error == NULL || *error == NULL, FALSE); + g_return_if_fail (FWUPD_IS_CLIENT (self)); + g_return_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable)); + g_return_if_fail (priv->proxy != NULL); - /* connect */ - if (!fwupd_client_connect (self, cancellable, error)) - return FALSE; + /* move to a thread if this ever takes more than a few ms */ + istr = fwupd_unix_input_stream_from_bytes (bytes, &error); + if (istr == NULL) { + g_autoptr(GTask) task = g_task_new (self, cancellable, callback, callback_data); + g_task_return_error (task, g_steal_pointer (&error)); + return; + } - istr = fwupd_unix_input_stream_from_bytes (bytes, error); - if (istr == NULL) - return FALSE; - return fwupd_client_install_fd (self, device_id, istr, NULL, - install_flags, cancellable, error); + /* call into daemon */ + fwupd_client_install_stream_async (self, device_id, istr, NULL, + install_flags, cancellable, + callback, callback_data); #else - g_set_error_literal (error, - FWUPD_ERROR, - FWUPD_ERROR_NOT_SUPPORTED, - "Not supported as is unavailable"); - return FALSE; + g_autoptr(GTask) task = g_task_new (self, cancellable, callback, callback_data); + g_task_return_new_error (task, + FWUPD_ERROR, + FWUPD_ERROR_NOT_SUPPORTED, + "Not supported as is unavailable"); #endif } /** - * fwupd_client_install: + * fwupd_client_install_bytes_finish: + * @self: A #FwupdClient + * @res: the #GAsyncResult + * @error: the #GError, or %NULL + * + * Gets the result of fwupd_client_install_bytes_async(). + * + * Returns: %TRUE for success + * + * Since: 1.5.0 + **/ +gboolean +fwupd_client_install_bytes_finish (FwupdClient *self, GAsyncResult *res, GError **error) +{ + g_return_val_if_fail (FWUPD_IS_CLIENT (self), FALSE); + g_return_val_if_fail (g_task_is_valid (res, self), FALSE); + g_return_val_if_fail (error == NULL || *error == NULL, FALSE); + return g_task_propagate_boolean (G_TASK(res), error); +} + +/** + * fwupd_client_install_async: * @self: A #FwupdClient * @device_id: the device ID * @filename: the filename to install * @install_flags: the #FwupdInstallFlags, e.g. %FWUPD_INSTALL_FLAG_ALLOW_REINSTALL * @cancellable: the #GCancellable, or %NULL - * @error: the #GError, or %NULL + * @callback: the function to run on completion + * @callback_data: the data to pass to @callback * - * Install a file onto a specific device. + * Install firmware onto a specific device. * - * Returns: %TRUE for success - * - * Since: 0.7.0 + * Since: 1.5.0 **/ -gboolean -fwupd_client_install (FwupdClient *self, - const gchar *device_id, - const gchar *filename, - FwupdInstallFlags install_flags, - GCancellable *cancellable, - GError **error) +void +fwupd_client_install_async (FwupdClient *self, + const gchar *device_id, + const gchar *filename, + FwupdInstallFlags install_flags, + GCancellable *cancellable, + GAsyncReadyCallback callback, + gpointer callback_data) { #ifdef HAVE_GIO_UNIX + FwupdClientPrivate *priv = GET_PRIVATE (self); + g_autoptr(GError) error = NULL; g_autoptr(GUnixInputStream) istr = NULL; - g_return_val_if_fail (FWUPD_IS_CLIENT (self), FALSE); - g_return_val_if_fail (device_id != NULL, FALSE); - g_return_val_if_fail (filename != NULL, FALSE); - g_return_val_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable), FALSE); - g_return_val_if_fail (error == NULL || *error == NULL, FALSE); + g_return_if_fail (FWUPD_IS_CLIENT (self)); + g_return_if_fail (device_id != NULL); + g_return_if_fail (filename != NULL); + g_return_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable)); + g_return_if_fail (priv->proxy != NULL); - /* connect */ - if (!fwupd_client_connect (self, cancellable, error)) - return FALSE; + /* move to a thread if this ever takes more than a few ms */ + istr = fwupd_unix_input_stream_from_fn (filename, &error); + if (istr == NULL) { + g_autoptr(GTask) task = g_task_new (self, cancellable, callback, callback_data); + g_task_return_error (task, g_steal_pointer (&error)); + return; + } - istr = fwupd_unix_input_stream_from_fn (filename, error); - if (istr == NULL) - return FALSE; - return fwupd_client_install_fd (self, device_id, istr, filename, - install_flags, cancellable, error); + /* call into daemon */ + fwupd_client_install_stream_async (self, device_id, istr, NULL, + install_flags, cancellable, + callback, callback_data); #else - g_set_error_literal (error, - FWUPD_ERROR, - FWUPD_ERROR_NOT_SUPPORTED, - "Not supported as is unavailable"); - return FALSE; + g_autoptr(GTask) task = g_task_new (self, cancellable, callback, callback_data); + g_task_return_new_error (task, + FWUPD_ERROR, + FWUPD_ERROR_NOT_SUPPORTED, + "Not supported as is unavailable"); #endif } /** - * fwupd_client_install_release: + * fwupd_client_install_finish: + * @self: A #FwupdClient + * @res: the #GAsyncResult + * @error: the #GError, or %NULL + * + * Gets the result of fwupd_client_install_async(). + * + * Returns: %TRUE for success + * + * Since: 1.5.0 + **/ +gboolean +fwupd_client_install_finish (FwupdClient *self, GAsyncResult *res, GError **error) +{ + g_return_val_if_fail (FWUPD_IS_CLIENT (self), FALSE); + g_return_val_if_fail (g_task_is_valid (res, self), FALSE); + g_return_val_if_fail (error == NULL || *error == NULL, FALSE); + return g_task_propagate_boolean (G_TASK(res), error); +} + +typedef struct { + FwupdDevice *device; + FwupdRelease *release; + FwupdInstallFlags install_flags; +} FwupdClientInstallReleaseData; + +static void +fwupd_client_install_release_data_free (FwupdClientInstallReleaseData *data) +{ + g_object_unref (data->device); + g_object_unref (data->release); + g_free (data); +} + +static void +fwupd_client_install_release_cb (GObject *source, GAsyncResult *res, gpointer user_data) +{ + g_autoptr(GError) error = NULL; + g_autoptr(GTask) task = G_TASK (user_data); + + if (!fwupd_client_install_release_finish (FWUPD_CLIENT (source), res, &error)) { + g_task_return_error (task, g_steal_pointer (&error)); + return; + } + + /* success */ + g_task_return_boolean (task, TRUE); +} + +static void +fwupd_client_install_release_bytes_cb (GObject *source, GAsyncResult *res, gpointer user_data) +{ + g_autoptr(GError) error = NULL; + g_autoptr(GTask) task = G_TASK (user_data); + + if (!fwupd_client_install_bytes_finish (FWUPD_CLIENT (source), res, &error)) { + g_task_return_error (task, g_steal_pointer (&error)); + return; + } + + /* success */ + g_task_return_boolean (task, TRUE); +} + +static void +fwupd_client_install_release_download_cb (GObject *source, GAsyncResult *res, gpointer user_data) +{ + g_autoptr(GBytes) blob = NULL; + g_autoptr(GError) error = NULL; + g_autoptr(GTask) task = G_TASK (user_data); + FwupdClientInstallReleaseData *data = g_task_get_task_data (task); + GChecksumType checksum_type; + GCancellable *cancellable = g_task_get_cancellable (task); + const gchar *checksum_expected; + g_autofree gchar *checksum_actual = NULL; + + blob = fwupd_client_download_bytes_finish (FWUPD_CLIENT (source), res, &error); + if (blob == NULL) { + g_task_return_error (task, g_steal_pointer (&error)); + return; + } + + /* verify checksum */ + checksum_expected = fwupd_checksum_get_best (fwupd_release_get_checksums (data->release)); + checksum_type = fwupd_checksum_guess_kind (checksum_expected); + checksum_actual = g_compute_checksum_for_bytes (checksum_type, blob); + if (g_strcmp0 (checksum_expected, checksum_actual) != 0) { + g_task_return_new_error (task, + FWUPD_ERROR, + FWUPD_ERROR_INVALID_FILE, + "checksum invalid, expected %s got %s", + checksum_expected, checksum_actual); + return; + } + + /* if the device specifies ONLY_OFFLINE automatically set this flag */ + if (fwupd_device_has_flag (data->device, FWUPD_DEVICE_FLAG_ONLY_OFFLINE)) + data->install_flags |= FWUPD_INSTALL_FLAG_OFFLINE; + fwupd_client_install_bytes_async (FWUPD_CLIENT (source), + fwupd_device_get_id (data->device), blob, + data->install_flags, cancellable, + fwupd_client_install_release_bytes_cb, + g_steal_pointer (&task)); +} + +static void +fwupd_client_install_release_remote_cb (GObject *source, GAsyncResult *res, gpointer user_data) +{ + g_autofree gchar *fn = NULL; + g_autofree gchar *uri_str = NULL; + g_autoptr(FwupdRemote) remote = NULL; + g_autoptr(GError) error = NULL; + g_autoptr(GTask) task = G_TASK (user_data); + g_autoptr(SoupURI) uri = NULL; + FwupdClientInstallReleaseData *data = g_task_get_task_data (task); + GCancellable *cancellable = g_task_get_cancellable (task); + + /* if a remote-id was specified, the remote has to exist */ + remote = fwupd_client_get_remote_by_id_finish (FWUPD_CLIENT (source), res, &error); + if (remote == NULL) { + g_task_return_error (task, g_steal_pointer (&error)); + return; + } + + /* local and directory remotes may have the firmware already */ + uri = soup_uri_new (fwupd_release_get_uri (data->release)); + if (fwupd_remote_get_kind (remote) == FWUPD_REMOTE_KIND_LOCAL && uri == NULL) { + const gchar *fn_cache = fwupd_remote_get_filename_cache (remote); + g_autofree gchar *path = g_path_get_dirname (fn_cache); + fn = g_build_filename (path, fwupd_release_get_uri (data->release), NULL); + } else if (fwupd_remote_get_kind (remote) == FWUPD_REMOTE_KIND_DIRECTORY) { + fn = g_strdup (fwupd_release_get_uri (data->release) + 7); + } + + /* install with flags chosen by the user */ + if (fn != NULL) { + fwupd_client_install_async (FWUPD_CLIENT (source), + fwupd_device_get_id (data->device), + fn, data->install_flags, + cancellable, + fwupd_client_install_release_cb, + g_steal_pointer (&task)); + return; + } + + /* remote file */ + uri_str = fwupd_remote_build_firmware_uri (remote, + fwupd_release_get_uri (data->release), + &error); + if (uri_str == NULL) { + g_task_return_error (task, g_steal_pointer (&error)); + return; + } + + /* download file */ + fwupd_client_download_bytes_async (FWUPD_CLIENT (source), uri_str, + FWUPD_CLIENT_DOWNLOAD_FLAG_NONE, + cancellable, + fwupd_client_install_release_download_cb, + g_steal_pointer (&task)); +} + +/** + * fwupd_client_install_release_async: * @self: A #FwupdClient * @device: A #FwupdDevice * @release: A #FwupdRelease * @install_flags: the #FwupdInstallFlags, e.g. %FWUPD_INSTALL_FLAG_ALLOW_REINSTALL - * @cancellable: A #GCancellable, or %NULL - * @error: A #GError, or %NULL + * @cancellable: the #GCancellable, or %NULL + * @callback: the function to run on completion + * @callback_data: the data to pass to @callback * * Installs a new release on a device, downloading the firmware if required. * - * Returns: %TRUE for success - * - * Since: 1.4.5 + * Since: 1.5.0 **/ -gboolean -fwupd_client_install_release (FwupdClient *self, - FwupdDevice *device, - FwupdRelease *release, - FwupdInstallFlags install_flags, - GCancellable *cancellable, - GError **error) +void +fwupd_client_install_release_async (FwupdClient *self, + FwupdDevice *device, + FwupdRelease *release, + FwupdInstallFlags install_flags, + GCancellable *cancellable, + GAsyncReadyCallback callback, + gpointer callback_data) { - GChecksumType checksum_type; - const gchar *checksum_expected; + FwupdClientPrivate *priv = GET_PRIVATE (self); + g_autoptr(GError) error = NULL; + g_autoptr(GTask) task = NULL; + FwupdClientInstallReleaseData *data; const gchar *remote_id; - const gchar *uri_tmp; - g_autofree gchar *checksum_actual = NULL; - g_autofree gchar *uri_str = NULL; - g_autoptr(GBytes) blob = NULL; - g_autoptr(SoupURI) uri = NULL; + + g_return_if_fail (FWUPD_IS_CLIENT (self)); + g_return_if_fail (FWUPD_IS_DEVICE (device)); + g_return_if_fail (FWUPD_IS_RELEASE (release)); + g_return_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable)); + g_return_if_fail (priv->proxy != NULL); + + /* call into daemon */ + task = g_task_new (self, cancellable, callback, callback_data); + data = g_new0 (FwupdClientInstallReleaseData, 1); + data->device = g_object_ref (device); + data->release = g_object_ref (release); + data->install_flags = install_flags; + g_task_set_task_data (task, data, (GDestroyNotify) fwupd_client_install_release_data_free); /* work out what remote-specific URI fields this should use */ - uri_tmp = fwupd_release_get_uri (release); - uri = soup_uri_new (uri_tmp); remote_id = fwupd_release_get_remote_id (release); - if (remote_id != NULL) { - g_autoptr(FwupdRemote) remote = NULL; - g_autofree gchar *fn = NULL; - - /* if a remote-id was specified, the remote has to exist */ - remote = fwupd_client_get_remote_by_id (self, remote_id, cancellable, error); - if (remote == NULL) - return FALSE; - - /* local and directory remotes may have the firmware already */ - if (fwupd_remote_get_kind (remote) == FWUPD_REMOTE_KIND_LOCAL && uri == NULL) { - const gchar *fn_cache = fwupd_remote_get_filename_cache (remote); - g_autofree gchar *path = g_path_get_dirname (fn_cache); - - fn = g_build_filename (path, uri_tmp, NULL); - } else if (fwupd_remote_get_kind (remote) == FWUPD_REMOTE_KIND_DIRECTORY) { - fn = g_strdup (uri_tmp + 7); - } - - /* install with flags chosen by the user */ - if (fn != NULL) { - return fwupd_client_install (self, fwupd_device_get_id (device), - fn, install_flags, cancellable, error); - } - - /* remote file */ - uri_str = fwupd_remote_build_firmware_uri (remote, uri_tmp, error); - if (uri_str == NULL) - return FALSE; - } else { - uri_str = g_strdup (uri_tmp); + if (remote_id == NULL) { + fwupd_client_download_bytes_async (self, + fwupd_release_get_uri (release), + FWUPD_CLIENT_DOWNLOAD_FLAG_NONE, + cancellable, + fwupd_client_install_release_download_cb, + g_steal_pointer (&task)); + return; } - /* download file */ - blob = fwupd_client_download_bytes (self, uri_str, - FWUPD_CLIENT_DOWNLOAD_FLAG_NONE, - cancellable, error); - if (blob == NULL) - return FALSE; - - /* verify checksum */ - checksum_expected = fwupd_checksum_get_best (fwupd_release_get_checksums (release)); - checksum_type = fwupd_checksum_guess_kind (checksum_expected); - checksum_actual = g_compute_checksum_for_bytes (checksum_type, blob); - if (g_strcmp0 (checksum_expected, checksum_actual) != 0) { - g_set_error (error, - FWUPD_ERROR, - FWUPD_ERROR_INVALID_FILE, - "Checksum invalid, expected %s got %s", - checksum_expected, checksum_actual); - return FALSE; - } - - /* if the device specifies ONLY_OFFLINE automatically set this flag */ - if (fwupd_device_has_flag (device, FWUPD_DEVICE_FLAG_ONLY_OFFLINE)) - install_flags |= FWUPD_INSTALL_FLAG_OFFLINE; - return fwupd_client_install_bytes (self, - fwupd_device_get_id (device), blob, - install_flags, NULL, error); + /* if a remote-id was specified, the remote has to exist */ + fwupd_client_get_remote_by_id_async (self, remote_id, cancellable, + fwupd_client_install_release_remote_cb, + g_steal_pointer (&task)); } /** - * fwupd_client_get_details: + * fwupd_client_install_release_finish: * @self: A #FwupdClient - * @filename: the firmware filename, e.g. `firmware.cab` - * @cancellable: the #GCancellable, or %NULL + * @res: the #GAsyncResult * @error: the #GError, or %NULL * - * Gets details about a specific firmware file. + * Gets the result of fwupd_client_install_release_async(). * - * Returns: (transfer container) (element-type FwupdDevice): an array of results + * Returns: %TRUE for success * - * Since: 1.0.0 + * Since: 1.5.0 **/ -GPtrArray * -fwupd_client_get_details (FwupdClient *self, const gchar *filename, - GCancellable *cancellable, GError **error) +gboolean +fwupd_client_install_release_finish (FwupdClient *self, GAsyncResult *res, GError **error) { + g_return_val_if_fail (FWUPD_IS_CLIENT (self), FALSE); + g_return_val_if_fail (g_task_is_valid (res, self), FALSE); + g_return_val_if_fail (error == NULL || *error == NULL, FALSE); + return g_task_propagate_boolean (G_TASK(res), error); +} + #ifdef HAVE_GIO_UNIX + +static void +fwupd_client_get_details_stream_cb (GObject *source, GAsyncResult *res, gpointer user_data) +{ + g_autoptr(GDBusMessage) msg = NULL; + g_autoptr(GError) error = NULL; + g_autoptr(GTask) task = G_TASK (user_data); + + msg = g_dbus_connection_send_message_with_reply_finish (G_DBUS_CONNECTION (source), + res, &error); + if (msg == NULL) { + fwupd_client_fixup_dbus_error (error); + g_task_return_error (task, g_steal_pointer (&error)); + return; + } + if (g_dbus_message_to_gerror (msg, &error)) { + fwupd_client_fixup_dbus_error (error); + g_task_return_error (task, g_steal_pointer (&error)); + return; + } + + /* success */ + g_task_return_pointer (task, + fwupd_device_array_from_variant (g_dbus_message_get_body (msg)), + (GDestroyNotify) g_ptr_array_unref); +} + +void +fwupd_client_get_details_stream_async (FwupdClient *self, + GUnixInputStream *istr, + GCancellable *cancellable, + GAsyncReadyCallback callback, + gpointer callback_data) +{ FwupdClientPrivate *priv = GET_PRIVATE (self); - GVariant *body; - gint fd; - gint retval; - g_autoptr(FwupdClientHelper) helper = NULL; + gint fd = g_unix_input_stream_get_fd (istr); g_autoptr(GDBusMessage) request = NULL; g_autoptr(GUnixFDList) fd_list = NULL; - - g_return_val_if_fail (FWUPD_IS_CLIENT (self), NULL); - g_return_val_if_fail (filename != NULL, NULL); - g_return_val_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable), NULL); - g_return_val_if_fail (error == NULL || *error == NULL, NULL); - - /* connect */ - if (!fwupd_client_connect (self, cancellable, error)) - return NULL; - - /* open file */ - fd = open (filename, O_RDONLY); - if (fd < 0) { - g_set_error (error, - FWUPD_ERROR, - FWUPD_ERROR_INVALID_FILE, - "failed to open %s", - filename); - return NULL; - } + g_autoptr(GTask) task = g_task_new (self, cancellable, callback, callback_data); /* set out of band file descriptor */ fd_list = g_unix_fd_list_new (); - retval = g_unix_fd_list_append (fd_list, fd, NULL); - g_assert (retval != -1); + g_unix_fd_list_append (fd_list, fd, NULL); request = g_dbus_message_new_method_call (FWUPD_DBUS_SERVICE, FWUPD_DBUS_PATH, FWUPD_DBUS_INTERFACE, "GetDetails"); g_dbus_message_set_unix_fd_list (request, fd_list); - /* g_unix_fd_list_append did a dup() already */ - close (fd); - /* call into daemon */ - helper = fwupd_client_helper_new (); - body = g_variant_new ("(h)", fd); - g_dbus_message_set_body (request, body); - + g_dbus_message_set_body (request, g_variant_new ("(h)", fd)); g_dbus_connection_send_message_with_reply (priv->conn, request, G_DBUS_SEND_MESSAGE_FLAGS_NONE, - -1, + G_MAXINT, NULL, cancellable, - fwupd_client_send_message_cb, - helper); - g_main_loop_run (helper->loop); - if (!helper->ret) { - g_propagate_error (error, helper->error); - helper->error = NULL; - return NULL; + fwupd_client_get_details_stream_cb, + g_steal_pointer (&task)); +} +#endif + +/** + * fwupd_client_get_details_bytes_async: + * @self: A #FwupdClient + * @bytes: a #GBytes for the firmware, e.g. `firmware.cab` + * @cancellable: the #GCancellable, or %NULL + * @callback: the function to run on completion + * @callback_data: the data to pass to @callback + * + * Gets details about a specific firmware file. + * + * Since: 1.5.0 + **/ +void +fwupd_client_get_details_bytes_async (FwupdClient *self, + GBytes *bytes, + GCancellable *cancellable, + GAsyncReadyCallback callback, + gpointer callback_data) +{ +#ifdef HAVE_GIO_UNIX + FwupdClientPrivate *priv = GET_PRIVATE (self); + g_autoptr(GError) error = NULL; + g_autoptr(GUnixInputStream) istr = NULL; + + g_return_if_fail (FWUPD_IS_CLIENT (self)); + g_return_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable)); + g_return_if_fail (priv->proxy != NULL); + + /* move to a thread if this ever takes more than a few ms */ + istr = fwupd_unix_input_stream_from_bytes (bytes, &error); + if (istr == NULL) { + g_autoptr(GTask) task = g_task_new (self, cancellable, callback, callback_data); + g_task_return_error (task, g_steal_pointer (&error)); + return; } - /* return results */ - return fwupd_device_array_from_variant (helper->val); + /* call into daemon */ + fwupd_client_get_details_stream_async (self, istr, cancellable, + callback, callback_data); #else - g_set_error_literal (error, - FWUPD_ERROR, - FWUPD_ERROR_NOT_SUPPORTED, - "Not supported as is unavailable"); - return NULL; + g_autoptr(GTask) task = g_task_new (self, cancellable, callback, callback_data); + g_task_return_new_error (task, + FWUPD_ERROR, + FWUPD_ERROR_NOT_SUPPORTED, + "Not supported as is unavailable"); #endif } +/** + * fwupd_client_get_details_bytes_finish: + * @self: A #FwupdClient + * @res: the #GAsyncResult + * @error: the #GError, or %NULL + * + * Gets the result of fwupd_client_get_details_bytes_async(). + * + * Returns: (transfer container) (element-type FwupdDevice): an array of results + * + * Since: 1.5.0 + **/ +GPtrArray * +fwupd_client_get_details_bytes_finish (FwupdClient *self, GAsyncResult *res, GError **error) +{ + g_return_val_if_fail (FWUPD_IS_CLIENT (self), NULL); + g_return_val_if_fail (g_task_is_valid (res, self), NULL); + g_return_val_if_fail (error == NULL || *error == NULL, NULL); + return g_task_propagate_pointer (G_TASK(res), error); +} + /** * fwupd_client_get_percentage: * @self: A #FwupdClient @@ -1752,7 +2545,6 @@ fwupd_client_get_tainted (FwupdClient *self) return priv->tainted; } - /** * fwupd_client_get_daemon_interactive: * @self: A #FwupdClient @@ -1772,24 +2564,49 @@ fwupd_client_get_daemon_interactive (FwupdClient *self) } #ifdef HAVE_GIO_UNIX -static gboolean -fwupd_client_update_metadata_fds (FwupdClient *self, - const gchar *remote_id, - GUnixInputStream *metadata, - GUnixInputStream *signature, - GCancellable *cancellable, - GError **error) + +static void +fwupd_client_update_metadata_stream_cb (GObject *source, GAsyncResult *res, gpointer user_data) +{ + g_autoptr(GDBusMessage) msg = NULL; + g_autoptr(GError) error = NULL; + g_autoptr(GTask) task = G_TASK (user_data); + + msg = g_dbus_connection_send_message_with_reply_finish (G_DBUS_CONNECTION (source), + res, &error); + if (msg == NULL) { + fwupd_client_fixup_dbus_error (error); + g_task_return_error (task, g_steal_pointer (&error)); + return; + } + if (g_dbus_message_to_gerror (msg, &error)) { + fwupd_client_fixup_dbus_error (error); + g_task_return_error (task, g_steal_pointer (&error)); + return; + } + + /* success */ + g_task_return_boolean (task, TRUE); +} + +void +fwupd_client_update_metadata_stream_async (FwupdClient *self, + const gchar *remote_id, + GUnixInputStream *istr, + GUnixInputStream *istr_sig, + GCancellable *cancellable, + GAsyncReadyCallback callback, + gpointer callback_data) { FwupdClientPrivate *priv = GET_PRIVATE (self); - GVariant *body; - g_autoptr(FwupdClientHelper) helper = NULL; g_autoptr(GDBusMessage) request = NULL; g_autoptr(GUnixFDList) fd_list = NULL; + g_autoptr(GTask) task = g_task_new (self, cancellable, callback, callback_data); /* set out of band file descriptor */ fd_list = g_unix_fd_list_new (); - g_unix_fd_list_append (fd_list, g_unix_input_stream_get_fd (metadata), NULL); - g_unix_fd_list_append (fd_list, g_unix_input_stream_get_fd (signature), NULL); + g_unix_fd_list_append (fd_list, g_unix_input_stream_get_fd (istr), NULL); + g_unix_fd_list_append (fd_list, g_unix_input_stream_get_fd (istr_sig), NULL); request = g_dbus_message_new_method_call (FWUPD_DBUS_SERVICE, FWUPD_DBUS_PATH, FWUPD_DBUS_INTERFACE, @@ -1797,101 +2614,30 @@ fwupd_client_update_metadata_fds (FwupdClient *self, g_dbus_message_set_unix_fd_list (request, fd_list); /* call into daemon */ - body = g_variant_new ("(shh)", - remote_id, - g_unix_input_stream_get_fd (metadata), - g_unix_input_stream_get_fd (signature)); - g_dbus_message_set_body (request, body); - helper = fwupd_client_helper_new (); + g_dbus_message_set_body (request, g_variant_new ("(shh)", + remote_id, + g_unix_input_stream_get_fd (istr), + g_unix_input_stream_get_fd (istr_sig))); g_dbus_connection_send_message_with_reply (priv->conn, request, G_DBUS_SEND_MESSAGE_FLAGS_NONE, - -1, + G_MAXINT, NULL, cancellable, - fwupd_client_send_message_cb, - helper); - g_main_loop_run (helper->loop); - if (!helper->ret) { - g_propagate_error (error, helper->error); - helper->error = NULL; - return FALSE; - } - return TRUE; + fwupd_client_update_metadata_stream_cb, + g_steal_pointer (&task)); } - #endif /** - * fwupd_client_update_metadata: - * @self: A #FwupdClient - * @remote_id: the remote ID, e.g. `lvfs-testing` - * @metadata_fn: the XML metadata filename - * @signature_fn: the GPG signature file - * @cancellable: the #GCancellable, or %NULL - * @error: the #GError, or %NULL - * - * Updates the metadata. This allows a session process to download the metadata - * and metadata signing file to be passed into the daemon to be checked and - * parsed. - * - * The @remote_id allows the firmware to be tagged so that the remote can be - * matched when the firmware is downloaded. - * - * Returns: %TRUE for success - * - * Since: 1.0.0 - **/ -gboolean -fwupd_client_update_metadata (FwupdClient *self, - const gchar *remote_id, - const gchar *metadata_fn, - const gchar *signature_fn, - GCancellable *cancellable, - GError **error) -{ -#ifdef HAVE_GIO_UNIX - GUnixInputStream *istr; - GUnixInputStream *istr_sig; - - g_return_val_if_fail (FWUPD_IS_CLIENT (self), FALSE); - g_return_val_if_fail (remote_id != NULL, FALSE); - g_return_val_if_fail (metadata_fn != NULL, FALSE); - g_return_val_if_fail (signature_fn != NULL, FALSE); - g_return_val_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable), FALSE); - g_return_val_if_fail (error == NULL || *error == NULL, FALSE); - - /* connect */ - if (!fwupd_client_connect (self, cancellable, error)) - return FALSE; - - /* open files */ - istr = fwupd_unix_input_stream_from_fn (metadata_fn, error); - if (istr == NULL) - return FALSE; - istr_sig = fwupd_unix_input_stream_from_fn (signature_fn, error); - if (istr_sig == NULL) - return FALSE; - return fwupd_client_update_metadata_fds (self, remote_id, - istr, istr_sig, - cancellable, error); -#else - g_set_error_literal (error, - FWUPD_ERROR, - FWUPD_ERROR_NOT_SUPPORTED, - "Not supported as is unavailable"); - return FALSE; -#endif -} - -/** - * fwupd_client_update_metadata_bytes: + * fwupd_client_update_metadata_bytes_async: * @self: A #FwupdClient * @remote_id: remote ID, e.g. `lvfs-testing` * @metadata: XML metadata data * @signature: signature data * @cancellable: #GCancellable, or %NULL - * @error: the #GError, or %NULL + * @callback: the function to run on completion + * @callback_data: the data to pass to @callback * * Updates the metadata. This allows a session process to download the metadata * and metadata signing file to be passed into the daemon to be checked and @@ -1900,411 +2646,784 @@ fwupd_client_update_metadata (FwupdClient *self, * The @remote_id allows the firmware to be tagged so that the remote can be * matched when the firmware is downloaded. * - * Returns: %TRUE for success - * - * Since: 1.4.5 + * Since: 1.5.0 **/ -gboolean -fwupd_client_update_metadata_bytes (FwupdClient *self, - const gchar *remote_id, - GBytes *metadata, - GBytes *signature, - GCancellable *cancellable, - GError **error) +void +fwupd_client_update_metadata_bytes_async (FwupdClient *self, + const gchar *remote_id, + GBytes *metadata, + GBytes *signature, + GCancellable *cancellable, + GAsyncReadyCallback callback, + gpointer callback_data) { #ifdef HAVE_GIO_UNIX - GUnixInputStream *istr; - GUnixInputStream *istr_sig; + FwupdClientPrivate *priv = GET_PRIVATE (self); + g_autoptr(GError) error = NULL; + g_autoptr(GUnixInputStream) istr = NULL; + g_autoptr(GUnixInputStream) istr_sig = NULL; - g_return_val_if_fail (FWUPD_IS_CLIENT (self), FALSE); - g_return_val_if_fail (remote_id != NULL, FALSE); - g_return_val_if_fail (metadata != NULL, FALSE); - g_return_val_if_fail (signature != NULL, FALSE); - g_return_val_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable), FALSE); - g_return_val_if_fail (error == NULL || *error == NULL, FALSE); + g_return_if_fail (FWUPD_IS_CLIENT (self)); + g_return_if_fail (remote_id != NULL); + g_return_if_fail (metadata != NULL); + g_return_if_fail (signature != NULL); + g_return_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable)); + g_return_if_fail (priv->proxy != NULL); - /* convert bytes to a readable fd */ - istr = fwupd_unix_input_stream_from_bytes (metadata, error); - if (istr == NULL) - return FALSE; - istr_sig = fwupd_unix_input_stream_from_bytes (signature, error); - if (istr_sig == NULL) - return FALSE; - return fwupd_client_update_metadata_fds (self, remote_id, - istr, istr_sig, - cancellable, error); + /* move to a thread if this ever takes more than a few ms */ + istr = fwupd_unix_input_stream_from_bytes (metadata, &error); + if (istr == NULL) { + g_autoptr(GTask) task = g_task_new (self, cancellable, callback, callback_data); + g_task_return_error (task, g_steal_pointer (&error)); + return; + } + istr_sig = fwupd_unix_input_stream_from_bytes (signature, &error); + if (istr_sig == NULL) { + g_autoptr(GTask) task = g_task_new (self, cancellable, callback, callback_data); + g_task_return_error (task, g_steal_pointer (&error)); + return; + } + + /* call into daemon */ + fwupd_client_update_metadata_stream_async (self, remote_id, istr, istr_sig, + cancellable, + callback, callback_data); #else - g_set_error_literal (error, - FWUPD_ERROR, - FWUPD_ERROR_NOT_SUPPORTED, - "Not supported as is unavailable"); - return FALSE; + g_autoptr(GTask) task = g_task_new (self, cancellable, callback, callback_data); + g_task_return_new_error (task, + FWUPD_ERROR, + FWUPD_ERROR_NOT_SUPPORTED, + "Not supported as is unavailable"); #endif } /** - * fwupd_client_refresh_remote: + * fwupd_client_update_metadata_bytes_finish: + * @self: A #FwupdClient + * @res: the #GAsyncResult + * @error: the #GError, or %NULL + * + * Gets the result of fwupd_client_update_metadata_bytes_async(). + * + * Returns: %TRUE for success + * + * Since: 1.5.0 + **/ +gboolean +fwupd_client_update_metadata_bytes_finish (FwupdClient *self, GAsyncResult *res, GError **error) +{ + g_return_val_if_fail (FWUPD_IS_CLIENT (self), FALSE); + g_return_val_if_fail (g_task_is_valid (res, self), FALSE); + g_return_val_if_fail (error == NULL || *error == NULL, FALSE); + return g_task_propagate_boolean (G_TASK(res), error); +} + +typedef struct { + FwupdRemote *remote; + GBytes *signature; + GBytes *metadata; +} FwupdClientRefreshRemoteData; + +static void +fwupd_client_refresh_remote_data_free (FwupdClientRefreshRemoteData *data) +{ + if (data->signature != NULL) + g_bytes_unref (data->signature); + if (data->metadata != NULL) + g_bytes_unref (data->metadata); + g_object_unref (data->remote); + g_free (data); +} + +static void +fwupd_client_refresh_remote_update_cb (GObject *source, + GAsyncResult *res, + gpointer user_data) +{ + g_autoptr(GError) error = NULL; + g_autoptr(GTask) task = G_TASK (user_data); + + /* save metadata */ + if (!fwupd_client_update_metadata_bytes_finish (FWUPD_CLIENT (source), res, &error)) { + g_task_return_error (task, g_steal_pointer (&error)); + return; + } + + /* success */ + g_task_return_boolean (task, TRUE); +} + +static void +fwupd_client_refresh_remote_metadata_cb (GObject *source, + GAsyncResult *res, + gpointer user_data) +{ + g_autoptr(GBytes) bytes = NULL; + g_autoptr(GError) error = NULL; + g_autoptr(GTask) task = G_TASK (user_data); + FwupdClientRefreshRemoteData *data = g_task_get_task_data (task); + FwupdClient *self = g_task_get_source_object (task); + GCancellable *cancellable = g_task_get_cancellable (task); + + /* save metadata */ + bytes = fwupd_client_download_bytes_finish (FWUPD_CLIENT (source), res, &error); + if (bytes == NULL) { + g_task_return_error (task, g_steal_pointer (&error)); + return; + } + data->metadata = g_steal_pointer (&bytes); + + /* send all this to fwupd */ + fwupd_client_update_metadata_bytes_async (self, + fwupd_remote_get_id (data->remote), + data->metadata, + data->signature, + cancellable, + fwupd_client_refresh_remote_update_cb, + g_steal_pointer (&task)); +} + +static void +fwupd_client_refresh_remote_signature_cb (GObject *source, + GAsyncResult *res, + gpointer user_data) +{ + g_autoptr(GBytes) bytes = NULL; + g_autoptr(GError) error = NULL; + g_autoptr(GTask) task = G_TASK (user_data); + FwupdClientRefreshRemoteData *data = g_task_get_task_data (task); + FwupdClient *self = g_task_get_source_object (task); + GCancellable *cancellable = g_task_get_cancellable (task); + + /* save signature */ + bytes = fwupd_client_download_bytes_finish (FWUPD_CLIENT (source), res, &error); + if (bytes == NULL) { + g_task_return_error (task, g_steal_pointer (&error)); + return; + } + data->signature = g_steal_pointer (&bytes); + + /* download metadata */ + fwupd_client_download_bytes_async (self, + fwupd_remote_get_metadata_uri (data->remote), + FWUPD_CLIENT_DOWNLOAD_FLAG_NONE, + cancellable, + fwupd_client_refresh_remote_metadata_cb, + g_steal_pointer (&task)); +} + +/** + * fwupd_client_refresh_remote_async: * @self: A #FwupdClient * @remote: A #FwupdRemote - * @cancellable: A #GCancellable, or %NULL - * @error: A #GError, or %NULL + * @cancellable: the #GCancellable, or %NULL + * @callback: the function to run on completion + * @callback_data: the data to pass to @callback * * Refreshes a remote by downloading new metadata. * - * Returns: %TRUE for success - * - * Since: 1.4.5 + * Since: 1.5.0 **/ -gboolean -fwupd_client_refresh_remote (FwupdClient *self, - FwupdRemote *remote, - GCancellable *cancellable, - GError **error) +void +fwupd_client_refresh_remote_async (FwupdClient *self, + FwupdRemote *remote, + GCancellable *cancellable, + GAsyncReadyCallback callback, + gpointer callback_data) { - g_autoptr(GBytes) metadata = NULL; - g_autoptr(GBytes) signature = NULL; + FwupdClientRefreshRemoteData *data; + g_autoptr(GTask) task = NULL; - g_return_val_if_fail (FWUPD_IS_CLIENT (self), FALSE); - g_return_val_if_fail (FWUPD_IS_REMOTE (remote), FALSE); - g_return_val_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable), FALSE); - g_return_val_if_fail (error == NULL || *error == NULL, FALSE); + g_return_if_fail (FWUPD_IS_CLIENT (self)); + g_return_if_fail (FWUPD_IS_REMOTE (remote)); + g_return_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable)); - /* download the signature */ - signature = fwupd_client_download_bytes (self, - fwupd_remote_get_metadata_uri_sig (remote), - FWUPD_CLIENT_DOWNLOAD_FLAG_NONE, - cancellable, error); - if (signature == NULL) - return FALSE; + task = g_task_new (self, cancellable, callback, callback_data); + data = g_new0 (FwupdClientRefreshRemoteData, 1); + data->remote = g_object_ref (remote); + g_task_set_task_data (task, + g_steal_pointer (&data), + (GDestroyNotify) fwupd_client_refresh_remote_data_free); - /* find the download URI of the metadata from the JCat file */ - if (!fwupd_remote_load_signature_bytes (remote, signature, error)) - return FALSE; + /* download signature */ + fwupd_client_download_bytes_async (self, + fwupd_remote_get_metadata_uri_sig (remote), + FWUPD_CLIENT_DOWNLOAD_FLAG_NONE, + cancellable, + fwupd_client_refresh_remote_signature_cb, + g_steal_pointer (&task)); - /* download the metadata */ - metadata = fwupd_client_download_bytes (self, - fwupd_remote_get_metadata_uri (remote), - FWUPD_CLIENT_DOWNLOAD_FLAG_NONE, - cancellable, error); - if (metadata == NULL) - return FALSE; - - /* send all this to fwupd */ - return fwupd_client_update_metadata_bytes (self, - fwupd_remote_get_id (remote), - metadata, signature, - cancellable, error); } /** - * fwupd_client_get_remotes: + * fwupd_client_refresh_remote_finish: + * @self: A #FwupdClient + * @res: the #GAsyncResult + * @error: the #GError, or %NULL + * + * Gets the result of fwupd_client_refresh_remote_async(). + * + * Returns: %TRUE for success + * + * Since: 1.5.0 + **/ +gboolean +fwupd_client_refresh_remote_finish (FwupdClient *self, GAsyncResult *res, GError **error) +{ + g_return_val_if_fail (FWUPD_IS_CLIENT (self), FALSE); + g_return_val_if_fail (g_task_is_valid (res, self), FALSE); + g_return_val_if_fail (error == NULL || *error == NULL, FALSE); + return g_task_propagate_boolean (G_TASK(res), error); +} + +static void +fwupd_client_get_remotes_cb (GObject *source, + GAsyncResult *res, + gpointer user_data) +{ + g_autoptr(GTask) task = G_TASK (user_data); + g_autoptr(GError) error = NULL; + g_autoptr(GVariant) val = NULL; + + val = g_dbus_proxy_call_finish (G_DBUS_PROXY (source), res, &error); + if (val == NULL) { + fwupd_client_fixup_dbus_error (error); + g_task_return_error (task, g_steal_pointer (&error)); + return; + } + + /* success */ + g_task_return_pointer (task, + fwupd_remote_array_from_variant (val), + (GDestroyNotify) g_ptr_array_unref); +} + +/** + * fwupd_client_get_remotes_async: * @self: A #FwupdClient * @cancellable: the #GCancellable, or %NULL - * @error: the #GError, or %NULL + * @callback: the function to run on completion + * @callback_data: the data to pass to @callback * * Gets the list of remotes that have been configured for the system. * - * Returns: (element-type FwupdRemote) (transfer container): list of remotes, or %NULL + * You must have called fwupd_client_connect_async() on @self before using + * this method. * - * Since: 0.9.3 + * Since: 1.5.0 **/ -GPtrArray * -fwupd_client_get_remotes (FwupdClient *self, GCancellable *cancellable, GError **error) +void +fwupd_client_get_remotes_async (FwupdClient *self, GCancellable *cancellable, + GAsyncReadyCallback callback, gpointer callback_data) { FwupdClientPrivate *priv = GET_PRIVATE (self); - g_autoptr(GVariant) val = NULL; + g_autoptr(GTask) task = NULL; - g_return_val_if_fail (FWUPD_IS_CLIENT (self), NULL); - g_return_val_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable), NULL); - g_return_val_if_fail (error == NULL || *error == NULL, NULL); - - /* connect */ - if (!fwupd_client_connect (self, cancellable, error)) - return NULL; + g_return_if_fail (FWUPD_IS_CLIENT (self)); + g_return_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable)); + g_return_if_fail (priv->proxy != NULL); /* call into daemon */ - val = g_dbus_proxy_call_sync (priv->proxy, - "GetRemotes", - NULL, - G_DBUS_CALL_FLAGS_NONE, - -1, - cancellable, - error); - if (val == NULL) { - if (error != NULL) - fwupd_client_fixup_dbus_error (*error); - return NULL; - } - return fwupd_remote_array_from_variant (val); + task = g_task_new (self, cancellable, callback, callback_data); + g_dbus_proxy_call (priv->proxy, "GetRemotes", + NULL, G_DBUS_CALL_FLAGS_NONE, + -1, cancellable, + fwupd_client_get_remotes_cb, + g_steal_pointer (&task)); } /** - * fwupd_client_get_approved_firmware: + * fwupd_client_get_remotes_finish: + * @self: A #FwupdClient + * @res: the #GAsyncResult + * @error: the #GError, or %NULL + * + * Gets the result of fwupd_client_get_remotes_async(). + * + * Returns: (element-type FwupdRemote) (transfer container): results + * + * Since: 1.5.0 + **/ +GPtrArray * +fwupd_client_get_remotes_finish (FwupdClient *self, GAsyncResult *res, GError **error) +{ + g_return_val_if_fail (FWUPD_IS_CLIENT (self), NULL); + g_return_val_if_fail (g_task_is_valid (res, self), NULL); + g_return_val_if_fail (error == NULL || *error == NULL, NULL); + return g_task_propagate_pointer (G_TASK(res), error); +} + +static void +fwupd_client_get_approved_firmware_cb (GObject *source, + GAsyncResult *res, + gpointer user_data) +{ + g_auto(GStrv) strv = NULL; + g_autoptr(GTask) task = G_TASK (user_data); + g_autoptr(GError) error = NULL; + g_autoptr(GPtrArray) array = g_ptr_array_new_with_free_func (g_free); + g_autoptr(GVariant) val = NULL; + + val = g_dbus_proxy_call_finish (G_DBUS_PROXY (source), res, &error); + if (val == NULL) { + fwupd_client_fixup_dbus_error (error); + g_task_return_error (task, g_steal_pointer (&error)); + return; + } + + g_variant_get (val, "(^as)", &strv); + for (guint i = 0; strv[i] != NULL; i++) + g_ptr_array_add (array, g_strdup (strv[i])); + + /* success */ + g_task_return_pointer (task, + g_steal_pointer (&array), + (GDestroyNotify) g_ptr_array_unref); +} + +/** + * fwupd_client_get_approved_firmware_async: * @self: A #FwupdClient * @cancellable: the #GCancellable, or %NULL - * @error: the #GError, or %NULL + * @callback: the function to run on completion + * @callback_data: the data to pass to @callback * * Gets the list of approved firmware. * - * Returns: (transfer full): list of remotes, or %NULL + * You must have called fwupd_client_connect_async() on @self before using + * this method. * - * Since: 1.2.6 + * Since: 1.5.0 **/ -gchar ** -fwupd_client_get_approved_firmware (FwupdClient *self, - GCancellable *cancellable, - GError **error) +void +fwupd_client_get_approved_firmware_async (FwupdClient *self, + GCancellable *cancellable, + GAsyncReadyCallback callback, + gpointer callback_data) { FwupdClientPrivate *priv = GET_PRIVATE (self); - g_autoptr(GVariant) val = NULL; - gchar **retval = NULL; + g_autoptr(GTask) task = NULL; - g_return_val_if_fail (FWUPD_IS_CLIENT (self), NULL); - g_return_val_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable), NULL); - g_return_val_if_fail (error == NULL || *error == NULL, NULL); - - /* connect */ - if (!fwupd_client_connect (self, cancellable, error)) - return NULL; + g_return_if_fail (FWUPD_IS_CLIENT (self)); + g_return_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable)); + g_return_if_fail (priv->proxy != NULL); /* call into daemon */ - val = g_dbus_proxy_call_sync (priv->proxy, - "GetApprovedFirmware", - NULL, - G_DBUS_CALL_FLAGS_NONE, - -1, - cancellable, - error); - if (val == NULL) { - if (error != NULL) - fwupd_client_fixup_dbus_error (*error); - return NULL; - } - g_variant_get (val, "(^as)", &retval); - return retval; + task = g_task_new (self, cancellable, callback, callback_data); + g_dbus_proxy_call (priv->proxy, "GetApprovedFirmware", + NULL, + G_DBUS_CALL_FLAGS_NONE, + -1, cancellable, + fwupd_client_get_approved_firmware_cb, + g_steal_pointer (&task)); } /** - * fwupd_client_set_approved_firmware: + * fwupd_client_get_approved_firmware_finish: * @self: A #FwupdClient - * @checksums: Array of checksums - * @cancellable: the #GCancellable, or %NULL + * @res: the #GAsyncResult * @error: the #GError, or %NULL * + * Gets the result of fwupd_client_get_approved_firmware_async(). + * + * Returns: (element-type utf8) (transfer container): checksums, or %NULL for error + * + * Since: 1.5.0 + **/ +GPtrArray * +fwupd_client_get_approved_firmware_finish (FwupdClient *self, GAsyncResult *res, GError **error) +{ + g_return_val_if_fail (FWUPD_IS_CLIENT (self), NULL); + g_return_val_if_fail (g_task_is_valid (res, self), NULL); + g_return_val_if_fail (error == NULL || *error == NULL, NULL); + return g_task_propagate_pointer (G_TASK(res), error); +} + +static void +fwupd_client_set_approved_firmware_cb (GObject *source, + GAsyncResult *res, + gpointer user_data) +{ + g_autoptr(GTask) task = G_TASK (user_data); + g_autoptr(GError) error = NULL; + g_autoptr(GVariant) val = NULL; + + val = g_dbus_proxy_call_finish (G_DBUS_PROXY (source), res, &error); + if (val == NULL) { + fwupd_client_fixup_dbus_error (error); + g_task_return_error (task, g_steal_pointer (&error)); + return; + } + + /* success */ + g_task_return_boolean (task, TRUE); +} + +/** + * fwupd_client_set_approved_firmware_async: + * @self: A #FwupdClient + * @checksums: (element-type utf8): firmware checksums + * @cancellable: the #GCancellable, or %NULL + * @callback: the function to run on completion + * @callback_data: the data to pass to @callback + * * Sets the list of approved firmware. * - * Returns: %TRUE for success - * - * Since: 1.2.6 + * Since: 1.5.0 **/ -gboolean -fwupd_client_set_approved_firmware (FwupdClient *self, - gchar **checksums, - GCancellable *cancellable, - GError **error) +void +fwupd_client_set_approved_firmware_async (FwupdClient *self, + GPtrArray *checksums, + GCancellable *cancellable, + GAsyncReadyCallback callback, + gpointer callback_data) { FwupdClientPrivate *priv = GET_PRIVATE (self); - g_autoptr(GVariant) val = NULL; + g_autoptr(GTask) task = NULL; + g_auto(GStrv) strv = NULL; - g_return_val_if_fail (FWUPD_IS_CLIENT (self), FALSE); - g_return_val_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable), FALSE); - g_return_val_if_fail (error == NULL || *error == NULL, FALSE); - - /* connect */ - if (!fwupd_client_connect (self, cancellable, error)) - return FALSE; + g_return_if_fail (FWUPD_IS_CLIENT (self)); + g_return_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable)); + g_return_if_fail (priv->proxy != NULL); /* call into daemon */ - val = g_dbus_proxy_call_sync (priv->proxy, - "SetApprovedFirmware", - g_variant_new ("(^as)", checksums), - G_DBUS_CALL_FLAGS_NONE, - -1, - cancellable, - error); - if (val == NULL) { - if (error != NULL) - fwupd_client_fixup_dbus_error (*error); - return FALSE; + task = g_task_new (self, cancellable, callback, callback_data); + strv = g_new0 (gchar *, checksums->len + 1); + for (guint i = 0; i < checksums->len; i++) { + const gchar *tmp = g_ptr_array_index (checksums, i); + strv[i] = g_strdup (tmp); } - return TRUE; + g_dbus_proxy_call (priv->proxy, "SetApprovedFirmware", + g_variant_new ("(^as)", strv), + G_DBUS_CALL_FLAGS_NONE, -1, + cancellable, + fwupd_client_set_approved_firmware_cb, + g_steal_pointer (&task)); } /** - * fwupd_client_get_blocked_firmware: + * fwupd_client_set_approved_firmware_finish: + * @self: A #FwupdClient + * @res: the #GAsyncResult + * @error: the #GError, or %NULL + * + * Gets the result of fwupd_client_set_approved_firmware_async(). + * + * Returns: %TRUE for success + * + * Since: 1.5.0 + **/ +gboolean +fwupd_client_set_approved_firmware_finish (FwupdClient *self, GAsyncResult *res, GError **error) +{ + g_return_val_if_fail (FWUPD_IS_CLIENT (self), FALSE); + g_return_val_if_fail (g_task_is_valid (res, self), FALSE); + g_return_val_if_fail (error == NULL || *error == NULL, FALSE); + return g_task_propagate_boolean (G_TASK(res), error); +} + +static void +fwupd_client_get_blocked_firmware_cb (GObject *source, + GAsyncResult *res, + gpointer user_data) +{ + g_auto(GStrv) strv = NULL; + g_autoptr(GTask) task = G_TASK (user_data); + g_autoptr(GError) error = NULL; + g_autoptr(GPtrArray) array = g_ptr_array_new_with_free_func (g_free); + g_autoptr(GVariant) val = NULL; + + val = g_dbus_proxy_call_finish (G_DBUS_PROXY (source), res, &error); + if (val == NULL) { + fwupd_client_fixup_dbus_error (error); + g_task_return_error (task, g_steal_pointer (&error)); + return; + } + + g_variant_get (val, "(^as)", &strv); + for (guint i = 0; strv[i] != NULL; i++) + g_ptr_array_add (array, g_strdup (strv[i])); + + /* success */ + g_task_return_pointer (task, + g_steal_pointer (&array), + (GDestroyNotify) g_ptr_array_unref); +} + +/** + * fwupd_client_get_blocked_firmware_async: * @self: A #FwupdClient * @cancellable: the #GCancellable, or %NULL - * @error: the #GError, or %NULL + * @callback: the function to run on completion + * @callback_data: the data to pass to @callback * * Gets the list of blocked firmware. * - * Returns: (transfer full): list of checksums, or %NULL + * You must have called fwupd_client_connect_async() on @self before using + * this method. * - * Since: 1.4.6 + * Since: 1.5.0 **/ -gchar ** -fwupd_client_get_blocked_firmware (FwupdClient *self, - GCancellable *cancellable, - GError **error) +void +fwupd_client_get_blocked_firmware_async (FwupdClient *self, + GCancellable *cancellable, + GAsyncReadyCallback callback, + gpointer callback_data) { FwupdClientPrivate *priv = GET_PRIVATE (self); - g_autoptr(GVariant) val = NULL; - gchar **retval = NULL; + g_autoptr(GTask) task = NULL; - g_return_val_if_fail (FWUPD_IS_CLIENT (self), NULL); - g_return_val_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable), NULL); - g_return_val_if_fail (error == NULL || *error == NULL, NULL); - - /* connect */ - if (!fwupd_client_connect (self, cancellable, error)) - return NULL; + g_return_if_fail (FWUPD_IS_CLIENT (self)); + g_return_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable)); + g_return_if_fail (priv->proxy != NULL); /* call into daemon */ - val = g_dbus_proxy_call_sync (priv->proxy, - "GetBlockedFirmware", - NULL, - G_DBUS_CALL_FLAGS_NONE, - -1, - cancellable, - error); - if (val == NULL) { - if (error != NULL) - fwupd_client_fixup_dbus_error (*error); - return NULL; - } - g_variant_get (val, "(^as)", &retval); - return retval; + task = g_task_new (self, cancellable, callback, callback_data); + g_dbus_proxy_call (priv->proxy, "GetBlockedFirmware", + NULL, + G_DBUS_CALL_FLAGS_NONE, + -1, cancellable, + fwupd_client_get_blocked_firmware_cb, + g_steal_pointer (&task)); } /** - * fwupd_client_set_blocked_firmware: + * fwupd_client_get_blocked_firmware_finish: * @self: A #FwupdClient - * @checksums: Array of checksums - * @cancellable: the #GCancellable, or %NULL + * @res: the #GAsyncResult * @error: the #GError, or %NULL * + * Gets the result of fwupd_client_get_blocked_firmware_async(). + * + * Returns: (element-type utf8) (transfer container): checksums, or %NULL for error + * + * Since: 1.5.0 + **/ +GPtrArray * +fwupd_client_get_blocked_firmware_finish (FwupdClient *self, GAsyncResult *res, GError **error) +{ + g_return_val_if_fail (FWUPD_IS_CLIENT (self), NULL); + g_return_val_if_fail (g_task_is_valid (res, self), NULL); + g_return_val_if_fail (error == NULL || *error == NULL, NULL); + return g_task_propagate_pointer (G_TASK(res), error); +} + +static void +fwupd_client_set_blocked_firmware_cb (GObject *source, + GAsyncResult *res, + gpointer user_data) +{ + g_autoptr(GTask) task = G_TASK (user_data); + g_autoptr(GError) error = NULL; + g_autoptr(GVariant) val = NULL; + + val = g_dbus_proxy_call_finish (G_DBUS_PROXY (source), res, &error); + if (val == NULL) { + fwupd_client_fixup_dbus_error (error); + g_task_return_error (task, g_steal_pointer (&error)); + return; + } + + /* success */ + g_task_return_boolean (task, TRUE); +} + +/** + * fwupd_client_set_blocked_firmware_async: + * @self: A #FwupdClient + * @checksums: (element-type utf8): firmware checksums + * @cancellable: the #GCancellable, or %NULL + * @callback: the function to run on completion + * @callback_data: the data to pass to @callback + * * Sets the list of blocked firmware. * - * Returns: %TRUE for success - * - * Since: 1.4.6 + * Since: 1.5.0 **/ -gboolean -fwupd_client_set_blocked_firmware (FwupdClient *self, - gchar **checksums, - GCancellable *cancellable, - GError **error) +void +fwupd_client_set_blocked_firmware_async (FwupdClient *self, + GPtrArray *checksums, + GCancellable *cancellable, + GAsyncReadyCallback callback, + gpointer callback_data) { FwupdClientPrivate *priv = GET_PRIVATE (self); - g_autoptr(GVariant) val = NULL; + g_autoptr(GTask) task = NULL; + g_auto(GStrv) strv = NULL; - g_return_val_if_fail (FWUPD_IS_CLIENT (self), FALSE); - g_return_val_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable), FALSE); - g_return_val_if_fail (error == NULL || *error == NULL, FALSE); - - /* connect */ - if (!fwupd_client_connect (self, cancellable, error)) - return FALSE; + g_return_if_fail (FWUPD_IS_CLIENT (self)); + g_return_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable)); + g_return_if_fail (priv->proxy != NULL); /* call into daemon */ - val = g_dbus_proxy_call_sync (priv->proxy, - "SetBlockedFirmware", - g_variant_new ("(^as)", checksums), - G_DBUS_CALL_FLAGS_NONE, - -1, - cancellable, - error); - if (val == NULL) { - if (error != NULL) - fwupd_client_fixup_dbus_error (*error); - return FALSE; + task = g_task_new (self, cancellable, callback, callback_data); + strv = g_new0 (gchar *, checksums->len + 1); + for (guint i = 0; i < checksums->len; i++) { + const gchar *tmp = g_ptr_array_index (checksums, i); + strv[i] = g_strdup (tmp); } - return TRUE; + g_dbus_proxy_call (priv->proxy, "SetBlockedFirmware", + g_variant_new ("(^as)", strv), + G_DBUS_CALL_FLAGS_NONE, -1, + cancellable, + fwupd_client_set_blocked_firmware_cb, + g_steal_pointer (&task)); } /** - * fwupd_client_set_feature_flags: + * fwupd_client_set_blocked_firmware_finish: + * @self: A #FwupdClient + * @res: the #GAsyncResult + * @error: the #GError, or %NULL + * + * Gets the result of fwupd_client_set_blocked_firmware_async(). + * + * Returns: %TRUE for success + * + * Since: 1.5.0 + **/ +gboolean +fwupd_client_set_blocked_firmware_finish (FwupdClient *self, GAsyncResult *res, GError **error) +{ + g_return_val_if_fail (FWUPD_IS_CLIENT (self), FALSE); + g_return_val_if_fail (g_task_is_valid (res, self), FALSE); + g_return_val_if_fail (error == NULL || *error == NULL, FALSE); + return g_task_propagate_boolean (G_TASK(res), error); +} + +static void +fwupd_client_set_feature_flags_cb (GObject *source, + GAsyncResult *res, + gpointer user_data) +{ + g_autoptr(GTask) task = G_TASK (user_data); + g_autoptr(GError) error = NULL; + g_autoptr(GVariant) val = NULL; + + val = g_dbus_proxy_call_finish (G_DBUS_PROXY (source), res, &error); + if (val == NULL) { + fwupd_client_fixup_dbus_error (error); + g_task_return_error (task, g_steal_pointer (&error)); + return; + } + + /* success */ + g_task_return_boolean (task, TRUE); +} + +/** + * fwupd_client_set_feature_flags_async: * @self: A #FwupdClient * @feature_flags: #FwupdFeatureFlags, e.g. %FWUPD_FEATURE_FLAG_UPDATE_TEXT * @cancellable: the #GCancellable, or %NULL - * @error: the #GError, or %NULL + * @callback: the function to run on completion + * @callback_data: the data to pass to @callback * * Sets the features the client supports. This allows firmware to depend on * specific front-end features, for instance showing the user an image on * how to detach the hardware. * - * Clients can call this none or multiple times. - * - * Returns: %TRUE for success - * - * Since: 1.4.5 + * Since: 1.5.0 **/ -gboolean -fwupd_client_set_feature_flags (FwupdClient *self, - FwupdFeatureFlags feature_flags, - GCancellable *cancellable, - GError **error) +void +fwupd_client_set_feature_flags_async (FwupdClient *self, + FwupdFeatureFlags feature_flags, + GCancellable *cancellable, + GAsyncReadyCallback callback, + gpointer callback_data) { FwupdClientPrivate *priv = GET_PRIVATE (self); - g_autoptr(GVariant) val = NULL; + g_autoptr(GTask) task = NULL; - g_return_val_if_fail (FWUPD_IS_CLIENT (self), FALSE); - g_return_val_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable), FALSE); - g_return_val_if_fail (error == NULL || *error == NULL, FALSE); - - /* connect */ - if (!fwupd_client_connect (self, cancellable, error)) - return FALSE; + g_return_if_fail (FWUPD_IS_CLIENT (self)); + g_return_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable)); + g_return_if_fail (priv->proxy != NULL); /* call into daemon */ - val = g_dbus_proxy_call_sync (priv->proxy, - "SetFeatureFlags", - g_variant_new ("(t)", (guint64) feature_flags), - G_DBUS_CALL_FLAGS_NONE, - -1, - cancellable, - error); - if (val == NULL) { - if (error != NULL) - fwupd_client_fixup_dbus_error (*error); - return FALSE; - } - return TRUE; + task = g_task_new (self, cancellable, callback, callback_data); + g_dbus_proxy_call (priv->proxy, "SetFeatureFlags", + g_variant_new ("(t)", (guint64) feature_flags), + G_DBUS_CALL_FLAGS_NONE, -1, + cancellable, + fwupd_client_set_feature_flags_cb, + g_steal_pointer (&task)); } /** - * fwupd_client_self_sign: + * fwupd_client_set_feature_flags_finish: + * @self: A #FwupdClient + * @res: the #GAsyncResult + * @error: the #GError, or %NULL + * + * Gets the result of fwupd_client_set_feature_flags_async(). + * + * Returns: %TRUE for success + * + * Since: 1.5.0 + **/ +gboolean +fwupd_client_set_feature_flags_finish (FwupdClient *self, GAsyncResult *res, GError **error) +{ + g_return_val_if_fail (FWUPD_IS_CLIENT (self), FALSE); + g_return_val_if_fail (g_task_is_valid (res, self), FALSE); + g_return_val_if_fail (error == NULL || *error == NULL, FALSE); + return g_task_propagate_boolean (G_TASK(res), error); +} + +static void +fwupd_client_self_sign_cb (GObject *source, GAsyncResult *res, gpointer user_data) +{ + gchar *str = NULL; + g_autoptr(GTask) task = G_TASK (user_data); + g_autoptr(GError) error = NULL; + g_autoptr(GVariant) val = NULL; + + val = g_dbus_proxy_call_finish (G_DBUS_PROXY (source), res, &error); + if (val == NULL) { + fwupd_client_fixup_dbus_error (error); + g_task_return_error (task, g_steal_pointer (&error)); + return; + } + + /* success */ + g_variant_get (val, "(s)", &str); + g_task_return_pointer (task, + g_steal_pointer (&str), + (GDestroyNotify) g_free); +} + +/** + * fwupd_client_self_sign_async: * @self: A #FwupdClient * @value: A string to sign, typically a JSON blob * @flags: #FwupdSelfSignFlags, e.g. %FWUPD_SELF_SIGN_FLAG_ADD_TIMESTAMP * @cancellable: the #GCancellable, or %NULL - * @error: the #GError, or %NULL + * @callback: the function to run on completion + * @callback_data: the data to pass to @callback * * Signs the data using the client self-signed certificate. * - * Returns: %TRUE for success + * You must have called fwupd_client_connect_async() on @self before using + * this method. * - * Since: 1.2.6 + * Since: 1.5.0 **/ -gchar * -fwupd_client_self_sign (FwupdClient *self, - const gchar *value, - FwupdSelfSignFlags flags, - GCancellable *cancellable, - GError **error) +void +fwupd_client_self_sign_async (FwupdClient *self, + const gchar *value, + FwupdSelfSignFlags flags, + GCancellable *cancellable, + GAsyncReadyCallback callback, + gpointer callback_data) { FwupdClientPrivate *priv = GET_PRIVATE (self); GVariantBuilder builder; - g_autoptr(GVariant) val = NULL; - gchar *retval = NULL; + g_autoptr(GTask) task = NULL; - g_return_val_if_fail (FWUPD_IS_CLIENT (self), NULL); - g_return_val_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable), NULL); - g_return_val_if_fail (error == NULL || *error == NULL, NULL); - - /* connect */ - if (!fwupd_client_connect (self, cancellable, error)) - return NULL; + g_return_if_fail (FWUPD_IS_CLIENT (self)); + g_return_if_fail (value != NULL); + g_return_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable)); + g_return_if_fail (priv->proxy != NULL); /* set options */ g_variant_builder_init (&builder, G_VARIANT_TYPE_VARDICT); @@ -2318,131 +3437,204 @@ fwupd_client_self_sign (FwupdClient *self, } /* call into daemon */ - val = g_dbus_proxy_call_sync (priv->proxy, - "SelfSign", - g_variant_new ("(sa{sv})", value, &builder), - G_DBUS_CALL_FLAGS_NONE, - -1, - cancellable, - error); - if (val == NULL) { - if (error != NULL) - fwupd_client_fixup_dbus_error (*error); - return NULL; - } - g_variant_get (val, "(s)", &retval); - return retval; + task = g_task_new (self, cancellable, callback, callback_data); + g_dbus_proxy_call (priv->proxy, + "SelfSign", + g_variant_new ("(sa{sv})", value, &builder), + G_DBUS_CALL_FLAGS_NONE, + -1, cancellable, + fwupd_client_self_sign_cb, + g_steal_pointer (&task)); } /** - * fwupd_client_modify_remote: + * fwupd_client_self_sign_finish: + * @self: A #FwupdClient + * @res: the #GAsyncResult + * @error: the #GError, or %NULL + * + * Gets the result of fwupd_client_self_sign_async(). + * + * Returns: a signature, or %NULL for failure + * + * Since: 1.5.0 + **/ +gchar * +fwupd_client_self_sign_finish (FwupdClient *self, GAsyncResult *res, GError **error) +{ + g_return_val_if_fail (FWUPD_IS_CLIENT (self), NULL); + g_return_val_if_fail (g_task_is_valid (res, self), NULL); + g_return_val_if_fail (error == NULL || *error == NULL, NULL); + return g_task_propagate_pointer (G_TASK(res), error); +} + +static void +fwupd_client_modify_remote_cb (GObject *source, + GAsyncResult *res, + gpointer user_data) +{ + g_autoptr(GTask) task = G_TASK (user_data); + g_autoptr(GError) error = NULL; + g_autoptr(GVariant) val = NULL; + + val = g_dbus_proxy_call_finish (G_DBUS_PROXY (source), res, &error); + if (val == NULL) { + fwupd_client_fixup_dbus_error (error); + g_task_return_error (task, g_steal_pointer (&error)); + return; + } + + /* success */ + g_task_return_boolean (task, TRUE); +} + +/** + * fwupd_client_modify_remote_async: * @self: A #FwupdClient * @remote_id: the remote ID, e.g. `lvfs-testing` * @key: the key, e.g. `Enabled` * @value: the key, e.g. `true` * @cancellable: the #GCancellable, or %NULL - * @error: the #GError, or %NULL + * @callback: the function to run on completion + * @callback_data: the data to pass to @callback * * Modifies a system remote in a specific way. * - * NOTE: User authentication may be required to complete this action. - * - * Returns: %TRUE for success - * - * Since: 0.9.8 + * Since: 1.5.0 **/ -gboolean -fwupd_client_modify_remote (FwupdClient *self, - const gchar *remote_id, - const gchar *key, - const gchar *value, - GCancellable *cancellable, - GError **error) +void +fwupd_client_modify_remote_async (FwupdClient *self, + const gchar *remote_id, + const gchar *key, + const gchar *value, + GCancellable *cancellable, + GAsyncReadyCallback callback, + gpointer callback_data) { FwupdClientPrivate *priv = GET_PRIVATE (self); - g_autoptr(GVariant) val = NULL; + g_autoptr(GTask) task = NULL; - g_return_val_if_fail (FWUPD_IS_CLIENT (self), FALSE); - g_return_val_if_fail (remote_id != NULL, FALSE); - g_return_val_if_fail (key != NULL, FALSE); - g_return_val_if_fail (value != NULL, FALSE); - g_return_val_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable), FALSE); - g_return_val_if_fail (error == NULL || *error == NULL, FALSE); - - /* connect */ - if (!fwupd_client_connect (self, cancellable, error)) - return FALSE; + g_return_if_fail (FWUPD_IS_CLIENT (self)); + g_return_if_fail (remote_id != NULL); + g_return_if_fail (key != NULL); + g_return_if_fail (value != NULL); + g_return_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable)); + g_return_if_fail (priv->proxy != NULL); /* call into daemon */ - val = g_dbus_proxy_call_sync (priv->proxy, - "ModifyRemote", - g_variant_new ("(sss)", remote_id, key, value), - G_DBUS_CALL_FLAGS_NONE, - -1, - cancellable, - error); - if (val == NULL) { - if (error != NULL) - fwupd_client_fixup_dbus_error (*error); - return FALSE; - } - return TRUE; + task = g_task_new (self, cancellable, callback, callback_data); + g_dbus_proxy_call (priv->proxy, "ModifyRemote", + g_variant_new ("(sss)", remote_id, key, value), + G_DBUS_CALL_FLAGS_NONE, -1, + cancellable, + fwupd_client_modify_remote_cb, + g_steal_pointer (&task)); } /** - * fwupd_client_modify_device: + * fwupd_client_modify_remote_finish: + * @self: A #FwupdClient + * @res: the #GAsyncResult + * @error: the #GError, or %NULL + * + * Gets the result of fwupd_client_modify_remote_async(). + * + * Returns: %TRUE for success + * + * Since: 1.5.0 + **/ +gboolean +fwupd_client_modify_remote_finish (FwupdClient *self, GAsyncResult *res, GError **error) +{ + g_return_val_if_fail (FWUPD_IS_CLIENT (self), FALSE); + g_return_val_if_fail (g_task_is_valid (res, self), FALSE); + g_return_val_if_fail (error == NULL || *error == NULL, FALSE); + return g_task_propagate_boolean (G_TASK(res), error); +} + +static void +fwupd_client_modify_device_cb (GObject *source, + GAsyncResult *res, + gpointer user_data) +{ + g_autoptr(GTask) task = G_TASK (user_data); + g_autoptr(GError) error = NULL; + g_autoptr(GVariant) val = NULL; + + val = g_dbus_proxy_call_finish (G_DBUS_PROXY (source), res, &error); + if (val == NULL) { + fwupd_client_fixup_dbus_error (error); + g_task_return_error (task, g_steal_pointer (&error)); + return; + } + + /* success */ + g_task_return_boolean (task, TRUE); +} + +/** + * fwupd_client_modify_device_async: * @self: A #FwupdClient * @device_id: the device ID * @key: the key, e.g. `Flags` * @value: the key, e.g. `reported` * @cancellable: the #GCancellable, or %NULL - * @error: the #GError, or %NULL + * @callback: the function to run on completion + * @callback_data: the data to pass to @callback * * Modifies a device in a specific way. Not all properties on the #FwupdDevice * are settable by the client, and some may have other restrictions on @value. * - * NOTE: User authentication may be required to complete this action. + * Since: 1.5.0 + **/ +void +fwupd_client_modify_device_async (FwupdClient *self, + const gchar *device_id, + const gchar *key, + const gchar *value, + GCancellable *cancellable, + GAsyncReadyCallback callback, + gpointer callback_data) +{ + FwupdClientPrivate *priv = GET_PRIVATE (self); + g_autoptr(GTask) task = NULL; + + g_return_if_fail (FWUPD_IS_CLIENT (self)); + g_return_if_fail (device_id != NULL); + g_return_if_fail (key != NULL); + g_return_if_fail (value != NULL); + g_return_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable)); + g_return_if_fail (priv->proxy != NULL); + + /* call into daemon */ + task = g_task_new (self, cancellable, callback, callback_data); + g_dbus_proxy_call (priv->proxy, "ModifyDevice", + g_variant_new ("(sss)", device_id, key, value), + G_DBUS_CALL_FLAGS_NONE, -1, + cancellable, + fwupd_client_modify_device_cb, + g_steal_pointer (&task)); +} + +/** + * fwupd_client_modify_device_finish: + * @self: A #FwupdClient + * @res: the #GAsyncResult + * @error: the #GError, or %NULL + * + * Gets the result of fwupd_client_modify_device_async(). * * Returns: %TRUE for success * - * Since: 1.0.4 + * Since: 1.5.0 **/ gboolean -fwupd_client_modify_device (FwupdClient *self, - const gchar *remote_id, - const gchar *key, - const gchar *value, - GCancellable *cancellable, - GError **error) +fwupd_client_modify_device_finish (FwupdClient *self, GAsyncResult *res, GError **error) { - FwupdClientPrivate *priv = GET_PRIVATE (self); - g_autoptr(GVariant) val = NULL; - g_return_val_if_fail (FWUPD_IS_CLIENT (self), FALSE); - g_return_val_if_fail (remote_id != NULL, FALSE); - g_return_val_if_fail (key != NULL, FALSE); - g_return_val_if_fail (value != NULL, FALSE); - g_return_val_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable), FALSE); + g_return_val_if_fail (g_task_is_valid (res, self), FALSE); g_return_val_if_fail (error == NULL || *error == NULL, FALSE); - - /* connect */ - if (!fwupd_client_connect (self, cancellable, error)) - return FALSE; - - /* call into daemon */ - val = g_dbus_proxy_call_sync (priv->proxy, - "ModifyDevice", - g_variant_new ("(sss)", remote_id, key, value), - G_DBUS_CALL_FLAGS_NONE, - -1, - cancellable, - error); - if (val == NULL) { - if (error != NULL) - fwupd_client_fixup_dbus_error (*error); - return FALSE; - } - return TRUE; + return g_task_propagate_boolean (G_TASK(res), error); } static FwupdRemote * @@ -2456,49 +3648,93 @@ fwupd_client_get_remote_by_id_noref (GPtrArray *remotes, const gchar *remote_id) return NULL; } -/** - * fwupd_client_get_remote_by_id: - * @self: A #FwupdClient - * @remote_id: the remote ID, e.g. `lvfs-testing` - * @cancellable: the #GCancellable, or %NULL - * @error: the #GError, or %NULL - * - * Gets a specific remote that has been configured for the system. - * - * Returns: (transfer full): a #FwupdRemote, or %NULL if not found - * - * Since: 0.9.3 - **/ -FwupdRemote * -fwupd_client_get_remote_by_id (FwupdClient *self, - const gchar *remote_id, - GCancellable *cancellable, - GError **error) +static void +fwupd_client_get_remote_by_id_cb (GObject *source, + GAsyncResult *res, + gpointer user_data) { - FwupdRemote *remote; + FwupdRemote *remote_tmp; + g_autoptr(GTask) task = G_TASK (user_data); + g_autoptr(GError) error = NULL; g_autoptr(GPtrArray) remotes = NULL; + const gchar *remote_id = g_task_get_task_data (task); - g_return_val_if_fail (FWUPD_IS_CLIENT (self), NULL); - g_return_val_if_fail (remote_id != NULL, NULL); - g_return_val_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable), NULL); - g_return_val_if_fail (error == NULL || *error == NULL, NULL); + remotes = fwupd_client_get_remotes_finish (FWUPD_CLIENT (source), res, &error); + if (remotes == NULL) { + g_task_return_error (task, g_steal_pointer (&error)); + return; + } - /* find remote in list */ - remotes = fwupd_client_get_remotes (self, cancellable, error); - if (remotes == NULL) - return NULL; - remote = fwupd_client_get_remote_by_id_noref (remotes, remote_id); - if (remote == NULL) { - g_set_error (error, - FWUPD_ERROR, - FWUPD_ERROR_NOT_FOUND, - "No remote '%s' found in search paths", - remote_id); - return NULL; + remote_tmp = fwupd_client_get_remote_by_id_noref (remotes, remote_id); + if (remote_tmp == NULL) { + g_task_return_new_error (task, + FWUPD_ERROR, + FWUPD_ERROR_NOT_FOUND, + "no remote '%s' found in search paths", + remote_id); + return; } /* success */ - return g_object_ref (remote); + g_task_return_pointer (task, + g_object_ref (remote_tmp), + (GDestroyNotify) g_object_unref); +} + +/** + * fwupd_client_get_remote_by_id_async: + * @self: A #FwupdClient + * @remote_id: the remote ID, e.g. `lvfs-testing` + * @cancellable: the #GCancellable, or %NULL + * @callback: the function to run on completion + * @callback_data: the data to pass to @callback + * + * Gets a specific remote that has been configured for the system. + * + * Since: 1.5.0 + **/ +void +fwupd_client_get_remote_by_id_async (FwupdClient *self, + const gchar *remote_id, + GCancellable *cancellable, + GAsyncReadyCallback callback, + gpointer callback_data) +{ + FwupdClientPrivate *priv = GET_PRIVATE (self); + g_autoptr(GTask) task = NULL; + + g_return_if_fail (FWUPD_IS_CLIENT (self)); + g_return_if_fail (remote_id != NULL); + g_return_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable)); + g_return_if_fail (priv->proxy != NULL); + + /* call into daemon */ + task = g_task_new (self, cancellable, callback, callback_data); + g_task_set_task_data (task, g_strdup (remote_id), g_free); + fwupd_client_get_remotes_async (self, cancellable, + fwupd_client_get_remote_by_id_cb, + g_steal_pointer (&task)); +} + +/** + * fwupd_client_get_remote_by_id_finish: + * @self: A #FwupdClient + * @res: the #GAsyncResult + * @error: the #GError, or %NULL + * + * Gets the result of fwupd_client_get_remote_by_id_async(). + * + * Returns: (transfer full): a #FwupdRemote, or %NULL if not found + * + * Since: 1.5.0 + **/ +FwupdRemote * +fwupd_client_get_remote_by_id_finish (FwupdClient *self, GAsyncResult *res, GError **error) +{ + g_return_val_if_fail (FWUPD_IS_CLIENT (self), NULL); + g_return_val_if_fail (g_task_is_valid (res, self), NULL); + g_return_val_if_fail (error == NULL || *error == NULL, NULL); + return g_task_propagate_pointer (G_TASK(res), error); } /** @@ -2569,7 +3805,6 @@ fwupd_client_set_user_agent_for_package (FwupdClient *self, priv->user_agent = g_string_free (str, FALSE); } - static void fwupd_client_download_chunk_cb (SoupMessage *msg, SoupBuffer *chunk, gpointer user_data) { @@ -2598,126 +3833,246 @@ fwupd_client_download_chunk_cb (SoupMessage *msg, SoupBuffer *chunk, gpointer us fwupd_client_set_percentage (self, percentage); } +static void +fwupd_client_read_bytes_cb (GObject *source, GAsyncResult *res, gpointer user_data) +{ + g_autoptr(GBytes) bytes = NULL; + g_autoptr(GError) error = NULL; + g_autoptr(GTask) task = G_TASK (user_data); + + bytes = fwupd_input_stream_read_bytes_finish (G_INPUT_STREAM (source), res, &error); + if (bytes == NULL) { + g_task_return_error (task, g_steal_pointer (&error)); + return; + } + + /* success */ + g_task_return_pointer (task, + g_steal_pointer (&bytes), + (GDestroyNotify) g_bytes_unref); +} + +static void +fwupd_client_download_bytes_cb (GObject *source, + GAsyncResult *res, + gpointer user_data) +{ + g_autoptr(GTask) task = G_TASK (user_data); + FwupdClient *self = g_task_get_source_object (task); + FwupdClientPrivate *priv = GET_PRIVATE (self); + GCancellable *cancellable = g_task_get_cancellable (task); + g_autoptr(GError) error = NULL; + g_autoptr(GInputStream) istr = NULL; + guint status_code = 0; + SoupMessage *msg = g_task_get_task_data (task); + + /* get the result */ + istr = soup_session_send_finish (priv->soup_session, res, &error); + if (istr == NULL) { + g_task_return_error (task, g_steal_pointer (&error)); + return; + } + + /* check the input stream before reading the data */ + g_object_get (msg, "status-code", &status_code, NULL); + g_debug ("status-code was %u", status_code); + if (status_code == 429) { + g_task_return_new_error (task, + FWUPD_ERROR, + FWUPD_ERROR_INVALID_FILE, + "Failed to download due to server limit"); + return; + } + if (status_code != SOUP_STATUS_OK) { + g_task_return_new_error (task, + FWUPD_ERROR, + FWUPD_ERROR_INVALID_FILE, + "Failed to download: %s", + soup_status_get_phrase (status_code)); + return; + } + + /* read the input stream into a GBytes, async */ + fwupd_input_stream_read_bytes_async (istr, cancellable, + fwupd_client_read_bytes_cb, + g_steal_pointer (&task)); +} + /** - * fwupd_client_download_bytes: + * fwupd_client_download_bytes_async: * @self: A #FwupdClient * @url: the remote URL * @flags: #FwupdClientDownloadFlags, e.g. %FWUPD_CLIENT_DOWNLOAD_FLAG_NONE * @cancellable: the #GCancellable, or %NULL - * @error: the #GError, or %NULL + * @callback: the function to run on completion + * @callback_data: the data to pass to @callback * * Downloads data from a remote server. The fwupd_client_set_user_agent() function * should be called before this method is used. * - * Returns: (transfer full): downloaded data, or %NULL for error + * You must have called fwupd_client_connect_async() on @self before using + * this method. * - * Since: 1.4.5 + * Since: 1.5.0 **/ -GBytes * -fwupd_client_download_bytes (FwupdClient *self, - const gchar *url, - FwupdClientDownloadFlags flags, - GCancellable *cancellable, - GError **error) +void +fwupd_client_download_bytes_async (FwupdClient *self, + const gchar *url, + FwupdClientDownloadFlags flags, + GCancellable *cancellable, + GAsyncReadyCallback callback, + gpointer callback_data) { FwupdClientPrivate *priv = GET_PRIVATE (self); - guint status_code; + g_autoptr(GTask) task = NULL; g_autoptr(SoupMessage) msg = NULL; g_autoptr(SoupURI) uri = NULL; + g_autoptr(GError) error = NULL; - g_return_val_if_fail (FWUPD_IS_CLIENT (self), NULL); - g_return_val_if_fail (url != NULL, NULL); - g_return_val_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable), NULL); - g_return_val_if_fail (error == NULL || *error == NULL, NULL); + g_return_if_fail (FWUPD_IS_CLIENT (self)); + g_return_if_fail (url != NULL); + g_return_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable)); + g_return_if_fail (priv->proxy != NULL); /* ensure networking set up */ - if (!fwupd_client_ensure_networking (self, error)) - return NULL; + task = g_task_new (self, cancellable, callback, callback_data); + if (!fwupd_client_ensure_networking (self, &error)) { + g_task_return_error (task, g_steal_pointer (&error)); + return; + } /* download data */ g_debug ("downloading %s", url); uri = soup_uri_new (url); msg = soup_message_new_from_uri (SOUP_METHOD_GET, uri); if (msg == NULL) { - g_set_error (error, - FWUPD_ERROR, - FWUPD_ERROR_INVALID_FILE, - "Failed to parse URI %s", url); - return NULL; + g_task_return_new_error (task, + FWUPD_ERROR, + FWUPD_ERROR_INVALID_FILE, + "Failed to parse URI %s", url); + return; } g_signal_connect (msg, "got-chunk", G_CALLBACK (fwupd_client_download_chunk_cb), self); - status_code = soup_session_send_message (priv->soup_session, msg); + g_task_set_task_data (task, g_object_ref (msg), (GDestroyNotify) g_object_unref); fwupd_client_set_status (self, FWUPD_STATUS_IDLE); - if (status_code == 429) { - g_autofree gchar *str = g_strndup (msg->response_body->data, - msg->response_body->length); - if (g_strcmp0 (str, "Too Many Requests") == 0) { - g_set_error (error, - FWUPD_ERROR, - FWUPD_ERROR_INVALID_FILE, - "Failed to download due to server limit"); - return NULL; - } - g_set_error (error, - FWUPD_ERROR, - FWUPD_ERROR_INVALID_FILE, - "Failed to download due to server limit: %s", str); - return NULL; - } - if (status_code != SOUP_STATUS_OK) { - g_set_error (error, - FWUPD_ERROR, - FWUPD_ERROR_INVALID_FILE, - "Failed to download %s: %s", - url, soup_status_get_phrase (status_code)); - return NULL; - } - - /* success */ - return g_bytes_new (msg->response_body->data, msg->response_body->length); + soup_session_send_async (priv->soup_session, msg, + cancellable, + fwupd_client_download_bytes_cb, + g_steal_pointer (&task)); } /** - * fwupd_client_upload_bytes: + * fwupd_client_download_bytes_finish: + * @self: A #FwupdClient + * @res: the #GAsyncResult + * @error: the #GError, or %NULL + * + * Gets the result of fwupd_client_download_bytes_async(). + * + * Returns: (transfer full): downloaded data, or %NULL for error + * + * Since: 1.5.0 + **/ +GBytes * +fwupd_client_download_bytes_finish (FwupdClient *self, GAsyncResult *res, GError **error) +{ + g_return_val_if_fail (FWUPD_IS_CLIENT (self), NULL); + g_return_val_if_fail (g_task_is_valid (res, self), NULL); + g_return_val_if_fail (error == NULL || *error == NULL, NULL); + return g_task_propagate_pointer (G_TASK(res), error); +} + +static void +fwupd_client_upload_bytes_cb (GObject *source, + GAsyncResult *res, + gpointer user_data) +{ + g_autoptr(GTask) task = G_TASK (user_data); + FwupdClient *self = g_task_get_source_object (task); + FwupdClientPrivate *priv = GET_PRIVATE (self); + GCancellable *cancellable = g_task_get_cancellable (task); + g_autoptr(GError) error = NULL; + g_autoptr(GInputStream) istr = NULL; + guint status_code; + SoupMessage *msg = g_task_get_task_data (task); + + /* get the result */ + istr = soup_session_send_finish (priv->soup_session, res, &error); + if (istr == NULL) { + g_task_return_error (task, g_steal_pointer (&error)); + return; + } + + /* check the input stream before reading the data */ + g_object_get (msg, "status-code", &status_code, NULL); + g_debug ("status-code was %u", status_code); + if (!SOUP_STATUS_IS_SUCCESSFUL (status_code)) { + g_task_return_new_error (task, + FWUPD_ERROR, + FWUPD_ERROR_INVALID_FILE, + "Failed to download: %s", + soup_status_get_phrase (status_code)); + return; + } + + /* read the input stream into a GBytes, async */ + fwupd_input_stream_read_bytes_async (istr, cancellable, + fwupd_client_read_bytes_cb, + g_steal_pointer (&task)); +} + +/** + * fwupd_client_upload_bytes_async: * @self: A #FwupdClient * @url: the remote URL * @payload: payload string * @signature: (nullable): signature string * @flags: #FwupdClientDownloadFlags, e.g. %FWUPD_CLIENT_DOWNLOAD_FLAG_NONE * @cancellable: the #GCancellable, or %NULL - * @error: the #GError, or %NULL + * @callback: the function to run on completion + * @callback_data: the data to pass to @callback * * Uploads data to a remote server. The fwupd_client_set_user_agent() function * should be called before this method is used. * - * Returns: (transfer full): downloaded data, or %NULL for error + * You must have called fwupd_client_connect_async() on @self before using + * this method. * - * Since: 1.4.5 + * Since: 1.5.0 **/ -GBytes * -fwupd_client_upload_bytes (FwupdClient *self, - const gchar *url, - const gchar *payload, - const gchar *signature, - FwupdClientUploadFlags flags, - GCancellable *cancellable, - GError **error) +void +fwupd_client_upload_bytes_async (FwupdClient *self, + const gchar *url, + const gchar *payload, + const gchar *signature, + FwupdClientUploadFlags flags, + GCancellable *cancellable, + GAsyncReadyCallback callback, + gpointer callback_data) { FwupdClientPrivate *priv = GET_PRIVATE (self); - guint status_code; + g_autoptr(GTask) task = NULL; g_autoptr(SoupMessage) msg = NULL; g_autoptr(SoupURI) uri = NULL; + g_autoptr(GError) error = NULL; - g_return_val_if_fail (FWUPD_IS_CLIENT (self), NULL); - g_return_val_if_fail (url != NULL, NULL); - g_return_val_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable), NULL); - g_return_val_if_fail (error == NULL || *error == NULL, NULL); + g_return_if_fail (FWUPD_IS_CLIENT (self)); + g_return_if_fail (url != NULL); + g_return_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable)); + g_return_if_fail (priv->proxy != NULL); /* ensure networking set up */ - if (!fwupd_client_ensure_networking (self, error)) - return NULL; + task = g_task_new (self, cancellable, callback, callback_data); + if (!fwupd_client_ensure_networking (self, &error)) { + g_task_return_error (task, g_steal_pointer (&error)); + return; + } + + /* download data */ + g_debug ("downloading %s", url); + uri = soup_uri_new (url); /* build message */ if ((flags & FWUPD_CLIENT_UPLOAD_FLAG_ALWAYS_MULTIPART) > 0 || @@ -2736,28 +4091,43 @@ fwupd_client_upload_bytes (FwupdClient *self, /* POST request */ if (msg == NULL) { - g_set_error (error, - FWUPD_ERROR, - FWUPD_ERROR_INVALID_FILE, - "Failed to parse URI %s", url); - return NULL; + g_task_return_new_error (task, + FWUPD_ERROR, + FWUPD_ERROR_INVALID_FILE, + "Failed to parse URI %s", url); + return; } + g_signal_connect (msg, "got-chunk", + G_CALLBACK (fwupd_client_download_chunk_cb), + self); + g_task_set_task_data (task, g_object_ref (msg), (GDestroyNotify) g_object_unref); + fwupd_client_set_status (self, FWUPD_STATUS_IDLE); g_debug ("uploading to %s", url); - status_code = soup_session_send_message (priv->soup_session, msg); - g_debug ("server returned: %s", msg->response_body->data); + soup_session_send_async (priv->soup_session, msg, + cancellable, + fwupd_client_upload_bytes_cb, + g_steal_pointer (&task)); +} - /* fall back to HTTP status codes in case the server is offline */ - if (!SOUP_STATUS_IS_SUCCESSFUL (status_code)) { - g_set_error (error, - FWUPD_ERROR, - FWUPD_ERROR_INVALID_FILE, - "Failed to upllooad to %s: %s", - url, soup_status_get_phrase (status_code)); - return NULL; - } - - /* success */ - return g_bytes_new (msg->response_body->data, msg->response_body->length); +/** + * fwupd_client_upload_bytes_finish: + * @self: A #FwupdClient + * @res: the #GAsyncResult + * @error: the #GError, or %NULL + * + * Gets the result of fwupd_client_upload_bytes_async(). + * + * Returns: (transfer full): response data, or %NULL for error + * + * Since: 1.5.0 + **/ +GBytes * +fwupd_client_upload_bytes_finish (FwupdClient *self, GAsyncResult *res, GError **error) +{ + g_return_val_if_fail (FWUPD_IS_CLIENT (self), NULL); + g_return_val_if_fail (g_task_is_valid (res, self), NULL); + g_return_val_if_fail (error == NULL || *error == NULL, NULL); + return g_task_propagate_pointer (G_TASK(res), error); } static void diff --git a/libfwupd/fwupd-client.h b/libfwupd/fwupd-client.h index d7b796f67..ea3eeadb4 100644 --- a/libfwupd/fwupd-client.h +++ b/libfwupd/fwupd-client.h @@ -67,120 +67,215 @@ typedef enum { } FwupdClientUploadFlags; FwupdClient *fwupd_client_new (void); -gboolean fwupd_client_connect (FwupdClient *self, +void fwupd_client_connect_async (FwupdClient *self, GCancellable *cancellable, + GAsyncReadyCallback callback, + gpointer callback_data); +gboolean fwupd_client_connect_finish (FwupdClient *self, + GAsyncResult *res, GError **error); -GPtrArray *fwupd_client_get_devices (FwupdClient *self, +void fwupd_client_get_devices_async (FwupdClient *self, GCancellable *cancellable, + GAsyncReadyCallback callback, + gpointer callback_data); +GPtrArray *fwupd_client_get_devices_finish (FwupdClient *self, + GAsyncResult *res, GError **error); -GPtrArray *fwupd_client_get_history (FwupdClient *self, +void fwupd_client_get_history_async (FwupdClient *self, GCancellable *cancellable, + GAsyncReadyCallback callback, + gpointer callback_data); +GPtrArray *fwupd_client_get_history_finish (FwupdClient *self, + GAsyncResult *res, GError **error); -GPtrArray *fwupd_client_get_releases (FwupdClient *self, +void fwupd_client_get_releases_async (FwupdClient *self, const gchar *device_id, GCancellable *cancellable, + GAsyncReadyCallback callback, + gpointer callback_data); +GPtrArray *fwupd_client_get_releases_finish (FwupdClient *self, + GAsyncResult *res, GError **error); -GPtrArray *fwupd_client_get_downgrades (FwupdClient *self, +void fwupd_client_get_downgrades_async (FwupdClient *self, const gchar *device_id, GCancellable *cancellable, + GAsyncReadyCallback callback, + gpointer callback_data); +GPtrArray *fwupd_client_get_downgrades_finish (FwupdClient *self, + GAsyncResult *res, GError **error); -GPtrArray *fwupd_client_get_upgrades (FwupdClient *self, +void fwupd_client_get_upgrades_async (FwupdClient *self, const gchar *device_id, GCancellable *cancellable, + GAsyncReadyCallback callback, + gpointer callback_data); +GPtrArray *fwupd_client_get_upgrades_finish (FwupdClient *self, + GAsyncResult *res, GError **error); -GPtrArray *fwupd_client_get_details (FwupdClient *self, - const gchar *filename, +void fwupd_client_get_details_bytes_async (FwupdClient *self, + GBytes *bytes, GCancellable *cancellable, + GAsyncReadyCallback callback, + gpointer callback_data); +GPtrArray *fwupd_client_get_details_bytes_finish (FwupdClient *self, + GAsyncResult *res, GError **error); -gboolean fwupd_client_verify (FwupdClient *self, +void fwupd_client_verify_async (FwupdClient *self, const gchar *device_id, GCancellable *cancellable, + GAsyncReadyCallback callback, + gpointer callback_data); +gboolean fwupd_client_verify_finish (FwupdClient *self, + GAsyncResult *res, GError **error); -gboolean fwupd_client_verify_update (FwupdClient *self, +void fwupd_client_verify_update_async (FwupdClient *self, const gchar *device_id, GCancellable *cancellable, + GAsyncReadyCallback callback, + gpointer callback_data); +gboolean fwupd_client_verify_update_finish (FwupdClient *self, + GAsyncResult *res, GError **error); -gboolean fwupd_client_unlock (FwupdClient *self, +void fwupd_client_unlock_async (FwupdClient *self, const gchar *device_id, GCancellable *cancellable, + GAsyncReadyCallback callback, + gpointer callback_data); +gboolean fwupd_client_unlock_finish (FwupdClient *self, + GAsyncResult *res, GError **error); -gboolean fwupd_client_modify_config (FwupdClient *self, +void fwupd_client_modify_config_async (FwupdClient *self, const gchar *key, const gchar *value, GCancellable *cancellable, + GAsyncReadyCallback callback, + gpointer callback_data); +gboolean fwupd_client_modify_config_finish (FwupdClient *self, + GAsyncResult *res, GError **error); -gboolean fwupd_client_activate (FwupdClient *self, - GCancellable *cancellable, - const gchar *device_id, - GError **error); -gboolean fwupd_client_clear_results (FwupdClient *self, +void fwupd_client_activate_async (FwupdClient *self, const gchar *device_id, GCancellable *cancellable, + GAsyncReadyCallback callback, + gpointer callback_data); +gboolean fwupd_client_activate_finish (FwupdClient *self, + GAsyncResult *res, GError **error); -FwupdDevice *fwupd_client_get_results (FwupdClient *self, +void fwupd_client_clear_results_async (FwupdClient *self, const gchar *device_id, GCancellable *cancellable, + GAsyncReadyCallback callback, + gpointer callback_data); +gboolean fwupd_client_clear_results_finish (FwupdClient *self, + GAsyncResult *res, GError **error); -GPtrArray *fwupd_client_get_host_security_attrs (FwupdClient *self, - GCancellable *cancellable, - GError **error); -FwupdDevice *fwupd_client_get_device_by_id (FwupdClient *self, +void fwupd_client_get_results_async (FwupdClient *self, const gchar *device_id, GCancellable *cancellable, + GAsyncReadyCallback callback, + gpointer callback_data); +FwupdDevice *fwupd_client_get_results_finish (FwupdClient *self, + GAsyncResult *res, GError **error); -GPtrArray *fwupd_client_get_devices_by_guid (FwupdClient *self, +void fwupd_client_get_host_security_attrs_async(FwupdClient *self, + GCancellable *cancellable, + GAsyncReadyCallback callback, + gpointer callback_data); +GPtrArray *fwupd_client_get_host_security_attrs_finish(FwupdClient *self, + GAsyncResult *res, + GError **error); +void fwupd_client_get_device_by_id_async (FwupdClient *self, + const gchar *device_id, + GCancellable *cancellable, + GAsyncReadyCallback callback, + gpointer callback_data); +FwupdDevice *fwupd_client_get_device_by_id_finish (FwupdClient *self, + GAsyncResult *res, + GError **error); +void fwupd_client_get_devices_by_guid_async (FwupdClient *self, const gchar *guid, GCancellable *cancellable, + GAsyncReadyCallback callback, + gpointer callback_data); +GPtrArray *fwupd_client_get_devices_by_guid_finish (FwupdClient *self, + GAsyncResult *res, GError **error); -gboolean fwupd_client_install (FwupdClient *self, +void fwupd_client_install_async (FwupdClient *self, const gchar *device_id, const gchar *filename, FwupdInstallFlags install_flags, GCancellable *cancellable, + GAsyncReadyCallback callback, + gpointer callback_data); +gboolean fwupd_client_install_finish (FwupdClient *self, + GAsyncResult *res, GError **error); -gboolean fwupd_client_install_bytes (FwupdClient *self, +void fwupd_client_install_bytes_async (FwupdClient *self, const gchar *device_id, GBytes *bytes, FwupdInstallFlags install_flags, GCancellable *cancellable, + GAsyncReadyCallback callback, + gpointer callback_data); +gboolean fwupd_client_install_bytes_finish (FwupdClient *self, + GAsyncResult *res, GError **error); -gboolean fwupd_client_install_release (FwupdClient *self, +void fwupd_client_install_release_async (FwupdClient *self, FwupdDevice *device, FwupdRelease *release, FwupdInstallFlags install_flags, GCancellable *cancellable, + GAsyncReadyCallback callback, + gpointer callback_data); +gboolean fwupd_client_install_release_finish (FwupdClient *self, + GAsyncResult *res, GError **error); -gboolean fwupd_client_update_metadata (FwupdClient *self, - const gchar *remote_id, - const gchar *metadata_fn, - const gchar *signature_fn, - GCancellable *cancellable, - GError **error); -gboolean fwupd_client_update_metadata_bytes (FwupdClient *self, +void fwupd_client_update_metadata_bytes_async (FwupdClient *self, const gchar *remote_id, GBytes *metadata, GBytes *signature, GCancellable *cancellable, + GAsyncReadyCallback callback, + gpointer callback_data); +gboolean fwupd_client_update_metadata_bytes_finish (FwupdClient *self, + GAsyncResult *res, GError **error); -gboolean fwupd_client_refresh_remote (FwupdClient *self, +void fwupd_client_refresh_remote_async (FwupdClient *self, FwupdRemote *remote, GCancellable *cancellable, + GAsyncReadyCallback callback, + gpointer callback_data); +gboolean fwupd_client_refresh_remote_finish (FwupdClient *self, + GAsyncResult *res, GError **error); -gboolean fwupd_client_modify_remote (FwupdClient *self, +void fwupd_client_modify_remote_async (FwupdClient *self, const gchar *remote_id, const gchar *key, const gchar *value, GCancellable *cancellable, + GAsyncReadyCallback callback, + gpointer callback_data); +gboolean fwupd_client_modify_remote_finish (FwupdClient *self, + GAsyncResult *res, GError **error); -gboolean fwupd_client_modify_device (FwupdClient *self, +void fwupd_client_modify_device_async (FwupdClient *self, const gchar *device_id, const gchar *key, const gchar *value, GCancellable *cancellable, + GAsyncReadyCallback callback, + gpointer callback_data); +gboolean fwupd_client_modify_device_finish (FwupdClient *self, + GAsyncResult *res, GError **error); -GHashTable *fwupd_client_get_report_metadata (FwupdClient *self, +void fwupd_client_get_report_metadata_async (FwupdClient *self, GCancellable *cancellable, + GAsyncReadyCallback callback, + gpointer callback_data); +GHashTable *fwupd_client_get_report_metadata_finish(FwupdClient *self, + GAsyncResult *res, GError **error); + FwupdStatus fwupd_client_get_status (FwupdClient *self); gboolean fwupd_client_get_tainted (FwupdClient *self); gboolean fwupd_client_get_daemon_interactive (FwupdClient *self); @@ -190,53 +285,92 @@ const gchar *fwupd_client_get_host_product (FwupdClient *self); const gchar *fwupd_client_get_host_machine_id (FwupdClient *self); const gchar *fwupd_client_get_host_security_id (FwupdClient *self); -GPtrArray *fwupd_client_get_remotes (FwupdClient *self, +void fwupd_client_get_remotes_async (FwupdClient *self, GCancellable *cancellable, + GAsyncReadyCallback callback, + gpointer callback_data); +GPtrArray *fwupd_client_get_remotes_finish (FwupdClient *self, + GAsyncResult *res, GError **error); -FwupdRemote *fwupd_client_get_remote_by_id (FwupdClient *self, +void fwupd_client_get_remote_by_id_async (FwupdClient *self, const gchar *remote_id, GCancellable *cancellable, + GAsyncReadyCallback callback, + gpointer callback_data); +FwupdRemote *fwupd_client_get_remote_by_id_finish (FwupdClient *self, + GAsyncResult *res, GError **error); - -gchar **fwupd_client_get_approved_firmware (FwupdClient *self, +void fwupd_client_get_approved_firmware_async(FwupdClient *self, GCancellable *cancellable, + GAsyncReadyCallback callback, + gpointer callback_data); +GPtrArray *fwupd_client_get_approved_firmware_finish(FwupdClient *self, + GAsyncResult *res, GError **error); -gboolean fwupd_client_set_approved_firmware (FwupdClient *self, - gchar **checksums, +void fwupd_client_set_approved_firmware_async (FwupdClient *self, + GPtrArray *checksums, GCancellable *cancellable, + GAsyncReadyCallback callback, + gpointer callback_data); +gboolean fwupd_client_set_approved_firmware_finish (FwupdClient *self, + GAsyncResult *res, GError **error); -gchar **fwupd_client_get_blocked_firmware (FwupdClient *self, +void fwupd_client_get_blocked_firmware_async(FwupdClient *self, GCancellable *cancellable, + GAsyncReadyCallback callback, + gpointer callback_data); +GPtrArray *fwupd_client_get_blocked_firmware_finish(FwupdClient *self, + GAsyncResult *res, GError **error); -gboolean fwupd_client_set_blocked_firmware (FwupdClient *self, - gchar **checksums, +void fwupd_client_set_blocked_firmware_async (FwupdClient *self, + GPtrArray *checksums, GCancellable *cancellable, + GAsyncReadyCallback callback, + gpointer callback_data); +gboolean fwupd_client_set_blocked_firmware_finish (FwupdClient *self, + GAsyncResult *res, GError **error); -gchar *fwupd_client_self_sign (FwupdClient *self, +void fwupd_client_self_sign_async (FwupdClient *self, const gchar *value, FwupdSelfSignFlags flags, GCancellable *cancellable, + GAsyncReadyCallback callback, + gpointer callback_data); +gchar *fwupd_client_self_sign_finish (FwupdClient *self, + GAsyncResult *res, GError **error); -gboolean fwupd_client_set_feature_flags (FwupdClient *self, +void fwupd_client_set_feature_flags_async (FwupdClient *self, FwupdFeatureFlags feature_flags, GCancellable *cancellable, + GAsyncReadyCallback callback, + gpointer callback_data); +gboolean fwupd_client_set_feature_flags_finish (FwupdClient *self, + GAsyncResult *res, GError **error); void fwupd_client_set_user_agent (FwupdClient *self, const gchar *user_agent); void fwupd_client_set_user_agent_for_package(FwupdClient *self, const gchar *package_name, const gchar *package_version); -GBytes *fwupd_client_download_bytes (FwupdClient *self, +void fwupd_client_download_bytes_async (FwupdClient *self, const gchar *url, FwupdClientDownloadFlags flags, GCancellable *cancellable, + GAsyncReadyCallback callback, + gpointer callback_data); +GBytes *fwupd_client_download_bytes_finish (FwupdClient *self, + GAsyncResult *res, GError **error); -GBytes *fwupd_client_upload_bytes (FwupdClient *self, +void fwupd_client_upload_bytes_async (FwupdClient *self, const gchar *url, const gchar *payload, const gchar *signature, FwupdClientUploadFlags flags, GCancellable *cancellable, + GAsyncReadyCallback callback, + gpointer callback_data); +GBytes *fwupd_client_upload_bytes_finish (FwupdClient *self, + GAsyncResult *res, GError **error); gboolean fwupd_client_ensure_networking (FwupdClient *self, GError **error); diff --git a/libfwupd/fwupd-common-private.h b/libfwupd/fwupd-common-private.h index fc1f91474..fb342eea2 100644 --- a/libfwupd/fwupd-common-private.h +++ b/libfwupd/fwupd-common-private.h @@ -6,7 +6,7 @@ #pragma once -#include +#include #ifdef HAVE_GIO_UNIX #include @@ -21,6 +21,14 @@ GVariant *fwupd_hash_kv_to_variant (GHashTable *hash); GHashTable *fwupd_variant_to_hash_kv (GVariant *dict); gchar *fwupd_build_user_agent_system (void); +void fwupd_input_stream_read_bytes_async (GInputStream *stream, + GCancellable *cancellable, + GAsyncReadyCallback callback, + gpointer callback_data); +GBytes *fwupd_input_stream_read_bytes_finish (GInputStream *stream, + GAsyncResult *res, + GError **error); + #ifdef HAVE_GIO_UNIX GUnixInputStream *fwupd_unix_input_stream_from_bytes (GBytes *bytes, GError **error); diff --git a/libfwupd/fwupd-common.c b/libfwupd/fwupd-common.c index 40bfc0387..705ecc2ae 100644 --- a/libfwupd/fwupd-common.c +++ b/libfwupd/fwupd-common.c @@ -941,6 +941,96 @@ fwupd_variant_to_hash_kv (GVariant *dict) return hash; } +static void +fwupd_input_stream_read_bytes_cb (GObject *source, + GAsyncResult *res, + gpointer user_data) +{ + GByteArray *bufarr; + GInputStream *stream = G_INPUT_STREAM (source); + g_autoptr(GBytes) bytes = NULL; + g_autoptr(GError) error = NULL; + g_autoptr(GTask) task = G_TASK (user_data); +#if GLIB_CHECK_VERSION(2, 64, 0) + guint8 *buf; + gsize bufsz = 0; +#endif + + /* read buf */ + bytes = g_input_stream_read_bytes_finish (stream, res, &error); + if (bytes == NULL) { + g_task_return_error (task, g_steal_pointer (&error)); + return; + } + + /* add bytes to buffer */ + bufarr = g_task_get_task_data (task); + if (g_bytes_get_size (bytes) > 0) { + GCancellable *cancellable = g_task_get_cancellable (task); + g_debug ("add %u", (guint) g_bytes_get_size (bytes)); + g_byte_array_append (bufarr, + g_bytes_get_data (bytes, NULL), + g_bytes_get_size (bytes)); + g_input_stream_read_bytes_async (g_steal_pointer (&stream), + 256 * 1024, /* bigger chunk */ + G_PRIORITY_DEFAULT, + cancellable, + fwupd_input_stream_read_bytes_cb, + g_steal_pointer (&task)); + return; + } + + /* success */ +#if GLIB_CHECK_VERSION(2, 64, 0) + buf = g_byte_array_steal (bufarr, &bufsz); + g_task_return_pointer (task, + g_bytes_new_take (buf, bufsz), + (GDestroyNotify) g_bytes_unref); +#else + g_task_return_pointer (task, + g_bytes_new (bufarr->data, bufarr->len), + (GDestroyNotify) g_bytes_unref); +#endif +} + +/** + * fwupd_input_stream_read_bytes_async: (skip): + **/ +void +fwupd_input_stream_read_bytes_async (GInputStream *stream, + GCancellable *cancellable, + GAsyncReadyCallback callback, + gpointer callback_data) +{ + g_autoptr(GTask) task = NULL; + + g_return_if_fail (G_IS_INPUT_STREAM (stream)); + g_return_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable)); + + task = g_task_new (stream, cancellable, callback, callback_data); + g_task_set_task_data (task, g_byte_array_new (), (GDestroyNotify) g_byte_array_unref); + g_input_stream_read_bytes_async (stream, + 64 * 1024, /* small */ + G_PRIORITY_DEFAULT, + cancellable, + fwupd_input_stream_read_bytes_cb, + g_steal_pointer (&task)); +} + +/** + * fwupd_input_stream_read_bytes_finish: (skip): + **/ +GBytes * +fwupd_input_stream_read_bytes_finish (GInputStream *stream, + GAsyncResult *res, + GError **error) +{ + g_return_val_if_fail (G_IS_INPUT_STREAM (stream), NULL); + g_return_val_if_fail (g_task_is_valid (res, stream), NULL); + g_return_val_if_fail (error == NULL || *error == NULL, NULL); + return g_task_propagate_pointer (G_TASK(res), error); +} + #ifdef HAVE_GIO_UNIX /** * fwupd_unix_input_stream_from_bytes: (skip): diff --git a/libfwupd/fwupd-device.c b/libfwupd/fwupd-device.c index 3d82ba344..64684b98f 100644 --- a/libfwupd/fwupd-device.c +++ b/libfwupd/fwupd-device.c @@ -1098,7 +1098,6 @@ fwupd_device_get_created (FwupdDevice *device) return priv->created; } - /** * fwupd_device_set_created: * @device: A #FwupdDevice diff --git a/libfwupd/fwupd-self-test.c b/libfwupd/fwupd-self-test.c index 679360b02..626c713b0 100644 --- a/libfwupd/fwupd-self-test.c +++ b/libfwupd/fwupd-self-test.c @@ -12,6 +12,7 @@ #endif #include "fwupd-client.h" +#include "fwupd-client-sync.h" #include "fwupd-common.h" #include "fwupd-enums.h" #include "fwupd-error.h" diff --git a/libfwupd/fwupd.h b/libfwupd/fwupd.h index 149f47862..a8bffb347 100644 --- a/libfwupd/fwupd.h +++ b/libfwupd/fwupd.h @@ -14,6 +14,7 @@ #define __FWUPD_H_INSIDE__ #include +#include #include #include #include diff --git a/libfwupd/fwupd.map b/libfwupd/fwupd.map index 1b669fe8a..a1ca0ff4d 100644 --- a/libfwupd/fwupd.map +++ b/libfwupd/fwupd.map @@ -478,9 +478,80 @@ LIBFWUPD_1.4.6 { LIBFWUPD_1.5.0 { global: + fwupd_client_activate_async; + fwupd_client_activate_finish; + fwupd_client_clear_results_async; + fwupd_client_clear_results_finish; + fwupd_client_connect_async; + fwupd_client_connect_finish; + fwupd_client_download_bytes_async; + fwupd_client_download_bytes_finish; + fwupd_client_get_approved_firmware_async; + fwupd_client_get_approved_firmware_finish; + fwupd_client_get_blocked_firmware_async; + fwupd_client_get_blocked_firmware_finish; + fwupd_client_get_details_bytes; + fwupd_client_get_details_bytes_async; + fwupd_client_get_details_bytes_finish; + fwupd_client_get_device_by_id_async; + fwupd_client_get_device_by_id_finish; + fwupd_client_get_devices_async; + fwupd_client_get_devices_by_guid_async; + fwupd_client_get_devices_by_guid_finish; + fwupd_client_get_devices_finish; + fwupd_client_get_downgrades_async; + fwupd_client_get_downgrades_finish; + fwupd_client_get_history_async; + fwupd_client_get_history_finish; fwupd_client_get_host_security_attrs; + fwupd_client_get_host_security_attrs_async; + fwupd_client_get_host_security_attrs_finish; fwupd_client_get_host_security_id; + fwupd_client_get_releases_async; + fwupd_client_get_releases_finish; + fwupd_client_get_remote_by_id_async; + fwupd_client_get_remote_by_id_finish; + fwupd_client_get_remotes_async; + fwupd_client_get_remotes_finish; fwupd_client_get_report_metadata; + fwupd_client_get_report_metadata_async; + fwupd_client_get_report_metadata_finish; + fwupd_client_get_results_async; + fwupd_client_get_results_finish; + fwupd_client_get_upgrades_async; + fwupd_client_get_upgrades_finish; + fwupd_client_install_async; + fwupd_client_install_bytes_async; + fwupd_client_install_bytes_finish; + fwupd_client_install_finish; + fwupd_client_install_release_async; + fwupd_client_install_release_finish; + fwupd_client_modify_config_async; + fwupd_client_modify_config_finish; + fwupd_client_modify_device_async; + fwupd_client_modify_device_finish; + fwupd_client_modify_remote_async; + fwupd_client_modify_remote_finish; + fwupd_client_refresh_remote_async; + fwupd_client_refresh_remote_finish; + fwupd_client_self_sign_async; + fwupd_client_self_sign_finish; + fwupd_client_set_approved_firmware_async; + fwupd_client_set_approved_firmware_finish; + fwupd_client_set_blocked_firmware_async; + fwupd_client_set_blocked_firmware_finish; + fwupd_client_set_feature_flags_async; + fwupd_client_set_feature_flags_finish; + fwupd_client_unlock_async; + fwupd_client_unlock_finish; + fwupd_client_update_metadata_bytes_async; + fwupd_client_update_metadata_bytes_finish; + fwupd_client_upload_bytes_async; + fwupd_client_upload_bytes_finish; + fwupd_client_verify_async; + fwupd_client_verify_finish; + fwupd_client_verify_update_async; + fwupd_client_verify_update_finish; fwupd_remote_get_automatic_security_reports; fwupd_remote_get_security_report_uri; fwupd_security_attr_add_flag; diff --git a/libfwupd/meson.build b/libfwupd/meson.build index a8772030c..57e35b0da 100644 --- a/libfwupd/meson.build +++ b/libfwupd/meson.build @@ -15,6 +15,7 @@ install_headers( install_headers([ 'fwupd-client.h', + 'fwupd-client-sync.h', 'fwupd-common.h', 'fwupd-deprecated.h', 'fwupd-device.h', @@ -34,6 +35,7 @@ fwupd = shared_library( 'fwupd', sources : [ 'fwupd-client.c', + 'fwupd-client-sync.c', 'fwupd-common.c', 'fwupd-device.c', 'fwupd-enums.c', @@ -76,6 +78,8 @@ if get_option('introspection') sources : [ 'fwupd-client.c', 'fwupd-client.h', + 'fwupd-client-sync.c', + 'fwupd-client-sync.h', 'fwupd-common.c', 'fwupd-common.h', 'fwupd-common-private.h', From 82f9a852019daaa4a2c4ec867e5123cbf57b3def Mon Sep 17 00:00:00 2001 From: Richard Hughes Date: Thu, 3 Sep 2020 09:40:10 +0100 Subject: [PATCH 381/607] Fall back from ID_VENDOR_FROM_DATABASE to ID_VENDOR for NVMe devices --- libfwupdplugin/fu-udev-device.c | 32 ++++++++++++++++++++++---------- 1 file changed, 22 insertions(+), 10 deletions(-) diff --git a/libfwupdplugin/fu-udev-device.c b/libfwupdplugin/fu-udev-device.c index 038f80739..07a422bbd 100644 --- a/libfwupdplugin/fu-udev-device.c +++ b/libfwupdplugin/fu-udev-device.c @@ -184,6 +184,24 @@ fu_udev_device_set_device_file (FuUdevDevice *self, const gchar *device_file) g_object_notify (G_OBJECT (self), "device-file"); } +static const gchar * +fu_udev_device_get_vendor_fallback (GUdevDevice *udev_device) +{ +#ifdef HAVE_GUDEV + const gchar *tmp; + tmp = g_udev_device_get_property (udev_device, "FWUPD_VENDOR"); + if (tmp != NULL) + return tmp; + tmp = g_udev_device_get_property (udev_device, "ID_VENDOR_FROM_DATABASE"); + if (tmp != NULL) + return tmp; + tmp = g_udev_device_get_property (udev_device, "ID_VENDOR"); + if (tmp != NULL) + return tmp; +#endif + return NULL; +} + static gboolean fu_udev_device_probe (FuDevice *device, GError **error) { @@ -256,11 +274,9 @@ fu_udev_device_probe (FuDevice *device, GError **error) g_autoptr(GUdevDevice) device_tmp = g_object_ref (udev_parent); for (guint i = 0; i < 0xff; i++) { g_autoptr(GUdevDevice) parent = NULL; - const gchar *id_vendor; - id_vendor = g_udev_device_get_property (device_tmp, - "ID_VENDOR_FROM_DATABASE"); - if (id_vendor != NULL) { - fu_device_set_vendor (device, id_vendor); + tmp = fu_udev_device_get_vendor_fallback (device_tmp); + if (tmp != NULL) { + fu_device_set_vendor (device, tmp); break; } parent = g_udev_device_get_parent (device_tmp); @@ -295,11 +311,7 @@ fu_udev_device_probe (FuDevice *device, GError **error) /* set vendor */ if (fu_device_get_vendor (device) == NULL) { - tmp = g_udev_device_get_property (priv->udev_device, "FWUPD_VENDOR"); - if (tmp == NULL) - tmp = g_udev_device_get_property (priv->udev_device, "ID_VENDOR_FROM_DATABASE"); - if (tmp == NULL) - tmp = g_udev_device_get_property (priv->udev_device, "ID_VENDOR"); + tmp = fu_udev_device_get_vendor_fallback (priv->udev_device); if (tmp != NULL) fu_device_set_vendor (device, tmp); } From ecb4d1416dd65fad102ec984966a15a82f57f11d Mon Sep 17 00:00:00 2001 From: Richard Hughes Date: Thu, 3 Sep 2020 09:42:34 +0100 Subject: [PATCH 382/607] trivial: Only use FU_UDEV_DEVICE_FLAG_VENDOR_FROM_PARENT as a fallback If the device node actually provides a vendor string, always use that before falling back. The flag was initially designed to fall back in the event the NVMe device does not declare a valid sysfs vendor ID. --- libfwupdplugin/fu-udev-device.c | 36 ++++++++++++++++----------------- 1 file changed, 18 insertions(+), 18 deletions(-) diff --git a/libfwupdplugin/fu-udev-device.c b/libfwupdplugin/fu-udev-device.c index 07a422bbd..8774d13e0 100644 --- a/libfwupdplugin/fu-udev-device.c +++ b/libfwupdplugin/fu-udev-device.c @@ -268,24 +268,6 @@ fu_udev_device_probe (FuDevice *device, GError **error) } } - /* try harder to find a vendor name the user will recognise */ - if (priv->flags & FU_UDEV_DEVICE_FLAG_VENDOR_FROM_PARENT && - udev_parent != NULL && fu_device_get_vendor (device) == NULL) { - g_autoptr(GUdevDevice) device_tmp = g_object_ref (udev_parent); - for (guint i = 0; i < 0xff; i++) { - g_autoptr(GUdevDevice) parent = NULL; - tmp = fu_udev_device_get_vendor_fallback (device_tmp); - if (tmp != NULL) { - fu_device_set_vendor (device, tmp); - break; - } - parent = g_udev_device_get_parent (device_tmp); - if (parent == NULL) - break; - g_set_object (&device_tmp, parent); - } - } - /* set the version if the revision has been set */ if (fu_device_get_version (device) == NULL && fu_device_get_version_format (device) == FWUPD_VERSION_FORMAT_UNKNOWN) { @@ -316,6 +298,24 @@ fu_udev_device_probe (FuDevice *device, GError **error) fu_device_set_vendor (device, tmp); } + /* try harder to find a vendor name the user will recognise */ + if (priv->flags & FU_UDEV_DEVICE_FLAG_VENDOR_FROM_PARENT && + udev_parent != NULL && fu_device_get_vendor (device) == NULL) { + g_autoptr(GUdevDevice) device_tmp = g_object_ref (udev_parent); + for (guint i = 0; i < 0xff; i++) { + g_autoptr(GUdevDevice) parent = NULL; + tmp = fu_udev_device_get_vendor_fallback (device_tmp); + if (tmp != NULL) { + fu_device_set_vendor (device, tmp); + break; + } + parent = g_udev_device_get_parent (device_tmp); + if (parent == NULL) + break; + g_set_object (&device_tmp, parent); + } + } + /* set serial */ if (fu_device_get_serial (device) == NULL) { tmp = g_udev_device_get_property (priv->udev_device, "ID_SERIAL_SHORT"); From 9a074074018565cc01f804c8ace22993eca97b3d Mon Sep 17 00:00:00 2001 From: Richard Hughes Date: Thu, 3 Sep 2020 10:03:15 +0100 Subject: [PATCH 383/607] Use the FuUdevDevice ->to_string() output Print the sysfs path for devices deriving from FuUdevDevice, which also allows us to use FU_UDEV_DEVICE_DEBUG without monkey-patching the plugins that also define a device_class->to_string() vfunc. --- libfwupdplugin/fu-udev-device.c | 34 +++++++++++-------- libfwupdplugin/fu-udev-device.h | 5 ++- plugins/emmc/fu-emmc-device.c | 4 +-- .../fu-logitech-hidpp-peripheral.c | 4 +-- .../fu-logitech-hidpp-runtime.c | 4 +-- plugins/nvme/fu-nvme-device.c | 4 +-- plugins/superio/fu-superio-device.c | 5 +-- .../synaptics-mst/fu-synaptics-mst-device.c | 4 +-- .../synaptics-rmi/fu-synaptics-rmi-device.c | 4 +-- plugins/thunderbolt/fu-thunderbolt-device.c | 4 +-- plugins/wacom-raw/fu-wacom-device.c | 4 +-- 11 files changed, 43 insertions(+), 33 deletions(-) diff --git a/libfwupdplugin/fu-udev-device.c b/libfwupdplugin/fu-udev-device.c index 8774d13e0..80fc65a82 100644 --- a/libfwupdplugin/fu-udev-device.c +++ b/libfwupdplugin/fu-udev-device.c @@ -120,6 +120,8 @@ static void fu_udev_device_to_string_raw (GUdevDevice *udev_device, guint idt, GString *str) { const gchar * const *keys; + if (udev_device == NULL) + return; keys = g_udev_device_get_property_keys (udev_device); for (guint i = 0; keys[i] != NULL; i++) { fu_common_string_append_kv (str, idt, keys[i], @@ -136,24 +138,28 @@ fu_udev_device_to_string_raw (GUdevDevice *udev_device, guint idt, GString *str) static void fu_udev_device_to_string (FuDevice *device, guint idt, GString *str) { -#ifdef HAVE_GUDEV FuUdevDevice *self = FU_UDEV_DEVICE (device); + FuUdevDeviceClass *klass = FU_UDEV_DEVICE_GET_CLASS (self); +#ifdef HAVE_GUDEV FuUdevDevicePrivate *priv = GET_PRIVATE (self); - g_autoptr(GUdevDevice) udev_parent = NULL; - - if (priv->udev_device == NULL) - return; - - if (g_getenv ("FU_UDEV_DEVICE_DEBUG") == NULL) - return; - - fu_udev_device_to_string_raw (priv->udev_device, idt, str); - udev_parent = g_udev_device_get_parent (priv->udev_device); - if (udev_parent != NULL) { - fu_common_string_append_kv (str, idt, "Parent", NULL); - fu_udev_device_to_string_raw (udev_parent, idt + 1, str); + if (priv->udev_device != NULL) { + fu_common_string_append_kv (str, idt, "SysfsPath", + g_udev_device_get_sysfs_path (priv->udev_device)); + } + if (g_getenv ("FU_UDEV_DEVICE_DEBUG") != NULL) { + g_autoptr(GUdevDevice) udev_parent = NULL; + fu_udev_device_to_string_raw (priv->udev_device, idt, str); + udev_parent = g_udev_device_get_parent (priv->udev_device); + if (udev_parent != NULL) { + fu_common_string_append_kv (str, idt, "Parent", NULL); + fu_udev_device_to_string_raw (udev_parent, idt + 1, str); + } } #endif + + /* subclassed */ + if (klass->to_string != NULL) + klass->to_string (self, idt, str); } static void diff --git a/libfwupdplugin/fu-udev-device.h b/libfwupdplugin/fu-udev-device.h index f0aa9af5c..ba50af081 100644 --- a/libfwupdplugin/fu-udev-device.h +++ b/libfwupdplugin/fu-udev-device.h @@ -29,7 +29,10 @@ struct _FuUdevDeviceClass GError **error); gboolean (*close) (FuUdevDevice *device, GError **error); - gpointer __reserved[29]; + void (*to_string) (FuUdevDevice *self, + guint indent, + GString *str); + gpointer __reserved[28]; }; /** diff --git a/plugins/emmc/fu-emmc-device.c b/plugins/emmc/fu-emmc-device.c index 043392e3e..301f55f05 100644 --- a/plugins/emmc/fu-emmc-device.c +++ b/plugins/emmc/fu-emmc-device.c @@ -71,7 +71,7 @@ struct _FuEmmcDevice { G_DEFINE_TYPE (FuEmmcDevice, fu_emmc_device, FU_TYPE_UDEV_DEVICE) static void -fu_emmc_device_to_string (FuDevice *device, guint idt, GString *str) +fu_emmc_device_to_string (FuUdevDevice *device, guint idt, GString *str) { FuEmmcDevice *self = FU_EMMC_DEVICE (device); fu_common_string_append_ku (str, idt, "SectorSize", self->sect_size); @@ -500,7 +500,7 @@ fu_emmc_device_class_init (FuEmmcDeviceClass *klass) FuUdevDeviceClass *klass_udev_device = FU_UDEV_DEVICE_CLASS (klass); object_class->finalize = fu_emmc_device_finalize; klass_device->setup = fu_emmc_device_setup; - klass_device->to_string = fu_emmc_device_to_string; + klass_udev_device->to_string = fu_emmc_device_to_string; klass_device->prepare_firmware = fu_emmc_device_prepare_firmware; klass_udev_device->probe = fu_emmc_device_probe; klass_device->write_firmware = fu_emmc_device_write_firmware; diff --git a/plugins/logitech-hidpp/fu-logitech-hidpp-peripheral.c b/plugins/logitech-hidpp/fu-logitech-hidpp-peripheral.c index 67ebe0575..288e5100d 100644 --- a/plugins/logitech-hidpp/fu-logitech-hidpp-peripheral.c +++ b/plugins/logitech-hidpp/fu-logitech-hidpp-peripheral.c @@ -258,7 +258,7 @@ fu_logitech_hidpp_map_to_string (FuLogitechHidPpHidppMap *map, guint idt, GStrin } static void -fu_logitech_hidpp_peripheral_to_string (FuDevice *device, guint idt, GString *str) +fu_logitech_hidpp_peripheral_to_string (FuUdevDevice *device, guint idt, GString *str) { FuLogitechHidPpPeripheral *self = FU_UNIFYING_PERIPHERAL (device); fu_common_string_append_ku (str, idt, "HidppVersion", self->hidpp_version); @@ -1029,7 +1029,7 @@ fu_logitech_hidpp_peripheral_class_init (FuLogitechHidPpPeripheralClass *klass) klass_device->attach = fu_logitech_hidpp_peripheral_attach; klass_device->detach = fu_logitech_hidpp_peripheral_detach; klass_device->poll = fu_logitech_hidpp_peripheral_poll; - klass_device->to_string = fu_logitech_hidpp_peripheral_to_string; + klass_device_udev->to_string = fu_logitech_hidpp_peripheral_to_string; klass_device_udev->probe = fu_logitech_hidpp_peripheral_probe; } diff --git a/plugins/logitech-hidpp/fu-logitech-hidpp-runtime.c b/plugins/logitech-hidpp/fu-logitech-hidpp-runtime.c index 869ff5065..0b53064b6 100644 --- a/plugins/logitech-hidpp/fu-logitech-hidpp-runtime.c +++ b/plugins/logitech-hidpp/fu-logitech-hidpp-runtime.c @@ -23,7 +23,7 @@ struct _FuLogitechHidPpRuntime G_DEFINE_TYPE (FuLogitechHidPpRuntime, fu_logitech_hidpp_runtime, FU_TYPE_UDEV_DEVICE) static void -fu_logitech_hidpp_runtime_to_string (FuDevice *device, guint idt, GString *str) +fu_logitech_hidpp_runtime_to_string (FuUdevDevice *device, guint idt, GString *str) { FuLogitechHidPpRuntime *self = FU_UNIFYING_RUNTIME (device); fu_common_string_append_kb (str, idt, "SignedFirmware", self->signed_firmware); @@ -316,7 +316,7 @@ fu_logitech_hidpp_runtime_class_init (FuLogitechHidPpRuntimeClass *klass) klass_device->close = fu_logitech_hidpp_runtime_close; klass_device->detach = fu_logitech_hidpp_runtime_detach; klass_device->poll = fu_logitech_hidpp_runtime_poll; - klass_device->to_string = fu_logitech_hidpp_runtime_to_string; + klass_device_udev->to_string = fu_logitech_hidpp_runtime_to_string; } static void diff --git a/plugins/nvme/fu-nvme-device.c b/plugins/nvme/fu-nvme-device.c index 15c1c8cba..4e92a217b 100644 --- a/plugins/nvme/fu-nvme-device.c +++ b/plugins/nvme/fu-nvme-device.c @@ -24,7 +24,7 @@ struct _FuNvmeDevice { G_DEFINE_TYPE (FuNvmeDevice, fu_nvme_device, FU_TYPE_UDEV_DEVICE) static void -fu_nvme_device_to_string (FuDevice *device, guint idt, GString *str) +fu_nvme_device_to_string (FuUdevDevice *device, guint idt, GString *str) { FuNvmeDevice *self = FU_NVME_DEVICE (device); fu_common_string_append_ku (str, idt, "PciDepth", self->pci_depth); @@ -412,7 +412,7 @@ fu_nvme_device_class_init (FuNvmeDeviceClass *klass) FuDeviceClass *klass_device = FU_DEVICE_CLASS (klass); FuUdevDeviceClass *klass_udev_device = FU_UDEV_DEVICE_CLASS (klass); object_class->finalize = fu_nvme_device_finalize; - klass_device->to_string = fu_nvme_device_to_string; + klass_udev_device->to_string = fu_nvme_device_to_string; klass_device->set_quirk_kv = fu_nvme_device_set_quirk_kv; klass_device->setup = fu_nvme_device_setup; klass_device->write_firmware = fu_nvme_device_write_firmware; diff --git a/plugins/superio/fu-superio-device.c b/plugins/superio/fu-superio-device.c index 348b8b95d..561e299be 100644 --- a/plugins/superio/fu-superio-device.c +++ b/plugins/superio/fu-superio-device.c @@ -111,7 +111,7 @@ fu_superio_device_regdump (FuSuperioDevice *self, guint8 ldn, GError **error) } static void -fu_superio_device_to_string (FuDevice *device, guint idt, GString *str) +fu_superio_device_to_string (FuUdevDevice *device, guint idt, GString *str) { FuSuperioDevice *self = FU_SUPERIO_DEVICE (device); FuSuperioDevicePrivate *priv = GET_PRIVATE (self); @@ -413,6 +413,7 @@ fu_superio_device_class_init (FuSuperioDeviceClass *klass) GObjectClass *object_class = G_OBJECT_CLASS (klass); GParamSpec *pspec; FuDeviceClass *klass_device = FU_DEVICE_CLASS (klass); + FuUdevDeviceClass *klass_udev_device = FU_UDEV_DEVICE_CLASS (klass); /* properties */ object_class->get_property = fu_superio_device_get_property; @@ -436,7 +437,7 @@ fu_superio_device_class_init (FuSuperioDeviceClass *klass) g_object_class_install_property (object_class, PROP_ID, pspec); object_class->finalize = fu_superio_device_finalize; - klass_device->to_string = fu_superio_device_to_string; + klass_udev_device->to_string = fu_superio_device_to_string; klass_device->probe = fu_superio_device_probe; klass_device->setup = fu_superio_device_setup; klass_device->prepare_firmware = fu_superio_device_prepare_firmware; diff --git a/plugins/synaptics-mst/fu-synaptics-mst-device.c b/plugins/synaptics-mst/fu-synaptics-mst-device.c index 77649a2d1..c36eedb67 100644 --- a/plugins/synaptics-mst/fu-synaptics-mst-device.c +++ b/plugins/synaptics-mst/fu-synaptics-mst-device.c @@ -81,7 +81,7 @@ fu_synaptics_mst_device_init (FuSynapticsMstDevice *self) } static void -fu_synaptics_mst_device_to_string (FuDevice *device, guint idt, GString *str) +fu_synaptics_mst_device_to_string (FuUdevDevice *device, guint idt, GString *str) { FuSynapticsMstDevice *self = FU_SYNAPTICS_MST_DEVICE (device); if (self->mode != FU_SYNAPTICS_MST_MODE_UNKNOWN) { @@ -1177,7 +1177,7 @@ fu_synaptics_mst_device_class_init (FuSynapticsMstDeviceClass *klass) FuDeviceClass *klass_device = FU_DEVICE_CLASS (klass); FuUdevDeviceClass *klass_udev_device = FU_UDEV_DEVICE_CLASS (klass); object_class->finalize = fu_synaptics_mst_device_finalize; - klass_device->to_string = fu_synaptics_mst_device_to_string; + klass_udev_device->to_string = fu_synaptics_mst_device_to_string; klass_device->rescan = fu_synaptics_mst_device_rescan; klass_device->write_firmware = fu_synaptics_mst_device_write_firmware; klass_device->prepare_firmware = fu_synaptics_mst_device_prepare_firmware; diff --git a/plugins/synaptics-rmi/fu-synaptics-rmi-device.c b/plugins/synaptics-rmi/fu-synaptics-rmi-device.c index 3c9cb8076..c957ac2fe 100644 --- a/plugins/synaptics-rmi/fu-synaptics-rmi-device.c +++ b/plugins/synaptics-rmi/fu-synaptics-rmi-device.c @@ -121,7 +121,7 @@ fu_synaptics_rmi_flash_to_string (FuSynapticsRmiFlash *flash, guint idt, GString } static void -fu_synaptics_rmi_device_to_string (FuDevice *device, guint idt, GString *str) +fu_synaptics_rmi_device_to_string (FuUdevDevice *device, guint idt, GString *str) { FuSynapticsRmiDevice *self = FU_SYNAPTICS_RMI_DEVICE (device); FuSynapticsRmiDevicePrivate *priv = GET_PRIVATE (self); @@ -1026,7 +1026,7 @@ fu_synaptics_rmi_device_class_init (FuSynapticsRmiDeviceClass *klass) FuDeviceClass *klass_device = FU_DEVICE_CLASS (klass); FuUdevDeviceClass *klass_device_udev = FU_UDEV_DEVICE_CLASS (klass); object_class->finalize = fu_synaptics_rmi_device_finalize; - klass_device->to_string = fu_synaptics_rmi_device_to_string; + klass_device_udev->to_string = fu_synaptics_rmi_device_to_string; klass_device->prepare_firmware = fu_synaptics_rmi_device_prepare_firmware; klass_device->attach = fu_synaptics_rmi_device_attach; klass_device->setup = fu_synaptics_rmi_device_setup; diff --git a/plugins/thunderbolt/fu-thunderbolt-device.c b/plugins/thunderbolt/fu-thunderbolt-device.c index ab24a907e..56af0a3af 100644 --- a/plugins/thunderbolt/fu-thunderbolt-device.c +++ b/plugins/thunderbolt/fu-thunderbolt-device.c @@ -198,7 +198,7 @@ fu_thunderbolt_device_type_to_string (FuThunderboltDevice *self) } static void -fu_thunderbolt_device_to_string (FuDevice *device, guint idt, GString *str) +fu_thunderbolt_device_to_string (FuUdevDevice *device, guint idt, GString *str) { FuThunderboltDevice *self = FU_THUNDERBOLT_DEVICE (device); fu_common_string_append_kv (str, idt, "Device Type", fu_thunderbolt_device_type_to_string (self)); @@ -717,7 +717,7 @@ fu_thunderbolt_device_class_init (FuThunderboltDeviceClass *klass) FuUdevDeviceClass *klass_udev_device = FU_UDEV_DEVICE_CLASS (klass); object_class->finalize = fu_thunderbolt_device_finalize; klass_device->activate = fu_thunderbolt_device_authenticate; - klass_device->to_string = fu_thunderbolt_device_to_string; + klass_udev_device->to_string = fu_thunderbolt_device_to_string; klass_device->setup = fu_thunderbolt_device_setup; klass_device->prepare_firmware = fu_thunderbolt_device_prepare_firmware; klass_device->write_firmware = fu_thunderbolt_device_write_firmware; diff --git a/plugins/wacom-raw/fu-wacom-device.c b/plugins/wacom-raw/fu-wacom-device.c index 745a88a61..1da396575 100644 --- a/plugins/wacom-raw/fu-wacom-device.c +++ b/plugins/wacom-raw/fu-wacom-device.c @@ -26,7 +26,7 @@ G_DEFINE_TYPE_WITH_PRIVATE (FuWacomDevice, fu_wacom_device, FU_TYPE_UDEV_DEVICE) #define GET_PRIVATE(o) (fu_wacom_device_get_instance_private (o)) static void -fu_wacom_device_to_string (FuDevice *device, guint idt, GString *str) +fu_wacom_device_to_string (FuUdevDevice *device, guint idt, GString *str) { FuWacomDevice *self = FU_WACOM_DEVICE (device); FuWacomDevicePrivate *priv = GET_PRIVATE (self); @@ -362,7 +362,7 @@ fu_wacom_device_class_init (FuWacomDeviceClass *klass) { FuDeviceClass *klass_device = FU_DEVICE_CLASS (klass); FuUdevDeviceClass *klass_device_udev = FU_UDEV_DEVICE_CLASS (klass); - klass_device->to_string = fu_wacom_device_to_string; + klass_device_udev->to_string = fu_wacom_device_to_string; klass_device->prepare_firmware = fu_wacom_device_prepare_firmware; klass_device->write_firmware = fu_wacom_device_write_firmware; klass_device->attach = fu_wacom_device_attach; From 2506dbff6f4cf5b469c92988dd7bb8c484281b30 Mon Sep 17 00:00:00 2001 From: Richard Hughes Date: Thu, 3 Sep 2020 10:04:19 +0100 Subject: [PATCH 384/607] trivial: Use the same indent size when appending key values --- libfwupdplugin/fu-common.c | 2 +- libfwupdplugin/fu-self-test.c | 22 +++++++++++----------- 2 files changed, 12 insertions(+), 12 deletions(-) diff --git a/libfwupdplugin/fu-common.c b/libfwupdplugin/fu-common.c index fbc9ff2aa..06b05712d 100644 --- a/libfwupdplugin/fu-common.c +++ b/libfwupdplugin/fu-common.c @@ -1261,7 +1261,7 @@ fu_common_strwidth (const gchar *text) void fu_common_string_append_kv (GString *str, guint idt, const gchar *key, const gchar *value) { - const guint align = 25; + const guint align = 24; gsize keysz; g_return_if_fail (idt * 2 < align); diff --git a/libfwupdplugin/fu-self-test.c b/libfwupdplugin/fu-self-test.c index ca4c8575a..8fcd81c54 100644 --- a/libfwupdplugin/fu-self-test.c +++ b/libfwupdplugin/fu-self-test.c @@ -119,11 +119,11 @@ fu_common_string_append_kv_func (void) fu_common_string_append_kv (str, 2, "key3", "value3"); g_assert_cmpstr (str->str, ==, "hdr:\n" - "key: value\n" - "key1: value1\n" - " key2: value2\n" - " value2\n" - " key3: value3\n"); + "key: value\n" + "key1: value1\n" + " key2: value2\n" + " value2\n" + " key3: value3\n"); } static void @@ -1625,13 +1625,13 @@ fu_firmware_func (void) str = fu_firmware_to_string (firmware); g_assert_cmpstr (str, ==, "FuFirmware:\n" " FuFirmwareImage:\n" - " ID: primary\n" - " Index: 0xd\n" - " Address: 0x200\n" + " ID: primary\n" + " Index: 0xd\n" + " Address: 0x200\n" " FuFirmwareImage:\n" - " ID: secondary\n" - " Index: 0x17\n" - " Address: 0x400\n"); + " ID: secondary\n" + " Index: 0x17\n" + " Address: 0x400\n"); } static void From ae7563d7d7e9d0abfe12ebf27fb402e40447f071 Mon Sep 17 00:00:00 2001 From: Jerry Zhang Date: Thu, 3 Sep 2020 22:56:58 -0500 Subject: [PATCH 385/607] dfu: Allow device to attach to normal without a bus reset As described in DFU protocol (7. Manifestation Phase), after the firmware reprogramming is done, if bitWillDetach = 1, it doesn't require the host to issue a USB bus reset, but the device can generate a detach-attach sequence itself to go back to normal. Add a quirk flag "no-bus-reset-attach" to skip the bus reset in dfu_device_attach(), and increase the "RemoveDelay" as well. --- plugins/dfu/dfu-device.c | 6 +++++- plugins/dfu/dfu.quirk | 20 ++++++++++---------- 2 files changed, 15 insertions(+), 11 deletions(-) diff --git a/plugins/dfu/dfu-device.c b/plugins/dfu/dfu-device.c index 792f12f43..34d332d84 100644 --- a/plugins/dfu/dfu-device.c +++ b/plugins/dfu/dfu-device.c @@ -45,6 +45,7 @@ * * `detach-for-attach`: Requires a DFU_REQUEST_DETACH to attach * * `absent-sector-size`: In absence of sector size, assume byte * * `manifest-poll`: Requires polling via GetStatus in dfuManifest state + * * `no-bus-reset-attach`: Do not require a bus reset to attach to normal * * Default value: `none` * @@ -1365,7 +1366,10 @@ dfu_device_attach (FuDevice *device, GError **error) return FALSE; /* normal DFU mode just needs a bus reset */ - if (!dfu_target_attach (target, error)) + if (fu_device_has_custom_flag (device, "no-bus-reset-attach") && + dfu_device_has_attribute (self, DFU_DEVICE_ATTRIBUTE_WILL_DETACH)) + g_debug ("Bus reset is not required. Device will reboot to normal"); + else if (!dfu_target_attach (target, error)) return FALSE; /* success */ diff --git a/plugins/dfu/dfu.quirk b/plugins/dfu/dfu.quirk index 73908e34d..a4e3c4e86 100644 --- a/plugins/dfu/dfu.quirk +++ b/plugins/dfu/dfu.quirk @@ -333,12 +333,12 @@ DfuForceTimeout = 5000 # Poly Studio [DeviceInstanceId=USB\VID_095D&PID_9217] Plugin = dfu -Flags = manifest-poll -RemoveDelay = 40000 +Flags = manifest-poll,no-bus-reset-attach +RemoveDelay = 60000 [DeviceInstanceId=USB\VID_095D&PID_9218] Plugin = dfu -Flags = manifest-poll -RemoveDelay = 40000 +Flags = manifest-poll,no-bus-reset-attach +RemoveDelay = 60000 # Poly Eagle Eye Cube [DeviceInstanceId=USB\VID_095D&PID_9212] @@ -354,21 +354,21 @@ RemoveDelay = 30000 [DeviceInstanceId=USB\VID_095D&PID_9290] Plugin = dfu Flags = manifest-poll -RemoveDelay = 40000 +RemoveDelay = 60000 [DeviceInstanceId=USB\VID_095D&PID_9291] Plugin = dfu Flags = manifest-poll -RemoveDelay = 40000 +RemoveDelay = 60000 # Poly ULCC [DeviceInstanceId=USB\VID_095D&PID_9160] Plugin = dfu -Flags = manifest-poll -RemoveDelay = 50000 +Flags = manifest-poll,no-bus-reset-attach +RemoveDelay = 60000 [DeviceInstanceId=USB\VID_095D&PID_927B] Plugin = dfu -Flags = manifest-poll -RemoveDelay = 50000 +Flags = manifest-poll,no-bus-reset-attach +RemoveDelay = 60000 # Poly Eagle Eye Mini [DeviceInstanceId=USB\VID_095D&PID_3001] From 581aa3c0bed46f40a241b7700a2acbd9e6af32e2 Mon Sep 17 00:00:00 2001 From: Richard Hughes Date: Wed, 2 Sep 2020 13:27:02 +0100 Subject: [PATCH 386/607] elantp: Support more hardware types Read the pattern from the hardware rather than hardcoding and support bigger page sizes for later hardware versions. --- plugins/elantp/elantp.quirk | 57 ++++++++++++++-- plugins/elantp/fu-elantp-common.h | 6 +- plugins/elantp/fu-elantp-hid-device.c | 93 +++++++++++++++++++++------ 3 files changed, 130 insertions(+), 26 deletions(-) diff --git a/plugins/elantp/elantp.quirk b/plugins/elantp/elantp.quirk index 7d3fcca80..4760d6489 100644 --- a/plugins/elantp/elantp.quirk +++ b/plugins/elantp/elantp.quirk @@ -6,19 +6,66 @@ GType = FuElantpHidDevice Plugin = elantp GType = FuElantpHidDevice +[DeviceInstanceId=ELANTP\ICTYPE_00] +ElantpIcPageCount = 0x200 +ElantpIapPassword = 0x1EA5 + +[DeviceInstanceId=ELANTP\ICTYPE_03] +ElantpIcPageCount = 0x300 +ElantpIapPassword = 0x1EA5 + +[DeviceInstanceId=ELANTP\ICTYPE_06] +ElantpIcPageCount = 0x200 +ElantpIapPassword = 0x1EA5 + +[DeviceInstanceId=ELANTP\ICTYPE_07] +ElantpIcPageCount = 0x300 +ElantpIapPassword = 0x1EA5 + +[DeviceInstanceId=ELANTP\ICTYPE_08] +ElantpIcPageCount = 0x200 +ElantpIapPassword = 0x1EA5 + [DeviceInstanceId=ELANTP\ICTYPE_0A] -ElantpIcPageCount = 768 +ElantpIcPageCount = 0x300 ElantpIapPassword = 0xE15A +[DeviceInstanceId=ELANTP\ICTYPE_0B] +ElantpIcPageCount = 0x300 +ElantpIapPassword = 0x1EA5 + +[DeviceInstanceId=ELANTP\ICTYPE_0C] +ElantpIcPageCount = 0x300 +ElantpIapPassword = 0x1EA5 + +[DeviceInstanceId=ELANTP\ICTYPE_0E] +ElantpIcPageCount = 0x280 +ElantpIapPassword = 0x1EA5 + [DeviceInstanceId=ELANTP\ICTYPE_09] -ElantpIcPageCount = 768 +ElantpIcPageCount = 0x300 ElantpIapPassword = 0x1EA5 [DeviceInstanceId=ELANTP\ICTYPE_0D] -ElantpIcPageCount = 896 +ElantpIcPageCount = 0x380 ElantpIapPassword = 0x1EA5 [DeviceInstanceId=ELANTP\ICTYPE_10] -ElantpIcPageCount = 1024 +ElantpIcPageCount = 0x400 +ElantpIapPassword = 0x1EA5 + +[DeviceInstanceId=ELANTP\ICTYPE_11] +ElantpIcPageCount = 0x500 +ElantpIapPassword = 0x1EA5 + +[DeviceInstanceId=ELANTP\ICTYPE_13] +ElantpIcPageCount = 0x800 +ElantpIapPassword = 0x1EA5 + +[DeviceInstanceId=ELANTP\ICTYPE_14] +ElantpIcPageCount = 0x400 +ElantpIapPassword = 0x1EA5 + +[DeviceInstanceId=ELANTP\ICTYPE_15] +ElantpIcPageCount = 0x400 ElantpIapPassword = 0x1EA5 -Flags = iap-version-2 diff --git a/plugins/elantp/fu-elantp-common.h b/plugins/elantp/fu-elantp-common.h index 94d60e1a5..a607be532 100644 --- a/plugins/elantp/fu-elantp-common.h +++ b/plugins/elantp/fu-elantp-common.h @@ -8,8 +8,6 @@ #include -#define FW_PAGE_SIZE 64 - #define ETP_CMD_GET_HARDWARE_ID 0x0100 #define ETP_CMD_GET_MODULE_ID 0x0101 #define ETP_CMD_I2C_FW_CHECKSUM 0x030F @@ -22,6 +20,10 @@ #define ETP_CMD_I2C_IAP_VERSION 0x0111 #define ETP_CMD_I2C_IAP_VERSION_2 0x0110 #define ETP_CMD_I2C_OSM_VERSION 0x0103 +#define ETP_CMD_I2C_GET_HID_ID 0x0100 +#define ETP_CMD_I2C_IAP_TYPE 0x0304 + +#define ETP_I2C_IAP_TYPE_REG 0x0040 #define ETP_I2C_ENABLE_REPORT 0x0800 diff --git a/plugins/elantp/fu-elantp-hid-device.c b/plugins/elantp/fu-elantp-hid-device.c index e6cb76ffe..6fffc162b 100644 --- a/plugins/elantp/fu-elantp-hid-device.c +++ b/plugins/elantp/fu-elantp-hid-device.c @@ -18,15 +18,19 @@ struct _FuElantpHidDevice { FuUdevDevice parent_instance; guint16 ic_page_count; + guint16 iap_type; guint16 iap_ctrl; guint16 iap_password; guint16 module_id; + guint16 fw_page_size; + guint8 pattern; }; #define ELANTP_DELAY_COMPLETE 1200 /* ms */ #define ELANTP_DELAY_RESET 30 /* ms */ #define ELANTP_DELAY_UNLOCK 100 /* ms */ #define ELANTP_DELAY_WRITE_BLOCK 35 /* ms */ +#define ELANTP_DELAY_WRITE_BLOCK_512 50 /* ms */ G_DEFINE_TYPE (FuElantpHidDevice, fu_elantp_hid_device, FU_TYPE_UDEV_DEVICE) @@ -35,8 +39,11 @@ fu_elantp_hid_device_to_string (FuDevice *device, guint idt, GString *str) { FuElantpHidDevice *self = FU_ELANTP_HID_DEVICE (device); fu_common_string_append_kx (str, idt, "ModuleId", self->module_id); + fu_common_string_append_kx (str, idt, "Pattern", self->pattern); + fu_common_string_append_kx (str, idt, "FwPageSize", self->fw_page_size); fu_common_string_append_kx (str, idt, "IcPageCount", self->ic_page_count); - fu_common_string_append_kx (str, idt, "EapCtrl", self->iap_ctrl); + fu_common_string_append_kx (str, idt, "IapType", self->iap_type); + fu_common_string_append_kx (str, idt, "IapCtrl", self->iap_ctrl); } static gboolean @@ -63,7 +70,10 @@ fu_elantp_hid_device_send_cmd (FuElantpHidDevice *self, GError **error) { g_autofree guint8 *buf = NULL; + gsize bufsz = rxsz + 3; + if (g_getenv ("FWUPD_ELANTP_VERBOSE") != NULL) + fu_common_dump_raw (G_LOG_DOMAIN, "SetReport", tx, txsz); if (!fu_udev_device_ioctl (FU_UDEV_DEVICE (self), HIDIOCSFEATURE(txsz), tx, NULL, error)) @@ -72,12 +82,14 @@ fu_elantp_hid_device_send_cmd (FuElantpHidDevice *self, return TRUE; /* GetFeature */ - buf = g_malloc0 (rxsz + 1); + buf = g_malloc0 (bufsz); buf[0] = tx[0]; /* report number */ if (!fu_udev_device_ioctl (FU_UDEV_DEVICE (self), - HIDIOCGFEATURE(rxsz + 3), buf, + HIDIOCGFEATURE(bufsz), buf, NULL, error)) return FALSE; + if (g_getenv ("FWUPD_ELANTP_VERBOSE") != NULL) + fu_common_dump_raw (G_LOG_DOMAIN, "GetReport", buf, bufsz); /* success */ memcpy (rx, buf + 0x3, rxsz); @@ -90,8 +102,6 @@ fu_elantp_hid_device_read_cmd (FuElantpHidDevice *self, guint16 reg, { guint8 buf[5] = { 0x0d, 0x05, 0x03 }; fu_common_write_uint16 (buf + 0x3, reg, G_LITTLE_ENDIAN); - if (g_getenv ("FWUPD_ELANTP_VERBOSE") != NULL) - fu_common_dump_raw (G_LOG_DOMAIN, "ReadCmd", buf, sizeof(buf)); return fu_elantp_hid_device_send_cmd (self, buf, sizeof(buf), rx, rxsz, error); } @@ -103,9 +113,6 @@ fu_elantp_hid_device_write_cmd (FuElantpHidDevice *self, guint8 buf[5] = { 0x0d }; fu_common_write_uint16 (buf + 0x1, reg, G_LITTLE_ENDIAN); fu_common_write_uint16 (buf + 0x3, cmd, G_LITTLE_ENDIAN); - if (g_getenv ("FWUPD_ELANTP_VERBOSE") != NULL) - fu_common_dump_raw (G_LOG_DOMAIN, "WriteCmd", buf, sizeof(buf)); - return fu_elantp_hid_device_send_cmd (self, buf, sizeof(buf), NULL, 0, error); } @@ -133,8 +140,8 @@ fu_elantp_hid_device_setup (FuDevice *device, GError **error) { FuElantpHidDevice *self = FU_ELANTP_HID_DEVICE (device); FuUdevDevice *udev_device = FU_UDEV_DEVICE (device); - gboolean is_new_pattern; guint16 fwver; + guint16 iap_ver; guint16 tmp; guint8 buf[2] = { 0x0 }; guint8 ic_type; @@ -143,6 +150,16 @@ fu_elantp_hid_device_setup (FuDevice *device, GError **error) g_autofree gchar *version_bl = NULL; g_autofree gchar *version = NULL; + /* get pattern */ + if (!fu_elantp_hid_device_read_cmd (self, + ETP_CMD_I2C_GET_HID_ID, + buf, sizeof(buf), error)) { + g_prefix_error (error, "failed to read HID ID: "); + return FALSE; + } + tmp = fu_common_read_uint16 (buf, G_LITTLE_ENDIAN); + self->pattern = tmp != 0xffff ? (tmp & 0xff00) >> 8 : 0; + /* get current firmware version */ if (!fu_elantp_hid_device_read_cmd (self, ETP_CMD_I2C_FW_VERSION, @@ -154,16 +171,19 @@ fu_elantp_hid_device_setup (FuDevice *device, GError **error) version = fu_common_version_from_uint16 (fwver, FWUPD_VERSION_FORMAT_HEX); fu_device_set_version (device, version); - /* get EAP firmware version */ - is_new_pattern = fu_device_has_custom_flag (FU_DEVICE (self), "iap-version-2"); + /* get IAP firmware version */ if (!fu_elantp_hid_device_read_cmd (self, - is_new_pattern ? ETP_CMD_I2C_IAP_VERSION_2 : ETP_CMD_I2C_IAP_VERSION, + self->pattern == 0 ? ETP_CMD_I2C_IAP_VERSION : ETP_CMD_I2C_IAP_VERSION_2, buf, sizeof(buf), error)) { g_prefix_error (error, "failed to read bootloader version: "); return FALSE; } - fwver = fu_common_read_uint16 (buf, G_LITTLE_ENDIAN); - version_bl = fu_common_version_from_uint16 (fwver, FWUPD_VERSION_FORMAT_HEX); + if (self->pattern >= 1) { + iap_ver = buf[1]; + } else { + iap_ver = fu_common_read_uint16 (buf, G_LITTLE_ENDIAN); + } + version_bl = fu_common_version_from_uint16 (iap_ver, FWUPD_VERSION_FORMAT_HEX); fu_device_set_version_bootloader (device, version_bl); /* get module ID */ @@ -200,6 +220,37 @@ fu_elantp_hid_device_setup (FuDevice *device, GError **error) instance_id_ic_type = g_strdup_printf ("ELANTP\\ICTYPE_%02X", ic_type); fu_device_add_instance_id (device, instance_id_ic_type); + /* set the page size */ + self->fw_page_size = 64; + if (ic_type >= 0x10) { + if (iap_ver >= 1) { + /* set the IAP type, presumably some kind of ABI */ + if (!fu_elantp_hid_device_write_cmd (self, + ETP_CMD_I2C_IAP_TYPE, + ETP_I2C_IAP_TYPE_REG, + error)) + return FALSE; + if (!fu_elantp_hid_device_read_cmd (self, ETP_CMD_I2C_IAP_TYPE, + buf, sizeof(buf), error)) { + g_prefix_error (error, "failed to read IAP type: "); + return FALSE; + } + self->iap_type = fu_common_read_uint16 (buf, G_LITTLE_ENDIAN); + if (self->iap_type != ETP_I2C_IAP_TYPE_REG) { + g_set_error_literal (error, + FWUPD_ERROR, + FWUPD_ERROR_NOT_SUPPORTED, + "failed to set IAP type"); + return FALSE; + } + if (iap_ver >= 2 && (ic_type == 0x14 || ic_type==0x15)) { + self->fw_page_size = 512; + } else { + self->fw_page_size = 128; + } + } + } + /* no quirk entry */ if (self->ic_page_count == 0x0) { g_set_error (error, @@ -209,7 +260,7 @@ fu_elantp_hid_device_setup (FuDevice *device, GError **error) ic_type); return FALSE; } - fu_device_set_firmware_size (device, self->ic_page_count * FW_PAGE_SIZE); + fu_device_set_firmware_size (device, (guint64) self->ic_page_count * (guint64) self->fw_page_size); /* is in bootloader mode */ if (!fu_elantp_hid_device_ensure_iap_ctrl (self, error)) @@ -293,20 +344,24 @@ fu_elantp_hid_device_write_firmware (FuDevice *device, fu_device_set_status (device, FWUPD_STATUS_DEVICE_WRITE); buf = g_bytes_get_data (fw, &bufsz); iap_addr = fu_elantp_firmware_get_iap_addr (firmware_elantp); - chunks = fu_chunk_array_new (buf + iap_addr, bufsz - iap_addr, 0x0, 0x0, FW_PAGE_SIZE); + chunks = fu_chunk_array_new (buf + iap_addr, bufsz - iap_addr, 0x0, 0x0, self->fw_page_size); for (guint i = 0; i < chunks->len; i++) { FuChunk *chk = g_ptr_array_index (chunks, i); guint16 csum_tmp = fu_elantp_calc_checksum (chk->data, chk->data_sz); - guint8 blk[FW_PAGE_SIZE + 3]; + gsize blksz = self->fw_page_size + 3; + g_autofree guint8 *blk = g_malloc0 (blksz); /* write block */ blk[0] = 0x0B; /* report ID */ memcpy (blk + 1, chk->data, chk->data_sz); fu_common_write_uint16 (blk + chk->data_sz + 1, csum_tmp, G_LITTLE_ENDIAN); - if (!fu_elantp_hid_device_send_cmd (self, blk, sizeof (blk), NULL, 0, error)) + if (!fu_elantp_hid_device_send_cmd (self, blk, blksz, NULL, 0, error)) return FALSE; - g_usleep (ELANTP_DELAY_WRITE_BLOCK * 1000); + g_usleep (self->fw_page_size == 512 ? + ELANTP_DELAY_WRITE_BLOCK_512 * 1000 : + ELANTP_DELAY_WRITE_BLOCK * 1000); + if (!fu_elantp_hid_device_ensure_iap_ctrl (self, error)) return FALSE; if (self->iap_ctrl & (ETP_FW_IAP_PAGE_ERR | ETP_FW_IAP_INTF_ERR)) { From fbe3304420ffdd0994834cf1a052c6c4104acb71 Mon Sep 17 00:00:00 2001 From: Richard Hughes Date: Tue, 8 Sep 2020 11:42:28 +0100 Subject: [PATCH 387/607] trivial: Remove the anti-pattern where plugins check the firmware size This is already done in fu_device_prepare_firmware() and so is completely redundant. --- plugins/elantp/fu-elantp-hid-device.c | 20 -------------------- plugins/fresco-pd/fu-fresco-pd-device.c | 11 ----------- plugins/vli/fu-vli-pd-parade-device.c | 21 --------------------- plugins/vli/fu-vli-usbhub-device.c | 20 -------------------- plugins/vli/fu-vli-usbhub-pd-device.c | 20 -------------------- 5 files changed, 92 deletions(-) diff --git a/plugins/elantp/fu-elantp-hid-device.c b/plugins/elantp/fu-elantp-hid-device.c index 6fffc162b..f4b1be798 100644 --- a/plugins/elantp/fu-elantp-hid-device.c +++ b/plugins/elantp/fu-elantp-hid-device.c @@ -280,26 +280,6 @@ fu_elantp_hid_device_prepare_firmware (FuDevice *device, guint16 module_id; g_autoptr(FuFirmware) firmware = fu_elantp_firmware_new (); - /* check size */ - if (g_bytes_get_size (fw) < fu_device_get_firmware_size_min (device)) { - g_set_error (error, - FWUPD_ERROR, - FWUPD_ERROR_INVALID_FILE, - "firmware too small, got 0x%x, expected >= 0x%x", - (guint) g_bytes_get_size (fw), - (guint) fu_device_get_firmware_size_min (device)); - return NULL; - } - if (g_bytes_get_size (fw) > fu_device_get_firmware_size_max (device)) { - g_set_error (error, - FWUPD_ERROR, - FWUPD_ERROR_INVALID_FILE, - "firmware too large, got 0x%x, expected <= 0x%x", - (guint) g_bytes_get_size (fw), - (guint) fu_device_get_firmware_size_max (device)); - return NULL; - } - /* check is compatible with hardware */ fu_device_set_status (device, FWUPD_STATUS_DECOMPRESSING); if (!fu_firmware_parse (firmware, fw, flags, error)) diff --git a/plugins/fresco-pd/fu-fresco-pd-device.c b/plugins/fresco-pd/fu-fresco-pd-device.c index 745f6f251..3e9775109 100644 --- a/plugins/fresco-pd/fu-fresco-pd-device.c +++ b/plugins/fresco-pd/fu-fresco-pd-device.c @@ -203,17 +203,6 @@ fu_fresco_pd_device_prepare_firmware (FuDevice *device, guint8 customer_id; g_autoptr(FuFirmware) firmware = fu_fresco_pd_firmware_new (); - /* check size */ - if (g_bytes_get_size (fw) < fu_device_get_firmware_size_min (device)) { - g_set_error (error, - FWUPD_ERROR, - FWUPD_ERROR_INVALID_FILE, - "firmware too small, got 0x%x, expected >= 0x%x", - (guint) g_bytes_get_size (fw), - (guint) fu_device_get_firmware_size_min (device)); - return NULL; - } - /* check firmware is suitable */ fu_device_set_status (device, FWUPD_STATUS_DECOMPRESSING); if (!fu_firmware_parse (firmware, fw, flags, error)) diff --git a/plugins/vli/fu-vli-pd-parade-device.c b/plugins/vli/fu-vli-pd-parade-device.c index 6da3d283a..2bf8b0317 100644 --- a/plugins/vli/fu-vli-pd-parade-device.c +++ b/plugins/vli/fu-vli-pd-parade-device.c @@ -613,26 +613,6 @@ fu_vli_pd_parade_device_read_firmware (FuDevice *device, GError **error) return fu_firmware_new_from_bytes (fw); } - -static FuFirmware * -fu_vli_pd_parade_device_prepare_firmware (FuDevice *device, - GBytes *fw, - FwupdInstallFlags flags, - GError **error) -{ - /* check size */ - if (g_bytes_get_size (fw) < fu_device_get_firmware_size_min (device)) { - g_set_error (error, - FWUPD_ERROR, - FWUPD_ERROR_INVALID_FILE, - "firmware too small, got 0x%x, expected >= 0x%x", - (guint) g_bytes_get_size (fw), - (guint) fu_device_get_firmware_size_min (device)); - return NULL; - } - return fu_firmware_new_from_bytes (fw); -} - static gboolean fu_vli_pd_parade_device_probe (FuDevice *device, GError **error) { @@ -678,7 +658,6 @@ fu_vli_pd_parade_device_class_init (FuVliPdParadeDeviceClass *klass) klass_device->to_string = fu_vli_pd_parade_device_to_string; klass_device->probe = fu_vli_pd_parade_device_probe; klass_device->read_firmware = fu_vli_pd_parade_device_read_firmware; - klass_device->prepare_firmware = fu_vli_pd_parade_device_prepare_firmware; klass_device->write_firmware = fu_vli_pd_parade_device_write_firmware; } diff --git a/plugins/vli/fu-vli-usbhub-device.c b/plugins/vli/fu-vli-usbhub-device.c index 9502d2d97..9dd46d022 100644 --- a/plugins/vli/fu-vli-usbhub-device.c +++ b/plugins/vli/fu-vli-usbhub-device.c @@ -693,26 +693,6 @@ fu_vli_usbhub_device_prepare_firmware (FuDevice *device, guint16 device_id; g_autoptr(FuFirmware) firmware = fu_vli_usbhub_firmware_new (); - /* check size */ - if (g_bytes_get_size (fw) < fu_device_get_firmware_size_min (device)) { - g_set_error (error, - FWUPD_ERROR, - FWUPD_ERROR_INVALID_FILE, - "firmware too small, got 0x%x, expected >= 0x%x", - (guint) g_bytes_get_size (fw), - (guint) fu_device_get_firmware_size_min (device)); - return NULL; - } - if (g_bytes_get_size (fw) > fu_device_get_firmware_size_max (device)) { - g_set_error (error, - FWUPD_ERROR, - FWUPD_ERROR_INVALID_FILE, - "firmware too large, got 0x%x, expected <= 0x%x", - (guint) g_bytes_get_size (fw), - (guint) fu_device_get_firmware_size_max (device)); - return NULL; - } - /* check is compatible with firmware */ fu_device_set_status (device, FWUPD_STATUS_DECOMPRESSING); if (!fu_firmware_parse (firmware, fw, flags, error)) diff --git a/plugins/vli/fu-vli-usbhub-pd-device.c b/plugins/vli/fu-vli-usbhub-pd-device.c index 9209e6436..c02608b6e 100644 --- a/plugins/vli/fu-vli-usbhub-pd-device.c +++ b/plugins/vli/fu-vli-usbhub-pd-device.c @@ -104,26 +104,6 @@ fu_vli_usbhub_pd_device_prepare_firmware (FuDevice *device, FuVliDeviceKind device_kind; g_autoptr(FuFirmware) firmware = fu_vli_pd_firmware_new (); - /* check size */ - if (g_bytes_get_size (fw) < fu_device_get_firmware_size_min (device)) { - g_set_error (error, - FWUPD_ERROR, - FWUPD_ERROR_INVALID_FILE, - "firmware too small, got 0x%x, expected >= 0x%x", - (guint) g_bytes_get_size (fw), - (guint) fu_device_get_firmware_size_min (device)); - return NULL; - } - if (g_bytes_get_size (fw) > fu_device_get_firmware_size_max (device)) { - g_set_error (error, - FWUPD_ERROR, - FWUPD_ERROR_INVALID_FILE, - "firmware too large, got 0x%x, expected <= 0x%x", - (guint) g_bytes_get_size (fw), - (guint) fu_device_get_firmware_size_max (device)); - return NULL; - } - /* check is compatible with firmware */ fu_device_set_status (device, FWUPD_STATUS_DECOMPRESSING); if (!fu_firmware_parse (firmware, fw, flags, error)) From 9b688d0b732a48247124b26ddc4447a1b2965d33 Mon Sep 17 00:00:00 2001 From: Richard Hughes Date: Tue, 8 Sep 2020 11:49:15 +0100 Subject: [PATCH 388/607] trivial: Set FWUPD_STATUS_DECOMPRESSING when preparing firmware This avoids the plugins forgetting to do it themselves. --- libfwupdplugin/fu-device.c | 1 + plugins/cros-ec/fu-cros-ec-usb-device.c | 1 - plugins/ebitdo/fu-ebitdo-device.c | 1 - plugins/elantp/fu-elantp-hid-device.c | 1 - plugins/ep963x/fu-ep963x-device.c | 1 - plugins/fresco-pd/fu-fresco-pd-device.c | 1 - plugins/solokey/fu-solokey-device.c | 1 - plugins/synaptics-cxaudio/fu-synaptics-cxaudio-device.c | 2 -- plugins/synaptics-prometheus/fu-synaprom-config.c | 1 - plugins/synaptics-prometheus/fu-synaprom-device.c | 1 - plugins/uefi-dbx/fu-uefi-dbx-device.c | 1 - plugins/vli/fu-vli-pd-device.c | 1 - plugins/vli/fu-vli-usbhub-device.c | 1 - plugins/vli/fu-vli-usbhub-msp430-device.c | 1 - plugins/vli/fu-vli-usbhub-pd-device.c | 1 - plugins/wacom-usb/fu-wac-device.c | 1 - 16 files changed, 1 insertion(+), 16 deletions(-) diff --git a/libfwupdplugin/fu-device.c b/libfwupdplugin/fu-device.c index 167a38409..c7f2b1f01 100644 --- a/libfwupdplugin/fu-device.c +++ b/libfwupdplugin/fu-device.c @@ -2487,6 +2487,7 @@ fu_device_prepare_firmware (FuDevice *self, /* optionally subclassed */ if (klass->prepare_firmware != NULL) { + fu_device_set_status (self, FWUPD_STATUS_DECOMPRESSING); firmware = klass->prepare_firmware (self, fw, flags, error); if (firmware == NULL) return NULL; diff --git a/plugins/cros-ec/fu-cros-ec-usb-device.c b/plugins/cros-ec/fu-cros-ec-usb-device.c index 97b187f65..24864aa39 100644 --- a/plugins/cros-ec/fu-cros-ec-usb-device.c +++ b/plugins/cros-ec/fu-cros-ec-usb-device.c @@ -777,7 +777,6 @@ fu_cros_ec_usb_device_prepare_firmware (FuDevice *device, FuCrosEcFirmware *cros_ec_firmware = NULL; g_autoptr(FuFirmware) firmware = fu_cros_ec_firmware_new (); - fu_device_set_status (device, FWUPD_STATUS_DECOMPRESSING); if (!fu_firmware_parse (firmware, fw, flags, error)) return NULL; cros_ec_firmware = FU_CROS_EC_FIRMWARE (firmware); diff --git a/plugins/ebitdo/fu-ebitdo-device.c b/plugins/ebitdo/fu-ebitdo-device.c index 4a9311910..97c916aa5 100644 --- a/plugins/ebitdo/fu-ebitdo-device.c +++ b/plugins/ebitdo/fu-ebitdo-device.c @@ -581,7 +581,6 @@ fu_ebitdo_device_prepare_firmware (FuDevice *device, GError **error) { g_autoptr(FuFirmware) firmware = fu_ebitdo_firmware_new (); - fu_device_set_status (device, FWUPD_STATUS_DECOMPRESSING); if (!fu_firmware_parse (firmware, fw, flags, error)) return NULL; return g_steal_pointer (&firmware); diff --git a/plugins/elantp/fu-elantp-hid-device.c b/plugins/elantp/fu-elantp-hid-device.c index f4b1be798..62fc7b64c 100644 --- a/plugins/elantp/fu-elantp-hid-device.c +++ b/plugins/elantp/fu-elantp-hid-device.c @@ -281,7 +281,6 @@ fu_elantp_hid_device_prepare_firmware (FuDevice *device, g_autoptr(FuFirmware) firmware = fu_elantp_firmware_new (); /* check is compatible with hardware */ - fu_device_set_status (device, FWUPD_STATUS_DECOMPRESSING); if (!fu_firmware_parse (firmware, fw, flags, error)) return NULL; module_id = fu_elantp_firmware_get_module_id (FU_ELANTP_FIRMWARE (firmware)); diff --git a/plugins/ep963x/fu-ep963x-device.c b/plugins/ep963x/fu-ep963x-device.c index 916b64c31..2c833b1ed 100644 --- a/plugins/ep963x/fu-ep963x-device.c +++ b/plugins/ep963x/fu-ep963x-device.c @@ -182,7 +182,6 @@ fu_ep963x_device_prepare_firmware (FuDevice *device, GError **error) { g_autoptr(FuFirmware) firmware = fu_ep963x_firmware_new (); - fu_device_set_status (device, FWUPD_STATUS_DECOMPRESSING); if (!fu_firmware_parse (firmware, fw, flags, error)) return NULL; return g_steal_pointer (&firmware); diff --git a/plugins/fresco-pd/fu-fresco-pd-device.c b/plugins/fresco-pd/fu-fresco-pd-device.c index 3e9775109..df1d9977c 100644 --- a/plugins/fresco-pd/fu-fresco-pd-device.c +++ b/plugins/fresco-pd/fu-fresco-pd-device.c @@ -204,7 +204,6 @@ fu_fresco_pd_device_prepare_firmware (FuDevice *device, g_autoptr(FuFirmware) firmware = fu_fresco_pd_firmware_new (); /* check firmware is suitable */ - fu_device_set_status (device, FWUPD_STATUS_DECOMPRESSING); if (!fu_firmware_parse (firmware, fw, flags, error)) return NULL; customer_id = fu_fresco_pd_firmware_get_customer_id (FU_FRESCO_PD_FIRMWARE (firmware)); diff --git a/plugins/solokey/fu-solokey-device.c b/plugins/solokey/fu-solokey-device.c index 13d85a1e8..ef329030d 100644 --- a/plugins/solokey/fu-solokey-device.c +++ b/plugins/solokey/fu-solokey-device.c @@ -407,7 +407,6 @@ fu_solokey_device_prepare_firmware (FuDevice *device, GError **error) { g_autoptr(FuFirmware) firmware = fu_solokey_firmware_new (); - fu_device_set_status (device, FWUPD_STATUS_DECOMPRESSING); if (!fu_firmware_parse (firmware, fw, flags, error)) return NULL; return g_steal_pointer (&firmware); diff --git a/plugins/synaptics-cxaudio/fu-synaptics-cxaudio-device.c b/plugins/synaptics-cxaudio/fu-synaptics-cxaudio-device.c index 76a8f09b7..7abdd3ddb 100644 --- a/plugins/synaptics-cxaudio/fu-synaptics-cxaudio-device.c +++ b/plugins/synaptics-cxaudio/fu-synaptics-cxaudio-device.c @@ -550,8 +550,6 @@ fu_synaptics_cxaudio_device_prepare_firmware (FuDevice *device, FuSynapticsCxaudioDevice *self = FU_SYNAPTICS_CXAUDIO_DEVICE (device); guint32 chip_id_base; g_autoptr(FuFirmware) firmware = fu_synaptics_cxaudio_firmware_new (); - - fu_device_set_status (device, FWUPD_STATUS_DECOMPRESSING); if (!fu_firmware_parse (firmware, fw, flags, error)) return NULL; chip_id_base = fu_synaptics_cxaudio_firmware_get_devtype (FU_SYNAPTICS_CXAUDIO_FIRMWARE (firmware)); diff --git a/plugins/synaptics-prometheus/fu-synaprom-config.c b/plugins/synaptics-prometheus/fu-synaprom-config.c index 371d8d809..628a764f2 100644 --- a/plugins/synaptics-prometheus/fu-synaprom-config.c +++ b/plugins/synaptics-prometheus/fu-synaprom-config.c @@ -133,7 +133,6 @@ fu_synaprom_config_prepare_firmware (FuDevice *device, guint32 id2; /* parse the firmware */ - fu_device_set_status (device, FWUPD_STATUS_DECOMPRESSING); if (!fu_firmware_parse (firmware, fw, flags, error)) return NULL; diff --git a/plugins/synaptics-prometheus/fu-synaprom-device.c b/plugins/synaptics-prometheus/fu-synaprom-device.c index 299ebde27..fb8822bcb 100644 --- a/plugins/synaptics-prometheus/fu-synaprom-device.c +++ b/plugins/synaptics-prometheus/fu-synaprom-device.c @@ -252,7 +252,6 @@ fu_synaprom_device_prepare_fw (FuDevice *device, g_autoptr(FuFirmware) firmware = fu_synaprom_firmware_new (); /* parse the firmware */ - fu_device_set_status (device, FWUPD_STATUS_DECOMPRESSING); if (!fu_firmware_parse (firmware, fw, flags, error)) return NULL; diff --git a/plugins/uefi-dbx/fu-uefi-dbx-device.c b/plugins/uefi-dbx/fu-uefi-dbx-device.c index 3236a1be2..fad3a403b 100644 --- a/plugins/uefi-dbx/fu-uefi-dbx-device.c +++ b/plugins/uefi-dbx/fu-uefi-dbx-device.c @@ -87,7 +87,6 @@ fu_uefi_dbx_prepare_firmware (FuDevice *device, g_autoptr(GPtrArray) siglists = NULL; /* parse dbx */ - fu_device_set_status (device, FWUPD_STATUS_DECOMPRESSING); buf = g_bytes_get_data (fw, &bufsz); siglists = fu_efi_signature_parser_new (buf, bufsz, FU_EFI_SIGNATURE_PARSER_FLAGS_IGNORE_HEADER, diff --git a/plugins/vli/fu-vli-pd-device.c b/plugins/vli/fu-vli-pd-device.c index 024f71596..d7348fbb3 100644 --- a/plugins/vli/fu-vli-pd-device.c +++ b/plugins/vli/fu-vli-pd-device.c @@ -344,7 +344,6 @@ fu_vli_pd_device_prepare_firmware (FuDevice *device, } /* check is compatible with firmware */ - fu_device_set_status (device, FWUPD_STATUS_DECOMPRESSING); if (!fu_firmware_parse (firmware, fw, flags, error)) return NULL; device_kind = fu_vli_pd_firmware_get_kind (FU_VLI_PD_FIRMWARE (firmware)); diff --git a/plugins/vli/fu-vli-usbhub-device.c b/plugins/vli/fu-vli-usbhub-device.c index 9dd46d022..b495cf242 100644 --- a/plugins/vli/fu-vli-usbhub-device.c +++ b/plugins/vli/fu-vli-usbhub-device.c @@ -694,7 +694,6 @@ fu_vli_usbhub_device_prepare_firmware (FuDevice *device, g_autoptr(FuFirmware) firmware = fu_vli_usbhub_firmware_new (); /* check is compatible with firmware */ - fu_device_set_status (device, FWUPD_STATUS_DECOMPRESSING); if (!fu_firmware_parse (firmware, fw, flags, error)) return NULL; device_kind = fu_vli_usbhub_firmware_get_device_kind (FU_VLI_USBHUB_FIRMWARE (firmware)); diff --git a/plugins/vli/fu-vli-usbhub-msp430-device.c b/plugins/vli/fu-vli-usbhub-msp430-device.c index e7597b8fd..49ca4de45 100644 --- a/plugins/vli/fu-vli-usbhub-msp430-device.c +++ b/plugins/vli/fu-vli-usbhub-msp430-device.c @@ -167,7 +167,6 @@ fu_vli_usbhub_msp430_device_prepare_firmware (FuDevice *device, GError **error) { g_autoptr(FuFirmware) firmware = fu_ihex_firmware_new (); - fu_device_set_status (device, FWUPD_STATUS_DECOMPRESSING); if (!fu_firmware_tokenize (firmware, fw, flags, error)) return NULL; return g_steal_pointer (&firmware); diff --git a/plugins/vli/fu-vli-usbhub-pd-device.c b/plugins/vli/fu-vli-usbhub-pd-device.c index c02608b6e..28ccb8ea4 100644 --- a/plugins/vli/fu-vli-usbhub-pd-device.c +++ b/plugins/vli/fu-vli-usbhub-pd-device.c @@ -105,7 +105,6 @@ fu_vli_usbhub_pd_device_prepare_firmware (FuDevice *device, g_autoptr(FuFirmware) firmware = fu_vli_pd_firmware_new (); /* check is compatible with firmware */ - fu_device_set_status (device, FWUPD_STATUS_DECOMPRESSING); if (!fu_firmware_parse (firmware, fw, flags, error)) return NULL; device_kind = fu_vli_pd_firmware_get_kind (FU_VLI_PD_FIRMWARE (firmware)); diff --git a/plugins/wacom-usb/fu-wac-device.c b/plugins/wacom-usb/fu-wac-device.c index a7ed34fb5..b49e80c72 100644 --- a/plugins/wacom-usb/fu-wac-device.c +++ b/plugins/wacom-usb/fu-wac-device.c @@ -435,7 +435,6 @@ fu_wac_device_prepare_firmware (FuDevice *device, GError **error) { g_autoptr(FuFirmware) firmware = fu_wac_firmware_new (); - fu_device_set_status (device, FWUPD_STATUS_DECOMPRESSING); if (!fu_firmware_parse (firmware, fw, flags, error)) return NULL; return g_steal_pointer (&firmware); From 45fbc50f8d68809270df9ecc9def7b6caabeeefb Mon Sep 17 00:00:00 2001 From: Richard Hughes Date: Mon, 7 Sep 2020 09:20:23 +0100 Subject: [PATCH 389/607] mei: Document some more of HFSTS6 --- plugins/pci-mei/fu-mei-common.c | 22 ++++++++++++++++------ plugins/pci-mei/fu-mei-common.h | 11 ++++++++--- 2 files changed, 24 insertions(+), 9 deletions(-) diff --git a/plugins/pci-mei/fu-mei-common.c b/plugins/pci-mei/fu-mei-common.c index 87be19179..1230e1460 100644 --- a/plugins/pci-mei/fu-mei-common.c +++ b/plugins/pci-mei/fu-mei-common.c @@ -271,20 +271,30 @@ fu_mei_hfsts2_to_string (FuMeiHfsts2 hfsts2, guint idt, GString *str) void fu_mei_hfsts3_to_string (FuMeiHfsts3 hfsts3, guint idt, GString *str) { - fu_common_string_append_kx (str, idt, "Reserved0", - hfsts3.fields.reserved_0); + fu_common_string_append_kx (str, idt, "Chunk0", + hfsts3.fields.chunk0); + fu_common_string_append_kx (str, idt, "Chunk1", + hfsts3.fields.chunk1); + fu_common_string_append_kx (str, idt, "Chunk2", + hfsts3.fields.chunk2); + fu_common_string_append_kx (str, idt, "Chunk3", + hfsts3.fields.chunk3); fu_common_string_append_kx (str, idt, "FwSku", hfsts3.fields.fw_sku); fu_common_string_append_kb (str, idt, "EncryptKeyCheck", hfsts3.fields.encrypt_key_check); fu_common_string_append_kb (str, idt, "PchConfigChange", hfsts3.fields.pch_config_change); - fu_common_string_append_kx (str, idt, "Reserved9", - hfsts3.fields.reserved_9); + fu_common_string_append_kb (str, idt, "IbbVerificationResult", + hfsts3.fields.ibb_verification_result); + fu_common_string_append_kb (str, idt, "IbbVerificationDone", + hfsts3.fields.ibb_verification_done); fu_common_string_append_kx (str, idt, "Reserved11", hfsts3.fields.reserved_11); - fu_common_string_append_kx (str, idt, "Reserved14", - hfsts3.fields.reserved_14); + fu_common_string_append_kx (str, idt, "ActualIbbSize", + hfsts3.fields.actual_ibb_size * 1024); + fu_common_string_append_ku (str, idt, "NumberOfChunks", + hfsts3.fields.number_of_chunks); fu_common_string_append_kb (str, idt, "EncryptKeyOverride", hfsts3.fields.encrypt_key_override); fu_common_string_append_kb (str, idt, "PowerDownMitigation", diff --git a/plugins/pci-mei/fu-mei-common.h b/plugins/pci-mei/fu-mei-common.h index 1ad930bf9..440d8949c 100644 --- a/plugins/pci-mei/fu-mei-common.h +++ b/plugins/pci-mei/fu-mei-common.h @@ -83,13 +83,18 @@ typedef union { typedef union { guint32 data; struct { - guint32 reserved_0 : 4; + guint32 chunk0 : 1; + guint32 chunk1 : 1; + guint32 chunk2 : 1; + guint32 chunk3 : 1; guint32 fw_sku : 3; guint32 encrypt_key_check : 1; guint32 pch_config_change : 1; - guint32 reserved_9 : 2; + guint32 ibb_verification_result : 1; + guint32 ibb_verification_done : 1; guint32 reserved_11 : 3; - guint32 reserved_14 : 16; + guint32 actual_ibb_size : 14; + guint32 number_of_chunks : 2; guint32 encrypt_key_override : 1; guint32 power_down_mitigation : 1; } __attribute__((packed)) fields; From d19aff3df18a816bbdb694b1ebe0d634e6d1321f Mon Sep 17 00:00:00 2001 From: Richard Hughes Date: Mon, 7 Sep 2020 09:26:31 +0100 Subject: [PATCH 390/607] mei: Do not attempt to parse HFSTS6 when using TXT It seems the MEI parameters are not set for platforms such as Apollo Lake. The only bit set was FPF_SOC_LOCK, with the others all cleared to zero. Fixes https://github.com/fwupd/fwupd/issues/2335 for a peculiar definition of 'fix'. --- plugins/pci-mei/fu-plugin-pci-mei.c | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/plugins/pci-mei/fu-plugin-pci-mei.c b/plugins/pci-mei/fu-plugin-pci-mei.c index 3c24c3ce5..e52d03a2c 100644 --- a/plugins/pci-mei/fu-plugin-pci-mei.c +++ b/plugins/pci-mei/fu-plugin-pci-mei.c @@ -264,6 +264,10 @@ fu_plugin_add_security_attrs_bootguard_enabled (FuPlugin *plugin, FuSecurityAttr FuPluginData *priv = fu_plugin_get_data (plugin); g_autoptr(FwupdSecurityAttr) attr = NULL; + /* not supported */ + if (priv->family == FU_MEI_FAMILY_TXE) + return; + /* create attr */ attr = fwupd_security_attr_new (FWUPD_SECURITY_ATTR_ID_INTEL_BOOTGUARD_ENABLED); fwupd_security_attr_set_plugin (attr, fu_plugin_get_name (plugin)); @@ -288,6 +292,10 @@ fu_plugin_add_security_attrs_bootguard_verified (FuPlugin *plugin, FuSecurityAtt FuPluginData *priv = fu_plugin_get_data (plugin); g_autoptr(FwupdSecurityAttr) attr = NULL; + /* not supported */ + if (priv->family == FU_MEI_FAMILY_TXE) + return; + /* disabled */ if (priv->hfsts6.fields.boot_guard_disable) return; @@ -316,6 +324,10 @@ fu_plugin_add_security_attrs_bootguard_acm (FuPlugin *plugin, FuSecurityAttrs *a FuPluginData *priv = fu_plugin_get_data (plugin); g_autoptr(FwupdSecurityAttr) attr = NULL; + /* not supported */ + if (priv->family == FU_MEI_FAMILY_TXE) + return; + /* disabled */ if (priv->hfsts6.fields.boot_guard_disable) return; @@ -343,6 +355,10 @@ fu_plugin_add_security_attrs_bootguard_policy (FuPlugin *plugin, FuSecurityAttrs FuPluginData *priv = fu_plugin_get_data (plugin); g_autoptr(FwupdSecurityAttr) attr = NULL; + /* not supported */ + if (priv->family == FU_MEI_FAMILY_TXE) + return; + /* disabled */ if (priv->hfsts6.fields.boot_guard_disable) return; @@ -371,6 +387,10 @@ fu_plugin_add_security_attrs_bootguard_otp (FuPlugin *plugin, FuSecurityAttrs *a FuPluginData *priv = fu_plugin_get_data (plugin); g_autoptr(FwupdSecurityAttr) attr = NULL; + /* not supported */ + if (priv->family == FU_MEI_FAMILY_TXE) + return; + /* disabled */ if (priv->hfsts6.fields.boot_guard_disable) return; From 110eb286bcef515ec8b5c4ea80792cf8084cd1bb Mon Sep 17 00:00:00 2001 From: Mario Limonciello Date: Tue, 8 Sep 2020 12:58:38 -0500 Subject: [PATCH 391/607] Make TPM more optional (Fixes: #2360) - Rename the `plugin_tpm` option to `tpm` and when it's disabled remove TPM support from all plugins - If enabled then require the TSS to be installed --- contrib/ci/build_windows.sh | 2 +- contrib/ci/trust.sh | 2 +- contrib/fwupd.spec.in | 4 ++-- meson.build | 11 +++++------ meson_options.txt | 2 +- plugins/meson.build | 4 ++-- plugins/uefi/fu-self-test.c | 5 +++++ 7 files changed, 17 insertions(+), 13 deletions(-) diff --git a/contrib/ci/build_windows.sh b/contrib/ci/build_windows.sh index 33c2a8604..28230fb78 100755 --- a/contrib/ci/build_windows.sh +++ b/contrib/ci/build_windows.sh @@ -22,7 +22,7 @@ meson .. \ -Dplugin_altos=false \ -Dplugin_dell=false \ -Dplugin_nvme=false \ - -Dplugin_tpm=false \ + -Dtpm=false \ -Dsystemd=false \ -Dplugin_emmc=false \ -Dplugin_amt=false \ diff --git a/contrib/ci/trust.sh b/contrib/ci/trust.sh index d1ebc5c3a..506776243 100755 --- a/contrib/ci/trust.sh +++ b/contrib/ci/trust.sh @@ -15,7 +15,7 @@ meson build \ -Dman=false \ -Ddaemon=false \ -Dgusb:tests=false \ - -Dplugin_tpm=false \ + -Dtpm=false \ -Dplugin_modem_manager=false \ -Dplugin_flashrom=false \ -Dplugin_uefi=false \ diff --git a/contrib/fwupd.spec.in b/contrib/fwupd.spec.in index 49e26f837..ef825a70d 100644 --- a/contrib/fwupd.spec.in +++ b/contrib/fwupd.spec.in @@ -201,11 +201,11 @@ Data files for installed tests. %if 0%{?have_uefi} -Dplugin_uefi=true \ -Dplugin_nvme=true \ - -Dplugin_tpm=true \ + -Dtpm=true \ %else -Dplugin_uefi=false \ -Dplugin_nvme=false \ - -Dplugin_tpm=false \ + -Dtpm=false \ %endif %if 0%{?have_dell} -Dplugin_dell=true \ diff --git a/meson.build b/meson.build index 473015489..bf8e4775b 100644 --- a/meson.build +++ b/meson.build @@ -226,10 +226,6 @@ libgcab = dependency('libgcab-1.0', version : '>= 1.0', fallback : ['gcab', 'gca gcab = find_program('gcab', required : true) bashcomp = dependency('bash-completion', required: false) python3 = find_program('python3') -tpm2tss = dependency('tss2-esys', version : '>= 2.0', required: false) -if tpm2tss.found() - conf.set('HAVE_TSS2', '1') -endif platform_deps = [] if get_option('default_library') != 'static' @@ -290,8 +286,11 @@ if cc.has_function('pwrite', args : '-D_XOPEN_SOURCE') conf.set('HAVE_PWRITE', '1') endif -if build_standalone and get_option('plugin_tpm') and not tpm2tss.found() - error('tss2-esys is required for -Dplugin_tpm=true') +if build_standalone and get_option('tpm') + tpm2tss = dependency('tss2-esys', version : '>= 2.0') + conf.set('HAVE_TSS2', '1') +else + tpm2tss = dependency('', required: false) endif if build_standalone and get_option('plugin_uefi') diff --git a/meson_options.txt b/meson_options.txt index c2fb1f720..ad0f3b730 100644 --- a/meson_options.txt +++ b/meson_options.txt @@ -15,7 +15,6 @@ option('plugin_emmc', type : 'boolean', value : true, description : 'enable eMMC option('plugin_synaptics', type: 'boolean', value: true, description : 'enable Synaptics MST hub support') option('plugin_thunderbolt', type : 'boolean', value : true, description : 'enable Thunderbolt support') option('plugin_redfish', type : 'boolean', value : true, description : 'enable Redfish support') -option('plugin_tpm', type : 'boolean', value : true, description : 'enable TPM support') option('plugin_uefi', type : 'boolean', value : true, description : 'enable UEFI support') option('plugin_nvme', type : 'boolean', value : true, description : 'enable NVMe support') option('plugin_modem_manager', type : 'boolean', value : false, description : 'enable ModemManager support') @@ -27,6 +26,7 @@ option('systemd', type : 'boolean', value : true, description : 'enable systemd option('systemd_root_prefix', type: 'string', value: '', description: 'Directory to base systemd’s installation directories on') option('elogind', type : 'boolean', value : false, description : 'enable elogind support') option('tests', type : 'boolean', value : true, description : 'enable tests') +option('tpm', type : 'boolean', value : true, description : 'enable TPM support') option('udevdir', type: 'string', value: '', description: 'Directory for udev rules') option('efi-cc', type : 'string', value : 'gcc', description : 'the compiler to use for EFI modules') option('efi-ld', type : 'string', value : 'ld', description : 'the linker to use for EFI modules') diff --git a/plugins/meson.build b/plugins/meson.build index 6ecd99578..b24c13920 100644 --- a/plugins/meson.build +++ b/plugins/meson.build @@ -57,9 +57,9 @@ endif # depends on dfu subdir('csr') -if get_option('plugin_tpm') +if get_option('tpm') if not get_option('gudev') - error('gudev is required for plugin_tpm') + error('gudev is required for tpm') endif subdir('tpm') subdir('tpm-eventlog') diff --git a/plugins/uefi/fu-self-test.c b/plugins/uefi/fu-self-test.c index 19899b38d..aef078cc6 100644 --- a/plugins/uefi/fu-self-test.c +++ b/plugins/uefi/fu-self-test.c @@ -50,6 +50,11 @@ fu_uefi_pcrs_2_0_func (void) 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)) { From af53a4fc22735869f143c0b70b821ecc5083c675 Mon Sep 17 00:00:00 2001 From: Richard Hughes Date: Wed, 9 Sep 2020 13:01:09 +0100 Subject: [PATCH 392/607] vli: Do not dedupe USB hub PD devices This object derives from FuDevice rather than FuVliDevice and so does not inherit the NO_GUID_MATCHING flag like other devices. Fixes https://github.com/fwupd/fwupd/issues/2364 --- plugins/vli/fu-vli-usbhub-pd-device.c | 1 + 1 file changed, 1 insertion(+) diff --git a/plugins/vli/fu-vli-usbhub-pd-device.c b/plugins/vli/fu-vli-usbhub-pd-device.c index 28ccb8ea4..2d8c5cc81 100644 --- a/plugins/vli/fu-vli-usbhub-pd-device.c +++ b/plugins/vli/fu-vli-usbhub-pd-device.c @@ -207,6 +207,7 @@ fu_vli_usbhub_pd_device_init (FuVliUsbhubPdDevice *self) fu_device_set_protocol (FU_DEVICE (self), "com.vli.usbhub"); fu_device_add_flag (FU_DEVICE (self), FWUPD_DEVICE_FLAG_UPDATABLE); fu_device_add_flag (FU_DEVICE (self), FWUPD_DEVICE_FLAG_CAN_VERIFY_IMAGE); + fu_device_add_flag (FU_DEVICE (self), FWUPD_DEVICE_FLAG_NO_GUID_MATCHING); fu_device_set_version_format (FU_DEVICE (self), FWUPD_VERSION_FORMAT_QUAD); fu_device_set_install_duration (FU_DEVICE (self), 15); /* seconds */ fu_device_set_logical_id (FU_DEVICE (self), "PD"); From 49b911f0942981e549f8849571dc2e7fee8f845d Mon Sep 17 00:00:00 2001 From: Richard Hughes Date: Wed, 9 Sep 2020 15:05:04 +0100 Subject: [PATCH 393/607] nvme: Do not dedupe NVMe devices Fixes https://github.com/fwupd/fwupd/issues/2366 --- plugins/nvme/fu-nvme-device.c | 1 + 1 file changed, 1 insertion(+) diff --git a/plugins/nvme/fu-nvme-device.c b/plugins/nvme/fu-nvme-device.c index 4e92a217b..3eacdcd13 100644 --- a/plugins/nvme/fu-nvme-device.c +++ b/plugins/nvme/fu-nvme-device.c @@ -390,6 +390,7 @@ fu_nvme_device_init (FuNvmeDevice *self) { fu_device_add_flag (FU_DEVICE (self), FWUPD_DEVICE_FLAG_REQUIRE_AC); fu_device_add_flag (FU_DEVICE (self), FWUPD_DEVICE_FLAG_UPDATABLE); + fu_device_add_flag (FU_DEVICE (self), FWUPD_DEVICE_FLAG_NO_GUID_MATCHING); fu_device_set_version_format (FU_DEVICE (self), FWUPD_VERSION_FORMAT_PLAIN); fu_device_set_summary (FU_DEVICE (self), "NVM Express Solid State Drive"); fu_device_add_icon (FU_DEVICE (self), "drive-harddisk"); From fb6315f1c6e103aae1805f42ddd648e29913f204 Mon Sep 17 00:00:00 2001 From: Richard Hughes Date: Wed, 9 Sep 2020 17:05:20 +0100 Subject: [PATCH 394/607] trivial: Show the failing remote when using 'fwupdtool refresh' --- src/fu-tool.c | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/src/fu-tool.c b/src/fu-tool.c index 6d1de3795..f28441d4a 100644 --- a/src/fu-tool.c +++ b/src/fu-tool.c @@ -1892,10 +1892,11 @@ fu_util_refresh_remote (FuUtilPrivate *priv, FwupdRemote *remote, GError **error /* payload */ metadata_uri = fwupd_remote_get_metadata_uri (remote); if (metadata_uri == NULL) { - g_set_error_literal (error, - FWUPD_ERROR, - FWUPD_ERROR_NOTHING_TO_DO, - "no metadata URI available"); + g_set_error (error, + FWUPD_ERROR, + FWUPD_ERROR_NOTHING_TO_DO, + "no metadata URI available for %s", + fwupd_remote_get_id (remote)); return FALSE; } fn_raw = fu_util_get_user_cache_path (metadata_uri); @@ -1910,10 +1911,11 @@ fu_util_refresh_remote (FuUtilPrivate *priv, FwupdRemote *remote, GError **error /* signature */ metadata_uri = fwupd_remote_get_metadata_uri_sig (remote); if (metadata_uri == NULL) { - g_set_error_literal (error, - FWUPD_ERROR, - FWUPD_ERROR_NOTHING_TO_DO, - "no metadata signature URI available"); + g_set_error (error, + FWUPD_ERROR, + FWUPD_ERROR_NOTHING_TO_DO, + "no metadata signature URI available for %s", + fwupd_remote_get_id (remote)); return FALSE; } fn_sig = fu_util_get_user_cache_path (metadata_uri); From 50ff31de5690a5fda0aae7d0113980b5ebd3e926 Mon Sep 17 00:00:00 2001 From: Richard Hughes Date: Wed, 9 Sep 2020 17:07:38 +0100 Subject: [PATCH 395/607] Fix memory unsafety when using fu_engine_get_remotes() When using fwupdtool that runs a mainloop we can get into the state where the inotify watch fires on the remote directory as we're iterating on the list of remotes. This corrupts the list and we start reading freed objects. Return a deep copy so we can safely update each remote. --- src/fu-engine.c | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) diff --git a/src/fu-engine.c b/src/fu-engine.c index a87a9ce22..26cd7a94c 100644 --- a/src/fu-engine.c +++ b/src/fu-engine.c @@ -4094,6 +4094,19 @@ fu_engine_get_history (FuEngine *self, GError **error) return g_steal_pointer (&devices); } +#if !GLIB_CHECK_VERSION(2,62,0) +static GPtrArray * +g_ptr_array_copy (GPtrArray *array, GCopyFunc func, gpointer user_data) +{ + GPtrArray *new = g_ptr_array_new_with_free_func ((GDestroyNotify) g_object_unref); + for (guint i = 0; i < array->len; i++) { + GObject *obj = g_ptr_array_index (array, i); + g_ptr_array_add (new, g_object_ref (obj)); + } + return new; +} +#endif + /** * fu_engine_get_remotes: * @self: A #FuEngine @@ -4119,7 +4132,9 @@ fu_engine_get_remotes (FuEngine *self, GError **error) "No remotes configured"); return NULL; } - return g_ptr_array_ref (remotes); + + /* deep copy so the remote list can be kept up to date */ + return g_ptr_array_copy (remotes, (GCopyFunc) g_object_ref, NULL); } /** From db344d5a40574ba9e2e485adeef4cd2b4977aea7 Mon Sep 17 00:00:00 2001 From: Richard Hughes Date: Wed, 9 Sep 2020 19:42:27 +0100 Subject: [PATCH 396/607] trivial: Fix several small memory leaks discovered with valgrind --- libfwupdplugin/fu-common.c | 9 ++++----- libfwupdplugin/fu-volume.c | 2 +- plugins/uefi/fu-plugin-uefi.c | 2 ++ plugins/uefi/fu-uefi-device.c | 2 ++ src/fu-engine.c | 2 +- src/fu-tool.c | 4 +++- 6 files changed, 13 insertions(+), 8 deletions(-) diff --git a/libfwupdplugin/fu-common.c b/libfwupdplugin/fu-common.c index 06b05712d..7225cdcfa 100644 --- a/libfwupdplugin/fu-common.c +++ b/libfwupdplugin/fu-common.c @@ -2148,7 +2148,6 @@ static GPtrArray * fu_common_get_block_devices (GDBusConnection *connection, GError **error) { GVariantBuilder builder; - GVariant *input; const gchar *obj; g_autoptr(GVariant) output = NULL; g_autoptr(GDBusProxy) proxy = NULL; @@ -2166,16 +2165,16 @@ fu_common_get_block_devices (GDBusConnection *connection, GError **error) return NULL; } g_variant_builder_init (&builder, G_VARIANT_TYPE_VARDICT); - input = g_variant_new ("(a{sv})", &builder); output = g_dbus_proxy_call_sync (proxy, - "GetBlockDevices", g_variant_ref (input), + "GetBlockDevices", + g_variant_new ("(a{sv})", &builder), G_DBUS_CALL_FLAGS_NONE, -1, NULL, error); if (output == NULL) return NULL; devices = g_ptr_array_new_with_free_func (g_free); g_variant_get (output, "(ao)", &iter); - while (g_variant_iter_next (iter, "o", &obj)) + while (g_variant_iter_next (iter, "&o", &obj)) g_ptr_array_add (devices, g_strdup (obj)); return g_steal_pointer (&devices); @@ -2232,7 +2231,7 @@ fu_common_get_volumes_by_kind (const gchar *kind, GError **error) if (val == NULL) continue; - g_variant_get (val, "s", &type_str); + g_variant_get (val, "&s", &type_str); g_debug ("device %s, type: %s", obj, type_str); if (g_strcmp0 (type_str, kind) != 0) continue; diff --git a/libfwupdplugin/fu-volume.c b/libfwupdplugin/fu-volume.c index 889173186..0ce53c511 100644 --- a/libfwupdplugin/fu-volume.c +++ b/libfwupdplugin/fu-volume.c @@ -81,7 +81,7 @@ fu_volume_get_id (FuVolume *self) gchar * fu_volume_get_mount_point (FuVolume *self) { - const gchar **mountpoints = NULL; + g_autofree const gchar **mountpoints = NULL; g_autoptr(GVariant) val = NULL; g_autoptr(GError) error_local = NULL; diff --git a/plugins/uefi/fu-plugin-uefi.c b/plugins/uefi/fu-plugin-uefi.c index 7ea48c741..d550d51cf 100644 --- a/plugins/uefi/fu-plugin-uefi.c +++ b/plugins/uefi/fu-plugin-uefi.c @@ -47,6 +47,8 @@ void fu_plugin_destroy (FuPlugin *plugin) { FuPluginData *data = fu_plugin_get_data (plugin); + if (data->esp != NULL) + g_object_unref (data->esp); g_object_unref (data->bgrt); } diff --git a/plugins/uefi/fu-uefi-device.c b/plugins/uefi/fu-uefi-device.c index ed1d17206..fce6f7aec 100644 --- a/plugins/uefi/fu-uefi-device.c +++ b/plugins/uefi/fu-uefi-device.c @@ -730,6 +730,8 @@ fu_uefi_device_finalize (GObject *object) FuUefiDevice *self = FU_UEFI_DEVICE (object); g_free (self->fw_class); + if (self->esp != NULL) + g_object_unref (self->esp); if (self->esp_locker != NULL) g_object_unref (self->esp_locker); diff --git a/src/fu-engine.c b/src/fu-engine.c index 26cd7a94c..72dff9b9a 100644 --- a/src/fu-engine.c +++ b/src/fu-engine.c @@ -3498,12 +3498,12 @@ fu_engine_update_metadata_bytes (FuEngine *self, const gchar *remote_id, /* verify file */ keyring_kind = fwupd_remote_get_keyring_kind (remote); if (keyring_kind != FWUPD_KEYRING_KIND_NONE) { - JcatResult *jcat_result; g_autoptr(GError) error_local = NULL; g_autoptr(GInputStream) istream = NULL; g_autoptr(GPtrArray) results = NULL; g_autoptr(JcatFile) jcat_file = jcat_file_new (); g_autoptr(JcatItem) jcat_item = NULL; + g_autoptr(JcatResult) jcat_result = NULL; g_autoptr(JcatResult) jcat_result_old = NULL; /* load Jcat file */ diff --git a/src/fu-tool.c b/src/fu-tool.c index f28441d4a..379192c1c 100644 --- a/src/fu-tool.c +++ b/src/fu-tool.c @@ -822,7 +822,9 @@ fu_util_download_out_of_process (const gchar *uri, const gchar *fn, GError **err { NULL } }; for (guint i = 0; argv[i][0] != NULL; i++) { g_autoptr(GError) error_local = NULL; - if (!fu_common_find_program_in_path (argv[i][0], &error_local)) { + g_autofree gchar *fn_tmp = NULL; + fn_tmp = fu_common_find_program_in_path (argv[i][0], &error_local); + if (fn_tmp == NULL) { g_debug ("%s", error_local->message); continue; } From 8c200a9e414163a91eda0adfe728a2bb9407cf6f Mon Sep 17 00:00:00 2001 From: Richard Hughes Date: Fri, 4 Sep 2020 14:57:26 +0100 Subject: [PATCH 397/607] cpu: Correct the BCR address for Atom Bay Trail --- plugins/cpu/cpu.quirk | 4 ++-- plugins/pci-bcr/fu-plugin-pci-bcr.c | 9 +++++++++ 2 files changed, 11 insertions(+), 2 deletions(-) diff --git a/plugins/cpu/cpu.quirk b/plugins/cpu/cpu.quirk index dace03cfe..88ee7c5c1 100644 --- a/plugins/cpu/cpu.quirk +++ b/plugins/cpu/cpu.quirk @@ -1,3 +1,3 @@ # Intel Atom Bay Trail [Silvermont] -[DeviceInstanceId=CPUID\PRO_0&FAM_06&MOD_07] -BcrAddr = 0x54 +[DeviceInstanceId=CPUID\PRO_0&FAM_06&MOD_37] +BcrAddr = 0x0 diff --git a/plugins/pci-bcr/fu-plugin-pci-bcr.c b/plugins/pci-bcr/fu-plugin-pci-bcr.c index dbebe9dd6..b96ce0ac3 100644 --- a/plugins/pci-bcr/fu-plugin-pci-bcr.c +++ b/plugins/pci-bcr/fu-plugin-pci-bcr.c @@ -136,6 +136,15 @@ fu_plugin_udev_device_added (FuPlugin *plugin, FuUdevDevice *device, GError **er FuPluginData *priv = fu_plugin_get_data (plugin); g_autoptr(FuDeviceLocker) locker = NULL; + /* not supported */ + if (priv->bcr_addr == 0x0) { + g_set_error_literal (error, + FWUPD_ERROR, + FWUPD_ERROR_NOT_SUPPORTED, + "BCR not supported on this platform"); + return FALSE; + } + /* interesting device? */ if (g_strcmp0 (fu_udev_device_get_subsystem (device), "pci") != 0) return TRUE; From 0b74e2c91a34fae54e7b1d897c37a551a0c97106 Mon Sep 17 00:00:00 2001 From: Daniel Campello Date: Wed, 9 Sep 2020 16:02:51 -0600 Subject: [PATCH 398/607] thunderbolt: Call fu_device_set_physical_id() during probe for retimer Error will show up if (priv->physical_id == NULL) on fu_device_ensure_id(). This method is called after probe but before setup on fu_device_open. Call fu_device_set_physical_id() on fu_thunderbolt_device_probe() for the retimer case. Fixes https://github.com/fwupd/fwupd/issues/2371 Change-Id: I0e462fff5e8abf6073318f6424b6736afc8259b8 --- plugins/thunderbolt/fu-thunderbolt-device.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/plugins/thunderbolt/fu-thunderbolt-device.c b/plugins/thunderbolt/fu-thunderbolt-device.c index 56af0a3af..fe71a7cb1 100644 --- a/plugins/thunderbolt/fu-thunderbolt-device.c +++ b/plugins/thunderbolt/fu-thunderbolt-device.c @@ -222,6 +222,9 @@ fu_thunderbolt_device_probe (FuUdevDevice *device, GError **error) /* retimer */ } else if (g_strcmp0 (tmp, "thunderbolt_retimer") == 0) { self->device_type = FU_THUNDERBOLT_DEVICE_TYPE_RETIMER; + tmp = g_path_get_basename (fu_udev_device_get_sysfs_path (FU_UDEV_DEVICE (device))); + if (tmp != NULL) + fu_device_set_physical_id (FU_DEVICE (device), tmp); /* domain or unsupported */ } else { g_set_error (error, From 8541a874f0a6510469ea3bd64ae0c5b7873add8e Mon Sep 17 00:00:00 2001 From: Richard Hughes Date: Thu, 10 Sep 2020 16:43:45 +0100 Subject: [PATCH 399/607] synaptics-cxaudio: Fix the topology of the audio device on the TR dock This ensures we perform the updates in this order: * cxaudio * vli * thunderbolt As any other order causes enumeration failures. Fixes some of https://github.com/fwupd/fwupd/issues/2377 --- plugins/synaptics-cxaudio/synaptics-cxaudio.quirk | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugins/synaptics-cxaudio/synaptics-cxaudio.quirk b/plugins/synaptics-cxaudio/synaptics-cxaudio.quirk index 3d6fef156..9aec0dbc1 100644 --- a/plugins/synaptics-cxaudio/synaptics-cxaudio.quirk +++ b/plugins/synaptics-cxaudio/synaptics-cxaudio.quirk @@ -1,7 +1,7 @@ # ThinkPad TBT3-TR Gen 2 dock [DeviceInstanceId=USB\VID_17EF&PID_3083] Guid = SYNAPTICS_CXAUDIO\CX2098X -ParentGuid = TBT-01081720 +ParentGuid = USB\VID_17EF&PID_307F&HUB_0006 # ThinkPad TBT3-MS Gen 2 dock [DeviceInstanceId=USB\VID_17EF&PID_3092] From 64f3857751555bdfea3084b6269c7863aa327b6e Mon Sep 17 00:00:00 2001 From: Mario Limonciello Date: Wed, 9 Sep 2020 20:57:13 -0500 Subject: [PATCH 400/607] thunderbolt: ignore non-updatable host controller (Fixes: #2373) nvm_version will not export in Intel USB4 host controller running in SW CM, there is no point in fwupd displaying a device for it. --- plugins/thunderbolt/fu-thunderbolt-device.c | 36 +++++++++++++++++---- 1 file changed, 30 insertions(+), 6 deletions(-) diff --git a/plugins/thunderbolt/fu-thunderbolt-device.c b/plugins/thunderbolt/fu-thunderbolt-device.c index fe71a7cb1..bfa14224f 100644 --- a/plugins/thunderbolt/fu-thunderbolt-device.c +++ b/plugins/thunderbolt/fu-thunderbolt-device.c @@ -126,7 +126,7 @@ fu_thunderbolt_device_can_update (FuThunderboltDevice *self) } static gboolean -fu_thunderbolt_device_get_version (FuThunderboltDevice *self) +fu_thunderbolt_device_get_version (FuThunderboltDevice *self, GError **error) { g_auto(GStrv) split = NULL; g_autofree gchar *version_raw = NULL; @@ -134,6 +134,14 @@ fu_thunderbolt_device_get_version (FuThunderboltDevice *self) /* read directly from file to prevent udev caching */ g_autofree gchar *safe_path = g_build_path ("/", self->devpath, "nvm_version", NULL); + if (!g_file_test (safe_path, G_FILE_TEST_EXISTS)) { + g_set_error_literal (error, + FWUPD_ERROR, + FWUPD_ERROR_NOT_SUPPORTED, + "missing nvm_version attribute"); + return FALSE; + } + for (guint i = 0; i < 50; i++) { g_autoptr(GError) error_local = NULL; /* glib can't return a properly mapped -ENODATA but the @@ -147,11 +155,21 @@ fu_thunderbolt_device_get_version (FuThunderboltDevice *self) break; } - if (version_raw == NULL) + if (version_raw == NULL) { + g_set_error_literal (error, + FWUPD_ERROR, + FWUPD_ERROR_INTERNAL, + "failed to read NVM"); return FALSE; + } split = g_strsplit (version_raw, ".", -1); - if (g_strv_length (split) != 2) + if (g_strv_length (split) != 2) { + g_set_error (error, + FWUPD_ERROR, + FWUPD_ERROR_NOT_SUPPORTED, + "invalid nvm_version format: %s", version_raw); return FALSE; + } version = g_strdup_printf ("%02x.%02x", (guint) g_ascii_strtoull (split[0], NULL, 16), @@ -423,13 +441,19 @@ static gboolean fu_thunderbolt_device_setup (FuDevice *device, GError **error) { FuThunderboltDevice *self = FU_THUNDERBOLT_DEVICE (device); + g_autoptr(GError) error_version = NULL; self->devpath = g_strdup (fu_udev_device_get_sysfs_path (FU_UDEV_DEVICE (device))); fu_device_set_metadata (device, "sysfs-path", self->devpath); /* try to read the version */ - if (!fu_thunderbolt_device_get_version (self)) - g_debug ("failed to read version"); + if (!fu_thunderbolt_device_get_version (self, &error_version)) { + if (g_error_matches (error_version, FWUPD_ERROR, FWUPD_ERROR_NOT_SUPPORTED)) { + g_propagate_error (error, g_steal_pointer (&error_version)); + return FALSE; + } + g_debug ("%s", error_version->message); + } /* default behavior */ self->auth_method = "nvm_authenticate"; @@ -496,7 +520,7 @@ fu_thunderbolt_device_rescan (FuDevice *device, GError **error) { FuThunderboltDevice *self = FU_THUNDERBOLT_DEVICE (device); /* refresh the version */ - return fu_thunderbolt_device_get_version (self); + return fu_thunderbolt_device_get_version (self, error); } static gboolean From 4550cf51f89ee1b24813c5bf8f21bc2c886dd91c Mon Sep 17 00:00:00 2001 From: Mario Limonciello Date: Thu, 10 Sep 2020 11:53:27 -0500 Subject: [PATCH 401/607] trivial: stop creating sysfs-path metadata This isn't needed anymore, it was only for legacy thunderbolt3 controllers that didn't support native enumeration. --- plugins/thunderbolt/fu-thunderbolt-device.c | 1 - 1 file changed, 1 deletion(-) diff --git a/plugins/thunderbolt/fu-thunderbolt-device.c b/plugins/thunderbolt/fu-thunderbolt-device.c index bfa14224f..e8cba0cca 100644 --- a/plugins/thunderbolt/fu-thunderbolt-device.c +++ b/plugins/thunderbolt/fu-thunderbolt-device.c @@ -444,7 +444,6 @@ fu_thunderbolt_device_setup (FuDevice *device, GError **error) g_autoptr(GError) error_version = NULL; self->devpath = g_strdup (fu_udev_device_get_sysfs_path (FU_UDEV_DEVICE (device))); - fu_device_set_metadata (device, "sysfs-path", self->devpath); /* try to read the version */ if (!fu_thunderbolt_device_get_version (self, &error_version)) { From 25b78a6870b98efd99fe5cfb2296df8a3fb24836 Mon Sep 17 00:00:00 2001 From: Jochen Sprickerhof Date: Thu, 10 Sep 2020 23:57:02 +0200 Subject: [PATCH 402/607] Check returned volumes before accessing them Without udisks2 installed the list of volumes is empty and fwupdtool esp-list segfaults. --- src/fu-tool.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/fu-tool.c b/src/fu-tool.c index 379192c1c..591500c6b 100644 --- a/src/fu-tool.c +++ b/src/fu-tool.c @@ -2035,6 +2035,8 @@ fu_util_prompt_for_volume (GError **error) /* exactly one */ volumes = fu_common_get_volumes_by_kind (FU_VOLUME_KIND_ESP, error); + if (volumes == NULL) + return NULL; if (volumes->len == 1) { volume = g_ptr_array_index (volumes, 0); /* TRANSLATORS: Volume has been chosen by the user */ From eb4472a47949875a4d68f02997d32ab1e487ae54 Mon Sep 17 00:00:00 2001 From: Mario Limonciello Date: Thu, 10 Sep 2020 17:31:10 -0500 Subject: [PATCH 403/607] trivial: debian: add udisks2 to recommends (Closes: #970054) --- contrib/debian/control.in | 1 + 1 file changed, 1 insertion(+) diff --git a/contrib/debian/control.in b/contrib/debian/control.in index 752696172..d700307f3 100644 --- a/contrib/debian/control.in +++ b/contrib/debian/control.in @@ -50,6 +50,7 @@ Depends: ${misc:Depends}, Recommends: python3, bolt, secureboot-db, + udisks2, fwupd-signed Provides: fwupdate Conflicts: fwupdate-amd64-signed, From 6d23514fb1f52b3423fe2d18bfd3979399e3286b Mon Sep 17 00:00:00 2001 From: Mario Limonciello Date: Thu, 10 Sep 2020 21:35:17 -0500 Subject: [PATCH 404/607] Revert "fu-plugin: add a new udev_device_changed function that calls rescan" This reverts commit 096e3cfbb6eb065b42eab5a21847341341441551. --- libfwupdplugin/fu-plugin.c | 20 +------------------- 1 file changed, 1 insertion(+), 19 deletions(-) diff --git a/libfwupdplugin/fu-plugin.c b/libfwupdplugin/fu-plugin.c index 36a1a3612..66da432e7 100644 --- a/libfwupdplugin/fu-plugin.c +++ b/libfwupdplugin/fu-plugin.c @@ -1753,18 +1753,6 @@ fu_plugin_usb_device_added (FuPlugin *self, FuUsbDevice *device, GError **error) return TRUE; } -static gboolean -fu_plugin_udev_device_changed (FuPlugin *self, FuUdevDevice *device, GError **error) -{ - g_autoptr(FuDeviceLocker) locker = NULL; - - /* open */ - locker = fu_device_locker_new (FU_DEVICE (device), error); - if (locker == NULL) - return FALSE; - return fu_device_rescan (FU_DEVICE (device), error); -} - static gboolean fu_plugin_udev_device_added (FuPlugin *self, FuUdevDevice *device, GError **error) { @@ -1944,14 +1932,8 @@ fu_plugin_runner_udev_device_changed (FuPlugin *self, FuUdevDevice *device, GErr /* optional */ g_module_symbol (priv->module, "fu_plugin_udev_device_changed", (gpointer *) &func); - if (func == NULL) { - if (priv->device_gtype != G_TYPE_INVALID || - fu_device_get_specialized_gtype (FU_DEVICE (device)) != G_TYPE_INVALID) { - if (!fu_plugin_udev_device_changed (self, device, error)) - return FALSE; - } + if (func == NULL) return TRUE; - } g_debug ("performing udev_device_changed() on %s", priv->name); if (!func (self, device, &error_local)) { if (error_local == NULL) { From 6d0c4897e14b05fcff303e86ea95939d547e755c Mon Sep 17 00:00:00 2001 From: Mario Limonciello Date: Thu, 10 Sep 2020 21:46:05 -0500 Subject: [PATCH 405/607] fu-udev-device: call rescan on the device for change events This allows calling the correct method, and instead doesn't have all the plugins try to process the event when they're missing vfuncs --- libfwupdplugin/fu-udev-device.c | 3 +++ plugins/thunderbolt/fu-self-test.c | 4 ++-- plugins/thunderbolt/fu-thunderbolt-device.c | 1 + 3 files changed, 6 insertions(+), 2 deletions(-) diff --git a/libfwupdplugin/fu-udev-device.c b/libfwupdplugin/fu-udev-device.c index 80fc65a82..255783302 100644 --- a/libfwupdplugin/fu-udev-device.c +++ b/libfwupdplugin/fu-udev-device.c @@ -76,8 +76,11 @@ static guint signals[SIGNAL_LAST] = { 0 }; void fu_udev_device_emit_changed (FuUdevDevice *self) { + g_autoptr(GError) error = NULL; g_return_if_fail (FU_IS_UDEV_DEVICE (self)); g_debug ("FuUdevDevice emit changed"); + if (!fu_device_rescan (FU_DEVICE (self), &error)) + g_debug ("%s", error->message); g_signal_emit (self, signals[SIGNAL_CHANGED], 0); } diff --git a/plugins/thunderbolt/fu-self-test.c b/plugins/thunderbolt/fu-self-test.c index 90d2105f8..cab8dceb4 100644 --- a/plugins/thunderbolt/fu-self-test.c +++ b/plugins/thunderbolt/fu-self-test.c @@ -26,6 +26,7 @@ #include "fu-plugin-private.h" #include "fu-thunderbolt-firmware.h" #include "fu-thunderbolt-firmware-update.h" +#include "fu-udev-device-private.h" static gchar * udev_mock_add_domain (UMockdevTestbed *bed, int id) @@ -891,8 +892,7 @@ fu_thunderbolt_gudev_uevent_cb (GUdevClient *gudev_client, const gchar *uuid = g_udev_device_get_sysfs_attr (udev_device, "unique_id"); MockTree *target = (MockTree *) mock_tree_find_uuid (tt->tree, uuid); g_assert_nonnull (target); - fu_plugin_runner_udev_device_changed (tt->plugin, FU_UDEV_DEVICE (target->fu_device), - &error_local); + fu_udev_device_emit_changed (FU_UDEV_DEVICE (target->fu_device)); return; } } diff --git a/plugins/thunderbolt/fu-thunderbolt-device.c b/plugins/thunderbolt/fu-thunderbolt-device.c index e8cba0cca..d4adff6e8 100644 --- a/plugins/thunderbolt/fu-thunderbolt-device.c +++ b/plugins/thunderbolt/fu-thunderbolt-device.c @@ -20,6 +20,7 @@ #include "fu-thunderbolt-device.h" #include "fu-thunderbolt-firmware.h" #include "fu-thunderbolt-firmware-update.h" +#include "fu-udev-device-private.h" typedef enum { FU_THUNDERBOLT_DEVICE_TYPE_DEVICE_CONTROLLER, From c7564055291c48c9869174682efcea619e9791ef Mon Sep 17 00:00:00 2001 From: Mario Limonciello Date: Thu, 10 Sep 2020 21:49:56 -0500 Subject: [PATCH 406/607] trivial: thunderbolt: fixup retimer setting physical ID twice Only needs to be set once in probe. --- plugins/thunderbolt/fu-thunderbolt-device.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/plugins/thunderbolt/fu-thunderbolt-device.c b/plugins/thunderbolt/fu-thunderbolt-device.c index d4adff6e8..207a00d29 100644 --- a/plugins/thunderbolt/fu-thunderbolt-device.c +++ b/plugins/thunderbolt/fu-thunderbolt-device.c @@ -392,10 +392,8 @@ fu_thunderbolt_device_setup_retimer (FuDevice *device, GError **error) FuThunderboltDevice *self = FU_THUNDERBOLT_DEVICE (device); guint16 did; guint16 vid; - g_autofree gchar *idx = g_path_get_basename (self->devpath); g_autofree gchar *instance = NULL; - fu_device_set_physical_id (device, idx); /* as defined in PCIe 4.0 spec */ fu_device_set_summary (device, "A physical layer protocol-aware, software-transparent extension device " "that forms two separate electrical link segments"); @@ -425,7 +423,7 @@ fu_thunderbolt_device_setup_retimer (FuDevice *device, GError **error) instance = g_strdup_printf ("TBT-%04x%04x-retimer%s", (guint) vid, (guint) did, - idx); + fu_device_get_physical_id (device)); fu_device_add_instance_id (device, instance); /* hardcoded for now: From 76cc23c73684e7a4e3aea365652f1395e9289ebc Mon Sep 17 00:00:00 2001 From: Mario Limonciello Date: Thu, 10 Sep 2020 21:55:44 -0500 Subject: [PATCH 407/607] thunderbolt: make sure that authorized to add updatable flag If the device is not authorized, it may cause a composite update that it's part of to not behave properly. If device is authorized at runtime, add updatable flag at runtime as well See #2374 for more details --- plugins/thunderbolt/fu-self-test.c | 2 +- plugins/thunderbolt/fu-thunderbolt-device.c | 47 ++++++++++++++++++++- 2 files changed, 47 insertions(+), 2 deletions(-) diff --git a/plugins/thunderbolt/fu-self-test.c b/plugins/thunderbolt/fu-self-test.c index cab8dceb4..def08a110 100644 --- a/plugins/thunderbolt/fu-self-test.c +++ b/plugins/thunderbolt/fu-self-test.c @@ -396,7 +396,7 @@ mock_tree_attach_device (gpointer user_data) "device", dev->id, "vendor", "042", "vendor_name", "GNOME.org", - "authorized", "0", + "authorized", "1", "nvm_authenticate", authenticate, "nvm_version", tree->nvm_version, "unique_id", tree->uuid, diff --git a/plugins/thunderbolt/fu-thunderbolt-device.c b/plugins/thunderbolt/fu-thunderbolt-device.c index 207a00d29..de106aac7 100644 --- a/plugins/thunderbolt/fu-thunderbolt-device.c +++ b/plugins/thunderbolt/fu-thunderbolt-device.c @@ -110,6 +110,42 @@ fu_thunderbolt_device_read_status_block (FuThunderboltDevice *self, GError **err return TRUE; } +static gboolean +fu_thunderbolt_device_check_authorized (FuThunderboltDevice *self, GError **error) +{ + guint64 status; + g_autofree gchar *attribute = NULL; + const gchar *update_error = NULL; + /* read directly from file to prevent udev caching */ + g_autofree gchar *safe_path = g_build_path ("/", self->devpath, "authorized", NULL); + + if (!g_file_test (safe_path, G_FILE_TEST_EXISTS)) { + g_set_error_literal (error, + FWUPD_ERROR, + FWUPD_ERROR_NOT_SUPPORTED, + "missing authorized attribute"); + return FALSE; + } + + if (!g_file_get_contents (safe_path, &attribute, NULL, error)) + return FALSE; + status = g_ascii_strtoull (attribute, NULL, 16); + if (status == G_MAXUINT64 && errno == ERANGE) { + g_set_error (error, G_IO_ERROR, + g_io_error_from_errno (errno), + "failed to read 'authorized: %s", + g_strerror (errno)); + return FALSE; + } + if (status == 1) + fu_device_add_flag (FU_DEVICE (self), FWUPD_DEVICE_FLAG_UPDATABLE); + else + update_error = "Not authorized"; + fu_device_set_update_error (FU_DEVICE (self), update_error); + + return TRUE; +} + static gboolean fu_thunderbolt_device_can_update (FuThunderboltDevice *self) { @@ -362,8 +398,12 @@ fu_thunderbolt_device_setup_controller (FuDevice *device, GError **error) (guint) vid, (guint) did, self->is_native ? "-native" : ""); - fu_device_add_flag (device, FWUPD_DEVICE_FLAG_UPDATABLE); fu_device_add_flag (device, FWUPD_DEVICE_FLAG_DUAL_IMAGE); + + /* check if device is authorized */ + if (!fu_thunderbolt_device_check_authorized (self, error)) + return FALSE; + } else { device_id = g_strdup ("TBT-fixed"); } @@ -517,6 +557,11 @@ static gboolean fu_thunderbolt_device_rescan (FuDevice *device, GError **error) { FuThunderboltDevice *self = FU_THUNDERBOLT_DEVICE (device); + + /* refresh updatability */ + if (!fu_thunderbolt_device_check_authorized (self, error)) + return FALSE; + /* refresh the version */ return fu_thunderbolt_device_get_version (self, error); } From 258177472f59c1ff4c52ce4c1d8a64ff08d91070 Mon Sep 17 00:00:00 2001 From: Mario Limonciello Date: Thu, 10 Sep 2020 19:51:52 -0500 Subject: [PATCH 408/607] trivial: debian/rules: disable flashrom for ia64 --- contrib/debian/rules | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/contrib/debian/rules b/contrib/debian/rules index e41695cae..78519118c 100755 --- a/contrib/debian/rules +++ b/contrib/debian/rules @@ -16,13 +16,15 @@ endif SB_STYLE := debian deb_version := $(shell dpkg-parsechangelog --show-field Version) +export FLASHROM=-Dplugin_flashrom=false ifeq (yes,$(shell dpkg-vendor --derives-from Ubuntu && echo yes)) SB_STYLE := ubuntu tar_name := fwupd_$(deb_version)_$(DEB_HOST_ARCH).tar.gz - export FLASHROM=-Dplugin_flashrom=false else TMPLDIR := debian/fwupd-$(DEB_HOST_ARCH)-signed-template/usr/share/code-signing/fwupd-$(DEB_HOST_ARCH)-signed-template - export FLASHROM=-Dplugin_flashrom=true + ifneq "$(DEB_HOST_ARCH)" "ia64" + export FLASHROM=-Dplugin_flashrom=true + endif endif %: From 6a1a49eaef73b28dc0a7d8dd3c3ba9041387b6dd Mon Sep 17 00:00:00 2001 From: Mario Limonciello Date: Fri, 11 Sep 2020 13:40:18 -0500 Subject: [PATCH 409/607] dell-dock: mirror updatable flag into thunderbolt This makes sure that if an update is pending (as stored in the EC), Thunderbolt won't show in a needing update state again. Fixes: #2374 --- plugins/dell-dock/fu-plugin-dell-dock.c | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/plugins/dell-dock/fu-plugin-dell-dock.c b/plugins/dell-dock/fu-plugin-dell-dock.c index 2d5a2aac5..5c3396500 100644 --- a/plugins/dell-dock/fu-plugin-dell-dock.c +++ b/plugins/dell-dock/fu-plugin-dell-dock.c @@ -121,6 +121,17 @@ fu_plugin_usb_device_added (FuPlugin *plugin, return TRUE; } +void +fu_plugin_device_registered (FuPlugin *plugin, FuDevice *device) +{ + /* thunderbolt plugin */ + if (g_strcmp0 (fu_device_get_plugin (device), "thunderbolt") != 0 || + fu_device_has_flag (device, FWUPD_DEVICE_FLAG_INTERNAL)) + return; + /* clone updatable flag to leave in needs activation state */ + fu_dell_dock_clone_updatable (device); +} + gboolean fu_plugin_device_removed (FuPlugin *plugin, FuDevice *device, GError **error) { From 5c82b94322e3937626953d92a04d4bf7a6a0d432 Mon Sep 17 00:00:00 2001 From: Richard Hughes Date: Mon, 14 Sep 2020 12:24:06 +0100 Subject: [PATCH 410/607] Do not show HSI obsoleted attributes by default When one result is obsoleted by another, then do not show the old result by default. Additionally hide the HSI URLs as this was designed more for GUI clients like gnome-firmware than CLI tools such as fwupdmgr. --- data/bash-completion/fwupdmgr.in | 2 +- data/bash-completion/fwupdtool.in | 2 +- data/fish-completion/fwupdmgr.fish | 2 +- src/fu-tool.c | 20 +++++++++++++++----- src/fu-util-common.c | 20 ++++++++++++++------ src/fu-util-common.h | 11 ++++++++++- src/fu-util.c | 20 +++++++++++++++----- 7 files changed, 57 insertions(+), 20 deletions(-) diff --git a/data/bash-completion/fwupdmgr.in b/data/bash-completion/fwupdmgr.in index 623a75917..0288c0d34 100644 --- a/data/bash-completion/fwupdmgr.in +++ b/data/bash-completion/fwupdmgr.in @@ -47,7 +47,7 @@ _fwupdmgr_opts=( '--no-metadata-check' '--no-reboot-check' '--no-safety-check' - '--show-all-devices' + '--show-all' '--sign' '--filter' '--disable-ssl-strict' diff --git a/data/bash-completion/fwupdtool.in b/data/bash-completion/fwupdtool.in index 7cac716b4..82c676a3f 100644 --- a/data/bash-completion/fwupdtool.in +++ b/data/bash-completion/fwupdtool.in @@ -40,7 +40,7 @@ _fwupdtool_opts=( '--allow-reinstall' '--allow-older' '--force' - '--show-all-devices' + '--show-all' '--plugins' '--prepare' '--cleanup' diff --git a/data/fish-completion/fwupdmgr.fish b/data/fish-completion/fwupdmgr.fish index 1568554c4..aec7e11c9 100644 --- a/data/fish-completion/fwupdmgr.fish +++ b/data/fish-completion/fwupdmgr.fish @@ -26,7 +26,7 @@ complete -c fwupdmgr -l no-metadata-check -d 'Do not check for old metadata' complete -c fwupdmgr -l no-reboot-check -d 'Do not check for reboot after update' complete -c fwupdmgr -l no-safety-check -d 'Do not perform device safety checks' complete -c fwupdmgr -l no-history -d 'Do not write to the history database' -complete -c fwupdmgr -l show-all-devices -d 'Show devices that are not updatable' +complete -c fwupdmgr -l show-all -d 'Show all results' complete -c fwupdmgr -l disable-ssl-strict -d 'Ignore SSL strict checks when downloading files' complete -c fwupdmgr -l filter -d 'Filter with a set of device flags' diff --git a/src/fu-tool.c b/src/fu-tool.c index 591500c6b..29e72d752 100644 --- a/src/fu-tool.c +++ b/src/fu-tool.c @@ -61,7 +61,7 @@ struct FuUtilPrivate { gboolean cleanup_blob; gboolean enable_json_state; FwupdInstallFlags flags; - gboolean show_all_devices; + gboolean show_all; gboolean disable_ssl_strict; /* only valid in update and downgrade */ FuUtilOperation current_operation; @@ -411,7 +411,7 @@ fu_util_get_details (FuUtilPrivate *priv, gchar **values, GError **error) } /* implied, important for get-details on a device not in your system */ - priv->show_all_devices = TRUE; + priv->show_all = TRUE; /* open file */ fd = open (values[0], O_RDONLY); @@ -473,7 +473,7 @@ fu_util_build_device_tree (FuUtilPrivate *priv, GNode *root, GPtrArray *devs, Fu FuDevice *dev_tmp = g_ptr_array_index (devs, i); if (!fu_util_filter_device (priv, FWUPD_DEVICE (dev_tmp))) continue; - if (!priv->show_all_devices && + if (!priv->show_all && !fu_util_is_interesting_device (FWUPD_DEVICE (dev_tmp))) continue; if (fu_device_get_parent (dev_tmp) == dev) { @@ -1997,6 +1997,7 @@ fu_util_get_remotes (FuUtilPrivate *priv, gchar **values, GError **error) static gboolean fu_util_security (FuUtilPrivate *priv, gchar **values, GError **error) { + FuSecurityAttrToStringFlags flags = FU_SECURITY_ATTR_TO_STRING_FLAG_NONE; g_autoptr(FuSecurityAttrs) attrs = NULL; g_autoptr(GPtrArray) items = NULL; g_autofree gchar *str = NULL; @@ -2018,10 +2019,16 @@ fu_util_security (FuUtilPrivate *priv, gchar **values, GError **error) g_print ("%s \033[1m%s\033[0m\n", _("Host Security ID:"), fu_engine_get_host_security_id (priv->engine)); + /* show or hide different elements */ + if (priv->show_all) { + flags |= FU_SECURITY_ATTR_TO_STRING_FLAG_SHOW_OBSOLETES; + flags |= FU_SECURITY_ATTR_TO_STRING_FLAG_SHOW_URLS; + } + /* print the "why" */ attrs = fu_engine_get_host_security_attrs (priv->engine); items = fu_security_attrs_get_all (attrs); - str = fu_util_security_attrs_to_string (items); + str = fu_util_security_attrs_to_string (items, flags); g_print ("%s\n", str); return TRUE; } @@ -2144,7 +2151,10 @@ main (int argc, char *argv[]) { "no-safety-check", '\0', 0, G_OPTION_ARG_NONE, &priv->no_safety_check, /* TRANSLATORS: command line option */ _("Do not perform device safety checks"), NULL }, - { "show-all-devices", '\0', 0, G_OPTION_ARG_NONE, &priv->show_all_devices, + { "show-all", '\0', 0, G_OPTION_ARG_NONE, &priv->show_all, + /* TRANSLATORS: command line option */ + _("Show all results"), NULL }, + { "show-all-devices", '\0', G_OPTION_FLAG_HIDDEN, G_OPTION_ARG_NONE, &priv->show_all, /* TRANSLATORS: command line option */ _("Show devices that are not updatable"), NULL }, { "plugins", '\0', 0, G_OPTION_ARG_STRING_ARRAY, &plugin_glob, diff --git a/src/fu-util-common.c b/src/fu-util-common.c index 5d8c9ae92..53ac9fef0 100644 --- a/src/fu-util-common.c +++ b/src/fu-util-common.c @@ -1545,9 +1545,16 @@ fu_util_remote_to_string (FwupdRemote *remote, guint idt) } static void -fu_security_attr_append_str (FwupdSecurityAttr *attr, GString *str) +fu_security_attr_append_str (FwupdSecurityAttr *attr, GString *str, FuSecurityAttrToStringFlags flags) { - g_autofree gchar *name = fu_security_attr_get_name (attr); + g_autofree gchar *name = NULL; + + /* hide obsoletes by default */ + if (fwupd_security_attr_has_flag (attr, FWUPD_SECURITY_ATTR_FLAG_OBSOLETED) && + (flags & FU_SECURITY_ATTR_TO_STRING_FLAG_SHOW_OBSOLETES) == 0) + return; + + name = fu_security_attr_get_name (attr); if (name == NULL) name = g_strdup (fwupd_security_attr_get_appstream_id (attr)); if (fwupd_security_attr_has_flag (attr, FWUPD_SECURITY_ATTR_FLAG_OBSOLETED)) { @@ -1567,7 +1574,8 @@ fu_security_attr_append_str (FwupdSecurityAttr *attr, GString *str) } else { g_string_append_printf (str, "\033[31m\033[1m%s\033[0m", fu_security_attr_get_result (attr)); } - if (fwupd_security_attr_get_url (attr) != NULL) { + if ((flags & FU_SECURITY_ATTR_TO_STRING_FLAG_SHOW_URLS) > 0 && + fwupd_security_attr_get_url (attr) != NULL) { g_string_append_printf (str, ": %s", fwupd_security_attr_get_url (attr)); } @@ -1579,7 +1587,7 @@ fu_security_attr_append_str (FwupdSecurityAttr *attr, GString *str) } gchar * -fu_util_security_attrs_to_string (GPtrArray *attrs) +fu_util_security_attrs_to_string (GPtrArray *attrs, FuSecurityAttrToStringFlags strflags) { FwupdSecurityAttrFlags flags = FWUPD_SECURITY_ATTR_FLAG_NONE; const FwupdSecurityAttrFlags hpi_suffixes[] = { @@ -1603,7 +1611,7 @@ fu_util_security_attrs_to_string (GPtrArray *attrs) g_string_append_printf (str, "\n\033[1mHSI-%u\033[0m\n", j); has_header = TRUE; } - fu_security_attr_append_str (attr, str); + fu_security_attr_append_str (attr, str, strflags); /* make sure they have at least HSI-1 */ if (j < FWUPD_SECURITY_ATTR_LEVEL_IMPORTANT && !fwupd_security_attr_has_flag (attr, FWUPD_SECURITY_ATTR_FLAG_SUCCESS)) @@ -1633,7 +1641,7 @@ fu_util_security_attrs_to_string (GPtrArray *attrs) if (fwupd_security_attr_has_flag (attr, FWUPD_SECURITY_ATTR_FLAG_RUNTIME_ISSUE) && !fwupd_security_attr_has_flag (attr, FWUPD_SECURITY_ATTR_FLAG_SUCCESS)) runtime_help = TRUE; - fu_security_attr_append_str (attr, str); + fu_security_attr_append_str (attr, str, strflags); } } } diff --git a/src/fu-util-common.h b/src/fu-util-common.h index 207206f40..96f282655 100644 --- a/src/fu-util-common.h +++ b/src/fu-util-common.h @@ -24,6 +24,14 @@ typedef struct { FuUtilCmdFunc callback; } FuUtilCmd; +typedef enum { + FU_SECURITY_ATTR_TO_STRING_FLAG_NONE = 0, + FU_SECURITY_ATTR_TO_STRING_FLAG_SHOW_OBSOLETES = 1 << 0, + FU_SECURITY_ATTR_TO_STRING_FLAG_SHOW_URLS = 1 << 1, + /*< private >*/ + FU_SECURITY_ATTR_TO_STRING_FLAG_LAST +} FuSecurityAttrToStringFlags; + void fu_util_print_data (const gchar *title, const gchar *msg); guint fu_util_prompt_for_number (guint maxnum); @@ -76,7 +84,8 @@ gchar *fu_util_release_to_string (FwupdRelease *rel, guint idt); gchar *fu_util_remote_to_string (FwupdRemote *remote, guint idt); -gchar *fu_util_security_attrs_to_string (GPtrArray *attrs); +gchar *fu_util_security_attrs_to_string (GPtrArray *attrs, + FuSecurityAttrToStringFlags flags); gboolean fu_util_send_report (FwupdClient *client, const gchar *report_uri, const gchar *data, diff --git a/src/fu-util.c b/src/fu-util.c index d9f29c042..9996df4fa 100644 --- a/src/fu-util.c +++ b/src/fu-util.c @@ -66,7 +66,7 @@ struct FuUtilPrivate { gboolean no_safety_check; gboolean assume_yes; gboolean sign; - gboolean show_all_devices; + gboolean show_all; gboolean disable_ssl_strict; /* only valid in update and downgrade */ FuUtilOperation current_operation; @@ -506,7 +506,7 @@ fu_util_build_device_tree (FuUtilPrivate *priv, GNode *root, GPtrArray *devs, Fw FwupdDevice *dev_tmp = g_ptr_array_index (devs, i); if (!fu_util_filter_device (priv, dev_tmp)) continue; - if (!priv->show_all_devices && + if (!priv->show_all && !fu_util_is_interesting_device (dev_tmp)) continue; if (fwupd_device_get_parent (dev_tmp) == dev) { @@ -656,7 +656,7 @@ fu_util_get_details (FuUtilPrivate *priv, gchar **values, GError **error) } /* implied, important for get-details on a device not in your system */ - priv->show_all_devices = TRUE; + priv->show_all = TRUE; array = fwupd_client_get_details (priv->client, values[0], NULL, error); if (array == NULL) @@ -2195,6 +2195,7 @@ fu_util_upload_security (FuUtilPrivate *priv, GPtrArray *attrs, GError **error) static gboolean fu_util_security (FuUtilPrivate *priv, gchar **values, GError **error) { + FuSecurityAttrToStringFlags flags = FU_SECURITY_ATTR_TO_STRING_FLAG_NONE; g_autoptr(GPtrArray) attrs = NULL; g_autofree gchar *str = NULL; @@ -2218,7 +2219,13 @@ fu_util_security (FuUtilPrivate *priv, gchar **values, GError **error) error); if (attrs == NULL) return FALSE; - str = fu_util_security_attrs_to_string (attrs); + + /* show or hide different elements */ + if (priv->show_all) { + flags |= FU_SECURITY_ATTR_TO_STRING_FLAG_SHOW_OBSOLETES; + flags |= FU_SECURITY_ATTR_TO_STRING_FLAG_SHOW_URLS; + } + str = fu_util_security_attrs_to_string (attrs, flags); g_print ("%s\n", str); /* opted-out */ @@ -2524,7 +2531,10 @@ main (int argc, char *argv[]) { "no-history", '\0', 0, G_OPTION_ARG_NONE, &no_history, /* TRANSLATORS: command line option */ _("Do not write to the history database"), NULL }, - { "show-all-devices", '\0', 0, G_OPTION_ARG_NONE, &priv->show_all_devices, + { "show-all", '\0', 0, G_OPTION_ARG_NONE, &priv->show_all, + /* TRANSLATORS: command line option */ + _("Show all results"), NULL }, + { "show-all-devices", '\0', G_OPTION_FLAG_HIDDEN, G_OPTION_ARG_NONE, &priv->show_all, /* TRANSLATORS: command line option */ _("Show devices that are not updatable"), NULL }, { "disable-ssl-strict", '\0', 0, G_OPTION_ARG_NONE, &priv->disable_ssl_strict, From a1ebcbf7439ff117fca50ef94bd3cdfb3ef80ba7 Mon Sep 17 00:00:00 2001 From: Richard Hughes Date: Mon, 14 Sep 2020 15:27:43 +0100 Subject: [PATCH 411/607] trivial: Add back the hidden --plugin-whitelist option It is essentially part of our 'CLI API' and we have to support people using the old name. --- src/fu-tool.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/fu-tool.c b/src/fu-tool.c index 29e72d752..fb7de426c 100644 --- a/src/fu-tool.c +++ b/src/fu-tool.c @@ -2160,6 +2160,9 @@ main (int argc, char *argv[]) { "plugins", '\0', 0, G_OPTION_ARG_STRING_ARRAY, &plugin_glob, /* TRANSLATORS: command line option */ _("Manually enable specific plugins"), NULL }, + { "plugin-whitelist", '\0', G_OPTION_FLAG_HIDDEN, G_OPTION_ARG_STRING_ARRAY, &plugin_glob, + /* TRANSLATORS: command line option */ + _("Manually enable specific plugins"), NULL }, { "prepare", '\0', 0, G_OPTION_ARG_NONE, &priv->prepare_blob, /* TRANSLATORS: command line option */ _("Run the plugin composite prepare routine when using install-blob"), NULL }, From b7fbb07dcbcc5615005b566935609c51ed9401b8 Mon Sep 17 00:00:00 2001 From: Richard Hughes Date: Sun, 13 Sep 2020 15:08:16 +0100 Subject: [PATCH 412/607] trivial: Convert the device order to an unsigned int This allows us to set the parent of an existing parent without wrapping. --- libfwupdplugin/fu-device-private.h | 4 ++-- libfwupdplugin/fu-device.c | 9 +++++---- 2 files changed, 7 insertions(+), 6 deletions(-) diff --git a/libfwupdplugin/fu-device-private.h b/libfwupdplugin/fu-device-private.h index 1a3375fa3..1fc80479d 100644 --- a/libfwupdplugin/fu-device-private.h +++ b/libfwupdplugin/fu-device-private.h @@ -16,9 +16,9 @@ gboolean fu_device_has_parent_guid (FuDevice *self, const gchar *guid); void fu_device_set_parent (FuDevice *self, FuDevice *parent); -guint fu_device_get_order (FuDevice *self); +gint fu_device_get_order (FuDevice *self); void fu_device_set_order (FuDevice *self, - guint order); + gint order); void fu_device_set_alternate (FuDevice *self, FuDevice *alternate); GType fu_device_get_specialized_gtype (FuDevice *self); diff --git a/libfwupdplugin/fu-device.c b/libfwupdplugin/fu-device.c index c7f2b1f01..8b29de013 100644 --- a/libfwupdplugin/fu-device.c +++ b/libfwupdplugin/fu-device.c @@ -48,7 +48,7 @@ typedef struct { GPtrArray *children; guint remove_delay; /* ms */ guint progress; - guint order; + gint order; guint priority; guint poll_id; gboolean done_probe; @@ -405,7 +405,7 @@ fu_device_set_poll_interval (FuDevice *self, guint interval) * * Since: 1.0.8 **/ -guint +gint fu_device_get_order (FuDevice *self) { FuDevicePrivate *priv = GET_PRIVATE (self); @@ -424,7 +424,7 @@ fu_device_get_order (FuDevice *self) * Since: 1.0.8 **/ void -fu_device_set_order (FuDevice *self, guint order) +fu_device_set_order (FuDevice *self, gint order) { FuDevicePrivate *priv = GET_PRIVATE (self); g_return_if_fail (FU_IS_DEVICE (self)); @@ -2299,7 +2299,7 @@ fu_device_add_string (FuDevice *self, guint idt, GString *str) g_autofree gchar *sz = g_strdup_printf ("%" G_GUINT64_FORMAT, priv->size_max); fu_common_string_append_kv (str, idt + 1, "FirmwareSizeMax", sz); } - if (priv->order > 0) + if (priv->order != G_MAXINT) fu_common_string_append_ku (str, idt + 1, "Order", priv->order); if (priv->priority > 0) fu_common_string_append_ku (str, idt + 1, "Priority", priv->priority); @@ -3224,6 +3224,7 @@ static void fu_device_init (FuDevice *self) { FuDevicePrivate *priv = GET_PRIVATE (self); + priv->order = G_MAXINT; priv->children = g_ptr_array_new_with_free_func ((GDestroyNotify) g_object_unref); priv->parent_guids = g_ptr_array_new_with_free_func (g_free); priv->possible_plugins = g_ptr_array_new_with_free_func (g_free); From 81f9552095d1da63b50b1376bab6a8b74b79db5b Mon Sep 17 00:00:00 2001 From: Richard Hughes Date: Sun, 13 Sep 2020 15:12:57 +0100 Subject: [PATCH 413/607] Correctly order devices when using logical parents If the device parent is added using fu_device_add_parent_guid() or ParentGuid from a quirk file then the child is not returned in fu_device_get_children() by design as the physical ID will be likely different. This means we cannot reliably 'depsolve' the order in FuDevice as we need the full list of devices that might be parents. The existing algorithm had several logical problems when dealing with more than a single parent and child. The FuDeviceList object is the right place to do this as it knows about all added devices on the system. This means the addition of a logical device causes the root logical device (and all it's children, and grandchildren) to be re-ordered. This allows firmware on deeply nested composite devices like hubs to be installed in the correct order. --- libfwupdplugin/fu-device.c | 16 ----------- src/fu-device-list.c | 54 ++++++++++++++++++++++++++++++++++++++ src/fu-device-list.h | 2 ++ src/fu-engine.c | 3 +++ src/fu-self-test.c | 9 ++++--- 5 files changed, 65 insertions(+), 19 deletions(-) diff --git a/libfwupdplugin/fu-device.c b/libfwupdplugin/fu-device.c index 8b29de013..5720a9ec1 100644 --- a/libfwupdplugin/fu-device.c +++ b/libfwupdplugin/fu-device.c @@ -653,13 +653,6 @@ fu_device_set_parent (FuDevice *self, FuDevice *parent) g_return_if_fail (FU_IS_DEVICE (self)); - /* if unspecified, always child before parent */ - if (parent != NULL && - fu_device_get_order (parent) == fu_device_get_order (self)) { - g_debug ("auto-setting %s order", fu_device_get_id (parent)); - fu_device_set_order (parent, fu_device_get_order (self) + 1); - } - /* if the parent has quirks, make the child inherit it */ if (parent != NULL) { if (fu_device_get_quirks (self) == NULL && @@ -802,15 +795,6 @@ fu_device_add_child (FuDevice *self, FuDevice *child) /* ensure the parent is also set on the child */ fu_device_set_parent (child, self); - - /* order devices so they are updated in the correct sequence */ - if (fu_device_has_flag (child, FWUPD_DEVICE_FLAG_INSTALL_PARENT_FIRST)) { - if (priv->order >= fu_device_get_order (child)) - fu_device_set_order (child, priv->order + 1); - } else { - if (priv->order <= fu_device_get_order (child)) - priv->order = fu_device_get_order (child) + 1; - } } /** diff --git a/src/fu-device-list.c b/src/fu-device-list.c index fc154442d..de25ed3be 100644 --- a/src/fu-device-list.c +++ b/src/fu-device-list.c @@ -81,6 +81,60 @@ fu_device_list_emit_device_changed (FuDeviceList *self, FuDevice *device) g_signal_emit (self, signals[SIGNAL_CHANGED], 0, device); } +/* we cannot use fu_device_get_children() as this will not find "parent-only" + * logical relationships added using fu_device_add_parent_guid() */ +static GPtrArray * +fu_device_list_get_children (FuDeviceList *self, FuDevice *device) +{ + GPtrArray *devices = g_ptr_array_new_with_free_func ((GDestroyNotify) g_object_unref); + g_rw_lock_reader_lock (&self->devices_mutex); + for (guint i = 0; i < self->devices->len; i++) { + FuDeviceItem *item = g_ptr_array_index (self->devices, i); + if (device == fu_device_get_parent (item->device)) + g_ptr_array_add (devices, g_object_ref (item->device)); + } + g_rw_lock_reader_unlock (&self->devices_mutex); + return devices; +} + +static void +fu_device_list_depsolve_order_full (FuDeviceList *self, FuDevice *device, guint depth) +{ + g_autoptr(GPtrArray) children = NULL; + + /* ourself */ + fu_device_set_order (device, depth); + + /* optional children */ + children = fu_device_list_get_children (self, device); + for (guint i = 0; i < children->len; i++) { + FuDevice *child = g_ptr_array_index (children, i); + if (fu_device_has_flag (child, FWUPD_DEVICE_FLAG_INSTALL_PARENT_FIRST)) { + fu_device_list_depsolve_order_full (self, child, depth + 1); + } else { + fu_device_list_depsolve_order_full (self, child, depth - 1); + } + } +} + +/** + * fu_device_list_depsolve_order: + * @self: A #FuDeviceList + * @device: A #FuDevice + * + * Sets the device order using the logical parent->child relationships -- by default + * the child is updated first, unless the device has set flag + * %FWUPD_DEVICE_FLAG_INSTALL_PARENT_FIRST. + * + * Since: 1.5.0 + **/ +void +fu_device_list_depsolve_order (FuDeviceList *self, FuDevice *device) +{ + g_autoptr(FuDevice) root = fu_device_get_root (device); + fu_device_list_depsolve_order_full (self, root, 0); +} + /** * fu_device_list_get_all: * @self: A #FuDeviceList diff --git a/src/fu-device-list.h b/src/fu-device-list.h index 783b9d765..eaf711a6b 100644 --- a/src/fu-device-list.h +++ b/src/fu-device-list.h @@ -31,3 +31,5 @@ FuDevice *fu_device_list_get_by_guid (FuDeviceList *self, gboolean fu_device_list_wait_for_replug (FuDeviceList *self, FuDevice *device, GError **error); +void fu_device_list_depsolve_order (FuDeviceList *self, + FuDevice *device); diff --git a/src/fu-engine.c b/src/fu-engine.c index 72dff9b9a..f0c543ce3 100644 --- a/src/fu-engine.c +++ b/src/fu-engine.c @@ -5208,6 +5208,9 @@ fu_engine_add_device (FuEngine *self, FuDevice *device) /* create new device */ fu_device_list_add (self->device_list, device); + /* fix order */ + fu_device_list_depsolve_order (self->device_list, device); + /* fixup the name and format as needed from cached metadata */ if (component != NULL) fu_engine_md_refresh_device_from_component (self, device, component); diff --git a/src/fu-self-test.c b/src/fu-self-test.c index 1f9abbabf..903edba41 100644 --- a/src/fu-self-test.c +++ b/src/fu-self-test.c @@ -1076,15 +1076,18 @@ fu_engine_device_parent_func (gconstpointer user_data) /* add two together */ fu_engine_add_device (engine, device2); + /* this is normally done by fu_plugin_device_add() */ + fu_engine_add_device (engine, device3); + /* verify both children were adopted */ g_assert (fu_device_get_parent (device3) == device2); g_assert (fu_device_get_parent (device1) == device2); g_assert_cmpstr (fu_device_get_vendor (device3), ==, "oem"); /* verify order */ - g_assert_cmpint (fu_device_get_order (device1), ==, 0); - g_assert_cmpint (fu_device_get_order (device2), ==, 1); - g_assert_cmpint (fu_device_get_order (device3), ==, 0); + g_assert_cmpint (fu_device_get_order (device1), ==, -1); + g_assert_cmpint (fu_device_get_order (device2), ==, 0); + g_assert_cmpint (fu_device_get_order (device3), ==, -1); } static void From 13bae744be55d5f901133d957a0f3114b7381024 Mon Sep 17 00:00:00 2001 From: Richard Hughes Date: Mon, 7 Sep 2020 13:01:22 +0100 Subject: [PATCH 414/607] platform-integrity: Use the BCR values provided by the kernel class This requires the new kernel driver by Daniel Gutson. --- contrib/fwupd.spec.in | 2 + meson_options.txt | 1 - plugins/linux-spi-lpc/meson.build | 23 --- plugins/meson.build | 5 +- plugins/pci-bcr/fu-plugin-pci-bcr.c | 3 - .../README.md | 4 +- .../fu-plugin-platform-integrity.c} | 134 +++++++++++------- .../fwupd-platform-integrity.conf | 1 + plugins/platform-integrity/meson.build | 33 +++++ .../platform-integrity.quirk | 3 + 10 files changed, 123 insertions(+), 86 deletions(-) delete mode 100644 plugins/linux-spi-lpc/meson.build rename plugins/{linux-spi-lpc => platform-integrity}/README.md (78%) rename plugins/{linux-spi-lpc/fu-plugin-linux-spi-lpc.c => platform-integrity/fu-plugin-platform-integrity.c} (71%) create mode 100644 plugins/platform-integrity/fwupd-platform-integrity.conf create mode 100644 plugins/platform-integrity/meson.build create mode 100644 plugins/platform-integrity/platform-integrity.quirk diff --git a/contrib/fwupd.spec.in b/contrib/fwupd.spec.in index ef825a70d..4e69f80ec 100644 --- a/contrib/fwupd.spec.in +++ b/contrib/fwupd.spec.in @@ -308,6 +308,7 @@ mkdir -p --mode=0700 $RPM_BUILD_ROOT%{_localstatedir}/lib/fwupd/gnupg %{_sysconfdir}/pki/fwupd-metadata %if 0%{?have_msr} %{_sysconfdir}/modules-load.d/fwupd-msr.conf +%{_sysconfdir}/modules-load.d/fwupd-platform-integrity.conf %endif %{_datadir}/dbus-1/system.d/org.freedesktop.fwupd.conf %{_datadir}/bash-completion/completions/fwupdmgr @@ -402,6 +403,7 @@ mkdir -p --mode=0700 $RPM_BUILD_ROOT%{_localstatedir}/lib/fwupd/gnupg %{_libdir}/fwupd-plugins-3/libfu_plugin_optionrom.so %{_libdir}/fwupd-plugins-3/libfu_plugin_pci_bcr.so %{_libdir}/fwupd-plugins-3/libfu_plugin_pci_mei.so +%{_libdir}/fwupd-plugins-3/libfu_plugin_platform_integrity.so %if 0%{?have_redfish} %{_libdir}/fwupd-plugins-3/libfu_plugin_redfish.so %endif diff --git a/meson_options.txt b/meson_options.txt index ad0f3b730..bedb929dd 100644 --- a/meson_options.txt +++ b/meson_options.txt @@ -21,7 +21,6 @@ option('plugin_modem_manager', type : 'boolean', value : false, description : 'e option('plugin_msr', type : 'boolean', value : true, description : 'enable MSR support') option('plugin_flashrom', type : 'boolean', value : false, description : 'enable libflashrom support') option('plugin_coreboot', type : 'boolean', value : true, description : 'enable coreboot support') -option('plugin_linux_spi_lpc', type : 'boolean', value : false, description : 'enable Linux SPI SecurityFS support') option('systemd', type : 'boolean', value : true, description : 'enable systemd support') option('systemd_root_prefix', type: 'string', value: '', description: 'Directory to base systemd’s installation directories on') option('elogind', type : 'boolean', value : false, description : 'enable elogind support') diff --git a/plugins/linux-spi-lpc/meson.build b/plugins/linux-spi-lpc/meson.build deleted file mode 100644 index cba7801bc..000000000 --- a/plugins/linux-spi-lpc/meson.build +++ /dev/null @@ -1,23 +0,0 @@ -cargs = ['-DG_LOG_DOMAIN="FuPluginLinuxSpiLpc"'] - -shared_module('fu_plugin_linux_spi_lpc', - fu_hash, - sources : [ - 'fu-plugin-linux-spi-lpc.c', - ], - include_directories : [ - root_incdir, - fwupd_incdir, - fwupdplugin_incdir, - ], - install : true, - install_dir: plugin_dir, - link_with : [ - fwupd, - fwupdplugin, - ], - c_args : cargs, - dependencies : [ - plugin_deps, - ], -) diff --git a/plugins/meson.build b/plugins/meson.build index b24c13920..8e1a7956d 100644 --- a/plugins/meson.build +++ b/plugins/meson.build @@ -21,6 +21,7 @@ subdir('dell-dock') subdir('nitrokey') subdir('pci-bcr') subdir('pci-mei') +subdir('platform-integrity') subdir('rts54hid') subdir('rts54hub') subdir('solokey') @@ -35,10 +36,6 @@ if get_option('plugin_msr') subdir('msr') endif -if get_option('plugin_linux_spi_lpc') -subdir('linux-spi-lpc') -endif - if get_option('gudev') subdir('ata') subdir('elantp') diff --git a/plugins/pci-bcr/fu-plugin-pci-bcr.c b/plugins/pci-bcr/fu-plugin-pci-bcr.c index b96ce0ac3..01661f7ca 100644 --- a/plugins/pci-bcr/fu-plugin-pci-bcr.c +++ b/plugins/pci-bcr/fu-plugin-pci-bcr.c @@ -54,7 +54,6 @@ fu_plugin_add_security_attr_bioswe (FuPlugin *plugin, FuSecurityAttrs *attrs) attr = fwupd_security_attr_new (FWUPD_SECURITY_ATTR_ID_SPI_BIOSWE); fwupd_security_attr_set_plugin (attr, fu_plugin_get_name (plugin)); fwupd_security_attr_set_level (attr, FWUPD_SECURITY_ATTR_LEVEL_CRITICAL); - fwupd_security_attr_add_obsolete (attr, "linux_spi_lpc"); fu_security_attrs_append (attrs, attr); /* no device */ @@ -88,7 +87,6 @@ fu_plugin_add_security_attr_ble (FuPlugin *plugin, FuSecurityAttrs *attrs) attr = fwupd_security_attr_new (FWUPD_SECURITY_ATTR_ID_SPI_BLE); fwupd_security_attr_set_plugin (attr, fu_plugin_get_name (plugin)); fwupd_security_attr_set_level (attr, FWUPD_SECURITY_ATTR_LEVEL_CRITICAL); - fwupd_security_attr_add_obsolete (attr, "linux_spi_lpc"); fu_security_attrs_append (attrs, attr); /* load file */ @@ -116,7 +114,6 @@ fu_plugin_add_security_attr_smm_bwp (FuPlugin *plugin, FuSecurityAttrs *attrs) attr = fwupd_security_attr_new (FWUPD_SECURITY_ATTR_ID_SPI_SMM_BWP); fwupd_security_attr_set_plugin (attr, fu_plugin_get_name (plugin)); fwupd_security_attr_set_level (attr, FWUPD_SECURITY_ATTR_LEVEL_CRITICAL); - fwupd_security_attr_add_obsolete (attr, "linux_spi_lpc"); fu_security_attrs_append (attrs, attr); /* load file */ diff --git a/plugins/linux-spi-lpc/README.md b/plugins/platform-integrity/README.md similarity index 78% rename from plugins/linux-spi-lpc/README.md rename to plugins/platform-integrity/README.md index 04d1909b2..aad353a5e 100644 --- a/plugins/linux-spi-lpc/README.md +++ b/plugins/platform-integrity/README.md @@ -1,5 +1,5 @@ -Linux SPI LPC -============= +Platform Integrity +================== Introduction ------------ diff --git a/plugins/linux-spi-lpc/fu-plugin-linux-spi-lpc.c b/plugins/platform-integrity/fu-plugin-platform-integrity.c similarity index 71% rename from plugins/linux-spi-lpc/fu-plugin-linux-spi-lpc.c rename to plugins/platform-integrity/fu-plugin-platform-integrity.c index bcdede6ad..29662b9c3 100644 --- a/plugins/linux-spi-lpc/fu-plugin-linux-spi-lpc.c +++ b/plugins/platform-integrity/fu-plugin-platform-integrity.c @@ -10,17 +10,53 @@ #include "fu-plugin-vfuncs.h" #include "fu-hash.h" -#define FU_PLUGIN_LINUX_SPI_LPC_SYSFS_DIR "/sys/kernel/security/spi" +struct FuPluginData { + gchar *sysfs_path; +}; void fu_plugin_init (FuPlugin *plugin) { + fu_plugin_alloc_data (plugin, sizeof (FuPluginData)); fu_plugin_set_build_hash (plugin, FU_BUILD_HASH); + fu_plugin_add_udev_subsystem (plugin, "platform-integrity"); +} + +void +fu_plugin_destroy (FuPlugin *plugin) +{ + FuPluginData *priv = fu_plugin_get_data (plugin); + g_free (priv->sysfs_path); +} + +gboolean +fu_plugin_udev_device_added (FuPlugin *plugin, FuUdevDevice *device, GError **error) +{ + FuPluginData *priv = fu_plugin_get_data (plugin); + + /* interesting device? */ + if (g_strcmp0 (fu_udev_device_get_subsystem (device), "platform-integrity") != 0) + return TRUE; + + /* we only care about the first instance */ + if (priv->sysfs_path != NULL) { + g_set_error (error, + FWUPD_ERROR, + FWUPD_ERROR_NOT_SUPPORTED, + "only one platform-integrity device supported; already using %s", + priv->sysfs_path); + return FALSE; + } + + /* success */ + priv->sysfs_path = g_strdup (fu_udev_device_get_sysfs_path (device)); + return TRUE; } static void fu_plugin_add_security_attr_bioswe (FuPlugin *plugin, FuSecurityAttrs *attrs) { + FuPluginData *priv = fu_plugin_get_data (plugin); gsize bufsz = 0; g_autofree gchar *buf = NULL; g_autofree gchar *fn = NULL; @@ -34,56 +70,14 @@ fu_plugin_add_security_attr_bioswe (FuPlugin *plugin, FuSecurityAttrs *attrs) fwupd_security_attr_add_obsolete (attr, "pci_bcr"); fu_security_attrs_append (attrs, attr); - /* maybe the kernel module does not exist */ - if (!g_file_test (FU_PLUGIN_LINUX_SPI_LPC_SYSFS_DIR, G_FILE_TEST_IS_DIR)) { - fwupd_security_attr_set_result (attr, FWUPD_SECURITY_ATTR_RESULT_NOT_FOUND); - return; - } - /* load file */ - fn = g_build_filename (FU_PLUGIN_LINUX_SPI_LPC_SYSFS_DIR, "bioswe", NULL); + fn = g_build_filename (priv->sysfs_path, "bioswe", NULL); if (!g_file_get_contents (fn, &buf, &bufsz, &error_local)) { g_warning ("could not open %s: %s", fn, error_local->message); fwupd_security_attr_set_result (attr, FWUPD_SECURITY_ATTR_RESULT_NOT_VALID); return; } if (g_strcmp0 (buf, "0\n") != 0) { - fwupd_security_attr_set_result (attr, FWUPD_SECURITY_ATTR_RESULT_NOT_ENABLED); - return; - } - - /* success */ - fwupd_security_attr_add_flag (attr, FWUPD_SECURITY_ATTR_FLAG_SUCCESS); - fwupd_security_attr_set_result (attr, FWUPD_SECURITY_ATTR_RESULT_ENABLED); -} - -static void -fu_plugin_add_security_attr_ble (FuPlugin *plugin, FuSecurityAttrs *attrs) -{ - gsize bufsz = 0; - g_autofree gchar *buf = NULL; - g_autofree gchar *fn = NULL; - g_autoptr(FwupdSecurityAttr) attr = NULL; - g_autoptr(GError) error_local = NULL; - - /* maybe the kernel module does not exist */ - if (!g_file_test (FU_PLUGIN_LINUX_SPI_LPC_SYSFS_DIR, G_FILE_TEST_IS_DIR)) - return; - - /* create attr */ - attr = fwupd_security_attr_new (FWUPD_SECURITY_ATTR_ID_SPI_BLE); - fwupd_security_attr_set_level (attr, FWUPD_SECURITY_ATTR_LEVEL_CRITICAL); - fwupd_security_attr_add_obsolete (attr, "pci_bcr"); - fu_security_attrs_append (attrs, attr); - - /* load file */ - fn = g_build_filename (FU_PLUGIN_LINUX_SPI_LPC_SYSFS_DIR, "ble", NULL); - if (!g_file_get_contents (fn, &buf, &bufsz, &error_local)) { - g_warning ("could not open %s: %s", fn, error_local->message); - fwupd_security_attr_set_result (attr, FWUPD_SECURITY_ATTR_RESULT_NOT_VALID); - return; - } - if (g_strcmp0 (buf, "1\n") != 0) { fwupd_security_attr_set_result (attr, FWUPD_SECURITY_ATTR_RESULT_ENABLED); return; } @@ -94,26 +88,58 @@ fu_plugin_add_security_attr_ble (FuPlugin *plugin, FuSecurityAttrs *attrs) } static void -fu_plugin_add_security_attr_smm_bwp (FuPlugin *plugin, FuSecurityAttrs *attrs) +fu_plugin_add_security_attr_ble (FuPlugin *plugin, FuSecurityAttrs *attrs) { + FuPluginData *priv = fu_plugin_get_data (plugin); gsize bufsz = 0; g_autofree gchar *buf = NULL; g_autofree gchar *fn = NULL; g_autoptr(FwupdSecurityAttr) attr = NULL; g_autoptr(GError) error_local = NULL; - /* maybe the kernel module does not exist */ - if (!g_file_test (FU_PLUGIN_LINUX_SPI_LPC_SYSFS_DIR, G_FILE_TEST_IS_DIR)) - return; - /* create attr */ - attr = fwupd_security_attr_new (FWUPD_SECURITY_ATTR_ID_SPI_SMM_BWP); + attr = fwupd_security_attr_new (FWUPD_SECURITY_ATTR_ID_SPI_BLE); + fwupd_security_attr_set_plugin (attr, fu_plugin_get_name (plugin)); fwupd_security_attr_set_level (attr, FWUPD_SECURITY_ATTR_LEVEL_CRITICAL); fwupd_security_attr_add_obsolete (attr, "pci_bcr"); fu_security_attrs_append (attrs, attr); /* load file */ - fn = g_build_filename (FU_PLUGIN_LINUX_SPI_LPC_SYSFS_DIR, "smm_bwp", NULL); + fn = g_build_filename (priv->sysfs_path, "ble", NULL); + if (!g_file_get_contents (fn, &buf, &bufsz, &error_local)) { + g_warning ("could not open %s: %s", fn, error_local->message); + fwupd_security_attr_set_result (attr, FWUPD_SECURITY_ATTR_RESULT_NOT_VALID); + return; + } + if (g_strcmp0 (buf, "1\n") != 0) { + fwupd_security_attr_set_result (attr, FWUPD_SECURITY_ATTR_RESULT_NOT_ENABLED); + return; + } + + /* success */ + fwupd_security_attr_add_flag (attr, FWUPD_SECURITY_ATTR_FLAG_SUCCESS); + fwupd_security_attr_set_result (attr, FWUPD_SECURITY_ATTR_RESULT_ENABLED); +} + +static void +fu_plugin_add_security_attr_smm_bwp (FuPlugin *plugin, FuSecurityAttrs *attrs) +{ + FuPluginData *priv = fu_plugin_get_data (plugin); + gsize bufsz = 0; + g_autofree gchar *buf = NULL; + g_autofree gchar *fn = NULL; + g_autoptr(FwupdSecurityAttr) attr = NULL; + g_autoptr(GError) error_local = NULL; + + /* create attr */ + attr = fwupd_security_attr_new (FWUPD_SECURITY_ATTR_ID_SPI_SMM_BWP); + fwupd_security_attr_set_plugin (attr, fu_plugin_get_name (plugin)); + fwupd_security_attr_set_level (attr, FWUPD_SECURITY_ATTR_LEVEL_CRITICAL); + fwupd_security_attr_add_obsolete (attr, "pci_bcr"); + fu_security_attrs_append (attrs, attr); + + /* load file */ + fn = g_build_filename (priv->sysfs_path, "smm_bwp", NULL); if (!g_file_get_contents (fn, &buf, &bufsz, &error_local)) { g_warning ("could not open %s: %s", fn, error_local->message); fwupd_security_attr_set_result (attr, FWUPD_SECURITY_ATTR_RESULT_NOT_VALID); @@ -132,8 +158,10 @@ fu_plugin_add_security_attr_smm_bwp (FuPlugin *plugin, FuSecurityAttrs *attrs) void fu_plugin_add_security_attrs (FuPlugin *plugin, FuSecurityAttrs *attrs) { - /* only Intel */ - if (!fu_common_is_cpu_intel ()) + FuPluginData *priv = fu_plugin_get_data (plugin); + + /* only when the kernel module is available */ + if (priv->sysfs_path == NULL) return; /* look for the three files in sysfs */ diff --git a/plugins/platform-integrity/fwupd-platform-integrity.conf b/plugins/platform-integrity/fwupd-platform-integrity.conf new file mode 100644 index 000000000..2fd69d6ea --- /dev/null +++ b/plugins/platform-integrity/fwupd-platform-integrity.conf @@ -0,0 +1 @@ +platform-integrity diff --git a/plugins/platform-integrity/meson.build b/plugins/platform-integrity/meson.build new file mode 100644 index 000000000..6f1c4bc51 --- /dev/null +++ b/plugins/platform-integrity/meson.build @@ -0,0 +1,33 @@ +cargs = ['-DG_LOG_DOMAIN="FuPluginPlatformIntegrity"'] + +install_data([ + 'platform-integrity.quirk', + ], + install_dir: join_paths(datadir, 'fwupd', 'quirks.d') +) + +install_data(['fwupd-platform-integrity.conf'], + install_dir: join_paths(sysconfdir, 'modules-load.d') +) + +shared_module('fu_plugin_platform_integrity', + fu_hash, + sources : [ + 'fu-plugin-platform-integrity.c', + ], + include_directories : [ + root_incdir, + fwupd_incdir, + fwupdplugin_incdir, + ], + install : true, + install_dir: plugin_dir, + link_with : [ + fwupd, + fwupdplugin, + ], + c_args : cargs, + dependencies : [ + plugin_deps, + ], +) diff --git a/plugins/platform-integrity/platform-integrity.quirk b/plugins/platform-integrity/platform-integrity.quirk new file mode 100644 index 000000000..c24cf0c0e --- /dev/null +++ b/plugins/platform-integrity/platform-integrity.quirk @@ -0,0 +1,3 @@ +# match all devices with this udev subsystem +[DeviceInstanceId=PLATFORM-INTEGRITY] +Plugin = platform_integrity From a06a4809042acae2d7bfbd981fef9436432bcd05 Mon Sep 17 00:00:00 2001 From: Richard Hughes Date: Tue, 8 Sep 2020 10:32:22 +0100 Subject: [PATCH 415/607] trivial: Allow using fu_udev_device_pread_full() at offset zero Do not enforce the port is nonzero when reading and writing to a device. --- libfwupdplugin/fu-udev-device.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/libfwupdplugin/fu-udev-device.c b/libfwupdplugin/fu-udev-device.c index 255783302..39fdb5d7a 100644 --- a/libfwupdplugin/fu-udev-device.c +++ b/libfwupdplugin/fu-udev-device.c @@ -1010,7 +1010,6 @@ fu_udev_device_pread_full (FuUdevDevice *self, goffset port, FuUdevDevicePrivate *priv = GET_PRIVATE (self); g_return_val_if_fail (FU_IS_UDEV_DEVICE (self), FALSE); - g_return_val_if_fail (port != 0x0, FALSE); g_return_val_if_fail (buf != NULL, FALSE); g_return_val_if_fail (priv->fd > 0, FALSE); @@ -1056,7 +1055,6 @@ fu_udev_device_pwrite_full (FuUdevDevice *self, goffset port, FuUdevDevicePrivate *priv = GET_PRIVATE (self); g_return_val_if_fail (FU_IS_UDEV_DEVICE (self), FALSE); - g_return_val_if_fail (port != 0x0, FALSE); g_return_val_if_fail (priv->fd > 0, FALSE); #ifdef HAVE_PWRITE From 1d633a58fe3f32accffd3cded2083584e33020b0 Mon Sep 17 00:00:00 2001 From: Richard Hughes Date: Tue, 8 Sep 2020 10:48:56 +0100 Subject: [PATCH 416/607] trivial: Show the device GType when deduping This allows us to make sense of the case where the same plugin has multiple possible GTypes. --- src/fu-device-list.c | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) diff --git a/src/fu-device-list.c b/src/fu-device-list.c index de25ed3be..30b038e7b 100644 --- a/src/fu-device-list.c +++ b/src/fu-device-list.c @@ -735,26 +735,32 @@ fu_device_list_add (FuDeviceList *self, FuDevice *device) fu_device_get_protocol (device)) == 0) { if (!fu_device_has_flag (device, FWUPD_DEVICE_FLAG_NO_GUID_MATCHING)) { if (fu_device_get_priority (device) < fu_device_get_priority (item->device)) { - g_debug ("ignoring device %s [%s] as better device %s [%s] already exists", + g_debug ("ignoring device %s [%s:%s] as better device %s [%s:%s] already exists", fu_device_get_id (device), fu_device_get_plugin (device), + g_type_name (fu_device_get_specialized_gtype (device)), fu_device_get_id (item->device), - fu_device_get_plugin (item->device)); + fu_device_get_plugin (item->device), + g_type_name (fu_device_get_specialized_gtype (item->device))); return; } if (fu_device_get_priority (device) == fu_device_get_priority (item->device)) { - g_warning ("ignoring device %s [%s] existing device %s [%s] already exists", + g_warning ("ignoring device %s [%s:%s] existing device %s [%s:%s] already exists", fu_device_get_id (device), fu_device_get_plugin (device), + g_type_name (fu_device_get_specialized_gtype (device)), fu_device_get_id (item->device), - fu_device_get_plugin (item->device)); + fu_device_get_plugin (item->device), + g_type_name (fu_device_get_specialized_gtype (item->device))); return; } - g_debug ("removing device %s [%s] as better device %s [%s] added", + g_debug ("removing device %s [%s:%s] as better device %s [%s:%s] added", fu_device_get_id (item->device), fu_device_get_plugin (item->device), + g_type_name (fu_device_get_specialized_gtype (item->device)), fu_device_get_id (device), - fu_device_get_plugin (device)); + fu_device_get_plugin (device), + g_type_name (fu_device_get_specialized_gtype (device))); fu_device_list_remove (self, item->device); } else { g_debug ("not adding matching %s for device add, use " From ad32b0c17e177153d55c9aa28e4c678d2f3871f5 Mon Sep 17 00:00:00 2001 From: Richard Hughes Date: Mon, 7 Sep 2020 21:03:08 +0100 Subject: [PATCH 417/607] elaptp: Allow recovery when the HID firmware fails to load --- libfwupdplugin/fu-udev-device.c | 23 ++ plugins/elantp/README.md | 2 +- plugins/elantp/elantp.quirk | 6 + plugins/elantp/fu-elantp-common.h | 8 + plugins/elantp/fu-elantp-hid-device.c | 7 +- plugins/elantp/fu-elantp-i2c-device.c | 573 ++++++++++++++++++++++++++ plugins/elantp/fu-elantp-i2c-device.h | 12 + plugins/elantp/fu-plugin-elantp.c | 3 + plugins/elantp/meson.build | 1 + 9 files changed, 628 insertions(+), 7 deletions(-) create mode 100644 plugins/elantp/fu-elantp-i2c-device.c create mode 100644 plugins/elantp/fu-elantp-i2c-device.h diff --git a/libfwupdplugin/fu-udev-device.c b/libfwupdplugin/fu-udev-device.c index 39fdb5d7a..e8f6a4587 100644 --- a/libfwupdplugin/fu-udev-device.c +++ b/libfwupdplugin/fu-udev-device.c @@ -211,6 +211,23 @@ fu_udev_device_get_vendor_fallback (GUdevDevice *udev_device) return NULL; } +#ifdef HAVE_GUDEV +static gboolean +fu_udev_device_probe_i2c_dev (FuUdevDevice *self, GError **error) +{ + FuUdevDevicePrivate *priv = GET_PRIVATE (self); + const gchar *name = g_udev_device_get_sysfs_attr (priv->udev_device, "name"); + if (name != NULL) { + g_autofree gchar *devid = NULL; + g_autofree gchar *name_safe = g_strdup (name); + g_strdelimit (name_safe, " /\\\"", '-'); + devid = g_strdup_printf ("I2C\\NAME_%s", name_safe); + fu_device_add_instance_id (FU_DEVICE (self), devid); + } + return TRUE; +} +#endif + static gboolean fu_udev_device_probe (FuDevice *device, GError **error) { @@ -401,6 +418,12 @@ fu_udev_device_probe (FuDevice *device, GError **error) FU_DEVICE_INSTANCE_FLAG_ONLY_QUIRKS); } + /* i2c devices all expose a name */ + if (g_strcmp0 (g_udev_device_get_subsystem (priv->udev_device), "i2c-dev") == 0) { + if (!fu_udev_device_probe_i2c_dev (self, error)) + return FALSE; + } + /* determine if we're wired internally */ parent_i2c = g_udev_device_get_parent_with_subsystem (priv->udev_device, "i2c", NULL); diff --git a/plugins/elantp/README.md b/plugins/elantp/README.md index cd1bbc37d..3f867e89e 100644 --- a/plugins/elantp/README.md +++ b/plugins/elantp/README.md @@ -5,7 +5,7 @@ Introduction ------------ This plugin allows updating Touchpad devices from Elan. Devices are enumerated -using HID. +using HID and raw I²C nodes. The I²C mode is used for firmware recovery. Firmware Format --------------- diff --git a/plugins/elantp/elantp.quirk b/plugins/elantp/elantp.quirk index 4760d6489..7d9c07802 100644 --- a/plugins/elantp/elantp.quirk +++ b/plugins/elantp/elantp.quirk @@ -6,6 +6,12 @@ GType = FuElantpHidDevice Plugin = elantp GType = FuElantpHidDevice +# recovery device +[DeviceInstanceId=I2C\NAME_Synopsys-DesignWare-I2C-adapter] +Plugin = elantp +GType = FuElantpI2cDevice +ElantpI2cTargetAddress = 0x15 + [DeviceInstanceId=ELANTP\ICTYPE_00] ElantpIcPageCount = 0x200 ElantpIapPassword = 0x1EA5 diff --git a/plugins/elantp/fu-elantp-common.h b/plugins/elantp/fu-elantp-common.h index a607be532..05d7ed818 100644 --- a/plugins/elantp/fu-elantp-common.h +++ b/plugins/elantp/fu-elantp-common.h @@ -8,6 +8,7 @@ #include +#define ETP_CMD_GET_HID_DESCRIPTOR 0x0001 #define ETP_CMD_GET_HARDWARE_ID 0x0100 #define ETP_CMD_GET_MODULE_ID 0x0101 #define ETP_CMD_I2C_FW_CHECKSUM 0x030F @@ -38,5 +39,12 @@ #define ETP_FW_IAP_CHECK_PW (1 << 7) #define ETP_FW_IAP_LAST_FIT (1 << 9) + +#define ELANTP_DELAY_COMPLETE 1200 /* ms */ +#define ELANTP_DELAY_RESET 30 /* ms */ +#define ELANTP_DELAY_UNLOCK 100 /* ms */ +#define ELANTP_DELAY_WRITE_BLOCK 35 /* ms */ +#define ELANTP_DELAY_WRITE_BLOCK_512 50 /* ms */ + guint16 fu_elantp_calc_checksum (const guint8 *data, gsize length); diff --git a/plugins/elantp/fu-elantp-hid-device.c b/plugins/elantp/fu-elantp-hid-device.c index 62fc7b64c..5e0f52646 100644 --- a/plugins/elantp/fu-elantp-hid-device.c +++ b/plugins/elantp/fu-elantp-hid-device.c @@ -26,12 +26,6 @@ struct _FuElantpHidDevice { guint8 pattern; }; -#define ELANTP_DELAY_COMPLETE 1200 /* ms */ -#define ELANTP_DELAY_RESET 30 /* ms */ -#define ELANTP_DELAY_UNLOCK 100 /* ms */ -#define ELANTP_DELAY_WRITE_BLOCK 35 /* ms */ -#define ELANTP_DELAY_WRITE_BLOCK_512 50 /* ms */ - G_DEFINE_TYPE (FuElantpHidDevice, fu_elantp_hid_device, FU_TYPE_UDEV_DEVICE) static void @@ -498,6 +492,7 @@ fu_elantp_hid_device_init (FuElantpHidDevice *self) fu_device_add_icon (FU_DEVICE (self), "input-touchpad"); fu_device_set_protocol (FU_DEVICE (self), "tw.com.emc.elantp"); fu_device_set_version_format (FU_DEVICE (self), FWUPD_VERSION_FORMAT_HEX); + fu_device_set_priority (FU_DEVICE (self), 1); /* better than i2c */ fu_udev_device_set_flags (FU_UDEV_DEVICE (self), FU_UDEV_DEVICE_FLAG_OPEN_READ | FU_UDEV_DEVICE_FLAG_OPEN_WRITE | diff --git a/plugins/elantp/fu-elantp-i2c-device.c b/plugins/elantp/fu-elantp-i2c-device.c new file mode 100644 index 000000000..1e9cc2ddb --- /dev/null +++ b/plugins/elantp/fu-elantp-i2c-device.c @@ -0,0 +1,573 @@ +/* + * Copyright (C) 2020 Richard Hughes + * + * SPDX-License-Identifier: LGPL-2.1+ + */ + +#include + +#include "config.h" + +#include "fu-elantp-common.h" +#include "fu-elantp-firmware.h" +#include "fu-elantp-i2c-device.h" +#include "fu-chunk.h" + +struct _FuElantpI2cDevice { + FuUdevDevice parent_instance; + guint16 i2c_addr; + guint16 ic_page_count; + guint16 iap_type; + guint16 iap_ctrl; + guint16 iap_password; + guint16 module_id; + guint16 fw_page_size; + guint8 pattern; +}; + +G_DEFINE_TYPE (FuElantpI2cDevice, fu_elantp_i2c_device, FU_TYPE_UDEV_DEVICE) + +static void +fu_elantp_i2c_device_to_string (FuDevice *device, guint idt, GString *str) +{ + FuElantpI2cDevice *self = FU_ELANTP_I2C_DEVICE (device); + fu_common_string_append_kx (str, idt, "I2cAddr", self->i2c_addr); + fu_common_string_append_kx (str, idt, "ModuleId", self->module_id); + fu_common_string_append_kx (str, idt, "Pattern", self->pattern); + fu_common_string_append_kx (str, idt, "FwPageSize", self->fw_page_size); + fu_common_string_append_kx (str, idt, "IcPageCount", self->ic_page_count); + fu_common_string_append_kx (str, idt, "IapType", self->iap_type); + fu_common_string_append_kx (str, idt, "IapCtrl", self->iap_ctrl); +} + +static gboolean +fu_elantp_i2c_device_probe (FuUdevDevice *device, GError **error) +{ + /* check is valid */ + if (g_strcmp0 (fu_udev_device_get_subsystem (device), "i2c-dev") != 0) { + g_set_error (error, + FWUPD_ERROR, + FWUPD_ERROR_NOT_SUPPORTED, + "is not correct subsystem=%s, expected i2c-dev", + fu_udev_device_get_subsystem (device)); + return FALSE; + } + if (fu_udev_device_get_device_file (device) == NULL) { + g_set_error_literal (error, + FWUPD_ERROR, + FWUPD_ERROR_NOT_SUPPORTED, + "no device file"); + return FALSE; + } + + /* set the physical ID */ + return fu_udev_device_set_physical_id (device, "i2c", error); +} + +static gboolean +fu_elantp_i2c_device_send_cmd (FuElantpI2cDevice *self, + guint8 *tx, gssize txsz, + guint8 *rx, gssize rxsz, + GError **error) +{ + if (g_getenv ("FWUPD_ELANTP_VERBOSE") != NULL) + fu_common_dump_raw (G_LOG_DOMAIN, "Write", tx, txsz); + if (!fu_udev_device_pwrite_full (FU_UDEV_DEVICE (self), 0, tx, txsz, error)) + return FALSE; + if (rxsz == 0) + return TRUE; + if (!fu_udev_device_pread_full (FU_UDEV_DEVICE (self), 0, rx, rxsz, error)) + return FALSE; + if (g_getenv ("FWUPD_ELANTP_VERBOSE") != NULL) + fu_common_dump_raw (G_LOG_DOMAIN, "Read", rx, rxsz); + return TRUE; +} + +static gboolean +fu_elantp_i2c_device_write_cmd (FuElantpI2cDevice *self, guint16 reg, guint16 cmd, GError **error) +{ + guint8 buf[4]; + fu_common_write_uint16 (buf + 0x0, reg, G_LITTLE_ENDIAN); + fu_common_write_uint16 (buf + 0x2, cmd, G_LITTLE_ENDIAN); + return fu_elantp_i2c_device_send_cmd (self, buf, sizeof(buf), NULL, 0, error); +} + +static gboolean +fu_elantp_i2c_device_read_cmd (FuElantpI2cDevice *self, guint16 reg, + guint8 *rx, gsize rxsz, GError **error) +{ + guint8 buf[2]; + fu_common_write_uint16 (buf + 0x0, reg, G_LITTLE_ENDIAN); + return fu_elantp_i2c_device_send_cmd (self, buf, sizeof(buf), + rx, rxsz, error); +} + +static gboolean +fu_elantp_i2c_device_ensure_iap_ctrl (FuElantpI2cDevice *self, GError **error) +{ + guint8 buf[2] = { 0x0 }; + if (!fu_elantp_i2c_device_read_cmd (self, ETP_CMD_I2C_IAP_CTRL, buf, sizeof(buf), error)) { + g_prefix_error (error, "failed to read IAPControl: "); + return FALSE; + } + self->iap_ctrl = fu_common_read_uint16 (buf, G_LITTLE_ENDIAN); + + /* in bootloader mode? */ + if ((self->iap_ctrl & ETP_I2C_MAIN_MODE_ON) == 0) + fu_device_add_flag (FU_DEVICE (self), FWUPD_DEVICE_FLAG_IS_BOOTLOADER); + else + fu_device_remove_flag (FU_DEVICE (self), FWUPD_DEVICE_FLAG_IS_BOOTLOADER); + + return TRUE; +} + +static gboolean +fu_elantp_i2c_device_setup (FuDevice *device, GError **error) +{ + FuElantpI2cDevice *self = FU_ELANTP_I2C_DEVICE (device); + guint16 fwver; + guint16 iap_ver; + guint16 tmp; + guint32 pid; + guint32 vid; + guint8 buf[30] = { 0x0 }; + guint8 ic_type; + g_autofree gchar *instance_id1 = NULL; + g_autofree gchar *instance_id_ic_type = NULL; + g_autofree gchar *version_bl = NULL; + g_autofree gchar *version = NULL; + + /* read the I2C descriptor */ + if (!fu_elantp_i2c_device_read_cmd (self, ETP_CMD_GET_HID_DESCRIPTOR, + buf, sizeof(buf), error)) { + g_prefix_error (error, "failed to get HID descriptor: "); + return FALSE; + } + vid = fu_common_read_uint16 (buf + 20, G_LITTLE_ENDIAN); + pid = fu_common_read_uint16 (buf + 22, G_LITTLE_ENDIAN); + + /* set the vendor ID */ + if (vid != 0x0000) { + g_autofree gchar *vendor_id = NULL; + vendor_id = g_strdup_printf ("HIDRAW:0x%04X", vid); + fu_device_set_vendor_id (device, vendor_id); + } + + /* add GUIDs in order of priority */ + if (vid != 0x0 && pid != 0x0) { + g_autofree gchar *devid = NULL; + devid = g_strdup_printf ("HIDRAW\\VID_%04X&PID_%04X", + vid, pid); + fu_device_add_instance_id (device, devid); + } + + /* get pattern */ + if (!fu_elantp_i2c_device_read_cmd (self, + ETP_CMD_I2C_GET_HID_ID, + buf, sizeof(buf), error)) { + g_prefix_error (error, "failed to read I2C ID: "); + return FALSE; + } + tmp = fu_common_read_uint16 (buf, G_LITTLE_ENDIAN); + self->pattern = tmp != 0xffff ? (tmp & 0xff00) >> 8 : 0; + + /* get current firmware version */ + if (!fu_elantp_i2c_device_read_cmd (self, + ETP_CMD_I2C_FW_VERSION, + buf, sizeof(buf), error)) { + g_prefix_error (error, "failed to read fw version: "); + return FALSE; + } + fwver = fu_common_read_uint16 (buf, G_LITTLE_ENDIAN); + version = fu_common_version_from_uint16 (fwver, FWUPD_VERSION_FORMAT_HEX); + fu_device_set_version (device, version); + + /* get IAP firmware version */ + if (!fu_elantp_i2c_device_read_cmd (self, + self->pattern == 0 ? ETP_CMD_I2C_IAP_VERSION : ETP_CMD_I2C_IAP_VERSION_2, + buf, sizeof(buf), error)) { + g_prefix_error (error, "failed to read bootloader version: "); + return FALSE; + } + if (self->pattern >= 1) { + iap_ver = buf[1]; + } else { + iap_ver = fu_common_read_uint16 (buf, G_LITTLE_ENDIAN); + } + version_bl = fu_common_version_from_uint16 (iap_ver, FWUPD_VERSION_FORMAT_HEX); + fu_device_set_version_bootloader (device, version_bl); + + /* get module ID */ + if (!fu_elantp_i2c_device_read_cmd (self, + ETP_CMD_GET_MODULE_ID, + buf, sizeof(buf), error)) { + g_prefix_error (error, "failed to read module ID: "); + return FALSE; + } + self->module_id = fu_common_read_uint16 (buf, G_LITTLE_ENDIAN); + + /* define the extra instance IDs */ + instance_id1 = g_strdup_printf ("HIDRAW\\VEN_%04X&DEV_%04X&MOD_%04X", + vid, pid, self->module_id); + fu_device_add_instance_id (device, instance_id1); + + /* get OSM version */ + if (!fu_elantp_i2c_device_read_cmd (self, ETP_CMD_I2C_OSM_VERSION, buf, sizeof(buf), error)) { + g_prefix_error (error, "failed to read OSM version: "); + return FALSE; + } + tmp = fu_common_read_uint16 (buf, G_LITTLE_ENDIAN); + if (tmp == ETP_CMD_I2C_OSM_VERSION || tmp == 0xFFFF) { + if (!fu_elantp_i2c_device_read_cmd (self, ETP_CMD_I2C_IAP_ICBODY, buf, sizeof(buf), error)) { + g_prefix_error (error, "failed to read IC body: "); + return FALSE; + } + ic_type = fu_common_read_uint16 (buf, G_LITTLE_ENDIAN) & 0xFF; + } else { + ic_type = (tmp >> 8) & 0xFF; + } + instance_id_ic_type = g_strdup_printf ("ELANTP\\ICTYPE_%02X", ic_type); + fu_device_add_instance_id (device, instance_id_ic_type); + + /* set the page size */ + self->fw_page_size = 64; + if (ic_type >= 0x10) { + if (iap_ver >= 1) { + /* set the IAP type, presumably some kind of ABI */ + if (!fu_elantp_i2c_device_write_cmd (self, + ETP_CMD_I2C_IAP_TYPE, + ETP_I2C_IAP_TYPE_REG, + error)) + return FALSE; + if (!fu_elantp_i2c_device_read_cmd (self, ETP_CMD_I2C_IAP_TYPE, + buf, sizeof(buf), error)) { + g_prefix_error (error, "failed to read IAP type: "); + return FALSE; + } + self->iap_type = fu_common_read_uint16 (buf, G_LITTLE_ENDIAN); + if (self->iap_type != ETP_I2C_IAP_TYPE_REG) { + g_set_error_literal (error, + FWUPD_ERROR, + FWUPD_ERROR_NOT_SUPPORTED, + "failed to set IAP type"); + return FALSE; + } + if (iap_ver >= 2 && (ic_type == 0x14 || ic_type==0x15)) { + self->fw_page_size = 512; + } else { + self->fw_page_size = 128; + } + } + } + + /* no quirk entry */ + if (self->ic_page_count == 0x0) { + g_set_error (error, + FWUPD_ERROR, + FWUPD_ERROR_NOT_SUPPORTED, + "no page count for ELANTP\\ICTYPE_%02X", + ic_type); + return FALSE; + } + fu_device_set_firmware_size (device, (guint64) self->ic_page_count * (guint64) self->fw_page_size); + + /* is in bootloader mode */ + if (!fu_elantp_i2c_device_ensure_iap_ctrl (self, error)) + return FALSE; + + /* success */ + return TRUE; +} + +static gboolean +fu_elantp_i2c_device_open (FuUdevDevice *device, GError **error) +{ + FuElantpI2cDevice *self = FU_ELANTP_I2C_DEVICE (device); + gint addr = self->i2c_addr; + guint8 tx_buf[] = { 0x02, 0x01 }; + + /* set target address */ + if (!fu_udev_device_ioctl (device, I2C_SLAVE, + GINT_TO_POINTER (addr), NULL, NULL)) { + if (!fu_udev_device_ioctl (device, I2C_SLAVE_FORCE, + GINT_TO_POINTER (addr), NULL, error)) { + g_prefix_error (error, + "failed to set target address to 0x%x: ", + self->i2c_addr); + return FALSE; + } + } + + /* read i2c device */ + return fu_udev_device_pwrite_full (device, 0x0, tx_buf, sizeof(tx_buf), error); +} + +static FuFirmware * +fu_elantp_i2c_device_prepare_firmware (FuDevice *device, + GBytes *fw, + FwupdInstallFlags flags, + GError **error) +{ + FuElantpI2cDevice *self = FU_ELANTP_I2C_DEVICE (device); + guint16 module_id; + g_autoptr(FuFirmware) firmware = fu_elantp_firmware_new (); + + /* check is compatible with hardware */ + if (!fu_firmware_parse (firmware, fw, flags, error)) + return NULL; + module_id = fu_elantp_firmware_get_module_id (FU_ELANTP_FIRMWARE (firmware)); + if (self->module_id != module_id) { + g_set_error (error, + FWUPD_ERROR, + FWUPD_ERROR_INVALID_FILE, + "firmware incompatible, got 0x%04x, expected 0x%04x", + module_id, self->module_id); + return NULL; + } + + /* success */ + return g_steal_pointer (&firmware); +} + +static gboolean +fu_elantp_i2c_device_write_firmware (FuDevice *device, + FuFirmware *firmware, + FwupdInstallFlags flags, + GError **error) +{ + FuElantpI2cDevice *self = FU_ELANTP_I2C_DEVICE (device); + FuElantpFirmware *firmware_elantp = FU_ELANTP_FIRMWARE (firmware); + gsize bufsz = 0; + guint16 checksum = 0; + guint16 checksum_device = 0; + guint16 iap_addr; + const guint8 *buf; + guint8 csum_buf[2] = { 0x0 }; + g_autoptr(GBytes) fw = NULL; + g_autoptr(GPtrArray) chunks = NULL; + + /* simple image */ + fw = fu_firmware_get_image_default_bytes (firmware, error); + if (fw == NULL) + return FALSE; + + /* write each block */ + fu_device_set_status (device, FWUPD_STATUS_DEVICE_WRITE); + buf = g_bytes_get_data (fw, &bufsz); + iap_addr = fu_elantp_firmware_get_iap_addr (firmware_elantp); + chunks = fu_chunk_array_new (buf + iap_addr, bufsz - iap_addr, 0x0, 0x0, self->fw_page_size); + for (guint i = 0; i < chunks->len; i++) { + FuChunk *chk = g_ptr_array_index (chunks, i); + guint16 csum_tmp = fu_elantp_calc_checksum (chk->data, chk->data_sz); + gsize blksz = self->fw_page_size + 3; + g_autofree guint8 *blk = g_malloc0 (blksz); + + /* write block */ + blk[0] = 0x0B; /* report ID */ + memcpy (blk + 1, chk->data, chk->data_sz); + fu_common_write_uint16 (blk + chk->data_sz + 1, csum_tmp, G_LITTLE_ENDIAN); + + if (!fu_elantp_i2c_device_send_cmd (self, blk, blksz, NULL, 0, error)) + return FALSE; + g_usleep (self->fw_page_size == 512 ? + ELANTP_DELAY_WRITE_BLOCK_512 * 1000 : + ELANTP_DELAY_WRITE_BLOCK * 1000); + + if (!fu_elantp_i2c_device_ensure_iap_ctrl (self, error)) + return FALSE; + if (self->iap_ctrl & (ETP_FW_IAP_PAGE_ERR | ETP_FW_IAP_INTF_ERR)) { + g_set_error (error, + FWUPD_ERROR, + FWUPD_ERROR_WRITE, + "bootloader reports failed write: 0x%x", + self->iap_ctrl); + return FALSE; + } + + /* update progress */ + checksum += csum_tmp; + fu_device_set_progress_full (device, (gsize) i, (gsize) chunks->len); + } + + /* verify the written checksum */ + fu_device_set_status (device, FWUPD_STATUS_DEVICE_VERIFY); + if (!fu_elantp_i2c_device_read_cmd (self, ETP_CMD_I2C_IAP_CHECKSUM, + csum_buf, sizeof(csum_buf), error)) + return FALSE; + checksum_device = fu_common_read_uint16 (csum_buf, G_LITTLE_ENDIAN); + if (checksum != checksum_device) { + g_set_error (error, + FWUPD_ERROR, + FWUPD_ERROR_WRITE, + "checksum failed 0x%04x != 0x%04x", + checksum, checksum_device); + return FALSE; + } + + /* wait for a reset */ + fu_device_set_progress (device, 0); + fu_device_set_status (device, FWUPD_STATUS_DEVICE_RESTART); + g_usleep (ELANTP_DELAY_COMPLETE * 1000); + return TRUE; +} + +static gboolean +fu_elantp_i2c_device_detach (FuDevice *device, GError **error) +{ + FuElantpI2cDevice *self = FU_ELANTP_I2C_DEVICE (device); + + /* sanity check */ + if (fu_device_has_flag (device, FWUPD_DEVICE_FLAG_IS_BOOTLOADER)) { + g_debug ("already in bootloader mode, skipping"); + return TRUE; + } + + g_debug ("in bootloader mode, reset IC"); + fu_device_set_status (device, FWUPD_STATUS_DEVICE_RESTART); + if (!fu_elantp_i2c_device_write_cmd (self, + ETP_CMD_I2C_IAP_RESET, + ETP_I2C_IAP_RESET, + error)) + return FALSE; + g_usleep (ELANTP_DELAY_RESET * 1000); + if (!fu_elantp_i2c_device_write_cmd (self, + ETP_CMD_I2C_IAP, + self->iap_password, + error)) + return FALSE; + g_usleep (ELANTP_DELAY_UNLOCK * 1000); + if (!fu_elantp_i2c_device_ensure_iap_ctrl (self, error)) + return FALSE; + if ((self->iap_ctrl & ETP_FW_IAP_CHECK_PW) == 0) { + g_set_error_literal (error, + FWUPD_ERROR, + FWUPD_ERROR_WRITE, + "unexpected bootloader password"); + return FALSE; + } + + /* success */ + return TRUE; +} + +static gboolean +fu_elantp_i2c_device_attach (FuDevice *device, GError **error) +{ + FuElantpI2cDevice *self = FU_ELANTP_I2C_DEVICE (device); + + /* sanity check */ + if (!fu_device_has_flag (device, FWUPD_DEVICE_FLAG_IS_BOOTLOADER)) { + g_debug ("already in runtime mode, skipping"); + return TRUE; + } + + /* reset back to runtime */ + fu_device_set_status (device, FWUPD_STATUS_DEVICE_RESTART); + if (!fu_elantp_i2c_device_write_cmd (self, ETP_CMD_I2C_IAP_RESET, ETP_I2C_IAP_RESET, error)) + return FALSE; + g_usleep (ELANTP_DELAY_RESET * 1000); + if (!fu_elantp_i2c_device_write_cmd (self, ETP_CMD_I2C_IAP_RESET, ETP_I2C_ENABLE_REPORT, error)) { + g_prefix_error (error, "cannot enable TP report: "); + return FALSE; + } + if (!fu_elantp_i2c_device_write_cmd (self, 0x0306, 0x003, error)) { + g_prefix_error (error, "cannot switch to TP PTP mode: "); + return FALSE; + } + if (!fu_elantp_i2c_device_ensure_iap_ctrl (self, error)) + return FALSE; + + /* success */ + return TRUE; +} + +static gboolean +fu_elantp_i2c_device_set_quirk_kv (FuDevice *device, + const gchar *key, + const gchar *value, + GError **error) +{ + FuElantpI2cDevice *self = FU_ELANTP_I2C_DEVICE (device); + if (g_strcmp0 (key, "ElantpIcPageCount") == 0) { + guint64 tmp = fu_common_strtoull (value); + if (tmp > 0xffff) { + g_set_error_literal (error, + G_IO_ERROR, + G_IO_ERROR_NOT_SUPPORTED, + "ElantpIcPageCount only supports " + "values <= 0xffff"); + return FALSE; + } + self->ic_page_count = (guint16) tmp; + return TRUE; + } + if (g_strcmp0 (key, "ElantpIapPassword") == 0) { + guint64 tmp = fu_common_strtoull (value); + if (tmp > 0xffff) { + g_set_error_literal (error, + G_IO_ERROR, + G_IO_ERROR_NOT_SUPPORTED, + "ElantpIapPassword only supports " + "values <= 0xffff"); + return FALSE; + } + self->iap_password = (guint16) tmp; + return TRUE; + } + if (g_strcmp0 (key, "ElantpI2cTargetAddress") == 0) { + guint64 tmp = fu_common_strtoull (value); + if (tmp > 0xffff) { + g_set_error_literal (error, + G_IO_ERROR, + G_IO_ERROR_NOT_SUPPORTED, + "ElantpI2cTargetAddress only supports " + "values <= 0xffff"); + return FALSE; + } + self->i2c_addr = (guint16) tmp; + return TRUE; + } + g_set_error_literal (error, + G_IO_ERROR, + G_IO_ERROR_NOT_SUPPORTED, + "quirk key not supported"); + return FALSE; +} + +static void +fu_elantp_i2c_device_init (FuElantpI2cDevice *self) +{ + fu_device_add_flag (FU_DEVICE (self), FWUPD_DEVICE_FLAG_INTERNAL); + fu_device_add_flag (FU_DEVICE (self), FWUPD_DEVICE_FLAG_UPDATABLE); + fu_device_set_summary (FU_DEVICE (self), "Elan Touchpad (I²C Recovery)"); + fu_device_add_icon (FU_DEVICE (self), "input-touchpad"); + fu_device_set_protocol (FU_DEVICE (self), "tw.com.emc.elantp"); + fu_device_set_version_format (FU_DEVICE (self), FWUPD_VERSION_FORMAT_HEX); + fu_udev_device_set_flags (FU_UDEV_DEVICE (self), + FU_UDEV_DEVICE_FLAG_OPEN_READ | + FU_UDEV_DEVICE_FLAG_OPEN_WRITE); +} + +static void +fu_elantp_i2c_device_finalize (GObject *object) +{ + G_OBJECT_CLASS (fu_elantp_i2c_device_parent_class)->finalize (object); +} + +static void +fu_elantp_i2c_device_class_init (FuElantpI2cDeviceClass *klass) +{ + GObjectClass *object_class = G_OBJECT_CLASS (klass); + FuDeviceClass *klass_device = FU_DEVICE_CLASS (klass); + FuUdevDeviceClass *klass_udev_device = FU_UDEV_DEVICE_CLASS (klass); + object_class->finalize = fu_elantp_i2c_device_finalize; + klass_device->to_string = fu_elantp_i2c_device_to_string; + klass_device->attach = fu_elantp_i2c_device_attach; + klass_device->detach = fu_elantp_i2c_device_detach; + klass_device->set_quirk_kv = fu_elantp_i2c_device_set_quirk_kv; + klass_device->setup = fu_elantp_i2c_device_setup; + klass_device->write_firmware = fu_elantp_i2c_device_write_firmware; + klass_device->prepare_firmware = fu_elantp_i2c_device_prepare_firmware; + klass_udev_device->probe = fu_elantp_i2c_device_probe; + klass_udev_device->open = fu_elantp_i2c_device_open; +} diff --git a/plugins/elantp/fu-elantp-i2c-device.h b/plugins/elantp/fu-elantp-i2c-device.h new file mode 100644 index 000000000..0d2147a94 --- /dev/null +++ b/plugins/elantp/fu-elantp-i2c-device.h @@ -0,0 +1,12 @@ +/* + * Copyright (C) 2020 Richard Hughes + * + * SPDX-License-Identifier: LGPL-2.1+ + */ + +#pragma once + +#include "fu-plugin.h" + +#define FU_TYPE_ELANTP_I2C_DEVICE (fu_elantp_i2c_device_get_type ()) +G_DECLARE_FINAL_TYPE (FuElantpI2cDevice, fu_elantp_i2c_device, FU, ELANTP_I2C_DEVICE, FuUdevDevice) diff --git a/plugins/elantp/fu-plugin-elantp.c b/plugins/elantp/fu-plugin-elantp.c index 5bd05ed37..bc1c97d8e 100644 --- a/plugins/elantp/fu-plugin-elantp.c +++ b/plugins/elantp/fu-plugin-elantp.c @@ -11,12 +11,15 @@ #include "fu-elantp-firmware.h" #include "fu-elantp-hid-device.h" +#include "fu-elantp-i2c-device.h" void fu_plugin_init (FuPlugin *plugin) { fu_plugin_set_build_hash (plugin, FU_BUILD_HASH); + fu_plugin_add_udev_subsystem (plugin, "i2c-dev"); fu_plugin_add_udev_subsystem (plugin, "hidraw"); fu_plugin_add_firmware_gtype (plugin, "elantp", FU_TYPE_ELANTP_FIRMWARE); + fu_plugin_set_device_gtype (plugin, FU_TYPE_ELANTP_I2C_DEVICE); fu_plugin_set_device_gtype (plugin, FU_TYPE_ELANTP_HID_DEVICE); } diff --git a/plugins/elantp/meson.build b/plugins/elantp/meson.build index 97527e9d9..c982ede1b 100644 --- a/plugins/elantp/meson.build +++ b/plugins/elantp/meson.build @@ -13,6 +13,7 @@ shared_module('fu_plugin_elantp', 'fu-elantp-common.c', 'fu-elantp-firmware.c', 'fu-elantp-hid-device.c', + 'fu-elantp-i2c-device.c', ], include_directories : [ root_incdir, From 32173430d44b304487ac223e698640974bb7beb3 Mon Sep 17 00:00:00 2001 From: Richard Hughes Date: Wed, 9 Sep 2020 10:22:38 +0100 Subject: [PATCH 418/607] elantp: Only match the I2C adaptor on the correct laptop model I2C doesn't have any specification for what is a probe and what is a more destructive action. Sending tx_buf out on the i2c bus to a generic address might not be safe in all cases. To prevent this, use a HWID to check the machine DMI value during device creation before ->probe() or ->setup() is called on the device. --- libfwupdplugin/fu-device-private.h | 1 - libfwupdplugin/fu-device.h | 1 + plugins/elantp/elantp.quirk | 4 ++++ plugins/elantp/fu-plugin-elantp.c | 14 ++++++++++++++ 4 files changed, 19 insertions(+), 1 deletion(-) diff --git a/libfwupdplugin/fu-device-private.h b/libfwupdplugin/fu-device-private.h index 1fc80479d..eb64c3633 100644 --- a/libfwupdplugin/fu-device-private.h +++ b/libfwupdplugin/fu-device-private.h @@ -21,7 +21,6 @@ void fu_device_set_order (FuDevice *self, gint order); void fu_device_set_alternate (FuDevice *self, FuDevice *alternate); -GType fu_device_get_specialized_gtype (FuDevice *self); gboolean fu_device_ensure_id (FuDevice *self, GError **error); void fu_device_incorporate_from_component (FuDevice *device, diff --git a/libfwupdplugin/fu-device.h b/libfwupdplugin/fu-device.h index 39cc515d7..feb8ea2f6 100644 --- a/libfwupdplugin/fu-device.h +++ b/libfwupdplugin/fu-device.h @@ -267,6 +267,7 @@ void fu_device_set_quirks (FuDevice *self, FuQuirks *quirks); FuQuirks *fu_device_get_quirks (FuDevice *self); FwupdRelease *fu_device_get_release_default (FuDevice *self); +GType fu_device_get_specialized_gtype (FuDevice *self); gboolean fu_device_write_firmware (FuDevice *self, GBytes *fw, FwupdInstallFlags flags, diff --git a/plugins/elantp/elantp.quirk b/plugins/elantp/elantp.quirk index 7d9c07802..d8504f697 100644 --- a/plugins/elantp/elantp.quirk +++ b/plugins/elantp/elantp.quirk @@ -6,6 +6,10 @@ GType = FuElantpHidDevice Plugin = elantp GType = FuElantpHidDevice +# Acer Aspire V3-372T +[HwId=513cde3d-d939-59bd-a634-5c1645ebb93b] +Flags = elantp-recovery + # recovery device [DeviceInstanceId=I2C\NAME_Synopsys-DesignWare-I2C-adapter] Plugin = elantp diff --git a/plugins/elantp/fu-plugin-elantp.c b/plugins/elantp/fu-plugin-elantp.c index bc1c97d8e..e29db3e7c 100644 --- a/plugins/elantp/fu-plugin-elantp.c +++ b/plugins/elantp/fu-plugin-elantp.c @@ -13,6 +13,20 @@ #include "fu-elantp-hid-device.h" #include "fu-elantp-i2c-device.h" +gboolean +fu_plugin_device_created (FuPlugin *plugin, FuDevice *dev, GError **error) +{ + if (fu_device_get_specialized_gtype (dev) == FU_TYPE_ELANTP_I2C_DEVICE && + !fu_plugin_has_custom_flag (plugin, "elantp-recovery")) { + g_set_error_literal (error, + FWUPD_ERROR, + FWUPD_ERROR_NOT_SUPPORTED, + "not required"); + return FALSE; + } + return TRUE; +} + void fu_plugin_init (FuPlugin *plugin) { From 02085a03719bb603fcb20b7832d14f9399110a65 Mon Sep 17 00:00:00 2001 From: Mario Limonciello Date: Fri, 11 Sep 2020 14:59:35 -0500 Subject: [PATCH 419/607] trivial: rework fwupdtool activate Only use the history database to tell if activation should be run. Instead query the connected devices to find the ones needing activation. This should allow non-connected devices to not cause a failure (although it might be a longer shutdown). Also sort the devices, so that the order follows the defined order from the daemon and they activate in the same order they install. --- src/fu-engine.c | 14 ++++++++- src/fu-engine.h | 3 ++ src/fu-tool.c | 73 +++++++++++++++++++++++++++++++------------- src/fu-util-common.c | 19 ++++++++++++ src/fu-util-common.h | 2 ++ src/fu-util.c | 2 ++ 6 files changed, 90 insertions(+), 23 deletions(-) diff --git a/src/fu-engine.c b/src/fu-engine.c index f0c543ce3..fee5f92ab 100644 --- a/src/fu-engine.c +++ b/src/fu-engine.c @@ -2398,7 +2398,19 @@ fu_engine_get_plugins (FuEngine *self) return fu_plugin_list_get_all (self->plugin_list); } -static FuDevice * +/** + * fu_engine_get_device_by_id: + * @self: A #FuEngine + * @device_id: A string + * @error: A #GError or NULL + * + * Returns the device from the engine or NULL if not found + * + * Returns: (transfer full): a #FuDevice + * + * Since: 1.5.0 + **/ +FuDevice * fu_engine_get_device_by_id (FuEngine *self, const gchar *device_id, GError **error) { g_autoptr(FuDevice) device1 = NULL; diff --git a/src/fu-engine.h b/src/fu-engine.h index 08462198b..7430cdd63 100644 --- a/src/fu-engine.h +++ b/src/fu-engine.h @@ -58,6 +58,9 @@ XbSilo *fu_engine_get_silo_from_blob (FuEngine *self, GError **error); guint64 fu_engine_get_archive_size_max (FuEngine *self); GPtrArray *fu_engine_get_plugins (FuEngine *self); +FuDevice *fu_engine_get_device_by_id (FuEngine *self, + const gchar *device_id, + GError **error); GPtrArray *fu_engine_get_devices (FuEngine *self, GError **error); FuDevice *fu_engine_get_device (FuEngine *self, diff --git a/src/fu-tool.c b/src/fu-tool.c index fb7de426c..fdb78f27e 100644 --- a/src/fu-tool.c +++ b/src/fu-tool.c @@ -1330,20 +1330,57 @@ fu_util_attach (FuUtilPrivate *priv, gchar **values, GError **error) } static gboolean -fu_util_activate (FuUtilPrivate *priv, gchar **values, GError **error) +fu_util_check_activation_needed (FuUtilPrivate *priv, GError **error) { gboolean has_pending = FALSE; g_autoptr(FuHistory) history = fu_history_new (); + g_autoptr(GPtrArray) devices = fu_history_get_devices (history, error); + if (devices == NULL) + return FALSE; + + /* only start up the plugins needed */ + for (guint i = 0; i < devices->len; i++) { + FuDevice *dev = g_ptr_array_index (devices, i); + if (fu_device_has_flag (dev, FWUPD_DEVICE_FLAG_NEEDS_ACTIVATION)) { + fu_engine_add_plugin_filter (priv->engine, + fu_device_get_plugin (dev)); + has_pending = TRUE; + } + } + + if (!has_pending) { + g_set_error_literal (error, + FWUPD_ERROR, + FWUPD_ERROR_NOTHING_TO_DO, + "No devices to activate"); + return FALSE; + } + + return TRUE; +} + +static gboolean +fu_util_activate (FuUtilPrivate *priv, gchar **values, GError **error) +{ + gboolean has_pending = FALSE; g_autoptr(GPtrArray) devices = NULL; /* check the history database before starting the daemon */ + if (!fu_util_check_activation_needed (priv, error)) + return FALSE; + + /* load engine */ + if (!fu_util_start_engine (priv, FU_ENGINE_LOAD_FLAG_READONLY_FS, error)) + return FALSE; + + /* parse arguments */ if (g_strv_length (values) == 0) { - devices = fu_history_get_devices (history, error); + devices = fu_engine_get_devices (priv->engine, error); if (devices == NULL) return FALSE; } else if (g_strv_length (values) == 1) { FuDevice *device; - device = fu_history_get_device_by_id (history, values[0], error); + device = fu_engine_get_device_by_id (priv->engine, values[0], error); if (device == NULL) return FALSE; devices = g_ptr_array_new_with_free_func ((GDestroyNotify) g_object_unref); @@ -1356,38 +1393,30 @@ fu_util_activate (FuUtilPrivate *priv, gchar **values, GError **error) return FALSE; } - /* nothing to do */ - for (guint i = 0; i < devices->len; i++) { - FuDevice *dev = g_ptr_array_index (devices, i); - if (fu_device_has_flag (dev, FWUPD_DEVICE_FLAG_NEEDS_ACTIVATION)) { - fu_engine_add_plugin_filter (priv->engine, - fu_device_get_plugin (dev)); - has_pending = TRUE; - } - } - - if (!has_pending) { - g_printerr ("No firmware to activate\n"); - return TRUE; - } - - /* load engine */ - if (!fu_util_start_engine (priv, FU_ENGINE_LOAD_FLAG_READONLY_FS, error)) - return FALSE; - /* activate anything with _NEEDS_ACTIVATION */ + /* order by device priority */ + g_ptr_array_sort (devices, fu_util_device_order_sort_cb); for (guint i = 0; i < devices->len; i++) { FuDevice *device = g_ptr_array_index (devices, i); if (!fu_util_filter_device (priv, FWUPD_DEVICE (device))) continue; if (!fu_device_has_flag (device, FWUPD_DEVICE_FLAG_NEEDS_ACTIVATION)) continue; + has_pending = TRUE; /* TRANSLATORS: shown when shutting down to switch to the new version */ g_print ("%s %s…\n", _("Activating firmware update"), fu_device_get_name (device)); if (!fu_engine_activate (priv->engine, fu_device_get_id (device), error)) return FALSE; } + if (!has_pending) { + g_set_error_literal (error, + FWUPD_ERROR, + FWUPD_ERROR_NOTHING_TO_DO, + "No devices to activate"); + return FALSE; + } + return TRUE; } diff --git a/src/fu-util-common.c b/src/fu-util-common.c index 53ac9fef0..8b84d721e 100644 --- a/src/fu-util-common.c +++ b/src/fu-util-common.c @@ -14,6 +14,7 @@ #include #include "fu-common.h" +#include "fu-device-private.h" #include "fu-util-common.h" #include "fu-device.h" #include "fu-security-attr.h" @@ -1774,3 +1775,21 @@ fu_util_sort_devices_by_flags_cb (gconstpointer a, gconstpointer b) return 0; } + +static gint +fu_util_device_order_compare (FuDevice *device1, FuDevice *device2) +{ + if (fu_device_get_order (device1) < fu_device_get_order (device2)) + return -1; + if (fu_device_get_order (device1) > fu_device_get_order (device2)) + return 1; + return 0; +} + +gint +fu_util_device_order_sort_cb (gconstpointer a, gconstpointer b) +{ + FuDevice *device_a = *((FuDevice **) a); + FuDevice *device_b = *((FuDevice **) b); + return fu_util_device_order_compare (device_a, device_b); +} diff --git a/src/fu-util-common.h b/src/fu-util-common.h index 96f282655..67ca69139 100644 --- a/src/fu-util-common.h +++ b/src/fu-util-common.h @@ -94,3 +94,5 @@ gboolean fu_util_send_report (FwupdClient *client, GError **error); gint fu_util_sort_devices_by_flags_cb (gconstpointer a, gconstpointer b); +gint fu_util_device_order_sort_cb (gconstpointer a, + gconstpointer b); diff --git a/src/fu-util.c b/src/fu-util.c index 9996df4fa..b16ef7a4e 100644 --- a/src/fu-util.c +++ b/src/fu-util.c @@ -1901,6 +1901,8 @@ fu_util_activate (FuUtilPrivate *priv, gchar **values, GError **error) } /* activate anything with _NEEDS_ACTIVATION */ + /* order by device priority */ + g_ptr_array_sort (devices, fu_util_device_order_sort_cb); for (guint i = 0; i < devices->len; i++) { FwupdDevice *device = g_ptr_array_index (devices, i); if (!fu_util_filter_device (priv, device)) From 0f057d227b704d7c2bb90fb4ddb438fcf89a42ef Mon Sep 17 00:00:00 2001 From: Mario Limonciello Date: Fri, 11 Sep 2020 15:43:51 -0500 Subject: [PATCH 420/607] thunderbolt: if calling activate always use nvm_authenticate (#2374) This will force the update to complete on logout or shutdown --- plugins/thunderbolt/fu-thunderbolt-device.c | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/plugins/thunderbolt/fu-thunderbolt-device.c b/plugins/thunderbolt/fu-thunderbolt-device.c index de106aac7..494bbef07 100644 --- a/plugins/thunderbolt/fu-thunderbolt-device.c +++ b/plugins/thunderbolt/fu-thunderbolt-device.c @@ -502,6 +502,14 @@ fu_thunderbolt_device_setup (FuDevice *device, GError **error) return fu_thunderbolt_device_setup_controller (device, error); } +static gboolean +fu_thunderbolt_device_activate (FuDevice *device, GError **error) +{ + FuUdevDevice *udev = FU_UDEV_DEVICE (device); + + return fu_udev_device_write_sysfs (udev, "nvm_authenticate", "1", error); +} + static gboolean fu_thunderbolt_device_authenticate (FuDevice *device, GError **error) { @@ -786,7 +794,7 @@ fu_thunderbolt_device_class_init (FuThunderboltDeviceClass *klass) FuDeviceClass *klass_device = FU_DEVICE_CLASS (klass); FuUdevDeviceClass *klass_udev_device = FU_UDEV_DEVICE_CLASS (klass); object_class->finalize = fu_thunderbolt_device_finalize; - klass_device->activate = fu_thunderbolt_device_authenticate; + klass_device->activate = fu_thunderbolt_device_activate; klass_udev_device->to_string = fu_thunderbolt_device_to_string; klass_device->setup = fu_thunderbolt_device_setup; klass_device->prepare_firmware = fu_thunderbolt_device_prepare_firmware; From 7fc7da3999a3bb0d7e75b4e72993783d82836329 Mon Sep 17 00:00:00 2001 From: Mario Limonciello Date: Sat, 12 Sep 2020 15:18:24 -0500 Subject: [PATCH 421/607] thunderbolt: set install parent first flag for WD19TB This is only applicable for kernel 5.9 or kernels that backported the authenticate on disconnect patches. For installation time this isn't very important since no device will restart. This also isn't relevant for the authenticate on disconnect scenario. However the manual activation scenario, it's important to activate the WD19TB device first, followed by Thunderbolt. --- plugins/thunderbolt/fu-thunderbolt-device.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/plugins/thunderbolt/fu-thunderbolt-device.c b/plugins/thunderbolt/fu-thunderbolt-device.c index 494bbef07..7e16d1af5 100644 --- a/plugins/thunderbolt/fu-thunderbolt-device.c +++ b/plugins/thunderbolt/fu-thunderbolt-device.c @@ -421,6 +421,8 @@ fu_thunderbolt_device_setup_controller (FuDevice *device, GError **error) fu_device_add_flag (device, FWUPD_DEVICE_FLAG_USABLE_DURING_UPDATE); /* forces the device to write to authenticate on disconnect attribute */ fu_device_remove_flag (device, FWUPD_DEVICE_FLAG_SKIPS_RESTART); + /* control the order of activation (less relevant; install too though) */ + fu_device_add_flag (device, FWUPD_DEVICE_FLAG_INSTALL_PARENT_FIRST); } return TRUE; From 88f0d422ec93d8ea167226b3a14fbdab08b67488 Mon Sep 17 00:00:00 2001 From: Mario Limonciello Date: Tue, 15 Sep 2020 14:30:34 -0500 Subject: [PATCH 422/607] uefi: correct a logic error in TPM PCR reading (Fixes: #2382) 069449e tried to avoid issues with all zero TPM PCR's, but caused a problem with any byte was zero. --- plugins/uefi/fu-uefi-pcrs.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/plugins/uefi/fu-uefi-pcrs.c b/plugins/uefi/fu-uefi-pcrs.c index 9396c80ad..ab3f486e4 100644 --- a/plugins/uefi/fu-uefi-pcrs.c +++ b/plugins/uefi/fu-uefi-pcrs.c @@ -163,14 +163,16 @@ fu_uefi_pcrs_setup_tpm20 (FuUefiPcrs *self, GError **error) for (guint i = 0; i < pcr_values->count; i++) { FuUefiPcrItem *item; g_autoptr(GString) str = NULL; + gboolean valid = FALSE; str = g_string_new (NULL); for (guint j = 0; j < pcr_values->digests[i].size; j++) { gint64 val = pcr_values->digests[i].buffer[j]; if (val > 0) - g_string_append_printf (str, "%02x", pcr_values->digests[i].buffer[j]); + valid = TRUE; + g_string_append_printf (str, "%02x", pcr_values->digests[i].buffer[j]); } - if (str->len > 0) { + if (valid) { item = g_new0 (FuUefiPcrItem, 1); item->idx = 0; /* constant PCR index 0, since we only read this single PCR */ item->checksum = g_string_free (g_steal_pointer (&str), FALSE); From 0038b4a78052be2c69d0090c15f4fde92a6a9e74 Mon Sep 17 00:00:00 2001 From: Richard Hughes Date: Wed, 16 Sep 2020 09:53:38 +0100 Subject: [PATCH 423/607] Allow plugins to match using the SUBSYS IDs This is the same format specified by Microsoft in "Identifiers for PCI Devices" https://docs.microsoft.com/en-us/windows-hardware/drivers/install/identifiers-for-pci-devices --- libfwupdplugin/fu-udev-device.c | 56 +++++++++++++++++++++++++++++++++ libfwupdplugin/fu-udev-device.h | 2 ++ libfwupdplugin/fwupdplugin.map | 2 ++ 3 files changed, 60 insertions(+) diff --git a/libfwupdplugin/fu-udev-device.c b/libfwupdplugin/fu-udev-device.c index e8f6a4587..b730a13ce 100644 --- a/libfwupdplugin/fu-udev-device.c +++ b/libfwupdplugin/fu-udev-device.c @@ -39,6 +39,8 @@ typedef struct GUdevDevice *udev_device; guint32 vendor; guint32 model; + guint32 subsystem_vendor; + guint32 subsystem_model; guint8 revision; gchar *subsystem; gchar *device_file; @@ -249,6 +251,8 @@ fu_udev_device_probe (FuDevice *device, GError **error) priv->vendor = fu_udev_device_get_sysfs_attr_as_uint32 (priv->udev_device, "vendor"); priv->model = fu_udev_device_get_sysfs_attr_as_uint32 (priv->udev_device, "device"); priv->revision = fu_udev_device_get_sysfs_attr_as_uint8 (priv->udev_device, "revision"); + priv->subsystem_vendor = fu_udev_device_get_sysfs_attr_as_uint32 (priv->udev_device, "subsystem_vendor"); + priv->subsystem_model = fu_udev_device_get_sysfs_attr_as_uint32 (priv->udev_device, "subsystem_device"); #ifdef HAVE_GUDEV /* fallback to the parent */ @@ -368,6 +372,22 @@ fu_udev_device_probe (FuDevice *device, GError **error) } /* add GUIDs in order of priority */ + if (priv->vendor != 0x0000 && priv->model != 0x0000 && + priv->subsystem_vendor != 0x0000 && priv->subsystem_model != 0x0000) { + g_autofree gchar *devid1 = NULL; + g_autofree gchar *devid2 = NULL; + devid1 = g_strdup_printf ("%s\\VEN_%04X&DEV_%04X&SUBSYS_%04X%04X&REV_%02X", + subsystem, + priv->vendor, priv->model, + priv->subsystem_vendor, priv->subsystem_model, + priv->revision); + fu_device_add_instance_id (device, devid1); + devid2 = g_strdup_printf ("%s\\VEN_%04X&DEV_%04X&SUBSYS_%04X%04X", + subsystem, + priv->vendor, priv->model, + priv->subsystem_vendor, priv->subsystem_model); + fu_device_add_instance_id (device, devid2); + } if (priv->vendor != 0x0000 && priv->model != 0x0000) { g_autofree gchar *devid = NULL; devid = g_strdup_printf ("%s\\VEN_%04X&DEV_%04X&REV_%02X", @@ -632,6 +652,42 @@ fu_udev_device_get_model (FuUdevDevice *self) return priv->model; } +/** + * fu_udev_device_get_subsystem_vendor: + * @self: A #FuUdevDevice + * + * Gets the device subsystem vendor code. + * + * Returns: a vendor code, or 0 if unset or invalid + * + * Since: 1.5.0 + **/ +guint32 +fu_udev_device_get_subsystem_vendor (FuUdevDevice *self) +{ + FuUdevDevicePrivate *priv = GET_PRIVATE (self); + g_return_val_if_fail (FU_IS_UDEV_DEVICE (self), 0x0000); + return priv->subsystem_vendor; +} + +/** + * fu_udev_device_get_subsystem_model: + * @self: A #FuUdevDevice + * + * Gets the device subsystem model code. + * + * Returns: a vendor code, or 0 if unset or invalid + * + * Since: 1.5.0 + **/ +guint32 +fu_udev_device_get_subsystem_model (FuUdevDevice *self) +{ + FuUdevDevicePrivate *priv = GET_PRIVATE (self); + g_return_val_if_fail (FU_IS_UDEV_DEVICE (self), 0x0000); + return priv->subsystem_model; +} + /** * fu_udev_device_get_revision: * @self: A #FuUdevDevice diff --git a/libfwupdplugin/fu-udev-device.h b/libfwupdplugin/fu-udev-device.h index ba50af081..38b63d422 100644 --- a/libfwupdplugin/fu-udev-device.h +++ b/libfwupdplugin/fu-udev-device.h @@ -63,6 +63,8 @@ const gchar *fu_udev_device_get_sysfs_path (FuUdevDevice *self); const gchar *fu_udev_device_get_subsystem (FuUdevDevice *self); guint32 fu_udev_device_get_vendor (FuUdevDevice *self); guint32 fu_udev_device_get_model (FuUdevDevice *self); +guint32 fu_udev_device_get_subsystem_vendor (FuUdevDevice *self); +guint32 fu_udev_device_get_subsystem_model (FuUdevDevice *self); guint8 fu_udev_device_get_revision (FuUdevDevice *self); guint fu_udev_device_get_slot_depth (FuUdevDevice *self, const gchar *subsystem); diff --git a/libfwupdplugin/fwupdplugin.map b/libfwupdplugin/fwupdplugin.map index ec78769c2..094b6f102 100644 --- a/libfwupdplugin/fwupdplugin.map +++ b/libfwupdplugin/fwupdplugin.map @@ -630,5 +630,7 @@ LIBFWUPDPLUGIN_1.5.0 { fu_security_attrs_new; fu_security_attrs_remove_all; fu_security_attrs_to_variant; + fu_udev_device_get_subsystem_model; + fu_udev_device_get_subsystem_vendor; local: *; } LIBFWUPDPLUGIN_1.4.6; From fbd3508655d1a71d527ff1489a5dff33c6d20ad4 Mon Sep 17 00:00:00 2001 From: Mario Limonciello Date: Wed, 16 Sep 2020 14:27:22 -0500 Subject: [PATCH 424/607] trivial: correct some documentation typos --- libfwupd/fwupd-enums.c | 2 +- libfwupd/fwupd-security-attr.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/libfwupd/fwupd-enums.c b/libfwupd/fwupd-enums.c index 16d3356da..63ebf6d42 100644 --- a/libfwupd/fwupd-enums.c +++ b/libfwupd/fwupd-enums.c @@ -578,7 +578,7 @@ fwupd_release_urgency_to_string (FwupdReleaseUrgency release_urgency) /** * fwupd_release_urgency_from_string: - * @release_urgency: A string, e.g. `trusted-payload` + * @release_urgency: A string, e.g. `low` * * Converts a string to an enumerated value. * diff --git a/libfwupd/fwupd-security-attr.c b/libfwupd/fwupd-security-attr.c index 7e3613110..1adeabd73 100644 --- a/libfwupd/fwupd-security-attr.c +++ b/libfwupd/fwupd-security-attr.c @@ -364,7 +364,7 @@ fwupd_security_attr_get_flags (FwupdSecurityAttr *self) /** * fwupd_security_attr_set_flags: * @self: A #FwupdSecurityAttr - * @flags: the self flags, e.g. %FWUPD_SECURITY_ATTR_FLAG_TRUSTED_PAYLOAD + * @flags: the self flags, e.g. %FWUPD_SECURITY_ATTR_FLAG_OBSOLETED * * Sets the self flags. * From 6da96cd04a688d6c1a5e77b522119c98749c5424 Mon Sep 17 00:00:00 2001 From: Richard Hughes Date: Thu, 17 Sep 2020 10:28:42 +0100 Subject: [PATCH 425/607] Add FuFirmwareFlags to allow opt-in dedupe of added images The function fu_firmware_add_image() has the comment text 'If an image with the same ID is present it is replaced' which has not been true for some time. This was removed, as the common case of adding two images with no ID would only leave one. However, some plugins do actually want to dedupe on the ID or IDX, so provide a flag they can set which enables this functionality without introducing regressions into other plugins. --- libfwupdplugin/fu-firmware.c | 115 ++++++++++++++++++++++++++++++++- libfwupdplugin/fu-firmware.h | 20 ++++++ libfwupdplugin/fu-self-test.c | 46 +++++++++++++ libfwupdplugin/fwupdplugin.map | 4 ++ 4 files changed, 184 insertions(+), 1 deletion(-) diff --git a/libfwupdplugin/fu-firmware.c b/libfwupdplugin/fu-firmware.c index d2ddcd76e..375d060c3 100644 --- a/libfwupdplugin/fu-firmware.c +++ b/libfwupdplugin/fu-firmware.c @@ -21,6 +21,7 @@ */ typedef struct { + FuFirmwareFlags flags; GPtrArray *images; /* FuFirmwareImage */ gchar *version; } FuFirmwarePrivate; @@ -28,6 +29,85 @@ typedef struct { G_DEFINE_TYPE_WITH_PRIVATE (FuFirmware, fu_firmware, G_TYPE_OBJECT) #define GET_PRIVATE(o) (fu_firmware_get_instance_private (o)) +/** + * fu_firmware_flag_to_string: + * @flag: A #FuFirmwareFlags, e.g. %FU_FIRMWARE_FLAG_DEDUPE_ID + * + * Converts a #FuFirmwareFlags to a string. + * + * Return value: identifier string + * + * Since: 1.5.0 + **/ +const gchar * +fu_firmware_flag_to_string (FuFirmwareFlags flag) +{ + if (flag == FU_FIRMWARE_FLAG_NONE) + return "none"; + if (flag == FU_FIRMWARE_FLAG_DEDUPE_ID) + return "dedupe-id"; + if (flag == FU_FIRMWARE_FLAG_DEDUPE_IDX) + return "dedupe-idx"; + return NULL; +} + +/** + * fu_firmware_flag_from_string: + * @flag: A string, e.g. `dedupe-id` + * + * Converts a string to a #FuFirmwareFlags. + * + * Return value: enumerated value + * + * Since: 1.5.0 + **/ +FuFirmwareFlags +fu_firmware_flag_from_string (const gchar *flag) +{ + if (g_strcmp0 (flag, "dedupe-id") == 0) + return FU_FIRMWARE_FLAG_DEDUPE_ID; + if (g_strcmp0 (flag, "dedupe-idx") == 0) + return FU_FIRMWARE_FLAG_DEDUPE_IDX; + return FU_FIRMWARE_FLAG_NONE; +} + +/** + * fu_firmware_add_flag: + * @firmware: A #FuFirmware + * @flag: the #FuFirmwareFlags + * + * Adds a specific firmware flag to the firmware. + * + * Since: 1.5.0 + **/ +void +fu_firmware_add_flag (FuFirmware *firmware, FuFirmwareFlags flag) +{ + FuFirmwarePrivate *priv = GET_PRIVATE (firmware); + g_return_if_fail (FU_IS_FIRMWARE (firmware)); + priv->flags |= flag; +} + + +/** + * fu_firmware_has_flag: + * @firmware: A #FuFirmware + * @flag: the #FuFirmwareFlags + * + * Finds if the firmware has a specific firmware flag. + * + * Returns: %TRUE if the flag is set + * + * Since: 1.5.0 + **/ +gboolean +fu_firmware_has_flag (FuFirmware *firmware, FuFirmwareFlags flag) +{ + FuFirmwarePrivate *priv = GET_PRIVATE (firmware); + g_return_val_if_fail (FU_IS_FIRMWARE (firmware), FALSE); + return (priv->flags & flag) > 0; +} + /** * fu_firmware_get_version: * @self: A #FuFirmware @@ -245,7 +325,8 @@ fu_firmware_write_file (FuFirmware *self, GFile *file, GError **error) * * Adds an image to the firmware. * - * If an image with the same ID is already present it is replaced. + * If %FU_FIRMWARE_FLAG_DEDUPE_ID is set, an image with the same ID is already + * present it is replaced. * * Since: 1.3.1 **/ @@ -255,6 +336,26 @@ fu_firmware_add_image (FuFirmware *self, FuFirmwareImage *img) FuFirmwarePrivate *priv = GET_PRIVATE (self); g_return_if_fail (FU_IS_FIRMWARE (self)); g_return_if_fail (FU_IS_FIRMWARE_IMAGE (img)); + + /* dedupe */ + for (guint i = 0; i < priv->images->len; i++) { + FuFirmwareImage *img_tmp = g_ptr_array_index (priv->images, i); + if (priv->flags & FU_FIRMWARE_FLAG_DEDUPE_ID) { + if (g_strcmp0 (fu_firmware_image_get_id (img_tmp), + fu_firmware_image_get_id (img)) == 0) { + g_ptr_array_remove_index (priv->images, i); + break; + } + } + if (priv->flags & FU_FIRMWARE_FLAG_DEDUPE_IDX) { + if (fu_firmware_image_get_idx (img_tmp) == + fu_firmware_image_get_idx (img)) { + g_ptr_array_remove_index (priv->images, i); + break; + } + } + } + g_ptr_array_add (priv->images, g_object_ref (img)); } @@ -464,6 +565,18 @@ fu_firmware_to_string (FuFirmware *self) /* subclassed type */ fu_common_string_append_kv (str, 0, G_OBJECT_TYPE_NAME (self), NULL); + if (priv->flags != FU_FIRMWARE_FLAG_NONE) { + g_autoptr(GString) tmp = g_string_new (""); + for (guint i = 0; i < 64; i++) { + if ((priv->flags & ((guint64) 1 << i)) == 0) + continue; + g_string_append_printf (tmp, "%s|", + fu_firmware_flag_to_string ((guint64) 1 << i)); + } + if (tmp->len > 0) + g_string_truncate (tmp, tmp->len - 1); + fu_common_string_append_kv (str, 0, "Flags", tmp->str); + } if (priv->version != NULL) fu_common_string_append_kv (str, 0, "Version", priv->version); diff --git a/libfwupdplugin/fu-firmware.h b/libfwupdplugin/fu-firmware.h index e6b3e65c1..798787aef 100644 --- a/libfwupdplugin/fu-firmware.h +++ b/libfwupdplugin/fu-firmware.h @@ -36,12 +36,32 @@ struct _FuFirmwareClass gpointer padding[28]; }; +/** + * FuFirmwareFlags: + * @FU_FIRMWARE_FLAG_NONE: No flags set + * @FU_FIRMWARE_FLAG_DEDUPE_ID: Dedupe imges by ID + * @FU_FIRMWARE_FLAG_DEDUPE_IDX: Dedupe imges by IDX + * + * The firmware flags. + **/ +#define FU_FIRMWARE_FLAG_NONE (0u) /* Since: 1.5.0 */ +#define FU_FIRMWARE_FLAG_DEDUPE_ID (1u << 0) /* Since: 1.5.0 */ +#define FU_FIRMWARE_FLAG_DEDUPE_IDX (1u << 1) /* Since: 1.5.0 */ +typedef guint64 FuFirmwareFlags; + +const gchar *fu_firmware_flag_to_string (FuFirmwareFlags flag); +FuFirmwareFlags fu_firmware_flag_from_string (const gchar *flag); + FuFirmware *fu_firmware_new (void); FuFirmware *fu_firmware_new_from_bytes (GBytes *fw); gchar *fu_firmware_to_string (FuFirmware *self); const gchar *fu_firmware_get_version (FuFirmware *self); void fu_firmware_set_version (FuFirmware *self, const gchar *version); +void fu_firmware_add_flag (FuFirmware *firmware, + FuFirmwareFlags flag); +gboolean fu_firmware_has_flag (FuFirmware *firmware, + FuFirmwareFlags flag); gboolean fu_firmware_tokenize (FuFirmware *self, GBytes *fw, diff --git a/libfwupdplugin/fu-self-test.c b/libfwupdplugin/fu-self-test.c index 8fcd81c54..900142aa2 100644 --- a/libfwupdplugin/fu-self-test.c +++ b/libfwupdplugin/fu-self-test.c @@ -1634,6 +1634,51 @@ fu_firmware_func (void) " Address: 0x400\n"); } +static void +fu_firmware_dedupe_func (void) +{ + g_autoptr(FuFirmware) firmware = fu_firmware_new (); + g_autoptr(FuFirmwareImage) img1 = fu_firmware_image_new (NULL); + g_autoptr(FuFirmwareImage) img1_old = fu_firmware_image_new (NULL); + g_autoptr(FuFirmwareImage) img2 = fu_firmware_image_new (NULL); + g_autoptr(FuFirmwareImage) img2_old = fu_firmware_image_new (NULL); + g_autoptr(FuFirmwareImage) img_id = NULL; + g_autoptr(FuFirmwareImage) img_idx = NULL; + g_autoptr(GError) error = NULL; + + fu_firmware_add_flag (firmware, FU_FIRMWARE_FLAG_DEDUPE_ID); + fu_firmware_add_flag (firmware, FU_FIRMWARE_FLAG_DEDUPE_IDX); + + fu_firmware_image_set_idx (img1_old, 13); + fu_firmware_image_set_id (img1_old, "DAVE"); + fu_firmware_add_image (firmware, img1_old); + + fu_firmware_image_set_idx (img1, 13); + fu_firmware_image_set_id (img1, "primary"); + fu_firmware_add_image (firmware, img1); + + + fu_firmware_image_set_idx (img2_old, 123456); + fu_firmware_image_set_id (img2_old, "secondary"); + fu_firmware_add_image (firmware, img2_old); + + fu_firmware_image_set_idx (img2, 23); + fu_firmware_image_set_id (img2, "secondary"); + fu_firmware_add_image (firmware, img2); + + img_id = fu_firmware_get_image_by_id (firmware, "primary", &error); + g_assert_no_error (error); + g_assert_nonnull (img_id); + g_assert_cmpint (fu_firmware_image_get_idx (img_id), ==, 13); + g_assert_cmpstr (fu_firmware_image_get_id (img_id), ==, "primary"); + + img_idx = fu_firmware_get_image_by_idx (firmware, 23, &error); + g_assert_no_error (error); + g_assert_nonnull (img_idx); + g_assert_cmpint (fu_firmware_image_get_idx (img_idx), ==, 23); + g_assert_cmpstr (fu_firmware_image_get_id (img_idx), ==, "secondary"); +} + static void fu_efivar_func (void) { @@ -1928,6 +1973,7 @@ main (int argc, char **argv) g_test_add_func ("/fwupd/smbios", fu_smbios_func); g_test_add_func ("/fwupd/smbios3", fu_smbios3_func); g_test_add_func ("/fwupd/firmware", fu_firmware_func); + g_test_add_func ("/fwupd/firmware{dedupe}", fu_firmware_dedupe_func); g_test_add_func ("/fwupd/firmware{ihex}", fu_firmware_ihex_func); g_test_add_func ("/fwupd/firmware{ihex-offset}", fu_firmware_ihex_offset_func); g_test_add_func ("/fwupd/firmware{ihex-signed}", fu_firmware_ihex_signed_func); diff --git a/libfwupdplugin/fwupdplugin.map b/libfwupdplugin/fwupdplugin.map index 094b6f102..28d91ebc4 100644 --- a/libfwupdplugin/fwupdplugin.map +++ b/libfwupdplugin/fwupdplugin.map @@ -617,6 +617,10 @@ LIBFWUPDPLUGIN_1.5.0 { fu_common_is_cpu_intel; fu_device_report_metadata_post; fu_device_report_metadata_pre; + fu_firmware_add_flag; + fu_firmware_flag_from_string; + fu_firmware_flag_to_string; + fu_firmware_has_flag; fu_fmap_firmware_get_type; fu_fmap_firmware_new; fu_plugin_runner_add_security_attrs; From 0d37a9a93a5d39b5fefb43836d1831eb788cab1f Mon Sep 17 00:00:00 2001 From: Richard Hughes Date: Thu, 17 Sep 2020 16:55:53 +0100 Subject: [PATCH 426/607] bios: Only warn about CSM when using i?86 or x86_64 We're telling people on PPC64 to switch to UEFI mode... --- plugins/bios/fu-plugin-bios.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/plugins/bios/fu-plugin-bios.c b/plugins/bios/fu-plugin-bios.c index 7b643a46b..b229bd627 100644 --- a/plugins/bios/fu-plugin-bios.c +++ b/plugins/bios/fu-plugin-bios.c @@ -73,15 +73,17 @@ gboolean fu_plugin_coldplug (FuPlugin *plugin, GError **error) { g_autofree gchar *sysfsfwdir = NULL; - g_autoptr(GError) error_local = NULL; g_autofree gchar *esrt_path = NULL; /* are the EFI dirs set up so we can update each device */ +#if defined(__x86_64__) || defined(__i386__) + g_autoptr(GError) error_local = NULL; if (!fu_efivar_supported (&error_local)) { const gchar *reason = "Firmware can not be updated in legacy BIOS mode, switch to UEFI mode"; g_warning ("%s", error_local->message); return fu_plugin_bios_create_dummy (plugin, reason, error); } +#endif /* get the directory of ESRT entries */ sysfsfwdir = fu_common_get_path (FU_PATH_KIND_SYSFSDIR_FW); From 923d01b84023f614f88201e742362ca13986863f Mon Sep 17 00:00:00 2001 From: mendel5 <60322520+mendel5@users.noreply.github.com> Date: Sat, 19 Sep 2020 21:53:17 +0200 Subject: [PATCH 427/607] flag_require_ac: System requires external power source --- libfwupd/fwupd-enums.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libfwupd/fwupd-enums.h b/libfwupd/fwupd-enums.h index cb39ffee7..84cd853da 100644 --- a/libfwupd/fwupd-enums.h +++ b/libfwupd/fwupd-enums.h @@ -88,7 +88,7 @@ typedef enum { * @FWUPD_DEVICE_FLAG_INTERNAL: Device cannot be removed easily * @FWUPD_DEVICE_FLAG_UPDATABLE: Device is updatable in this or any other mode * @FWUPD_DEVICE_FLAG_ONLY_OFFLINE: Update can only be done from offline mode - * @FWUPD_DEVICE_FLAG_REQUIRE_AC: Requires AC power + * @FWUPD_DEVICE_FLAG_REQUIRE_AC: System requires external power source * @FWUPD_DEVICE_FLAG_LOCKED: Is locked and can be unlocked * @FWUPD_DEVICE_FLAG_SUPPORTED: Is found in current metadata * @FWUPD_DEVICE_FLAG_NEEDS_BOOTLOADER: Requires a bootloader mode to be manually enabled by the user From f75ff4261368ed5d1d6a83fe05a7049088bfe102 Mon Sep 17 00:00:00 2001 From: mendel5 <60322520+mendel5@users.noreply.github.com> Date: Sat, 19 Sep 2020 21:58:19 +0200 Subject: [PATCH 428/607] flag_require_ac: System requires external power source --- src/fu-util-common.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/fu-util-common.c b/src/fu-util-common.c index 8b84d721e..6f3352a88 100644 --- a/src/fu-util-common.c +++ b/src/fu-util-common.c @@ -967,7 +967,7 @@ fu_util_device_flag_to_string (guint64 device_flag) } if (device_flag == FWUPD_DEVICE_FLAG_REQUIRE_AC) { /* TRANSLATORS: Must be plugged in to an outlet */ - return _("Requires AC power"); + return _("System requires external power source"); } if (device_flag == FWUPD_DEVICE_FLAG_LOCKED) { /* TRANSLATORS: Is locked and can be unlocked */ From 75810207dc8b26d88de312231a984009b17e72fd Mon Sep 17 00:00:00 2001 From: mendel5 <60322520+mendel5@users.noreply.github.com> Date: Sat, 19 Sep 2020 22:01:48 +0200 Subject: [PATCH 429/607] flag_require_ac: System requires external power source --- data/org.freedesktop.fwupd.metainfo.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/data/org.freedesktop.fwupd.metainfo.xml b/data/org.freedesktop.fwupd.metainfo.xml index 692123aad..1af27d66e 100644 --- a/data/org.freedesktop.fwupd.metainfo.xml +++ b/data/org.freedesktop.fwupd.metainfo.xml @@ -450,7 +450,7 @@
    2. Do not fail to start the daemon if tpm2_pcrlist hangs
    3. Do not fail when scheduling more than one update to be run offline
    4. Do not let failing to find DBus prevent fwuptool from starting
    5. -
    6. Do not schedule an update on battery power if it requires AC power
    7. +
    8. Do not schedule an update on battery power if it requires an external power source
    9. Include all device checksums in the LVFS report
    10. Rename the shimx64.efi binary for known broken firmware
    11. Upload the UPDATE_INFO entry for the UEFI UX capsule
    12. From b9ef4399c96eaa7708b54b0ea798a98232330e67 Mon Sep 17 00:00:00 2001 From: Richard Hughes Date: Sat, 19 Sep 2020 10:57:16 +0100 Subject: [PATCH 430/607] Remove unused udev rules We used these before we had the quirk files, and now with all the VLI devices supported in the quirk files these entries do nothing at all. --- data/90-fwupd-devices.rules | 15 --------------- libfwupdplugin/fu-udev-device.c | 7 +------ 2 files changed, 1 insertion(+), 21 deletions(-) diff --git a/data/90-fwupd-devices.rules b/data/90-fwupd-devices.rules index 12b5fe991..9f0cd7624 100644 --- a/data/90-fwupd-devices.rules +++ b/data/90-fwupd-devices.rules @@ -4,21 +4,6 @@ # SPDX-License-Identifier: LGPL-2.1+ # -# VIA USB 3.0 VL811 Hub -SUBSYSTEM=="usb", DRIVER=="hub", ATTRS{idVendor}=="2109", ATTRS{idProduct}=="0810", ENV{FWUPD_GUID}="adbb9034-b577-42c2-a661-1ee4f49ef64c", ENV{FWUPD_VENDOR}="VIA", ENV{FWUPD_MODEL}="USB 3.0 VL811 Hub" - -# VIA USB 3.0 VL811+ Hub -SUBSYSTEM=="usb", DRIVER=="hub", ATTRS{idVendor}=="2109", ATTRS{idProduct}=="0811", ENV{FWUPD_GUID}="54f84d05-c917-4c50-8b35-44feabaaa323", ENV{FWUPD_VENDOR}="VIA", ENV{FWUPD_MODEL}="USB 3.0 VL811+ Hub" - -# VIA USB 3.0 VL812 Hub -SUBSYSTEM=="usb", DRIVER=="hub", ATTRS{idVendor}=="2109", ATTRS{idProduct}=="0812", ENV{FWUPD_GUID}="cd0314ec-b80f-4d1a-a24f-c409183a8b2d", ENV{FWUPD_VENDOR}="VIA", ENV{FWUPD_MODEL}="USB 3.0 VL812 Hub" - -# VIA USB 3.0 VL812 B2 Hub -SUBSYSTEM=="usb", DRIVER=="hub", ATTRS{idVendor}=="2109", ATTRS{idProduct}=="2812", ENV{FWUPD_GUID}="26470009-97a8-4028-867a-bbbac6ee7bf0", ENV{FWUPD_VENDOR}="VIA", ENV{FWUPD_MODEL}="USB 3.0 VL812 B2 Hub" - -ENV{FWUPD_GUID}=="*?", ENV{ID_MODEL}=="", IMPORT{builtin}="usb_id" -ENV{FWUPD_GUID}=="*?", ENV{ID_MODEL_FROM_DATABASE}=="", IMPORT{builtin}="hwdb --subsystem=usb" - # PCI cards with ROM SUBSYSTEM=="pci", TEST=="/sys$devpath/rom", ENV{FWUPD_GUID}="$attr{vendor}:$attr{device}" diff --git a/libfwupdplugin/fu-udev-device.c b/libfwupdplugin/fu-udev-device.c index b730a13ce..c801b87e2 100644 --- a/libfwupdplugin/fu-udev-device.c +++ b/libfwupdplugin/fu-udev-device.c @@ -200,9 +200,6 @@ fu_udev_device_get_vendor_fallback (GUdevDevice *udev_device) { #ifdef HAVE_GUDEV const gchar *tmp; - tmp = g_udev_device_get_property (udev_device, "FWUPD_VENDOR"); - if (tmp != NULL) - return tmp; tmp = g_udev_device_get_property (udev_device, "ID_VENDOR_FROM_DATABASE"); if (tmp != NULL) return tmp; @@ -310,9 +307,7 @@ fu_udev_device_probe (FuDevice *device, GError **error) /* set model */ if (fu_device_get_name (device) == NULL) { - tmp = g_udev_device_get_property (priv->udev_device, "FWUPD_MODEL"); - if (tmp == NULL) - tmp = g_udev_device_get_property (priv->udev_device, "ID_MODEL_FROM_DATABASE"); + tmp = g_udev_device_get_property (priv->udev_device, "ID_MODEL_FROM_DATABASE"); if (tmp == NULL) tmp = g_udev_device_get_property (priv->udev_device, "ID_MODEL"); if (tmp == NULL) From 7ef2dea2713339c5e51b5e5becc03f51ac607e99 Mon Sep 17 00:00:00 2001 From: Richard Hughes Date: Sat, 19 Sep 2020 10:59:47 +0100 Subject: [PATCH 431/607] optionrom: Test if the PCI device has ROM in probe This means we make things a simpler by not relying on udev to stat the file. It also reduces the number of added *unused* GUIDs by one per device too. --- data/90-fwupd-devices.rules | 3 --- plugins/optionrom/fu-optionrom-device.c | 10 +++++----- 2 files changed, 5 insertions(+), 8 deletions(-) diff --git a/data/90-fwupd-devices.rules b/data/90-fwupd-devices.rules index 9f0cd7624..2bc9efc49 100644 --- a/data/90-fwupd-devices.rules +++ b/data/90-fwupd-devices.rules @@ -4,8 +4,5 @@ # SPDX-License-Identifier: LGPL-2.1+ # -# PCI cards with ROM -SUBSYSTEM=="pci", TEST=="/sys$devpath/rom", ENV{FWUPD_GUID}="$attr{vendor}:$attr{device}" - # NVMe hardware SUBSYSTEM=="nvme", ENV{ID_VENDOR_FROM_DATABASE}=="", IMPORT{builtin}="hwdb --subsystem=pci" diff --git a/plugins/optionrom/fu-optionrom-device.c b/plugins/optionrom/fu-optionrom-device.c index 248d7a546..2723994c8 100644 --- a/plugins/optionrom/fu-optionrom-device.c +++ b/plugins/optionrom/fu-optionrom-device.c @@ -18,15 +18,15 @@ G_DEFINE_TYPE (FuOptionromDevice, fu_optionrom_device, FU_TYPE_UDEV_DEVICE) static gboolean fu_optionrom_device_probe (FuUdevDevice *device, GError **error) { - GUdevDevice *udev_device = fu_udev_device_get_dev (device); - const gchar *guid = NULL; + g_autofree gchar *fn = NULL; - guid = g_udev_device_get_property (udev_device, "FWUPD_GUID"); - if (guid == NULL) { + /* does the device even have ROM? */ + fn = g_build_filename (fu_udev_device_get_sysfs_path (device), "rom", NULL); + if (!g_file_test (fn, G_FILE_TEST_EXISTS)) { g_set_error_literal (error, FWUPD_ERROR, FWUPD_ERROR_NOT_SUPPORTED, - "no FWUPD_GUID property"); + "Unable to read firmware from device"); return FALSE; } From 366805e18e8aa7e383be8ab1587c408e3dc7fd78 Mon Sep 17 00:00:00 2001 From: Richard Hughes Date: Sun, 20 Sep 2020 22:17:04 +0100 Subject: [PATCH 432/607] Add the missing fu_firmware_image_parse() We provided the FuFirmwareImage->parse() vfunc, but did not provide any way to actually call it... --- libfwupdplugin/fu-firmware-image.c | 34 ++++++++++++++++++++++++++++++ libfwupdplugin/fu-firmware-image.h | 4 ++++ libfwupdplugin/fwupdplugin.map | 1 + 3 files changed, 39 insertions(+) diff --git a/libfwupdplugin/fu-firmware-image.c b/libfwupdplugin/fu-firmware-image.c index c23ceac36..5cd6fc528 100644 --- a/libfwupdplugin/fu-firmware-image.c +++ b/libfwupdplugin/fu-firmware-image.c @@ -188,6 +188,40 @@ fu_firmware_image_set_bytes (FuFirmwareImage *self, GBytes *bytes) priv->bytes = g_bytes_ref (bytes); } +/** + * fu_firmware_image_parse: + * @self: A #FuFirmwareImage + * @fw: A #GBytes + * @flags: some #FwupdInstallFlags, e.g. %FWUPD_INSTALL_FLAG_FORCE + * @error: A #GError, or %NULL + * + * Parses a firmware image, typically checking image CRCs and/or headers. + * + * Returns: %TRUE for success + * + * Since: 1.5.0 + **/ +gboolean +fu_firmware_image_parse (FuFirmwareImage *self, + GBytes *fw, + FwupdInstallFlags flags, + GError **error) +{ + FuFirmwareImageClass *klass = FU_FIRMWARE_IMAGE_GET_CLASS (self); + + g_return_val_if_fail (FU_IS_FIRMWARE_IMAGE (self), FALSE); + g_return_val_if_fail (fw != NULL, FALSE); + g_return_val_if_fail (error == NULL || *error == NULL, FALSE); + + /* subclassed */ + if (klass->parse != NULL) + return klass->parse (self, fw, flags, error); + + /* just add entire blob */ + fu_firmware_image_set_bytes (self, fw); + return TRUE; +} + /** * fu_firmware_image_write: * @self: a #FuPlugin diff --git a/libfwupdplugin/fu-firmware-image.h b/libfwupdplugin/fu-firmware-image.h index 7c946e6e8..8049e422c 100644 --- a/libfwupdplugin/fu-firmware-image.h +++ b/libfwupdplugin/fu-firmware-image.h @@ -49,6 +49,10 @@ void fu_firmware_image_set_idx (FuFirmwareImage *self, guint64 idx); void fu_firmware_image_set_bytes (FuFirmwareImage *self, GBytes *bytes); +gboolean fu_firmware_image_parse (FuFirmwareImage *self, + GBytes *fw, + FwupdInstallFlags flags, + GError **error); GBytes *fu_firmware_image_write (FuFirmwareImage *self, GError **error); GBytes *fu_firmware_image_write_chunk (FuFirmwareImage *self, diff --git a/libfwupdplugin/fwupdplugin.map b/libfwupdplugin/fwupdplugin.map index 28d91ebc4..50d245cdc 100644 --- a/libfwupdplugin/fwupdplugin.map +++ b/libfwupdplugin/fwupdplugin.map @@ -621,6 +621,7 @@ LIBFWUPDPLUGIN_1.5.0 { fu_firmware_flag_from_string; fu_firmware_flag_to_string; fu_firmware_has_flag; + fu_firmware_image_parse; fu_fmap_firmware_get_type; fu_fmap_firmware_new; fu_plugin_runner_add_security_attrs; From 9a1e8e44e05d38f0a248348b3f223674a255e0b7 Mon Sep 17 00:00:00 2001 From: Richard Hughes Date: Mon, 21 Sep 2020 09:02:12 +0100 Subject: [PATCH 433/607] uefi: Fix critical warning regression with 'fwupdate -a' Set the ESP when creating the device with a known GUID. Fixes https://github.com/fwupd/fwupd/issues/2406 --- plugins/uefi/fu-uefi-tool.c | 1 + 1 file changed, 1 insertion(+) diff --git a/plugins/uefi/fu-uefi-tool.c b/plugins/uefi/fu-uefi-tool.c index 82463c57a..a6f373f67 100644 --- a/plugins/uefi/fu-uefi-tool.c +++ b/plugins/uefi/fu-uefi-tool.c @@ -327,6 +327,7 @@ main (int argc, char *argv[]) g_printerr ("failed: %s\n", error_local->message); return EXIT_FAILURE; } + fu_uefi_device_set_esp (dev, esp); if (flags != NULL) fu_device_set_custom_flags (FU_DEVICE (dev), flags); if (!fu_device_prepare (FU_DEVICE (dev), From f17db477eb2f8e12c3b269c142e505b2e35e4e4f Mon Sep 17 00:00:00 2001 From: Richard Hughes Date: Fri, 18 Sep 2020 14:09:45 +0100 Subject: [PATCH 434/607] Tag the FuFirmwareImage objects with the filename For containers with multiple images it is sometimes very helpful to know what file they've been loaded from. This would also allow us to 'explode' the firmware container into seporate image files on disk. --- libfwupdplugin/fu-firmware-image.c | 40 ++++++++++++++++++++++++++++++ libfwupdplugin/fu-firmware-image.h | 3 +++ libfwupdplugin/fu-self-test.c | 2 ++ libfwupdplugin/fwupdplugin.map | 2 ++ 4 files changed, 47 insertions(+) diff --git a/libfwupdplugin/fu-firmware-image.c b/libfwupdplugin/fu-firmware-image.c index 5cd6fc528..63a28df39 100644 --- a/libfwupdplugin/fu-firmware-image.c +++ b/libfwupdplugin/fu-firmware-image.c @@ -24,6 +24,7 @@ typedef struct { guint64 addr; guint64 idx; gchar *version; + gchar *filename; } FuFirmwareImagePrivate; G_DEFINE_TYPE_WITH_PRIVATE (FuFirmwareImage, fu_firmware_image, G_TYPE_OBJECT) @@ -65,6 +66,42 @@ fu_firmware_image_set_version (FuFirmwareImage *self, const gchar *version) priv->version = g_strdup (version); } +/** + * fu_firmware_image_get_filename: + * @self: A #FuFirmwareImage + * + * Gets an optional filename that represents the image source or destination. + * + * Returns: a string, or %NULL + * + * Since: 1.5.0 + **/ +const gchar * +fu_firmware_image_get_filename (FuFirmwareImage *self) +{ + FuFirmwareImagePrivate *priv = GET_PRIVATE (self); + g_return_val_if_fail (FU_IS_FIRMWARE_IMAGE (self), NULL); + return priv->filename; +} + +/** + * fu_firmware_image_set_filename: + * @self: A #FuFirmwareImage + * @filename: (nullable): A string filename, or %NULL + * + * Sets an optional filename that represents the image source or destination. + * + * Since: 1.5.0 + **/ +void +fu_firmware_image_set_filename (FuFirmwareImage *self, const gchar *filename) +{ + FuFirmwareImagePrivate *priv = GET_PRIVATE (self); + g_return_if_fail (FU_IS_FIRMWARE_IMAGE (self)); + g_free (priv->filename); + priv->filename = g_strdup (filename); +} + /** * fu_firmware_image_set_id: * @self: a #FuPlugin @@ -333,6 +370,8 @@ fu_firmware_image_add_string (FuFirmwareImage *self, guint idt, GString *str) fu_common_string_append_kx (str, idt, "Address", priv->addr); if (priv->version != NULL) fu_common_string_append_kv (str, idt, "Version", priv->version); + if (priv->filename != NULL) + fu_common_string_append_kv (str, idt, "Filename", priv->filename); if (priv->bytes != NULL) { fu_common_string_append_kx (str, idt, "Data", g_bytes_get_size (priv->bytes)); @@ -373,6 +412,7 @@ fu_firmware_image_finalize (GObject *object) FuFirmwareImagePrivate *priv = GET_PRIVATE (self); g_free (priv->id); g_free (priv->version); + g_free (priv->filename); if (priv->bytes != NULL) g_bytes_unref (priv->bytes); G_OBJECT_CLASS (fu_firmware_image_parent_class)->finalize (object); diff --git a/libfwupdplugin/fu-firmware-image.h b/libfwupdplugin/fu-firmware-image.h index 8049e422c..97be313d1 100644 --- a/libfwupdplugin/fu-firmware-image.h +++ b/libfwupdplugin/fu-firmware-image.h @@ -38,6 +38,9 @@ gchar *fu_firmware_image_to_string (FuFirmwareImage *self); const gchar *fu_firmware_image_get_version (FuFirmwareImage *self); void fu_firmware_image_set_version (FuFirmwareImage *self, const gchar *version); +const gchar *fu_firmware_image_get_filename (FuFirmwareImage *self); +void fu_firmware_image_set_filename (FuFirmwareImage *self, + const gchar *filename); const gchar *fu_firmware_image_get_id (FuFirmwareImage *self); void fu_firmware_image_set_id (FuFirmwareImage *self, const gchar *id); diff --git a/libfwupdplugin/fu-self-test.c b/libfwupdplugin/fu-self-test.c index 900142aa2..7db112b8e 100644 --- a/libfwupdplugin/fu-self-test.c +++ b/libfwupdplugin/fu-self-test.c @@ -1594,6 +1594,7 @@ fu_firmware_func (void) fu_firmware_image_set_addr (img1, 0x200); fu_firmware_image_set_idx (img1, 13); fu_firmware_image_set_id (img1, "primary"); + fu_firmware_image_set_filename (img1, "BIOS.bin"); fu_firmware_add_image (firmware, img1); fu_firmware_image_set_addr (img2, 0x400); fu_firmware_image_set_idx (img2, 23); @@ -1628,6 +1629,7 @@ fu_firmware_func (void) " ID: primary\n" " Index: 0xd\n" " Address: 0x200\n" + " Filename: BIOS.bin\n" " FuFirmwareImage:\n" " ID: secondary\n" " Index: 0x17\n" diff --git a/libfwupdplugin/fwupdplugin.map b/libfwupdplugin/fwupdplugin.map index 50d245cdc..f79829e75 100644 --- a/libfwupdplugin/fwupdplugin.map +++ b/libfwupdplugin/fwupdplugin.map @@ -621,7 +621,9 @@ LIBFWUPDPLUGIN_1.5.0 { fu_firmware_flag_from_string; fu_firmware_flag_to_string; fu_firmware_has_flag; + fu_firmware_image_get_filename; fu_firmware_image_parse; + fu_firmware_image_set_filename; fu_fmap_firmware_get_type; fu_fmap_firmware_new; fu_plugin_runner_add_security_attrs; From 41400a8cc65c1fef4aa5b72c0d6642220788a482 Mon Sep 17 00:00:00 2001 From: Richard Hughes Date: Mon, 21 Sep 2020 13:43:15 +0100 Subject: [PATCH 435/607] Allow contructing a firmware with multiple images At the moment there are commands to convert one file format to another, but not to 'merge' or alter them. Some firmware files are containers which can store multiple images, each with optional id, idx and addresses. This would allow us to, for instance, create a DfuSe file with two different raw files that are flashed to different addresses on the SPI flash. It would also allow us to create very small complicated container formats for fuzzing. This can be used by writing a `firmware.builder.xml` file like: 1.2.3 4.5.6 header 456 0x456 header.bin 7.8.9 payload 789 0x789 aGVsbG8= ...and then using something like: # fwupdtool firmware-convert firmware.builder.xml firmware.dfu builder dfu --- libfwupdplugin/fu-firmware-image.c | 57 ++++++++++++++++ libfwupdplugin/fu-firmware-image.h | 4 ++ libfwupdplugin/fu-firmware.c | 50 ++++++++++++++ libfwupdplugin/fu-firmware.h | 8 ++- libfwupdplugin/fu-self-test.c | 70 +++++++++++++++++++ libfwupdplugin/fwupdplugin.map | 2 + plugins/dfu/meson.build | 1 + plugins/synaptics-prometheus/meson.build | 1 + plugins/synaptics-rmi/meson.build | 1 + src/fu-tool.c | 85 ++++++++++++++++++++---- src/meson.build | 1 + 11 files changed, 265 insertions(+), 15 deletions(-) diff --git a/libfwupdplugin/fu-firmware-image.c b/libfwupdplugin/fu-firmware-image.c index 63a28df39..bfef23a28 100644 --- a/libfwupdplugin/fu-firmware-image.c +++ b/libfwupdplugin/fu-firmware-image.c @@ -259,6 +259,63 @@ fu_firmware_image_parse (FuFirmwareImage *self, return TRUE; } +/** + * fu_firmware_image_build: + * @self: A #FuFirmwareImage + * @n: A #XbNode + * @error: A #GError, or %NULL + * + * Builds a firmware image from an XML manifest. + * + * Returns: %TRUE for success + * + * Since: 1.5.0 + **/ +gboolean +fu_firmware_image_build (FuFirmwareImage *self, XbNode *n, GError **error) +{ + guint64 tmpval; + const gchar *tmp; + + g_return_val_if_fail (FU_IS_FIRMWARE_IMAGE (self), FALSE); + g_return_val_if_fail (XB_IS_NODE (n), FALSE); + g_return_val_if_fail (error == NULL || *error == NULL, FALSE); + + tmp = xb_node_query_text (n, "version", NULL); + if (tmp != NULL) + fu_firmware_image_set_version (self, tmp); + tmp = xb_node_query_text (n, "id", NULL); + if (tmp != NULL) + fu_firmware_image_set_id (self, tmp); + tmpval = xb_node_query_text_as_uint (n, "idx", NULL); + if (tmpval != G_MAXUINT64) + fu_firmware_image_set_idx (self, tmpval); + tmpval = xb_node_query_text_as_uint (n, "addr", NULL); + if (tmpval != G_MAXUINT64) + fu_firmware_image_set_addr (self, tmpval); + tmp = xb_node_query_text (n, "filename", NULL); + if (tmp != NULL) { + g_autoptr(GBytes) blob = NULL; + blob = fu_common_get_contents_bytes (tmp, error); + if (blob == NULL) + return FALSE; + fu_firmware_image_set_bytes (self, blob); + fu_firmware_image_set_filename (self, tmp); + } + tmp = xb_node_query_text (n, "data", NULL); + if (tmp != NULL) { + gsize bufsz = 0; + g_autofree guchar *buf = NULL; + g_autoptr(GBytes) blob = NULL; + buf = g_base64_decode (tmp, &bufsz); + blob = g_bytes_new (buf, bufsz); + fu_firmware_image_set_bytes (self, blob); + } + + /* success */ + return TRUE; +} + /** * fu_firmware_image_write: * @self: a #FuPlugin diff --git a/libfwupdplugin/fu-firmware-image.h b/libfwupdplugin/fu-firmware-image.h index 97be313d1..7310a3b8e 100644 --- a/libfwupdplugin/fu-firmware-image.h +++ b/libfwupdplugin/fu-firmware-image.h @@ -8,6 +8,7 @@ #include #include +#include #define FU_TYPE_FIRMWARE_IMAGE (fu_firmware_image_get_type ()) G_DECLARE_DERIVABLE_TYPE (FuFirmwareImage, fu_firmware_image, FU, FIRMWARE_IMAGE, GObject) @@ -56,6 +57,9 @@ gboolean fu_firmware_image_parse (FuFirmwareImage *self, GBytes *fw, FwupdInstallFlags flags, GError **error); +gboolean fu_firmware_image_build (FuFirmwareImage *self, + XbNode *n, + GError **error); GBytes *fu_firmware_image_write (FuFirmwareImage *self, GError **error); GBytes *fu_firmware_image_write_chunk (FuFirmwareImage *self, diff --git a/libfwupdplugin/fu-firmware.c b/libfwupdplugin/fu-firmware.c index 375d060c3..5e5b60bab 100644 --- a/libfwupdplugin/fu-firmware.c +++ b/libfwupdplugin/fu-firmware.c @@ -239,6 +239,56 @@ fu_firmware_parse (FuFirmware *self, GBytes *fw, FwupdInstallFlags flags, GError return fu_firmware_parse_full (self, fw, 0x0, 0x0, flags, error); } +/** + * fu_firmware_build: + * @self: A #FuFirmware + * @n: A #XbNode + * @error: A #GError, or %NULL + * + * Builds a firmware from an XML manifest. + * + * Returns: %TRUE for success + * + * Since: 1.5.0 + **/ +gboolean +fu_firmware_build (FuFirmware *self, XbNode *n, GError **error) +{ + FuFirmwareClass *klass = FU_FIRMWARE_GET_CLASS (self); + const gchar *tmp; + g_autoptr(GPtrArray) xb_images = NULL; + + g_return_val_if_fail (FU_IS_FIRMWARE (self), FALSE); + g_return_val_if_fail (XB_IS_NODE (n), FALSE); + g_return_val_if_fail (error == NULL || *error == NULL, FALSE); + + /* set attributes */ + tmp = xb_node_query_text (n, "version", NULL); + if (tmp != NULL) + fu_firmware_set_version (self, tmp); + + /* parse images */ + xb_images = xb_node_query (n, "image", 0, NULL); + if (xb_images != NULL) { + for (guint i = 0; i < xb_images->len; i++) { + XbNode *xb_image = g_ptr_array_index (xb_images, i); + g_autoptr(FuFirmwareImage) img = fu_firmware_image_new (NULL); + if (!fu_firmware_image_build (img, xb_image, error)) + return FALSE; + fu_firmware_add_image (self, img); + } + } + + /* subclassed */ + if (klass->build != NULL) { + if (!klass->build (self, n, error)) + return FALSE; + } + + /* success */ + return TRUE; +} + /** * fu_firmware_parse_file: * @self: A #FuFirmware diff --git a/libfwupdplugin/fu-firmware.h b/libfwupdplugin/fu-firmware.h index 798787aef..119de9a82 100644 --- a/libfwupdplugin/fu-firmware.h +++ b/libfwupdplugin/fu-firmware.h @@ -32,8 +32,11 @@ struct _FuFirmwareClass GBytes *fw, FwupdInstallFlags flags, GError **error); + gboolean (*build) (FuFirmware *self, + XbNode *n, + GError **error); /*< private >*/ - gpointer padding[28]; + gpointer padding[27]; }; /** @@ -67,6 +70,9 @@ gboolean fu_firmware_tokenize (FuFirmware *self, GBytes *fw, FwupdInstallFlags flags, GError **error); +gboolean fu_firmware_build (FuFirmware *self, + XbNode *n, + GError **error); gboolean fu_firmware_parse (FuFirmware *self, GBytes *fw, FwupdInstallFlags flags, diff --git a/libfwupdplugin/fu-self-test.c b/libfwupdplugin/fu-self-test.c index 7db112b8e..238a5755a 100644 --- a/libfwupdplugin/fu-self-test.c +++ b/libfwupdplugin/fu-self-test.c @@ -1539,6 +1539,75 @@ fu_firmware_srec_tokenization_func (void) g_assert_cmpint (rcd->buf->data[0], ==, 0x50); } +static void +fu_firmware_build_func (void) +{ + gboolean ret; + g_autofree gchar *str = NULL; + g_autoptr(FuFirmware) firmware = fu_firmware_new (); + g_autoptr(FuFirmwareImage) img = NULL; + g_autoptr(GBytes) blob = NULL; + g_autoptr(GBytes) blob2 = NULL; + g_autoptr(GError) error = NULL; + g_autoptr(XbBuilder) builder = xb_builder_new (); + g_autoptr(XbBuilderSource) source = xb_builder_source_new (); + g_autoptr(XbNode) n = NULL; + g_autoptr(XbSilo) silo = NULL; + const gchar *buf = + "\n" + "\n" + " 1.2.3\n" + " \n" + " 4.5.6\n" + " header\n" + " 456\n" + " 0x456\n" + " aGVsbG8=\n" + " \n" + " \n" + " 7.8.9\n" + " header\n" + " 789\n" + " 0x789\n" + " \n" + "\n"; + blob = g_bytes_new_static (buf, strlen (buf)); + g_assert_no_error (error); + g_assert_nonnull (blob); + + /* parse XML */ + ret = xb_builder_source_load_bytes (source, blob, XB_BUILDER_SOURCE_FLAG_NONE, &error); + g_assert_no_error (error); + g_assert (ret); + xb_builder_import_source (builder, source); + silo = xb_builder_compile (builder, XB_BUILDER_COMPILE_FLAG_NONE, NULL, &error); + g_assert_no_error (error); + g_assert_nonnull (silo); + n = xb_silo_query_first (silo, "firmware", &error); + g_assert_no_error (error); + g_assert_nonnull (n); + + /* build object */ + ret = fu_firmware_build (firmware, n, &error); + g_assert_no_error (error); + g_assert (ret); + g_assert_cmpstr (fu_firmware_get_version (firmware), ==, "1.2.3"); + + /* verify image */ + img = fu_firmware_get_image_by_id (firmware, "header", &error); + g_assert_no_error (error); + g_assert_nonnull (img); + g_assert_cmpstr (fu_firmware_image_get_version (img), ==, "4.5.6"); + g_assert_cmpint (fu_firmware_image_get_idx (img), ==, 456); + g_assert_cmpint (fu_firmware_image_get_addr (img), ==, 0x456); + blob2 = fu_firmware_image_write (img, &error); + g_assert_no_error (error); + g_assert_nonnull (blob2); + g_assert_cmpint (g_bytes_get_size (blob2), ==, 5); + str = g_strndup (g_bytes_get_data (blob2, NULL), g_bytes_get_size (blob2)); + g_assert_cmpstr (str, ==, "hello"); +} + static void fu_firmware_dfu_func (void) { @@ -1976,6 +2045,7 @@ main (int argc, char **argv) g_test_add_func ("/fwupd/smbios3", fu_smbios3_func); g_test_add_func ("/fwupd/firmware", fu_firmware_func); g_test_add_func ("/fwupd/firmware{dedupe}", fu_firmware_dedupe_func); + g_test_add_func ("/fwupd/firmware{build}", fu_firmware_build_func); g_test_add_func ("/fwupd/firmware{ihex}", fu_firmware_ihex_func); g_test_add_func ("/fwupd/firmware{ihex-offset}", fu_firmware_ihex_offset_func); g_test_add_func ("/fwupd/firmware{ihex-signed}", fu_firmware_ihex_signed_func); diff --git a/libfwupdplugin/fwupdplugin.map b/libfwupdplugin/fwupdplugin.map index f79829e75..89353c287 100644 --- a/libfwupdplugin/fwupdplugin.map +++ b/libfwupdplugin/fwupdplugin.map @@ -618,9 +618,11 @@ LIBFWUPDPLUGIN_1.5.0 { fu_device_report_metadata_post; fu_device_report_metadata_pre; fu_firmware_add_flag; + fu_firmware_build; fu_firmware_flag_from_string; fu_firmware_flag_to_string; fu_firmware_has_flag; + fu_firmware_image_build; fu_firmware_image_get_filename; fu_firmware_image_parse; fu_firmware_image_set_filename; diff --git a/plugins/dfu/meson.build b/plugins/dfu/meson.build index 0a5a9a4e2..4fca2246f 100644 --- a/plugins/dfu/meson.build +++ b/plugins/dfu/meson.build @@ -24,6 +24,7 @@ dfu = static_library( dependencies : [ giounix, libm, + libxmlb, gusb, gudev, ], diff --git a/plugins/synaptics-prometheus/meson.build b/plugins/synaptics-prometheus/meson.build index b7b5d0a65..fed45214c 100644 --- a/plugins/synaptics-prometheus/meson.build +++ b/plugins/synaptics-prometheus/meson.build @@ -76,6 +76,7 @@ if get_option('tests') ], dependencies : [ gio, + libxmlb, ], link_with : [ fwupd, diff --git a/plugins/synaptics-rmi/meson.build b/plugins/synaptics-rmi/meson.build index 3e71f911c..3272fad87 100644 --- a/plugins/synaptics-rmi/meson.build +++ b/plugins/synaptics-rmi/meson.build @@ -48,6 +48,7 @@ if get_option('tests') ], dependencies : [ gio, + libxmlb, ], link_with : [ fwupd, diff --git a/src/fu-tool.c b/src/fu-tool.c index fdb78f27e..0694f3f9f 100644 --- a/src/fu-tool.c +++ b/src/fu-tool.c @@ -1639,12 +1639,16 @@ fu_util_get_firmware_types (FuUtilPrivate *priv, gchar **values, GError **error) } static gchar * -fu_util_prompt_for_firmware_type (FuUtilPrivate *priv, GError **error) +fu_util_prompt_for_firmware_type (FuUtilPrivate *priv, gboolean add_builder, GError **error) { g_autoptr(GPtrArray) firmware_types = NULL; guint idx; firmware_types = fu_engine_get_firmware_gtype_ids (priv->engine); + /* add fake entry */ + if (add_builder) + g_ptr_array_add (firmware_types, g_strdup ("builder")); + /* TRANSLATORS: get interactive prompt */ g_print ("%s\n", _("Choose a firmware type:")); /* TRANSLATORS: this is to abort the interactive prompt */ @@ -1697,7 +1701,7 @@ fu_util_firmware_parse (FuUtilPrivate *priv, gchar **values, GError **error) /* find the GType to use */ if (firmware_type == NULL) - firmware_type = fu_util_prompt_for_firmware_type (priv, error); + firmware_type = fu_util_prompt_for_firmware_type (priv, TRUE, error); if (firmware_type == NULL) return FALSE; gtype = fu_engine_get_firmware_gtype_by_id (priv->engine, firmware_type); @@ -1716,6 +1720,53 @@ fu_util_firmware_parse (FuUtilPrivate *priv, gchar **values, GError **error) return TRUE; } +static FuFirmware * +fu_util_firmware_builder_new (FuUtilPrivate *priv, GBytes *fw, GError **error) +{ + const gchar *tmp; + g_autoptr(FuFirmware) firmware = NULL; + g_autoptr(XbBuilder) builder = xb_builder_new (); + g_autoptr(XbBuilderSource) source = xb_builder_source_new (); + g_autoptr(XbNode) n = NULL; + g_autoptr(XbSilo) silo = NULL; + + /* parse XML */ + if (!xb_builder_source_load_bytes (source, fw, + XB_BUILDER_SOURCE_FLAG_NONE, + error)) { + g_prefix_error (error, "could not parse XML: "); + return NULL; + } + xb_builder_import_source (builder, source); + silo = xb_builder_compile (builder, XB_BUILDER_COMPILE_FLAG_NONE, NULL, error); + if (silo == NULL) + return NULL; + + /* create FuFirmware of specific GType */ + n = xb_silo_query_first (silo, "firmware", error); + if (n == NULL) + return FALSE; + tmp = xb_node_get_attr (n, "gtype"); + if (tmp != NULL) { + GType gtype = fu_engine_get_firmware_gtype_by_id (priv->engine, tmp); + if (gtype == G_TYPE_INVALID) { + g_set_error (error, + G_IO_ERROR, + G_IO_ERROR_NOT_FOUND, + "GType %s not supported", tmp); + return NULL; + } + firmware = g_object_new (gtype, NULL); + } else { + firmware = fu_firmware_new (); + } + if (!fu_firmware_build (firmware, n, error)) + return NULL; + + /* success */ + return g_steal_pointer (&firmware); +} + static gboolean fu_util_firmware_convert (FuUtilPrivate *priv, gchar **values, GError **error) { @@ -1756,20 +1807,29 @@ fu_util_firmware_convert (FuUtilPrivate *priv, gchar **values, GError **error) /* find the GType to use */ if (firmware_type_src == NULL) - firmware_type_src = fu_util_prompt_for_firmware_type (priv, error); + firmware_type_src = fu_util_prompt_for_firmware_type (priv, TRUE, error); if (firmware_type_src == NULL) return FALSE; if (firmware_type_dst == NULL) - firmware_type_dst = fu_util_prompt_for_firmware_type (priv, error); + firmware_type_dst = fu_util_prompt_for_firmware_type (priv, FALSE, error); if (firmware_type_dst == NULL) return FALSE; - gtype_src = fu_engine_get_firmware_gtype_by_id (priv->engine, firmware_type_src); - if (gtype_src == G_TYPE_INVALID) { - g_set_error (error, - G_IO_ERROR, - G_IO_ERROR_NOT_FOUND, - "GType %s not supported", firmware_type_src); - return FALSE; + if (g_strcmp0 (firmware_type_src, "builder") == 0) { + firmware_src = fu_util_firmware_builder_new (priv, blob_src, error); + if (firmware_src == NULL) + return FALSE; + } else { + gtype_src = fu_engine_get_firmware_gtype_by_id (priv->engine, firmware_type_src); + if (gtype_src == G_TYPE_INVALID) { + g_set_error (error, + G_IO_ERROR, + G_IO_ERROR_NOT_FOUND, + "GType %s not supported", firmware_type_src); + return FALSE; + } + firmware_src = g_object_new (gtype_src, NULL); + if (!fu_firmware_parse (firmware_src, blob_src, priv->flags, error)) + return FALSE; } gtype_dst = fu_engine_get_firmware_gtype_by_id (priv->engine, firmware_type_dst); if (gtype_dst == G_TYPE_INVALID) { @@ -1779,9 +1839,6 @@ fu_util_firmware_convert (FuUtilPrivate *priv, gchar **values, GError **error) "GType %s not supported", firmware_type_dst); return FALSE; } - firmware_src = g_object_new (gtype_src, NULL); - if (!fu_firmware_parse (firmware_src, blob_src, priv->flags, error)) - return FALSE; str_src = fu_firmware_to_string (firmware_src); g_print ("%s", str_src); diff --git a/src/meson.build b/src/meson.build index d63a52092..8a07de033 100644 --- a/src/meson.build +++ b/src/meson.build @@ -345,6 +345,7 @@ if get_option('tests') fwupdplugin_incdir, ], dependencies : [ + libxmlb, gio, ], link_with : [ From 34f7d9d8fb5db12c50f396de00f3c697d565e843 Mon Sep 17 00:00:00 2001 From: Richard Hughes Date: Sat, 19 Sep 2020 15:28:11 +0100 Subject: [PATCH 436/607] Allow binding and unbinding kernel drivers --- data/bash-completion/fwupdtool.in | 2 + libfwupdplugin/fu-device.c | 76 ++++++++++++++++++++ libfwupdplugin/fu-device.h | 14 +++- libfwupdplugin/fu-udev-device.c | 116 ++++++++++++++++++++++++++++++ libfwupdplugin/fu-usb-device.c | 36 ++++++++++ libfwupdplugin/fwupdplugin.map | 2 + src/fu-tool.c | 72 +++++++++++++++++++ 7 files changed, 317 insertions(+), 1 deletion(-) diff --git a/data/bash-completion/fwupdtool.in b/data/bash-completion/fwupdtool.in index 82c676a3f..88f26f5ed 100644 --- a/data/bash-completion/fwupdtool.in +++ b/data/bash-completion/fwupdtool.in @@ -32,6 +32,8 @@ _fwupdtool_cmd_list=( 'refresh' 'verify-update' 'watch' + 'unbind-driver' + 'bind-driver' ) _fwupdtool_opts=( diff --git a/libfwupdplugin/fu-device.c b/libfwupdplugin/fu-device.c index 5720a9ec1..1e0698c90 100644 --- a/libfwupdplugin/fu-device.c +++ b/libfwupdplugin/fu-device.c @@ -3041,6 +3041,82 @@ fu_device_report_metadata_post (FuDevice *self) return g_steal_pointer (&metadata); } +/** + * fu_device_bind_driver: + * @self: A #FuDevice + * @subsystem: A subsystem string, e.g. `pci` + * @driver: A kernel module name, e.g. `tg3` + * @error: A #GError, or %NULL + * + * Binds a driver to the device, which normally means the kernel driver takes + * control of the hardware. + * + * Returns: %TRUE if driver was bound. + * + * Since: 1.5.0 + **/ +gboolean +fu_device_bind_driver (FuDevice *self, + const gchar *subsystem, + const gchar *driver, + GError **error) +{ + FuDeviceClass *klass = FU_DEVICE_GET_CLASS (self); + + g_return_val_if_fail (FU_IS_DEVICE (self), FALSE); + g_return_val_if_fail (subsystem != NULL, FALSE); + g_return_val_if_fail (driver != NULL, FALSE); + g_return_val_if_fail (error == NULL || *error == NULL, FALSE); + + /* not implemented */ + if (klass->bind_driver == NULL) { + g_set_error_literal (error, + FWUPD_ERROR, + FWUPD_ERROR_NOT_SUPPORTED, + "not supported"); + return FALSE; + } + + /* subclass */ + return klass->bind_driver (self, subsystem, driver, error); +} + +/** + * fu_device_unbind_driver: + * @self: A #FuDevice + * @error: A #GError, or %NULL + * + * Unbinds the driver from the device, which normally means the kernel releases + * the hardware so it can be used from userspace. + * + * If there is no driver bound then this function will return with success + * without actually doing anything. + * + * Returns: %TRUE if driver was unbound. + * + * Since: 1.5.0 + **/ +gboolean +fu_device_unbind_driver (FuDevice *self, GError **error) +{ + FuDeviceClass *klass = FU_DEVICE_GET_CLASS (self); + + g_return_val_if_fail (FU_IS_DEVICE (self), FALSE); + g_return_val_if_fail (error == NULL || *error == NULL, FALSE); + + /* not implemented */ + if (klass->unbind_driver == NULL) { + g_set_error_literal (error, + FWUPD_ERROR, + FWUPD_ERROR_NOT_SUPPORTED, + "not supported"); + return FALSE; + } + + /* subclass */ + return klass->unbind_driver (self, error); +} + /** * fu_device_incorporate: * @self: A #FuDevice diff --git a/libfwupdplugin/fu-device.h b/libfwupdplugin/fu-device.h index feb8ea2f6..2b9c3ad88 100644 --- a/libfwupdplugin/fu-device.h +++ b/libfwupdplugin/fu-device.h @@ -68,8 +68,14 @@ struct _FuDeviceClass GHashTable *metadata); void (*report_metadata_post)(FuDevice *self, GHashTable *metadata); + gboolean (*bind_driver) (FuDevice *self, + const gchar *subsystem, + const gchar *driver, + GError **error); + gboolean (*unbind_driver) (FuDevice *self, + GError **error); /*< private >*/ - gpointer padding[14]; + gpointer padding[12]; }; /** @@ -323,5 +329,11 @@ gboolean fu_device_retry (FuDevice *self, guint count, gpointer user_data, GError **error); +gboolean fu_device_bind_driver (FuDevice *self, + const gchar *subsystem, + const gchar *driver, + GError **error); +gboolean fu_device_unbind_driver (FuDevice *self, + GError **error); GHashTable *fu_device_report_metadata_pre (FuDevice *self); GHashTable *fu_device_report_metadata_post (FuDevice *self); diff --git a/libfwupdplugin/fu-udev-device.c b/libfwupdplugin/fu-udev-device.c index c801b87e2..631faa1d9 100644 --- a/libfwupdplugin/fu-udev-device.c +++ b/libfwupdplugin/fu-udev-device.c @@ -518,6 +518,120 @@ fu_udev_device_get_slot_depth (FuUdevDevice *self, const gchar *subsystem) return 0; } +#ifndef _WIN32 +static gchar * +fu_udev_device_get_bind_id (FuUdevDevice *self) +{ + FuUdevDevicePrivate *priv = GET_PRIVATE (self); + if (g_strcmp0 (fu_udev_device_get_subsystem (self), "pci") == 0) + return g_strdup (g_udev_device_get_property (priv->udev_device, "PCI_SLOT_NAME")); + if (g_strcmp0 (fu_udev_device_get_subsystem (self), "hid") == 0) + return g_strdup (g_udev_device_get_property (priv->udev_device, "HID_PHYS")); + if (g_strcmp0 (fu_udev_device_get_subsystem (self), "usb") == 0) + return g_path_get_basename (g_udev_device_get_sysfs_path (priv->udev_device)); + return NULL; +} +#endif + +static gboolean +fu_udev_device_unbind_driver (FuDevice *device, GError **error) +{ +#ifndef _WIN32 + FuUdevDevice *self = FU_UDEV_DEVICE (device); + FuUdevDevicePrivate *priv = GET_PRIVATE (self); + g_autofree gchar *bind_id = NULL; + g_autofree gchar *fn = NULL; + g_autoptr(GFile) file = NULL; + g_autoptr(GOutputStream) stream = NULL; + + /* is already unbound */ + fn = g_build_filename (g_udev_device_get_sysfs_path (priv->udev_device), + "driver", "unbind", NULL); + if (!g_file_test (fn, G_FILE_TEST_EXISTS)) + return TRUE; + + /* write bus ID to file */ + bind_id = fu_udev_device_get_bind_id (self); + if (bind_id == NULL) { + g_set_error (error, + FWUPD_ERROR, + FWUPD_ERROR_NOT_SUPPORTED, + "bind-id not set for subsystem %s", + priv->subsystem); + return FALSE; + } + file = g_file_new_for_path (fn); + stream = G_OUTPUT_STREAM (g_file_replace (file, NULL, FALSE, + G_FILE_CREATE_NONE, NULL, error)); + if (stream == NULL) + return FALSE; + return g_output_stream_write_all (stream, bind_id, strlen (bind_id), + NULL, NULL, error); +#else + g_set_error_literal (error, + FWUPD_ERROR, + FWUPD_ERROR_NOT_SUPPORTED, + "driver unbinding not supported on Windows"); + return FALSE; +#endif +} + +static gboolean +fu_udev_device_bind_driver (FuDevice *device, + const gchar *subsystem, + const gchar *driver, + GError **error) +{ +#ifndef _WIN32 + FuUdevDevice *self = FU_UDEV_DEVICE (device); + FuUdevDevicePrivate *priv = GET_PRIVATE (self); + g_autofree gchar *bind_id = NULL; + g_autofree gchar *driver_safe = g_strdup (driver); + g_autofree gchar *fn = NULL; + g_autoptr(GFile) file = NULL; + g_autoptr(GOutputStream) stream = NULL; + + /* copy the logic from modprobe */ + g_strdelimit (driver_safe, "-", '_'); + + /* driver exists */ + fn = g_strdup_printf ("/sys/module/%s/drivers/%s:%s/bind", + driver_safe, subsystem, driver_safe); + if (!g_file_test (fn, G_FILE_TEST_EXISTS)) { + g_set_error (error, + FWUPD_ERROR, + FWUPD_ERROR_NOT_SUPPORTED, + "cannot bind with %s:%s", + subsystem, driver); + return FALSE; + } + + /* write bus ID to file */ + bind_id = fu_udev_device_get_bind_id (self); + if (bind_id == NULL) { + g_set_error (error, + FWUPD_ERROR, + FWUPD_ERROR_NOT_SUPPORTED, + "bind-id not set for subsystem %s", + priv->subsystem); + return FALSE; + } + file = g_file_new_for_path (fn); + stream = G_OUTPUT_STREAM (g_file_replace (file, NULL, FALSE, + G_FILE_CREATE_NONE, NULL, error)); + if (stream == NULL) + return FALSE; + return g_output_stream_write_all (stream, bind_id, strlen (bind_id), + NULL, NULL, error); +#else + g_set_error_literal (error, + FWUPD_ERROR, + FWUPD_ERROR_NOT_SUPPORTED, + "driver binding not supported on Windows"); + return FALSE; +#endif +} + static void fu_udev_device_incorporate (FuDevice *self, FuDevice *donor) { @@ -1443,6 +1557,8 @@ fu_udev_device_class_init (FuUdevDeviceClass *klass) device_class->open = fu_udev_device_open; device_class->close = fu_udev_device_close; device_class->to_string = fu_udev_device_to_string; + device_class->bind_driver = fu_udev_device_bind_driver; + device_class->unbind_driver = fu_udev_device_unbind_driver; signals[SIGNAL_CHANGED] = g_signal_new ("changed", diff --git a/libfwupdplugin/fu-usb-device.c b/libfwupdplugin/fu-usb-device.c index 0337652b1..fc6f6ef31 100644 --- a/libfwupdplugin/fu-usb-device.c +++ b/libfwupdplugin/fu-usb-device.c @@ -570,6 +570,40 @@ fu_usb_device_incorporate (FuDevice *self, FuDevice *donor) fu_usb_device_get_dev (FU_USB_DEVICE (donor))); } +static gboolean +fu_udev_device_bind_driver (FuDevice *device, + const gchar *subsystem, + const gchar *driver, + GError **error) +{ + FuUsbDevice *self = FU_USB_DEVICE (device); + g_autoptr(GUdevDevice) dev = NULL; + g_autoptr(FuUdevDevice) udev_device = NULL; + + /* use udev for this */ + dev = fu_usb_device_find_udev_device (self, error); + if (dev == NULL) + return FALSE; + udev_device = fu_udev_device_new (dev); + return fu_device_bind_driver (FU_DEVICE (udev_device), + subsystem, driver, error); +} + +static gboolean +fu_udev_device_unbind_driver (FuDevice *device, GError **error) +{ + FuUsbDevice *self = FU_USB_DEVICE (device); + g_autoptr(GUdevDevice) dev = NULL; + g_autoptr(FuUdevDevice) udev_device = NULL; + + /* use udev for this */ + dev = fu_usb_device_find_udev_device (self, error); + if (dev == NULL) + return FALSE; + udev_device = fu_udev_device_new (dev); + return fu_device_unbind_driver (FU_DEVICE (udev_device), error); +} + /** * fu_usb_device_new: * @usb_device: A #GUsbDevice @@ -602,6 +636,8 @@ fu_usb_device_class_init (FuUsbDeviceClass *klass) device_class->close = fu_usb_device_close; device_class->probe = fu_usb_device_probe; device_class->incorporate = fu_usb_device_incorporate; + device_class->bind_driver = fu_udev_device_bind_driver; + device_class->unbind_driver = fu_udev_device_unbind_driver; pspec = g_param_spec_object ("usb-device", NULL, NULL, G_USB_TYPE_DEVICE, diff --git a/libfwupdplugin/fwupdplugin.map b/libfwupdplugin/fwupdplugin.map index 89353c287..a16c2647c 100644 --- a/libfwupdplugin/fwupdplugin.map +++ b/libfwupdplugin/fwupdplugin.map @@ -615,8 +615,10 @@ LIBFWUPDPLUGIN_1.5.0 { fu_common_cpuid; fu_common_filename_glob; fu_common_is_cpu_intel; + fu_device_bind_driver; fu_device_report_metadata_post; fu_device_report_metadata_pre; + fu_device_unbind_driver; fu_firmware_add_flag; fu_firmware_build; fu_firmware_flag_from_string; diff --git a/src/fu-tool.c b/src/fu-tool.c index 0694f3f9f..69290d895 100644 --- a/src/fu-tool.c +++ b/src/fu-tool.c @@ -1301,6 +1301,66 @@ fu_util_detach (FuUtilPrivate *priv, gchar **values, GError **error) return fu_device_detach (device, error); } +static gboolean +fu_util_unbind_driver (FuUtilPrivate *priv, gchar **values, GError **error) +{ + g_autoptr(FuDevice) device = NULL; + g_autoptr(FuDeviceLocker) locker = NULL; + + /* load engine */ + if (!fu_util_start_engine (priv, FU_ENGINE_LOAD_FLAG_NONE, error)) + return FALSE; + + /* get device */ + if (g_strv_length (values) == 1) { + device = fu_util_get_device (priv, values[0], error); + } else { + device = fu_util_prompt_for_device (priv, NULL, error); + } + if (device == NULL) + return FALSE; + + /* run vfunc */ + locker = fu_device_locker_new (device, error); + if (locker == NULL) + return FALSE; + return fu_device_unbind_driver (device, error); +} + +static gboolean +fu_util_bind_driver (FuUtilPrivate *priv, gchar **values, GError **error) +{ + g_autoptr(FuDevice) device = NULL; + g_autoptr(FuDeviceLocker) locker = NULL; + + /* load engine */ + if (!fu_util_start_engine (priv, FU_ENGINE_LOAD_FLAG_NONE, error)) + return FALSE; + + /* get device */ + if (g_strv_length (values) == 3) { + device = fu_util_get_device (priv, values[2], error); + if (device == NULL) + return FALSE; + } else if (g_strv_length (values) == 2) { + device = fu_util_prompt_for_device (priv, NULL, error); + if (device == NULL) + return FALSE; + } else { + g_set_error_literal (error, + FWUPD_ERROR, + FWUPD_ERROR_INVALID_ARGS, + "Invalid arguments"); + return FALSE; + } + + /* run vfunc */ + locker = fu_device_locker_new (device, error); + if (locker == NULL) + return FALSE; + return fu_device_bind_driver (device, values[0], values[1], error); +} + static gboolean fu_util_attach (FuUtilPrivate *priv, gchar **values, GError **error) { @@ -2376,6 +2436,18 @@ main (int argc, char *argv[]) /* TRANSLATORS: command description */ _("Detach to bootloader mode"), fu_util_detach); + fu_util_cmd_array_add (cmd_array, + "unbind-driver", + "[DEVICE-ID|GUID]", + /* TRANSLATORS: command description */ + _("Unbind current driver"), + fu_util_unbind_driver); + fu_util_cmd_array_add (cmd_array, + "bind-driver", + "subsystem driver [DEVICE-ID|GUID]", + /* TRANSLATORS: command description */ + _("Bind new kernel driver"), + fu_util_bind_driver); fu_util_cmd_array_add (cmd_array, "activate", "[DEVICE-ID|GUID]", From dd65344dded9d58ceb49564cbeab401882ed01c1 Mon Sep 17 00:00:00 2001 From: Richard Hughes Date: Tue, 22 Sep 2020 10:23:52 +0100 Subject: [PATCH 437/607] Add firmware-extract subcommand to fwupdtool --- data/bash-completion/fwupdtool.in | 1 + src/fu-tool.c | 83 +++++++++++++++++++++++++++++++ 2 files changed, 84 insertions(+) diff --git a/data/bash-completion/fwupdtool.in b/data/bash-completion/fwupdtool.in index 88f26f5ed..0f7bc748e 100644 --- a/data/bash-completion/fwupdtool.in +++ b/data/bash-completion/fwupdtool.in @@ -5,6 +5,7 @@ _fwupdtool_cmd_list=( 'esp-mount' 'esp-unmount' 'firmware-convert' + 'firmware-extract' 'firmware-parse' 'get-updates' 'get-upgrades' diff --git a/src/fu-tool.c b/src/fu-tool.c index 69290d895..7bcf4759a 100644 --- a/src/fu-tool.c +++ b/src/fu-tool.c @@ -1780,6 +1780,83 @@ fu_util_firmware_parse (FuUtilPrivate *priv, gchar **values, GError **error) return TRUE; } +static gboolean +fu_util_firmware_extract (FuUtilPrivate *priv, gchar **values, GError **error) +{ + GType gtype; + g_autofree gchar *firmware_type = NULL; + g_autofree gchar *str = NULL; + g_autoptr(FuFirmware) firmware = NULL; + g_autoptr(GBytes) blob = NULL; + g_autoptr(GPtrArray) images = NULL; + + /* check args */ + if (g_strv_length (values) == 0 || g_strv_length (values) > 2) { + g_set_error_literal (error, + FWUPD_ERROR, + FWUPD_ERROR_INVALID_ARGS, + "Invalid arguments: filename required"); + return FALSE; + } + if (g_strv_length (values) == 2) + firmware_type = g_strdup (values[1]); + + /* load file */ + blob = fu_common_get_contents_bytes (values[0], error); + if (blob == NULL) + return FALSE; + + /* load engine */ + if (!fu_engine_load (priv->engine, FU_ENGINE_LOAD_FLAG_NO_ENUMERATE, error)) + return FALSE; + + /* find the GType to use */ + if (firmware_type == NULL) + firmware_type = fu_util_prompt_for_firmware_type (priv, TRUE, error); + if (firmware_type == NULL) + return FALSE; + gtype = fu_engine_get_firmware_gtype_by_id (priv->engine, firmware_type); + if (gtype == G_TYPE_INVALID) { + g_set_error (error, + G_IO_ERROR, + G_IO_ERROR_NOT_FOUND, + "GType %s not supported", firmware_type); + return FALSE; + } + firmware = g_object_new (gtype, NULL); + if (!fu_firmware_parse (firmware, blob, priv->flags, error)) + return FALSE; + str = fu_firmware_to_string (firmware); + g_print ("%s", str); + images = fu_firmware_get_images (firmware); + for (guint i = 0; i < images->len; i++) { + FuFirmwareImage *img = g_ptr_array_index (images, i); + g_autofree gchar *fn = NULL; + g_autoptr(GBytes) blob_img = NULL; + + /* use suitable filename */ + if (fu_firmware_image_get_filename (img) != NULL) { + fn = g_strdup (fu_firmware_image_get_filename (img)); + } else if (fu_firmware_image_get_id (img) != NULL) { + fn = g_strdup_printf ("id-%s.fw", fu_firmware_image_get_id (img)); + } else if (fu_firmware_image_get_idx (img) != 0x0) { + fn = g_strdup_printf ("idx-0x%x.fw", (guint) fu_firmware_image_get_idx (img)); + } else { + fn = g_strdup_printf ("img-0x%x.fw", i); + } + /* TRANSLATORS: decompressing images from a container firmware */ + g_print ("%s : %s\n", _("Writing file:"), fn); + blob_img = fu_firmware_image_write (img, error); + if (blob_img == NULL) + return FALSE; + if (!fu_common_set_contents_bytes (fn, blob_img, error)) + return FALSE; + } + + /* success */ + return TRUE; +} + static FuFirmware * fu_util_firmware_builder_new (FuUtilPrivate *priv, GBytes *fw, GError **error) { @@ -2503,6 +2580,12 @@ main (int argc, char *argv[]) /* TRANSLATORS: command description */ _("Parse and show details about a firmware file"), fu_util_firmware_parse); + fu_util_cmd_array_add (cmd_array, + "firmware-extract", + "FILENAME [FIRMWARE-TYPE]", + /* TRANSLATORS: command description */ + _("Extract a firmware blob to images"), + fu_util_firmware_extract); fu_util_cmd_array_add (cmd_array, "get-firmware-types", NULL, From c43208f3d61bd81db01e76540e0080dbd29d8932 Mon Sep 17 00:00:00 2001 From: Richard Hughes Date: Tue, 22 Sep 2020 15:16:28 +0100 Subject: [PATCH 438/607] Add fu_firmware_image_get_offset This allows us to save the image file offset, rather than the destination address and is really useful for debugging. --- libfwupdplugin/fu-firmware-image.c | 41 ++++++++++++++++++++++++++++++ libfwupdplugin/fu-firmware-image.h | 3 +++ libfwupdplugin/fwupdplugin.map | 2 ++ 3 files changed, 46 insertions(+) diff --git a/libfwupdplugin/fu-firmware-image.c b/libfwupdplugin/fu-firmware-image.c index bfef23a28..7be3126e4 100644 --- a/libfwupdplugin/fu-firmware-image.c +++ b/libfwupdplugin/fu-firmware-image.c @@ -22,6 +22,7 @@ typedef struct { gchar *id; GBytes *bytes; guint64 addr; + guint64 offset; guint64 idx; gchar *version; gchar *filename; @@ -171,6 +172,41 @@ fu_firmware_image_get_addr (FuFirmwareImage *self) return priv->addr; } +/** + * fu_firmware_image_set_offset: + * @self: a #FuPlugin + * @offset: integer + * + * Sets the base offset of the image. + * + * Since: 1.5.0 + **/ +void +fu_firmware_image_set_offset (FuFirmwareImage *self, guint64 offset) +{ + FuFirmwareImagePrivate *priv = GET_PRIVATE (self); + g_return_if_fail (FU_IS_FIRMWARE_IMAGE (self)); + priv->offset = offset; +} + +/** + * fu_firmware_image_get_offset: + * @self: a #FuPlugin + * + * Gets the base offset of the image. + * + * Returns: integer + * + * Since: 1.5.0 + **/ +guint64 +fu_firmware_image_get_offset (FuFirmwareImage *self) +{ + FuFirmwareImagePrivate *priv = GET_PRIVATE (self); + g_return_val_if_fail (FU_IS_FIRMWARE_IMAGE (self), G_MAXUINT64); + return priv->offset; +} + /** * fu_firmware_image_set_idx: * @self: a #FuPlugin @@ -293,6 +329,9 @@ fu_firmware_image_build (FuFirmwareImage *self, XbNode *n, GError **error) tmpval = xb_node_query_text_as_uint (n, "addr", NULL); if (tmpval != G_MAXUINT64) fu_firmware_image_set_addr (self, tmpval); + tmpval = xb_node_query_text_as_uint (n, "offset", NULL); + if (tmpval != G_MAXUINT64) + fu_firmware_image_set_offset (self, tmpval); tmp = xb_node_query_text (n, "filename", NULL); if (tmp != NULL) { g_autoptr(GBytes) blob = NULL; @@ -425,6 +464,8 @@ fu_firmware_image_add_string (FuFirmwareImage *self, guint idt, GString *str) fu_common_string_append_kx (str, idt, "Index", priv->idx); if (priv->addr != 0x0) fu_common_string_append_kx (str, idt, "Address", priv->addr); + if (priv->offset != 0x0) + fu_common_string_append_kx (str, idt, "Offset", priv->offset); if (priv->version != NULL) fu_common_string_append_kv (str, idt, "Version", priv->version); if (priv->filename != NULL) diff --git a/libfwupdplugin/fu-firmware-image.h b/libfwupdplugin/fu-firmware-image.h index 7310a3b8e..195ea49f9 100644 --- a/libfwupdplugin/fu-firmware-image.h +++ b/libfwupdplugin/fu-firmware-image.h @@ -48,6 +48,9 @@ void fu_firmware_image_set_id (FuFirmwareImage *self, guint64 fu_firmware_image_get_addr (FuFirmwareImage *self); void fu_firmware_image_set_addr (FuFirmwareImage *self, guint64 addr); +guint64 fu_firmware_image_get_offset (FuFirmwareImage *self); +void fu_firmware_image_set_offset (FuFirmwareImage *self, + guint64 offset); guint64 fu_firmware_image_get_idx (FuFirmwareImage *self); void fu_firmware_image_set_idx (FuFirmwareImage *self, guint64 idx); diff --git a/libfwupdplugin/fwupdplugin.map b/libfwupdplugin/fwupdplugin.map index a16c2647c..451d367a4 100644 --- a/libfwupdplugin/fwupdplugin.map +++ b/libfwupdplugin/fwupdplugin.map @@ -626,8 +626,10 @@ LIBFWUPDPLUGIN_1.5.0 { fu_firmware_has_flag; fu_firmware_image_build; fu_firmware_image_get_filename; + fu_firmware_image_get_offset; fu_firmware_image_parse; fu_firmware_image_set_filename; + fu_firmware_image_set_offset; fu_fmap_firmware_get_type; fu_fmap_firmware_new; fu_plugin_runner_add_security_attrs; From 88dd7c44022ca8c270b4284c3f3d276fd97d1bb8 Mon Sep 17 00:00:00 2001 From: Richard Hughes Date: Tue, 22 Sep 2020 16:54:40 +0100 Subject: [PATCH 439/607] Add fu_firmware_image_get_bytes Without a 'getter' it's impossible to obtain the raw data for the image extractor or in a image subclass that wants to add a header or CRC. --- libfwupdplugin/fu-firmware-image.c | 23 +++++++++++++++++++++++ libfwupdplugin/fu-firmware-image.h | 1 + libfwupdplugin/fwupdplugin.map | 1 + src/fu-tool.c | 8 +++++--- 4 files changed, 30 insertions(+), 3 deletions(-) diff --git a/libfwupdplugin/fu-firmware-image.c b/libfwupdplugin/fu-firmware-image.c index 7be3126e4..d6e332748 100644 --- a/libfwupdplugin/fu-firmware-image.c +++ b/libfwupdplugin/fu-firmware-image.c @@ -261,6 +261,29 @@ fu_firmware_image_set_bytes (FuFirmwareImage *self, GBytes *bytes) priv->bytes = g_bytes_ref (bytes); } +/** + * fu_firmware_image_get_bytes: + * @self: a #FuPlugin + * + * Gets the data set using fu_firmware_image_set_bytes(). + * + * This should only really be used by objects subclassing #FuFirmwareImage as + * images are normally exported to a file using fu_firmware_image_write(). + * + * Returns: (transfer full): a #GBytes of the data, or %NULL if the bytes is not set + * + * Since: 1.5.0 + **/ +GBytes * +fu_firmware_image_get_bytes (FuFirmwareImage *self) +{ + FuFirmwareImagePrivate *priv = GET_PRIVATE (self); + g_return_val_if_fail (FU_IS_FIRMWARE_IMAGE (self), FALSE); + if (priv->bytes == NULL) + return NULL; + return g_bytes_ref (priv->bytes); +} + /** * fu_firmware_image_parse: * @self: A #FuFirmwareImage diff --git a/libfwupdplugin/fu-firmware-image.h b/libfwupdplugin/fu-firmware-image.h index 195ea49f9..b33e8608b 100644 --- a/libfwupdplugin/fu-firmware-image.h +++ b/libfwupdplugin/fu-firmware-image.h @@ -54,6 +54,7 @@ void fu_firmware_image_set_offset (FuFirmwareImage *self, guint64 fu_firmware_image_get_idx (FuFirmwareImage *self); void fu_firmware_image_set_idx (FuFirmwareImage *self, guint64 idx); +GBytes *fu_firmware_image_get_bytes (FuFirmwareImage *self); void fu_firmware_image_set_bytes (FuFirmwareImage *self, GBytes *bytes); gboolean fu_firmware_image_parse (FuFirmwareImage *self, diff --git a/libfwupdplugin/fwupdplugin.map b/libfwupdplugin/fwupdplugin.map index 451d367a4..94553fe66 100644 --- a/libfwupdplugin/fwupdplugin.map +++ b/libfwupdplugin/fwupdplugin.map @@ -625,6 +625,7 @@ LIBFWUPDPLUGIN_1.5.0 { fu_firmware_flag_to_string; fu_firmware_has_flag; fu_firmware_image_build; + fu_firmware_image_get_bytes; fu_firmware_image_get_filename; fu_firmware_image_get_offset; fu_firmware_image_parse; diff --git a/src/fu-tool.c b/src/fu-tool.c index 7bcf4759a..7b84bf4eb 100644 --- a/src/fu-tool.c +++ b/src/fu-tool.c @@ -1834,6 +1834,11 @@ fu_util_firmware_extract (FuUtilPrivate *priv, gchar **values, GError **error) g_autofree gchar *fn = NULL; g_autoptr(GBytes) blob_img = NULL; + /* get raw image without generated header, footer or crc */ + blob_img = fu_firmware_image_get_bytes (img); + if (blob_img == NULL || g_bytes_get_size (blob_img) == 0) + continue; + /* use suitable filename */ if (fu_firmware_image_get_filename (img) != NULL) { fn = g_strdup (fu_firmware_image_get_filename (img)); @@ -1846,9 +1851,6 @@ fu_util_firmware_extract (FuUtilPrivate *priv, gchar **values, GError **error) } /* TRANSLATORS: decompressing images from a container firmware */ g_print ("%s : %s\n", _("Writing file:"), fn); - blob_img = fu_firmware_image_write (img, error); - if (blob_img == NULL) - return FALSE; if (!fu_common_set_contents_bytes (fn, blob_img, error)) return FALSE; } From 9e96eb67c9f7707cb5b630faad4830e8ee27f7be Mon Sep 17 00:00:00 2001 From: Richard Hughes Date: Tue, 22 Sep 2020 18:10:58 +0100 Subject: [PATCH 440/607] Allow building firmware with subclassed FuFirmwareImages --- libfwupdplugin/fu-firmware.c | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/libfwupdplugin/fu-firmware.c b/libfwupdplugin/fu-firmware.c index 5e5b60bab..d115f8f84 100644 --- a/libfwupdplugin/fu-firmware.c +++ b/libfwupdplugin/fu-firmware.c @@ -272,7 +272,21 @@ fu_firmware_build (FuFirmware *self, XbNode *n, GError **error) if (xb_images != NULL) { for (guint i = 0; i < xb_images->len; i++) { XbNode *xb_image = g_ptr_array_index (xb_images, i); - g_autoptr(FuFirmwareImage) img = fu_firmware_image_new (NULL); + g_autoptr(FuFirmwareImage) img = NULL; + tmp = xb_node_get_attr (xb_image, "gtype"); + if (tmp != NULL) { + GType gtype = g_type_from_name (tmp); + if (gtype == G_TYPE_INVALID) { + g_set_error (error, + G_IO_ERROR, + G_IO_ERROR_NOT_FOUND, + "GType %s not registered", tmp); + return FALSE; + } + img = g_object_new (gtype, NULL); + } else { + img = fu_firmware_image_new (NULL); + } if (!fu_firmware_image_build (img, xb_image, error)) return FALSE; fu_firmware_add_image (self, img); From d0b205887a7af763d294837920e122e2993a6d18 Mon Sep 17 00:00:00 2001 From: Richard Hughes Date: Tue, 22 Sep 2020 19:05:28 +0100 Subject: [PATCH 441/607] Allow subclassing FuFirmwareImage->build() --- libfwupdplugin/fu-firmware-image.c | 7 +++++++ libfwupdplugin/fu-firmware-image.h | 5 ++++- 2 files changed, 11 insertions(+), 1 deletion(-) diff --git a/libfwupdplugin/fu-firmware-image.c b/libfwupdplugin/fu-firmware-image.c index d6e332748..7953e7112 100644 --- a/libfwupdplugin/fu-firmware-image.c +++ b/libfwupdplugin/fu-firmware-image.c @@ -333,6 +333,7 @@ fu_firmware_image_parse (FuFirmwareImage *self, gboolean fu_firmware_image_build (FuFirmwareImage *self, XbNode *n, GError **error) { + FuFirmwareImageClass *klass = FU_FIRMWARE_IMAGE_GET_CLASS (self); guint64 tmpval; const gchar *tmp; @@ -374,6 +375,12 @@ fu_firmware_image_build (FuFirmwareImage *self, XbNode *n, GError **error) fu_firmware_image_set_bytes (self, blob); } + /* subclassed */ + if (klass->build != NULL) { + if (!klass->build (self, n, error)) + return FALSE; + } + /* success */ return TRUE; } diff --git a/libfwupdplugin/fu-firmware-image.h b/libfwupdplugin/fu-firmware-image.h index b33e8608b..ebbae446d 100644 --- a/libfwupdplugin/fu-firmware-image.h +++ b/libfwupdplugin/fu-firmware-image.h @@ -25,8 +25,11 @@ struct _FuFirmwareImageClass GString *str); GBytes *(*write) (FuFirmwareImage *self, GError **error); + gboolean (*build) (FuFirmwareImage *self, + XbNode *n, + GError **error); /*< private >*/ - gpointer padding[28]; + gpointer padding[27]; }; #define FU_FIRMWARE_IMAGE_ID_PAYLOAD "payload" From 0924c93422cf306163226288e52cf274259ac32b Mon Sep 17 00:00:00 2001 From: Richard Hughes Date: Tue, 22 Sep 2020 19:07:05 +0100 Subject: [PATCH 442/607] Do not use firmware-convert to build firmware Copying the images from the src to the destination meant we could never set properties on the new FuFirmware instance or subclass. --- data/bash-completion/fwupdtool.in | 1 + src/fu-tool.c | 116 ++++++++++++++++++++---------- 2 files changed, 80 insertions(+), 37 deletions(-) diff --git a/data/bash-completion/fwupdtool.in b/data/bash-completion/fwupdtool.in index 0f7bc748e..2b3ed4687 100644 --- a/data/bash-completion/fwupdtool.in +++ b/data/bash-completion/fwupdtool.in @@ -4,6 +4,7 @@ _fwupdtool_cmd_list=( 'esp-list' 'esp-mount' 'esp-unmount' + 'firmware-build' 'firmware-convert' 'firmware-extract' 'firmware-parse' diff --git a/src/fu-tool.c b/src/fu-tool.c index 7b84bf4eb..dd2c44e5b 100644 --- a/src/fu-tool.c +++ b/src/fu-tool.c @@ -1699,16 +1699,12 @@ fu_util_get_firmware_types (FuUtilPrivate *priv, gchar **values, GError **error) } static gchar * -fu_util_prompt_for_firmware_type (FuUtilPrivate *priv, gboolean add_builder, GError **error) +fu_util_prompt_for_firmware_type (FuUtilPrivate *priv, GError **error) { g_autoptr(GPtrArray) firmware_types = NULL; guint idx; firmware_types = fu_engine_get_firmware_gtype_ids (priv->engine); - /* add fake entry */ - if (add_builder) - g_ptr_array_add (firmware_types, g_strdup ("builder")); - /* TRANSLATORS: get interactive prompt */ g_print ("%s\n", _("Choose a firmware type:")); /* TRANSLATORS: this is to abort the interactive prompt */ @@ -1761,7 +1757,7 @@ fu_util_firmware_parse (FuUtilPrivate *priv, gchar **values, GError **error) /* find the GType to use */ if (firmware_type == NULL) - firmware_type = fu_util_prompt_for_firmware_type (priv, TRUE, error); + firmware_type = fu_util_prompt_for_firmware_type (priv, error); if (firmware_type == NULL) return FALSE; gtype = fu_engine_get_firmware_gtype_by_id (priv->engine, firmware_type); @@ -1812,7 +1808,7 @@ fu_util_firmware_extract (FuUtilPrivate *priv, gchar **values, GError **error) /* find the GType to use */ if (firmware_type == NULL) - firmware_type = fu_util_prompt_for_firmware_type (priv, TRUE, error); + firmware_type = fu_util_prompt_for_firmware_type (priv, error); if (firmware_type == NULL) return FALSE; gtype = fu_engine_get_firmware_gtype_by_id (priv->engine, firmware_type); @@ -1859,27 +1855,50 @@ fu_util_firmware_extract (FuUtilPrivate *priv, gchar **values, GError **error) return TRUE; } -static FuFirmware * -fu_util_firmware_builder_new (FuUtilPrivate *priv, GBytes *fw, GError **error) +static gboolean +fu_util_firmware_build (FuUtilPrivate *priv, gchar **values, GError **error) { + GType gtype = FU_TYPE_FIRMWARE; const gchar *tmp; + g_autofree gchar *str = NULL; g_autoptr(FuFirmware) firmware = NULL; + g_autoptr(FuFirmware) firmware_dst = NULL; + g_autoptr(GBytes) blob_dst = NULL; + g_autoptr(GBytes) blob_src = NULL; g_autoptr(XbBuilder) builder = xb_builder_new (); g_autoptr(XbBuilderSource) source = xb_builder_source_new (); g_autoptr(XbNode) n = NULL; g_autoptr(XbSilo) silo = NULL; + /* check args */ + if (g_strv_length (values) != 2) { + g_set_error_literal (error, + FWUPD_ERROR, + FWUPD_ERROR_INVALID_ARGS, + "Invalid arguments: filename required"); + return FALSE; + } + + /* load file */ + blob_src = fu_common_get_contents_bytes (values[0], error); + if (blob_src == NULL) + return FALSE; + + /* load engine */ + if (!fu_engine_load (priv->engine, FU_ENGINE_LOAD_FLAG_NO_ENUMERATE, error)) + return FALSE; + /* parse XML */ - if (!xb_builder_source_load_bytes (source, fw, + if (!xb_builder_source_load_bytes (source, blob_src, XB_BUILDER_SOURCE_FLAG_NONE, error)) { g_prefix_error (error, "could not parse XML: "); - return NULL; + return FALSE; } xb_builder_import_source (builder, source); silo = xb_builder_compile (builder, XB_BUILDER_COMPILE_FLAG_NONE, NULL, error); if (silo == NULL) - return NULL; + return FALSE; /* create FuFirmware of specific GType */ n = xb_silo_query_first (silo, "firmware", error); @@ -1887,23 +1906,46 @@ fu_util_firmware_builder_new (FuUtilPrivate *priv, GBytes *fw, GError **error) return FALSE; tmp = xb_node_get_attr (n, "gtype"); if (tmp != NULL) { - GType gtype = fu_engine_get_firmware_gtype_by_id (priv->engine, tmp); + gtype = g_type_from_name (tmp); + if (gtype == G_TYPE_INVALID) { + g_set_error (error, + G_IO_ERROR, + G_IO_ERROR_NOT_FOUND, + "GType %s not registered", tmp); + return FALSE; + } + } + tmp = xb_node_get_attr (n, "id"); + if (tmp != NULL) { + gtype = fu_engine_get_firmware_gtype_by_id (priv->engine, tmp); if (gtype == G_TYPE_INVALID) { g_set_error (error, G_IO_ERROR, G_IO_ERROR_NOT_FOUND, "GType %s not supported", tmp); - return NULL; + return FALSE; } - firmware = g_object_new (gtype, NULL); - } else { - firmware = fu_firmware_new (); } + firmware = g_object_new (gtype, NULL); if (!fu_firmware_build (firmware, n, error)) - return NULL; + return FALSE; + + /* write new file */ + blob_dst = fu_firmware_write (firmware, error); + if (blob_dst == NULL) + return FALSE; + if (!fu_common_set_contents_bytes (values[1], blob_dst, error)) + return FALSE; + + /* show what we wrote */ + firmware_dst = g_object_new (gtype, NULL); + if (!fu_firmware_parse (firmware_dst, blob_dst, priv->flags, error)) + return FALSE; + str = fu_firmware_to_string (firmware_dst); + g_print ("%s", str); /* success */ - return g_steal_pointer (&firmware); + return TRUE; } static gboolean @@ -1946,30 +1988,24 @@ fu_util_firmware_convert (FuUtilPrivate *priv, gchar **values, GError **error) /* find the GType to use */ if (firmware_type_src == NULL) - firmware_type_src = fu_util_prompt_for_firmware_type (priv, TRUE, error); + firmware_type_src = fu_util_prompt_for_firmware_type (priv, error); if (firmware_type_src == NULL) return FALSE; if (firmware_type_dst == NULL) - firmware_type_dst = fu_util_prompt_for_firmware_type (priv, FALSE, error); + firmware_type_dst = fu_util_prompt_for_firmware_type (priv, error); if (firmware_type_dst == NULL) return FALSE; - if (g_strcmp0 (firmware_type_src, "builder") == 0) { - firmware_src = fu_util_firmware_builder_new (priv, blob_src, error); - if (firmware_src == NULL) - return FALSE; - } else { - gtype_src = fu_engine_get_firmware_gtype_by_id (priv->engine, firmware_type_src); - if (gtype_src == G_TYPE_INVALID) { - g_set_error (error, - G_IO_ERROR, - G_IO_ERROR_NOT_FOUND, - "GType %s not supported", firmware_type_src); - return FALSE; - } - firmware_src = g_object_new (gtype_src, NULL); - if (!fu_firmware_parse (firmware_src, blob_src, priv->flags, error)) - return FALSE; + gtype_src = fu_engine_get_firmware_gtype_by_id (priv->engine, firmware_type_src); + if (gtype_src == G_TYPE_INVALID) { + g_set_error (error, + G_IO_ERROR, + G_IO_ERROR_NOT_FOUND, + "GType %s not supported", firmware_type_src); + return FALSE; } + firmware_src = g_object_new (gtype_src, NULL); + if (!fu_firmware_parse (firmware_src, blob_src, priv->flags, error)) + return FALSE; gtype_dst = fu_engine_get_firmware_gtype_by_id (priv->engine, firmware_type_dst); if (gtype_dst == G_TYPE_INVALID) { g_set_error (error, @@ -2576,6 +2612,12 @@ main (int argc, char *argv[]) /* TRANSLATORS: command description */ _("Convert a firmware file"), fu_util_firmware_convert); + fu_util_cmd_array_add (cmd_array, + "firmware-build", + "BUILDER-XML FILENAME-DST", + /* TRANSLATORS: command description */ + _("Build a firmware file"), + fu_util_firmware_build); fu_util_cmd_array_add (cmd_array, "firmware-parse", "FILENAME [FIRMWARE-TYPE]", From aff64d3e756d0f3fc975a1eb56d07c3db921b53c Mon Sep 17 00:00:00 2001 From: Richard Hughes Date: Tue, 22 Sep 2020 19:46:29 +0100 Subject: [PATCH 443/607] trivial: Allow specifying zero-sized data sections This can be done using '' to specify a zero-sized image. --- libfwupdplugin/fu-firmware-image.c | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/libfwupdplugin/fu-firmware-image.c b/libfwupdplugin/fu-firmware-image.c index 7953e7112..f5d562239 100644 --- a/libfwupdplugin/fu-firmware-image.c +++ b/libfwupdplugin/fu-firmware-image.c @@ -336,6 +336,7 @@ fu_firmware_image_build (FuFirmwareImage *self, XbNode *n, GError **error) FuFirmwareImageClass *klass = FU_FIRMWARE_IMAGE_GET_CLASS (self); guint64 tmpval; const gchar *tmp; + g_autoptr(XbNode) data = NULL; g_return_val_if_fail (FU_IS_FIRMWARE_IMAGE (self), FALSE); g_return_val_if_fail (XB_IS_NODE (n), FALSE); @@ -365,14 +366,18 @@ fu_firmware_image_build (FuFirmwareImage *self, XbNode *n, GError **error) fu_firmware_image_set_bytes (self, blob); fu_firmware_image_set_filename (self, tmp); } - tmp = xb_node_query_text (n, "data", NULL); - if (tmp != NULL) { + data = xb_node_query_first (n, "data", NULL); + if (data != NULL && xb_node_get_text (data) != NULL) { gsize bufsz = 0; g_autofree guchar *buf = NULL; g_autoptr(GBytes) blob = NULL; - buf = g_base64_decode (tmp, &bufsz); + buf = g_base64_decode (xb_node_get_text (data), &bufsz); blob = g_bytes_new (buf, bufsz); fu_firmware_image_set_bytes (self, blob); + } else if (data != NULL) { + g_autoptr(GBytes) blob = NULL; + blob = g_bytes_new (NULL, 0); + fu_firmware_image_set_bytes (self, blob); } /* subclassed */ From 88d80119d1b42afc016058184443a11b88b6c903 Mon Sep 17 00:00:00 2001 From: Richard Hughes Date: Wed, 23 Sep 2020 12:44:52 +0100 Subject: [PATCH 444/607] trivial: Document the firmware build XML format --- libfwupdplugin/fu-firmware.c | 40 +++++++++++++++++++++++++++++++++++- 1 file changed, 39 insertions(+), 1 deletion(-) diff --git a/libfwupdplugin/fu-firmware.c b/libfwupdplugin/fu-firmware.c index d115f8f84..9bce7fc64 100644 --- a/libfwupdplugin/fu-firmware.c +++ b/libfwupdplugin/fu-firmware.c @@ -245,7 +245,45 @@ fu_firmware_parse (FuFirmware *self, GBytes *fw, FwupdInstallFlags flags, GError * @n: A #XbNode * @error: A #GError, or %NULL * - * Builds a firmware from an XML manifest. + * Builds a firmware from an XML manifest. The manifest would typically have the + * following form: + * + * |[ + * + * + * 1.2.3 + * + * 7.8.9 + * stage1 + * 0x01 + * stage1.bin + * + * + * stage2 + * + * + * + * ape + * 0x7 + * aGVsbG8gd29ybGQ= + * + * + * ]| + * + * This would be used in a build-system to merge images from generated files: + * `fwupdtool firmware-build fw.builder.xml test.fw` + * + * Static binary content can be specified in the `/` sections and + * is encoded as base64 text if not empty. + * + * Additionally, extra nodes can be included under `` and `` + * which can be parsed by the subclassed objects. You should verify the + * subclassed object `FuFirmwareImage->build` vfunc for the specific additional + * options supported. + * + * Plugins should manually g_type_ensure() subclassed image objects if not + * constructed as part of the plugin fu_plugin_init() or fu_plugin_setup() + * functions. * * Returns: %TRUE for success * From da17ff4888e0296491e54711f64b904f5f3a2a20 Mon Sep 17 00:00:00 2001 From: Richard Hughes Date: Thu, 24 Sep 2020 08:07:31 +0100 Subject: [PATCH 445/607] trivial: Add another Toshiba OUI quirk Fixes https://github.com/fwupd/fwupd/issues/2413 --- plugins/ata/ata.quirk | 3 +++ 1 file changed, 3 insertions(+) diff --git a/plugins/ata/ata.quirk b/plugins/ata/ata.quirk index 21a95cc0f..211c7f84d 100644 --- a/plugins/ata/ata.quirk +++ b/plugins/ata/ata.quirk @@ -74,3 +74,6 @@ VendorId = ATA:0x1CC1 Vendor = SanDisk VendorId = ATA:0x15B7 +[DeviceInstanceId=OUI\e83a97] +Vendor = Toshiba +VendorId = ATA:0x1179 From 6b5926ca593f79c58301c03f11276eff6cda3255 Mon Sep 17 00:00:00 2001 From: Richard Hughes Date: Thu, 24 Sep 2020 09:19:15 +0100 Subject: [PATCH 446/607] trivial: Fix two warnings in the win32 build --- libfwupdplugin/fu-efivar.c | 10 ++-------- libfwupdplugin/fu-udev-device.c | 4 ++-- 2 files changed, 4 insertions(+), 10 deletions(-) diff --git a/libfwupdplugin/fu-efivar.c b/libfwupdplugin/fu-efivar.c index 0bde17fd6..e976ee202 100644 --- a/libfwupdplugin/fu-efivar.c +++ b/libfwupdplugin/fu-efivar.c @@ -69,13 +69,13 @@ fu_efivar_supported (GError **error) #endif } +#ifndef _WIN32 static gboolean fu_efivar_set_immutable_fd (int fd, gboolean value, gboolean *value_old, GError **error) { -#ifndef _WIN32 guint flags; gboolean is_immutable; int rc; @@ -124,14 +124,8 @@ fu_efivar_set_immutable_fd (int fd, return FALSE; } return TRUE; -#else - g_set_error_literal (error, - FWUPD_ERROR, - FWUPD_ERROR_NOT_SUPPORTED, - "efivarfs not currently supported on Windows"); - return FALSE; -#endif } +#endif static gboolean fu_efivar_set_immutable (const gchar *fn, diff --git a/libfwupdplugin/fu-udev-device.c b/libfwupdplugin/fu-udev-device.c index 631faa1d9..c66672ba6 100644 --- a/libfwupdplugin/fu-udev-device.c +++ b/libfwupdplugin/fu-udev-device.c @@ -195,10 +195,10 @@ fu_udev_device_set_device_file (FuUdevDevice *self, const gchar *device_file) g_object_notify (G_OBJECT (self), "device-file"); } +#ifdef HAVE_GUDEV static const gchar * fu_udev_device_get_vendor_fallback (GUdevDevice *udev_device) { -#ifdef HAVE_GUDEV const gchar *tmp; tmp = g_udev_device_get_property (udev_device, "ID_VENDOR_FROM_DATABASE"); if (tmp != NULL) @@ -206,9 +206,9 @@ fu_udev_device_get_vendor_fallback (GUdevDevice *udev_device) tmp = g_udev_device_get_property (udev_device, "ID_VENDOR"); if (tmp != NULL) return tmp; -#endif return NULL; } +#endif #ifdef HAVE_GUDEV static gboolean From 6f4f1caca47d401ad37815161e4e2313a68d3254 Mon Sep 17 00:00:00 2001 From: Richard Hughes Date: Thu, 24 Sep 2020 10:43:26 +0100 Subject: [PATCH 447/607] trivial: Fix some typos spotted by codespell --- libfwupd/fwupd-enums.h | 4 ++-- plugins/emmc/fu-emmc-device.c | 2 +- plugins/pci-mei/fu-plugin-pci-mei.c | 2 +- plugins/tpm-eventlog/fu-tpm-eventlog.c | 2 +- src/fu-engine.c | 2 +- 5 files changed, 6 insertions(+), 6 deletions(-) diff --git a/libfwupd/fwupd-enums.h b/libfwupd/fwupd-enums.h index 84cd853da..c402a88af 100644 --- a/libfwupd/fwupd-enums.h +++ b/libfwupd/fwupd-enums.h @@ -221,7 +221,7 @@ typedef enum { * @FWUPD_INSTALL_FLAG_FORCE: Force the update even if not a good idea * @FWUPD_INSTALL_FLAG_NO_HISTORY: Do not write to the history database * - * Flags to set when performing the firwmare update or install. + * Flags to set when performing the firmware update or install. **/ typedef enum { FWUPD_INSTALL_FLAG_NONE = 0, /* Since: 0.7.0 */ @@ -240,7 +240,7 @@ typedef enum { * @FWUPD_SELF_SIGN_FLAG_ADD_TIMESTAMP: Add the timestamp to the detached signature * @FWUPD_SELF_SIGN_FLAG_ADD_CERT: Add the certificate to the detached signature * - * Flags to set when performing the firwmare update or install. + * Flags to set when performing the firmware update or install. **/ typedef enum { FWUPD_SELF_SIGN_FLAG_NONE = 0, /* Since: 1.2.6 */ diff --git a/plugins/emmc/fu-emmc-device.c b/plugins/emmc/fu-emmc-device.c index 301f55f05..776645d06 100644 --- a/plugins/emmc/fu-emmc-device.c +++ b/plugins/emmc/fu-emmc-device.c @@ -214,7 +214,7 @@ fu_emmc_device_probe (FuUdevDevice *device, GError **error) if (flag == 0) fu_device_add_flag (FU_DEVICE (device), FWUPD_DEVICE_FLAG_INTERNAL); - /* firwmare version */ + /* firmware version */ tmp = g_udev_device_get_sysfs_attr (udev_parent, "fwrev"); if (tmp != NULL) { fu_device_set_version_format (FU_DEVICE (device), FWUPD_VERSION_FORMAT_NUMBER); diff --git a/plugins/pci-mei/fu-plugin-pci-mei.c b/plugins/pci-mei/fu-plugin-pci-mei.c index e52d03a2c..6e5517d02 100644 --- a/plugins/pci-mei/fu-plugin-pci-mei.c +++ b/plugins/pci-mei/fu-plugin-pci-mei.c @@ -370,7 +370,7 @@ fu_plugin_add_security_attrs_bootguard_policy (FuPlugin *plugin, FuSecurityAttrs fwupd_security_attr_set_url (attr, "#org.fwupd.hsi.Kernel.IntelBootguard"); fu_security_attrs_append (attrs, attr); - /* policy must be to immediatly shutdown */ + /* policy must be to immediately shutdown */ if (priv->hfsts6.fields.error_enforce_policy != ME_HFS_ENFORCEMENT_POLICY_SHUTDOWN_NOW) { fwupd_security_attr_set_result (attr, FWUPD_SECURITY_ATTR_RESULT_NOT_VALID); return; diff --git a/plugins/tpm-eventlog/fu-tpm-eventlog.c b/plugins/tpm-eventlog/fu-tpm-eventlog.c index dce7f09d9..95f88679b 100644 --- a/plugins/tpm-eventlog/fu-tpm-eventlog.c +++ b/plugins/tpm-eventlog/fu-tpm-eventlog.c @@ -121,7 +121,7 @@ main (int argc, char *argv[]) g_option_context_add_main_entries (context, options, NULL); g_option_context_set_description (context, "This tool will read and parse the TPM event log " - "from the system firwmare."); + "from the system firmware."); if (!g_option_context_parse (context, &argc, &argv, &error)) { /* TRANSLATORS: the user didn't read the man page */ g_print ("%s: %s\n", _("Failed to parse arguments"), diff --git a/src/fu-engine.c b/src/fu-engine.c index fee5f92ab..65093ba12 100644 --- a/src/fu-engine.c +++ b/src/fu-engine.c @@ -837,7 +837,7 @@ fu_engine_verify_from_local_metadata (FuEngine *self, if (release == NULL) return NULL; - /* silo has to have same lifecyle as node */ + /* silo has to have same lifecycle as node */ g_object_set_data_full (G_OBJECT (release), "XbSilo", g_steal_pointer (&silo), (GDestroyNotify) g_object_unref); From fbd8b5d3251ed44e749450cf77f40f9e9aec3a6b Mon Sep 17 00:00:00 2001 From: Richard Hughes Date: Thu, 24 Sep 2020 11:48:59 +0100 Subject: [PATCH 448/607] Add fu_device_dump_firmware() Conceptually we were trying to stuff subtly different actions into one vfunc: * Read firmware from the device to update the verification checksums * Read a firmware blob from the device for debugging For the first action we might want to mask out the sections of the flash with serial numbers (so the verification hashes match the ones published on the LVFS) and for the second we want just a raw ROM file from the hardware with no pre-processing that we can compare against an external SPI dumper. Split out ->dump_firmware to get the raw blob, and allow plugins to also implement ->read_firmware() if they have to mask out specific offsets or remove specific images from the FuFirmware container. In the common case when masking is not required, fall back to using a 'binary' FuFirmware automatically to make most plugins simpler. --- data/bash-completion/fwupdtool.in | 4 +- libfwupdplugin/fu-device.c | 56 +++++++++++++-- libfwupdplugin/fu-device.h | 6 +- libfwupdplugin/fwupdplugin.map | 1 + plugins/altos/fu-altos-device.c | 10 ++- plugins/csr/fu-csr-device.c | 8 +-- plugins/dfu/dfu-device.c | 10 ++- plugins/optionrom/fu-optionrom-device.c | 27 ++++++-- plugins/optionrom/fu-rom.c | 88 ++++++++++++------------ plugins/optionrom/fu-rom.h | 6 +- plugins/superio/fu-superio-it89-device.c | 19 +++-- plugins/vli/fu-vli-pd-device.c | 18 ++--- plugins/vli/fu-vli-pd-parade-device.c | 8 +-- plugins/vli/fu-vli-usbhub-device.c | 18 ++--- plugins/vli/fu-vli-usbhub-pd-device.c | 20 +++--- src/fu-engine.c | 10 +-- src/fu-engine.h | 2 +- src/fu-tool.c | 8 +-- 18 files changed, 188 insertions(+), 131 deletions(-) diff --git a/data/bash-completion/fwupdtool.in b/data/bash-completion/fwupdtool.in index 2b3ed4687..6b46f51b4 100644 --- a/data/bash-completion/fwupdtool.in +++ b/data/bash-completion/fwupdtool.in @@ -30,7 +30,7 @@ _fwupdtool_cmd_list=( 'smbios-dump' 'attach' 'detach' - 'firmware-read' + 'firmware-dump' 'refresh' 'verify-update' 'watch' @@ -100,7 +100,7 @@ _fwupdtool() esac case $command in - get-details|install|install-blob|firmware-read) + get-details|install|install-blob|firmware-dump) #find files if [[ "$prev" = "$command" ]]; then _filedir diff --git a/libfwupdplugin/fu-device.c b/libfwupdplugin/fu-device.c index 1e0698c90..645f07b94 100644 --- a/libfwupdplugin/fu-device.c +++ b/libfwupdplugin/fu-device.c @@ -2515,6 +2515,11 @@ fu_device_prepare_firmware (FuDevice *self, * @error: A #GError * * Reads firmware from the device by calling a plugin-specific vfunc. + * The device subclass should try to ensure the firmware does not contain any + * serial numbers or user-configuration values and can be used to calculate the + * device checksum. + * + * The return value can be converted to a blob of memory using fu_firmware_write(). * * Returns: (transfer full): A #FuFirmware, or %NULL for error * @@ -2524,14 +2529,13 @@ FuFirmware * fu_device_read_firmware (FuDevice *self, GError **error) { FuDeviceClass *klass = FU_DEVICE_GET_CLASS (self); + g_autoptr(GBytes) fw = NULL; g_return_val_if_fail (FU_IS_DEVICE (self), NULL); g_return_val_if_fail (error == NULL || *error == NULL, NULL); - - /* no plugin-specific method or device doesn't support */ - if (!fu_device_has_flag (self, FWUPD_DEVICE_FLAG_CAN_VERIFY_IMAGE) || - klass->read_firmware == NULL) { + /* device does not support reading for verification CRCs */ + if (!fu_device_has_flag (self, FWUPD_DEVICE_FLAG_CAN_VERIFY_IMAGE)) { g_set_error_literal (error, FWUPD_ERROR, FWUPD_ERROR_NOT_SUPPORTED, @@ -2540,7 +2544,49 @@ fu_device_read_firmware (FuDevice *self, GError **error) } /* call vfunc */ - return klass->read_firmware (self, error); + if (klass->read_firmware != NULL) + return klass->read_firmware (self, error); + + /* use the default FuFirmware when only ->dump_firmware is provided */ + fw = fu_device_dump_firmware (self, error); + if (fw == NULL) + return NULL; + return fu_firmware_new_from_bytes (fw); +} + +/** + * fu_device_dump_firmware: + * @self: A #FuDevice + * @error: A #GError + * + * Reads the raw firmware image from the device by calling a plugin-specific + * vfunc. This raw firmware image may contain serial numbers or device-specific + * configuration but should be a byte-for-byte match compared to using an + * external SPI programmer. + * + * Returns: (transfer full): A #GBytes, or %NULL for error + * + * Since: 1.5.0 + **/ +GBytes * +fu_device_dump_firmware (FuDevice *self, GError **error) +{ + FuDeviceClass *klass = FU_DEVICE_GET_CLASS (self); + + g_return_val_if_fail (FU_IS_DEVICE (self), NULL); + g_return_val_if_fail (error == NULL || *error == NULL, NULL); + + /* use the default FuFirmware when only ->dump_firmware is provided */ + if (klass->dump_firmware == NULL) { + g_set_error_literal (error, + FWUPD_ERROR, + FWUPD_ERROR_NOT_SUPPORTED, + "not supported"); + return NULL; + } + + /* proxy */ + return klass->dump_firmware (self, error); } /** diff --git a/libfwupdplugin/fu-device.h b/libfwupdplugin/fu-device.h index 2b9c3ad88..3468ce781 100644 --- a/libfwupdplugin/fu-device.h +++ b/libfwupdplugin/fu-device.h @@ -74,8 +74,10 @@ struct _FuDeviceClass GError **error); gboolean (*unbind_driver) (FuDevice *self, GError **error); + GBytes *(*dump_firmware) (FuDevice *self, + GError **error); /*< private >*/ - gpointer padding[12]; + gpointer padding[11]; }; /** @@ -284,6 +286,8 @@ FuFirmware *fu_device_prepare_firmware (FuDevice *self, GError **error); FuFirmware *fu_device_read_firmware (FuDevice *self, GError **error); +GBytes *fu_device_dump_firmware (FuDevice *self, + GError **error); gboolean fu_device_attach (FuDevice *self, GError **error); gboolean fu_device_detach (FuDevice *self, diff --git a/libfwupdplugin/fwupdplugin.map b/libfwupdplugin/fwupdplugin.map index 94553fe66..bd85f519a 100644 --- a/libfwupdplugin/fwupdplugin.map +++ b/libfwupdplugin/fwupdplugin.map @@ -616,6 +616,7 @@ LIBFWUPDPLUGIN_1.5.0 { fu_common_filename_glob; fu_common_is_cpu_intel; fu_device_bind_driver; + fu_device_dump_firmware; fu_device_report_metadata_post; fu_device_report_metadata_pre; fu_device_unbind_driver; diff --git a/plugins/altos/fu-altos-device.c b/plugins/altos/fu-altos-device.c index ab3381df9..55180dad1 100644 --- a/plugins/altos/fu-altos-device.c +++ b/plugins/altos/fu-altos-device.c @@ -381,13 +381,12 @@ fu_altos_device_write_firmware (FuDevice *device, return TRUE; } -static FuFirmware * -fu_altos_device_read_firmware (FuDevice *device, GError **error) +static GBytes * +fu_altos_device_dump_firmware (FuDevice *device, GError **error) { FuAltosDevice *self = FU_ALTOS_DEVICE (device); guint flash_len; g_autoptr(FuDeviceLocker) locker = NULL; - g_autoptr(GBytes) fw = NULL; g_autoptr(GString) buf = g_string_new (NULL); /* check kind */ @@ -441,8 +440,7 @@ fu_altos_device_read_firmware (FuDevice *device, GError **error) } /* success */ - fw = g_bytes_new (buf->str, buf->len); - return fu_firmware_new_from_bytes (fw); + return g_bytes_new (buf->str, buf->len); } static gboolean @@ -577,6 +575,6 @@ fu_altos_device_class_init (FuAltosDeviceClass *klass) klass_device->probe = fu_altos_device_probe; klass_device->prepare_firmware = fu_altos_device_prepare_firmware; klass_device->write_firmware = fu_altos_device_write_firmware; - klass_device->read_firmware = fu_altos_device_read_firmware; + klass_device->dump_firmware = fu_altos_device_dump_firmware; object_class->finalize = fu_altos_device_finalize; } diff --git a/plugins/csr/fu-csr-device.c b/plugins/csr/fu-csr-device.c index 7e045b4a6..e4a540875 100644 --- a/plugins/csr/fu-csr-device.c +++ b/plugins/csr/fu-csr-device.c @@ -188,12 +188,11 @@ fu_csr_device_upload_chunk (FuCsrDevice *self, GError **error) sizeof(buf) - FU_CSR_COMMAND_HEADER_SIZE); } -static FuFirmware * +static GBytes * fu_csr_device_upload (FuDevice *device, GError **error) { FuCsrDevice *self = FU_CSR_DEVICE (device); g_autoptr(GPtrArray) chunks = NULL; - g_autoptr(GBytes) fw = NULL; guint32 total_sz = 0; gsize done_sz = 0; @@ -253,8 +252,7 @@ fu_csr_device_upload (FuDevice *device, GError **error) } /* notify UI */ - fw = dfu_utils_bytes_join_array (chunks); - return fu_firmware_new_from_bytes (fw); + return dfu_utils_bytes_join_array (chunks); } static gboolean @@ -434,7 +432,7 @@ fu_csr_device_class_init (FuCsrDeviceClass *klass) FuUsbDeviceClass *klass_usb_device = FU_USB_DEVICE_CLASS (klass); klass_device->to_string = fu_csr_device_to_string; klass_device->write_firmware = fu_csr_device_download; - klass_device->read_firmware = fu_csr_device_upload; + klass_device->dump_firmware = fu_csr_device_upload; klass_device->prepare_firmware = fu_csr_device_prepare_firmware; klass_device->attach = fu_csr_device_attach; klass_device->setup = fu_csr_device_setup; diff --git a/plugins/dfu/dfu-device.c b/plugins/dfu/dfu-device.c index 34d332d84..2e1e8a625 100644 --- a/plugins/dfu/dfu-device.c +++ b/plugins/dfu/dfu-device.c @@ -1679,12 +1679,11 @@ dfu_device_error_fixup (DfuDevice *device, GError **error) } } -static FuFirmware * -dfu_device_read_firmware (FuDevice *device, GError **error) +static GBytes * +dfu_device_dump_firmware (FuDevice *device, GError **error) { DfuDevice *self = DFU_DEVICE (device); g_autoptr(DfuFirmware) dfu_firmware = NULL; - g_autoptr(GBytes) fw = NULL; /* get data from hardware */ g_debug ("uploading from device->host"); @@ -1697,8 +1696,7 @@ dfu_device_read_firmware (FuDevice *device, GError **error) return NULL; /* get the checksum */ - fw = dfu_firmware_write_data (dfu_firmware, error); - return fu_firmware_new_from_bytes (fw); + return dfu_firmware_write_data (dfu_firmware, error); } static gboolean @@ -1825,7 +1823,7 @@ dfu_device_class_init (DfuDeviceClass *klass) FuUsbDeviceClass *klass_usb_device = FU_USB_DEVICE_CLASS (klass); klass_device->set_quirk_kv = dfu_device_set_quirk_kv; klass_device->to_string = dfu_device_to_string; - klass_device->read_firmware = dfu_device_read_firmware; + klass_device->dump_firmware = dfu_device_dump_firmware; klass_device->write_firmware = dfu_device_write_firmware; klass_device->attach = dfu_device_attach; klass_device->detach = dfu_device_detach; diff --git a/plugins/optionrom/fu-optionrom-device.c b/plugins/optionrom/fu-optionrom-device.c index 2723994c8..4a2690e1b 100644 --- a/plugins/optionrom/fu-optionrom-device.c +++ b/plugins/optionrom/fu-optionrom-device.c @@ -37,15 +37,12 @@ fu_optionrom_device_probe (FuUdevDevice *device, GError **error) return TRUE; } -static FuFirmware * -fu_optionrom_device_read_firmware (FuDevice *device, GError **error) +static GBytes * +fu_optionrom_device_dump_firmware (FuDevice *device, GError **error) { FuUdevDevice *udev_device = FU_UDEV_DEVICE (device); - g_autofree gchar *guid = NULL; - g_autofree gchar *rom_fn = NULL; - g_autoptr(FuRom) rom = NULL; - g_autoptr(GBytes) fw = NULL; g_autoptr(GFile) file = NULL; + g_autofree gchar *rom_fn = NULL; /* open the file */ rom_fn = g_build_filename (fu_udev_device_get_sysfs_path (udev_device), "rom", NULL); @@ -57,8 +54,23 @@ fu_optionrom_device_read_firmware (FuDevice *device, GError **error) return NULL; } file = g_file_new_for_path (rom_fn); + return fu_rom_dump_firmware (file, NULL, error); +} + +static FuFirmware * +fu_optionrom_device_read_firmware (FuDevice *device, GError **error) +{ + g_autofree gchar *guid = NULL; + g_autoptr(FuRom) rom = NULL; + g_autoptr(GBytes) blob = NULL; + g_autoptr(GBytes) fw = NULL; + + /* open the file */ + blob = fu_optionrom_device_dump_firmware (device, error); + if (blob == NULL) + return NULL; rom = fu_rom_new (); - if (!fu_rom_load_file (rom, file, FU_ROM_LOAD_FLAG_BLANK_PPID, NULL, error)) + if (!fu_rom_load_data (rom, blob, FU_ROM_LOAD_FLAG_BLANK_PPID, NULL, error)) return NULL; /* update version */ @@ -110,5 +122,6 @@ fu_optionrom_device_class_init (FuOptionromDeviceClass *klass) FuUdevDeviceClass *klass_udev_device = FU_UDEV_DEVICE_CLASS (klass); object_class->finalize = fu_optionrom_device_finalize; klass_device->read_firmware = fu_optionrom_device_read_firmware; + klass_device->dump_firmware = fu_optionrom_device_dump_firmware; klass_udev_device->probe = fu_optionrom_device_probe; } diff --git a/plugins/optionrom/fu-rom.c b/plugins/optionrom/fu-rom.c index 9a4ae3c3e..11e47b4f7 100644 --- a/plugins/optionrom/fu-rom.c +++ b/plugins/optionrom/fu-rom.c @@ -112,7 +112,7 @@ fu_rom_blank_serial_numbers (guint8 *buffer, guint buffer_sz) } static gchar * -fu_rom_get_hex_dump (guint8 *buffer, guint32 sz) +fu_rom_get_hex_dump (const guint8 *buffer, guint32 sz) { GString *str = g_string_new (""); for (guint32 i = 0; i < sz; i++) @@ -135,7 +135,7 @@ typedef struct { } FooRomPciCertificateHdr; static void -fu_rom_pci_print_certificate_data (guint8 *buffer, gssize sz) +fu_rom_pci_print_certificate_data (const guint8 *buffer, gssize sz) { guint16 off = 0; g_autofree gchar *hdr_str = NULL; @@ -155,7 +155,7 @@ fu_rom_pci_print_certificate_data (guint8 *buffer, gssize sz) g_debug (" ISBN segment @%02x: %s", off, segment_str); h.segment_kind = buffer[off+1]; h.next_offset = (guint16) (((guint16) buffer[off+14] << 8) + buffer[off+13]); - h.data = &buffer[off+29]; + h.data = (guint8 *) &buffer[off+29]; /* calculate last block length automatically */ if (h.next_offset == 0) @@ -396,7 +396,7 @@ fu_rom_pci_parse_data (FuRomPciHeader *hdr) } static FuRomPciHeader * -fu_rom_pci_get_header (guint8 *buffer, guint32 sz) +fu_rom_pci_get_header (const guint8 *buffer, guint32 sz) { FuRomPciHeader *hdr; @@ -536,15 +536,17 @@ fu_rom_find_version (FuRomKind kind, FuRomPciHeader *hdr) gboolean fu_rom_load_data (FuRom *self, - guint8 *buffer, gsize buffer_sz, + GBytes *blob, FuRomLoadFlags flags, GCancellable *cancellable, GError **error) { FuRomPciHeader *hdr = NULL; - guint32 sz = buffer_sz; guint32 jump = 0; guint32 hdr_sz = 0; + gsize buffer_sz = 0; + const guint8 *buffer = g_bytes_get_data (blob, &buffer_sz); + guint32 sz = buffer_sz; g_return_val_if_fail (FU_IS_ROM (self), FALSE); @@ -682,19 +684,16 @@ fu_rom_load_data (FuRom *self, return TRUE; } -gboolean -fu_rom_load_file (FuRom *self, GFile *file, FuRomLoadFlags flags, - GCancellable *cancellable, GError **error) +GBytes * +fu_rom_dump_firmware (GFile *file, GCancellable *cancellable, GError **error) { - const gssize buffer_sz = 0x400000; - gssize sz; guint number_reads = 0; - g_autoptr(GError) error_local = NULL; g_autofree gchar *fn = NULL; - g_autofree guint8 *buffer = NULL; + g_autoptr(GByteArray) buf = NULL; + g_autoptr(GError) error_local = NULL; g_autoptr(GInputStream) stream = NULL; - g_return_val_if_fail (FU_IS_ROM (self), FALSE); + g_return_val_if_fail (G_IS_FILE (file), NULL); /* open file */ stream = G_INPUT_STREAM (g_file_read (file, cancellable, &error_local)); @@ -719,38 +718,20 @@ fu_rom_load_file (FuRom *self, GFile *file, FuRomLoadFlags flags, return FALSE; } - /* read out the header */ - buffer = g_malloc ((gsize) buffer_sz); - sz = g_input_stream_read (stream, buffer, buffer_sz, - cancellable, error); - if (sz < 0) - return FALSE; - if (sz < 512) { - g_set_error (error, - FWUPD_ERROR, - FWUPD_ERROR_INVALID_FILE, - "Firmware too small: %" G_GSSIZE_FORMAT " bytes", sz); - return FALSE; - } - /* ensure we got enough data to fill the buffer */ - while (sz < buffer_sz) { - gssize sz_chunk; - sz_chunk = g_input_stream_read (stream, - buffer + sz, - buffer_sz - sz, - cancellable, - error); - if (sz_chunk == 0) + while (TRUE) { + gssize sz; + guint8 tmp[32 * 1024] = { 0x0 }; + sz = g_input_stream_read (stream, tmp, sizeof(tmp), cancellable, error); + if (sz == 0) break; - g_debug ("ROM returned 0x%04x bytes, adding 0x%04x...", - (guint) sz, (guint) sz_chunk); - if (sz_chunk < 0) + g_debug ("ROM returned 0x%04x bytes", (guint) sz); + if (sz < 0) return FALSE; - sz += sz_chunk; + g_byte_array_append (buf, tmp, sz); /* check the firmware isn't serving us small chunks */ - if (number_reads++ > 16) { + if (number_reads++ > 1024) { g_set_error_literal (error, FWUPD_ERROR, FWUPD_ERROR_INVALID_FILE, @@ -758,9 +739,28 @@ fu_rom_load_file (FuRom *self, GFile *file, FuRomLoadFlags flags, return FALSE; } } - g_debug ("ROM buffer filled %" G_GSSIZE_FORMAT "kb/%" G_GSSIZE_FORMAT "kb", - sz / 0x400, buffer_sz / 0x400); - return fu_rom_load_data (self, buffer, sz, flags, cancellable, error); + if (buf->len < 512) { + g_set_error (error, + FWUPD_ERROR, + FWUPD_ERROR_INVALID_FILE, + "firmware too small: %u bytes", buf->len); + return FALSE; + } + return g_byte_array_free_to_bytes (g_steal_pointer (&buf)); +} + +gboolean +fu_rom_load_file (FuRom *self, GFile *file, FuRomLoadFlags flags, + GCancellable *cancellable, GError **error) +{ + g_autoptr(GBytes) blob = NULL; + + g_return_val_if_fail (FU_IS_ROM (self), FALSE); + + blob = fu_rom_dump_firmware (file, cancellable, error); + if (blob == NULL) + return FALSE; + return fu_rom_load_data (self, blob, flags, cancellable, error); } FuRomKind diff --git a/plugins/optionrom/fu-rom.h b/plugins/optionrom/fu-rom.h index 45088fe21..532b9ead6 100644 --- a/plugins/optionrom/fu-rom.h +++ b/plugins/optionrom/fu-rom.h @@ -34,8 +34,7 @@ gboolean fu_rom_load_file (FuRom *self, GCancellable *cancellable, GError **error); gboolean fu_rom_load_data (FuRom *self, - guint8 *buffer, - gsize buffer_sz, + GBytes *blob, FuRomLoadFlags flags, GCancellable *cancellable, GError **error); @@ -48,3 +47,6 @@ GBytes *fu_rom_get_data (FuRom *self); guint16 fu_rom_get_vendor (FuRom *self); guint16 fu_rom_get_model (FuRom *self); const gchar *fu_rom_kind_to_string (FuRomKind kind); +GBytes *fu_rom_dump_firmware (GFile *file, + GCancellable *cancellable, + GError **error); diff --git a/plugins/superio/fu-superio-it89-device.c b/plugins/superio/fu-superio-it89-device.c index f038780c2..58b62af8d 100644 --- a/plugins/superio/fu-superio-it89-device.c +++ b/plugins/superio/fu-superio-it89-device.c @@ -417,18 +417,26 @@ fu_plugin_superio_fix_signature (FuSuperioDevice *self, GBytes *fw, GError **err return g_bytes_new_take (g_steal_pointer (&buf2), sz); } +static GBytes * +fu_superio_it89_device_dump_firmware (FuDevice *device, GError **error) +{ + FuSuperioDevice *self = FU_SUPERIO_DEVICE (device); + guint64 fwsize = fu_device_get_firmware_size_min (device); + + fu_device_set_status (device, FWUPD_STATUS_DEVICE_READ); + return fu_superio_it89_device_read_addr (self, 0x0, fwsize, + fu_superio_it89_device_progress_cb, + error); +} + static FuFirmware * fu_superio_it89_device_read_firmware (FuDevice *device, GError **error) { FuSuperioDevice *self = FU_SUPERIO_DEVICE (device); - guint64 fwsize = fu_device_get_firmware_size_min (device); g_autoptr(GBytes) blob = NULL; g_autoptr(GBytes) fw = NULL; - fu_device_set_status (device, FWUPD_STATUS_DEVICE_READ); - blob = fu_superio_it89_device_read_addr (self, 0x0, fwsize, - fu_superio_it89_device_progress_cb, - error); + blob = fu_superio_it89_device_dump_firmware (device, error); fw = fu_plugin_superio_fix_signature (self, blob, error); return fu_firmware_new_from_bytes (fw); } @@ -681,6 +689,7 @@ fu_superio_it89_device_class_init (FuSuperioIt89DeviceClass *klass) klass_device->attach = fu_superio_it89_device_attach; klass_device->detach = fu_superio_it89_device_detach; klass_device->read_firmware = fu_superio_it89_device_read_firmware; + klass_device->dump_firmware = fu_superio_it89_device_dump_firmware; klass_device->write_firmware = fu_superio_it89_device_write_firmware; klass_superio_device->setup = fu_superio_it89_device_setup; } diff --git a/plugins/vli/fu-vli-pd-device.c b/plugins/vli/fu-vli-pd-device.c index d7348fbb3..4ad683d3b 100644 --- a/plugins/vli/fu-vli-pd-device.c +++ b/plugins/vli/fu-vli-pd-device.c @@ -362,18 +362,14 @@ fu_vli_pd_device_prepare_firmware (FuDevice *device, return g_steal_pointer (&firmware); } -static FuFirmware * -fu_vli_pd_device_read_firmware (FuDevice *device, GError **error) +static GBytes * +fu_vli_pd_device_dump_firmware (FuDevice *device, GError **error) { FuVliPdDevice *self = FU_VLI_PD_DEVICE (device); - g_autoptr(GBytes) fw = NULL; - fu_device_set_status (FU_DEVICE (self), FWUPD_STATUS_DEVICE_VERIFY); - fw = fu_vli_device_spi_read (FU_VLI_DEVICE (self), 0x0, - fu_device_get_firmware_size_max (device), - error); - if (fw == NULL) - return NULL; - return fu_firmware_new_from_bytes (fw); + fu_device_set_status (FU_DEVICE (self), FWUPD_STATUS_DEVICE_READ); + return fu_vli_device_spi_read (FU_VLI_DEVICE (self), 0x0, + fu_device_get_firmware_size_max (device), + error); } static gboolean @@ -688,7 +684,7 @@ fu_vli_pd_device_class_init (FuVliPdDeviceClass *klass) { FuDeviceClass *klass_device = FU_DEVICE_CLASS (klass); FuVliDeviceClass *klass_vli_device = FU_VLI_DEVICE_CLASS (klass); - klass_device->read_firmware = fu_vli_pd_device_read_firmware; + klass_device->dump_firmware = fu_vli_pd_device_dump_firmware; klass_device->write_firmware = fu_vli_pd_device_write_firmware; klass_device->prepare_firmware = fu_vli_pd_device_prepare_firmware; klass_device->attach = fu_vli_pd_device_attach; diff --git a/plugins/vli/fu-vli-pd-parade-device.c b/plugins/vli/fu-vli-pd-parade-device.c index 2bf8b0317..deab6d632 100644 --- a/plugins/vli/fu-vli-pd-parade-device.c +++ b/plugins/vli/fu-vli-pd-parade-device.c @@ -579,8 +579,8 @@ fu_vli_pd_parade_device_write_firmware (FuDevice *device, return TRUE; } -static FuFirmware * -fu_vli_pd_parade_device_read_firmware (FuDevice *device, GError **error) +static GBytes * +fu_vli_pd_parade_device_dump_firmware (FuDevice *device, GError **error) { FuVliPdDevice *parent = FU_VLI_PD_DEVICE (fu_device_get_parent (device)); FuVliPdParadeDevice *self = FU_VLI_PD_PARADE_DEVICE (device); @@ -610,7 +610,7 @@ fu_vli_pd_parade_device_read_firmware (FuDevice *device, GError **error) error)) return NULL; } - return fu_firmware_new_from_bytes (fw); + return g_steal_pointer (&fw); } static gboolean @@ -657,7 +657,7 @@ fu_vli_pd_parade_device_class_init (FuVliPdParadeDeviceClass *klass) FuDeviceClass *klass_device = FU_DEVICE_CLASS (klass); klass_device->to_string = fu_vli_pd_parade_device_to_string; klass_device->probe = fu_vli_pd_parade_device_probe; - klass_device->read_firmware = fu_vli_pd_parade_device_read_firmware; + klass_device->dump_firmware = fu_vli_pd_parade_device_dump_firmware; klass_device->write_firmware = fu_vli_pd_parade_device_write_firmware; } diff --git a/plugins/vli/fu-vli-usbhub-device.c b/plugins/vli/fu-vli-usbhub-device.c index b495cf242..07b485625 100644 --- a/plugins/vli/fu-vli-usbhub-device.c +++ b/plugins/vli/fu-vli-usbhub-device.c @@ -948,18 +948,14 @@ fu_vli_usbhub_device_update_v2 (FuVliUsbhubDevice *self, FuFirmware *firmware, G return TRUE; } -static FuFirmware * -fu_vli_usbhub_device_read_firmware (FuDevice *device, GError **error) +static GBytes * +fu_vli_usbhub_device_dump_firmware (FuDevice *device, GError **error) { FuVliUsbhubDevice *self = FU_VLI_USBHUB_DEVICE (device); - g_autoptr(GBytes) fw = NULL; - fu_device_set_status (FU_DEVICE (self), FWUPD_STATUS_DEVICE_VERIFY); - fw = fu_vli_device_spi_read (FU_VLI_DEVICE (self), 0x0, - fu_device_get_firmware_size_max (device), - error); - if (fw == NULL) - return NULL; - return fu_firmware_new_from_bytes (fw); + fu_device_set_status (FU_DEVICE (self), FWUPD_STATUS_DEVICE_READ); + return fu_vli_device_spi_read (FU_VLI_DEVICE (self), 0x0, + fu_device_get_firmware_size_max (device), + error); } static gboolean @@ -1007,7 +1003,7 @@ fu_vli_usbhub_device_class_init (FuVliUsbhubDeviceClass *klass) FuDeviceClass *klass_device = FU_DEVICE_CLASS (klass); FuVliDeviceClass *klass_vli_device = FU_VLI_DEVICE_CLASS (klass); klass_device->probe = fu_vli_usbhub_device_probe; - klass_device->read_firmware = fu_vli_usbhub_device_read_firmware; + klass_device->dump_firmware = fu_vli_usbhub_device_dump_firmware; klass_device->write_firmware = fu_vli_usbhub_device_write_firmware; klass_device->prepare_firmware = fu_vli_usbhub_device_prepare_firmware; klass_device->attach = fu_vli_usbhub_device_attach; diff --git a/plugins/vli/fu-vli-usbhub-pd-device.c b/plugins/vli/fu-vli-usbhub-pd-device.c index 2d8c5cc81..ba470c77d 100644 --- a/plugins/vli/fu-vli-usbhub-pd-device.c +++ b/plugins/vli/fu-vli-usbhub-pd-device.c @@ -123,13 +123,12 @@ fu_vli_usbhub_pd_device_prepare_firmware (FuDevice *device, return g_steal_pointer (&firmware); } -static FuFirmware * -fu_vli_usbhub_pd_device_read_firmware (FuDevice *device, GError **error) +static GBytes * +fu_vli_usbhub_pd_device_dump_firmware (FuDevice *device, GError **error) { FuVliUsbhubDevice *parent = FU_VLI_USBHUB_DEVICE (fu_device_get_parent (device)); FuVliUsbhubPdDevice *self = FU_VLI_USBHUB_PD_DEVICE (device); g_autoptr(FuDeviceLocker) locker = NULL; - g_autoptr(GBytes) fw = NULL; /* open device */ locker = fu_device_locker_new (parent, error); @@ -137,14 +136,11 @@ fu_vli_usbhub_pd_device_read_firmware (FuDevice *device, GError **error) return NULL; /* read */ - fu_device_set_status (FU_DEVICE (device), FWUPD_STATUS_DEVICE_VERIFY); - fw = fu_vli_device_spi_read (FU_VLI_DEVICE (parent), - fu_vli_common_device_kind_get_offset (self->device_kind), - fu_device_get_firmware_size_max (device), - error); - if (fw == NULL) - return NULL; - return fu_firmware_new_from_bytes (fw); + fu_device_set_status (FU_DEVICE (device), FWUPD_STATUS_DEVICE_READ); + return fu_vli_device_spi_read (FU_VLI_DEVICE (parent), + fu_vli_common_device_kind_get_offset (self->device_kind), + fu_device_get_firmware_size_max (device), + error); } static gboolean @@ -221,7 +217,7 @@ fu_vli_usbhub_pd_device_class_init (FuVliUsbhubPdDeviceClass *klass) klass_device->to_string = fu_vli_usbhub_pd_device_to_string; klass_device->probe = fu_vli_usbhub_pd_device_probe; klass_device->attach = fu_vli_usbhub_pd_device_attach; - klass_device->read_firmware = fu_vli_usbhub_pd_device_read_firmware; + klass_device->dump_firmware = fu_vli_usbhub_pd_device_dump_firmware; klass_device->write_firmware = fu_vli_usbhub_pd_device_write_firmware; klass_device->prepare_firmware = fu_vli_usbhub_pd_device_prepare_firmware; } diff --git a/src/fu-engine.c b/src/fu-engine.c index 65093ba12..d1a4e408f 100644 --- a/src/fu-engine.c +++ b/src/fu-engine.c @@ -2753,13 +2753,13 @@ fu_engine_update (FuEngine *self, } GBytes * -fu_engine_firmware_read (FuEngine *self, +fu_engine_firmware_dump (FuEngine *self, FuDevice *device, FwupdInstallFlags flags, GError **error) { g_autoptr(FuDeviceLocker) locker = NULL; - g_autoptr(FuFirmware) firmware = NULL; + g_autoptr(GBytes) fw = NULL; /* open, detach, read, attach, serialize */ locker = fu_device_locker_new (device, error); @@ -2769,8 +2769,8 @@ fu_engine_firmware_read (FuEngine *self, } if (!fu_device_detach (device, error)) return NULL; - firmware = fu_device_read_firmware (device, error); - if (firmware == NULL) { + fw = fu_device_dump_firmware (device, error); + if (fw == NULL) { g_autoptr(GError) error_local = NULL; if (!fu_device_attach (device, &error_local)) { g_warning ("failed to attach after read image failure: %s", @@ -2780,7 +2780,7 @@ fu_engine_firmware_read (FuEngine *self, } if (!fu_device_attach (device, error)) return NULL; - return fu_firmware_write (firmware, error); + return g_steal_pointer (&fw); } gboolean diff --git a/src/fu-engine.h b/src/fu-engine.h index 7430cdd63..12de88642 100644 --- a/src/fu-engine.h +++ b/src/fu-engine.h @@ -116,7 +116,7 @@ gboolean fu_engine_verify (FuEngine *self, gboolean fu_engine_verify_update (FuEngine *self, const gchar *device_id, GError **error); -GBytes *fu_engine_firmware_read (FuEngine *self, +GBytes *fu_engine_firmware_dump (FuEngine *self, FuDevice *device, FwupdInstallFlags flags, GError **error); diff --git a/src/fu-tool.c b/src/fu-tool.c index dd2c44e5b..f88cc461c 100644 --- a/src/fu-tool.c +++ b/src/fu-tool.c @@ -751,7 +751,7 @@ fu_util_install_blob (FuUtilPrivate *priv, gchar **values, GError **error) } static gboolean -fu_util_firmware_read (FuUtilPrivate *priv, gchar **values, GError **error) +fu_util_firmware_dump (FuUtilPrivate *priv, gchar **values, GError **error) { g_autoptr(FuDevice) device = NULL; g_autoptr(GBytes) blob_empty = g_bytes_new (NULL, 0); @@ -800,7 +800,7 @@ fu_util_firmware_read (FuUtilPrivate *priv, gchar **values, GError **error) G_CALLBACK (fu_util_update_device_changed_cb), priv); /* dump firmware */ - blob_fw = fu_engine_firmware_read (priv->engine, device, priv->flags, error); + blob_fw = fu_engine_firmware_dump (priv->engine, device, priv->flags, error); if (blob_fw == NULL) return FALSE; return fu_common_set_contents_bytes (values[0], blob_fw, error); @@ -2601,11 +2601,11 @@ main (int argc, char *argv[]) _("Update the stored metadata with current contents"), fu_util_verify_update); fu_util_cmd_array_add (cmd_array, - "firmware-read", + "firmware-dump", "FILENAME [DEVICE-ID|GUID]", /* TRANSLATORS: command description */ _("Read a firmware blob from a device"), - fu_util_firmware_read); + fu_util_firmware_dump); fu_util_cmd_array_add (cmd_array, "firmware-convert", "FILENAME-SRC FILENAME-DST [FIRMWARE-TYPE-SRC] [FIRMWARE-TYPE-DST]", From 3e9fafcc6f696353c7d82c59f4fa6577b94fc044 Mon Sep 17 00:00:00 2001 From: Richard Hughes Date: Thu, 24 Sep 2020 13:08:21 +0100 Subject: [PATCH 449/607] Add fu_firmware_remove_image() --- libfwupdplugin/fu-firmware.c | 89 ++++++++++++++++++++++++++++++++++ libfwupdplugin/fu-firmware.h | 9 ++++ libfwupdplugin/fu-self-test.c | 15 ++++++ libfwupdplugin/fwupdplugin.map | 3 ++ 4 files changed, 116 insertions(+) diff --git a/libfwupdplugin/fu-firmware.c b/libfwupdplugin/fu-firmware.c index 9bce7fc64..f7c9fcbbf 100644 --- a/libfwupdplugin/fu-firmware.c +++ b/libfwupdplugin/fu-firmware.c @@ -461,6 +461,95 @@ fu_firmware_add_image (FuFirmware *self, FuFirmwareImage *img) g_ptr_array_add (priv->images, g_object_ref (img)); } +/** + * fu_firmware_remove_image: + * @self: a #FuPlugin + * @img: A #FuFirmwareImage + * @error: A #GError, or %NULL + * + * Remove an image from the firmware. + * + * Returns: %TRUE if the image was removed + * + * Since: 1.5.0 + **/ +gboolean +fu_firmware_remove_image (FuFirmware *self, FuFirmwareImage *img, GError **error) +{ + FuFirmwarePrivate *priv = GET_PRIVATE (self); + + g_return_val_if_fail (FU_IS_FIRMWARE (self), FALSE); + g_return_val_if_fail (FU_IS_FIRMWARE_IMAGE (img), FALSE); + g_return_val_if_fail (error == NULL || *error == NULL, FALSE); + + if (g_ptr_array_remove (priv->images, img)) + return TRUE; + + /* did not exist */ + g_set_error (error, + FWUPD_ERROR, + FWUPD_ERROR_NOT_FOUND, + "image %s not found in firmware", + fu_firmware_image_get_id (img)); + return FALSE; +} + +/** + * fu_firmware_remove_image_by_idx: + * @self: a #FuPlugin + * @idx: index + * @error: A #GError, or %NULL + * + * Removes the first image from the firmware matching the index. + * + * Returns: %TRUE if an image was removed + * + * Since: 1.5.0 + **/ +gboolean +fu_firmware_remove_image_by_idx (FuFirmware *self, guint64 idx, GError **error) +{ + FuFirmwarePrivate *priv = GET_PRIVATE (self); + g_autoptr(FuFirmwareImage) img = NULL; + + g_return_val_if_fail (FU_IS_FIRMWARE (self), FALSE); + g_return_val_if_fail (error == NULL || *error == NULL, FALSE); + + img = fu_firmware_get_image_by_idx (self, idx, error); + if (img == NULL) + return FALSE; + g_ptr_array_remove (priv->images, img); + return TRUE; +} + +/** + * fu_firmware_remove_image_by_id: + * @self: a #FuPlugin + * @id: (nullable): image ID, e.g. "config" + * @error: A #GError, or %NULL + * + * Removes the first image from the firmware matching the ID. + * + * Returns: %TRUE if an image was removed + * + * Since: 1.5.0 + **/ +gboolean +fu_firmware_remove_image_by_id (FuFirmware *self, const gchar *id, GError **error) +{ + FuFirmwarePrivate *priv = GET_PRIVATE (self); + g_autoptr(FuFirmwareImage) img = NULL; + + g_return_val_if_fail (FU_IS_FIRMWARE (self), FALSE); + g_return_val_if_fail (error == NULL || *error == NULL, FALSE); + + img = fu_firmware_get_image_by_id (self, id, error); + if (img == NULL) + return FALSE; + g_ptr_array_remove (priv->images, img); + return TRUE; +} + /** * fu_firmware_get_images: * @self: a #FuFirmware diff --git a/libfwupdplugin/fu-firmware.h b/libfwupdplugin/fu-firmware.h index 119de9a82..c31bb2bee 100644 --- a/libfwupdplugin/fu-firmware.h +++ b/libfwupdplugin/fu-firmware.h @@ -95,6 +95,15 @@ gboolean fu_firmware_write_file (FuFirmware *self, void fu_firmware_add_image (FuFirmware *self, FuFirmwareImage *img); +gboolean fu_firmware_remove_image (FuFirmware *self, + FuFirmwareImage *img, + GError **error); +gboolean fu_firmware_remove_image_by_idx (FuFirmware *self, + guint64 idx, + GError **error); +gboolean fu_firmware_remove_image_by_id (FuFirmware *self, + const gchar *id, + GError **error); GPtrArray *fu_firmware_get_images (FuFirmware *self); FuFirmwareImage *fu_firmware_get_image_by_id (FuFirmware *self, const gchar *id, diff --git a/libfwupdplugin/fu-self-test.c b/libfwupdplugin/fu-self-test.c index 238a5755a..bbc236df2 100644 --- a/libfwupdplugin/fu-self-test.c +++ b/libfwupdplugin/fu-self-test.c @@ -1652,12 +1652,14 @@ fu_firmware_dfu_func (void) static void fu_firmware_func (void) { + gboolean ret; g_autoptr(FuFirmware) firmware = fu_firmware_new (); g_autoptr(FuFirmwareImage) img1 = fu_firmware_image_new (NULL); g_autoptr(FuFirmwareImage) img2 = fu_firmware_image_new (NULL); g_autoptr(FuFirmwareImage) img_id = NULL; g_autoptr(FuFirmwareImage) img_idx = NULL; g_autoptr(GError) error = NULL; + g_autoptr(GPtrArray) images = NULL; g_autofree gchar *str = NULL; fu_firmware_image_set_addr (img1, 0x200); @@ -1703,6 +1705,19 @@ fu_firmware_func (void) " ID: secondary\n" " Index: 0x17\n" " Address: 0x400\n"); + + ret = fu_firmware_remove_image_by_idx (firmware, 0xd, &error); + g_assert_no_error (error); + g_assert_true (ret); + ret = fu_firmware_remove_image_by_id (firmware, "secondary", &error); + g_assert_no_error (error); + g_assert_true (ret); + images = fu_firmware_get_images (firmware); + g_assert_nonnull (images); + g_assert_cmpint (images->len, ==, 0); + ret = fu_firmware_remove_image_by_id (firmware, "NOTGOINGTOEXIST", &error); + g_assert_error (error, FWUPD_ERROR, FWUPD_ERROR_NOT_FOUND); + g_assert_false (ret); } static void diff --git a/libfwupdplugin/fwupdplugin.map b/libfwupdplugin/fwupdplugin.map index bd85f519a..d7acc4980 100644 --- a/libfwupdplugin/fwupdplugin.map +++ b/libfwupdplugin/fwupdplugin.map @@ -632,6 +632,9 @@ LIBFWUPDPLUGIN_1.5.0 { fu_firmware_image_parse; fu_firmware_image_set_filename; fu_firmware_image_set_offset; + fu_firmware_remove_image; + fu_firmware_remove_image_by_id; + fu_firmware_remove_image_by_idx; fu_fmap_firmware_get_type; fu_fmap_firmware_new; fu_plugin_runner_add_security_attrs; From 95187939cacfa092d65e1f2bf0f47193f1355672 Mon Sep 17 00:00:00 2001 From: Richard Hughes Date: Fri, 25 Sep 2020 09:43:56 +0100 Subject: [PATCH 450/607] platform-integrity: Use the post-review BIOS write protection attrs --- plugins/platform-integrity/fu-plugin-platform-integrity.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/plugins/platform-integrity/fu-plugin-platform-integrity.c b/plugins/platform-integrity/fu-plugin-platform-integrity.c index 29662b9c3..876f1cab4 100644 --- a/plugins/platform-integrity/fu-plugin-platform-integrity.c +++ b/plugins/platform-integrity/fu-plugin-platform-integrity.c @@ -105,7 +105,7 @@ fu_plugin_add_security_attr_ble (FuPlugin *plugin, FuSecurityAttrs *attrs) fu_security_attrs_append (attrs, attr); /* load file */ - fn = g_build_filename (priv->sysfs_path, "ble", NULL); + fn = g_build_filename (priv->sysfs_path, "biosle", NULL); if (!g_file_get_contents (fn, &buf, &bufsz, &error_local)) { g_warning ("could not open %s: %s", fn, error_local->message); fwupd_security_attr_set_result (attr, FWUPD_SECURITY_ATTR_RESULT_NOT_VALID); @@ -139,7 +139,7 @@ fu_plugin_add_security_attr_smm_bwp (FuPlugin *plugin, FuSecurityAttrs *attrs) fu_security_attrs_append (attrs, attr); /* load file */ - fn = g_build_filename (priv->sysfs_path, "smm_bwp", NULL); + fn = g_build_filename (priv->sysfs_path, "smm_bioswp", NULL); if (!g_file_get_contents (fn, &buf, &bufsz, &error_local)) { g_warning ("could not open %s: %s", fn, error_local->message); fwupd_security_attr_set_result (attr, FWUPD_SECURITY_ATTR_RESULT_NOT_VALID); From de9be2d34c0e7b3ebfda6657403ffc03105495be Mon Sep 17 00:00:00 2001 From: Richard Hughes Date: Fri, 25 Sep 2020 12:57:14 +0100 Subject: [PATCH 451/607] trivial: Correctly set subsystem when using _VENDOR_FROM_PARENT --- libfwupdplugin/fu-udev-device.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/libfwupdplugin/fu-udev-device.c b/libfwupdplugin/fu-udev-device.c index c66672ba6..7f77f89f9 100644 --- a/libfwupdplugin/fu-udev-device.c +++ b/libfwupdplugin/fu-udev-device.c @@ -260,6 +260,8 @@ fu_udev_device_probe (FuDevice *device, GError **error) priv->vendor = fu_udev_device_get_sysfs_attr_as_uint32 (udev_parent, "vendor"); priv->model = fu_udev_device_get_sysfs_attr_as_uint32 (udev_parent, "device"); priv->revision = fu_udev_device_get_sysfs_attr_as_uint8 (udev_parent, "revision"); + priv->subsystem_vendor = fu_udev_device_get_sysfs_attr_as_uint32 (udev_parent, "subsystem_vendor"); + priv->subsystem_model = fu_udev_device_get_sysfs_attr_as_uint32 (udev_parent, "subsystem_device"); } /* hidraw helpfully encodes the information in a different place */ From f02571b3f3670494f2faee4114f4ca3da187ff96 Mon Sep 17 00:00:00 2001 From: Richard Hughes Date: Fri, 25 Sep 2020 12:57:52 +0100 Subject: [PATCH 452/607] Use the 'real' hardware class for virtual classes like net --- libfwupdplugin/fu-udev-device.c | 20 ++++++++++++++++++-- 1 file changed, 18 insertions(+), 2 deletions(-) diff --git a/libfwupdplugin/fu-udev-device.c b/libfwupdplugin/fu-udev-device.c index 7f77f89f9..b4e708f3a 100644 --- a/libfwupdplugin/fu-udev-device.c +++ b/libfwupdplugin/fu-udev-device.c @@ -464,13 +464,28 @@ fu_udev_device_set_dev (FuUdevDevice *self, GUdevDevice *udev_device) FuUdevDevicePrivate *priv = GET_PRIVATE (self); #ifdef HAVE_GUDEV const gchar *summary; - g_autoptr(GUdevDevice) parent = NULL; #endif g_return_if_fail (FU_IS_UDEV_DEVICE (self)); - /* set new device */ +#ifdef HAVE_GUDEV + /* the net subsystem is not a real hardware class */ + if (udev_device != NULL && + g_strcmp0 (g_udev_device_get_subsystem (udev_device), "net") == 0) { + g_autoptr(GUdevDevice) udev_device_phys = NULL; + udev_device_phys = g_udev_device_get_parent (udev_device); + g_set_object (&priv->udev_device, udev_device_phys); + fu_device_set_metadata (FU_DEVICE (self), + "ParentSubsystem", + g_udev_device_get_subsystem (udev_device)); + } else { + g_set_object (&priv->udev_device, udev_device); + } +#else g_set_object (&priv->udev_device, udev_device); +#endif + + /* set new device */ if (priv->udev_device == NULL) return; #ifdef HAVE_GUDEV @@ -480,6 +495,7 @@ fu_udev_device_set_dev (FuUdevDevice *self, GUdevDevice *udev_device) /* try to get one line summary */ summary = g_udev_device_get_sysfs_attr (priv->udev_device, "description"); if (summary == NULL) { + g_autoptr(GUdevDevice) parent = NULL; parent = g_udev_device_get_parent (priv->udev_device); if (parent != NULL) summary = g_udev_device_get_sysfs_attr (parent, "description"); From 6f5e35a3ea99add73bc41199ff433a005ab835e3 Mon Sep 17 00:00:00 2001 From: Richard Hughes Date: Fri, 25 Sep 2020 14:14:52 +0100 Subject: [PATCH 453/607] Add common CRC routines We have quite a few versions of CRC in-tree, and are about to get two more... --- libfwupdplugin/fu-common.c | 72 ++++++++++++++++++++++++++++++++ libfwupdplugin/fu-common.h | 9 ++++ libfwupdplugin/fu-dfu-firmware.c | 60 +------------------------- libfwupdplugin/fu-self-test.c | 9 ++++ libfwupdplugin/fwupdplugin.map | 3 ++ plugins/vli/fu-vli-common.c | 17 -------- plugins/vli/fu-vli-common.h | 2 - plugins/vli/fu-vli-pd-device.c | 3 +- plugins/vli/fu-vli-pd-firmware.c | 4 +- 9 files changed, 100 insertions(+), 79 deletions(-) diff --git a/libfwupdplugin/fu-common.c b/libfwupdplugin/fu-common.c index 7225cdcfa..ee8969260 100644 --- a/libfwupdplugin/fu-common.c +++ b/libfwupdplugin/fu-common.c @@ -2335,3 +2335,75 @@ fu_common_get_esp_for_path (const gchar *esp_path, GError **error) esp_path); return NULL; } + +/** + * fu_common_crc16: + * @buf: memory buffer + * @bufsz: sizeof buf + * + * Returns the cyclic redundancy check value for the given memory buffer. + * + * Returns: CRC value + * + * Since: 1.5.0 + **/ +guint16 +fu_common_crc16 (const guint8 *buf, gsize bufsz) +{ + guint16 crc = 0xffff; + for (gsize len = bufsz; len > 0; len--) { + crc = (guint16) (crc ^ (*buf++)); + for (guint8 i = 0; i < 8; i++) { + if (crc & 0x1) { + crc = (crc >> 1) ^ 0xa001; + } else { + crc >>= 1; + } + } + } + return ~crc; +} + +/** + * fu_common_crc32_full: + * @buf: memory buffer + * @bufsz: sizeof buf + * @crc: initial CRC value, typically 0xFFFFFFFF + * @polynomial: CRC polynomial, typically 0xEDB88320 + * + * Returns the cyclic redundancy check value for the given memory buffer. + * + * Returns: CRC value + * + * Since: 1.5.0 + **/ +guint32 +fu_common_crc32_full (const guint8 *buf, gsize bufsz, guint32 crc, guint32 polynomial) +{ + for (guint32 idx = 0; idx < bufsz; idx++) { + guint8 data = *buf++; + crc = crc ^ data; + for (guint32 bit = 0; bit < 8; bit++) { + guint32 mask = -(crc & 1); + crc = (crc >> 1) ^ (polynomial & mask); + } + } + return ~crc; +} + +/** + * fu_common_crc32: + * @buf: memory buffer + * @bufsz: sizeof buf + * + * Returns the cyclic redundancy check value for the given memory buffer. + * + * Returns: CRC value + * + * Since: 1.5.0 + **/ +guint32 +fu_common_crc32 (const guint8 *buf, gsize bufsz) +{ + return fu_common_crc32_full (buf, bufsz, 0xFFFFFFFF, 0xEDB88320); +} diff --git a/libfwupdplugin/fu-common.h b/libfwupdplugin/fu-common.h index 0b99ac43f..2d15f41c2 100644 --- a/libfwupdplugin/fu-common.h +++ b/libfwupdplugin/fu-common.h @@ -239,3 +239,12 @@ GPtrArray *fu_common_get_volumes_by_kind (const gchar *kind, FuVolume *fu_common_get_esp_for_path (const gchar *esp_path, GError **error); FuVolume *fu_common_get_esp_default (GError **error); + +guint16 fu_common_crc16 (const guint8 *buf, + gsize bufsz); +guint32 fu_common_crc32 (const guint8 *buf, + gsize bufsz); +guint32 fu_common_crc32_full (const guint8 *buf, + gsize bufsz, + guint32 crc, + guint32 polynomial); diff --git a/libfwupdplugin/fu-dfu-firmware.c b/libfwupdplugin/fu-dfu-firmware.c index bc9e47950..033aaaa26 100644 --- a/libfwupdplugin/fu-dfu-firmware.c +++ b/libfwupdplugin/fu-dfu-firmware.c @@ -181,60 +181,6 @@ fu_dfu_firmware_set_version (FuDfuFirmware *self, guint16 version) priv->version = version; } -static guint32 _crctbl[] = { - 0x00000000, 0x77073096, 0xee0e612c, 0x990951ba, 0x076dc419, 0x706af48f, - 0xe963a535, 0x9e6495a3, 0x0edb8832, 0x79dcb8a4, 0xe0d5e91e, 0x97d2d988, - 0x09b64c2b, 0x7eb17cbd, 0xe7b82d07, 0x90bf1d91, 0x1db71064, 0x6ab020f2, - 0xf3b97148, 0x84be41de, 0x1adad47d, 0x6ddde4eb, 0xf4d4b551, 0x83d385c7, - 0x136c9856, 0x646ba8c0, 0xfd62f97a, 0x8a65c9ec, 0x14015c4f, 0x63066cd9, - 0xfa0f3d63, 0x8d080df5, 0x3b6e20c8, 0x4c69105e, 0xd56041e4, 0xa2677172, - 0x3c03e4d1, 0x4b04d447, 0xd20d85fd, 0xa50ab56b, 0x35b5a8fa, 0x42b2986c, - 0xdbbbc9d6, 0xacbcf940, 0x32d86ce3, 0x45df5c75, 0xdcd60dcf, 0xabd13d59, - 0x26d930ac, 0x51de003a, 0xc8d75180, 0xbfd06116, 0x21b4f4b5, 0x56b3c423, - 0xcfba9599, 0xb8bda50f, 0x2802b89e, 0x5f058808, 0xc60cd9b2, 0xb10be924, - 0x2f6f7c87, 0x58684c11, 0xc1611dab, 0xb6662d3d, 0x76dc4190, 0x01db7106, - 0x98d220bc, 0xefd5102a, 0x71b18589, 0x06b6b51f, 0x9fbfe4a5, 0xe8b8d433, - 0x7807c9a2, 0x0f00f934, 0x9609a88e, 0xe10e9818, 0x7f6a0dbb, 0x086d3d2d, - 0x91646c97, 0xe6635c01, 0x6b6b51f4, 0x1c6c6162, 0x856530d8, 0xf262004e, - 0x6c0695ed, 0x1b01a57b, 0x8208f4c1, 0xf50fc457, 0x65b0d9c6, 0x12b7e950, - 0x8bbeb8ea, 0xfcb9887c, 0x62dd1ddf, 0x15da2d49, 0x8cd37cf3, 0xfbd44c65, - 0x4db26158, 0x3ab551ce, 0xa3bc0074, 0xd4bb30e2, 0x4adfa541, 0x3dd895d7, - 0xa4d1c46d, 0xd3d6f4fb, 0x4369e96a, 0x346ed9fc, 0xad678846, 0xda60b8d0, - 0x44042d73, 0x33031de5, 0xaa0a4c5f, 0xdd0d7cc9, 0x5005713c, 0x270241aa, - 0xbe0b1010, 0xc90c2086, 0x5768b525, 0x206f85b3, 0xb966d409, 0xce61e49f, - 0x5edef90e, 0x29d9c998, 0xb0d09822, 0xc7d7a8b4, 0x59b33d17, 0x2eb40d81, - 0xb7bd5c3b, 0xc0ba6cad, 0xedb88320, 0x9abfb3b6, 0x03b6e20c, 0x74b1d29a, - 0xead54739, 0x9dd277af, 0x04db2615, 0x73dc1683, 0xe3630b12, 0x94643b84, - 0x0d6d6a3e, 0x7a6a5aa8, 0xe40ecf0b, 0x9309ff9d, 0x0a00ae27, 0x7d079eb1, - 0xf00f9344, 0x8708a3d2, 0x1e01f268, 0x6906c2fe, 0xf762575d, 0x806567cb, - 0x196c3671, 0x6e6b06e7, 0xfed41b76, 0x89d32be0, 0x10da7a5a, 0x67dd4acc, - 0xf9b9df6f, 0x8ebeeff9, 0x17b7be43, 0x60b08ed5, 0xd6d6a3e8, 0xa1d1937e, - 0x38d8c2c4, 0x4fdff252, 0xd1bb67f1, 0xa6bc5767, 0x3fb506dd, 0x48b2364b, - 0xd80d2bda, 0xaf0a1b4c, 0x36034af6, 0x41047a60, 0xdf60efc3, 0xa867df55, - 0x316e8eef, 0x4669be79, 0xcb61b38c, 0xbc66831a, 0x256fd2a0, 0x5268e236, - 0xcc0c7795, 0xbb0b4703, 0x220216b9, 0x5505262f, 0xc5ba3bbe, 0xb2bd0b28, - 0x2bb45a92, 0x5cb36a04, 0xc2d7ffa7, 0xb5d0cf31, 0x2cd99e8b, 0x5bdeae1d, - 0x9b64c2b0, 0xec63f226, 0x756aa39c, 0x026d930a, 0x9c0906a9, 0xeb0e363f, - 0x72076785, 0x05005713, 0x95bf4a82, 0xe2b87a14, 0x7bb12bae, 0x0cb61b38, - 0x92d28e9b, 0xe5d5be0d, 0x7cdcefb7, 0x0bdbdf21, 0x86d3d2d4, 0xf1d4e242, - 0x68ddb3f8, 0x1fda836e, 0x81be16cd, 0xf6b9265b, 0x6fb077e1, 0x18b74777, - 0x88085ae6, 0xff0f6a70, 0x66063bca, 0x11010b5c, 0x8f659eff, 0xf862ae69, - 0x616bffd3, 0x166ccf45, 0xa00ae278, 0xd70dd2ee, 0x4e048354, 0x3903b3c2, - 0xa7672661, 0xd06016f7, 0x4969474d, 0x3e6e77db, 0xaed16a4a, 0xd9d65adc, - 0x40df0b66, 0x37d83bf0, 0xa9bcae53, 0xdebb9ec5, 0x47b2cf7f, 0x30b5ffe9, - 0xbdbdf21c, 0xcabac28a, 0x53b39330, 0x24b4a3a6, 0xbad03605, 0xcdd70693, - 0x54de5729, 0x23d967bf, 0xb3667a2e, 0xc4614ab8, 0x5d681b02, 0x2a6f2b94, - 0xb40bbe37, 0xc30c8ea1, 0x5a05df1b, 0x2d02ef8d }; - -static guint32 -fu_dfu_firmware_generate_crc32 (const guint8 *data, gsize length) -{ - guint32 accum = 0xffffffff; - for (guint i = 0; i < length; i++) - accum = _crctbl[(accum^data[i]) & 0xff] ^ (accum >> 8); - return accum; -} - typedef struct __attribute__((packed)) { guint16 release; guint16 pid; @@ -290,7 +236,7 @@ fu_dfu_firmware_parse (FuFirmware *firmware, return FALSE; crc = GUINT32_FROM_LE(ftr.crc); if ((flags & FWUPD_INSTALL_FLAG_FORCE) == 0) { - crc_new = fu_dfu_firmware_generate_crc32 (data, len - 4); + crc_new = ~fu_common_crc32 (data, len - 4); if (crc != crc_new) { g_set_error (error, FWUPD_ERROR, @@ -343,9 +289,7 @@ fu_dfu_firmware_add_footer (FuDfuFirmware *self, GBytes *contents, GError **erro fu_byte_array_append_uint16 (buf, priv->version, G_LITTLE_ENDIAN); g_byte_array_append (buf, (const guint8 *) "UFD", 3); fu_byte_array_append_uint8 (buf, sizeof(FuDfuFirmwareFooter)); - fu_byte_array_append_uint32 (buf, - fu_dfu_firmware_generate_crc32 (buf->data, buf->len), - G_LITTLE_ENDIAN); + fu_byte_array_append_uint32 (buf, ~fu_common_crc32 (buf->data, buf->len), G_LITTLE_ENDIAN); return g_byte_array_free_to_bytes (buf); } diff --git a/libfwupdplugin/fu-self-test.c b/libfwupdplugin/fu-self-test.c index bbc236df2..e6cb49ffc 100644 --- a/libfwupdplugin/fu-self-test.c +++ b/libfwupdplugin/fu-self-test.c @@ -107,6 +107,14 @@ fu_archive_cab_func (void) g_assert_null (data_tmp); } +static void +fu_common_crc_func (void) +{ + guint8 buf[] = { 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09 }; + g_assert_cmpint (fu_common_crc16 (buf, sizeof(buf)), ==, 0x4DF1); + g_assert_cmpint (fu_common_crc32 (buf, sizeof(buf)), ==, 0x40EFAB9E); +} + static void fu_common_string_append_kv_func (void) { @@ -2036,6 +2044,7 @@ main (int argc, char **argv) g_test_add_func ("/fwupd/plugin{quirks-performance}", fu_plugin_quirks_performance_func); g_test_add_func ("/fwupd/plugin{quirks-device}", fu_plugin_quirks_device_func); g_test_add_func ("/fwupd/chunk", fu_chunk_func); + g_test_add_func ("/fwupd/common{crc}", fu_common_crc_func); g_test_add_func ("/fwupd/common{string-append-kv}", fu_common_string_append_kv_func); g_test_add_func ("/fwupd/common{version-guess-format}", fu_common_version_guess_format_func); g_test_add_func ("/fwupd/common{version}", fu_common_version_func); diff --git a/libfwupdplugin/fwupdplugin.map b/libfwupdplugin/fwupdplugin.map index d7acc4980..6a1910db9 100644 --- a/libfwupdplugin/fwupdplugin.map +++ b/libfwupdplugin/fwupdplugin.map @@ -613,6 +613,9 @@ LIBFWUPDPLUGIN_1.4.6 { LIBFWUPDPLUGIN_1.5.0 { global: fu_common_cpuid; + fu_common_crc16; + fu_common_crc32; + fu_common_crc32_full; fu_common_filename_glob; fu_common_is_cpu_intel; fu_device_bind_driver; diff --git a/plugins/vli/fu-vli-common.c b/plugins/vli/fu-vli-common.c index 8c6904af9..38e93537a 100644 --- a/plugins/vli/fu-vli-common.c +++ b/plugins/vli/fu-vli-common.c @@ -24,23 +24,6 @@ fu_vli_common_crc8 (const guint8 *buf, gsize bufsz) return (guint8) (crc >> 8); } -guint16 -fu_vli_common_crc16 (const guint8 *buf, gsize bufsz) -{ - guint16 crc = 0xffff; - for (gsize len = bufsz; len > 0; len--) { - crc = (guint16) (crc ^ (*buf++)); - for (guint8 i = 0; i < 8; i++) { - if (crc & 0x1) { - crc = (crc >> 1) ^ 0xa001; - } else { - crc >>= 1; - } - } - } - return ~crc; -} - const gchar * fu_vli_common_device_kind_to_string (FuVliDeviceKind device_kind) { diff --git a/plugins/vli/fu-vli-common.h b/plugins/vli/fu-vli-common.h index cc652f427..e3c2c9e35 100644 --- a/plugins/vli/fu-vli-common.h +++ b/plugins/vli/fu-vli-common.h @@ -46,5 +46,3 @@ guint32 fu_vli_common_device_kind_get_offset (FuVliDeviceKind device_kind); guint8 fu_vli_common_crc8 (const guint8 *buf, gsize bufsz); -guint16 fu_vli_common_crc16 (const guint8 *buf, - gsize bufsz); diff --git a/plugins/vli/fu-vli-pd-device.c b/plugins/vli/fu-vli-pd-device.c index 4ad683d3b..f71bd1800 100644 --- a/plugins/vli/fu-vli-pd-device.c +++ b/plugins/vli/fu-vli-pd-device.c @@ -7,6 +7,7 @@ #include "config.h" +#include "fu-common.h" #include "fu-firmware.h" #include "fu-vli-pd-device.h" @@ -415,7 +416,7 @@ fu_vli_pd_device_write_dual_firmware (FuVliPdDevice *self, GBytes *fw, GError ** g_prefix_error (error, "failed to read file CRC: "); return FALSE; } - crc_actual = fu_vli_common_crc16 (sbuf, sbufsz - 2); + crc_actual = fu_common_crc16 (sbuf, sbufsz - 2); fu_device_set_status (FU_DEVICE (self), FWUPD_STATUS_DEVICE_WRITE); /* update fw2 first if fw1 correct */ diff --git a/plugins/vli/fu-vli-pd-firmware.c b/plugins/vli/fu-vli-pd-firmware.c index a3391ce9f..78891f79a 100644 --- a/plugins/vli/fu-vli-pd-firmware.c +++ b/plugins/vli/fu-vli-pd-firmware.c @@ -7,6 +7,8 @@ #include "config.h" +#include "fu-common.h" + #include "fu-vli-pd-common.h" #include "fu-vli-pd-firmware.h" @@ -136,7 +138,7 @@ fu_vli_pd_firmware_parse (FuFirmware *firmware, g_prefix_error (error, "failed to read file CRC: "); return FALSE; } - crc_actual = fu_vli_common_crc16 (buf, bufsz - 2); + crc_actual = fu_common_crc16 (buf, bufsz - 2); if (crc_actual != crc_file) { g_set_error (error, FWUPD_ERROR, From 44ae2a75e44a7e6d1b83e8151bcd4bda03a69aee Mon Sep 17 00:00:00 2001 From: Richard Hughes Date: Fri, 25 Sep 2020 18:00:21 +0100 Subject: [PATCH 454/607] trivial: Add CRC8 as well --- libfwupdplugin/fu-common.c | 26 ++++++++++++++++++++++++++ libfwupdplugin/fu-common.h | 2 ++ libfwupdplugin/fu-self-test.c | 1 + libfwupdplugin/fwupdplugin.map | 1 + plugins/vli/fu-vli-common.c | 15 --------------- plugins/vli/fu-vli-common.h | 3 --- plugins/vli/fu-vli-usbhub-common.c | 2 +- 7 files changed, 31 insertions(+), 19 deletions(-) diff --git a/libfwupdplugin/fu-common.c b/libfwupdplugin/fu-common.c index ee8969260..13db2afa5 100644 --- a/libfwupdplugin/fu-common.c +++ b/libfwupdplugin/fu-common.c @@ -2336,6 +2336,32 @@ fu_common_get_esp_for_path (const gchar *esp_path, GError **error) return NULL; } +/** + * fu_common_crc8: + * @buf: memory buffer + * @bufsz: sizeof buf + * + * Returns the cyclic redundancy check value for the given memory buffer. + * + * Returns: CRC value + * + * Since: 1.5.0 + **/ +guint8 +fu_common_crc8 (const guint8 *buf, gsize bufsz) +{ + guint32 crc = 0; + for (gsize j = bufsz; j > 0; j--) { + crc ^= (*(buf++) << 8); + for (guint32 i = 8; i; i--) { + if (crc & 0x8000) + crc ^= (0x1070 << 3); + crc <<= 1; + } + } + return ~((guint8) (crc >> 8)); +} + /** * fu_common_crc16: * @buf: memory buffer diff --git a/libfwupdplugin/fu-common.h b/libfwupdplugin/fu-common.h index 2d15f41c2..c65dafa7c 100644 --- a/libfwupdplugin/fu-common.h +++ b/libfwupdplugin/fu-common.h @@ -240,6 +240,8 @@ FuVolume *fu_common_get_esp_for_path (const gchar *esp_path, GError **error); FuVolume *fu_common_get_esp_default (GError **error); +guint8 fu_common_crc8 (const guint8 *buf, + gsize bufsz); guint16 fu_common_crc16 (const guint8 *buf, gsize bufsz); guint32 fu_common_crc32 (const guint8 *buf, diff --git a/libfwupdplugin/fu-self-test.c b/libfwupdplugin/fu-self-test.c index e6cb49ffc..383788f9d 100644 --- a/libfwupdplugin/fu-self-test.c +++ b/libfwupdplugin/fu-self-test.c @@ -111,6 +111,7 @@ static void fu_common_crc_func (void) { guint8 buf[] = { 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09 }; + g_assert_cmpint (fu_common_crc8 (buf, sizeof(buf)), ==, 0x7A); g_assert_cmpint (fu_common_crc16 (buf, sizeof(buf)), ==, 0x4DF1); g_assert_cmpint (fu_common_crc32 (buf, sizeof(buf)), ==, 0x40EFAB9E); } diff --git a/libfwupdplugin/fwupdplugin.map b/libfwupdplugin/fwupdplugin.map index 6a1910db9..7164d61b3 100644 --- a/libfwupdplugin/fwupdplugin.map +++ b/libfwupdplugin/fwupdplugin.map @@ -616,6 +616,7 @@ LIBFWUPDPLUGIN_1.5.0 { fu_common_crc16; fu_common_crc32; fu_common_crc32_full; + fu_common_crc8; fu_common_filename_glob; fu_common_is_cpu_intel; fu_device_bind_driver; diff --git a/plugins/vli/fu-vli-common.c b/plugins/vli/fu-vli-common.c index 38e93537a..c5b7fda1b 100644 --- a/plugins/vli/fu-vli-common.c +++ b/plugins/vli/fu-vli-common.c @@ -9,21 +9,6 @@ #include "fu-vli-common.h" -guint8 -fu_vli_common_crc8 (const guint8 *buf, gsize bufsz) -{ - guint32 crc = 0; - for (gsize j = bufsz; j > 0; j--) { - crc ^= (*(buf++) << 8); - for (guint32 i = 8; i; i--) { - if (crc & 0x8000) - crc ^= (0x1070 << 3); - crc <<= 1; - } - } - return (guint8) (crc >> 8); -} - const gchar * fu_vli_common_device_kind_to_string (FuVliDeviceKind device_kind) { diff --git a/plugins/vli/fu-vli-common.h b/plugins/vli/fu-vli-common.h index e3c2c9e35..30d964835 100644 --- a/plugins/vli/fu-vli-common.h +++ b/plugins/vli/fu-vli-common.h @@ -43,6 +43,3 @@ const gchar *fu_vli_common_device_kind_to_string (FuVliDeviceKind device_kind); FuVliDeviceKind fu_vli_common_device_kind_from_string (const gchar *device_kind); guint32 fu_vli_common_device_kind_get_size (FuVliDeviceKind device_kind); guint32 fu_vli_common_device_kind_get_offset (FuVliDeviceKind device_kind); - -guint8 fu_vli_common_crc8 (const guint8 *buf, - gsize bufsz); diff --git a/plugins/vli/fu-vli-usbhub-common.c b/plugins/vli/fu-vli-usbhub-common.c index e45ee85d8..3fa77f964 100644 --- a/plugins/vli/fu-vli-usbhub-common.c +++ b/plugins/vli/fu-vli-usbhub-common.c @@ -12,7 +12,7 @@ guint8 fu_vli_usbhub_header_crc8 (FuVliUsbhubHeader *hdr) { - return fu_vli_common_crc8 ((const guint8 *) hdr, sizeof(*hdr) - 1); + return ~fu_common_crc8 ((const guint8 *) hdr, sizeof(*hdr) - 1); } void From 496fb826f136eb32116ada62dd8ae4bdd8c5add6 Mon Sep 17 00:00:00 2001 From: Richard Hughes Date: Fri, 25 Sep 2020 20:04:44 +0100 Subject: [PATCH 455/607] trivial: Add fu_udev_device_get_number() --- libfwupdplugin/fu-udev-device.c | 23 +++++++++++++++++++++++ libfwupdplugin/fu-udev-device.h | 1 + libfwupdplugin/fwupdplugin.map | 1 + 3 files changed, 25 insertions(+) diff --git a/libfwupdplugin/fu-udev-device.c b/libfwupdplugin/fu-udev-device.c index b4e708f3a..beef46da9 100644 --- a/libfwupdplugin/fu-udev-device.c +++ b/libfwupdplugin/fu-udev-device.c @@ -743,6 +743,29 @@ fu_udev_device_get_sysfs_path (FuUdevDevice *self) return NULL; } +/** + * fu_udev_device_get_number: + * @self: A #FuUdevDevice + * + * Gets the device number, if any. + * + * Returns: integer, 0 if the data is unavailable, or %G_MAXUINT64 if the + * feature is not available + * + * Since: 1.5.0 + **/ +guint64 +fu_udev_device_get_number (FuUdevDevice *self) +{ +#ifdef HAVE_GUDEV + FuUdevDevicePrivate *priv = GET_PRIVATE (self); + g_return_val_if_fail (FU_IS_UDEV_DEVICE (self), 0); + if (priv->udev_device != NULL) + return fu_common_strtoull (g_udev_device_get_number (priv->udev_device)); +#endif + return G_MAXUINT64; +} + /** * fu_udev_device_get_vendor: * @self: A #FuUdevDevice diff --git a/libfwupdplugin/fu-udev-device.h b/libfwupdplugin/fu-udev-device.h index 38b63d422..f5698e1cc 100644 --- a/libfwupdplugin/fu-udev-device.h +++ b/libfwupdplugin/fu-udev-device.h @@ -66,6 +66,7 @@ guint32 fu_udev_device_get_model (FuUdevDevice *self); guint32 fu_udev_device_get_subsystem_vendor (FuUdevDevice *self); guint32 fu_udev_device_get_subsystem_model (FuUdevDevice *self); guint8 fu_udev_device_get_revision (FuUdevDevice *self); +guint64 fu_udev_device_get_number (FuUdevDevice *self); guint fu_udev_device_get_slot_depth (FuUdevDevice *self, const gchar *subsystem); gboolean fu_udev_device_set_physical_id (FuUdevDevice *self, diff --git a/libfwupdplugin/fwupdplugin.map b/libfwupdplugin/fwupdplugin.map index 7164d61b3..11edfe335 100644 --- a/libfwupdplugin/fwupdplugin.map +++ b/libfwupdplugin/fwupdplugin.map @@ -652,6 +652,7 @@ LIBFWUPDPLUGIN_1.5.0 { fu_security_attrs_new; fu_security_attrs_remove_all; fu_security_attrs_to_variant; + fu_udev_device_get_number; fu_udev_device_get_subsystem_model; fu_udev_device_get_subsystem_vendor; local: *; From 4986e0f020ed8f70a21e4e763ef0f2496ec1eaa6 Mon Sep 17 00:00:00 2001 From: "boger.wang" Date: Thu, 24 Sep 2020 16:35:19 +0800 Subject: [PATCH 456/607] Add plugin for goodix fingerprint sensors Support updating firmware for Goodix MOC fingerprint sensors. --- contrib/fwupd.spec.in | 1 + plugins/goodix-moc/README.md | 31 ++ plugins/goodix-moc/fu-goodixmoc-common.c | 82 +++++ plugins/goodix-moc/fu-goodixmoc-common.h | 81 +++++ plugins/goodix-moc/fu-goodixmoc-device.c | 398 +++++++++++++++++++++++ plugins/goodix-moc/fu-goodixmoc-device.h | 13 + plugins/goodix-moc/fu-plugin-goodixmoc.c | 19 ++ plugins/goodix-moc/goodixmoc.quirk | 13 + plugins/goodix-moc/meson.build | 31 ++ plugins/meson.build | 1 + 10 files changed, 670 insertions(+) create mode 100644 plugins/goodix-moc/README.md create mode 100644 plugins/goodix-moc/fu-goodixmoc-common.c create mode 100644 plugins/goodix-moc/fu-goodixmoc-common.h create mode 100644 plugins/goodix-moc/fu-goodixmoc-device.c create mode 100644 plugins/goodix-moc/fu-goodixmoc-device.h create mode 100644 plugins/goodix-moc/fu-plugin-goodixmoc.c create mode 100644 plugins/goodix-moc/goodixmoc.quirk create mode 100644 plugins/goodix-moc/meson.build diff --git a/contrib/fwupd.spec.in b/contrib/fwupd.spec.in index 4e69f80ec..1f5cef6cb 100644 --- a/contrib/fwupd.spec.in +++ b/contrib/fwupd.spec.in @@ -437,6 +437,7 @@ mkdir -p --mode=0700 $RPM_BUILD_ROOT%{_localstatedir}/lib/fwupd/gnupg %{_libdir}/fwupd-plugins-3/libfu_plugin_vli.so %{_libdir}/fwupd-plugins-3/libfu_plugin_wacom_raw.so %{_libdir}/fwupd-plugins-3/libfu_plugin_wacom_usb.so +%{_libdir}/fwupd-plugins-3/libfu_plugin_goodixmoc.so %ghost %{_localstatedir}/lib/fwupd/gnupg %if 0%{?have_uefi} %{_datadir}/locale/*/LC_IMAGES/fwupd* diff --git a/plugins/goodix-moc/README.md b/plugins/goodix-moc/README.md new file mode 100644 index 000000000..8c35edbc7 --- /dev/null +++ b/plugins/goodix-moc/README.md @@ -0,0 +1,31 @@ +Goodix Fingerprint Sensor Support +================================= + +Introduction +------------ + +The plugin used for update firmware for fingerprint sensors from Goodix. + +Firmware Format +--------------- + +The daemon will decompress the cabinet archive and extract a firmware blob in +a packed binary file format. + +This plugin supports the following protocol ID: + + * com.goodix.goodixmoc + +GUID Generation +--------------- + +These devices use the standard USB DeviceInstanceId values, e.g. + + * `USB\VID_27C6&PID_6001&REV_0001` + * `USB\VID_27C6&PID_6001` + * `USB\VID_27C6` + +Vendor ID Security +------------------ + +The vendor ID is set from the USB vendor, in this instance set to `USB:0x27C6` diff --git a/plugins/goodix-moc/fu-goodixmoc-common.c b/plugins/goodix-moc/fu-goodixmoc-common.c new file mode 100644 index 000000000..edcb582d6 --- /dev/null +++ b/plugins/goodix-moc/fu-goodixmoc-common.c @@ -0,0 +1,82 @@ +/* + * Copyright (C) 2016-2018 Richard Hughes + * Copyright (C) 2020 boger wang + * + * SPDX-License-Identifier: LGPL-2.1+ + */ + +#include "config.h" + +#include + +#include "fu-common.h" +#include "fu-goodixmoc-common.h" + +void +fu_goodixmoc_build_header (GxfpPkgHeader *pheader, + guint16 len, + guint8 cmd0, + guint8 cmd1, + GxPkgType type) +{ + static guint8 dummy_seq = 0; + + g_return_if_fail (pheader != NULL); + + pheader->cmd0 = (cmd0); + pheader->cmd1 = (cmd1); + pheader->pkg_flag = (guint8)type; + pheader->reserved = dummy_seq++; + pheader->len = len + GX_SIZE_CRC32; + pheader->crc8 = fu_common_crc8 ((guint8 *)pheader, 6); + pheader->rev_crc8 = ~pheader->crc8; +} + +gboolean +fu_goodixmoc_parse_header (guint8 *buf, guint32 bufsz, + GxfpPkgHeader *pheader, GError **error) +{ + g_return_val_if_fail (buf != NULL, FALSE); + g_return_val_if_fail (pheader != NULL, FALSE); + + if (!fu_memcpy_safe ((guint8 *) &pheader, sizeof(*pheader), 0x0, /* dst */ + buf, bufsz, 0x01, /* src */ + sizeof(*pheader), error)) + return FALSE; + memcpy (pheader, buf, sizeof(*pheader)); + pheader->len = GUINT16_FROM_LE(*(buf + 4)); + pheader->len -= GX_SIZE_CRC32; + return TRUE; +} + +gboolean +fu_goodixmoc_parse_body (guint8 cmd, guint8 *buf, guint32 bufsz, + GxfpCmdResp *presp, GError **error) +{ + g_return_val_if_fail (buf != NULL, FALSE); + g_return_val_if_fail (presp != NULL, FALSE); + + presp->result = buf[0]; + switch (cmd) { + case GX_CMD_ACK: + if (bufsz == 0) { + g_set_error_literal (error, + FWUPD_ERROR, + FWUPD_ERROR_INTERNAL, + "invalid bufsz"); + return FALSE; + } + presp->ack_msg.cmd = buf[1]; + break; + case GX_CMD_VERSION: + if (!fu_memcpy_safe ((guint8 *) &presp->version_info, + sizeof(presp->version_info), 0x0, /* dst */ + buf, bufsz, 0x01, /* src */ + sizeof(GxfpVersiomInfo), error)) + return FALSE; + break; + default: + break; + } + return TRUE; +} diff --git a/plugins/goodix-moc/fu-goodixmoc-common.h b/plugins/goodix-moc/fu-goodixmoc-common.h new file mode 100644 index 000000000..499330247 --- /dev/null +++ b/plugins/goodix-moc/fu-goodixmoc-common.h @@ -0,0 +1,81 @@ +/* + * Copyright (C) 2016-2018 Richard Hughes + * Copyright (C) 2020 boger wang + * + * SPDX-License-Identifier: LGPL-2.1+ + */ + +#pragma once + +#include + +/* protocol */ +#define GX_CMD_ACK 0xAA +#define GX_CMD_VERSION 0xD0 +#define GX_CMD_RESET 0xB4 +#define GX_CMD_UPGRADE 0x80 +#define GX_CMD_UPGRADE_INIT 0x00 +#define GX_CMD_UPGRADE_DATA 0x01 +#define GX_CMD1_DEFAULT 0x00 + +#define GX_SIZE_CRC32 4 + +/* type covert */ +#define MAKE_CMD_EX(cmd0, cmd1) ((guint16)(((cmd0) << 8) | (cmd1))) + +typedef struct { + guint8 format[2]; + guint8 fwtype[8]; + guint8 fwversion[8]; + guint8 customer[8]; + guint8 mcu[8]; + guint8 sensor[8]; + guint8 algversion[8]; + guint8 interface[8]; + guint8 protocol[8]; + guint8 flashVersion[8]; + guint8 reserved[62]; +} GxfpVersiomInfo; + +typedef struct { + guint8 cmd; + gboolean configured; +} GxfpAckMsg; + +typedef struct { + guint8 result; + union { + GxfpAckMsg ack_msg; + GxfpVersiomInfo version_info; + }; +} GxfpCmdResp; + +typedef enum { + GX_PKG_TYPE_NORMAL = 0x80, + GX_PKG_TYPE_EOP = 0, +} GxPkgType; + +typedef struct __attribute__((__packed__)) { + guint8 cmd0; + guint8 cmd1; + guint8 pkg_flag; + guint8 reserved; + guint16 len; + guint8 crc8; + guint8 rev_crc8; +} GxfpPkgHeader; + +void fu_goodixmoc_build_header (GxfpPkgHeader *pheader, + guint16 len, + guint8 cmd0, + guint8 cmd1, + GxPkgType type); +gboolean fu_goodixmoc_parse_header (guint8 *buf, + guint32 bufsz, + GxfpPkgHeader *pheader, + GError **error); +gboolean fu_goodixmoc_parse_body (guint8 cmd, + guint8 *buf, + guint32 bufsz, + GxfpCmdResp *presp, + GError **error); diff --git a/plugins/goodix-moc/fu-goodixmoc-device.c b/plugins/goodix-moc/fu-goodixmoc-device.c new file mode 100644 index 000000000..9cbcc5b8f --- /dev/null +++ b/plugins/goodix-moc/fu-goodixmoc-device.c @@ -0,0 +1,398 @@ +/* + * Copyright (C) 2016-2017 Richard Hughes + * Copyright (C) 2020 boger wang + * + * SPDX-License-Identifier: LGPL-2.1+ + */ + +#include "config.h" + +#include "fu-chunk.h" + +#include "fu-goodixmoc-common.h" +#include "fu-goodixmoc-device.h" + +struct _FuGoodixMocDevice { + FuUsbDevice parent_instance; +}; + +G_DEFINE_TYPE (FuGoodixMocDevice, fu_goodixmoc_device, FU_TYPE_USB_DEVICE) + +#define GX_USB_BULK_EP_IN (3 | 0x80) +#define GX_USB_BULK_EP_OUT (1 | 0x00) +#define GX_USB_INTERFACE 0 + +#define GX_USB_DATAIN_TIMEOUT 2000 /* ms */ +#define GX_USB_DATAOUT_TIMEOUT 200 /* ms */ +#define GX_FLASH_TRANSFER_BLOCK_SIZE 1000 /* 1000 */ + +static gboolean +goodixmoc_device_cmd_send (GUsbDevice *usbdevice, + guint8 cmd0, + guint8 cmd1, + GxPkgType type, + GByteArray *req, + GError **error) +{ + GxfpPkgHeader header = { 0 }; + guint32 crc_actual = 0; + gsize actual_len = 0; + g_autoptr(GByteArray) buf = g_byte_array_new (); + + fu_goodixmoc_build_header (&header, req->len, cmd0, cmd1, type); + g_byte_array_append (buf, (guint8 *)&header, sizeof(header)); + g_byte_array_append (buf, req->data, req->len); + crc_actual = fu_common_crc32 (buf->data, sizeof(header) + req->len); + fu_byte_array_append_uint32 (buf, crc_actual, G_LITTLE_ENDIAN); + + /* send zero length package */ + if (!g_usb_device_bulk_transfer (usbdevice, + GX_USB_BULK_EP_OUT, + NULL, + 0, + NULL, + GX_USB_DATAOUT_TIMEOUT, NULL, error)) { + g_prefix_error (error, "failed to req: "); + return FALSE; + } + if (g_getenv ("FWUPD_GOODIXFP_VERBOSE") != NULL) { + fu_common_dump_full (G_LOG_DOMAIN, "REQST", + buf->data, buf->len, 16, + FU_DUMP_FLAGS_SHOW_ADDRESSES); + } + + /* send data */ + if (!g_usb_device_bulk_transfer (usbdevice, + GX_USB_BULK_EP_OUT, + buf->data, + buf->len, + &actual_len, + GX_USB_DATAOUT_TIMEOUT, NULL, error)) { + g_prefix_error (error, "failed to req: "); + return FALSE; + } + if (actual_len != buf->len) { + g_set_error_literal (error, + FWUPD_ERROR, + FWUPD_ERROR_INTERNAL, + "invalid length"); + return FALSE; + } + + /* success */ + return TRUE; +} + +static gboolean +goodixmoc_device_cmd_recv (GUsbDevice *usbdevice, + GxfpCmdResp *presponse, + gboolean data_reply, + GError **error) +{ + GxfpPkgHeader header = { 0 }; + guint32 crc_actual = 0; + gsize actual_len = 0; + gsize offset = 0; + + g_return_val_if_fail (presponse != NULL, FALSE); + + /* + * package format + * | zlp | ack | zlp | data | + */ + while (1) { + g_autoptr(GByteArray) reply = g_byte_array_new (); + g_byte_array_set_size (reply, GX_FLASH_TRANSFER_BLOCK_SIZE); + if (!g_usb_device_bulk_transfer (usbdevice, + GX_USB_BULK_EP_IN, + reply->data, + reply->len, + &actual_len, /* allowed to return short read */ + GX_USB_DATAIN_TIMEOUT, + NULL, error)) { + g_prefix_error (error, "failed to reply: "); + return FALSE; + } + + /* receive zero length package */ + if (actual_len == 0) + continue; + if (g_getenv ("FWUPD_GOODIXFP_VERBOSE") != NULL) { + fu_common_dump_full (G_LOG_DOMAIN, "REPLY", + reply->data, actual_len, 16, + FU_DUMP_FLAGS_SHOW_ADDRESSES); + } + + /* parse package header */ + if (!fu_goodixmoc_parse_header (reply->data, + actual_len, + &header, + error)) + return FALSE; + offset = sizeof(header) + header.len; + crc_actual = fu_common_crc32 (reply->data, offset); + if (crc_actual != GUINT32_FROM_LE(*(guint32 *)(reply->data + offset))) { + g_set_error_literal (error, + FWUPD_ERROR, + FWUPD_ERROR_INTERNAL, + "invalid checksum"); + return FALSE; + } + + /* parse package data */ + if (!fu_goodixmoc_parse_body (header.cmd0, + reply->data + sizeof(header), + header.len, + presponse, + error)) + return FALSE; + + /* continue after ack received */ + if (header.cmd0 == GX_CMD_ACK && data_reply) + continue; + break; + } + + /* success */ + return TRUE; +} + +static gboolean +fu_goodixmoc_device_cmd_xfer (FuGoodixMocDevice *device, + guint8 cmd0, + guint8 cmd1, + GxPkgType type, + GByteArray *req, + GxfpCmdResp *presponse, + gboolean data_reply, + GError **error) +{ + GUsbDevice *usb_device = fu_usb_device_get_dev (FU_USB_DEVICE(device)); + if (!goodixmoc_device_cmd_send (usb_device, cmd0, cmd1, type, req, error)) + return FALSE; + return goodixmoc_device_cmd_recv (usb_device, presponse, data_reply, error); +} + +static gchar * +fu_goodixmoc_device_get_version (FuGoodixMocDevice *self, GError **error) +{ + GxfpCmdResp rsp = { 0 }; + gchar ver[9] = { 0 }; + guint8 dummy = 0; + g_autoptr(GByteArray) req = g_byte_array_new (); + + fu_byte_array_append_uint8 (req, dummy); + if (!fu_goodixmoc_device_cmd_xfer (self, GX_CMD_VERSION, GX_CMD1_DEFAULT, + GX_PKG_TYPE_EOP, + req, + &rsp, + TRUE, + error)) + return NULL; + if (!fu_memcpy_safe ((guint8 *) ver, sizeof(ver), 0x0, + rsp.version_info.fwversion, + sizeof(rsp.version_info.fwversion), + 0x0, + sizeof(rsp.version_info.fwversion), + error)) + return NULL; + return g_strndup (ver, sizeof(ver)); +} + +static gboolean +fu_goodixmoc_device_update_init (FuGoodixMocDevice *self, GError **error) +{ + GxfpCmdResp rsp = { 0 }; + g_autoptr(GByteArray) req = g_byte_array_new (); + + /* update initial */ + if (!fu_goodixmoc_device_cmd_xfer (self, GX_CMD_UPGRADE, GX_CMD_UPGRADE_INIT, + GX_PKG_TYPE_EOP, + req, + &rsp, + TRUE, + error)) { + g_prefix_error (error, "failed to send initial update: "); + return FALSE; + } + + /* check result */ + if (rsp.result != 0) { + g_set_error (error, + FWUPD_ERROR, + FWUPD_ERROR_WRITE, + "initial update failed [0x%x]", + rsp.result); + return FALSE; + } + return TRUE; +} + +static gboolean +fu_goodixmoc_device_attach (FuDevice *device, GError **error) +{ + FuGoodixMocDevice *self = FU_GOODIXMOC_DEVICE(device); + GxfpCmdResp rsp = { 0 }; + g_autoptr(GByteArray) req = g_byte_array_new (); + + /* reset device */ + fu_device_set_status (device, FWUPD_STATUS_DEVICE_RESTART); + if (!fu_goodixmoc_device_cmd_xfer (self, GX_CMD_RESET, 0x03, + GX_PKG_TYPE_EOP, + req, + &rsp, + FALSE, + error)) { + g_prefix_error (error, "failed to send reset device: "); + return FALSE; + } + + /* check result */ + if (rsp.result != 0) { + g_set_error (error, + FWUPD_ERROR, + FWUPD_ERROR_WRITE, + "failed to reset device [0x%x]", + rsp.result); + return FALSE; + } + fu_device_add_flag (device, FWUPD_DEVICE_FLAG_WAIT_FOR_REPLUG); + return TRUE; +} + +static gboolean +fu_goodixmoc_device_open (FuUsbDevice *device, GError **error) +{ + GUsbDevice *usb_device = fu_usb_device_get_dev (device); + return g_usb_device_claim_interface (usb_device, GX_USB_INTERFACE, + G_USB_DEVICE_CLAIM_INTERFACE_BIND_KERNEL_DRIVER, + error); +} + +static gboolean +fu_goodixmoc_device_setup (FuDevice *device, GError **error) +{ + FuGoodixMocDevice *self = FU_GOODIXMOC_DEVICE(device); + g_autofree gchar *version = NULL; + + version = fu_goodixmoc_device_get_version (self, error); + if (version == NULL) { + g_prefix_error (error, "failed to get firmware version: "); + return FALSE; + } + fu_device_set_version (device, version); + + /* success */ + return TRUE; +} + +static gboolean +fu_goodixmoc_device_write_firmware (FuDevice *device, + FuFirmware *firmware, + FwupdInstallFlags flags, + GError **error) +{ + FuGoodixMocDevice *self = FU_GOODIXMOC_DEVICE(device); + GxPkgType pkg_eop = GX_PKG_TYPE_NORMAL; + GxfpCmdResp rsp = { 0 }; + gboolean wait_data_reply = FALSE; + g_autoptr(GBytes) fw = NULL; + g_autoptr(GError) error_local = NULL; + g_autoptr(GPtrArray) chunks = NULL; + + /* get default image */ + fw = fu_firmware_get_image_default_bytes (firmware, error); + if (fw == NULL) + return FALSE; + + /* build packets */ + chunks = fu_chunk_array_new_from_bytes (fw, + 0x00, + 0x00, /* page_sz */ + GX_FLASH_TRANSFER_BLOCK_SIZE); + + /* don't auto-boot firmware */ + fu_device_set_status (device, FWUPD_STATUS_DEVICE_WRITE); + if (!fu_goodixmoc_device_update_init (self, &error_local)) { + g_set_error (error, + FWUPD_ERROR, + FWUPD_ERROR_WRITE, + "failed to initial update: %s", + error_local->message); + return FALSE; + } + + /* write each block */ + for (guint i = 0; i < chunks->len; i++) { + FuChunk *chk = g_ptr_array_index (chunks, i); + g_autoptr(GByteArray) req = g_byte_array_new (); + g_autoptr(GError) error_block = NULL; + + g_byte_array_append (req, chk->data, chk->data_sz); + + /* the last chunk */ + if (i == chunks->len - 1) { + wait_data_reply = TRUE; + pkg_eop = GX_PKG_TYPE_EOP; + } + if (!fu_goodixmoc_device_cmd_xfer (self, + GX_CMD_UPGRADE, + GX_CMD_UPGRADE_DATA, + pkg_eop, + req, + &rsp, + wait_data_reply, + &error_block)) { + g_set_error (error, + FWUPD_ERROR, + FWUPD_ERROR_WRITE, + "failed to write: %s", + error_block->message); + return FALSE; + } + + /* check update status */ + if (wait_data_reply && rsp.result != 0) { + g_set_error (error, + FWUPD_ERROR, + FWUPD_ERROR_WRITE, + "failed to verify firmware [0x%x]", + rsp.result); + return FALSE; + } + + /* update progress */ + fu_device_set_progress_full (device, (gsize) i, (gsize) chunks->len); + } + + /* success! */ + return TRUE; +} + +static void +fu_goodixmoc_device_init (FuGoodixMocDevice *self) +{ + fu_device_add_flag (FU_DEVICE(self), FWUPD_DEVICE_FLAG_UPDATABLE); + fu_device_add_flag (FU_DEVICE(self), FWUPD_DEVICE_FLAG_SELF_RECOVERY); + fu_device_add_flag (FU_DEVICE(self), FWUPD_DEVICE_FLAG_USE_RUNTIME_VERSION); + fu_device_set_version_format (FU_DEVICE(self), FWUPD_VERSION_FORMAT_PLAIN); + fu_device_set_remove_delay (FU_DEVICE(self), 5000); + fu_device_set_protocol (FU_DEVICE (self), "com.goodix.goodixmoc"); + fu_device_set_name (FU_DEVICE(self), "Fingerprint Sensor"); + fu_device_set_summary (FU_DEVICE(self), "Match-On-Chip Fingerprint Sensor"); + fu_device_set_vendor (FU_DEVICE(self), "Goodix"); + fu_device_set_install_duration (FU_DEVICE(self), 10); + fu_device_set_firmware_size_min (FU_DEVICE(self), 0x20000); + fu_device_set_firmware_size_max (FU_DEVICE(self), 0x30000); +} + +static void +fu_goodixmoc_device_class_init(FuGoodixMocDeviceClass *klass) +{ + FuDeviceClass *klass_device = FU_DEVICE_CLASS(klass); + FuUsbDeviceClass *klass_usb_device = FU_USB_DEVICE_CLASS(klass); + klass_device->write_firmware = fu_goodixmoc_device_write_firmware; + klass_device->setup = fu_goodixmoc_device_setup; + klass_device->attach = fu_goodixmoc_device_attach; + klass_usb_device->open = fu_goodixmoc_device_open; +} diff --git a/plugins/goodix-moc/fu-goodixmoc-device.h b/plugins/goodix-moc/fu-goodixmoc-device.h new file mode 100644 index 000000000..0897b65a8 --- /dev/null +++ b/plugins/goodix-moc/fu-goodixmoc-device.h @@ -0,0 +1,13 @@ +/* + * Copyright (C) 2016-2017 Richard Hughes + * Copyright (C) 2020 boger wang + * + * SPDX-License-Identifier: LGPL-2.1+ + */ + +#pragma once + +#include "fu-plugin.h" + +#define FU_TYPE_GOODIXMOC_DEVICE (fu_goodixmoc_device_get_type ()) +G_DECLARE_FINAL_TYPE (FuGoodixMocDevice, fu_goodixmoc_device, FU, GOODIXMOC_DEVICE, FuUsbDevice) diff --git a/plugins/goodix-moc/fu-plugin-goodixmoc.c b/plugins/goodix-moc/fu-plugin-goodixmoc.c new file mode 100644 index 000000000..61e799c4e --- /dev/null +++ b/plugins/goodix-moc/fu-plugin-goodixmoc.c @@ -0,0 +1,19 @@ +/* + * Copyright (C) 2015-2017 Richard Hughes + * Copyright (C) 2020 boger wang + * + * SPDX-License-Identifier: LGPL-2.1+ + */ + +#include "config.h" + +#include "fu-plugin-vfuncs.h" +#include "fu-hash.h" +#include "fu-goodixmoc-device.h" + +void +fu_plugin_init (FuPlugin *plugin) +{ + fu_plugin_set_build_hash (plugin, FU_BUILD_HASH); + fu_plugin_set_device_gtype (plugin, FU_TYPE_GOODIXMOC_DEVICE); +} diff --git a/plugins/goodix-moc/goodixmoc.quirk b/plugins/goodix-moc/goodixmoc.quirk new file mode 100644 index 000000000..fd802133d --- /dev/null +++ b/plugins/goodix-moc/goodixmoc.quirk @@ -0,0 +1,13 @@ +# Goodix Fingerprint sensor +[DeviceInstanceId=USB\VID_27C6&PID_60A2] +Plugin = goodixmoc +[DeviceInstanceId=USB\VID_27C6&PID_6384] +Plugin = goodixmoc +[DeviceInstanceId=USB\VID_27C6&PID_639C] +Plugin = goodixmoc +[DeviceInstanceId=USB\VID_27C6&PID_63AC] +Plugin = goodixmoc +[DeviceInstanceId=USB\VID_27C6&PID_6594] +Plugin = goodixmoc +[DeviceInstanceId=USB\VID_27C6&PID_6496] +Plugin = goodixmoc diff --git a/plugins/goodix-moc/meson.build b/plugins/goodix-moc/meson.build new file mode 100644 index 000000000..4e1287e47 --- /dev/null +++ b/plugins/goodix-moc/meson.build @@ -0,0 +1,31 @@ +cargs = ['-DG_LOG_DOMAIN="FuPluginGoodixMoc"'] + +install_data([ + 'goodixmoc.quirk', + ], + install_dir: join_paths(datadir, 'fwupd', 'quirks.d') +) + +shared_module('fu_plugin_goodixmoc', + fu_hash, + sources : [ + 'fu-goodixmoc-common.c', + 'fu-goodixmoc-device.c', + 'fu-plugin-goodixmoc.c', + ], + include_directories : [ + root_incdir, + fwupd_incdir, + fwupdplugin_incdir, + ], + install : true, + install_dir: plugin_dir, + link_with : [ + fwupd, + fwupdplugin, + ], + c_args : cargs, + dependencies : [ + plugin_deps, + ], +) diff --git a/plugins/meson.build b/plugins/meson.build index 8e1a7956d..15179bbaa 100644 --- a/plugins/meson.build +++ b/plugins/meson.build @@ -31,6 +31,7 @@ subdir('test') subdir('upower') subdir('wacom-usb') subdir('vli') +subdir('goodix-moc') if get_option('plugin_msr') subdir('msr') From c46aa815ea4a6e3857eb0c6dd3c498b131b1bd7c Mon Sep 17 00:00:00 2001 From: Richard Hughes Date: Mon, 28 Sep 2020 14:20:26 +0100 Subject: [PATCH 457/607] trivial: Do not show the libxmlb debugging by default --- libfwupdplugin/fu-cabinet.c | 2 +- libfwupdplugin/fu-quirks.c | 2 +- src/fu-engine.c | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/libfwupdplugin/fu-cabinet.c b/libfwupdplugin/fu-cabinet.c index 86a87954b..6134301a9 100644 --- a/libfwupdplugin/fu-cabinet.c +++ b/libfwupdplugin/fu-cabinet.c @@ -485,7 +485,7 @@ fu_cabinet_build_silo (FuCabinet *self, GBytes *data, GError **error) g_autoptr(XbBuilderFixup) fixup2 = NULL; /* verbose profiling */ - if (g_getenv ("FWUPD_VERBOSE") != NULL) { + if (g_getenv ("FWUPD_XMLB_VERBOSE") != NULL) { xb_builder_set_profile_flags (self->builder, XB_SILO_PROFILE_FLAG_XPATH | XB_SILO_PROFILE_FLAG_DEBUG); diff --git a/libfwupdplugin/fu-quirks.c b/libfwupdplugin/fu-quirks.c index 0125f422c..ffba1420d 100644 --- a/libfwupdplugin/fu-quirks.c +++ b/libfwupdplugin/fu-quirks.c @@ -229,7 +229,7 @@ fu_quirks_check_silo (FuQuirks *self, GError **error) cachedirpkg = fu_common_get_path (FU_PATH_KIND_CACHEDIR_PKG); xmlbfn = g_build_filename (cachedirpkg, "quirks.xmlb", NULL); file = g_file_new_for_path (xmlbfn); - if (g_getenv ("XMLB_VERBOSE") != NULL) { + if (g_getenv ("FWUPD_XMLB_VERBOSE") != NULL) { xb_builder_set_profile_flags (builder, XB_SILO_PROFILE_FLAG_XPATH | XB_SILO_PROFILE_FLAG_DEBUG); diff --git a/src/fu-engine.c b/src/fu-engine.c index d1a4e408f..806407530 100644 --- a/src/fu-engine.c +++ b/src/fu-engine.c @@ -3222,7 +3222,7 @@ fu_engine_load_metadata_store (FuEngine *self, FuEngineLoadFlags flags, GError * g_clear_object (&self->silo); /* verbose profiling */ - if (g_getenv ("FWUPD_VERBOSE") != NULL) { + if (g_getenv ("FWUPD_XMLB_VERBOSE") != NULL) { xb_builder_set_profile_flags (builder, XB_SILO_PROFILE_FLAG_XPATH | XB_SILO_PROFILE_FLAG_DEBUG); From 33dcfb721941a0965827b640e588895b10f7a148 Mon Sep 17 00:00:00 2001 From: Richard Hughes Date: Mon, 28 Sep 2020 15:58:39 +0100 Subject: [PATCH 458/607] trivial: Remove over-eager debugging output --- libfwupdplugin/fu-cabinet.c | 8 +++++--- src/fu-engine.c | 2 -- src/fu-main.c | 18 ++++++++++-------- src/fu-remote-list.c | 2 +- 4 files changed, 16 insertions(+), 14 deletions(-) diff --git a/libfwupdplugin/fu-cabinet.c b/libfwupdplugin/fu-cabinet.c index 6134301a9..32bf6c757 100644 --- a/libfwupdplugin/fu-cabinet.c +++ b/libfwupdplugin/fu-cabinet.c @@ -341,8 +341,11 @@ fu_cabinet_set_container_checksum_cb (XbBuilderFixup *builder_fixup, /* verify it is correct */ if (g_strcmp0 (xb_builder_node_get_text (csum), self->container_checksum) != 0) { - g_debug ("invalid container checksum %s, fixing up to %s", - xb_builder_node_get_text (csum), self->container_checksum); + if (xb_builder_node_get_text (csum) != NULL) { + g_warning ("invalid container checksum %s, fixing up to %s", + xb_builder_node_get_text (csum), + self->container_checksum); + } xb_builder_node_set_text (csum, self->container_checksum, -1); } return TRUE; @@ -504,7 +507,6 @@ fu_cabinet_build_silo (FuCabinet *self, GBytes *data, GError **error) /* adds each metainfo file to the silo */ for (guint i = 0; i < folders->len; i++) { GCabFolder *cabfolder = GCAB_FOLDER (g_ptr_array_index (folders, i)); - g_debug ("processing folder: %u/%u", i + 1, folders->len); if (!fu_cabinet_build_silo_folder (self, cabfolder, error)) return FALSE; } diff --git a/src/fu-engine.c b/src/fu-engine.c index 806407530..0088d5e1d 100644 --- a/src/fu-engine.c +++ b/src/fu-engine.c @@ -4215,7 +4215,6 @@ fu_engine_check_release_is_blocked (FuEngine *self, FwupdRelease *rel) return FALSE; for (guint i = 0; i < csums->len; i++) { const gchar *csum = g_ptr_array_index (csums, i); - g_debug ("checking %s against blocked list", csum); if (g_hash_table_lookup (self->blocked_firmware, csum) != NULL) return TRUE; } @@ -5856,7 +5855,6 @@ fu_engine_load_plugins (FuEngine *self, GError **error) g_signal_connect (plugin, "add-firmware-gtype", G_CALLBACK (fu_engine_plugin_add_firmware_gtype_cb), self); - g_debug ("adding plugin %s", filename); /* if loaded from fu_engine_load() open the plugin */ if (self->usb_ctx != NULL) { diff --git a/src/fu-main.c b/src/fu-main.c index b93f57c98..05074acf7 100644 --- a/src/fu-main.c +++ b/src/fu-main.c @@ -776,10 +776,14 @@ fu_main_install_with_helper (FuMainAuthHelper *helper_ref, GError **error) task, helper->flags | FWUPD_INSTALL_FLAG_FORCE, &error_local)) { - g_debug ("first pass requirement on %s:%s failed: %s", - fu_device_get_id (device), - xb_node_query_text (component, "id", NULL), - error_local->message); + if (!g_error_matches (error_local, + FWUPD_ERROR, + FWUPD_ERROR_NOT_FOUND)) { + g_debug ("first pass requirement on %s:%s failed: %s", + fu_device_get_id (device), + xb_node_query_text (component, "id", NULL), + error_local->message); + } g_ptr_array_add (errors, g_steal_pointer (&error_local)); continue; } @@ -1604,7 +1608,7 @@ fu_main_on_name_acquired_cb (GDBusConnection *connection, const gchar *name, gpointer user_data) { - g_debug ("FuMain: acquired name: %s", name); + g_debug ("acquired name: %s", name); } static void @@ -1857,10 +1861,8 @@ main (int argc, char *argv[]) else if (timed_exit) g_timeout_add_seconds (5, fu_main_timed_exit_cb, priv->loop); - g_debug ("Started with locale %s", g_getenv ("LANG")); - /* wait */ - g_message ("Daemon ready for requests"); + g_message ("Daemon ready for requests (locale %s)", g_getenv ("LANG")); g_main_loop_run (priv->loop); /* success */ diff --git a/src/fu-remote-list.c b/src/fu-remote-list.c index 1646bde3a..68344d6b4 100644 --- a/src/fu-remote-list.c +++ b/src/fu-remote-list.c @@ -183,7 +183,7 @@ fu_remote_list_add_for_path (FuRemoteList *self, const gchar *path, GError **err fwupd_remote_set_remotes_dir (remote, remotesdir); /* load from keyfile */ - g_debug ("loading remotes from %s", filename); + g_debug ("loading remote from %s", filename); if (!fwupd_remote_load_from_filename (remote, filename, NULL, error)) { g_prefix_error (error, "failed to load %s: ", filename); From 3754b007d3db282bbc113f68f068a7850fe4075d Mon Sep 17 00:00:00 2001 From: Richard Hughes Date: Mon, 28 Sep 2020 16:23:56 +0100 Subject: [PATCH 459/607] policy: Make untrusted authorization also imply trusted --- policy/org.freedesktop.fwupd.policy.in | 2 ++ 1 file changed, 2 insertions(+) diff --git a/policy/org.freedesktop.fwupd.policy.in b/policy/org.freedesktop.fwupd.policy.in index 5e45825df..55782c2d7 100644 --- a/policy/org.freedesktop.fwupd.policy.in +++ b/policy/org.freedesktop.fwupd.policy.in @@ -33,6 +33,7 @@ no auth_admin_keep + org.freedesktop.fwupd.update-internal-trusted @@ -66,6 +67,7 @@ no auth_admin_keep + org.freedesktop.fwupd.update-hotplug-trusted From 905ad3e1a729b505d5772a79249c0dfe60720108 Mon Sep 17 00:00:00 2001 From: Richard Hughes Date: Mon, 28 Sep 2020 16:24:27 +0100 Subject: [PATCH 460/607] policy: Make downgrade authorization also imply upgrade --- policy/org.freedesktop.fwupd.policy.in | 2 ++ 1 file changed, 2 insertions(+) diff --git a/policy/org.freedesktop.fwupd.policy.in b/policy/org.freedesktop.fwupd.policy.in index 55782c2d7..60354a9b8 100644 --- a/policy/org.freedesktop.fwupd.policy.in +++ b/policy/org.freedesktop.fwupd.policy.in @@ -45,6 +45,7 @@ no auth_admin_keep + org.freedesktop.fwupd.update-internal @@ -79,6 +80,7 @@ no auth_admin_keep + org.freedesktop.fwupd.update-hotplug From 0430bf2b8ca0a088d4de26c73fec2fdfefceb03c Mon Sep 17 00:00:00 2001 From: Richard Hughes Date: Mon, 28 Sep 2020 16:24:50 +0100 Subject: [PATCH 461/607] policy: Make config modification authorization also imply remote modification --- policy/org.freedesktop.fwupd.policy.in | 1 + 1 file changed, 1 insertion(+) diff --git a/policy/org.freedesktop.fwupd.policy.in b/policy/org.freedesktop.fwupd.policy.in index 60354a9b8..22cb19f7e 100644 --- a/policy/org.freedesktop.fwupd.policy.in +++ b/policy/org.freedesktop.fwupd.policy.in @@ -103,6 +103,7 @@ no auth_admin_keep + org.freedesktop.fwupd.modify-remote From 10ef83c96f3886f9b6f1ad77466d7c6efda56125 Mon Sep 17 00:00:00 2001 From: Mario Limonciello Date: Mon, 28 Sep 2020 13:40:43 -0500 Subject: [PATCH 462/607] trivial: thunderbolt: drop unnecessary verbose statements --- plugins/thunderbolt/fu-thunderbolt-device.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/plugins/thunderbolt/fu-thunderbolt-device.c b/plugins/thunderbolt/fu-thunderbolt-device.c index 7e16d1af5..b7064362c 100644 --- a/plugins/thunderbolt/fu-thunderbolt-device.c +++ b/plugins/thunderbolt/fu-thunderbolt-device.c @@ -212,8 +212,6 @@ fu_thunderbolt_device_get_version (FuThunderboltDevice *self, GError **error) (guint) g_ascii_strtoull (split[0], NULL, 16), (guint) g_ascii_strtoull (split[1], NULL, 16)); fu_device_set_version (FU_DEVICE (self), version); - g_debug ("setting version to %s", version); - g_debug ("path is %s", self->devpath); return TRUE; } From 5d902778e408657159c5696b438c198fcdeaf269 Mon Sep 17 00:00:00 2001 From: Mario Limonciello Date: Mon, 28 Sep 2020 13:58:33 -0500 Subject: [PATCH 463/607] trivial: uefi: remove extra flag for secure boot (shown in device flags) --- plugins/uefi/fu-plugin-uefi.c | 1 - 1 file changed, 1 deletion(-) diff --git a/plugins/uefi/fu-plugin-uefi.c b/plugins/uefi/fu-plugin-uefi.c index d550d51cf..57850c2fc 100644 --- a/plugins/uefi/fu-plugin-uefi.c +++ b/plugins/uefi/fu-plugin-uefi.c @@ -543,7 +543,6 @@ fu_plugin_uefi_test_secure_boot (FuPlugin *plugin) const gchar *result_str = "Disabled"; if (fu_efivar_secure_boot_enabled ()) result_str = "Enabled"; - g_debug ("SecureBoot is: %s", result_str); fu_plugin_add_report_metadata (plugin, "SecureBoot", result_str); } From 67a8b89453ea324f0601503743010ea5c0e7136a Mon Sep 17 00:00:00 2001 From: Mario Limonciello Date: Mon, 28 Sep 2020 13:44:39 -0500 Subject: [PATCH 464/607] trivial: clean up some debugging statements --- libfwupdplugin/fu-plugin.c | 74 ++++++++++++++++----------------- plugins/jabra/fu-plugin-jabra.c | 3 +- plugins/uefi/fu-plugin-uefi.c | 1 - src/fu-engine.c | 20 ++++----- 4 files changed, 48 insertions(+), 50 deletions(-) diff --git a/libfwupdplugin/fu-plugin.c b/libfwupdplugin/fu-plugin.c index 66da432e7..027884de9 100644 --- a/libfwupdplugin/fu-plugin.c +++ b/libfwupdplugin/fu-plugin.c @@ -444,7 +444,7 @@ fu_plugin_open (FuPlugin *self, const gchar *filename, GError **error) /* optional */ g_module_symbol (priv->module, "fu_plugin_init", (gpointer *) &func); if (func != NULL) { - g_debug ("performing init() on %s", filename); + g_debug ("init(%s)", filename); func (self); } @@ -1124,10 +1124,10 @@ fu_plugin_runner_startup (FuPlugin *self, GError **error) g_module_symbol (priv->module, "fu_plugin_startup", (gpointer *) &func); if (func == NULL) return TRUE; - g_debug ("performing startup() on %s", priv->name); + g_debug ("startup(%s)", priv->name); if (!func (self, &error_local)) { if (error_local == NULL) { - g_critical ("unset error in plugin %s for startup()", + g_critical ("unset plugin error in startup(%s)", priv->name); g_set_error_literal (&error_local, FWUPD_ERROR, @@ -1164,16 +1164,16 @@ fu_plugin_runner_device_generic (FuPlugin *self, FuDevice *device, g_module_symbol (priv->module, symbol_name, (gpointer *) &func); if (func == NULL) { if (device_func != NULL) { - g_debug ("running superclassed %s() on %s", + g_debug ("running superclassed %s(%s)", symbol_name + 10, priv->name); return device_func (self, device, error); } return TRUE; } - g_debug ("performing %s() on %s", symbol_name + 10, priv->name); + g_debug ("%s(%s)", symbol_name + 10, priv->name); if (!func (self, device, &error_local)) { if (error_local == NULL) { - g_critical ("unset error in plugin %s for %s()", + g_critical ("unset plugin error in %s(%s)", priv->name, symbol_name + 10); g_set_error_literal (&error_local, FWUPD_ERROR, @@ -1209,10 +1209,10 @@ fu_plugin_runner_flagged_device_generic (FuPlugin *self, FwupdInstallFlags flags g_module_symbol (priv->module, symbol_name, (gpointer *) &func); if (func == NULL) return TRUE; - g_debug ("performing %s() on %s", symbol_name + 10, priv->name); + g_debug ("%s(%s)", symbol_name + 10, priv->name); if (!func (self, flags, device, &error_local)) { if (error_local == NULL) { - g_critical ("unset error in plugin %s for %s()", + g_critical ("unset plugin error in %s(%s)", priv->name, symbol_name + 10); g_set_error_literal (&error_local, FWUPD_ERROR, @@ -1248,10 +1248,10 @@ fu_plugin_runner_device_array_generic (FuPlugin *self, GPtrArray *devices, g_module_symbol (priv->module, symbol_name, (gpointer *) &func); if (func == NULL) return TRUE; - g_debug ("performing %s() on %s", symbol_name + 10, priv->name); + g_debug ("%s(%s)", symbol_name + 10, priv->name); if (!func (self, devices, &error_local)) { if (error_local == NULL) { - g_critical ("unset error in plugin %s for %s()", + g_critical ("unset plugin error in for %s(%s)", priv->name, symbol_name + 10); g_set_error_literal (&error_local, FWUPD_ERROR, @@ -1296,10 +1296,10 @@ fu_plugin_runner_coldplug (FuPlugin *self, GError **error) g_module_symbol (priv->module, "fu_plugin_coldplug", (gpointer *) &func); if (func == NULL) return TRUE; - g_debug ("performing coldplug() on %s", priv->name); + g_debug ("coldplug(%s)", priv->name); if (!func (self, &error_local)) { if (error_local == NULL) { - g_critical ("unset error in plugin %s for coldplug()", + g_critical ("unset plugin error in coldplug(%s)", priv->name); g_set_error_literal (&error_local, FWUPD_ERROR, @@ -1343,10 +1343,10 @@ fu_plugin_runner_recoldplug (FuPlugin *self, GError **error) g_module_symbol (priv->module, "fu_plugin_recoldplug", (gpointer *) &func); if (func == NULL) return TRUE; - g_debug ("performing recoldplug() on %s", priv->name); + g_debug ("recoldplug(%s)", priv->name); if (!func (self, &error_local)) { if (error_local == NULL) { - g_critical ("unset error in plugin %s for recoldplug()", + g_critical ("unset plugin error in recoldplug(%s)", priv->name); g_set_error_literal (&error_local, FWUPD_ERROR, @@ -1391,10 +1391,10 @@ fu_plugin_runner_coldplug_prepare (FuPlugin *self, GError **error) g_module_symbol (priv->module, "fu_plugin_coldplug_prepare", (gpointer *) &func); if (func == NULL) return TRUE; - g_debug ("performing coldplug_prepare() on %s", priv->name); + g_debug ("coldplug_prepare(%s)", priv->name); if (!func (self, &error_local)) { if (error_local == NULL) { - g_critical ("unset error in plugin %s for coldplug_prepare()", + g_critical ("unset plugin error in coldplug_prepare(%s)", priv->name); g_set_error_literal (&error_local, FWUPD_ERROR, @@ -1439,10 +1439,10 @@ fu_plugin_runner_coldplug_cleanup (FuPlugin *self, GError **error) g_module_symbol (priv->module, "fu_plugin_coldplug_cleanup", (gpointer *) &func); if (func == NULL) return TRUE; - g_debug ("performing coldplug_cleanup() on %s", priv->name); + g_debug ("coldplug_cleanup(%s)", priv->name); if (!func (self, &error_local)) { if (error_local == NULL) { - g_critical ("unset error in plugin %s for coldplug_cleanup()", + g_critical ("unset plugin error in coldplug_cleanup(%s)", priv->name); g_set_error_literal (&error_local, FWUPD_ERROR, @@ -1631,7 +1631,7 @@ fu_plugin_runner_add_security_attrs (FuPlugin *self, FuSecurityAttrs *attrs) g_module_symbol (priv->module, symbol_name, (gpointer *) &func); if (func == NULL) return; - g_debug ("performing %s() on %s", symbol_name + 10, priv->name); + g_debug ("%s(%s)", symbol_name + 10, priv->name); func (self, attrs); } @@ -1830,10 +1830,10 @@ fu_plugin_runner_usb_device_added (FuPlugin *self, FuUsbDevice *device, GError * } return TRUE; } - g_debug ("performing usb_device_added() on %s", priv->name); + g_debug ("usb_device_added(%s)", priv->name); if (!func (self, device, &error_local)) { if (error_local == NULL) { - g_critical ("unset error in plugin %s for usb_device_added()", + g_critical ("unset plugin error in usb_device_added(%s)", priv->name); g_set_error_literal (&error_local, FWUPD_ERROR, @@ -1885,10 +1885,10 @@ fu_plugin_runner_udev_device_added (FuPlugin *self, FuUdevDevice *device, GError } return TRUE; } - g_debug ("performing udev_device_added() on %s", priv->name); + g_debug ("udev_device_added(%s)", priv->name); if (!func (self, device, &error_local)) { if (error_local == NULL) { - g_critical ("unset error in plugin %s for udev_device_added()", + g_critical ("unset plugin error in udev_device_added(%s)", priv->name); g_set_error_literal (&error_local, FWUPD_ERROR, @@ -1934,10 +1934,10 @@ fu_plugin_runner_udev_device_changed (FuPlugin *self, FuUdevDevice *device, GErr g_module_symbol (priv->module, "fu_plugin_udev_device_changed", (gpointer *) &func); if (func == NULL) return TRUE; - g_debug ("performing udev_device_changed() on %s", priv->name); + g_debug ("udev_device_changed(%s)", priv->name); if (!func (self, device, &error_local)) { if (error_local == NULL) { - g_critical ("unset error in plugin %s for udev_device_changed()", + g_critical ("unset plugin error in udev_device_changed(%s)", priv->name); g_set_error_literal (&error_local, FWUPD_ERROR, @@ -1977,7 +1977,7 @@ fu_plugin_runner_device_added (FuPlugin *self, FuDevice *device) g_module_symbol (priv->module, "fu_plugin_device_added", (gpointer *) &func); if (func == NULL) return; - g_debug ("performing fu_plugin_device_added() on %s", priv->name); + g_debug ("fu_plugin_device_added(%s)", priv->name); func (self, device); } @@ -2030,7 +2030,7 @@ fu_plugin_runner_device_register (FuPlugin *self, FuDevice *device) /* optional */ g_module_symbol (priv->module, "fu_plugin_device_registered", (gpointer *) &func); if (func != NULL) { - g_debug ("performing fu_plugin_device_registered() on %s", priv->name); + g_debug ("fu_plugin_device_registered(%s)", priv->name); func (self, device); } } @@ -2063,7 +2063,7 @@ fu_plugin_runner_device_created (FuPlugin *self, FuDevice *device, GError **erro g_module_symbol (priv->module, "fu_plugin_device_created", (gpointer *) &func); if (func == NULL) return TRUE; - g_debug ("performing fu_plugin_device_created() on %s", priv->name); + g_debug ("fu_plugin_device_created(%s)", priv->name); return func (self, device, error); } @@ -2117,11 +2117,11 @@ fu_plugin_runner_verify (FuPlugin *self, return FALSE; /* run vfunc */ - g_debug ("performing verify() on %s", priv->name); + g_debug ("verify(%s)", priv->name); if (!func (self, device, flags, &error_local)) { g_autoptr(GError) error_attach = NULL; if (error_local == NULL) { - g_critical ("unset error in plugin %s for verify()", + g_critical ("unset plugin error in verify(%s)", priv->name); g_set_error_literal (&error_local, FWUPD_ERROR, @@ -2276,14 +2276,14 @@ fu_plugin_runner_update (FuPlugin *self, /* optional */ g_module_symbol (priv->module, "fu_plugin_update", (gpointer *) &update_func); if (update_func == NULL) { - g_debug ("running superclassed write_firmware() on %s", priv->name); + g_debug ("superclassed write_firmware(%s)", priv->name); return fu_plugin_device_write_firmware (self, device, blob_fw, flags, error); } /* online */ if (!update_func (self, device, blob_fw, flags, &error_local)) { if (error_local == NULL) { - g_critical ("unset error in plugin %s for update()", + g_critical ("unset plugin error in update(%s)", priv->name); g_set_error_literal (&error_local, FWUPD_ERROR, @@ -2338,10 +2338,10 @@ fu_plugin_runner_clear_results (FuPlugin *self, FuDevice *device, GError **error g_module_symbol (priv->module, "fu_plugin_clear_results", (gpointer *) &func); if (func == NULL) return TRUE; - g_debug ("performing clear_result() on %s", priv->name); + g_debug ("clear_result(%s)", priv->name); if (!func (self, device, &error_local)) { if (error_local == NULL) { - g_critical ("unset error in plugin %s for clear_result()", + g_critical ("unset plugin error in clear_result(%s)", priv->name); g_set_error_literal (&error_local, FWUPD_ERROR, @@ -2387,10 +2387,10 @@ fu_plugin_runner_get_results (FuPlugin *self, FuDevice *device, GError **error) g_module_symbol (priv->module, "fu_plugin_get_results", (gpointer *) &func); if (func == NULL) return TRUE; - g_debug ("performing get_results() on %s", priv->name); + g_debug ("get_results(%s)", priv->name); if (!func (self, device, &error_local)) { if (error_local == NULL) { - g_critical ("unset error in plugin %s for get_results()", + g_critical ("unset plugin error in get_results(%s)", priv->name); g_set_error_literal (&error_local, FWUPD_ERROR, @@ -2762,7 +2762,7 @@ fu_plugin_finalize (GObject *object) if (priv->module != NULL) { g_module_symbol (priv->module, "fu_plugin_destroy", (gpointer *) &func); if (func != NULL) { - g_debug ("performing destroy() on %s", priv->name); + g_debug ("destroy(%s)", priv->name); func (self); } } diff --git a/plugins/jabra/fu-plugin-jabra.c b/plugins/jabra/fu-plugin-jabra.c index 7add28c7d..477806fc6 100644 --- a/plugins/jabra/fu-plugin-jabra.c +++ b/plugins/jabra/fu-plugin-jabra.c @@ -37,7 +37,7 @@ fu_plugin_update_cleanup (FuPlugin *plugin, locker = fu_device_locker_new (device, error); if (locker == NULL) return FALSE; - g_debug ("performing extra reset into firmware mode"); + fu_device_set_status (device, FWUPD_STATUS_DEVICE_RESTART); usb_device = fu_usb_device_get_dev (FU_USB_DEVICE (device)); if (!g_usb_device_reset (usb_device, &error_local)) { g_set_error (error, @@ -50,7 +50,6 @@ fu_plugin_update_cleanup (FuPlugin *plugin, } /* wait for device to re-appear */ - fu_device_set_status (device, FWUPD_STATUS_DEVICE_RESTART); fu_device_add_flag (device, FWUPD_DEVICE_FLAG_WAIT_FOR_REPLUG); return TRUE; } diff --git a/plugins/uefi/fu-plugin-uefi.c b/plugins/uefi/fu-plugin-uefi.c index 57850c2fc..380f98fd9 100644 --- a/plugins/uefi/fu-plugin-uefi.c +++ b/plugins/uefi/fu-plugin-uefi.c @@ -402,7 +402,6 @@ fu_plugin_update (FuPlugin *plugin, g_assert (str != NULL); /* perform the update */ - g_debug ("Performing UEFI capsule update"); fu_device_set_status (device, FWUPD_STATUS_SCHEDULING); if (!fu_plugin_uefi_update_splash (plugin, device, &error_splash)) { g_debug ("failed to upload UEFI UX capsule text: %s", diff --git a/src/fu-engine.c b/src/fu-engine.c index 0088d5e1d..fea18a7b5 100644 --- a/src/fu-engine.c +++ b/src/fu-engine.c @@ -1331,7 +1331,7 @@ fu_engine_check_requirement_id (FuEngine *self, XbNode *req, GError **error) return FALSE; } - g_debug ("requirement %s %s %s on %s passed", + g_debug ("requirement %s %s %s -> %s passed", xb_node_get_attr (req, "version"), xb_node_get_attr (req, "compare"), version, xb_node_get_text (req)); @@ -1757,7 +1757,7 @@ fu_engine_install_tasks (FuEngine *self, g_autoptr(GPtrArray) devices_new = NULL; /* do not allow auto-shutdown during this time */ - locker = fu_idle_locker_new (self->idle, "performing update"); + locker = fu_idle_locker_new (self->idle, "update"); g_assert (locker != NULL); /* notify the plugins about the composite action */ @@ -2506,7 +2506,7 @@ fu_engine_update_prepare (FuEngine *self, fu_device_remove_flag (device, FWUPD_DEVICE_FLAG_ANOTHER_WRITE_REQUIRED); str = fu_device_to_string (device); - g_debug ("performing prepare on %s", str); + g_debug ("prepare -> %s", str); if (!fu_engine_device_prepare (self, device, flags, error)) return FALSE; for (guint j = 0; j < plugins->len; j++) { @@ -2540,7 +2540,7 @@ fu_engine_update_cleanup (FuEngine *self, if (device == NULL) return FALSE; str = fu_device_to_string (device); - g_debug ("performing cleanup on %s", str); + g_debug ("cleanup -> %s", str); if (!fu_engine_device_cleanup (self, device, flags, error)) return FALSE; for (guint j = 0; j < plugins->len; j++) { @@ -2571,7 +2571,7 @@ fu_engine_update_detach (FuEngine *self, const gchar *device_id, GError **error) if (device == NULL) return FALSE; str = fu_device_to_string (device); - g_debug ("performing detach on %s", str); + g_debug ("detach -> %s", str); plugin = fu_plugin_list_find_by_name (self->plugin_list, fu_device_get_plugin (device), error); @@ -2596,7 +2596,7 @@ fu_engine_update_attach (FuEngine *self, const gchar *device_id, GError **error) return FALSE; } str = fu_device_to_string (device); - g_debug ("performing attach on %s", str); + g_debug ("attach -> %s", str); plugin = fu_plugin_list_find_by_name (self->plugin_list, fu_device_get_plugin (device), error); @@ -2624,7 +2624,7 @@ fu_engine_activate (FuEngine *self, const gchar *device_id, GError **error) if (device == NULL) return FALSE; str = fu_device_to_string (device); - g_debug ("performing activate on %s", str); + g_debug ("activate -> %s", str); plugin = fu_plugin_list_find_by_name (self->plugin_list, fu_device_get_plugin (device), error); @@ -2655,7 +2655,7 @@ fu_engine_update_reload (FuEngine *self, const gchar *device_id, GError **error) return FALSE; } str = fu_device_to_string (device); - g_debug ("performing reload on %s", str); + g_debug ("reload -> %s", str); plugin = fu_plugin_list_find_by_name (self->plugin_list, fu_device_get_plugin (device), error); @@ -2698,7 +2698,7 @@ fu_engine_update (FuEngine *self, } device_pending = fu_history_get_device_by_id (self->history, device_id, NULL); str = fu_device_to_string (device); - g_debug ("performing update on %s", str); + g_debug ("update -> %s", str); plugin = fu_plugin_list_find_by_name (self->plugin_list, fu_device_get_plugin (device), error); @@ -5314,7 +5314,7 @@ static gboolean fu_engine_recoldplug_delay_cb (gpointer user_data) { FuEngine *self = (FuEngine *) user_data; - g_debug ("performing a recoldplug"); + g_debug ("recoldplugging"); fu_engine_plugins_coldplug (self, TRUE); self->coldplug_id = 0; return FALSE; From 4a202141836613667baac9140efd3ef1a8e81d80 Mon Sep 17 00:00:00 2001 From: Mario Limonciello Date: Mon, 28 Sep 2020 13:54:03 -0500 Subject: [PATCH 465/607] trivial: fu-engine: don't show 0 devices with subsystem %s message --- src/fu-engine.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/fu-engine.c b/src/fu-engine.c index fea18a7b5..ceac8252b 100644 --- a/src/fu-engine.c +++ b/src/fu-engine.c @@ -5494,8 +5494,9 @@ fu_engine_enumerate_udev (FuEngine *self) const gchar *subsystem = g_ptr_array_index (self->udev_subsystems, i); GList *devices = g_udev_client_query_by_subsystem (self->gudev_client, subsystem); - g_debug ("%u devices with subsystem %s", - g_list_length (devices), subsystem); + if (g_list_length (devices) > 0) + g_debug ("%u devices with subsystem %s", + g_list_length (devices), subsystem); for (GList *l = devices; l != NULL; l = l->next) { GUdevDevice *udev_device = l->data; fu_engine_udev_device_add (self, udev_device); From 7a3664f52b597897f0497bb6c319c24d256d2957 Mon Sep 17 00:00:00 2001 From: Mario Limonciello Date: Mon, 28 Sep 2020 15:04:44 -0500 Subject: [PATCH 466/607] use < instead of less than --- src/fu-engine.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/fu-engine.c b/src/fu-engine.c index ceac8252b..04b4bf533 100644 --- a/src/fu-engine.c +++ b/src/fu-engine.c @@ -4724,7 +4724,7 @@ fu_engine_get_upgrades (FuEngine *self, !fwupd_release_has_flag (rel_tmp, FWUPD_RELEASE_FLAG_IS_DOWNGRADE)) { g_string_append_printf (error_str, "%s=same, ", fwupd_release_get_version (rel_tmp)); - g_debug ("ignoring %s as the same as %s", + g_debug ("ignoring %s == %s", fwupd_release_get_version (rel_tmp), fu_device_get_version (device)); continue; @@ -4734,7 +4734,7 @@ fu_engine_get_upgrades (FuEngine *self, if (fwupd_release_has_flag (rel_tmp, FWUPD_RELEASE_FLAG_IS_DOWNGRADE)) { g_string_append_printf (error_str, "%s=older, ", fwupd_release_get_version (rel_tmp)); - g_debug ("ignoring %s as older than %s", + g_debug ("ignoring %s < %s", fwupd_release_get_version (rel_tmp), fu_device_get_version (device)); continue; From c7cf40ebda68c95acf29247997276147d472141b Mon Sep 17 00:00:00 2001 From: Mario Limonciello Date: Mon, 28 Sep 2020 15:17:39 -0500 Subject: [PATCH 467/607] trivial: fu-engine: simplify missing plugin errors --- src/fu-engine.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/src/fu-engine.c b/src/fu-engine.c index 04b4bf533..b5620b3ed 100644 --- a/src/fu-engine.c +++ b/src/fu-engine.c @@ -5353,8 +5353,7 @@ fu_engine_udev_device_add (FuEngine *self, GUdevDevice *udev_device) plugin = fu_plugin_list_find_by_name (self->plugin_list, plugin_name, &error); if (plugin == NULL) { - g_debug ("failed to find specified plugin %s: %s", - plugin_name, error->message); + g_debug ("%s", error->message); continue; } if (!fu_plugin_runner_udev_device_added (plugin, device, &error)) { @@ -5996,8 +5995,7 @@ fu_engine_usb_device_added_cb (GUsbContext *ctx, plugin = fu_plugin_list_find_by_name (self->plugin_list, plugin_name, &error); if (plugin == NULL) { - g_debug ("failed to find specified plugin %s: %s", - plugin_name, error->message); + g_debug ("%s", error->message); continue; } if (!fu_plugin_runner_usb_device_added (plugin, device, &error)) { From d4155ff67352d167bd0a523ac5bf5d0d8e6afb69 Mon Sep 17 00:00:00 2001 From: Mario Limonciello Date: Mon, 28 Sep 2020 15:20:07 -0500 Subject: [PATCH 468/607] trivial: fu-common: don't mention making directories unless they don't exist --- libfwupdplugin/fu-common.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/libfwupdplugin/fu-common.c b/libfwupdplugin/fu-common.c index 13db2afa5..12e177d41 100644 --- a/libfwupdplugin/fu-common.c +++ b/libfwupdplugin/fu-common.c @@ -163,7 +163,8 @@ fu_common_mkdir_parent (const gchar *filename, GError **error) g_autofree gchar *parent = NULL; parent = g_path_get_dirname (filename); - g_debug ("creating path %s", parent); + if (!g_file_test (parent, G_FILE_TEST_IS_DIR)) + g_debug ("creating path %s", parent); if (g_mkdir_with_parents (parent, 0755) == -1) { g_set_error (error, FWUPD_ERROR, From 2865b6199139ecbed727681896d57b09b359ca9f Mon Sep 17 00:00:00 2001 From: Mario Limonciello Date: Mon, 28 Sep 2020 15:26:33 -0500 Subject: [PATCH 469/607] trivial: don't show messages about missing version format This is a plugin error, it shouldn't be in logs constantly for history devices while plugins load --- libfwupdplugin/fu-common-version.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/libfwupdplugin/fu-common-version.c b/libfwupdplugin/fu-common-version.c index 582e85cde..1b3923a2f 100644 --- a/libfwupdplugin/fu-common-version.c +++ b/libfwupdplugin/fu-common-version.c @@ -444,10 +444,8 @@ fu_common_version_verify_format (const gchar *version, return TRUE; /* nothing we can check for */ - if (fmt == FWUPD_VERSION_FORMAT_UNKNOWN) { - g_debug ("not checking %s as no version format set", version); + if (fmt == FWUPD_VERSION_FORMAT_UNKNOWN) return TRUE; - } /* check the base format */ fmt_guess = fu_common_version_guess_format (version); From c53940e7d7ea2d30eb135f7ae0620853e998d996 Mon Sep 17 00:00:00 2001 From: Mario Limonciello Date: Mon, 28 Sep 2020 15:28:32 -0500 Subject: [PATCH 470/607] trivial: fu-history: don't show message on every device fetch --- src/fu-history.c | 1 - 1 file changed, 1 deletion(-) diff --git a/src/fu-history.c b/src/fu-history.c index 2903fbebd..703e37d94 100644 --- a/src/fu-history.c +++ b/src/fu-history.c @@ -852,7 +852,6 @@ fu_history_get_device_by_id (FuHistory *self, const gchar *device_id, GError **e /* get all the devices */ locker = g_rw_lock_reader_locker_new (&self->db_mutex); g_return_val_if_fail (locker != NULL, NULL); - g_debug ("get device"); rc = sqlite3_prepare_v2 (self->db, "SELECT device_id, " "checksum, " From 9fbd7fe65dbc62325c1c64b260b7bad69bd1af39 Mon Sep 17 00:00:00 2001 From: Daniel Campello Date: Mon, 28 Sep 2020 14:53:39 -0600 Subject: [PATCH 471/607] Allow to filter get-updates on device-id This change allows to get available updates for a given device. This is similar to what is done for the update and activate commands. --- data/bash-completion/fwupdmgr.in | 2 +- data/bash-completion/fwupdtool.in | 2 +- src/fu-tool.c | 24 ++++++++++++++++++++---- src/fu-util.c | 25 +++++++++++++++++++++---- 4 files changed, 43 insertions(+), 10 deletions(-) diff --git a/data/bash-completion/fwupdmgr.in b/data/bash-completion/fwupdmgr.in index 0288c0d34..106a205a0 100644 --- a/data/bash-completion/fwupdmgr.in +++ b/data/bash-completion/fwupdmgr.in @@ -98,7 +98,7 @@ _fwupdmgr() esac case $command in - activate|clear-results|downgrade|get-releases|get-results|unlock|verify|verify-update) + activate|clear-results|downgrade|get-releases|get-results|unlock|verify|verify-update|get-updates) if [[ "$prev" = "$command" ]]; then _show_device_ids else diff --git a/data/bash-completion/fwupdtool.in b/data/bash-completion/fwupdtool.in index 6b46f51b4..7d062e46b 100644 --- a/data/bash-completion/fwupdtool.in +++ b/data/bash-completion/fwupdtool.in @@ -109,7 +109,7 @@ _fwupdtool() _show_modifiers fi ;; - attach|detach|activate|verify-update|reinstall) + attach|detach|activate|verify-update|reinstall|get-updates) if [[ "$prev" = "$command" ]]; then _show_device_ids #modifiers diff --git a/src/fu-tool.c b/src/fu-tool.c index f88cc461c..c97661e44 100644 --- a/src/fu-tool.c +++ b/src/fu-tool.c @@ -328,10 +328,26 @@ fu_util_get_updates (FuUtilPrivate *priv, gchar **values, GError **error) return FALSE; title = fu_util_get_tree_title (priv); - /* get devices from daemon */ - devices = fu_engine_get_devices (priv->engine, error); - if (devices == NULL) + /* parse arguments */ + if (g_strv_length (values) == 0) { + devices = fu_engine_get_devices (priv->engine, error); + if (devices == NULL) + return FALSE; + } else if (g_strv_length (values) == 1) { + FuDevice *device; + device = fu_engine_get_device_by_id (priv->engine, values[0], error); + if (device == NULL) + return FALSE; + devices = g_ptr_array_new_with_free_func ((GDestroyNotify) g_object_unref); + g_ptr_array_add (devices, device); + } else { + g_set_error_literal (error, + FWUPD_ERROR, + FWUPD_ERROR_INVALID_ARGS, + "Invalid arguments"); return FALSE; + } + fwupd_device_array_ensure_parents (devices); g_ptr_array_sort (devices, fu_util_sort_devices_by_flags_cb); for (guint i = 0; i < devices->len; i++) { @@ -2499,7 +2515,7 @@ main (int argc, char *argv[]) fu_util_get_history); fu_util_cmd_array_add (cmd_array, "get-updates,get-upgrades", - NULL, + "[DEVICE-ID|GUID]", /* TRANSLATORS: command description */ _("Gets the list of updates for connected hardware"), fu_util_get_updates); diff --git a/src/fu-util.c b/src/fu-util.c index b16ef7a4e..617d2c366 100644 --- a/src/fu-util.c +++ b/src/fu-util.c @@ -1376,10 +1376,27 @@ fu_util_get_updates (FuUtilPrivate *priv, gchar **values, GError **error) if (!fu_util_perhaps_refresh_remotes (priv, error)) return FALSE; - /* get devices from daemon */ - devices = fwupd_client_get_devices (priv->client, NULL, error); - if (devices == NULL) + /* handle both forms */ + if (g_strv_length (values) == 0) { + devices = fwupd_client_get_devices (priv->client, NULL, error); + if (devices == NULL) + return FALSE; + } else if (g_strv_length (values) == 1) { + FwupdDevice *device = fwupd_client_get_device_by_id (priv->client, + values[0], + NULL, + error); + if (device == NULL) + return FALSE; + devices = g_ptr_array_new_with_free_func ((GDestroyNotify) g_object_unref); + g_ptr_array_add (devices, device); + } else { + g_set_error_literal (error, + FWUPD_ERROR, + FWUPD_ERROR_INVALID_ARGS, + "Invalid arguments"); return FALSE; + } g_ptr_array_sort (devices, fu_util_sort_devices_by_flags_cb); for (guint i = 0; i < devices->len; i++) { FwupdDevice *dev = g_ptr_array_index (devices, i); @@ -2601,7 +2618,7 @@ main (int argc, char *argv[]) fu_util_get_details); fu_util_cmd_array_add (cmd_array, "get-updates,get-upgrades", - NULL, + "[DEVICE-ID|GUID]", /* TRANSLATORS: command description */ _("Gets the list of updates for connected hardware"), fu_util_get_updates); From 177470e9eb9088c1a2cf3a79dd2bc72883fa7c6e Mon Sep 17 00:00:00 2001 From: Sean-StarLabs <38053956+Sean-StarLabs@users.noreply.github.com> Date: Tue, 29 Sep 2020 11:32:58 +0100 Subject: [PATCH 472/607] Update superio.quirk Added Lite Mk III --- plugins/superio/superio.quirk | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/plugins/superio/superio.quirk b/plugins/superio/superio.quirk index 13194972c..5ff98f138 100644 --- a/plugins/superio/superio.quirk +++ b/plugins/superio/superio.quirk @@ -6,6 +6,11 @@ SuperioChipsets=IT8587 [HwId=f00d8c4e-dce2-51c3-89d6-6cbc5fc5cdbb] SuperioChipsets=IT8587 +# Star Lite Mk III +[HwId=23fe120a-f9e1-590d-9e6b-4a2a9274b293] +SuperioChipsets=IT8987 +InstallDuration=20 + # Star LabTop Mk IV [HwId=6ed215ec-75d5-54e9-9c60-7708b325b904] SuperioChipsets=IT8987 From deabfc501203ab9ae77441a7b8e87bc2805058f1 Mon Sep 17 00:00:00 2001 From: Richard Hughes Date: Tue, 29 Sep 2020 12:40:15 +0100 Subject: [PATCH 473/607] uefi-dbx: Do not upload a failure report for a failed dbx check Use one of the errors mapping to FWUPD_UPDATE_STATE_FAILED_TRANSIENT to avoid uploading a failure report for something the user has to fix, i.e. update the distro shim package. --- plugins/uefi-dbx/fu-uefi-dbx-common.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/plugins/uefi-dbx/fu-uefi-dbx-common.c b/plugins/uefi-dbx/fu-uefi-dbx-common.c index 5a00a6cdd..a48528f6f 100644 --- a/plugins/uefi-dbx/fu-uefi-dbx-common.c +++ b/plugins/uefi-dbx/fu-uefi-dbx-common.c @@ -6,6 +6,8 @@ #include "config.h" +#include "fwupd-error.h" + #include "fu-common.h" #include "fu-efi-image.h" #include "fu-efi-signature-common.h" @@ -64,8 +66,8 @@ fu_uefi_dbx_signature_list_validate_volume (GPtrArray *siglists, FuVolume *esp, g_debug ("fn=%s, checksum=%s", fn, checksum); if (fu_efi_signature_list_array_has_checksum (siglists, checksum)) { g_set_error (error, - G_IO_ERROR, - G_IO_ERROR_INVALID_DATA, + FWUPD_ERROR, + FWUPD_ERROR_NEEDS_USER_ACTION, "%s Authenticode checksum [%s] is present in dbx", fn, checksum); return FALSE; From a350198f535890eddc792a099d642db8c548ef90 Mon Sep 17 00:00:00 2001 From: Richard Hughes Date: Tue, 29 Sep 2020 12:07:27 +0100 Subject: [PATCH 474/607] Quit the replug loop on idle If we wait for the child of a composite device to reappear and *then* go on to update the replugged parent in the same transaction then we still use the old GUsbDevice as the add event is still pending when we quit the replug loop. Just schedule an idle action to quit the loop to allow the child *and* parent to be added on replug. Fixes https://github.com/fwupd/fwupd/issues/2376 --- src/fu-device-list.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/src/fu-device-list.c b/src/fu-device-list.c index 30b038e7b..0a73f0a2c 100644 --- a/src/fu-device-list.c +++ b/src/fu-device-list.c @@ -567,6 +567,15 @@ fu_device_list_item_set_device (FuDeviceItem *item, FuDevice *device) g_set_object (&item->device, device); } +static gboolean +fu_device_list_replug_loop_quit_cb (gpointer user_data) +{ + FuDeviceList *self = FU_DEVICE_LIST (user_data); + g_debug ("quitting replug loop"); + g_main_loop_quit (self->replug_loop); + return G_SOURCE_REMOVE; +} + static void fu_device_list_replace (FuDeviceList *self, FuDeviceItem *item, FuDevice *device) { @@ -644,9 +653,9 @@ fu_device_list_replace (FuDeviceList *self, FuDeviceItem *item, FuDevice *device /* we were waiting for this... */ if (fu_device_has_flag (item->device_old, FWUPD_DEVICE_FLAG_WAIT_FOR_REPLUG) && g_main_loop_is_running (self->replug_loop)) { - g_debug ("quitting replug loop"); + g_debug ("schedule quit replug loop in idle"); fu_device_remove_flag (item->device_old, FWUPD_DEVICE_FLAG_WAIT_FOR_REPLUG); - g_main_loop_quit (self->replug_loop); + g_idle_add (fu_device_list_replug_loop_quit_cb, self); } } From 0f89a0d2f0218c26d3764f4987e8d2e5c3df9238 Mon Sep 17 00:00:00 2001 From: Richard Hughes Date: Tue, 29 Sep 2020 09:56:58 +0100 Subject: [PATCH 475/607] Use pkttyagent to request user passwords if running without GUI This change will allow it to use pkcon over remote-shells (ssh) or to use it witout a running GUI desktop environment in the background. Should fix https://github.com/fwupd/fwupd/issues/2429 --- src/fu-polkit-agent.c | 237 ++++++++++++++++++++++++++++++++++++++++++ src/fu-polkit-agent.h | 13 +++ src/fu-progressbar.c | 6 +- src/fu-util.c | 14 +++ src/meson.build | 1 + 5 files changed, 270 insertions(+), 1 deletion(-) create mode 100644 src/fu-polkit-agent.c create mode 100644 src/fu-polkit-agent.h diff --git a/src/fu-polkit-agent.c b/src/fu-polkit-agent.c new file mode 100644 index 000000000..28991320a --- /dev/null +++ b/src/fu-polkit-agent.c @@ -0,0 +1,237 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- + * + * Copyright (C) 2011 Lennart Poettering + * Copyright (C) 2012 Matthias Klumpp + * Copyright (C) 2015-2020 Richard Hughes + * + * SPDX-License-Identifier: LGPL-2.1+ + */ + +#include +#include +#ifdef __linux__ +#include +#endif +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "fu-common.h" +#include "fu-polkit-agent.h" + +static pid_t agent_pid = 0; + +static int +fork_agent (pid_t *pid, const char *path, ...) +{ + char **l; + gboolean stderr_is_tty; + gboolean stdout_is_tty; + int fd; + pid_t n_agent_pid; + pid_t parent_pid; + unsigned n, i; + va_list ap; + + g_return_val_if_fail (pid != 0, 0); + g_assert (path); + + parent_pid = getpid (); + + /* spawns a temporary TTY agent, making sure it goes away when + * we go away */ + n_agent_pid = fork (); + if (n_agent_pid < 0) + return -errno; + + if (n_agent_pid != 0) { + *pid = n_agent_pid; + return 0; + } + +#ifdef __linux__ + /* make sure the agent goes away when the parent dies */ + if (prctl (PR_SET_PDEATHSIG, SIGTERM) < 0) + _exit (EXIT_FAILURE); +#endif + /* check whether our parent died before we were able + * to set the death signal */ + if (getppid () != parent_pid) + _exit (EXIT_SUCCESS); + + /* TODO: it might be more clean to close all FDs so we don't leak them to the agent */ + stdout_is_tty = isatty (STDOUT_FILENO); + stderr_is_tty = isatty (STDERR_FILENO); + + if (!stdout_is_tty || !stderr_is_tty) { + /* Detach from stdout/stderr. and reopen + * /dev/tty for them. This is important to + * ensure that when systemctl is started via + * popen() or a similar call that expects to + * read EOF we actually do generate EOF and + * not delay this indefinitely by because we + * keep an unused copy of stdin around. */ + fd = open("/dev/tty", O_WRONLY); + if (fd < 0) { + g_error ("Failed to open /dev/tty: %m"); + _exit(EXIT_FAILURE); + } + if (!stdout_is_tty) + dup2 (fd, STDOUT_FILENO); + if (!stderr_is_tty) + dup2 (fd, STDERR_FILENO); + if (fd > 2) + close (fd); + } + + /* count arguments */ + va_start (ap, path); + for (n = 0; va_arg (ap, char*); n++) + ; + va_end(ap); + + /* allocate strv */ + l = alloca (sizeof(char *) * (n + 1)); + + /* fill in arguments */ + va_start (ap, path); + for (i = 0; i <= n; i++) + l[i] = va_arg (ap, char*); + va_end (ap); + + execv (path, l); + _exit (EXIT_FAILURE); +} + +static int +close_nointr (int fd) +{ + g_assert (fd >= 0); + for (;;) { + int r; + r = close (fd); + if (r >= 0) + return r; + if (errno != EINTR) + return -errno; + } +} + +static void +close_nointr_nofail (int fd) +{ + int saved_errno = errno; + /* cannot fail, and guarantees errno is unchanged */ + g_assert (close_nointr (fd) == 0); + errno = saved_errno; +} + +static int +fd_wait_for_event (int fd, int event, uint64_t t) +{ + struct pollfd pollfd = { 0 }; + int r; + + pollfd.fd = fd; + pollfd.events = event; + r = poll (&pollfd, 1, t == (uint64_t) -1 ? -1 : (int) (t / 1000)); + if (r < 0) + return -errno; + if (r == 0) + return 0; + + return pollfd.revents; +} + +static int +wait_for_terminate (pid_t pid) +{ + g_return_val_if_fail (pid >= 1, 0); + + for (;;) { + int status; + if (waitpid (pid, &status, 0) < 0) { + if (errno == EINTR) + continue; + return -errno; + } + return 0; + } +} + +gboolean +fu_polkit_agent_open (GError **error) +{ + int r; + int pipe_fd[2]; + g_autofree gchar *notify_fd = NULL; + g_autofree gchar *pkttyagent_fn = NULL; + + if (agent_pid > 0) + return TRUE; + + /* find binary */ + pkttyagent_fn = fu_common_find_program_in_path ("pkttyagent", error); + if (pkttyagent_fn == NULL) + return FALSE; + + /* check STDIN here, not STDOUT, since this is about input, not output */ + if (!isatty (STDIN_FILENO)) + return TRUE; + if (pipe (pipe_fd) < 0) { + g_set_error (error, + G_IO_ERROR, + G_IO_ERROR_FAILED, + "failed to create pipe: %s", + strerror (-errno)); + return FALSE; + } + + /* fork pkttyagent */ + notify_fd = g_strdup_printf ("%i", pipe_fd[1]); + r = fork_agent (&agent_pid, + pkttyagent_fn, + pkttyagent_fn, + "--notify-fd", notify_fd, + "--fallback", NULL); + if (r < 0) { + g_set_error (error, + G_IO_ERROR, + G_IO_ERROR_FAILED, + "failed to fork TTY ask password agent: %s", + strerror (-r)); + close_nointr_nofail (pipe_fd[1]); + close_nointr_nofail (pipe_fd[0]); + return FALSE; + } + + /* close the writing side, because that is the one for the agent */ + close_nointr_nofail (pipe_fd[1]); + + /* wait until the agent closes the fd */ + fd_wait_for_event (pipe_fd[0], POLLHUP, (uint64_t) -1); + + close_nointr_nofail (pipe_fd[0]); + return TRUE; +} + +void +fu_polkit_agent_close (void) { + + if (agent_pid <= 0) + return; + + /* inform agent that we are done */ + kill (agent_pid, SIGTERM); + kill (agent_pid, SIGCONT); + wait_for_terminate (agent_pid); + agent_pid = 0; +} diff --git a/src/fu-polkit-agent.h b/src/fu-polkit-agent.h new file mode 100644 index 000000000..15f3b831e --- /dev/null +++ b/src/fu-polkit-agent.h @@ -0,0 +1,13 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- + * + * Copyright (C) 2011 Lennart Poettering + * Copyright (C) 2012 Matthias Klumpp + * Copyright (C) 2015-2020 Richard Hughes + * + * SPDX-License-Identifier: LGPL-2.1+ + */ + +#pragma once + +gboolean fu_polkit_agent_open (GError **error); +void fu_polkit_agent_close (void); diff --git a/src/fu-progressbar.c b/src/fu-progressbar.c index db0bd6834..9a7378c5a 100644 --- a/src/fu-progressbar.c +++ b/src/fu-progressbar.c @@ -162,6 +162,8 @@ fu_progressbar_refresh (FuProgressbar *self, FwupdStatus status, guint percentag percentage = 100; status = self->status; is_idle_newline = TRUE; + } else if (status == FWUPD_STATUS_WAITING_FOR_AUTH) { + is_idle_newline = TRUE; } title = fu_progressbar_status_to_string (status); g_string_append (str, title); @@ -243,7 +245,8 @@ fu_progressbar_spin_cb (gpointer user_data) FuProgressbar *self = FU_PROGRESSBAR (user_data); /* ignore */ - if (self->status == FWUPD_STATUS_IDLE) + if (self->status == FWUPD_STATUS_IDLE || + self->status == FWUPD_STATUS_WAITING_FOR_AUTH) return G_SOURCE_CONTINUE; /* move the spinner index up to down */ @@ -310,6 +313,7 @@ fu_progressbar_update (FuProgressbar *self, FwupdStatus status, guint percentage * execute the callback just do the refresh now manually */ if (percentage == 0 && status != FWUPD_STATUS_IDLE && + status != FWUPD_STATUS_WAITING_FOR_AUTH && self->status != FWUPD_STATUS_UNKNOWN) { if ((g_get_monotonic_time () - self->last_animated) / 1000 > 40) { fu_progressbar_spin_inc (self); diff --git a/src/fu-util.c b/src/fu-util.c index 617d2c366..c582a5178 100644 --- a/src/fu-util.c +++ b/src/fu-util.c @@ -25,6 +25,7 @@ #include "fu-history.h" #include "fu-plugin-private.h" +#include "fu-polkit-agent.h" #include "fu-progressbar.h" #include "fu-security-attrs.h" #include "fu-util-common.h" @@ -2507,6 +2508,7 @@ main (int argc, char *argv[]) gboolean version = FALSE; g_autoptr(FuUtilPrivate) priv = g_new0 (FuUtilPrivate, 1); g_autoptr(GError) error = NULL; + g_autoptr(GError) error_polkit = NULL; g_autoptr(GPtrArray) cmd_array = fu_util_cmd_array_new (); g_autofree gchar *cmd_descriptions = NULL; g_autofree gchar *filter = NULL; @@ -2845,6 +2847,14 @@ main (int argc, char *argv[]) if (no_history) priv->flags |= FWUPD_INSTALL_FLAG_NO_HISTORY; + /* start polkit tty agent to listen for password requests */ + if (is_interactive) { + if (!fu_polkit_agent_open (&error_polkit)) { + g_printerr ("Failed to open polkit agent: %s\n", + error_polkit->message); + } + } + /* connect to the daemon */ priv->client = fwupd_client_new (); g_signal_connect (priv->client, "notify::percentage", @@ -2930,6 +2940,10 @@ main (int argc, char *argv[]) return EXIT_FAILURE; } + + /* stop listening for polkit questions */ + fu_polkit_agent_close (); + /* success */ return EXIT_SUCCESS; } diff --git a/src/meson.build b/src/meson.build index 8a07de033..953d4705f 100644 --- a/src/meson.build +++ b/src/meson.build @@ -19,6 +19,7 @@ fwupdmgr = executable( 'fu-progressbar.c', 'fu-security-attr.c', 'fu-util-common.c', + 'fu-polkit-agent.c', systemd_src ], include_directories : [ From f8fb2dc436c58d7d0c0881ac78da1143b10145d0 Mon Sep 17 00:00:00 2001 From: Daniel Campello Date: Tue, 29 Sep 2020 13:48:55 -0600 Subject: [PATCH 476/607] Fix get-updates and activate to use GUID in addition to device-id Also merge fu_engine_get_device and fu_engine_get_device_by_id --- src/fu-engine.c | 49 ++++--------- src/fu-engine.h | 3 - src/fu-tool.c | 186 ++++++++++++++++++++++++------------------------ src/fu-util.c | 10 +-- 4 files changed, 108 insertions(+), 140 deletions(-) diff --git a/src/fu-engine.c b/src/fu-engine.c index b5620b3ed..da7fc1954 100644 --- a/src/fu-engine.c +++ b/src/fu-engine.c @@ -2399,19 +2399,17 @@ fu_engine_get_plugins (FuEngine *self) } /** - * fu_engine_get_device_by_id: + * fu_engine_get_device: * @self: A #FuEngine - * @device_id: A string - * @error: A #GError or NULL + * @device_id: A device ID + * @error: A #GError, or %NULL * - * Returns the device from the engine or NULL if not found + * Gets a specific device. * - * Returns: (transfer full): a #FuDevice - * - * Since: 1.5.0 + * Returns: (transfer full): a device, or %NULL if not found **/ FuDevice * -fu_engine_get_device_by_id (FuEngine *self, const gchar *device_id, GError **error) +fu_engine_get_device (FuEngine *self, const gchar *device_id, GError **error) { g_autoptr(FuDevice) device1 = NULL; g_autoptr(FuDevice) device2 = NULL; @@ -2498,7 +2496,7 @@ fu_engine_update_prepare (FuEngine *self, g_autoptr(FuDevice) device = NULL; /* the device and plugin both may have changed */ - device = fu_engine_get_device_by_id (self, device_id, error); + device = fu_engine_get_device (self, device_id, error); if (device == NULL) return FALSE; @@ -2536,7 +2534,7 @@ fu_engine_update_cleanup (FuEngine *self, g_autoptr(FuDevice) device = NULL; /* the device and plugin both may have changed */ - device = fu_engine_get_device_by_id (self, device_id, error); + device = fu_engine_get_device (self, device_id, error); if (device == NULL) return FALSE; str = fu_device_to_string (device); @@ -2567,7 +2565,7 @@ fu_engine_update_detach (FuEngine *self, const gchar *device_id, GError **error) g_autoptr(FuDevice) device = NULL; /* the device and plugin both may have changed */ - device = fu_engine_get_device_by_id (self, device_id, error); + device = fu_engine_get_device (self, device_id, error); if (device == NULL) return FALSE; str = fu_device_to_string (device); @@ -2590,7 +2588,7 @@ fu_engine_update_attach (FuEngine *self, const gchar *device_id, GError **error) g_autoptr(FuDevice) device = NULL; /* the device and plugin both may have changed */ - device = fu_engine_get_device_by_id (self, device_id, error); + device = fu_engine_get_device (self, device_id, error); if (device == NULL) { g_prefix_error (error, "failed to get device after update: "); return FALSE; @@ -2649,7 +2647,7 @@ fu_engine_update_reload (FuEngine *self, const gchar *device_id, GError **error) g_autoptr(FuDevice) device = NULL; /* the device and plugin both may have changed */ - device = fu_engine_get_device_by_id (self, device_id, error); + device = fu_engine_get_device (self, device_id, error); if (device == NULL) { g_prefix_error (error, "failed to get device after update: "); return FALSE; @@ -2691,7 +2689,7 @@ fu_engine_update (FuEngine *self, return FALSE; /* the device and plugin both may have changed */ - device = fu_engine_get_device_by_id (self, device_id, error); + device = fu_engine_get_device (self, device_id, error); if (device == NULL) { g_prefix_error (error, "failed to get device after detach: "); return FALSE; @@ -2838,7 +2836,7 @@ fu_engine_install_blob (FuEngine *self, return FALSE; /* the device and plugin both may have changed */ - device_tmp = fu_engine_get_device_by_id (self, device_id, error); + device_tmp = fu_engine_get_device (self, device_id, error); if (device_tmp == NULL) return FALSE; if (!fu_device_has_flag (device_tmp, FWUPD_DEVICE_FLAG_ANOTHER_WRITE_REQUIRED)) @@ -3964,27 +3962,6 @@ fu_engine_get_devices (FuEngine *self, GError **error) return g_steal_pointer (&devices); } -/** - * fu_engine_get_device: - * @self: A #FuEngine - * @device_id: A device ID - * @error: A #GError, or %NULL - * - * Gets a specific device. - * - * Returns: (transfer full): a device, or %NULL if not found - **/ -FuDevice * -fu_engine_get_device (FuEngine *self, const gchar *device_id, GError **error) -{ - FuDevice *device; - - device = fu_device_list_get_by_id (self->device_list, device_id, error); - if (device == NULL) - return NULL; - return device; -} - /** * fu_engine_get_devices_by_guid: * @self: A #FuEngine diff --git a/src/fu-engine.h b/src/fu-engine.h index 12de88642..97fdd1351 100644 --- a/src/fu-engine.h +++ b/src/fu-engine.h @@ -58,9 +58,6 @@ XbSilo *fu_engine_get_silo_from_blob (FuEngine *self, GError **error); guint64 fu_engine_get_archive_size_max (FuEngine *self); GPtrArray *fu_engine_get_plugins (FuEngine *self); -FuDevice *fu_engine_get_device_by_id (FuEngine *self, - const gchar *device_id, - GError **error); GPtrArray *fu_engine_get_devices (FuEngine *self, GError **error); FuDevice *fu_engine_get_device (FuEngine *self, diff --git a/src/fu-tool.c b/src/fu-tool.c index c97661e44..314884867 100644 --- a/src/fu-tool.c +++ b/src/fu-tool.c @@ -314,6 +314,97 @@ fu_util_get_tree_title (FuUtilPrivate *priv) return g_strdup (fu_engine_get_host_product (priv->engine)); } +static FuDevice * +fu_util_prompt_for_device (FuUtilPrivate *priv, GPtrArray *devices_opt, GError **error) +{ + FuDevice *dev; + guint idx; + g_autoptr(GPtrArray) devices = NULL; + g_autoptr(GPtrArray) devices_filtered = NULL; + + /* get devices from daemon */ + if (devices_opt != NULL) { + devices = g_ptr_array_ref (devices_opt); + } else { + devices = fu_engine_get_devices (priv->engine, error); + if (devices == NULL) + return NULL; + } + fwupd_device_array_ensure_parents (devices); + + /* filter results */ + devices_filtered = g_ptr_array_new_with_free_func ((GDestroyNotify) g_object_unref); + for (guint i = 0; i < devices->len; i++) { + dev = g_ptr_array_index (devices, i); + if (!fu_util_filter_device (priv, FWUPD_DEVICE (dev))) + continue; + g_ptr_array_add (devices_filtered, g_object_ref (dev)); + } + + /* nothing */ + if (devices_filtered->len == 0) { + g_set_error_literal (error, + FWUPD_ERROR, + FWUPD_ERROR_NOTHING_TO_DO, + "No supported devices"); + return NULL; + } + + /* exactly one */ + if (devices_filtered->len == 1) { + dev = g_ptr_array_index (devices_filtered, 0); + /* TRANSLATORS: Device has been chosen by the daemon for the user */ + g_print ("%s: %s\n", _("Selected device"), fu_device_get_name (dev)); + return g_object_ref (dev); + } + + /* TRANSLATORS: get interactive prompt */ + g_print ("%s\n", _("Choose a device:")); + /* TRANSLATORS: this is to abort the interactive prompt */ + g_print ("0.\t%s\n", _("Cancel")); + for (guint i = 0; i < devices_filtered->len; i++) { + dev = g_ptr_array_index (devices_filtered, i); + g_print ("%u.\t%s (%s)\n", + i + 1, + fu_device_get_id (dev), + fu_device_get_name (dev)); + } + idx = fu_util_prompt_for_number (devices_filtered->len); + if (idx == 0) { + g_set_error_literal (error, + FWUPD_ERROR, + FWUPD_ERROR_NOTHING_TO_DO, + "Request canceled"); + return NULL; + } + dev = g_ptr_array_index (devices_filtered, idx - 1); + return g_object_ref (dev); +} + +static FuDevice * +fu_util_get_device (FuUtilPrivate *priv, const gchar *id, GError **error) +{ + if (fwupd_guid_is_valid (id)) { + g_autoptr(GPtrArray) devices = NULL; + devices = fu_engine_get_devices_by_guid (priv->engine, id, error); + if (devices == NULL) + return NULL; + return fu_util_prompt_for_device (priv, devices, error); + } + + /* did this look like a GUID? */ + for (guint i = 0; id[i] != '\0'; i++) { + if (id[i] == '-') { + g_set_error_literal (error, + FWUPD_ERROR, + FWUPD_ERROR_INVALID_ARGS, + "Invalid arguments"); + return NULL; + } + } + return fu_engine_get_device (priv->engine, id, error); +} + static gboolean fu_util_get_updates (FuUtilPrivate *priv, gchar **values, GError **error) { @@ -335,7 +426,7 @@ fu_util_get_updates (FuUtilPrivate *priv, gchar **values, GError **error) return FALSE; } else if (g_strv_length (values) == 1) { FuDevice *device; - device = fu_engine_get_device_by_id (priv->engine, values[0], error); + device = fu_util_get_device (priv, values[0], error); if (device == NULL) return FALSE; devices = g_ptr_array_new_with_free_func ((GDestroyNotify) g_object_unref); @@ -530,73 +621,6 @@ fu_util_get_devices (FuUtilPrivate *priv, gchar **values, GError **error) return fu_util_save_current_state (priv, error); } -static FuDevice * -fu_util_prompt_for_device (FuUtilPrivate *priv, GPtrArray *devices_opt, GError **error) -{ - FuDevice *dev; - guint idx; - g_autoptr(GPtrArray) devices = NULL; - g_autoptr(GPtrArray) devices_filtered = NULL; - - /* get devices from daemon */ - if (devices_opt != NULL) { - devices = g_ptr_array_ref (devices_opt); - } else { - devices = fu_engine_get_devices (priv->engine, error); - if (devices == NULL) - return NULL; - } - fwupd_device_array_ensure_parents (devices); - - /* filter results */ - devices_filtered = g_ptr_array_new_with_free_func ((GDestroyNotify) g_object_unref); - for (guint i = 0; i < devices->len; i++) { - dev = g_ptr_array_index (devices, i); - if (!fu_util_filter_device (priv, FWUPD_DEVICE (dev))) - continue; - g_ptr_array_add (devices_filtered, g_object_ref (dev)); - } - - /* nothing */ - if (devices_filtered->len == 0) { - g_set_error_literal (error, - FWUPD_ERROR, - FWUPD_ERROR_NOTHING_TO_DO, - "No supported devices"); - return NULL; - } - - /* exactly one */ - if (devices_filtered->len == 1) { - dev = g_ptr_array_index (devices_filtered, 0); - /* TRANSLATORS: Device has been chosen by the daemon for the user */ - g_print ("%s: %s\n", _("Selected device"), fu_device_get_name (dev)); - return g_object_ref (dev); - } - - /* TRANSLATORS: get interactive prompt */ - g_print ("%s\n", _("Choose a device:")); - /* TRANSLATORS: this is to abort the interactive prompt */ - g_print ("0.\t%s\n", _("Cancel")); - for (guint i = 0; i < devices_filtered->len; i++) { - dev = g_ptr_array_index (devices_filtered, i); - g_print ("%u.\t%s (%s)\n", - i + 1, - fu_device_get_id (dev), - fu_device_get_name (dev)); - } - idx = fu_util_prompt_for_number (devices_filtered->len); - if (idx == 0) { - g_set_error_literal (error, - FWUPD_ERROR, - FWUPD_ERROR_NOTHING_TO_DO, - "Request canceled"); - return NULL; - } - dev = g_ptr_array_index (devices_filtered, idx - 1); - return g_object_ref (dev); -} - static void fu_util_update_device_changed_cb (FwupdClient *client, FwupdDevice *device, @@ -661,30 +685,6 @@ fu_util_display_current_message (FuUtilPrivate *priv) g_clear_pointer (&priv->current_message, g_free); } -static FuDevice * -fu_util_get_device (FuUtilPrivate *priv, const gchar *id, GError **error) -{ - if (fwupd_guid_is_valid (id)) { - g_autoptr(GPtrArray) devices = NULL; - devices = fu_engine_get_devices_by_guid (priv->engine, id, error); - if (devices == NULL) - return NULL; - return fu_util_prompt_for_device (priv, devices, error); - } - - /* did this look like a GUID? */ - for (guint i = 0; id[i] != '\0'; i++) { - if (id[i] == '-') { - g_set_error_literal (error, - FWUPD_ERROR, - FWUPD_ERROR_INVALID_ARGS, - "Invalid arguments"); - return NULL; - } - } - return fu_engine_get_device (priv->engine, id, error); -} - static gboolean fu_util_install_blob (FuUtilPrivate *priv, gchar **values, GError **error) { @@ -1456,7 +1456,7 @@ fu_util_activate (FuUtilPrivate *priv, gchar **values, GError **error) return FALSE; } else if (g_strv_length (values) == 1) { FuDevice *device; - device = fu_engine_get_device_by_id (priv->engine, values[0], error); + device = fu_util_get_device (priv, values[0], error); if (device == NULL) return FALSE; devices = g_ptr_array_new_with_free_func ((GDestroyNotify) g_object_unref); diff --git a/src/fu-util.c b/src/fu-util.c index c582a5178..0fa62b495 100644 --- a/src/fu-util.c +++ b/src/fu-util.c @@ -1383,10 +1383,7 @@ fu_util_get_updates (FuUtilPrivate *priv, gchar **values, GError **error) if (devices == NULL) return FALSE; } else if (g_strv_length (values) == 1) { - FwupdDevice *device = fwupd_client_get_device_by_id (priv->client, - values[0], - NULL, - error); + FwupdDevice *device = fu_util_get_device_by_id (priv, values[0], error); if (device == NULL) return FALSE; devices = g_ptr_array_new_with_free_func ((GDestroyNotify) g_object_unref); @@ -1891,10 +1888,7 @@ fu_util_activate (FuUtilPrivate *priv, gchar **values, GError **error) } } } else if (g_strv_length (values) == 1) { - FwupdDevice *device = fwupd_client_get_device_by_id (priv->client, - values[0], - NULL, - error); + FwupdDevice *device = fu_util_get_device_by_id (priv, values[0], error); if (device == NULL) return FALSE; devices = g_ptr_array_new_with_free_func ((GDestroyNotify) g_object_unref); From 460c4b75fe0248ef93e04c1f300f73cf5d9a8b58 Mon Sep 17 00:00:00 2001 From: Richard Hughes Date: Fri, 25 Sep 2020 20:59:28 +0100 Subject: [PATCH 477/607] Add the concept of firmware 'branches' This allows a device to identify with different streams, for instance a Lenovo laptop could have a coreboot firmware or a AMI firmware. The GUIDs would be the same, but switching firmware would only be done rarely and very carefully. Another example would be switching the Broadcom BCM57xx nework adaptors from the vendor nonfree firmware with a signed PXE image, to the free software reverse engineered driver with no PXE support (and thus no signed DXE) at all. It is expected firmware would have additional metadata something like this: ... sdcc

      This is an alternate firmware built by the community using only free software tools.

      org.freedesktop.fwupd switch-branch ... Additionally, alternate branch firmware will not be returned for clients not setting the FWUPD_FEATURE_FLAG_SWITCH_BRANCH before the GetReleases request. --- data/bash-completion/fwupdmgr.in | 3 +- data/fish-completion/fwupdmgr.fish | 1 + libfwupd/fwupd-device.c | 53 ++++++++- libfwupd/fwupd-device.h | 5 +- libfwupd/fwupd-enums-private.h | 3 +- libfwupd/fwupd-enums.c | 12 +++ libfwupd/fwupd-enums.h | 6 ++ libfwupd/fwupd-release.c | 51 ++++++++- libfwupd/fwupd-release.h | 5 +- libfwupd/fwupd.map | 4 + libfwupdplugin/fu-device.c | 4 + libfwupdplugin/fu-device.h | 2 + libfwupdplugin/fu-quirks.h | 1 + src/fu-engine.c | 60 +++++++++++ src/fu-util-common.c | 9 ++ src/fu-util.c | 168 +++++++++++++++++++++++++++++ 16 files changed, 381 insertions(+), 6 deletions(-) diff --git a/data/bash-completion/fwupdmgr.in b/data/bash-completion/fwupdmgr.in index 106a205a0..e5a884819 100644 --- a/data/bash-completion/fwupdmgr.in +++ b/data/bash-completion/fwupdmgr.in @@ -26,6 +26,7 @@ _fwupdmgr_cmd_list=( 'report-history' 'security' 'set-approved-firmware' + 'switch-branch' 'unlock' 'unblock-firmware' 'update' @@ -98,7 +99,7 @@ _fwupdmgr() esac case $command in - activate|clear-results|downgrade|get-releases|get-results|unlock|verify|verify-update|get-updates) + activate|clear-results|downgrade|get-releases|get-results|unlock|verify|verify-update|get-updates|switch-branch) if [[ "$prev" = "$command" ]]; then _show_device_ids else diff --git a/data/fish-completion/fwupdmgr.fish b/data/fish-completion/fwupdmgr.fish index aec7e11c9..57e084c59 100644 --- a/data/fish-completion/fwupdmgr.fish +++ b/data/fish-completion/fwupdmgr.fish @@ -53,6 +53,7 @@ complete -c fwupdmgr -n '__fish_use_subcommand' -x -a refresh -d 'Refresh metada complete -c fwupdmgr -n '__fish_use_subcommand' -x -a reinstall -d 'Reinstall current firmware on the device.' complete -c fwupdmgr -n '__fish_use_subcommand' -x -a report-history -d 'Share firmware history with the developers' complete -c fwupdmgr -n '__fish_use_subcommand' -x -a set-approved-firmware -d 'Sets the list of approved firmware.' +complete -c fwupdmgr -n '__fish_use_subcommand' -x -a switch-branch -d 'Switch the firmware branch on the device.' complete -c fwupdmgr -n '__fish_use_subcommand' -x -a unlock -d 'Unlocks the device for firmware access' complete -c fwupdmgr -n '__fish_use_subcommand' -x -a update -d 'Updates all firmware to latest versions available' complete -c fwupdmgr -n '__fish_use_subcommand' -x -a verify -d 'Checks cryptographic hash matches firmware' diff --git a/libfwupd/fwupd-device.c b/libfwupd/fwupd-device.c index 64684b98f..99810a460 100644 --- a/libfwupd/fwupd-device.c +++ b/libfwupd/fwupd-device.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2015-2017 Richard Hughes + * Copyright (C) 2015-2020 Richard Hughes * * SPDX-License-Identifier: LGPL-2.1+ */ @@ -39,6 +39,7 @@ typedef struct { gchar *name; gchar *serial; gchar *summary; + gchar *branch; gchar *description; gchar *vendor; gchar *vendor_id; @@ -172,6 +173,42 @@ fwupd_device_set_summary (FwupdDevice *device, const gchar *summary) priv->summary = g_strdup (summary); } +/** + * fwupd_device_get_branch: + * @device: A #FwupdDevice + * + * Gets the current device branch. + * + * Returns: the device branch, or %NULL if unset + * + * Since: 1.5.0 + **/ +const gchar * +fwupd_device_get_branch (FwupdDevice *device) +{ + FwupdDevicePrivate *priv = GET_PRIVATE (device); + g_return_val_if_fail (FWUPD_IS_DEVICE (device), NULL); + return priv->branch; +} + +/** + * fwupd_device_set_branch: + * @device: A #FwupdDevice + * @branch: the device one line branch + * + * Sets the current device branch. + * + * Since: 1.5.0 + **/ +void +fwupd_device_set_branch (FwupdDevice *device, const gchar *branch) +{ + FwupdDevicePrivate *priv = GET_PRIVATE (device); + g_return_if_fail (FWUPD_IS_DEVICE (device)); + g_free (priv->branch); + priv->branch = g_strdup (branch); +} + /** * fwupd_device_get_serial: * @device: A #FwupdDevice @@ -1189,6 +1226,8 @@ fwupd_device_incorporate (FwupdDevice *self, FwupdDevice *donor) fwupd_device_set_serial (self, priv_donor->serial); if (priv->summary == NULL) fwupd_device_set_summary (self, priv_donor->summary); + if (priv->branch == NULL) + fwupd_device_set_branch (self, priv_donor->branch); if (priv->vendor == NULL) fwupd_device_set_vendor (self, priv_donor->vendor); if (priv->vendor_id == NULL) @@ -1324,6 +1363,11 @@ fwupd_device_to_variant_full (FwupdDevice *device, FwupdDeviceFlags flags) FWUPD_RESULT_KEY_SUMMARY, g_variant_new_string (priv->summary)); } + if (priv->branch != NULL) { + g_variant_builder_add (&builder, "{sv}", + FWUPD_RESULT_KEY_BRANCH, + g_variant_new_string (priv->branch)); + } if (priv->checksums->len > 0) { g_autoptr(GString) str = g_string_new (""); for (guint i = 0; i < priv->checksums->len; i++) { @@ -1536,6 +1580,10 @@ fwupd_device_from_key_value (FwupdDevice *device, const gchar *key, GVariant *va fwupd_device_set_summary (device, g_variant_get_string (value, NULL)); return; } + if (g_strcmp0 (key, FWUPD_RESULT_KEY_BRANCH) == 0) { + fwupd_device_set_branch (device, g_variant_get_string (value, NULL)); + return; + } if (g_strcmp0 (key, FWUPD_RESULT_KEY_DESCRIPTION) == 0) { fwupd_device_set_description (device, g_variant_get_string (value, NULL)); return; @@ -2036,6 +2084,7 @@ fwupd_device_to_json (FwupdDevice *device, JsonBuilder *builder) fwupd_device_json_add_string (builder, FWUPD_RESULT_KEY_SERIAL, priv->serial); fwupd_device_json_add_string (builder, FWUPD_RESULT_KEY_SUMMARY, priv->summary); fwupd_device_json_add_string (builder, FWUPD_RESULT_KEY_DESCRIPTION, priv->description); + fwupd_device_json_add_string (builder, FWUPD_RESULT_KEY_BRANCH, priv->branch); fwupd_device_json_add_string (builder, FWUPD_RESULT_KEY_PLUGIN, priv->plugin); fwupd_device_json_add_string (builder, FWUPD_RESULT_KEY_PROTOCOL, priv->protocol); if (priv->flags != FWUPD_DEVICE_FLAG_NONE) { @@ -2172,6 +2221,7 @@ fwupd_device_to_string (FwupdDevice *device) fwupd_pad_kv_str (str, FWUPD_RESULT_KEY_SERIAL, priv->serial); fwupd_pad_kv_str (str, FWUPD_RESULT_KEY_SUMMARY, priv->summary); fwupd_pad_kv_str (str, FWUPD_RESULT_KEY_DESCRIPTION, priv->description); + fwupd_pad_kv_str (str, FWUPD_RESULT_KEY_BRANCH, priv->branch); fwupd_pad_kv_str (str, FWUPD_RESULT_KEY_PLUGIN, priv->plugin); fwupd_pad_kv_str (str, FWUPD_RESULT_KEY_PROTOCOL, priv->protocol); fwupd_pad_kv_dfl (str, FWUPD_RESULT_KEY_FLAGS, priv->flags); @@ -2343,6 +2393,7 @@ fwupd_device_finalize (GObject *object) g_free (priv->name); g_free (priv->serial); g_free (priv->summary); + g_free (priv->branch); g_free (priv->vendor); g_free (priv->vendor_id); g_free (priv->plugin); diff --git a/libfwupd/fwupd-device.h b/libfwupd/fwupd-device.h index 4dfd593da..db8c8adf3 100644 --- a/libfwupd/fwupd-device.h +++ b/libfwupd/fwupd-device.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2015-2017 Richard Hughes + * Copyright (C) 2015-2020 Richard Hughes * * SPDX-License-Identifier: LGPL-2.1+ */ @@ -51,6 +51,9 @@ void fwupd_device_set_serial (FwupdDevice *device, const gchar *fwupd_device_get_summary (FwupdDevice *device); void fwupd_device_set_summary (FwupdDevice *device, const gchar *summary); +const gchar *fwupd_device_get_branch (FwupdDevice *device); +void fwupd_device_set_branch (FwupdDevice *device, + const gchar *branch); const gchar *fwupd_device_get_description (FwupdDevice *device); void fwupd_device_set_description (FwupdDevice *device, const gchar *description); diff --git a/libfwupd/fwupd-enums-private.h b/libfwupd/fwupd-enums-private.h index 386422eea..deaf86f1d 100644 --- a/libfwupd/fwupd-enums-private.h +++ b/libfwupd/fwupd-enums-private.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2016-2018 Richard Hughes + * Copyright (C) 2016-2020 Richard Hughes * * SPDX-License-Identifier: LGPL-2.1+ */ @@ -45,6 +45,7 @@ G_BEGIN_DECLS #define FWUPD_RESULT_KEY_SIZE "Size" /* t */ #define FWUPD_RESULT_KEY_STATUS "Status" /* u */ #define FWUPD_RESULT_KEY_SUMMARY "Summary" /* s */ +#define FWUPD_RESULT_KEY_BRANCH "Branch" /* s */ #define FWUPD_RESULT_KEY_TRUST_FLAGS "TrustFlags" /* t */ #define FWUPD_RESULT_KEY_UPDATE_MESSAGE "UpdateMessage" /* s */ #define FWUPD_RESULT_KEY_UPDATE_IMAGE "UpdateImage" /* s */ diff --git a/libfwupd/fwupd-enums.c b/libfwupd/fwupd-enums.c index 63ebf6d42..af349107f 100644 --- a/libfwupd/fwupd-enums.c +++ b/libfwupd/fwupd-enums.c @@ -197,6 +197,8 @@ fwupd_device_flag_to_string (FwupdDeviceFlags device_flag) return "updatable-hidden"; if (device_flag == FWUPD_DEVICE_FLAG_SKIPS_RESTART) return "skips-restart"; + if (device_flag == FWUPD_DEVICE_FLAG_HAS_MULTIPLE_BRANCHES) + return "has-multiple-branches"; if (device_flag == FWUPD_DEVICE_FLAG_UNKNOWN) return "unknown"; return NULL; @@ -295,6 +297,8 @@ fwupd_device_flag_from_string (const gchar *device_flag) return FWUPD_DEVICE_FLAG_UPDATABLE_HIDDEN; if (g_strcmp0 (device_flag, "skips-restart") == 0) return FWUPD_DEVICE_FLAG_SKIPS_RESTART; + if (g_strcmp0 (device_flag, "has-multiple-branches") == 0) + return FWUPD_DEVICE_FLAG_HAS_MULTIPLE_BRANCHES; return FWUPD_DEVICE_FLAG_UNKNOWN; } @@ -419,6 +423,8 @@ fwupd_feature_flag_to_string (FwupdFeatureFlags feature_flag) return "detach-action"; if (feature_flag == FWUPD_FEATURE_FLAG_UPDATE_ACTION) return "update-action"; + if (feature_flag == FWUPD_FEATURE_FLAG_SWITCH_BRANCH) + return "switch-branch"; return NULL; } @@ -443,6 +449,8 @@ fwupd_feature_flag_from_string (const gchar *feature_flag) return FWUPD_FEATURE_FLAG_DETACH_ACTION; if (g_strcmp0 (feature_flag, "update-action") == 0) return FWUPD_FEATURE_FLAG_UPDATE_ACTION; + if (g_strcmp0 (feature_flag, "switch-branch") == 0) + return FWUPD_FEATURE_FLAG_SWITCH_BRANCH; return FWUPD_FEATURE_FLAG_LAST; } @@ -521,6 +529,8 @@ fwupd_release_flag_to_string (FwupdReleaseFlags release_flag) return "blocked-version"; if (release_flag == FWUPD_RELEASE_FLAG_BLOCKED_APPROVAL) return "blocked-approval"; + if (release_flag == FWUPD_RELEASE_FLAG_IS_ALTERNATE_BRANCH) + return "is-alternate-branch"; return NULL; } @@ -549,6 +559,8 @@ fwupd_release_flag_from_string (const gchar *release_flag) return FWUPD_RELEASE_FLAG_BLOCKED_VERSION; if (g_strcmp0 (release_flag, "blocked-approval") == 0) return FWUPD_RELEASE_FLAG_BLOCKED_APPROVAL; + if (g_strcmp0 (release_flag, "is-alternate-branch") == 0) + return FWUPD_RELEASE_FLAG_IS_ALTERNATE_BRANCH; return FWUPD_RELEASE_FLAG_NONE; } diff --git a/libfwupd/fwupd-enums.h b/libfwupd/fwupd-enums.h index c402a88af..785a28a72 100644 --- a/libfwupd/fwupd-enums.h +++ b/libfwupd/fwupd-enums.h @@ -70,6 +70,7 @@ typedef enum { * @FWUPD_FEATURE_FLAG_CAN_REPORT: Can upload a report of the update back to the server * @FWUPD_FEATURE_FLAG_DETACH_ACTION: Can perform detach action, typically showing text * @FWUPD_FEATURE_FLAG_UPDATE_ACTION: Can perform update action, typically showing text + * @FWUPD_FEATURE_FLAG_SWITCH_BRANCH: Can switch the firmware branch * * The flags to the feature capabilities of the front-end client. **/ @@ -78,6 +79,7 @@ typedef enum { FWUPD_FEATURE_FLAG_CAN_REPORT = 1 << 0, /* Since: 1.4.5 */ FWUPD_FEATURE_FLAG_DETACH_ACTION = 1 << 1, /* Since: 1.4.5 */ FWUPD_FEATURE_FLAG_UPDATE_ACTION = 1 << 2, /* Since: 1.4.5 */ + FWUPD_FEATURE_FLAG_SWITCH_BRANCH = 1 << 3, /* Since: 1.5.0 */ /*< private >*/ FWUPD_FEATURE_FLAG_LAST } FwupdFeatureFlags; @@ -124,6 +126,7 @@ typedef enum { * @FWUPD_DEVICE_FLAG_NO_GUID_MATCHING: Force an explicit ID match when adding devices to the device list * @FWUPD_DEVICE_FLAG_UPDATABLE_HIDDEN: Device is updatable but should not be called by the client * @FWUPD_DEVICE_FLAG_SKIPS_RESTART: Device relies upon activation or power cycle to load firmware + * @FWUPD_DEVICE_FLAG_HAS_MULTIPLE_BRANCHES: Device supports switching to a different stream of firmware * * The device flags. **/ @@ -167,6 +170,7 @@ typedef enum { #define FWUPD_DEVICE_FLAG_NO_GUID_MATCHING (1llu << 36) /* Since: 1.4.1 */ #define FWUPD_DEVICE_FLAG_UPDATABLE_HIDDEN (1llu << 37) /* Since: 1.4.1 */ #define FWUPD_DEVICE_FLAG_SKIPS_RESTART (1llu << 38) /* Since: 1.5.0 */ +#define FWUPD_DEVICE_FLAG_HAS_MULTIPLE_BRANCHES (1llu << 39) /* Since: 1.5.0 */ #define FWUPD_DEVICE_FLAG_UNKNOWN G_MAXUINT64 /* Since: 0.7.3 */ typedef guint64 FwupdDeviceFlags; @@ -179,6 +183,7 @@ typedef guint64 FwupdDeviceFlags; * @FWUPD_RELEASE_FLAG_IS_DOWNGRADE: Is older than the device version * @FWUPD_RELEASE_FLAG_BLOCKED_VERSION: Blocked as below device version-lowest * @FWUPD_RELEASE_FLAG_BLOCKED_APPROVAL: Blocked as release not approved + * @FWUPD_RELEASE_FLAG_IS_ALTERNATE_BRANCH: Is an alternate branch of firmware * * The release flags. **/ @@ -189,6 +194,7 @@ typedef guint64 FwupdDeviceFlags; #define FWUPD_RELEASE_FLAG_IS_DOWNGRADE (1u << 3) /* Since: 1.2.6 */ #define FWUPD_RELEASE_FLAG_BLOCKED_VERSION (1u << 4) /* Since: 1.2.6 */ #define FWUPD_RELEASE_FLAG_BLOCKED_APPROVAL (1u << 5) /* Since: 1.2.6 */ +#define FWUPD_RELEASE_FLAG_IS_ALTERNATE_BRANCH (1u << 6) /* Since: 1.5.0 */ #define FWUPD_RELEASE_FLAG_UNKNOWN G_MAXUINT64 /* Since: 1.2.6 */ typedef guint64 FwupdReleaseFlags; diff --git a/libfwupd/fwupd-release.c b/libfwupd/fwupd-release.c index 875b4e518..86cd3fcb7 100644 --- a/libfwupd/fwupd-release.c +++ b/libfwupd/fwupd-release.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2015-2018 Richard Hughes + * Copyright (C) 2015-2020 Richard Hughes * * SPDX-License-Identifier: LGPL-2.1+ */ @@ -46,6 +46,7 @@ typedef struct { gchar *name; gchar *name_variant_suffix; gchar *summary; + gchar *branch; gchar *uri; gchar *vendor; gchar *version; @@ -934,6 +935,42 @@ fwupd_release_set_summary (FwupdRelease *release, const gchar *summary) priv->summary = g_strdup (summary); } +/** + * fwupd_release_get_branch: + * @release: A #FwupdRelease + * + * Gets the update branch. + * + * Returns: the alternate branch, or %NULL if unset + * + * Since: 1.5.0 + **/ +const gchar * +fwupd_release_get_branch (FwupdRelease *release) +{ + FwupdReleasePrivate *priv = GET_PRIVATE (release); + g_return_val_if_fail (FWUPD_IS_RELEASE (release), NULL); + return priv->branch; +} + +/** + * fwupd_release_set_branch: + * @release: A #FwupdRelease + * @branch: the update one line branch + * + * Sets the alternate branch. + * + * Since: 1.5.0 + **/ +void +fwupd_release_set_branch (FwupdRelease *release, const gchar *branch) +{ + FwupdReleasePrivate *priv = GET_PRIVATE (release); + g_return_if_fail (FWUPD_IS_RELEASE (release)); + g_free (priv->branch); + priv->branch = g_strdup (branch); +} + /** * fwupd_release_get_vendor: * @release: A #FwupdRelease @@ -1354,6 +1391,11 @@ fwupd_release_to_variant (FwupdRelease *release) FWUPD_RESULT_KEY_SUMMARY, g_variant_new_string (priv->summary)); } + if (priv->branch != NULL) { + g_variant_builder_add (&builder, "{sv}", + FWUPD_RESULT_KEY_BRANCH, + g_variant_new_string (priv->branch)); + } if (priv->description != NULL) { g_variant_builder_add (&builder, "{sv}", FWUPD_RESULT_KEY_DESCRIPTION, @@ -1492,6 +1534,10 @@ fwupd_release_from_key_value (FwupdRelease *release, const gchar *key, GVariant fwupd_release_set_summary (release, g_variant_get_string (value, NULL)); return; } + if (g_strcmp0 (key, FWUPD_RESULT_KEY_BRANCH) == 0) { + fwupd_release_set_branch (release, g_variant_get_string (value, NULL)); + return; + } if (g_strcmp0 (key, FWUPD_RESULT_KEY_DESCRIPTION) == 0) { fwupd_release_set_description (release, g_variant_get_string (value, NULL)); return; @@ -1675,6 +1721,7 @@ fwupd_release_to_json (FwupdRelease *release, JsonBuilder *builder) fwupd_release_json_add_string (builder, FWUPD_RESULT_KEY_REMOTE_ID, priv->remote_id); fwupd_release_json_add_string (builder, FWUPD_RESULT_KEY_SUMMARY, priv->summary); fwupd_release_json_add_string (builder, FWUPD_RESULT_KEY_DESCRIPTION, priv->description); + fwupd_release_json_add_string (builder, FWUPD_RESULT_KEY_BRANCH, priv->branch); fwupd_release_json_add_string (builder, FWUPD_RESULT_KEY_VERSION, priv->version); fwupd_release_json_add_string (builder, FWUPD_RESULT_KEY_FILENAME, priv->filename); fwupd_release_json_add_string (builder, FWUPD_RESULT_KEY_PROTOCOL, priv->protocol); @@ -1764,6 +1811,7 @@ fwupd_release_to_string (FwupdRelease *release) fwupd_pad_kv_str (str, FWUPD_RESULT_KEY_REMOTE_ID, priv->remote_id); fwupd_pad_kv_str (str, FWUPD_RESULT_KEY_SUMMARY, priv->summary); fwupd_pad_kv_str (str, FWUPD_RESULT_KEY_DESCRIPTION, priv->description); + fwupd_pad_kv_str (str, FWUPD_RESULT_KEY_BRANCH, priv->branch); fwupd_pad_kv_str (str, FWUPD_RESULT_KEY_VERSION, priv->version); fwupd_pad_kv_str (str, FWUPD_RESULT_KEY_FILENAME, priv->filename); fwupd_pad_kv_str (str, FWUPD_RESULT_KEY_PROTOCOL, priv->protocol); @@ -1844,6 +1892,7 @@ fwupd_release_finalize (GObject *object) g_free (priv->name); g_free (priv->name_variant_suffix); g_free (priv->summary); + g_free (priv->branch); g_free (priv->uri); g_free (priv->homepage); g_free (priv->details_url); diff --git a/libfwupd/fwupd-release.h b/libfwupd/fwupd-release.h index d00979047..051863101 100644 --- a/libfwupd/fwupd-release.h +++ b/libfwupd/fwupd-release.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2015-2018 Richard Hughes + * Copyright (C) 2015-2020 Richard Hughes * * SPDX-License-Identifier: LGPL-2.1+ */ @@ -90,6 +90,9 @@ void fwupd_release_set_name_variant_suffix (FwupdRelease *release, const gchar *fwupd_release_get_summary (FwupdRelease *release); void fwupd_release_set_summary (FwupdRelease *release, const gchar *summary); +const gchar *fwupd_release_get_branch (FwupdRelease *release); +void fwupd_release_set_branch (FwupdRelease *release, + const gchar *branch); const gchar *fwupd_release_get_description (FwupdRelease *release); void fwupd_release_set_description (FwupdRelease *release, const gchar *description); diff --git a/libfwupd/fwupd.map b/libfwupd/fwupd.map index a1ca0ff4d..6cce79529 100644 --- a/libfwupd/fwupd.map +++ b/libfwupd/fwupd.map @@ -552,6 +552,10 @@ LIBFWUPD_1.5.0 { fwupd_client_verify_finish; fwupd_client_verify_update_async; fwupd_client_verify_update_finish; + fwupd_device_get_branch; + fwupd_device_set_branch; + fwupd_release_get_branch; + fwupd_release_set_branch; fwupd_remote_get_automatic_security_reports; fwupd_remote_get_security_report_uri; fwupd_security_attr_add_flag; diff --git a/libfwupdplugin/fu-device.c b/libfwupdplugin/fu-device.c index 645f07b94..adff698dc 100644 --- a/libfwupdplugin/fu-device.c +++ b/libfwupdplugin/fu-device.c @@ -973,6 +973,10 @@ fu_device_set_quirk_kv (FuDevice *self, fu_device_set_summary (self, value); return TRUE; } + if (g_strcmp0 (key, FU_QUIRKS_BRANCH) == 0) { + fu_device_set_branch (self, value); + return TRUE; + } if (g_strcmp0 (key, FU_QUIRKS_VENDOR) == 0) { fu_device_set_vendor (self, value); return TRUE; diff --git a/libfwupdplugin/fu-device.h b/libfwupdplugin/fu-device.h index 3468ce781..2b389e659 100644 --- a/libfwupdplugin/fu-device.h +++ b/libfwupdplugin/fu-device.h @@ -132,6 +132,7 @@ FuDevice *fu_device_new (void); #define fu_device_set_plugin(d,v) fwupd_device_set_plugin(FWUPD_DEVICE(d),v) #define fu_device_set_serial(d,v) fwupd_device_set_serial(FWUPD_DEVICE(d),v) #define fu_device_set_summary(d,v) fwupd_device_set_summary(FWUPD_DEVICE(d),v) +#define fu_device_set_branch(d,v) fwupd_device_set_branch(FWUPD_DEVICE(d),v) #define fu_device_set_update_message(d,v) fwupd_device_set_update_message(FWUPD_DEVICE(d),v) #define fu_device_set_update_image(d,v) fwupd_device_set_update_image(FWUPD_DEVICE(d),v) #define fu_device_set_update_error(d,v) fwupd_device_set_update_error(FWUPD_DEVICE(d),v) @@ -154,6 +155,7 @@ FuDevice *fu_device_new (void); #define fu_device_get_name(d) fwupd_device_get_name(FWUPD_DEVICE(d)) #define fu_device_get_serial(d) fwupd_device_get_serial(FWUPD_DEVICE(d)) #define fu_device_get_summary(d) fwupd_device_get_summary(FWUPD_DEVICE(d)) +#define fu_device_get_branch(d) fwupd_device_get_branch(FWUPD_DEVICE(d)) #define fu_device_get_id(d) fwupd_device_get_id(FWUPD_DEVICE(d)) #define fu_device_get_plugin(d) fwupd_device_get_plugin(FWUPD_DEVICE(d)) #define fu_device_get_update_error(d) fwupd_device_get_update_error(FWUPD_DEVICE(d)) diff --git a/libfwupdplugin/fu-quirks.h b/libfwupdplugin/fu-quirks.h index 763c365e6..49be5c236 100644 --- a/libfwupdplugin/fu-quirks.h +++ b/libfwupdplugin/fu-quirks.h @@ -48,6 +48,7 @@ gboolean fu_quirks_lookup_by_id_iter (FuQuirks *self, #define FU_QUIRKS_SUMMARY "Summary" #define FU_QUIRKS_ICON "Icon" #define FU_QUIRKS_NAME "Name" +#define FU_QUIRKS_BRANCH "Branch" #define FU_QUIRKS_GUID "Guid" #define FU_QUIRKS_COUNTERPART_GUID "CounterpartGuid" #define FU_QUIRKS_PARENT_GUID "ParentGuid" diff --git a/src/fu-engine.c b/src/fu-engine.c index da7fc1954..222862741 100644 --- a/src/fu-engine.c +++ b/src/fu-engine.c @@ -356,6 +356,9 @@ fu_engine_set_release_from_appstream (FuEngine *self, tmp = xb_node_query_text (component, "summary", NULL); if (tmp != NULL) fwupd_release_set_summary (rel, tmp); + tmp = xb_node_query_text (component, "branch", NULL); + if (tmp != NULL) + fwupd_release_set_branch (rel, tmp); tmp = xb_node_query_text (component, "developer_name", NULL); if (tmp != NULL) fwupd_release_set_vendor (rel, tmp); @@ -4164,6 +4167,14 @@ fu_engine_sort_releases_cb (gconstpointer a, gconstpointer b, gpointer user_data FuDevice *device = FU_DEVICE (user_data); FwupdRelease *rel_a = FWUPD_RELEASE (*((FwupdRelease **) a)); FwupdRelease *rel_b = FWUPD_RELEASE (*((FwupdRelease **) b)); + gint rc; + + /* first by branch */ + rc = g_strcmp0 (fwupd_release_get_branch (rel_b), fwupd_release_get_branch (rel_a)); + if (rc != 0) + return rc; + + /* then by version */ return fu_common_vercmp_full (fwupd_release_get_version (rel_b), fwupd_release_get_version (rel_a), fu_device_get_version_format (device)); @@ -4206,6 +4217,7 @@ fu_engine_add_releases_for_device_component (FuEngine *self, GPtrArray *releases, GError **error) { + FwupdFeatureFlags feature_flags; FwupdVersionFormat fmt = fu_device_get_version_format (device); g_autoptr(GError) error_local = NULL; g_autoptr(FuInstallTask) task = fu_install_task_new (device, component); @@ -4228,6 +4240,7 @@ fu_engine_add_releases_for_device_component (FuEngine *self, g_propagate_error (error, g_steal_pointer (&error_local)); return FALSE; } + feature_flags = fu_engine_request_get_feature_flags (request); for (guint i = 0; i < releases_tmp->len; i++) { XbNode *release = g_ptr_array_index (releases_tmp, i); const gchar *remote_id; @@ -4261,6 +4274,18 @@ fu_engine_add_releases_for_device_component (FuEngine *self, if (checksums->len == 0) continue; + /* different branch */ + if (g_strcmp0 (fwupd_release_get_branch (rel), + fu_device_get_branch (device)) != 0) { + if ((feature_flags & FWUPD_FEATURE_FLAG_SWITCH_BRANCH) == 0) { + g_debug ("client does not understand branches, skipping %s:%s", + fwupd_release_get_branch (rel), + fwupd_release_get_version (rel)); + continue; + } + fwupd_release_add_flag (rel, FWUPD_RELEASE_FLAG_IS_ALTERNATE_BRANCH); + } + /* test for upgrade or downgrade */ vercmp = fu_common_vercmp_full (fwupd_release_get_version (rel), fu_device_get_version (device), @@ -4323,6 +4348,7 @@ fu_engine_get_releases_for_device (FuEngine *self, const gchar *version; g_autoptr(GError) error_all = NULL; g_autoptr(GError) error_local = NULL; + g_autoptr(GPtrArray) branches = NULL; g_autoptr(GPtrArray) components = NULL; g_autoptr(GString) xpath = g_string_new (NULL); @@ -4389,6 +4415,21 @@ fu_engine_get_releases_for_device (FuEngine *self, } } + /* are there multiple branches available */ + branches = g_ptr_array_new_with_free_func (g_free); + for (guint i = 0; i < releases->len; i++) { + FwupdRelease *rel_tmp = FWUPD_RELEASE (g_ptr_array_index (releases, i)); + const gchar *branch_tmp = fwupd_release_get_branch (rel_tmp); + if (branch_tmp == NULL) + branch_tmp = "default"; + if (g_ptr_array_find_with_equal_func (branches, branch_tmp, + g_str_equal, NULL)) + continue; + g_ptr_array_add (branches, g_strdup (branch_tmp)); + } + if (branches->len > 0) + fu_device_add_flag (device, FWUPD_DEVICE_FLAG_HAS_MULTIPLE_BRANCHES); + /* return the compound error */ if (releases->len == 0) { if (error_all != NULL) { @@ -4518,6 +4559,16 @@ fu_engine_get_downgrades (FuEngine *self, fu_device_get_version_lowest (device)); continue; } + + /* different branch */ + if (fwupd_release_has_flag (rel_tmp, FWUPD_RELEASE_FLAG_IS_ALTERNATE_BRANCH)) { + g_debug ("ignoring release %s as branch %s, and device is %s", + fwupd_release_get_version (rel_tmp), + fwupd_release_get_branch (rel_tmp), + fu_device_get_branch (device)); + continue; + } + g_ptr_array_add (releases, g_object_ref (rel_tmp)); } if (error_str->len > 2) @@ -4727,6 +4778,15 @@ fu_engine_get_upgrades (FuEngine *self, continue; } + /* different branch */ + if (fwupd_release_has_flag (rel_tmp, FWUPD_RELEASE_FLAG_IS_ALTERNATE_BRANCH)) { + g_debug ("ignoring release %s as branch %s, and device is %s", + fwupd_release_get_version (rel_tmp), + fwupd_release_get_branch (rel_tmp), + fu_device_get_branch (device)); + continue; + } + g_ptr_array_add (releases, g_object_ref (rel_tmp)); } if (error_str->len > 2) diff --git a/src/fu-util-common.c b/src/fu-util-common.c index 6f3352a88..c0cc85d1e 100644 --- a/src/fu-util-common.c +++ b/src/fu-util-common.c @@ -1073,6 +1073,10 @@ fu_util_device_flag_to_string (guint64 device_flag) /* TRANSLATORS: a version check is required for all firmware */ return _("Device is required to install all provided releases"); } + if (device_flag == FWUPD_DEVICE_FLAG_HAS_MULTIPLE_BRANCHES) { + /* TRANSLATORS: there is more than one supplier of the firmware */ + return _("Device supports switching to a different branch of firmware"); + } if (device_flag == FWUPD_DEVICE_FLAG_MD_SET_NAME) { /* skip */ return NULL; @@ -1337,6 +1341,11 @@ fu_util_release_to_string (FwupdRelease *rel, guint idt) fu_common_string_append_kv (str, idt + 1, _("Remote ID"), fwupd_release_get_remote_id (rel)); } + if (fwupd_release_get_branch (rel) != NULL) { + /* TRANSLATORS: the stream of firmware, e.g. nonfree or open-source */ + fu_common_string_append_kv (str, idt + 1, _("Branch"), + fwupd_release_get_branch (rel)); + } if (fwupd_release_get_summary (rel) != NULL) { /* TRANSLATORS: one line summary of device */ fu_common_string_append_kv (str, idt + 1, _("Summary"), diff --git a/src/fu-util.c b/src/fu-util.c index 0fa62b495..9b30dec34 100644 --- a/src/fu-util.c +++ b/src/fu-util.c @@ -1868,6 +1868,167 @@ fu_util_reinstall (FuUtilPrivate *priv, gchar **values, GError **error) return fu_util_prompt_complete (priv->completion_flags, TRUE, error); } +static gboolean +fu_util_switch_branch_warning (FuUtilPrivate *priv, + FwupdDevice *dev, + FwupdRelease *rel, + GError **error) +{ + const gchar *desc_markup = NULL; + g_autofree gchar *desc_plain = NULL; + g_autoptr(GString) desc_full = g_string_new (NULL); + + /* warn the user if the vendor is different */ + if (g_strcmp0 (fwupd_device_get_vendor (dev), fwupd_release_get_vendor (rel)) != 0) { + /* TRANSLATORS: %1 is the firmware vendor, %2 is the device vendor name */ + g_string_append_printf (desc_full, _("The firmware from %s is not " + "supplied by %s, the hardware vendor."), + fwupd_release_get_vendor (rel), + fwupd_device_get_vendor (dev)); + g_string_append (desc_full, "\n\n"); + /* TRANSLATORS: %1 is the device vendor name */ + g_string_append_printf (desc_full, _("Your hardware may be damaged using this firmware, " + "and installing this release may void any warranty " + "with %s."), + fwupd_device_get_vendor (dev)); + g_string_append (desc_full, "\n\n"); + } + + /* from the in the AppStream data */ + desc_markup = fwupd_release_get_description (rel); + if (desc_markup == NULL) + return TRUE; + desc_plain = fu_util_convert_description (desc_markup, error); + if (desc_plain == NULL) + return FALSE; + g_string_append (desc_full, desc_plain); + + /* show and ask user to confirm */ + fu_util_warning_box (desc_full->str, 80); + if (!priv->assume_yes) { + /* ask for permission */ + g_print ("\n%s [y|N]: ", + /* TRANSLATORS: should the branch be changed */ + _("Do you understand the consequences of changing the firmware branch?")); + if (!fu_util_prompt_for_boolean (FALSE)) { + g_set_error_literal (error, + FWUPD_ERROR, + FWUPD_ERROR_NOTHING_TO_DO, + "Declined branch switch"); + return FALSE; + } + } + return TRUE; +} + +static gboolean +fu_util_switch_branch (FuUtilPrivate *priv, gchar **values, GError **error) +{ + const gchar *remote_id; + const gchar *branch; + g_autoptr(FwupdRelease) rel = NULL; + g_autoptr(GPtrArray) rels = NULL; + g_autoptr(GPtrArray) branches = g_ptr_array_new_with_free_func (g_free); + g_autoptr(FwupdDevice) dev = NULL; + + /* find the device and check it has multiple branches */ + priv->filter_include |= FWUPD_DEVICE_FLAG_SUPPORTED; + dev = fu_util_get_device_or_prompt (priv, values, error); + if (dev == NULL) + return FALSE; + if (!fwupd_device_has_flag (dev, FWUPD_DEVICE_FLAG_HAS_MULTIPLE_BRANCHES)) { + g_set_error_literal (error, + FWUPD_ERROR, + FWUPD_ERROR_NOT_SUPPORTED, + "Multiple branches not available"); + return FALSE; + } + + /* get all releases, including the alternate branch versions */ + rels = fwupd_client_get_releases (priv->client, fwupd_device_get_id (dev), + NULL, error); + if (rels == NULL) + return FALSE; + + /* branch name is optional */ + if (g_strv_length (values) > 1) { + branch = values[1]; + if (g_strcmp0 (branch, fu_device_get_branch (dev)) == 0) { + g_set_error (error, + FWUPD_ERROR, + FWUPD_ERROR_NOT_SUPPORTED, + "Device %s is already on branch %s", + fu_device_get_name (dev), + branch); + return FALSE; + } + } else { + guint idx; + + /* TRANSLATORS: get interactive prompt, where branch is the + * supplier of the firmware, e.g. "non-free" or "free" */ + g_print ("%s\n", _("Choose a branch:")); + /* TRANSLATORS: this is to abort the interactive prompt */ + g_print ("0.\t%s\n", _("Cancel")); + for (guint i = 0; i < branches->len; i++) { + const gchar *branch_tmp = g_ptr_array_index (branches, i); + g_print ("%u.\t%s\n", i + 1, branch_tmp); + } + idx = fu_util_prompt_for_number (branches->len); + if (idx == 0) { + g_set_error_literal (error, + FWUPD_ERROR, + FWUPD_ERROR_NOTHING_TO_DO, + "Request canceled"); + return FALSE; + } + branch = g_ptr_array_index (branches, idx - 1); + } + + /* the releases are ordered by version */ + for (guint j = 0; j < rels->len; j++) { + FwupdRelease *rel_tmp = g_ptr_array_index (rels, j); + if (g_strcmp0 (fwupd_release_get_branch (rel_tmp), branch) == 0) { + rel = g_object_ref (rel_tmp); + break; + } + } + if (rel == NULL) { + g_set_error (error, + FWUPD_ERROR, + FWUPD_ERROR_NOT_SUPPORTED, + "No releases for branch %s", + branch); + return FALSE; + } + + /* we're switching branch */ + if (!fu_util_switch_branch_warning (priv, dev, rel, error)) + return FALSE; + + /* update the console if composite devices are also updated */ + priv->current_operation = FU_UTIL_OPERATION_INSTALL; + g_signal_connect (priv->client, "device-changed", + G_CALLBACK (fu_util_update_device_changed_cb), priv); + priv->flags |= FWUPD_INSTALL_FLAG_ALLOW_REINSTALL; + if (!fu_util_update_device_with_release (priv, dev, rel, error)) + return FALSE; + fu_util_display_current_message (priv); + + /* send report if we're supposed to */ + remote_id = fwupd_release_get_remote_id (rel); + if (!fu_util_maybe_send_reports (priv, remote_id, error)) + return FALSE; + + /* we don't want to ask anything */ + if (priv->no_reboot_check) { + g_debug ("skipping reboot check"); + return TRUE; + } + + return fu_util_prompt_complete (priv->completion_flags, TRUE, error); +} + static gboolean fu_util_activate (FuUtilPrivate *priv, gchar **values, GError **error) { @@ -2732,6 +2893,12 @@ main (int argc, char *argv[]) /* TRANSLATORS: command description */ _("Reinstall current firmware on the device."), fu_util_reinstall); + fu_util_cmd_array_add (cmd_array, + "switch-branch", + "[DEVICE-ID|GUID] [BRANCH]", + /* TRANSLATORS: command description */ + _("Switch the firmware branch on the device."), + fu_util_switch_branch); fu_util_cmd_array_add (cmd_array, "security", NULL, @@ -2911,6 +3078,7 @@ main (int argc, char *argv[]) if (is_interactive) { if (!fwupd_client_set_feature_flags (priv->client, FWUPD_FEATURE_FLAG_CAN_REPORT | + FWUPD_FEATURE_FLAG_SWITCH_BRANCH | FWUPD_FEATURE_FLAG_UPDATE_ACTION | FWUPD_FEATURE_FLAG_DETACH_ACTION, priv->cancellable, &error)) { From 1a612582395c4259e036d8b2f0f42ed7e441e59b Mon Sep 17 00:00:00 2001 From: Richard Hughes Date: Tue, 29 Sep 2020 19:39:38 +0100 Subject: [PATCH 478/607] Allow devices to save the old firmware to disk for recovery This would also help, for example, to go back to the nonfree firmware when the alternate firmware did not work as well as hoped. It would also allow flashing the firmware using an SPI programmer if everything went very wrong indeed. --- libfwupd/fwupd-enums.c | 4 ++++ libfwupd/fwupd-enums.h | 2 ++ libfwupdplugin/fu-plugin.c | 26 ++++++++++++++++++++++++++ src/fu-util-common.c | 4 ++++ 4 files changed, 36 insertions(+) diff --git a/libfwupd/fwupd-enums.c b/libfwupd/fwupd-enums.c index af349107f..a35cf31e7 100644 --- a/libfwupd/fwupd-enums.c +++ b/libfwupd/fwupd-enums.c @@ -199,6 +199,8 @@ fwupd_device_flag_to_string (FwupdDeviceFlags device_flag) return "skips-restart"; if (device_flag == FWUPD_DEVICE_FLAG_HAS_MULTIPLE_BRANCHES) return "has-multiple-branches"; + if (device_flag == FWUPD_DEVICE_FLAG_BACKUP_BEFORE_INSTALL) + return "backup-before-install"; if (device_flag == FWUPD_DEVICE_FLAG_UNKNOWN) return "unknown"; return NULL; @@ -299,6 +301,8 @@ fwupd_device_flag_from_string (const gchar *device_flag) return FWUPD_DEVICE_FLAG_SKIPS_RESTART; if (g_strcmp0 (device_flag, "has-multiple-branches") == 0) return FWUPD_DEVICE_FLAG_HAS_MULTIPLE_BRANCHES; + if (g_strcmp0 (device_flag, "backup-before-install") == 0) + return FWUPD_DEVICE_FLAG_BACKUP_BEFORE_INSTALL; return FWUPD_DEVICE_FLAG_UNKNOWN; } diff --git a/libfwupd/fwupd-enums.h b/libfwupd/fwupd-enums.h index 785a28a72..cda52db1f 100644 --- a/libfwupd/fwupd-enums.h +++ b/libfwupd/fwupd-enums.h @@ -127,6 +127,7 @@ typedef enum { * @FWUPD_DEVICE_FLAG_UPDATABLE_HIDDEN: Device is updatable but should not be called by the client * @FWUPD_DEVICE_FLAG_SKIPS_RESTART: Device relies upon activation or power cycle to load firmware * @FWUPD_DEVICE_FLAG_HAS_MULTIPLE_BRANCHES: Device supports switching to a different stream of firmware + * @FWUPD_DEVICE_FLAG_BACKUP_BEFORE_INSTALL: Device firmware should be saved before installing firmware * * The device flags. **/ @@ -171,6 +172,7 @@ typedef enum { #define FWUPD_DEVICE_FLAG_UPDATABLE_HIDDEN (1llu << 37) /* Since: 1.4.1 */ #define FWUPD_DEVICE_FLAG_SKIPS_RESTART (1llu << 38) /* Since: 1.5.0 */ #define FWUPD_DEVICE_FLAG_HAS_MULTIPLE_BRANCHES (1llu << 39) /* Since: 1.5.0 */ +#define FWUPD_DEVICE_FLAG_BACKUP_BEFORE_INSTALL (1llu << 40) /* Since: 1.5.0 */ #define FWUPD_DEVICE_FLAG_UNKNOWN G_MAXUINT64 /* Since: 0.7.3 */ typedef guint64 FwupdDeviceFlags; diff --git a/libfwupdplugin/fu-plugin.c b/libfwupdplugin/fu-plugin.c index 027884de9..f7df74d68 100644 --- a/libfwupdplugin/fu-plugin.c +++ b/libfwupdplugin/fu-plugin.c @@ -1052,6 +1052,32 @@ fu_plugin_device_write_firmware (FuPlugin *self, FuDevice *device, locker = fu_device_locker_new (device, error); if (locker == NULL) return FALSE; + + /* back the old firmware up to /var/lib/fwupd */ + if (fu_device_has_flag (device, FWUPD_DEVICE_FLAG_BACKUP_BEFORE_INSTALL)) { + g_autoptr(GBytes) fw_old = NULL; + g_autofree gchar *path = NULL; + g_autofree gchar *fn = NULL; + g_autofree gchar *localstatedir = NULL; + + fw_old = fu_device_dump_firmware (device, error); + if (fw_old == NULL) { + g_prefix_error (error, "failed to backup old firmware: "); + return FALSE; + } + localstatedir = fu_common_get_path (FU_PATH_KIND_LOCALSTATEDIR_PKG); + fn = g_strdup_printf ("%s.bin", fu_device_get_version (device)); + path = g_build_filename (localstatedir, + "backup", + fu_device_get_id (device), + fu_device_get_serial (device) != NULL ? + fu_device_get_serial (device) : + "default", + fn, NULL); + if (!fu_common_set_contents_bytes (path, fw_old, error)) + return FALSE; + } + return fu_device_write_firmware (device, fw, flags, error); } diff --git a/src/fu-util-common.c b/src/fu-util-common.c index c0cc85d1e..3daf56e3b 100644 --- a/src/fu-util-common.c +++ b/src/fu-util-common.c @@ -1077,6 +1077,10 @@ fu_util_device_flag_to_string (guint64 device_flag) /* TRANSLATORS: there is more than one supplier of the firmware */ return _("Device supports switching to a different branch of firmware"); } + if (device_flag == FWUPD_DEVICE_FLAG_BACKUP_BEFORE_INSTALL) { + /* TRANSLATORS: save the old firmware to disk before installing the new one */ + return _("Device will backup firmware before installing"); + } if (device_flag == FWUPD_DEVICE_FLAG_MD_SET_NAME) { /* skip */ return NULL; From 10c3fd2ff9c78ec4fd55ffb9319635726be9988c Mon Sep 17 00:00:00 2001 From: Richard Hughes Date: Wed, 30 Sep 2020 16:06:35 +0100 Subject: [PATCH 479/607] Support loading DMI data from DT systems To do this with the existing codebase just fake the required SMBIOS structures. --- .../base/ibm,firmware-versions/version | 1 + data/tests/devicetree/base/model | 1 + data/tests/devicetree/base/model-name | 1 + data/tests/devicetree/base/name | Bin 0 -> 1 bytes data/tests/devicetree/base/vendor | 1 + data/tests/devicetree/base/vpd/name | Bin 0 -> 4 bytes .../enclosure@1e00/backplane@800/name | Bin 0 -> 10 bytes .../enclosure@1e00/backplane@800/part-number | 1 + .../enclosure@1e00/backplane@800/vendor | 1 + .../root-node-vpd@a000/enclosure@1e00/name | Bin 0 -> 10 bytes .../base/vpd/root-node-vpd@a000/name | Bin 0 -> 14 bytes libfwupdplugin/fu-self-test.c | 26 +++ libfwupdplugin/fu-smbios.c | 162 ++++++++++++++---- libfwupdplugin/fu-smbios.h | 1 + 14 files changed, 165 insertions(+), 30 deletions(-) create mode 100644 data/tests/devicetree/base/ibm,firmware-versions/version create mode 100644 data/tests/devicetree/base/model create mode 100644 data/tests/devicetree/base/model-name create mode 100644 data/tests/devicetree/base/name create mode 100644 data/tests/devicetree/base/vendor create mode 100644 data/tests/devicetree/base/vpd/name create mode 100644 data/tests/devicetree/base/vpd/root-node-vpd@a000/enclosure@1e00/backplane@800/name create mode 100644 data/tests/devicetree/base/vpd/root-node-vpd@a000/enclosure@1e00/backplane@800/part-number create mode 100644 data/tests/devicetree/base/vpd/root-node-vpd@a000/enclosure@1e00/backplane@800/vendor create mode 100644 data/tests/devicetree/base/vpd/root-node-vpd@a000/enclosure@1e00/name create mode 100644 data/tests/devicetree/base/vpd/root-node-vpd@a000/name diff --git a/data/tests/devicetree/base/ibm,firmware-versions/version b/data/tests/devicetree/base/ibm,firmware-versions/version new file mode 100644 index 000000000..94b2bd66d --- /dev/null +++ b/data/tests/devicetree/base/ibm,firmware-versions/version @@ -0,0 +1 @@ +1.2.3-4 \ No newline at end of file diff --git a/data/tests/devicetree/base/model b/data/tests/devicetree/base/model new file mode 100644 index 000000000..86c8a128b --- /dev/null +++ b/data/tests/devicetree/base/model @@ -0,0 +1 @@ +ColorHug \ No newline at end of file diff --git a/data/tests/devicetree/base/model-name b/data/tests/devicetree/base/model-name new file mode 100644 index 000000000..9d37fc1ac --- /dev/null +++ b/data/tests/devicetree/base/model-name @@ -0,0 +1 @@ +To Be Filled By O.E.M. \ No newline at end of file diff --git a/data/tests/devicetree/base/name b/data/tests/devicetree/base/name new file mode 100644 index 0000000000000000000000000000000000000000..f76dd238ade08917e6712764a16a22005a50573d GIT binary patch literal 1 IcmZPo000310RR91 literal 0 HcmV?d00001 diff --git a/data/tests/devicetree/base/vendor b/data/tests/devicetree/base/vendor new file mode 100644 index 000000000..1555d1a5c --- /dev/null +++ b/data/tests/devicetree/base/vendor @@ -0,0 +1 @@ +Hughski Limited \ No newline at end of file diff --git a/data/tests/devicetree/base/vpd/name b/data/tests/devicetree/base/vpd/name new file mode 100644 index 0000000000000000000000000000000000000000..b8acbc9ee850c5c1285c4a0f54a03d28165f653b GIT binary patch literal 4 LcmXRbNMQf~1M~q) literal 0 HcmV?d00001 diff --git a/data/tests/devicetree/base/vpd/root-node-vpd@a000/enclosure@1e00/backplane@800/name b/data/tests/devicetree/base/vpd/root-node-vpd@a000/enclosure@1e00/backplane@800/name new file mode 100644 index 0000000000000000000000000000000000000000..1f22cb8d670d0d08120031be7c8461f5027f4644 GIT binary patch literal 10 RcmYdFOwKOINz6-S000%B1EK%` literal 0 HcmV?d00001 diff --git a/data/tests/devicetree/base/vpd/root-node-vpd@a000/enclosure@1e00/backplane@800/part-number b/data/tests/devicetree/base/vpd/root-node-vpd@a000/enclosure@1e00/backplane@800/part-number new file mode 100644 index 000000000..e00c9e144 --- /dev/null +++ b/data/tests/devicetree/base/vpd/root-node-vpd@a000/enclosure@1e00/backplane@800/part-number @@ -0,0 +1 @@ +PCB-CH001 \ No newline at end of file diff --git a/data/tests/devicetree/base/vpd/root-node-vpd@a000/enclosure@1e00/backplane@800/vendor b/data/tests/devicetree/base/vpd/root-node-vpd@a000/enclosure@1e00/backplane@800/vendor new file mode 100644 index 000000000..ffbb9e015 --- /dev/null +++ b/data/tests/devicetree/base/vpd/root-node-vpd@a000/enclosure@1e00/backplane@800/vendor @@ -0,0 +1 @@ +Richard Hughes \ No newline at end of file diff --git a/data/tests/devicetree/base/vpd/root-node-vpd@a000/enclosure@1e00/name b/data/tests/devicetree/base/vpd/root-node-vpd@a000/enclosure@1e00/name new file mode 100644 index 0000000000000000000000000000000000000000..88600030bc3acfe10f5bce653908c3a00e821e6e GIT binary patch literal 10 RcmYezOU}tJE-gxB000)V1JM8g literal 0 HcmV?d00001 diff --git a/data/tests/devicetree/base/vpd/root-node-vpd@a000/name b/data/tests/devicetree/base/vpd/root-node-vpd@a000/name new file mode 100644 index 0000000000000000000000000000000000000000..c6f7bd989f98cda61046b5f287ea2d6462a197ec GIT binary patch literal 14 VcmXTQ&o9x<%TGzwEh|W2001c<1rGoK literal 0 HcmV?d00001 diff --git a/libfwupdplugin/fu-self-test.c b/libfwupdplugin/fu-self-test.c index 383788f9d..feab161b1 100644 --- a/libfwupdplugin/fu-self-test.c +++ b/libfwupdplugin/fu-self-test.c @@ -275,6 +275,31 @@ fu_smbios3_func (void) g_assert_cmpstr (str, ==, "Dell Inc."); } +static void +fu_smbios_dt_func (void) +{ + const gchar *str; + gboolean ret; + g_autofree gchar *path = NULL; + g_autoptr(FuSmbios) smbios = NULL; + g_autoptr(GError) error = NULL; + + path = g_build_filename (TESTDATADIR_SRC, "devicetree", "base", NULL); + smbios = fu_smbios_new (); + ret = fu_smbios_setup_from_path (smbios, path, &error); + g_assert_no_error (error); + g_assert (ret); + if (g_getenv ("VERBOSE") != NULL) { + g_autofree gchar *dump = fu_smbios_to_string (smbios); + g_debug ("%s", dump); + } + + /* get vendor */ + str = fu_smbios_get_string (smbios, FU_SMBIOS_STRUCTURE_TYPE_SYSTEM, 0x04, &error); + g_assert_no_error (error); + g_assert_cmpstr (str, ==, "Hughski Limited"); +} + static void fu_hwids_func (void) { @@ -2068,6 +2093,7 @@ main (int argc, char **argv) g_test_add_func ("/fwupd/hwids", fu_hwids_func); g_test_add_func ("/fwupd/smbios", fu_smbios_func); g_test_add_func ("/fwupd/smbios3", fu_smbios3_func); + g_test_add_func ("/fwupd/smbios{dt}", fu_smbios_dt_func); g_test_add_func ("/fwupd/firmware", fu_firmware_func); g_test_add_func ("/fwupd/firmware{dedupe}", fu_firmware_dedupe_func); g_test_add_func ("/fwupd/firmware{build}", fu_firmware_build_func); diff --git a/libfwupdplugin/fu-smbios.c b/libfwupdplugin/fu-smbios.c index c1e9cdee4..90ec1e4f4 100644 --- a/libfwupdplugin/fu-smbios.c +++ b/libfwupdplugin/fu-smbios.c @@ -64,12 +64,71 @@ typedef struct __attribute__((packed)) { typedef struct { guint8 type; guint16 handle; - GBytes *data; + GByteArray *buf; GPtrArray *strings; } FuSmbiosItem; G_DEFINE_TYPE (FuSmbios, fu_smbios, G_TYPE_OBJECT) +static void +fu_smbios_convert_dt_string (FuSmbios *self, guint8 type, guint8 offset, + const gchar *path, const gchar *subpath) +{ + FuSmbiosItem *item = g_ptr_array_index (self->items, type); + gsize bufsz = 0; + g_autofree gchar *fn = g_build_filename (path, subpath, NULL); + g_autofree gchar *buf = NULL; + + /* not found */ + if (!g_file_get_contents (fn, &buf, &bufsz, NULL)) + return; + + /* add to strtab */ + g_ptr_array_add (item->strings, g_strndup (buf, bufsz)); + for (guint i = item->buf->len; i < (guint) offset + 1; i++) + fu_byte_array_append_uint8 (item->buf, 0x0); + item->buf->data[offset] = item->strings->len; +} + +static gboolean +fu_smbios_setup_from_path_dt (FuSmbios *self, const gchar *path, GError **error) +{ + /* add all four faked structures */ + for (guint i = 0; i < FU_SMBIOS_STRUCTURE_TYPE_LAST; i++) { + FuSmbiosItem *item = g_new0 (FuSmbiosItem, 1); + item->type = i; + item->buf = g_byte_array_new (); + item->strings = g_ptr_array_new_with_free_func (g_free); + g_ptr_array_add (self->items, item); + } + + /* DMI:Manufacturer */ + fu_smbios_convert_dt_string (self, FU_SMBIOS_STRUCTURE_TYPE_SYSTEM, 0x04, + path, "vendor"); + + /* DMI:Family */ + fu_smbios_convert_dt_string (self, FU_SMBIOS_STRUCTURE_TYPE_SYSTEM, 0x1a, + path, "model-name"); + + /* DMI:ProductName */ + fu_smbios_convert_dt_string (self, FU_SMBIOS_STRUCTURE_TYPE_SYSTEM, 0x05, + path, "model"); + + /* DMI:BiosVersion */ + fu_smbios_convert_dt_string (self, FU_SMBIOS_STRUCTURE_TYPE_BIOS, 0x05, + path, "ibm,firmware-versions/version"); + + /* DMI:BaseboardManufacturer */ + fu_smbios_convert_dt_string (self, FU_SMBIOS_STRUCTURE_TYPE_BASEBOARD, 0x04, + path, "vpd/root-node-vpd@a000/enclosure@1e00/backplane@800/vendor"); + + /* DMI:BaseboardProduct */ + fu_smbios_convert_dt_string (self, FU_SMBIOS_STRUCTURE_TYPE_BASEBOARD, 0x05, + path, "vpd/root-node-vpd@a000/enclosure@1e00/backplane@800/part-number"); + + return TRUE; +} + static gboolean fu_smbios_setup_from_data (FuSmbios *self, const guint8 *buf, gsize sz, GError **error) { @@ -93,8 +152,9 @@ fu_smbios_setup_from_data (FuSmbios *self, const guint8 *buf, gsize sz, GError * item = g_new0 (FuSmbiosItem, 1); item->type = str->type; item->handle = GUINT16_FROM_LE (str->handle); - item->data = g_bytes_new (buf + i, str->len); + item->buf = g_byte_array_sized_new (str->len); item->strings = g_ptr_array_new_with_free_func (g_free); + g_byte_array_append (item->buf, buf + i, str->len); g_ptr_array_add (self->items, item); /* jump to the end of the struct */ @@ -135,6 +195,17 @@ fu_smbios_setup_from_file (FuSmbios *self, const gchar *filename, GError **error { gsize sz = 0; g_autofree gchar *buf = NULL; + g_autofree gchar *basename = NULL; + + g_return_val_if_fail (FU_IS_SMBIOS (self), FALSE); + g_return_val_if_fail (filename != NULL, FALSE); + + /* use a heuristic */ + basename = g_path_get_basename (filename); + if (g_strcmp0 (basename, "base") == 0) + return fu_smbios_setup_from_path_dt (self, filename, error); + + /* DMI blob */ if (!g_file_get_contents (filename, &buf, &sz, error)) return FALSE; return fu_smbios_setup_from_data (self, (guint8 *) buf, sz, error); @@ -229,20 +300,8 @@ fu_smbios_parse_ep64 (FuSmbios *self, const gchar *buf, gsize sz, GError **error return TRUE; } -/** - * fu_smbios_setup_from_path: - * @self: A #FuSmbios - * @path: A path, e.g. `/sys/firmware/dmi/tables` - * @error: A #GError or %NULL - * - * Reads all the SMBIOS values from a specific path. - * - * Returns: %TRUE for success - * - * Since: 1.0.0 - **/ -gboolean -fu_smbios_setup_from_path (FuSmbios *self, const gchar *path, GError **error) +static gboolean +fu_smbios_setup_from_path_dmi (FuSmbios *self, const gchar *path, GError **error) { gsize sz = 0; g_autofree gchar *dmi_fn = NULL; @@ -304,6 +363,33 @@ fu_smbios_setup_from_path (FuSmbios *self, const gchar *path, GError **error) return fu_smbios_setup_from_data (self, (guint8 *) dmi_raw, sz, error); } +/** + * fu_smbios_setup_from_path: + * @self: A #FuSmbios + * @path: A path, e.g. `/sys/firmware/dmi/tables` + * @error: A #GError or %NULL + * + * Reads all the SMBIOS values from a specific path. + * + * Returns: %TRUE for success + * + * Since: 1.0.0 + **/ +gboolean +fu_smbios_setup_from_path (FuSmbios *self, const gchar *path, GError **error) +{ + g_autofree gchar *basename = NULL; + + g_return_val_if_fail (FU_IS_SMBIOS (self), FALSE); + g_return_val_if_fail (path != NULL, FALSE); + + /* use a heuristic */ + basename = g_path_get_basename (path); + if (g_strcmp0 (basename, "base") == 0) + return fu_smbios_setup_from_path_dt (self, path, error); + return fu_smbios_setup_from_path_dmi (self, path, error); +} + /** * fu_smbios_setup: * @self: A #FuSmbios @@ -319,11 +405,30 @@ gboolean fu_smbios_setup (FuSmbios *self, GError **error) { g_autofree gchar *path = NULL; + g_autofree gchar *path_dt = NULL; g_autofree gchar *sysfsfwdir = NULL; + g_return_val_if_fail (FU_IS_SMBIOS (self), FALSE); + sysfsfwdir = fu_common_get_path (FU_PATH_KIND_SYSFSDIR_FW); + + /* DMI */ path = g_build_filename (sysfsfwdir, "dmi", "tables", NULL); - return fu_smbios_setup_from_path (self, path, error); + if (g_file_test (path, G_FILE_TEST_EXISTS)) + return fu_smbios_setup_from_path (self, path, error); + + /* DT */ + path_dt = g_build_filename (sysfsfwdir, "devicetree", "base", NULL); + if (g_file_test (path_dt, G_FILE_TEST_EXISTS)) + return fu_smbios_setup_from_path (self, path_dt, error); + + /* neither found */ + g_set_error_literal (error, + FWUPD_ERROR, + FWUPD_ERROR_INVALID_FILE, + "neither SMBIOS or DT found"); + return FALSE; + } /** @@ -348,8 +453,7 @@ fu_smbios_to_string (FuSmbios *self) for (guint i = 0; i < self->items->len; i++) { FuSmbiosItem *item = g_ptr_array_index (self->items, i); g_string_append_printf (str, "Type: %02x\n", item->type); - g_string_append_printf (str, " Length: %" G_GSIZE_FORMAT "\n", - g_bytes_get_size (item->data)); + g_string_append_printf (str, " Length: %u\n", item->buf->len); g_string_append_printf (str, " Handle: 0x%04x\n", item->handle); for (guint j = 0; j < item->strings->len; j++) { const gchar *tmp = g_ptr_array_index (item->strings, j); @@ -395,7 +499,7 @@ fu_smbios_get_data (FuSmbios *self, guint8 type, GError **error) "no structure with type %02x", type); return NULL; } - return g_bytes_ref (item->data); + return g_bytes_new (item->buf->data, item->buf->len); } /** @@ -418,8 +522,6 @@ const gchar * fu_smbios_get_string (FuSmbios *self, guint8 type, guint8 offset, GError **error) { FuSmbiosItem *item; - const guint8 *data; - gsize sz; g_return_val_if_fail (FU_IS_SMBIOS (self), NULL); @@ -434,15 +536,15 @@ fu_smbios_get_string (FuSmbios *self, guint8 type, guint8 offset, GError **error } /* check offset valid */ - data = g_bytes_get_data (item->data, &sz); - if (offset >= sz) { + if (offset >= item->buf->len) { g_set_error (error, FWUPD_ERROR, FWUPD_ERROR_INVALID_FILE, - "offset bigger than size %" G_GSIZE_FORMAT, sz); + "offset bigger than size %u", + item->buf->len); return NULL; } - if (data[offset] == 0x00) { + if (item->buf->data[offset] == 0x00) { g_set_error (error, FWUPD_ERROR, FWUPD_ERROR_NOT_FOUND, @@ -451,21 +553,21 @@ fu_smbios_get_string (FuSmbios *self, guint8 type, guint8 offset, GError **error } /* check string index valid */ - if (data[offset] > item->strings->len) { + if (item->buf->data[offset] > item->strings->len) { g_set_error (error, FWUPD_ERROR, FWUPD_ERROR_INVALID_FILE, "index larger than string table %u", - data[offset]); + item->strings->len); return NULL; } - return g_ptr_array_index (item->strings, data[offset] - 1); + return g_ptr_array_index (item->strings, item->buf->data[offset] - 1); } static void fu_smbios_item_free (FuSmbiosItem *item) { - g_bytes_unref (item->data); + g_byte_array_unref (item->buf); g_ptr_array_unref (item->strings); g_free (item); } diff --git a/libfwupdplugin/fu-smbios.h b/libfwupdplugin/fu-smbios.h index e9ef02c74..a8084c351 100644 --- a/libfwupdplugin/fu-smbios.h +++ b/libfwupdplugin/fu-smbios.h @@ -18,6 +18,7 @@ FuSmbios *fu_smbios_new (void); #define FU_SMBIOS_STRUCTURE_TYPE_SYSTEM 0x01 #define FU_SMBIOS_STRUCTURE_TYPE_BASEBOARD 0x02 #define FU_SMBIOS_STRUCTURE_TYPE_CHASSIS 0x03 +#define FU_SMBIOS_STRUCTURE_TYPE_LAST 0x04 gchar *fu_smbios_to_string (FuSmbios *self); From 2d22ee2faea6ccb0bfc95f6fa8d1cf15ba606693 Mon Sep 17 00:00:00 2001 From: Richard Hughes Date: Thu, 1 Oct 2020 13:25:15 +0100 Subject: [PATCH 480/607] Remove 16 extra lines of debugging at startup On my system I get 16 lines of 'device overwriting same name value' for the ME device. Once we set valid metadata about a device just remove the flag to stop scanning for every call to fu_engine_ensure_device_supported() --- src/fu-engine.c | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/src/fu-engine.c b/src/fu-engine.c index 222862741..052fea628 100644 --- a/src/fu-engine.c +++ b/src/fu-engine.c @@ -3075,8 +3075,10 @@ fu_engine_md_refresh_device_name (FuEngine *self, FuDevice *device, XbNode *comp /* copy 1:1 */ name = xb_node_query_text (component, "name", NULL); - if (name != NULL) + if (name != NULL) { fu_device_set_name (device, name); + fu_device_remove_flag (device, FWUPD_DEVICE_FLAG_MD_SET_NAME); + } } static const gchar * @@ -3119,8 +3121,10 @@ fu_engine_md_refresh_device_name_category (FuEngine *self, FuDevice *device, XbN if (name != NULL) break; } - if (name != NULL) + if (name != NULL) { fu_device_set_name (device, name); + fu_device_remove_flag (device, FWUPD_DEVICE_FLAG_MD_SET_NAME_CATEGORY); + } } static void @@ -3176,6 +3180,9 @@ fu_engine_md_refresh_device_verfmt (FuEngine *self, FuDevice *device, XbNode *co fu_device_set_version_bootloader (device, version); } } + + /* do not try to do this again */ + fu_device_remove_flag (device, FWUPD_DEVICE_FLAG_MD_SET_VERFMT); } void From d852480f12eae6175e0fe4f453b637ddf2976959 Mon Sep 17 00:00:00 2001 From: Richard Hughes Date: Thu, 1 Oct 2020 13:31:06 +0100 Subject: [PATCH 481/607] tpm-eventlog: Remove 8 lines of debugging at startup --- plugins/tpm-eventlog/fu-plugin-tpm-eventlog.c | 1 - 1 file changed, 1 deletion(-) diff --git a/plugins/tpm-eventlog/fu-plugin-tpm-eventlog.c b/plugins/tpm-eventlog/fu-plugin-tpm-eventlog.c index 2699dede0..aed42f21c 100644 --- a/plugins/tpm-eventlog/fu-plugin-tpm-eventlog.c +++ b/plugins/tpm-eventlog/fu-plugin-tpm-eventlog.c @@ -71,7 +71,6 @@ fu_plugin_coldplug (FuPlugin *plugin, GError **error) /* add optional report metadata */ str = fu_tpm_eventlog_device_report_metadata (dev); - g_debug ("using TPM event log report data of:\n%s", str); fu_plugin_add_report_metadata (plugin, "TpmEventLog", str); fu_plugin_device_add (plugin, FU_DEVICE (dev)); return TRUE; From 69f7a8c4597ba03497d02af6616b86644c71cd1b Mon Sep 17 00:00:00 2001 From: Richard Hughes Date: Thu, 1 Oct 2020 13:33:15 +0100 Subject: [PATCH 482/607] vli: Remove 32 lines of debugging at startup I'll admit it's not normal to have *two* docks connected to one machine... --- plugins/vli/fu-vli-usbhub-device.c | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/plugins/vli/fu-vli-usbhub-device.c b/plugins/vli/fu-vli-usbhub-device.c index 07b485625..64f8bc3b1 100644 --- a/plugins/vli/fu-vli-usbhub-device.c +++ b/plugins/vli/fu-vli-usbhub-device.c @@ -419,14 +419,16 @@ fu_vli_usbhub_device_guess_kind (FuVliUsbhubDevice *self, GError **error) g_prefix_error (error, "Read_820Q7Q8 failed: "); return FALSE; } - g_debug ("chipver = 0x%02x", chipver); - g_debug ("chipver2 = 0x%02x", chipver2); - g_debug ("b811P812 = 0x%02x", b811P812); - g_debug ("chipid1 = 0x%02x", chipid1); - g_debug ("chipid2 = 0x%02x", chipid2); - g_debug ("chipid12 = 0x%02x", chipid12); - g_debug ("chipid22 = 0x%02x", chipid22); - g_debug ("b820Q7Q8 = 0x%02x", b820Q7Q8); + if (g_getenv ("FWUPD_VLI_USBHUB_VERBOSE") != NULL) { + g_debug ("chipver = 0x%02x", chipver); + g_debug ("chipver2 = 0x%02x", chipver2); + g_debug ("b811P812 = 0x%02x", b811P812); + g_debug ("chipid1 = 0x%02x", chipid1); + g_debug ("chipid2 = 0x%02x", chipid2); + g_debug ("chipid12 = 0x%02x", chipid12); + g_debug ("chipid22 = 0x%02x", chipid22); + g_debug ("b820Q7Q8 = 0x%02x", b820Q7Q8); + } if (chipid2 == 0x35 && chipid1 == 0x07) { fu_vli_device_set_kind (FU_VLI_DEVICE (self), FU_VLI_DEVICE_KIND_VL210); From 538fa633e8c022dc848e2702a7b7345b501ef95c Mon Sep 17 00:00:00 2001 From: Richard Hughes Date: Thu, 1 Oct 2020 13:52:04 +0100 Subject: [PATCH 483/607] vli: Remove useless debugging line We know the flash_id as it's one of the InstanceIDs. --- plugins/vli/fu-vli-device.c | 1 - 1 file changed, 1 deletion(-) diff --git a/plugins/vli/fu-vli-device.c b/plugins/vli/fu-vli-device.c index ad1292d22..d431e294e 100644 --- a/plugins/vli/fu-vli-device.c +++ b/plugins/vli/fu-vli-device.c @@ -539,7 +539,6 @@ fu_vli_device_setup (FuDevice *device, GError **error) g_autofree gchar *devid1 = NULL; g_autofree gchar *devid2 = NULL; g_autofree gchar *flash_id = fu_vli_device_get_flash_id_str (self); - g_debug ("using flash part %s", flash_id); /* load the SPI parameters from quirks */ spi_id = g_strdup_printf ("VLI_USBHUB\\SPI_%s", flash_id); From 66ff7c45a9f0ab95aa387520709c92aaececf5f0 Mon Sep 17 00:00:00 2001 From: Richard Hughes Date: Thu, 1 Oct 2020 14:02:29 +0100 Subject: [PATCH 484/607] vli: Remove invalid quirk entry The 721C is a VL103, which isn't a FuVliUsbhubDevice at all. Fixes the: already set GType to FuVliPdDevice, ignoring FuVliUsbhubDevice ...message when the Mini dock / powered hub is inserted. --- plugins/vli/vli-usbhub-lenovo.quirk | 6 ------ 1 file changed, 6 deletions(-) diff --git a/plugins/vli/vli-usbhub-lenovo.quirk b/plugins/vli/vli-usbhub-lenovo.quirk index e35fc5a9c..b5835b47c 100644 --- a/plugins/vli/vli-usbhub-lenovo.quirk +++ b/plugins/vli/vli-usbhub-lenovo.quirk @@ -265,9 +265,3 @@ Plugin = vli GType = FuVliUsbhubDevice Flags = usb2 ParentGuid = USB\VID_2109&PID_2822 - -# Lenovo Powered Hub -[DeviceInstanceId=USB\VID_17EF&PID_721C] -Plugin = vli -GType = FuVliUsbhubDevice -Flags = usb2 From e9ada9ed7213688ec3d260b77477574706fc469e Mon Sep 17 00:00:00 2001 From: Richard Hughes Date: Thu, 1 Oct 2020 13:35:18 +0100 Subject: [PATCH 485/607] uefi-dbx: Remove three unhelpful lines of debugging --- plugins/uefi-dbx/fu-efi-signature-parser.c | 3 --- 1 file changed, 3 deletions(-) diff --git a/plugins/uefi-dbx/fu-efi-signature-parser.c b/plugins/uefi-dbx/fu-efi-signature-parser.c index 3754064c8..a1a932be6 100644 --- a/plugins/uefi-dbx/fu-efi-signature-parser.c +++ b/plugins/uefi-dbx/fu-efi-signature-parser.c @@ -73,13 +73,10 @@ fu_efi_signature_list_parse_list (GPtrArray *siglists, } sig_type = fwupd_guid_to_string (&guid, FWUPD_GUID_FLAG_MIXED_ENDIAN); if (g_strcmp0 (sig_type, "c1c41626-504c-4092-aca9-41f936934328") == 0) { - g_debug ("EFI_SIGNATURE_LIST SHA256"); siglist = fu_efi_signature_list_new (FU_EFI_SIGNATURE_KIND_SHA256); } else if (g_strcmp0 (sig_type, "a5c059a1-94e4-4aa7-87b5-ab155c2bf072") == 0) { - g_debug ("EFI_SIGNATURE_LIST X509"); siglist = fu_efi_signature_list_new (FU_EFI_SIGNATURE_KIND_X509); } else { - g_debug ("EFI_SIGNATURE_LIST unknown: %s", sig_type); siglist = fu_efi_signature_list_new (FU_EFI_SIGNATURE_KIND_UNKNOWN); } if (!fu_common_read_uint32_safe (buf, bufsz, *offset + 0x10, From 61a2dbad136b42b7b9b64fe3e862f98584a29b62 Mon Sep 17 00:00:00 2001 From: Richard Hughes Date: Thu, 1 Oct 2020 13:41:24 +0100 Subject: [PATCH 486/607] trivial: Do not inform if no fwupd::ReleaseFlags were set This is never set in the AppStream metadata, and means that every call to fu_engine_ensure_device_supported() at startup does not generate 16x debugs. For cab archives we know if the archive was unsigned as we show the flags in the to_string() output. --- src/fu-keyring-utils.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/fu-keyring-utils.c b/src/fu-keyring-utils.c index 2bf46aae5..409220e67 100644 --- a/src/fu-keyring-utils.c +++ b/src/fu-keyring-utils.c @@ -30,10 +30,8 @@ fu_keyring_get_release_flags (XbNode *release, GBytes *blob; blob = g_object_get_data (G_OBJECT (release), "fwupd::ReleaseFlags"); - if (blob == NULL) { - g_debug ("no fwupd::ReleaseFlags set by loader"); + if (blob == NULL) return TRUE; - } if (g_bytes_get_size (blob) != sizeof(FwupdReleaseFlags)) { g_set_error_literal (error, FWUPD_ERROR, From f4052b53f40d977752cf92452275283b35e5c47c Mon Sep 17 00:00:00 2001 From: Richard Hughes Date: Thu, 1 Oct 2020 13:47:14 +0100 Subject: [PATCH 487/607] trivial: Do not warn about the same missing remote more than once Removes 4 instances of 'ignoring unfound remote fwupd' at startup. --- src/fu-remote-list.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/fu-remote-list.c b/src/fu-remote-list.c index 68344d6b4..e9a24e8f2 100644 --- a/src/fu-remote-list.c +++ b/src/fu-remote-list.c @@ -34,6 +34,7 @@ struct _FuRemoteList GObject parent_instance; GPtrArray *array; /* (element-type FwupdRemote) */ GPtrArray *monitors; /* (element-type GFileMonitor) */ + GHashTable *hash_unfound; /* utf8 : NULL */ XbSilo *silo; }; @@ -296,6 +297,7 @@ static guint fu_remote_list_depsolve_with_direction (FuRemoteList *self, gint inc) { guint cnt = 0; + for (guint i = 0; i < self->array->len; i++) { FwupdRemote *remote = g_ptr_array_index (self->array, i); gchar **order = inc < 0 ? fwupd_remote_get_order_after (remote) : @@ -310,7 +312,11 @@ fu_remote_list_depsolve_with_direction (FuRemoteList *self, gint inc) } remote2 = fu_remote_list_get_by_id (self, order[j]); if (remote2 == NULL) { + if (g_hash_table_contains (self->hash_unfound, order[j])) + continue; g_debug ("ignoring unfound remote %s", order[j]); + g_hash_table_insert (self->hash_unfound, + g_strdup (order[j]), NULL); continue; } if (fwupd_remote_get_priority (remote) > fwupd_remote_get_priority (remote2)) @@ -487,6 +493,7 @@ fu_remote_list_init (FuRemoteList *self) { self->array = g_ptr_array_new_with_free_func ((GDestroyNotify) g_object_unref); self->monitors = g_ptr_array_new_with_free_func ((GDestroyNotify) fu_remote_list_monitor_unref); + self->hash_unfound = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, NULL); } static void @@ -497,6 +504,7 @@ fu_remote_list_finalize (GObject *obj) g_object_unref (self->silo); g_ptr_array_unref (self->array); g_ptr_array_unref (self->monitors); + g_hash_table_unref (self->hash_unfound); G_OBJECT_CLASS (fu_remote_list_parent_class)->finalize (obj); } From 5e0729ecf8ba98297ff2cedf0874d0ed52f35de7 Mon Sep 17 00:00:00 2001 From: Richard Hughes Date: Thu, 1 Oct 2020 13:50:37 +0100 Subject: [PATCH 488/607] ata: Demote two debug lines to require the plugin verbose flag --- plugins/ata/fu-ata-device.c | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/plugins/ata/fu-ata-device.c b/plugins/ata/fu-ata-device.c index 85d9191ba..0bb2782c3 100644 --- a/plugins/ata/fu-ata-device.c +++ b/plugins/ata/fu-ata-device.c @@ -548,10 +548,11 @@ fu_ata_device_command (FuAtaDevice *self, struct ata_tf *tf, SG_IO, (guint8 *) &io_hdr, NULL, error)) return FALSE; - g_debug ("ATA_%u status=0x%x, host_status=0x%x, driver_status=0x%x", - io_hdr.cmd_len, io_hdr.status, io_hdr.host_status, io_hdr.driver_status); - if (g_getenv ("FWUPD_ATA_VERBOSE") != NULL) + if (g_getenv ("FWUPD_ATA_VERBOSE") != NULL) { + g_debug ("ATA_%u status=0x%x, host_status=0x%x, driver_status=0x%x", + io_hdr.cmd_len, io_hdr.status, io_hdr.host_status, io_hdr.driver_status); fu_common_dump_raw (G_LOG_DOMAIN, "SB", sb, sizeof(sb)); + } /* error check */ if (io_hdr.status && io_hdr.status != SG_CHECK_CONDITION) { @@ -584,8 +585,12 @@ fu_ata_device_command (FuAtaDevice *self, struct ata_tf *tf, tf->lbah = sb[8 + 11]; tf->dev = sb[8 + 12]; tf->status = sb[8 + 13]; - g_debug ("ATA_%u stat=%02x err=%02x nsect=%02x lbal=%02x lbam=%02x lbah=%02x dev=%02x", - io_hdr.cmd_len, tf->status, tf->error, tf->nsect, tf->lbal, tf->lbam, tf->lbah, tf->dev); + if (g_getenv ("FWUPD_ATA_VERBOSE") != NULL) { + g_debug ("ATA_%u stat=%02x err=%02x nsect=%02x lbal=%02x " + "lbam=%02x lbah=%02x dev=%02x", + io_hdr.cmd_len, tf->status, tf->error, tf->nsect, tf->lbal, + tf->lbam, tf->lbah, tf->dev); + } /* io error */ if (tf->status & (ATA_STAT_ERR | ATA_STAT_DRQ)) { From 521c2e2cd288ae02755949d13628b61369ccb344 Mon Sep 17 00:00:00 2001 From: Richard Hughes Date: Thu, 1 Oct 2020 14:12:41 +0100 Subject: [PATCH 489/607] trivial: Do not print 'bare' GError strings Give them come context so we know where they came from... --- src/fu-engine.c | 28 ++++++++++++++++++---------- 1 file changed, 18 insertions(+), 10 deletions(-) diff --git a/src/fu-engine.c b/src/fu-engine.c index 052fea628..b1b88d851 100644 --- a/src/fu-engine.c +++ b/src/fu-engine.c @@ -137,7 +137,8 @@ fu_engine_emit_changed (FuEngine *self) fu_config_get_update_motd (self->config)) { g_autoptr(GError) error_local = NULL; if (!fu_engine_update_motd (self, &error_local)) - g_debug ("%s", error_local->message); + g_debug ("failed to update MOTD: %s", + error_local->message); } } @@ -2996,7 +2997,8 @@ fu_engine_create_metadata (FuEngine *self, XbBuilder *builder, /* build source for file */ source = fu_engine_create_metadata_builder_source (self, fn, &error_local); if (source == NULL) { - g_warning ("%s", error_local->message); + g_warning ("failed to create builder source: %s", + error_local->message); continue; } @@ -5328,7 +5330,9 @@ fu_engine_plugin_device_removed_cb (FuPlugin *plugin, fu_device_get_id (device), &error); if (device_tmp == NULL) { - g_debug ("%s", error->message); + g_debug ("failed to find device %s: %s", + fu_device_get_id (device), + error->message); return; } @@ -5337,7 +5341,9 @@ fu_engine_plugin_device_removed_cb (FuPlugin *plugin, fu_device_get_plugin (device), &error); if (plugin_old == NULL) { - g_debug ("%s", error->message); + g_debug ("failed to find plugin %s: %s", + fu_device_get_plugin (device), + error->message); return; } @@ -5397,7 +5403,7 @@ fu_engine_udev_device_add (FuEngine *self, GUdevDevice *udev_device) plugin = fu_plugin_list_find_by_name (self->plugin_list, plugin_name, &error); if (plugin == NULL) { - g_debug ("%s", error->message); + g_debug ("failed to add udev device: %s", error->message); continue; } if (!fu_plugin_runner_udev_device_added (plugin, device, &error)) { @@ -5903,7 +5909,7 @@ fu_engine_load_plugins (FuEngine *self, GError **error) /* if loaded from fu_engine_load() open the plugin */ if (self->usb_ctx != NULL) { if (!fu_plugin_open (plugin, filename, &error_local)) { - g_warning ("%s", error_local->message); + g_warning ("cannot load: %s", error_local->message); continue; } } @@ -6039,7 +6045,7 @@ fu_engine_usb_device_added_cb (GUsbContext *ctx, plugin = fu_plugin_list_find_by_name (self->plugin_list, plugin_name, &error); if (plugin == NULL) { - g_debug ("%s", error->message); + g_debug ("failed to add usb device: %s", error->message); continue; } if (!fu_plugin_runner_usb_device_added (plugin, device, &error)) { @@ -6198,8 +6204,10 @@ fu_engine_update_history_database (FuEngine *self, GError **error) continue; /* try to save the new update-state, but ignoring any error */ - if (!fu_engine_update_history_device (self, dev, &error_local)) - g_warning ("%s", error_local->message); + if (!fu_engine_update_history_device (self, dev, &error_local)) { + g_warning ("failed to update history database: %s", + error_local->message); + } } return TRUE; } @@ -6283,7 +6291,7 @@ fu_engine_load (FuEngine *self, FuEngineLoadFlags flags, GError **error) /* cache machine ID so we can use it from a sandboxed app */ self->host_machine_id = fwupd_build_machine_id ("fwupd", &error_local); if (self->host_machine_id == NULL) - g_debug ("%s", error_local->message); + g_debug ("failed to build machine-id: %s", error_local->message); #endif /* read config file */ if (!fu_config_load (self->config, error)) { From f64e7a9cb4b22b83b05246bd70de2eb90b22fd35 Mon Sep 17 00:00:00 2001 From: Richard Hughes Date: Thu, 1 Oct 2020 18:05:36 +0100 Subject: [PATCH 490/607] trivial: Fix typo when setting _HAS_MULTIPLE_BRANCHES Fixes https://github.com/fwupd/fwupd/issues/2439 --- src/fu-engine.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/fu-engine.c b/src/fu-engine.c index b1b88d851..4c1f53aeb 100644 --- a/src/fu-engine.c +++ b/src/fu-engine.c @@ -4436,7 +4436,7 @@ fu_engine_get_releases_for_device (FuEngine *self, continue; g_ptr_array_add (branches, g_strdup (branch_tmp)); } - if (branches->len > 0) + if (branches->len > 1) fu_device_add_flag (device, FWUPD_DEVICE_FLAG_HAS_MULTIPLE_BRANCHES); /* return the compound error */ From 7d1267fd841a8a8c913681e3e91340e9542f7e2a Mon Sep 17 00:00:00 2001 From: Richard Hughes Date: Tue, 15 Sep 2020 10:35:24 +0100 Subject: [PATCH 491/607] Clarify various parts of the HSI specification Firsly, that HSI isn't expected for embedded devices and then secondary how we require SecureBoot to be available for HSI:1 At the moment we get a runtime failure if it is disabled. Making SB a part of `HSI:1` makes this requiremnt explicit and prevents us getting `HSI:2!` if it is not available. --- docs/hsi.xml | 41 ++++++++++++++++++++++++++++++- libfwupdplugin/fu-efivar.c | 45 +++++++++++++++++++++++++++------- libfwupdplugin/fu-efivar.h | 3 ++- libfwupdplugin/fwupdplugin.map | 1 + plugins/uefi/fu-plugin-uefi.c | 13 +++++++--- 5 files changed, 89 insertions(+), 14 deletions(-) diff --git a/docs/hsi.xml b/docs/hsi.xml index 522c2dce5..4b3717b69 100644 --- a/docs/hsi.xml +++ b/docs/hsi.xml @@ -128,6 +128,12 @@ connected, additional software to be installed, or disabling any existing security layers to measure. + + The HSI specification is primarily designed for laptop and desktop + hardware, although some tests may still make sense + on server or embedded hardware. + It is not expected that non-consumer hardware will publish an HSI number. + @@ -161,7 +167,8 @@ This security level corresponds to the most basic of security protections considered essential by security professionals. - Any failures at this level would have critical security impact. + Any failures at this level would have critical security impact and could + likely be used to compromise the system firmware without physical access. @@ -259,6 +266,38 @@ + + UEFI SecureBoot + + UEFI Secure boot is a verification mechanism for ensuring that code + launched by firmware is trusted. + + + Secure Boot requires that each binary loaded at boot is validated + against trusted certifictes. + + + + + For HSI-1 SecureBoot must be available for use on UEFI systems. + v1.5.0 + + + + + + See also: + + + + UEFI Wiki Entry + + + + + + + BIOS Write Enable (BWE) diff --git a/libfwupdplugin/fu-efivar.c b/libfwupdplugin/fu-efivar.c index e976ee202..4bcd15d9b 100644 --- a/libfwupdplugin/fu-efivar.c +++ b/libfwupdplugin/fu-efivar.c @@ -407,6 +407,41 @@ fu_efivar_set_data (const gchar *guid, const gchar *name, const guint8 *data, #endif } +/** + * fu_efivar_secure_boot_enabled_full: + * @error: A #GError + * + * Determines if secure boot was enabled + * + * Returns: %TRUE on success + * + * Since: 1.5.0 + **/ +gboolean +fu_efivar_secure_boot_enabled_full (GError **error) +{ + gsize data_size = 0; + g_autofree guint8 *data = NULL; + + if (!fu_efivar_get_data (FU_EFIVAR_GUID_EFI_GLOBAL, "SecureBoot", + &data, &data_size, NULL, NULL)) { + g_set_error_literal (error, + FWUPD_ERROR, + FWUPD_ERROR_NOT_SUPPORTED, + "SecureBoot is not available"); + return FALSE; + } + if (data_size >= 1 && data[0] & 1) + return TRUE; + + /* available, but not enabled */ + g_set_error_literal (error, + FWUPD_ERROR, + FWUPD_ERROR_NOT_FOUND, + "SecureBoot is not enabled"); + return FALSE; +} + /** * fu_efivar_secure_boot_enabled: * @@ -419,13 +454,5 @@ fu_efivar_set_data (const gchar *guid, const gchar *name, const guint8 *data, gboolean fu_efivar_secure_boot_enabled (void) { - gsize data_size = 0; - g_autofree guint8 *data = NULL; - - if (!fu_efivar_get_data (FU_EFIVAR_GUID_EFI_GLOBAL, "SecureBoot", - &data, &data_size, NULL, NULL)) - return FALSE; - if (data_size >= 1 && data[0] & 1) - return TRUE; - return FALSE; + return fu_efivar_secure_boot_enabled_full (NULL); } diff --git a/libfwupdplugin/fu-efivar.h b/libfwupdplugin/fu-efivar.h index 6bea1768c..926e60aec 100644 --- a/libfwupdplugin/fu-efivar.h +++ b/libfwupdplugin/fu-efivar.h @@ -43,4 +43,5 @@ gboolean fu_efivar_delete (const gchar *guid, gboolean fu_efivar_delete_with_glob (const gchar *guid, const gchar *name_glob, GError **error); -gboolean fu_efivar_secure_boot_enabled (void); +gboolean fu_efivar_secure_boot_enabled (void); +gboolean fu_efivar_secure_boot_enabled_full(GError **error); diff --git a/libfwupdplugin/fwupdplugin.map b/libfwupdplugin/fwupdplugin.map index 11edfe335..d7c1d5222 100644 --- a/libfwupdplugin/fwupdplugin.map +++ b/libfwupdplugin/fwupdplugin.map @@ -624,6 +624,7 @@ LIBFWUPDPLUGIN_1.5.0 { fu_device_report_metadata_post; fu_device_report_metadata_pre; fu_device_unbind_driver; + fu_efivar_secure_boot_enabled_full; fu_firmware_add_flag; fu_firmware_build; fu_firmware_flag_from_string; diff --git a/plugins/uefi/fu-plugin-uefi.c b/plugins/uefi/fu-plugin-uefi.c index 380f98fd9..8a05d0630 100644 --- a/plugins/uefi/fu-plugin-uefi.c +++ b/plugins/uefi/fu-plugin-uefi.c @@ -98,15 +98,22 @@ void fu_plugin_add_security_attrs (FuPlugin *plugin, FuSecurityAttrs *attrs) { g_autoptr(FwupdSecurityAttr) attr = NULL; + g_autoptr(GError) error = NULL; /* create attr */ attr = fwupd_security_attr_new (FWUPD_SECURITY_ATTR_ID_UEFI_SECUREBOOT); fwupd_security_attr_set_plugin (attr, fu_plugin_get_name (plugin)); - fwupd_security_attr_add_flag (attr, FWUPD_SECURITY_ATTR_FLAG_RUNTIME_ISSUE); fu_security_attrs_append (attrs, attr); - /* SB disabled */ - if (!fu_efivar_secure_boot_enabled ()) { + /* SB not available or disabled */ + if (!fu_efivar_secure_boot_enabled_full (&error)) { + if (g_error_matches (error, + FWUPD_ERROR, + FWUPD_ERROR_NOT_SUPPORTED)) { + fwupd_security_attr_set_result (attr, FWUPD_SECURITY_ATTR_RESULT_NOT_FOUND); + return; + } + fwupd_security_attr_add_flag (attr, FWUPD_SECURITY_ATTR_FLAG_RUNTIME_ISSUE); fwupd_security_attr_set_result (attr, FWUPD_SECURITY_ATTR_RESULT_NOT_ENABLED); return; } From c5ea3a39f904d5face45d352c45cdecd36561f57 Mon Sep 17 00:00:00 2001 From: Mario Limonciello Date: Fri, 2 Oct 2020 16:23:35 -0500 Subject: [PATCH 492/607] trivial: uefi: quiet down debugging messages With how well fwupd UEFI updates work these days >99% of people don't need to see messages about the capsule update running. Those who have problems, this isn't going to help them. --- plugins/uefi/efi/fwupdate.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/plugins/uefi/efi/fwupdate.c b/plugins/uefi/efi/fwupdate.c index d500a28da..f8248b926 100644 --- a/plugins/uefi/efi/fwupdate.c +++ b/plugins/uefi/efi/fwupdate.c @@ -155,7 +155,7 @@ fwup_populate_update_table(FWUP_UPDATE_TABLE **updates, UINTN *n_updates_out) continue; } - fwup_info(L"Found update %s", variable_name); + fwup_debug(L"Found update %s", variable_name); _cleanup_update_table FWUP_UPDATE_TABLE *update = fwup_malloc0(sizeof(FWUP_UPDATE_TABLE)); if (update == NULL) return EFI_OUT_OF_RESOURCES; @@ -574,7 +574,7 @@ efi_main(EFI_HANDLE image, EFI_SYSTEM_TABLE *systab) if (cbd_data == NULL) return EFI_OUT_OF_RESOURCES; for (i = 0; i < n_updates; i++) { - fwup_info(L"Adding new capsule"); + fwup_debug(L"Adding new capsule"); rc = fwup_add_update_capsule(updates[i], &capsules[j], &cbd_data[j], image); if (EFI_ERROR(rc)) { /* ignore a failing capsule */ From 2195237f12d7b965ccdd778de064660cdee06882 Mon Sep 17 00:00:00 2001 From: Mario Limonciello Date: Fri, 2 Oct 2020 16:28:44 -0500 Subject: [PATCH 493/607] trivial: don't show OS release paths checked --- libfwupd/fwupd-common.c | 1 - 1 file changed, 1 deletion(-) diff --git a/libfwupd/fwupd-common.c b/libfwupd/fwupd-common.c index 705ecc2ae..e5d989618 100644 --- a/libfwupd/fwupd-common.c +++ b/libfwupd/fwupd-common.c @@ -169,7 +169,6 @@ fwupd_get_os_release (GError **error) /* find the correct file */ for (guint i = 0; paths[i] != NULL; i++) { - g_debug ("looking for os-release at %s", paths[i]); if (g_file_test (paths[i], G_FILE_TEST_EXISTS)) { filename = paths[i]; break; From 39bd45f4f759ac922cd43f8e4c89d760c28e4060 Mon Sep 17 00:00:00 2001 From: Mario Limonciello Date: Fri, 2 Oct 2020 16:30:29 -0500 Subject: [PATCH 494/607] trivial: don't show quirk directories skipped --- libfwupdplugin/fu-quirks.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/libfwupdplugin/fu-quirks.c b/libfwupdplugin/fu-quirks.c index ffba1420d..792534d25 100644 --- a/libfwupdplugin/fu-quirks.c +++ b/libfwupdplugin/fu-quirks.c @@ -149,10 +149,8 @@ fu_quirks_add_quirks_for_path (FuQuirks *self, XbBuilder *builder, /* add valid files to the array */ path_hw = g_build_filename (path, "quirks.d", NULL); - if (!g_file_test (path_hw, G_FILE_TEST_EXISTS)) { - g_debug ("no %s, skipping", path_hw); + if (!g_file_test (path_hw, G_FILE_TEST_EXISTS)) return TRUE; - } dir = g_dir_open (path_hw, 0, error); if (dir == NULL) return FALSE; From 933e43005fb4f32da0a8c04f6a263f8e39d4ade2 Mon Sep 17 00:00:00 2001 From: Mario Limonciello Date: Fri, 2 Oct 2020 16:33:12 -0500 Subject: [PATCH 495/607] trivial: fu-engine: don't show information for disabled remotes --- src/fu-engine.c | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) diff --git a/src/fu-engine.c b/src/fu-engine.c index 4c1f53aeb..36249698d 100644 --- a/src/fu-engine.c +++ b/src/fu-engine.c @@ -3249,16 +3249,11 @@ fu_engine_load_metadata_store (FuEngine *self, FuEngineLoadFlags flags, GError * g_autoptr(XbBuilderSource) source = xb_builder_source_new (); FwupdRemote *remote = g_ptr_array_index (remotes, i); - if (!fwupd_remote_get_enabled (remote)) { - g_debug ("remote %s not enabled, so skipping", - fwupd_remote_get_id (remote)); + if (!fwupd_remote_get_enabled (remote)) continue; - } path = fwupd_remote_get_filename_cache (remote); - if (!g_file_test (path, G_FILE_TEST_EXISTS)) { - g_debug ("no %s, so skipping", path); + if (!g_file_test (path, G_FILE_TEST_EXISTS)) continue; - } /* generate all metadata on demand */ if (fwupd_remote_get_kind (remote) == FWUPD_REMOTE_KIND_DIRECTORY) { From 9ed4d470404747c123e65e284383f343b027c315 Mon Sep 17 00:00:00 2001 From: Richard Hughes Date: Mon, 5 Oct 2020 11:37:26 +0100 Subject: [PATCH 496/607] trivial: Remove more debugging when disabling plugins We already have a list of enabled and disabled plugins, don't tell the user hundreds of times that 'optionrom is not found'. --- src/fu-engine.c | 14 ++++---------- 1 file changed, 4 insertions(+), 10 deletions(-) diff --git a/src/fu-engine.c b/src/fu-engine.c index 36249698d..edf312c8f 100644 --- a/src/fu-engine.c +++ b/src/fu-engine.c @@ -5395,12 +5395,9 @@ fu_engine_udev_device_add (FuEngine *self, GUdevDevice *udev_device) const gchar *plugin_name = g_ptr_array_index (possible_plugins, i); g_autoptr(GError) error = NULL; - plugin = fu_plugin_list_find_by_name (self->plugin_list, - plugin_name, &error); - if (plugin == NULL) { - g_debug ("failed to add udev device: %s", error->message); + plugin = fu_plugin_list_find_by_name (self->plugin_list, plugin_name, NULL); + if (plugin == NULL) continue; - } if (!fu_plugin_runner_udev_device_added (plugin, device, &error)) { if (g_error_matches (error, FWUPD_ERROR, FWUPD_ERROR_NOT_SUPPORTED)) { if (g_getenv ("FWUPD_PROBE_VERBOSE") != NULL) { @@ -6037,12 +6034,9 @@ fu_engine_usb_device_added_cb (GUsbContext *ctx, const gchar *plugin_name = g_ptr_array_index (possible_plugins, i); g_autoptr(GError) error = NULL; - plugin = fu_plugin_list_find_by_name (self->plugin_list, - plugin_name, &error); - if (plugin == NULL) { - g_debug ("failed to add usb device: %s", error->message); + plugin = fu_plugin_list_find_by_name (self->plugin_list, plugin_name, NULL); + if (plugin == NULL) continue; - } if (!fu_plugin_runner_usb_device_added (plugin, device, &error)) { if (g_error_matches (error, FWUPD_ERROR, FWUPD_ERROR_NOT_SUPPORTED)) { if (g_getenv ("FWUPD_PROBE_VERBOSE") != NULL) { From 24281476597dac140d680e5c29eb43e451168d4b Mon Sep 17 00:00:00 2001 From: Richard Hughes Date: Mon, 5 Oct 2020 11:45:47 +0100 Subject: [PATCH 497/607] trivial: Show a single line for each plugin state at startup --- src/fu-engine.c | 30 ++++++++++++++++++++++++++---- 1 file changed, 26 insertions(+), 4 deletions(-) diff --git a/src/fu-engine.c b/src/fu-engine.c index edf312c8f..165a4b002 100644 --- a/src/fu-engine.c +++ b/src/fu-engine.c @@ -5854,6 +5854,9 @@ fu_engine_load_plugins (FuEngine *self, GError **error) g_autoptr(GDir) dir = NULL; g_autofree gchar *plugin_path = NULL; g_autofree gchar *suffix = g_strdup_printf (".%s", G_MODULE_SUFFIX); + g_autoptr(GPtrArray) plugins_disabled = g_ptr_array_new_with_free_func (g_free); + g_autoptr(GPtrArray) plugins_not_enabled = g_ptr_array_new_with_free_func (g_free); + g_autoptr(GPtrArray) plugins_self_disabled = g_ptr_array_new_with_free_func (g_free); /* search */ plugin_path = fu_common_get_path (FU_PATH_KIND_PLUGINDIR_PKG); @@ -5875,11 +5878,11 @@ fu_engine_load_plugins (FuEngine *self, GError **error) if (name == NULL) continue; if (fu_engine_is_plugin_name_disabled (self, name)) { - g_debug ("plugin %s is disabled", name); + g_ptr_array_add (plugins_disabled, g_steal_pointer (&name)); continue; } if (!fu_engine_is_plugin_name_enabled (self, name)) { - g_debug ("plugin %s is not enabled", name); + g_ptr_array_add (plugins_not_enabled, g_steal_pointer (&name)); continue; } @@ -5908,8 +5911,7 @@ fu_engine_load_plugins (FuEngine *self, GError **error) /* self disabled */ if (!fu_plugin_get_enabled (plugin)) { - g_debug ("%s self disabled", - fu_plugin_get_name (plugin)); + g_ptr_array_add (plugins_self_disabled, g_steal_pointer (&name)); continue; } @@ -5943,6 +5945,26 @@ fu_engine_load_plugins (FuEngine *self, GError **error) fu_engine_add_plugin (self, plugin); } + /* show list */ + if (plugins_disabled->len > 0) { + g_autofree gchar *str = NULL; + g_ptr_array_add (plugins_disabled, NULL); + str = g_strjoinv (", ", (gchar **) plugins_disabled->pdata); + g_debug ("plugins disabled: %s", str); + } + if (plugins_not_enabled->len > 0) { + g_autofree gchar *str = NULL; + g_ptr_array_add (plugins_not_enabled, NULL); + str = g_strjoinv (", ", (gchar **) plugins_not_enabled->pdata); + g_debug ("plugins not-enabled: %s", str); + } + if (plugins_self_disabled->len > 0) { + g_autofree gchar *str = NULL; + g_ptr_array_add (plugins_self_disabled, NULL); + str = g_strjoinv (", ", (gchar **) plugins_self_disabled->pdata); + g_debug ("plugins self-disabled: %s", str); + } + /* depsolve into the correct order */ if (!fu_plugin_list_depsolve (self->plugin_list, error)) return FALSE; From 26e57dd4e2e23888f4f69e2f38b76dcdfc904cde Mon Sep 17 00:00:00 2001 From: Richard Hughes Date: Mon, 5 Oct 2020 13:49:23 +0100 Subject: [PATCH 498/607] Do not auto-detach when dumping firmware This allows us to handle this in the plugin, which might mean detaching the *proxy* device. It's also very important as a few plugins reboot the device in ->attach() to get the new firmware version, which isn't required for a dump. This partially reverts a58510b2460e780f8488e399d83252290b7f97ce and does the detach and attach in the few plugins where actually required. --- plugins/dfu/dfu-device.c | 9 +++++++++ plugins/superio/fu-superio-it89-device.c | 9 +++++++++ plugins/vli/fu-vli-pd-device.c | 9 +++++++++ src/fu-engine.c | 18 ++---------------- 4 files changed, 29 insertions(+), 16 deletions(-) diff --git a/plugins/dfu/dfu-device.c b/plugins/dfu/dfu-device.c index 2e1e8a625..e92484b4c 100644 --- a/plugins/dfu/dfu-device.c +++ b/plugins/dfu/dfu-device.c @@ -1684,6 +1684,15 @@ dfu_device_dump_firmware (FuDevice *device, GError **error) { DfuDevice *self = DFU_DEVICE (device); g_autoptr(DfuFirmware) dfu_firmware = NULL; + g_autoptr(FuDeviceLocker) locker = NULL; + + /* require detach -> attach */ + locker = fu_device_locker_new_full (device, + (FuDeviceLockerFunc) fu_device_detach, + (FuDeviceLockerFunc) fu_device_attach, + error); + if (locker == NULL) + return NULL; /* get data from hardware */ g_debug ("uploading from device->host"); diff --git a/plugins/superio/fu-superio-it89-device.c b/plugins/superio/fu-superio-it89-device.c index 58b62af8d..03e8c3297 100644 --- a/plugins/superio/fu-superio-it89-device.c +++ b/plugins/superio/fu-superio-it89-device.c @@ -422,6 +422,15 @@ fu_superio_it89_device_dump_firmware (FuDevice *device, GError **error) { FuSuperioDevice *self = FU_SUPERIO_DEVICE (device); guint64 fwsize = fu_device_get_firmware_size_min (device); + g_autoptr(FuDeviceLocker) locker = NULL; + + /* require detach -> attach */ + locker = fu_device_locker_new_full (device, + (FuDeviceLockerFunc) fu_device_detach, + (FuDeviceLockerFunc) fu_device_attach, + error); + if (locker == NULL) + return NULL; fu_device_set_status (device, FWUPD_STATUS_DEVICE_READ); return fu_superio_it89_device_read_addr (self, 0x0, fwsize, diff --git a/plugins/vli/fu-vli-pd-device.c b/plugins/vli/fu-vli-pd-device.c index f71bd1800..8dc675e0c 100644 --- a/plugins/vli/fu-vli-pd-device.c +++ b/plugins/vli/fu-vli-pd-device.c @@ -367,6 +367,15 @@ static GBytes * fu_vli_pd_device_dump_firmware (FuDevice *device, GError **error) { FuVliPdDevice *self = FU_VLI_PD_DEVICE (device); + g_autoptr(FuDeviceLocker) locker = NULL; + + /* require detach -> attach */ + locker = fu_device_locker_new_full (device, + (FuDeviceLockerFunc) fu_device_detach, + (FuDeviceLockerFunc) fu_device_attach, + error); + if (locker == NULL) + return NULL; fu_device_set_status (FU_DEVICE (self), FWUPD_STATUS_DEVICE_READ); return fu_vli_device_spi_read (FU_VLI_DEVICE (self), 0x0, fu_device_get_firmware_size_max (device), diff --git a/src/fu-engine.c b/src/fu-engine.c index 165a4b002..17fe1af97 100644 --- a/src/fu-engine.c +++ b/src/fu-engine.c @@ -2761,28 +2761,14 @@ fu_engine_firmware_dump (FuEngine *self, GError **error) { g_autoptr(FuDeviceLocker) locker = NULL; - g_autoptr(GBytes) fw = NULL; - /* open, detach, read, attach, serialize */ + /* open, read, close */ locker = fu_device_locker_new (device, error); if (locker == NULL) { g_prefix_error (error, "failed to open device for firmware read: "); return NULL; } - if (!fu_device_detach (device, error)) - return NULL; - fw = fu_device_dump_firmware (device, error); - if (fw == NULL) { - g_autoptr(GError) error_local = NULL; - if (!fu_device_attach (device, &error_local)) { - g_warning ("failed to attach after read image failure: %s", - error_local->message); - } - return NULL; - } - if (!fu_device_attach (device, error)) - return NULL; - return g_steal_pointer (&fw); + return fu_device_dump_firmware (device, error); } gboolean From ad69dbbe4851c1df95b69acb9a4c372a0a8dfd76 Mon Sep 17 00:00:00 2001 From: Richard Hughes Date: Mon, 5 Oct 2020 22:13:51 +0100 Subject: [PATCH 499/607] trivial: Fix 'returning FALSE in a pointer function' warning --- libfwupdplugin/fu-firmware-image.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libfwupdplugin/fu-firmware-image.c b/libfwupdplugin/fu-firmware-image.c index f5d562239..a7c3034bc 100644 --- a/libfwupdplugin/fu-firmware-image.c +++ b/libfwupdplugin/fu-firmware-image.c @@ -278,7 +278,7 @@ GBytes * fu_firmware_image_get_bytes (FuFirmwareImage *self) { FuFirmwareImagePrivate *priv = GET_PRIVATE (self); - g_return_val_if_fail (FU_IS_FIRMWARE_IMAGE (self), FALSE); + g_return_val_if_fail (FU_IS_FIRMWARE_IMAGE (self), NULL); if (priv->bytes == NULL) return NULL; return g_bytes_ref (priv->bytes); From 488a8a76d40ccb420918305f7238627ded292b02 Mon Sep 17 00:00:00 2001 From: Richard Hughes Date: Mon, 5 Oct 2020 22:14:31 +0100 Subject: [PATCH 500/607] trivial: Fix 'returning FALSE in a pointer function' warning --- plugins/optionrom/fu-rom.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/plugins/optionrom/fu-rom.c b/plugins/optionrom/fu-rom.c index 11e47b4f7..84dfdce21 100644 --- a/plugins/optionrom/fu-rom.c +++ b/plugins/optionrom/fu-rom.c @@ -702,7 +702,7 @@ fu_rom_dump_firmware (GFile *file, GCancellable *cancellable, GError **error) FWUPD_ERROR, FWUPD_ERROR_AUTH_FAILED, error_local->message); - return FALSE; + return NULL; } /* we have to enable the read for devices */ @@ -712,10 +712,10 @@ fu_rom_dump_firmware (GFile *file, GCancellable *cancellable, GError **error) output_stream = g_file_replace (file, NULL, FALSE, G_FILE_CREATE_NONE, cancellable, error); if (output_stream == NULL) - return FALSE; + return NULL; if (g_output_stream_write (G_OUTPUT_STREAM (output_stream), "1", 1, cancellable, error) < 0) - return FALSE; + return NULL; } /* ensure we got enough data to fill the buffer */ @@ -727,7 +727,7 @@ fu_rom_dump_firmware (GFile *file, GCancellable *cancellable, GError **error) break; g_debug ("ROM returned 0x%04x bytes", (guint) sz); if (sz < 0) - return FALSE; + return NULL; g_byte_array_append (buf, tmp, sz); /* check the firmware isn't serving us small chunks */ @@ -736,7 +736,7 @@ fu_rom_dump_firmware (GFile *file, GCancellable *cancellable, GError **error) FWUPD_ERROR, FWUPD_ERROR_INVALID_FILE, "firmware not fulfilling requests"); - return FALSE; + return NULL; } } if (buf->len < 512) { @@ -744,7 +744,7 @@ fu_rom_dump_firmware (GFile *file, GCancellable *cancellable, GError **error) FWUPD_ERROR, FWUPD_ERROR_INVALID_FILE, "firmware too small: %u bytes", buf->len); - return FALSE; + return NULL; } return g_byte_array_free_to_bytes (g_steal_pointer (&buf)); } From 406025ba567e905000a49a76784f1bc2e6b4901a Mon Sep 17 00:00:00 2001 From: Mario Limonciello Date: Tue, 6 Oct 2020 10:54:11 -0500 Subject: [PATCH 501/607] trivial: ci: fix installed-tests for test plugin This has been broken for a while and missed various changes. * Reading firmware version * Passing `-y` into build * New verify / verify-image split --- data/installed-tests/fakedevice123.bin | 2 +- data/installed-tests/fakedevice123.bin.asc | 16 ++++++++-------- data/installed-tests/fakedevice123.metainfo.xml | 4 ++-- data/installed-tests/fakedevice124.bin | 2 +- data/installed-tests/fakedevice124.bin.asc | 16 ++++++++-------- data/installed-tests/fakedevice124.metainfo.xml | 4 ++-- data/installed-tests/fwupdmgr.sh | 6 +++--- plugins/test/fu-plugin-test.c | 2 +- 8 files changed, 26 insertions(+), 26 deletions(-) diff --git a/data/installed-tests/fakedevice123.bin b/data/installed-tests/fakedevice123.bin index a284bbbf9..885b0f234 100644 --- a/data/installed-tests/fakedevice123.bin +++ b/data/installed-tests/fakedevice123.bin @@ -1 +1 @@ -fakedevice123 -n +0x1020003 diff --git a/data/installed-tests/fakedevice123.bin.asc b/data/installed-tests/fakedevice123.bin.asc index 6cf14f45e..ed6d9b858 100644 --- a/data/installed-tests/fakedevice123.bin.asc +++ b/data/installed-tests/fakedevice123.bin.asc @@ -1,11 +1,11 @@ -----BEGIN PGP SIGNATURE----- -Version: GnuPG v2.0.14 (GNU/Linux) +Version: GnuPG v2.0.22 (GNU/Linux) -iQEcBAABAgAGBQJZQqynAAoJEEim2A5FOLrCVcsH/3Vn56wSeRCol0rOeXvoupg2 -qpTAmqUvlubv2vX1IDbcL/lHIIEAHAlN/4LRHUh+Om0T7bMKX1uSfmcgCyUTBxl0 -fm3TfXRhybi9VtZ5ZpwWxGsFsCNC9eOU0i8tB1zp9e9KjDPiYnluFkTRQ+Aw3u1u -tKBMTk6Z+VQlIUFrsveFYmPMGDkvn8AWbJCz6E4jc8can/lP/9djSi91mCqtEq/j -YTBz4OwfU80MRrSgoxykHgcB1RiT43ywfKlpHQzcO+rqCV7rv7LkXIEzBdWRZstk -XmboCnEKuMxtr+vXlGqU4n+upQkYur3Vs+07ut1OewQnJT3eeZbAH0mr42MVf7c= -=MQJe +iQEcBAABAgAGBQJfey1HAAoJEEim2A5FOLrCn2MIAK6BnVojGYSwHVpZm58b05Xs +rNqozg5pvfDfB0Bde1S0T/4TlDEnJNUku0Gz5IFNbR3ENT5VnJgBkE5xa8Rmv6cy +Gm30CmX+UE1E8qK4BVhUdbNN8bEmeMtzUMK2KfpwMXlIqcpSjpln76PQIxMHj+3P +600bkcppkLEKhiOo+THNhiHxPYJ+wjSSPm3paeMmUuApIvP4YFH8uQ5qkKLdLDVI +V5QOx3O5P3avmHu936GILG9EwV3TkR1eNOe33OqtrGvpoMTcsxUF0Wc/qmUD066d +c9hkTe01paQoN0HW/RMgrIaMnLFwK2mBcwySOo6TU9MIyQfDmLGN3u12nCrmRH8= +=Rq70 -----END PGP SIGNATURE----- diff --git a/data/installed-tests/fakedevice123.metainfo.xml b/data/installed-tests/fakedevice123.metainfo.xml index cef8c055e..52c9c71f4 100644 --- a/data/installed-tests/fakedevice123.metainfo.xml +++ b/data/installed-tests/fakedevice123.metainfo.xml @@ -1,8 +1,8 @@ - fakedevice.firmware - FakeDevice Firmware + org.fwupd.fakedevice.firmware + FakeDevice Firmware for the ACME Corp Integrated Webcam

      diff --git a/data/installed-tests/fakedevice124.bin b/data/installed-tests/fakedevice124.bin index 913d074d1..f1b2c68db 100644 --- a/data/installed-tests/fakedevice124.bin +++ b/data/installed-tests/fakedevice124.bin @@ -1 +1 @@ -fakedevice124 -n +0x1020004 diff --git a/data/installed-tests/fakedevice124.bin.asc b/data/installed-tests/fakedevice124.bin.asc index d765b59d3..2b2192170 100644 --- a/data/installed-tests/fakedevice124.bin.asc +++ b/data/installed-tests/fakedevice124.bin.asc @@ -1,11 +1,11 @@ -----BEGIN PGP SIGNATURE----- -Version: GnuPG v2.0.14 (GNU/Linux) +Version: GnuPG v2.0.22 (GNU/Linux) -iQEcBAABAgAGBQJZQqy9AAoJEEim2A5FOLrCRLEH/27k0IfUtfGS8T5CPTvwW8kF -Cf6EIzw+2HgjbxLdeMNHwiHCBdIR58z44O1I9Xy6gY1vF3H4kKft6oBAUFDH0Ja5 -YpQHXMZVSNdnwdg57cyC67kLOycHTSDlLXKB74tU3R4J8xntA1cY+DSYmCs2uAjq -3T3ExfjrX6PGbRhbNr8vBUQckCxcGvEZNOws2081mTosEQNpIxFyJ2tbbKLR60d0 -5O/UDjNEYfUFCGy7MycXePEIOR+rO6KuEQ3vjJnv80UKE8msFxJTM1iKwct+B2HI -JNecCsx14BGDXCiE0Xc0heunfWiBHmNS2lymrHsU2Z82VrFqP0obD2cm64PBf0Y= -=Wsq/ +iQEcBAABAgAGBQJfey2FAAoJEEim2A5FOLrCl88IAKCggwAz3qBrBfrc91sYHCq5 +OthMyftOUTQ4JpfISY38k20pwFEhsSHKdKAYDKEVO2jopw+Cr9oTyFycWK20R2lz +tUn4e1EF8zQ29OLxGbvgGlP5/4vPJ2Cv5ujkub6LtNBrOMkNJ6+bB6G8nJZRTElU +e3wi9+E9oKPBgP40A/y79pzPiFMxXl1piYjU3JNeofd3nbtmyRqb6VAs9exQ94+p +CMWWZaJ9igxSAsQiE/NxZpO8qgG3KEmsW7yXRiaIe6xHxb49+JQdjxqS8Oc/C9sX +FSiVHDPzlUegZtcRWZy2zeSNTqmu8vzNSei0xEaLCaQ6PO+pQibxS2VZI/jDLdQ= +=Gha4 -----END PGP SIGNATURE----- diff --git a/data/installed-tests/fakedevice124.metainfo.xml b/data/installed-tests/fakedevice124.metainfo.xml index d9230f399..6b67f36cd 100644 --- a/data/installed-tests/fakedevice124.metainfo.xml +++ b/data/installed-tests/fakedevice124.metainfo.xml @@ -1,8 +1,8 @@ - fakedevice.firmware - FakeDevice Firmware + org.fwupd.fakedevice.firmware + FakeDevice

      Firmware for the ACME Corp Integrated Webcam

      diff --git a/data/installed-tests/fwupdmgr.sh b/data/installed-tests/fwupdmgr.sh index ed77e6d04..2d96bf4df 100755 --- a/data/installed-tests/fwupdmgr.sh +++ b/data/installed-tests/fwupdmgr.sh @@ -43,7 +43,7 @@ rc=$?; if [[ $rc != 0 ]]; then error $rc; fi # --- echo "Installing test firmware..." -fwupdmgr install ${dirname}/fakedevice124.cab +fwupdmgr update $device -y rc=$?; if [[ $rc != 0 ]]; then error $rc; fi # --- @@ -58,7 +58,7 @@ rc=$?; if [[ $rc != 0 ]]; then error $rc; fi # --- echo "Downgrading to older release (requires network access)" -fwupdmgr downgrade $device +fwupdmgr downgrade $device -y rc=$?; if [[ $rc != 0 ]]; then error $rc; fi # --- @@ -68,7 +68,7 @@ rc=$?; if [[ $rc != 2 ]]; then error $rc; fi # --- echo "Updating all devices to latest release (requires network access)" -fwupdmgr --no-unreported-check --no-metadata-check --no-reboot-check update +fwupdmgr --no-unreported-check --no-metadata-check --no-reboot-check update -y rc=$?; if [[ $rc != 0 ]]; then error $rc; fi # --- diff --git a/plugins/test/fu-plugin-test.c b/plugins/test/fu-plugin-test.c index a2d90d030..2380ecb56 100644 --- a/plugins/test/fu-plugin-test.c +++ b/plugins/test/fu-plugin-test.c @@ -38,7 +38,7 @@ fu_plugin_coldplug (FuPlugin *plugin, GError **error) fu_device_set_name (device, "Integrated_Webcam(TM)"); fu_device_add_icon (device, "preferences-desktop-keyboard"); fu_device_add_flag (device, FWUPD_DEVICE_FLAG_UPDATABLE); - fu_device_add_flag (device, FWUPD_DEVICE_FLAG_CAN_VERIFY); + fu_device_add_flag (device, FWUPD_DEVICE_FLAG_CAN_VERIFY_IMAGE); fu_device_set_protocol (device, "com.acme.test"); fu_device_set_summary (device, "A fake webcam"); fu_device_set_vendor (device, "ACME Corp."); From e8946a74d16e26a2fcd47f94f7ca5a439d129a4c Mon Sep 17 00:00:00 2001 From: Mario Limonciello Date: Wed, 30 Sep 2020 16:31:03 -0500 Subject: [PATCH 502/607] fwupdtool/fwupdmgr: make return code different for get-updates with no updates This allows other tools to depend on it when checking for updates rather than reading the output. --- src/fu-tool.c | 13 ++++++++++--- src/fu-util.c | 19 +++++++++++++------ 2 files changed, 23 insertions(+), 9 deletions(-) diff --git a/src/fu-tool.c b/src/fu-tool.c index 314884867..4d803a408 100644 --- a/src/fu-tool.c +++ b/src/fu-tool.c @@ -485,13 +485,20 @@ fu_util_get_updates (FuUtilPrivate *priv, gchar **values, GError **error) g_node_append_data (child, g_object_ref (rel)); } } - if (g_node_n_nodes (root, G_TRAVERSE_ALL) > 1) - fu_util_print_tree (root, title); /* save the device state for other applications to see */ if (!fu_util_save_current_state (priv, error)) return FALSE; - /* success */ + /* updates */ + if (g_node_n_nodes (root, G_TRAVERSE_ALL) <= 1) { + g_set_error_literal (error, + FWUPD_ERROR, + FWUPD_ERROR_NOTHING_TO_DO, + "No updates available for remaining devices"); + return FALSE; + } + + fu_util_print_tree (root, title); return TRUE; } diff --git a/src/fu-util.c b/src/fu-util.c index 9b30dec34..340663c66 100644 --- a/src/fu-util.c +++ b/src/fu-util.c @@ -1442,9 +1442,6 @@ fu_util_get_updates (FuUtilPrivate *priv, gchar **values, GError **error) } } - if (g_node_n_nodes (root, G_TRAVERSE_ALL) > 1) - fu_util_print_tree (root, title); - /* nag? */ if (!fu_util_perhaps_show_unreported (priv, error)) return FALSE; @@ -1452,11 +1449,21 @@ fu_util_get_updates (FuUtilPrivate *priv, gchar **values, GError **error) /* no devices supported by LVFS or all are filtered */ if (!supported) { g_set_error_literal (error, - FWUPD_ERROR, - FWUPD_ERROR_NOTHING_TO_DO, - "No updatable devices"); + FWUPD_ERROR, + FWUPD_ERROR_NOTHING_TO_DO, + "No updatable devices"); return FALSE; } + /* no updates available */ + if (g_node_n_nodes (root, G_TRAVERSE_ALL) <= 1) { + g_set_error_literal (error, + FWUPD_ERROR, + FWUPD_ERROR_NOTHING_TO_DO, + "No updates available for remaining devices"); + return FALSE; + } + + fu_util_print_tree (root, title); /* success */ return TRUE; From 8d850db5cd31f323a38fc5e2b4cefcfcbc5ffbaa Mon Sep 17 00:00:00 2001 From: Richard Hughes Date: Wed, 7 Oct 2020 08:44:55 +0100 Subject: [PATCH 503/607] spec: Split out a fwupd-plugin-modem-manager subpackage This is installed by default, but means it can be excluded from the minimal CoreOS image. It's highly unlikely that anything running CoreOS has mobile broadband hardware attached. This drops inclusion of libmbim, libqmi and ModemManager-glib as hard dependencies from the package set. --- contrib/fwupd.spec.in | 22 +++++++++++++++++++--- 1 file changed, 19 insertions(+), 3 deletions(-) diff --git a/contrib/fwupd.spec.in b/contrib/fwupd.spec.in index 1f5cef6cb..701176c0c 100644 --- a/contrib/fwupd.spec.in +++ b/contrib/fwupd.spec.in @@ -144,6 +144,11 @@ Provides: fwupdate Provides: fwupdate-efi %endif +# optional, but a really good idea +%if 0%{?have_modem_manager} +Recommends: %{name}-plugin-modem-manager +%endif + %description fwupd is a daemon to allow session software to update device firmware. @@ -162,6 +167,15 @@ Summary: Data files for installed tests %description tests Data files for installed tests. +%if 0%{?have_modem_manager} +%package plugin-modem-manager +Summary: fwupd plugin using ModemManger + +%description plugin-modem-manager +This provides the optional package which is only required on hardware that +might have mobile broadband hardware. It is probably not required on servers. +%endif + %prep %autosetup -p1 @@ -390,9 +404,6 @@ mkdir -p --mode=0700 $RPM_BUILD_ROOT%{_localstatedir}/lib/fwupd/gnupg %{_libdir}/fwupd-plugins-3/libfu_plugin_linux_sleep.so %{_libdir}/fwupd-plugins-3/libfu_plugin_linux_swap.so %{_libdir}/fwupd-plugins-3/libfu_plugin_linux_tainted.so -%if 0%{?have_modem_manager} -%{_libdir}/fwupd-plugins-3/libfu_plugin_modem_manager.so -%endif %if 0%{?have_msr} %{_libdir}/fwupd-plugins-3/libfu_plugin_msr.so %endif @@ -443,6 +454,11 @@ mkdir -p --mode=0700 $RPM_BUILD_ROOT%{_localstatedir}/lib/fwupd/gnupg %{_datadir}/locale/*/LC_IMAGES/fwupd* %endif +%if 0%{?have_modem_manager} +%files plugin-modem-manager +%{_libdir}/fwupd-plugins-3/libfu_plugin_modem_manager.so +%endif + %files devel %{_datadir}/gir-1.0/Fwupd-2.0.gir %{_datadir}/gir-1.0/FwupdPlugin-1.0.gir From a1bc349dbac18ae2e38b6c18737e865d581354be Mon Sep 17 00:00:00 2001 From: Richard Hughes Date: Wed, 7 Oct 2020 08:52:18 +0100 Subject: [PATCH 504/607] spec: Split out a fwupd-plugin-flashrom subpackage This is installed by default, but means it can be excluded from the minimal CoreOS image. It's highly unlikely that anything running CoreOS has anything unlocked that can be flashed using flashrom. This drops inclusion of dmidecode, libftdi, pciutils-libs and flashrom as hard dependencies from the package set. --- contrib/fwupd.spec.in | 19 ++++++++++++++++--- 1 file changed, 16 insertions(+), 3 deletions(-) diff --git a/contrib/fwupd.spec.in b/contrib/fwupd.spec.in index 701176c0c..f4b4a11f1 100644 --- a/contrib/fwupd.spec.in +++ b/contrib/fwupd.spec.in @@ -148,6 +148,9 @@ Provides: fwupdate-efi %if 0%{?have_modem_manager} Recommends: %{name}-plugin-modem-manager %endif +%if 0%{?have_flashrom} +Recommends: %{name}-plugin-flashrom +%endif %description fwupd is a daemon to allow session software to update device firmware. @@ -176,6 +179,15 @@ This provides the optional package which is only required on hardware that might have mobile broadband hardware. It is probably not required on servers. %endif +%if 0%{?have_flashrom} +%package plugin-flashrom +Summary: fwupd plugin using flashrom + +%description plugin-flashrom +This provides the optional package which is only required on hardware that +can be flashed using flashrom. It is probably not required on servers. +%endif + %prep %autosetup -p1 @@ -394,9 +406,6 @@ mkdir -p --mode=0700 $RPM_BUILD_ROOT%{_localstatedir}/lib/fwupd/gnupg %{_libdir}/fwupd-plugins-3/libfu_plugin_emmc.so %{_libdir}/fwupd-plugins-3/libfu_plugin_ep963x.so %{_libdir}/fwupd-plugins-3/libfu_plugin_fastboot.so -%if 0%{?have_flashrom} -%{_libdir}/fwupd-plugins-3/libfu_plugin_flashrom.so -%endif %{_libdir}/fwupd-plugins-3/libfu_plugin_fresco_pd.so %{_libdir}/fwupd-plugins-3/libfu_plugin_iommu.so %{_libdir}/fwupd-plugins-3/libfu_plugin_jabra.so @@ -458,6 +467,10 @@ mkdir -p --mode=0700 $RPM_BUILD_ROOT%{_localstatedir}/lib/fwupd/gnupg %files plugin-modem-manager %{_libdir}/fwupd-plugins-3/libfu_plugin_modem_manager.so %endif +%if 0%{?have_flashrom} +%files plugin-flashrom +%{_libdir}/fwupd-plugins-3/libfu_plugin_flashrom.so +%endif %files devel %{_datadir}/gir-1.0/Fwupd-2.0.gir From 5bbf01387996050ce3f63c6ff0e374ffc3ea99d2 Mon Sep 17 00:00:00 2001 From: Richard Hughes Date: Mon, 5 Oct 2020 13:44:39 +0100 Subject: [PATCH 505/607] Add a --allow-branch-switch to fwupdmgr This allows us to turn off the tests like version format differences and checking for downgrades. --- data/bash-completion/fwupdmgr.in | 1 + libfwupd/fwupd-client.c | 4 ++++ libfwupd/fwupd-enums.h | 2 ++ src/fu-engine.c | 2 ++ src/fu-install-task.c | 25 +++++++++++++++++++++++-- src/fu-main.c | 3 +++ src/fu-util.c | 7 +++++++ 7 files changed, 42 insertions(+), 2 deletions(-) diff --git a/data/bash-completion/fwupdmgr.in b/data/bash-completion/fwupdmgr.in index e5a884819..993d88381 100644 --- a/data/bash-completion/fwupdmgr.in +++ b/data/bash-completion/fwupdmgr.in @@ -41,6 +41,7 @@ _fwupdmgr_opts=( '--offline' '--allow-reinstall' '--allow-older' + '--allow-branch-switch' '--force' '--assume-yes' '--no-history' diff --git a/libfwupd/fwupd-client.c b/libfwupd/fwupd-client.c index 00a4417bc..47136bf20 100644 --- a/libfwupd/fwupd-client.c +++ b/libfwupd/fwupd-client.c @@ -1879,6 +1879,10 @@ fwupd_client_install_stream_async (FwupdClient *self, g_variant_builder_add (&builder, "{sv}", "allow-reinstall", g_variant_new_boolean (TRUE)); } + if (install_flags & FWUPD_INSTALL_FLAG_ALLOW_BRANCH_SWITCH) { + g_variant_builder_add (&builder, "{sv}", + "allow-branch-switch", g_variant_new_boolean (TRUE)); + } if (install_flags & FWUPD_INSTALL_FLAG_FORCE) { g_variant_builder_add (&builder, "{sv}", "force", g_variant_new_boolean (TRUE)); diff --git a/libfwupd/fwupd-enums.h b/libfwupd/fwupd-enums.h index cda52db1f..88f59869e 100644 --- a/libfwupd/fwupd-enums.h +++ b/libfwupd/fwupd-enums.h @@ -228,6 +228,7 @@ typedef enum { * @FWUPD_INSTALL_FLAG_ALLOW_OLDER: Allow downgrading firmware * @FWUPD_INSTALL_FLAG_FORCE: Force the update even if not a good idea * @FWUPD_INSTALL_FLAG_NO_HISTORY: Do not write to the history database + * @FWUPD_INSTALL_FLAG_ALLOW_BRANCH_SWITCH: Allow firmware branch switching * * Flags to set when performing the firmware update or install. **/ @@ -238,6 +239,7 @@ typedef enum { FWUPD_INSTALL_FLAG_ALLOW_OLDER = 1 << 2, /* Since: 0.7.0 */ FWUPD_INSTALL_FLAG_FORCE = 1 << 3, /* Since: 0.7.1 */ FWUPD_INSTALL_FLAG_NO_HISTORY = 1 << 4, /* Since: 1.0.8 */ + FWUPD_INSTALL_FLAG_ALLOW_BRANCH_SWITCH = 1 << 5, /* Since: 1.5.0 */ /*< private >*/ FWUPD_INSTALL_FLAG_LAST } FwupdInstallFlags; diff --git a/src/fu-engine.c b/src/fu-engine.c index 17fe1af97..9188a9560 100644 --- a/src/fu-engine.c +++ b/src/fu-engine.c @@ -3883,6 +3883,7 @@ fu_engine_get_details (FuEngine *self, FuEngineRequest *request, gint fd, GError if (!fu_engine_check_requirements (self, request, task, FWUPD_INSTALL_FLAG_OFFLINE | FWUPD_INSTALL_FLAG_ALLOW_REINSTALL | + FWUPD_INSTALL_FLAG_ALLOW_BRANCH_SWITCH | FWUPD_INSTALL_FLAG_ALLOW_OLDER, &error_req)) { g_debug ("%s failed requirement checks: %s", @@ -4215,6 +4216,7 @@ fu_engine_add_releases_for_device_component (FuEngine *self, if (!fu_engine_check_requirements (self, request, task, FWUPD_INSTALL_FLAG_OFFLINE | + FWUPD_INSTALL_FLAG_ALLOW_BRANCH_SWITCH | FWUPD_INSTALL_FLAG_ALLOW_REINSTALL | FWUPD_INSTALL_FLAG_ALLOW_OLDER, error)) diff --git a/src/fu-install-task.c b/src/fu-install-task.c index ccab6bc57..6304cc0ad 100644 --- a/src/fu-install-task.c +++ b/src/fu-install-task.c @@ -198,6 +198,8 @@ fu_install_task_check_requirements (FuInstallTask *self, FwupdInstallFlags flags, GError **error) { + const gchar *branch_new; + const gchar *branch_old; const gchar *protocol; const gchar *version; const gchar *version_release_raw; @@ -275,6 +277,22 @@ fu_install_task_check_requirements (FuInstallTask *self, return FALSE; } + /* check the branch is not switching */ + branch_new = xb_node_query_text (self->component, "branch", NULL); + branch_old = fu_device_get_branch (self->device); + if ((flags & FWUPD_INSTALL_FLAG_ALLOW_BRANCH_SWITCH) == 0 && + g_strcmp0 (branch_old, branch_new) != 0) { + g_set_error (error, + FWUPD_ERROR, + FWUPD_ERROR_NOT_SUPPORTED, + "Device %s [%s] would switch firmware branch from %s to %s", + fu_device_get_name (self->device), + fu_device_get_id (self->device), + branch_old != NULL ? branch_old : "default", + branch_new != NULL ? branch_new : "default"); + return FALSE; + } + /* no update abilities */ if (!fu_device_has_flag (self->device, FWUPD_DEVICE_FLAG_UPDATABLE) && !fu_device_has_flag (self->device, FWUPD_DEVICE_FLAG_UPDATABLE_HIDDEN)) { @@ -335,7 +353,8 @@ fu_install_task_check_requirements (FuInstallTask *self, } /* check the version formats match if set in the release */ - if ((flags & FWUPD_INSTALL_FLAG_FORCE) == 0) { + if ((flags & FWUPD_INSTALL_FLAG_FORCE) == 0 && + (flags & FWUPD_INSTALL_FLAG_ALLOW_BRANCH_SWITCH) == 0) { verfmts = xb_node_query (self->component, "custom/value[@key='LVFS::VersionFormat']", 0, NULL); @@ -377,7 +396,9 @@ fu_install_task_check_requirements (FuInstallTask *self, return FALSE; } self->is_downgrade = vercmp > 0; - if (self->is_downgrade && (flags & FWUPD_INSTALL_FLAG_ALLOW_OLDER) == 0) { + if (self->is_downgrade && + (flags & FWUPD_INSTALL_FLAG_ALLOW_OLDER) == 0 && + (flags & FWUPD_INSTALL_FLAG_ALLOW_BRANCH_SWITCH) == 0) { g_set_error (error, FWUPD_ERROR, FWUPD_ERROR_VERSION_NEWER, diff --git a/src/fu-main.c b/src/fu-main.c index 05074acf7..6fba8a83b 100644 --- a/src/fu-main.c +++ b/src/fu-main.c @@ -1429,6 +1429,9 @@ fu_main_daemon_method_call (GDBusConnection *connection, const gchar *sender, if (g_strcmp0 (prop_key, "allow-reinstall") == 0 && g_variant_get_boolean (prop_value) == TRUE) helper->flags |= FWUPD_INSTALL_FLAG_ALLOW_REINSTALL; + if (g_strcmp0 (prop_key, "allow-branch-switch") == 0 && + g_variant_get_boolean (prop_value) == TRUE) + helper->flags |= FWUPD_INSTALL_FLAG_ALLOW_BRANCH_SWITCH; if (g_strcmp0 (prop_key, "force") == 0 && g_variant_get_boolean (prop_value) == TRUE) helper->flags |= FWUPD_INSTALL_FLAG_FORCE; diff --git a/src/fu-util.c b/src/fu-util.c index 340663c66..1796401d2 100644 --- a/src/fu-util.c +++ b/src/fu-util.c @@ -2018,6 +2018,7 @@ fu_util_switch_branch (FuUtilPrivate *priv, gchar **values, GError **error) g_signal_connect (priv->client, "device-changed", G_CALLBACK (fu_util_update_device_changed_cb), priv); priv->flags |= FWUPD_INSTALL_FLAG_ALLOW_REINSTALL; + priv->flags |= FWUPD_INSTALL_FLAG_ALLOW_BRANCH_SWITCH; if (!fu_util_update_device_with_release (priv, dev, rel, error)) return FALSE; fu_util_display_current_message (priv); @@ -2660,6 +2661,7 @@ int main (int argc, char *argv[]) { gboolean force = FALSE; + gboolean allow_branch_switch = FALSE; gboolean allow_older = FALSE; gboolean allow_reinstall = FALSE; gboolean is_interactive = TRUE; @@ -2690,6 +2692,9 @@ main (int argc, char *argv[]) { "allow-older", '\0', 0, G_OPTION_ARG_NONE, &allow_older, /* TRANSLATORS: command line option */ _("Allow downgrading firmware versions"), NULL }, + { "allow-branch-switch", '\0', 0, G_OPTION_ARG_NONE, &allow_branch_switch, + /* TRANSLATORS: command line option */ + _("Allow switching firmware branch"), NULL }, { "force", '\0', 0, G_OPTION_ARG_NONE, &force, /* TRANSLATORS: command line option */ _("Override warnings and force the action"), NULL }, @@ -3010,6 +3015,8 @@ main (int argc, char *argv[]) priv->flags |= FWUPD_INSTALL_FLAG_ALLOW_REINSTALL; if (allow_older) priv->flags |= FWUPD_INSTALL_FLAG_ALLOW_OLDER; + if (allow_branch_switch) + priv->flags |= FWUPD_INSTALL_FLAG_ALLOW_BRANCH_SWITCH; if (force) priv->flags |= FWUPD_INSTALL_FLAG_FORCE; if (no_history) From 6450d0deb446380befa28795c52f5f0b628c4595 Mon Sep 17 00:00:00 2001 From: Richard Hughes Date: Tue, 6 Oct 2020 16:05:24 +0100 Subject: [PATCH 506/607] Add FwupdInstallFlags of _IGNORE_CHECKSUM, _IGNORE_VID_PID and _IGNORE_POWER The FWUPD_INSTALL_FLAG_FORCE flag has really unclear semantics, and ignoring a file CRC, checksum or model ID should only be done when using fwupdtool actually debugging a plugin or firmware parser. Use the existing --force flag when we want a "gentle nudge" like reuploading previously processed reports. --- data/bash-completion/fwupdmgr.in | 1 + data/bash-completion/fwupdtool.in | 3 ++ libfwupd/fwupd-client.c | 4 +++ libfwupd/fwupd-enums.h | 6 ++++ libfwupdplugin/fu-dfu-firmware.c | 2 +- libfwupdplugin/fu-ihex-firmware.c | 2 +- libfwupdplugin/fu-srec-firmware.c | 2 +- plugins/ccgx/fu-ccgx-hpi-device.c | 2 +- plugins/dfu/dfu-device.c | 2 +- plugins/dfu/dfu-tool.c | 6 ++-- .../synaptics-mst/fu-synaptics-mst-device.c | 2 +- .../synaptics-prometheus/fu-synaprom-config.c | 4 +-- .../synaptics-prometheus/fu-synaprom-device.c | 2 +- plugins/synaptics-rmi/fu-dump.c | 2 +- .../synaptics-rmi/fu-synaptics-rmi-firmware.c | 2 +- plugins/thunderbolt/fu-thunderbolt-device.c | 2 +- plugins/upower/fu-plugin-upower.c | 4 +-- plugins/vli/fu-vli-pd-firmware.c | 2 +- src/fu-firmware-dump.c | 5 +++- src/fu-main.c | 7 ++++- src/fu-tool.c | 30 +++++++++++++++++-- src/fu-util.c | 12 ++++++-- 22 files changed, 81 insertions(+), 23 deletions(-) diff --git a/data/bash-completion/fwupdmgr.in b/data/bash-completion/fwupdmgr.in index 993d88381..f93631860 100644 --- a/data/bash-completion/fwupdmgr.in +++ b/data/bash-completion/fwupdmgr.in @@ -53,6 +53,7 @@ _fwupdmgr_opts=( '--sign' '--filter' '--disable-ssl-strict' + '--ignore-power' ) _show_filters() diff --git a/data/bash-completion/fwupdtool.in b/data/bash-completion/fwupdtool.in index 7d062e46b..753673211 100644 --- a/data/bash-completion/fwupdtool.in +++ b/data/bash-completion/fwupdtool.in @@ -51,6 +51,9 @@ _fwupdtool_opts=( '--filter' '--disable-ssl-strict' '--no-safety-check' + '--ignore-checksum' + '--ignore-vid-pid' + '--ignore-power' ) _show_filters() diff --git a/libfwupd/fwupd-client.c b/libfwupd/fwupd-client.c index 47136bf20..28ba6ce06 100644 --- a/libfwupd/fwupd-client.c +++ b/libfwupd/fwupd-client.c @@ -1887,6 +1887,10 @@ fwupd_client_install_stream_async (FwupdClient *self, g_variant_builder_add (&builder, "{sv}", "force", g_variant_new_boolean (TRUE)); } + if (install_flags & FWUPD_INSTALL_FLAG_IGNORE_POWER) { + g_variant_builder_add (&builder, "{sv}", + "ignore-power", g_variant_new_boolean (TRUE)); + } if (install_flags & FWUPD_INSTALL_FLAG_NO_HISTORY) { g_variant_builder_add (&builder, "{sv}", "no-history", g_variant_new_boolean (TRUE)); diff --git a/libfwupd/fwupd-enums.h b/libfwupd/fwupd-enums.h index 88f59869e..5bc9f6eee 100644 --- a/libfwupd/fwupd-enums.h +++ b/libfwupd/fwupd-enums.h @@ -229,6 +229,9 @@ typedef enum { * @FWUPD_INSTALL_FLAG_FORCE: Force the update even if not a good idea * @FWUPD_INSTALL_FLAG_NO_HISTORY: Do not write to the history database * @FWUPD_INSTALL_FLAG_ALLOW_BRANCH_SWITCH: Allow firmware branch switching + * @FWUPD_INSTALL_FLAG_IGNORE_CHECKSUM: Ignore firmware CRCs and checksums + * @FWUPD_INSTALL_FLAG_IGNORE_VID_PID: Ignore firmware vendor and project checks + * @FWUPD_INSTALL_FLAG_IGNORE_POWER: Ignore requirement of external power source * * Flags to set when performing the firmware update or install. **/ @@ -240,6 +243,9 @@ typedef enum { FWUPD_INSTALL_FLAG_FORCE = 1 << 3, /* Since: 0.7.1 */ FWUPD_INSTALL_FLAG_NO_HISTORY = 1 << 4, /* Since: 1.0.8 */ FWUPD_INSTALL_FLAG_ALLOW_BRANCH_SWITCH = 1 << 5, /* Since: 1.5.0 */ + FWUPD_INSTALL_FLAG_IGNORE_CHECKSUM = 1 << 6, /* Since: 1.5.0 */ + FWUPD_INSTALL_FLAG_IGNORE_VID_PID = 1 << 7, /* Since: 1.5.0 */ + FWUPD_INSTALL_FLAG_IGNORE_POWER = 1 << 8, /* Since: 1.5.0 */ /*< private >*/ FWUPD_INSTALL_FLAG_LAST } FwupdInstallFlags; diff --git a/libfwupdplugin/fu-dfu-firmware.c b/libfwupdplugin/fu-dfu-firmware.c index 033aaaa26..17c28d14c 100644 --- a/libfwupdplugin/fu-dfu-firmware.c +++ b/libfwupdplugin/fu-dfu-firmware.c @@ -235,7 +235,7 @@ fu_dfu_firmware_parse (FuFirmware *firmware, sizeof(FuDfuFirmwareFooter), error)) return FALSE; crc = GUINT32_FROM_LE(ftr.crc); - if ((flags & FWUPD_INSTALL_FLAG_FORCE) == 0) { + if ((flags & FWUPD_INSTALL_FLAG_IGNORE_CHECKSUM) == 0) { crc_new = ~fu_common_crc32 (data, len - 4); if (crc != crc_new) { g_set_error (error, diff --git a/libfwupdplugin/fu-ihex-firmware.c b/libfwupdplugin/fu-ihex-firmware.c index 98ddb4052..27b4d34e7 100644 --- a/libfwupdplugin/fu-ihex-firmware.c +++ b/libfwupdplugin/fu-ihex-firmware.c @@ -195,7 +195,7 @@ fu_ihex_firmware_parse (FuFirmware *firmware, } /* verify checksum */ - if ((flags & FWUPD_INSTALL_FLAG_FORCE) == 0) { + if ((flags & FWUPD_INSTALL_FLAG_IGNORE_CHECKSUM) == 0) { guint8 checksum = 0; for (guint i = 1; i < line_end + 2; i += 2) { guint8 data_tmp = fu_firmware_strparse_uint8 (line + i); diff --git a/libfwupdplugin/fu-srec-firmware.c b/libfwupdplugin/fu-srec-firmware.c index 8a12810c9..d42dfcedf 100644 --- a/libfwupdplugin/fu-srec-firmware.c +++ b/libfwupdplugin/fu-srec-firmware.c @@ -142,7 +142,7 @@ fu_srec_firmware_tokenize (FuFirmware *firmware, GBytes *fw, } /* checksum check */ - if ((flags & FWUPD_INSTALL_FLAG_FORCE) == 0) { + if ((flags & FWUPD_INSTALL_FLAG_IGNORE_CHECKSUM) == 0) { guint8 rec_csum = 0; guint8 rec_csum_expected; for (guint8 i = 0; i < rec_count; i++) diff --git a/plugins/ccgx/fu-ccgx-hpi-device.c b/plugins/ccgx/fu-ccgx-hpi-device.c index 606a7a7e5..e61a095ba 100644 --- a/plugins/ccgx/fu-ccgx-hpi-device.c +++ b/plugins/ccgx/fu-ccgx-hpi-device.c @@ -1082,7 +1082,7 @@ fu_ccgx_hpi_device_prepare_firmware (FuDevice *device, self->silicon_id, fw_silicon_id); return NULL; } - if ((flags & FWUPD_INSTALL_FLAG_FORCE) == 0) { + if ((flags & FWUPD_INSTALL_FLAG_IGNORE_VID_PID) == 0) { fw_app_type = fu_ccgx_firmware_get_app_type (FU_CCGX_FIRMWARE (firmware)); if (fw_app_type != self->fw_app_type) { g_set_error (error, diff --git a/plugins/dfu/dfu-device.c b/plugins/dfu/dfu-device.c index e92484b4c..7fe9fb6cd 100644 --- a/plugins/dfu/dfu-device.c +++ b/plugins/dfu/dfu-device.c @@ -1726,7 +1726,7 @@ dfu_device_write_firmware (FuDevice *device, if (!dfu_device_refresh_and_clear (self, error)) return FALSE; - if (flags & FWUPD_INSTALL_FLAG_FORCE) { + if (flags & FWUPD_INSTALL_FLAG_IGNORE_VID_PID) { transfer_flags |= DFU_TARGET_TRANSFER_FLAG_WILDCARD_VID; transfer_flags |= DFU_TARGET_TRANSFER_FLAG_WILDCARD_PID; } diff --git a/plugins/dfu/dfu-tool.c b/plugins/dfu/dfu-tool.c index f5f221a93..655095cd0 100644 --- a/plugins/dfu/dfu-tool.c +++ b/plugins/dfu/dfu-tool.c @@ -924,8 +924,10 @@ dfu_tool_write (DfuToolPrivate *priv, gchar **values, GError **error) } /* allow wildcards */ - if (priv->force) - flags |= FWUPD_INSTALL_FLAG_FORCE; + if (priv->force) { + flags |= FWUPD_INSTALL_FLAG_IGNORE_VID_PID; + flags |= FWUPD_INSTALL_FLAG_IGNORE_CHECKSUM; + } /* transfer */ g_signal_connect (device, "notify::status", diff --git a/plugins/synaptics-mst/fu-synaptics-mst-device.c b/plugins/synaptics-mst/fu-synaptics-mst-device.c index c36eedb67..23e3eb59e 100644 --- a/plugins/synaptics-mst/fu-synaptics-mst-device.c +++ b/plugins/synaptics-mst/fu-synaptics-mst-device.c @@ -776,7 +776,7 @@ fu_synaptics_mst_device_prepare_firmware (FuDevice *device, FuSynapticsMstDevice *self = FU_SYNAPTICS_MST_DEVICE (device); /* check firmware and board ID match */ - if ((flags & FWUPD_INSTALL_FLAG_FORCE) == 0 && + if ((flags & FWUPD_INSTALL_FLAG_IGNORE_VID_PID) == 0 && !fu_device_has_custom_flag (device, "ignore-board-id")) { const guint8 *buf; gsize len; diff --git a/plugins/synaptics-prometheus/fu-synaprom-config.c b/plugins/synaptics-prometheus/fu-synaprom-config.c index 628a764f2..74f9a5fca 100644 --- a/plugins/synaptics-prometheus/fu-synaprom-config.c +++ b/plugins/synaptics-prometheus/fu-synaprom-config.c @@ -150,7 +150,7 @@ fu_synaprom_config_prepare_firmware (FuDevice *device, memcpy (&hdr, g_bytes_get_data (blob, NULL), sizeof(hdr)); product = GUINT32_FROM_LE(hdr.product); if (product != FU_SYNAPROM_PRODUCT_PROMETHEUS) { - if (flags & FWUPD_INSTALL_FLAG_FORCE) { + if (flags & FWUPD_INSTALL_FLAG_IGNORE_VID_PID) { g_warning ("CFG metadata not compatible, " "got 0x%02x expected 0x%02x", product, (guint) FU_SYNAPROM_PRODUCT_PROMETHEUS); @@ -167,7 +167,7 @@ fu_synaprom_config_prepare_firmware (FuDevice *device, id1 = GUINT32_FROM_LE(hdr.id1); id2 = GUINT32_FROM_LE(hdr.id2); if (id1 != self->configid1 || id2 != self->configid2) { - if (flags & FWUPD_INSTALL_FLAG_FORCE) { + if (flags & FWUPD_INSTALL_FLAG_IGNORE_VID_PID) { g_warning ("CFG version not compatible, " "got %u:%u expected %u:%u", id1, id2, self->configid1, self->configid2); diff --git a/plugins/synaptics-prometheus/fu-synaprom-device.c b/plugins/synaptics-prometheus/fu-synaprom-device.c index fb8822bcb..26ba80ead 100644 --- a/plugins/synaptics-prometheus/fu-synaprom-device.c +++ b/plugins/synaptics-prometheus/fu-synaprom-device.c @@ -269,7 +269,7 @@ fu_synaprom_device_prepare_fw (FuDevice *device, memcpy (&hdr, g_bytes_get_data (blob, NULL), sizeof(hdr)); product = GUINT32_FROM_LE(hdr.product); if (product != FU_SYNAPROM_PRODUCT_PROMETHEUS) { - if (flags & FWUPD_INSTALL_FLAG_FORCE) { + if (flags & FWUPD_INSTALL_FLAG_IGNORE_VID_PID) { g_warning ("MFW metadata not compatible, " "got 0x%02x expected 0x%02x", product, (guint) FU_SYNAPROM_PRODUCT_PROMETHEUS); diff --git a/plugins/synaptics-rmi/fu-dump.c b/plugins/synaptics-rmi/fu-dump.c index 2a0d1170d..ffc5a5adf 100644 --- a/plugins/synaptics-rmi/fu-dump.c +++ b/plugins/synaptics-rmi/fu-dump.c @@ -19,7 +19,7 @@ fu_dump_parse (const gchar *filename, GError **error) if (!g_file_get_contents (filename, &data, &len, error)) return FALSE; blob = g_bytes_new_take (data, len); - if (!fu_firmware_parse (firmware, blob, FWUPD_INSTALL_FLAG_FORCE, error)) + if (!fu_firmware_parse (firmware, blob, FWUPD_INSTALL_FLAG_IGNORE_CHECKSUM, error)) return FALSE; str = fu_firmware_to_string (firmware); g_print ("%s", str); diff --git a/plugins/synaptics-rmi/fu-synaptics-rmi-firmware.c b/plugins/synaptics-rmi/fu-synaptics-rmi-firmware.c index 23b14dc01..3d7f870b5 100644 --- a/plugins/synaptics-rmi/fu-synaptics-rmi-firmware.c +++ b/plugins/synaptics-rmi/fu-synaptics-rmi-firmware.c @@ -349,7 +349,7 @@ fu_synaptics_rmi_firmware_parse (FuFirmware *firmware, /* verify checksum */ self->checksum = fu_common_read_uint32 (data + RMI_IMG_CHECKSUM_OFFSET, G_LITTLE_ENDIAN); checksum_calculated = fu_synaptics_rmi_generate_checksum (data + 4, sz - 4); - if ((flags & FWUPD_INSTALL_FLAG_FORCE) == 0) { + if ((flags & FWUPD_INSTALL_FLAG_IGNORE_CHECKSUM) == 0) { if (self->checksum != checksum_calculated) { g_set_error (error, FWUPD_ERROR, diff --git a/plugins/thunderbolt/fu-thunderbolt-device.c b/plugins/thunderbolt/fu-thunderbolt-device.c index b7064362c..e51d83a44 100644 --- a/plugins/thunderbolt/fu-thunderbolt-device.c +++ b/plugins/thunderbolt/fu-thunderbolt-device.c @@ -684,7 +684,7 @@ fu_thunderbolt_device_prepare_firmware (FuDevice *device, fu_thunderbolt_firmware_get_device_id (firmware_old)); return NULL; } - if ((flags & FWUPD_INSTALL_FLAG_FORCE) == 0) { + if ((flags & FWUPD_INSTALL_FLAG_IGNORE_VID_PID) == 0) { if (fu_thunderbolt_firmware_get_model_id (FU_THUNDERBOLT_FIRMWARE (firmware)) != fu_thunderbolt_firmware_get_model_id (firmware_old)) { g_set_error (error, diff --git a/plugins/upower/fu-plugin-upower.c b/plugins/upower/fu-plugin-upower.c index 25546c229..2d83f9b9b 100644 --- a/plugins/upower/fu-plugin-upower.c +++ b/plugins/upower/fu-plugin-upower.c @@ -149,7 +149,7 @@ fu_plugin_update_prepare (FuPlugin *plugin, /* determine if operating on AC or battery */ if (fu_plugin_upower_check_on_battery (plugin) && - (flags & FWUPD_INSTALL_FLAG_FORCE) == 0) { + (flags & FWUPD_INSTALL_FLAG_IGNORE_POWER) == 0) { g_set_error_literal (error, FWUPD_ERROR, FWUPD_ERROR_AC_POWER_REQUIRED, @@ -160,7 +160,7 @@ fu_plugin_update_prepare (FuPlugin *plugin, /* determine if battery high enough */ if (!fu_plugin_upower_check_percentage_level (plugin) && - (flags & FWUPD_INSTALL_FLAG_FORCE) == 0) { + (flags & FWUPD_INSTALL_FLAG_IGNORE_POWER) == 0) { FuPluginData *data = fu_plugin_get_data (plugin); g_set_error (error, FWUPD_ERROR, diff --git a/plugins/vli/fu-vli-pd-firmware.c b/plugins/vli/fu-vli-pd-firmware.c index 78891f79a..ec3b0a8a5 100644 --- a/plugins/vli/fu-vli-pd-firmware.c +++ b/plugins/vli/fu-vli-pd-firmware.c @@ -130,7 +130,7 @@ fu_vli_pd_firmware_parse (FuFirmware *firmware, } /* check CRC */ - if ((flags & FWUPD_INSTALL_FLAG_FORCE) == 0) { + if ((flags & FWUPD_INSTALL_FLAG_IGNORE_CHECKSUM) == 0) { guint16 crc_actual; guint16 crc_file = 0x0; if (!fu_common_read_uint16_safe (buf, bufsz, bufsz - 2, &crc_file, diff --git a/src/fu-firmware-dump.c b/src/fu-firmware-dump.c index d7045db88..eaa90c0bf 100644 --- a/src/fu-firmware-dump.c +++ b/src/fu-firmware-dump.c @@ -45,7 +45,10 @@ main (int argc, char **argv) g_printerr ("firmware invalid type, expected .srec or .hex\n"); return 2; } - if (!fu_firmware_parse (firmware, blob, FWUPD_INSTALL_FLAG_FORCE, &error)) { + if (!fu_firmware_parse (firmware, blob, + FWUPD_INSTALL_FLAG_IGNORE_VID_PID | + FWUPD_INSTALL_FLAG_IGNORE_CHECKSUM, + &error)) { g_printerr ("failed to parse file: %s\n", error->message); return 3; } diff --git a/src/fu-main.c b/src/fu-main.c index 6fba8a83b..de6c3d237 100644 --- a/src/fu-main.c +++ b/src/fu-main.c @@ -1433,8 +1433,13 @@ fu_main_daemon_method_call (GDBusConnection *connection, const gchar *sender, g_variant_get_boolean (prop_value) == TRUE) helper->flags |= FWUPD_INSTALL_FLAG_ALLOW_BRANCH_SWITCH; if (g_strcmp0 (prop_key, "force") == 0 && - g_variant_get_boolean (prop_value) == TRUE) + g_variant_get_boolean (prop_value) == TRUE) { helper->flags |= FWUPD_INSTALL_FLAG_FORCE; + helper->flags |= FWUPD_INSTALL_FLAG_IGNORE_POWER; + } + if (g_strcmp0 (prop_key, "ignore-power") == 0 && + g_variant_get_boolean (prop_value) == TRUE) + helper->flags |= FWUPD_INSTALL_FLAG_IGNORE_POWER; if (g_strcmp0 (prop_key, "no-history") == 0 && g_variant_get_boolean (prop_value) == TRUE) helper->flags |= FWUPD_INSTALL_FLAG_NO_HISTORY; diff --git a/src/fu-tool.c b/src/fu-tool.c index 4d803a408..e30a53a17 100644 --- a/src/fu-tool.c +++ b/src/fu-tool.c @@ -2404,11 +2404,15 @@ fu_util_esp_list (FuUtilPrivate *priv, gchar **values, GError **error) int main (int argc, char *argv[]) { + gboolean allow_branch_switch = FALSE; gboolean allow_older = FALSE; gboolean allow_reinstall = FALSE; gboolean force = FALSE; gboolean ret; gboolean version = FALSE; + gboolean ignore_checksum = FALSE; + gboolean ignore_power = FALSE; + gboolean ignore_vid_pid = FALSE; gboolean interactive = isatty (fileno (stdout)) != 0; g_auto(GStrv) plugin_glob = NULL; g_autoptr(FuUtilPrivate) priv = g_new0 (FuUtilPrivate, 1); @@ -2426,9 +2430,21 @@ main (int argc, char *argv[]) { "allow-older", '\0', 0, G_OPTION_ARG_NONE, &allow_older, /* TRANSLATORS: command line option */ _("Allow downgrading firmware versions"), NULL }, + { "allow-branch-switch", '\0', 0, G_OPTION_ARG_NONE, &allow_branch_switch, + /* TRANSLATORS: command line option */ + _("Allow switching firmware branch"), NULL }, { "force", '\0', 0, G_OPTION_ARG_NONE, &force, /* TRANSLATORS: command line option */ - _("Override plugin warning"), NULL }, + _("Force the action by relaxing some runtime checks"), NULL }, + { "ignore-checksum", '\0', 0, G_OPTION_ARG_NONE, &ignore_checksum, + /* TRANSLATORS: command line option */ + _("Ignore firmware checksum failures"), NULL }, + { "ignore-vid-pid", '\0', 0, G_OPTION_ARG_NONE, &ignore_vid_pid, + /* TRANSLATORS: command line option */ + _("Ignore firmware hardware mismatch failures"), NULL }, + { "ignore-power", '\0', 0, G_OPTION_ARG_NONE, &ignore_power, + /* TRANSLATORS: command line option */ + _("Ignore requirement of external power source"), NULL }, { "no-reboot-check", '\0', 0, G_OPTION_ARG_NONE, &priv->no_reboot_check, /* TRANSLATORS: command line option */ _("Do not check for reboot after update"), NULL }, @@ -2769,8 +2785,18 @@ main (int argc, char *argv[]) priv->flags |= FWUPD_INSTALL_FLAG_ALLOW_REINSTALL; if (allow_older) priv->flags |= FWUPD_INSTALL_FLAG_ALLOW_OLDER; - if (force) + if (allow_branch_switch) + priv->flags |= FWUPD_INSTALL_FLAG_ALLOW_BRANCH_SWITCH; + if (force) { priv->flags |= FWUPD_INSTALL_FLAG_FORCE; + priv->flags |= FWUPD_INSTALL_FLAG_IGNORE_POWER; + } + if (ignore_checksum) + priv->flags |= FWUPD_INSTALL_FLAG_IGNORE_CHECKSUM; + if (ignore_vid_pid) + priv->flags |= FWUPD_INSTALL_FLAG_IGNORE_VID_PID; + if (ignore_power) + priv->flags |= FWUPD_INSTALL_FLAG_IGNORE_POWER; /* load engine */ priv->engine = fu_engine_new (FU_APP_FLAGS_NO_IDLE_SOURCES); diff --git a/src/fu-util.c b/src/fu-util.c index 1796401d2..50d868eb1 100644 --- a/src/fu-util.c +++ b/src/fu-util.c @@ -2664,6 +2664,7 @@ main (int argc, char *argv[]) gboolean allow_branch_switch = FALSE; gboolean allow_older = FALSE; gboolean allow_reinstall = FALSE; + gboolean ignore_power = FALSE; gboolean is_interactive = TRUE; gboolean no_history = FALSE; gboolean offline = FALSE; @@ -2697,7 +2698,7 @@ main (int argc, char *argv[]) _("Allow switching firmware branch"), NULL }, { "force", '\0', 0, G_OPTION_ARG_NONE, &force, /* TRANSLATORS: command line option */ - _("Override warnings and force the action"), NULL }, + _("Force the action by relaxing some runtime checks"), NULL }, { "assume-yes", 'y', 0, G_OPTION_ARG_NONE, &priv->assume_yes, /* TRANSLATORS: command line option */ _("Answer yes to all questions"), NULL }, @@ -2732,6 +2733,9 @@ main (int argc, char *argv[]) /* TRANSLATORS: command line option */ _("Filter with a set of device flags using a ~ prefix to " "exclude, e.g. 'internal,~needs-reboot'"), NULL }, + { "ignore-power", '\0', 0, G_OPTION_ARG_NONE, &ignore_power, + /* TRANSLATORS: command line option */ + _("Ignore requirement of external power source"), NULL }, { NULL} }; @@ -3017,10 +3021,14 @@ main (int argc, char *argv[]) priv->flags |= FWUPD_INSTALL_FLAG_ALLOW_OLDER; if (allow_branch_switch) priv->flags |= FWUPD_INSTALL_FLAG_ALLOW_BRANCH_SWITCH; - if (force) + if (force) { priv->flags |= FWUPD_INSTALL_FLAG_FORCE; + priv->flags |= FWUPD_INSTALL_FLAG_IGNORE_POWER; + } if (no_history) priv->flags |= FWUPD_INSTALL_FLAG_NO_HISTORY; + if (ignore_power) + priv->flags |= FWUPD_INSTALL_FLAG_IGNORE_POWER; /* start polkit tty agent to listen for password requests */ if (is_interactive) { From 738e3f01e1a0b937216895716e59534623837f3b Mon Sep 17 00:00:00 2001 From: Richard Hughes Date: Wed, 7 Oct 2020 13:46:33 +0100 Subject: [PATCH 507/607] trivial: Ensure config.h is included in all C files --- src/fu-polkit-agent.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/fu-polkit-agent.c b/src/fu-polkit-agent.c index 28991320a..7db8c1bec 100644 --- a/src/fu-polkit-agent.c +++ b/src/fu-polkit-agent.c @@ -7,6 +7,8 @@ * SPDX-License-Identifier: LGPL-2.1+ */ +#include "config.h" + #include #include #ifdef __linux__ From 27b399ce273149847a5c9d0db99a23a371224d32 Mon Sep 17 00:00:00 2001 From: Richard Hughes Date: Wed, 7 Oct 2020 10:53:35 +0100 Subject: [PATCH 508/607] libfwupd: Actually use the JCat file to select the metadata file This recent regression was caused when porting libfwupd to the async model. Fixes https://github.com/fwupd/fwupd/issues/2360 --- libfwupd/fwupd-client.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/libfwupd/fwupd-client.c b/libfwupd/fwupd-client.c index 28ba6ce06..c8a1aed5e 100644 --- a/libfwupd/fwupd-client.c +++ b/libfwupd/fwupd-client.c @@ -2810,6 +2810,10 @@ fwupd_client_refresh_remote_signature_cb (GObject *source, return; } data->signature = g_steal_pointer (&bytes); + if (!fwupd_remote_load_signature_bytes (data->remote, data->signature, &error)) { + g_task_return_error (task, g_steal_pointer (&error)); + return; + } /* download metadata */ fwupd_client_download_bytes_async (self, From f083af3e71c632269385b6f90dbc60d5f2ff6c97 Mon Sep 17 00:00:00 2001 From: Richard Hughes Date: Wed, 7 Oct 2020 13:59:09 +0100 Subject: [PATCH 509/607] Download the metadata first when using 'fwupdtool refresh' This allows us to use fwupd_remote_load_signature_bytes() to enable all the JCat mirror-fix features. --- src/fu-tool.c | 40 +++++++++++++++++++++------------------- 1 file changed, 21 insertions(+), 19 deletions(-) diff --git a/src/fu-tool.c b/src/fu-tool.c index e30a53a17..8bde01271 100644 --- a/src/fu-tool.c +++ b/src/fu-tool.c @@ -2175,25 +2175,6 @@ fu_util_refresh_remote (FuUtilPrivate *priv, FwupdRemote *remote, GError **error g_autoptr(GBytes) bytes_raw = NULL; g_autoptr(GBytes) bytes_sig = NULL; - /* payload */ - metadata_uri = fwupd_remote_get_metadata_uri (remote); - if (metadata_uri == NULL) { - g_set_error (error, - FWUPD_ERROR, - FWUPD_ERROR_NOTHING_TO_DO, - "no metadata URI available for %s", - fwupd_remote_get_id (remote)); - return FALSE; - } - fn_raw = fu_util_get_user_cache_path (metadata_uri); - if (!fu_common_mkdir_parent (fn_raw, error)) - return FALSE; - if (!fu_util_download_out_of_process (metadata_uri, fn_raw, error)) - return FALSE; - bytes_raw = fu_common_get_contents_bytes (fn_raw, error); - if (bytes_raw == NULL) - return FALSE; - /* signature */ metadata_uri = fwupd_remote_get_metadata_uri_sig (remote); if (metadata_uri == NULL) { @@ -2205,11 +2186,32 @@ fu_util_refresh_remote (FuUtilPrivate *priv, FwupdRemote *remote, GError **error return FALSE; } fn_sig = fu_util_get_user_cache_path (metadata_uri); + if (!fu_common_mkdir_parent (fn_sig, error)) + return FALSE; if (!fu_util_download_out_of_process (metadata_uri, fn_sig, error)) return FALSE; bytes_sig = fu_common_get_contents_bytes (fn_sig, error); if (bytes_sig == NULL) return FALSE; + if (!fwupd_remote_load_signature_bytes (remote, bytes_sig, error)) + return FALSE; + + /* payload */ + metadata_uri = fwupd_remote_get_metadata_uri (remote); + if (metadata_uri == NULL) { + g_set_error (error, + FWUPD_ERROR, + FWUPD_ERROR_NOTHING_TO_DO, + "no metadata URI available for %s", + fwupd_remote_get_id (remote)); + return FALSE; + } + fn_raw = fu_util_get_user_cache_path (metadata_uri); + if (!fu_util_download_out_of_process (metadata_uri, fn_raw, error)) + return FALSE; + bytes_raw = fu_common_get_contents_bytes (fn_raw, error); + if (bytes_raw == NULL) + return FALSE; /* send to daemon */ g_debug ("updating %s", fwupd_remote_get_id (remote)); From e8a2fc8c5784ccca2430c4a170b0d83344b8844f Mon Sep 17 00:00:00 2001 From: Mario Limonciello Date: Wed, 7 Oct 2020 14:14:13 -0500 Subject: [PATCH 510/607] uefi: Make udisks2 errors more apparent When support for dynamically mounting disks was added for https://github.com/fwupd/fwupd/commit/25ba41579fb170cf3a29cb2753733172a54984cd udisks2 became a harder dependency and it was less obvious to users. Create devices but show an error in why devices aren't updatable if it's not found. Users can still configure ESP manually in `uefi.conf` Fixes: #2444 --- plugins/uefi/fu-plugin-uefi.c | 28 ++++++++++++++++++++-------- 1 file changed, 20 insertions(+), 8 deletions(-) diff --git a/plugins/uefi/fu-plugin-uefi.c b/plugins/uefi/fu-plugin-uefi.c index 8a05d0630..087932a2f 100644 --- a/plugins/uefi/fu-plugin-uefi.c +++ b/plugins/uefi/fu-plugin-uefi.c @@ -443,10 +443,18 @@ fu_plugin_uefi_register_proxy_device (FuPlugin *plugin, FuDevice *device) { FuPluginData *data = fu_plugin_get_data (plugin); g_autoptr(FuUefiDevice) dev = fu_uefi_device_new_from_dev (device); + g_autoptr(GError) error_local = NULL; /* load all configuration variables */ fu_plugin_uefi_load_config (plugin, FU_DEVICE (dev)); - fu_uefi_device_set_esp (dev, data->esp); + if (data->esp == NULL) + data->esp = fu_common_get_esp_default (&error_local); + if (data->esp == NULL) { + fu_device_set_update_error (FU_DEVICE (dev), error_local->message); + fu_device_remove_flag (FU_DEVICE (dev), FWUPD_DEVICE_FLAG_UPDATABLE); + } else { + fu_uefi_device_set_esp (dev, data->esp); + } fu_plugin_device_add (plugin, FU_DEVICE (dev)); } @@ -631,12 +639,6 @@ fu_plugin_startup (FuPlugin *plugin, GError **error) "specified in config: ", esp_path); return FALSE; } - } else { - data->esp = fu_common_get_esp_default (error); - if (data->esp == NULL) { - g_prefix_error (error, "cannot find default ESP: "); - return FALSE; - } } /* test for invalid ESP in coldplug, and set the update-error rather @@ -743,6 +745,7 @@ fu_plugin_coldplug (FuPlugin *plugin, GError **error) const gchar *str; g_autofree gchar *esrt_path = NULL; g_autofree gchar *sysfsfwdir = NULL; + g_autoptr(GError) error_udisks2 = NULL; g_autoptr(GError) error_efivarfs = NULL; g_autoptr(GError) error_local = NULL; g_autoptr(GPtrArray) entries = NULL; @@ -758,6 +761,12 @@ fu_plugin_coldplug (FuPlugin *plugin, GError **error) if (!fu_plugin_uefi_ensure_efivarfs_rw (&error_efivarfs)) g_warning ("%s", error_efivarfs->message); + if (data->esp == NULL) { + data->esp = fu_common_get_esp_default (&error_udisks2); + if (data->esp == NULL) + g_warning ("cannot find default ESP: %s", error_udisks2->message); + } + /* add each device */ for (guint i = 0; i < entries->len; i++) { const gchar *path = g_ptr_array_index (entries, i); @@ -768,11 +777,14 @@ fu_plugin_coldplug (FuPlugin *plugin, GError **error) continue; } fu_device_set_quirks (FU_DEVICE (dev), fu_plugin_get_quirks (plugin)); - fu_uefi_device_set_esp (FU_UEFI_DEVICE (dev), data->esp); + if (data->esp != NULL) + fu_uefi_device_set_esp (FU_UEFI_DEVICE (dev), data->esp); if (!fu_plugin_uefi_coldplug_device (plugin, dev, error)) return FALSE; if (error_efivarfs != NULL) { fu_device_set_update_error (FU_DEVICE (dev), error_efivarfs->message); + } else if (error_udisks2 != NULL) { + fu_device_set_update_error (FU_DEVICE (dev), error_udisks2->message); } else { fu_device_add_flag (FU_DEVICE (dev), FWUPD_DEVICE_FLAG_UPDATABLE); fu_device_add_flag (FU_DEVICE (dev), FWUPD_DEVICE_FLAG_USABLE_DURING_UPDATE); From 5a83563701147346bec66d9637e295e7608c7e66 Mon Sep 17 00:00:00 2001 From: Mario Limonciello Date: Wed, 7 Oct 2020 14:22:08 -0500 Subject: [PATCH 511/607] uefi: Correct a logic error with `FuVolume` Fixes: #2443 --- libfwupdplugin/fu-common.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libfwupdplugin/fu-common.c b/libfwupdplugin/fu-common.c index 12e177d41..03ee9cef0 100644 --- a/libfwupdplugin/fu-common.c +++ b/libfwupdplugin/fu-common.c @@ -2325,7 +2325,7 @@ fu_common_get_esp_for_path (const gchar *esp_path, GError **error) return NULL; for (guint i = 0; i < volumes->len; i++) { FuVolume *vol = g_ptr_array_index (volumes, i); - g_autofree gchar *vol_basename = g_path_get_basename (fu_volume_get_id (vol)); + g_autofree gchar *vol_basename = g_path_get_basename (fu_volume_get_mount_point (vol)); if (g_strcmp0 (basename, vol_basename) == 0) return g_object_ref (vol); } From e6eb913b745684a174cb8db5ebef90629fae9451 Mon Sep 17 00:00:00 2001 From: Richard Hughes Date: Wed, 7 Oct 2020 09:14:54 +0100 Subject: [PATCH 512/607] uefi: Only set the version format for ESRT entries Setting the default to number unconditionally causes problems when the device is created using _register_proxy_device(). Based on a patch by Mario Limonciello , many thanks. --- plugins/uefi/fu-uefi-device.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/plugins/uefi/fu-uefi-device.c b/plugins/uefi/fu-uefi-device.c index fce6f7aec..f35964b6f 100644 --- a/plugins/uefi/fu-uefi-device.c +++ b/plugins/uefi/fu-uefi-device.c @@ -721,7 +721,6 @@ static void fu_uefi_device_init (FuUefiDevice *self) { fu_device_set_protocol (FU_DEVICE (self), "org.uefi.capsule"); - fu_device_set_version_format (FU_DEVICE (self), FWUPD_VERSION_FORMAT_NUMBER); } static void @@ -765,6 +764,9 @@ fu_uefi_device_new_from_entry (const gchar *entry_path, GError **error) /* create object */ self = g_object_new (FU_TYPE_UEFI_DEVICE, NULL); + /* assume a uint64_t unless told otherwise by a quirk entry or metadata */ + fu_device_set_version_format (FU_DEVICE (self), FWUPD_VERSION_FORMAT_NUMBER); + /* read values from sysfs */ fw_class_fn = g_build_filename (entry_path, "fw_class", NULL); if (g_file_get_contents (fw_class_fn, &self->fw_class, NULL, NULL)) @@ -824,5 +826,6 @@ fu_uefi_device_new_from_guid (const gchar *guid) FuUefiDevice *self; self = g_object_new (FU_TYPE_UEFI_DEVICE, NULL); self->fw_class = g_strdup (guid); + fu_device_set_version_format (FU_DEVICE (self), FWUPD_VERSION_FORMAT_NUMBER); return self; } From 9d1372a928b076124ce9b95d25cfe40c0f825920 Mon Sep 17 00:00:00 2001 From: Richard Hughes Date: Wed, 7 Oct 2020 15:36:35 +0100 Subject: [PATCH 513/607] trivial: Do not build the HSI documentation We can re-enable this once we have concrete buy-in from more than just Intel. --- docs/fwupd-docs.xml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/docs/fwupd-docs.xml b/docs/fwupd-docs.xml index cae03b8fa..42b6637f5 100644 --- a/docs/fwupd-docs.xml +++ b/docs/fwupd-docs.xml @@ -69,7 +69,9 @@ + API Index From f4c206d319dd088ccd36a818b0b4ee2999047b80 Mon Sep 17 00:00:00 2001 From: Richard Hughes Date: Thu, 8 Oct 2020 09:21:27 +0100 Subject: [PATCH 514/607] libfwupd: Do not export the HSI AppStream IDs The clients don't need to know this, and exporting them means we paint-ourselves into a corner if we want to change the 'namespace' or how HSI actually works. --- libfwupd/fwupd-security-attr-private.h | 31 ++++++++++++++++++++++++++ libfwupd/fwupd-security-attr.h | 31 -------------------------- src/fu-security-attr.c | 2 ++ 3 files changed, 33 insertions(+), 31 deletions(-) diff --git a/libfwupd/fwupd-security-attr-private.h b/libfwupd/fwupd-security-attr-private.h index 6106ec1cb..ad88826ec 100644 --- a/libfwupd/fwupd-security-attr-private.h +++ b/libfwupd/fwupd-security-attr-private.h @@ -13,6 +13,37 @@ G_BEGIN_DECLS +#define FWUPD_SECURITY_ATTR_ID_ACPI_DMAR "org.fwupd.hsi.AcpiDmar" /* Since: 1.5.0 */ +#define FWUPD_SECURITY_ATTR_ID_ENCRYPTED_RAM "org.fwupd.hsi.EncryptedRam" /* Since: 1.5.0 */ +#define FWUPD_SECURITY_ATTR_ID_FWUPD_ATTESTATION "org.fwupd.hsi.Fwupd.Attestation" /* Since: 1.5.0 */ +#define FWUPD_SECURITY_ATTR_ID_FWUPD_PLUGINS "org.fwupd.hsi.Fwupd.Plugins" /* Since: 1.5.0 */ +#define FWUPD_SECURITY_ATTR_ID_FWUPD_UPDATES "org.fwupd.hsi.Fwupd.Updates" /* Since: 1.5.0 */ +#define FWUPD_SECURITY_ATTR_ID_INTEL_BOOTGUARD_ENABLED "org.fwupd.hsi.IntelBootguard.Enabled" /* Since: 1.5.0 */ +#define FWUPD_SECURITY_ATTR_ID_INTEL_BOOTGUARD_VERIFIED "org.fwupd.hsi.IntelBootguard.Verified" /* Since: 1.5.0 */ +#define FWUPD_SECURITY_ATTR_ID_INTEL_BOOTGUARD_ACM "org.fwupd.hsi.IntelBootguard.Acm" /* Since: 1.5.0 */ +#define FWUPD_SECURITY_ATTR_ID_INTEL_BOOTGUARD_POLICY "org.fwupd.hsi.IntelBootguard.Policy" /* Since: 1.5.0 */ +#define FWUPD_SECURITY_ATTR_ID_INTEL_BOOTGUARD_OTP "org.fwupd.hsi.IntelBootguard.Otp" /* Since: 1.5.0 */ +#define FWUPD_SECURITY_ATTR_ID_INTEL_CET_ENABLED "org.fwupd.hsi.IntelCet.Enabled" /* Since: 1.5.0 */ +#define FWUPD_SECURITY_ATTR_ID_INTEL_CET_ACTIVE "org.fwupd.hsi.IntelCet.Active" /* Since: 1.5.0 */ +#define FWUPD_SECURITY_ATTR_ID_INTEL_SMAP "org.fwupd.hsi.IntelSmap" /* Since: 1.5.0 */ +#define FWUPD_SECURITY_ATTR_ID_IOMMU "org.fwupd.hsi.Iommu" /* Since: 1.5.0 */ +#define FWUPD_SECURITY_ATTR_ID_KERNEL_LOCKDOWN "org.fwupd.hsi.Kernel.Lockdown" /* Since: 1.5.0 */ +#define FWUPD_SECURITY_ATTR_ID_KERNEL_SWAP "org.fwupd.hsi.Kernel.Swap" /* Since: 1.5.0 */ +#define FWUPD_SECURITY_ATTR_ID_KERNEL_TAINTED "org.fwupd.hsi.Kernel.Tainted" /* Since: 1.5.0 */ +#define FWUPD_SECURITY_ATTR_ID_MEI_MANUFACTURING_MODE "org.fwupd.hsi.Mei.ManufacturingMode" /* Since: 1.5.0 */ +#define FWUPD_SECURITY_ATTR_ID_MEI_OVERRIDE_STRAP "org.fwupd.hsi.Mei.OverrideStrap" /* Since: 1.5.0 */ +#define FWUPD_SECURITY_ATTR_ID_MEI_VERSION "org.fwupd.hsi.Mei.Version" /* Since: 1.5.0 */ +#define FWUPD_SECURITY_ATTR_ID_SPI_BIOSWE "org.fwupd.hsi.Spi.Bioswe" /* Since: 1.5.0 */ +#define FWUPD_SECURITY_ATTR_ID_SPI_BLE "org.fwupd.hsi.Spi.Ble" /* Since: 1.5.0 */ +#define FWUPD_SECURITY_ATTR_ID_SPI_SMM_BWP "org.fwupd.hsi.Spi.SmmBwp" /* Since: 1.5.0 */ +#define FWUPD_SECURITY_ATTR_ID_SUSPEND_TO_IDLE "org.fwupd.hsi.SuspendToIdle" /* Since: 1.5.0 */ +#define FWUPD_SECURITY_ATTR_ID_SUSPEND_TO_RAM "org.fwupd.hsi.SuspendToRam" /* Since: 1.5.0 */ +#define FWUPD_SECURITY_ATTR_ID_TPM_RECONSTRUCTION_PCR0 "org.fwupd.hsi.Tpm.ReconstructionPcr0" /* Since: 1.5.0 */ +#define FWUPD_SECURITY_ATTR_ID_TPM_VERSION_20 "org.fwupd.hsi.Tpm.Version20" /* Since: 1.5.0 */ +#define FWUPD_SECURITY_ATTR_ID_UEFI_SECUREBOOT "org.fwupd.hsi.Uefi.SecureBoot" /* Since: 1.5.0 */ +#define FWUPD_SECURITY_ATTR_ID_INTEL_DCI_ENABLED "org.fwupd.hsi.IntelDci.Enabled" /* Since: 1.5.0 */ +#define FWUPD_SECURITY_ATTR_ID_INTEL_DCI_LOCKED "org.fwupd.hsi.IntelDci.Locked" /* Since: 1.5.0 */ + GVariant *fwupd_security_attr_to_variant (FwupdSecurityAttr *self); void fwupd_security_attr_to_json (FwupdSecurityAttr *self, JsonBuilder *builder); diff --git a/libfwupd/fwupd-security-attr.h b/libfwupd/fwupd-security-attr.h index fd8c533d3..34e197087 100644 --- a/libfwupd/fwupd-security-attr.h +++ b/libfwupd/fwupd-security-attr.h @@ -111,37 +111,6 @@ typedef enum { FWUPD_SECURITY_ATTR_RESULT_LAST } FwupdSecurityAttrResult; -#define FWUPD_SECURITY_ATTR_ID_ACPI_DMAR "org.fwupd.hsi.AcpiDmar" /* Since: 1.5.0 */ -#define FWUPD_SECURITY_ATTR_ID_ENCRYPTED_RAM "org.fwupd.hsi.EncryptedRam" /* Since: 1.5.0 */ -#define FWUPD_SECURITY_ATTR_ID_FWUPD_ATTESTATION "org.fwupd.hsi.Fwupd.Attestation" /* Since: 1.5.0 */ -#define FWUPD_SECURITY_ATTR_ID_FWUPD_PLUGINS "org.fwupd.hsi.Fwupd.Plugins" /* Since: 1.5.0 */ -#define FWUPD_SECURITY_ATTR_ID_FWUPD_UPDATES "org.fwupd.hsi.Fwupd.Updates" /* Since: 1.5.0 */ -#define FWUPD_SECURITY_ATTR_ID_INTEL_BOOTGUARD_ENABLED "org.fwupd.hsi.IntelBootguard.Enabled" /* Since: 1.5.0 */ -#define FWUPD_SECURITY_ATTR_ID_INTEL_BOOTGUARD_VERIFIED "org.fwupd.hsi.IntelBootguard.Verified" /* Since: 1.5.0 */ -#define FWUPD_SECURITY_ATTR_ID_INTEL_BOOTGUARD_ACM "org.fwupd.hsi.IntelBootguard.Acm" /* Since: 1.5.0 */ -#define FWUPD_SECURITY_ATTR_ID_INTEL_BOOTGUARD_POLICY "org.fwupd.hsi.IntelBootguard.Policy" /* Since: 1.5.0 */ -#define FWUPD_SECURITY_ATTR_ID_INTEL_BOOTGUARD_OTP "org.fwupd.hsi.IntelBootguard.Otp" /* Since: 1.5.0 */ -#define FWUPD_SECURITY_ATTR_ID_INTEL_CET_ENABLED "org.fwupd.hsi.IntelCet.Enabled" /* Since: 1.5.0 */ -#define FWUPD_SECURITY_ATTR_ID_INTEL_CET_ACTIVE "org.fwupd.hsi.IntelCet.Active" /* Since: 1.5.0 */ -#define FWUPD_SECURITY_ATTR_ID_INTEL_SMAP "org.fwupd.hsi.IntelSmap" /* Since: 1.5.0 */ -#define FWUPD_SECURITY_ATTR_ID_IOMMU "org.fwupd.hsi.Iommu" /* Since: 1.5.0 */ -#define FWUPD_SECURITY_ATTR_ID_KERNEL_LOCKDOWN "org.fwupd.hsi.Kernel.Lockdown" /* Since: 1.5.0 */ -#define FWUPD_SECURITY_ATTR_ID_KERNEL_SWAP "org.fwupd.hsi.Kernel.Swap" /* Since: 1.5.0 */ -#define FWUPD_SECURITY_ATTR_ID_KERNEL_TAINTED "org.fwupd.hsi.Kernel.Tainted" /* Since: 1.5.0 */ -#define FWUPD_SECURITY_ATTR_ID_MEI_MANUFACTURING_MODE "org.fwupd.hsi.Mei.ManufacturingMode" /* Since: 1.5.0 */ -#define FWUPD_SECURITY_ATTR_ID_MEI_OVERRIDE_STRAP "org.fwupd.hsi.Mei.OverrideStrap" /* Since: 1.5.0 */ -#define FWUPD_SECURITY_ATTR_ID_MEI_VERSION "org.fwupd.hsi.Mei.Version" /* Since: 1.5.0 */ -#define FWUPD_SECURITY_ATTR_ID_SPI_BIOSWE "org.fwupd.hsi.Spi.Bioswe" /* Since: 1.5.0 */ -#define FWUPD_SECURITY_ATTR_ID_SPI_BLE "org.fwupd.hsi.Spi.Ble" /* Since: 1.5.0 */ -#define FWUPD_SECURITY_ATTR_ID_SPI_SMM_BWP "org.fwupd.hsi.Spi.SmmBwp" /* Since: 1.5.0 */ -#define FWUPD_SECURITY_ATTR_ID_SUSPEND_TO_IDLE "org.fwupd.hsi.SuspendToIdle" /* Since: 1.5.0 */ -#define FWUPD_SECURITY_ATTR_ID_SUSPEND_TO_RAM "org.fwupd.hsi.SuspendToRam" /* Since: 1.5.0 */ -#define FWUPD_SECURITY_ATTR_ID_TPM_RECONSTRUCTION_PCR0 "org.fwupd.hsi.Tpm.ReconstructionPcr0" /* Since: 1.5.0 */ -#define FWUPD_SECURITY_ATTR_ID_TPM_VERSION_20 "org.fwupd.hsi.Tpm.Version20" /* Since: 1.5.0 */ -#define FWUPD_SECURITY_ATTR_ID_UEFI_SECUREBOOT "org.fwupd.hsi.Uefi.SecureBoot" /* Since: 1.5.0 */ -#define FWUPD_SECURITY_ATTR_ID_INTEL_DCI_ENABLED "org.fwupd.hsi.IntelDci.Enabled" /* Since: 1.5.0 */ -#define FWUPD_SECURITY_ATTR_ID_INTEL_DCI_LOCKED "org.fwupd.hsi.IntelDci.Locked" /* Since: 1.5.0 */ - FwupdSecurityAttr *fwupd_security_attr_new (const gchar *appstream_id); gchar *fwupd_security_attr_to_string (FwupdSecurityAttr *self); diff --git a/src/fu-security-attr.c b/src/fu-security-attr.c index ffdbd0e64..29765c905 100644 --- a/src/fu-security-attr.c +++ b/src/fu-security-attr.c @@ -7,6 +7,8 @@ #include #include +#include "fwupd-security-attr-private.h" + #include "fu-security-attr.h" gchar * From 4f2cb4598c802acc5c83066323178ce57990e081 Mon Sep 17 00:00:00 2001 From: "jingle.wu" Date: Tue, 29 Sep 2020 10:58:31 +0800 Subject: [PATCH 515/607] elantp: Modify firmware update flow 1. Check FW in bootloader mode, need send reset command to firmware. 2. IAP Type register parameter is defind as how many bytes/page to be written. 3. Write IAP Type function in detach function. 4. Remove IAP Type function in setup function. 5. Modify page format for i2c-device 6. Modify firmware bin file size. 7. Modify firmware update flow when the firmware in bootloader mode. 8. Add another instance ID which corresponds to the IC type & module ID * `ELANTP\ICTYPE_09&MOD_1234` 9. Add Lenovo ThinkPad X1 nano gen1 to elantp.quick 10. Add recovry device - lenovo thinkpad x1 nanao gen 1 11. Add elan touchpad device - vid:04f3 pid:314f 12. Set the firmware version when the firmware is incorrect. --- plugins/elantp/README.md | 4 + plugins/elantp/elantp.quirk | 8 ++ plugins/elantp/fu-elantp-hid-device.c | 119 ++++++++++++++++-------- plugins/elantp/fu-elantp-i2c-device.c | 127 +++++++++++++++++--------- 4 files changed, 174 insertions(+), 84 deletions(-) diff --git a/plugins/elantp/README.md b/plugins/elantp/README.md index 3f867e89e..5e4ea26d7 100644 --- a/plugins/elantp/README.md +++ b/plugins/elantp/README.md @@ -31,6 +31,10 @@ Additionally another instance ID is added which corresponds to the module ID: These devices also use custom GUID values for the IC configuration, e.g. * `ELANTP\ICTYPE_09` + + Additionally another instance ID is added which corresponds to the IC type & module ID: + + * `ELANTP\ICTYPE_09&MOD_1234` Vendor ID Security ------------------ diff --git a/plugins/elantp/elantp.quirk b/plugins/elantp/elantp.quirk index d8504f697..b2543eb51 100644 --- a/plugins/elantp/elantp.quirk +++ b/plugins/elantp/elantp.quirk @@ -6,6 +6,14 @@ GType = FuElantpHidDevice Plugin = elantp GType = FuElantpHidDevice +[DeviceInstanceId=HIDRAW\VEN_04F3&DEV_314F] +Plugin = elantp +GType = FuElantpHidDevice + +# Lenovo X1 Nano Gen1 +[HwId=4c20262a-aee0-5d6e-ba72-6d29b23fe350] +Flags = elantp-recovery + # Acer Aspire V3-372T [HwId=513cde3d-d939-59bd-a634-5c1645ebb93b] Flags = elantp-recovery diff --git a/plugins/elantp/fu-elantp-hid-device.c b/plugins/elantp/fu-elantp-hid-device.c index 5e0f52646..86364bf0e 100644 --- a/plugins/elantp/fu-elantp-hid-device.c +++ b/plugins/elantp/fu-elantp-hid-device.c @@ -140,6 +140,7 @@ fu_elantp_hid_device_setup (FuDevice *device, GError **error) guint8 buf[2] = { 0x0 }; guint8 ic_type; g_autofree gchar *instance_id1 = NULL; + g_autofree gchar *instance_id2 = NULL; g_autofree gchar *instance_id_ic_type = NULL; g_autofree gchar *version_bl = NULL; g_autofree gchar *version = NULL; @@ -162,6 +163,8 @@ fu_elantp_hid_device_setup (FuDevice *device, GError **error) return FALSE; } fwver = fu_common_read_uint16 (buf, G_LITTLE_ENDIAN); + if (fwver == 0xFFFF || fwver == ETP_CMD_I2C_FW_VERSION) + fwver = 0; version = fu_common_version_from_uint16 (fwver, FWUPD_VERSION_FORMAT_HEX); fu_device_set_version (device, version); @@ -214,36 +217,10 @@ fu_elantp_hid_device_setup (FuDevice *device, GError **error) instance_id_ic_type = g_strdup_printf ("ELANTP\\ICTYPE_%02X", ic_type); fu_device_add_instance_id (device, instance_id_ic_type); - /* set the page size */ - self->fw_page_size = 64; - if (ic_type >= 0x10) { - if (iap_ver >= 1) { - /* set the IAP type, presumably some kind of ABI */ - if (!fu_elantp_hid_device_write_cmd (self, - ETP_CMD_I2C_IAP_TYPE, - ETP_I2C_IAP_TYPE_REG, - error)) - return FALSE; - if (!fu_elantp_hid_device_read_cmd (self, ETP_CMD_I2C_IAP_TYPE, - buf, sizeof(buf), error)) { - g_prefix_error (error, "failed to read IAP type: "); - return FALSE; - } - self->iap_type = fu_common_read_uint16 (buf, G_LITTLE_ENDIAN); - if (self->iap_type != ETP_I2C_IAP_TYPE_REG) { - g_set_error_literal (error, - FWUPD_ERROR, - FWUPD_ERROR_NOT_SUPPORTED, - "failed to set IAP type"); - return FALSE; - } - if (iap_ver >= 2 && (ic_type == 0x14 || ic_type==0x15)) { - self->fw_page_size = 512; - } else { - self->fw_page_size = 128; - } - } - } + /* define the extra instance IDs (ic_type + module_id) */ + instance_id2 = g_strdup_printf ("ELANTP\\ICTYPE_%02X&MOD_%04X", + ic_type, self->module_id); + fu_device_add_instance_id (device, instance_id2); /* no quirk entry */ if (self->ic_page_count == 0x0) { @@ -254,7 +231,9 @@ fu_elantp_hid_device_setup (FuDevice *device, GError **error) ic_type); return FALSE; } - fu_device_set_firmware_size (device, (guint64) self->ic_page_count * (guint64) self->fw_page_size); + + /* The ic_page_count is based on 64 bytes/page. */ + fu_device_set_firmware_size (device, (guint64) self->ic_page_count * (guint64) 64); /* is in bootloader mode */ if (!fu_elantp_hid_device_ensure_iap_ctrl (self, error)) @@ -377,21 +356,81 @@ static gboolean fu_elantp_hid_device_detach (FuDevice *device, GError **error) { FuElantpHidDevice *self = FU_ELANTP_HID_DEVICE (device); - + guint16 iap_ver; + guint16 ic_type; + guint8 buf[2] = { 0x0 }; + guint16 tmp; + /* sanity check */ if (fu_device_has_flag (device, FWUPD_DEVICE_FLAG_IS_BOOTLOADER)) { - g_debug ("already in bootloader mode, skipping"); - return TRUE; - } - - g_debug ("in bootloader mode, reset IC"); - fu_device_set_status (device, FWUPD_STATUS_DEVICE_RESTART); - if (!fu_elantp_hid_device_write_cmd (self, + g_debug ("in bootloader mode, reset IC"); + fu_device_set_status (device, FWUPD_STATUS_DEVICE_RESTART); + if (!fu_elantp_hid_device_write_cmd (self, ETP_CMD_I2C_IAP_RESET, ETP_I2C_IAP_RESET, error)) + return FALSE; + g_usleep (ELANTP_DELAY_RESET * 1000); + } + + /* get OSM version */ + if (!fu_elantp_hid_device_read_cmd (self, ETP_CMD_I2C_OSM_VERSION, buf, sizeof(buf), error)) { + g_prefix_error (error, "failed to read OSM version: "); return FALSE; - g_usleep (ELANTP_DELAY_RESET * 1000); + } + tmp = fu_common_read_uint16 (buf, G_LITTLE_ENDIAN); + if (tmp == ETP_CMD_I2C_OSM_VERSION || tmp == 0xFFFF) { + if (!fu_elantp_hid_device_read_cmd (self, ETP_CMD_I2C_IAP_ICBODY, buf, sizeof(buf), error)) { + g_prefix_error (error, "failed to read IC body: "); + return FALSE; + } + ic_type = fu_common_read_uint16 (buf, G_LITTLE_ENDIAN) & 0xFF; + } else { + ic_type = (tmp >> 8) & 0xFF; + } + + /* get IAP firmware version */ + if (!fu_elantp_hid_device_read_cmd (self, + self->pattern == 0 ? ETP_CMD_I2C_IAP_VERSION : ETP_CMD_I2C_IAP_VERSION_2, + buf, sizeof(buf), error)) { + g_prefix_error (error, "failed to read bootloader version: "); + return FALSE; + } + if (self->pattern >= 1) { + iap_ver = buf[1]; + } else { + iap_ver = fu_common_read_uint16 (buf, G_LITTLE_ENDIAN); + } + if (ic_type >= 0x10) { + if (iap_ver >= 1) { + /* set the IAP type, presumably some kind of ABI */ + if (iap_ver >= 2 && (ic_type == 0x14 || ic_type==0x15)) { + self->fw_page_size = 512; + } else { + self->fw_page_size = 128; + } + + if (!fu_elantp_hid_device_write_cmd (self, + ETP_CMD_I2C_IAP_TYPE, + self->fw_page_size, + error)) + return FALSE; + if (!fu_elantp_hid_device_read_cmd (self, ETP_CMD_I2C_IAP_TYPE, + buf, sizeof(buf), error)) { + g_prefix_error (error, "failed to read IAP type: "); + return FALSE; + } + self->iap_type = fu_common_read_uint16 (buf, G_LITTLE_ENDIAN); + if (self->iap_type != self->fw_page_size) { + g_set_error_literal (error, + FWUPD_ERROR, + FWUPD_ERROR_NOT_SUPPORTED, + "failed to set IAP type"); + return FALSE; + } + + } + } if (!fu_elantp_hid_device_write_cmd (self, ETP_CMD_I2C_IAP, self->iap_password, diff --git a/plugins/elantp/fu-elantp-i2c-device.c b/plugins/elantp/fu-elantp-i2c-device.c index 1e9cc2ddb..90c17ee1d 100644 --- a/plugins/elantp/fu-elantp-i2c-device.c +++ b/plugins/elantp/fu-elantp-i2c-device.c @@ -133,6 +133,7 @@ fu_elantp_i2c_device_setup (FuDevice *device, GError **error) guint8 buf[30] = { 0x0 }; guint8 ic_type; g_autofree gchar *instance_id1 = NULL; + g_autofree gchar *instance_id2 = NULL; g_autofree gchar *instance_id_ic_type = NULL; g_autofree gchar *version_bl = NULL; g_autofree gchar *version = NULL; @@ -179,6 +180,8 @@ fu_elantp_i2c_device_setup (FuDevice *device, GError **error) return FALSE; } fwver = fu_common_read_uint16 (buf, G_LITTLE_ENDIAN); + if (fwver == 0xFFFF || fwver == ETP_CMD_I2C_FW_VERSION) + fwver = 0; version = fu_common_version_from_uint16 (fwver, FWUPD_VERSION_FORMAT_HEX); fu_device_set_version (device, version); @@ -228,37 +231,11 @@ fu_elantp_i2c_device_setup (FuDevice *device, GError **error) } instance_id_ic_type = g_strdup_printf ("ELANTP\\ICTYPE_%02X", ic_type); fu_device_add_instance_id (device, instance_id_ic_type); - - /* set the page size */ - self->fw_page_size = 64; - if (ic_type >= 0x10) { - if (iap_ver >= 1) { - /* set the IAP type, presumably some kind of ABI */ - if (!fu_elantp_i2c_device_write_cmd (self, - ETP_CMD_I2C_IAP_TYPE, - ETP_I2C_IAP_TYPE_REG, - error)) - return FALSE; - if (!fu_elantp_i2c_device_read_cmd (self, ETP_CMD_I2C_IAP_TYPE, - buf, sizeof(buf), error)) { - g_prefix_error (error, "failed to read IAP type: "); - return FALSE; - } - self->iap_type = fu_common_read_uint16 (buf, G_LITTLE_ENDIAN); - if (self->iap_type != ETP_I2C_IAP_TYPE_REG) { - g_set_error_literal (error, - FWUPD_ERROR, - FWUPD_ERROR_NOT_SUPPORTED, - "failed to set IAP type"); - return FALSE; - } - if (iap_ver >= 2 && (ic_type == 0x14 || ic_type==0x15)) { - self->fw_page_size = 512; - } else { - self->fw_page_size = 128; - } - } - } + + /* define the extra instance IDs (ic_type + module_id) */ + instance_id2 = g_strdup_printf ("ELANTP\\ICTYPE_%02X&MOD_%04X", + ic_type, self->module_id); + fu_device_add_instance_id (device, instance_id2); /* no quirk entry */ if (self->ic_page_count == 0x0) { @@ -269,7 +246,7 @@ fu_elantp_i2c_device_setup (FuDevice *device, GError **error) ic_type); return FALSE; } - fu_device_set_firmware_size (device, (guint64) self->ic_page_count * (guint64) self->fw_page_size); + fu_device_set_firmware_size (device, (guint64) self->ic_page_count * (guint64) 64); /* is in bootloader mode */ if (!fu_elantp_i2c_device_ensure_iap_ctrl (self, error)) @@ -359,13 +336,14 @@ fu_elantp_i2c_device_write_firmware (FuDevice *device, for (guint i = 0; i < chunks->len; i++) { FuChunk *chk = g_ptr_array_index (chunks, i); guint16 csum_tmp = fu_elantp_calc_checksum (chk->data, chk->data_sz); - gsize blksz = self->fw_page_size + 3; + gsize blksz = self->fw_page_size + 4; g_autofree guint8 *blk = g_malloc0 (blksz); /* write block */ - blk[0] = 0x0B; /* report ID */ - memcpy (blk + 1, chk->data, chk->data_sz); - fu_common_write_uint16 (blk + chk->data_sz + 1, csum_tmp, G_LITTLE_ENDIAN); + blk[0] = ETP_I2C_IAP_REG_L; + blk[1] = ETP_I2C_IAP_REG_H; + memcpy (blk + 2, chk->data, chk->data_sz); + fu_common_write_uint16 (blk + chk->data_sz + 2, csum_tmp, G_LITTLE_ENDIAN); if (!fu_elantp_i2c_device_send_cmd (self, blk, blksz, NULL, 0, error)) return FALSE; @@ -414,22 +392,83 @@ fu_elantp_i2c_device_write_firmware (FuDevice *device, static gboolean fu_elantp_i2c_device_detach (FuDevice *device, GError **error) { + guint16 iap_ver; + guint16 ic_type; + guint8 buf[2] = { 0x0 }; + guint16 tmp; FuElantpI2cDevice *self = FU_ELANTP_I2C_DEVICE (device); /* sanity check */ if (fu_device_has_flag (device, FWUPD_DEVICE_FLAG_IS_BOOTLOADER)) { - g_debug ("already in bootloader mode, skipping"); - return TRUE; - } - - g_debug ("in bootloader mode, reset IC"); - fu_device_set_status (device, FWUPD_STATUS_DEVICE_RESTART); - if (!fu_elantp_i2c_device_write_cmd (self, + g_debug ("in bootloader mode, reset IC"); + fu_device_set_status (device, FWUPD_STATUS_DEVICE_RESTART); + if (!fu_elantp_i2c_device_write_cmd (self, ETP_CMD_I2C_IAP_RESET, ETP_I2C_IAP_RESET, error)) + return FALSE; + g_usleep (ELANTP_DELAY_RESET * 1000); + } + /* get OSM version */ + if (!fu_elantp_i2c_device_read_cmd (self, ETP_CMD_I2C_OSM_VERSION, buf, sizeof(buf), error)) { + g_prefix_error (error, "failed to read OSM version: "); return FALSE; - g_usleep (ELANTP_DELAY_RESET * 1000); + } + tmp = fu_common_read_uint16 (buf, G_LITTLE_ENDIAN); + if (tmp == ETP_CMD_I2C_OSM_VERSION || tmp == 0xFFFF) { + if (!fu_elantp_i2c_device_read_cmd (self, ETP_CMD_I2C_IAP_ICBODY, buf, sizeof(buf), error)) { + g_prefix_error (error, "failed to read IC body: "); + return FALSE; + } + ic_type = fu_common_read_uint16 (buf, G_LITTLE_ENDIAN) & 0xFF; + } else { + ic_type = (tmp >> 8) & 0xFF; + } + + /* get IAP firmware version */ + if (!fu_elantp_i2c_device_read_cmd (self, + self->pattern == 0 ? ETP_CMD_I2C_IAP_VERSION : ETP_CMD_I2C_IAP_VERSION_2, + buf, sizeof(buf), error)) { + g_prefix_error (error, "failed to read bootloader version: "); + return FALSE; + } + if (self->pattern >= 1) { + iap_ver = buf[1]; + } else { + iap_ver = fu_common_read_uint16 (buf, G_LITTLE_ENDIAN); + } + + /* set the page size */ + self->fw_page_size = 64; + if (ic_type >= 0x10) { + if (iap_ver >= 1) { + if (iap_ver >= 2 && (ic_type == 0x14 || ic_type==0x15)) { + self->fw_page_size = 512; + } else { + self->fw_page_size = 128; + } + /* set the IAP type, presumably some kind of ABI */ + if (!fu_elantp_i2c_device_write_cmd (self, + ETP_CMD_I2C_IAP_TYPE, + self->fw_page_size , + error)) + return FALSE; + if (!fu_elantp_i2c_device_read_cmd (self, ETP_CMD_I2C_IAP_TYPE , + buf, sizeof(buf), error)) { + g_prefix_error (error, "failed to read IAP type: "); + return FALSE; + } + self->iap_type = fu_common_read_uint16 (buf, G_LITTLE_ENDIAN); + if (self->iap_type != self->fw_page_size) { + g_set_error_literal (error, + FWUPD_ERROR, + FWUPD_ERROR_NOT_SUPPORTED, + "failed to set IAP type"); + return FALSE; + } + + } + } if (!fu_elantp_i2c_device_write_cmd (self, ETP_CMD_I2C_IAP, self->iap_password, From 4123885c816ed4482af5abd52a7cd5d92762887f Mon Sep 17 00:00:00 2001 From: Richard Hughes Date: Wed, 16 Sep 2020 10:01:31 +0100 Subject: [PATCH 516/607] bcm57xx: Add a plugin that can update the BCM5719 network adapter --- contrib/fwupd.spec.in | 1 + meson.build | 9 + plugins/bcm57xx/README.md | 28 + plugins/bcm57xx/bcm57xx.quirk | 9 + plugins/bcm57xx/fu-bcm57xx-common.c | 111 +++ plugins/bcm57xx/fu-bcm57xx-common.h | 72 ++ plugins/bcm57xx/fu-bcm57xx-device.c | 626 +++++++++++++++ plugins/bcm57xx/fu-bcm57xx-device.h | 12 + plugins/bcm57xx/fu-bcm57xx-dict-image.c | 176 +++++ plugins/bcm57xx/fu-bcm57xx-dict-image.h | 20 + plugins/bcm57xx/fu-bcm57xx-firmware.c | 580 ++++++++++++++ plugins/bcm57xx/fu-bcm57xx-firmware.h | 17 + plugins/bcm57xx/fu-bcm57xx-recovery-device.c | 784 +++++++++++++++++++ plugins/bcm57xx/fu-bcm57xx-recovery-device.h | 14 + plugins/bcm57xx/fu-bcm57xx-stage1-image.c | 128 +++ plugins/bcm57xx/fu-bcm57xx-stage1-image.h | 14 + plugins/bcm57xx/fu-bcm57xx-stage2-image.c | 85 ++ plugins/bcm57xx/fu-bcm57xx-stage2-image.h | 14 + plugins/bcm57xx/fu-plugin-bcm57xx.c | 29 + plugins/bcm57xx/fu-self-test.c | 103 +++ plugins/bcm57xx/meson.build | 64 ++ plugins/meson.build | 1 + 22 files changed, 2897 insertions(+) create mode 100644 plugins/bcm57xx/README.md create mode 100644 plugins/bcm57xx/bcm57xx.quirk create mode 100644 plugins/bcm57xx/fu-bcm57xx-common.c create mode 100644 plugins/bcm57xx/fu-bcm57xx-common.h create mode 100644 plugins/bcm57xx/fu-bcm57xx-device.c create mode 100644 plugins/bcm57xx/fu-bcm57xx-device.h create mode 100644 plugins/bcm57xx/fu-bcm57xx-dict-image.c create mode 100644 plugins/bcm57xx/fu-bcm57xx-dict-image.h create mode 100644 plugins/bcm57xx/fu-bcm57xx-firmware.c create mode 100644 plugins/bcm57xx/fu-bcm57xx-firmware.h create mode 100644 plugins/bcm57xx/fu-bcm57xx-recovery-device.c create mode 100644 plugins/bcm57xx/fu-bcm57xx-recovery-device.h create mode 100644 plugins/bcm57xx/fu-bcm57xx-stage1-image.c create mode 100644 plugins/bcm57xx/fu-bcm57xx-stage1-image.h create mode 100644 plugins/bcm57xx/fu-bcm57xx-stage2-image.c create mode 100644 plugins/bcm57xx/fu-bcm57xx-stage2-image.h create mode 100644 plugins/bcm57xx/fu-plugin-bcm57xx.c create mode 100644 plugins/bcm57xx/fu-self-test.c create mode 100644 plugins/bcm57xx/meson.build diff --git a/contrib/fwupd.spec.in b/contrib/fwupd.spec.in index f4b4a11f1..3557053e5 100644 --- a/contrib/fwupd.spec.in +++ b/contrib/fwupd.spec.in @@ -388,6 +388,7 @@ mkdir -p --mode=0700 $RPM_BUILD_ROOT%{_localstatedir}/lib/fwupd/gnupg %{_libdir}/fwupd-plugins-3/libfu_plugin_altos.so %{_libdir}/fwupd-plugins-3/libfu_plugin_amt.so %{_libdir}/fwupd-plugins-3/libfu_plugin_ata.so +%{_libdir}/fwupd-plugins-3/libfu_plugin_bcm57xx.so %{_libdir}/fwupd-plugins-3/libfu_plugin_bios.so %{_libdir}/fwupd-plugins-3/libfu_plugin_ccgx.so %{_libdir}/fwupd-plugins-3/libfu_plugin_colorhug.so diff --git a/meson.build b/meson.build index bf8e4775b..8a2be56c0 100644 --- a/meson.build +++ b/meson.build @@ -257,6 +257,15 @@ endif if cc.has_header('sys/errno.h') conf.set('HAVE_ERRNO_H', '1') endif +if cc.has_header('sys/socket.h') + conf.set('HAVE_SOCKET_H', '1') +endif +if cc.has_header('linux/ethtool.h') + conf.set('HAVE_ETHTOOL_H', '1') +endif +if cc.has_header('sys/mman.h') + conf.set('HAVE_MMAN_H', '1') +endif if cc.has_header('poll.h') conf.set('HAVE_POLL_H', '1') endif diff --git a/plugins/bcm57xx/README.md b/plugins/bcm57xx/README.md new file mode 100644 index 000000000..5cb0890d7 --- /dev/null +++ b/plugins/bcm57xx/README.md @@ -0,0 +1,28 @@ +BCM57xx Support +=============== + +Introduction +------------ + +This plugin updates BCM57xx wired network adaptors from Broadcom using a +reverse-engineered flashing protocol. It is designed to be used with the +clean-room reimplementation of the BCM5719 firmware found here: +https://github.com/meklort/bcm5719-fw + +Protocol +-------- +BCM57xx devices support a custom `com.broadcom.bcm57xx` protocol which is +implemented as ioctls like ethtool does. + +GUID Generation +--------------- + +These devices use the standard PCI instance IDs, for example: + + * `PCI\VEN_14E4&DEV_1657` + * `PCI\VEN_14E4&DEV_1657&SUBSYS_17AA222E` + +Vendor ID Security +------------------ + +The vendor ID is set from the PCI vendor, in this instance set to `PCI:0x14E4` diff --git a/plugins/bcm57xx/bcm57xx.quirk b/plugins/bcm57xx/bcm57xx.quirk new file mode 100644 index 000000000..25d6b17b2 --- /dev/null +++ b/plugins/bcm57xx/bcm57xx.quirk @@ -0,0 +1,9 @@ +# Broadcom BCM5719 +[DeviceInstanceId=PCI\VEN_14E4&DEV_1657] +Plugin = bcm57xx + +# Dell PCI card +[DeviceInstanceId=PCI\VEN_14E4&DEV_1657&SUBSYS_14E41904] +FirmwareSize = 0x80000 +[DeviceInstanceId=PCI\VEN_14E4&DEV_1657&SUBSYS_94E41904] +FirmwareSize = 0x80000 diff --git a/plugins/bcm57xx/fu-bcm57xx-common.c b/plugins/bcm57xx/fu-bcm57xx-common.c new file mode 100644 index 000000000..be2068db9 --- /dev/null +++ b/plugins/bcm57xx/fu-bcm57xx-common.c @@ -0,0 +1,111 @@ +/* + * Copyright (C) 2018 Evan Lojewski + * Copyright (C) 2020 Richard Hughes + * + * SPDX-License-Identifier: GPL-2+ + */ + +#include "config.h" + +#include "fu-common.h" + +#include "fu-bcm57xx-common.h" + +guint32 +fu_bcm57xx_nvram_crc (const guint8 *buf, gsize bufsz) +{ + return GUINT32_FROM_BE(fu_common_crc32 (buf, bufsz)); +} + +gboolean +fu_bcm57xx_verify_crc (GBytes *fw, GError **error) +{ + guint32 crc_actual; + guint32 crc_file = 0; + gsize bufsz = 0x0; + const guint8 *buf = g_bytes_get_data (fw, &bufsz); + + /* expected */ + if (!fu_common_read_uint32_safe (buf, bufsz, bufsz - sizeof(guint32), + &crc_file, G_BIG_ENDIAN, error)) + return FALSE; + + /* reality */ + crc_actual = fu_bcm57xx_nvram_crc (buf, bufsz - sizeof(guint32)); + if (crc_actual != crc_file) { + g_set_error (error, + FWUPD_ERROR, + FWUPD_ERROR_NOT_SUPPORTED, + "invalid CRC, expected 0x%08x got: 0x%08x", + (guint) crc_file, (guint) crc_actual); + return FALSE; + } + + /* success */ + return TRUE; +} + +gboolean +fu_bcm57xx_verify_magic (GBytes *fw, gsize offset, GError **error) +{ + guint32 magic = 0; + gsize bufsz = 0x0; + const guint8 *buf = g_bytes_get_data (fw, &bufsz); + + /* hardcoded value */ + if (!fu_common_read_uint32_safe (buf, bufsz, offset, &magic, G_BIG_ENDIAN, error)) + return FALSE; + if (magic != BCM_NVRAM_MAGIC) { + g_set_error (error, + FWUPD_ERROR, + FWUPD_ERROR_NOT_SUPPORTED, + "invalid magic, got: 0x%x", + (guint) magic); + return FALSE; + } + + /* success */ + return TRUE; +} + +void +fu_bcm57xx_veritem_free (Bcm57xxVeritem *veritem) +{ + g_free (veritem->branch); + g_free (veritem->version); + g_free (veritem); +} + +Bcm57xxVeritem * +fu_bcm57xx_veritem_new (const guint8 *buf, gsize bufsz) +{ + g_autofree gchar *tmp = NULL; + g_autoptr(Bcm57xxVeritem) veritem = g_new0 (Bcm57xxVeritem, 1); + struct { + const gchar *prefix; + const gchar *branch; + FwupdVersionFormat verfmt; + } data[] = { + { "5719-v", BCM_FW_BRANCH_UNKNOWN, FWUPD_VERSION_FORMAT_PAIR }, + { "stage1-", BCM_FW_BRANCH_OSS_FIRMWARE, FWUPD_VERSION_FORMAT_TRIPLET }, + { NULL, NULL, 0 } + }; + + /* dont assume this is NUL terminated */ + tmp = g_strndup ((const gchar *) buf, bufsz); + if (tmp == NULL || tmp[0] == '\0') + return NULL; + + /* use prefix to define object */ + for (guint i = 0; data[i].prefix != NULL; i++) { + if (g_str_has_prefix (tmp, data[i].prefix)) { + veritem->version = g_strdup (tmp + strlen (data[i].prefix)); + veritem->branch = g_strdup (data[i].branch); + veritem->verfmt = data[i].verfmt; + return g_steal_pointer (&veritem); + } + } + veritem->verfmt = FWUPD_VERSION_FORMAT_UNKNOWN; + veritem->version = g_strdup (tmp); + return g_steal_pointer (&veritem); +} diff --git a/plugins/bcm57xx/fu-bcm57xx-common.h b/plugins/bcm57xx/fu-bcm57xx-common.h new file mode 100644 index 000000000..aadbb45a7 --- /dev/null +++ b/plugins/bcm57xx/fu-bcm57xx-common.h @@ -0,0 +1,72 @@ +/* + * Copyright (C) 2018 Richard Hughes + * + * SPDX-License-Identifier: LGPL-2.1+ + */ + +#pragma once + +#include +#include + +#define BCM_VENDOR_BROADCOM 0x14E4 + +#define BCM_FW_BRANCH_UNKNOWN NULL +#define BCM_FW_BRANCH_OSS_FIRMWARE "oss-firmware" + +#define BCM_FIRMWARE_SIZE 0x40000 /* x2 for Dell */ +#define BCM_PHYS_ADDR_DEFAULT 0x08003800 + +#define BCM_NVRAM_MAGIC 0x669955AA + +/* offsets into NVMRAM */ +#define BCM_NVRAM_HEADER_BASE 0x00 +#define BCM_NVRAM_DIRECTORY_BASE 0x14 +#define BCM_NVRAM_INFO_BASE 0x74 +#define BCM_NVRAM_VPD_BASE 0x100 +#define BCM_NVRAM_INFO2_BASE 0x200 +#define BCM_NVRAM_STAGE1_BASE 0x28c + +#define BCM_NVRAM_HEADER_MAGIC 0x00 +#define BCM_NVRAM_HEADER_PHYS_ADDR 0x04 +#define BCM_NVRAM_HEADER_SIZE_WRDS 0x08 +#define BCM_NVRAM_HEADER_OFFSET 0x0C +#define BCM_NVRAM_HEADER_CRC 0x10 +#define BCM_NVRAM_HEADER_SZ 0x14 + +#define BCM_NVRAM_INFO_MAC_ADDR0 0x00 +#define BCM_NVRAM_INFO_VENDOR 0x2C +#define BCM_NVRAM_INFO_DEVICE 0x2E +#define BCM_NVRAM_INFO_SZ 0x8C + +#define BCM_NVRAM_DIRECTORY_ADDR 0x00 +#define BCM_NVRAM_DIRECTORY_SIZE_WRDS 0x04 +#define BCM_NVRAM_DIRECTORY_OFFSET 0x08 +#define BCM_NVRAM_DIRECTORY_SZ 0x0c + +#define BCM_NVRAM_VPD_SZ 0x100 + +#define BCM_NVRAM_INFO2_SZ 0x8c + +#define BCM_NVRAM_STAGE1_VERADDR 0x08 +#define BCM_NVRAM_STAGE1_VERSION 0x0C + +typedef struct { + gchar *branch; + gchar *version; + FwupdVersionFormat verfmt; +} Bcm57xxVeritem; + +guint32 fu_bcm57xx_nvram_crc (const guint8 *buf, + gsize bufsz); +gboolean fu_bcm57xx_verify_crc (GBytes *fw, + GError **error); +gboolean fu_bcm57xx_verify_magic (GBytes *fw, + gsize offset, + GError **error); + +/* parses stage1 version */ +void fu_bcm57xx_veritem_free (Bcm57xxVeritem *veritem); +Bcm57xxVeritem *fu_bcm57xx_veritem_new (const guint8 *buf, + gsize bufsz); +G_DEFINE_AUTOPTR_CLEANUP_FUNC(Bcm57xxVeritem, fu_bcm57xx_veritem_free) diff --git a/plugins/bcm57xx/fu-bcm57xx-device.c b/plugins/bcm57xx/fu-bcm57xx-device.c new file mode 100644 index 000000000..b416ce19f --- /dev/null +++ b/plugins/bcm57xx/fu-bcm57xx-device.c @@ -0,0 +1,626 @@ +/* + * Copyright (C) 2018-2020 Evan Lojewski + * Copyright (C) 2020 Richard Hughes + * + * SPDX-License-Identifier: GPL-2+ + */ + +#include "config.h" + +#ifdef HAVE_ETHTOOL_H +#include +#include +#include +#endif +#ifdef HAVE_IOCTL_H +#include +#endif +#ifdef HAVE_SOCKET_H +#include +#endif + +#include "fu-chunk.h" +#include "fu-common.h" + +#include "fu-bcm57xx-common.h" +#include "fu-bcm57xx-device.h" +#include "fu-bcm57xx-recovery-device.h" +#include "fu-bcm57xx-firmware.h" +#include "fu-bcm57xx-dict-image.h" + +#define FU_BCM57XX_BLOCK_SZ 0x4000 /* 16kb */ + +struct _FuBcm57xxDevice { + FuUdevDevice parent_instance; + FuBcm57xxRecoveryDevice *recovery; + gchar *ethtool_iface; + int ethtool_fd; +}; + +G_DEFINE_TYPE (FuBcm57xxDevice, fu_bcm57xx_device, FU_TYPE_UDEV_DEVICE) + +static void +fu_bcm57xx_device_to_string (FuUdevDevice *device, guint idt, GString *str) +{ + FuBcm57xxDevice *self = FU_BCM57XX_DEVICE (device); + fu_common_string_append_kv (str, idt, "EthtoolIface", self->ethtool_iface); +} + +static gboolean +fu_bcm57xx_device_probe (FuUdevDevice *device, GError **error) +{ + FuBcm57xxDevice *self = FU_BCM57XX_DEVICE (device); + g_autofree gchar *fn = NULL; + g_autoptr(GPtrArray) ifaces = NULL; + + /* only enumerate number 1 */ + if (fu_udev_device_get_number (device) != 1) { + g_set_error_literal (error, + FWUPD_ERROR, + FWUPD_ERROR_NOT_SUPPORTED, + "only device 1 supported on multi-device card"); + return FALSE; + } + + /* we need this even for non-recovery to reset APE */ + fu_device_set_quirks (FU_DEVICE (self->recovery), + fu_device_get_quirks (FU_DEVICE (self))); + fu_device_incorporate (FU_DEVICE (self->recovery), FU_DEVICE (self)); + if (!fu_device_probe (FU_DEVICE (self->recovery), error)) + return FALSE; + + /* only if has an interface */ + fn = g_build_filename (fu_udev_device_get_sysfs_path (device), "net", NULL); + ifaces = fu_common_filename_glob (fn, "en*", NULL); + if (ifaces == NULL || ifaces->len == 0) { + fu_device_add_child (FU_DEVICE (self), FU_DEVICE (self->recovery)); + } else { + self->ethtool_iface = g_path_get_basename (g_ptr_array_index (ifaces, 0)); + } + + /* success */ + return fu_udev_device_set_physical_id (device, "pci", error); +} + +static gboolean +fu_bcm57xx_device_nvram_write (FuBcm57xxDevice *self, + guint32 address, + const guint8 *buf, + gsize bufsz, + GError **error) +{ +#ifdef HAVE_ETHTOOL_H + gsize eepromsz; + gint rc = -1; + struct ifreq ifr = { 0 }; + g_autofree struct ethtool_eeprom *eeprom = NULL; + + /* failed to load tg3 */ + if (self->ethtool_iface == NULL) { + g_set_error_literal (error, + FWUPD_ERROR, + FWUPD_ERROR_NOT_SUPPORTED, + "Not supported as ethtool interface disabled"); + return FALSE; + } + + /* sanity check */ + if (address + bufsz > fu_device_get_firmware_size_max (FU_DEVICE (self))) { + g_set_error (error, + G_IO_ERROR, + G_IO_ERROR_FAILED, + "tried to read outside of EEPROM size [0x%x]", + (guint) fu_device_get_firmware_size_max (FU_DEVICE (self))); + return FALSE; + } + + /* write EEPROM (NVRAM) data */ + eepromsz = sizeof(struct ethtool_eeprom) + bufsz; + eeprom = (struct ethtool_eeprom *) g_malloc0 (eepromsz); + eeprom->cmd = ETHTOOL_SEEPROM; + eeprom->magic = BCM_NVRAM_MAGIC; + eeprom->len = bufsz; + eeprom->offset = address; + memcpy (eeprom->data, buf, eeprom->len); + strncpy (ifr.ifr_name, self->ethtool_iface, IFNAMSIZ - 1); + ifr.ifr_data = (char *) eeprom; +#ifdef HAVE_IOCTL_H + rc = ioctl (self->ethtool_fd, SIOCETHTOOL, &ifr); +#else + g_set_error_literal (error, + FWUPD_ERROR, + FWUPD_ERROR_NOT_SUPPORTED, + "Not supported as not found"); + return FALSE; +#endif + if (rc < 0) { + g_set_error (error, + G_IO_ERROR, + G_IO_ERROR_FAILED, + "cannot write eeprom [%i]", rc); + return FALSE; + } + + /* success */ + return TRUE; +#else + g_set_error_literal (error, + FWUPD_ERROR, + FWUPD_ERROR_NOT_SUPPORTED, + "Not supported as not found"); + return FALSE; +#endif +} + +static gboolean +fu_bcm57xx_device_nvram_read (FuBcm57xxDevice *self, + guint32 address, + guint8 *buf, + gsize bufsz, + GError **error) +{ +#ifdef HAVE_ETHTOOL_H + gsize eepromsz; + gint rc = -1; + struct ifreq ifr = { 0 }; + g_autofree struct ethtool_eeprom *eeprom = NULL; + + /* failed to load tg3 */ + if (self->ethtool_iface == NULL) { + g_set_error_literal (error, + FWUPD_ERROR, + FWUPD_ERROR_NOT_SUPPORTED, + "Not supported as ethtool interface disabled"); + return FALSE; + } + + /* sanity check */ + if (address + bufsz > fu_device_get_firmware_size_max (FU_DEVICE (self))) { + g_set_error (error, + G_IO_ERROR, + G_IO_ERROR_FAILED, + "tried to read outside of EEPROM size [0x%x]", + (guint) fu_device_get_firmware_size_max (FU_DEVICE (self))); + return FALSE; + } + + /* read EEPROM (NVRAM) data */ + eepromsz = sizeof(struct ethtool_eeprom) + bufsz; + eeprom = (struct ethtool_eeprom *) g_malloc0 (eepromsz); + eeprom->cmd = ETHTOOL_GEEPROM; + eeprom->len = bufsz; + eeprom->offset = address; + strncpy (ifr.ifr_name, self->ethtool_iface, IFNAMSIZ - 1); + ifr.ifr_data = (char *) eeprom; +#ifdef HAVE_IOCTL_H + rc = ioctl (self->ethtool_fd, SIOCETHTOOL, &ifr); +#else + g_set_error_literal (error, + FWUPD_ERROR, + FWUPD_ERROR_NOT_SUPPORTED, + "Not supported as not found"); + return FALSE; +#endif + if (rc < 0) { + g_set_error (error, + G_IO_ERROR, + G_IO_ERROR_FAILED, + "cannot read eeprom [%i]", rc); + return FALSE; + } + + /* copy back data */ + if (!fu_memcpy_safe (buf, bufsz, 0x0, /* dst */ + (guint8 *) eeprom, eepromsz, /* src */ + G_STRUCT_OFFSET(struct ethtool_eeprom, data), + bufsz, error)) + return FALSE; + + /* success */ + return TRUE; +#else + g_set_error_literal (error, + FWUPD_ERROR, + FWUPD_ERROR_NOT_SUPPORTED, + "Not supported as not found"); + return FALSE; +#endif +} + +static gboolean +fu_bcm57xx_device_nvram_check (FuBcm57xxDevice *self, GError **error) +{ +#ifdef HAVE_ETHTOOL_H + gint rc = -1; + struct ethtool_drvinfo drvinfo = { 0 }; + struct ifreq ifr = { 0 }; + + /* failed to load tg3 */ + if (self->ethtool_iface == NULL) { + g_set_error_literal (error, + FWUPD_ERROR, + FWUPD_ERROR_NOT_SUPPORTED, + "Not supported as ethtool interface disabled"); + return FALSE; + } + + /* get driver info */ + drvinfo.cmd = ETHTOOL_GDRVINFO; + strncpy (ifr.ifr_name, self->ethtool_iface, IFNAMSIZ - 1); + ifr.ifr_data = (char *) &drvinfo; +#ifdef HAVE_IOCTL_H + rc = ioctl (self->ethtool_fd, SIOCETHTOOL, &ifr); +#else + g_set_error_literal (error, + FWUPD_ERROR, + FWUPD_ERROR_NOT_SUPPORTED, + "Not supported as not found"); + return FALSE; +#endif + if (rc < 0) { + g_set_error (error, + G_IO_ERROR, + G_IO_ERROR_FAILED, + "cannot get driver information [%i]", rc); + return FALSE; + } + g_debug ("FW version %s", drvinfo.fw_version); + + /* sanity check */ + if (drvinfo.eedump_len != fu_device_get_firmware_size_max (FU_DEVICE (self))) { + g_set_error (error, + G_IO_ERROR, + G_IO_ERROR_FAILED, + "EEPROM size invalid, got 0x%x, expected 0x%x", + drvinfo.eedump_len, + (guint) fu_device_get_firmware_size_max (FU_DEVICE (self))); + return FALSE; + } + + /* success */ + return TRUE; +#else + g_set_error (error, + FWUPD_ERROR, + FWUPD_ERROR_NOT_SUPPORTED, + "Not supported as not found"); + return FALSE; +#endif +} + +static gboolean +fu_bcm57xx_device_activate (FuDevice *device, GError **error) +{ + FuBcm57xxDevice *self = FU_BCM57XX_DEVICE (device); + g_autoptr(FuDeviceLocker) locker1 = NULL; + g_autoptr(FuDeviceLocker) locker2 = NULL; + + /* the only way to do this is using the mmap method */ + locker2 = fu_device_locker_new_full (FU_DEVICE (self->recovery), + (FuDeviceLockerFunc) fu_device_detach, + (FuDeviceLockerFunc) fu_device_attach, + error); + if (locker2 == NULL) + return FALSE; + + /* open */ + locker1 = fu_device_locker_new (FU_DEVICE (self->recovery), error); + if (locker1 == NULL) + return FALSE; + + /* activate, causing APE reset, then close, then attach */ + if (!fu_device_activate (FU_DEVICE (self->recovery), error)) + return FALSE; + + /* ensure we attach before we close */ + if (!fu_device_locker_close (locker2, error)) + return FALSE; + + /* wait for the device to restart before calling reload() */ + fu_device_set_status (device, FWUPD_STATUS_DEVICE_BUSY); + fu_device_set_progress (device, 0); + g_usleep (G_USEC_PER_SEC * 5); + return TRUE; +} + +static GBytes * +fu_bcm57xx_device_dump_firmware (FuDevice *device, GError **error) +{ + FuBcm57xxDevice *self = FU_BCM57XX_DEVICE (device); + const gsize bufsz = fu_device_get_firmware_size_max (FU_DEVICE (self)); + g_autofree guint8 *buf = g_malloc0 (bufsz); + g_autoptr(GPtrArray) chunks = NULL; + + fu_device_set_status (device, FWUPD_STATUS_DEVICE_READ); + chunks = fu_chunk_array_new (buf, bufsz, 0x0, 0x0, FU_BCM57XX_BLOCK_SZ); + for (guint i = 0; i < chunks->len; i++) { + FuChunk *chk = g_ptr_array_index (chunks, i); + if (!fu_bcm57xx_device_nvram_read (self, chk->address, + (guint8 *) chk->data, chk->data_sz, + error)) + return NULL; + fu_device_set_progress_full (device, i, chunks->len - 1); + } + + /* read from hardware */ + return g_bytes_new_take (g_steal_pointer (&buf), bufsz); +} + +static FuFirmware * +fu_bcm57xx_device_read_firmware (FuDevice *device, GError **error) +{ + g_autoptr(FuFirmware) firmware = fu_bcm57xx_firmware_new (); + g_autoptr(GBytes) fw = NULL; + + /* read from hardware */ + fw = fu_bcm57xx_device_dump_firmware (device, error); + if (fw == NULL) + return NULL; + if (!fu_firmware_parse (firmware, fw, FWUPD_INSTALL_FLAG_NONE, error)) + return NULL; + + /* remove images that will contain user-data */ + if (!fu_firmware_remove_image_by_id (firmware, "info", error)) + return NULL; + if (!fu_firmware_remove_image_by_id (firmware, "info2", error)) + return NULL; + if (!fu_firmware_remove_image_by_id (firmware, "vpd", error)) + return NULL; + return g_steal_pointer (&firmware); +} + +static FuFirmware * +fu_bcm57xx_device_prepare_firmware (FuDevice *device, + GBytes *fw, + FwupdInstallFlags flags, + GError **error) +{ + guint dict_cnt = 0; + g_autoptr(GBytes) fw_old = NULL; + g_autoptr(FuFirmware) firmware = fu_bcm57xx_firmware_new (); + g_autoptr(FuFirmware) firmware_tmp = fu_bcm57xx_firmware_new (); + g_autoptr(FuFirmwareImage) img_ape = NULL; + g_autoptr(FuFirmwareImage) img_stage1 = NULL; + g_autoptr(FuFirmwareImage) img_stage2 = NULL; + g_autoptr(GPtrArray) images = NULL; + + /* try to parse NVRAM, stage1 or APE */ + if (!fu_firmware_parse (firmware_tmp, fw, flags, error)) { + g_prefix_error (error, "failed to parse new firmware: "); + return NULL; + } + + /* for full NVRAM image, verify if correct device */ + if ((flags & FWUPD_INSTALL_FLAG_IGNORE_VID_PID) == 0) { + guint16 vid = fu_bcm57xx_firmware_get_vendor (FU_BCM57XX_FIRMWARE (firmware_tmp)); + guint16 did = fu_bcm57xx_firmware_get_model (FU_BCM57XX_FIRMWARE (firmware_tmp)); + if (vid != 0x0 && did != 0x0 && + (fu_udev_device_get_vendor (FU_UDEV_DEVICE (device)) != vid || + fu_udev_device_get_model (FU_UDEV_DEVICE (device)) != did)) { + g_set_error (error, + FWUPD_ERROR, + FWUPD_ERROR_NOT_SUPPORTED, + "PCI vendor or model incorrect, " + "got: %04X:%04X expected %04X:%04X", + vid, did, + fu_udev_device_get_vendor (FU_UDEV_DEVICE (device)), + fu_udev_device_get_model (FU_UDEV_DEVICE (device))); + return NULL; + } + } + + /* get the existing firmware from the device */ + fw_old = fu_bcm57xx_device_dump_firmware (device, error); + if (fw_old == NULL) + return NULL; + if (!fu_firmware_parse (firmware, fw_old, flags, error)) { + g_prefix_error (error, "failed to parse existing firmware: "); + return NULL; + } + if (g_getenv ("FWUPD_BCM57XX_VERBOSE") != NULL) { + g_autofree gchar *str = fu_firmware_to_string (firmware); + g_debug ("existing device firware: %s", str); + } + + /* merge in all the provided images into the existing firmware */ + img_stage1 = fu_firmware_get_image_by_id (firmware_tmp, "stage1", NULL); + if (img_stage1 != NULL) + fu_firmware_add_image (firmware, img_stage1); + img_stage2 = fu_firmware_get_image_by_id (firmware_tmp, "stage2", NULL); + if (img_stage2 != NULL) + fu_firmware_add_image (firmware, img_stage2); + img_ape = fu_firmware_get_image_by_id (firmware_tmp, "ape", NULL); + if (img_ape != NULL) + fu_firmware_add_image (firmware, img_ape); + + /* the src and dst dictionaries may be in different order */ + images = fu_firmware_get_images (firmware); + for (guint i = 0; i < images->len; i++) { + FuFirmwareImage *img = g_ptr_array_index (images, i); + if (FU_IS_BCM57XX_DICT_IMAGE (img)) { + fu_firmware_image_set_idx (img, 0x80 + dict_cnt); + dict_cnt++; + } + } + if (g_getenv ("FWUPD_BCM57XX_VERBOSE") != NULL) { + g_autofree gchar *str = fu_firmware_to_string (firmware); + g_debug ("proposed device firware: %s", str); + } + + /* success */ + return g_steal_pointer (&firmware); +} + +static gboolean +fu_bcm57xx_device_write_firmware (FuDevice *device, + FuFirmware *firmware, + FwupdInstallFlags flags, + GError **error) +{ + FuBcm57xxDevice *self = FU_BCM57XX_DEVICE (device); + g_autoptr(GBytes) blob = NULL; + g_autoptr(GBytes) blob_verify = NULL; + g_autoptr(GPtrArray) chunks = NULL; + + /* build the images into one linear blob of the correct size */ + fu_device_set_status (device, FWUPD_STATUS_DECOMPRESSING); + blob = fu_firmware_write (firmware, error); + if (blob == NULL) + return FALSE; + + /* hit hardware */ + fu_device_set_status (device, FWUPD_STATUS_DEVICE_WRITE); + chunks = fu_chunk_array_new_from_bytes (blob, 0x0, 0x0, FU_BCM57XX_BLOCK_SZ); + for (guint i = 0; i < chunks->len; i++) { + FuChunk *chk = g_ptr_array_index (chunks, i); + if (!fu_bcm57xx_device_nvram_write (self, chk->address, + chk->data, chk->data_sz, + error)) + return FALSE; + fu_device_set_progress_full (device, i, chunks->len - 1); + } + + /* verify */ + fu_device_set_status (device, FWUPD_STATUS_DEVICE_VERIFY); + blob_verify = fu_bcm57xx_device_dump_firmware (device, error); + if (blob_verify == NULL) + return FALSE; + if (!fu_common_bytes_compare (blob, blob_verify, error)) + return FALSE; + + /* reset APE */ + return fu_device_activate (device, error); +} + +static gboolean +fu_bcm57xx_device_setup (FuDevice *device, GError **error) +{ + FuBcm57xxDevice *self = FU_BCM57XX_DEVICE (device); + guint32 fwversion = 0; + + /* device is in recovery mode */ + if (self->ethtool_iface == NULL) { + g_autoptr(FuDeviceLocker) locker = NULL; + g_debug ("device in recovery mode, use alternate device"); + locker = fu_device_locker_new (FU_DEVICE (self->recovery), error); + if (locker == NULL) + return FALSE; + return fu_device_setup (FU_DEVICE (self->recovery), error); + } + + /* check the EEPROM size */ + if (!fu_bcm57xx_device_nvram_check (self, error)) + return FALSE; + + /* get NVRAM version */ + if (!fu_bcm57xx_device_nvram_read (self, BCM_NVRAM_STAGE1_BASE + BCM_NVRAM_STAGE1_VERSION, + (guint8 *) &fwversion, sizeof(guint32), error)) + return FALSE; + if (fwversion != 0x0) { + g_autofree gchar *fwversion_str = NULL; + + /* this is only set on the OSS firmware */ + fwversion_str = fu_common_version_from_uint32 (GUINT32_FROM_BE(fwversion), + FWUPD_VERSION_FORMAT_TRIPLET); + fu_device_set_version_format (device, FWUPD_VERSION_FORMAT_TRIPLET); + fu_device_set_version (device, fwversion_str); + fu_device_set_version_raw (device, fwversion); + fu_device_set_branch (device, BCM_FW_BRANCH_OSS_FIRMWARE); + } else { + guint8 bufver[16] = { 0x0 }; + guint32 veraddr = 0; + g_autoptr(Bcm57xxVeritem) veritem = NULL; + + /* fall back to the string, e.g. '5719-v1.43' */ + if (!fu_bcm57xx_device_nvram_read (self, + BCM_NVRAM_STAGE1_BASE + BCM_NVRAM_STAGE1_VERADDR, + (guint8 *) &veraddr, sizeof(guint32), error)) + return FALSE; + veraddr = GUINT32_FROM_BE(veraddr); + if (veraddr > BCM_PHYS_ADDR_DEFAULT) + veraddr -= BCM_PHYS_ADDR_DEFAULT; + if (!fu_bcm57xx_device_nvram_read (self, + BCM_NVRAM_STAGE1_BASE + veraddr, + bufver, sizeof(bufver), error)) + return FALSE; + veritem = fu_bcm57xx_veritem_new (bufver, sizeof(bufver)); + if (veritem != NULL) { + fu_device_set_version_format (device, veritem->verfmt); + fu_device_set_version (device, veritem->version); + fu_device_set_branch (device, veritem->branch); + } + } + + /* success */ + fu_device_add_flag (FU_DEVICE (self), FWUPD_DEVICE_FLAG_UPDATABLE); + fu_device_add_flag (FU_DEVICE (self), FWUPD_DEVICE_FLAG_CAN_VERIFY_IMAGE); + fu_device_add_flag (FU_DEVICE (self), FWUPD_DEVICE_FLAG_NEEDS_REBOOT); + fu_device_add_flag (FU_DEVICE (self), FWUPD_DEVICE_FLAG_BACKUP_BEFORE_INSTALL); + return TRUE; +} + +static gboolean +fu_bcm57xx_device_open (FuDevice *device, GError **error) +{ +#ifdef HAVE_SOCKET_H + FuBcm57xxDevice *self = FU_BCM57XX_DEVICE (device); + self->ethtool_fd = socket (AF_INET, SOCK_DGRAM, 0); + return TRUE; +#else + g_set_error_literal (error, + G_IO_ERROR, + G_IO_ERROR_NOT_SUPPORTED, + "socket() not supported as sys/socket.h not available"); + return FALSE; +#endif +} + +static gboolean +fu_bcm57xx_device_close (FuDevice *device, GError **error) +{ + FuBcm57xxDevice *self = FU_BCM57XX_DEVICE (device); + close (self->ethtool_fd); + return TRUE; +} + +static void +fu_bcm57xx_device_init (FuBcm57xxDevice *self) +{ + fu_device_add_flag (FU_DEVICE (self), FWUPD_DEVICE_FLAG_NO_GUID_MATCHING); + fu_device_set_protocol (FU_DEVICE (self), "com.broadcom.bcm57xx"); + fu_device_add_icon (FU_DEVICE (self), "network-wired"); + + /* other values are set from a quirk */ + fu_device_set_firmware_size (FU_DEVICE (self), BCM_FIRMWARE_SIZE); + + /* used for recovery in case of ethtool failure and for APE reset */ + self->recovery = fu_bcm57xx_recovery_device_new (); +} + +static void +fu_bcm57xx_device_finalize (GObject *object) +{ + FuBcm57xxDevice *self= FU_BCM57XX_DEVICE (object); + g_free (self->ethtool_iface); + G_OBJECT_CLASS (fu_bcm57xx_device_parent_class)->finalize (object); +} + +static void +fu_bcm57xx_device_class_init (FuBcm57xxDeviceClass *klass) +{ + GObjectClass *object_class = G_OBJECT_CLASS (klass); + FuDeviceClass *klass_device = FU_DEVICE_CLASS (klass); + FuUdevDeviceClass *klass_udev_device = FU_UDEV_DEVICE_CLASS (klass); + object_class->finalize = fu_bcm57xx_device_finalize; + klass_device->prepare_firmware = fu_bcm57xx_device_prepare_firmware; + klass_device->setup = fu_bcm57xx_device_setup; + klass_device->reload = fu_bcm57xx_device_setup; + klass_device->open = fu_bcm57xx_device_open; + klass_device->close = fu_bcm57xx_device_close; + klass_device->activate = fu_bcm57xx_device_activate; + klass_device->write_firmware = fu_bcm57xx_device_write_firmware; + klass_device->read_firmware = fu_bcm57xx_device_read_firmware; + klass_device->dump_firmware = fu_bcm57xx_device_dump_firmware; + klass_udev_device->probe = fu_bcm57xx_device_probe; + klass_udev_device->to_string = fu_bcm57xx_device_to_string; +} diff --git a/plugins/bcm57xx/fu-bcm57xx-device.h b/plugins/bcm57xx/fu-bcm57xx-device.h new file mode 100644 index 000000000..cc93537df --- /dev/null +++ b/plugins/bcm57xx/fu-bcm57xx-device.h @@ -0,0 +1,12 @@ +/* + * Copyright (C) 2020 Richard Hughes + * + * SPDX-License-Identifier: LGPL-2.1+ + */ + +#pragma once + +#include "fu-plugin.h" + +#define FU_TYPE_BCM57XX_DEVICE (fu_bcm57xx_device_get_type ()) +G_DECLARE_FINAL_TYPE (FuBcm57xxDevice, fu_bcm57xx_device, FU, BCM57XX_DEVICE, FuUdevDevice) diff --git a/plugins/bcm57xx/fu-bcm57xx-dict-image.c b/plugins/bcm57xx/fu-bcm57xx-dict-image.c new file mode 100644 index 000000000..c499bbb94 --- /dev/null +++ b/plugins/bcm57xx/fu-bcm57xx-dict-image.c @@ -0,0 +1,176 @@ +/* + * Copyright (C) 2020 Richard Hughes + * + * SPDX-License-Identifier: LGPL-2.1+ + */ + +#include "config.h" + +#include "fu-common.h" + +#include "fu-bcm57xx-common.h" +#include "fu-bcm57xx-dict-image.h" + +struct _FuBcm57xxDictImage { + FuFirmwareImage parent_instance; + guint8 target; + guint8 kind; +}; + +G_DEFINE_TYPE (FuBcm57xxDictImage, fu_bcm57xx_dict_image, FU_TYPE_FIRMWARE_IMAGE) + +static void +fu_bcm57xx_dict_image_to_string (FuFirmwareImage *image, guint idt, GString *str) +{ + FuBcm57xxDictImage *self = FU_BCM57XX_DICT_IMAGE (image); + if (self->target != 0xff) + fu_common_string_append_kx (str, idt, "Target", self->target); + if (self->kind != 0xff) + fu_common_string_append_kx (str, idt, "Kind", self->kind); +} + +static gboolean +fu_bcm57xx_dict_image_parse (FuFirmwareImage *image, + GBytes *fw, + FwupdInstallFlags flags, + GError **error) +{ + g_autoptr(GBytes) fw_nocrc = NULL; + if ((flags & FWUPD_INSTALL_FLAG_IGNORE_CHECKSUM) == 0) { + if (!fu_bcm57xx_verify_crc (fw, error)) + return FALSE; + } + fw_nocrc = g_bytes_new_from_bytes (fw, 0x0, g_bytes_get_size (fw) - sizeof(guint32)); + fu_firmware_image_set_bytes (image, fw_nocrc); + return TRUE; +} + +static GBytes * +fu_bcm57xx_dict_image_write (FuFirmwareImage *image, GError **error) +{ + const guint8 *buf; + gsize bufsz = 0; + guint32 crc; + g_autoptr(GByteArray) blob = NULL; + g_autoptr(GBytes) fw_nocrc = NULL; + + /* get the CRC-less data */ + fw_nocrc = fu_firmware_image_get_bytes (image); + if (fw_nocrc == NULL) { + g_set_error_literal (error, + FWUPD_ERROR, + FWUPD_ERROR_NOT_SUPPORTED, + "not supported"); + return NULL; + } + + /* add to a mutable buffer */ + buf = g_bytes_get_data (fw_nocrc, &bufsz); + blob = g_byte_array_sized_new (bufsz + sizeof(guint32)); + g_byte_array_append (blob, buf, bufsz); + + /* add CRC */ + crc = fu_bcm57xx_nvram_crc (buf, bufsz); + fu_byte_array_append_uint32 (blob, crc, G_BIG_ENDIAN); + return g_byte_array_free_to_bytes (g_steal_pointer (&blob)); +} + +static gboolean +fu_bcm57xx_dict_image_build (FuFirmwareImage *image, XbNode *n, GError **error) +{ + FuBcm57xxDictImage *self = FU_BCM57XX_DICT_IMAGE (image); + guint64 tmp; + + /* two simple properties */ + tmp = xb_node_query_text_as_uint (n, "kind", NULL); + if (tmp != G_MAXUINT64 && tmp <= G_MAXUINT8) + fu_bcm57xx_dict_image_set_kind (self, tmp); + tmp = xb_node_query_text_as_uint (n, "target", NULL); + if (tmp != G_MAXUINT64 && tmp <= G_MAXUINT8) + fu_bcm57xx_dict_image_set_target (self, tmp); + + /* success */ + return TRUE; +} + +static void +fu_bcm57xx_dict_image_ensure_id (FuBcm57xxDictImage *self) +{ + g_autofree gchar *id = NULL; + struct { + guint8 target; + guint8 kind; + const gchar *id; + } ids[] = { + { 0x00, 0x00, "pxe" }, + { 0x0D, 0x00, "ape" }, + { 0x09, 0x00, "iscsi1" }, + { 0x05, 0x00, "iscsi2" }, + { 0x0b, 0x00, "iscsi3" }, + { 0x00, 0x01, "cfg1000" }, + { 0x04, 0x01, "vpd2" }, + { 0xff, 0xff, NULL } + }; + if (self->target == 0xff || self->kind == 0xff) + return; + for (guint i = 0; ids[i].id != NULL; i++) { + if (self->target == ids[i].target && self->kind == ids[i].kind) { + g_debug ("using %s for %02x:%02x", + ids[i].id, self->target, self->kind); + fu_firmware_image_set_id (FU_FIRMWARE_IMAGE (self), ids[i].id); + return; + } + } + id = g_strdup_printf ("dict-%02x-%02x", self->target, self->kind); + g_warning ("falling back to %s, please report", id); + fu_firmware_image_set_id (FU_FIRMWARE_IMAGE (self), id); +} + +void +fu_bcm57xx_dict_image_set_target (FuBcm57xxDictImage *self, guint8 target) +{ + self->target = target; + fu_bcm57xx_dict_image_ensure_id (self); +} + +guint8 +fu_bcm57xx_dict_image_get_target (FuBcm57xxDictImage *self) +{ + return self->target; +} + +void +fu_bcm57xx_dict_image_set_kind (FuBcm57xxDictImage *self, guint8 kind) +{ + self->kind = kind; + fu_bcm57xx_dict_image_ensure_id (self); +} + +guint8 +fu_bcm57xx_dict_image_get_kind (FuBcm57xxDictImage *self) +{ + return self->kind; +} + +static void +fu_bcm57xx_dict_image_init (FuBcm57xxDictImage *self) +{ + self->target = 0xff; + self->kind = 0xff; +} + +static void +fu_bcm57xx_dict_image_class_init (FuBcm57xxDictImageClass *klass) +{ + FuFirmwareImageClass *klass_image = FU_FIRMWARE_IMAGE_CLASS (klass); + klass_image->parse = fu_bcm57xx_dict_image_parse; + klass_image->write = fu_bcm57xx_dict_image_write; + klass_image->build = fu_bcm57xx_dict_image_build; + klass_image->to_string = fu_bcm57xx_dict_image_to_string; +} + +FuFirmwareImage * +fu_bcm57xx_dict_image_new (void) +{ + return FU_FIRMWARE_IMAGE (g_object_new (FU_TYPE_BCM57XX_DICT_IMAGE, NULL)); +} diff --git a/plugins/bcm57xx/fu-bcm57xx-dict-image.h b/plugins/bcm57xx/fu-bcm57xx-dict-image.h new file mode 100644 index 000000000..5f376078a --- /dev/null +++ b/plugins/bcm57xx/fu-bcm57xx-dict-image.h @@ -0,0 +1,20 @@ +/* + * Copyright (C) 2020 Richard Hughes + * + * SPDX-License-Identifier: LGPL-2.1+ + */ + +#pragma once + +#include "fu-firmware-image.h" + +#define FU_TYPE_BCM57XX_DICT_IMAGE (fu_bcm57xx_dict_image_get_type ()) +G_DECLARE_FINAL_TYPE (FuBcm57xxDictImage, fu_bcm57xx_dict_image, FU, BCM57XX_DICT_IMAGE, FuFirmwareImage) + +FuFirmwareImage *fu_bcm57xx_dict_image_new (void); +void fu_bcm57xx_dict_image_set_kind (FuBcm57xxDictImage *self, + guint8 kind); +guint8 fu_bcm57xx_dict_image_get_kind (FuBcm57xxDictImage *self); +void fu_bcm57xx_dict_image_set_target (FuBcm57xxDictImage *self, + guint8 target); +guint8 fu_bcm57xx_dict_image_get_target (FuBcm57xxDictImage *self); diff --git a/plugins/bcm57xx/fu-bcm57xx-firmware.c b/plugins/bcm57xx/fu-bcm57xx-firmware.c new file mode 100644 index 000000000..8e49baec8 --- /dev/null +++ b/plugins/bcm57xx/fu-bcm57xx-firmware.c @@ -0,0 +1,580 @@ +/* + * Copyright (C) 2018-2020 Evan Lojewski + * Copyright (C) 2020 Richard Hughes + * + * SPDX-License-Identifier: LGPL-2.1+ + */ + +#include "config.h" + +#include "fu-common.h" + +#include "fu-bcm57xx-common.h" +#include "fu-bcm57xx-firmware.h" +#include "fu-bcm57xx-dict-image.h" +#include "fu-bcm57xx-stage1-image.h" +#include "fu-bcm57xx-stage2-image.h" + +struct _FuBcm57xxFirmware { + FuFirmware parent_instance; + guint16 vendor; + guint16 model; + gboolean is_backup; + guint32 phys_addr; + gsize source_size; + guint8 source_padchar; +}; + +G_DEFINE_TYPE (FuBcm57xxFirmware, fu_bcm57xx_firmware, FU_TYPE_FIRMWARE) + +#define BCM_STAGE1_HEADER_MAGIC_BROADCOM 0x0E000E03 +#define BCM_STAGE1_HEADER_MAGIC_MEKLORT 0x3C1D0800 + +#define BCM_APE_HEADER_MAGIC 0x1A4D4342 + +#define BCM_CODE_DIRECTORY_ADDR_APE 0x07 + +static void +fu_bcm57xx_firmware_to_string (FuFirmware *firmware, guint idt, GString *str) +{ + FuBcm57xxFirmware *self = FU_BCM57XX_FIRMWARE (firmware); + fu_common_string_append_kx (str, idt, "Vendor", self->vendor); + fu_common_string_append_kx (str, idt, "Model", self->model); + fu_common_string_append_kb (str, idt, "IsBackup", self->is_backup); + fu_common_string_append_kx (str, idt, "PhysAddr", self->phys_addr); +} + +static gboolean +fu_bcm57xx_firmware_parse_header (FuBcm57xxFirmware *self, GBytes *fw, GError **error) +{ + gsize bufsz = 0x0; + const guint8 *buf = g_bytes_get_data (fw, &bufsz); + + /* verify magic and CRC */ + if (!fu_bcm57xx_verify_magic (fw, 0x0, error)) + return FALSE; + if (!fu_bcm57xx_verify_crc (fw, error)) + return FALSE; + + /* get address */ + return fu_common_read_uint32_safe (buf, bufsz, BCM_NVRAM_HEADER_PHYS_ADDR, + &self->phys_addr, G_BIG_ENDIAN, error); +} + +static FuFirmwareImage * +fu_bcm57xx_firmware_parse_info (FuBcm57xxFirmware *self, GBytes *fw, GError **error) +{ + gsize bufsz = 0x0; + guint32 mac_addr0 = 0; + const guint8 *buf = g_bytes_get_data (fw, &bufsz); + g_autoptr(FuFirmwareImage) img = fu_firmware_image_new (fw); + + /* if the MAC is set non-zero this is an actual backup rather than a container */ + if (!fu_common_read_uint32_safe (buf, bufsz, BCM_NVRAM_INFO_MAC_ADDR0, + &mac_addr0, G_BIG_ENDIAN, error)) + return NULL; + self->is_backup = mac_addr0 != 0x0 && mac_addr0 != 0xffffffff; + + /* read vendor + model */ + if (!fu_common_read_uint16_safe (buf, bufsz, BCM_NVRAM_INFO_VENDOR, + &self->vendor, G_BIG_ENDIAN, error)) + return NULL; + if (!fu_common_read_uint16_safe (buf, bufsz, BCM_NVRAM_INFO_DEVICE, + &self->model, G_BIG_ENDIAN, error)) + return NULL; + + /* success */ + fu_firmware_image_set_id (img, "info"); + return g_steal_pointer (&img); +} + +static FuFirmwareImage * +fu_bcm57xx_firmware_parse_stage1 (FuBcm57xxFirmware *self, + GBytes *fw, + guint32 *out_stage1_sz, + FwupdInstallFlags flags, + GError **error) +{ + gsize bufsz = 0x0; + guint32 stage1_wrds = 0; + guint32 stage1_sz; + guint32 stage1_off = 0; + const guint8 *buf = g_bytes_get_data (fw, &bufsz); + g_autoptr(FuFirmwareImage) img = fu_bcm57xx_stage1_image_new (); + g_autoptr(GBytes) blob = NULL; + + if (!fu_common_read_uint32_safe (buf, bufsz, + BCM_NVRAM_HEADER_BASE + BCM_NVRAM_HEADER_SIZE_WRDS, + &stage1_wrds, G_BIG_ENDIAN, error)) + return NULL; + if (!fu_common_read_uint32_safe (buf, bufsz, + BCM_NVRAM_HEADER_BASE + BCM_NVRAM_HEADER_OFFSET, + &stage1_off, G_BIG_ENDIAN, error)) + return NULL; + stage1_sz = (stage1_wrds * sizeof(guint32)); + if (stage1_off != BCM_NVRAM_STAGE1_BASE) { + g_set_error (error, + FWUPD_ERROR, + FWUPD_ERROR_NOT_SUPPORTED, + "stage1 offset invalid, got: 0x%x, expected 0x%x", + (guint) stage1_sz, (guint) BCM_NVRAM_STAGE1_BASE); + return NULL; + } + if (stage1_off + stage1_sz > bufsz) { + g_set_error (error, + FWUPD_ERROR, + FWUPD_ERROR_NOT_SUPPORTED, + "bigger than firmware, got: 0x%x @ 0x%x", + (guint) stage1_sz, (guint) stage1_off); + return NULL; + } + + /* verify CRC */ + blob = g_bytes_new_from_bytes (fw, stage1_off, stage1_sz); + if (!fu_firmware_image_parse (img, blob, flags, error)) + return NULL; + + /* needed for stage2 */ + if (out_stage1_sz != NULL) + *out_stage1_sz = stage1_sz; + + /* success */ + fu_firmware_image_set_id (img, "stage1"); + fu_firmware_image_set_offset (img, stage1_off); + return g_steal_pointer (&img); +} + +static FuFirmwareImage * +fu_bcm57xx_firmware_parse_stage2 (FuBcm57xxFirmware *self, + GBytes *fw, + guint32 stage1_sz, + FwupdInstallFlags flags, + GError **error) +{ + gsize bufsz = 0x0; + const guint8 *buf = g_bytes_get_data (fw, &bufsz); + guint32 stage2_off = 0; + guint32 stage2_sz = 0; + g_autoptr(FuFirmwareImage) img = fu_bcm57xx_stage2_image_new (); + g_autoptr(GBytes) blob = NULL; + + stage2_off = BCM_NVRAM_STAGE1_BASE + stage1_sz; + if (!fu_bcm57xx_verify_magic (fw, stage2_off, error)) + return NULL; + if (!fu_common_read_uint32_safe (buf, bufsz, stage2_off + sizeof(guint32), + &stage2_sz, G_BIG_ENDIAN, error)) + return NULL; + if (stage2_off + stage2_sz > bufsz) { + g_set_error (error, + FWUPD_ERROR, + FWUPD_ERROR_NOT_SUPPORTED, + "bigger than firmware, got: 0x%x @ 0x%x", + (guint) stage2_sz, (guint) stage2_off); + return NULL; + } + + /* verify CRC */ + blob = g_bytes_new_from_bytes (fw, stage2_off + 0x8, stage2_sz); + if (!fu_firmware_image_parse (img, blob, flags, error)) + return NULL; + + /* success */ + fu_firmware_image_set_id (img, "stage2"); + fu_firmware_image_set_offset (img, stage2_off); + return g_steal_pointer (&img); +} + +static gboolean +fu_bcm57xx_firmware_parse_dict (FuBcm57xxFirmware *self, GBytes *fw, guint idx, + FwupdInstallFlags flags, GError **error) +{ + gsize bufsz = 0x0; + guint32 dict_addr = 0x0; + guint32 dict_info = 0x0; + guint32 dict_off = 0x0; + guint32 dict_sz; + guint32 base = BCM_NVRAM_DIRECTORY_BASE + (idx * BCM_NVRAM_DIRECTORY_SZ); + const guint8 *buf = g_bytes_get_data (fw, &bufsz); + g_autoptr(FuFirmwareImage) img = fu_bcm57xx_dict_image_new (); + g_autoptr(GBytes) blob = NULL; + + /* header */ + if (!fu_common_read_uint32_safe (buf, bufsz, + base + BCM_NVRAM_DIRECTORY_ADDR, + &dict_addr, G_BIG_ENDIAN, error)) + return FALSE; + if (!fu_common_read_uint32_safe (buf, bufsz, + base + BCM_NVRAM_DIRECTORY_SIZE_WRDS, + &dict_info, G_BIG_ENDIAN, error)) + return FALSE; + if (!fu_common_read_uint32_safe (buf, bufsz, + base + BCM_NVRAM_DIRECTORY_OFFSET, + &dict_off, G_BIG_ENDIAN, error)) + return FALSE; + + /* no dict stored */ + if (dict_addr == 0 && dict_info == 0 && dict_off == 0) + return TRUE; + + dict_sz = (dict_info & 0x00FFFFFF) * sizeof(guint32); /* implies that maximum size is 16 MB */ + fu_bcm57xx_dict_image_set_target (FU_BCM57XX_DICT_IMAGE (img), (dict_info & 0x0F000000) >> 24); + fu_bcm57xx_dict_image_set_kind (FU_BCM57XX_DICT_IMAGE (img), (dict_info & 0xF0000000) >> 28); + fu_firmware_image_set_addr (img, dict_addr); + fu_firmware_image_set_offset (img, dict_off); + fu_firmware_image_set_idx (img, 0x80 + idx); + + /* empty */ + if (dict_sz == 0) { + blob = g_bytes_new (NULL, 0); + fu_firmware_image_set_bytes (img, blob); + fu_firmware_add_image (FU_FIRMWARE (self), img); + return TRUE; + } + + /* check against image size */ + if (dict_off + dict_sz > bufsz) { + g_set_error (error, + FWUPD_ERROR, + FWUPD_ERROR_NOT_SUPPORTED, + "bigger than firmware, got: 0x%x @ 0x%x", + (guint) dict_sz, (guint) dict_off); + return FALSE; + } + blob = g_bytes_new_from_bytes (fw, dict_off, dict_sz); + if (!fu_firmware_image_parse (img, blob, flags, error)) + return FALSE; + + /* success */ + fu_firmware_add_image (FU_FIRMWARE (self), img); + return TRUE; +} + +static gboolean +fu_bcm57xx_firmware_parse (FuFirmware *firmware, + GBytes *fw, + guint64 addr_start, + guint64 addr_end, + FwupdInstallFlags flags, + GError **error) +{ + FuBcm57xxFirmware *self = FU_BCM57XX_FIRMWARE (firmware); + gsize bufsz = 0x0; + guint32 magic = 0; + guint32 stage1_sz = 0; + const guint8 *buf = g_bytes_get_data (fw, &bufsz); + g_autoptr(FuFirmwareImage) img_info2 = NULL; + g_autoptr(FuFirmwareImage) img_info = NULL; + g_autoptr(FuFirmwareImage) img_stage1 = NULL; + g_autoptr(FuFirmwareImage) img_stage2 = NULL; + g_autoptr(FuFirmwareImage) img_vpd = NULL; + g_autoptr(GBytes) blob_header = NULL; + g_autoptr(GBytes) blob_info2 = NULL; + g_autoptr(GBytes) blob_info = NULL; + g_autoptr(GBytes) blob_vpd = NULL; + + /* try to autodetect the file type */ + if (!fu_common_read_uint32_safe (buf, bufsz, 0x0, &magic, G_BIG_ENDIAN, error)) + return FALSE; + + /* standalone APE */ + if (magic == BCM_APE_HEADER_MAGIC) { + g_autoptr(FuFirmwareImage) img = fu_bcm57xx_dict_image_new (); + fu_bcm57xx_dict_image_set_target (FU_BCM57XX_DICT_IMAGE (img), 0xD); + fu_bcm57xx_dict_image_set_kind (FU_BCM57XX_DICT_IMAGE (img), 0x0); + fu_firmware_image_set_bytes (img, fw); + fu_firmware_image_set_addr (img, BCM_CODE_DIRECTORY_ADDR_APE); + fu_firmware_image_set_id (img, "ape"); + fu_firmware_add_image (firmware, img); + return TRUE; + } + + /* standalone stage1 */ + if (magic == BCM_STAGE1_HEADER_MAGIC_BROADCOM || + magic == BCM_STAGE1_HEADER_MAGIC_MEKLORT) { + img_stage1 = fu_firmware_image_new (fw); + fu_firmware_image_set_id (img_stage1, "stage1"); + fu_firmware_add_image (firmware, img_stage1); + return TRUE; + } + + /* not full NVRAM image */ + if (magic != BCM_NVRAM_MAGIC) { + g_set_error (error, + FWUPD_ERROR, + FWUPD_ERROR_NOT_SUPPORTED, + "file not supported, got: 0x%08X", + magic); + return FALSE; + } + + /* save the size so we can export the padding for a perfect roundtrip */ + self->source_size = bufsz; + self->source_padchar = buf[bufsz - 1]; + + /* NVRAM header */ + blob_header = g_bytes_new_from_bytes (fw, BCM_NVRAM_HEADER_BASE, BCM_NVRAM_HEADER_SZ); + if (!fu_bcm57xx_firmware_parse_header (self, blob_header, error)) { + g_prefix_error (error, "failed to parse header: "); + return FALSE; + } + + /* info */ + blob_info = g_bytes_new_from_bytes (fw, BCM_NVRAM_INFO_BASE, BCM_NVRAM_INFO_SZ); + img_info = fu_bcm57xx_firmware_parse_info (self, blob_info, error); + if (img_info == NULL) { + g_prefix_error (error, "failed to parse info: "); + return FALSE; + } + fu_firmware_image_set_offset (img_info, BCM_NVRAM_INFO_BASE); + fu_firmware_add_image (firmware, img_info); + + /* VPD */ + blob_vpd = g_bytes_new_from_bytes (fw, BCM_NVRAM_VPD_BASE, BCM_NVRAM_VPD_SZ); + img_vpd = fu_firmware_image_new (blob_vpd); + fu_firmware_image_set_id (img_vpd, "vpd"); + fu_firmware_image_set_offset (img_vpd, BCM_NVRAM_VPD_BASE); + fu_firmware_add_image (firmware, img_vpd); + + /* info2 */ + blob_info2 = g_bytes_new_from_bytes (fw, BCM_NVRAM_INFO2_BASE, BCM_NVRAM_INFO2_SZ); + img_info2 = fu_firmware_image_new (blob_info2); + fu_firmware_image_set_id (img_info2, "info2"); + fu_firmware_image_set_offset (img_info2, BCM_NVRAM_INFO2_BASE); + fu_firmware_add_image (firmware, img_info2); + + /* stage1 */ + img_stage1 = fu_bcm57xx_firmware_parse_stage1 (self, fw, &stage1_sz, flags, error); + if (img_stage1 == NULL) { + g_prefix_error (error, "failed to parse stage1: "); + return FALSE; + } + fu_firmware_add_image (firmware, img_stage1); + + /* stage2 */ + img_stage2 = fu_bcm57xx_firmware_parse_stage2 (self, fw, stage1_sz, flags, error); + if (img_stage2 == NULL) { + g_prefix_error (error, "failed to parse stage2: "); + return FALSE; + } + fu_firmware_add_image (firmware, img_stage2); + + /* dictionaries, e.g. APE */ + for (guint i = 0; i < 8; i++) { + g_autoptr(FuFirmwareImage) img = NULL; + if (!fu_bcm57xx_firmware_parse_dict (self, fw, i, flags, error)) { + g_prefix_error (error, "failed to parse dict 0x%x: ", i); + return FALSE; + } + } + + /* success */ + return TRUE; +} + +static void +_g_byte_array_append_bytes (GByteArray *buf, GBytes *bytes) +{ + g_byte_array_append (buf, g_bytes_get_data (bytes, NULL), g_bytes_get_size (bytes)); +} + +static GBytes * +_g_bytes_new_sized (gsize sz) +{ + GByteArray *tmp = g_byte_array_sized_new (sz); + for (gsize i = 0; i < sz; i++) + fu_byte_array_append_uint8 (tmp, 0x0); + return g_byte_array_free_to_bytes (tmp); +} + +static gboolean +fu_bcm57xx_firmware_build (FuFirmware *firmware, XbNode *n, GError **error) +{ + FuBcm57xxFirmware *self = FU_BCM57XX_FIRMWARE (firmware); + guint64 tmp; + + /* two simple properties */ + tmp = xb_node_query_text_as_uint (n, "vendor", NULL); + if (tmp != G_MAXUINT64 && tmp <= G_MAXUINT16) + self->vendor = tmp; + tmp = xb_node_query_text_as_uint (n, "model", NULL); + if (tmp != G_MAXUINT64 && tmp <= G_MAXUINT16) + self->model = tmp; + + /* success */ + return TRUE; +} + +static GBytes * +fu_bcm57xx_firmware_write (FuFirmware *firmware, GError **error) +{ + gsize off = BCM_NVRAM_STAGE1_BASE; + FuBcm57xxFirmware *self = FU_BCM57XX_FIRMWARE (firmware); + g_autoptr(GByteArray) buf = g_byte_array_sized_new (self->source_size); + g_autoptr(FuFirmwareImage) img_info2 = NULL; + g_autoptr(FuFirmwareImage) img_info = NULL; + g_autoptr(FuFirmwareImage) img_stage1 = NULL; + g_autoptr(FuFirmwareImage) img_stage2 = NULL; + g_autoptr(FuFirmwareImage) img_vpd = NULL; + g_autoptr(GBytes) blob_info2 = NULL; + g_autoptr(GBytes) blob_info = NULL; + g_autoptr(GBytes) blob_stage1 = NULL; + g_autoptr(GBytes) blob_stage2 = NULL; + g_autoptr(GBytes) blob_vpd = NULL; + g_autoptr(GPtrArray) blob_dicts = NULL; + + /* write out the things we need to pre-compute */ + img_stage1 = fu_firmware_get_image_by_id (firmware, "stage1", error); + if (img_stage1 == NULL) + return NULL; + blob_stage1 = fu_firmware_image_write (img_stage1, error); + if (blob_stage1 == NULL) + return NULL; + off += g_bytes_get_size (blob_stage1); + img_stage2 = fu_firmware_get_image_by_id (firmware, "stage2", error); + if (img_stage2 == NULL) + return NULL; + blob_stage2 = fu_firmware_image_write (img_stage2, error); + if (blob_stage2 == NULL) + return NULL; + off += g_bytes_get_size (blob_stage2); + + /* add header */ + fu_byte_array_append_uint32 (buf, BCM_NVRAM_MAGIC, G_BIG_ENDIAN); + fu_byte_array_append_uint32 (buf, self->phys_addr, G_BIG_ENDIAN); + fu_byte_array_append_uint32 (buf, g_bytes_get_size (blob_stage1) / sizeof(guint32), G_BIG_ENDIAN); + fu_byte_array_append_uint32 (buf, BCM_NVRAM_STAGE1_BASE, G_BIG_ENDIAN); + fu_byte_array_append_uint32 (buf, fu_bcm57xx_nvram_crc (buf->data, buf->len), G_BIG_ENDIAN); + + /* add directory entries */ + blob_dicts = g_ptr_array_new_with_free_func ((GDestroyNotify) g_bytes_unref); + for (guint i = 0; i < 8; i++) { + g_autoptr(FuFirmwareImage) img = NULL; + g_autoptr(GBytes) blob = NULL; + + img = fu_firmware_get_image_by_idx (firmware, 0x80 + i, NULL); + if (img != NULL) { + blob = fu_firmware_image_write (img, error); + if (blob == NULL) + return NULL; + } + if (blob != NULL) { + fu_byte_array_append_uint32 (buf, fu_firmware_image_get_addr (img), G_BIG_ENDIAN); + fu_byte_array_append_uint32 (buf, + (g_bytes_get_size (blob) / sizeof(guint32)) | + (guint32) fu_bcm57xx_dict_image_get_target (FU_BCM57XX_DICT_IMAGE (img)) << 24 | + (guint32) fu_bcm57xx_dict_image_get_kind (FU_BCM57XX_DICT_IMAGE (img)) << 28, + G_BIG_ENDIAN); + if (g_bytes_get_size (blob) > 0) { + fu_byte_array_append_uint32 (buf, off, G_BIG_ENDIAN); + off += g_bytes_get_size (blob); + } else { + fu_byte_array_append_uint32 (buf, 0x0, G_BIG_ENDIAN); + } + } else { + blob = g_bytes_new (NULL, 0); + for (guint32 j = 0; j < sizeof(guint32) * 3; j++) + fu_byte_array_append_uint8 (buf, 0x0); + } + g_ptr_array_add (blob_dicts, g_steal_pointer (&blob)); + } + + /* add info */ + img_info = fu_firmware_get_image_by_id (firmware, "info", NULL); + if (img_info != NULL) { + blob_info = fu_firmware_image_write (img_info, error); + if (blob_info == NULL) + return NULL; + } else { + GByteArray *tmp = g_byte_array_sized_new (BCM_NVRAM_INFO_SZ); + for (gsize i = 0; i < BCM_NVRAM_INFO_SZ; i++) + fu_byte_array_append_uint8 (tmp, 0x0); + fu_common_write_uint16 (tmp->data + BCM_NVRAM_INFO_VENDOR, + self->vendor, G_BIG_ENDIAN); + fu_common_write_uint16 (tmp->data + BCM_NVRAM_INFO_DEVICE, + self->model, G_BIG_ENDIAN); + blob_info = g_byte_array_free_to_bytes (tmp); + } + _g_byte_array_append_bytes (buf, blob_info); + + /* add vpd */ + img_vpd = fu_firmware_get_image_by_id (firmware, "vpd", NULL); + if (img_vpd != NULL) { + blob_vpd = fu_firmware_image_write (img_vpd, error); + if (blob_vpd == NULL) + return NULL; + } else { + blob_vpd = _g_bytes_new_sized (BCM_NVRAM_VPD_SZ); + } + _g_byte_array_append_bytes (buf, blob_vpd); + + /* add info2 */ + img_info2 = fu_firmware_get_image_by_id (firmware, "info2", NULL); + if (img_info2 != NULL) { + blob_info2 = fu_firmware_image_write (img_info2, error); + if (blob_info2 == NULL) + return NULL; + } else { + blob_info2 = _g_bytes_new_sized (BCM_NVRAM_INFO2_SZ); + } + _g_byte_array_append_bytes (buf, blob_info2); + + /* add stage1+2 */ + _g_byte_array_append_bytes (buf, blob_stage1); + _g_byte_array_append_bytes (buf, blob_stage2); + + /* add dictionaries, e.g. APE */ + for (guint i = 0; i < blob_dicts->len; i++) { + GBytes *blob = g_ptr_array_index (blob_dicts, i); + _g_byte_array_append_bytes (buf, blob); + } + + /* pad until full */ + for (guint32 i = buf->len; i < self->source_size; i++) + fu_byte_array_append_uint8 (buf, self->source_padchar); + + /* add EOF */ + return g_byte_array_free_to_bytes (g_steal_pointer (&buf)); +} + +guint16 +fu_bcm57xx_firmware_get_vendor (FuBcm57xxFirmware *self) +{ + return self->vendor; +} + +guint16 +fu_bcm57xx_firmware_get_model (FuBcm57xxFirmware *self) +{ + return self->model; +} + +gboolean +fu_bcm57xx_firmware_is_backup (FuBcm57xxFirmware *self) +{ + return self->is_backup; +} + +static void +fu_bcm57xx_firmware_init (FuBcm57xxFirmware *self) +{ + self->phys_addr = BCM_PHYS_ADDR_DEFAULT; + self->source_size = BCM_FIRMWARE_SIZE; + self->source_padchar = 0xff; + fu_firmware_add_flag (FU_FIRMWARE (self), FU_FIRMWARE_FLAG_DEDUPE_ID); +} + +static void +fu_bcm57xx_firmware_class_init (FuBcm57xxFirmwareClass *klass) +{ + FuFirmwareClass *klass_firmware = FU_FIRMWARE_CLASS (klass); + klass_firmware->parse = fu_bcm57xx_firmware_parse; + klass_firmware->to_string = fu_bcm57xx_firmware_to_string; + klass_firmware->write = fu_bcm57xx_firmware_write; + klass_firmware->build = fu_bcm57xx_firmware_build; +} + +FuFirmware * +fu_bcm57xx_firmware_new (void) +{ + return FU_FIRMWARE (g_object_new (FU_TYPE_BCM57XX_FIRMWARE, NULL)); +} diff --git a/plugins/bcm57xx/fu-bcm57xx-firmware.h b/plugins/bcm57xx/fu-bcm57xx-firmware.h new file mode 100644 index 000000000..59aafc424 --- /dev/null +++ b/plugins/bcm57xx/fu-bcm57xx-firmware.h @@ -0,0 +1,17 @@ +/* + * Copyright (C) 2020 Richard Hughes + * + * SPDX-License-Identifier: LGPL-2.1+ + */ + +#pragma once + +#include "fu-firmware.h" + +#define FU_TYPE_BCM57XX_FIRMWARE (fu_bcm57xx_firmware_get_type ()) +G_DECLARE_FINAL_TYPE (FuBcm57xxFirmware, fu_bcm57xx_firmware, FU, BCM57XX_FIRMWARE, FuFirmware) + +FuFirmware *fu_bcm57xx_firmware_new (void); +guint16 fu_bcm57xx_firmware_get_vendor (FuBcm57xxFirmware *self); +guint16 fu_bcm57xx_firmware_get_model (FuBcm57xxFirmware *self); +gboolean fu_bcm57xx_firmware_is_backup (FuBcm57xxFirmware *self); diff --git a/plugins/bcm57xx/fu-bcm57xx-recovery-device.c b/plugins/bcm57xx/fu-bcm57xx-recovery-device.c new file mode 100644 index 000000000..34ff27af3 --- /dev/null +++ b/plugins/bcm57xx/fu-bcm57xx-recovery-device.c @@ -0,0 +1,784 @@ +/* + * Copyright (C) 2018-2020 Evan Lojewski + * Copyright (C) 2020 Richard Hughes + * + * SPDX-License-Identifier: GPL-2+ + */ + +#include "config.h" + +#include +#include +#include +#include +#include +#ifdef HAVE_MMAN_H +#include +#endif + +#ifdef HAVE_VALGRIND +#include +#endif /* HAVE_VALGRIND */ + +#include "fu-common.h" + +#include "fu-bcm57xx-common.h" +#include "fu-bcm57xx-recovery-device.h" +#include "fu-bcm57xx-firmware.h" + +/* offsets into BAR[0] */ +#define REG_DEVICE_PCI_VENDOR_DEVICE_ID 0x6434 +#define REG_NVM_SOFTWARE_ARBITRATION 0x7020 +#define REG_NVM_ACCESS 0x7024 +#define REG_NVM_COMMAND 0x7000 +#define REG_NVM_ADDR 0x700c +#define REG_NVM_READ 0x7010 +#define REG_NVM_WRITE 0x7008 + +/* offsets into BAR[2] */ +#define REG_APE_MODE 0x10000 + +typedef struct { + guint8 *buf; + gsize bufsz; +} FuBcm57xxMmap; + +#define FU_BCM57XX_BAR_DEVICE 0 +#define FU_BCM57XX_BAR_APE 1 +#define FU_BCM57XX_BAR_MAX 3 + +struct _FuBcm57xxRecoveryDevice { + FuUdevDevice parent_instance; + FuBcm57xxMmap bar[FU_BCM57XX_BAR_MAX]; +}; + +typedef union { + guint32 r32; + struct { + guint32 reserved_0_0 : 1; + guint32 Reset : 1; + guint32 reserved_2_2 : 1; + guint32 Done : 1; + guint32 Doit : 1; + guint32 Wr : 1; + guint32 Erase : 1; + guint32 First : 1; + guint32 Last : 1; + guint32 reserved_15_9 : 7; + guint32 WriteEnableCommand : 1; + guint32 WriteDisableCommand : 1; + guint32 reserved_31_18 : 14; + } __attribute__((packed)) bits; +} BcmRegNVMCommand; + +typedef union { + guint32 r32; + struct { + guint32 ReqSet0 : 1; + guint32 ReqSet1 : 1; + guint32 ReqSet2 : 1; + guint32 ReqSet3 : 1; + guint32 ReqClr0 : 1; + guint32 ReqClr1 : 1; + guint32 ReqClr2 : 1; + guint32 ReqClr3 : 1; + guint32 ArbWon0 : 1; + guint32 ArbWon1 : 1; + guint32 ArbWon2 : 1; + guint32 ArbWon3 : 1; + guint32 Req0 : 1; + guint32 Req1 : 1; + guint32 Req2 : 1; + guint32 Req3 : 1; + guint32 reserved_31_16 : 16; + } __attribute__((packed)) bits; +} BcmRegNVMSoftwareArbitration; + +typedef union { + guint32 r32; + struct { + guint32 Enable : 1; + guint32 WriteEnable : 1; + guint32 reserved_31_2 : 30; + } __attribute__((packed)) bits; +} BcmRegNVMAccess; + +typedef union { + guint32 r32; + struct { + guint32 Reset : 1; + guint32 Halt : 1; + guint32 FastBoot : 1; + guint32 HostDiag : 1; + guint32 reserved_4_4 : 1; + guint32 Event1 : 1; + guint32 Event2 : 1; + guint32 GRCint : 1; + guint32 reserved_8_8 : 1; + guint32 SwapATBdword : 1; + guint32 reserved_10_10 : 1; + guint32 SwapARBdword : 1; + guint32 reserved_13_12 : 2; + guint32 Channel0Enable : 1; + guint32 Channel2Enable : 1; + guint32 reserved_17_16 : 2; + guint32 MemoryECC : 1; + guint32 ICodePIPRdDisable : 1; + guint32 reserved_29_20 : 10; + guint32 Channel1Enable : 1; + guint32 Channel3Enable : 1; + } __attribute__((packed)) bits; +} BcmRegAPEMode; + +G_DEFINE_TYPE (FuBcm57xxRecoveryDevice, fu_bcm57xx_recovery_device, FU_TYPE_UDEV_DEVICE) + +#ifdef __ppc64__ +#define BARRIER() __asm__ volatile ("sync 0\neieio\n" : : : "memory") +#else +#define BARRIER() __asm__ volatile ("" : : : "memory"); +#endif + +static gboolean +fu_bcm57xx_recovery_device_bar_read (FuBcm57xxRecoveryDevice *self, + guint bar, gsize offset, guint32 *val, + GError **error) +{ + guint8 *base = self->bar[bar].buf + offset; + + /* this should never happen */ + if (self->bar[bar].buf == NULL) { + g_set_error (error, + FWUPD_ERROR, + FWUPD_ERROR_INTERNAL, + "BAR[%u] is not mapped!", bar); + return FALSE; + } + + BARRIER(); + *val = *(guint32 *)base; + return TRUE; +} + +static gboolean +fu_bcm57xx_recovery_device_bar_write (FuBcm57xxRecoveryDevice *self, + guint bar, gsize offset, guint32 val, + GError **error) +{ + guint8 *base = self->bar[bar].buf + offset; + + /* this should never happen */ + if (self->bar[bar].buf == NULL) { + g_set_error (error, + FWUPD_ERROR, + FWUPD_ERROR_INTERNAL, + "BAR[%u] is not mapped!", bar); + return FALSE; + } + + BARRIER(); + *(guint32 *)base = val; + BARRIER(); + return TRUE; +} + +static gboolean +fu_bcm57xx_recovery_device_nvram_disable (FuBcm57xxRecoveryDevice *self, + GError **error) +{ + BcmRegNVMAccess tmp; + if (!fu_bcm57xx_recovery_device_bar_read (self, FU_BCM57XX_BAR_DEVICE, + REG_NVM_ACCESS, &tmp.r32, error)) + return FALSE; + tmp.bits.Enable = FALSE; + tmp.bits.WriteEnable = FALSE; + return fu_bcm57xx_recovery_device_bar_write (self, FU_BCM57XX_BAR_DEVICE, + REG_NVM_ACCESS, tmp.r32, error); +} + +static gboolean +fu_bcm57xx_recovery_device_nvram_enable (FuBcm57xxRecoveryDevice *self, + GError **error) +{ + BcmRegNVMAccess tmp; + if (!fu_bcm57xx_recovery_device_bar_read (self, FU_BCM57XX_BAR_DEVICE, + REG_NVM_ACCESS, &tmp.r32, error)) + return FALSE; + tmp.bits.Enable = TRUE; + tmp.bits.WriteEnable = FALSE; + return fu_bcm57xx_recovery_device_bar_write (self, FU_BCM57XX_BAR_DEVICE, + REG_NVM_ACCESS, tmp.r32, error); +} + +static gboolean +fu_bcm57xx_recovery_device_nvram_enable_write (FuBcm57xxRecoveryDevice *self, + GError **error) +{ + BcmRegNVMAccess tmp; + if (!fu_bcm57xx_recovery_device_bar_read (self, FU_BCM57XX_BAR_DEVICE, + REG_NVM_ACCESS, &tmp.r32, error)) + return FALSE; + tmp.bits.Enable = TRUE; + tmp.bits.WriteEnable = TRUE; + return fu_bcm57xx_recovery_device_bar_write (self, FU_BCM57XX_BAR_DEVICE, + REG_NVM_ACCESS, tmp.r32, error); +} + +static gboolean +fu_bcm57xx_recovery_device_nvram_acquire_lock (FuBcm57xxRecoveryDevice *self, + GError **error) +{ + BcmRegNVMSoftwareArbitration tmp = { 0 }; + g_autoptr(GTimer) timer = g_timer_new (); + tmp.bits.ReqSet1 = 1; + if (!fu_bcm57xx_recovery_device_bar_write (self, FU_BCM57XX_BAR_DEVICE, + REG_NVM_SOFTWARE_ARBITRATION, + tmp.r32, error)) + return FALSE; + do { + if (!fu_bcm57xx_recovery_device_bar_read (self, + FU_BCM57XX_BAR_DEVICE, + REG_NVM_SOFTWARE_ARBITRATION, + &tmp.r32, error)) + return FALSE; + if (tmp.bits.ArbWon1) + return TRUE; + if (g_timer_elapsed (timer, NULL) > 0.2) + break; + } while (TRUE); + + /* timed out */ + g_set_error_literal (error, + G_IO_ERROR, + G_IO_ERROR_TIMED_OUT, + "timed out trying to acquire lock #1"); + return FALSE; +} + +static gboolean +fu_bcm57xx_recovery_device_nvram_release_lock (FuBcm57xxRecoveryDevice *self, + GError **error) +{ + BcmRegNVMSoftwareArbitration tmp = { 0 }; + tmp.r32 = 0; + tmp.bits.ReqClr1 = 1; + return fu_bcm57xx_recovery_device_bar_write (self, FU_BCM57XX_BAR_DEVICE, + REG_NVM_SOFTWARE_ARBITRATION, tmp.r32, + error); +} + +static gboolean +fu_bcm57xx_recovery_device_nvram_wait_done (FuBcm57xxRecoveryDevice *self, GError **error) +{ + BcmRegNVMCommand tmp = { 0 }; + g_autoptr(GTimer) timer = g_timer_new (); + do { + if (!fu_bcm57xx_recovery_device_bar_read (self, + FU_BCM57XX_BAR_DEVICE, + REG_NVM_COMMAND, &tmp.r32, + error)) + return FALSE; + if (tmp.bits.Done) + return TRUE; + if (g_timer_elapsed (timer, NULL) > 0.2) + break; + } while (TRUE); + + /* timed out */ + g_set_error_literal (error, + G_IO_ERROR, + G_IO_ERROR_TIMED_OUT, + "timed out"); + return FALSE; +} + +static gboolean +fu_bcm57xx_recovery_device_nvram_clear_done (FuBcm57xxRecoveryDevice *self, GError **error) +{ + BcmRegNVMCommand tmp = { 0 }; + tmp.bits.Done = 1; + return fu_bcm57xx_recovery_device_bar_write (self, FU_BCM57XX_BAR_DEVICE, + REG_NVM_COMMAND, tmp.r32, error); +} + +static gboolean +fu_bcm57xx_recovery_device_nvram_read (FuBcm57xxRecoveryDevice *self, + guint32 address, guint32 *buf, gsize bufsz, + GError **error) +{ + for (guint i = 0; i < bufsz; i++) { + BcmRegNVMCommand tmp = { 0 }; + guint32 val32 = 0; + if (!fu_bcm57xx_recovery_device_nvram_clear_done (self, error)) + return FALSE; + if (!fu_bcm57xx_recovery_device_bar_write (self, FU_BCM57XX_BAR_DEVICE, + REG_NVM_ADDR, address, error)) + return FALSE; + tmp.bits.Doit = 1; + tmp.bits.First = i == 0; + tmp.bits.Last = i == bufsz - 1; + + if (!fu_bcm57xx_recovery_device_bar_write (self, FU_BCM57XX_BAR_DEVICE, + REG_NVM_COMMAND, tmp.r32, error)) + return FALSE; + if (!fu_bcm57xx_recovery_device_nvram_wait_done (self, error)) { + g_prefix_error (error, "failed to read @0x%x: ", address); + return FALSE; + } + if (!fu_bcm57xx_recovery_device_bar_read (self, FU_BCM57XX_BAR_DEVICE, + REG_NVM_READ, &val32, error)) + return FALSE; + buf[i] = GUINT32_FROM_BE(val32); + address += sizeof(guint32); + fu_device_set_progress_full (FU_DEVICE (self), i, bufsz); + } + + /* success */ + return TRUE; +} + +static gboolean +fu_bcm57xx_recovery_device_nvram_write (FuBcm57xxRecoveryDevice *self, + guint32 address, const guint32 *buf, gsize bufsz_dwrds, + GError **error) +{ + const guint32 page_size_dwrds = 64; + + /* can only write in pages of 64 dwords */ + if (bufsz_dwrds % page_size_dwrds != 0 || + (address * sizeof(guint32)) % page_size_dwrds != 0) { + g_set_error (error, + FWUPD_ERROR, + FWUPD_ERROR_NOT_SUPPORTED, + "can only write aligned with page size 0x%x", + page_size_dwrds); + return FALSE; + } + + for (guint i = 0; i < bufsz_dwrds; i++) { + BcmRegNVMCommand tmp = { 0 }; + if (!fu_bcm57xx_recovery_device_nvram_clear_done (self, error)) + return FALSE; + if (!fu_bcm57xx_recovery_device_bar_write (self, FU_BCM57XX_BAR_DEVICE, + REG_NVM_WRITE, GUINT32_TO_BE(buf[i]), error)) + return FALSE; + if (!fu_bcm57xx_recovery_device_bar_write (self, FU_BCM57XX_BAR_DEVICE, + REG_NVM_ADDR, address, error)) + return FALSE; + tmp.bits.Wr = TRUE; + tmp.bits.Doit = TRUE; + tmp.bits.First = i % page_size_dwrds == 0; + tmp.bits.Last = (i + 1) % page_size_dwrds == 0; + if (!fu_bcm57xx_recovery_device_bar_write (self, FU_BCM57XX_BAR_DEVICE, + REG_NVM_COMMAND, tmp.r32, error)) + return FALSE; + if (!fu_bcm57xx_recovery_device_nvram_wait_done (self, error)) { + g_prefix_error (error, "failed to write @0x%x: ", address); + return FALSE; + } + address += sizeof(guint32); + fu_device_set_progress_full (FU_DEVICE (self), i, bufsz_dwrds); + } + + /* success */ + return TRUE; +} + +static gboolean +fu_bcm57xx_recovery_device_detach (FuDevice *device, GError **error) +{ + /* unbind tg3 */ + return fu_device_unbind_driver (device, error); +} + +static gboolean +fu_bcm57xx_recovery_device_attach (FuDevice *device, GError **error) +{ + g_autoptr(GError) error_local = NULL; + + /* bind tg3, which might fail if the module is not compiled */ + if (!fu_device_bind_driver (device, "pci", "tg3", &error_local)) { + if (g_error_matches (error_local, + FWUPD_ERROR, + FWUPD_ERROR_NOT_SUPPORTED)) { + g_warning ("failed to bind tg3: %s", error_local->message); + } else { + g_propagate_prefixed_error (error, + g_steal_pointer (&error_local), + "failed to bind tg3: "); + return FALSE; + } + } + + /* success */ + return TRUE; +} + +static gboolean +fu_bcm57xx_recovery_device_activate (FuDevice *device, GError **error) +{ + BcmRegAPEMode mode = { 0 }; + FuBcm57xxRecoveryDevice *self = FU_BCM57XX_RECOVERY_DEVICE (device); + g_autoptr(FuDeviceLocker) locker = NULL; + g_autoptr(FuDeviceLocker) locker2 = NULL; + + locker = fu_device_locker_new_full (self, + (FuDeviceLockerFunc) fu_bcm57xx_recovery_device_nvram_acquire_lock, + (FuDeviceLockerFunc) fu_bcm57xx_recovery_device_nvram_release_lock, + error); + if (locker == NULL) + return FALSE; + locker2 = fu_device_locker_new_full (self, + (FuDeviceLockerFunc) fu_bcm57xx_recovery_device_nvram_enable, + (FuDeviceLockerFunc) fu_bcm57xx_recovery_device_nvram_disable, + error); + if (locker2 == NULL) + return FALSE; + + /* halt */ + mode.bits.Halt = 1; + mode.bits.FastBoot = 0; + if (!fu_bcm57xx_recovery_device_bar_write (self, FU_BCM57XX_BAR_APE, + REG_APE_MODE, mode.r32, error)) + return FALSE; + + /* boot */ + mode.bits.Halt = 0; + mode.bits.FastBoot = 0; + mode.bits.Reset = 1; + return fu_bcm57xx_recovery_device_bar_write (self, FU_BCM57XX_BAR_APE, + REG_APE_MODE, mode.r32, error); +} + +static GBytes * +fu_bcm57xx_recovery_device_dump_firmware (FuDevice *device, GError **error) +{ + FuBcm57xxRecoveryDevice *self = FU_BCM57XX_RECOVERY_DEVICE (device); + gsize bufsz_dwrds = fu_device_get_firmware_size_max (FU_DEVICE (self)) / sizeof(guint32); + g_autofree guint32 *buf_dwrds = g_new0 (guint32, bufsz_dwrds); + g_autoptr(FuDeviceLocker) locker = NULL; + g_autoptr(FuDeviceLocker) locker2 = NULL; + + /* read from hardware */ + fu_device_set_status (device, FWUPD_STATUS_DEVICE_READ); + locker = fu_device_locker_new_full (self, + (FuDeviceLockerFunc) fu_bcm57xx_recovery_device_nvram_acquire_lock, + (FuDeviceLockerFunc) fu_bcm57xx_recovery_device_nvram_release_lock, + error); + if (locker == NULL) + return NULL; + locker2 = fu_device_locker_new_full (self, + (FuDeviceLockerFunc) fu_bcm57xx_recovery_device_nvram_enable, + (FuDeviceLockerFunc) fu_bcm57xx_recovery_device_nvram_disable, + error); + if (locker2 == NULL) + return NULL; + if (!fu_bcm57xx_recovery_device_nvram_read (self, 0x0, buf_dwrds, bufsz_dwrds, error)) + return NULL; + if (!fu_device_locker_close (locker2, error)) + return NULL; + return g_bytes_new (buf_dwrds, bufsz_dwrds * sizeof(guint32)); +} + +static FuFirmware * +fu_bcm57xx_recovery_device_prepare_firmware (FuDevice *device, + GBytes *fw, + FwupdInstallFlags flags, + GError **error) +{ + g_autoptr(FuFirmware) firmware_bin = fu_firmware_new (); + g_autoptr(FuFirmware) firmware_tmp = fu_bcm57xx_firmware_new (); + + /* check is a NVRAM backup */ + if (!fu_firmware_parse (firmware_tmp, fw, flags, error)) { + g_prefix_error (error, "failed to parse new firmware: "); + return NULL; + } + if (!fu_bcm57xx_firmware_is_backup (FU_BCM57XX_FIRMWARE (firmware_tmp))) { + g_set_error_literal (error, + FWUPD_ERROR, + FWUPD_ERROR_NOT_SUPPORTED, + "can only recover with backup firmware"); + return NULL; + } + if (!fu_firmware_parse (firmware_bin, fw, flags, error)) + return NULL; + return g_steal_pointer (&firmware_bin); +} + +static gboolean +fu_bcm57xx_recovery_device_write_firmware (FuDevice *device, + FuFirmware *firmware, + FwupdInstallFlags flags, + GError **error) +{ + FuBcm57xxRecoveryDevice *self= FU_BCM57XX_RECOVERY_DEVICE (device); + const guint8 *buf; + gsize bufsz = 0; + gsize bufsz_dwrds; + g_autofree guint32 *buf_dwrds = NULL; + g_autoptr(FuDeviceLocker) locker = NULL; + g_autoptr(FuDeviceLocker) locker2 = NULL; + g_autoptr(GBytes) blob = NULL; + + /* build the images into one linear blob of the correct size */ + fu_device_set_status (device, FWUPD_STATUS_DECOMPRESSING); + blob = fu_firmware_write (firmware, error); + if (blob == NULL) + return FALSE; + + /* align into uint32_t buffer */ + buf = g_bytes_get_data (blob, &bufsz); + bufsz_dwrds = bufsz / sizeof(guint32); + buf_dwrds = g_new0 (guint32, bufsz_dwrds); + if (!fu_memcpy_safe ((guint8 *) buf_dwrds, bufsz_dwrds * sizeof(guint32), 0x0, /* dst */ + buf, bufsz, 0x0, /* src */ + bufsz, error)) + return FALSE; + + /* hit hardware */ + fu_device_set_status (device, FWUPD_STATUS_DEVICE_WRITE); + locker = fu_device_locker_new_full (self, + (FuDeviceLockerFunc) fu_bcm57xx_recovery_device_nvram_acquire_lock, + (FuDeviceLockerFunc) fu_bcm57xx_recovery_device_nvram_release_lock, + error); + if (locker == NULL) + return FALSE; + locker2 = fu_device_locker_new_full (self, + (FuDeviceLockerFunc) fu_bcm57xx_recovery_device_nvram_enable_write, + (FuDeviceLockerFunc) fu_bcm57xx_recovery_device_nvram_disable, + error); + if (locker2 == NULL) + return FALSE; + if (!fu_bcm57xx_recovery_device_nvram_write (self, 0x0, buf_dwrds, bufsz_dwrds, error)) + return FALSE; + if (!fu_device_locker_close (locker2, error)) + return FALSE; + if (!fu_device_locker_close (locker, error)) + return FALSE; + + /* reset APE */ + return fu_device_activate (device, error); +} + +static gboolean +fu_bcm57xx_recovery_device_setup (FuDevice *device, GError **error) +{ + FuBcm57xxRecoveryDevice *self = FU_BCM57XX_RECOVERY_DEVICE (device); + guint32 fwversion = 0; + g_autoptr(FuDeviceLocker) locker = NULL; + g_autoptr(FuDeviceLocker) locker2 = NULL; + + locker = fu_device_locker_new_full (self, + (FuDeviceLockerFunc) fu_bcm57xx_recovery_device_nvram_acquire_lock, + (FuDeviceLockerFunc) fu_bcm57xx_recovery_device_nvram_release_lock, + error); + if (locker == NULL) + return FALSE; + locker2 = fu_device_locker_new_full (self, + (FuDeviceLockerFunc) fu_bcm57xx_recovery_device_nvram_enable, + (FuDeviceLockerFunc) fu_bcm57xx_recovery_device_nvram_disable, + error); + if (locker2 == NULL) + return FALSE; + + /* get NVRAM version */ + if (!fu_bcm57xx_recovery_device_nvram_read (self, BCM_NVRAM_STAGE1_BASE + BCM_NVRAM_STAGE1_VERSION, + &fwversion, 1, error)) + return FALSE; + if (fwversion != 0x0) { + g_autofree gchar *fwversion_str = NULL; + + /* this is only set on the OSS firmware */ + fwversion_str = fu_common_version_from_uint32 (GUINT32_FROM_BE(fwversion), + FWUPD_VERSION_FORMAT_TRIPLET); + fu_device_set_version_format (device, FWUPD_VERSION_FORMAT_TRIPLET); + fu_device_set_version (device, fwversion_str); + fu_device_set_version_raw (device, fwversion); + fu_device_set_branch (device, BCM_FW_BRANCH_OSS_FIRMWARE); + } else { + guint32 bufver[4] = { 0x0 }; + guint32 veraddr = 0; + g_autoptr(Bcm57xxVeritem) veritem = NULL; + + /* fall back to the string, e.g. '5719-v1.43' */ + if (!fu_bcm57xx_recovery_device_nvram_read (self, + BCM_NVRAM_STAGE1_BASE + BCM_NVRAM_STAGE1_VERADDR, + &veraddr, 1, error)) + return FALSE; + veraddr = GUINT32_FROM_BE(veraddr); + if (veraddr > BCM_PHYS_ADDR_DEFAULT) + veraddr -= BCM_PHYS_ADDR_DEFAULT; + if (!fu_bcm57xx_recovery_device_nvram_read (self, + BCM_NVRAM_STAGE1_BASE + veraddr, + bufver, 4, error)) + return FALSE; + veritem = fu_bcm57xx_veritem_new ((guint8 *) bufver, sizeof(bufver)); + if (veritem != NULL) { + fu_device_set_version (device, veritem->version); + fu_device_set_branch (device, veritem->branch); + fu_device_set_version_format (device, veritem->verfmt); + } + } + + return TRUE; +} + +static gboolean +fu_bcm57xx_recovery_device_open (FuDevice *device, GError **error) +{ + FuBcm57xxRecoveryDevice *self = FU_BCM57XX_RECOVERY_DEVICE (device); +#ifdef HAVE_MMAN_H + FuUdevDevice *udev_device = FU_UDEV_DEVICE (device); + const gchar *sysfs_path = fu_udev_device_get_sysfs_path (udev_device); +#endif + +#ifdef RUNNING_ON_VALGRIND + /* this can't work */ + if (RUNNING_ON_VALGRIND) { + g_set_error_literal (error, + G_IO_ERROR, + G_IO_ERROR_NOT_SUPPORTED, + "cannot mmap'ing BARs when using valgrind"); + return FALSE; + } +#endif + +#ifdef HAVE_MMAN_H + /* map BARs */ + for (guint i = 0; i < FU_BCM57XX_BAR_MAX; i++) { + int memfd; + struct stat st; + g_autofree gchar *fn = NULL; + g_autofree gchar *resfn = NULL; + + /* open 64 bit resource */ + resfn = g_strdup_printf ("resource%u", i * 2); + fn = g_build_filename (sysfs_path, resfn, NULL); + memfd = open (fn, O_RDWR | O_SYNC); + if (memfd < 0) { + g_set_error (error, + G_IO_ERROR, + G_IO_ERROR_NOT_FOUND, + "error opening %s", fn); + return FALSE; + } + if (fstat (memfd, &st) < 0) { + g_set_error (error, + G_IO_ERROR, + G_IO_ERROR_NOT_SUPPORTED, + "could not stat %s", fn); + close (memfd); + return FALSE; + } + + /* mmap */ + if (g_getenv ("FWUPD_BCM57XX_VERBOSE") != NULL) + g_debug ("mapping BAR[%u] %s for 0x%x bytes", i, fn, (guint) st.st_size); + self->bar[i].buf = (guint8 *) mmap (0, st.st_size, + PROT_READ | PROT_WRITE, + MAP_SHARED, memfd, 0); + self->bar[i].bufsz = st.st_size; + close (memfd); + if (self->bar[i].buf == MAP_FAILED) { + g_set_error (error, + G_IO_ERROR, + G_IO_ERROR_NOT_SUPPORTED, + "cound not mmap %s: %s", + fn, strerror(errno)); + return FALSE; + } + } + + /* success */ + return TRUE; +#else + g_set_error_literal (error, + G_IO_ERROR, + G_IO_ERROR_NOT_SUPPORTED, + "mmap() not supported as sys/mman.h not available"); + return FALSE; +#endif +} + +static gboolean +fu_bcm57xx_recovery_device_close (FuDevice *device, GError **error) +{ +#ifdef HAVE_MMAN_H + FuBcm57xxRecoveryDevice *self = FU_BCM57XX_RECOVERY_DEVICE (device); + + /* unmap BARs */ + for (guint i = 0; i < FU_BCM57XX_BAR_MAX; i++) { + if (self->bar[i].buf == NULL) + continue; + if (g_getenv ("FWUPD_BCM57XX_VERBOSE") != NULL) + g_debug ("unmapping BAR[%u]", i); + munmap (self->bar[i].buf, self->bar[i].bufsz); + self->bar[i].buf = NULL; + self->bar[i].bufsz = 0; + } + + /* success */ + return TRUE; +#else + g_set_error_literal (error, + G_IO_ERROR, + G_IO_ERROR_NOT_SUPPORTED, + "munmap() not supported as sys/mman.h not available"); + return FALSE; +#endif +} + +static void +fu_bcm57xx_recovery_device_init (FuBcm57xxRecoveryDevice *self) +{ + fu_device_add_flag (FU_DEVICE (self), FWUPD_DEVICE_FLAG_UPDATABLE); + fu_device_add_flag (FU_DEVICE (self), FWUPD_DEVICE_FLAG_CAN_VERIFY_IMAGE); + fu_device_add_flag (FU_DEVICE (self), FWUPD_DEVICE_FLAG_NO_GUID_MATCHING); + fu_device_add_flag (FU_DEVICE (self), FWUPD_DEVICE_FLAG_NEEDS_REBOOT); + fu_device_add_flag (FU_DEVICE (self), FWUPD_DEVICE_FLAG_BACKUP_BEFORE_INSTALL); + fu_device_add_flag (FU_DEVICE (self), FWUPD_DEVICE_FLAG_IGNORE_VALIDATION); + fu_device_set_protocol (FU_DEVICE (self), "com.broadcom.bcm57xx"); + fu_device_add_icon (FU_DEVICE (self), "network-wired"); + fu_device_set_logical_id (FU_DEVICE (self), "recovery"); + + /* other values are set from a quirk */ + fu_device_set_firmware_size (FU_DEVICE (self), BCM_FIRMWARE_SIZE); + + /* no BARs mapped */ + for (guint i = 0; i < FU_BCM57XX_BAR_MAX; i++) { + self->bar[i].buf = NULL; + self->bar[i].bufsz = 0; + } +} + +static gboolean +fu_bcm57xx_recovery_device_probe (FuUdevDevice *device, GError **error) +{ + /* success */ + return fu_udev_device_set_physical_id (device, "pci", error); +} + +static void +fu_bcm57xx_recovery_device_class_init (FuBcm57xxRecoveryDeviceClass *klass) +{ + FuDeviceClass *klass_device = FU_DEVICE_CLASS (klass); + FuUdevDeviceClass *klass_udev_device = FU_UDEV_DEVICE_CLASS (klass); + klass_device->activate = fu_bcm57xx_recovery_device_activate; + klass_device->prepare_firmware = fu_bcm57xx_recovery_device_prepare_firmware; + klass_device->setup = fu_bcm57xx_recovery_device_setup; + klass_device->reload = fu_bcm57xx_recovery_device_setup; + klass_device->open = fu_bcm57xx_recovery_device_open; + klass_device->close = fu_bcm57xx_recovery_device_close; + klass_device->write_firmware = fu_bcm57xx_recovery_device_write_firmware; + klass_device->dump_firmware = fu_bcm57xx_recovery_device_dump_firmware; + klass_device->attach = fu_bcm57xx_recovery_device_attach; + klass_device->detach = fu_bcm57xx_recovery_device_detach; + klass_udev_device->probe = fu_bcm57xx_recovery_device_probe; +} + +FuBcm57xxRecoveryDevice * +fu_bcm57xx_recovery_device_new (void) +{ + FuUdevDevice *self = g_object_new (FU_TYPE_BCM57XX_RECOVERY_DEVICE, NULL); + return FU_BCM57XX_RECOVERY_DEVICE (self); +} diff --git a/plugins/bcm57xx/fu-bcm57xx-recovery-device.h b/plugins/bcm57xx/fu-bcm57xx-recovery-device.h new file mode 100644 index 000000000..a78c5b511 --- /dev/null +++ b/plugins/bcm57xx/fu-bcm57xx-recovery-device.h @@ -0,0 +1,14 @@ +/* + * Copyright (C) 2020 Richard Hughes + * + * SPDX-License-Identifier: LGPL-2.1+ + */ + +#pragma once + +#include "fu-plugin.h" + +#define FU_TYPE_BCM57XX_RECOVERY_DEVICE (fu_bcm57xx_recovery_device_get_type ()) +G_DECLARE_FINAL_TYPE (FuBcm57xxRecoveryDevice, fu_bcm57xx_recovery_device, FU, BCM57XX_RECOVERY_DEVICE, FuUdevDevice) + +FuBcm57xxRecoveryDevice *fu_bcm57xx_recovery_device_new (void); diff --git a/plugins/bcm57xx/fu-bcm57xx-stage1-image.c b/plugins/bcm57xx/fu-bcm57xx-stage1-image.c new file mode 100644 index 000000000..93d5a1268 --- /dev/null +++ b/plugins/bcm57xx/fu-bcm57xx-stage1-image.c @@ -0,0 +1,128 @@ +/* + * Copyright (C) 2020 Richard Hughes + * + * SPDX-License-Identifier: LGPL-2.1+ + */ + +#include "config.h" + +#include "fu-common.h" +#include "fu-common-version.h" + +#include "fu-bcm57xx-common.h" +#include "fu-bcm57xx-stage1-image.h" + +struct _FuBcm57xxStage1Image { + FuFirmwareImage parent_instance; +}; + +G_DEFINE_TYPE (FuBcm57xxStage1Image, fu_bcm57xx_stage1_image, FU_TYPE_FIRMWARE_IMAGE) + +static gboolean +fu_bcm57xx_stage1_image_parse (FuFirmwareImage *image, + GBytes *fw, + FwupdInstallFlags flags, + GError **error) +{ + gsize bufsz = 0x0; + guint32 fwversion = 0; + const guint8 *buf = g_bytes_get_data (fw, &bufsz); + g_autoptr(GBytes) fw_nocrc = NULL; + + /* verify CRC */ + if ((flags & FWUPD_INSTALL_FLAG_IGNORE_CHECKSUM) == 0) { + if (!fu_bcm57xx_verify_crc (fw, error)) + return FALSE; + } + + /* get version number */ + if (!fu_common_read_uint32_safe (buf, bufsz, BCM_NVRAM_STAGE1_VERSION, + &fwversion, G_BIG_ENDIAN, error)) + return FALSE; + if (fwversion != 0x0) { + g_autofree gchar *tmp = NULL; + tmp = fu_common_version_from_uint32 (fwversion, FWUPD_VERSION_FORMAT_TRIPLET); + fu_firmware_image_set_version (image, tmp); + } else { + guint32 bufver[4] = { '\0' }; + guint32 veraddr = 0x0; + g_autoptr(Bcm57xxVeritem) veritem = NULL; + + /* fall back to the string, e.g. '5719-v1.43' */ + if (!fu_common_read_uint32_safe (buf, bufsz, BCM_NVRAM_STAGE1_VERADDR, + &veraddr, G_BIG_ENDIAN, error)) + return FALSE; + if (veraddr < BCM_PHYS_ADDR_DEFAULT + sizeof(bufver)) { + g_set_error (error, + FWUPD_ERROR, + FWUPD_ERROR_NOT_SUPPORTED, + "version address 0x%x less than physical 0x%x", + veraddr, (guint) BCM_PHYS_ADDR_DEFAULT); + return FALSE; + } + if (!fu_memcpy_safe ((guint8 *) bufver, sizeof(bufver), 0x0, /* dst */ + buf, bufsz, veraddr - BCM_PHYS_ADDR_DEFAULT, /* src */ + sizeof(bufver), error)) + return FALSE; + veritem = fu_bcm57xx_veritem_new ((guint8 *) bufver, sizeof(bufver)); + if (veritem != NULL) + fu_firmware_image_set_version (image, veritem->version); + } + + fw_nocrc = g_bytes_new_from_bytes (fw, 0x0, g_bytes_get_size (fw) - sizeof(guint32)); + fu_firmware_image_set_bytes (image, fw_nocrc); + return TRUE; +} + +static GBytes * +fu_bcm57xx_stage1_image_write (FuFirmwareImage *image, GError **error) +{ + const guint8 *buf; + gsize bufsz = 0; + guint32 crc; + g_autoptr(GByteArray) blob = NULL; + g_autoptr(GBytes) fw_nocrc = NULL; + g_autoptr(GBytes) fw_align = NULL; + + /* get the CRC-less data */ + fw_nocrc = fu_firmware_image_get_bytes (image); + if (fw_nocrc == NULL) { + g_set_error_literal (error, + FWUPD_ERROR, + FWUPD_ERROR_NOT_SUPPORTED, + "not supported"); + return NULL; + } + + /* this has to be aligned by DWORDs */ + fw_align = fu_common_bytes_align (fw_nocrc, sizeof(guint32), 0xff); + + /* add to a mutable buffer */ + buf = g_bytes_get_data (fw_align, &bufsz); + blob = g_byte_array_sized_new (bufsz + sizeof(guint32)); + g_byte_array_append (blob, buf, bufsz); + + /* add CRC */ + crc = fu_bcm57xx_nvram_crc (buf, bufsz); + fu_byte_array_append_uint32 (blob, crc, G_BIG_ENDIAN); + return g_byte_array_free_to_bytes (g_steal_pointer (&blob)); +} + +static void +fu_bcm57xx_stage1_image_init (FuBcm57xxStage1Image *self) +{ +} + +static void +fu_bcm57xx_stage1_image_class_init (FuBcm57xxStage1ImageClass *klass) +{ + FuFirmwareImageClass *klass_image = FU_FIRMWARE_IMAGE_CLASS (klass); + klass_image->parse = fu_bcm57xx_stage1_image_parse; + klass_image->write = fu_bcm57xx_stage1_image_write; +} + +FuFirmwareImage * +fu_bcm57xx_stage1_image_new (void) +{ + return FU_FIRMWARE_IMAGE (g_object_new (FU_TYPE_BCM57XX_STAGE1_IMAGE, NULL)); +} diff --git a/plugins/bcm57xx/fu-bcm57xx-stage1-image.h b/plugins/bcm57xx/fu-bcm57xx-stage1-image.h new file mode 100644 index 000000000..c895a193a --- /dev/null +++ b/plugins/bcm57xx/fu-bcm57xx-stage1-image.h @@ -0,0 +1,14 @@ +/* + * Copyright (C) 2020 Richard Hughes + * + * SPDX-License-Identifier: LGPL-2.1+ + */ + +#pragma once + +#include "fu-firmware-image.h" + +#define FU_TYPE_BCM57XX_STAGE1_IMAGE (fu_bcm57xx_stage1_image_get_type ()) +G_DECLARE_FINAL_TYPE (FuBcm57xxStage1Image, fu_bcm57xx_stage1_image, FU, BCM57XX_STAGE1_IMAGE, FuFirmwareImage) + +FuFirmwareImage *fu_bcm57xx_stage1_image_new (void); diff --git a/plugins/bcm57xx/fu-bcm57xx-stage2-image.c b/plugins/bcm57xx/fu-bcm57xx-stage2-image.c new file mode 100644 index 000000000..f9c2f6fc4 --- /dev/null +++ b/plugins/bcm57xx/fu-bcm57xx-stage2-image.c @@ -0,0 +1,85 @@ +/* + * Copyright (C) 2020 Richard Hughes + * + * SPDX-License-Identifier: LGPL-2.1+ + */ + +#include "config.h" + +#include "fu-common.h" + +#include "fu-bcm57xx-common.h" +#include "fu-bcm57xx-stage2-image.h" + +struct _FuBcm57xxStage2Image { + FuFirmwareImage parent_instance; +}; + +G_DEFINE_TYPE (FuBcm57xxStage2Image, fu_bcm57xx_stage2_image, FU_TYPE_FIRMWARE_IMAGE) + +static gboolean +fu_bcm57xx_stage2_image_parse (FuFirmwareImage *image, + GBytes *fw, + FwupdInstallFlags flags, + GError **error) +{ + g_autoptr(GBytes) fw_nocrc = NULL; + if ((flags & FWUPD_INSTALL_FLAG_IGNORE_CHECKSUM) == 0) { + if (!fu_bcm57xx_verify_crc (fw, error)) + return FALSE; + } + fw_nocrc = g_bytes_new_from_bytes (fw, 0x0, g_bytes_get_size (fw) - sizeof(guint32)); + fu_firmware_image_set_bytes (image, fw_nocrc); + return TRUE; +} + +static GBytes * +fu_bcm57xx_stage2_image_write (FuFirmwareImage *image, GError **error) +{ + const guint8 *buf; + gsize bufsz = 0; + g_autoptr(GByteArray) blob = NULL; + g_autoptr(GBytes) fw_nocrc = NULL; + + /* get the CRC-less data */ + fw_nocrc = fu_firmware_image_get_bytes (image); + if (fw_nocrc == NULL) { + g_set_error_literal (error, + FWUPD_ERROR, + FWUPD_ERROR_NOT_SUPPORTED, + "not supported"); + return NULL; + } + + /* add to a mutable buffer */ + buf = g_bytes_get_data (fw_nocrc, &bufsz); + blob = g_byte_array_sized_new (bufsz + (sizeof(guint32) * 3)); + fu_byte_array_append_uint32 (blob, BCM_NVRAM_MAGIC, G_BIG_ENDIAN); + fu_byte_array_append_uint32 (blob, + g_bytes_get_size (fw_nocrc) + sizeof(guint32), + G_BIG_ENDIAN); + g_byte_array_append (blob, buf, bufsz); + + /* add CRC */ + fu_byte_array_append_uint32 (blob, fu_bcm57xx_nvram_crc (buf, bufsz), G_BIG_ENDIAN); + return g_byte_array_free_to_bytes (g_steal_pointer (&blob)); +} + +static void +fu_bcm57xx_stage2_image_init (FuBcm57xxStage2Image *self) +{ +} + +static void +fu_bcm57xx_stage2_image_class_init (FuBcm57xxStage2ImageClass *klass) +{ + FuFirmwareImageClass *klass_image = FU_FIRMWARE_IMAGE_CLASS (klass); + klass_image->parse = fu_bcm57xx_stage2_image_parse; + klass_image->write = fu_bcm57xx_stage2_image_write; +} + +FuFirmwareImage * +fu_bcm57xx_stage2_image_new (void) +{ + return FU_FIRMWARE_IMAGE (g_object_new (FU_TYPE_BCM57XX_STAGE2_IMAGE, NULL)); +} diff --git a/plugins/bcm57xx/fu-bcm57xx-stage2-image.h b/plugins/bcm57xx/fu-bcm57xx-stage2-image.h new file mode 100644 index 000000000..b971e1ace --- /dev/null +++ b/plugins/bcm57xx/fu-bcm57xx-stage2-image.h @@ -0,0 +1,14 @@ +/* + * Copyright (C) 2020 Richard Hughes + * + * SPDX-License-Identifier: LGPL-2.1+ + */ + +#pragma once + +#include "fu-firmware-image.h" + +#define FU_TYPE_BCM57XX_STAGE2_IMAGE (fu_bcm57xx_stage2_image_get_type ()) +G_DECLARE_FINAL_TYPE (FuBcm57xxStage2Image, fu_bcm57xx_stage2_image, FU, BCM57XX_STAGE2_IMAGE, FuFirmwareImage) + +FuFirmwareImage *fu_bcm57xx_stage2_image_new (void); diff --git a/plugins/bcm57xx/fu-plugin-bcm57xx.c b/plugins/bcm57xx/fu-plugin-bcm57xx.c new file mode 100644 index 000000000..a36f5f345 --- /dev/null +++ b/plugins/bcm57xx/fu-plugin-bcm57xx.c @@ -0,0 +1,29 @@ +/* + * Copyright (C) 2020 Richard Hughes + * + * SPDX-License-Identifier: LGPL-2.1+ + */ + +#include "config.h" + +#include "fu-plugin-vfuncs.h" +#include "fu-hash.h" + +#include "fu-bcm57xx-device.h" +#include "fu-bcm57xx-dict-image.h" +#include "fu-bcm57xx-firmware.h" +#include "fu-bcm57xx-stage1-image.h" +#include "fu-bcm57xx-stage2-image.h" + +void +fu_plugin_init (FuPlugin *plugin) +{ + fu_plugin_set_build_hash (plugin, FU_BUILD_HASH); + fu_plugin_add_udev_subsystem (plugin, "pci"); + fu_plugin_set_device_gtype (plugin, FU_TYPE_BCM57XX_DEVICE); + fu_plugin_add_firmware_gtype (plugin, "bcm57xx", FU_TYPE_BCM57XX_FIRMWARE); + fu_plugin_add_rule (plugin, FU_PLUGIN_RULE_BETTER_THAN, "optionrom"); + g_type_ensure (FU_TYPE_BCM57XX_DICT_IMAGE); + g_type_ensure (FU_TYPE_BCM57XX_STAGE1_IMAGE); + g_type_ensure (FU_TYPE_BCM57XX_STAGE2_IMAGE); +} diff --git a/plugins/bcm57xx/fu-self-test.c b/plugins/bcm57xx/fu-self-test.c new file mode 100644 index 000000000..ceaf77168 --- /dev/null +++ b/plugins/bcm57xx/fu-self-test.c @@ -0,0 +1,103 @@ +/* + * Copyright (C) 2020 Richard Hughes + * + * SPDX-License-Identifier: LGPL-2.1+ + */ + +#include "config.h" + +#include +#include + +#include "fu-common.h" +#include "fu-bcm57xx-common.h" +#include "fu-bcm57xx-firmware.h" + +static void +fu_bcm57xx_create_verbuf (guint8 *bufver, const gchar *version) +{ + memcpy (bufver, version, strlen (version) + 1); +} + +static void +fu_bcm57xx_common_veritem_func (void) +{ + g_autoptr(Bcm57xxVeritem) veritem1 = NULL; + g_autoptr(Bcm57xxVeritem) veritem2 = NULL; + g_autoptr(Bcm57xxVeritem) veritem3 = NULL; + guint8 bufver[16] = { 0x0 }; + + fu_bcm57xx_create_verbuf (bufver, "5719-v1.43"); + veritem1 = fu_bcm57xx_veritem_new (bufver, sizeof(bufver)); + g_assert_nonnull (veritem1); + g_assert_cmpstr (veritem1->version, ==, "1.43"); + g_assert_cmpstr (veritem1->branch, ==, BCM_FW_BRANCH_UNKNOWN); + g_assert_cmpint (veritem1->verfmt, ==, FWUPD_VERSION_FORMAT_PAIR); + + fu_bcm57xx_create_verbuf (bufver, "stage1-0.4.391"); + veritem2 = fu_bcm57xx_veritem_new (bufver, sizeof(bufver)); + g_assert_nonnull (veritem2); + g_assert_cmpstr (veritem2->version, ==, "0.4.391"); + g_assert_cmpstr (veritem2->branch, ==, BCM_FW_BRANCH_OSS_FIRMWARE); + g_assert_cmpint (veritem2->verfmt, ==, FWUPD_VERSION_FORMAT_TRIPLET); + + fu_bcm57xx_create_verbuf (bufver, "RANDOM-7"); + veritem3 = fu_bcm57xx_veritem_new (bufver, sizeof(bufver)); + g_assert_nonnull (veritem3); + g_assert_cmpstr (veritem3->version, ==, "RANDOM-7"); + g_assert_cmpstr (veritem3->branch, ==, BCM_FW_BRANCH_UNKNOWN); + g_assert_cmpint (veritem3->verfmt, ==, FWUPD_VERSION_FORMAT_UNKNOWN); +} + +static void +fu_bcm57xx_firmware_talos_func (void) +{ + gboolean ret; + g_autofree gchar *fn = NULL; + g_autofree gchar *fn_out = NULL; + g_autoptr(GBytes) blob = NULL; + g_autoptr(GBytes) blob_out = NULL; + g_autoptr(GError) error = NULL; + g_autoptr(GPtrArray) images = NULL; + g_autoptr(FuFirmware) firmware = fu_bcm57xx_firmware_new (); + + /* load file */ + fn = g_test_build_filename (G_TEST_DIST, "tests", "Bcm5719_talos.bin", NULL); + if (!g_file_test (fn, G_FILE_TEST_EXISTS)) { + g_test_skip ("missing file"); + return; + } + blob = fu_common_get_contents_bytes (fn, &error); + g_assert_no_error (error); + g_assert_nonnull (blob); + ret = fu_firmware_parse (firmware, blob, FWUPD_INSTALL_FLAG_NONE, &error); + g_assert_no_error (error); + g_assert_true (ret); + images = fu_firmware_get_images (firmware); + g_assert_cmpint (images->len, ==, 6); + + blob_out = fu_firmware_write (firmware, &error); + g_assert_no_error (error); + g_assert_nonnull (blob_out); + fn_out = g_test_build_filename (G_TEST_BUILT, "tests", "Bcm5719_talos.bin", NULL); + ret = fu_common_set_contents_bytes (fn_out, blob_out, &error); + g_assert_no_error (error); + g_assert_true (ret); + ret = fu_common_bytes_compare (blob, blob_out, &error); + g_assert_no_error (error); + g_assert_true (ret); +} + +int +main (int argc, char **argv) +{ + g_test_init (&argc, &argv, NULL); + + /* only critical and error are fatal */ + g_log_set_fatal_mask (NULL, G_LOG_LEVEL_ERROR | G_LOG_LEVEL_CRITICAL); + + /* tests go here */ + g_test_add_func ("/fwupd/bcm57xx/firmware{talos}", fu_bcm57xx_firmware_talos_func); + g_test_add_func ("/fwupd/bcm57xx/common{veritem}", fu_bcm57xx_common_veritem_func); + return g_test_run (); +} diff --git a/plugins/bcm57xx/meson.build b/plugins/bcm57xx/meson.build new file mode 100644 index 000000000..38cb196b8 --- /dev/null +++ b/plugins/bcm57xx/meson.build @@ -0,0 +1,64 @@ +cargs = ['-DG_LOG_DOMAIN="FuPluginBcm57xx"'] + +install_data(['bcm57xx.quirk'], + install_dir: join_paths(datadir, 'fwupd', 'quirks.d') +) +shared_module('fu_plugin_bcm57xx', + fu_hash, + sources : [ + 'fu-plugin-bcm57xx.c', + 'fu-bcm57xx-common.c', + 'fu-bcm57xx-device.c', + 'fu-bcm57xx-dict-image.c', + 'fu-bcm57xx-firmware.c', + 'fu-bcm57xx-recovery-device.c', + 'fu-bcm57xx-stage1-image.c', + 'fu-bcm57xx-stage2-image.c', + ], + include_directories : [ + root_incdir, + fwupd_incdir, + fwupdplugin_incdir, + ], + install : true, + install_dir: plugin_dir, + link_with : [ + fwupd, + fwupdplugin, + ], + c_args : cargs, + dependencies : [ + plugin_deps, + valgrind, + ], +) + +if get_option('tests') + e = executable( + 'bcm57xx-self-test', + fu_hash, + sources : [ + 'fu-self-test.c', + 'fu-bcm57xx-common.c', + 'fu-bcm57xx-dict-image.c', + 'fu-bcm57xx-firmware.c', + 'fu-bcm57xx-stage1-image.c', + 'fu-bcm57xx-stage2-image.c', + ], + include_directories : [ + root_incdir, + fwupd_incdir, + fwupdplugin_incdir, + ], + dependencies : [ + plugin_deps, + ], + link_with : [ + fwupd, + fwupdplugin, + ], + install : true, + install_dir : installed_test_bindir, + ) + test('ata-self-test', e) +endif diff --git a/plugins/meson.build b/plugins/meson.build index 15179bbaa..132bc34ad 100644 --- a/plugins/meson.build +++ b/plugins/meson.build @@ -1,5 +1,6 @@ subdir('acpi-dmar') subdir('acpi-facp') +subdir('bcm57xx') subdir('bios') subdir('ccgx') subdir('cros-ec') From 44361fa14e12935c6666b4ea73c8499e19cab3ac Mon Sep 17 00:00:00 2001 From: Evan Lojewski Date: Thu, 8 Oct 2020 21:29:23 -0600 Subject: [PATCH 517/607] bcm57xx: Improve reliability when flashing - Use pci function 0 instead of 1 when flashing firmware. In certain situations, the BCM5719 NVM controller can lockup if a function other than 0 is used to read from NVM word-by-word like the kernel driver does. - Fix APE_MODE offset in BAR[2] to enable proper resetting of the APE. - Remove unnededed NVRam lock when resetting the APE. Signed-off-by: Evan Lojewski --- plugins/bcm57xx/fu-bcm57xx-device.c | 6 +++--- plugins/bcm57xx/fu-bcm57xx-recovery-device.c | 17 +---------------- 2 files changed, 4 insertions(+), 19 deletions(-) diff --git a/plugins/bcm57xx/fu-bcm57xx-device.c b/plugins/bcm57xx/fu-bcm57xx-device.c index b416ce19f..c47974f76 100644 --- a/plugins/bcm57xx/fu-bcm57xx-device.c +++ b/plugins/bcm57xx/fu-bcm57xx-device.c @@ -53,12 +53,12 @@ fu_bcm57xx_device_probe (FuUdevDevice *device, GError **error) g_autofree gchar *fn = NULL; g_autoptr(GPtrArray) ifaces = NULL; - /* only enumerate number 1 */ - if (fu_udev_device_get_number (device) != 1) { + /* only enumerate number 0 */ + if (fu_udev_device_get_number (device) != 0) { g_set_error_literal (error, FWUPD_ERROR, FWUPD_ERROR_NOT_SUPPORTED, - "only device 1 supported on multi-device card"); + "only device 0 supported on multi-device card"); return FALSE; } diff --git a/plugins/bcm57xx/fu-bcm57xx-recovery-device.c b/plugins/bcm57xx/fu-bcm57xx-recovery-device.c index 34ff27af3..cede4a319 100644 --- a/plugins/bcm57xx/fu-bcm57xx-recovery-device.c +++ b/plugins/bcm57xx/fu-bcm57xx-recovery-device.c @@ -36,7 +36,7 @@ #define REG_NVM_WRITE 0x7008 /* offsets into BAR[2] */ -#define REG_APE_MODE 0x10000 +#define REG_APE_MODE 0x0 typedef struct { guint8 *buf; @@ -418,21 +418,6 @@ fu_bcm57xx_recovery_device_activate (FuDevice *device, GError **error) { BcmRegAPEMode mode = { 0 }; FuBcm57xxRecoveryDevice *self = FU_BCM57XX_RECOVERY_DEVICE (device); - g_autoptr(FuDeviceLocker) locker = NULL; - g_autoptr(FuDeviceLocker) locker2 = NULL; - - locker = fu_device_locker_new_full (self, - (FuDeviceLockerFunc) fu_bcm57xx_recovery_device_nvram_acquire_lock, - (FuDeviceLockerFunc) fu_bcm57xx_recovery_device_nvram_release_lock, - error); - if (locker == NULL) - return FALSE; - locker2 = fu_device_locker_new_full (self, - (FuDeviceLockerFunc) fu_bcm57xx_recovery_device_nvram_enable, - (FuDeviceLockerFunc) fu_bcm57xx_recovery_device_nvram_disable, - error); - if (locker2 == NULL) - return FALSE; /* halt */ mode.bits.Halt = 1; From acd95c661b05ea266b884395c8160b0643a1c140 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=89rico=20Rolim?= Date: Fri, 9 Oct 2020 21:00:41 -0300 Subject: [PATCH 518/607] uefi: add configuration option for objcopy utility. --- meson.build | 2 ++ meson_options.txt | 1 + .../efi/{generate_binary.sh => generate_binary.sh.in} | 2 +- plugins/uefi/efi/meson.build | 11 +++++++++-- 4 files changed, 13 insertions(+), 3 deletions(-) rename plugins/uefi/efi/{generate_binary.sh => generate_binary.sh.in} (92%) diff --git a/meson.build b/meson.build index 8a2be56c0..cd4d7e708 100644 --- a/meson.build +++ b/meson.build @@ -316,6 +316,8 @@ if build_standalone and get_option('plugin_uefi') efi_app_location = join_paths(libexecdir, 'fwupd', 'efi') conf.set_quoted ('EFI_APP_LOCATION', efi_app_location) + conf.set('EFI_OBJCOPY', get_option('efi-objcopy')) + if host_cpu == 'x86' EFI_MACHINE_TYPE_NAME = 'ia32' gnu_efi_arch = 'ia32' diff --git a/meson_options.txt b/meson_options.txt index bedb929dd..ecef6dc92 100644 --- a/meson_options.txt +++ b/meson_options.txt @@ -29,6 +29,7 @@ option('tpm', type : 'boolean', value : true, description : 'enable TPM support' option('udevdir', type: 'string', value: '', description: 'Directory for udev rules') option('efi-cc', type : 'string', value : 'gcc', description : 'the compiler to use for EFI modules') option('efi-ld', type : 'string', value : 'ld', description : 'the linker to use for EFI modules') +option('efi-objcopy', type : 'string', value : 'objcopy', description : 'the objcopy utility to use for EFI modules') option('efi-libdir', type : 'string', description : 'path to the EFI lib directory') option('efi-ldsdir', type : 'string', description : 'path to the EFI lds directory') option('efi-includedir', type : 'string', value : '/usr/include/efi', description : 'path to the EFI header directory') diff --git a/plugins/uefi/efi/generate_binary.sh b/plugins/uefi/efi/generate_binary.sh.in similarity index 92% rename from plugins/uefi/efi/generate_binary.sh rename to plugins/uefi/efi/generate_binary.sh.in index 8c27867d9..606362068 100755 --- a/plugins/uefi/efi/generate_binary.sh +++ b/plugins/uefi/efi/generate_binary.sh.in @@ -1,6 +1,6 @@ #!/bin/sh output=$2 -objcopy_cmd=$(command -v objcopy) +objcopy_cmd=$(command -v @EFI_OBJCOPY@) genpeimg_cmd=$(command -v genpeimg) "$objcopy_cmd" -j .text \ diff --git a/plugins/uefi/efi/meson.build b/plugins/uefi/efi/meson.build index d834e6267..70eb726a7 100644 --- a/plugins/uefi/efi/meson.build +++ b/plugins/uefi/efi/meson.build @@ -1,5 +1,6 @@ efi_cc = get_option('efi-cc') efi_ld = get_option('efi-ld') +efi_objcopy = get_option('efi-objcopy') efi_ldsdir = get_option('efi-ldsdir') efi_incdir = get_option('efi-includedir') @@ -153,7 +154,13 @@ so = custom_target('fwup.so', efi_ldflags + ['@INPUT@'] + ['-lefi', '-lgnuefi', libgcc_file_name]) -build_tool = join_paths(meson.source_root(), 'plugins', 'uefi', 'efi', 'generate_binary.sh') +configure_file( + input : 'generate_binary.sh.in', + output : 'generate_binary.sh', + configuration : conf +) + +build_tool = join_paths(meson.current_build_dir(), 'generate_binary.sh') app = custom_target(efi_name, input : so, output : efi_name, @@ -164,7 +171,7 @@ app = custom_target(efi_name, dbg = custom_target('efi_debug', input : so, output : efi_name + '.debug', - command : [objcopy, + command : [efi_objcopy, '-j', '.text', '-j', '.sdata', '-j', '.data', From 0651aeef24a7330659febbf5e8fbc1b78283e7a2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=89rico=20Rolim?= Date: Fri, 9 Oct 2020 21:31:07 -0300 Subject: [PATCH 519/607] Fix header names. - should be - should be --- libfwupdplugin/fu-udev-device.c | 2 +- meson.build | 2 +- src/fu-polkit-agent.c | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/libfwupdplugin/fu-udev-device.c b/libfwupdplugin/fu-udev-device.c index beef46da9..f79cc0d35 100644 --- a/libfwupdplugin/fu-udev-device.c +++ b/libfwupdplugin/fu-udev-device.c @@ -11,7 +11,7 @@ #include #include #ifdef HAVE_ERRNO_H -#include +#include #endif #ifdef HAVE_IOCTL_H #include diff --git a/meson.build b/meson.build index cd4d7e708..b747a1f2f 100644 --- a/meson.build +++ b/meson.build @@ -254,7 +254,7 @@ endif if cc.has_header('sys/ioctl.h') conf.set('HAVE_IOCTL_H', '1') endif -if cc.has_header('sys/errno.h') +if cc.has_header('errno.h') conf.set('HAVE_ERRNO_H', '1') endif if cc.has_header('sys/socket.h') diff --git a/src/fu-polkit-agent.c b/src/fu-polkit-agent.c index 7db8c1bec..afe721ae0 100644 --- a/src/fu-polkit-agent.c +++ b/src/fu-polkit-agent.c @@ -22,7 +22,7 @@ #include #include #include -#include +#include #include #include From cc2f6aa1b282798aeecc5aaa0b85aa0105eda0d6 Mon Sep 17 00:00:00 2001 From: Richard Hughes Date: Sat, 10 Oct 2020 15:33:55 +0100 Subject: [PATCH 520/607] Add fu_device_sleep_with_progress helper() This makes the console a bit more helpful than just 'hanging'... --- libfwupdplugin/fu-device.c | 26 +++++++++++++++++++++++ libfwupdplugin/fu-device.h | 2 ++ libfwupdplugin/fwupdplugin.map | 1 + plugins/bcm57xx/fu-bcm57xx-device.c | 3 +-- plugins/dfu/dfu-device.c | 2 +- plugins/rts54hid/fu-rts54hid-device.c | 2 +- plugins/vli/fu-vli-device.c | 2 +- plugins/vli/fu-vli-usbhub-msp430-device.c | 3 +-- plugins/wacom-raw/fu-wacom-aes-device.c | 2 +- 9 files changed, 35 insertions(+), 8 deletions(-) diff --git a/libfwupdplugin/fu-device.c b/libfwupdplugin/fu-device.c index adff698dc..cb6d6a3c4 100644 --- a/libfwupdplugin/fu-device.c +++ b/libfwupdplugin/fu-device.c @@ -2250,6 +2250,32 @@ fu_device_set_progress_full (FuDevice *self, gsize progress_done, gsize progress fu_device_set_progress (self, (guint) percentage); } +/** + * fu_device_sleep_with_progress: + * @self: A #FuDevice + * @delay_secs: the delay in seconds + * + * Sleeps, setting the device progress from 0..100% as time continues. + * The value is gven in whole seconds as it does not make sense to show the + * progressbar advancing so quickly for durations of less than one second. + * + * Since: 1.5.0 + **/ +void +fu_device_sleep_with_progress (FuDevice *self, guint delay_secs) +{ + gulong delay_us_pc = (delay_secs * G_USEC_PER_SEC) / 100; + + g_return_if_fail (FU_IS_DEVICE (self)); + g_return_if_fail (delay_secs > 0); + + fu_device_set_progress (self, 0); + for (guint i = 0; i < 100; i++) { + g_usleep (delay_us_pc); + fu_device_set_progress (self, i + 1); + } +} + static void fu_device_add_string (FuDevice *self, guint idt, GString *str) { diff --git a/libfwupdplugin/fu-device.h b/libfwupdplugin/fu-device.h index 2b389e659..376a27db5 100644 --- a/libfwupdplugin/fu-device.h +++ b/libfwupdplugin/fu-device.h @@ -273,6 +273,8 @@ void fu_device_set_progress (FuDevice *self, void fu_device_set_progress_full (FuDevice *self, gsize progress_done, gsize progress_total); +void fu_device_sleep_with_progress (FuDevice *self, + guint delay_secs); void fu_device_set_quirks (FuDevice *self, FuQuirks *quirks); FuQuirks *fu_device_get_quirks (FuDevice *self); diff --git a/libfwupdplugin/fwupdplugin.map b/libfwupdplugin/fwupdplugin.map index d7c1d5222..3242e4cfa 100644 --- a/libfwupdplugin/fwupdplugin.map +++ b/libfwupdplugin/fwupdplugin.map @@ -623,6 +623,7 @@ LIBFWUPDPLUGIN_1.5.0 { fu_device_dump_firmware; fu_device_report_metadata_post; fu_device_report_metadata_pre; + fu_device_sleep_with_progress; fu_device_unbind_driver; fu_efivar_secure_boot_enabled_full; fu_firmware_add_flag; diff --git a/plugins/bcm57xx/fu-bcm57xx-device.c b/plugins/bcm57xx/fu-bcm57xx-device.c index c47974f76..8bee27df3 100644 --- a/plugins/bcm57xx/fu-bcm57xx-device.c +++ b/plugins/bcm57xx/fu-bcm57xx-device.c @@ -318,8 +318,7 @@ fu_bcm57xx_device_activate (FuDevice *device, GError **error) /* wait for the device to restart before calling reload() */ fu_device_set_status (device, FWUPD_STATUS_DEVICE_BUSY); - fu_device_set_progress (device, 0); - g_usleep (G_USEC_PER_SEC * 5); + fu_device_sleep_with_progress (device, 5); /* seconds */ return TRUE; } diff --git a/plugins/dfu/dfu-device.c b/plugins/dfu/dfu-device.c index 7fe9fb6cd..c3b977a6a 100644 --- a/plugins/dfu/dfu-device.c +++ b/plugins/dfu/dfu-device.c @@ -1270,7 +1270,7 @@ dfu_device_probe (FuUsbDevice *device, GError **error) /* hardware rom Jabra literally reboots if you try to retry a failed * write -- there's no way to avoid blocking the daemon like this... */ if (fu_device_has_custom_flag (FU_DEVICE (device), "attach-extra-reset")) - g_usleep (10 * G_USEC_PER_SEC); + fu_device_sleep_with_progress (FU_DEVICE (self), 10); /* seconds */ /* success */ return TRUE; diff --git a/plugins/rts54hid/fu-rts54hid-device.c b/plugins/rts54hid/fu-rts54hid-device.c index 0592dd425..1a3c9c0bc 100644 --- a/plugins/rts54hid/fu-rts54hid-device.c +++ b/plugins/rts54hid/fu-rts54hid-device.c @@ -132,7 +132,7 @@ fu_rts54hid_device_verify_update_fw (FuRts54HidDevice *self, GError **error) FU_HID_DEVICE_FLAG_NONE, error)) return FALSE; - g_usleep (4 * G_USEC_PER_SEC); + fu_device_sleep_with_progress (FU_DEVICE (self), 4); /* seconds */ if (!fu_hid_device_get_report (FU_HID_DEVICE (self), 0x0, buf, sizeof(buf), FU_RTS54HID_DEVICE_TIMEOUT, FU_HID_DEVICE_FLAG_NONE, diff --git a/plugins/vli/fu-vli-device.c b/plugins/vli/fu-vli-device.c index d431e294e..a2a9ff213 100644 --- a/plugins/vli/fu-vli-device.c +++ b/plugins/vli/fu-vli-device.c @@ -370,7 +370,7 @@ fu_vli_device_spi_erase_all (FuVliDevice *self, GError **error) return FALSE; if (!fu_vli_device_spi_chip_erase (self, error)) return FALSE; - g_usleep (4 * G_USEC_PER_SEC); + fu_device_sleep_with_progress (FU_DEVICE (self), 4); /* seconds */ /* verify chip was erased */ for (guint addr = 0; addr < 0x10000; addr += 0x1000) { diff --git a/plugins/vli/fu-vli-usbhub-msp430-device.c b/plugins/vli/fu-vli-usbhub-msp430-device.c index 49ca4de45..ec5637b74 100644 --- a/plugins/vli/fu-vli-usbhub-msp430-device.c +++ b/plugins/vli/fu-vli-usbhub-msp430-device.c @@ -149,8 +149,7 @@ fu_vli_usbhub_msp430_device_detach (FuDevice *device, GError **error) /* avoid power instability by waiting T1 */ fu_device_set_status (device, FWUPD_STATUS_DEVICE_RESTART); - fu_device_set_progress (device, 0); - g_usleep (G_USEC_PER_SEC); + fu_device_sleep_with_progress (device, 1); /* seconds */ /* check the device came back */ if (!fu_vli_usbhub_device_i2c_read_status (parent, &status, error)) { diff --git a/plugins/wacom-raw/fu-wacom-aes-device.c b/plugins/wacom-raw/fu-wacom-aes-device.c index 033a65004..61d11bcab 100644 --- a/plugins/wacom-raw/fu-wacom-aes-device.c +++ b/plugins/wacom-raw/fu-wacom-aes-device.c @@ -164,7 +164,7 @@ fu_wacom_aes_device_erase_all (FuWacomAesDevice *self, GError **error) g_prefix_error (error, "failed to send eraseall command: "); return FALSE; } - g_usleep (2 * G_USEC_PER_SEC); + fu_device_sleep_with_progress (FU_DEVICE (self), 2); /* seconds */ return TRUE; } From b093de999a3c0bca2341dc742aa37b13adbba28a Mon Sep 17 00:00:00 2001 From: Benson Leung Date: Wed, 7 Oct 2020 21:07:58 -0700 Subject: [PATCH 521/607] cros-ec: Fix reboot to RO sequence Previously, we sent a 'stay-in-ro' subcommand when we are in fu_cros_ec_usb_device_reset_to_ro, which is called from the detach phase, in other words, we are currently sitting in RW. This is incorrect, since stay-in-ro only interrupts an RO's rw_sig process if it is in progress. Instead, 'stay-in-ro' must be issued when the device reenumerates in RO, immediately before the writing sequence starts. On devices that implement rw_sig, they will briefly enumerate as RO before self-issuing a jump to RW on the signature check being valid. In order to stay in RO to perform a RW partition update, we must interrupt it as soon as we see the RO version enumerate. --- plugins/cros-ec/fu-cros-ec-usb-device.c | 50 +++++++++++++++++-------- 1 file changed, 34 insertions(+), 16 deletions(-) diff --git a/plugins/cros-ec/fu-cros-ec-usb-device.c b/plugins/cros-ec/fu-cros-ec-usb-device.c index 24864aa39..5bb55a8d8 100644 --- a/plugins/cros-ec/fu-cros-ec-usb-device.c +++ b/plugins/cros-ec/fu-cros-ec-usb-device.c @@ -641,19 +641,12 @@ static gboolean fu_cros_ec_usb_device_reset_to_ro (FuDevice *device, GError **error) { guint8 response; - guint16 subcommand = UPDATE_EXTRA_CMD_STAY_IN_RO; + guint16 subcommand = UPDATE_EXTRA_CMD_IMMEDIATE_RESET; guint8 command_body[2]; /* Max command body size. */ gsize command_body_size = 0; gsize response_size = 1; - /* send subcommand to remain in RO */ - if (!fu_cros_ec_usb_device_send_subcommand (device, subcommand, command_body, - command_body_size, &response, - &response_size, FALSE, error)) - return FALSE; - - response_size = 1; - subcommand = UPDATE_EXTRA_CMD_IMMEDIATE_RESET; + fu_device_set_custom_flags (device, "rebooting-to-ro"); if (!fu_cros_ec_usb_device_send_subcommand (device, subcommand, command_body, command_body_size, &response, &response_size, FALSE, error)) { @@ -694,6 +687,23 @@ fu_cros_ec_usb_device_write_firmware (FuDevice *device, FuCrosEcFirmware *cros_ec_firmware = FU_CROS_EC_FIRMWARE (firmware); gint num_txed_sections = 0; + if (fu_device_has_custom_flag (device, "rebooting-to-ro")) { + gsize response_size = 1; + guint8 response; + guint16 subcommand = UPDATE_EXTRA_CMD_STAY_IN_RO; + guint8 command_body[2]; /* Max command body size. */ + gsize command_body_size = 0; + + if (!fu_cros_ec_usb_device_send_subcommand (device, subcommand, command_body, + command_body_size, &response, + &response_size, FALSE, error)) { + /* failure here is ok */ + g_clear_error (error); + } + /* clear custom flags */ + fu_device_set_custom_flags (device, ""); + } + sections = fu_cros_ec_firmware_get_sections (cros_ec_firmware); if (sections == NULL) { g_set_error_literal (error, @@ -812,18 +822,26 @@ fu_cros_ec_usb_device_attach (FuDevice *device, GError **error) } static gboolean -fu_cros_ec_usb_device_detach (FuDevice *self, GError **error) +fu_cros_ec_usb_device_detach (FuDevice *device, GError **error) { - if (fu_device_has_custom_flag (self, "rw-written") && - !fu_device_has_custom_flag (self, "ro-written")) + FuCrosEcUsbDevice *self = FU_CROS_EC_USB_DEVICE (device); + + if (fu_device_has_custom_flag (device, "rw-written") && + !fu_device_has_custom_flag (device, "ro-written")) return TRUE; - fu_device_set_remove_delay (self, FU_DEVICE_REMOVE_DELAY_RE_ENUMERATE); - if (!fu_cros_ec_usb_device_reset_to_ro (self, error)) + if (self->in_bootloader) { + g_debug ("skipping immediate reboot in case of already in bootloader"); + /* already in ro so skip reboot */ + return TRUE; + } + + fu_device_set_remove_delay (device, FU_DEVICE_REMOVE_DELAY_RE_ENUMERATE); + if (!fu_cros_ec_usb_device_reset_to_ro (device, error)) return FALSE; - fu_device_set_status (self, FWUPD_STATUS_DEVICE_RESTART); - fu_device_add_flag (self, FWUPD_DEVICE_FLAG_WAIT_FOR_REPLUG); + fu_device_set_status (device, FWUPD_STATUS_DEVICE_RESTART); + fu_device_add_flag (device, FWUPD_DEVICE_FLAG_WAIT_FOR_REPLUG); /* success */ return TRUE; From 08c396b31c62892c9d6fd2a9fc7247d326397276 Mon Sep 17 00:00:00 2001 From: Benson Leung Date: Wed, 5 Aug 2020 19:15:08 -0700 Subject: [PATCH 522/607] cros-ec: Send an immediate reset after jump to rw Some devices don't do the jump, so an immediate reset is required to get us into RW. --- plugins/cros-ec/fu-cros-ec-usb-device.c | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-) diff --git a/plugins/cros-ec/fu-cros-ec-usb-device.c b/plugins/cros-ec/fu-cros-ec-usb-device.c index 5bb55a8d8..8cfff2c03 100644 --- a/plugins/cros-ec/fu-cros-ec-usb-device.c +++ b/plugins/cros-ec/fu-cros-ec-usb-device.c @@ -668,9 +668,19 @@ fu_cros_ec_usb_device_jump_to_rw (FuDevice *device) gsize command_body_size = 0; gsize response_size = 1; - fu_cros_ec_usb_device_send_subcommand (device, subcommand, command_body, - command_body_size, &response, - &response_size, FALSE, NULL); + if (!fu_cros_ec_usb_device_send_subcommand (device, subcommand, command_body, + command_body_size, &response, + &response_size, FALSE, NULL)) { + /* bail out early here if subcommand failed, which is normal */ + return TRUE; + } + + /* Jump to rw may not work, so if we've reached here, initiate a + * full reset using immediate reset */ + subcommand = UPDATE_EXTRA_CMD_IMMEDIATE_RESET; + fu_cros_ec_usb_device_send_subcommand (device, subcommand, command_body, + command_body_size, &response, + &response_size, FALSE, NULL); /* success */ return TRUE; From c5167242780ec6411441a240645a6936e4dabd0d Mon Sep 17 00:00:00 2001 From: Benson Leung Date: Wed, 12 Aug 2020 20:50:00 -0700 Subject: [PATCH 523/607] cros-ec: Set another write required if we immediate reset back into RO As a result of the previous change, where we send an immediate reset to devices in order to transition back to rw, we will end up reenumerating as RO briefly, although the destination we wanted to get to was RW. In that case, basically skip the write firmware step, set another write required and allow the RO firmware to complete rw_sig and jump to the rw partition. --- plugins/cros-ec/fu-cros-ec-usb-device.c | 27 +++++++++++++++++++++++++ 1 file changed, 27 insertions(+) diff --git a/plugins/cros-ec/fu-cros-ec-usb-device.c b/plugins/cros-ec/fu-cros-ec-usb-device.c index 8cfff2c03..62bdf1002 100644 --- a/plugins/cros-ec/fu-cros-ec-usb-device.c +++ b/plugins/cros-ec/fu-cros-ec-usb-device.c @@ -712,6 +712,26 @@ fu_cros_ec_usb_device_write_firmware (FuDevice *device, } /* clear custom flags */ fu_device_set_custom_flags (device, ""); + + /* flush all data from endpoint to recover in case of error */ + if (!fu_device_retry (device, fu_cros_ec_usb_device_flush, + SETUP_RETRY_CNT, NULL, error)) { + g_prefix_error (error, "failed to flush device to idle state: "); + return FALSE; + } + } + + if (fu_device_has_custom_flag (device, "rw-written") && self->in_bootloader) { + /* + * we had previously written to the rw region but somehow + * ended back up here while still in bootloader; this is + * a transitory state due to the fact that we have to boot + * through RO to get to RW. Set another write required to + * allow the RO region to auto-jump to RW + */ + fu_device_set_custom_flags (device, "special,rw-written"); + fu_device_add_flag (device, FWUPD_DEVICE_FLAG_ANOTHER_WRITE_REQUIRED); + return TRUE; } sections = fu_cros_ec_firmware_get_sections (cros_ec_firmware); @@ -816,6 +836,13 @@ fu_cros_ec_usb_device_attach (FuDevice *device, GError **error) { FuCrosEcUsbDevice *self = FU_CROS_EC_USB_DEVICE (device); + if (self->in_bootloader && fu_device_has_custom_flag (device, "special")) { + fu_device_set_remove_delay (device, FU_DEVICE_REMOVE_DELAY_RE_ENUMERATE); + fu_device_set_status (device, FWUPD_STATUS_DEVICE_RESTART); + fu_device_add_flag (device, FWUPD_DEVICE_FLAG_WAIT_FOR_REPLUG); + return TRUE; + } + if (!self->in_bootloader) { /* already in rw, so skip jump to rw */ return TRUE; From af07f32c0f52f28d929a7eea9b3db2710c1c55dd Mon Sep 17 00:00:00 2001 From: Benson Leung Date: Wed, 19 Aug 2020 17:03:31 -0700 Subject: [PATCH 524/607] cros-ec: Send a start message after the stay-in-ro The extra command (stay-in-ro) consumes the start message, so we need to issue another one before write firmware. --- plugins/cros-ec/fu-cros-ec-usb-device.c | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/plugins/cros-ec/fu-cros-ec-usb-device.c b/plugins/cros-ec/fu-cros-ec-usb-device.c index 62bdf1002..60b245783 100644 --- a/plugins/cros-ec/fu-cros-ec-usb-device.c +++ b/plugins/cros-ec/fu-cros-ec-usb-device.c @@ -703,12 +703,13 @@ fu_cros_ec_usb_device_write_firmware (FuDevice *device, guint16 subcommand = UPDATE_EXTRA_CMD_STAY_IN_RO; guint8 command_body[2]; /* Max command body size. */ gsize command_body_size = 0; + START_RESP start_resp; if (!fu_cros_ec_usb_device_send_subcommand (device, subcommand, command_body, command_body_size, &response, &response_size, FALSE, error)) { - /* failure here is ok */ - g_clear_error (error); + g_prefix_error (error, "failed to send stay-in-ro subcommand: "); + return FALSE; } /* clear custom flags */ fu_device_set_custom_flags (device, ""); @@ -719,6 +720,13 @@ fu_cros_ec_usb_device_write_firmware (FuDevice *device, g_prefix_error (error, "failed to flush device to idle state: "); return FALSE; } + + /* send start request */ + if (!fu_device_retry (device, fu_cros_ec_usb_device_start_request, + SETUP_RETRY_CNT, &start_resp, error)) { + g_prefix_error (error, "failed to send start request: "); + return FALSE; + } } if (fu_device_has_custom_flag (device, "rw-written") && self->in_bootloader) { From 2c5558e51d4d553f3959fba06fd0c05280e31846 Mon Sep 17 00:00:00 2001 From: Benson Leung Date: Fri, 28 Aug 2020 18:19:44 -0700 Subject: [PATCH 525/607] cros-ec: Log error paths, and trigger flushes In case of a failure during the bulk transfer sequence, flush out before trying again. --- plugins/cros-ec/fu-cros-ec-usb-device.c | 45 ++++++++++++++++++++----- 1 file changed, 36 insertions(+), 9 deletions(-) diff --git a/plugins/cros-ec/fu-cros-ec-usb-device.c b/plugins/cros-ec/fu-cros-ec-usb-device.c index 60b245783..0ea509723 100644 --- a/plugins/cros-ec/fu-cros-ec-usb-device.c +++ b/plugins/cros-ec/fu-cros-ec-usb-device.c @@ -264,6 +264,20 @@ fu_cros_ec_usb_device_flush (FuDevice *device, gpointer user_data, return TRUE; } +static gboolean +fu_cros_ec_usb_device_recovery (FuDevice *device, GError **error) +{ + /* flush all data from endpoint to recover in case of error */ + if (!fu_device_retry (device, fu_cros_ec_usb_device_flush, + SETUP_RETRY_CNT, NULL, error)) { + g_prefix_error (error, "failed to flush device to idle state: "); + return FALSE; + } + + /* success */ + return TRUE; +} + /* * Channel TPM extension/vendor command over USB. The payload of the USB frame * in this case consists of the 2 byte subcommand code concatenated with the @@ -341,12 +355,8 @@ fu_cros_ec_usb_device_setup (FuDevice *device, GError **error) START_RESP start_resp; g_auto(GStrv) config_split = NULL; - /* flush all data from endpoint to recover in case of error */ - if (!fu_device_retry (device, fu_cros_ec_usb_device_flush, - SETUP_RETRY_CNT, NULL, error)) { - g_prefix_error (error, "failed to flush device to idle state: "); + if (!fu_cros_ec_usb_device_recovery (device, error)) return FALSE; - } /* send start request */ if (!fu_device_retry (device, fu_cros_ec_usb_device_start_request, @@ -481,8 +491,14 @@ fu_cros_ec_usb_device_transfer_block (FuDevice *device, gpointer user_data, sizeof(struct update_frame_header), NULL, 0, FALSE, - NULL, error)) + NULL, error)) { + /* flush all data from endpoint to recover in case of error */ + if (!fu_cros_ec_usb_device_recovery (device, NULL)) { + g_debug ("failed to flush to idle"); + } + g_prefix_error (error, "failed at sending header: "); return FALSE; + } /* send the block, chunk by chunk */ for (guint i = 0; i < chunks->len; i++) { @@ -494,6 +510,12 @@ fu_cros_ec_usb_device_transfer_block (FuDevice *device, gpointer user_data, NULL, 0, FALSE, NULL, error)) { + g_prefix_error (error, "failed at sending chunk: "); + + /* flush all data from endpoint to recover in case of error */ + if (!fu_cros_ec_usb_device_recovery (device, NULL)) { + g_debug ("failed to flush to idle"); + } return FALSE; } } @@ -501,8 +523,14 @@ fu_cros_ec_usb_device_transfer_block (FuDevice *device, gpointer user_data, /* get the reply */ if (!fu_cros_ec_usb_device_do_xfer (self, NULL, 0, (guint8 *)&reply, sizeof (reply), - TRUE, &transfer_size, error)) + TRUE, &transfer_size, error)) { + g_prefix_error (error, "failed at reply: "); + /* flush all data from endpoint to recover in case of error */ + if (!fu_cros_ec_usb_device_recovery (device, NULL)) { + g_debug ("failed to flush to idle"); + } return FALSE; + } if (transfer_size == 0) { g_set_error_literal (error, G_IO_ERROR, @@ -715,8 +743,7 @@ fu_cros_ec_usb_device_write_firmware (FuDevice *device, fu_device_set_custom_flags (device, ""); /* flush all data from endpoint to recover in case of error */ - if (!fu_device_retry (device, fu_cros_ec_usb_device_flush, - SETUP_RETRY_CNT, NULL, error)) { + if (!fu_cros_ec_usb_device_recovery (device, error)) { g_prefix_error (error, "failed to flush device to idle state: "); return FALSE; } From e8fd2cdfa46cbf3decc6a48310b4a8aef244435b Mon Sep 17 00:00:00 2001 From: Benson Leung Date: Thu, 17 Sep 2020 16:55:40 -0700 Subject: [PATCH 526/607] cros-ec: Restructure to allow RO update first Our update flow prior to this was: 1. On detach, reboot to RO. 2. From Old RO, Update RW. 3. Reboot to New RW 4. From New RW, Update RO. 5. Reboot to finish This flow has a flaw, which is that the Old RO may be buggy (especially during development, before it's actually locked down and actually Read-Only). This change will do the following instead: 1. On detach, do not reboot to RO if RO is writeable, and we are in RW 2. From old RW, Update RO 3. Reboot to new RO 4. From New RO, update RW 5. Reboot to finish. This has a speed advantage as well, as we save one reboot cycle (2 vs 3). --- plugins/cros-ec/fu-cros-ec-usb-device.c | 58 +++++++++++++++---------- 1 file changed, 34 insertions(+), 24 deletions(-) diff --git a/plugins/cros-ec/fu-cros-ec-usb-device.c b/plugins/cros-ec/fu-cros-ec-usb-device.c index 0ea509723..ee025ea0d 100644 --- a/plugins/cros-ec/fu-cros-ec-usb-device.c +++ b/plugins/cros-ec/fu-cros-ec-usb-device.c @@ -674,7 +674,10 @@ fu_cros_ec_usb_device_reset_to_ro (FuDevice *device, GError **error) gsize command_body_size = 0; gsize response_size = 1; - fu_device_set_custom_flags (device, "rebooting-to-ro"); + if (fu_device_has_custom_flag (device, "ro-written")) + fu_device_set_custom_flags (device, "ro-written,rebooting-to-ro"); + else + fu_device_set_custom_flags (device, "rebooting-to-ro"); if (!fu_cros_ec_usb_device_send_subcommand (device, subcommand, command_body, command_body_size, &response, &response_size, FALSE, error)) { @@ -739,8 +742,6 @@ fu_cros_ec_usb_device_write_firmware (FuDevice *device, g_prefix_error (error, "failed to send stay-in-ro subcommand: "); return FALSE; } - /* clear custom flags */ - fu_device_set_custom_flags (device, ""); /* flush all data from endpoint to recover in case of error */ if (!fu_cros_ec_usb_device_recovery (device, error)) { @@ -811,16 +812,22 @@ fu_cros_ec_usb_device_write_firmware (FuDevice *device, return FALSE; } - if (self->in_bootloader) - fu_device_set_custom_flags (device, "rw-written"); - else if (fu_device_has_custom_flag (device, "rw-written")) + if (self->in_bootloader) { + if (fu_device_has_custom_flag (device, "ro-written")) + fu_device_set_custom_flags (device, "ro-written,rw-written"); + else + fu_device_set_custom_flags (device, "rw-written"); + } else if (fu_device_has_custom_flag (device, "rw-written")) { fu_device_set_custom_flags (device, "ro-written,rw-written"); - else + } else { fu_device_set_custom_flags (device, "ro-written"); + } - if (fu_device_has_custom_flag (device, "rw-written") && - !fu_device_has_custom_flag (device, "ro-written")) + /* logical XOR */ + if (fu_device_has_custom_flag (device, "rw-written") != + fu_device_has_custom_flag (device, "ro-written")) fu_device_add_flag (device, FWUPD_DEVICE_FLAG_ANOTHER_WRITE_REQUIRED); + /* success */ return TRUE; } @@ -878,14 +885,15 @@ fu_cros_ec_usb_device_attach (FuDevice *device, GError **error) return TRUE; } - if (!self->in_bootloader) { - /* already in rw, so skip jump to rw */ - return TRUE; - } - fu_device_set_remove_delay (device, FU_DEVICE_REMOVE_DELAY_RE_ENUMERATE); - fu_cros_ec_usb_device_jump_to_rw (device); - + if (fu_device_has_custom_flag (device, "ro-written") && + !fu_device_has_custom_flag (device, "rw-written")) { + if (!fu_cros_ec_usb_device_reset_to_ro (device, error)) { + return FALSE; + } + } else { + fu_cros_ec_usb_device_jump_to_rw (device); + } fu_device_set_status (device, FWUPD_STATUS_DEVICE_RESTART); fu_device_add_flag (device, FWUPD_DEVICE_FLAG_WAIT_FOR_REPLUG); @@ -904,17 +912,19 @@ fu_cros_ec_usb_device_detach (FuDevice *device, GError **error) if (self->in_bootloader) { g_debug ("skipping immediate reboot in case of already in bootloader"); - /* already in ro so skip reboot */ + /* in RO so skip reboot */ return TRUE; + } else if (self->targ.common.flash_protection != 0x0) { + /* in RW, and RO region is write protected, so jump to RO */ + fu_device_set_custom_flags (device, "ro-written"); + fu_device_set_remove_delay (device, FU_DEVICE_REMOVE_DELAY_RE_ENUMERATE); + if (!fu_cros_ec_usb_device_reset_to_ro (device, error)) + return FALSE; + + fu_device_set_status (device, FWUPD_STATUS_DEVICE_RESTART); + fu_device_add_flag (device, FWUPD_DEVICE_FLAG_WAIT_FOR_REPLUG); } - fu_device_set_remove_delay (device, FU_DEVICE_REMOVE_DELAY_RE_ENUMERATE); - if (!fu_cros_ec_usb_device_reset_to_ro (device, error)) - return FALSE; - - fu_device_set_status (device, FWUPD_STATUS_DEVICE_RESTART); - fu_device_add_flag (device, FWUPD_DEVICE_FLAG_WAIT_FOR_REPLUG); - /* success */ return TRUE; } From 343613954b986f8da8ba727c3ff7fe9b20141524 Mon Sep 17 00:00:00 2001 From: Benson Leung Date: Wed, 7 Oct 2020 19:36:30 -0700 Subject: [PATCH 527/607] cros-ec: Increase remove delay for reenumeration to 20s. --- plugins/cros-ec/fu-cros-ec-usb-device.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/plugins/cros-ec/fu-cros-ec-usb-device.c b/plugins/cros-ec/fu-cros-ec-usb-device.c index ee025ea0d..b9a2de7dd 100644 --- a/plugins/cros-ec/fu-cros-ec-usb-device.c +++ b/plugins/cros-ec/fu-cros-ec-usb-device.c @@ -21,6 +21,7 @@ #define FLUSH_TIMEOUT_MS 10 #define BULK_SEND_TIMEOUT_MS 2000 #define BULK_RECV_TIMEOUT_MS 5000 +#define CROS_EC_REMOVE_DELAY_RE_ENUMERATE 20000 #define UPDATE_DONE 0xB007AB1E #define UPDATE_EXTRA_CMD 0xB007AB1F @@ -879,13 +880,13 @@ fu_cros_ec_usb_device_attach (FuDevice *device, GError **error) FuCrosEcUsbDevice *self = FU_CROS_EC_USB_DEVICE (device); if (self->in_bootloader && fu_device_has_custom_flag (device, "special")) { - fu_device_set_remove_delay (device, FU_DEVICE_REMOVE_DELAY_RE_ENUMERATE); + fu_device_set_remove_delay (device, CROS_EC_REMOVE_DELAY_RE_ENUMERATE); fu_device_set_status (device, FWUPD_STATUS_DEVICE_RESTART); fu_device_add_flag (device, FWUPD_DEVICE_FLAG_WAIT_FOR_REPLUG); return TRUE; } - fu_device_set_remove_delay (device, FU_DEVICE_REMOVE_DELAY_RE_ENUMERATE); + fu_device_set_remove_delay (device, CROS_EC_REMOVE_DELAY_RE_ENUMERATE); if (fu_device_has_custom_flag (device, "ro-written") && !fu_device_has_custom_flag (device, "rw-written")) { if (!fu_cros_ec_usb_device_reset_to_ro (device, error)) { @@ -917,7 +918,7 @@ fu_cros_ec_usb_device_detach (FuDevice *device, GError **error) } else if (self->targ.common.flash_protection != 0x0) { /* in RW, and RO region is write protected, so jump to RO */ fu_device_set_custom_flags (device, "ro-written"); - fu_device_set_remove_delay (device, FU_DEVICE_REMOVE_DELAY_RE_ENUMERATE); + fu_device_set_remove_delay (device, CROS_EC_REMOVE_DELAY_RE_ENUMERATE); if (!fu_cros_ec_usb_device_reset_to_ro (device, error)) return FALSE; From 42f2e22dd232835590810de2c068d9bf5b100b49 Mon Sep 17 00:00:00 2001 From: Benson Leung Date: Fri, 17 Jul 2020 17:25:44 -0700 Subject: [PATCH 528/607] cros-ec: Add support for quiche and gingerbread boards Add quirks for PID 5048 and 5049, which are cros-ec devices that update via USB endpoint. Notable about these two are they support rw_sig, for RW region signature verification. --- plugins/cros-ec/cros-ec.quirk | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/plugins/cros-ec/cros-ec.quirk b/plugins/cros-ec/cros-ec.quirk index 0df5faf0f..91a46201d 100644 --- a/plugins/cros-ec/cros-ec.quirk +++ b/plugins/cros-ec/cros-ec.quirk @@ -2,3 +2,13 @@ [DeviceInstanceId=USB\VID_18D1&PID_501A] Plugin = cros_ec Summary = Servo Micro (aka "uServo") Debug Board + +# Quiche +[DeviceInstanceId=USB\VID_18D1&PID_5048] +Plugin = cros_ec +Summary = Quiche Reference Board + +# Gingerbread +[DeviceInstanceId=USB\VID_18D1&PID_5049] +Plugin = cros_ec +Summary = Gingerbread Reference Board From e8e7a16c2e001cddf1e4907cc9a79aaf2ead40bd Mon Sep 17 00:00:00 2001 From: Richard Hughes Date: Mon, 12 Oct 2020 09:17:47 +0100 Subject: [PATCH 529/607] trivial: Fix aarch64 Fedora build --- contrib/fwupd.spec.in | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/contrib/fwupd.spec.in b/contrib/fwupd.spec.in index 3557053e5..9c9dd2b96 100644 --- a/contrib/fwupd.spec.in +++ b/contrib/fwupd.spec.in @@ -334,8 +334,8 @@ mkdir -p --mode=0700 $RPM_BUILD_ROOT%{_localstatedir}/lib/fwupd/gnupg %{_sysconfdir}/pki/fwupd-metadata %if 0%{?have_msr} %{_sysconfdir}/modules-load.d/fwupd-msr.conf -%{_sysconfdir}/modules-load.d/fwupd-platform-integrity.conf %endif +%{_sysconfdir}/modules-load.d/fwupd-platform-integrity.conf %{_datadir}/dbus-1/system.d/org.freedesktop.fwupd.conf %{_datadir}/bash-completion/completions/fwupdmgr %{_datadir}/bash-completion/completions/fwupdtool From 02d9d23f13b171fe229fbe351ca1d35d5100d627 Mon Sep 17 00:00:00 2001 From: Mario Limonciello Date: Mon, 12 Oct 2020 08:30:27 -0500 Subject: [PATCH 530/607] trivial: fix shutdown error on fwupdtool activate EXIT_NOTHING_TO_DO needs to be caught by the shutdown script too. Fixes: #2463 --- data/fwupd.shutdown.in | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/data/fwupd.shutdown.in b/data/fwupd.shutdown.in index 53b334555..abde9394b 100755 --- a/data/fwupd.shutdown.in +++ b/data/fwupd.shutdown.in @@ -4,4 +4,8 @@ [ -f @localstatedir@/lib/fwupd/pending.db ] || exit 0 # activate firmware when we have a read-only filesysten -@bindir@/fwupdtool activate +if !@bindir@/fwupdtool activate; then + ret=$? + [ "$ret" -eq "2" ] && exit 0 + exit $ret +fi From 7bcb8d4385665700f21b246747b69ab5aff0c136 Mon Sep 17 00:00:00 2001 From: Richard Hughes Date: Thu, 8 Oct 2020 15:47:47 +0100 Subject: [PATCH 531/607] Export FwupdPlugin so we can convey enumerated system errors to the end user For instance, we can tell the user that UEFI UpdateCapsule is disabled in the system firmware, or that efivarfs is not mounted. This is much better than creating "dummy" devices which are really just hacks around the problem because no better API existed. THe dummy devices cause as many problems as they solve. Plugins have to set FWUPD_PLUGIN_FLAG_USER_WARNING if a warning should be shown to the user, and only one warning will be shown of each failure type. It is expected that GUI clients like gnome-software and gnome-firmware would use this API to notify the user the localized message for why firmware updates are not being shown. Fixes https://github.com/fwupd/fwupd/issues/2456 --- data/bash-completion/fwupdmgr.in | 1 + docs/fwupd-docs.xml | 1 + libfwupd/fwupd-client-sync.c | 45 ++ libfwupd/fwupd-client-sync.h | 3 + libfwupd/fwupd-client.c | 78 +++ libfwupd/fwupd-client.h | 8 + libfwupd/fwupd-enums-private.h | 2 + libfwupd/fwupd-enums.c | 74 +++ libfwupd/fwupd-enums.h | 30 ++ libfwupd/fwupd-plugin-private.h | 20 + libfwupd/fwupd-plugin.c | 484 ++++++++++++++++++ libfwupd/fwupd-plugin.h | 50 ++ libfwupd/fwupd-self-test.c | 6 + libfwupd/fwupd.h | 1 + libfwupd/fwupd.map | 19 + libfwupd/meson.build | 5 + libfwupdplugin/fu-plugin.c | 210 ++++---- libfwupdplugin/fu-plugin.h | 15 +- plugins/bios/fu-plugin-bios.c | 50 +- plugins/dell/fu-plugin-dell.c | 16 +- plugins/tpm-eventlog/fu-plugin-tpm-eventlog.c | 2 +- plugins/uefi/fu-plugin-uefi.c | 23 +- src/fu-engine.c | 41 +- src/fu-main.c | 23 + src/fu-plugin-list.c | 12 +- src/fu-self-test.c | 6 +- src/fu-tool.c | 65 ++- src/fu-util-common.c | 118 +++++ src/fu-util-common.h | 16 + src/fu-util.c | 91 +++- src/org.freedesktop.fwupd.xml | 18 + 31 files changed, 1326 insertions(+), 207 deletions(-) create mode 100644 libfwupd/fwupd-plugin-private.h create mode 100644 libfwupd/fwupd-plugin.c create mode 100644 libfwupd/fwupd-plugin.h diff --git a/data/bash-completion/fwupdmgr.in b/data/bash-completion/fwupdmgr.in index f93631860..cfcc0ca5d 100644 --- a/data/bash-completion/fwupdmgr.in +++ b/data/bash-completion/fwupdmgr.in @@ -18,6 +18,7 @@ _fwupdmgr_cmd_list=( 'get-topology' 'get-updates' 'get-upgrades' + 'get-plugins' 'install' 'modify-config' 'modify-remote' diff --git a/docs/fwupd-docs.xml b/docs/fwupd-docs.xml index 42b6637f5..15f6b4a35 100644 --- a/docs/fwupd-docs.xml +++ b/docs/fwupd-docs.xml @@ -29,6 +29,7 @@ + diff --git a/libfwupd/fwupd-client-sync.c b/libfwupd/fwupd-client-sync.c index e122b376b..cb6b3c23b 100644 --- a/libfwupd/fwupd-client-sync.c +++ b/libfwupd/fwupd-client-sync.c @@ -146,6 +146,51 @@ fwupd_client_get_devices (FwupdClient *self, GCancellable *cancellable, GError * } return g_steal_pointer (&helper->array); } + +static void +fwupd_client_get_plugins_cb (GObject *source, GAsyncResult *res, gpointer user_data) +{ + FwupdClientHelper *helper = (FwupdClientHelper *) user_data; + helper->array = fwupd_client_get_plugins_finish (FWUPD_CLIENT (source), res, &helper->error); + g_main_loop_quit (helper->loop); +} + +/** + * fwupd_client_get_plugins: + * @self: A #FwupdClient + * @cancellable: the #GCancellable, or %NULL + * @error: the #GError, or %NULL + * + * Gets all the plugins being used the daemon. + * + * Returns: (element-type FwupdPlugin) (transfer container): results + * + * Since: 1.5.0 + **/ +GPtrArray * +fwupd_client_get_plugins (FwupdClient *self, GCancellable *cancellable, GError **error) +{ + g_autoptr(FwupdClientHelper) helper = fwupd_client_helper_new (); + + g_return_val_if_fail (FWUPD_IS_CLIENT (self), NULL); + g_return_val_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable), NULL); + g_return_val_if_fail (error == NULL || *error == NULL, NULL); + + /* connect */ + if (!fwupd_client_connect (self, cancellable, error)) + return NULL; + + /* call async version and run loop until complete */ + fwupd_client_get_plugins_async (self, cancellable, + fwupd_client_get_plugins_cb, helper); + g_main_loop_run (helper->loop); + if (helper->array == NULL) { + g_propagate_error (error, g_steal_pointer (&helper->error)); + return NULL; + } + return g_steal_pointer (&helper->array); +} + static void fwupd_client_get_history_cb (GObject *source, GAsyncResult *res, gpointer user_data) { diff --git a/libfwupd/fwupd-client-sync.h b/libfwupd/fwupd-client-sync.h index 947ddab05..974b5a44f 100644 --- a/libfwupd/fwupd-client-sync.h +++ b/libfwupd/fwupd-client-sync.h @@ -14,6 +14,9 @@ gboolean fwupd_client_connect (FwupdClient *self, GPtrArray *fwupd_client_get_devices (FwupdClient *self, GCancellable *cancellable, GError **error); +GPtrArray *fwupd_client_get_plugins (FwupdClient *self, + GCancellable *cancellable, + GError **error); GPtrArray *fwupd_client_get_history (FwupdClient *self, GCancellable *cancellable, GError **error); diff --git a/libfwupd/fwupd-client.c b/libfwupd/fwupd-client.c index c8a1aed5e..769031665 100644 --- a/libfwupd/fwupd-client.c +++ b/libfwupd/fwupd-client.c @@ -25,6 +25,7 @@ #include "fwupd-enums.h" #include "fwupd-error.h" #include "fwupd-device-private.h" +#include "fwupd-plugin-private.h" #include "fwupd-security-attr-private.h" #include "fwupd-release-private.h" #include "fwupd-remote-private.h" @@ -746,6 +747,83 @@ fwupd_client_get_devices_finish (FwupdClient *self, GAsyncResult *res, GError ** return g_task_propagate_pointer (G_TASK(res), error); } +static void +fwupd_client_get_plugins_cb (GObject *source, + GAsyncResult *res, + gpointer user_data) +{ + g_autoptr(GTask) task = G_TASK (user_data); + g_autoptr(GError) error = NULL; + g_autoptr(GVariant) val = NULL; + + val = g_dbus_proxy_call_finish (G_DBUS_PROXY (source), res, &error); + if (val == NULL) { + fwupd_client_fixup_dbus_error (error); + g_task_return_error (task, g_steal_pointer (&error)); + return; + } + + /* success */ + g_task_return_pointer (task, + fwupd_plugin_array_from_variant (val), + (GDestroyNotify) g_ptr_array_unref); +} + +/** + * fwupd_client_get_plugins_async: + * @self: A #FwupdClient + * @cancellable: the #GCancellable, or %NULL + * @callback: the function to run on completion + * @callback_data: the data to pass to @callback + * + * Gets all the plugins being used by the daemon. + * + * You must have called fwupd_client_connect_async() on @self before using + * this method. + * + * Since: 1.5.0 + **/ +void +fwupd_client_get_plugins_async (FwupdClient *self, GCancellable *cancellable, + GAsyncReadyCallback callback, gpointer callback_data) +{ + FwupdClientPrivate *priv = GET_PRIVATE (self); + g_autoptr(GTask) task = NULL; + + g_return_if_fail (FWUPD_IS_CLIENT (self)); + g_return_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable)); + g_return_if_fail (priv->proxy != NULL); + + /* call into daemon */ + task = g_task_new (self, cancellable, callback, callback_data); + g_dbus_proxy_call (priv->proxy, "GetPlugins", + NULL, G_DBUS_CALL_FLAGS_NONE, + -1, cancellable, + fwupd_client_get_plugins_cb, + g_steal_pointer (&task)); +} + +/** + * fwupd_client_get_plugins_finish: + * @self: A #FwupdClient + * @res: the #GAsyncResult + * @error: the #GError, or %NULL + * + * Gets the result of fwupd_client_get_plugins_async(). + * + * Returns: (element-type FwupdDevice) (transfer container): results + * + * Since: 1.5.0 + **/ +GPtrArray * +fwupd_client_get_plugins_finish (FwupdClient *self, GAsyncResult *res, GError **error) +{ + g_return_val_if_fail (FWUPD_IS_CLIENT (self), NULL); + g_return_val_if_fail (g_task_is_valid (res, self), NULL); + g_return_val_if_fail (error == NULL || *error == NULL, NULL); + return g_task_propagate_pointer (G_TASK(res), error); +} + static void fwupd_client_get_history_cb (GObject *source, GAsyncResult *res, diff --git a/libfwupd/fwupd-client.h b/libfwupd/fwupd-client.h index ea3eeadb4..6899df329 100644 --- a/libfwupd/fwupd-client.h +++ b/libfwupd/fwupd-client.h @@ -11,6 +11,7 @@ #include "fwupd-enums.h" #include "fwupd-device.h" +#include "fwupd-plugin.h" #include "fwupd-remote.h" G_BEGIN_DECLS @@ -81,6 +82,13 @@ void fwupd_client_get_devices_async (FwupdClient *self, GPtrArray *fwupd_client_get_devices_finish (FwupdClient *self, GAsyncResult *res, GError **error); +void fwupd_client_get_plugins_async (FwupdClient *self, + GCancellable *cancellable, + GAsyncReadyCallback callback, + gpointer callback_data); +GPtrArray *fwupd_client_get_plugins_finish (FwupdClient *self, + GAsyncResult *res, + GError **error); void fwupd_client_get_history_async (FwupdClient *self, GCancellable *cancellable, GAsyncReadyCallback callback, diff --git a/libfwupd/fwupd-enums-private.h b/libfwupd/fwupd-enums-private.h index deaf86f1d..7176d2d89 100644 --- a/libfwupd/fwupd-enums-private.h +++ b/libfwupd/fwupd-enums-private.h @@ -6,6 +6,8 @@ #pragma once +#include + G_BEGIN_DECLS #define FWUPD_RESULT_KEY_APPSTREAM_ID "AppstreamId" /* s */ diff --git a/libfwupd/fwupd-enums.c b/libfwupd/fwupd-enums.c index a35cf31e7..f3b1fae29 100644 --- a/libfwupd/fwupd-enums.c +++ b/libfwupd/fwupd-enums.c @@ -306,6 +306,80 @@ fwupd_device_flag_from_string (const gchar *device_flag) return FWUPD_DEVICE_FLAG_UNKNOWN; } +/** + * fwupd_plugin_flag_to_string: + * @plugin_flag: A #FwupdPluginFlags, e.g. %FWUPD_DEVICE_FLAG_REQUIRE_AC + * + * Converts a #FwupdDeviceFlags to a string. + * + * Return value: identifier string + * + * Since: 1.5.0 + **/ +const gchar * +fwupd_plugin_flag_to_string (FwupdPluginFlags plugin_flag) +{ + if (plugin_flag == FWUPD_DEVICE_FLAG_NONE) + return "none"; + if (plugin_flag == FWUPD_PLUGIN_FLAG_DISABLED) + return "disabled"; + if (plugin_flag == FWUPD_PLUGIN_FLAG_USER_WARNING) + return "user-warning"; + if (plugin_flag == FWUPD_PLUGIN_FLAG_CLEAR_UPDATABLE) + return "clear-updatable"; + if (plugin_flag == FWUPD_PLUGIN_FLAG_NO_HARDWARE) + return "no-hardware"; + if (plugin_flag == FWUPD_PLUGIN_FLAG_CAPSULES_UNSUPPORTED) + return "capsules-unsupported"; + if (plugin_flag == FWUPD_PLUGIN_FLAG_UNLOCK_REQUIRED) + return "unlock-required"; + if (plugin_flag == FWUPD_PLUGIN_FLAG_EFIVAR_NOT_MOUNTED) + return "efivar-not-mounted"; + if (plugin_flag == FWUPD_PLUGIN_FLAG_ESP_NOT_FOUND) + return "esp-not-found"; + if (plugin_flag == FWUPD_PLUGIN_FLAG_LEGACY_BIOS) + return "legacy-bios"; + if (plugin_flag == FWUPD_DEVICE_FLAG_UNKNOWN) + return "unknown"; + return NULL; +} + +/** + * fwupd_plugin_flag_from_string: + * @plugin_flag: A string, e.g. `require-ac` + * + * Converts a string to a #FwupdPluginFlags. + * + * Return value: enumerated value + * + * Since: 1.5.0 + **/ +FwupdPluginFlags +fwupd_plugin_flag_from_string (const gchar *plugin_flag) +{ + if (g_strcmp0 (plugin_flag, "none") == 0) + return FWUPD_DEVICE_FLAG_NONE; + if (g_strcmp0 (plugin_flag, "disabled") == 0) + return FWUPD_PLUGIN_FLAG_DISABLED; + if (g_strcmp0 (plugin_flag, "user-warning") == 0) + return FWUPD_PLUGIN_FLAG_USER_WARNING; + if (g_strcmp0 (plugin_flag, "clear-updatable") == 0) + return FWUPD_PLUGIN_FLAG_CLEAR_UPDATABLE; + if (g_strcmp0 (plugin_flag, "no-hardware") == 0) + return FWUPD_PLUGIN_FLAG_NO_HARDWARE; + if (g_strcmp0 (plugin_flag, "capsules-unsupported") == 0) + return FWUPD_PLUGIN_FLAG_CAPSULES_UNSUPPORTED; + if (g_strcmp0 (plugin_flag, "unlock-required") == 0) + return FWUPD_PLUGIN_FLAG_UNLOCK_REQUIRED; + if (g_strcmp0 (plugin_flag, "efivar-not-mounted") == 0) + return FWUPD_PLUGIN_FLAG_EFIVAR_NOT_MOUNTED; + if (g_strcmp0 (plugin_flag, "esp-not-found") == 0) + return FWUPD_PLUGIN_FLAG_ESP_NOT_FOUND; + if (g_strcmp0 (plugin_flag, "legacy-bios") == 0) + return FWUPD_PLUGIN_FLAG_LEGACY_BIOS; + return FWUPD_DEVICE_FLAG_UNKNOWN; +} + /** * fwupd_update_state_to_string: * @update_state: A #FwupdUpdateState, e.g. %FWUPD_UPDATE_STATE_PENDING diff --git a/libfwupd/fwupd-enums.h b/libfwupd/fwupd-enums.h index 5bc9f6eee..6d8143e3e 100644 --- a/libfwupd/fwupd-enums.h +++ b/libfwupd/fwupd-enums.h @@ -220,6 +220,34 @@ typedef enum { FWUPD_RELEASE_URGENCY_LAST } FwupdReleaseUrgency; +/** + * FwupdPluginFlags: + * @FWUPD_PLUGIN_FLAG_NONE: No flags set + * @FWUPD_PLUGIN_FLAG_DISABLED: Disabled + * @FWUPD_PLUGIN_FLAG_USER_WARNING: Show the user a warning + * @FWUPD_PLUGIN_FLAG_CLEAR_UPDATABLE: Clear the UPDATABLE flag from devices + * @FWUPD_PLUGIN_FLAG_NO_HARDWARE: No hardware is found + * @FWUPD_PLUGIN_FLAG_CAPSULES_UNSUPPORTED: UEFI UpdateCapsule are unsupported + * @FWUPD_PLUGIN_FLAG_UNLOCK_REQUIRED: Hardware unlock is required + * @FWUPD_PLUGIN_FLAG_EFIVAR_NOT_MOUNTED: The efivar filesystem is not found + * @FWUPD_PLUGIN_FLAG_ESP_NOT_FOUND: The EFI ESP not found + * @FWUPD_PLUGIN_FLAG_LEGACY_BIOS: System running in legacy CSM mode + * + * The plugin flags. + **/ +#define FWUPD_PLUGIN_FLAG_NONE (0u) /* Since: 1.5.0 */ +#define FWUPD_PLUGIN_FLAG_DISABLED (1u << 0) /* Since: 1.5.0 */ +#define FWUPD_PLUGIN_FLAG_USER_WARNING (1u << 1) /* Since: 1.5.0 */ +#define FWUPD_PLUGIN_FLAG_CLEAR_UPDATABLE (1u << 2) /* Since: 1.5.0 */ +#define FWUPD_PLUGIN_FLAG_NO_HARDWARE (1u << 3) /* Since: 1.5.0 */ +#define FWUPD_PLUGIN_FLAG_CAPSULES_UNSUPPORTED (1u << 4) /* Since: 1.5.0 */ +#define FWUPD_PLUGIN_FLAG_UNLOCK_REQUIRED (1u << 5) /* Since: 1.5.0 */ +#define FWUPD_PLUGIN_FLAG_EFIVAR_NOT_MOUNTED (1u << 6) /* Since: 1.5.0 */ +#define FWUPD_PLUGIN_FLAG_ESP_NOT_FOUND (1u << 7) /* Since: 1.5.0 */ +#define FWUPD_PLUGIN_FLAG_LEGACY_BIOS (1u << 8) /* Since: 1.5.0 */ +#define FWUPD_PLUGIN_FLAG_UNKNOWN G_MAXUINT64 /* Since: 1.5.0 */ +typedef guint64 FwupdPluginFlags; + /** * FwupdInstallFlags: * @FWUPD_INSTALL_FLAG_NONE: No flags set @@ -351,6 +379,8 @@ const gchar *fwupd_status_to_string (FwupdStatus status); FwupdStatus fwupd_status_from_string (const gchar *status); const gchar *fwupd_device_flag_to_string (FwupdDeviceFlags device_flag); FwupdDeviceFlags fwupd_device_flag_from_string (const gchar *device_flag); +const gchar *fwupd_plugin_flag_to_string (FwupdPluginFlags plugin_flag); +FwupdPluginFlags fwupd_plugin_flag_from_string (const gchar *plugin_flag); const gchar *fwupd_release_flag_to_string (FwupdReleaseFlags release_flag); FwupdReleaseFlags fwupd_release_flag_from_string (const gchar *release_flag); const gchar *fwupd_release_urgency_to_string (FwupdReleaseUrgency release_urgency); diff --git a/libfwupd/fwupd-plugin-private.h b/libfwupd/fwupd-plugin-private.h new file mode 100644 index 000000000..8902ada43 --- /dev/null +++ b/libfwupd/fwupd-plugin-private.h @@ -0,0 +1,20 @@ +/* + * Copyright (C) 2020 Richard Hughes + * + * SPDX-License-Identifier: LGPL-2.1+ + */ + +#pragma once + +#include + +#include "fwupd-plugin.h" + +G_BEGIN_DECLS + +GVariant *fwupd_plugin_to_variant (FwupdPlugin *plugin); +void fwupd_plugin_to_json (FwupdPlugin *plugin, + JsonBuilder *builder); + +G_END_DECLS + diff --git a/libfwupd/fwupd-plugin.c b/libfwupd/fwupd-plugin.c new file mode 100644 index 000000000..e27820521 --- /dev/null +++ b/libfwupd/fwupd-plugin.c @@ -0,0 +1,484 @@ +/* + * Copyright (C) 2020 Richard Hughes + * + * SPDX-License-Identifier: LGPL-2.1+ + */ + +#include "config.h" + +#include "fwupd-enums-private.h" +#include "fwupd-plugin-private.h" + +/** + * SECTION:fwupd-plugin + * @short_description: a hardware plugin + * + * An object that represents a fwupd plugin. + * + * See also: #FwupdRelease + */ + +static void fwupd_plugin_finalize (GObject *object); + +typedef struct { + gchar *name; + guint64 flags; +} FwupdPluginPrivate; + +enum { + PROP_0, + PROP_NAME, + PROP_FLAGS, + PROP_LAST +}; + +G_DEFINE_TYPE_WITH_PRIVATE (FwupdPlugin, fwupd_plugin, G_TYPE_OBJECT) +#define GET_PRIVATE(o) (fwupd_plugin_get_instance_private (o)) + +/** + * fwupd_plugin_get_name: + * @plugin: A #FwupdPlugin + * + * Gets the plugin name. + * + * Returns: the plugin name, or %NULL if unset + * + * Since: 1.5.0 + **/ +const gchar * +fwupd_plugin_get_name (FwupdPlugin *plugin) +{ + FwupdPluginPrivate *priv = GET_PRIVATE (plugin); + g_return_val_if_fail (FWUPD_IS_PLUGIN (plugin), NULL); + return priv->name; +} + +/** + * fwupd_plugin_set_name: + * @plugin: A #FwupdPlugin + * @name: the plugin name, e.g. `bios` + * + * Sets the plugin name. + * + * Since: 1.5.0 + **/ +void +fwupd_plugin_set_name (FwupdPlugin *plugin, const gchar *name) +{ + FwupdPluginPrivate *priv = GET_PRIVATE (plugin); + g_return_if_fail (FWUPD_IS_PLUGIN (plugin)); + g_return_if_fail (name != NULL); + g_free (priv->name); + priv->name = g_strdup (name); + g_object_notify (G_OBJECT (plugin), "name"); +} + +/** + * fwupd_plugin_get_flags: + * @plugin: A #FwupdPlugin + * + * Gets the plugin flags. + * + * Returns: the plugin flags, or 0 if unset + * + * Since: 1.5.0 + **/ +guint64 +fwupd_plugin_get_flags (FwupdPlugin *plugin) +{ + FwupdPluginPrivate *priv = GET_PRIVATE (plugin); + g_return_val_if_fail (FWUPD_IS_PLUGIN (plugin), 0); + return priv->flags; +} + +/** + * fwupd_plugin_set_flags: + * @plugin: A #FwupdPlugin + * @flags: the plugin flags, e.g. %FWUPD_PLUGIN_FLAG_CAPSULES_UNSUPPORTED + * + * Sets the plugin flags. + * + * Since: 1.5.0 + **/ +void +fwupd_plugin_set_flags (FwupdPlugin *plugin, guint64 flags) +{ + FwupdPluginPrivate *priv = GET_PRIVATE (plugin); + g_return_if_fail (FWUPD_IS_PLUGIN (plugin)); + if (priv->flags == flags) + return; + priv->flags = flags; + g_object_notify (G_OBJECT (plugin), "flags"); +} + +/** + * fwupd_plugin_add_flag: + * @plugin: A #FwupdPlugin + * @flag: the #FwupdPluginFlags + * + * Adds a specific plugin flag to the plugin. + * + * Since: 1.5.0 + **/ +void +fwupd_plugin_add_flag (FwupdPlugin *plugin, FwupdPluginFlags flag) +{ + FwupdPluginPrivate *priv = GET_PRIVATE (plugin); + g_return_if_fail (FWUPD_IS_PLUGIN (plugin)); + if (flag == 0) + return; + if ((priv->flags & flag) > 0) + return; + priv->flags |= flag; + g_object_notify (G_OBJECT (plugin), "flags"); +} + +/** + * fwupd_plugin_remove_flag: + * @plugin: A #FwupdPlugin + * @flag: the #FwupdPluginFlags + * + * Removes a specific plugin flag from the plugin. + * + * Since: 1.5.0 + **/ +void +fwupd_plugin_remove_flag (FwupdPlugin *plugin, FwupdPluginFlags flag) +{ + FwupdPluginPrivate *priv = GET_PRIVATE (plugin); + g_return_if_fail (FWUPD_IS_PLUGIN (plugin)); + if (flag == 0) + return; + if ((priv->flags & flag) == 0) + return; + priv->flags &= ~flag; + g_object_notify (G_OBJECT (plugin), "flags"); +} + +/** + * fwupd_plugin_has_flag: + * @plugin: A #FwupdPlugin + * @flag: the #FwupdPluginFlags + * + * Finds if the plugin has a specific plugin flag. + * + * Returns: %TRUE if the flag is set + * + * Since: 1.5.0 + **/ +gboolean +fwupd_plugin_has_flag (FwupdPlugin *plugin, FwupdPluginFlags flag) +{ + FwupdPluginPrivate *priv = GET_PRIVATE (plugin); + g_return_val_if_fail (FWUPD_IS_PLUGIN (plugin), FALSE); + return (priv->flags & flag) > 0; +} + +/** + * fwupd_plugin_to_variant: + * @plugin: A #FwupdPlugin + * + * Creates a GVariant from the plugin data omitting sensitive fields + * + * Returns: the GVariant, or %NULL for error + * + * Since: 1.5.0 + **/ +GVariant * +fwupd_plugin_to_variant (FwupdPlugin *plugin) +{ + FwupdPluginPrivate *priv = GET_PRIVATE (plugin); + GVariantBuilder builder; + + g_return_val_if_fail (FWUPD_IS_PLUGIN (plugin), NULL); + + /* create an array with all the metadata in */ + g_variant_builder_init (&builder, G_VARIANT_TYPE_VARDICT); + if (priv->name != NULL) { + g_variant_builder_add (&builder, "{sv}", + FWUPD_RESULT_KEY_NAME, + g_variant_new_string (priv->name)); + } + if (priv->flags > 0) { + g_variant_builder_add (&builder, "{sv}", + FWUPD_RESULT_KEY_FLAGS, + g_variant_new_uint64 (priv->flags)); + } + return g_variant_new ("a{sv}", &builder); +} + +static void +fwupd_plugin_from_key_value (FwupdPlugin *plugin, const gchar *key, GVariant *value) +{ + if (g_strcmp0 (key, FWUPD_RESULT_KEY_NAME) == 0) { + fwupd_plugin_set_name (plugin, g_variant_get_string (value, NULL)); + return; + } + if (g_strcmp0 (key, FWUPD_RESULT_KEY_FLAGS) == 0) { + fwupd_plugin_set_flags (plugin, g_variant_get_uint64 (value)); + return; + } +} + +static void +fwupd_pad_kv_str (GString *str, const gchar *key, const gchar *value) +{ + /* ignore */ + if (key == NULL || value == NULL) + return; + g_string_append_printf (str, " %s: ", key); + for (gsize i = strlen (key); i < 20; i++) + g_string_append (str, " "); + g_string_append_printf (str, "%s\n", value); +} + +static void +fwupd_pad_kv_dfl (GString *str, const gchar *key, guint64 plugin_flags) +{ + g_autoptr(GString) tmp = g_string_new (""); + for (guint i = 0; i < 64; i++) { + if ((plugin_flags & ((guint64) 1 << i)) == 0) + continue; + g_string_append_printf (tmp, "%s|", + fwupd_plugin_flag_to_string ((guint64) 1 << i)); + } + if (tmp->len == 0) { + g_string_append (tmp, fwupd_plugin_flag_to_string (0)); + } else { + g_string_truncate (tmp, tmp->len - 1); + } + fwupd_pad_kv_str (str, key, tmp->str); +} + +static void +fwupd_plugin_json_add_string (JsonBuilder *builder, const gchar *key, const gchar *str) +{ + if (str == NULL) + return; + json_builder_set_member_name (builder, key); + json_builder_add_string_value (builder, str); +} + +/** + * fwupd_plugin_to_json: + * @plugin: A #FwupdPlugin + * @builder: A #JsonBuilder + * + * Adds a fwupd plugin to a JSON builder + * + * Since: 1.5.0 + **/ +void +fwupd_plugin_to_json (FwupdPlugin *plugin, JsonBuilder *builder) +{ + FwupdPluginPrivate *priv = GET_PRIVATE (plugin); + + g_return_if_fail (FWUPD_IS_PLUGIN (plugin)); + g_return_if_fail (builder != NULL); + + fwupd_plugin_json_add_string (builder, FWUPD_RESULT_KEY_NAME, priv->name); + if (priv->flags != FWUPD_PLUGIN_FLAG_NONE) { + json_builder_set_member_name (builder, FWUPD_RESULT_KEY_FLAGS); + json_builder_begin_array (builder); + for (guint i = 0; i < 64; i++) { + const gchar *tmp; + if ((priv->flags & ((guint64) 1 << i)) == 0) + continue; + tmp = fwupd_plugin_flag_to_string ((guint64) 1 << i); + json_builder_add_string_value (builder, tmp); + } + json_builder_end_array (builder); + } +} + +/** + * fwupd_plugin_to_string: + * @plugin: A #FwupdPlugin + * + * Builds a text representation of the object. + * + * Returns: text, or %NULL for invalid + * + * Since: 1.5.0 + **/ +gchar * +fwupd_plugin_to_string (FwupdPlugin *plugin) +{ + FwupdPluginPrivate *priv = GET_PRIVATE (plugin); + GString *str; + + g_return_val_if_fail (FWUPD_IS_PLUGIN (plugin), NULL); + + str = g_string_new (NULL); + fwupd_pad_kv_str (str, FWUPD_RESULT_KEY_NAME, priv->name); + fwupd_pad_kv_dfl (str, FWUPD_RESULT_KEY_FLAGS, priv->flags); + return g_string_free (str, FALSE); +} + +static void +fwupd_plugin_get_property (GObject *object, guint prop_id, + GValue *value, GParamSpec *pspec) +{ + FwupdPlugin *self = FWUPD_PLUGIN (object); + FwupdPluginPrivate *priv = GET_PRIVATE (self); + switch (prop_id) { + case PROP_NAME: + g_value_set_string (value, priv->name); + break; + case PROP_FLAGS: + g_value_set_uint64 (value, priv->flags); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} + +static void +fwupd_plugin_set_property (GObject *object, guint prop_id, + const GValue *value, GParamSpec *pspec) +{ + FwupdPlugin *self = FWUPD_PLUGIN (object); + switch (prop_id) { + case PROP_NAME: + fwupd_plugin_set_name (self, g_value_get_string (value)); + break; + case PROP_FLAGS: + fwupd_plugin_set_flags (self, g_value_get_uint64 (value)); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} + +static void +fwupd_plugin_class_init (FwupdPluginClass *klass) +{ + GObjectClass *object_class = G_OBJECT_CLASS (klass); + GParamSpec *pspec; + + object_class->finalize = fwupd_plugin_finalize; + object_class->get_property = fwupd_plugin_get_property; + object_class->set_property = fwupd_plugin_set_property; + + pspec = g_param_spec_string ("name", NULL, NULL, NULL, + G_PARAM_READWRITE | + G_PARAM_STATIC_NAME); + g_object_class_install_property (object_class, PROP_NAME, pspec); + + pspec = g_param_spec_uint64 ("flags", NULL, NULL, + FWUPD_PLUGIN_FLAG_NONE, + FWUPD_PLUGIN_FLAG_UNKNOWN, + FWUPD_PLUGIN_FLAG_NONE, + G_PARAM_READWRITE | + G_PARAM_STATIC_NAME); + g_object_class_install_property (object_class, PROP_FLAGS, pspec); +} + +static void +fwupd_plugin_init (FwupdPlugin *plugin) +{ +} + +static void +fwupd_plugin_finalize (GObject *object) +{ + FwupdPlugin *plugin = FWUPD_PLUGIN (object); + FwupdPluginPrivate *priv = GET_PRIVATE (plugin); + g_free (priv->name); + G_OBJECT_CLASS (fwupd_plugin_parent_class)->finalize (object); +} + +static void +fwupd_plugin_set_from_variant_iter (FwupdPlugin *plugin, GVariantIter *iter) +{ + GVariant *value; + const gchar *key; + while (g_variant_iter_next (iter, "{&sv}", &key, &value)) { + fwupd_plugin_from_key_value (plugin, key, value); + g_variant_unref (value); + } +} + +/** + * fwupd_plugin_from_variant: + * @value: a #GVariant + * + * Creates a new plugin using packed data. + * + * Returns: (transfer full): a new #FwupdPlugin, or %NULL if @value was invalid + * + * Since: 1.5.0 + **/ +FwupdPlugin * +fwupd_plugin_from_variant (GVariant *value) +{ + FwupdPlugin *plugin = NULL; + const gchar *type_string; + g_autoptr(GVariantIter) iter = NULL; + + /* format from GetDetails */ + type_string = g_variant_get_type_string (value); + if (g_strcmp0 (type_string, "(a{sv})") == 0) { + plugin = fwupd_plugin_new (); + g_variant_get (value, "(a{sv})", &iter); + fwupd_plugin_set_from_variant_iter (plugin, iter); + } else if (g_strcmp0 (type_string, "a{sv}") == 0) { + plugin = fwupd_plugin_new (); + g_variant_get (value, "a{sv}", &iter); + fwupd_plugin_set_from_variant_iter (plugin, iter); + } else { + g_warning ("type %s not known", type_string); + } + return plugin; +} + +/** + * fwupd_plugin_array_from_variant: + * @value: a #GVariant + * + * Creates an array of new plugins using packed data. + * + * Returns: (transfer container) (element-type FwupdPlugin): plugins, or %NULL if @value was invalid + * + * Since: 1.5.0 + **/ +GPtrArray * +fwupd_plugin_array_from_variant (GVariant *value) +{ + GPtrArray *array = NULL; + gsize sz; + g_autoptr(GVariant) untuple = NULL; + + array = g_ptr_array_new_with_free_func ((GDestroyNotify) g_object_unref); + untuple = g_variant_get_child_value (value, 0); + sz = g_variant_n_children (untuple); + for (guint i = 0; i < sz; i++) { + FwupdPlugin *plugin; + g_autoptr(GVariant) data = NULL; + data = g_variant_get_child_value (untuple, i); + plugin = fwupd_plugin_from_variant (data); + if (plugin == NULL) + continue; + g_ptr_array_add (array, plugin); + } + return array; +} + +/** + * fwupd_plugin_new: + * + * Creates a new plugin. + * + * Returns: a new #FwupdPlugin + * + * Since: 1.5.0 + **/ +FwupdPlugin * +fwupd_plugin_new (void) +{ + FwupdPlugin *plugin; + plugin = g_object_new (FWUPD_TYPE_PLUGIN, NULL); + return FWUPD_PLUGIN (plugin); +} diff --git a/libfwupd/fwupd-plugin.h b/libfwupd/fwupd-plugin.h new file mode 100644 index 000000000..5d7cfaf12 --- /dev/null +++ b/libfwupd/fwupd-plugin.h @@ -0,0 +1,50 @@ +/* + * Copyright (C) 2020 Richard Hughes + * + * SPDX-License-Identifier: LGPL-2.1+ + */ + +#pragma once + +#include + +#include "fwupd-enums.h" + +G_BEGIN_DECLS + +#define FWUPD_TYPE_PLUGIN (fwupd_plugin_get_type ()) +G_DECLARE_DERIVABLE_TYPE (FwupdPlugin, fwupd_plugin, FWUPD, PLUGIN, GObject) + +struct _FwupdPluginClass +{ + GObjectClass parent_class; + /*< private >*/ + void (*_fwupd_reserved1) (void); + void (*_fwupd_reserved2) (void); + void (*_fwupd_reserved3) (void); + void (*_fwupd_reserved4) (void); + void (*_fwupd_reserved5) (void); + void (*_fwupd_reserved6) (void); + void (*_fwupd_reserved7) (void); +}; + +FwupdPlugin *fwupd_plugin_new (void); +gchar *fwupd_plugin_to_string (FwupdPlugin *plugin); + +const gchar *fwupd_plugin_get_name (FwupdPlugin *plugin); +void fwupd_plugin_set_name (FwupdPlugin *plugin, + const gchar *name); +guint64 fwupd_plugin_get_flags (FwupdPlugin *plugin); +void fwupd_plugin_set_flags (FwupdPlugin *plugin, + guint64 flags); +void fwupd_plugin_add_flag (FwupdPlugin *plugin, + FwupdPluginFlags flag); +void fwupd_plugin_remove_flag (FwupdPlugin *plugin, + FwupdPluginFlags flag); +gboolean fwupd_plugin_has_flag (FwupdPlugin *plugin, + FwupdPluginFlags flag); + +FwupdPlugin *fwupd_plugin_from_variant (GVariant *value); +GPtrArray *fwupd_plugin_array_from_variant (GVariant *value); + +G_END_DECLS diff --git a/libfwupd/fwupd-self-test.c b/libfwupd/fwupd-self-test.c index 626c713b0..62d9b082e 100644 --- a/libfwupd/fwupd-self-test.c +++ b/libfwupd/fwupd-self-test.c @@ -148,6 +148,12 @@ fwupd_enums_func (void) break; g_assert_cmpint (fwupd_device_flag_from_string (tmp), ==, i); } + for (guint64 i = 1; i < FWUPD_PLUGIN_FLAG_UNKNOWN; i *= 2) { + const gchar *tmp = fwupd_plugin_flag_to_string (i); + if (tmp == NULL) + break; + g_assert_cmpint (fwupd_plugin_flag_from_string (tmp), ==, i); + } } static void diff --git a/libfwupd/fwupd.h b/libfwupd/fwupd.h index a8bffb347..a3c020ed9 100644 --- a/libfwupd/fwupd.h +++ b/libfwupd/fwupd.h @@ -17,6 +17,7 @@ #include #include #include +#include #include #include #include diff --git a/libfwupd/fwupd.map b/libfwupd/fwupd.map index 6cce79529..097d967ea 100644 --- a/libfwupd/fwupd.map +++ b/libfwupd/fwupd.map @@ -507,6 +507,9 @@ LIBFWUPD_1.5.0 { fwupd_client_get_host_security_attrs_async; fwupd_client_get_host_security_attrs_finish; fwupd_client_get_host_security_id; + fwupd_client_get_plugins; + fwupd_client_get_plugins_async; + fwupd_client_get_plugins_finish; fwupd_client_get_releases_async; fwupd_client_get_releases_finish; fwupd_client_get_remote_by_id_async; @@ -554,6 +557,22 @@ LIBFWUPD_1.5.0 { fwupd_client_verify_update_finish; fwupd_device_get_branch; fwupd_device_set_branch; + fwupd_plugin_add_flag; + fwupd_plugin_array_from_variant; + fwupd_plugin_flag_from_string; + fwupd_plugin_flag_to_string; + fwupd_plugin_from_variant; + fwupd_plugin_get_flags; + fwupd_plugin_get_name; + fwupd_plugin_get_type; + fwupd_plugin_has_flag; + fwupd_plugin_new; + fwupd_plugin_remove_flag; + fwupd_plugin_set_flags; + fwupd_plugin_set_name; + fwupd_plugin_to_json; + fwupd_plugin_to_string; + fwupd_plugin_to_variant; fwupd_release_get_branch; fwupd_release_set_branch; fwupd_remote_get_automatic_security_reports; diff --git a/libfwupd/meson.build b/libfwupd/meson.build index 57e35b0da..4ac681473 100644 --- a/libfwupd/meson.build +++ b/libfwupd/meson.build @@ -24,6 +24,7 @@ install_headers([ 'fwupd-remote.h', 'fwupd-security-attr.h', 'fwupd-release.h', + 'fwupd-plugin.h', fwupd_version_h, ], subdir : 'fwupd-1/libfwupd', @@ -42,6 +43,7 @@ fwupd = shared_library( 'fwupd-error.c', 'fwupd-security-attr.c', 'fwupd-release.c', + 'fwupd-plugin.c', 'fwupd-remote.c', ], soversion : libfwupd_lt_current, @@ -97,6 +99,9 @@ if get_option('introspection') 'fwupd-release.c', 'fwupd-release.h', 'fwupd-release-private.h', + 'fwupd-plugin.c', + 'fwupd-plugin.h', + 'fwupd-plugin-private.h', 'fwupd-remote.c', 'fwupd-remote.h', 'fwupd-remote-private.h', diff --git a/libfwupdplugin/fu-plugin.c b/libfwupdplugin/fu-plugin.c index f7df74d68..19c58ab51 100644 --- a/libfwupdplugin/fu-plugin.c +++ b/libfwupdplugin/fu-plugin.c @@ -37,11 +37,9 @@ static void fu_plugin_finalize (GObject *object); typedef struct { GModule *module; GUsbContext *usb_ctx; - gboolean enabled; guint order; guint priority; GPtrArray *rules[FU_PLUGIN_RULE_LAST]; - gchar *name; gchar *build_hash; FuHwids *hwids; FuQuirks *quirks; @@ -71,7 +69,7 @@ enum { static guint signals[SIGNAL_LAST] = { 0 }; -G_DEFINE_TYPE_WITH_PRIVATE (FuPlugin, fu_plugin, G_TYPE_OBJECT) +G_DEFINE_TYPE_WITH_PRIVATE (FuPlugin, fu_plugin, FWUPD_TYPE_PLUGIN) #define GET_PRIVATE(o) (fu_plugin_get_instance_private (o)) typedef const gchar *(*FuPluginGetNameFunc) (void); @@ -138,9 +136,8 @@ fu_plugin_is_open (FuPlugin *self) const gchar * fu_plugin_get_name (FuPlugin *self) { - FuPluginPrivate *priv = GET_PRIVATE (self); g_return_val_if_fail (FU_IS_PLUGIN (self), NULL); - return priv->name; + return fwupd_plugin_get_name (FWUPD_PLUGIN (self)); } /** @@ -155,11 +152,8 @@ fu_plugin_get_name (FuPlugin *self) void fu_plugin_set_name (FuPlugin *self, const gchar *name) { - FuPluginPrivate *priv = GET_PRIVATE (self); g_return_if_fail (FU_IS_PLUGIN (self)); - g_return_if_fail (name != NULL); - g_free (priv->name); - priv->name = g_strdup (name); + fwupd_plugin_set_name (FWUPD_PLUGIN (self), name); } /** @@ -364,9 +358,8 @@ fu_plugin_set_usb_context (FuPlugin *self, GUsbContext *usb_ctx) gboolean fu_plugin_get_enabled (FuPlugin *self) { - FuPluginPrivate *priv = GET_PRIVATE (self); g_return_val_if_fail (FU_IS_PLUGIN (self), FALSE); - return priv->enabled; + return !fu_plugin_has_flag (self, FWUPD_PLUGIN_FLAG_DISABLED); } /** @@ -381,9 +374,13 @@ fu_plugin_get_enabled (FuPlugin *self) void fu_plugin_set_enabled (FuPlugin *self, gboolean enabled) { - FuPluginPrivate *priv = GET_PRIVATE (self); g_return_if_fail (FU_IS_PLUGIN (self)); - priv->enabled = enabled; + if (enabled) { + fwupd_plugin_remove_flag (FWUPD_PLUGIN (self), + FWUPD_PLUGIN_FLAG_DISABLED); + } else { + fu_plugin_add_flag (self, FWUPD_PLUGIN_FLAG_DISABLED); + } } /** @@ -438,8 +435,10 @@ fu_plugin_open (FuPlugin *self, const gchar *filename, GError **error) } /* set automatically */ - if (priv->name == NULL) - priv->name = fu_plugin_guess_name_from_fn (filename); + if (fu_plugin_get_name (self) == NULL) { + g_autofree gchar *str = fu_plugin_guess_name_from_fn (filename); + fu_plugin_set_name (self, str); + } /* optional */ g_module_symbol (priv->module, "fu_plugin_init", (gpointer *) &func); @@ -451,6 +450,27 @@ fu_plugin_open (FuPlugin *self, const gchar *filename, GError **error) return TRUE; } +/* order of usefullness to the user */ +static const gchar * +fu_plugin_build_device_update_error (FuPlugin *self) +{ + if (fu_plugin_has_flag (self, FWUPD_PLUGIN_FLAG_NO_HARDWARE)) + return "Not updatable as required hardware was not found"; + if (fu_plugin_has_flag (self, FWUPD_PLUGIN_FLAG_LEGACY_BIOS)) + return "Not updatable in legacy BIOS mode"; + if (fu_plugin_has_flag (self, FWUPD_PLUGIN_FLAG_CAPSULES_UNSUPPORTED)) + return "Not updatable as UEFI capsule updates not enabled"; + if (fu_plugin_has_flag (self, FWUPD_PLUGIN_FLAG_UNLOCK_REQUIRED)) + return "Not updatable as requires unlock"; + if (fu_plugin_has_flag (self, FWUPD_PLUGIN_FLAG_EFIVAR_NOT_MOUNTED)) + return "Not updatable as efivarfs was not found"; + if (fu_plugin_has_flag (self, FWUPD_PLUGIN_FLAG_ESP_NOT_FOUND)) + return "Not updatable as UEFI ESP partition not detected"; + if (fu_plugin_has_flag (self, FWUPD_PLUGIN_FLAG_DISABLED)) + return "Not updatable as plugin was disabled"; + return NULL; +} + /** * fu_plugin_device_add: * @self: A #FuPlugin @@ -481,6 +501,21 @@ fu_plugin_device_add (FuPlugin *self, FuDevice *device) return; } + /* proxy to device where required */ + if (fu_plugin_has_flag (self, FWUPD_PLUGIN_FLAG_CLEAR_UPDATABLE)) { + g_debug ("plugin %s has _CLEAR_UPDATABLE, so removing from %s", + fu_plugin_get_name (self), + fu_device_get_id (device)); + fu_device_remove_flag (device, FWUPD_DEVICE_FLAG_UPDATABLE); + } + if (fu_plugin_has_flag (self, FWUPD_PLUGIN_FLAG_USER_WARNING) && + fu_device_get_update_error (device) == NULL) { + const gchar *tmp = fu_plugin_build_device_update_error (self); + g_debug ("setting %s update error to '%s' from %s", + fu_device_get_id (device), tmp, fu_plugin_get_name (self)); + fu_device_set_update_error (device, tmp); + } + g_debug ("emit added from %s: %s", fu_plugin_get_name (self), fu_device_get_id (device)); @@ -1139,7 +1174,7 @@ fu_plugin_runner_startup (FuPlugin *self, GError **error) g_autoptr(GError) error_local = NULL; /* not enabled */ - if (!priv->enabled) + if (fu_plugin_has_flag (self, FWUPD_PLUGIN_FLAG_DISABLED)) return TRUE; /* no object loaded */ @@ -1150,11 +1185,11 @@ fu_plugin_runner_startup (FuPlugin *self, GError **error) g_module_symbol (priv->module, "fu_plugin_startup", (gpointer *) &func); if (func == NULL) return TRUE; - g_debug ("startup(%s)", priv->name); + g_debug ("startup(%s)", fu_plugin_get_name (self)); if (!func (self, &error_local)) { if (error_local == NULL) { g_critical ("unset plugin error in startup(%s)", - priv->name); + fu_plugin_get_name (self)); g_set_error_literal (&error_local, FWUPD_ERROR, FWUPD_ERROR_INTERNAL, @@ -1162,7 +1197,7 @@ fu_plugin_runner_startup (FuPlugin *self, GError **error) } g_propagate_prefixed_error (error, g_steal_pointer (&error_local), "failed to startup using %s: ", - priv->name); + fu_plugin_get_name (self)); return FALSE; } return TRUE; @@ -1179,7 +1214,7 @@ fu_plugin_runner_device_generic (FuPlugin *self, FuDevice *device, g_autoptr(GError) error_local = NULL; /* not enabled */ - if (!priv->enabled) + if (fu_plugin_has_flag (self, FWUPD_PLUGIN_FLAG_DISABLED)) return TRUE; /* no object loaded */ @@ -1191,16 +1226,16 @@ fu_plugin_runner_device_generic (FuPlugin *self, FuDevice *device, if (func == NULL) { if (device_func != NULL) { g_debug ("running superclassed %s(%s)", - symbol_name + 10, priv->name); + symbol_name + 10, fu_plugin_get_name (self)); return device_func (self, device, error); } return TRUE; } - g_debug ("%s(%s)", symbol_name + 10, priv->name); + g_debug ("%s(%s)", symbol_name + 10, fu_plugin_get_name (self)); if (!func (self, device, &error_local)) { if (error_local == NULL) { g_critical ("unset plugin error in %s(%s)", - priv->name, symbol_name + 10); + fu_plugin_get_name (self), symbol_name + 10); g_set_error_literal (&error_local, FWUPD_ERROR, FWUPD_ERROR_INTERNAL, @@ -1208,7 +1243,7 @@ fu_plugin_runner_device_generic (FuPlugin *self, FuDevice *device, } g_propagate_prefixed_error (error, g_steal_pointer (&error_local), "failed to %s using %s: ", - symbol_name + 10, priv->name); + symbol_name + 10, fu_plugin_get_name (self)); return FALSE; } return TRUE; @@ -1224,7 +1259,7 @@ fu_plugin_runner_flagged_device_generic (FuPlugin *self, FwupdInstallFlags flags g_autoptr(GError) error_local = NULL; /* not enabled */ - if (!priv->enabled) + if (fu_plugin_has_flag (self, FWUPD_PLUGIN_FLAG_DISABLED)) return TRUE; /* no object loaded */ @@ -1235,11 +1270,11 @@ fu_plugin_runner_flagged_device_generic (FuPlugin *self, FwupdInstallFlags flags g_module_symbol (priv->module, symbol_name, (gpointer *) &func); if (func == NULL) return TRUE; - g_debug ("%s(%s)", symbol_name + 10, priv->name); + g_debug ("%s(%s)", symbol_name + 10, fu_plugin_get_name (self)); if (!func (self, flags, device, &error_local)) { if (error_local == NULL) { g_critical ("unset plugin error in %s(%s)", - priv->name, symbol_name + 10); + fu_plugin_get_name (self), symbol_name + 10); g_set_error_literal (&error_local, FWUPD_ERROR, FWUPD_ERROR_INTERNAL, @@ -1247,7 +1282,7 @@ fu_plugin_runner_flagged_device_generic (FuPlugin *self, FwupdInstallFlags flags } g_propagate_prefixed_error (error, g_steal_pointer (&error_local), "failed to %s using %s: ", - symbol_name + 10, priv->name); + symbol_name + 10, fu_plugin_get_name (self)); return FALSE; } return TRUE; @@ -1263,7 +1298,7 @@ fu_plugin_runner_device_array_generic (FuPlugin *self, GPtrArray *devices, g_autoptr(GError) error_local = NULL; /* not enabled */ - if (!priv->enabled) + if (fu_plugin_has_flag (self, FWUPD_PLUGIN_FLAG_DISABLED)) return TRUE; /* no object loaded */ @@ -1274,11 +1309,11 @@ fu_plugin_runner_device_array_generic (FuPlugin *self, GPtrArray *devices, g_module_symbol (priv->module, symbol_name, (gpointer *) &func); if (func == NULL) return TRUE; - g_debug ("%s(%s)", symbol_name + 10, priv->name); + g_debug ("%s(%s)", symbol_name + 10, fu_plugin_get_name (self)); if (!func (self, devices, &error_local)) { if (error_local == NULL) { g_critical ("unset plugin error in for %s(%s)", - priv->name, symbol_name + 10); + fu_plugin_get_name (self), symbol_name + 10); g_set_error_literal (&error_local, FWUPD_ERROR, FWUPD_ERROR_INTERNAL, @@ -1286,7 +1321,7 @@ fu_plugin_runner_device_array_generic (FuPlugin *self, GPtrArray *devices, } g_propagate_prefixed_error (error, g_steal_pointer (&error_local), "failed to %s using %s: ", - symbol_name + 10, priv->name); + symbol_name + 10, fu_plugin_get_name (self)); return FALSE; } return TRUE; @@ -1311,7 +1346,7 @@ fu_plugin_runner_coldplug (FuPlugin *self, GError **error) g_autoptr(GError) error_local = NULL; /* not enabled */ - if (!priv->enabled) + if (fu_plugin_has_flag (self, FWUPD_PLUGIN_FLAG_DISABLED)) return TRUE; /* no object loaded */ @@ -1322,18 +1357,18 @@ fu_plugin_runner_coldplug (FuPlugin *self, GError **error) g_module_symbol (priv->module, "fu_plugin_coldplug", (gpointer *) &func); if (func == NULL) return TRUE; - g_debug ("coldplug(%s)", priv->name); + g_debug ("coldplug(%s)", fu_plugin_get_name (self)); if (!func (self, &error_local)) { if (error_local == NULL) { g_critical ("unset plugin error in coldplug(%s)", - priv->name); + fu_plugin_get_name (self)); g_set_error_literal (&error_local, FWUPD_ERROR, FWUPD_ERROR_INTERNAL, "unspecified error"); } g_propagate_prefixed_error (error, g_steal_pointer (&error_local), - "failed to coldplug using %s: ", priv->name); + "failed to coldplug using %s: ", fu_plugin_get_name (self)); return FALSE; } return TRUE; @@ -1358,7 +1393,7 @@ fu_plugin_runner_recoldplug (FuPlugin *self, GError **error) g_autoptr(GError) error_local = NULL; /* not enabled */ - if (!priv->enabled) + if (fu_plugin_has_flag (self, FWUPD_PLUGIN_FLAG_DISABLED)) return TRUE; /* no object loaded */ @@ -1369,11 +1404,11 @@ fu_plugin_runner_recoldplug (FuPlugin *self, GError **error) g_module_symbol (priv->module, "fu_plugin_recoldplug", (gpointer *) &func); if (func == NULL) return TRUE; - g_debug ("recoldplug(%s)", priv->name); + g_debug ("recoldplug(%s)", fu_plugin_get_name (self)); if (!func (self, &error_local)) { if (error_local == NULL) { g_critical ("unset plugin error in recoldplug(%s)", - priv->name); + fu_plugin_get_name (self)); g_set_error_literal (&error_local, FWUPD_ERROR, FWUPD_ERROR_INTERNAL, @@ -1381,7 +1416,7 @@ fu_plugin_runner_recoldplug (FuPlugin *self, GError **error) } g_propagate_prefixed_error (error, g_steal_pointer (&error_local), "failed to recoldplug using %s: ", - priv->name); + fu_plugin_get_name (self)); return FALSE; } return TRUE; @@ -1406,7 +1441,7 @@ fu_plugin_runner_coldplug_prepare (FuPlugin *self, GError **error) g_autoptr(GError) error_local = NULL; /* not enabled */ - if (!priv->enabled) + if (fu_plugin_has_flag (self, FWUPD_PLUGIN_FLAG_DISABLED)) return TRUE; /* no object loaded */ @@ -1417,11 +1452,11 @@ fu_plugin_runner_coldplug_prepare (FuPlugin *self, GError **error) g_module_symbol (priv->module, "fu_plugin_coldplug_prepare", (gpointer *) &func); if (func == NULL) return TRUE; - g_debug ("coldplug_prepare(%s)", priv->name); + g_debug ("coldplug_prepare(%s)", fu_plugin_get_name (self)); if (!func (self, &error_local)) { if (error_local == NULL) { g_critical ("unset plugin error in coldplug_prepare(%s)", - priv->name); + fu_plugin_get_name (self)); g_set_error_literal (&error_local, FWUPD_ERROR, FWUPD_ERROR_INTERNAL, @@ -1429,7 +1464,7 @@ fu_plugin_runner_coldplug_prepare (FuPlugin *self, GError **error) } g_propagate_prefixed_error (error, g_steal_pointer (&error_local), "failed to coldplug_prepare using %s: ", - priv->name); + fu_plugin_get_name (self)); return FALSE; } return TRUE; @@ -1454,7 +1489,7 @@ fu_plugin_runner_coldplug_cleanup (FuPlugin *self, GError **error) g_autoptr(GError) error_local = NULL; /* not enabled */ - if (!priv->enabled) + if (fu_plugin_has_flag (self, FWUPD_PLUGIN_FLAG_DISABLED)) return TRUE; /* no object loaded */ @@ -1465,11 +1500,11 @@ fu_plugin_runner_coldplug_cleanup (FuPlugin *self, GError **error) g_module_symbol (priv->module, "fu_plugin_coldplug_cleanup", (gpointer *) &func); if (func == NULL) return TRUE; - g_debug ("coldplug_cleanup(%s)", priv->name); + g_debug ("coldplug_cleanup(%s)", fu_plugin_get_name (self)); if (!func (self, &error_local)) { if (error_local == NULL) { g_critical ("unset plugin error in coldplug_cleanup(%s)", - priv->name); + fu_plugin_get_name (self)); g_set_error_literal (&error_local, FWUPD_ERROR, FWUPD_ERROR_INTERNAL, @@ -1477,7 +1512,7 @@ fu_plugin_runner_coldplug_cleanup (FuPlugin *self, GError **error) } g_propagate_prefixed_error (error, g_steal_pointer (&error_local), "failed to coldplug_cleanup using %s: ", - priv->name); + fu_plugin_get_name (self)); return FALSE; } return TRUE; @@ -1619,11 +1654,10 @@ fu_plugin_runner_update_detach (FuPlugin *self, FuDevice *device, GError **error gboolean fu_plugin_runner_update_reload (FuPlugin *self, FuDevice *device, GError **error) { - FuPluginPrivate *priv = GET_PRIVATE (self); g_autoptr(FuDeviceLocker) locker = NULL; /* not enabled */ - if (!priv->enabled) + if (fu_plugin_has_flag (self, FWUPD_PLUGIN_FLAG_DISABLED)) return TRUE; /* no object loaded */ @@ -1657,7 +1691,7 @@ fu_plugin_runner_add_security_attrs (FuPlugin *self, FuSecurityAttrs *attrs) g_module_symbol (priv->module, symbol_name, (gpointer *) &func); if (func == NULL) return; - g_debug ("%s(%s)", symbol_name + 10, priv->name); + g_debug ("%s(%s)", symbol_name + 10, fu_plugin_get_name (self)); func (self, attrs); } @@ -1839,7 +1873,7 @@ fu_plugin_runner_usb_device_added (FuPlugin *self, FuUsbDevice *device, GError * g_autoptr(GError) error_local = NULL; /* not enabled */ - if (!priv->enabled) + if (fu_plugin_has_flag (self, FWUPD_PLUGIN_FLAG_DISABLED)) return TRUE; /* no object loaded */ @@ -1856,11 +1890,11 @@ fu_plugin_runner_usb_device_added (FuPlugin *self, FuUsbDevice *device, GError * } return TRUE; } - g_debug ("usb_device_added(%s)", priv->name); + g_debug ("usb_device_added(%s)", fu_plugin_get_name (self)); if (!func (self, device, &error_local)) { if (error_local == NULL) { g_critical ("unset plugin error in usb_device_added(%s)", - priv->name); + fu_plugin_get_name (self)); g_set_error_literal (&error_local, FWUPD_ERROR, FWUPD_ERROR_INTERNAL, @@ -1868,7 +1902,7 @@ fu_plugin_runner_usb_device_added (FuPlugin *self, FuUsbDevice *device, GError * } g_propagate_prefixed_error (error, g_steal_pointer (&error_local), "failed to add device using on %s: ", - priv->name); + fu_plugin_get_name (self)); return FALSE; } return TRUE; @@ -1894,7 +1928,7 @@ fu_plugin_runner_udev_device_added (FuPlugin *self, FuUdevDevice *device, GError g_autoptr(GError) error_local = NULL; /* not enabled */ - if (!priv->enabled) + if (fu_plugin_has_flag (self, FWUPD_PLUGIN_FLAG_DISABLED)) return TRUE; /* no object loaded */ @@ -1911,11 +1945,11 @@ fu_plugin_runner_udev_device_added (FuPlugin *self, FuUdevDevice *device, GError } return TRUE; } - g_debug ("udev_device_added(%s)", priv->name); + g_debug ("udev_device_added(%s)", fu_plugin_get_name (self)); if (!func (self, device, &error_local)) { if (error_local == NULL) { g_critical ("unset plugin error in udev_device_added(%s)", - priv->name); + fu_plugin_get_name (self)); g_set_error_literal (&error_local, FWUPD_ERROR, FWUPD_ERROR_INTERNAL, @@ -1923,7 +1957,7 @@ fu_plugin_runner_udev_device_added (FuPlugin *self, FuUdevDevice *device, GError } g_propagate_prefixed_error (error, g_steal_pointer (&error_local), "failed to add device using on %s: ", - priv->name); + fu_plugin_get_name (self)); return FALSE; } return TRUE; @@ -1949,7 +1983,7 @@ fu_plugin_runner_udev_device_changed (FuPlugin *self, FuUdevDevice *device, GErr g_autoptr(GError) error_local = NULL; /* not enabled */ - if (!priv->enabled) + if (fu_plugin_has_flag (self, FWUPD_PLUGIN_FLAG_DISABLED)) return TRUE; /* no object loaded */ @@ -1960,11 +1994,11 @@ fu_plugin_runner_udev_device_changed (FuPlugin *self, FuUdevDevice *device, GErr g_module_symbol (priv->module, "fu_plugin_udev_device_changed", (gpointer *) &func); if (func == NULL) return TRUE; - g_debug ("udev_device_changed(%s)", priv->name); + g_debug ("udev_device_changed(%s)", fu_plugin_get_name (self)); if (!func (self, device, &error_local)) { if (error_local == NULL) { g_critical ("unset plugin error in udev_device_changed(%s)", - priv->name); + fu_plugin_get_name (self)); g_set_error_literal (&error_local, FWUPD_ERROR, FWUPD_ERROR_INTERNAL, @@ -1972,7 +2006,7 @@ fu_plugin_runner_udev_device_changed (FuPlugin *self, FuUdevDevice *device, GErr } g_propagate_prefixed_error (error, g_steal_pointer (&error_local), "failed to change device on %s: ", - priv->name); + fu_plugin_get_name (self)); return FALSE; } return TRUE; @@ -1994,7 +2028,7 @@ fu_plugin_runner_device_added (FuPlugin *self, FuDevice *device) FuPluginDeviceRegisterFunc func = NULL; /* not enabled */ - if (!priv->enabled) + if (fu_plugin_has_flag (self, FWUPD_PLUGIN_FLAG_DISABLED)) return; if (priv->module == NULL) return; @@ -2003,7 +2037,7 @@ fu_plugin_runner_device_added (FuPlugin *self, FuDevice *device) g_module_symbol (priv->module, "fu_plugin_device_added", (gpointer *) &func); if (func == NULL) return; - g_debug ("fu_plugin_device_added(%s)", priv->name); + g_debug ("fu_plugin_device_added(%s)", fu_plugin_get_name (self)); func (self, device); } @@ -2044,7 +2078,7 @@ fu_plugin_runner_device_register (FuPlugin *self, FuDevice *device) FuPluginDeviceRegisterFunc func = NULL; /* not enabled */ - if (!priv->enabled) + if (fu_plugin_has_flag (self, FWUPD_PLUGIN_FLAG_DISABLED)) return; if (priv->module == NULL) return; @@ -2056,7 +2090,7 @@ fu_plugin_runner_device_register (FuPlugin *self, FuDevice *device) /* optional */ g_module_symbol (priv->module, "fu_plugin_device_registered", (gpointer *) &func); if (func != NULL) { - g_debug ("fu_plugin_device_registered(%s)", priv->name); + g_debug ("fu_plugin_device_registered(%s)", fu_plugin_get_name (self)); func (self, device); } } @@ -2080,7 +2114,7 @@ fu_plugin_runner_device_created (FuPlugin *self, FuDevice *device, GError **erro FuPluginDeviceFunc func = NULL; /* not enabled */ - if (!priv->enabled) + if (fu_plugin_has_flag (self, FWUPD_PLUGIN_FLAG_DISABLED)) return TRUE; if (priv->module == NULL) return TRUE; @@ -2089,7 +2123,7 @@ fu_plugin_runner_device_created (FuPlugin *self, FuDevice *device, GError **erro g_module_symbol (priv->module, "fu_plugin_device_created", (gpointer *) &func); if (func == NULL) return TRUE; - g_debug ("fu_plugin_device_created(%s)", priv->name); + g_debug ("fu_plugin_device_created(%s)", fu_plugin_get_name (self)); return func (self, device, error); } @@ -2118,7 +2152,7 @@ fu_plugin_runner_verify (FuPlugin *self, g_autoptr(GError) error_local = NULL; /* not enabled */ - if (!priv->enabled) + if (fu_plugin_has_flag (self, FWUPD_PLUGIN_FLAG_DISABLED)) return TRUE; /* no object loaded */ @@ -2143,12 +2177,12 @@ fu_plugin_runner_verify (FuPlugin *self, return FALSE; /* run vfunc */ - g_debug ("verify(%s)", priv->name); + g_debug ("verify(%s)", fu_plugin_get_name (self)); if (!func (self, device, flags, &error_local)) { g_autoptr(GError) error_attach = NULL; if (error_local == NULL) { g_critical ("unset plugin error in verify(%s)", - priv->name); + fu_plugin_get_name (self)); g_set_error_literal (&error_local, FWUPD_ERROR, FWUPD_ERROR_INTERNAL, @@ -2156,7 +2190,7 @@ fu_plugin_runner_verify (FuPlugin *self, } g_propagate_prefixed_error (error, g_steal_pointer (&error_local), "failed to verify using %s: ", - priv->name); + fu_plugin_get_name (self)); /* make the device "work" again, but don't prefix the error */ if (!fu_plugin_runner_device_generic (self, device, "fu_plugin_update_attach", @@ -2288,7 +2322,7 @@ fu_plugin_runner_update (FuPlugin *self, g_autoptr(GError) error_local = NULL; /* not enabled */ - if (!priv->enabled) { + if (fu_plugin_has_flag (self, FWUPD_PLUGIN_FLAG_DISABLED)) { g_debug ("plugin not enabled, skipping"); return TRUE; } @@ -2302,7 +2336,7 @@ fu_plugin_runner_update (FuPlugin *self, /* optional */ g_module_symbol (priv->module, "fu_plugin_update", (gpointer *) &update_func); if (update_func == NULL) { - g_debug ("superclassed write_firmware(%s)", priv->name); + g_debug ("superclassed write_firmware(%s)", fu_plugin_get_name (self)); return fu_plugin_device_write_firmware (self, device, blob_fw, flags, error); } @@ -2310,7 +2344,7 @@ fu_plugin_runner_update (FuPlugin *self, if (!update_func (self, device, blob_fw, flags, &error_local)) { if (error_local == NULL) { g_critical ("unset plugin error in update(%s)", - priv->name); + fu_plugin_get_name (self)); g_set_error_literal (&error_local, FWUPD_ERROR, FWUPD_ERROR_INTERNAL, @@ -2353,7 +2387,7 @@ fu_plugin_runner_clear_results (FuPlugin *self, FuDevice *device, GError **error g_autoptr(GError) error_local = NULL; /* not enabled */ - if (!priv->enabled) + if (fu_plugin_has_flag (self, FWUPD_PLUGIN_FLAG_DISABLED)) return TRUE; /* no object loaded */ @@ -2364,11 +2398,11 @@ fu_plugin_runner_clear_results (FuPlugin *self, FuDevice *device, GError **error g_module_symbol (priv->module, "fu_plugin_clear_results", (gpointer *) &func); if (func == NULL) return TRUE; - g_debug ("clear_result(%s)", priv->name); + g_debug ("clear_result(%s)", fu_plugin_get_name (self)); if (!func (self, device, &error_local)) { if (error_local == NULL) { g_critical ("unset plugin error in clear_result(%s)", - priv->name); + fu_plugin_get_name (self)); g_set_error_literal (&error_local, FWUPD_ERROR, FWUPD_ERROR_INTERNAL, @@ -2376,7 +2410,7 @@ fu_plugin_runner_clear_results (FuPlugin *self, FuDevice *device, GError **error } g_propagate_prefixed_error (error, g_steal_pointer (&error_local), "failed to clear_result using %s: ", - priv->name); + fu_plugin_get_name (self)); return FALSE; } return TRUE; @@ -2402,7 +2436,7 @@ fu_plugin_runner_get_results (FuPlugin *self, FuDevice *device, GError **error) g_autoptr(GError) error_local = NULL; /* not enabled */ - if (!priv->enabled) + if (fu_plugin_has_flag (self, FWUPD_PLUGIN_FLAG_DISABLED)) return TRUE; /* no object loaded */ @@ -2413,11 +2447,11 @@ fu_plugin_runner_get_results (FuPlugin *self, FuDevice *device, GError **error) g_module_symbol (priv->module, "fu_plugin_get_results", (gpointer *) &func); if (func == NULL) return TRUE; - g_debug ("get_results(%s)", priv->name); + g_debug ("get_results(%s)", fu_plugin_get_name (self)); if (!func (self, device, &error_local)) { if (error_local == NULL) { g_critical ("unset plugin error in get_results(%s)", - priv->name); + fu_plugin_get_name (self)); g_set_error_literal (&error_local, FWUPD_ERROR, FWUPD_ERROR_INTERNAL, @@ -2425,7 +2459,7 @@ fu_plugin_runner_get_results (FuPlugin *self, FuDevice *device, GError **error) } g_propagate_prefixed_error (error, g_steal_pointer (&error_local), "failed to get_results using %s: ", - priv->name); + fu_plugin_get_name (self)); return FALSE; } return TRUE; @@ -2678,9 +2712,7 @@ fu_plugin_get_config_value_boolean (FuPlugin *self, const gchar *key) gint fu_plugin_name_compare (FuPlugin *plugin1, FuPlugin *plugin2) { - FuPluginPrivate *priv1 = fu_plugin_get_instance_private (plugin1); - FuPluginPrivate *priv2 = fu_plugin_get_instance_private (plugin2); - return g_strcmp0 (priv1->name, priv2->name); + return g_strcmp0 (fu_plugin_get_name (plugin1), fu_plugin_get_name (plugin2)); } /** @@ -2771,7 +2803,6 @@ static void fu_plugin_init (FuPlugin *self) { FuPluginPrivate *priv = GET_PRIVATE (self); - priv->enabled = TRUE; g_rw_lock_init (&priv->devices_mutex); } @@ -2788,7 +2819,7 @@ fu_plugin_finalize (GObject *object) if (priv->module != NULL) { g_module_symbol (priv->module, "fu_plugin_destroy", (gpointer *) &func); if (func != NULL) { - g_debug ("destroy(%s)", priv->name); + g_debug ("destroy(%s)", fu_plugin_get_name (self)); func (self); } } @@ -2816,7 +2847,6 @@ fu_plugin_finalize (GObject *object) if (priv->devices != NULL) g_hash_table_unref (priv->devices); g_free (priv->build_hash); - g_free (priv->name); g_free (priv->data); /* Must happen as the last step to avoid prematurely * freeing memory held by the plugin */ diff --git a/libfwupdplugin/fu-plugin.h b/libfwupdplugin/fu-plugin.h index 671d5a12d..0b232eb8d 100644 --- a/libfwupdplugin/fu-plugin.h +++ b/libfwupdplugin/fu-plugin.h @@ -22,13 +22,18 @@ #include "fu-udev-device.h" #endif #include "fwupd-common.h" +#include "fwupd-plugin.h" #define FU_TYPE_PLUGIN (fu_plugin_get_type ()) -G_DECLARE_DERIVABLE_TYPE (FuPlugin, fu_plugin, FU, PLUGIN, GObject) +G_DECLARE_DERIVABLE_TYPE (FuPlugin, fu_plugin, FU, PLUGIN, FwupdPlugin) + +#define fu_plugin_get_flags(p) fwupd_plugin_get_flags(FWUPD_PLUGIN(p)) +#define fu_plugin_has_flag(p,f) fwupd_plugin_has_flag(FWUPD_PLUGIN(p),f) +#define fu_plugin_add_flag(p,f) fwupd_plugin_add_flag(FWUPD_PLUGIN(p),f) struct _FuPluginClass { - GObjectClass parent_class; + FwupdPluginClass parent_class; /* signals */ void (* device_added) (FuPlugin *self, FuDevice *device); @@ -96,9 +101,11 @@ const gchar *fu_plugin_get_name (FuPlugin *self); FuPluginData *fu_plugin_get_data (FuPlugin *self); FuPluginData *fu_plugin_alloc_data (FuPlugin *self, gsize data_sz); -gboolean fu_plugin_get_enabled (FuPlugin *self); +gboolean fu_plugin_get_enabled (FuPlugin *self) +G_DEPRECATED_FOR(fu_plugin_has_flag); void fu_plugin_set_enabled (FuPlugin *self, - gboolean enabled); + gboolean enabled) +G_DEPRECATED_FOR(fu_plugin_add_flag); void fu_plugin_set_build_hash (FuPlugin *self, const gchar *build_hash); GUsbContext *fu_plugin_get_usb_context (FuPlugin *self); diff --git a/plugins/bios/fu-plugin-bios.c b/plugins/bios/fu-plugin-bios.c index b229bd627..ef8bbddb1 100644 --- a/plugins/bios/fu-plugin-bios.c +++ b/plugins/bios/fu-plugin-bios.c @@ -16,7 +16,6 @@ fu_plugin_init (FuPlugin *plugin) fu_plugin_set_build_hash (plugin, FU_BUILD_HASH); } - gboolean fu_plugin_startup (FuPlugin *plugin, GError **error) { @@ -34,41 +33,6 @@ fu_plugin_startup (FuPlugin *plugin, GError **error) return TRUE; } - -static gboolean -fu_plugin_bios_create_dummy (FuPlugin *plugin, const gchar *reason, GError **error) -{ - const gchar *key; - g_autoptr(FuDevice) dev = fu_device_new (); - - fu_device_set_version_format (dev, FWUPD_VERSION_FORMAT_PLAIN); - key = fu_plugin_get_dmi_value (plugin, FU_HWIDS_KEY_MANUFACTURER); - if (key != NULL) - fu_device_set_vendor (dev, key); - key = fu_plugin_get_dmi_value (plugin, FU_HWIDS_KEY_BIOS_VENDOR); - if (key != NULL) { - g_autofree gchar *vendor_id = g_strdup_printf ("DMI:%s", key); - fu_device_set_vendor_id (FU_DEVICE (dev), vendor_id); - } - key = "System Firmware"; - fu_device_set_name (dev, key); - key = fu_plugin_get_dmi_value (plugin, FU_HWIDS_KEY_BIOS_VERSION); - if (key != NULL) - fu_device_set_version (dev, key); - fu_device_set_update_error (dev, reason); - - fu_device_add_flag (dev, FWUPD_DEVICE_FLAG_INTERNAL); - - fu_device_add_icon (dev, "computer"); - fu_device_set_id (dev, "BIOS-dummy"); - fu_device_add_instance_id (dev, "main-system-firmware"); - if (!fu_device_setup (dev, error)) - return FALSE; - fu_plugin_device_add (plugin, dev); - - return TRUE; -} - gboolean fu_plugin_coldplug (FuPlugin *plugin, GError **error) { @@ -79,9 +43,9 @@ fu_plugin_coldplug (FuPlugin *plugin, GError **error) #if defined(__x86_64__) || defined(__i386__) g_autoptr(GError) error_local = NULL; if (!fu_efivar_supported (&error_local)) { - const gchar *reason = "Firmware can not be updated in legacy BIOS mode, switch to UEFI mode"; - g_warning ("%s", error_local->message); - return fu_plugin_bios_create_dummy (plugin, reason, error); + fu_plugin_add_flag (plugin, FWUPD_PLUGIN_FLAG_LEGACY_BIOS); + fu_plugin_add_flag (plugin, FWUPD_PLUGIN_FLAG_USER_WARNING); + return TRUE; } #endif @@ -89,12 +53,12 @@ fu_plugin_coldplug (FuPlugin *plugin, GError **error) sysfsfwdir = fu_common_get_path (FU_PATH_KIND_SYSFSDIR_FW); esrt_path = g_build_filename (sysfsfwdir, "efi", "esrt", NULL); if (!g_file_test (esrt_path, G_FILE_TEST_IS_DIR)) { - const gchar *reason = "UEFI Capsule updates not available or enabled"; - return fu_plugin_bios_create_dummy (plugin, reason, error); + fu_plugin_add_flag (plugin, FWUPD_PLUGIN_FLAG_CAPSULES_UNSUPPORTED); + fu_plugin_add_flag (plugin, FWUPD_PLUGIN_FLAG_USER_WARNING); + return TRUE; } /* we appear to have UEFI capsule updates */ - fu_plugin_set_enabled (plugin, FALSE); - + fu_plugin_add_flag (plugin, FWUPD_PLUGIN_FLAG_DISABLED); return TRUE; } diff --git a/plugins/dell/fu-plugin-dell.c b/plugins/dell/fu-plugin-dell.c index 90ba57c57..3b500da24 100644 --- a/plugins/dell/fu-plugin-dell.c +++ b/plugins/dell/fu-plugin-dell.c @@ -286,9 +286,6 @@ fu_plugin_dock_node (FuPlugin *plugin, const gchar *platform, if (fu_plugin_dell_capsule_supported (plugin)) { fu_device_add_flag (dev, FWUPD_DEVICE_FLAG_UPDATABLE); fu_device_add_flag (dev, FWUPD_DEVICE_FLAG_NEEDS_REBOOT); - } else { - fu_device_set_update_error (dev, - "UEFI capsule updates turned off in BIOS setup"); } } @@ -734,9 +731,6 @@ fu_plugin_dell_detect_tpm (FuPlugin *plugin, GError **error) if (fu_plugin_dell_capsule_supported (plugin)) { fu_device_add_flag (dev, FWUPD_DEVICE_FLAG_UPDATABLE); fu_device_add_flag (dev, FWUPD_DEVICE_FLAG_NEEDS_REBOOT); - } else { - fu_device_set_update_error (dev, - "UEFI capsule updates turned off in BIOS setup"); } fu_device_set_flashes_left (dev, out->flashes_left); } else { @@ -892,10 +886,14 @@ fu_plugin_startup (FuPlugin *plugin, GError **error) */ sysfsfwdir = fu_common_get_path (FU_PATH_KIND_SYSFSDIR_FW); esrtdir = g_build_filename (sysfsfwdir, "efi", "esrt", NULL); - if (g_file_test (esrtdir, G_FILE_TEST_EXISTS)) { + if (g_file_test (esrtdir, G_FILE_TEST_EXISTS)) data->capsule_supported = TRUE; - } else { - g_debug ("UEFI capsule firmware updating not supported"); + + /* capsules not supported */ + if (!fu_plugin_dell_capsule_supported (plugin)) { + fu_plugin_add_flag (plugin, FWUPD_PLUGIN_FLAG_USER_WARNING); + fu_plugin_add_flag (plugin, FWUPD_PLUGIN_FLAG_CLEAR_UPDATABLE); + fu_plugin_add_flag (plugin, FWUPD_PLUGIN_FLAG_CAPSULES_UNSUPPORTED); } return TRUE; diff --git a/plugins/tpm-eventlog/fu-plugin-tpm-eventlog.c b/plugins/tpm-eventlog/fu-plugin-tpm-eventlog.c index aed42f21c..c03713611 100644 --- a/plugins/tpm-eventlog/fu-plugin-tpm-eventlog.c +++ b/plugins/tpm-eventlog/fu-plugin-tpm-eventlog.c @@ -147,7 +147,7 @@ fu_plugin_add_security_attrs (FuPlugin *plugin, FuSecurityAttrs *attrs) fu_security_attrs_append (attrs, attr); /* check reconstructed to PCR0 */ - if (!fu_plugin_get_enabled (plugin) || !data->has_uefi_device) { + if (fu_plugin_has_flag (plugin, FWUPD_PLUGIN_FLAG_DISABLED) || !data->has_uefi_device) { fwupd_security_attr_set_result (attr, FWUPD_SECURITY_ATTR_RESULT_NOT_FOUND); return; } diff --git a/plugins/uefi/fu-plugin-uefi.c b/plugins/uefi/fu-plugin-uefi.c index 087932a2f..0be6e1614 100644 --- a/plugins/uefi/fu-plugin-uefi.c +++ b/plugins/uefi/fu-plugin-uefi.c @@ -758,13 +758,21 @@ fu_plugin_coldplug (FuPlugin *plugin, GError **error) return FALSE; /* make sure that efivarfs is rw */ - if (!fu_plugin_uefi_ensure_efivarfs_rw (&error_efivarfs)) + if (!fu_plugin_uefi_ensure_efivarfs_rw (&error_efivarfs)) { + fu_plugin_add_flag (plugin, FWUPD_PLUGIN_FLAG_EFIVAR_NOT_MOUNTED); + fu_plugin_add_flag (plugin, FWUPD_PLUGIN_FLAG_CLEAR_UPDATABLE); + fu_plugin_add_flag (plugin, FWUPD_PLUGIN_FLAG_USER_WARNING); g_warning ("%s", error_efivarfs->message); + } if (data->esp == NULL) { data->esp = fu_common_get_esp_default (&error_udisks2); - if (data->esp == NULL) + if (data->esp == NULL) { + fu_plugin_add_flag (plugin, FWUPD_PLUGIN_FLAG_ESP_NOT_FOUND); + fu_plugin_add_flag (plugin, FWUPD_PLUGIN_FLAG_CLEAR_UPDATABLE); + fu_plugin_add_flag (plugin, FWUPD_PLUGIN_FLAG_USER_WARNING); g_warning ("cannot find default ESP: %s", error_udisks2->message); + } } /* add each device */ @@ -781,14 +789,9 @@ fu_plugin_coldplug (FuPlugin *plugin, GError **error) fu_uefi_device_set_esp (FU_UEFI_DEVICE (dev), data->esp); if (!fu_plugin_uefi_coldplug_device (plugin, dev, error)) return FALSE; - if (error_efivarfs != NULL) { - fu_device_set_update_error (FU_DEVICE (dev), error_efivarfs->message); - } else if (error_udisks2 != NULL) { - fu_device_set_update_error (FU_DEVICE (dev), error_udisks2->message); - } else { - fu_device_add_flag (FU_DEVICE (dev), FWUPD_DEVICE_FLAG_UPDATABLE); - fu_device_add_flag (FU_DEVICE (dev), FWUPD_DEVICE_FLAG_USABLE_DURING_UPDATE); - } + fu_device_add_flag (FU_DEVICE (dev), FWUPD_DEVICE_FLAG_UPDATABLE); + fu_device_add_flag (FU_DEVICE (dev), FWUPD_DEVICE_FLAG_USABLE_DURING_UPDATE); + /* load all configuration variables */ fu_plugin_uefi_load_config (plugin, FU_DEVICE (dev)); fu_plugin_device_add (plugin, FU_DEVICE (dev)); diff --git a/src/fu-engine.c b/src/fu-engine.c index 9188a9560..c7f6aa012 100644 --- a/src/fu-engine.c +++ b/src/fu-engine.c @@ -4899,7 +4899,12 @@ fu_engine_plugins_setup (FuEngine *self) g_autoptr(GError) error = NULL; FuPlugin *plugin = g_ptr_array_index (plugins, i); if (!fu_plugin_runner_startup (plugin, &error)) { - fu_plugin_set_enabled (plugin, FALSE); + fu_plugin_add_flag (plugin, FWUPD_PLUGIN_FLAG_DISABLED); + if (g_error_matches (error, + FWUPD_ERROR, + FWUPD_ERROR_NOT_SUPPORTED)) { + fu_plugin_add_flag (plugin, FWUPD_PLUGIN_FLAG_NO_HARDWARE); + } g_message ("disabling plugin because: %s", error->message); } } @@ -4938,7 +4943,7 @@ fu_engine_plugins_coldplug (FuEngine *self, gboolean is_recoldplug) g_message ("failed recoldplug: %s", error->message); } else { if (!fu_plugin_runner_coldplug (plugin, &error)) { - fu_plugin_set_enabled (plugin, FALSE); + fu_plugin_add_flag (plugin, FWUPD_PLUGIN_FLAG_DISABLED); g_message ("disabling plugin because: %s", error->message); } @@ -4956,7 +4961,7 @@ fu_engine_plugins_coldplug (FuEngine *self, gboolean is_recoldplug) /* print what we do have */ for (guint i = 0; i < plugins->len; i++) { FuPlugin *plugin = g_ptr_array_index (plugins, i); - if (!fu_plugin_get_enabled (plugin)) + if (fu_plugin_has_flag (plugin, FWUPD_PLUGIN_FLAG_DISABLED)) continue; g_string_append_printf (str, "%s, ", fu_plugin_get_name (plugin)); } @@ -5843,8 +5848,7 @@ fu_engine_load_plugins (FuEngine *self, GError **error) g_autofree gchar *plugin_path = NULL; g_autofree gchar *suffix = g_strdup_printf (".%s", G_MODULE_SUFFIX); g_autoptr(GPtrArray) plugins_disabled = g_ptr_array_new_with_free_func (g_free); - g_autoptr(GPtrArray) plugins_not_enabled = g_ptr_array_new_with_free_func (g_free); - g_autoptr(GPtrArray) plugins_self_disabled = g_ptr_array_new_with_free_func (g_free); + g_autoptr(GPtrArray) plugins_disabled_rt = g_ptr_array_new_with_free_func (g_free); /* search */ plugin_path = fu_common_get_path (FU_PATH_KIND_PLUGINDIR_PKG); @@ -5865,14 +5869,11 @@ fu_engine_load_plugins (FuEngine *self, GError **error) name = fu_plugin_guess_name_from_fn (fn); if (name == NULL) continue; - if (fu_engine_is_plugin_name_disabled (self, name)) { + if (fu_engine_is_plugin_name_disabled (self, name) || + !fu_engine_is_plugin_name_enabled (self, name)) { g_ptr_array_add (plugins_disabled, g_steal_pointer (&name)); continue; } - if (!fu_engine_is_plugin_name_enabled (self, name)) { - g_ptr_array_add (plugins_not_enabled, g_steal_pointer (&name)); - continue; - } /* open module */ filename = g_build_filename (plugin_path, fn, NULL); @@ -5897,9 +5898,9 @@ fu_engine_load_plugins (FuEngine *self, GError **error) } } - /* self disabled */ - if (!fu_plugin_get_enabled (plugin)) { - g_ptr_array_add (plugins_self_disabled, g_steal_pointer (&name)); + /* runtime disabled */ + if (fu_plugin_has_flag (plugin, FWUPD_PLUGIN_FLAG_DISABLED)) { + g_ptr_array_add (plugins_disabled_rt, g_steal_pointer (&name)); continue; } @@ -5940,17 +5941,11 @@ fu_engine_load_plugins (FuEngine *self, GError **error) str = g_strjoinv (", ", (gchar **) plugins_disabled->pdata); g_debug ("plugins disabled: %s", str); } - if (plugins_not_enabled->len > 0) { + if (plugins_disabled_rt->len > 0) { g_autofree gchar *str = NULL; - g_ptr_array_add (plugins_not_enabled, NULL); - str = g_strjoinv (", ", (gchar **) plugins_not_enabled->pdata); - g_debug ("plugins not-enabled: %s", str); - } - if (plugins_self_disabled->len > 0) { - g_autofree gchar *str = NULL; - g_ptr_array_add (plugins_self_disabled, NULL); - str = g_strjoinv (", ", (gchar **) plugins_self_disabled->pdata); - g_debug ("plugins self-disabled: %s", str); + g_ptr_array_add (plugins_disabled_rt, NULL); + str = g_strjoinv (", ", (gchar **) plugins_disabled_rt->pdata); + g_debug ("plugins runtime-disabled: %s", str); } /* depsolve into the correct order */ diff --git a/src/fu-main.c b/src/fu-main.c index de6c3d237..0af2288c5 100644 --- a/src/fu-main.c +++ b/src/fu-main.c @@ -20,6 +20,7 @@ #include #include "fwupd-device-private.h" +#include "fwupd-plugin-private.h" #include "fwupd-security-attr-private.h" #include "fwupd-release-private.h" #include "fwupd-remote-private.h" @@ -269,6 +270,22 @@ fu_main_device_array_to_variant (FuMainPrivate *priv, FuEngineRequest *request, return g_variant_new ("(aa{sv})", &builder); } +static GVariant * +fu_main_plugin_array_to_variant (GPtrArray *plugins) +{ + GVariantBuilder builder; + + g_return_val_if_fail (plugins->len > 0, NULL); + g_variant_builder_init (&builder, G_VARIANT_TYPE_ARRAY); + + for (guint i = 0; i < plugins->len; i++) { + FuDevice *plugin = g_ptr_array_index (plugins, i); + GVariant *tmp = fwupd_plugin_to_variant (FWUPD_PLUGIN (plugin)); + g_variant_builder_add_value (&builder, tmp); + } + return g_variant_new ("(aa{sv})", &builder); +} + static GVariant * fu_main_release_array_to_variant (GPtrArray *results) { @@ -882,6 +899,12 @@ fu_main_daemon_method_call (GDBusConnection *connection, const gchar *sender, g_dbus_method_invocation_return_value (invocation, val); return; } + if (g_strcmp0 (method_name, "GetPlugins") == 0) { + g_debug ("Called %s()", method_name); + val = fu_main_plugin_array_to_variant (fu_engine_get_plugins (priv->engine)); + g_dbus_method_invocation_return_value (invocation, val); + return; + } if (g_strcmp0 (method_name, "GetReleases") == 0) { const gchar *device_id; g_autoptr(GPtrArray) releases = NULL; diff --git a/src/fu-plugin-list.c b/src/fu-plugin-list.c index 5283a5278..777bbe0c4 100644 --- a/src/fu-plugin-list.c +++ b/src/fu-plugin-list.c @@ -157,7 +157,7 @@ fu_plugin_list_depsolve (FuPluginList *self, GError **error) fu_plugin_get_name (plugin)); continue; } - if (!fu_plugin_get_enabled (dep)) + if (fu_plugin_has_flag (dep, FWUPD_PLUGIN_FLAG_DISABLED)) continue; if (fu_plugin_get_order (plugin) <= fu_plugin_get_order (dep)) { g_debug ("%s [%u] to be ordered after %s [%u] " @@ -187,7 +187,7 @@ fu_plugin_list_depsolve (FuPluginList *self, GError **error) fu_plugin_get_name (plugin)); continue; } - if (!fu_plugin_get_enabled (dep)) + if (fu_plugin_has_flag (dep, FWUPD_PLUGIN_FLAG_DISABLED)) continue; if (fu_plugin_get_order (plugin) >= fu_plugin_get_order (dep)) { g_debug ("%s [%u] to be ordered before %s [%u] " @@ -219,7 +219,7 @@ fu_plugin_list_depsolve (FuPluginList *self, GError **error) fu_plugin_get_name (plugin)); continue; } - if (!fu_plugin_get_enabled (dep)) + if (fu_plugin_has_flag (dep, FWUPD_PLUGIN_FLAG_DISABLED)) continue; if (fu_plugin_get_priority (plugin) <= fu_plugin_get_priority (dep)) { g_debug ("%s [%u] better than %s [%u] " @@ -248,7 +248,7 @@ fu_plugin_list_depsolve (FuPluginList *self, GError **error) /* check for conflicts */ for (guint i = 0; i < self->plugins->len; i++) { FuPlugin *plugin = g_ptr_array_index (self->plugins, i); - if (!fu_plugin_get_enabled (plugin)) + if (fu_plugin_has_flag (plugin, FWUPD_PLUGIN_FLAG_DISABLED)) continue; deps = fu_plugin_get_rules (plugin, FU_PLUGIN_RULE_CONFLICTS); if (deps == NULL) @@ -258,12 +258,12 @@ fu_plugin_list_depsolve (FuPluginList *self, GError **error) dep = fu_plugin_list_find_by_name (self, plugin_name, NULL); if (dep == NULL) continue; - if (!fu_plugin_get_enabled (dep)) + if (fu_plugin_has_flag (dep, FWUPD_PLUGIN_FLAG_DISABLED)) continue; g_debug ("disabling %s as conflicts with %s", fu_plugin_get_name (dep), fu_plugin_get_name (plugin)); - fu_plugin_set_enabled (dep, FALSE); + fu_plugin_add_flag (dep, FWUPD_PLUGIN_FLAG_DISABLED); } } diff --git a/src/fu-self-test.c b/src/fu-self-test.c index 903edba41..0caaf197d 100644 --- a/src/fu-self-test.c +++ b/src/fu-self-test.c @@ -2395,7 +2395,7 @@ fu_plugin_list_depsolve_func (gconstpointer user_data) plugin = g_ptr_array_index (plugins, 0); g_assert_cmpstr (fu_plugin_get_name (plugin), ==, "plugin2"); g_assert_cmpint (fu_plugin_get_order (plugin), ==, 0); - g_assert (fu_plugin_get_enabled (plugin)); + g_assert_false (fu_plugin_has_flag (plugin, FWUPD_PLUGIN_FLAG_DISABLED)); /* add another rule, then re-depsolve */ fu_plugin_add_rule (plugin1, FU_PLUGIN_RULE_CONFLICTS, "plugin2"); @@ -2405,11 +2405,11 @@ fu_plugin_list_depsolve_func (gconstpointer user_data) plugin = fu_plugin_list_find_by_name (plugin_list, "plugin1", &error); g_assert_no_error (error); g_assert (plugin != NULL); - g_assert (fu_plugin_get_enabled (plugin)); + g_assert_false (fu_plugin_has_flag (plugin, FWUPD_PLUGIN_FLAG_DISABLED)); plugin = fu_plugin_list_find_by_name (plugin_list, "plugin2", &error); g_assert_no_error (error); g_assert (plugin != NULL); - g_assert (!fu_plugin_get_enabled (plugin)); + g_assert_true (fu_plugin_has_flag (plugin, FWUPD_PLUGIN_FLAG_DISABLED)); } static void diff --git a/src/fu-tool.c b/src/fu-tool.c index 8bde01271..b6a534bcd 100644 --- a/src/fu-tool.c +++ b/src/fu-tool.c @@ -120,6 +120,40 @@ fu_util_save_current_state (FuUtilPrivate *priv, GError **error) return g_file_set_contents (filename, state, -1, error); } +static void +fu_util_show_plugin_warnings (FuUtilPrivate *priv) +{ + FwupdPluginFlags flags = FWUPD_PLUGIN_FLAG_NONE; + GPtrArray *plugins; + + /* get a superset so we do not show the same message more than once */ + plugins = fu_engine_get_plugins (priv->engine); + for (guint i = 0; i < plugins->len; i++) { + FwupdPlugin *plugin = g_ptr_array_index (plugins, i); + if (!fwupd_plugin_has_flag (plugin, FWUPD_PLUGIN_FLAG_USER_WARNING)) + continue; + flags |= fwupd_plugin_get_flags (plugin); + } + + /* never show these, they're way too generic */ + flags &= ~FWUPD_PLUGIN_FLAG_DISABLED; + flags &= ~FWUPD_PLUGIN_FLAG_NO_HARDWARE; + + /* print */ + for (guint i = 0; i < 64; i++) { + const gchar *tmp; + g_autofree gchar *fmt = NULL; + if ((flags & ((guint64) 1 << i)) == 0) + continue; + tmp = fu_util_plugin_flag_to_string ((guint64) 1 << i); + if (tmp == NULL) + continue; + /* TRANSLATORS: this is a prefix on the console */ + fmt = fu_util_term_format (_("WARNING:"), FU_UTIL_TERM_COLOR_RED); + g_printerr ("%s %s\n", fmt, tmp); + } +} + static gboolean fu_util_start_engine (FuUtilPrivate *priv, FuEngineLoadFlags flags, GError **error) { @@ -132,9 +166,15 @@ fu_util_start_engine (FuUtilPrivate *priv, FuEngineLoadFlags flags, GError **err if (!fu_engine_load (priv->engine, flags, error)) return FALSE; if (fu_engine_get_tainted (priv->engine)) { - g_printerr ("WARNING: This tool has loaded 3rd party code and " - "is no longer supported by the upstream developers!\n"); + g_autofree gchar *fmt = NULL; + + /* TRANSLATORS: this is a prefix on the console */ + fmt = fu_util_term_format (_("WARNING:"), FU_UTIL_TERM_COLOR_RED); + g_printerr ("%s This tool has loaded 3rd party code and " + "is no longer supported by the upstream developers!\n", + fmt); } + fu_util_show_plugin_warnings (priv); return TRUE; } @@ -269,10 +309,9 @@ static gboolean fu_util_get_plugins (FuUtilPrivate *priv, gchar **values, GError **error) { GPtrArray *plugins; - guint cnt = 0; /* load engine */ - if (!fu_engine_load_plugins (priv->engine, error)) + if (!fu_util_start_engine (priv, FU_ENGINE_LOAD_FLAG_NONE, error)) return FALSE; /* print */ @@ -280,15 +319,12 @@ fu_util_get_plugins (FuUtilPrivate *priv, gchar **values, GError **error) g_ptr_array_sort (plugins, (GCompareFunc) fu_util_plugin_name_sort_cb); for (guint i = 0; i < plugins->len; i++) { FuPlugin *plugin = g_ptr_array_index (plugins, i); - if (!fu_plugin_get_enabled (plugin)) - continue; - g_print ("%s\n", fu_plugin_get_name (plugin)); - cnt++; + g_autofree gchar *str = fu_util_plugin_to_string (FWUPD_PLUGIN (plugin), 0); + g_print ("%s\n", str); } - if (cnt == 0) { + if (plugins->len == 0) { /* TRANSLATORS: nothing found */ g_print ("%s\n", _("No plugins found")); - return TRUE; } return TRUE; @@ -2761,10 +2797,13 @@ main (int argc, char *argv[]) /* allow disabling SSL strict mode for broken corporate proxies */ if (priv->disable_ssl_strict) { + g_autofree gchar *fmt = NULL; + /* TRANSLATORS: this is a prefix on the console */ + fmt = fu_util_term_format (_("WARNING:"), FU_UTIL_TERM_COLOR_RED); /* TRANSLATORS: try to help */ - g_printerr ("%s\n", _("WARNING: Ignoring SSL strict checks, " - "to do this automatically in the future " - "export DISABLE_SSL_STRICT in your environment")); + g_printerr ("%s %s\n", fmt, _("Ignoring SSL strict checks, " + "to do this automatically in the future " + "export DISABLE_SSL_STRICT in your environment")); g_setenv ("DISABLE_SSL_STRICT", "1", TRUE); } diff --git a/src/fu-util-common.c b/src/fu-util-common.c index 3daf56e3b..88fa803a5 100644 --- a/src/fu-util-common.c +++ b/src/fu-util-common.c @@ -12,6 +12,7 @@ #include #include #include +#include #include "fu-common.h" #include "fu-device-private.h" @@ -35,6 +36,12 @@ fu_util_get_systemd_unit (void) return SYSTEMD_FWUPD_UNIT; } +gchar * +fu_util_term_format (const gchar *text, FuUtilTermColor fg_color) +{ + return g_strdup_printf ("\033[%um\033[1m%s\033[0m", fg_color, text); +} + #ifdef HAVE_SYSTEMD static const gchar * fu_util_get_expected_command (const gchar *target) @@ -1286,6 +1293,117 @@ fu_util_device_to_string (FwupdDevice *dev, guint idt) return g_string_free (str, FALSE); } +const gchar * +fu_util_plugin_flag_to_string (FwupdPluginFlags plugin_flag) +{ + if (plugin_flag == FWUPD_PLUGIN_FLAG_UNKNOWN) + return NULL; + if (plugin_flag == FWUPD_PLUGIN_FLAG_CLEAR_UPDATABLE) + return NULL; + if (plugin_flag == FWUPD_PLUGIN_FLAG_USER_WARNING) + return NULL; + if (plugin_flag == FWUPD_PLUGIN_FLAG_NONE) { + /* TRANSLATORS: Plugin is active and in use */ + return _("Enabled"); + } + if (plugin_flag == FWUPD_PLUGIN_FLAG_DISABLED) { + /* TRANSLATORS: Plugin is inactive and not used */ + return _("Disabled"); + } + if (plugin_flag == FWUPD_PLUGIN_FLAG_NO_HARDWARE) { + /* TRANSLATORS: not required for this system */ + return _("Required hardware was not found"); + } + if (plugin_flag == FWUPD_PLUGIN_FLAG_LEGACY_BIOS) { + /* TRANSLATORS: system is not booted in UEFI mode */ + return _("Firmware can not be updated in legacy BIOS mode"); + } + if (plugin_flag == FWUPD_PLUGIN_FLAG_CAPSULES_UNSUPPORTED) { + /* TRANSLATORS: capsule updates are an optional BIOS feature */ + return _("UEFI capsule updates not available or enabled"); + } + if (plugin_flag == FWUPD_PLUGIN_FLAG_UNLOCK_REQUIRED) { + /* TRANSLATORS: user needs to run a command */ + return _("Firmware updates disabled; run 'fwupdmgr unlock' to enable"); + } + if (plugin_flag == FWUPD_PLUGIN_FLAG_EFIVAR_NOT_MOUNTED) { + /* TRANSLATORS: the user is using Gentoo/Arch and has screwed something up */ + return _("Required efivarfs filesystem was not found"); + } + if (plugin_flag == FWUPD_PLUGIN_FLAG_ESP_NOT_FOUND) { + /* TRANSLATORS: partition refers to something on disk, again, hey Arch users */ + return _("UEFI ESP partition not detected or configured"); + } + + /* fall back for unknown types */ + return fwupd_plugin_flag_to_string (plugin_flag); +} + +static gchar * +fu_util_plugin_flag_to_cli_text (FwupdPluginFlags plugin_flag) +{ + switch (plugin_flag) { + case FWUPD_PLUGIN_FLAG_UNKNOWN: + case FWUPD_PLUGIN_FLAG_CLEAR_UPDATABLE: + case FWUPD_PLUGIN_FLAG_USER_WARNING: + return NULL; + case FWUPD_PLUGIN_FLAG_NONE: + return fu_util_term_format (fu_util_plugin_flag_to_string (plugin_flag), + FU_UTIL_CLI_COLOR_GREEN); + case FWUPD_PLUGIN_FLAG_DISABLED: + case FWUPD_PLUGIN_FLAG_NO_HARDWARE: + return fu_util_term_format (fu_util_plugin_flag_to_string (plugin_flag), + FU_UTIL_CLI_COLOR_BLACK); + case FWUPD_PLUGIN_FLAG_LEGACY_BIOS: + case FWUPD_PLUGIN_FLAG_CAPSULES_UNSUPPORTED: + case FWUPD_PLUGIN_FLAG_UNLOCK_REQUIRED: + case FWUPD_PLUGIN_FLAG_EFIVAR_NOT_MOUNTED: + case FWUPD_PLUGIN_FLAG_ESP_NOT_FOUND: + return fu_util_term_format (fu_util_plugin_flag_to_string (plugin_flag), + FU_UTIL_TERM_COLOR_RED); + default: + break; + } + + /* fall back for unknown types */ + return g_strdup (fwupd_plugin_flag_to_string (plugin_flag)); +} + +gchar * +fu_util_plugin_to_string (FwupdPlugin *plugin, guint idt) +{ + GString *str = g_string_new (NULL); + const gchar *hdr; + guint64 flags = fwupd_plugin_get_flags (plugin); + + fu_common_string_append_kv (str, idt, fwupd_plugin_get_name (plugin), NULL); + + /* TRANSLATORS: description of plugin state, e.g. disabled */ + hdr = _("Flags"); + if (flags == 0x0) { + const gchar *tmp = fu_util_plugin_flag_to_cli_text (flags); + g_autofree gchar *li = g_strdup_printf ("• %s", tmp); + fu_common_string_append_kv (str, idt + 1, hdr, li); + } else { + for (guint i = 0; i < 64; i++) { + g_autofree gchar *li = NULL; + g_autofree gchar *tmp = NULL; + if ((flags & ((guint64) 1 << i)) == 0) + continue; + tmp = fu_util_plugin_flag_to_cli_text ((guint64) 1 << i); + if (tmp == NULL) + continue; + li = g_strdup_printf ("• %s", tmp); + fu_common_string_append_kv (str, idt + 1, hdr, li); + + /* clear header */ + hdr = ""; + } + } + + return g_string_free (str, FALSE); +} + static const gchar * fu_util_license_to_string (const gchar *license) { diff --git a/src/fu-util-common.h b/src/fu-util-common.h index 67ca69139..955c03f40 100644 --- a/src/fu-util-common.h +++ b/src/fu-util-common.h @@ -32,8 +32,21 @@ typedef enum { FU_SECURITY_ATTR_TO_STRING_FLAG_LAST } FuSecurityAttrToStringFlags; +typedef enum { + FU_UTIL_CLI_COLOR_BLACK = 30, + FU_UTIL_TERM_COLOR_RED = 31, + FU_UTIL_CLI_COLOR_GREEN = 32, + FU_UTIL_CLI_COLOR_YELLOW = 33, + FU_UTIL_CLI_COLOR_BLUE = 34, + FU_UTIL_CLI_COLOR_MAGENTA = 35, + FU_UTIL_CLI_COLOR_CYAN = 36, + FU_UTIL_CLI_COLOR_WHITE = 37, +} FuUtilTermColor; + void fu_util_print_data (const gchar *title, const gchar *msg); +gchar *fu_util_term_format (const gchar *text, + FuUtilTermColor fg_color); guint fu_util_prompt_for_number (guint maxnum); gboolean fu_util_prompt_for_boolean (gboolean def); @@ -80,6 +93,9 @@ gchar *fu_util_time_to_str (guint64 tmp); gchar *fu_util_device_to_string (FwupdDevice *dev, guint idt); +gchar *fu_util_plugin_to_string (FwupdPlugin *plugin, + guint idt); +const gchar *fu_util_plugin_flag_to_string (FwupdPluginFlags plugin_flag); gchar *fu_util_release_to_string (FwupdRelease *rel, guint idt); gchar *fu_util_remote_to_string (FwupdRemote *remote, diff --git a/src/fu-util.c b/src/fu-util.c index 50d868eb1..1b3df7eca 100644 --- a/src/fu-util.c +++ b/src/fu-util.c @@ -554,6 +554,31 @@ fu_util_get_devices (FuUtilPrivate *priv, gchar **values, GError **error) return TRUE; } +static gboolean +fu_util_get_plugins (FuUtilPrivate *priv, gchar **values, GError **error) +{ + g_autoptr(GPtrArray) plugins = NULL; + + /* get results from daemon */ + plugins = fwupd_client_get_plugins (priv->client, NULL, error); + if (plugins == NULL) + return FALSE; + + /* print */ + for (guint i = 0; i < plugins->len; i++) { + FuPlugin *plugin = g_ptr_array_index (plugins, i); + g_autofree gchar *str = fu_util_plugin_to_string (FWUPD_PLUGIN (plugin), 0); + g_print ("%s\n", str); + } + if (plugins->len == 0) { + /* TRANSLATORS: nothing found */ + g_print ("%s\n", _("No plugins found")); + } + + /* success */ + return TRUE; +} + static gchar * fu_util_download_if_required (FuUtilPrivate *priv, const gchar *perhapsfn, GError **error) { @@ -2657,6 +2682,44 @@ fu_util_get_blocked_firmware (FuUtilPrivate *priv, gchar **values, GError **erro return TRUE; } +static void +fu_util_show_plugin_warnings (FuUtilPrivate *priv) +{ + FwupdPluginFlags flags = FWUPD_PLUGIN_FLAG_NONE; + g_autoptr(GPtrArray) plugins = NULL; + + /* get plugins from daemon, ignoring if the daemon is too old */ + plugins = fwupd_client_get_plugins (priv->client, NULL, NULL); + if (plugins == NULL) + return; + + /* get a superset so we do not show the same message more than once */ + for (guint i = 0; i < plugins->len; i++) { + FwupdPlugin *plugin = g_ptr_array_index (plugins, i); + if (!fwupd_plugin_has_flag (plugin, FWUPD_PLUGIN_FLAG_USER_WARNING)) + continue; + flags |= fwupd_plugin_get_flags (plugin); + } + + /* never show these, they're way too generic */ + flags &= ~FWUPD_PLUGIN_FLAG_DISABLED; + flags &= ~FWUPD_PLUGIN_FLAG_NO_HARDWARE; + + /* print */ + for (guint i = 0; i < 64; i++) { + const gchar *tmp; + g_autofree gchar *fmt = NULL; + if ((flags & ((guint64) 1 << i)) == 0) + continue; + tmp = fu_util_plugin_flag_to_string ((guint64) 1 << i); + if (tmp == NULL) + continue; + /* TRANSLATORS: this is a prefix on the console */ + fmt = fu_util_term_format (_("WARNING:"), FU_UTIL_TERM_COLOR_RED); + g_printerr ("%s %s\n", fmt, tmp); + } +} + int main (int argc, char *argv[]) { @@ -2939,6 +3002,12 @@ main (int argc, char *argv[]) /* TRANSLATORS: command description */ _("Gets the list of blocked firmware."), fu_util_get_blocked_firmware); + fu_util_cmd_array_add (cmd_array, + "get-plugins", + NULL, + /* TRANSLATORS: command description */ + _("Get all enabled plugins registered with the system"), + fu_util_get_plugins); /* do stuff on ctrl+c */ priv->cancellable = g_cancellable_new (); @@ -2973,10 +3042,13 @@ main (int argc, char *argv[]) /* allow disabling SSL strict mode for broken corporate proxies */ if (priv->disable_ssl_strict) { + g_autofree gchar *fmt = NULL; + /* TRANSLATORS: this is a prefix on the console */ + fmt = fu_util_term_format (_("WARNING:"), FU_UTIL_TERM_COLOR_RED); /* TRANSLATORS: try to help */ - g_printerr ("%s\n", _("WARNING: Ignoring SSL strict checks, " - "to do this automatically in the future " - "export DISABLE_SSL_STRICT in your environment")); + g_printerr ("%s %s\n", fmt, _("Ignoring SSL strict checks, " + "to do this automatically in the future " + "export DISABLE_SSL_STRICT in your environment")); g_setenv ("DISABLE_SSL_STRICT", "1", TRUE); } @@ -3066,10 +3138,19 @@ main (int argc, char *argv[]) return EXIT_FAILURE; } if (fwupd_client_get_tainted (priv->client)) { - g_printerr ("WARNING: The daemon has loaded 3rd party code and " - "is no longer supported by the upstream developers!\n"); + g_autofree gchar *fmt = NULL; + /* TRANSLATORS: this is a prefix on the console */ + fmt = fu_util_term_format (_("WARNING:"), FU_UTIL_TERM_COLOR_RED); + g_printerr ("%s %s\n", + fmt, + /* TRANSLATORS: the user is SOL for support... */ + _("The daemon has loaded 3rd party code and " + "is no longer supported by the upstream developers!")); } + /* show user-visible warnings from the plugins */ + fu_util_show_plugin_warnings (priv); + /* we know the runtime daemon version now */ fwupd_client_set_user_agent_for_package (priv->client, "fwupdmgr", PACKAGE_VERSION); diff --git a/src/org.freedesktop.fwupd.xml b/src/org.freedesktop.fwupd.xml index 6b0f7448e..77b708b4c 100644 --- a/src/org.freedesktop.fwupd.xml +++ b/src/org.freedesktop.fwupd.xml @@ -117,6 +117,24 @@ + + + + + + Gets a list of all the plugins being used by the daemon. + + + + + + + An array of plugins, with any properties set on each. + + + + + From f994813858e6f395450b984bec25fa917d33657d Mon Sep 17 00:00:00 2001 From: Tomas Winkler Date: Wed, 2 Sep 2020 10:29:20 +0300 Subject: [PATCH 532/607] contrib: fwupd.spec : install tests only when enabled. Install tests in the rpm package only when tests are enabled. Signed-off-by: Tomas Winkler --- contrib/fwupd.spec.in | 2 ++ 1 file changed, 2 insertions(+) diff --git a/contrib/fwupd.spec.in b/contrib/fwupd.spec.in index 9c9dd2b96..139b98db0 100644 --- a/contrib/fwupd.spec.in +++ b/contrib/fwupd.spec.in @@ -483,6 +483,7 @@ mkdir -p --mode=0700 $RPM_BUILD_ROOT%{_localstatedir}/lib/fwupd/gnupg %{_libdir}/pkgconfig/fwupd.pc %{_libdir}/pkgconfig/fwupdplugin.pc +%if 0%{?enable_tests} %files tests %dir %{_datadir}/installed-tests/fwupd %{_datadir}/installed-tests/fwupd/fwupd-tests.xml @@ -492,6 +493,7 @@ mkdir -p --mode=0700 $RPM_BUILD_ROOT%{_localstatedir}/lib/fwupd/gnupg %{_libexecdir}/installed-tests/fwupd/* %dir %{_sysconfdir}/fwupd/remotes.d %config(noreplace)%{_sysconfdir}/fwupd/remotes.d/fwupd-tests.conf +%endif %changelog * #LONGDATE# Richard Hughes #VERSION#-0.#BUILD##ALPHATAG# From f27e19beacad2449c54ada1f5ecb4beca83f11c6 Mon Sep 17 00:00:00 2001 From: Richard Hughes Date: Tue, 13 Oct 2020 21:06:05 +0100 Subject: [PATCH 533/607] Parse the HEX version before comparing for equality This fixes the error: 'Update Error: device version not updated on success, 0x00000002 != 0x0002' -- it seems a bit crazy to have to specify 32 bits of zero digits in the firmware.metainfo.xml --- libfwupdplugin/fu-common-version.c | 7 +++++++ libfwupdplugin/fu-self-test.c | 1 + 2 files changed, 8 insertions(+) diff --git a/libfwupdplugin/fu-common-version.c b/libfwupdplugin/fu-common-version.c index 1b3923a2f..a09172de7 100644 --- a/libfwupdplugin/fu-common-version.c +++ b/libfwupdplugin/fu-common-version.c @@ -482,6 +482,13 @@ fu_common_vercmp_full (const gchar *version_a, { if (fmt == FWUPD_VERSION_FORMAT_PLAIN) return g_strcmp0 (version_a, version_b); + if (fmt == FWUPD_VERSION_FORMAT_HEX) { + g_autofree gchar *hex_a = NULL; + g_autofree gchar *hex_b = NULL; + hex_a = fu_common_version_parse_from_format (version_a, fmt); + hex_b = fu_common_version_parse_from_format (version_b, fmt); + return fu_common_vercmp (hex_a, hex_b); + } return fu_common_vercmp (version_a, version_b); } diff --git a/libfwupdplugin/fu-self-test.c b/libfwupdplugin/fu-self-test.c index feab161b1..f218acb4b 100644 --- a/libfwupdplugin/fu-self-test.c +++ b/libfwupdplugin/fu-self-test.c @@ -1314,6 +1314,7 @@ fu_common_vercmp_func (void) /* same */ g_assert_cmpint (fu_common_vercmp ("1.2.3", "1.2.3"), ==, 0); g_assert_cmpint (fu_common_vercmp ("001.002.003", "001.002.003"), ==, 0); + g_assert_cmpint (fu_common_vercmp_full ("0x00000002", "0x2", FWUPD_VERSION_FORMAT_HEX), ==, 0); /* upgrade and downgrade */ g_assert_cmpint (fu_common_vercmp ("1.2.3", "1.2.4"), <, 0); From 11b71f49787190a9924ad35dec33180b9d4f0081 Mon Sep 17 00:00:00 2001 From: Mario Limonciello Date: Tue, 13 Oct 2020 13:39:14 -0500 Subject: [PATCH 534/607] Offer to compile daemon without polkit support Based on a patch from Daniel Campello at https://chromium-review.googlesource.com/c/chromiumos/third_party/fwupd/+/2354521 --- contrib/ci/build_windows.sh | 1 + contrib/ci/trust.sh | 3 +- meson.build | 15 ++-- meson_options.txt | 1 + src/fu-main.c | 155 ++++++++++++++++++++++++++++++++++-- src/fu-util.c | 6 ++ src/meson.build | 10 ++- 7 files changed, 176 insertions(+), 15 deletions(-) diff --git a/contrib/ci/build_windows.sh b/contrib/ci/build_windows.sh index 28230fb78..01cc13a4c 100755 --- a/contrib/ci/build_windows.sh +++ b/contrib/ci/build_windows.sh @@ -15,6 +15,7 @@ meson .. \ --libexecdir=$target \ --bindir=$target \ -Dbuild=standalone \ + -Dpolkit=false \ -Dplugin_coreboot=false \ -Dplugin_flashrom=false \ -Dplugin_uefi=false \ diff --git a/contrib/ci/trust.sh b/contrib/ci/trust.sh index 506776243..7223d186a 100755 --- a/contrib/ci/trust.sh +++ b/contrib/ci/trust.sh @@ -13,7 +13,8 @@ fi rm -rf build meson build \ -Dman=false \ - -Ddaemon=false \ + -Ddaemon=true \ + -Dpolkit=false \ -Dgusb:tests=false \ -Dtpm=false \ -Dplugin_modem_manager=false \ diff --git a/meson.build b/meson.build index b747a1f2f..be40a097e 100644 --- a/meson.build +++ b/meson.build @@ -210,11 +210,16 @@ libjsonglib = dependency('json-glib-1.0', version : '>= 1.1.1') valgrind = dependency('valgrind', required: false) soup = dependency('libsoup-2.4', version : '>= 2.51.92') if build_daemon - polkit = dependency('polkit-gobject-1', version : '>= 0.103') - if polkit.version().version_compare('>= 0.114') - conf.set('HAVE_POLKIT_0_114', '1') - endif + if get_option('polkit') + polkit = dependency('polkit-gobject-1', version : '>= 0.103') + conf.set('HAVE_POLKIT', '1') + if polkit.version().version_compare('>= 0.114') + conf.set('HAVE_POLKIT_0_114', '1') + endif conf.set_quoted ('POLKIT_ACTIONDIR', polkit.get_pkgconfig_variable('actiondir')) + else + warning('Polkit is disabled, the daemon will allow ALL client actions') + endif udevdir = get_option('udevdir') if udevdir == '' udev = dependency('udev') @@ -454,7 +459,7 @@ if get_option('gtkdoc') subdir('docs') endif subdir('libfwupd') -if build_daemon +if build_daemon and get_option('polkit') subdir('policy') endif if build_standalone diff --git a/meson_options.txt b/meson_options.txt index ecef6dc92..0a0e28536 100644 --- a/meson_options.txt +++ b/meson_options.txt @@ -7,6 +7,7 @@ option('introspection', type : 'boolean', value : true, description : 'generate option('lvfs', type : 'boolean', value : true, description : 'enable LVFS remotes') option('man', type : 'boolean', value : true, description : 'enable man pages') option('gudev', type : 'boolean', value : true, description : 'enable GUdev support') +option('polkit', type: 'boolean', value : true, description : 'enable PolKit support in daemon') option('plugin_altos', type : 'boolean', value : true, description : 'enable altos support') option('plugin_amt', type : 'boolean', value : true, description : 'enable Intel AMT support') option('plugin_dell', type : 'boolean', value : true, description : 'enable Dell-specific support') diff --git a/src/fu-main.c b/src/fu-main.c index 0af2288c5..8be62f64e 100644 --- a/src/fu-main.c +++ b/src/fu-main.c @@ -14,7 +14,9 @@ #include #include #include +#ifdef HAVE_POLKIT #include +#endif #include #include #include @@ -33,13 +35,15 @@ #include "fu-install-task.h" #include "fu-security-attrs-private.h" +#ifdef HAVE_POLKIT #ifndef HAVE_POLKIT_0_114 #pragma clang diagnostic push #pragma clang diagnostic ignored "-Wunused-function" G_DEFINE_AUTOPTR_CLEANUP_FUNC(PolkitAuthorizationResult, g_object_unref) G_DEFINE_AUTOPTR_CLEANUP_FUNC(PolkitSubject, g_object_unref) #pragma clang diagnostic pop -#endif +#endif /* HAVE_POLKIT_0_114 */ +#endif /* HAVE_POLKIT */ typedef enum { FU_MAIN_MACHINE_KIND_PHYSICAL, @@ -57,7 +61,9 @@ typedef struct { #if GLIB_CHECK_VERSION(2,63,3) GMemoryMonitor *memory_monitor; #endif +#ifdef HAVE_POLKIT PolkitAuthority *authority; +#endif guint owner_id; FuEngine *engine; gboolean update_in_progress; @@ -331,7 +337,9 @@ fu_main_result_array_to_variant (GPtrArray *results) typedef struct { GDBusMethodInvocation *invocation; FuEngineRequest *request; +#ifdef HAVE_POLKIT PolkitSubject *subject; +#endif GPtrArray *install_tasks; GPtrArray *action_ids; GPtrArray *checksums; @@ -350,8 +358,10 @@ fu_main_auth_helper_free (FuMainAuthHelper *helper) { if (helper->blob_cab != NULL) g_bytes_unref (helper->blob_cab); +#ifdef HAVE_POLKIT if (helper->subject != NULL) g_object_unref (helper->subject); +#endif if (helper->silo != NULL) g_object_unref (helper->silo); if (helper->request != NULL) @@ -375,6 +385,7 @@ fu_main_auth_helper_free (FuMainAuthHelper *helper) G_DEFINE_AUTOPTR_CLEANUP_FUNC(FuMainAuthHelper, fu_main_auth_helper_free) #pragma clang diagnostic pop +#ifdef HAVE_POLKIT /* error may or may not already have been set */ static gboolean fu_main_authorization_is_valid (PolkitAuthorizationResult *auth, GError **error) @@ -402,15 +413,30 @@ fu_main_authorization_is_valid (PolkitAuthorizationResult *auth, GError **error) /* success */ return TRUE; } +#else +static gboolean +fu_main_authorization_is_trusted (FuEngineRequest *request, GError **error) +{ + FwupdDeviceFlags flags = fu_engine_request_get_device_flags (request); + if ((flags & FWUPD_DEVICE_FLAG_TRUSTED) == 0) { + g_set_error_literal (error, + FWUPD_ERROR, + FWUPD_ERROR_AUTH_FAILED, + "permission denied: untrusted client process"); + return FALSE; + } + return TRUE; +} +#endif /* HAVE_POLKIT */ static void fu_main_authorize_unlock_cb (GObject *source, GAsyncResult *res, gpointer user_data) { g_autoptr(FuMainAuthHelper) helper = (FuMainAuthHelper *) user_data; g_autoptr(GError) error = NULL; +#ifdef HAVE_POLKIT g_autoptr(PolkitAuthorizationResult) auth = NULL; - /* get result */ fu_main_set_status (helper->priv, FWUPD_STATUS_IDLE); auth = polkit_authority_check_authorization_finish (POLKIT_AUTHORITY (source), @@ -419,6 +445,12 @@ fu_main_authorize_unlock_cb (GObject *source, GAsyncResult *res, gpointer user_d g_dbus_method_invocation_return_gerror (helper->invocation, error); return; } +#else + if (!fu_main_authorization_is_trusted (helper->request, &error)) { + g_dbus_method_invocation_return_gerror (helper->invocation, error); + return; + } +#endif /* HAVE_POLKIT */ /* authenticated */ if (!fu_engine_unlock (helper->priv->engine, helper->device_id, &error)) { @@ -435,6 +467,7 @@ fu_main_authorize_set_approved_firmware_cb (GObject *source, GAsyncResult *res, { g_autoptr(FuMainAuthHelper) helper = (FuMainAuthHelper *) user_data; g_autoptr(GError) error = NULL; +#ifdef HAVE_POLKIT g_autoptr(PolkitAuthorizationResult) auth = NULL; /* get result */ @@ -445,6 +478,12 @@ fu_main_authorize_set_approved_firmware_cb (GObject *source, GAsyncResult *res, g_dbus_method_invocation_return_gerror (helper->invocation, error); return; } +#else + if (!fu_main_authorization_is_trusted (helper->request, &error)) { + g_dbus_method_invocation_return_gerror (helper->invocation, error); + return; + } +#endif /* HAVE_POLKIT */ /* success */ for (guint i = 0; i < helper->checksums->len; i++) { @@ -459,6 +498,7 @@ fu_main_authorize_set_blocked_firmware_cb (GObject *source, GAsyncResult *res, g { g_autoptr(FuMainAuthHelper) helper = (FuMainAuthHelper *) user_data; g_autoptr(GError) error = NULL; +#ifdef HAVE_POLKIT g_autoptr(PolkitAuthorizationResult) auth = NULL; /* get result */ @@ -469,6 +509,12 @@ fu_main_authorize_set_blocked_firmware_cb (GObject *source, GAsyncResult *res, g g_dbus_method_invocation_return_gerror (helper->invocation, error); return; } +#else + if (!fu_main_authorization_is_trusted (helper->request, &error)) { + g_dbus_method_invocation_return_gerror (helper->invocation, error); + return; + } +#endif /* HAVE_POLKIT */ /* success */ if (!fu_engine_set_blocked_firmware (helper->priv->engine, helper->checksums, &error)) { @@ -484,6 +530,7 @@ fu_main_authorize_self_sign_cb (GObject *source, GAsyncResult *res, gpointer use g_autoptr(FuMainAuthHelper) helper = (FuMainAuthHelper *) user_data; g_autofree gchar *sig = NULL; g_autoptr(GError) error = NULL; +#ifdef HAVE_POLKIT g_autoptr(PolkitAuthorizationResult) auth = NULL; /* get result */ @@ -494,6 +541,12 @@ fu_main_authorize_self_sign_cb (GObject *source, GAsyncResult *res, gpointer use g_dbus_method_invocation_return_gerror (helper->invocation, error); return; } +#else + if (!fu_main_authorization_is_trusted (helper->request, &error)) { + g_dbus_method_invocation_return_gerror (helper->invocation, error); + return; + } +#endif /* HAVE_POLKIT */ /* authenticated */ sig = fu_engine_self_sign (helper->priv->engine, helper->value, helper->flags, &error); @@ -511,6 +564,7 @@ fu_main_modify_config_cb (GObject *source, GAsyncResult *res, gpointer user_data { g_autoptr(FuMainAuthHelper) helper = (FuMainAuthHelper *) user_data; g_autoptr(GError) error = NULL; +#ifdef HAVE_POLKIT g_autoptr(PolkitAuthorizationResult) auth = NULL; /* get result */ @@ -520,6 +574,12 @@ fu_main_modify_config_cb (GObject *source, GAsyncResult *res, gpointer user_data g_dbus_method_invocation_return_gerror (helper->invocation, error); return; } +#else + if (!fu_main_authorization_is_trusted (helper->request, &error)) { + g_dbus_method_invocation_return_gerror (helper->invocation, error); + return; + } +#endif /* HAVE_POLKIT */ if (!fu_engine_modify_config (helper->priv->engine, helper->key, helper->value, &error)) { g_dbus_method_invocation_return_gerror (helper->invocation, error); @@ -535,6 +595,7 @@ fu_main_authorize_activate_cb (GObject *source, GAsyncResult *res, gpointer user { g_autoptr(FuMainAuthHelper) helper = (FuMainAuthHelper *) user_data; g_autoptr(GError) error = NULL; +#ifdef HAVE_POLKIT g_autoptr(PolkitAuthorizationResult) auth = NULL; /* get result */ @@ -545,6 +606,12 @@ fu_main_authorize_activate_cb (GObject *source, GAsyncResult *res, gpointer user g_dbus_method_invocation_return_gerror (helper->invocation, error); return; } +#else + if (!fu_main_authorization_is_trusted (helper->request, &error)) { + g_dbus_method_invocation_return_gerror (helper->invocation, error); + return; + } +#endif /* HAVE_POLKIT */ /* authenticated */ if (!fu_engine_activate (helper->priv->engine, helper->device_id, &error)) { @@ -561,6 +628,7 @@ fu_main_authorize_verify_update_cb (GObject *source, GAsyncResult *res, gpointer { g_autoptr(FuMainAuthHelper) helper = (FuMainAuthHelper *) user_data; g_autoptr(GError) error = NULL; +#ifdef HAVE_POLKIT g_autoptr(PolkitAuthorizationResult) auth = NULL; /* get result */ @@ -571,6 +639,12 @@ fu_main_authorize_verify_update_cb (GObject *source, GAsyncResult *res, gpointer g_dbus_method_invocation_return_gerror (helper->invocation, error); return; } +#else + if (!fu_main_authorization_is_trusted (helper->request, &error)) { + g_dbus_method_invocation_return_gerror (helper->invocation, error); + return; + } +#endif /* HAVE_POLKIT */ /* authenticated */ if (!fu_engine_verify_update (helper->priv->engine, helper->device_id, &error)) { @@ -587,6 +661,7 @@ fu_main_authorize_modify_remote_cb (GObject *source, GAsyncResult *res, gpointer { g_autoptr(FuMainAuthHelper) helper = (FuMainAuthHelper *) user_data; g_autoptr(GError) error = NULL; +#ifdef HAVE_POLKIT g_autoptr(PolkitAuthorizationResult) auth = NULL; /* get result */ @@ -597,6 +672,12 @@ fu_main_authorize_modify_remote_cb (GObject *source, GAsyncResult *res, gpointer g_dbus_method_invocation_return_gerror (helper->invocation, error); return; } +#else + if (!fu_main_authorization_is_trusted (helper->request, &error)) { + g_dbus_method_invocation_return_gerror (helper->invocation, error); + return; + } +#endif /* HAVE_POLKIT */ /* authenticated */ if (!fu_engine_modify_remote (helper->priv->engine, @@ -619,6 +700,7 @@ fu_main_authorize_install_cb (GObject *source, GAsyncResult *res, gpointer user_ { g_autoptr(FuMainAuthHelper) helper = (FuMainAuthHelper *) user_data; g_autoptr(GError) error = NULL; +#ifdef HAVE_POLKIT g_autoptr(PolkitAuthorizationResult) auth = NULL; /* get result */ @@ -629,6 +711,12 @@ fu_main_authorize_install_cb (GObject *source, GAsyncResult *res, gpointer user_ g_dbus_method_invocation_return_gerror (helper->invocation, error); return; } +#else + if (!fu_main_authorization_is_trusted (helper->request, &error)) { + g_dbus_method_invocation_return_gerror (helper->invocation, error); + return; + } +#endif /* HAVE_POLKIT */ /* do the next authentication action ID */ fu_main_authorize_install_queue (g_steal_pointer (&helper)); @@ -644,6 +732,7 @@ fu_main_authorize_install_queue (FuMainAuthHelper *helper_ref) /* still more things to to authenticate */ if (helper->action_ids->len > 0) { +#ifdef HAVE_POLKIT g_autofree gchar *action_id = g_strdup (g_ptr_array_index (helper->action_ids, 0)); g_autoptr(PolkitSubject) subject = g_object_ref (helper->subject); g_ptr_array_remove_index (helper->action_ids, 0); @@ -653,6 +742,9 @@ fu_main_authorize_install_queue (FuMainAuthHelper *helper_ref) NULL, fu_main_authorize_install_cb, g_steal_pointer (&helper)); +#else + fu_main_authorize_install_cb (NULL, NULL, g_steal_pointer (&helper)); +#endif /* HAVE_POLKIT */ return; } @@ -978,7 +1070,9 @@ fu_main_daemon_method_call (GDBusConnection *connection, const gchar *sender, g_autofree gchar *checksums_str = NULL; g_auto(GStrv) checksums = NULL; g_autoptr(FuMainAuthHelper) helper = NULL; +#ifdef HAVE_POLKIT g_autoptr(PolkitSubject) subject = NULL; +#endif /* HAVE_POLKIT */ g_variant_get (parameters, "(^as)", &checksums); checksums_str = g_strjoinv (",", checksums); @@ -993,6 +1087,7 @@ fu_main_daemon_method_call (GDBusConnection *connection, const gchar *sender, helper->checksums = g_ptr_array_new_with_free_func (g_free); for (guint i = 0; checksums[i] != NULL; i++) g_ptr_array_add (helper->checksums, g_strdup (checksums[i])); +#ifdef HAVE_POLKIT subject = polkit_system_bus_name_new (sender); polkit_authority_check_authorization (priv->authority, subject, "org.freedesktop.fwupd.set-approved-firmware", @@ -1001,14 +1096,18 @@ fu_main_daemon_method_call (GDBusConnection *connection, const gchar *sender, NULL, fu_main_authorize_set_approved_firmware_cb, g_steal_pointer (&helper)); +#else + fu_main_authorize_set_approved_firmware_cb (NULL, NULL, g_steal_pointer (&helper)); +#endif /* HAVE_POLKIT */ return; } if (g_strcmp0 (method_name, "SetBlockedFirmware") == 0) { g_autofree gchar *checksums_str = NULL; g_auto(GStrv) checksums = NULL; g_autoptr(FuMainAuthHelper) helper = NULL; +#ifdef HAVE_POLKIT g_autoptr(PolkitSubject) subject = NULL; - +#endif g_variant_get (parameters, "(^as)", &checksums); checksums_str = g_strjoinv (",", checksums); g_debug ("Called %s(%s)", method_name, checksums_str); @@ -1022,6 +1121,7 @@ fu_main_daemon_method_call (GDBusConnection *connection, const gchar *sender, helper->checksums = g_ptr_array_new_with_free_func (g_free); for (guint i = 0; checksums[i] != NULL; i++) g_ptr_array_add (helper->checksums, g_strdup (checksums[i])); +#ifdef HAVE_POLKIT subject = polkit_system_bus_name_new (sender); polkit_authority_check_authorization (priv->authority, subject, "org.freedesktop.fwupd.set-approved-firmware", @@ -1030,6 +1130,9 @@ fu_main_daemon_method_call (GDBusConnection *connection, const gchar *sender, NULL, fu_main_authorize_set_blocked_firmware_cb, g_steal_pointer (&helper)); +#else + fu_main_authorize_set_blocked_firmware_cb (NULL, NULL, g_steal_pointer (&helper)); +#endif /* HAVE_POLKIT */ return; } if (g_strcmp0 (method_name, "SelfSign") == 0) { @@ -1037,7 +1140,9 @@ fu_main_daemon_method_call (GDBusConnection *connection, const gchar *sender, gchar *prop_key; g_autofree gchar *value = NULL; g_autoptr(FuMainAuthHelper) helper = NULL; +#ifdef HAVE_POLKIT g_autoptr(PolkitSubject) subject = NULL; +#endif g_autoptr(GVariantIter) iter = NULL; g_variant_get (parameters, "(sa{sv})", &value, &iter); @@ -1062,6 +1167,7 @@ fu_main_daemon_method_call (GDBusConnection *connection, const gchar *sender, helper->value = g_steal_pointer (&value); helper->request = g_steal_pointer (&request); helper->invocation = g_object_ref (invocation); +#ifdef HAVE_POLKIT subject = polkit_system_bus_name_new (sender); polkit_authority_check_authorization (priv->authority, subject, "org.freedesktop.fwupd.self-sign", @@ -1070,6 +1176,9 @@ fu_main_daemon_method_call (GDBusConnection *connection, const gchar *sender, NULL, fu_main_authorize_self_sign_cb, g_steal_pointer (&helper)); +#else + fu_main_authorize_self_sign_cb (NULL, NULL, g_steal_pointer (&helper)); +#endif /* HAVE_POLKIT */ return; } if (g_strcmp0 (method_name, "GetDowngrades") == 0) { @@ -1241,8 +1350,9 @@ fu_main_daemon_method_call (GDBusConnection *connection, const gchar *sender, if (g_strcmp0 (method_name, "Unlock") == 0) { const gchar *device_id = NULL; g_autoptr(FuMainAuthHelper) helper = NULL; +#ifdef HAVE_POLKIT g_autoptr(PolkitSubject) subject = NULL; - +#endif /* HAVE_POLKIT */ g_variant_get (parameters, "(&s)", &device_id); g_debug ("Called %s(%s)", method_name, device_id); if (!fu_main_device_id_valid (device_id, &error)) { @@ -1257,6 +1367,7 @@ fu_main_daemon_method_call (GDBusConnection *connection, const gchar *sender, helper->request = g_steal_pointer (&request); helper->invocation = g_object_ref (invocation); helper->device_id = g_strdup (device_id); +#ifdef HAVE_POLKIT subject = polkit_system_bus_name_new (sender); polkit_authority_check_authorization (priv->authority, subject, "org.freedesktop.fwupd.device-unlock", @@ -1265,13 +1376,17 @@ fu_main_daemon_method_call (GDBusConnection *connection, const gchar *sender, NULL, fu_main_authorize_unlock_cb, g_steal_pointer (&helper)); +#else + fu_main_authorize_unlock_cb (NULL, NULL, g_steal_pointer (&helper)); +#endif /* HAVE_POLKIT */ return; } if (g_strcmp0 (method_name, "Activate") == 0) { const gchar *device_id = NULL; g_autoptr(FuMainAuthHelper) helper = NULL; +#ifdef HAVE_POLKIT g_autoptr(PolkitSubject) subject = NULL; - +#endif g_variant_get (parameters, "(&s)", &device_id); g_debug ("Called %s(%s)", method_name, device_id); if (!fu_main_device_id_valid (device_id, &error)) { @@ -1286,6 +1401,7 @@ fu_main_daemon_method_call (GDBusConnection *connection, const gchar *sender, helper->request = g_steal_pointer (&request); helper->invocation = g_object_ref (invocation); helper->device_id = g_strdup (device_id); +#ifdef HAVE_POLKIT subject = polkit_system_bus_name_new (sender); polkit_authority_check_authorization (priv->authority, subject, "org.freedesktop.fwupd.device-activate", @@ -1294,14 +1410,18 @@ fu_main_daemon_method_call (GDBusConnection *connection, const gchar *sender, NULL, fu_main_authorize_activate_cb, g_steal_pointer (&helper)); +#else + fu_main_authorize_activate_cb (NULL, NULL, g_steal_pointer (&helper)); +#endif /* HAVE_POLKIT */ return; } if (g_strcmp0 (method_name, "ModifyConfig") == 0) { g_autofree gchar *key = NULL; g_autofree gchar *value = NULL; g_autoptr(FuMainAuthHelper) helper = NULL; +#ifdef HAVE_POLKIT g_autoptr(PolkitSubject) subject = NULL; - +#endif g_variant_get (parameters, "(ss)", &key, &value); g_debug ("Called %s(%s=%s)", method_name, key, value); @@ -1312,6 +1432,7 @@ fu_main_daemon_method_call (GDBusConnection *connection, const gchar *sender, helper->value = g_steal_pointer (&value); helper->request = g_steal_pointer (&request); helper->invocation = g_object_ref (invocation); +#ifdef HAVE_POLKIT subject = polkit_system_bus_name_new (sender); polkit_authority_check_authorization (priv->authority, subject, "org.freedesktop.fwupd.modify-config", @@ -1320,6 +1441,9 @@ fu_main_daemon_method_call (GDBusConnection *connection, const gchar *sender, NULL, fu_main_modify_config_cb, g_steal_pointer (&helper)); +#else + fu_main_modify_config_cb (NULL, NULL, g_steal_pointer (&helper)); +#endif /* HAVE_POLKIT */ return; } if (g_strcmp0 (method_name, "ModifyRemote") == 0) { @@ -1327,8 +1451,9 @@ fu_main_daemon_method_call (GDBusConnection *connection, const gchar *sender, const gchar *key = NULL; const gchar *value = NULL; g_autoptr(FuMainAuthHelper) helper = NULL; +#ifdef HAVE_POLKIT g_autoptr(PolkitSubject) subject = NULL; - +#endif /* check the id exists */ g_variant_get (parameters, "(&s&s&s)", &remote_id, &key, &value); g_debug ("Called %s(%s,%s=%s)", method_name, remote_id, key, value); @@ -1344,6 +1469,7 @@ fu_main_daemon_method_call (GDBusConnection *connection, const gchar *sender, /* authenticate */ fu_main_set_status (priv, FWUPD_STATUS_WAITING_FOR_AUTH); +#ifdef HAVE_POLKIT subject = polkit_system_bus_name_new (sender); polkit_authority_check_authorization (priv->authority, subject, "org.freedesktop.fwupd.modify-remote", @@ -1352,12 +1478,17 @@ fu_main_daemon_method_call (GDBusConnection *connection, const gchar *sender, NULL, fu_main_authorize_modify_remote_cb, g_steal_pointer (&helper)); +#else + fu_main_authorize_modify_remote_cb (NULL, NULL, g_steal_pointer (&helper)); +#endif /* HAVE_POLKIT */ return; } if (g_strcmp0 (method_name, "VerifyUpdate") == 0) { const gchar *device_id = NULL; g_autoptr(FuMainAuthHelper) helper = NULL; +#ifdef HAVE_POLKIT g_autoptr(PolkitSubject) subject = NULL; +#endif /* check the id exists */ g_variant_get (parameters, "(&s)", &device_id); @@ -1375,6 +1506,7 @@ fu_main_daemon_method_call (GDBusConnection *connection, const gchar *sender, helper->priv = priv; /* authenticate */ +#ifdef HAVE_POLKIT fu_main_set_status (priv, FWUPD_STATUS_WAITING_FOR_AUTH); subject = polkit_system_bus_name_new (sender); polkit_authority_check_authorization (priv->authority, subject, @@ -1384,6 +1516,9 @@ fu_main_daemon_method_call (GDBusConnection *connection, const gchar *sender, NULL, fu_main_authorize_verify_update_cb, g_steal_pointer (&helper)); +#else + fu_main_authorize_verify_update_cb (NULL, NULL, g_steal_pointer (&helper)); +#endif /* HAVE_POLKIT */ return; } if (g_strcmp0 (method_name, "Verify") == 0) { @@ -1498,7 +1633,9 @@ fu_main_daemon_method_call (GDBusConnection *connection, const gchar *sender, } /* install all the things in the store */ +#ifdef HAVE_POLKIT helper->subject = polkit_system_bus_name_new (sender); +#endif /* HAVE_POLKIT */ if (!fu_main_install_with_helper (g_steal_pointer (&helper), &error)) { g_dbus_method_invocation_return_gerror (invocation, error); return; @@ -1749,8 +1886,10 @@ fu_main_private_free (FuMainPrivate *priv) g_object_unref (priv->engine); if (priv->connection != NULL) g_object_unref (priv->connection); +#ifdef HAVE_POLKIT if (priv->authority != NULL) g_object_unref (priv->authority); +#endif if (priv->argv0_monitor != NULL) { g_file_monitor_cancel (priv->argv0_monitor); g_object_unref (priv->argv0_monitor); @@ -1861,12 +2000,14 @@ main (int argc, char *argv[]) return EXIT_FAILURE; } +#ifdef HAVE_POLKIT /* get authority */ priv->authority = polkit_authority_get_sync (NULL, &error); if (priv->authority == NULL) { g_printerr ("Failed to load authority: %s\n", error->message); return EXIT_FAILURE; } +#endif /* are we a VM? */ if (fu_main_is_hypervisor ()) { diff --git a/src/fu-util.c b/src/fu-util.c index 1b3df7eca..4b1bde34f 100644 --- a/src/fu-util.c +++ b/src/fu-util.c @@ -2506,6 +2506,7 @@ fu_util_check_daemon_version (FuUtilPrivate *priv, GError **error) static gboolean fu_util_check_polkit_actions (GError **error) { +#ifdef HAVE_POLKIT g_autofree gchar *directory = fu_common_get_path (FU_PATH_KIND_POLKIT_ACTIONS); g_autofree gchar *filename = g_build_filename (directory, "org.freedesktop.fwupd.policy", @@ -2517,6 +2518,7 @@ fu_util_check_polkit_actions (GError **error) "PolicyKit files are missing, see https://github.com/fwupd/fwupd/wiki/PolicyKit-files-are-missing"); return FALSE; } +#endif return TRUE; } @@ -3102,6 +3104,7 @@ main (int argc, char *argv[]) if (ignore_power) priv->flags |= FWUPD_INSTALL_FLAG_IGNORE_POWER; +#ifdef HAVE_POLKIT /* start polkit tty agent to listen for password requests */ if (is_interactive) { if (!fu_polkit_agent_open (&error_polkit)) { @@ -3109,6 +3112,7 @@ main (int argc, char *argv[]) error_polkit->message); } } +#endif /* connect to the daemon */ priv->client = fwupd_client_new (); @@ -3206,8 +3210,10 @@ main (int argc, char *argv[]) } +#ifdef HAVE_POLKIT /* stop listening for polkit questions */ fu_polkit_agent_close (); +#endif /* success */ return EXIT_SUCCESS; diff --git a/src/meson.build b/src/meson.build index 953d4705f..efe7764b5 100644 --- a/src/meson.build +++ b/src/meson.build @@ -4,11 +4,17 @@ if build_daemon ) endif +client_src = [] systemd_src = [] +daemon_dep = [] if get_option('systemd') systemd_src += 'fu-systemd.c' endif +if get_option('polkit') + client_src += 'fu-polkit-agent.c' + daemon_dep += polkit +endif if build_daemon fwupdmgr = executable( @@ -19,7 +25,7 @@ fwupdmgr = executable( 'fu-progressbar.c', 'fu-security-attr.c', 'fu-util-common.c', - 'fu-polkit-agent.c', + client_src, systemd_src ], include_directories : [ @@ -255,12 +261,12 @@ executable( gmodule, gudev, gusb, - polkit, soup, sqlite, valgrind, libarchive, libjsonglib, + daemon_dep ], link_with : [ fwupd, From 1f6a1520fb824c6833439919e6ab0fe017306e8e Mon Sep 17 00:00:00 2001 From: Richard Hughes Date: Wed, 14 Oct 2020 09:20:58 +0100 Subject: [PATCH 535/607] elantp: Fix three impossible to hit bugs spotted by Coverity If somehow chk->data_sz is bigger than blksz then we would write past the end of the allocated buffer. --- plugins/elantp/fu-elantp-hid-device.c | 10 +++++++--- plugins/elantp/fu-elantp-i2c-device.c | 6 +++++- 2 files changed, 12 insertions(+), 4 deletions(-) diff --git a/plugins/elantp/fu-elantp-hid-device.c b/plugins/elantp/fu-elantp-hid-device.c index 86364bf0e..908bfb8ea 100644 --- a/plugins/elantp/fu-elantp-hid-device.c +++ b/plugins/elantp/fu-elantp-hid-device.c @@ -86,8 +86,9 @@ fu_elantp_hid_device_send_cmd (FuElantpHidDevice *self, fu_common_dump_raw (G_LOG_DOMAIN, "GetReport", buf, bufsz); /* success */ - memcpy (rx, buf + 0x3, rxsz); - return TRUE; + return fu_memcpy_safe (rx, rxsz, 0x0, /* dst */ + buf, bufsz, 0x3, /* src */ + rxsz, error); } static gboolean @@ -305,7 +306,10 @@ fu_elantp_hid_device_write_firmware (FuDevice *device, /* write block */ blk[0] = 0x0B; /* report ID */ - memcpy (blk + 1, chk->data, chk->data_sz); + if (!fu_memcpy_safe (blk, blksz, 0x1, /* dst */ + chk->data, chk->data_sz, 0x0, /* src */ + chk->data_sz, error)) + return FALSE; fu_common_write_uint16 (blk + chk->data_sz + 1, csum_tmp, G_LITTLE_ENDIAN); if (!fu_elantp_hid_device_send_cmd (self, blk, blksz, NULL, 0, error)) diff --git a/plugins/elantp/fu-elantp-i2c-device.c b/plugins/elantp/fu-elantp-i2c-device.c index 90c17ee1d..a3e8d78d5 100644 --- a/plugins/elantp/fu-elantp-i2c-device.c +++ b/plugins/elantp/fu-elantp-i2c-device.c @@ -342,7 +342,11 @@ fu_elantp_i2c_device_write_firmware (FuDevice *device, /* write block */ blk[0] = ETP_I2C_IAP_REG_L; blk[1] = ETP_I2C_IAP_REG_H; - memcpy (blk + 2, chk->data, chk->data_sz); + if (!fu_memcpy_safe (blk, blksz, 0x2, /* dst */ + chk->data, chk->data_sz, 0x0, /* src */ + chk->data_sz, error)) + return FALSE; + fu_common_write_uint16 (blk + chk->data_sz + 2, csum_tmp, G_LITTLE_ENDIAN); if (!fu_elantp_i2c_device_send_cmd (self, blk, blksz, NULL, 0, error)) From 88fdc59330eccb1660839b06dd37b2f9a04d7918 Mon Sep 17 00:00:00 2001 From: Richard Hughes Date: Thu, 15 Oct 2020 10:00:41 +0100 Subject: [PATCH 536/607] Set _HAS_MULTIPLE_BRANCHES when release differs from device Enable switch-branch any time a branch other than the default exists. Based on a patch by Evan Lojewski , many thanks. --- src/fu-engine.c | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/src/fu-engine.c b/src/fu-engine.c index c7f6aa012..f2638b9aa 100644 --- a/src/fu-engine.c +++ b/src/fu-engine.c @@ -4329,6 +4329,14 @@ fu_engine_add_releases_for_device_component (FuEngine *self, return TRUE; } +static const gchar * +fu_engine_get_branch_fallback (const gchar *nullable_branch) +{ + if (nullable_branch == NULL) + return "default"; + return nullable_branch; +} + GPtrArray * fu_engine_get_releases_for_device (FuEngine *self, FuEngineRequest *request, @@ -4409,11 +4417,11 @@ fu_engine_get_releases_for_device (FuEngine *self, /* are there multiple branches available */ branches = g_ptr_array_new_with_free_func (g_free); + g_ptr_array_add (branches, + g_strdup (fu_engine_get_branch_fallback (fu_device_get_branch (device)))); for (guint i = 0; i < releases->len; i++) { FwupdRelease *rel_tmp = FWUPD_RELEASE (g_ptr_array_index (releases, i)); - const gchar *branch_tmp = fwupd_release_get_branch (rel_tmp); - if (branch_tmp == NULL) - branch_tmp = "default"; + const gchar *branch_tmp = fu_engine_get_branch_fallback (fwupd_release_get_branch (rel_tmp)); if (g_ptr_array_find_with_equal_func (branches, branch_tmp, g_str_equal, NULL)) continue; From 1c62adec6915dc48d786c47318d5d1d9327ee116 Mon Sep 17 00:00:00 2001 From: Richard Hughes Date: Thu, 15 Oct 2020 14:58:19 +0100 Subject: [PATCH 537/607] Get the list of unique branch names for 'switch-branch' --- src/fu-util-common.c | 11 +++++++++++ src/fu-util-common.h | 1 + src/fu-util.c | 32 +++++++++++++++++++++++--------- 3 files changed, 35 insertions(+), 9 deletions(-) diff --git a/src/fu-util-common.c b/src/fu-util-common.c index 88fa803a5..13f7228cc 100644 --- a/src/fu-util-common.c +++ b/src/fu-util-common.c @@ -593,6 +593,17 @@ fu_util_cmd_array_to_string (GPtrArray *array) return g_string_free (string, FALSE); } +const gchar * +fu_util_release_get_branch (FwupdRelease *release) +{ + const gchar *tmp = fwupd_release_get_branch (release); + if (tmp == NULL) { + /* TRANSLATORS: this is the default branch name when unset */ + return _("default"); + } + return tmp; +} + gchar * fu_util_release_get_name (FwupdRelease *release) { diff --git a/src/fu-util-common.h b/src/fu-util-common.h index 955c03f40..c28ba2065 100644 --- a/src/fu-util-common.h +++ b/src/fu-util-common.h @@ -79,6 +79,7 @@ gboolean fu_util_cmd_array_run (GPtrArray *array, gchar **values, GError **error); gchar *fu_util_release_get_name (FwupdRelease *release); +const gchar *fu_util_release_get_branch (FwupdRelease *release); const gchar *fu_util_get_systemd_unit (void); gboolean fu_util_using_correct_daemon (GError **error); diff --git a/src/fu-util.c b/src/fu-util.c index 4b1bde34f..ea6114472 100644 --- a/src/fu-util.c +++ b/src/fu-util.c @@ -1982,18 +1982,21 @@ fu_util_switch_branch (FuUtilPrivate *priv, gchar **values, GError **error) if (rels == NULL) return FALSE; + /* get all the unique branches */ + for (guint i = 0; i < rels->len; i++) { + FwupdRelease *rel_tmp = g_ptr_array_index (rels, i); + const gchar *branch_tmp = fu_util_release_get_branch (rel_tmp); + if (g_ptr_array_find_with_equal_func (branches, branch_tmp, + g_str_equal, NULL)) + continue; + g_ptr_array_add (branches, g_strdup (branch_tmp)); + } + /* branch name is optional */ if (g_strv_length (values) > 1) { branch = values[1]; - if (g_strcmp0 (branch, fu_device_get_branch (dev)) == 0) { - g_set_error (error, - FWUPD_ERROR, - FWUPD_ERROR_NOT_SUPPORTED, - "Device %s is already on branch %s", - fu_device_get_name (dev), - branch); - return FALSE; - } + } else if (branches->len == 1) { + branch = g_ptr_array_index (branches, 0); } else { guint idx; @@ -2017,6 +2020,17 @@ fu_util_switch_branch (FuUtilPrivate *priv, gchar **values, GError **error) branch = g_ptr_array_index (branches, idx - 1); } + /* sanity check */ + if (g_strcmp0 (branch, fu_device_get_branch (dev)) == 0) { + g_set_error (error, + FWUPD_ERROR, + FWUPD_ERROR_NOT_SUPPORTED, + "Device %s is already on branch %s", + fu_device_get_name (dev), + branch); + return FALSE; + } + /* the releases are ordered by version */ for (guint j = 0; j < rels->len; j++) { FwupdRelease *rel_tmp = g_ptr_array_index (rels, j); From edab096c642c6591eab5dd65e5f544ddbe70cc49 Mon Sep 17 00:00:00 2001 From: Daniel Campello Date: Thu, 15 Oct 2020 13:46:17 -0600 Subject: [PATCH 538/607] trivial: Fix build error on build=standalone and polkit=true This fixes error introduced by 11b71f49787190a9924ad35dec33180b9d4f0081 --- src/meson.build | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/meson.build b/src/meson.build index efe7764b5..678694b19 100644 --- a/src/meson.build +++ b/src/meson.build @@ -11,7 +11,7 @@ daemon_dep = [] if get_option('systemd') systemd_src += 'fu-systemd.c' endif -if get_option('polkit') +if build_daemon and get_option('polkit') client_src += 'fu-polkit-agent.c' daemon_dep += polkit endif From 61ba02ae1687350c1240482492090bf69c131865 Mon Sep 17 00:00:00 2001 From: Mario Limonciello Date: Thu, 15 Oct 2020 16:33:33 -0500 Subject: [PATCH 539/607] trivial: increase debugging for for fu-uefi-bootmgr.c See #2169 for more context --- plugins/uefi/fu-uefi-bootmgr.c | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/plugins/uefi/fu-uefi-bootmgr.c b/plugins/uefi/fu-uefi-bootmgr.c index 4d9319be3..30dbb7a7a 100644 --- a/plugins/uefi/fu-uefi-bootmgr.c +++ b/plugins/uefi/fu-uefi-bootmgr.c @@ -92,6 +92,7 @@ fu_uefi_bootmgr_add_to_boot_order (guint16 boot_entry, GError **error) static gboolean fu_uefi_setup_bootnext_with_dp (const guint8 *dp_buf, guint8 *opt, gssize opt_size, GError **error) { + const gchar *desc; efi_guid_t *guid = NULL; efi_load_option *loadopt = NULL; gchar *name = NULL; @@ -103,7 +104,6 @@ fu_uefi_setup_bootnext_with_dp (const guint8 *dp_buf, guint8 *opt, gssize opt_si g_autofree guint8 *set_entries = g_malloc0 (G_MAXUINT16); while ((rc = efi_get_next_variable_name (&guid, &name)) > 0) { - const gchar *desc; gint scanned = 0; guint16 entry = 0; g_autofree guint8 *var_data_tmp = NULL; @@ -128,20 +128,20 @@ fu_uefi_setup_bootnext_with_dp (const guint8 *dp_buf, guint8 *opt, gssize opt_si rc = efi_get_variable (*guid, name, &var_data_tmp, &var_data_size, &attr); if (rc < 0) { - g_debug ("efi_get_variable(%s) failed", name); + g_debug ("efi_get_variable(%s) failed: %s", name, strerror(rc)); continue; } loadopt = (efi_load_option *)var_data_tmp; if (!efi_loadopt_is_valid(loadopt, var_data_size)) { - g_debug ("load option was invalid"); + g_debug ("%s -> load option was invalid", name); continue; } desc = (const gchar *) efi_loadopt_desc (loadopt, var_data_size); if (g_strcmp0 (desc, "Linux Firmware Updater") != 0 && g_strcmp0 (desc, "Linux-Firmware-Updater") != 0) { - g_debug ("description does not match"); + g_debug ("%s -> '%s' : does not match", name, desc); continue; } @@ -160,10 +160,10 @@ fu_uefi_setup_bootnext_with_dp (const guint8 *dp_buf, guint8 *opt, gssize opt_si /* already exists */ if (var_data != NULL) { - /* is different than before */ if (var_data_size != (gsize) opt_size || memcmp (var_data, opt, opt_size) != 0) { + g_debug ("%s -> '%s' : updating existing boot entry", name, desc); efi_loadopt_attr_set (loadopt, LOAD_OPTION_ACTIVE); rc = efi_set_variable (*guid, name, opt, opt_size, attr, 0644); if (rc < 0) { @@ -173,6 +173,8 @@ fu_uefi_setup_bootnext_with_dp (const guint8 *dp_buf, guint8 *opt, gssize opt_si "could not set boot variable active"); return FALSE; } + } else { + g_debug ("%s -> %s : re-using existing boot entry", name, desc); } /* create a new one */ } else { @@ -192,6 +194,7 @@ fu_uefi_setup_bootnext_with_dp (const guint8 *dp_buf, guint8 *opt, gssize opt_si return FALSE; } boot_next_name = g_strdup_printf ("Boot%04X", (guint) boot_next); + g_debug ("%s -> creating new entry", boot_next_name); rc = efi_set_variable (efi_guid_global, boot_next_name, opt, opt_size, EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS | From 0357881c428b1d1ca5a06afce00d1918ed544760 Mon Sep 17 00:00:00 2001 From: Richard Hughes Date: Wed, 14 Oct 2020 08:44:06 +0100 Subject: [PATCH 540/607] elantp: Implement the ->reload action to get the new firmware version --- plugins/elantp/fu-elantp-hid-device.c | 1 + plugins/elantp/fu-elantp-i2c-device.c | 1 + 2 files changed, 2 insertions(+) diff --git a/plugins/elantp/fu-elantp-hid-device.c b/plugins/elantp/fu-elantp-hid-device.c index 908bfb8ea..316b31dcb 100644 --- a/plugins/elantp/fu-elantp-hid-device.c +++ b/plugins/elantp/fu-elantp-hid-device.c @@ -560,6 +560,7 @@ fu_elantp_hid_device_class_init (FuElantpHidDeviceClass *klass) klass_device->detach = fu_elantp_hid_device_detach; klass_device->set_quirk_kv = fu_elantp_hid_device_set_quirk_kv; klass_device->setup = fu_elantp_hid_device_setup; + klass_device->reload = fu_elantp_hid_device_setup; klass_device->write_firmware = fu_elantp_hid_device_write_firmware; klass_device->prepare_firmware = fu_elantp_hid_device_prepare_firmware; klass_udev_device->probe = fu_elantp_hid_device_probe; diff --git a/plugins/elantp/fu-elantp-i2c-device.c b/plugins/elantp/fu-elantp-i2c-device.c index a3e8d78d5..31f56881e 100644 --- a/plugins/elantp/fu-elantp-i2c-device.c +++ b/plugins/elantp/fu-elantp-i2c-device.c @@ -609,6 +609,7 @@ fu_elantp_i2c_device_class_init (FuElantpI2cDeviceClass *klass) klass_device->detach = fu_elantp_i2c_device_detach; klass_device->set_quirk_kv = fu_elantp_i2c_device_set_quirk_kv; klass_device->setup = fu_elantp_i2c_device_setup; + klass_device->reload = fu_elantp_i2c_device_setup; klass_device->write_firmware = fu_elantp_i2c_device_write_firmware; klass_device->prepare_firmware = fu_elantp_i2c_device_prepare_firmware; klass_udev_device->probe = fu_elantp_i2c_device_probe; From 65698015ae1c442c0cef146f82e0084427d20760 Mon Sep 17 00:00:00 2001 From: Richard Hughes Date: Wed, 14 Oct 2020 16:02:20 +0100 Subject: [PATCH 541/607] Do not fix up the version on post-update mismatch We already set a update error if the fu_common_vercmp_full() fails to match, and trying to do anything else would just be papering over the issue. --- src/fu-engine.c | 14 -------------- 1 file changed, 14 deletions(-) diff --git a/src/fu-engine.c b/src/fu-engine.c index f2638b9aa..bbbb38364 100644 --- a/src/fu-engine.c +++ b/src/fu-engine.c @@ -2170,20 +2170,6 @@ fu_engine_install_release (FuEngine *self, str = g_strdup_printf ("device version not updated on success, %s != %s", version_rel, fu_device_get_version (device)); fu_device_set_update_error (device, str); - if ((flags & FWUPD_INSTALL_FLAG_NO_HISTORY) == 0 && - !fu_history_modify_device (self->history, device, error)) - return FALSE; - /* success */ - return TRUE; - } - - /* ensure the new version matched what we expected */ - if (version_rel != NULL && - g_strcmp0 (fu_device_get_version (device), version_rel) != 0) { - g_warning ("new device version '%s' was is not '%s', fixing up", - fu_device_get_version (device), version_rel); - fu_device_set_version_format (device, fu_device_get_version_format (device)); - fu_device_set_version (device, version_rel); } /* success */ From 84781f41cf2758ad402154fa1108c7a43ccb97d7 Mon Sep 17 00:00:00 2001 From: Richard Hughes Date: Fri, 16 Oct 2020 15:20:57 +0100 Subject: [PATCH 542/607] trivial: Fix a segfault when installing without PolicyKit --- src/fu-main.c | 1 + 1 file changed, 1 insertion(+) diff --git a/src/fu-main.c b/src/fu-main.c index 8be62f64e..66861120c 100644 --- a/src/fu-main.c +++ b/src/fu-main.c @@ -743,6 +743,7 @@ fu_main_authorize_install_queue (FuMainAuthHelper *helper_ref) fu_main_authorize_install_cb, g_steal_pointer (&helper)); #else + g_ptr_array_remove_index (helper->action_ids, 0); fu_main_authorize_install_cb (NULL, NULL, g_steal_pointer (&helper)); #endif /* HAVE_POLKIT */ return; From ae5858ff583e903a6a56efd77397cbbf9125f915 Mon Sep 17 00:00:00 2001 From: Richard Hughes Date: Fri, 16 Oct 2020 15:24:16 +0100 Subject: [PATCH 543/607] vli: Get the new firmware version when updating the PD device To do this without rebooting the device implement VliUsbhubPdDevice->reload() like the other FuVliUsbhubDevice child devices. Fixes half of https://github.com/fwupd/fwupd/issues/2376 --- plugins/vli/fu-vli-usbhub-device.c | 45 +++++----------- plugins/vli/fu-vli-usbhub-pd-device.c | 76 +++++++++++++++++++++------ plugins/vli/fu-vli-usbhub-pd-device.h | 4 +- 3 files changed, 74 insertions(+), 51 deletions(-) diff --git a/plugins/vli/fu-vli-usbhub-device.c b/plugins/vli/fu-vli-usbhub-device.c index 64f8bc3b1..b8f96b9e7 100644 --- a/plugins/vli/fu-vli-usbhub-device.c +++ b/plugins/vli/fu-vli-usbhub-device.c @@ -498,43 +498,22 @@ fu_vli_usbhub_device_probe (FuDevice *device, GError **error) static gboolean fu_vli_usbhub_device_pd_setup (FuVliUsbhubDevice *self, GError **error) { - FuVliPdHdr hdr = { 0x0 }; g_autoptr(FuDevice) dev = NULL; g_autoptr(GError) error_local = NULL; - /* legacy location */ - if (!fu_vli_device_spi_read_block (FU_VLI_DEVICE (self), - VLI_USBHUB_FLASHMAP_ADDR_PD_LEGACY + - VLI_USBHUB_PD_FLASHMAP_ADDR_LEGACY, - (guint8 *) &hdr, sizeof(hdr), error)) { - g_prefix_error (error, "failed to read legacy PD header"); - return FALSE; - } - - /* new location */ - if (GUINT16_FROM_LE (hdr.vid) != 0x2109) { - g_debug ("PD VID was 0x%04x trying new location", - GUINT16_FROM_LE (hdr.vid)); - if (!fu_vli_device_spi_read_block (FU_VLI_DEVICE (self), - VLI_USBHUB_FLASHMAP_ADDR_PD + - VLI_USBHUB_PD_FLASHMAP_ADDR, - (guint8 *) &hdr, sizeof(hdr), error)) { - g_prefix_error (error, "failed to read PD header"); - return FALSE; - } - } - - /* just empty space */ - if (hdr.fwver == G_MAXUINT32) { - g_debug ("no PD device header found"); - return TRUE; - } - /* add child */ - dev = fu_vli_usbhub_pd_device_new (&hdr); - fu_device_set_quirks (dev, fu_device_get_quirks (FU_DEVICE (self))); - if (!fu_device_probe (dev, &error_local)) { - g_warning ("cannot create PD device: %s", error_local->message); + dev = fu_vli_usbhub_pd_device_new (self); + if (!fu_device_probe (dev, error)) + return FALSE; + if (!fu_device_setup (dev, &error_local)) { + if (g_error_matches (error_local, + FWUPD_ERROR, + FWUPD_ERROR_NOT_FOUND)) { + g_debug ("%s", error_local->message); + } else { + g_warning ("cannot create PD device: %s", + error_local->message); + } return TRUE; } fu_device_add_child (FU_DEVICE (self), dev); diff --git a/plugins/vli/fu-vli-usbhub-pd-device.c b/plugins/vli/fu-vli-usbhub-pd-device.c index ba470c77d..684be5560 100644 --- a/plugins/vli/fu-vli-usbhub-pd-device.c +++ b/plugins/vli/fu-vli-usbhub-pd-device.c @@ -19,7 +19,6 @@ struct _FuVliUsbhubPdDevice { FuDevice parent_instance; - FuVliPdHdr hdr; FuVliDeviceKind device_kind; }; @@ -38,10 +37,11 @@ fu_vli_usbhub_pd_device_to_string (FuDevice *device, guint idt, GString *str) } static gboolean -fu_vli_usbhub_pd_device_probe (FuDevice *device, GError **error) +fu_vli_usbhub_pd_device_setup (FuDevice *device, GError **error) { + FuVliPdHdr hdr = { 0x0 }; FuVliUsbhubPdDevice *self = FU_VLI_USBHUB_PD_DEVICE (device); - + FuVliUsbhubDevice *parent = FU_VLI_USBHUB_DEVICE (fu_device_get_parent (device)); guint32 fwver; g_autofree gchar *fwver_str = NULL; g_autofree gchar *instance_id0 = NULL; @@ -49,8 +49,39 @@ fu_vli_usbhub_pd_device_probe (FuDevice *device, GError **error) g_autofree gchar *instance_id2 = NULL; g_autofree gchar *instance_id3 = NULL; + /* legacy location */ + if (!fu_vli_device_spi_read_block (FU_VLI_DEVICE (parent), + VLI_USBHUB_FLASHMAP_ADDR_PD_LEGACY + + VLI_USBHUB_PD_FLASHMAP_ADDR_LEGACY, + (guint8 *) &hdr, sizeof(hdr), error)) { + g_prefix_error (error, "failed to read legacy PD header"); + return FALSE; + } + + /* new location */ + if (GUINT16_FROM_LE (hdr.vid) != 0x2109) { + g_debug ("PD VID was 0x%04x trying new location", + GUINT16_FROM_LE (hdr.vid)); + if (!fu_vli_device_spi_read_block (FU_VLI_DEVICE (parent), + VLI_USBHUB_FLASHMAP_ADDR_PD + + VLI_USBHUB_PD_FLASHMAP_ADDR, + (guint8 *) &hdr, sizeof(hdr), error)) { + g_prefix_error (error, "failed to read PD header"); + return FALSE; + } + } + + /* just empty space */ + if (hdr.fwver == G_MAXUINT32) { + g_set_error (error, + FWUPD_ERROR, + FWUPD_ERROR_NOT_FOUND, + "no PD device header found"); + return FALSE; + } + /* get version */ - fwver = GUINT32_FROM_BE (self->hdr.fwver); + fwver = GUINT32_FROM_BE (hdr.fwver); self->device_kind = fu_vli_pd_common_guess_device_kind (fwver); if (self->device_kind == FU_VLI_DEVICE_KIND_UNKNOWN) { g_set_error (error, @@ -66,23 +97,23 @@ fu_vli_usbhub_pd_device_probe (FuDevice *device, GError **error) fwver_str = fu_common_version_from_uint32 (fwver, FWUPD_VERSION_FORMAT_QUAD); fu_device_set_version (device, fwver_str); instance_id0 = g_strdup_printf ("USB\\VID_%04X&PID_%04X&APP_%02X", - GUINT16_FROM_LE (self->hdr.vid), - GUINT16_FROM_LE (self->hdr.pid), + GUINT16_FROM_LE (hdr.vid), + GUINT16_FROM_LE (hdr.pid), fwver & 0xff); fu_device_add_instance_id (device, instance_id0); instance_id1 = g_strdup_printf ("USB\\VID_%04X&PID_%04X&DEV_%s", - GUINT16_FROM_LE (self->hdr.vid), - GUINT16_FROM_LE (self->hdr.pid), + GUINT16_FROM_LE (hdr.vid), + GUINT16_FROM_LE (hdr.pid), fu_vli_common_device_kind_to_string (self->device_kind)); fu_device_add_instance_id (device, instance_id1); /* add standard GUIDs in order of priority */ instance_id2 = g_strdup_printf ("USB\\VID_%04X&PID_%04X", - GUINT16_FROM_LE (self->hdr.vid), - GUINT16_FROM_LE (self->hdr.pid)); + GUINT16_FROM_LE (hdr.vid), + GUINT16_FROM_LE (hdr.pid)); fu_device_add_instance_id (device, instance_id2); instance_id3 = g_strdup_printf ("USB\\VID_%04X", - GUINT16_FROM_LE (self->hdr.vid)); + GUINT16_FROM_LE (hdr.vid)); fu_device_add_instance_id_full (device, instance_id3, FU_DEVICE_INSTANCE_FLAG_ONLY_QUIRKS); @@ -94,6 +125,19 @@ fu_vli_usbhub_pd_device_probe (FuDevice *device, GError **error) return TRUE; } +static gboolean +fu_vli_usbhub_pd_device_reload (FuDevice *device, GError **error) +{ + FuVliUsbhubDevice *parent = FU_VLI_USBHUB_DEVICE (fu_device_get_parent (device)); + g_autoptr(FuDeviceLocker) locker = NULL; + + /* open parent device */ + locker = fu_device_locker_new (parent, error); + if (locker == NULL) + return FALSE; + return fu_vli_usbhub_pd_device_setup (device, error); +} + static FuFirmware * fu_vli_usbhub_pd_device_prepare_firmware (FuDevice *device, GBytes *fw, @@ -215,7 +259,8 @@ fu_vli_usbhub_pd_device_class_init (FuVliUsbhubPdDeviceClass *klass) { FuDeviceClass *klass_device = FU_DEVICE_CLASS (klass); klass_device->to_string = fu_vli_usbhub_pd_device_to_string; - klass_device->probe = fu_vli_usbhub_pd_device_probe; + klass_device->setup = fu_vli_usbhub_pd_device_setup; + klass_device->reload = fu_vli_usbhub_pd_device_reload; klass_device->attach = fu_vli_usbhub_pd_device_attach; klass_device->dump_firmware = fu_vli_usbhub_pd_device_dump_firmware; klass_device->write_firmware = fu_vli_usbhub_pd_device_write_firmware; @@ -223,9 +268,10 @@ fu_vli_usbhub_pd_device_class_init (FuVliUsbhubPdDeviceClass *klass) } FuDevice * -fu_vli_usbhub_pd_device_new (FuVliPdHdr *hdr) +fu_vli_usbhub_pd_device_new (FuVliUsbhubDevice *parent) { - FuVliUsbhubPdDevice *self = g_object_new (FU_TYPE_VLI_USBHUB_PD_DEVICE, NULL); - memcpy (&self->hdr, hdr, sizeof(self->hdr)); + FuVliUsbhubPdDevice *self = g_object_new (FU_TYPE_VLI_USBHUB_PD_DEVICE, + "parent", parent, + NULL); return FU_DEVICE (self); } diff --git a/plugins/vli/fu-vli-usbhub-pd-device.h b/plugins/vli/fu-vli-usbhub-pd-device.h index 61280f328..cceb4c2c3 100644 --- a/plugins/vli/fu-vli-usbhub-pd-device.h +++ b/plugins/vli/fu-vli-usbhub-pd-device.h @@ -8,8 +8,6 @@ #include "fu-plugin.h" -#include "fu-vli-pd-common.h" - #define FU_TYPE_VLI_USBHUB_PD_DEVICE (fu_vli_usbhub_pd_device_get_type ()) G_DECLARE_FINAL_TYPE (FuVliUsbhubPdDevice, fu_vli_usbhub_pd_device, FU, VLI_USBHUB_PD_DEVICE, FuDevice) @@ -18,4 +16,4 @@ struct _FuVliUsbhubPdDeviceClass FuDeviceClass parent_class; }; -FuDevice *fu_vli_usbhub_pd_device_new (FuVliPdHdr *hdr); +FuDevice *fu_vli_usbhub_pd_device_new (FuVliUsbhubDevice *parent); From f2a3e01f96cfea2ac641559eb3011c3927fde328 Mon Sep 17 00:00:00 2001 From: Richard Hughes Date: Fri, 16 Oct 2020 16:54:15 +0100 Subject: [PATCH 544/607] Simplify fu_device_list_wait_for_replug() for sanity Rather than using a recursive GMainLoop, just run a single iteration of the mainloop every 1ms while we're waiting. This simplifies the device lifecycle dramatically as we don't have to worry about reentrant removals. It's also a lot simpler to debug as we know the only way to return is the timeout elapsing or FWUPD_DEVICE_FLAG_WAIT_FOR_REPLUG being unset. If multiple devices got removed and we're waiting for one to re-appear, also wait for all devices to come back before returning to the main loop. In the worst case, this causes the device list to wait the full removal_delay for the device rather than returning when the first device matches. This allows us to simplify the hub update when we reboot the entire device and various devices from different plugins come back in an unpredictable order. Fixes the other half of https://github.com/fwupd/fwupd/issues/2376 --- src/fu-device-list.c | 80 ++++++++++++++++++-------------------------- src/fu-self-test.c | 5 +-- 2 files changed, 35 insertions(+), 50 deletions(-) diff --git a/src/fu-device-list.c b/src/fu-device-list.c index 0a73f0a2c..6f24ed8eb 100644 --- a/src/fu-device-list.c +++ b/src/fu-device-list.c @@ -38,8 +38,6 @@ struct _FuDeviceList GObject parent_instance; GPtrArray *devices; /* of FuDeviceItem */ GRWLock devices_mutex; - GMainLoop *replug_loop; /* block waiting for replug */ - guint replug_id; /* timeout the loop */ }; enum { @@ -567,15 +565,6 @@ fu_device_list_item_set_device (FuDeviceItem *item, FuDevice *device) g_set_object (&item->device, device); } -static gboolean -fu_device_list_replug_loop_quit_cb (gpointer user_data) -{ - FuDeviceList *self = FU_DEVICE_LIST (user_data); - g_debug ("quitting replug loop"); - g_main_loop_quit (self->replug_loop); - return G_SOURCE_REMOVE; -} - static void fu_device_list_replace (FuDeviceList *self, FuDeviceItem *item, FuDevice *device) { @@ -651,11 +640,9 @@ fu_device_list_replace (FuDeviceList *self, FuDeviceItem *item, FuDevice *device fu_device_list_emit_device_changed (self, device); /* we were waiting for this... */ - if (fu_device_has_flag (item->device_old, FWUPD_DEVICE_FLAG_WAIT_FOR_REPLUG) && - g_main_loop_is_running (self->replug_loop)) { - g_debug ("schedule quit replug loop in idle"); + if (fu_device_has_flag (item->device_old, FWUPD_DEVICE_FLAG_WAIT_FOR_REPLUG)) { + g_debug ("device came back, clearing flag"); fu_device_remove_flag (item->device_old, FWUPD_DEVICE_FLAG_WAIT_FOR_REPLUG); - g_idle_add (fu_device_list_replug_loop_quit_cb, self); } } @@ -691,20 +678,13 @@ fu_device_list_add (FuDeviceList *self, FuDevice *device) /* is the device waiting to be replugged? */ item = fu_device_list_find_by_id (self, fu_device_get_id (device), NULL); - if (item != NULL && item->remove_id != 0) { + if (item != NULL) { g_debug ("found existing device %s, reusing item", fu_device_get_id (item->device)); fu_device_list_replace (self, item, device); return; } - /* verify the device does not already exist */ - if (item != NULL) { - g_debug ("device %s already exists, ignoring", - fu_device_get_id (item->device)); - return; - } - /* verify a device with same connection does not already exist */ item = fu_device_list_find_by_connection (self, fu_device_get_physical_id (device), @@ -818,18 +798,19 @@ fu_device_list_get_by_guid (FuDeviceList *self, const gchar *guid, GError **erro return NULL; } -static gboolean -fu_device_list_replug_cb (gpointer user_data) +/* count devices that are disconnected and are waiting to be replugged */ +static guint +fu_device_list_devices_wait_removed (FuDeviceList *self) { - FuDeviceList *self = FU_DEVICE_LIST (user_data); - - /* no longer valid */ - self->replug_id = 0; - - /* quit loop */ - g_debug ("device did not replug"); - g_main_loop_quit (self->replug_loop); - return FALSE; + guint cnt = 0; + g_rw_lock_reader_lock (&self->devices_mutex); + for (guint i = 0; i < self->devices->len; i++) { + FuDeviceItem *item = g_ptr_array_index (self->devices, i); + if (item->remove_id != 0) + cnt++; + } + g_rw_lock_reader_unlock (&self->devices_mutex); + return cnt; } /** @@ -852,11 +833,13 @@ fu_device_list_wait_for_replug (FuDeviceList *self, FuDevice *device, GError **e { FuDeviceItem *item; guint remove_delay; + guint wait_removed; + guint wait_removed_old = 0; + g_autoptr(GTimer) timer = g_timer_new (); g_return_val_if_fail (FU_IS_DEVICE_LIST (self), FALSE); g_return_val_if_fail (FU_IS_DEVICE (device), FALSE); g_return_val_if_fail (error == NULL || *error == NULL, FALSE); - g_return_val_if_fail (self->replug_id == 0, FALSE); /* not found */ item = fu_device_list_find_by_device (self, device); @@ -895,14 +878,20 @@ fu_device_list_wait_for_replug (FuDeviceList *self, FuDevice *device, GError **e } /* time to unplug and then re-plug */ - self->replug_id = g_timeout_add (remove_delay, fu_device_list_replug_cb, self); - g_main_loop_run (self->replug_loop); - - /* cancel timeout if still pending */ - if (self->replug_id != 0) { - g_source_remove (self->replug_id); - self->replug_id = 0; - } + do { + /* count how many devices are in the remove waiting state */ + wait_removed = fu_device_list_devices_wait_removed (self); + if (wait_removed != wait_removed_old) { + g_debug ("devices in wait_removed: %u -> %u", + wait_removed_old, wait_removed); + wait_removed_old = wait_removed; + } + g_usleep (1000); + g_main_context_iteration (NULL, FALSE); + if (!fu_device_has_flag (item->device, FWUPD_DEVICE_FLAG_WAIT_FOR_REPLUG) && + wait_removed == 0) + break; + } while (g_timer_elapsed (timer, NULL) * 1000.f < remove_delay); /* device was not added back to the device list */ if (fu_device_has_flag (item->device, FWUPD_DEVICE_FLAG_WAIT_FOR_REPLUG)) { @@ -1016,7 +1005,6 @@ static void fu_device_list_init (FuDeviceList *self) { self->devices = g_ptr_array_new_with_free_func ((GDestroyNotify) fu_device_list_item_free); - self->replug_loop = g_main_loop_new (NULL, FALSE); g_rw_lock_init (&self->devices_mutex); } @@ -1026,11 +1014,7 @@ fu_device_list_finalize (GObject *obj) FuDeviceList *self = FU_DEVICE_LIST (obj); g_rw_lock_clear (&self->devices_mutex); - - if (self->replug_id != 0) - g_source_remove (self->replug_id); g_ptr_array_unref (self->devices); - g_main_loop_unref (self->replug_loop); G_OBJECT_CLASS (fu_device_list_parent_class)->finalize (obj); } diff --git a/src/fu-self-test.c b/src/fu-self-test.c index 0caaf197d..471665338 100644 --- a/src/fu-self-test.c +++ b/src/fu-self-test.c @@ -1975,14 +1975,15 @@ fu_device_list_delay_func (gconstpointer user_data) fu_device_list_add (device_list, device1); g_assert_cmpint (added_cnt, ==, 1); g_assert_cmpint (removed_cnt, ==, 0); - g_assert_cmpint (changed_cnt, ==, 0); + g_assert_cmpint (changed_cnt, ==, 1); /* add a device with the same ID */ fu_device_set_id (device2, "device1"); fu_device_list_add (device_list, device2); + fu_device_set_remove_delay (device2, 100); g_assert_cmpint (added_cnt, ==, 1); g_assert_cmpint (removed_cnt, ==, 0); - g_assert_cmpint (changed_cnt, ==, 0); + g_assert_cmpint (changed_cnt, ==, 2); /* spin a bit */ fu_test_loop_run_with_timeout (10); From 9f93b8bc66162facd04edfeddd2ca3bf1b083e96 Mon Sep 17 00:00:00 2001 From: Richard Hughes Date: Sat, 17 Oct 2020 15:51:24 +0100 Subject: [PATCH 545/607] trivial: Add fu_smbios_get_integer() helper --- libfwupdplugin/fu-hwids.c | 34 +++++------------------- libfwupdplugin/fu-smbios.c | 47 ++++++++++++++++++++++++++++++++++ libfwupdplugin/fu-smbios.h | 4 +++ libfwupdplugin/fwupdplugin.map | 1 + 4 files changed, 58 insertions(+), 28 deletions(-) diff --git a/libfwupdplugin/fu-hwids.c b/libfwupdplugin/fu-hwids.c index 11fb1c088..f56ad675e 100644 --- a/libfwupdplugin/fu-hwids.c +++ b/libfwupdplugin/fu-hwids.c @@ -280,21 +280,10 @@ fu_hwids_convert_padded_integer_cb (FuSmbios *smbios, guint8 type, guint8 offset, GError **error) { - g_autoptr(GBytes) data = NULL; - const guint8 *data_raw; - gsize data_sz = 0; - data = fu_smbios_get_data (smbios, type, error); - if (data == NULL) + guint tmp = fu_smbios_get_integer (smbios, type, offset, error); + if (tmp == G_MAXUINT) return NULL; - data_raw = g_bytes_get_data (data, &data_sz); - if (offset >= data_sz) { - g_set_error_literal (error, - FWUPD_ERROR, - FWUPD_ERROR_INVALID_FILE, - "offset bigger than data"); - return NULL; - } - return g_strdup_printf ("%02x", data_raw[offset]); + return g_strdup_printf ("%02x", tmp); } static gchar * @@ -302,21 +291,10 @@ fu_hwids_convert_integer_cb (FuSmbios *smbios, guint8 type, guint8 offset, GError **error) { - g_autoptr(GBytes) data = NULL; - const guint8 *data_raw; - gsize data_sz = 0; - data = fu_smbios_get_data (smbios, type, error); - if (data == NULL) + guint tmp = fu_smbios_get_integer (smbios, type, offset, error); + if (tmp == G_MAXUINT) return NULL; - data_raw = g_bytes_get_data (data, &data_sz); - if (offset >= data_sz) { - g_set_error_literal (error, - FWUPD_ERROR, - FWUPD_ERROR_INVALID_FILE, - "offset bigger than data"); - return NULL; - } - return g_strdup_printf ("%x", data_raw[offset]); + return g_strdup_printf ("%x", tmp); } /** diff --git a/libfwupdplugin/fu-smbios.c b/libfwupdplugin/fu-smbios.c index 90ec1e4f4..1b5d09df9 100644 --- a/libfwupdplugin/fu-smbios.c +++ b/libfwupdplugin/fu-smbios.c @@ -502,6 +502,53 @@ fu_smbios_get_data (FuSmbios *self, guint8 type, GError **error) return g_bytes_new (item->buf->data, item->buf->len); } +/** + * fu_smbios_get_integer: + * @self: A #FuSmbios + * @type: A structure type, e.g. %FU_SMBIOS_STRUCTURE_TYPE_BIOS + * @offset: A structure offset + * @error: A #GError or %NULL + * + * Reads an integer value from the SMBIOS string table of a specific structure. + * + * The @type and @offset can be referenced from the DMTF SMBIOS specification: + * https://www.dmtf.org/sites/default/files/standards/documents/DSP0134_3.1.1.pdf + * + * Returns: an integer, or %G_MAXUINT if invalid or not found + * + * Since: 1.5.0 + **/ +guint +fu_smbios_get_integer (FuSmbios *self, guint8 type, guint8 offset, GError **error) +{ + FuSmbiosItem *item; + + g_return_val_if_fail (FU_IS_SMBIOS (self), 0); + + /* get item */ + item = fu_smbios_get_item_for_type (self, type); + if (item == NULL) { + g_set_error (error, + FWUPD_ERROR, + FWUPD_ERROR_INVALID_FILE, + "no structure with type %02x", type); + return G_MAXUINT; + } + + /* check offset valid */ + if (offset >= item->buf->len) { + g_set_error (error, + FWUPD_ERROR, + FWUPD_ERROR_INVALID_FILE, + "offset bigger than size %u", + item->buf->len); + return G_MAXUINT; + } + + /* success */ + return item->buf->data[offset]; +} + /** * fu_smbios_get_string: * @self: A #FuSmbios diff --git a/libfwupdplugin/fu-smbios.h b/libfwupdplugin/fu-smbios.h index a8084c351..4f3d13c31 100644 --- a/libfwupdplugin/fu-smbios.h +++ b/libfwupdplugin/fu-smbios.h @@ -26,6 +26,10 @@ const gchar *fu_smbios_get_string (FuSmbios *self, guint8 type, guint8 offset, GError **error); +guint fu_smbios_get_integer (FuSmbios *self, + guint8 type, + guint8 offset, + GError **error); GBytes *fu_smbios_get_data (FuSmbios *self, guint8 type, GError **error); diff --git a/libfwupdplugin/fwupdplugin.map b/libfwupdplugin/fwupdplugin.map index 3242e4cfa..aca29f593 100644 --- a/libfwupdplugin/fwupdplugin.map +++ b/libfwupdplugin/fwupdplugin.map @@ -654,6 +654,7 @@ LIBFWUPDPLUGIN_1.5.0 { fu_security_attrs_new; fu_security_attrs_remove_all; fu_security_attrs_to_variant; + fu_smbios_get_integer; fu_udev_device_get_number; fu_udev_device_get_subsystem_model; fu_udev_device_get_subsystem_vendor; From 377feea5002652198a2dca759c6f9f50127b5ad6 Mon Sep 17 00:00:00 2001 From: Richard Hughes Date: Sat, 17 Oct 2020 15:52:03 +0100 Subject: [PATCH 546/607] Only show the HSI for sane chassis types Fixes https://github.com/fwupd/fwupd/issues/2440 --- libfwupdplugin/fu-smbios.h | 40 +++++++++++++++++++++++++++++++ src/fu-engine.c | 49 ++++++++++++++++++++++++++++++++++++-- 2 files changed, 87 insertions(+), 2 deletions(-) diff --git a/libfwupdplugin/fu-smbios.h b/libfwupdplugin/fu-smbios.h index 4f3d13c31..87c0192b9 100644 --- a/libfwupdplugin/fu-smbios.h +++ b/libfwupdplugin/fu-smbios.h @@ -20,6 +20,46 @@ FuSmbios *fu_smbios_new (void); #define FU_SMBIOS_STRUCTURE_TYPE_CHASSIS 0x03 #define FU_SMBIOS_STRUCTURE_TYPE_LAST 0x04 +typedef enum { + FU_SMBIOS_CHASSIS_KIND_OTHER = 0x01, + FU_SMBIOS_CHASSIS_KIND_UNKNOWN = 0x02, + FU_SMBIOS_CHASSIS_KIND_DESKTOP = 0x03, + FU_SMBIOS_CHASSIS_KIND_LOW_PROFILE_DESKTOP = 0x04, + FU_SMBIOS_CHASSIS_KIND_PIZZA_BOX = 0x05, + FU_SMBIOS_CHASSIS_KIND_MINI_TOWER = 0x06, + FU_SMBIOS_CHASSIS_KIND_TOWER = 0x07, + FU_SMBIOS_CHASSIS_KIND_PORTABLE = 0x08, + FU_SMBIOS_CHASSIS_KIND_LAPTOP = 0x09, + FU_SMBIOS_CHASSIS_KIND_NOTEBOOK = 0x0A, + FU_SMBIOS_CHASSIS_KIND_HAND_HELD = 0x0B, + FU_SMBIOS_CHASSIS_KIND_DOCKING_STATION = 0x0C, + FU_SMBIOS_CHASSIS_KIND_ALL_IN_ONE = 0x0D, + FU_SMBIOS_CHASSIS_KIND_SUB_NOTEBOOK = 0x0E, + FU_SMBIOS_CHASSIS_KIND_SPACE_SAVING = 0x0F, + FU_SMBIOS_CHASSIS_KIND_LUNCH_BOX = 0x10, + FU_SMBIOS_CHASSIS_KIND_MAIN_SERVER = 0x11, + FU_SMBIOS_CHASSIS_KIND_EXPANSION = 0x12, + FU_SMBIOS_CHASSIS_KIND_SUBCHASSIS = 0x13, + FU_SMBIOS_CHASSIS_KIND_BUS_EXPANSION = 0x14, + FU_SMBIOS_CHASSIS_KIND_PERIPHERAL = 0x15, + FU_SMBIOS_CHASSIS_KIND_RAID = 0x16, + FU_SMBIOS_CHASSIS_KIND_RACK_MOUNT = 0x17, + FU_SMBIOS_CHASSIS_KIND_SEALED_CASE_PC = 0x18, + FU_SMBIOS_CHASSIS_KIND_MULTI_SYSTEM = 0x19, + FU_SMBIOS_CHASSIS_KIND_COMPACT_PCI = 0x1A, + FU_SMBIOS_CHASSIS_KIND_ADVANCED_TCA = 0x1B, + FU_SMBIOS_CHASSIS_KIND_BLADE = 0x1C, + FU_SMBIOS_CHASSIS_KIND_TABLET = 0x1E, + FU_SMBIOS_CHASSIS_KIND_CONVERTIBLE = 0x1F, + FU_SMBIOS_CHASSIS_KIND_DETACHABLE = 0x20, + FU_SMBIOS_CHASSIS_KIND_IOT_GATEWAY = 0x21, + FU_SMBIOS_CHASSIS_KIND_EMBEDDED_PC = 0x22, + FU_SMBIOS_CHASSIS_KIND_MINI_PC = 0x23, + FU_SMBIOS_CHASSIS_KIND_STICK_PC = 0x24, + /*< private >*/ + FU_SMBIOS_CHASSIS_KIND_LAST, +} FuSmbiosChassisKind; + gchar *fu_smbios_to_string (FuSmbios *self); const gchar *fu_smbios_get_string (FuSmbios *self, diff --git a/src/fu-engine.c b/src/fu-engine.c index bbbb38364..23fa2a054 100644 --- a/src/fu-engine.c +++ b/src/fu-engine.c @@ -5771,6 +5771,52 @@ fu_engine_ensure_security_attrs_supported (FuEngine *self) } } +static gchar * +fu_engine_attrs_calculate_hsi_for_chassis (FuEngine *self) +{ + guint val; + g_autoptr(GError) error = NULL; + + /* get chassis type from SMBIOS data */ + val = fu_smbios_get_integer (self->smbios, + FU_SMBIOS_STRUCTURE_TYPE_CHASSIS, + 0x05, &error); + if (val == G_MAXUINT) { + g_warning ("failed to get chassis type: %s", error->message); + return g_strdup ("HSI-INVALID:chassis"); + } + + /* verify HSI makes sense for this chassis type */ + switch (val) { + case FU_SMBIOS_CHASSIS_KIND_DESKTOP: + case FU_SMBIOS_CHASSIS_KIND_LOW_PROFILE_DESKTOP: + case FU_SMBIOS_CHASSIS_KIND_MINI_TOWER: + case FU_SMBIOS_CHASSIS_KIND_TOWER: + case FU_SMBIOS_CHASSIS_KIND_PORTABLE: + case FU_SMBIOS_CHASSIS_KIND_LAPTOP: + case FU_SMBIOS_CHASSIS_KIND_NOTEBOOK: + case FU_SMBIOS_CHASSIS_KIND_ALL_IN_ONE: + case FU_SMBIOS_CHASSIS_KIND_SUB_NOTEBOOK: + case FU_SMBIOS_CHASSIS_KIND_LUNCH_BOX: + case FU_SMBIOS_CHASSIS_KIND_MAIN_SERVER: + case FU_SMBIOS_CHASSIS_KIND_TABLET: + case FU_SMBIOS_CHASSIS_KIND_CONVERTIBLE: + case FU_SMBIOS_CHASSIS_KIND_DETACHABLE: + case FU_SMBIOS_CHASSIS_KIND_IOT_GATEWAY: + case FU_SMBIOS_CHASSIS_KIND_EMBEDDED_PC: + case FU_SMBIOS_CHASSIS_KIND_MINI_PC: + case FU_SMBIOS_CHASSIS_KIND_STICK_PC: + return fu_security_attrs_calculate_hsi (self->host_security_attrs, + FU_SECURITY_ATTRS_FLAG_ADD_VERSION); + default: + break; + } + + /* failed */ + return g_strdup_printf ("HSI-INVALID:chassis[0x%02x]", val); +} + + static void fu_engine_ensure_security_attrs (FuEngine *self) { @@ -5814,8 +5860,7 @@ fu_engine_ensure_security_attrs (FuEngine *self) /* distil into one simple string */ g_free (self->host_security_id); - self->host_security_id = fu_security_attrs_calculate_hsi (self->host_security_attrs, - FU_SECURITY_ATTRS_FLAG_ADD_VERSION); + self->host_security_id = fu_engine_attrs_calculate_hsi_for_chassis (self); } const gchar * From 43053d2a1393925166f4f536f0eeb28aabeb19a8 Mon Sep 17 00:00:00 2001 From: Richard Hughes Date: Sun, 18 Oct 2020 19:49:25 +0100 Subject: [PATCH 547/607] Do not include fullstops in the --help output Fixes https://github.com/fwupd/fwupd/issues/2487 --- src/fu-tool.c | 8 ++++---- src/fu-util.c | 18 +++++++++--------- 2 files changed, 13 insertions(+), 13 deletions(-) diff --git a/src/fu-tool.c b/src/fu-tool.c index b6a534bcd..ee4f256c7 100644 --- a/src/fu-tool.c +++ b/src/fu-tool.c @@ -2729,25 +2729,25 @@ main (int argc, char *argv[]) "security", NULL, /* TRANSLATORS: command description */ - _("Gets the host security attributes."), + _("Gets the host security attributes"), fu_util_security); fu_util_cmd_array_add (cmd_array, "esp-mount", NULL, /* TRANSLATORS: command description */ - _("Mounts the ESP."), + _("Mounts the ESP"), fu_util_esp_mount); fu_util_cmd_array_add (cmd_array, "esp-unmount", NULL, /* TRANSLATORS: command description */ - _("Unmounts the ESP."), + _("Unmounts the ESP"), fu_util_esp_unmount); fu_util_cmd_array_add (cmd_array, "esp-list", NULL, /* TRANSLATORS: command description */ - _("Lists files on the ESP."), + _("Lists files on the ESP"), fu_util_esp_list); /* do stuff on ctrl+c */ diff --git a/src/fu-util.c b/src/fu-util.c index ea6114472..47f0d18f2 100644 --- a/src/fu-util.c +++ b/src/fu-util.c @@ -2968,55 +2968,55 @@ main (int argc, char *argv[]) "get-approved-firmware", NULL, /* TRANSLATORS: firmware approved by the admin */ - _("Gets the list of approved firmware."), + _("Gets the list of approved firmware"), fu_util_get_approved_firmware); fu_util_cmd_array_add (cmd_array, "set-approved-firmware", "CHECKSUM1[,CHECKSUM2][,CHECKSUM3]", /* TRANSLATORS: firmware approved by the admin */ - _("Sets the list of approved firmware."), + _("Sets the list of approved firmware"), fu_util_set_approved_firmware); fu_util_cmd_array_add (cmd_array, "modify-config", "KEY,VALUE", /* TRANSLATORS: sets something in daemon.conf */ - _("Modifies a daemon configuration value."), + _("Modifies a daemon configuration value"), fu_util_modify_config); fu_util_cmd_array_add (cmd_array, "reinstall", "[DEVICE-ID|GUID]", /* TRANSLATORS: command description */ - _("Reinstall current firmware on the device."), + _("Reinstall current firmware on the device"), fu_util_reinstall); fu_util_cmd_array_add (cmd_array, "switch-branch", "[DEVICE-ID|GUID] [BRANCH]", /* TRANSLATORS: command description */ - _("Switch the firmware branch on the device."), + _("Switch the firmware branch on the device"), fu_util_switch_branch); fu_util_cmd_array_add (cmd_array, "security", NULL, /* TRANSLATORS: command description */ - _("Gets the host security attributes."), + _("Gets the host security attributes"), fu_util_security); fu_util_cmd_array_add (cmd_array, "block-firmware", "[CHECKSUM]", /* TRANSLATORS: command description */ - _("Blocks a specific firmware from being installed."), + _("Blocks a specific firmware from being installed"), fu_util_block_firmware); fu_util_cmd_array_add (cmd_array, "unblock-firmware", "[CHECKSUM]", /* TRANSLATORS: command description */ - _("Blocks a specific firmware from being installed."), + _("Blocks a specific firmware from being installed"), fu_util_unblock_firmware); fu_util_cmd_array_add (cmd_array, "get-blocked-firmware", NULL, /* TRANSLATORS: command description */ - _("Gets the list of blocked firmware."), + _("Gets the list of blocked firmware"), fu_util_get_blocked_firmware); fu_util_cmd_array_add (cmd_array, "get-plugins", From 81b5defaa6fe0f89acdd60f37009ee5e966a9bf0 Mon Sep 17 00:00:00 2001 From: Richard Hughes Date: Fri, 16 Oct 2020 18:38:02 +0100 Subject: [PATCH 548/607] uefi: Use fu_efivar_get_data() to fix setting BootNext correctly Fixes https://github.com/fwupd/fwupd/issues/2169 --- libfwupdplugin/fu-efivar.c | 47 ++++++++++++++++++++ libfwupdplugin/fu-efivar.h | 2 + libfwupdplugin/fu-self-test.c | 7 +++ libfwupdplugin/fwupdplugin.map | 8 +++- plugins/uefi/fu-uefi-bootmgr.c | 78 +++++++++++++++------------------- 5 files changed, 98 insertions(+), 44 deletions(-) diff --git a/libfwupdplugin/fu-efivar.c b/libfwupdplugin/fu-efivar.c index 4bcd15d9b..912b61fdc 100644 --- a/libfwupdplugin/fu-efivar.c +++ b/libfwupdplugin/fu-efivar.c @@ -322,6 +322,53 @@ fu_efivar_get_data (const gchar *guid, const gchar *name, guint8 **data, #endif } +/** + * fu_efivar_get_names: + * @guid: Globally unique identifier + * @error: A #GError + * + * Gets the list of names where the GUID matches. An error is set if there are + * no names matching the GUID. + * + * Returns: (transfer container) (element-type utf8): array of names + * + * Since: 1.4.7 + **/ +GPtrArray * +fu_efivar_get_names (const gchar *guid, GError **error) +{ + const gchar *name_guid; + g_autofree gchar *path = fu_efivar_get_path (); + g_autoptr(GDir) dir = NULL; + g_autoptr(GPtrArray) names = g_ptr_array_new_with_free_func (g_free); + + /* find names with matching GUID */ + dir = g_dir_open (path, 0, error); + if (dir == NULL) + return NULL; + while ((name_guid = g_dir_read_name (dir)) != NULL) { + gsize name_guidsz = strlen (name_guid); + if (name_guidsz < 38) + continue; + if (g_strcmp0 (name_guid + name_guidsz - 36, guid) == 0) { + g_ptr_array_add (names, + g_strndup (name_guid, name_guidsz - 37)); + } + } + + /* nothing found */ + if (names->len == 0) { + g_set_error (error, + G_IO_ERROR, + G_IO_ERROR_NOT_FOUND, + "no names for GUID %s", guid); + return NULL; + } + + /* success */ + return g_steal_pointer (&names); +} + /** * fu_efivar_set_data: * @guid: Globally unique identifier diff --git a/libfwupdplugin/fu-efivar.h b/libfwupdplugin/fu-efivar.h index 926e60aec..0401083de 100644 --- a/libfwupdplugin/fu-efivar.h +++ b/libfwupdplugin/fu-efivar.h @@ -43,5 +43,7 @@ gboolean fu_efivar_delete (const gchar *guid, gboolean fu_efivar_delete_with_glob (const gchar *guid, const gchar *name_glob, GError **error); +GPtrArray *fu_efivar_get_names (const gchar *guid, + GError **error); gboolean fu_efivar_secure_boot_enabled (void); gboolean fu_efivar_secure_boot_enabled_full(GError **error); diff --git a/libfwupdplugin/fu-self-test.c b/libfwupdplugin/fu-self-test.c index f218acb4b..2c10980b3 100644 --- a/libfwupdplugin/fu-self-test.c +++ b/libfwupdplugin/fu-self-test.c @@ -1808,6 +1808,7 @@ fu_efivar_func (void) guint32 attr = 0; g_autofree guint8 *data = NULL; g_autoptr(GError) error = NULL; + g_autoptr(GPtrArray) names = NULL; /* check supported */ ret = fu_efivar_supported (&error); @@ -1818,6 +1819,12 @@ fu_efivar_func (void) g_assert_false (fu_efivar_exists (FU_EFIVAR_GUID_EFI_GLOBAL, "NotGoingToExist")); g_assert_true (fu_efivar_exists (FU_EFIVAR_GUID_EFI_GLOBAL, "SecureBoot")); + /* list a few keys */ + names = fu_efivar_get_names (FU_EFIVAR_GUID_EFI_GLOBAL, &error); + g_assert_no_error (error); + g_assert_nonnull (names); + g_assert_cmpint (names->len, ==, 2); + /* write and read a key */ ret = fu_efivar_set_data (FU_EFIVAR_GUID_EFI_GLOBAL, "Test", (guint8 *) "1", 1, diff --git a/libfwupdplugin/fwupdplugin.map b/libfwupdplugin/fwupdplugin.map index aca29f593..b48b2ece0 100644 --- a/libfwupdplugin/fwupdplugin.map +++ b/libfwupdplugin/fwupdplugin.map @@ -610,6 +610,12 @@ LIBFWUPDPLUGIN_1.4.6 { local: *; } LIBFWUPDPLUGIN_1.4.5; +LIBFWUPDPLUGIN_1.4.7 { + global: + fu_efivar_get_names; + local: *; +} LIBFWUPDPLUGIN_1.4.6; + LIBFWUPDPLUGIN_1.5.0 { global: fu_common_cpuid; @@ -659,4 +665,4 @@ LIBFWUPDPLUGIN_1.5.0 { fu_udev_device_get_subsystem_model; fu_udev_device_get_subsystem_vendor; local: *; -} LIBFWUPDPLUGIN_1.4.6; +} LIBFWUPDPLUGIN_1.4.7; diff --git a/plugins/uefi/fu-uefi-bootmgr.c b/plugins/uefi/fu-uefi-bootmgr.c index 30dbb7a7a..8b04335f2 100644 --- a/plugins/uefi/fu-uefi-bootmgr.c +++ b/plugins/uefi/fu-uefi-bootmgr.c @@ -93,23 +93,26 @@ static gboolean fu_uefi_setup_bootnext_with_dp (const guint8 *dp_buf, guint8 *opt, gssize opt_size, GError **error) { const gchar *desc; - efi_guid_t *guid = NULL; + const gchar *name; efi_load_option *loadopt = NULL; - gchar *name = NULL; gint rc; gsize var_data_size = 0; guint32 attr; guint16 boot_next = G_MAXUINT16; g_autofree guint8 *var_data = NULL; g_autofree guint8 *set_entries = g_malloc0 (G_MAXUINT16); + g_autoptr(GPtrArray) names = NULL; - while ((rc = efi_get_next_variable_name (&guid, &name)) > 0) { + names = fu_efivar_get_names (FU_EFIVAR_GUID_EFI_GLOBAL, error); + if (names == NULL) + return FALSE; + for (guint i = 0; i < names->len; i++) { gint scanned = 0; guint16 entry = 0; g_autofree guint8 *var_data_tmp = NULL; + g_autoptr(GError) error_local = NULL; - if (efi_guid_cmp (guid, &efi_guid_global) != 0) - continue; + name = g_ptr_array_index (names, i); rc = sscanf (name, "Boot%hX%n", &entry, &scanned); if (rc < 0) { g_set_error (error, @@ -126,9 +129,11 @@ fu_uefi_setup_bootnext_with_dp (const guint8 *dp_buf, guint8 *opt, gssize opt_si /* mark this as used */ set_entries[entry] = 1; - rc = efi_get_variable (*guid, name, &var_data_tmp, &var_data_size, &attr); - if (rc < 0) { - g_debug ("efi_get_variable(%s) failed: %s", name, strerror(rc)); + if (!fu_efivar_get_data (FU_EFIVAR_GUID_EFI_GLOBAL, name, + &var_data_tmp, &var_data_size, + &attr, &error_local)) { + g_debug ("failed to get data for name %s: %s", + name, error_local->message); continue; } @@ -150,13 +155,6 @@ fu_uefi_setup_bootnext_with_dp (const guint8 *dp_buf, guint8 *opt, gssize opt_si efi_error_clear (); break; } - if (rc < 0) { - g_set_error_literal (error, - G_IO_ERROR, - G_IO_ERROR_FAILED, - "failed to find boot variable"); - return FALSE; - } /* already exists */ if (var_data != NULL) { @@ -165,12 +163,10 @@ fu_uefi_setup_bootnext_with_dp (const guint8 *dp_buf, guint8 *opt, gssize opt_si memcmp (var_data, opt, opt_size) != 0) { g_debug ("%s -> '%s' : updating existing boot entry", name, desc); efi_loadopt_attr_set (loadopt, LOAD_OPTION_ACTIVE); - rc = efi_set_variable (*guid, name, opt, opt_size, attr, 0644); - if (rc < 0) { - g_set_error_literal (error, - G_IO_ERROR, - G_IO_ERROR_FAILED, - "could not set boot variable active"); + if (!fu_efivar_set_data (FU_EFIVAR_GUID_EFI_GLOBAL, + name, opt, opt_size, attr, error)) { + g_prefix_error (error, + "could not set boot variable active: "); return FALSE; } } else { @@ -195,17 +191,15 @@ fu_uefi_setup_bootnext_with_dp (const guint8 *dp_buf, guint8 *opt, gssize opt_si } boot_next_name = g_strdup_printf ("Boot%04X", (guint) boot_next); g_debug ("%s -> creating new entry", boot_next_name); - rc = efi_set_variable (efi_guid_global, boot_next_name, opt, opt_size, - EFI_VARIABLE_NON_VOLATILE | - EFI_VARIABLE_BOOTSERVICE_ACCESS | - EFI_VARIABLE_RUNTIME_ACCESS, - 0644); - if (rc < 0) { - g_set_error (error, - G_IO_ERROR, - G_IO_ERROR_FAILED, - "could not set boot variable %s: %d", - boot_next_name, rc); + if (!fu_efivar_set_data (FU_EFIVAR_GUID_EFI_GLOBAL, + boot_next_name, opt, opt_size, + FU_EFIVAR_ATTR_NON_VOLATILE | + FU_EFIVAR_ATTR_BOOTSERVICE_ACCESS | + FU_EFIVAR_ATTR_RUNTIME_ACCESS, + error)) { + g_prefix_error (error, + "could not set boot variable %s: ", + boot_next_name); return FALSE; } } @@ -215,17 +209,15 @@ fu_uefi_setup_bootnext_with_dp (const guint8 *dp_buf, guint8 *opt, gssize opt_si return FALSE; /* set the boot next */ - rc = efi_set_variable (efi_guid_global, "BootNext", (guint8 *)&boot_next, 2, - EFI_VARIABLE_NON_VOLATILE | - EFI_VARIABLE_BOOTSERVICE_ACCESS | - EFI_VARIABLE_RUNTIME_ACCESS, - 0644); - if (rc < 0) { - g_set_error (error, - G_IO_ERROR, - G_IO_ERROR_FAILED, - "could not set BootNext(%" G_GUINT16_FORMAT ")", - boot_next); + if (!fu_efivar_set_data (FU_EFIVAR_GUID_EFI_GLOBAL, + "BootNext", (guint8 *)&boot_next, 2, + FU_EFIVAR_ATTR_NON_VOLATILE | + FU_EFIVAR_ATTR_BOOTSERVICE_ACCESS | + FU_EFIVAR_ATTR_RUNTIME_ACCESS, + error)) { + g_prefix_error (error, + "could not set BootNext(%" G_GUINT16_FORMAT "): ", + boot_next); return FALSE; } return TRUE; From 68df30bd2be8821c3ea40eb3f840e669d87def25 Mon Sep 17 00:00:00 2001 From: Mario Limonciello Date: Fri, 16 Oct 2020 13:23:53 -0500 Subject: [PATCH 549/607] dell: Drop efivar dependency Since we removed the ability to turn on/off force power this is dead code, and an unnecessary dependency. --- meson.build | 1 - plugins/dell/fu-dell-smi.c | 40 -------------------------------------- plugins/dell/fu-dell-smi.h | 4 ---- plugins/dell/meson.build | 2 -- 4 files changed, 47 deletions(-) diff --git a/meson.build b/meson.build index be40a097e..ce99884e9 100644 --- a/meson.build +++ b/meson.build @@ -348,7 +348,6 @@ endif if build_standalone and get_option('plugin_dell') libsmbios_c = dependency('libsmbios_c', version : '>= 2.4.0') - efivar = dependency('efivar') conf.set('HAVE_DELL', '1') if not get_option('plugin_uefi') error('plugin_dell also needs plugin_uefi to work') diff --git a/plugins/dell/fu-dell-smi.c b/plugins/dell/fu-dell-smi.c index a7802b236..84382e820 100644 --- a/plugins/dell/fu-dell-smi.c +++ b/plugins/dell/fu-dell-smi.c @@ -23,13 +23,6 @@ struct dock_count_out { guint32 reserved; }; -/* This is used for host flash GUIDs */ -typedef union _ADDR_UNION{ - uint8_t *buf; - efi_guid_t *guid; -} ADDR_UNION; -#pragma pack() - static void _dell_smi_obj_free (FuDellSmiObj *obj) { @@ -230,36 +223,3 @@ fu_dell_toggle_dock_mode (FuDellSmiObj *smi_obj, guint32 new_mode, } return TRUE; } - -gboolean -fu_dell_toggle_host_mode (FuDellSmiObj *smi_obj, const efi_guid_t guid, int mode) -{ - gint ret; - ADDR_UNION buf; - - dell_smi_obj_set_class (smi_obj->smi, DACI_FLASH_INTERFACE_CLASS); - dell_smi_obj_set_select (smi_obj->smi, DACI_FLASH_INTERFACE_SELECT); - dell_smi_obj_set_arg (smi_obj->smi, cbARG1, DACI_FLASH_ARG_FLASH_MODE); - dell_smi_obj_set_arg (smi_obj->smi, cbARG4, mode); - /* needs to be padded with an empty GUID */ - buf.buf = dell_smi_obj_make_buffer_frombios_withoutheader(smi_obj->smi, - cbARG2, - sizeof(efi_guid_t) * 2); - if (!buf.buf) { - g_debug ("Failed to initialize SMI buffer"); - return FALSE; - } - *buf.guid = guid; - ret = dell_smi_obj_execute(smi_obj->smi); - if (ret != SMI_SUCCESS){ - g_debug ("failed to execute SMI: %d", ret); - return FALSE; - } - - ret = dell_smi_obj_get_res(smi_obj->smi, cbRES1); - if (ret != SMI_SUCCESS) { - g_debug ("SMI execution returned error: %d", ret); - return FALSE; - } - return TRUE; -} diff --git a/plugins/dell/fu-dell-smi.h b/plugins/dell/fu-dell-smi.h index a5d0cf892..0530dd639 100644 --- a/plugins/dell/fu-dell-smi.h +++ b/plugins/dell/fu-dell-smi.h @@ -9,7 +9,6 @@ #include "fu-device.h" #include #include -#include typedef struct { struct dell_smi_obj *smi; @@ -95,9 +94,6 @@ gboolean fu_dell_toggle_dock_mode (FuDellSmiObj *smi_obj, guint32 new_mode, guint32 dock_location, GError **error); -gboolean -fu_dell_toggle_host_mode (FuDellSmiObj *smi_obj, const efi_guid_t guid, int mode); - /* SMI return values used */ #define SMI_SUCCESS 0 #define SMI_INVALID_BUFFER -6 diff --git a/plugins/dell/meson.build b/plugins/dell/meson.build index bf4f3eab0..f32f7b873 100644 --- a/plugins/dell/meson.build +++ b/plugins/dell/meson.build @@ -26,7 +26,6 @@ shared_module('fu_plugin_dell', ], dependencies : [ plugin_deps, - efivar, libsmbios_c, tpm2tss, ], @@ -51,7 +50,6 @@ if get_option('tests') ], dependencies : [ plugin_deps, - efivar, sqlite, libsmbios_c, valgrind, From f019971c001448a040710268e329340572802fd9 Mon Sep 17 00:00:00 2001 From: Richard Hughes Date: Fri, 16 Oct 2020 23:08:46 +0100 Subject: [PATCH 550/607] redfish: Drop efivar dependency --- libfwupdplugin/fu-efivar.c | 49 +++++++++++++++++++++++++++++ libfwupdplugin/fu-efivar.h | 9 ++++++ libfwupdplugin/fwupdplugin.map | 2 ++ meson.build | 4 --- plugins/redfish/fu-redfish-client.c | 13 ++++---- plugins/redfish/fu-redfish-common.c | 20 ------------ plugins/redfish/fu-redfish-common.h | 6 +--- plugins/redfish/meson.build | 2 -- 8 files changed, 68 insertions(+), 37 deletions(-) diff --git a/libfwupdplugin/fu-efivar.c b/libfwupdplugin/fu-efivar.c index 912b61fdc..39f738990 100644 --- a/libfwupdplugin/fu-efivar.c +++ b/libfwupdplugin/fu-efivar.c @@ -322,6 +322,32 @@ fu_efivar_get_data (const gchar *guid, const gchar *name, guint8 **data, #endif } +/** + * fu_efivar_get_data_bytes: + * @guid: Globally unique identifier + * @name: Variable name + * @attr: (nullable): Attributes + * @error: A #GError + * + * Gets the data from a UEFI variable in NVRAM + * + * Returns: (transfer full): a #GBytes, or %NULL + * + * Since: 1.5.0 + **/ +GBytes * +fu_efivar_get_data_bytes (const gchar *guid, + const gchar *name, + guint32 *attr, + GError **error) +{ + guint8 *data = NULL; + gsize datasz = 0; + if (!fu_efivar_get_data (guid, name, &data, &datasz, attr, error)) + return NULL; + return g_bytes_new_take (data, datasz); +} + /** * fu_efivar_get_names: * @guid: Globally unique identifier @@ -454,6 +480,29 @@ fu_efivar_set_data (const gchar *guid, const gchar *name, const guint8 *data, #endif } +/** + * fu_efivar_set_data_bytes: + * @guid: Globally unique identifier + * @name: Variable name + * @bytes: a #GBytes + * @attr: Attributes + * @error: A #GError + * + * Sets the data to a UEFI variable in NVRAM + * + * Returns: %TRUE on success + * + * Since: 1.5.0 + **/ +gboolean +fu_efivar_set_data_bytes (const gchar *guid, const gchar *name, GBytes *bytes, + guint32 attr, GError **error) +{ + gsize bufsz = 0; + const guint8 *buf = g_bytes_get_data (bytes, &bufsz); + return fu_efivar_set_data (guid, name, buf, bufsz, attr, error); +} + /** * fu_efivar_secure_boot_enabled_full: * @error: A #GError diff --git a/libfwupdplugin/fu-efivar.h b/libfwupdplugin/fu-efivar.h index 0401083de..2b48819a7 100644 --- a/libfwupdplugin/fu-efivar.h +++ b/libfwupdplugin/fu-efivar.h @@ -31,12 +31,21 @@ gboolean fu_efivar_get_data (const gchar *guid, gsize *data_sz, guint32 *attr, GError **error); +GBytes *fu_efivar_get_data_bytes (const gchar *guid, + const gchar *name, + guint32 *attr, + GError **error); gboolean fu_efivar_set_data (const gchar *guid, const gchar *name, const guint8 *data, gsize sz, guint32 attr, GError **error); +gboolean fu_efivar_set_data_bytes (const gchar *guid, + const gchar *name, + GBytes *bytes, + guint32 attr, + GError **error); gboolean fu_efivar_delete (const gchar *guid, const gchar *name, GError **error); diff --git a/libfwupdplugin/fwupdplugin.map b/libfwupdplugin/fwupdplugin.map index b48b2ece0..7d60ff9d7 100644 --- a/libfwupdplugin/fwupdplugin.map +++ b/libfwupdplugin/fwupdplugin.map @@ -631,7 +631,9 @@ LIBFWUPDPLUGIN_1.5.0 { fu_device_report_metadata_pre; fu_device_sleep_with_progress; fu_device_unbind_driver; + fu_efivar_get_data_bytes; fu_efivar_secure_boot_enabled_full; + fu_efivar_set_data_bytes; fu_firmware_add_flag; fu_firmware_build; fu_firmware_flag_from_string; diff --git a/meson.build b/meson.build index ce99884e9..42b22f516 100644 --- a/meson.build +++ b/meson.build @@ -243,10 +243,6 @@ if valgrind.found() conf.set('HAVE_VALGRIND', '1') endif -if build_standalone and get_option('plugin_redfish') - efivar = dependency('efivar') -endif - if build_standalone and get_option('plugin_altos') libelf = dependency('libelf') endif diff --git a/plugins/redfish/fu-redfish-client.c b/plugins/redfish/fu-redfish-client.c index a570d5459..9b708f975 100644 --- a/plugins/redfish/fu-redfish-client.c +++ b/plugins/redfish/fu-redfish-client.c @@ -14,6 +14,7 @@ #include "fwupd-enums.h" #include "fu-device.h" +#include "fu-efivar.h" #include "fu-redfish-client.h" #include "fu-redfish-common.h" @@ -361,9 +362,9 @@ fu_redfish_client_set_uefi_credentials (FuRedfishClient *self, GError **error) g_autoptr(GBytes) userpass = NULL; /* get the uint32 specifying if there are EFI variables set */ - indications = fu_redfish_common_get_evivar_raw (REDFISH_EFI_INFORMATION_GUID, - REDFISH_EFI_INFORMATION_INDICATIONS, - error); + indications = fu_efivar_get_data_bytes (REDFISH_EFI_INFORMATION_GUID, + REDFISH_EFI_INFORMATION_INDICATIONS, + NULL, error); if (indications == NULL) return FALSE; if (g_bytes_get_size (indications) != 4) { @@ -385,9 +386,9 @@ fu_redfish_client_set_uefi_credentials (FuRedfishClient *self, GError **error) } /* read the correct EFI var for runtime */ - userpass = fu_redfish_common_get_evivar_raw (REDFISH_EFI_INFORMATION_GUID, - REDFISH_EFI_INFORMATION_OS_CREDENTIALS, - error); + userpass = fu_efivar_get_data_bytes (REDFISH_EFI_INFORMATION_GUID, + REDFISH_EFI_INFORMATION_OS_CREDENTIALS, + NULL, error); if (userpass == NULL) return FALSE; diff --git a/plugins/redfish/fu-redfish-common.c b/plugins/redfish/fu-redfish-common.c index 812f3e7de..98311e62e 100644 --- a/plugins/redfish/fu-redfish-common.c +++ b/plugins/redfish/fu-redfish-common.c @@ -10,26 +10,6 @@ #include "fu-redfish-common.h" -GBytes * -fu_redfish_common_get_evivar_raw (efi_guid_t guid, const gchar *name, GError **error) -{ - gsize sz = 0; - guint32 attribs = 0; - guint8 *data = NULL; - - if (efi_get_variable (guid, name, &data, &sz, &attribs) < 0) { - g_autofree gchar *guid_str = NULL; - efi_guid_to_str (&guid, &guid_str); - g_set_error (error, - FWUPD_ERROR, - FWUPD_ERROR_INVALID_FILE, - "failed to get efivar for %s %s", - guid_str, name); - return NULL; - } - return g_bytes_new_take (data, sz); -} - gchar * fu_redfish_common_buffer_to_ipv4 (const guint8 *buffer) { diff --git a/plugins/redfish/fu-redfish-common.h b/plugins/redfish/fu-redfish-common.h index baaee9f08..a7b40d467 100644 --- a/plugins/redfish/fu-redfish-common.h +++ b/plugins/redfish/fu-redfish-common.h @@ -7,7 +7,6 @@ #pragma once #include -#include /* SMBIOS */ #define REDFISH_SMBIOS_TABLE_TYPE 0x42 @@ -29,7 +28,7 @@ #define REDFISH_IP_ADDRESS_FORMAT_V6 0x02 /* EFI */ -#define REDFISH_EFI_INFORMATION_GUID EFI_GUID(0x16faa37e,0x4b6a,0x4891,0x9028,0x24,0x2d,0xe6,0x5a,0x3b,0x70) +#define REDFISH_EFI_INFORMATION_GUID "16faa37e-4b6a-4891-9028-242de65a3b70" #define REDFISH_EFI_INFORMATION_INDICATIONS "RedfishIndications" #define REDFISH_EFI_INFORMATION_FW_CREDENTIALS "RedfishFWCredentials" @@ -39,8 +38,5 @@ #define REDFISH_EFI_INDICATIONS_OS_CREDENTIALS 0x00000002 /* shared */ -GBytes *fu_redfish_common_get_evivar_raw (efi_guid_t guid, - const gchar *name, - GError **error); gchar *fu_redfish_common_buffer_to_ipv4 (const guint8 *buffer); gchar *fu_redfish_common_buffer_to_ipv6 (const guint8 *buffer); diff --git a/plugins/redfish/meson.build b/plugins/redfish/meson.build index 49d77ab71..927627918 100644 --- a/plugins/redfish/meson.build +++ b/plugins/redfish/meson.build @@ -21,7 +21,6 @@ shared_module('fu_plugin_redfish', c_args : cargs, dependencies : [ plugin_deps, - efivar, libjsonglib, ], ) @@ -46,7 +45,6 @@ if get_option('tests') ], dependencies : [ plugin_deps, - efivar, libjsonglib, ], link_with : [ From c7283ea61e9f7fa81f439861f1a592e2c97cecca Mon Sep 17 00:00:00 2001 From: Richard Hughes Date: Fri, 16 Oct 2020 23:16:04 +0100 Subject: [PATCH 551/607] uefi: Drop efivar dependency --- libfwupdplugin/fu-efivar.h | 5 ++- meson.build | 2 - plugins/uefi/fu-plugin-uefi.c | 19 ++++---- plugins/uefi/fu-uefi-bootmgr.c | 71 ++++++++---------------------- plugins/uefi/fu-uefi-common.c | 18 -------- plugins/uefi/fu-uefi-common.h | 8 ++-- plugins/uefi/fu-uefi-device.c | 62 +++++++++++--------------- plugins/uefi/fu-uefi-device.h | 2 +- plugins/uefi/fu-uefi-tool.c | 12 ++--- plugins/uefi/fu-uefi-update-info.c | 15 +++---- plugins/uefi/meson.build | 3 -- 11 files changed, 73 insertions(+), 144 deletions(-) diff --git a/libfwupdplugin/fu-efivar.h b/libfwupdplugin/fu-efivar.h index 2b48819a7..688fd2319 100644 --- a/libfwupdplugin/fu-efivar.h +++ b/libfwupdplugin/fu-efivar.h @@ -10,13 +10,14 @@ #include #define FU_EFIVAR_GUID_EFI_GLOBAL "8be4df61-93ca-11d2-aa0d-00e098032b8c" -#define FU_EFIVAR_GUID_FWUPDATE "0abba7dc-e516-4167-bbf5-4d9d1c739416" +#define FU_EFIVAR_GUID_FWUPDATE "0abba7dc-e516-4167-bbf5-4d9d1c739416" #define FU_EFIVAR_GUID_UX_CAPSULE "3b8c8162-188c-46a4-aec9-be43f1d65697" #define FU_EFIVAR_GUID_SECURITY_DATABASE "d719b2cb-3d3a-4596-a3bc-dad00e67656f" +#define FU_EFIVAR_GUID_UX_CAPSULE "3b8c8162-188c-46a4-aec9-be43f1d65697" #define FU_EFIVAR_ATTR_NON_VOLATILE (1 << 0) #define FU_EFIVAR_ATTR_BOOTSERVICE_ACCESS (1 << 1) -#define FU_EFIVAR_ATTR_RUNTIME_ACCESS (1 << 2) +#define FU_EFIVAR_ATTR_RUNTIME_ACCESS (1 << 2) #define FU_EFIVAR_ATTR_HARDWARE_ERROR_RECORD (1 << 3) #define FU_EFIVAR_ATTR_AUTHENTICATED_WRITE_ACCESS (1 << 4) #define FU_EFIVAR_ATTR_TIME_BASED_AUTHENTICATED_WRITE_ACCESS (1 << 5) diff --git a/meson.build b/meson.build index 42b22f516..772b7bbe6 100644 --- a/meson.build +++ b/meson.build @@ -307,8 +307,6 @@ if build_standalone and get_option('plugin_uefi') cairo = dependency('cairo') fontconfig = cc.find_library('fontconfig') freetype = cc.find_library('freetype') - efivar = dependency('efivar', version : '>= 33') - conf.set_quoted('EFIVAR_LIBRARY_VERSION', efivar.version()) efiboot = dependency('efiboot') objcopy = find_program ('objcopy') readelf = find_program ('readelf') diff --git a/plugins/uefi/fu-plugin-uefi.c b/plugins/uefi/fu-plugin-uefi.c index 0be6e1614..3c621b1a3 100644 --- a/plugins/uefi/fu-plugin-uefi.c +++ b/plugins/uefi/fu-plugin-uefi.c @@ -39,7 +39,6 @@ fu_plugin_init (FuPlugin *plugin) data->bgrt = fu_uefi_bgrt_new (); fu_plugin_add_rule (plugin, FU_PLUGIN_RULE_RUN_AFTER, "upower"); fu_plugin_add_rule (plugin, FU_PLUGIN_RULE_METADATA_SOURCE, "tpm_eventlog"); - fu_plugin_add_compile_version (plugin, "com.redhat.efivar", EFIVAR_LIBRARY_VERSION); fu_plugin_set_build_hash (plugin, FU_BUILD_HASH); } @@ -218,7 +217,7 @@ fu_plugin_uefi_write_splash_data (FuPlugin *plugin, efi_ux_capsule_header_t header = { 0 }; efi_capsule_header_t capsule_header = { .flags = EFI_CAPSULE_HEADER_FLAGS_PERSIST_ACROSS_RESET, - .guid = efi_guid_ux_capsule, + .guid = { 0x0 }, .header_size = sizeof(efi_capsule_header_t), .capsule_image_size = 0 }; @@ -251,6 +250,11 @@ fu_plugin_uefi_write_splash_data (FuPlugin *plugin, if (ostream == NULL) return FALSE; + if (!fwupd_guid_from_string (FU_EFIVAR_GUID_UX_CAPSULE, + &capsule_header.guid, + FWUPD_GUID_FLAG_MIXED_ENDIAN, + error)) + return FALSE; capsule_header.capsule_image_size = g_bytes_get_size (blob) + sizeof(efi_capsule_header_t) + @@ -285,13 +289,10 @@ fu_plugin_uefi_write_splash_data (FuPlugin *plugin, return FALSE; /* write display capsule location as UPDATE_INFO */ - if (!fu_uefi_device_write_update_info (FU_UEFI_DEVICE (device), fn, - "fwupd-ux-capsule", - &efi_guid_ux_capsule, error)) - return FALSE; - - /* success */ - return TRUE; + return fu_uefi_device_write_update_info (FU_UEFI_DEVICE (device), fn, + "fwupd-ux-capsule", + FU_EFIVAR_GUID_UX_CAPSULE, + error); } static gboolean diff --git a/plugins/uefi/fu-uefi-bootmgr.c b/plugins/uefi/fu-uefi-bootmgr.c index 8b04335f2..ee7396728 100644 --- a/plugins/uefi/fu-uefi-bootmgr.c +++ b/plugins/uefi/fu-uefi-bootmgr.c @@ -7,7 +7,6 @@ #include "config.h" #include -#include #include #include @@ -25,46 +24,22 @@ static gboolean fu_uefi_bootmgr_add_to_boot_order (guint16 boot_entry, GError **error) { gsize boot_order_size = 0; - gint rc; guint i = 0; - guint32 attr = EFI_VARIABLE_NON_VOLATILE | - EFI_VARIABLE_BOOTSERVICE_ACCESS | - EFI_VARIABLE_RUNTIME_ACCESS; + guint32 attr = 0; g_autofree guint16 *boot_order = NULL; g_autofree guint16 *new_boot_order = NULL; - /* get size of the BootOrder */ - rc = efi_get_variable_size (efi_guid_global, "BootOrder", &boot_order_size); - if (rc == ENOENT) { - boot_order_size = 0; - efi_error_clear (); - } else if (rc < 0) { - g_set_error (error, - G_IO_ERROR, - G_IO_ERROR_FAILED, - "efi_get_variable_size() failed"); - return rc; - } - /* get the current boot order */ - if (boot_order_size != 0) { - rc = efi_get_variable (efi_guid_global, "BootOrder", - (guint8 **)&boot_order, &boot_order_size, - &attr); - if (rc < 0) { - g_set_error_literal (error, - G_IO_ERROR, - G_IO_ERROR_FAILED, - "efi_get_variable(BootOrder) failed"); - return FALSE; - } + if (!fu_efivar_get_data (FU_EFIVAR_GUID_EFI_GLOBAL, "BootOrder", + (guint8 **) &boot_order, &boot_order_size, + &attr, error)) + return FALSE; - /* already set next */ - for (i = 0; i < boot_order_size / sizeof (guint16); i++) { - guint16 val = boot_order[i]; - if (val == boot_entry) - return TRUE; - } + /* already set next */ + for (i = 0; i < boot_order_size / sizeof (guint16); i++) { + guint16 val = boot_order[i]; + if (val == boot_entry) + return TRUE; } /* add the new boot index to the end of the list */ @@ -72,21 +47,16 @@ fu_uefi_bootmgr_add_to_boot_order (guint16 boot_entry, GError **error) if (boot_order_size != 0) memcpy (new_boot_order, boot_order, boot_order_size); + attr |= FU_EFIVAR_ATTR_NON_VOLATILE | + FU_EFIVAR_ATTR_BOOTSERVICE_ACCESS | + FU_EFIVAR_ATTR_RUNTIME_ACCESS; + i = boot_order_size / sizeof (guint16); new_boot_order[i] = boot_entry; boot_order_size += sizeof (guint16); - rc = efi_set_variable(efi_guid_global, "BootOrder", - (guint8 *)new_boot_order, boot_order_size, - attr, 0644); - if (rc < 0) { - g_set_error_literal (error, - G_IO_ERROR, - G_IO_ERROR_FAILED, - "efi_set_variable(BootOrder) failed"); - return FALSE; - } - - return TRUE; + return fu_efivar_set_data (FU_EFIVAR_GUID_EFI_GLOBAL, "BootOrder", + (guint8 *)new_boot_order, boot_order_size, + attr, error); } static gboolean @@ -152,7 +122,6 @@ fu_uefi_setup_bootnext_with_dp (const guint8 *dp_buf, guint8 *opt, gssize opt_si var_data = g_steal_pointer (&var_data_tmp); boot_next = entry; - efi_error_clear (); break; } @@ -408,9 +377,5 @@ fu_uefi_bootmgr_bootnext (const gchar *esp_path, "loadopt size was unreasonable."); return FALSE; } - if (!fu_uefi_setup_bootnext_with_dp (dp_buf, opt, opt_size, error)) - return FALSE; - efi_error_clear(); - - return TRUE; + return fu_uefi_setup_bootnext_with_dp (dp_buf, opt, opt_size, error); } diff --git a/plugins/uefi/fu-uefi-common.c b/plugins/uefi/fu-uefi-common.c index 6cd556726..a5b554293 100644 --- a/plugins/uefi/fu-uefi-common.c +++ b/plugins/uefi/fu-uefi-common.c @@ -263,21 +263,3 @@ fu_uefi_read_file_as_uint64 (const gchar *path, const gchar *attr_name) return 0x0; return fu_common_strtoull (data); } - -void -fu_uefi_print_efivar_errors (void) -{ - for (gint i = 0; ; i++) { - gchar *filename = NULL; - gchar *function = NULL; - gchar *message = NULL; - gint line = 0; - gint err = 0; - if (efi_error_get (i, &filename, &function, &line, - &message, &err) <= 0) - break; - g_debug ("{efivar error #%d} %s:%d %s(): %s: %s\t", - i, filename, line, function, - message, strerror (err)); - } -} diff --git a/plugins/uefi/fu-uefi-common.h b/plugins/uefi/fu-uefi-common.h index cf7381169..42f89e956 100644 --- a/plugins/uefi/fu-uefi-common.h +++ b/plugins/uefi/fu-uefi-common.h @@ -8,7 +8,8 @@ #pragma once #include -#include + +#include "fwupd-common.h" #define EFI_CAPSULE_HEADER_FLAGS_PERSIST_ACROSS_RESET 0x00010000 #define EFI_CAPSULE_HEADER_FLAGS_POPULATE_SYSTEM_TABLE 0x00020000 @@ -29,7 +30,7 @@ typedef struct __attribute__((__packed__)) { } efi_time_t; typedef struct __attribute__((__packed__)) { - efi_guid_t guid; + fwupd_guid_t guid; guint32 header_size; guint32 flags; guint32 capsule_image_size; @@ -47,7 +48,7 @@ typedef struct __attribute__((__packed__)) { typedef struct __attribute__((__packed__)) { guint32 update_info_version; - efi_guid_t guid; + fwupd_guid_t guid; guint32 capsule_flags; guint64 hw_inst; efi_time_t time_attempted; @@ -74,4 +75,3 @@ GPtrArray *fu_uefi_get_esrt_entry_paths (const gchar *esrt_path, GError **error); guint64 fu_uefi_read_file_as_uint64 (const gchar *path, const gchar *attr_name); -void fu_uefi_print_efivar_errors (void); diff --git a/plugins/uefi/fu-uefi-device.c b/plugins/uefi/fu-uefi-device.c index f35964b6f..80f204125 100644 --- a/plugins/uefi/fu-uefi-device.c +++ b/plugins/uefi/fu-uefi-device.c @@ -340,26 +340,21 @@ fu_uefi_device_fixup_firmware (FuDevice *device, GBytes *fw, GError **error) { FuUefiDevice *self = FU_UEFI_DEVICE (device); gsize fw_length; - efi_guid_t esrt_guid; - efi_guid_t payload_guid; - const gchar *data = g_bytes_get_data (fw, &fw_length); + const guint8 *data = g_bytes_get_data (fw, &fw_length); + g_autofree gchar *guid_new = NULL; + self->missing_header = FALSE; - /* convert to EFI GUIDs */ - if (efi_str_to_guid (fu_uefi_device_get_guid (self), &esrt_guid) < 0) { - g_set_error_literal (error, FWUPD_ERROR, FWUPD_ERROR_INTERNAL, - "Invalid ESRT GUID"); - return NULL; - } - if (fw_length < sizeof(efi_guid_t)) { + /* GUID is the first 16 bytes */ + if (fw_length < sizeof(fwupd_guid_t)) { g_set_error_literal (error, FWUPD_ERROR, FWUPD_ERROR_INVALID_FILE, "Invalid payload"); return NULL; } - memcpy (&payload_guid, data, sizeof(efi_guid_t)); + guid_new = fwupd_guid_to_string ((fwupd_guid_t *) data, FWUPD_GUID_FLAG_MIXED_ENDIAN); /* ESRT header matches payload */ - if (efi_guid_cmp (&esrt_guid, &payload_guid) == 0) { + if (g_strcmp0 (fu_uefi_device_get_guid (self), guid_new) == 0) { g_debug ("ESRT matches payload GUID"); return g_bytes_new_from_bytes (fw, 0, fw_length); /* Type that doesn't require a header */ @@ -370,6 +365,7 @@ fu_uefi_device_fixup_firmware (FuDevice *device, GBytes *fw, GError **error) guint header_size = getpagesize(); guint8 *new_data = g_malloc (fw_length + header_size); guint8 *capsule = new_data + header_size; + fwupd_guid_t esrt_guid = { 0x0 }; efi_capsule_header_t *header = (efi_capsule_header_t *) new_data; g_warning ("missing or invalid embedded capsule header"); @@ -377,7 +373,12 @@ fu_uefi_device_fixup_firmware (FuDevice *device, GBytes *fw, GError **error) header->flags = self->capsule_flags; header->header_size = header_size; header->capsule_image_size = fw_length + header_size; - memcpy (&header->guid, &esrt_guid, sizeof (efi_guid_t)); + if (!fwupd_guid_from_string (fu_uefi_device_get_guid (self), &esrt_guid, + FWUPD_GUID_FLAG_MIXED_ENDIAN, error)) { + g_prefix_error (error, "Invalid ESRT GUID: "); + return NULL; + } + memcpy (&header->guid, &esrt_guid, sizeof (fwupd_guid_t)); memcpy (capsule, data, fw_length); return g_bytes_new_take (new_data, fw_length + header_size); @@ -388,7 +389,7 @@ gboolean fu_uefi_device_write_update_info (FuUefiDevice *self, const gchar *filename, const gchar *varname, - const efi_guid_t *guid, + const gchar *guid, GError **error) { gsize datasz = 0; @@ -412,27 +413,22 @@ fu_uefi_device_write_update_info (FuUefiDevice *self, /* convert to EFI device path */ dp_buf = fu_uefi_device_build_dp_buf (filename, &dp_bufsz, error); - if (dp_buf == NULL) { - fu_uefi_print_efivar_errors (); + if (dp_buf == NULL) return FALSE; - } /* save this header and body to the hardware */ - memcpy (&info.guid, guid, sizeof(efi_guid_t)); + if (!fwupd_guid_from_string (guid, &info.guid, FWUPD_GUID_FLAG_MIXED_ENDIAN, error)) + return FALSE; datasz = sizeof(info) + dp_bufsz; data = g_malloc0 (datasz); memcpy (data, &info, sizeof(info)); memcpy (data + sizeof(info), dp_buf, dp_bufsz); - if (!fu_efivar_set_data (FU_EFIVAR_GUID_FWUPDATE, varname, - data, datasz, - FU_EFIVAR_ATTR_NON_VOLATILE | - FU_EFIVAR_ATTR_BOOTSERVICE_ACCESS | - FU_EFIVAR_ATTR_RUNTIME_ACCESS, - error)) { - fu_uefi_print_efivar_errors (); - return FALSE; - } - return TRUE; + return fu_efivar_set_data (FU_EFIVAR_GUID_FWUPDATE, varname, + data, datasz, + FU_EFIVAR_ATTR_NON_VOLATILE | + FU_EFIVAR_ATTR_BOOTSERVICE_ACCESS | + FU_EFIVAR_ATTR_RUNTIME_ACCESS, + error); } static gboolean @@ -541,7 +537,6 @@ fu_uefi_device_write_firmware (FuDevice *device, FuUefiDevice *self = FU_UEFI_DEVICE (device); FuUefiBootmgrFlags flags = FU_UEFI_BOOTMGR_FLAG_NONE; const gchar *bootmgr_desc = "Linux Firmware Updater"; - efi_guid_t guid; g_autofree gchar *esp_path = fu_volume_get_mount_point (self->esp); g_autoptr(GBytes) fixed_fw = NULL; g_autoptr(GBytes) fw = NULL; @@ -577,14 +572,7 @@ fu_uefi_device_write_firmware (FuDevice *device, return FALSE; /* set the blob header shared with fwupd.efi */ - if (efi_str_to_guid (self->fw_class, &guid) < 0) { - g_set_error_literal (error, - FWUPD_ERROR, - FWUPD_ERROR_NOT_SUPPORTED, - "failed to get convert GUID"); - return FALSE; - } - if (!fu_uefi_device_write_update_info (self, fn, varname, &guid, error)) + if (!fu_uefi_device_write_update_info (self, fn, varname, self->fw_class, error)) return FALSE; /* update the firmware before the bootloader runs */ diff --git a/plugins/uefi/fu-uefi-device.h b/plugins/uefi/fu-uefi-device.h index ce60b338e..385430c9c 100644 --- a/plugins/uefi/fu-uefi-device.h +++ b/plugins/uefi/fu-uefi-device.h @@ -59,5 +59,5 @@ FuUefiUpdateInfo *fu_uefi_device_load_update_info (FuUefiDevice *self, gboolean fu_uefi_device_write_update_info (FuUefiDevice *self, const gchar *filename, const gchar *varname, - const efi_guid_t *guid, + const gchar *guid, GError **error); diff --git a/plugins/uefi/fu-uefi-tool.c b/plugins/uefi/fu-uefi-tool.c index a6f373f67..52b262240 100644 --- a/plugins/uefi/fu-uefi-tool.c +++ b/plugins/uefi/fu-uefi-tool.c @@ -288,12 +288,12 @@ main (int argc, char *argv[]) const guint8 data = 1; g_autoptr(GError) error_local = NULL; if (!fu_efivar_set_data (FU_EFIVAR_GUID_FWUPDATE, - "FWUPDATE_VERBOSE", - &data, sizeof(data), - EFI_VARIABLE_NON_VOLATILE | - EFI_VARIABLE_BOOTSERVICE_ACCESS | - EFI_VARIABLE_RUNTIME_ACCESS, - &error_local)) { + "FWUPDATE_VERBOSE", + &data, sizeof(data), + FU_EFIVAR_ATTR_NON_VOLATILE | + FU_EFIVAR_ATTR_BOOTSERVICE_ACCESS | + FU_EFIVAR_ATTR_RUNTIME_ACCESS, + &error_local)) { g_printerr ("failed: %s\n", error_local->message); return EXIT_FAILURE; } diff --git a/plugins/uefi/fu-uefi-update-info.c b/plugins/uefi/fu-uefi-update-info.c index 9454844ce..3dc138dcc 100644 --- a/plugins/uefi/fu-uefi-update-info.c +++ b/plugins/uefi/fu-uefi-update-info.c @@ -14,6 +14,9 @@ #include "fwupd-error.h" +#define EFIDP_MEDIA_TYPE 0x04 +#define EFIDP_MEDIA_FILE 0x4 + struct _FuUefiUpdateInfo { GObject parent_instance; guint32 version; @@ -80,7 +83,7 @@ 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; + fwupd_guid_t guid_tmp; g_return_val_if_fail (FU_IS_UEFI_UPDATE_INFO (self), FALSE); @@ -96,14 +99,8 @@ fu_uefi_update_info_parse (FuUefiUpdateInfo *self, const guint8 *buf, gsize sz, 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; - } + memcpy (&guid_tmp, &info.guid, sizeof(fwupd_guid_t)); + self->guid = fwupd_guid_to_string (&guid_tmp, FWUPD_GUID_FLAG_MIXED_ENDIAN); 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), diff --git a/plugins/uefi/meson.build b/plugins/uefi/meson.build index 3f13f4c75..2d1b2d221 100644 --- a/plugins/uefi/meson.build +++ b/plugins/uefi/meson.build @@ -37,7 +37,6 @@ shared_module('fu_plugin_uefi', c_args : cargs, dependencies : [ plugin_deps, - efivar, efiboot, tpm2tss, ], @@ -68,7 +67,6 @@ fwupdate = executable( giounix, gusb, gudev, - efivar, efiboot, tpm2tss, ], @@ -126,7 +124,6 @@ if get_option('tests') ], dependencies : [ plugin_deps, - efivar, efiboot, tpm2tss, ], From 6a29672bc394b1c96d00b3caa0803af10e72fa69 Mon Sep 17 00:00:00 2001 From: Richard Hughes Date: Mon, 19 Oct 2020 21:36:43 +0100 Subject: [PATCH 552/607] Do more processing when tokenizing the Intel HEX file --- libfwupdplugin/fu-ihex-firmware.c | 289 +++++++++++++++--------------- libfwupdplugin/fu-ihex-firmware.h | 12 ++ 2 files changed, 154 insertions(+), 147 deletions(-) diff --git a/libfwupdplugin/fu-ihex-firmware.c b/libfwupdplugin/fu-ihex-firmware.c index 27b4d34e7..49a9f5095 100644 --- a/libfwupdplugin/fu-ihex-firmware.c +++ b/libfwupdplugin/fu-ihex-firmware.c @@ -30,14 +30,6 @@ struct _FuIhexFirmware { G_DEFINE_TYPE (FuIhexFirmware, fu_ihex_firmware, FU_TYPE_FIRMWARE) -#define DFU_INHX32_RECORD_TYPE_DATA 0x00 -#define DFU_INHX32_RECORD_TYPE_EOF 0x01 -#define DFU_INHX32_RECORD_TYPE_EXTENDED_SEGMENT 0x02 -#define DFU_INHX32_RECORD_TYPE_START_SEGMENT 0x03 -#define DFU_INHX32_RECORD_TYPE_EXTENDED_LINEAR 0x04 -#define DFU_INHX32_RECORD_TYPE_START_LINEAR 0x05 -#define DFU_INHX32_RECORD_TYPE_SIGNATURE 0xfd - /** * fu_ihex_firmware_get_records: * @self: A #FuIhexFirmware @@ -62,36 +54,100 @@ static void fu_ihex_firmware_record_free (FuIhexFirmwareRecord *rcd) { g_string_free (rcd->buf, TRUE); + g_byte_array_unref (rcd->data); g_free (rcd); } G_DEFINE_AUTOPTR_CLEANUP_FUNC(FuIhexFirmwareRecord, fu_ihex_firmware_record_free) static FuIhexFirmwareRecord * -fu_ihex_firmware_record_new (guint ln, const gchar *buf) +fu_ihex_firmware_record_new (guint ln, const gchar *line, + FwupdInstallFlags flags, GError **error) { - FuIhexFirmwareRecord *rcd = g_new0 (FuIhexFirmwareRecord, 1); + g_autoptr(FuIhexFirmwareRecord) rcd = NULL; + guint line_end; + + /* check starting token */ + if (line[0] != ':') { + g_set_error (error, + FWUPD_ERROR, + FWUPD_ERROR_INVALID_FILE, + "invalid starting token: %s", + line); + return NULL; + } + + /* length, 16-bit address, type */ + rcd = g_new0 (FuIhexFirmwareRecord, 1); rcd->ln = ln; - rcd->buf = g_string_new (buf); - return rcd; + rcd->data = g_byte_array_new (); + rcd->buf = g_string_new (line); + rcd->byte_cnt = fu_firmware_strparse_uint8 (line + 1); + rcd->addr = fu_firmware_strparse_uint16 (line + 3); + rcd->record_type = fu_firmware_strparse_uint8 (line + 7); + + /* check there's enough data for the smallest possible record */ + if (rcd->buf->len < 11) { + g_set_error (error, + FWUPD_ERROR, + FWUPD_ERROR_INVALID_FILE, + "line incomplete, length: %u", + (guint) rcd->buf->len); + return NULL; + } + + /* position of checksum */ + line_end = 9 + rcd->byte_cnt * 2; + if (line_end > (guint) rcd->buf->len) { + g_set_error (error, + FWUPD_ERROR, + FWUPD_ERROR_INVALID_FILE, + "line malformed, length: %u", + line_end); + return NULL; + } + + /* verify checksum */ + if ((flags & FWUPD_INSTALL_FLAG_IGNORE_CHECKSUM) == 0) { + guint8 checksum = 0; + for (guint i = 1; i < line_end + 2; i += 2) { + guint8 data_tmp = fu_firmware_strparse_uint8 (line + i); + checksum += data_tmp; + } + if (checksum != 0) { + g_set_error (error, + FWUPD_ERROR, + FWUPD_ERROR_INVALID_FILE, + "invalid checksum (0x%02x)", + checksum); + return NULL; + } + } + + /* add data */ + for (guint i = 9; i < line_end; i += 2) { + guint8 tmp_c = fu_firmware_strparse_uint8 (line + i); + fu_byte_array_append_uint8 (rcd->data, tmp_c); + } + return g_steal_pointer (&rcd); } static const gchar * fu_ihex_firmware_record_type_to_string (guint8 record_type) { - if (record_type == DFU_INHX32_RECORD_TYPE_DATA) + if (record_type == FU_IHEX_FIRMWARE_RECORD_TYPE_DATA) return "DATA"; - if (record_type == DFU_INHX32_RECORD_TYPE_EOF) + if (record_type == FU_IHEX_FIRMWARE_RECORD_TYPE_EOF) return "EOF"; - if (record_type == DFU_INHX32_RECORD_TYPE_EXTENDED_SEGMENT) + if (record_type == FU_IHEX_FIRMWARE_RECORD_TYPE_EXTENDED_SEGMENT) return "EXTENDED_SEGMENT"; - if (record_type == DFU_INHX32_RECORD_TYPE_START_SEGMENT) + if (record_type == FU_IHEX_FIRMWARE_RECORD_TYPE_START_SEGMENT) return "START_SEGMENT"; - if (record_type == DFU_INHX32_RECORD_TYPE_EXTENDED_LINEAR) + if (record_type == FU_IHEX_FIRMWARE_RECORD_TYPE_EXTENDED_LINEAR) return "EXTENDED_LINEAR"; - if (record_type == DFU_INHX32_RECORD_TYPE_START_LINEAR) + if (record_type == FU_IHEX_FIRMWARE_RECORD_TYPE_START_LINEAR) return "ADDR32"; - if (record_type == DFU_INHX32_RECORD_TYPE_SIGNATURE) + if (record_type == FU_IHEX_FIRMWARE_RECORD_TYPE_SIGNATURE) return "SIGNATURE"; return NULL; } @@ -108,9 +164,15 @@ fu_ihex_firmware_tokenize (FuFirmware *firmware, GBytes *fw, for (guint ln = 0; lines[ln] != NULL; ln++) { g_autoptr(FuIhexFirmwareRecord) rcd = NULL; g_strdelimit (lines[ln], "\r\x1a", '\0'); + if (g_str_has_prefix (lines[ln], ";")) + continue; if (lines[ln][0] == '\0') continue; - rcd = fu_ihex_firmware_record_new (ln + 1, lines[ln]); + rcd = fu_ihex_firmware_record_new (ln + 1, lines[ln], flags, error); + if (rcd == NULL) { + g_prefix_error (error, "invalid line %u: ", ln + 1); + return FALSE; + } g_ptr_array_add (self->records, g_steal_pointer (&rcd)); } return TRUE; @@ -133,87 +195,21 @@ fu_ihex_firmware_parse (FuFirmware *firmware, g_autoptr(FuFirmwareImage) img = fu_firmware_image_new (NULL); g_autoptr(GBytes) img_bytes = NULL; g_autoptr(GByteArray) buf = g_byte_array_new (); - g_autoptr(GByteArray) buf_signature = g_byte_array_new (); /* parse records */ for (guint k = 0; k < self->records->len; k++) { FuIhexFirmwareRecord *rcd = g_ptr_array_index (self->records, k); - const gchar *line = rcd->buf->str; - guint32 addr; - guint8 byte_cnt; - guint8 record_type; - guint line_end; + guint16 addr16 = 0; + guint32 addr = rcd->addr + seg_addr + abs_addr; + guint32 len_hole; - /* ignore comments */ - if (g_str_has_prefix (line, ";")) - continue; - - /* ignore blank lines */ - if (rcd->buf->len == 0) - continue; - - /* check starting token */ - if (line[0] != ':') { - g_set_error (error, - FWUPD_ERROR, - FWUPD_ERROR_INVALID_FILE, - "invalid starting token on line %u: %s", - rcd->ln, line); - return FALSE; - } - - /* check there's enough data for the smallest possible record */ - if (rcd->buf->len < 11) { - g_set_error (error, - FWUPD_ERROR, - FWUPD_ERROR_INVALID_FILE, - "line %u is incomplete, length %u", - rcd->ln, (guint) rcd->buf->len); - return FALSE; - } - - /* length, 16-bit address, type */ - byte_cnt = fu_firmware_strparse_uint8 (line + 1); - addr = fu_firmware_strparse_uint16 (line + 3); - record_type = fu_firmware_strparse_uint8 (line + 7); - g_debug ("%s:", fu_ihex_firmware_record_type_to_string (record_type)); - g_debug (" addr_start:\t0x%04x", addr); - g_debug (" length:\t0x%02x", byte_cnt); - addr += seg_addr; - addr += abs_addr; + g_debug ("%s:", fu_ihex_firmware_record_type_to_string (rcd->record_type)); + g_debug (" length:\t0x%02x", rcd->data->len); g_debug (" addr:\t0x%08x", addr); - /* position of checksum */ - line_end = 9 + byte_cnt * 2; - if (line_end > (guint) rcd->buf->len) { - g_set_error (error, - FWUPD_ERROR, - FWUPD_ERROR_INVALID_FILE, - "line %u malformed, length: %u", - rcd->ln, line_end); - return FALSE; - } - - /* verify checksum */ - if ((flags & FWUPD_INSTALL_FLAG_IGNORE_CHECKSUM) == 0) { - guint8 checksum = 0; - for (guint i = 1; i < line_end + 2; i += 2) { - guint8 data_tmp = fu_firmware_strparse_uint8 (line + i); - checksum += data_tmp; - } - if (checksum != 0) { - g_set_error (error, - FWUPD_ERROR, - FWUPD_ERROR_INVALID_FILE, - "line %u has invalid checksum (0x%02x)", - rcd->ln, checksum); - return FALSE; - } - } - /* process different record types */ - switch (record_type) { - case DFU_INHX32_RECORD_TYPE_DATA: + switch (rcd->record_type) { + case FU_IHEX_FIRMWARE_RECORD_TYPE_DATA: /* base address for element */ if (img_addr == G_MAXUINT32) img_addr = addr; @@ -230,37 +226,32 @@ fu_ihex_firmware_parse (FuFirmware *firmware, return FALSE; } - /* parse bytes from line */ - g_debug ("writing data 0x%08x", (guint32) addr); - for (guint i = 9; i < line_end; i += 2) { - /* any holes in the hex record */ - guint32 len_hole = addr - addr_last; - guint8 data_tmp; - if (addr_last > 0 && len_hole > 0x100000) { - g_set_error (error, - FWUPD_ERROR, - FWUPD_ERROR_INVALID_FILE, - "hole of 0x%x bytes too large to fill on line %u", - (guint) len_hole, - rcd->ln); - return FALSE; - } - if (addr_last > 0x0 && len_hole > 1) { - g_debug ("filling address 0x%08x to 0x%08x on line %u", - addr_last + 1, addr_last + len_hole - 1, rcd->ln); - for (guint j = 1; j < len_hole; j++) { - /* although 0xff might be clearer, - * we can't write 0xffff to pic14 */ - fu_byte_array_append_uint8 (buf, 0x00); - } - } - /* write into buf */ - data_tmp = fu_firmware_strparse_uint8 (line + i); - fu_byte_array_append_uint8 (buf, (gchar) data_tmp); - addr_last = addr++; + /* any holes in the hex record */ + len_hole = addr - addr_last; + if (addr_last > 0 && len_hole > 0x100000) { + g_set_error (error, + FWUPD_ERROR, + FWUPD_ERROR_INVALID_FILE, + "hole of 0x%x bytes too large to fill on line %u", + (guint) len_hole, + rcd->ln); + return FALSE; } + if (addr_last > 0x0 && len_hole > 1) { + g_debug ("filling address 0x%08x to 0x%08x on line %u", + addr_last + 1, addr_last + len_hole - 1, rcd->ln); + for (guint j = 1; j < len_hole; j++) { + /* although 0xff might be clearer, + * we can't write 0xffff to pic14 */ + fu_byte_array_append_uint8 (buf, 0x00); + } + } + addr_last = addr + rcd->data->len - 1; + + /* write into buf */ + g_byte_array_append (buf, rcd->data->data, rcd->data->len); break; - case DFU_INHX32_RECORD_TYPE_EOF: + case FU_IHEX_FIRMWARE_RECORD_TYPE_EOF: if (got_eof) { g_set_error_literal (error, FWUPD_ERROR, @@ -271,28 +262,40 @@ fu_ihex_firmware_parse (FuFirmware *firmware, } got_eof = TRUE; break; - case DFU_INHX32_RECORD_TYPE_EXTENDED_LINEAR: - abs_addr = fu_firmware_strparse_uint16 (line + 9) << 16; + case FU_IHEX_FIRMWARE_RECORD_TYPE_EXTENDED_LINEAR: + if (!fu_common_read_uint16_safe (rcd->data->data, rcd->data->len, + 0x0, &addr16, G_BIG_ENDIAN, error)) + return FALSE; + abs_addr = (guint32) addr16 << 16; g_debug (" abs_addr:\t0x%02x on line %u", abs_addr, rcd->ln); break; - case DFU_INHX32_RECORD_TYPE_START_LINEAR: - abs_addr = fu_firmware_strparse_uint32 (line + 9); + case FU_IHEX_FIRMWARE_RECORD_TYPE_START_LINEAR: + if (!fu_common_read_uint32_safe (rcd->data->data, rcd->data->len, + 0x0, &abs_addr, G_BIG_ENDIAN, error)) + return FALSE; g_debug (" abs_addr:\t0x%08x on line %u", abs_addr, rcd->ln); break; - case DFU_INHX32_RECORD_TYPE_EXTENDED_SEGMENT: + case FU_IHEX_FIRMWARE_RECORD_TYPE_EXTENDED_SEGMENT: + if (!fu_common_read_uint16_safe (rcd->data->data, rcd->data->len, + 0x0, &addr16, G_BIG_ENDIAN, error)) + return FALSE; /* segment base address, so ~1Mb addressable */ - seg_addr = fu_firmware_strparse_uint16 (line + 9) * 16; + seg_addr = (guint32) addr16 * 16; g_debug (" seg_addr:\t0x%08x on line %u", seg_addr, rcd->ln); break; - case DFU_INHX32_RECORD_TYPE_START_SEGMENT: + case FU_IHEX_FIRMWARE_RECORD_TYPE_START_SEGMENT: /* initial content of the CS:IP registers */ - seg_addr = fu_firmware_strparse_uint32 (line + 9); + if (!fu_common_read_uint32_safe (rcd->data->data, rcd->data->len, + 0x0, &seg_addr, G_BIG_ENDIAN, error)) + return FALSE; g_debug (" seg_addr:\t0x%02x on line %u", seg_addr, rcd->ln); break; - case DFU_INHX32_RECORD_TYPE_SIGNATURE: - for (guint i = 9; i < line_end; i += 2) { - guint8 tmp_c = fu_firmware_strparse_uint8 (line + i); - fu_byte_array_append_uint8 (buf_signature, tmp_c); + case FU_IHEX_FIRMWARE_RECORD_TYPE_SIGNATURE: + if (rcd->data->len > 0) { + g_autoptr(GBytes) data_sig = g_bytes_new (rcd->data->data, rcd->data->len); + g_autoptr(FuFirmwareImage) img_sig = fu_firmware_image_new (data_sig); + fu_firmware_image_set_id (img_sig, FU_FIRMWARE_IMAGE_ID_SIGNATURE); + fu_firmware_add_image (firmware, img_sig); } break; default: @@ -303,7 +306,7 @@ fu_ihex_firmware_parse (FuFirmware *firmware, FWUPD_ERROR, FWUPD_ERROR_INVALID_FILE, "invalid ihex record type %i on line %u", - record_type, rcd->ln); + rcd->record_type, rcd->ln); return FALSE; } } @@ -323,14 +326,6 @@ fu_ihex_firmware_parse (FuFirmware *firmware, if (img_addr != G_MAXUINT32) fu_firmware_image_set_addr (img, img_addr); fu_firmware_add_image (firmware, img); - - /* add optional signature */ - if (buf_signature->len > 0) { - g_autoptr(GBytes) data_sig = g_bytes_new (buf_signature->data, buf_signature->len); - g_autoptr(FuFirmwareImage) img_sig = fu_firmware_image_new (data_sig); - fu_firmware_image_set_id (img_sig, FU_FIRMWARE_IMAGE_ID_SIGNATURE); - fu_firmware_add_image (firmware, img_sig); - } return TRUE; } @@ -364,7 +359,7 @@ fu_ihex_firmware_image_to_string (FuFirmwareImage *img, GString *str, GError **e const guint chunk_size = 16; gsize len; guint32 address_offset_last = 0x0; - guint8 record_type = DFU_INHX32_RECORD_TYPE_DATA; + guint8 record_type = FU_IHEX_FIRMWARE_RECORD_TYPE_DATA; g_autoptr(GBytes) bytes = NULL; /* get data */ @@ -375,7 +370,7 @@ fu_ihex_firmware_image_to_string (FuFirmwareImage *img, GString *str, GError **e /* special case */ if (g_strcmp0 (fu_firmware_image_get_id (img), FU_FIRMWARE_IMAGE_ID_SIGNATURE) == 0) - record_type = DFU_INHX32_RECORD_TYPE_SIGNATURE; + record_type = FU_IHEX_FIRMWARE_RECORD_TYPE_SIGNATURE; /* get number of chunks */ data = g_bytes_get_data (bytes, &len); @@ -389,7 +384,7 @@ fu_ihex_firmware_image_to_string (FuFirmwareImage *img, GString *str, GError **e guint8 buf[2]; fu_common_write_uint16 (buf, address_offset, G_BIG_ENDIAN); fu_ihex_firmware_emit_chunk (str, 0x0, - DFU_INHX32_RECORD_TYPE_EXTENDED_LINEAR, + FU_IHEX_FIRMWARE_RECORD_TYPE_EXTENDED_LINEAR, buf, 2); address_offset_last = address_offset; } @@ -416,7 +411,7 @@ fu_ihex_firmware_write (FuFirmware *firmware, GError **error) } /* add EOF */ - fu_ihex_firmware_emit_chunk (str, 0x0, DFU_INHX32_RECORD_TYPE_EOF, NULL, 0); + fu_ihex_firmware_emit_chunk (str, 0x0, FU_IHEX_FIRMWARE_RECORD_TYPE_EOF, NULL, 0); return g_bytes_new (str->str, str->len); } diff --git a/libfwupdplugin/fu-ihex-firmware.h b/libfwupdplugin/fu-ihex-firmware.h index a6754dd9b..ef429f647 100644 --- a/libfwupdplugin/fu-ihex-firmware.h +++ b/libfwupdplugin/fu-ihex-firmware.h @@ -14,7 +14,19 @@ G_DECLARE_FINAL_TYPE (FuIhexFirmware, fu_ihex_firmware, FU, IHEX_FIRMWARE, FuFir typedef struct { guint ln; GString *buf; + guint8 byte_cnt; + guint32 addr; + guint8 record_type; + GByteArray *data; } FuIhexFirmwareRecord; +#define FU_IHEX_FIRMWARE_RECORD_TYPE_DATA 0x00 +#define FU_IHEX_FIRMWARE_RECORD_TYPE_EOF 0x01 +#define FU_IHEX_FIRMWARE_RECORD_TYPE_EXTENDED_SEGMENT 0x02 +#define FU_IHEX_FIRMWARE_RECORD_TYPE_START_SEGMENT 0x03 +#define FU_IHEX_FIRMWARE_RECORD_TYPE_EXTENDED_LINEAR 0x04 +#define FU_IHEX_FIRMWARE_RECORD_TYPE_START_LINEAR 0x05 +#define FU_IHEX_FIRMWARE_RECORD_TYPE_SIGNATURE 0xfd + FuFirmware *fu_ihex_firmware_new (void); GPtrArray *fu_ihex_firmware_get_records (FuIhexFirmware *self); From 04d0a1b863c8a08c26836db642411b14b8550b72 Mon Sep 17 00:00:00 2001 From: Richard Hughes Date: Mon, 19 Oct 2020 21:37:32 +0100 Subject: [PATCH 553/607] vli: Use the tokenization data for the Intel HEX file --- plugins/vli/fu-vli-usbhub-msp430-device.c | 22 +--------------------- 1 file changed, 1 insertion(+), 21 deletions(-) diff --git a/plugins/vli/fu-vli-usbhub-msp430-device.c b/plugins/vli/fu-vli-usbhub-msp430-device.c index ec5637b74..0a2cdabed 100644 --- a/plugins/vli/fu-vli-usbhub-msp430-device.c +++ b/plugins/vli/fu-vli-usbhub-msp430-device.c @@ -244,28 +244,8 @@ fu_vli_usbhub_msp430_device_write_firmware (FuDevice *device, FuVliUsbhubDeviceRequest req = { 0x0 }; const gchar *line = rcd->buf->str; - /* check there's enough data for the smallest possible record */ - if (rcd->buf->len < 11) { - g_set_error (error, - FWUPD_ERROR, - FWUPD_ERROR_INVALID_FILE, - "line %u is incomplete, length %u", - rcd->ln, (guint) rcd->buf->len); - return FALSE; - } - - /* check starting token */ - if (line[0] != ':') { - g_set_error (error, - FWUPD_ERROR, - FWUPD_ERROR_INVALID_FILE, - "invalid starting token on line %u: %s", - rcd->ln, line); - return FALSE; - } - /* length, 16-bit address, type */ - req.len = fu_firmware_strparse_uint8 (line + 1); + req.len = rcd->byte_cnt; if (req.len >= sizeof(req.buf) - 7) { g_set_error (error, FWUPD_ERROR, From c3a8173a125fb5ee5e1b58dc421c72a5c05ddb39 Mon Sep 17 00:00:00 2001 From: Mario Limonciello Date: Tue, 20 Oct 2020 09:16:18 -0500 Subject: [PATCH 554/607] Show an error when a plugin is missing dependencies (Fixes: #1526) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ``` $ sudo mv /usr/lib/x86_64-linux-gnu/libtss2-esys.so.0.0.0 /usr/lib/x86_64-linux-gnu/libtss2-esys.so.0.0.0.renamed $ sudo fwupdtool get-devices --plugins=uefi 14:15:48:0735 FuEngine cannot load: failed to open plugin /usr/local/lib/x86_64-linux-gnu/fwupd-plugins-3/libfu_plugin_uefi.so: libtss2-esys.so.0: cannot open shared object file: No such file or directory Loading… [- ]14:15:48:0753 FuEngine failed to update history database: device ID b6c08fb9e5384d9d101853cc1ca20cf0ce2df2e2 was not found Loading… [***************************************] WARNING: Plugin depdendencies missing No detected devices ``` --- libfwupd/fwupd-enums.c | 4 ++++ libfwupd/fwupd-enums.h | 2 ++ libfwupdplugin/fu-plugin.c | 2 ++ src/fu-engine.c | 1 + src/fu-util-common.c | 4 ++++ 5 files changed, 13 insertions(+) diff --git a/libfwupd/fwupd-enums.c b/libfwupd/fwupd-enums.c index f3b1fae29..0cc32bd4d 100644 --- a/libfwupd/fwupd-enums.c +++ b/libfwupd/fwupd-enums.c @@ -339,6 +339,8 @@ fwupd_plugin_flag_to_string (FwupdPluginFlags plugin_flag) return "esp-not-found"; if (plugin_flag == FWUPD_PLUGIN_FLAG_LEGACY_BIOS) return "legacy-bios"; + if (plugin_flag == FWUPD_PLUGIN_FLAG_FAILED_OPEN) + return "failed-open"; if (plugin_flag == FWUPD_DEVICE_FLAG_UNKNOWN) return "unknown"; return NULL; @@ -377,6 +379,8 @@ fwupd_plugin_flag_from_string (const gchar *plugin_flag) return FWUPD_PLUGIN_FLAG_ESP_NOT_FOUND; if (g_strcmp0 (plugin_flag, "legacy-bios") == 0) return FWUPD_PLUGIN_FLAG_LEGACY_BIOS; + if (g_strcmp0 (plugin_flag, "failed-open") == 0) + return FWUPD_PLUGIN_FLAG_FAILED_OPEN; return FWUPD_DEVICE_FLAG_UNKNOWN; } diff --git a/libfwupd/fwupd-enums.h b/libfwupd/fwupd-enums.h index 6d8143e3e..0f0fcb0a0 100644 --- a/libfwupd/fwupd-enums.h +++ b/libfwupd/fwupd-enums.h @@ -232,6 +232,7 @@ typedef enum { * @FWUPD_PLUGIN_FLAG_EFIVAR_NOT_MOUNTED: The efivar filesystem is not found * @FWUPD_PLUGIN_FLAG_ESP_NOT_FOUND: The EFI ESP not found * @FWUPD_PLUGIN_FLAG_LEGACY_BIOS: System running in legacy CSM mode + * @FWUPD_PLUGIN_FLAG_FAILED_OPEN: Failed to open plugin (missing dependency) * * The plugin flags. **/ @@ -245,6 +246,7 @@ typedef enum { #define FWUPD_PLUGIN_FLAG_EFIVAR_NOT_MOUNTED (1u << 6) /* Since: 1.5.0 */ #define FWUPD_PLUGIN_FLAG_ESP_NOT_FOUND (1u << 7) /* Since: 1.5.0 */ #define FWUPD_PLUGIN_FLAG_LEGACY_BIOS (1u << 8) /* Since: 1.5.0 */ +#define FWUPD_PLUGIN_FLAG_FAILED_OPEN (1u << 9) /* Since: 1.5.0 */ #define FWUPD_PLUGIN_FLAG_UNKNOWN G_MAXUINT64 /* Since: 1.5.0 */ typedef guint64 FwupdPluginFlags; diff --git a/libfwupdplugin/fu-plugin.c b/libfwupdplugin/fu-plugin.c index 19c58ab51..a13a64518 100644 --- a/libfwupdplugin/fu-plugin.c +++ b/libfwupdplugin/fu-plugin.c @@ -431,6 +431,8 @@ fu_plugin_open (FuPlugin *self, const gchar *filename, GError **error) G_IO_ERROR_FAILED, "failed to open plugin %s: %s", filename, g_module_error ()); + fu_plugin_add_flag (self, FWUPD_PLUGIN_FLAG_FAILED_OPEN); + fu_plugin_add_flag (self, FWUPD_PLUGIN_FLAG_USER_WARNING); return FALSE; } diff --git a/src/fu-engine.c b/src/fu-engine.c index 23fa2a054..9f70cf38d 100644 --- a/src/fu-engine.c +++ b/src/fu-engine.c @@ -5933,6 +5933,7 @@ fu_engine_load_plugins (FuEngine *self, GError **error) if (self->usb_ctx != NULL) { if (!fu_plugin_open (plugin, filename, &error_local)) { g_warning ("cannot load: %s", error_local->message); + fu_engine_add_plugin (self, plugin); continue; } } diff --git a/src/fu-util-common.c b/src/fu-util-common.c index 13f7228cc..f5732503c 100644 --- a/src/fu-util-common.c +++ b/src/fu-util-common.c @@ -1345,6 +1345,10 @@ fu_util_plugin_flag_to_string (FwupdPluginFlags plugin_flag) /* TRANSLATORS: partition refers to something on disk, again, hey Arch users */ return _("UEFI ESP partition not detected or configured"); } + if (plugin_flag == FWUPD_PLUGIN_FLAG_FAILED_OPEN) { + /* TRANSLATORS: Failed to open plugin, hey Arch users */ + return _("Plugin dependencies missing"); + } /* fall back for unknown types */ return fwupd_plugin_flag_to_string (plugin_flag); From d7e3f09cbfdb59bf0d8dd845eaa15e507398bc2a Mon Sep 17 00:00:00 2001 From: Richard Hughes Date: Tue, 20 Oct 2020 18:21:04 +0100 Subject: [PATCH 555/607] trivial: Show what the device does support if the protocol match fails --- src/fu-install-task.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/fu-install-task.c b/src/fu-install-task.c index 6304cc0ad..77b58b130 100644 --- a/src/fu-install-task.c +++ b/src/fu-install-task.c @@ -260,9 +260,10 @@ fu_install_task_check_requirements (FuInstallTask *self, g_set_error (error, FWUPD_ERROR, FWUPD_ERROR_NOT_SUPPORTED, - "Device %s doesn't support %s", + "Device %s does not support %s, only %s", fu_device_get_name (self->device), - protocol); + protocol, + fu_device_get_protocol (self->device)); return FALSE; } From 92769bfba1700be80e8b13fbe0961357bed1fc6f Mon Sep 17 00:00:00 2001 From: Richard Hughes Date: Tue, 20 Oct 2020 18:21:27 +0100 Subject: [PATCH 556/607] trivial: Use fu_device_sleep_with_progress() in one more place --- plugins/vli/fu-vli-usbhub-rtd21xx-device.c | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/plugins/vli/fu-vli-usbhub-rtd21xx-device.c b/plugins/vli/fu-vli-usbhub-rtd21xx-device.c index 269ebfa85..e011eb9d4 100644 --- a/plugins/vli/fu-vli-usbhub-rtd21xx-device.c +++ b/plugins/vli/fu-vli-usbhub-rtd21xx-device.c @@ -448,10 +448,7 @@ fu_vli_usbhub_rtd21xx_device_write_firmware (FuDevice *device, /* the device needs some time to restart with the new firmware before * it can be queried again */ - for (guint i = 0; i < 100; i++) { - g_usleep (200000); - fu_device_set_progress (device, i); - } + fu_device_sleep_with_progress (device, 20); /* success */ return TRUE; From a2a8f8ea7066f5219e6e4ca058b6ef584ceb1375 Mon Sep 17 00:00:00 2001 From: Richard Hughes Date: Tue, 20 Oct 2020 09:27:26 +0100 Subject: [PATCH 557/607] Add fu_byte_array_set_size() The GLib g_byte_array_set_size() function does not zero the contents if the array size is larger, which leads to unpredictable output when using valgrind. --- libfwupdplugin/fu-common.c | 18 ++++++++++++++++++ libfwupdplugin/fu-common.h | 2 ++ libfwupdplugin/fu-self-test.c | 19 +++++++++++++++++++ libfwupdplugin/fwupdplugin.map | 1 + plugins/goodix-moc/fu-goodixmoc-device.c | 2 +- .../synaptics-prometheus/fu-synaprom-common.c | 2 +- .../synaptics-rmi/fu-synaptics-rmi-firmware.c | 4 ++-- 7 files changed, 44 insertions(+), 4 deletions(-) diff --git a/libfwupdplugin/fu-common.c b/libfwupdplugin/fu-common.c index 03ee9cef0..8c8709a41 100644 --- a/libfwupdplugin/fu-common.c +++ b/libfwupdplugin/fu-common.c @@ -2000,6 +2000,24 @@ fu_byte_array_append_uint32 (GByteArray *array, guint32 data, FuEndianType endia g_byte_array_append (array, buf, sizeof(buf)); } +/** + * fu_byte_array_set_size: + * @array: a #GByteArray + * @length: the new size of the GByteArray + * + * Sets the size of the GByteArray, expanding it with NULs if necessary. + * + * Since: 1.5.0 + **/ +void +fu_byte_array_set_size (GByteArray *array, guint length) +{ + guint oldlength = array->len; + g_byte_array_set_size (array, length); + if (length > oldlength) + memset (array->data + oldlength, 0x0, length - oldlength); +} + /** * fu_common_kernel_locked_down: * diff --git a/libfwupdplugin/fu-common.h b/libfwupdplugin/fu-common.h index c65dafa7c..97c4638ba 100644 --- a/libfwupdplugin/fu-common.h +++ b/libfwupdplugin/fu-common.h @@ -182,6 +182,8 @@ gboolean fu_common_read_uint32_safe (const guint8 *buf, FuEndianType endian, GError **error); +void fu_byte_array_set_size (GByteArray *array, + guint length); void fu_byte_array_append_uint8 (GByteArray *array, guint8 data); void fu_byte_array_append_uint16 (GByteArray *array, diff --git a/libfwupdplugin/fu-self-test.c b/libfwupdplugin/fu-self-test.c index 2c10980b3..beaa866ec 100644 --- a/libfwupdplugin/fu-self-test.c +++ b/libfwupdplugin/fu-self-test.c @@ -107,6 +107,24 @@ fu_archive_cab_func (void) g_assert_null (data_tmp); } +static void +fu_common_byte_array_func (void) +{ + g_autoptr(GByteArray) array = g_byte_array_new (); + + fu_byte_array_append_uint8 (array, (guint8) 'h'); + fu_byte_array_append_uint8 (array, (guint8) 'e'); + fu_byte_array_append_uint8 (array, (guint8) 'l'); + fu_byte_array_append_uint8 (array, (guint8) 'l'); + fu_byte_array_append_uint8 (array, (guint8) 'o'); + g_assert_cmpint (array->len, ==, 5); + g_assert_cmpint (memcmp (array->data, "hello", array->len), ==, 0); + + fu_byte_array_set_size (array, 10); + g_assert_cmpint (array->len, ==, 10); + g_assert_cmpint (memcmp (array->data, "hello\0\0\0\0\0", array->len), ==, 0); +} + static void fu_common_crc_func (void) { @@ -2078,6 +2096,7 @@ main (int argc, char **argv) g_test_add_func ("/fwupd/plugin{quirks-performance}", fu_plugin_quirks_performance_func); g_test_add_func ("/fwupd/plugin{quirks-device}", fu_plugin_quirks_device_func); g_test_add_func ("/fwupd/chunk", fu_chunk_func); + g_test_add_func ("/fwupd/common{byte-array}", fu_common_byte_array_func); g_test_add_func ("/fwupd/common{crc}", fu_common_crc_func); g_test_add_func ("/fwupd/common{string-append-kv}", fu_common_string_append_kv_func); g_test_add_func ("/fwupd/common{version-guess-format}", fu_common_version_guess_format_func); diff --git a/libfwupdplugin/fwupdplugin.map b/libfwupdplugin/fwupdplugin.map index 7d60ff9d7..22007b07a 100644 --- a/libfwupdplugin/fwupdplugin.map +++ b/libfwupdplugin/fwupdplugin.map @@ -618,6 +618,7 @@ LIBFWUPDPLUGIN_1.4.7 { LIBFWUPDPLUGIN_1.5.0 { global: + fu_byte_array_set_size; fu_common_cpuid; fu_common_crc16; fu_common_crc32; diff --git a/plugins/goodix-moc/fu-goodixmoc-device.c b/plugins/goodix-moc/fu-goodixmoc-device.c index 9cbcc5b8f..c37826d09 100644 --- a/plugins/goodix-moc/fu-goodixmoc-device.c +++ b/plugins/goodix-moc/fu-goodixmoc-device.c @@ -102,7 +102,7 @@ goodixmoc_device_cmd_recv (GUsbDevice *usbdevice, */ while (1) { g_autoptr(GByteArray) reply = g_byte_array_new (); - g_byte_array_set_size (reply, GX_FLASH_TRANSFER_BLOCK_SIZE); + fu_byte_array_set_size (reply, GX_FLASH_TRANSFER_BLOCK_SIZE); if (!g_usb_device_bulk_transfer (usbdevice, GX_USB_BULK_EP_IN, reply->data, diff --git a/plugins/synaptics-prometheus/fu-synaprom-common.c b/plugins/synaptics-prometheus/fu-synaprom-common.c index 80ac679a3..3d9036877 100644 --- a/plugins/synaptics-prometheus/fu-synaprom-common.c +++ b/plugins/synaptics-prometheus/fu-synaprom-common.c @@ -41,7 +41,7 @@ GByteArray * fu_synaprom_reply_new (gsize cmdlen) { GByteArray *blob = g_byte_array_new (); - g_byte_array_set_size (blob, cmdlen); + fu_byte_array_set_size (blob, cmdlen); return blob; } diff --git a/plugins/synaptics-rmi/fu-synaptics-rmi-firmware.c b/plugins/synaptics-rmi/fu-synaptics-rmi-firmware.c index 3d7f870b5..dba3cad69 100644 --- a/plugins/synaptics-rmi/fu-synaptics-rmi-firmware.c +++ b/plugins/synaptics-rmi/fu-synaptics-rmi-firmware.c @@ -403,7 +403,7 @@ fu_synaptics_rmi_firmware_generate_v0x (void) GByteArray *buf = g_byte_array_new (); /* create empty block */ - g_byte_array_set_size (buf, RMI_IMG_FW_OFFSET + 0x4 + 0x4); + fu_byte_array_set_size (buf, RMI_IMG_FW_OFFSET + 0x4 + 0x4); buf->data[RMI_IMG_IO_OFFSET] = 0x0; /* no build_id or package_id */ buf->data[RMI_IMG_BOOTLOADER_VERSION_OFFSET] = 0x2; /* not hierarchical */ memcpy (buf->data + RMI_IMG_PRODUCT_ID_OFFSET, "Example", 7); @@ -436,7 +436,7 @@ fu_synaptics_rmi_firmware_generate_v10 (void) }; /* create empty block */ - g_byte_array_set_size (buf, RMI_IMG_FW_OFFSET + 0x48); + fu_byte_array_set_size (buf, RMI_IMG_FW_OFFSET + 0x48); buf->data[RMI_IMG_IO_OFFSET] = 0x1; buf->data[RMI_IMG_BOOTLOADER_VERSION_OFFSET] = 16; /* hierarchical */ memcpy (buf->data + RMI_IMG_PRODUCT_ID_OFFSET, "Example", 7); From 7db8e88d98c870259963b05bfa3a87c4db0626f8 Mon Sep 17 00:00:00 2001 From: Mario Limonciello Date: Tue, 20 Oct 2020 08:52:51 -0500 Subject: [PATCH 558/607] When PK is disabled only allow trusted payloads Loosen the requirement of the user ID to match root for the following actions: * Install release * Activate firmware For install release action, reject CAB files not signed by LVFS --- src/fu-engine.c | 31 +++++++++++++------- src/fu-main.c | 10 ------- src/fu-self-test.c | 71 +++++++++++++++++++++++++++++++++++++++++++++- 3 files changed, 90 insertions(+), 22 deletions(-) diff --git a/src/fu-engine.c b/src/fu-engine.c index 9f70cf38d..d716a4175 100644 --- a/src/fu-engine.c +++ b/src/fu-engine.c @@ -1460,19 +1460,28 @@ fu_engine_check_requirements (FuEngine *self, /* do engine checks */ reqs = xb_node_query (fu_install_task_get_component (task), "requires/*", 0, &error_local); - if (reqs == NULL) { - if (g_error_matches (error_local, G_IO_ERROR, G_IO_ERROR_NOT_FOUND)) - return TRUE; - if (g_error_matches (error_local, G_IO_ERROR, G_IO_ERROR_INVALID_ARGUMENT)) - return TRUE; - g_propagate_error (error, g_steal_pointer (&error_local)); - return FALSE; - } - for (guint i = 0; i < reqs->len; i++) { - XbNode *req = g_ptr_array_index (reqs, i); - if (!fu_engine_check_requirement (self, request, req, device, error)) + if (reqs != NULL) { + for (guint i = 0; i < reqs->len; i++) { + XbNode *req = g_ptr_array_index (reqs, i); + if (!fu_engine_check_requirement (self, request, req, device, error)) + return FALSE; + } + } else if (!g_error_matches (error_local, G_IO_ERROR, G_IO_ERROR_NOT_FOUND) && + !g_error_matches (error_local, G_IO_ERROR, G_IO_ERROR_INVALID_ARGUMENT)) { + g_propagate_error (error, g_steal_pointer (&error_local)); return FALSE; } + +#ifndef HAVE_POLKIT + if ((fu_install_task_get_trust_flags (task) & FWUPD_TRUST_FLAG_PAYLOAD) == 0) { + g_set_error_literal (error, + FWUPD_ERROR, + FWUPD_ERROR_INVALID_FILE, + "archive signature missing or not trusted"); + return FALSE; + } +#endif + return TRUE; } diff --git a/src/fu-main.c b/src/fu-main.c index 66861120c..c7d0c035b 100644 --- a/src/fu-main.c +++ b/src/fu-main.c @@ -606,11 +606,6 @@ fu_main_authorize_activate_cb (GObject *source, GAsyncResult *res, gpointer user g_dbus_method_invocation_return_gerror (helper->invocation, error); return; } -#else - if (!fu_main_authorization_is_trusted (helper->request, &error)) { - g_dbus_method_invocation_return_gerror (helper->invocation, error); - return; - } #endif /* HAVE_POLKIT */ /* authenticated */ @@ -711,11 +706,6 @@ fu_main_authorize_install_cb (GObject *source, GAsyncResult *res, gpointer user_ g_dbus_method_invocation_return_gerror (helper->invocation, error); return; } -#else - if (!fu_main_authorization_is_trusted (helper->request, &error)) { - g_dbus_method_invocation_return_gerror (helper->invocation, error); - return; - } #endif /* HAVE_POLKIT */ /* do the next authentication action ID */ diff --git a/src/fu-self-test.c b/src/fu-self-test.c index 471665338..2848709d1 100644 --- a/src/fu-self-test.c +++ b/src/fu-self-test.c @@ -324,8 +324,13 @@ fu_engine_requirements_client_pass_func (gconstpointer user_data) ret = fu_engine_check_requirements (engine, request, task, FWUPD_INSTALL_FLAG_NONE, &error); +#ifdef HAVE_POLKIT g_assert_no_error (error); g_assert (ret); +#else + g_assert_error (error, FWUPD_ERROR, FWUPD_ERROR_INVALID_FILE); + g_assert_false (ret); +#endif } static void @@ -465,8 +470,13 @@ fu_engine_requirements_child_func (gconstpointer user_data) ret = fu_engine_check_requirements (engine, request, task, FWUPD_INSTALL_FLAG_NONE, &error); +#ifdef HAVE_POLKIT g_assert_no_error (error); g_assert (ret); +#else + g_assert_error (error, FWUPD_ERROR, FWUPD_ERROR_INVALID_FILE); + g_assert_false (ret); +#endif } static void @@ -560,8 +570,13 @@ fu_engine_requirements_func (gconstpointer user_data) ret = fu_engine_check_requirements (engine, request, task, FWUPD_INSTALL_FLAG_NONE, &error); +#ifdef HAVE_POLKIT g_assert_no_error (error); g_assert (ret); +#else + g_assert_error (error, FWUPD_ERROR, FWUPD_ERROR_INVALID_FILE); + g_assert_false (ret); +#endif } static void @@ -617,8 +632,13 @@ fu_engine_requirements_device_func (gconstpointer user_data) ret = fu_engine_check_requirements (engine, request, task, FWUPD_INSTALL_FLAG_NONE, &error); +#ifdef HAVE_POLKIT g_assert_no_error (error); g_assert (ret); +#else + g_assert_error (error, FWUPD_ERROR, FWUPD_ERROR_INVALID_FILE); + g_assert_false (ret); +#endif } static void @@ -664,8 +684,13 @@ fu_engine_requirements_device_plain_func (gconstpointer user_data) ret = fu_engine_check_requirements (engine, request, task, FWUPD_INSTALL_FLAG_NONE, &error); +#ifdef HAVE_POLKIT g_assert_no_error (error); g_assert (ret); +#else + g_assert_error (error, FWUPD_ERROR, FWUPD_ERROR_INVALID_FILE); + g_assert_false (ret); +#endif } static void @@ -780,8 +805,13 @@ fu_engine_requirements_other_device_func (gconstpointer user_data) ret = fu_engine_check_requirements (engine, request, task, FWUPD_INSTALL_FLAG_NONE, &error); +#ifdef HAVE_POLKIT g_assert_no_error (error); g_assert (ret); +#else + g_assert_error (error, FWUPD_ERROR, FWUPD_ERROR_INVALID_FILE); + g_assert_false (ret); +#endif } static void @@ -868,8 +898,13 @@ fu_engine_requirements_protocol_check_func (gconstpointer user_data) FWUPD_INSTALL_FLAG_NONE, &error); +#ifdef HAVE_POLKIT g_assert_no_error (error); g_assert (ret); +#else + g_assert_error (error, FWUPD_ERROR, FWUPD_ERROR_INVALID_FILE); + g_assert_false (ret); +#endif } static void @@ -936,8 +971,13 @@ fu_engine_requirements_parent_device_func (gconstpointer user_data) ret = fu_engine_check_requirements (engine, request, task, FWUPD_INSTALL_FLAG_NONE, &error); +#ifdef HAVE_POLKIT g_assert_no_error (error); g_assert (ret); +#else + g_assert_error (error, FWUPD_ERROR, FWUPD_ERROR_INVALID_FILE); + g_assert_false (ret); +#endif } static void @@ -1385,12 +1425,17 @@ fu_engine_downgrade_func (gconstpointer user_data) fu_device_set_name (device, "Test Device"); fu_device_add_guid (device, "aaaaaaaa-bbbb-cccc-dddd-eeeeeeeeeeee"); fu_device_add_flag (device, FWUPD_DEVICE_FLAG_UPDATABLE); +#ifndef HAVE_POLKIT + g_test_expect_message ("FuEngine", G_LOG_LEVEL_WARNING, "*archive signature missing or not trusted"); +#endif fu_engine_add_device (engine, device); devices = fu_engine_get_devices (engine, &error); g_assert_no_error (error); g_assert (devices != NULL); g_assert_cmpint (devices->len, ==, 1); +#ifdef HAVE_POLKIT g_assert (fu_device_has_flag (device, FWUPD_DEVICE_FLAG_SUPPORTED)); +#endif g_assert (fu_device_has_flag (device, FWUPD_DEVICE_FLAG_REGISTERED)); /* get the releases for one device */ @@ -1398,9 +1443,16 @@ fu_engine_downgrade_func (gconstpointer user_data) request, fu_device_get_id (device), &error); +#ifdef HAVE_POLKIT g_assert_no_error (error); g_assert (releases != NULL); g_assert_cmpint (releases->len, ==, 4); +#else + g_assert_error (error, FWUPD_ERROR, FWUPD_ERROR_INVALID_FILE); + g_assert (releases == NULL); + g_test_skip ("Compiling without PK requires trusted payloads for tests"); + return; +#endif /* no upgrades, as no firmware is approved */ releases_up = fu_engine_get_upgrades (engine, @@ -1445,7 +1497,9 @@ fu_engine_downgrade_func (gconstpointer user_data) static void fu_engine_install_duration_func (gconstpointer user_data) { +#ifdef HAVE_POLKIT FwupdRelease *rel; +#endif gboolean ret; g_autoptr(FuDevice) device = fu_device_new (); g_autoptr(FuEngine) engine = fu_engine_new (FU_APP_FLAGS_NONE); @@ -1495,23 +1549,32 @@ fu_engine_install_duration_func (gconstpointer user_data) fu_device_add_guid (device, "aaaaaaaa-bbbb-cccc-dddd-eeeeeeeeeeee"); fu_device_set_install_duration (device, 999); fu_device_add_flag (device, FWUPD_DEVICE_FLAG_UPDATABLE); +#ifndef HAVE_POLKIT + g_test_expect_message ("FuEngine", G_LOG_LEVEL_WARNING, "*archive signature missing or not trusted"); +#endif fu_engine_add_device (engine, device); devices = fu_engine_get_devices (engine, &error); g_assert_no_error (error); g_assert (devices != NULL); g_assert_cmpint (devices->len, ==, 1); +#ifdef HAVE_POLKIT g_assert (fu_device_has_flag (device, FWUPD_DEVICE_FLAG_SUPPORTED)); - +#endif /* check the release install duration */ releases = fu_engine_get_releases (engine, request, fu_device_get_id (device), &error); +#ifdef HAVE_POLKIT g_assert_no_error (error); g_assert (releases != NULL); g_assert_cmpint (releases->len, ==, 1); rel = FWUPD_RELEASE (g_ptr_array_index (releases, 0)); g_assert_cmpint (fwupd_release_get_install_duration (rel), ==, 120); +#else + g_assert_error (error, FWUPD_ERROR, FWUPD_ERROR_INVALID_FILE); + g_assert (releases == NULL); +#endif } static void @@ -2917,7 +2980,13 @@ fu_plugin_composite_func (gconstpointer user_data) g_ptr_array_add (install_tasks, g_steal_pointer (&task)); } } +#ifdef HAVE_POLKIT g_assert_cmpint (install_tasks->len, ==, 3); +#else + g_assert_cmpint (install_tasks->len, ==, 0); + g_test_skip ("Compiling without PK support requires signed payloads"); + return; +#endif /* install the cab */ ret = fu_engine_install_tasks (engine, From f6a765d251f3ba4e314eab03184e42afb1dfc6c6 Mon Sep 17 00:00:00 2001 From: Richard Hughes Date: Wed, 21 Oct 2020 16:25:12 +0100 Subject: [PATCH 559/607] vli: Remove one of the catch-all PD VID:PID matches This is already supported using the &APP_ GUID for the Lenovo USB-C Mini dock. --- plugins/vli/vli-pd.quirk | 3 --- 1 file changed, 3 deletions(-) diff --git a/plugins/vli/vli-pd.quirk b/plugins/vli/vli-pd.quirk index 2c8a39e61..694b4a1df 100644 --- a/plugins/vli/vli-pd.quirk +++ b/plugins/vli/vli-pd.quirk @@ -62,9 +62,6 @@ GType = FuVliPdDevice [DeviceInstanceId=USB\VID_17EF&PID_7217] Plugin = vli GType = FuVliPdDevice -[DeviceInstanceId=USB\VID_17EF&PID_721C] -Plugin = vli -GType = FuVliPdDevice [DeviceInstanceId=USB\VID_17EF&PID_7223] Plugin = vli GType = FuVliPdDevice From 0ad124a02bddd0ebae1a6fa9d7026c9e1c3e49e3 Mon Sep 17 00:00:00 2001 From: Mario Limonciello Date: Wed, 21 Oct 2020 08:40:52 -0500 Subject: [PATCH 560/607] elantp: Match all i2c-hid devices in quirk In the plugin probe routine, check whether they are actually i2c-hid touchpad by looking at PID. Fixes #2494 --- plugins/elantp/elantp.quirk | 10 +--------- plugins/elantp/fu-elantp-hid-device.c | 10 ++++++++++ 2 files changed, 11 insertions(+), 9 deletions(-) diff --git a/plugins/elantp/elantp.quirk b/plugins/elantp/elantp.quirk index b2543eb51..82f253ca4 100644 --- a/plugins/elantp/elantp.quirk +++ b/plugins/elantp/elantp.quirk @@ -1,12 +1,4 @@ -[DeviceInstanceId=HIDRAW\VEN_04F3&DEV_3010] -Plugin = elantp -GType = FuElantpHidDevice - -[DeviceInstanceId=HIDRAW\VEN_04F3&DEV_30C5] -Plugin = elantp -GType = FuElantpHidDevice - -[DeviceInstanceId=HIDRAW\VEN_04F3&DEV_314F] +[DeviceInstanceId=HIDRAW\VEN_04F3] Plugin = elantp GType = FuElantpHidDevice diff --git a/plugins/elantp/fu-elantp-hid-device.c b/plugins/elantp/fu-elantp-hid-device.c index 316b31dcb..168255024 100644 --- a/plugins/elantp/fu-elantp-hid-device.c +++ b/plugins/elantp/fu-elantp-hid-device.c @@ -53,6 +53,16 @@ fu_elantp_hid_device_probe (FuUdevDevice *device, GError **error) return FALSE; } + /* i2c-hid */ + if (fu_udev_device_get_model (device) < 0x3000 || + fu_udev_device_get_model (device) >= 0x4000) { + g_set_error_literal (error, + FWUPD_ERROR, + FWUPD_ERROR_NOT_SUPPORTED, + "not i2c-hid touchpad"); + return FALSE; + } + /* set the physical ID */ return fu_udev_device_set_physical_id (device, "hid", error); } From b15f4ab4b16c22c83dbd5ff92524fbf1fb423c60 Mon Sep 17 00:00:00 2001 From: Mario Limonciello Date: Wed, 21 Oct 2020 15:30:23 +0100 Subject: [PATCH 561/607] elantp: Trivial whitespace fixes --- plugins/elantp/fu-elantp-i2c-device.c | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/plugins/elantp/fu-elantp-i2c-device.c b/plugins/elantp/fu-elantp-i2c-device.c index 31f56881e..c3123f0b8 100644 --- a/plugins/elantp/fu-elantp-i2c-device.c +++ b/plugins/elantp/fu-elantp-i2c-device.c @@ -231,7 +231,7 @@ fu_elantp_i2c_device_setup (FuDevice *device, GError **error) } instance_id_ic_type = g_strdup_printf ("ELANTP\\ICTYPE_%02X", ic_type); fu_device_add_instance_id (device, instance_id_ic_type); - + /* define the extra instance IDs (ic_type + module_id) */ instance_id2 = g_strdup_printf ("ELANTP\\ICTYPE_%02X&MOD_%04X", ic_type, self->module_id); @@ -340,8 +340,8 @@ fu_elantp_i2c_device_write_firmware (FuDevice *device, g_autofree guint8 *blk = g_malloc0 (blksz); /* write block */ - blk[0] = ETP_I2C_IAP_REG_L; - blk[1] = ETP_I2C_IAP_REG_H; + blk[0] = ETP_I2C_IAP_REG_L; + blk[1] = ETP_I2C_IAP_REG_H; if (!fu_memcpy_safe (blk, blksz, 0x2, /* dst */ chk->data, chk->data_sz, 0x0, /* src */ chk->data_sz, error)) @@ -428,7 +428,7 @@ fu_elantp_i2c_device_detach (FuDevice *device, GError **error) } else { ic_type = (tmp >> 8) & 0xFF; } - + /* get IAP firmware version */ if (!fu_elantp_i2c_device_read_cmd (self, self->pattern == 0 ? ETP_CMD_I2C_IAP_VERSION : ETP_CMD_I2C_IAP_VERSION_2, @@ -470,7 +470,6 @@ fu_elantp_i2c_device_detach (FuDevice *device, GError **error) "failed to set IAP type"); return FALSE; } - } } if (!fu_elantp_i2c_device_write_cmd (self, From 07326182ca95c5bc43f054082c024222b888d86c Mon Sep 17 00:00:00 2001 From: Richard Hughes Date: Wed, 21 Oct 2020 17:42:38 +0100 Subject: [PATCH 562/607] vli: Do not expose the shared-SPI devices on the USB2 recovery device --- plugins/vli/vli-usbhub-lenovo.quirk | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/plugins/vli/vli-usbhub-lenovo.quirk b/plugins/vli/vli-usbhub-lenovo.quirk index b5835b47c..a6ed113d9 100644 --- a/plugins/vli/vli-usbhub-lenovo.quirk +++ b/plugins/vli/vli-usbhub-lenovo.quirk @@ -39,7 +39,7 @@ ParentGuid = USB\VID_17EF&PID_307F&HUB_0002 [DeviceInstanceId=USB\VID_17EF&PID_3080] Plugin = vli GType = FuVliUsbhubDevice -Flags = usb2,has-msp430 +Flags = usb2 [DeviceInstanceId=USB\VID_17EF&PID_3080&HUB_06] ParentGuid = USB\VID_17EF&PID_3080&HUB_20 [DeviceInstanceId=USB\VID_17EF&PID_3080&HUB_20] @@ -156,7 +156,7 @@ CounterpartGuid = USB\VID_17EF&PID_7225 [DeviceInstanceId=USB\VID_17EF&PID_7225] Plugin = vli GType = FuVliUsbhubDevice -Flags = usb2,has-shared-spi-pd +Flags = usb2 # Lenovo USB-C Mini dock [DeviceInstanceId=USB\VID_17EF&PID_3094] @@ -205,7 +205,7 @@ CounterpartGuid = USB\VID_17EF&PID_7229 [DeviceInstanceId=USB\VID_17EF&PID_7229] Plugin = vli GType = FuVliUsbhubDevice -Flags = usb2,has-shared-spi-pd +Flags = usb2 # Lenovo USB-C to 4 USB-A Hub [DeviceInstanceId=USB\VID_17EF&PID_1039] @@ -216,7 +216,7 @@ CounterpartGuid = USB\VID_17EF&PID_103A [DeviceInstanceId=USB\VID_17EF&PID_103A] Plugin = vli GType = FuVliUsbhubDevice -Flags = usb2,has-shared-spi-pd,attach-with-gpiob +Flags = usb2 # Lenovo Gen2 dock [DeviceInstanceId=USB\VID_17EF&PID_A391] From 0d778dbd50901271e92ba79dab2dd504134bcee5 Mon Sep 17 00:00:00 2001 From: Richard Hughes Date: Wed, 21 Oct 2020 17:43:24 +0100 Subject: [PATCH 563/607] vli: Set the parent of the USB2 recovery for cosmetic reasons --- plugins/vli/vli-usbhub-lenovo.quirk | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/plugins/vli/vli-usbhub-lenovo.quirk b/plugins/vli/vli-usbhub-lenovo.quirk index a6ed113d9..0317e247e 100644 --- a/plugins/vli/vli-usbhub-lenovo.quirk +++ b/plugins/vli/vli-usbhub-lenovo.quirk @@ -146,6 +146,7 @@ CounterpartGuid = USB\VID_17EF&PID_7224 Plugin = vli GType = FuVliUsbhubDevice Flags = usb2 +ParentGuid = USB\VID_17EF&PID_7216 # Lenovo Travel hub Gen2 [DeviceInstanceId=USB\VID_17EF&PID_721D] @@ -157,6 +158,7 @@ CounterpartGuid = USB\VID_17EF&PID_7225 Plugin = vli GType = FuVliUsbhubDevice Flags = usb2 +ParentGuid = USB\VID_17EF&PID_721D # Lenovo USB-C Mini dock [DeviceInstanceId=USB\VID_17EF&PID_3094] @@ -195,6 +197,7 @@ CounterpartGuid = USB\VID_17EF Plugin = vli GType = FuVliUsbhubDevice Flags = usb2 +ParentGuid = USB\VID_17EF&PID_7228 # Lenovo USB-C 7-in-1 Hub [DeviceInstanceId=USB\VID_17EF&PID_722A] @@ -206,6 +209,7 @@ CounterpartGuid = USB\VID_17EF&PID_7229 Plugin = vli GType = FuVliUsbhubDevice Flags = usb2 +ParentGuid = USB\VID_17EF&PID_722A # Lenovo USB-C to 4 USB-A Hub [DeviceInstanceId=USB\VID_17EF&PID_1039] @@ -217,6 +221,7 @@ CounterpartGuid = USB\VID_17EF&PID_103A Plugin = vli GType = FuVliUsbhubDevice Flags = usb2 +ParentGuid = USB\VID_17EF&PID_1039 # Lenovo Gen2 dock [DeviceInstanceId=USB\VID_17EF&PID_A391] From 02f2cc311e96bcec0ef1deed1110e309b93a84d1 Mon Sep 17 00:00:00 2001 From: Mario Limonciello Date: Tue, 20 Oct 2020 15:39:47 -0500 Subject: [PATCH 564/607] Add switch-branch support to fwupdtool --- data/bash-completion/fwupdtool.in | 1 + src/fu-tool.c | 134 ++++++++++++++++++++++++++++++ src/fu-util-common.c | 54 ++++++++++++ src/fu-util-common.h | 5 ++ src/fu-util.c | 55 +----------- 5 files changed, 195 insertions(+), 54 deletions(-) diff --git a/data/bash-completion/fwupdtool.in b/data/bash-completion/fwupdtool.in index 753673211..2a153336d 100644 --- a/data/bash-completion/fwupdtool.in +++ b/data/bash-completion/fwupdtool.in @@ -26,6 +26,7 @@ _fwupdtool_cmd_list=( 'monitor' 'reinstall' 'security' + 'switch-branch' 'self-sign' 'smbios-dump' 'attach' diff --git a/src/fu-tool.c b/src/fu-tool.c index ee4f256c7..835272c40 100644 --- a/src/fu-tool.c +++ b/src/fu-tool.c @@ -2439,6 +2439,133 @@ fu_util_esp_list (FuUtilPrivate *priv, gchar **values, GError **error) return TRUE; } + +static gboolean +fu_util_switch_branch (FuUtilPrivate *priv, gchar **values, GError **error) +{ + const gchar *branch; + g_autoptr(FwupdRelease) rel = NULL; + g_autoptr(GPtrArray) rels = NULL; + g_autoptr(GPtrArray) branches = g_ptr_array_new_with_free_func (g_free); + g_autoptr(FuDevice) dev = NULL; + + /* load engine */ + if (!fu_util_start_engine (priv, FU_ENGINE_LOAD_FLAG_NONE, error)) + return FALSE; + + /* find the device and check it has multiple branches */ + priv->filter_include |= FWUPD_DEVICE_FLAG_SUPPORTED; + if (g_strv_length (values) == 1) + dev = fu_util_get_device (priv, values[1], error); + else + dev = fu_util_prompt_for_device (priv, NULL, error); + if (dev == NULL) + return FALSE; + if (!fu_device_has_flag (dev, FWUPD_DEVICE_FLAG_HAS_MULTIPLE_BRANCHES)) { + g_set_error_literal (error, + FWUPD_ERROR, + FWUPD_ERROR_NOT_SUPPORTED, + "Multiple branches not available"); + return FALSE; + } + + /* get all releases, including the alternate branch versions */ + rels = fu_engine_get_releases (priv->engine, + priv->request, + fu_device_get_id (dev), + error); + if (rels == NULL) + return FALSE; + + /* get all the unique branches */ + for (guint i = 0; i < rels->len; i++) { + FwupdRelease *rel_tmp = g_ptr_array_index (rels, i); + const gchar *branch_tmp = fu_util_release_get_branch (rel_tmp); + if (g_ptr_array_find_with_equal_func (branches, branch_tmp, + g_str_equal, NULL)) + continue; + g_ptr_array_add (branches, g_strdup (branch_tmp)); + } + + /* branch name is optional */ + if (g_strv_length (values) > 1) { + branch = values[1]; + } else if (branches->len == 1) { + branch = g_ptr_array_index (branches, 0); + } else { + guint idx; + + /* TRANSLATORS: get interactive prompt, where branch is the + * supplier of the firmware, e.g. "non-free" or "free" */ + g_print ("%s\n", _("Choose a branch:")); + /* TRANSLATORS: this is to abort the interactive prompt */ + g_print ("0.\t%s\n", _("Cancel")); + for (guint i = 0; i < branches->len; i++) { + const gchar *branch_tmp = g_ptr_array_index (branches, i); + g_print ("%u.\t%s\n", i + 1, branch_tmp); + } + idx = fu_util_prompt_for_number (branches->len); + if (idx == 0) { + g_set_error_literal (error, + FWUPD_ERROR, + FWUPD_ERROR_NOTHING_TO_DO, + "Request canceled"); + return FALSE; + } + branch = g_ptr_array_index (branches, idx - 1); + } + + /* sanity check */ + if (g_strcmp0 (branch, fu_device_get_branch (dev)) == 0) { + g_set_error (error, + FWUPD_ERROR, + FWUPD_ERROR_NOT_SUPPORTED, + "Device %s is already on branch %s", + fu_device_get_name (dev), + branch); + return FALSE; + } + + /* the releases are ordered by version */ + for (guint j = 0; j < rels->len; j++) { + FwupdRelease *rel_tmp = g_ptr_array_index (rels, j); + if (g_strcmp0 (fwupd_release_get_branch (rel_tmp), branch) == 0) { + rel = g_object_ref (rel_tmp); + break; + } + } + if (rel == NULL) { + g_set_error (error, + FWUPD_ERROR, + FWUPD_ERROR_NOT_SUPPORTED, + "No releases for branch %s", + branch); + return FALSE; + } + + /* we're switching branch */ + if (!fu_util_switch_branch_warning (FWUPD_DEVICE (dev), rel, FALSE, error)) + return FALSE; + + /* update the console if composite devices are also updated */ + priv->current_operation = FU_UTIL_OPERATION_INSTALL; + g_signal_connect (priv->engine, "device-changed", + G_CALLBACK (fu_util_update_device_changed_cb), priv); + priv->flags |= FWUPD_INSTALL_FLAG_ALLOW_REINSTALL; + priv->flags |= FWUPD_INSTALL_FLAG_ALLOW_BRANCH_SWITCH; + if (!fu_util_install_release (priv, rel, error)) + return FALSE; + fu_util_display_current_message (priv); + + /* we don't want to ask anything */ + if (priv->no_reboot_check) { + g_debug ("skipping reboot check"); + return TRUE; + } + + return fu_util_prompt_complete (priv->completion_flags, TRUE, error); +} + int main (int argc, char *argv[]) { @@ -2749,6 +2876,12 @@ main (int argc, char *argv[]) /* TRANSLATORS: command description */ _("Lists files on the ESP"), fu_util_esp_list); + fu_util_cmd_array_add (cmd_array, + "switch-branch", + "[DEVICE-ID|GUID] [BRANCH]", + /* TRANSLATORS: command description */ + _("Switch the firmware branch on the device"), + fu_util_switch_branch); /* do stuff on ctrl+c */ priv->cancellable = g_cancellable_new (); @@ -2772,6 +2905,7 @@ main (int argc, char *argv[]) /* set our implemented feature set */ fu_engine_request_set_feature_flags (priv->request, FWUPD_FEATURE_FLAG_DETACH_ACTION | + FWUPD_FEATURE_FLAG_SWITCH_BRANCH | FWUPD_FEATURE_FLAG_UPDATE_ACTION); } diff --git a/src/fu-util-common.c b/src/fu-util-common.c index f5732503c..580bae264 100644 --- a/src/fu-util-common.c +++ b/src/fu-util-common.c @@ -1939,3 +1939,57 @@ fu_util_device_order_sort_cb (gconstpointer a, gconstpointer b) FuDevice *device_b = *((FuDevice **) b); return fu_util_device_order_compare (device_a, device_b); } + + +gboolean +fu_util_switch_branch_warning (FwupdDevice *dev, + FwupdRelease *rel, + gboolean assume_yes, + GError **error) +{ + const gchar *desc_markup = NULL; + g_autofree gchar *desc_plain = NULL; + g_autoptr(GString) desc_full = g_string_new (NULL); + + /* warn the user if the vendor is different */ + if (g_strcmp0 (fwupd_device_get_vendor (dev), fwupd_release_get_vendor (rel)) != 0) { + /* TRANSLATORS: %1 is the firmware vendor, %2 is the device vendor name */ + g_string_append_printf (desc_full, _("The firmware from %s is not " + "supplied by %s, the hardware vendor."), + fwupd_release_get_vendor (rel), + fwupd_device_get_vendor (dev)); + g_string_append (desc_full, "\n\n"); + /* TRANSLATORS: %1 is the device vendor name */ + g_string_append_printf (desc_full, _("Your hardware may be damaged using this firmware, " + "and installing this release may void any warranty " + "with %s."), + fwupd_device_get_vendor (dev)); + g_string_append (desc_full, "\n\n"); + } + + /* from the in the AppStream data */ + desc_markup = fwupd_release_get_description (rel); + if (desc_markup == NULL) + return TRUE; + desc_plain = fu_util_convert_description (desc_markup, error); + if (desc_plain == NULL) + return FALSE; + g_string_append (desc_full, desc_plain); + + /* show and ask user to confirm */ + fu_util_warning_box (desc_full->str, 80); + if (!assume_yes) { + /* ask for permission */ + g_print ("\n%s [y|N]: ", + /* TRANSLATORS: should the branch be changed */ + _("Do you understand the consequences of changing the firmware branch?")); + if (!fu_util_prompt_for_boolean (FALSE)) { + g_set_error_literal (error, + FWUPD_ERROR, + FWUPD_ERROR_NOTHING_TO_DO, + "Declined branch switch"); + return FALSE; + } + } + return TRUE; +} diff --git a/src/fu-util-common.h b/src/fu-util-common.h index c28ba2065..35f3b21ac 100644 --- a/src/fu-util-common.h +++ b/src/fu-util-common.h @@ -113,3 +113,8 @@ gint fu_util_sort_devices_by_flags_cb (gconstpointer a, gconstpointer b); gint fu_util_device_order_sort_cb (gconstpointer a, gconstpointer b); + +gboolean fu_util_switch_branch_warning (FwupdDevice *dev, + FwupdRelease *rel, + gboolean assume_yes, + GError **error); diff --git a/src/fu-util.c b/src/fu-util.c index 47f0d18f2..d0bfd83e8 100644 --- a/src/fu-util.c +++ b/src/fu-util.c @@ -1900,59 +1900,6 @@ fu_util_reinstall (FuUtilPrivate *priv, gchar **values, GError **error) return fu_util_prompt_complete (priv->completion_flags, TRUE, error); } -static gboolean -fu_util_switch_branch_warning (FuUtilPrivate *priv, - FwupdDevice *dev, - FwupdRelease *rel, - GError **error) -{ - const gchar *desc_markup = NULL; - g_autofree gchar *desc_plain = NULL; - g_autoptr(GString) desc_full = g_string_new (NULL); - - /* warn the user if the vendor is different */ - if (g_strcmp0 (fwupd_device_get_vendor (dev), fwupd_release_get_vendor (rel)) != 0) { - /* TRANSLATORS: %1 is the firmware vendor, %2 is the device vendor name */ - g_string_append_printf (desc_full, _("The firmware from %s is not " - "supplied by %s, the hardware vendor."), - fwupd_release_get_vendor (rel), - fwupd_device_get_vendor (dev)); - g_string_append (desc_full, "\n\n"); - /* TRANSLATORS: %1 is the device vendor name */ - g_string_append_printf (desc_full, _("Your hardware may be damaged using this firmware, " - "and installing this release may void any warranty " - "with %s."), - fwupd_device_get_vendor (dev)); - g_string_append (desc_full, "\n\n"); - } - - /* from the in the AppStream data */ - desc_markup = fwupd_release_get_description (rel); - if (desc_markup == NULL) - return TRUE; - desc_plain = fu_util_convert_description (desc_markup, error); - if (desc_plain == NULL) - return FALSE; - g_string_append (desc_full, desc_plain); - - /* show and ask user to confirm */ - fu_util_warning_box (desc_full->str, 80); - if (!priv->assume_yes) { - /* ask for permission */ - g_print ("\n%s [y|N]: ", - /* TRANSLATORS: should the branch be changed */ - _("Do you understand the consequences of changing the firmware branch?")); - if (!fu_util_prompt_for_boolean (FALSE)) { - g_set_error_literal (error, - FWUPD_ERROR, - FWUPD_ERROR_NOTHING_TO_DO, - "Declined branch switch"); - return FALSE; - } - } - return TRUE; -} - static gboolean fu_util_switch_branch (FuUtilPrivate *priv, gchar **values, GError **error) { @@ -2049,7 +1996,7 @@ fu_util_switch_branch (FuUtilPrivate *priv, gchar **values, GError **error) } /* we're switching branch */ - if (!fu_util_switch_branch_warning (priv, dev, rel, error)) + if (!fu_util_switch_branch_warning (dev, rel, priv->assume_yes, error)) return FALSE; /* update the console if composite devices are also updated */ From b7e406c2177eae8c7131c790339533649625eeb6 Mon Sep 17 00:00:00 2001 From: Richard Hughes Date: Wed, 21 Oct 2020 20:18:08 +0100 Subject: [PATCH 565/607] ata: Add OUI quirk for Corsair --- plugins/ata/ata.quirk | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/plugins/ata/ata.quirk b/plugins/ata/ata.quirk index 211c7f84d..3fa5df14f 100644 --- a/plugins/ata/ata.quirk +++ b/plugins/ata/ata.quirk @@ -10,6 +10,10 @@ VendorId = ATA:0x1179 Vendor = Samsung VendorId = ATA:0x144D +[DeviceInstanceId=OUI\000120] +Vendor = Corsair +VendorId = ATA:0x1987 + [DeviceInstanceId=OUI\0004cf] Vendor = Seagate VendorId = ATA:0x1BB1 From a9d8074c6139bdf208864b8f3a92bf5f41e1476d Mon Sep 17 00:00:00 2001 From: Vincent Huang Date: Thu, 22 Oct 2020 13:43:00 +0800 Subject: [PATCH 566/607] synaptics-prometheus: add pids to quirk file --- .../synaptics-prometheus/synaptics-prometheus.quirk | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/plugins/synaptics-prometheus/synaptics-prometheus.quirk b/plugins/synaptics-prometheus/synaptics-prometheus.quirk index 95170f9ee..3b23bce20 100644 --- a/plugins/synaptics-prometheus/synaptics-prometheus.quirk +++ b/plugins/synaptics-prometheus/synaptics-prometheus.quirk @@ -13,3 +13,16 @@ InstallDuration = 2 [DeviceInstanceId=USB\VID_06CB&PID_00E9] Plugin = synaptics_prometheus InstallDuration = 2 + +[DeviceInstanceId=USB\VID_06CB&PID_00C2] +Plugin = synaptics_prometheus +InstallDuration = 2 + +[DeviceInstanceId=USB\VID_06CB&PID_00F9] +Plugin = synaptics_prometheus +InstallDuration = 2 + +[DeviceInstanceId=USB\VID_06CB&PID_00FC] +Plugin = synaptics_prometheus +InstallDuration = 2 + From b6192458977fc904d72d7b474c75b8fa67e4b7f9 Mon Sep 17 00:00:00 2001 From: Richard Hughes Date: Thu, 22 Oct 2020 12:44:42 +0100 Subject: [PATCH 567/607] trivial: Write up some release notes for the next release --- data/org.freedesktop.fwupd.metainfo.xml | 52 +++++++++++++++++++++++++ 1 file changed, 52 insertions(+) diff --git a/data/org.freedesktop.fwupd.metainfo.xml b/data/org.freedesktop.fwupd.metainfo.xml index 1af27d66e..9c8389a1c 100644 --- a/data/org.freedesktop.fwupd.metainfo.xml +++ b/data/org.freedesktop.fwupd.metainfo.xml @@ -35,6 +35,58 @@ fwupdagent + + +

      This release adds the following features:

      +
        +
      • Add a compatible re-implementation of the rhboot dbxtool
      • +
      • Add async versions of the library for GUI tools
      • +
      • Add commands for interacting with the ESP to fwupdtool
      • +
      • Add firmware-extract subcommand to fwupdtool
      • +
      • Add FwupdPlugin so we can convey enumerated system errors to the end user
      • +
      • Add plugin for Goodix fingerprint sensors
      • +
      • Add plugin that can update the BCM5719 network adapter
      • +
      • Add plugin to update Elan Touchpads using HID
      • +
      • Add support for a delayed activation flow for Thunderbolt
      • +
      • Add support for ChromeOS Quiche and Gingerbread
      • +
      • Add support for the Host Security ID
      • +
      • Add support for ThunderBolt retimers
      • +
      • Add switch-branch command to fwupdtool and fwupdmgr
      • +
      • Allow blocking specific firmware releases by checksum
      • +
      • Allow contructing a firmware with multiple images
      • +
      • Allow firmware to require specific features from front-end clients
      • +
      • Allow updating the dbx using the LVFS, validating it is safe to apply
      • +
      • Include the HSI results and attributes in the uploaded report
      • +
      • Support loading DMI data from DT systems
      • +
      • Support LVFS::UpdateImage for GUI clients
      • +
      +

      This release fixes the following bugs:

      +
        +
      • Allow compiling the daemon without polkit support
      • +
      • Always look at all TPM eventlog supported algorithms
      • +
      • Change all instances of master/slave to initiator/target
      • +
      • Correctly order devices when using logical parents
      • +
      • Do not dedupe NVMe or VLI PD devices
      • +
      • Do not expose the VLI shared-SPI devices on the USB2 recovery device
      • +
      • Do not fix up the version on post-update mismatch
      • +
      • Download the metadata first when using 'fwupdtool refresh'
      • +
      • Drop efivar dependency
      • +
      • Drop support for ThunderBolt force power due to hardware issues
      • +
      • Fix setting BootNext correctly when multiple updates are scheduled
      • +
      • Fix the topology of the audio device on the Lenovo TR dock
      • +
      • Make return code different for get-updates with no updates
      • +
      • Make specific authorizations also imply others
      • +
      • Make TPM support more optional
      • +
      • Parse the HEX version before comparing for equality
      • +
      • Prevent dell-dock updates to occur via synaptics-mst plugin
      • +
      • Record the UEFI failure in more cases
      • +
      • Show an error when a plugin is missing dependencies
      • +
      • Use libxmlb bound parameters to speed up the device verification
      • +
      • Use pkttyagent to request user passwords if running without GUI
      • +
      • Use the JCat file to select the metadata file
      • +
      +
      +

      This release adds the following features:

      From 1fd1a8047e248ccaa446e89ee5ba28e0dec21583 Mon Sep 17 00:00:00 2001 From: Richard Hughes Date: Thu, 22 Oct 2020 13:22:34 +0100 Subject: [PATCH 568/607] optionrom: Add the fuzzing functionality as a meson target --- plugins/optionrom/fu-rom.c | 2 +- plugins/optionrom/fuzzing.md | 3 --- plugins/optionrom/fuzzing/meson.build | 9 +++++++++ plugins/optionrom/meson.build | 3 ++- 4 files changed, 12 insertions(+), 5 deletions(-) delete mode 100644 plugins/optionrom/fuzzing.md create mode 100644 plugins/optionrom/fuzzing/meson.build diff --git a/plugins/optionrom/fu-rom.c b/plugins/optionrom/fu-rom.c index 84dfdce21..e35464ab5 100644 --- a/plugins/optionrom/fu-rom.c +++ b/plugins/optionrom/fu-rom.c @@ -689,7 +689,7 @@ fu_rom_dump_firmware (GFile *file, GCancellable *cancellable, GError **error) { guint number_reads = 0; g_autofree gchar *fn = NULL; - g_autoptr(GByteArray) buf = NULL; + g_autoptr(GByteArray) buf = g_byte_array_new (); g_autoptr(GError) error_local = NULL; g_autoptr(GInputStream) stream = NULL; diff --git a/plugins/optionrom/fuzzing.md b/plugins/optionrom/fuzzing.md deleted file mode 100644 index bd1334cb3..000000000 --- a/plugins/optionrom/fuzzing.md +++ /dev/null @@ -1,3 +0,0 @@ -CC=afl-gcc ./configure --disable-shared -AFL_HARDEN=1 make -afl-fuzz -m 300 -i fuzzing -o findings ./fu-rom-tool rom @@ diff --git a/plugins/optionrom/fuzzing/meson.build b/plugins/optionrom/fuzzing/meson.build new file mode 100644 index 000000000..06c1cf426 --- /dev/null +++ b/plugins/optionrom/fuzzing/meson.build @@ -0,0 +1,9 @@ +run_target('fuzz-optionrom', + command: [ + join_paths(meson.source_root(), 'contrib/afl-fuzz.py'), + '--command', 'rom', + '-i', meson.current_source_dir(), + '-o', join_paths(meson.current_build_dir(), '..', 'findings'), + optionrom_tool, + ], +) diff --git a/plugins/optionrom/meson.build b/plugins/optionrom/meson.build index 56013ad56..8d0674062 100644 --- a/plugins/optionrom/meson.build +++ b/plugins/optionrom/meson.build @@ -28,7 +28,7 @@ shared_module('fu_plugin_optionrom', ], ) -executable( +optionrom_tool = executable( 'fu-rom-tool', fu_hash, sources : [ @@ -79,4 +79,5 @@ if get_option('tests') install_dir : installed_test_bindir, ) test('optionrom-self-test', e, env : testdatadirs) # added to installed-tests + subdir('fuzzing') endif From 3b577c5de3d4a3968cc43149e47a77409e6fcc3e Mon Sep 17 00:00:00 2001 From: Richard Hughes Date: Thu, 22 Oct 2020 13:55:14 +0100 Subject: [PATCH 569/607] bcm57xx: Fix trivial warnings when building on Win32 --- plugins/bcm57xx/fu-bcm57xx-device.c | 19 +++++++++++++++++-- plugins/bcm57xx/fu-bcm57xx-recovery-device.c | 2 +- 2 files changed, 18 insertions(+), 3 deletions(-) diff --git a/plugins/bcm57xx/fu-bcm57xx-device.c b/plugins/bcm57xx/fu-bcm57xx-device.c index 8bee27df3..6b9ded167 100644 --- a/plugins/bcm57xx/fu-bcm57xx-device.c +++ b/plugins/bcm57xx/fu-bcm57xx-device.c @@ -7,6 +7,10 @@ #include "config.h" +#ifdef HAVE_ERRNO_H +#include +#endif +#include #ifdef HAVE_ETHTOOL_H #include #include @@ -564,6 +568,18 @@ fu_bcm57xx_device_open (FuDevice *device, GError **error) #ifdef HAVE_SOCKET_H FuBcm57xxDevice *self = FU_BCM57XX_DEVICE (device); self->ethtool_fd = socket (AF_INET, SOCK_DGRAM, 0); + if (self->ethtool_fd < 0) { + g_set_error (error, + G_IO_ERROR, + G_IO_ERROR_NOT_SUPPORTED, + "failed to open socket: %s", +#ifdef HAVE_ERRNO_H + strerror (errno)); +#else + "unspecified error"); +#endif + return FALSE; + } return TRUE; #else g_set_error_literal (error, @@ -578,8 +594,7 @@ static gboolean fu_bcm57xx_device_close (FuDevice *device, GError **error) { FuBcm57xxDevice *self = FU_BCM57XX_DEVICE (device); - close (self->ethtool_fd); - return TRUE; + return g_close (self->ethtool_fd, error); } static void diff --git a/plugins/bcm57xx/fu-bcm57xx-recovery-device.c b/plugins/bcm57xx/fu-bcm57xx-recovery-device.c index cede4a319..7616f75d3 100644 --- a/plugins/bcm57xx/fu-bcm57xx-recovery-device.c +++ b/plugins/bcm57xx/fu-bcm57xx-recovery-device.c @@ -611,8 +611,8 @@ fu_bcm57xx_recovery_device_setup (FuDevice *device, GError **error) static gboolean fu_bcm57xx_recovery_device_open (FuDevice *device, GError **error) { - FuBcm57xxRecoveryDevice *self = FU_BCM57XX_RECOVERY_DEVICE (device); #ifdef HAVE_MMAN_H + FuBcm57xxRecoveryDevice *self = FU_BCM57XX_RECOVERY_DEVICE (device); FuUdevDevice *udev_device = FU_UDEV_DEVICE (device); const gchar *sysfs_path = fu_udev_device_get_sysfs_path (udev_device); #endif From d9b97e308b03c88e8ba858acb43ea81e87dc8157 Mon Sep 17 00:00:00 2001 From: Richard Hughes Date: Thu, 22 Oct 2020 10:12:18 +0100 Subject: [PATCH 570/607] Add a flag to retry the HID request up to 10 times This is something that we now need in two plugins, so move it into common code. --- libfwupdplugin/fu-hid-device.c | 184 ++++++++++++++++++++++++--------- libfwupdplugin/fu-hid-device.h | 2 + 2 files changed, 136 insertions(+), 50 deletions(-) diff --git a/libfwupdplugin/fu-hid-device.c b/libfwupdplugin/fu-hid-device.c index e2ab80b32..0568e5d4d 100644 --- a/libfwupdplugin/fu-hid-device.c +++ b/libfwupdplugin/fu-hid-device.c @@ -17,6 +17,8 @@ #define FU_HID_REPORT_TYPE_OUTPUT 0x02 #define FU_HID_REPORT_TYPE_FEATURE 0x03 +#define FU_HID_DEVICE_RETRIES 10 + /** * SECTION:fu-hid-device * @short_description: a HID device @@ -190,6 +192,63 @@ fu_hid_device_get_interface (FuHidDevice *self) return priv->interface; } +typedef struct { + guint8 value; + guint8 *buf; + gsize bufsz; + guint timeout; + FuHidDeviceFlags flags; +} FuHidDeviceRetryHelper; + +static gboolean +fu_hid_device_set_report_internal (FuHidDevice *self, + FuHidDeviceRetryHelper *helper, + GError **error) +{ + FuHidDevicePrivate *priv = GET_PRIVATE (self); + GUsbDevice *usb_device; + gsize actual_len = 0; + guint16 wvalue = (FU_HID_REPORT_TYPE_OUTPUT << 8) | helper->value; + + /* special case */ + if (helper->flags & FU_HID_DEVICE_FLAG_IS_FEATURE) + wvalue = (FU_HID_REPORT_TYPE_FEATURE << 8) | helper->value; + + if (g_getenv ("FU_HID_DEVICE_VERBOSE") != NULL) { + fu_common_dump_raw (G_LOG_DOMAIN, "HID::SetReport", + helper->buf, helper->bufsz); + } + usb_device = fu_usb_device_get_dev (FU_USB_DEVICE (self)); + if (!g_usb_device_control_transfer (usb_device, + G_USB_DEVICE_DIRECTION_HOST_TO_DEVICE, + G_USB_DEVICE_REQUEST_TYPE_CLASS, + G_USB_DEVICE_RECIPIENT_INTERFACE, + FU_HID_REPORT_SET, + wvalue, priv->interface, + helper->buf, helper->bufsz, + &actual_len, + helper->timeout, + NULL, error)) { + g_prefix_error (error, "failed to SetReport: "); + return FALSE; + } + if ((helper->flags & FU_HID_DEVICE_FLAG_ALLOW_TRUNC) == 0 && actual_len != helper->bufsz) { + g_set_error (error, G_IO_ERROR, G_IO_ERROR_INVALID_DATA, + "wrote %" G_GSIZE_FORMAT ", requested %" G_GSIZE_FORMAT " bytes", + actual_len, helper->bufsz); + return FALSE; + } + return TRUE; +} + +static gboolean +fu_hid_device_set_report_internal_cb (FuDevice *device, gpointer user_data, GError **error) +{ + FuHidDevice *self = FU_HID_DEVICE (device); + FuHidDeviceRetryHelper *helper = (FuHidDeviceRetryHelper *) user_data; + return fu_hid_device_set_report_internal (self, helper, error); +} + /** * fu_hid_device_set_report: * @self: A #FuHidDevice @@ -215,44 +274,83 @@ fu_hid_device_set_report (FuHidDevice *self, FuHidDeviceFlags flags, GError **error) { - FuHidDevicePrivate *priv = GET_PRIVATE (self); - GUsbDevice *usb_device; - gsize actual_len = 0; - guint16 wvalue = (FU_HID_REPORT_TYPE_OUTPUT << 8) | value; - - /* special case */ - if (flags & FU_HID_DEVICE_FLAG_IS_FEATURE) - wvalue = (FU_HID_REPORT_TYPE_FEATURE << 8) | value; + FuHidDeviceRetryHelper helper; g_return_val_if_fail (FU_HID_DEVICE (self), FALSE); g_return_val_if_fail (buf != NULL, FALSE); g_return_val_if_fail (bufsz != 0, FALSE); - if (g_getenv ("FU_HID_DEVICE_VERBOSE") != NULL) - fu_common_dump_raw (G_LOG_DOMAIN, "HID::SetReport", buf, bufsz); + /* create helper */ + helper.value = value; + helper.buf = buf; + helper.bufsz = bufsz; + helper.timeout = timeout; + helper.flags = flags; + + /* special case */ + if (flags & FU_HID_DEVICE_FLAG_RETRY_FAILURE) { + return fu_device_retry (FU_DEVICE (self), + fu_hid_device_set_report_internal_cb, + FU_HID_DEVICE_RETRIES, + &helper, + error); + } + + /* just one */ + return fu_hid_device_set_report_internal (self, &helper, error); +} + +static gboolean +fu_hid_device_get_report_internal (FuHidDevice *self, + FuHidDeviceRetryHelper *helper, + GError **error) +{ + FuHidDevicePrivate *priv = GET_PRIVATE (self); + GUsbDevice *usb_device; + gsize actual_len = 0; + guint16 wvalue = (FU_HID_REPORT_TYPE_INPUT << 8) | helper->value; + + /* special case */ + if (helper->flags & FU_HID_DEVICE_FLAG_IS_FEATURE) + wvalue = (FU_HID_REPORT_TYPE_FEATURE << 8) | helper->value; + + if (g_getenv ("FU_HID_DEVICE_VERBOSE") != NULL) { + fu_common_dump_raw (G_LOG_DOMAIN, "HID::GetReport", + helper->buf, actual_len); + } usb_device = fu_usb_device_get_dev (FU_USB_DEVICE (self)); if (!g_usb_device_control_transfer (usb_device, - G_USB_DEVICE_DIRECTION_HOST_TO_DEVICE, + G_USB_DEVICE_DIRECTION_DEVICE_TO_HOST, G_USB_DEVICE_REQUEST_TYPE_CLASS, G_USB_DEVICE_RECIPIENT_INTERFACE, - FU_HID_REPORT_SET, + FU_HID_REPORT_GET, wvalue, priv->interface, - buf, bufsz, - &actual_len, - timeout, + helper->buf, helper->bufsz, + &actual_len, /* actual length */ + helper->timeout, NULL, error)) { - g_prefix_error (error, "failed to SetReport: "); + g_prefix_error (error, "failed to GetReport: "); return FALSE; } - if ((flags & FU_HID_DEVICE_FLAG_ALLOW_TRUNC) == 0 && actual_len != bufsz) { + if (g_getenv ("FU_HID_DEVICE_VERBOSE") != NULL) + fu_common_dump_raw (G_LOG_DOMAIN, "HID::GetReport", helper->buf, actual_len); + if ((helper->flags & FU_HID_DEVICE_FLAG_ALLOW_TRUNC) == 0 && actual_len != helper->bufsz) { g_set_error (error, G_IO_ERROR, G_IO_ERROR_INVALID_DATA, - "wrote %" G_GSIZE_FORMAT ", requested %" G_GSIZE_FORMAT " bytes", - actual_len, bufsz); + "read %" G_GSIZE_FORMAT ", requested %" G_GSIZE_FORMAT " bytes", + actual_len, helper->bufsz); return FALSE; } return TRUE; } +static gboolean +fu_hid_device_get_report_internal_cb (FuDevice *device, gpointer user_data, GError **error) +{ + FuHidDevice *self = FU_HID_DEVICE (device); + FuHidDeviceRetryHelper *helper = (FuHidDeviceRetryHelper *) user_data; + return fu_hid_device_get_report_internal (self, helper, error); +} + /** * fu_hid_device_get_report: * @self: A #FuHidDevice @@ -278,44 +376,30 @@ fu_hid_device_get_report (FuHidDevice *self, FuHidDeviceFlags flags, GError **error) { - FuHidDevicePrivate *priv = GET_PRIVATE (self); - GUsbDevice *usb_device; - gsize actual_len = 0; - guint16 wvalue = (FU_HID_REPORT_TYPE_INPUT << 8) | value; + FuHidDeviceRetryHelper helper; g_return_val_if_fail (FU_HID_DEVICE (self), FALSE); g_return_val_if_fail (buf != NULL, FALSE); g_return_val_if_fail (bufsz != 0, FALSE); - /* special case */ - if (flags & FU_HID_DEVICE_FLAG_IS_FEATURE) - wvalue = (FU_HID_REPORT_TYPE_FEATURE << 8) | value; + /* create helper */ + helper.value = value; + helper.buf = buf; + helper.bufsz = bufsz; + helper.timeout = timeout; + helper.flags = flags; - if (g_getenv ("FU_HID_DEVICE_VERBOSE") != NULL) - fu_common_dump_raw (G_LOG_DOMAIN, "HID::GetReport", buf, actual_len); - usb_device = fu_usb_device_get_dev (FU_USB_DEVICE (self)); - if (!g_usb_device_control_transfer (usb_device, - G_USB_DEVICE_DIRECTION_DEVICE_TO_HOST, - G_USB_DEVICE_REQUEST_TYPE_CLASS, - G_USB_DEVICE_RECIPIENT_INTERFACE, - FU_HID_REPORT_GET, - wvalue, priv->interface, - buf, bufsz, - &actual_len, /* actual length */ - timeout, - NULL, error)) { - g_prefix_error (error, "failed to GetReport: "); - return FALSE; + /* special case */ + if (flags & FU_HID_DEVICE_FLAG_RETRY_FAILURE) { + return fu_device_retry (FU_DEVICE (self), + fu_hid_device_get_report_internal_cb, + FU_HID_DEVICE_RETRIES, + &helper, + error); } - if (g_getenv ("FU_HID_DEVICE_VERBOSE") != NULL) - fu_common_dump_raw (G_LOG_DOMAIN, "HID::GetReport", buf, actual_len); - if ((flags & FU_HID_DEVICE_FLAG_ALLOW_TRUNC) == 0 && actual_len != bufsz) { - g_set_error (error, G_IO_ERROR, G_IO_ERROR_INVALID_DATA, - "read %" G_GSIZE_FORMAT ", requested %" G_GSIZE_FORMAT " bytes", - actual_len, bufsz); - return FALSE; - } - return TRUE; + + /* just one */ + return fu_hid_device_get_report_internal (self, &helper, error); } static void diff --git a/libfwupdplugin/fu-hid-device.h b/libfwupdplugin/fu-hid-device.h index 2f78f0a2d..d445d4e9d 100644 --- a/libfwupdplugin/fu-hid-device.h +++ b/libfwupdplugin/fu-hid-device.h @@ -28,6 +28,7 @@ struct _FuHidDeviceClass * @FU_HID_DEVICE_FLAG_NONE: No flags set * @FU_HID_DEVICE_FLAG_ALLOW_TRUNC: Allow truncated reads and writes * @FU_HID_DEVICE_FLAG_IS_FEATURE: Use %FU_HID_REPORT_TYPE_FEATURE for wValue + * @FU_HID_DEVICE_FLAG_RETRY_FAILURE: Retry up to 10 times on failure * * Flags used when calling fu_hid_device_get_report() and fu_hid_device_set_report(). **/ @@ -35,6 +36,7 @@ typedef enum { FU_HID_DEVICE_FLAG_NONE = 0, FU_HID_DEVICE_FLAG_ALLOW_TRUNC = 1 << 0, FU_HID_DEVICE_FLAG_IS_FEATURE = 1 << 1, + FU_HID_DEVICE_FLAG_RETRY_FAILURE = 1 << 2, FU_HID_DEVICE_FLAG_LAST } FuHidDeviceFlags; From b814af80ef7bc3c8842c57ca3e0ed7f104434d17 Mon Sep 17 00:00:00 2001 From: Richard Hughes Date: Thu, 22 Oct 2020 10:14:50 +0100 Subject: [PATCH 571/607] synaptics-cxaudio: Retry the HID SetReport to fix flashing the TB3 dock Upon restarting the upstream VLI USB hub the cxaudio device re-enumerated okay but would not service HID requests for 100ms, returning 'endpoint stalled'. To make this more reliable retry the SetRequest up to 10 times after a short delay to make enumeration reliable. --- plugins/synaptics-cxaudio/fu-synaptics-cxaudio-device.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/plugins/synaptics-cxaudio/fu-synaptics-cxaudio-device.c b/plugins/synaptics-cxaudio/fu-synaptics-cxaudio-device.c index 7abdd3ddb..ebe6268d7 100644 --- a/plugins/synaptics-cxaudio/fu-synaptics-cxaudio-device.c +++ b/plugins/synaptics-cxaudio/fu-synaptics-cxaudio-device.c @@ -67,7 +67,7 @@ fu_synaptics_cxaudio_device_output_report (FuSynapticsCxaudioDevice *self, return fu_hid_device_set_report (FU_HID_DEVICE (self), buf[0], buf, bufsz, FU_SYNAPTICS_CXAUDIO_USB_TIMEOUT, - FU_HID_DEVICE_FLAG_NONE, + FU_HID_DEVICE_FLAG_RETRY_FAILURE, error); } @@ -760,6 +760,7 @@ fu_synaptics_cxaudio_device_init (FuSynapticsCxaudioDevice *self) fu_device_set_version_format (FU_DEVICE (self), FWUPD_VERSION_FORMAT_PLAIN); fu_device_set_install_duration (FU_DEVICE (self), 3); /* seconds */ fu_device_set_protocol (FU_DEVICE (self), "com.synaptics.cxaudio"); + fu_device_retry_set_delay (FU_DEVICE (self), 100); /* ms */ fu_device_set_remove_delay (FU_DEVICE (self), FU_DEVICE_REMOVE_DELAY_RE_ENUMERATE); } From e80547e8fca224de6229416a24fb5696029b709f Mon Sep 17 00:00:00 2001 From: Richard Hughes Date: Thu, 22 Oct 2020 14:14:51 +0100 Subject: [PATCH 572/607] Record the TPM version when reporting a UEFI update Fixes https://github.com/fwupd/fwupd/issues/2391 --- plugins/dell/fu-plugin-dell.c | 3 +++ plugins/tpm/fu-plugin-tpm.c | 5 ++++- plugins/uefi/fu-plugin-uefi.c | 2 ++ 3 files changed, 9 insertions(+), 1 deletion(-) diff --git a/plugins/dell/fu-plugin-dell.c b/plugins/dell/fu-plugin-dell.c index 3b500da24..efe6b1b19 100644 --- a/plugins/dell/fu-plugin-dell.c +++ b/plugins/dell/fu-plugin-dell.c @@ -605,6 +605,7 @@ fu_plugin_dell_add_tpm_model (FuDevice *dev, GError **error) "failed to read TPM vendor string"); return FALSE; } + fu_device_set_metadata (dev, "TpmFamily", family); /* these are not guaranteed by spec and may be NULL */ vendor2 = fu_plugin_dell_get_tpm_capability (ctx, TPM2_PT_VENDOR_STRING_2); @@ -744,6 +745,8 @@ fu_plugin_dell_detect_tpm (FuPlugin *plugin, GError **error) if (!fu_device_setup (dev, error)) return FALSE; fu_plugin_device_register (plugin, dev); + fu_plugin_add_report_metadata (plugin, "TpmFamily", + fu_device_get_metadata (dev, "TpmFamily")); /* build alternate device node */ if (can_switch_modes) { diff --git a/plugins/tpm/fu-plugin-tpm.c b/plugins/tpm/fu-plugin-tpm.c index 83e9534d8..f3227b53d 100644 --- a/plugins/tpm/fu-plugin-tpm.c +++ b/plugins/tpm/fu-plugin-tpm.c @@ -29,9 +29,12 @@ void fu_plugin_device_added (FuPlugin *plugin, FuDevice *dev) { FuPluginData *data = fu_plugin_get_data (plugin); + const gchar *family = fu_tpm_device_get_family (FU_TPM_DEVICE (dev)); + data->has_tpm = TRUE; - if (g_strcmp0 (fu_tpm_device_get_family (FU_TPM_DEVICE (dev)), "2.0") == 0) + if (g_strcmp0 (family, "2.0") == 0) data->has_tpm_v20 = TRUE; + fu_plugin_add_report_metadata (plugin, "TpmFamily", family); } void diff --git a/plugins/uefi/fu-plugin-uefi.c b/plugins/uefi/fu-plugin-uefi.c index 3c621b1a3..ba0b683ab 100644 --- a/plugins/uefi/fu-plugin-uefi.c +++ b/plugins/uefi/fu-plugin-uefi.c @@ -38,7 +38,9 @@ fu_plugin_init (FuPlugin *plugin) FuPluginData *data = fu_plugin_alloc_data (plugin, sizeof (FuPluginData)); data->bgrt = fu_uefi_bgrt_new (); fu_plugin_add_rule (plugin, FU_PLUGIN_RULE_RUN_AFTER, "upower"); + fu_plugin_add_rule (plugin, FU_PLUGIN_RULE_METADATA_SOURCE, "tpm"); fu_plugin_add_rule (plugin, FU_PLUGIN_RULE_METADATA_SOURCE, "tpm_eventlog"); + fu_plugin_add_rule (plugin, FU_PLUGIN_RULE_METADATA_SOURCE, "dell"); fu_plugin_set_build_hash (plugin, FU_BUILD_HASH); } From cb0e6140278dcf0d174bd57b4f804d048d9e6397 Mon Sep 17 00:00:00 2001 From: Richard Hughes Date: Thu, 22 Oct 2020 16:31:56 +0100 Subject: [PATCH 573/607] trivial: Do not list unsupported devices in switch-branch --- src/fu-tool.c | 2 +- src/fu-util.c | 9 +-------- 2 files changed, 2 insertions(+), 9 deletions(-) diff --git a/src/fu-tool.c b/src/fu-tool.c index 835272c40..0bbb293e3 100644 --- a/src/fu-tool.c +++ b/src/fu-tool.c @@ -2454,7 +2454,7 @@ fu_util_switch_branch (FuUtilPrivate *priv, gchar **values, GError **error) return FALSE; /* find the device and check it has multiple branches */ - priv->filter_include |= FWUPD_DEVICE_FLAG_SUPPORTED; + priv->filter_include |= FWUPD_DEVICE_FLAG_HAS_MULTIPLE_BRANCHES; if (g_strv_length (values) == 1) dev = fu_util_get_device (priv, values[1], error); else diff --git a/src/fu-util.c b/src/fu-util.c index d0bfd83e8..70c7b8336 100644 --- a/src/fu-util.c +++ b/src/fu-util.c @@ -1911,17 +1911,10 @@ fu_util_switch_branch (FuUtilPrivate *priv, gchar **values, GError **error) g_autoptr(FwupdDevice) dev = NULL; /* find the device and check it has multiple branches */ - priv->filter_include |= FWUPD_DEVICE_FLAG_SUPPORTED; + priv->filter_include |= FWUPD_DEVICE_FLAG_HAS_MULTIPLE_BRANCHES; dev = fu_util_get_device_or_prompt (priv, values, error); if (dev == NULL) return FALSE; - if (!fwupd_device_has_flag (dev, FWUPD_DEVICE_FLAG_HAS_MULTIPLE_BRANCHES)) { - g_set_error_literal (error, - FWUPD_ERROR, - FWUPD_ERROR_NOT_SUPPORTED, - "Multiple branches not available"); - return FALSE; - } /* get all releases, including the alternate branch versions */ rels = fwupd_client_get_releases (priv->client, fwupd_device_get_id (dev), From e4d52866d1c0d935edf1c7fc859b8a5685fdf0ff Mon Sep 17 00:00:00 2001 From: Mario Limonciello Date: Thu, 22 Oct 2020 20:21:47 -0500 Subject: [PATCH 574/607] fu-engine: Set a device when checking requirements for fu_engine_get_result_from_component The trust flags are only checked if check_requirements is called, which only happens when a device has been set. --- src/fu-engine.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/fu-engine.c b/src/fu-engine.c index d716a4175..1ece6fa3a 100644 --- a/src/fu-engine.c +++ b/src/fu-engine.c @@ -3721,7 +3721,7 @@ fu_engine_get_result_from_component (FuEngine *self, } /* check we can install it */ - task = fu_install_task_new (NULL, component); + task = fu_install_task_new (dev, component); if (!fu_engine_check_requirements (self, request, task, FWUPD_INSTALL_FLAG_NONE, error)) From 3460e0a5edc33e67491d4598be6cf92d90918881 Mon Sep 17 00:00:00 2001 From: Jingle Wu Date: Sat, 24 Oct 2020 02:31:18 +0800 Subject: [PATCH 575/607] elantp: Modify the correct input for the iap reg. 1. Modify the correct input for the iap reg (byte -> word). 2. Add new HWID for ThinkPad X1 Carbon Gen 9. --- plugins/elantp/elantp.quirk | 4 ++++ plugins/elantp/fu-elantp-hid-device.c | 4 ++-- plugins/elantp/fu-elantp-i2c-device.c | 4 ++-- 3 files changed, 8 insertions(+), 4 deletions(-) diff --git a/plugins/elantp/elantp.quirk b/plugins/elantp/elantp.quirk index 82f253ca4..40ce25c96 100644 --- a/plugins/elantp/elantp.quirk +++ b/plugins/elantp/elantp.quirk @@ -2,6 +2,10 @@ Plugin = elantp GType = FuElantpHidDevice +# ThinkPad X1 Carbon Gen 9 +[HwId=6c87726f-b545-549e-840a-189422ea21d0] +Flags = elantp-recovery + # Lenovo X1 Nano Gen1 [HwId=4c20262a-aee0-5d6e-ba72-6d29b23fe350] Flags = elantp-recovery diff --git a/plugins/elantp/fu-elantp-hid-device.c b/plugins/elantp/fu-elantp-hid-device.c index 168255024..809cd24cb 100644 --- a/plugins/elantp/fu-elantp-hid-device.c +++ b/plugins/elantp/fu-elantp-hid-device.c @@ -426,7 +426,7 @@ fu_elantp_hid_device_detach (FuDevice *device, GError **error) if (!fu_elantp_hid_device_write_cmd (self, ETP_CMD_I2C_IAP_TYPE, - self->fw_page_size, + self->fw_page_size / 2, error)) return FALSE; if (!fu_elantp_hid_device_read_cmd (self, ETP_CMD_I2C_IAP_TYPE, @@ -435,7 +435,7 @@ fu_elantp_hid_device_detach (FuDevice *device, GError **error) return FALSE; } self->iap_type = fu_common_read_uint16 (buf, G_LITTLE_ENDIAN); - if (self->iap_type != self->fw_page_size) { + if (self->iap_type != self->fw_page_size / 2) { g_set_error_literal (error, FWUPD_ERROR, FWUPD_ERROR_NOT_SUPPORTED, diff --git a/plugins/elantp/fu-elantp-i2c-device.c b/plugins/elantp/fu-elantp-i2c-device.c index c3123f0b8..362f46136 100644 --- a/plugins/elantp/fu-elantp-i2c-device.c +++ b/plugins/elantp/fu-elantp-i2c-device.c @@ -454,7 +454,7 @@ fu_elantp_i2c_device_detach (FuDevice *device, GError **error) /* set the IAP type, presumably some kind of ABI */ if (!fu_elantp_i2c_device_write_cmd (self, ETP_CMD_I2C_IAP_TYPE, - self->fw_page_size , + self->fw_page_size / 2, error)) return FALSE; if (!fu_elantp_i2c_device_read_cmd (self, ETP_CMD_I2C_IAP_TYPE , @@ -463,7 +463,7 @@ fu_elantp_i2c_device_detach (FuDevice *device, GError **error) return FALSE; } self->iap_type = fu_common_read_uint16 (buf, G_LITTLE_ENDIAN); - if (self->iap_type != self->fw_page_size) { + if (self->iap_type != self->fw_page_size / 2) { g_set_error_literal (error, FWUPD_ERROR, FWUPD_ERROR_NOT_SUPPORTED, From 381c27ca44ac6decd7f7e6bf0999a965d1391562 Mon Sep 17 00:00:00 2001 From: Mario Limonciello Date: Fri, 23 Oct 2020 16:32:26 -0500 Subject: [PATCH 576/607] trivial: Split check for signed metadata when no polkit Checking this requirement at daemon startup meant that trust was evaluated before releases could actually be checked. It's only important to check at install time. --- src/fu-engine.c | 25 +++++++++++-------- src/fu-engine.h | 2 ++ src/fu-main.c | 4 ++++ src/fu-self-test.c | 60 ---------------------------------------------- 4 files changed, 21 insertions(+), 70 deletions(-) diff --git a/src/fu-engine.c b/src/fu-engine.c index 1ece6fa3a..c65d12137 100644 --- a/src/fu-engine.c +++ b/src/fu-engine.c @@ -1440,6 +1440,21 @@ fu_engine_check_requirement (FuEngine *self, return FALSE; } +gboolean +fu_engine_check_trust (FuInstallTask *task, GError **error) +{ +#ifndef HAVE_POLKIT + if ((fu_install_task_get_trust_flags (task) & FWUPD_TRUST_FLAG_PAYLOAD) == 0) { + g_set_error_literal (error, + FWUPD_ERROR, + FWUPD_ERROR_INVALID_FILE, + "archive signature missing or not trusted"); + return FALSE; + } +#endif + return TRUE; +} + gboolean fu_engine_check_requirements (FuEngine *self, FuEngineRequest *request, @@ -1472,16 +1487,6 @@ fu_engine_check_requirements (FuEngine *self, return FALSE; } -#ifndef HAVE_POLKIT - if ((fu_install_task_get_trust_flags (task) & FWUPD_TRUST_FLAG_PAYLOAD) == 0) { - g_set_error_literal (error, - FWUPD_ERROR, - FWUPD_ERROR_INVALID_FILE, - "archive signature missing or not trusted"); - return FALSE; - } -#endif - return TRUE; } diff --git a/src/fu-engine.h b/src/fu-engine.h index 97fdd1351..47687578c 100644 --- a/src/fu-engine.h +++ b/src/fu-engine.h @@ -194,6 +194,8 @@ void fu_engine_add_plugin (FuEngine *self, void fu_engine_add_runtime_version (FuEngine *self, const gchar *component_id, const gchar *version); +gboolean fu_engine_check_trust (FuInstallTask *task, + GError **error); gboolean fu_engine_check_requirements (FuEngine *self, FuEngineRequest *request, FuInstallTask *task, diff --git a/src/fu-main.c b/src/fu-main.c index c7d0c035b..b971d897c 100644 --- a/src/fu-main.c +++ b/src/fu-main.c @@ -902,6 +902,10 @@ fu_main_install_with_helper (FuMainAuthHelper *helper_ref, GError **error) g_ptr_array_add (errors, g_steal_pointer (&error_local)); continue; } + if (!fu_engine_check_trust (task, &error_local)) { + g_ptr_array_add (errors, g_steal_pointer (&error_local)); + continue; + } /* if component should have an update message from CAB */ fu_device_incorporate_from_component (device, component); diff --git a/src/fu-self-test.c b/src/fu-self-test.c index 2848709d1..aaa3cd26c 100644 --- a/src/fu-self-test.c +++ b/src/fu-self-test.c @@ -324,13 +324,8 @@ fu_engine_requirements_client_pass_func (gconstpointer user_data) ret = fu_engine_check_requirements (engine, request, task, FWUPD_INSTALL_FLAG_NONE, &error); -#ifdef HAVE_POLKIT g_assert_no_error (error); g_assert (ret); -#else - g_assert_error (error, FWUPD_ERROR, FWUPD_ERROR_INVALID_FILE); - g_assert_false (ret); -#endif } static void @@ -470,13 +465,8 @@ fu_engine_requirements_child_func (gconstpointer user_data) ret = fu_engine_check_requirements (engine, request, task, FWUPD_INSTALL_FLAG_NONE, &error); -#ifdef HAVE_POLKIT g_assert_no_error (error); g_assert (ret); -#else - g_assert_error (error, FWUPD_ERROR, FWUPD_ERROR_INVALID_FILE); - g_assert_false (ret); -#endif } static void @@ -570,13 +560,8 @@ fu_engine_requirements_func (gconstpointer user_data) ret = fu_engine_check_requirements (engine, request, task, FWUPD_INSTALL_FLAG_NONE, &error); -#ifdef HAVE_POLKIT g_assert_no_error (error); g_assert (ret); -#else - g_assert_error (error, FWUPD_ERROR, FWUPD_ERROR_INVALID_FILE); - g_assert_false (ret); -#endif } static void @@ -632,13 +617,8 @@ fu_engine_requirements_device_func (gconstpointer user_data) ret = fu_engine_check_requirements (engine, request, task, FWUPD_INSTALL_FLAG_NONE, &error); -#ifdef HAVE_POLKIT g_assert_no_error (error); g_assert (ret); -#else - g_assert_error (error, FWUPD_ERROR, FWUPD_ERROR_INVALID_FILE); - g_assert_false (ret); -#endif } static void @@ -684,13 +664,8 @@ fu_engine_requirements_device_plain_func (gconstpointer user_data) ret = fu_engine_check_requirements (engine, request, task, FWUPD_INSTALL_FLAG_NONE, &error); -#ifdef HAVE_POLKIT g_assert_no_error (error); g_assert (ret); -#else - g_assert_error (error, FWUPD_ERROR, FWUPD_ERROR_INVALID_FILE); - g_assert_false (ret); -#endif } static void @@ -805,13 +780,8 @@ fu_engine_requirements_other_device_func (gconstpointer user_data) ret = fu_engine_check_requirements (engine, request, task, FWUPD_INSTALL_FLAG_NONE, &error); -#ifdef HAVE_POLKIT g_assert_no_error (error); g_assert (ret); -#else - g_assert_error (error, FWUPD_ERROR, FWUPD_ERROR_INVALID_FILE); - g_assert_false (ret); -#endif } static void @@ -898,13 +868,8 @@ fu_engine_requirements_protocol_check_func (gconstpointer user_data) FWUPD_INSTALL_FLAG_NONE, &error); -#ifdef HAVE_POLKIT g_assert_no_error (error); g_assert (ret); -#else - g_assert_error (error, FWUPD_ERROR, FWUPD_ERROR_INVALID_FILE); - g_assert_false (ret); -#endif } static void @@ -971,13 +936,8 @@ fu_engine_requirements_parent_device_func (gconstpointer user_data) ret = fu_engine_check_requirements (engine, request, task, FWUPD_INSTALL_FLAG_NONE, &error); -#ifdef HAVE_POLKIT g_assert_no_error (error); g_assert (ret); -#else - g_assert_error (error, FWUPD_ERROR, FWUPD_ERROR_INVALID_FILE); - g_assert_false (ret); -#endif } static void @@ -1443,16 +1403,9 @@ fu_engine_downgrade_func (gconstpointer user_data) request, fu_device_get_id (device), &error); -#ifdef HAVE_POLKIT g_assert_no_error (error); g_assert (releases != NULL); g_assert_cmpint (releases->len, ==, 4); -#else - g_assert_error (error, FWUPD_ERROR, FWUPD_ERROR_INVALID_FILE); - g_assert (releases == NULL); - g_test_skip ("Compiling without PK requires trusted payloads for tests"); - return; -#endif /* no upgrades, as no firmware is approved */ releases_up = fu_engine_get_upgrades (engine, @@ -1497,9 +1450,7 @@ fu_engine_downgrade_func (gconstpointer user_data) static void fu_engine_install_duration_func (gconstpointer user_data) { -#ifdef HAVE_POLKIT FwupdRelease *rel; -#endif gboolean ret; g_autoptr(FuDevice) device = fu_device_new (); g_autoptr(FuEngine) engine = fu_engine_new (FU_APP_FLAGS_NONE); @@ -1565,16 +1516,11 @@ fu_engine_install_duration_func (gconstpointer user_data) request, fu_device_get_id (device), &error); -#ifdef HAVE_POLKIT g_assert_no_error (error); g_assert (releases != NULL); g_assert_cmpint (releases->len, ==, 1); rel = FWUPD_RELEASE (g_ptr_array_index (releases, 0)); g_assert_cmpint (fwupd_release_get_install_duration (rel), ==, 120); -#else - g_assert_error (error, FWUPD_ERROR, FWUPD_ERROR_INVALID_FILE); - g_assert (releases == NULL); -#endif } static void @@ -2980,13 +2926,7 @@ fu_plugin_composite_func (gconstpointer user_data) g_ptr_array_add (install_tasks, g_steal_pointer (&task)); } } -#ifdef HAVE_POLKIT g_assert_cmpint (install_tasks->len, ==, 3); -#else - g_assert_cmpint (install_tasks->len, ==, 0); - g_test_skip ("Compiling without PK support requires signed payloads"); - return; -#endif /* install the cab */ ret = fu_engine_install_tasks (engine, From 13d077353bbc461447272f79057d3fa60eb033d1 Mon Sep 17 00:00:00 2001 From: Mario Limonciello Date: Fri, 23 Oct 2020 17:18:43 -0500 Subject: [PATCH 577/607] Revert "fu-engine: Set a device when checking requirements for fu_engine_get_result_from_component" This reverts commit e4d52866d1c0d935edf1c7fc859b8a5685fdf0ff. --- src/fu-engine.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/fu-engine.c b/src/fu-engine.c index c65d12137..2eef588a5 100644 --- a/src/fu-engine.c +++ b/src/fu-engine.c @@ -3726,7 +3726,7 @@ fu_engine_get_result_from_component (FuEngine *self, } /* check we can install it */ - task = fu_install_task_new (dev, component); + task = fu_install_task_new (NULL, component); if (!fu_engine_check_requirements (self, request, task, FWUPD_INSTALL_FLAG_NONE, error)) From f630678b6fbbdc75e58fe7f1303e99cc3f4c9930 Mon Sep 17 00:00:00 2001 From: Richard Hughes Date: Sun, 25 Oct 2020 08:55:03 +0000 Subject: [PATCH 578/607] Fix regression when filtering different priorities We need to check if the device is in the remove timeout before unconditionally replacing a device on insert. Fixes https://github.com/fwupd/fwupd/issues/2510 --- src/fu-device-list.c | 2 +- src/fu-self-test.c | 11 ++++++++--- 2 files changed, 9 insertions(+), 4 deletions(-) diff --git a/src/fu-device-list.c b/src/fu-device-list.c index 6f24ed8eb..3582e6487 100644 --- a/src/fu-device-list.c +++ b/src/fu-device-list.c @@ -678,7 +678,7 @@ fu_device_list_add (FuDeviceList *self, FuDevice *device) /* is the device waiting to be replugged? */ item = fu_device_list_find_by_id (self, fu_device_get_id (device), NULL); - if (item != NULL) { + if (item != NULL && item->remove_id != 0) { g_debug ("found existing device %s, reusing item", fu_device_get_id (item->device)); fu_device_list_replace (self, item, device); diff --git a/src/fu-self-test.c b/src/fu-self-test.c index aaa3cd26c..8434df162 100644 --- a/src/fu-self-test.c +++ b/src/fu-self-test.c @@ -1981,18 +1981,23 @@ fu_device_list_delay_func (gconstpointer user_data) g_assert_cmpint (changed_cnt, ==, 0); /* add the same device again */ + g_test_expect_message ("FuDeviceList", G_LOG_LEVEL_WARNING, + "ignoring device*existing device*already exists"); fu_device_list_add (device_list, device1); g_assert_cmpint (added_cnt, ==, 1); g_assert_cmpint (removed_cnt, ==, 0); - g_assert_cmpint (changed_cnt, ==, 1); + g_assert_cmpint (changed_cnt, ==, 0); - /* add a device with the same ID */ + /* remove device */ + fu_device_list_remove (device_list, device1); + + /* add a different device with the same ID */ fu_device_set_id (device2, "device1"); fu_device_list_add (device_list, device2); fu_device_set_remove_delay (device2, 100); g_assert_cmpint (added_cnt, ==, 1); g_assert_cmpint (removed_cnt, ==, 0); - g_assert_cmpint (changed_cnt, ==, 2); + g_assert_cmpint (changed_cnt, ==, 1); /* spin a bit */ fu_test_loop_run_with_timeout (10); From f9ad963bcf3d4d832e7a913eccc03b3d6852fa70 Mon Sep 17 00:00:00 2001 From: Emily Miller Date: Fri, 23 Oct 2020 14:08:15 +0800 Subject: [PATCH 579/607] vli: Add support for Hyper hardware --- plugins/vli/fu-vli-pd-firmware.c | 2 ++ plugins/vli/meson.build | 1 + plugins/vli/vli-usbhub-hyper.quirk | 11 +++++++++++ 3 files changed, 14 insertions(+) create mode 100644 plugins/vli/vli-usbhub-hyper.quirk diff --git a/plugins/vli/fu-vli-pd-firmware.c b/plugins/vli/fu-vli-pd-firmware.c index ec3b0a8a5..176ac6a7b 100644 --- a/plugins/vli/fu-vli-pd-firmware.c +++ b/plugins/vli/fu-vli-pd-firmware.c @@ -48,6 +48,8 @@ fu_vli_pd_firmware_validate_header (FuVliPdFirmware *self) return TRUE; if (GUINT16_FROM_LE (self->hdr.vid) == 0x17EF) return TRUE; + if (GUINT16_FROM_LE (self->hdr.vid) == 0x2D01) + return TRUE; return FALSE; } diff --git a/plugins/vli/meson.build b/plugins/vli/meson.build index 7db82864b..e3e8599da 100644 --- a/plugins/vli/meson.build +++ b/plugins/vli/meson.build @@ -4,6 +4,7 @@ install_data([ 'vli-pd.quirk', 'vli-usbhub.quirk', 'vli-usbhub-lenovo.quirk', + 'vli-usbhub-hyper.quirk', ], install_dir: join_paths(datadir, 'fwupd', 'quirks.d') ) diff --git a/plugins/vli/vli-usbhub-hyper.quirk b/plugins/vli/vli-usbhub-hyper.quirk new file mode 100644 index 000000000..1e90f42a8 --- /dev/null +++ b/plugins/vli/vli-usbhub-hyper.quirk @@ -0,0 +1,11 @@ +# Hyper USB-C Hub +[DeviceInstanceId=USB\VID_2D01&PID_0385] +Plugin = vli +GType = FuVliUsbhubDevice +Flags = usb3,has-shared-spi-pd +CounterpartGuid = USB\VID_2D01&PID_0382 +[DeviceInstanceId=USB\VID_2D01&PID_0382] +Plugin = vli +GType = FuVliUsbhubDevice +Flags = usb2 +ParentGuid = USB\VID_2D01&PID_0385 From f90cda6f0b0ff1ab0ebd31a6e5be1c4d2e3cc4e6 Mon Sep 17 00:00:00 2001 From: Richard Hughes Date: Mon, 26 Oct 2020 11:49:30 +0000 Subject: [PATCH 580/607] Release fwupd 1.5.0 --- data/org.freedesktop.fwupd.metainfo.xml | 2 + po/LINGUAS | 1 + po/af.po | 35 +- po/ca.po | 649 +++++++++++++-- po/cs.po | 708 +++++++++++++++- po/da.po | 643 +++++++++++++-- po/de.po | 40 +- po/en_GB.po | 655 +++++++++++++-- po/fi.po | 601 +++++++++++--- po/fr.po | 337 ++++++++ po/fur.po | 25 +- po/gl.po | 1010 +++++++++++++++++++++++ po/he.po | 9 + po/hr.po | 523 ++++++++++-- po/hu.po | 72 +- po/id.po | 85 +- po/it.po | 519 ++++++++++-- po/ko.po | 108 +-- po/lt.po | 56 +- po/nl.po | 11 +- po/oc.po | 13 + po/pl.po | 605 ++++++++++++-- po/pt_BR.po | 470 +++++++++-- po/ru.po | 60 +- po/sk.po | 13 + po/sr.po | 37 +- po/sv.po | 90 +- po/tr.po | 97 +-- po/uk.po | 603 ++++++++++++-- po/zh_CN.po | 94 +-- po/zh_TW.po | 46 +- 31 files changed, 7064 insertions(+), 1153 deletions(-) create mode 100644 po/gl.po diff --git a/data/org.freedesktop.fwupd.metainfo.xml b/data/org.freedesktop.fwupd.metainfo.xml index 9c8389a1c..9bf3afd7f 100644 --- a/data/org.freedesktop.fwupd.metainfo.xml +++ b/data/org.freedesktop.fwupd.metainfo.xml @@ -49,6 +49,7 @@
    13. Add plugin to update Elan Touchpads using HID
    14. Add support for a delayed activation flow for Thunderbolt
    15. Add support for ChromeOS Quiche and Gingerbread
    16. +
    17. Add support for Hyper hardware
    18. Add support for the Host Security ID
    19. Add support for ThunderBolt retimers
    20. Add switch-branch command to fwupdtool and fwupdmgr
    21. @@ -80,6 +81,7 @@
    22. Parse the HEX version before comparing for equality
    23. Prevent dell-dock updates to occur via synaptics-mst plugin
    24. Record the UEFI failure in more cases
    25. +
    26. Retry the HID SetReport to fix flashing the TB3 dock
    27. Show an error when a plugin is missing dependencies
    28. Use libxmlb bound parameters to speed up the device verification
    29. Use pkttyagent to request user passwords if running without GUI
    30. diff --git a/po/LINGUAS b/po/LINGUAS index cf53114c8..9c5acfebb 100644 --- a/po/LINGUAS +++ b/po/LINGUAS @@ -10,6 +10,7 @@ eu fi fr fur +gl he hi hr diff --git a/po/af.po b/po/af.po index 4af7811a6..38670f230 100644 --- a/po/af.po +++ b/po/af.po @@ -123,6 +123,7 @@ msgstr "Toestelle wat suksesvol bygewerk is:" msgid "Devices that were not updated correctly:" msgstr "Toestelle wat nie korrek bygewerk is nie:" +#. TRANSLATORS: success #. success msgid "Done!" msgstr "Klaar!" @@ -143,6 +144,8 @@ msgstr "Gradeer tans %s af…" msgid "Downloading…" msgstr "Laai tans af…" +#. TRANSLATORS: Suffix: the HSI result +#. TRANSLATORS: Plugin is active and in use #. TRANSLATORS: if the remote is enabled msgid "Enabled" msgstr "Geaktiveer" @@ -151,22 +154,6 @@ msgstr "Geaktiveer" msgid "Erasing…" msgstr "Vee tans uit…" -#. TRANSLATORS: the server is rate-limiting downloads -msgid "Failed to download due to server limit" -msgstr "Kon nie aflaai nie a.g.v. bedienerlimiet" - -#. TRANSLATORS: downloading unknown file -msgid "Fetching file" -msgstr "Kry tans lêer" - -#. TRANSLATORS: downloading new metadata file -msgid "Fetching metadata" -msgstr "Kry tans metadata" - -#. TRANSLATORS: downloading new signing file -msgid "Fetching signature" -msgstr "Kry tans handtekening" - #. TRANSLATORS: filename of the local file msgid "Filename" msgstr "Lêernaam" @@ -175,6 +162,10 @@ msgstr "Lêernaam" msgid "Filename Signature" msgstr "Lêernaamhandtekening" +#. TRANSLATORS: Suffix: the HSI result +msgid "Found" +msgstr "Gevind" + #. TRANSLATORS: daemon is inactive msgid "Idle…" msgstr "Ledig…" @@ -199,6 +190,10 @@ msgstr "Laai tans…" msgid "Metadata URI" msgstr "Metadata-URI" +#. TRANSLATORS: Suffix: the HSI result +msgid "OK" +msgstr "Goed" + #. TRANSLATORS: remote filename base msgid "Password" msgstr "Wagwoord" @@ -285,10 +280,6 @@ msgstr "Werk tans %s by vanaf %s na %s… " msgid "Updating %s…" msgstr "Werk tans %s by…" -#. TRANSLATORS: the server sent the user a small message -msgid "Upload message:" -msgstr "Oplaaiboodskap:" - #. TRANSLATORS: ask the user to upload msgid "Upload report now?" msgstr "Laai verslag nou op?" @@ -301,6 +292,10 @@ msgstr "Gebruikernaam" msgid "Verifying…" msgstr "Verifieer tans…" +#. TRANSLATORS: the detected version number of the dbx +msgid "Version" +msgstr "Weergawe" + #. TRANSLATORS: waiting for device to do something msgid "Waiting…" msgstr "Wag tans…" diff --git a/po/ca.po b/po/ca.po index 89f8517cf..ac89622a8 100644 --- a/po/ca.po +++ b/po/ca.po @@ -29,6 +29,12 @@ msgstr[1] "Manquen %.0f minuts" msgid "%s CPU Microcode Update" msgstr "%s Actualitza el microprogramari de la CPU" +#. TRANSLATORS: a specific part of hardware, +#. * the first %s is the device name, e.g. 'Secure Boot` +#, c-format +msgid "%s Configuration Update" +msgstr "Actualització de la configuració %s" + #. TRANSLATORS: ME stands for Management Engine, where #. * the first %s is the device name, e.g. 'ThinkPad P50` #, c-format @@ -52,7 +58,7 @@ msgstr "Actualització ME corporativa de %s" #. * the first %s is the device name, e.g. 'Unifying Receiver` #, c-format msgid "%s Device Update" -msgstr "Actualizació del dispositiu %s" +msgstr "Actualització del dispositiu %s" #. TRANSLATORS: the EC is typically the keyboard controller chip, #. * the first %s is the device name, e.g. 'ThinkPad P50` @@ -70,7 +76,7 @@ msgstr "Actualització ME de %s" #. * the first %s is the device name, e.g. 'ThinkPad P50` #, c-format msgid "%s System Update" -msgstr "Actualizació del sistema %s" +msgstr "Actualització del sistema %s" #. TRANSLATORS: the Thunderbolt controller is a device that #. * has other high speed Thunderbolt devices plugged into it; @@ -92,15 +98,35 @@ msgstr "Actualització de %s" msgid "%s and all connected devices may not be usable while updating." msgstr "%s i tots els dispositius connectats poden no ser usables en actualitzar." +#. TRANSLATORS: Title: %s is ME kind, e.g. CSME/TXT +#, c-format +msgid "%s manufacturing mode" +msgstr "Mode de fabricació %s" + #. TRANSLATORS: warn the user before updating, %1 is a device name #, c-format msgid "%s must remain connected for the duration of the update to avoid damage." -msgstr "%s haurà d'estar connectat durant tota l'actualització per evitar danys." +msgstr "%s haurà d'estar connectat durant tota l'actualització per a evitar danys." #. TRANSLATORS: warn the user before updating, %1 is a machine name #, c-format msgid "%s must remain plugged into a power source for the duration of the update to avoid damage." -msgstr "%s haurà de romandre connectat a una font d'alimentació durant tota l'actualització per evitar danys." +msgstr "%s haurà de romandre connectat a una font d'alimentació durant tota l'actualització per a evitar danys." + +#. TRANSLATORS: Title: %s is ME kind, e.g. CSME/TXT +#, c-format +msgid "%s override" +msgstr "Superposa %s" + +#. TRANSLATORS: Title: %1 is ME kind, e.g. CSME/TXT, %2 is a version number +#, c-format +msgid "%s v%s" +msgstr "%s versió %s" + +#. TRANSLATORS: Title: %s is ME kind, e.g. CSME/TXT +#, c-format +msgid "%s version" +msgstr "Versió %s" #. TRANSLATORS: duration in days! #, c-format @@ -143,6 +169,10 @@ msgid_plural "%u seconds" msgstr[0] "%u segon" msgstr[1] "%u segons" +#. TRANSLATORS: this is shown as a suffix for obsoleted tests +msgid "(obsoleted)" +msgstr "(obsolet)" + #. TRANSLATORS: command description msgid "Activate devices" msgstr "Activa els dispositius" @@ -160,7 +190,7 @@ msgstr "Activació de l'actualització del microprogramari" #. TRANSLATORS: shown when shutting down to switch to the new version msgid "Activating firmware update for" -msgstr "Activa l’actualització del microprogramari per a" +msgstr "Activa l'actualització del microprogramari per a" #. TRANSLATORS: this is when a device is hotplugged msgid "Added" @@ -177,7 +207,7 @@ msgstr "Accepteu i habiliteu el remot?" #. TRANSLATORS: this is a command alias, e.g. 'get-devices' #, c-format msgid "Alias to %s" -msgstr "Àlies per a %s" +msgstr "Àlies per a «%s»" #. TRANSLATORS: command line option msgid "Allow downgrading firmware versions" @@ -187,6 +217,10 @@ msgstr "Permet tornar a la versió anterior del microprogramari" msgid "Allow reinstalling existing firmware versions" msgstr "Permetre tornar a instal·lar les versions existents del microprogramari" +#. TRANSLATORS: command line option +msgid "Allow switching firmware branch" +msgstr "Permet canviar de branca de microprogramari" + #. TRANSLATORS: explain why we want to reboot msgid "An update requires a reboot to complete." msgstr "Una actualització requereix un reinici per a completar-se." @@ -201,7 +235,19 @@ msgstr "Respon sí a totes les preguntes" #. TRANSLATORS: command line option msgid "Apply firmware updates" -msgstr "Aplica les actualizacions de microprogramari" +msgstr "Aplica les actualitzacions de microprogramari" + +#. TRANSLATORS: command line option +msgid "Apply update even when not advised" +msgstr "Aplica una actualització fins i tot quan no se us aconselli" + +#. TRANSLATORS: command line option +msgid "Apply update files" +msgstr "Aplica els fitxers d'actualització" + +#. TRANSLATORS: actually sending the update to the hardware +msgid "Applying update…" +msgstr "S'està aplicant l'actualització" #. TRANSLATORS: approved firmware has been checked by #. * the domain administrator @@ -210,6 +256,10 @@ msgid_plural "Approved firmware:" msgstr[0] "Microprogramari aprovat:" msgstr[1] "Microprogramari aprovat:" +#. TRANSLATORS: stop nagging the user +msgid "Ask again next time?" +msgstr "Demana-m'ho de nou la propera vegada?" + #. TRANSLATORS: command description msgid "Attach to firmware mode" msgstr "Ajunta al mode microprogramari" @@ -220,7 +270,7 @@ msgstr "S'està autenticant..." #. TRANSLATORS: this is the PolicyKit modal dialog msgid "Authentication is required to downgrade the firmware on a removable device" -msgstr "Es requereix autenticació per a desactualitzar el microprogramari en un dispositiu extraible" +msgstr "Es requereix autenticació per a desactualitzar el microprogramari en un dispositiu extraïble" #. TRANSLATORS: this is the PolicyKit modal dialog msgid "Authentication is required to downgrade the firmware on this machine" @@ -244,7 +294,7 @@ msgstr "Es requereix autenticació per a signar les dades emprant el certificat #. TRANSLATORS: this is the PolicyKit modal dialog msgid "Authentication is required to switch to the new firmware version" -msgstr "Es requereix autenticació per a canviar a la nova versió del micropogramari" +msgstr "Es requereix autenticació per a canviar a la nova versió del microprogramari" #. TRANSLATORS: this is the PolicyKit modal dialog msgid "Authentication is required to unlock a device" @@ -252,24 +302,52 @@ msgstr "Es requereix autenticació per a desbloquejar un dispositiu" #. TRANSLATORS: this is the PolicyKit modal dialog msgid "Authentication is required to update the firmware on a removable device" -msgstr "Es requereix autenticació per actualitzar el microprogramari en un dispositiu extraible" +msgstr "Es requereix autenticació per a actualitzar el microprogramari en un dispositiu extraïble" #. TRANSLATORS: this is the PolicyKit modal dialog msgid "Authentication is required to update the firmware on this machine" -msgstr "Es requereix autenticació per actualitzar el microprogramari en aquesta màquina" +msgstr "Es requereix autenticació per a actualitzar el microprogramari en aquesta màquina" #. TRANSLATORS: this is the PolicyKit modal dialog msgid "Authentication is required to update the stored checksums for the device" -msgstr "Es requereix autenticació per actualitzar les sumes de verificació emmagatzemades pels dispositius" +msgstr "Es requereix autenticació per a actualitzar les sumes de verificació emmagatzemades pels dispositius" #. TRANSLATORS: Boolean value to automatically send reports msgid "Automatic Reporting" msgstr "Informa automàticament" +#. TRANSLATORS: can we JFDI? +msgid "Automatically upload every time?" +msgstr "El pujo automàticament cada vegada?" + +#. TRANSLATORS: command description +msgid "Bind new kernel driver" +msgstr "Vincula el controlador actual" + +#. TRANSLATORS: there follows a list of hashes +msgid "Blocked firmware files:" +msgstr "Fitxers del microprogramari bloquejat:" + +#. TRANSLATORS: we will not offer this firmware to the user +msgid "Blocking firmware:" +msgstr "Microprogramari bloquejat:" + +#. TRANSLATORS: command description +msgid "Blocks a specific firmware from being installed" +msgstr "Bloqueja la instal·lació d'un microprogramari específic" + #. TRANSLATORS: firmware version of bootloader msgid "Bootloader Version" msgstr "Versió del carregador d'arrencada" +#. TRANSLATORS: the stream of firmware, e.g. nonfree or open-source +msgid "Branch" +msgstr "Branca" + +#. TRANSLATORS: command description +msgid "Build a firmware file" +msgstr "Construeix un fitxer de microprogramari" + #. TRANSLATORS: command description msgid "Build firmware using a sandbox" msgstr "Construeix el microprogramari usant un entorn de proves" @@ -282,6 +360,14 @@ msgstr "Cancel·la" msgid "Cancelled" msgstr "S'ha cancel·lat" +#. TRANSLATORS: same or newer update already applied +msgid "Cannot apply as dbx update has already been applied." +msgstr "No s'ha pogut aplicar perquè l'actualització de la dbx ja s'ha aplicat." + +#. TRANSLATORS: the user is using a LiveCD or LiveUSB install disk +msgid "Cannot apply updates on live media" +msgstr "No s'han pogut aplicar les actualitzacions en els suports en viu" + #. TRANSLATORS: this is when a device is hotplugged #. TRANSLATORS: this is when the daemon state changes msgid "Changed" @@ -295,6 +381,11 @@ msgstr "Comprova que la suma criptogràfica coincideix amb el microprogramari" msgid "Checksum" msgstr "Suma de comprovació" +#. TRANSLATORS: get interactive prompt, where branch is the +#. * supplier of the firmware, e.g. "non-free" or "free" +msgid "Choose a branch:" +msgstr "Trieu una branca:" + #. TRANSLATORS: get interactive prompt msgid "Choose a device:" msgstr "Trieu un dispositiu:" @@ -307,9 +398,13 @@ msgstr "Trieu un tipus de microprogramari:" msgid "Choose a release:" msgstr "Trieu un alliberament:" +#. TRANSLATORS: get interactive prompt +msgid "Choose a volume:" +msgstr "Trieu un volum:" + #. TRANSLATORS: command description msgid "Clears any updates scheduled to be updated offline" -msgstr "Neteja qualsevol actualització programyada per a ser actualitzada sense connexió" +msgstr "Neteja qualsevol actualització programada per a ser actualitzada sense connexió" #. TRANSLATORS: command description msgid "Clears the results from the last update" @@ -397,7 +492,7 @@ msgstr "El dispositiu està bloquejat" #. TRANSLATORS: a version check is required for all firmware msgid "Device is required to install all provided releases" -msgstr "El dispositiu és necessari per instal·lar totes les versions llançades" +msgstr "El dispositiu és necessari per a instal·lar totes les versions subministrades" #. TRANSLATORS: Device remains usable during update msgid "Device is usable for the duration of the update" @@ -411,10 +506,18 @@ msgstr "S'ha eliminat el dispositiu:" msgid "Device stages updates" msgstr "Etapes d'actualització del dispositiu" +#. TRANSLATORS: there is more than one supplier of the firmware +msgid "Device supports switching to a different branch of firmware" +msgstr "El dispositiu admet el canvi a una branca diferent de microprogramari" + #. TRANSLATORS: Device update needs to be separately activated msgid "Device update needs activation" msgstr "Cal activar l'actualització del dispositiu" +#. TRANSLATORS: save the old firmware to disk before installing the new one +msgid "Device will backup firmware before installing" +msgstr "El dispositiu farà una còpia de seguretat del microprogramari abans d'instal·lar" + #. TRANSLATORS: Device will not return after update completes msgid "Device will not re-appear after update completes" msgstr "El dispositiu no tornarà a aparèixer un cop finalitzada l'actualització" @@ -427,6 +530,20 @@ msgstr "Els dispositius que s'han actualitzat correctament:" msgid "Devices that were not updated correctly:" msgstr "Els dispositius que no s'han actualitzat correctament:" +#. TRANSLATORS: message letting the user know no device upgrade available due +#. to missing on LVFS +msgid "Devices with no available firmware updates: " +msgstr "Dispositius sense actualitzacions de microprogramari disponibles:" + +#. TRANSLATORS: message letting the user know no device upgrade available +msgid "Devices with the latest available firmware version:" +msgstr "Dispositius amb la versió més recent del microprogramari disponible:" + +#. TRANSLATORS: Suffix: the HSI result +#. TRANSLATORS: Plugin is inactive and not used +msgid "Disabled" +msgstr "Inhabilitada" + msgid "Disabled fwupdate debugging" msgstr "La depuració del «fwupdate» està inhabilitada" @@ -476,6 +593,11 @@ msgstr[1] "No enviar els informes, i no sol·licitar-ho mai per a les futures ac msgid "Do not write to the history database" msgstr "No escriure a la base de dades de l'historial" +#. TRANSLATORS: should the branch be changed +msgid "Do you understand the consequences of changing the firmware branch?" +msgstr "Enteneu les conseqüències de canviar la branca del microprogramari?" + +#. TRANSLATORS: success #. success msgid "Done!" msgstr "Fet!" @@ -520,6 +642,8 @@ msgstr "Habilita el suport per a l'actualització del microprogramari sobre sist msgid "Enable this remote?" msgstr "Habilito aquest remot?" +#. TRANSLATORS: Suffix: the HSI result +#. TRANSLATORS: Plugin is active and in use #. TRANSLATORS: if the remote is enabled msgid "Enabled" msgstr "Habilitat" @@ -538,6 +662,14 @@ msgstr "Si habiliteu aquesta funcionalitat, ho fareu sota el vostre propi risc, msgid "Enabling this remote is done at your own risk." msgstr "Si habiliteu aquest remot, ho fareu sota el vostre propi risc." +#. TRANSLATORS: Suffix: the HSI result +msgid "Encrypted" +msgstr "Encriptada" + +#. TRANSLATORS: Title: Memory contents are encrypted, e.g. Intel TME +msgid "Encrypted RAM" +msgstr "RAM encriptada" + #. TRANSLATORS: command description msgid "Erase all firmware update history" msgstr "Esborra tot l'historial de les actualitzacions de microprogramari" @@ -554,13 +686,25 @@ msgstr "Surt després d'un petit retard" msgid "Exit after the engine has loaded" msgstr "Sur una vegada s'hagi carregat el motor" +#. TRANSLATORS: command description +msgid "Extract a firmware blob to images" +msgstr "Extreu un blob de microprogramari en imatges" + +#. TRANSLATORS: Suffix: the fallback HSI result +msgid "Failed" +msgstr "Ha fallat" + +#. TRANSLATORS: dbx file failed to be applied as an update +msgid "Failed to apply update" +msgstr "Ha fallat en aplicar l'actualització" + #. TRANSLATORS: we could not talk to the fwupd daemon msgid "Failed to connect to daemon" msgstr "Ha fallat en connectar amb el dimoni" -#. TRANSLATORS: the server is rate-limiting downloads -msgid "Failed to download due to server limit" -msgstr "La baixada ha fallat a causa del límit del servidor" +#. TRANSLATORS: could not parse file +msgid "Failed to extract local dbx " +msgstr "Ha fallat en extreure una dbx local" #. TRANSLATORS: we could not get the devices to update offline msgid "Failed to get pending devices" @@ -568,12 +712,21 @@ msgstr "Ha fallat en obtenir els dispositius pendents" #. TRANSLATORS: we could not install for some reason msgid "Failed to install firmware update" -msgstr "Ha fallat en instal·lar l’actualització del microprogramari" +msgstr "Ha fallat en instal·lar l'actualització del microprogramari" + +#. TRANSLATORS: could not read existing system data +#. TRANSLATORS: could not read file +msgid "Failed to load local dbx" +msgstr "Ha fallat en carregar una dbx local" #. TRANSLATORS: quirks are device-specific workarounds msgid "Failed to load quirks" msgstr "No s'han pogut carregar les peculiaritats" +#. TRANSLATORS: could not read existing system data +msgid "Failed to load system dbx" +msgstr "Ha fallat en carregar una dbx del sistema" + #. TRANSLATORS: the user didn't read the man page msgid "Failed to parse arguments" msgstr "Ha fallat en analitzar els arguments" @@ -586,6 +739,10 @@ msgstr "Ha fallat en analitzar el fitxer" msgid "Failed to parse flags for --filter" msgstr "Ha fallat en analitzar les etiquetes per a --filter" +#. TRANSLATORS: could not parse file +msgid "Failed to parse local dbx" +msgstr "Ha fallat en analitzar una dbx local" + #. TRANSLATORS: we could not reboot for some reason msgid "Failed to reboot" msgstr "Ha fallat en tornar a arrencar" @@ -594,21 +751,10 @@ msgstr "Ha fallat en tornar a arrencar" msgid "Failed to set splash mode" msgstr "Ha fallat en establir el mode de presentació" -#. TRANSLATORS: downloading unknown file -msgid "Fetching file" -msgstr "S'està obtenint el fitxer" - -#. TRANSLATORS: downloading new firmware file -msgid "Fetching firmware" -msgstr "S'està obtenint el microprogramari" - -#. TRANSLATORS: downloading new metadata file -msgid "Fetching metadata" -msgstr "S'estan obtenint les metadades" - -#. TRANSLATORS: downloading new signing file -msgid "Fetching signature" -msgstr "S'està obtenint la signatura" +#. TRANSLATORS: something with a blocked hash exists +#. * in the users ESP -- which would be bad! +msgid "Failed to validate ESP contents" +msgstr "Ha fallat en validar el contingut ESP" #. TRANSLATORS: filename of the local file msgid "Filename" @@ -618,6 +764,10 @@ msgstr "Nom del fitxer" msgid "Filename Signature" msgstr "Signatura del nom del fitxer" +#. TRANSLATORS: user did not include a filename parameter +msgid "Filename required" +msgstr "El nom del fitxer és obligatori" + #. TRANSLATORS: command line option msgid "Filter with a set of device flags using a ~ prefix to exclude, e.g. 'internal,~needs-reboot'" msgstr "Filtra amb un conjunt d'etiquetes del dispositiu amb un prefix «~» per a excloure, p. ex., «internal,~needs-reboot»" @@ -642,6 +792,22 @@ msgstr "Dimoni per a l'actualització de microprogramari" msgid "Firmware Utility" msgstr "Utilitat per al microprogramari" +#. TRANSLATORS: Title: if we can verify the firmware checksums +msgid "Firmware attestation" +msgstr "Atestat del microprogramari" + +#. TRANSLATORS: system is not booted in UEFI mode +msgid "Firmware can not be updated in legacy BIOS mode" +msgstr "El microprogramari no es pot actualitzar en el mode BIOS heretat" + +#. TRANSLATORS: user selected something not possible +msgid "Firmware is already blocked" +msgstr "El microprogramari ja està bloquejat" + +#. TRANSLATORS: user selected something not possible +msgid "Firmware is not already blocked" +msgstr "El microprogramari ja no està bloquejat" + #. TRANSLATORS: the metadata is very out of date; %u is a number > 1 #, c-format msgid "Firmware metadata has not been updated for %u day and may not be up to date." @@ -649,19 +815,36 @@ msgid_plural "Firmware metadata has not been updated for %u days and may not be msgstr[0] "Les metadades del microprogramari no s'han actualitzat durant %u dia i podria ser que no estiguin actualitzades." msgstr[1] "Les metadades del microprogramari no s'han actualitzat durant %u dies i podria ser que no estiguin actualitzades." +#. TRANSLATORS: Title: if firmware updates are available +msgid "Firmware updates" +msgstr "Actualitzacions del microprogramari" + msgid "Firmware updates are not supported on this machine." msgstr "Les actualitzacions de microprogramari no estan admeses en aquesta màquina." msgid "Firmware updates are supported on this machine." msgstr "Les actualitzacions de microprogramari estan admeses en aquesta màquina." +#. TRANSLATORS: user needs to run a command +msgid "Firmware updates disabled; run 'fwupdmgr unlock' to enable" +msgstr "Actualitzacions de microprogramari inhabilitades: executeu «fwupdmgr unlock» per a habilitar-les" + +#. TRANSLATORS: description of plugin state, e.g. disabled #. TRANSLATORS: release properties msgid "Flags" msgstr "Etiquetes" +#. TRANSLATORS: command line option +msgid "Force the action by relaxing some runtime checks" +msgstr "Força l'acció relaxant algunes comprovacions del temps d'execució" + msgid "Force the action ignoring all warnings" msgstr "Força l'acció ignorant tots els avisos" +#. TRANSLATORS: Suffix: the HSI result +msgid "Found" +msgstr "S'ha trobat" + #. TRANSLATORS: global ID common to all similar hardware msgid "GUID" msgid_plural "GUIDs" @@ -692,9 +875,17 @@ msgstr "Obté la informació sobre un fitxer de microprogramari" msgid "Gets the configured remotes" msgstr "Obtén els remots configurats" +#. TRANSLATORS: command description +msgid "Gets the host security attributes" +msgstr "Obté els atributs de seguretat de l'amfitrió" + #. TRANSLATORS: firmware approved by the admin -msgid "Gets the list of approved firmware." -msgstr "Obtén la llista del microprogramari aprovat." +msgid "Gets the list of approved firmware" +msgstr "Obtén la llista del microprogramari aprovat" + +#. TRANSLATORS: command description +msgid "Gets the list of blocked firmware" +msgstr "Obtén la llista del microprogramari bloquejat" #. TRANSLATORS: command description msgid "Gets the list of updates for connected hardware" @@ -716,6 +907,15 @@ msgstr "El maquinari està esperant a ser endollat" msgid "High" msgstr "Alta" +#. TRANSLATORS: this is a string like 'HSI:2-U' +msgid "Host Security ID:" +msgstr "ID de seguretat de l'amfitrió:" + +#. TRANSLATORS: Title: +#. https://en.wikipedia.org/wiki/Input%E2%80%93output_memory_management_unit +msgid "IOMMU" +msgstr "IOMMU" + #. TRANSLATORS: daemon is inactive msgid "Idle…" msgstr "Està ociós..." @@ -724,10 +924,26 @@ msgstr "Està ociós..." msgid "Ignore SSL strict checks when downloading files" msgstr "Ignora les comprovacions estrictes de SSL quan es baixin els fitxers" +#. TRANSLATORS: command line option +msgid "Ignore firmware checksum failures" +msgstr "Ignora les falles de la suma de comprovació del microprogramari" + +#. TRANSLATORS: command line option +msgid "Ignore firmware hardware mismatch failures" +msgstr "Ignora les falles de discrepància del maquinari del microprogramari" + +#. TRANSLATORS: command line option +msgid "Ignore requirement of external power source" +msgstr "Ignora el requisit de la font d'alimentació externa" + #. TRANSLATORS: Ignore validation safety checks when flashing this device msgid "Ignore validation safety checks" msgstr "Ignora les comprovacions de seguretat de validació" +#. TRANSLATORS: try to help +msgid "Ignoring SSL strict checks, to do this automatically in the future export DISABLE_SSL_STRICT in your environment" +msgstr "S'ignoren les comprovacions estrictes de SSL, per a fer-ho automàticament en el futur, exporteu DISABLE_SSL_STRICT en el vostre entorn" + #. TRANSLATORS: length of time the update takes to apply msgid "Install Duration" msgstr "Durada de la instal·lació" @@ -770,12 +986,59 @@ msgstr "S'està instal·lant l'actualització de microprogramari..." #. TRANSLATORS: %1 is a device name #, c-format msgid "Installing on %s…" -msgstr "S'està intal·lant a %s…" +msgstr "S'està instal·lant a %s…" + +#. TRANSLATORS: Title: BootGuard is a trademark from Intel +msgid "Intel BootGuard" +msgstr "BootGuard d'Intel" + +#. TRANSLATORS: Title: BootGuard is a trademark from Intel, +#. * ACM means to verify the integrity of Initial Boot Block +msgid "Intel BootGuard ACM protected" +msgstr "Protegit amb l'ACM per al BootGuard d'Intel" + +#. TRANSLATORS: Title: BootGuard is a trademark from Intel, +#. * OTP = one time programmable +msgid "Intel BootGuard OTP fuse" +msgstr "Fusible OTP del BootGuard d'Intel" + +#. TRANSLATORS: Title: BootGuard is a trademark from Intel, +#. * error policy is what to do on failure +msgid "Intel BootGuard error policy" +msgstr "Política d'error del BootGuard d'Intel" + +#. TRANSLATORS: Title: BootGuard is a trademark from Intel, +#. * verified boot refers to the way the boot process is verified +msgid "Intel BootGuard verified boot" +msgstr "Arrencada verificada per al BootGuard d'Intel" + +#. TRANSLATORS: Title: CET = Control-flow Enforcement Technology, +#. * active means being used by the OS +msgid "Intel CET Active" +msgstr "CET d'Intel actiu" + +#. TRANSLATORS: Title: CET = Control-flow Enforcement Technology, +#. * enabled means supported by the processor +msgid "Intel CET Enabled" +msgstr "CET d'Intel habilitat" + +#. TRANSLATORS: Title: Direct Connect Interface (DCI) allows +#. * debugging of Intel processors using the USB3 port +msgid "Intel DCI debugger" +msgstr "Depurador DCI d'Intel" + +#. TRANSLATORS: Title: SMAP = Supervisor Mode Access Prevention +msgid "Intel SMAP" +msgstr "SMAP d'Intel" #. TRANSLATORS: Device cannot be removed easily msgid "Internal device" msgstr "Dispositiu intern" +#. TRANSLATORS: Suffix: the HSI result +msgid "Invalid" +msgstr "No vàlid" + #. TRANSLATORS: Is currently in bootloader mode msgid "Is in bootloader mode" msgstr "Està en el mode carregador d'arrencada" @@ -807,6 +1070,22 @@ msgstr "Servei de microprogramari del proveïdor Linux (microprogramari estable) msgid "Linux Vendor Firmware Service (testing firmware)" msgstr "Servei de microprogramari del proveïdor Linux (microprogramari en proves)" +#. TRANSLATORS: Title: if it's tainted or not +msgid "Linux kernel" +msgstr "Nucli Linux" + +#. TRANSLATORS: Title: lockdown is a security mode of the kernel +msgid "Linux kernel lockdown" +msgstr "Bloqueig del nucli Linux" + +#. TRANSLATORS: Title: swap space or swap partition +msgid "Linux swap" +msgstr "Intercanvi de Linux" + +#. TRANSLATORS: command line option +msgid "List entries in dbx" +msgstr "Llista les entrades a la dbx" + #. TRANSLATORS: command line option msgid "List supported firmware updates" msgstr "Llista les actualitzacions de microprogramari compatibles" @@ -815,17 +1094,39 @@ msgstr "Llista les actualitzacions de microprogramari compatibles" msgid "List the available firmware types" msgstr "Llista els tipus de microprogramari disponibles" +#. TRANSLATORS: command description +msgid "Lists files on the ESP" +msgstr "Llista els fitxers en l'ESP" + #. TRANSLATORS: parsing the firmware information msgid "Loading…" msgstr "S'està carregant..." +#. TRANSLATORS: Suffix: the HSI result +msgid "Locked" +msgstr "Blocada" + #. TRANSLATORS: the release urgency msgid "Low" msgstr "Baixa" +#. TRANSLATORS: Title: MEI = Intel Management Engine +msgid "MEI manufacturing mode" +msgstr "Mode de fabricació MEI" + +#. TRANSLATORS: Title: MEI = Intel Management Engine, and the +#. * "override" is the physical PIN that can be driven to +#. * logic high -- luckily it is probably not accessible to +#. * end users on consumer boards +msgid "MEI override" +msgstr "Superposa el MEI" + +msgid "MEI version" +msgstr "Versió del MEI" + #. TRANSLATORS: command line option -msgid "Manually whitelist specific plugins" -msgstr "Connectors especíificats manualment a la llista blanca" +msgid "Manually enable specific plugins" +msgstr "Habilita manualment connectors específics" #. TRANSLATORS: the release urgency msgid "Medium" @@ -853,8 +1154,8 @@ msgid "Mismatched daemon and client, use %s instead" msgstr "El dimoni i el client no coincideixin, useu %s en el seu lloc" #. TRANSLATORS: sets something in daemon.conf -msgid "Modifies a daemon configuration value." -msgstr "Modifica un valor de la configuració del dimoni." +msgid "Modifies a daemon configuration value" +msgstr "Modifica un valor de la configuració del dimoni" #. TRANSLATORS: command description msgid "Modifies a given remote" @@ -868,7 +1169,11 @@ msgstr "Modifica la configuració del dimoni" #. TRANSLATORS: command description msgid "Monitor the daemon for events" -msgstr "Monitora el dimoni pels esdeveniments" +msgstr "Monitora el dimoni per als esdeveniments" + +#. TRANSLATORS: command description +msgid "Mounts the ESP" +msgstr "Munta l'ESP" #. TRANSLATORS: Requires a reboot to apply firmware or to reload hardware msgid "Needs a reboot after installation" @@ -882,6 +1187,7 @@ msgstr "Requereix aturar després de la instal·lació" msgid "New version" msgstr "Versió nova" +#. TRANSLATORS: user did not tell the tool what to do msgid "No action specified!" msgstr "No s'ha especificat cap acció!" @@ -917,16 +1223,24 @@ msgstr "No hi ha cap remot disponible" #. TRANSLATORS: nothing was updated offline msgid "No updates were applied" -msgstr "No s’han aplicat les actualitzacions" +msgstr "No s'han aplicat les actualitzacions" + +#. TRANSLATORS: Suffix: the HSI result +msgid "Not found" +msgstr "No s'ha trobat" + +#. TRANSLATORS: Suffix: the HSI result +msgid "Not supported" +msgstr "No admesa" + +#. TRANSLATORS: Suffix: the HSI result +msgid "OK" +msgstr "D'acord" #. TRANSLATORS: command line option msgid "Only show single PCR value" msgstr "Mostra només un únic valor de PCR" -#. TRANSLATORS: command line option -msgid "Override plugin warning" -msgstr "Passa per alt els avisos del connector" - #. TRANSLATORS: command line option msgid "Override the default ESP path" msgstr "Preferència sobre el camí ESP predeterminat" @@ -939,6 +1253,14 @@ msgstr "Anul·la els avisos i força l'acció" msgid "Parse and show details about a firmware file" msgstr "Analitza i mostra els detalls sobre un fitxer de microprogramari" +#. TRANSLATORS: reading new dbx from the update +msgid "Parsing dbx update…" +msgstr "S'està analitzant l'actualització de la dbx..." + +#. TRANSLATORS: reading existing dbx from the system +msgid "Parsing system dbx…" +msgstr "S'està analitzant la dbx del sistema..." + #. TRANSLATORS: remote filename base msgid "Password" msgstr "Contrasenya" @@ -955,6 +1277,10 @@ msgstr "Percentatge completat" msgid "Please enter a number from 0 to %u: " msgstr "Introduïu un número del 0 al %u: " +#. TRANSLATORS: Title: DMA as in https://en.wikipedia.org/wiki/DMA_attack +msgid "Pre-boot DMA protection" +msgstr "Protecció DMA durant la prearrencada" + #. TRANSLATORS: version number of previous firmware msgid "Previous version" msgstr "Versió anterior" @@ -974,7 +1300,7 @@ msgstr "Continuo amb l'enviament?" #. TRANSLATORS: a non-free software license msgid "Proprietary" -msgstr "Proprietari" +msgstr "Propietari" #. TRANSLATORS: command line option msgid "Query for firmware update support" @@ -1003,15 +1329,15 @@ msgstr "S'està llegint..." #. TRANSLATORS: console message when not using plymouth msgid "Rebooting…" -msgstr "S'està tornant a arencar..." +msgstr "S'està tornant a arrencar..." #. TRANSLATORS: command description msgid "Refresh metadata from remote server" msgstr "Refresca les metadades des del servidor remot" #. TRANSLATORS: command description -msgid "Reinstall current firmware on the device." -msgstr "Torna a instal·lar el microprogramari actual al dispositiu." +msgid "Reinstall current firmware on the device" +msgstr "Torna a instal·lar el microprogramari actual en el dispositiu" #. TRANSLATORS: command description msgid "Reinstall firmware on a device" @@ -1045,13 +1371,17 @@ msgstr "URI de l'informe" msgid "Reported to remote server" msgstr "Informat al servidor remot" -#. TRANSLATORS: Must be plugged in to an outlet -msgid "Requires AC power" -msgstr "Requereix una font d'alimentació" +#. TRANSLATORS: the user is using Gentoo/Arch and has screwed something up +msgid "Required efivarfs filesystem was not found" +msgstr "No s'ha trobat el sistema de fitxers «efivarfs» requerit" + +#. TRANSLATORS: not required for this system +msgid "Required hardware was not found" +msgstr "No s'ha trobat el maquinari requerit" #. TRANSLATORS: Requires a bootloader mode to be manually enabled by the user msgid "Requires a bootloader" -msgstr "Requereix un carregador d’arrencada" +msgstr "Requereix un carregador d'arrencada" #. TRANSLATORS: metadata is downloaded from the Internet msgid "Requires internet connection" @@ -1084,13 +1414,29 @@ msgstr "Executa la rutina de neteja de la composició del connector en usar inst msgid "Run the plugin composite prepare routine when using install-blob" msgstr "Executa la rutina de preparació de la composició del connector en usar install-blob" +#. TRANSLATORS: this is the HSI suffix +msgid "Runtime Suffix" +msgstr "Sufix d'execució" + +#. TRANSLATORS: Title: SPI refers to the flash chip in the computer +msgid "SPI BIOS region" +msgstr "regió del BIOS per a l'SPI" + +#. TRANSLATORS: Title: SPI refers to the flash chip in the computer +msgid "SPI lock" +msgstr "Bloca l'SPI" + +#. TRANSLATORS: Title: SPI refers to the flash chip in the computer +msgid "SPI write" +msgstr "Escriu l'SPI" + #. TRANSLATORS: command line option msgid "Save device state into a JSON file between executions" msgstr "Desa l'estat del dispositiu en un fitxer JSON entre les execucions" #. TRANSLATORS: command line option msgid "Schedule installation for next reboot when possible" -msgstr "Planifica la instal·lació per al següent reinici quan sigui posible" +msgstr "Planifica la instal·lació per al següent reinici quan sigui possible" #. TRANSLATORS: scheduling an update to be done on the next boot msgid "Scheduling…" @@ -1100,6 +1446,10 @@ msgstr "Planificació..." msgid "Selected device" msgstr "Dispositiu seleccionat" +#. TRANSLATORS: Volume has been chosen by the user +msgid "Selected volume" +msgstr "Volum seleccionat" + #. TRANSLATORS: serial number of hardware msgid "Serial Number" msgstr "Número de sèrie" @@ -1108,17 +1458,18 @@ msgstr "Número de sèrie" msgid "Set the debugging flag during update" msgstr "Estableix l'indicador de depuració durant l'actualització" +#. TRANSLATORS: firmware approved by the admin msgid "Sets the list of approved firmware" msgstr "Estableix la llista de microprogramari aprovat" -#. TRANSLATORS: firmware approved by the admin -msgid "Sets the list of approved firmware." -msgstr "Estableix la llista del microprogramari aprovat." - #. TRANSLATORS: command description msgid "Share firmware history with the developers" msgstr "Comparteix l'historial de microprogramari amb els desenvolupadors" +#. TRANSLATORS: command line option +msgid "Show all results" +msgstr "Mostra tots els resultats" + #. TRANSLATORS: command line option msgid "Show client and daemon versions" msgstr "Mostra les versions del client i el dimoni" @@ -1151,6 +1502,10 @@ msgstr "Mostra l'historial de les actualitzacions de microprogramari" msgid "Show plugin verbose information" msgstr "Mostra la informació detallada del connector" +#. TRANSLATORS: command line option +msgid "Show the calculated version of the dbx" +msgstr "Mostra la versió calculada de la dbx" + #. TRANSLATORS: command line option msgid "Show the debug log from the last attempted update" msgstr "Mostra el registre de depuració del darrer intent d'actualització" @@ -1188,6 +1543,10 @@ msgstr "Origen" msgid "Specify Vendor/Product ID(s) of DFU device" msgstr "Especifiqueu el proveïdor/ID del producte del dispositiu DFU" +#. TRANSLATORS: command line option +msgid "Specify the dbx database file" +msgstr "Especifica el fitxer de base de dades dbx" + msgid "Specify the number of bytes per USB transfer" msgstr "Especifiqueu el nombre de bytes per a la transferència USB" @@ -1245,10 +1604,42 @@ msgstr "S'han verificat correctament les sumes de verificació del dispositiu" msgid "Summary" msgstr "Resum" +#. TRANSLATORS: Suffix: the HSI result +msgid "Supported" +msgstr "Admesa" + #. TRANSLATORS: Is found in current metadata msgid "Supported on remote server" msgstr "Admès en el servidor remot" +#. TRANSLATORS: Title: a better sleep state +msgid "Suspend-to-idle" +msgstr "Suspensió a inactiu" + +#. TRANSLATORS: Title: sleep state +msgid "Suspend-to-ram" +msgstr "Suspensió a la RAM" + +#. TRANSLATORS: command description +msgid "Switch the firmware branch on the device" +msgstr "Canviar la branca de microprogramari en el dispositiu" + +#. TRANSLATORS: Must be plugged in to an outlet +msgid "System requires external power source" +msgstr "El sistema requereix una font d'alimentació externa" + +#. TRANSLATORS: Title: the PCR is rebuilt from the TPM event log +msgid "TPM PCR0 reconstruction" +msgstr "Reconstrucció PCR0 del TPM" + +#. TRANSLATORS: Title: TPM = Trusted Platform Module +msgid "TPM v2.0" +msgstr "TPM versió 2.0" + +#. TRANSLATORS: Suffix: the HSI result +msgid "Tainted" +msgstr "Contaminada" + msgid "Target" msgstr "Objectiu" @@ -1256,6 +1647,23 @@ msgstr "Objectiu" msgid "The LVFS is a free service that operates as an independent legal entity and has no connection with $OS_RELEASE:NAME$. Your distributor may not have verified any of the firmware updates for compatibility with your system or connected devices. All firmware is provided only by the original equipment manufacturer." msgstr "El LVFS és un servei gratuït que funciona com una entitat legal independent i no té cap vincle amb la $OS_RELEASE:NAME$. És possible que el vostre distribuïdor no hagi verificat cap de les actualitzacions del microprogramari per a la compatibilitat amb el vostre sistema o els dispositius connectats. Tot el microprogramari només és proporcionat pel fabricant original dels equips." +#. TRANSLATORS: this is more background on a security measurement problem +msgid "The TPM PCR0 differs from reconstruction." +msgstr "El PCR0 del TPM difereix de la reconstrucció." + +#. TRANSLATORS: the user is SOL for support... +msgid "The daemon has loaded 3rd party code and is no longer supported by the upstream developers!" +msgstr "El dimoni ha carregat codi de tercers i ja no és admès pels desenvolupadors originals!" + +#. TRANSLATORS: %1 is the firmware vendor, %2 is the device vendor name +#, c-format +msgid "The firmware from %s is not supplied by %s, the hardware vendor." +msgstr "El microprogramari des de %s no és proporcionat per %s, el proveïdor de maquinari." + +#. TRANSLATORS: nothing to show +msgid "There are no blocked firmware files" +msgstr "No hi ha cap fitxer de microprogramari bloquejat." + #. TRANSLATORS: approved firmware has been checked by #. * the domain administrator msgid "There is no approved firmware." @@ -1268,6 +1676,18 @@ msgstr "Aquest programa només pot funcionar correctament com a «root»" msgid "This remote contains firmware which is not embargoed, but is still being tested by the hardware vendor. You should ensure you have a way to manually downgrade the firmware if the firmware update fails." msgstr "Aquest remot conté microprogramari que no està embargat, però encara l'ha de provar el proveïdor del maquinari. Haureu d'assegurar-vos que teniu una manera de desactualitzar manualment el microprogramari si l'actualització del microprogramari no funciona." +#. TRANSLATORS: this is instructions on how to improve the HSI suffix +msgid "This system has HSI runtime issues." +msgstr "Aquest sistema té problemes d'execució HSI." + +#. TRANSLATORS: this is instructions on how to improve the HSI security level +msgid "This system has a low HSI security level." +msgstr "Aquest sistema té un nivell de seguretat HSI baix." + +#. TRANSLATORS: description of dbxtool +msgid "This tool allows an administrator to apply UEFI dbx updates." +msgstr "Aquesta eina permet a un administrador aplicar les actualitzacions des de la dbx UEFI." + #. TRANSLATORS: the user needs to stop playing with stuff msgid "This tool can only be used by the root user" msgstr "Aquesta eina només pot ser usada per l'usuari «root»." @@ -1276,10 +1696,42 @@ msgstr "Aquesta eina només pot ser usada per l'usuari «root»." msgid "Type" msgstr "Tipus" +#. TRANSLATORS: partition refers to something on disk, again, hey Arch users +msgid "UEFI ESP partition not detected or configured" +msgstr "No s'ha detectat o configurat la partició ESP de la UEFI" + #. TRANSLATORS: program name msgid "UEFI Firmware Utility" msgstr "Utilitat per al microprogramari UEFI" +#. TRANSLATORS: capsule updates are an optional BIOS feature +msgid "UEFI capsule updates not available or enabled" +msgstr "Les actualitzacions de la càpsula UEFI no estan disponibles o habilitades" + +#. TRANSLATORS: program name +msgid "UEFI dbx Utility" +msgstr "Utilitat dbx UEFI" + +#. TRANSLATORS: Title: SB is a way of locking down UEFI +msgid "UEFI secure boot" +msgstr "Arrancada segura de la UEFI" + +#. TRANSLATORS: error message +msgid "Unable to connect to service" +msgstr "No s'ha pogut connectar amb el servei" + +#. TRANSLATORS: command description +msgid "Unbind current driver" +msgstr "Desvincula el controlador actual" + +#. TRANSLATORS: we will now offer this firmware to the user +msgid "Unblocking firmware:" +msgstr "Microprogramari desbloquejat:" + +#. TRANSLATORS: Suffix: the HSI result +msgid "Unencrypted" +msgstr "Desencriptada" + #. TRANSLATORS: current daemon status is unknown #. TRANSLATORS: we don't know the license of the update #. TRANSLATORS: unknown release urgency @@ -1293,9 +1745,17 @@ msgstr "Dispositiu desconegut" msgid "Unlock the device to allow access" msgstr "Desbloqueja el dispositiu per a permetre l'accés" +#. TRANSLATORS: Suffix: the HSI result +msgid "Unlocked" +msgstr "Desblocada" + #. TRANSLATORS: command description msgid "Unlocks the device for firmware access" -msgstr "Desbloqueja el dispositiu per accedir al microprogramari" +msgstr "Desbloqueja el dispositiu per a accedir al microprogramari" + +#. TRANSLATORS: command description +msgid "Unmounts the ESP" +msgstr "Desmunta l'ESP" #. TRANSLATORS: command line option msgid "Unset the debugging flag during update" @@ -1306,6 +1766,10 @@ msgstr "No estableixis l'indicador de depuració durant l'actualització" msgid "Unsupported daemon version %s, client version is %s" msgstr "Versió %s no admesa del dimoni, la versió del client és %s" +#. TRANSLATORS: Suffix: the HSI result +msgid "Untainted" +msgstr "Sense contaminar" + #. TRANSLATORS: Device is updatable in this or any other mode msgid "Updatable" msgstr "Actualitzable" @@ -1329,7 +1793,7 @@ msgstr "Actualitza tots els dispositius que coincideixin amb les metadades local #. TRANSLATORS: the server sent the user a small message msgid "Update failure is a known issue, visit this URL for more information:" -msgstr "Que falli en actualitzar és un problema conegut, visiteu aquest URL per obtenir més informació:" +msgstr "Que falli en actualitzar és un problema conegut, visiteu aquest URL per a obtenir més informació:" #. TRANSLATORS: ask the user if we can update the metadata msgid "Update now?" @@ -1354,6 +1818,9 @@ msgstr "Actualitza les metadades emmagatzemades amb el contingut actual" msgid "Updates all firmware to latest versions available" msgstr "Actualitza tot el microprogramari a les versions més recents" +msgid "Updating" +msgstr "S'està actualitzant" + #. TRANSLATORS: the first replacement is a display name #. * e.g. "ColorHugALS" and the second and third are #. * version numbers e.g. "1.2.3" @@ -1372,10 +1839,6 @@ msgstr "S'està actualitzant %s…" msgid "Upgrade available for %s from %s to %s" msgstr "Actualització disponible per a %s des de %s a %s" -#. TRANSLATORS: the server sent the user a small message -msgid "Upload message:" -msgstr "Missatge de l'enviament:" - msgid "Upload report just this one time, but prompt again for future updates" msgid_plural "Upload reports just this one time, but prompt again for future updates" msgstr[0] "Envia l'informe només aquesta vegada, però sol·licita-ho de nou en les futures actualitzacions" @@ -1398,6 +1861,14 @@ msgstr "L'enviament dels informes de microprogramari ajudarà als proveïdors de msgid "Urgency" msgstr "Urgència" +#. TRANSLATORS: error message explaining command to run to how to get help +msgid "Use fwupdmgr --help for help" +msgstr "Empreu «fwupdmgr --help» per a l'ajuda" + +#. TRANSLATORS: error message explaining command to run to how to get help +msgid "Use fwupdtool --help for help" +msgstr "Empreu «fwupdtool --help» per a l'ajuda" + #. TRANSLATORS: command line option msgid "Use quirk flags when installing firmware" msgstr "Usa les etiquetes peculiars en instal·lar el microprogramari" @@ -1410,6 +1881,14 @@ msgstr "S'ha notificat a l'usuari" msgid "Username" msgstr "Nom d'usuari" +#. TRANSLATORS: Suffix: the HSI result +msgid "Valid" +msgstr "Vàlid" + +#. TRANSLATORS: ESP refers to the EFI System Partition +msgid "Validating ESP contents…" +msgstr "S'està validant el contingut ESP..." + #. TRANSLATORS: one line variant of release (e.g. 'Prerelease' or 'China') msgid "Variant" msgstr "Variant" @@ -1422,9 +1901,13 @@ msgstr "Venedor" msgid "Verifying…" msgstr "S'està verificant..." -#. TRANSLATORS: try to help -msgid "WARNING: Ignoring SSL strict checks, to do this automatically in the future export DISABLE_SSL_STRICT in your environment" -msgstr "AVÍS: S'ignoren les comprovacions estrictes de SSL. Per a fer-ho automàticament en el futur, exporteu DISABLE_SSL_STRICT en el vostre entorn" +#. TRANSLATORS: the detected version number of the dbx +msgid "Version" +msgstr "Versió:" + +#. TRANSLATORS: this is a prefix on the console +msgid "WARNING:" +msgstr "AVÍS:" #. TRANSLATORS: waiting for device to do something msgid "Waiting…" @@ -1446,6 +1929,10 @@ msgstr "Escriu el microprogramari des d'un fitxer a dins del dispositiu" msgid "Write firmware from file into one partition" msgstr "Escriu el microprogramari des d'un fitxer a dins d'una partició" +#. TRANSLATORS: decompressing images from a container firmware +msgid "Writing file:" +msgstr "Fitxer d'escriptura:" + #. TRANSLATORS: writing to the flash chips msgid "Writing…" msgstr "S'està escrivint..." @@ -1454,19 +1941,19 @@ msgstr "S'està escrivint..." msgid "Your distributor may not have verified any of the firmware updates for compatibility with your system or connected devices." msgstr "És possible que el vostre distribuïdor no hagi verificat cap de les actualitzacions del microprogramari per a la compatibilitat amb el vostre sistema o els dispositius connectats." +#. TRANSLATORS: %1 is the device vendor name +#, c-format +msgid "Your hardware may be damaged using this firmware, and installing this release may void any warranty with %s." +msgstr "El vostre maquinari pot danyar-se amb aquest microprogramari, i la instal·lació d'aquesta versió pot anul·lar qualsevol garantia amb %s." + +#. TRANSLATORS: this is the default branch name when unset +msgid "default" +msgstr "predeterminat" + #. TRANSLATORS: program name msgid "fwupd TPM event log utility" -msgstr "Utilitat per al registre d’esdeveniments TPM del fwupd" +msgstr "Utilitat per al registre d'esdeveniments TPM del fwupd" -#. TRANSLATORS: message letting the user know no device upgrade available due -#. to missing on LVFS -#. * %1 is the device name -#, c-format -msgid "• %s has no available firmware updates" -msgstr "• %s no té disponible cap actualització de microprogramari" - -#. TRANSLATORS: message letting the user know no device upgrade available -#. * %1 is the device name -#, c-format -msgid "• %s has the latest available firmware version" -msgstr "• %s té disponible la darrera versió del microprogramari" +#. TRANSLATORS: Title: if the fwupd plugins are all present and correct +msgid "fwupd plugins" +msgstr "Connectors del «fwupd»" diff --git a/po/cs.po b/po/cs.po index d10b6ebef..d36cce475 100644 --- a/po/cs.po +++ b/po/cs.po @@ -6,6 +6,7 @@ # Ascii Wolf , 2017,2019-2020 # Ascii Wolf , 2017 # Marek Černocký , 2016,2018 +# Pavel Borecki , 2020 msgid "" msgstr "" "Project-Id-Version: fwupd\n" @@ -26,6 +27,128 @@ msgstr[1] "Zbývají %.0f minuty" msgstr[2] "Zbývá %.0f minut" msgstr[3] "Zbývá %.0f minuty" +#. TRANSLATORS: the CPU microcode is firmware loaded onto the CPU +#. * at system bootup +#, c-format +msgid "%s CPU Microcode Update" +msgstr "Aktualizace mikrokódu procesoru %s" + +#. TRANSLATORS: a specific part of hardware, +#. * the first %s is the device name, e.g. 'Secure Boot` +#, c-format +msgid "%s Configuration Update" +msgstr "Aktualizace nastavení %s" + +#. TRANSLATORS: ME stands for Management Engine, where +#. * the first %s is the device name, e.g. 'ThinkPad P50` +#, c-format +msgid "%s Consumer ME Update" +msgstr "Aktualizace spotřebitelského ME v %s" + +#. TRANSLATORS: the controller is a device that has other devices +#. * plugged into it, for example ThunderBolt, FireWire or USB, +#. * the first %s is the device name, e.g. 'Intel ThunderBolt` +#, c-format +msgid "%s Controller Update" +msgstr "Aktualizace řadiče %s" + +#. TRANSLATORS: ME stands for Management Engine (with Intel AMT), +#. * where the first %s is the device name, e.g. 'ThinkPad P50` +#, c-format +msgid "%s Corporate ME Update" +msgstr "Aktualizace korporátního ME v %s" + +#. TRANSLATORS: a specific part of hardware, +#. * the first %s is the device name, e.g. 'Unifying Receiver` +#, c-format +msgid "%s Device Update" +msgstr "Aktualizace zařízení %s" + +#. TRANSLATORS: the EC is typically the keyboard controller chip, +#. * the first %s is the device name, e.g. 'ThinkPad P50` +#, c-format +msgid "%s Embedded Controller Update" +msgstr "Aktualizace vestavěného řadiče v %s" + +#. TRANSLATORS: ME stands for Management Engine, the Intel AMT thing, +#. * the first %s is the device name, e.g. 'ThinkPad P50` +#, c-format +msgid "%s ME Update" +msgstr "Aktualizace ME v %s" + +#. TRANSLATORS: the entire system, e.g. all internal devices, +#. * the first %s is the device name, e.g. 'ThinkPad P50` +#, c-format +msgid "%s System Update" +msgstr "Celková aktualizace %s" + +#. TRANSLATORS: the Thunderbolt controller is a device that +#. * has other high speed Thunderbolt devices plugged into it; +#. * the first %s is the system name, e.g. 'ThinkPad P50` +#, c-format +msgid "%s Thunderbolt Controller Update" +msgstr "Aktualizace řadiče Thunderbolt %s" + +#. TRANSLATORS: this is the fallback where we don't know if the release +#. * is updating the system, the device, or a device class, or something else +#. -- +#. * the first %s is the device name, e.g. 'ThinkPad P50` +#, c-format +msgid "%s Update" +msgstr "Aktualizace %s" + +#. TRANSLATORS: Title: %s is ME kind, e.g. CSME/TXT +#, c-format +msgid "%s manufacturing mode" +msgstr "režim pro výrobce v %s" + +#. TRANSLATORS: Title: %s is ME kind, e.g. CSME/TXT +#, c-format +msgid "%s override" +msgstr "přebití %s" + +#. TRANSLATORS: Title: %1 is ME kind, e.g. CSME/TXT, %2 is a version number +#, c-format +msgid "%s v%s" +msgstr "%s verze %s" + +#. TRANSLATORS: Title: %s is ME kind, e.g. CSME/TXT +#, c-format +msgid "%s version" +msgstr "Verze %s" + +#, c-format +msgid "%u device has a firmware upgrade available." +msgid_plural "%u devices have a firmware upgrade available." +msgstr[0] "Je k dispozici novější firmware pro %u zařízení." +msgstr[1] "Jsou k dispozici novější firmware pro %u zařízení." +msgstr[2] "Jsou k dispozici novější firmware pro %u zařízení." +msgstr[3] "Jsou k dispozici novější firmware pro %u zařízení." + +#. TRANSLATORS: duration in seconds +#, c-format +msgid "%u second" +msgid_plural "%u seconds" +msgstr[0] "%u sekunda" +msgstr[1] "%u sekundy" +msgstr[2] "%u sekund" +msgstr[3] "%u sekundy" + +#. TRANSLATORS: command description +msgid "Activate pending devices" +msgstr "Aktivovat čekající zařízení" + +msgid "Activate the new firmware on the device" +msgstr "Aktivovat nový firmware na zařízení" + +#. TRANSLATORS: shown when shutting down to switch to the new version +msgid "Activating firmware update" +msgstr "Aktivování aktualizace firmware" + +#. TRANSLATORS: shown when shutting down to switch to the new version +msgid "Activating firmware update for" +msgstr "Aktivace aktualizovaného firmware pro" + #. TRANSLATORS: this is when a device is hotplugged msgid "Added" msgstr "Přidáno" @@ -51,10 +174,18 @@ msgstr "Povolit přechod na nižší verze firmwaru" msgid "Allow reinstalling existing firmware versions" msgstr "Povolit reinstalaci stávající verze firmwaru" +#. TRANSLATORS: command line option +msgid "Allow switching firmware branch" +msgstr "Umožnit přepnutí varianty firmware" + #. TRANSLATORS: explain why we want to reboot msgid "An update requires a reboot to complete." msgstr "Některá z aktualizací vyžaduje pro dokončení restart." +#. TRANSLATORS: explain why we want to shutdown +msgid "An update requires the system to shutdown to complete." +msgstr "Pro dokončení aktualizace je zapotřebí vypnutí počítače." + #. TRANSLATORS: command line option msgid "Answer yes to all questions" msgstr "Na všechny dotazy odpovědět ano" @@ -63,6 +194,31 @@ msgstr "Na všechny dotazy odpovědět ano" msgid "Apply firmware updates" msgstr "Použít aktualizace firmwaru" +#. TRANSLATORS: command line option +msgid "Apply update even when not advised" +msgstr "Použít aktualizaci i když to není doporučeno" + +#. TRANSLATORS: command line option +msgid "Apply update files" +msgstr "Použít soubory s aktualizací" + +#. TRANSLATORS: actually sending the update to the hardware +msgid "Applying update…" +msgstr "Provádění aktualizace…" + +#. TRANSLATORS: approved firmware has been checked by +#. * the domain administrator +msgid "Approved firmware:" +msgid_plural "Approved firmware:" +msgstr[0] "Schválený firmware:" +msgstr[1] "Schválené firmwary:" +msgstr[2] "Schválených firmwarů:" +msgstr[3] "Schválené firmwary:" + +#. TRANSLATORS: stop nagging the user +msgid "Ask again next time?" +msgstr "Ptát se i příště?" + #. TRANSLATORS: command description msgid "Attach to firmware mode" msgstr "Napojit do režimu firmwaru" @@ -83,6 +239,18 @@ msgstr "K přechodu na nižší verzi firmwaru na tomto počítači je vyžadov msgid "Authentication is required to modify a configured remote used for firmware updates" msgstr "Ke změně nastaveného vzdáleného zdroje, který se používá pro aktualizace firmwaru, je vyžadováno ověření" +#. TRANSLATORS: this is the PolicyKit modal dialog +msgid "Authentication is required to modify daemon configuration" +msgstr "Ke změně nastavení procesu služby je vyžadováno ověření se" + +#. TRANSLATORS: this is the PolicyKit modal dialog +msgid "Authentication is required to set the list of approved firmware" +msgstr "Pro nastavení seznamu schválených firmwarů je vyžadováno ověření se" + +#. TRANSLATORS: this is the PolicyKit modal dialog +msgid "Authentication is required to switch to the new firmware version" +msgstr "Pro přepnutí na novou verzi firmware je vyžadováno ověření se" + #. TRANSLATORS: this is the PolicyKit modal dialog msgid "Authentication is required to unlock a device" msgstr "Pro odemknutí zařízení je požadováno ověření" @@ -99,6 +267,22 @@ msgstr "K aktualizaci firmwaru na tomto počítači je vyžadováno ověření" msgid "Authentication is required to update the stored checksums for the device" msgstr "K aktualizaci uložených kontrolních součtů zařízení je vyžadováno ověření" +#. TRANSLATORS: can we JFDI? +msgid "Automatically upload every time?" +msgstr "Pokaždé automaticky nahrát?" + +#. TRANSLATORS: command description +msgid "Bind new kernel driver" +msgstr "Napojit nový ovladač jádra" + +#. TRANSLATORS: we will not offer this firmware to the user +msgid "Blocking firmware:" +msgstr "Blokuje se firmware:" + +#. TRANSLATORS: command description +msgid "Build a firmware file" +msgstr "Sestavit soubor s firmware" + #. TRANSLATORS: command description msgid "Build firmware using a sandbox" msgstr "Sestavit firmware za použití izolovaného prostředí" @@ -111,6 +295,14 @@ msgstr "Zrušit" msgid "Cancelled" msgstr "Zrušeno" +#. TRANSLATORS: same or newer update already applied +msgid "Cannot apply as dbx update has already been applied." +msgstr "Tuto aktualizaci dbx už není možné použít, protože už je používána." + +#. TRANSLATORS: the user is using a LiveCD or LiveUSB install disk +msgid "Cannot apply updates on live media" +msgstr "Aktualizace není možné použít při provozování systému z instalačního média (live)" + #. TRANSLATORS: this is when a device is hotplugged #. TRANSLATORS: this is when the daemon state changes msgid "Changed" @@ -120,14 +312,27 @@ msgstr "Změněno" msgid "Checksum" msgstr "Kontrolní součet" +#. TRANSLATORS: get interactive prompt, where branch is the +#. * supplier of the firmware, e.g. "non-free" or "free" +msgid "Choose a branch:" +msgstr "Zvolte variantu firmware:" + #. TRANSLATORS: get interactive prompt msgid "Choose a device:" msgstr "Vyberte zařízení:" +#. TRANSLATORS: get interactive prompt +msgid "Choose a firmware type:" +msgstr "Zvolte typ firmware:" + #. TRANSLATORS: get interactive prompt msgid "Choose a release:" msgstr "Vyberte verzi:" +#. TRANSLATORS: get interactive prompt +msgid "Choose a volume:" +msgstr "Zvolte svazek:" + #. TRANSLATORS: command description msgid "Clears any updates scheduled to be updated offline" msgstr "Smazat vše naplánované pro aktualizaci při odpojení" @@ -140,6 +345,14 @@ msgstr "Smazat výsledky z poslední aktualizace" msgid "Command not found" msgstr "Příkaz nebyl nalezen" +#. TRANSLATORS: prompt to apply the update +msgid "Continue with update?" +msgstr "Pokračovat v aktualizaci?" + +#. TRANSLATORS: command description +msgid "Convert a firmware file" +msgstr "Převést soubor s firmware" + #. TRANSLATORS: DFU stands for device firmware update msgid "DFU Utility" msgstr "Nástroj pro práci s DFU" @@ -180,6 +393,15 @@ msgstr "Zařízení, která byla úspěšně aktualizována:" msgid "Devices that were not updated correctly:" msgstr "Zařízení, která nebyla úspěšně aktualizována:" +#. TRANSLATORS: message letting the user know no device upgrade available due +#. to missing on LVFS +msgid "Devices with no available firmware updates: " +msgstr "Zařízení, ke kterém nejsou k dispozici aktualizace firmware:" + +#. TRANSLATORS: message letting the user know no device upgrade available +msgid "Devices with the latest available firmware version:" +msgstr "Zařízení s nejnovějšími dostupnými verzemi firmware:" + msgid "Disabled fwupdate debugging" msgstr "Vypnout ladění fwupdate" @@ -203,10 +425,23 @@ msgstr "Nekontrolovat restart po aktualizaci" msgid "Do not check for unreported history" msgstr "Nekontrolovat nenahlášení historie" +#. TRANSLATORS: turn on all debugging +msgid "Do not include log domain prefix" +msgstr "Nepřidávat dlouhou příponu oblasti" + +#. TRANSLATORS: turn on all debugging +msgid "Do not include timestamp prefix" +msgstr "Nepřidávat příponu s datem a časem" + +#. TRANSLATORS: command line option +msgid "Do not perform device safety checks" +msgstr "Neprovádět kontroly bezpečnosti zařízení" + #. TRANSLATORS: command line option msgid "Do not write to the history database" msgstr "Nezapisovat do databáze historie" +#. TRANSLATORS: success #. success msgid "Done!" msgstr "Hotovo!" @@ -242,6 +477,8 @@ msgstr "Povolit podporu aktualizace firmwaru na podporovaných systémech" msgid "Enable this remote?" msgstr "Povolit tento vzdálený zdroj?" +#. TRANSLATORS: Suffix: the HSI result +#. TRANSLATORS: Plugin is active and in use #. TRANSLATORS: if the remote is enabled msgid "Enabled" msgstr "Povoleno" @@ -260,6 +497,14 @@ msgstr "Zapnutí této funkcionality je na vaše vlastní riziko, což znamená, msgid "Enabling this remote is done at your own risk." msgstr "Povolení tohoto zdroje je na vaše vlastní riziko." +#. TRANSLATORS: Suffix: the HSI result +msgid "Encrypted" +msgstr "Šifrované" + +#. TRANSLATORS: Title: Memory contents are encrypted, e.g. Intel TME +msgid "Encrypted RAM" +msgstr "Šifrovaná RAM" + #. TRANSLATORS: command description msgid "Erase all firmware update history" msgstr "Smazat veškerou historii aktualizací" @@ -276,33 +521,67 @@ msgstr "Skončit po krátké prodlevě" msgid "Exit after the engine has loaded" msgstr "Skončit po načtení výkonné části" -#. TRANSLATORS: the server is rate-limiting downloads -msgid "Failed to download due to server limit" -msgstr "Nezdařilo se stáhnout kvůli omezením serveru" +#. TRANSLATORS: Suffix: the fallback HSI result +msgid "Failed" +msgstr "Nezdařilo se" + +#. TRANSLATORS: dbx file failed to be applied as an update +msgid "Failed to apply update" +msgstr "Aktualizaci se nepodařilo provést" + +#. TRANSLATORS: we could not talk to the fwupd daemon +msgid "Failed to connect to daemon" +msgstr "Nepodařilo se spojit s procesem služby" + +#. TRANSLATORS: could not parse file +msgid "Failed to extract local dbx " +msgstr "Nepodařilo se rozbalit místní dbx" + +#. TRANSLATORS: we could not get the devices to update offline +msgid "Failed to get pending devices" +msgstr "Nepodařilo se získat čekající zařízení" + +#. TRANSLATORS: we could not install for some reason +msgid "Failed to install firmware update" +msgstr "Aktualizaci firmware se nepodařilo nainstalovat" + +#. TRANSLATORS: could not read existing system data +#. TRANSLATORS: could not read file +msgid "Failed to load local dbx" +msgstr "Nepodařilo se načíst místní dbx" #. TRANSLATORS: quirks are device-specific workarounds msgid "Failed to load quirks" msgstr "Selhalo načtení zvláštních požadavků" +#. TRANSLATORS: could not read existing system data +msgid "Failed to load system dbx" +msgstr "Nepodařilo se načíst systémové dbx" + #. TRANSLATORS: the user didn't read the man page msgid "Failed to parse arguments" msgstr "Selhalo zpracování argumentů" -#. TRANSLATORS: downloading unknown file -msgid "Fetching file" -msgstr "Stahuje se soubor" +#. TRANSLATORS: failed to read measurements file +msgid "Failed to parse file" +msgstr "Soubor se nepodařilo zpracovat" -#. TRANSLATORS: downloading new firmware file -msgid "Fetching firmware" -msgstr "Stahuje se firmware" +#. TRANSLATORS: could not parse file +msgid "Failed to parse local dbx" +msgstr "Nepodařilo se zpracovat místní dbx" -#. TRANSLATORS: downloading new metadata file -msgid "Fetching metadata" -msgstr "Stahují se metadata" +#. TRANSLATORS: we could not reboot for some reason +msgid "Failed to reboot" +msgstr "Nepodařilo se restartovat" -#. TRANSLATORS: downloading new signing file -msgid "Fetching signature" -msgstr "Stahuje se podpis" +#. TRANSLATORS: we could not talk to plymouth +msgid "Failed to set splash mode" +msgstr "Nepodařilo se nastavit režim startovací obrazovky" + +#. TRANSLATORS: something with a blocked hash exists +#. * in the users ESP -- which would be bad! +msgid "Failed to validate ESP contents" +msgstr "Nepodařilo se ověřit obsah ESP oddílu" #. TRANSLATORS: filename of the local file msgid "Filename" @@ -312,6 +591,10 @@ msgstr "Název souboru" msgid "Filename Signature" msgstr "Podpis názvu souboru" +#. TRANSLATORS: user did not include a filename parameter +msgid "Filename required" +msgstr "Je zapotřebí zadat název souboru" + #. TRANSLATORS: remote URI msgid "Firmware Base URI" msgstr "Základní URI firmwaru" @@ -328,6 +611,18 @@ msgstr "Démon pro aktualizaci firmwaru" msgid "Firmware Utility" msgstr "Nástroj pro práci s firmwarem" +#. TRANSLATORS: Title: if we can verify the firmware checksums +msgid "Firmware attestation" +msgstr "Atestace firmware" + +#. TRANSLATORS: user selected something not possible +msgid "Firmware is already blocked" +msgstr "Firmware už je blokován" + +#. TRANSLATORS: user selected something not possible +msgid "Firmware is not already blocked" +msgstr "Firmware ještě není blokován" + #. TRANSLATORS: the metadata is very out of date; %u is a number > 1 #, c-format msgid "Firmware metadata has not been updated for %u day and may not be up to date." @@ -337,12 +632,35 @@ msgstr[1] "Metadata firmwaru nebyla akualizována již %u dny a nelze je aktuali msgstr[2] "Metadata firmwaru nebyla akualizována již %u dní a nelze je aktualizovat." msgstr[3] "Metadata firmwaru nebyla akualizována již %u dne a nelze je aktualizovat." +#. TRANSLATORS: Title: if firmware updates are available +msgid "Firmware updates" +msgstr "Aktualizace firmware" + msgid "Firmware updates are not supported on this machine." msgstr "Aktualizace firmwaru nejsou na tomto počítači podporované." msgid "Firmware updates are supported on this machine." msgstr "Aktualizace firmwaru jsou na tomto počítači podporované." +#. TRANSLATORS: command line option +msgid "Force the action by relaxing some runtime checks" +msgstr "Vynutit akci uvolněním některých kontrol při vykonávání" + +msgid "Force the action ignoring all warnings" +msgstr "Vynutit, aby při akci byla ignorována všechna varování" + +#. TRANSLATORS: Suffix: the HSI result +msgid "Found" +msgstr "Nalezeno" + +#. TRANSLATORS: command description +msgid "Get all device flags supported by fwupd" +msgstr "Získat všechny příznaky zařízení podporované fwupd" + +#. TRANSLATORS: command description +msgid "Get all devices and possible releases" +msgstr "Zjistit všechna zařízení a vydání, která jsou možná" + #. TRANSLATORS: command description msgid "Get all devices that support firmware updates" msgstr "Zjistit všechna zařízení podporující aktualizaci firmwaru" @@ -359,6 +677,10 @@ msgstr "Zjistit podrobnosti o souboru s firmwarem" msgid "Gets the configured remotes" msgstr "Vypsat nastavené vzdálené zdroje" +#. TRANSLATORS: command description +msgid "Gets the host security attributes" +msgstr "Zjistit atributy zabezpečení hostitele" + #. TRANSLATORS: command description msgid "Gets the list of updates for connected hardware" msgstr "Vypsat seznam aktualizací pro připojený hardware" @@ -371,10 +693,35 @@ msgstr "Vypsat vydání pro zařízení" msgid "Gets the results from the last update" msgstr "Vypsat výsledky z poslední aktualizace" +#. TRANSLATORS: this is a string like 'HSI:2-U' +msgid "Host Security ID:" +msgstr "Identifikátor zabezpečení hostitele:" + +#. TRANSLATORS: Title: +#. https://en.wikipedia.org/wiki/Input%E2%80%93output_memory_management_unit +msgid "IOMMU" +msgstr "IOMMU" + #. TRANSLATORS: daemon is inactive msgid "Idle…" msgstr "Nečinný…" +#. TRANSLATORS: command line option +msgid "Ignore SSL strict checks when downloading files" +msgstr "Při stahování souborů ignorovat některé nedostatky SSL certifikátů" + +#. TRANSLATORS: command line option +msgid "Ignore firmware checksum failures" +msgstr "Ignorovat nesprávný kontrolní součet firmware" + +#. TRANSLATORS: command line option +msgid "Ignore firmware hardware mismatch failures" +msgstr "Ignorovat neshody firmware s hardware" + +#. TRANSLATORS: command line option +msgid "Ignore requirement of external power source" +msgstr "Ignorovat požadavek na přítomnost externího napájení" + #. TRANSLATORS: command description msgid "Install a firmware blob on a device" msgstr "Nainstalovat na zařízení binární soubor s firmwarem" @@ -398,6 +745,10 @@ msgstr "Instalace nepodepsaného firmwaru zařízení" msgid "Install unsigned system firmware" msgstr "Instalace nepodepsaného systémového firmwaru" +#. TRANSLATORS: console message when no Plymouth is installed +msgid "Installing Firmware…" +msgstr "Instalace firmware…" + #. TRANSLATORS: this is shown when updating the firmware after the reboot msgid "Installing firmware update…" msgstr "Instaluje se aktualizace firmwaru…" @@ -407,6 +758,43 @@ msgstr "Instaluje se aktualizace firmwaru…" msgid "Installing on %s…" msgstr "Instaluje se na zařízení %s…" +#. TRANSLATORS: Title: BootGuard is a trademark from Intel +msgid "Intel BootGuard" +msgstr "Intel BootGuard" + +#. TRANSLATORS: Title: BootGuard is a trademark from Intel, +#. * error policy is what to do on failure +msgid "Intel BootGuard error policy" +msgstr "Co Intel BootGuard udělá v případě chyb" + +#. TRANSLATORS: Title: BootGuard is a trademark from Intel, +#. * verified boot refers to the way the boot process is verified +msgid "Intel BootGuard verified boot" +msgstr "Ověřené zavádění s Intel BootGuard" + +#. TRANSLATORS: Title: CET = Control-flow Enforcement Technology, +#. * active means being used by the OS +msgid "Intel CET Active" +msgstr "Intel CET aktivní" + +#. TRANSLATORS: Title: CET = Control-flow Enforcement Technology, +#. * enabled means supported by the processor +msgid "Intel CET Enabled" +msgstr "Intel CET podporováno" + +#. TRANSLATORS: Title: Direct Connect Interface (DCI) allows +#. * debugging of Intel processors using the USB3 port +msgid "Intel DCI debugger" +msgstr "Ladící nástroj Intel DCI" + +#. TRANSLATORS: Title: SMAP = Supervisor Mode Access Prevention +msgid "Intel SMAP" +msgstr "Intel SMAP" + +#. TRANSLATORS: Suffix: the HSI result +msgid "Invalid" +msgstr "Neplatné" + msgid "Keyring" msgstr "Klíčenka" @@ -420,6 +808,22 @@ msgstr "Linux Vendor Firmware Service (stabilní firmware)" msgid "Linux Vendor Firmware Service (testing firmware)" msgstr "Linux Vendor Firmware Service (testovací firmware)" +#. TRANSLATORS: Title: if it's tainted or not +msgid "Linux kernel" +msgstr "Linuxové jádro" + +#. TRANSLATORS: Title: lockdown is a security mode of the kernel +msgid "Linux kernel lockdown" +msgstr "Uzamčení linuxového jádra" + +#. TRANSLATORS: Title: swap space or swap partition +msgid "Linux swap" +msgstr "Linuxový odkládací prostor" + +#. TRANSLATORS: command line option +msgid "List entries in dbx" +msgstr "Vypsat položky v dbx" + #. TRANSLATORS: command line option msgid "List supported firmware updates" msgstr "Vypsat podporované aktualizace firmwarů" @@ -428,9 +832,16 @@ msgstr "Vypsat podporované aktualizace firmwarů" msgid "Loading…" msgstr "Načítá se…" +#. TRANSLATORS: Suffix: the HSI result +msgid "Locked" +msgstr "Zamčeno" + +msgid "MEI version" +msgstr "Verze MEI" + #. TRANSLATORS: command line option -msgid "Manually whitelist specific plugins" -msgstr "Ručně povolit konkrétní zásuvné moduly" +msgid "Manually enable specific plugins" +msgstr "Ručně zapnout konkrétní zásuvné moduly" #. TRANSLATORS: remote URI msgid "Metadata URI" @@ -447,13 +858,27 @@ msgstr "Změnit zadaný vzdálený zdroj" msgid "Modify a configured remote" msgstr "Upravit nastavený vzdálený zdroj" +msgid "Modify daemon configuration" +msgstr "Upravit nastavení procesu služby" + #. TRANSLATORS: command description msgid "Monitor the daemon for events" msgstr "Sledovat události démona" +#. TRANSLATORS: user did not tell the tool what to do msgid "No action specified!" msgstr "Není určena žádné akce!" +#. TRANSLATORS: message letting the user know no device downgrade available +#. * %1 is the device name +#, c-format +msgid "No downgrades for %s" +msgstr "Pro %s nejsou k dispozici žádné starší verze" + +#. TRANSLATORS: nothing found +msgid "No firmware IDs found" +msgstr "Nenalezeny žádné identifikátory firmware" + #. TRANSLATORS: nothing attached that can be upgraded msgid "No hardware detected with firmware update capability" msgstr "Nebylo nalezeno žádné zařízení schopné aktualizace firmwaru" @@ -466,14 +891,46 @@ msgstr "Nebyl nalezen žádný zásuvný modul" msgid "No remotes are currently enabled so no metadata is available." msgstr "Zrovna nejsou povolené žádné vzdálené zdroje, takže nejsou k dispozici žádná metadata." +#. TRANSLATORS: nothing was updated offline +msgid "No updates were applied" +msgstr "Nebyly nainstalovány žádné aktualizace" + +#. TRANSLATORS: Suffix: the HSI result +msgid "Not found" +msgstr "Nenalezeno" + +#. TRANSLATORS: Suffix: the HSI result +msgid "Not supported" +msgstr "Nepodporováno" + +#. TRANSLATORS: Suffix: the HSI result +msgid "OK" +msgstr "V pořádku" + #. TRANSLATORS: command line option -msgid "Override plugin warning" -msgstr "Potlačit varování zásuvného modulu" +msgid "Only show single PCR value" +msgstr "Zobrazit pouze jedinou PCR hodnotu" #. TRANSLATORS: command line option msgid "Override the default ESP path" msgstr "Přepsat výchozí cestu ESP" +#. TRANSLATORS: command line option +msgid "Override warnings and force the action" +msgstr "Přebít varování a vynutit akci" + +#. TRANSLATORS: command description +msgid "Parse and show details about a firmware file" +msgstr "Zpracovat a zobrazit podrobnosti o souboru s firmware" + +#. TRANSLATORS: reading new dbx from the update +msgid "Parsing dbx update…" +msgstr "Zpracovávání aktualizace dbx…" + +#. TRANSLATORS: reading existing dbx from the system +msgid "Parsing system dbx…" +msgstr "Zpracovávání systémového dbx…" + #. TRANSLATORS: remote filename base msgid "Password" msgstr "Heslo" @@ -481,11 +938,25 @@ msgstr "Heslo" msgid "Payload" msgstr "Obsah" +#. TRANSLATORS: console message when not using plymouth +msgid "Percentage complete" +msgstr "Dokončeno procent" + #. TRANSLATORS: the user isn't reading the question #, c-format msgid "Please enter a number from 0 to %u: " msgstr "Zadejte prosím číslo od 0 do %u:" +#. TRANSLATORS: Title: DMA as in https://en.wikipedia.org/wiki/DMA_attack +msgid "Pre-boot DMA protection" +msgstr "Ochrana přímého přístupu do paměti před startem operačního systému" + +msgid "Print the version number" +msgstr "Vypsat číslo verze" + +msgid "Print verbose debug statements" +msgstr "Vypsat podrobná ladící hlášení" + #. TRANSLATORS: the numeric priority msgid "Priority" msgstr "Priorita" @@ -497,6 +968,10 @@ msgstr "Pokračovat v nahrávání?" msgid "Query for firmware update support" msgstr "Dotázat se na podporu aktualizace firmwaru" +#. TRANSLATORS: command description +msgid "Read a firmware blob from a device" +msgstr "Načíst blob firmware ze zařízení" + #. TRANSLATORS: command description msgid "Read firmware from device into a file" msgstr "Přečíst firmware ze zařízení do souboru" @@ -505,10 +980,19 @@ msgstr "Přečíst firmware ze zařízení do souboru" msgid "Read firmware from one partition into a file" msgstr "Přečíst firmware z jednoho oddílu do souboru" +#. TRANSLATORS: %1 is a device name +#, c-format +msgid "Reading from %s…" +msgstr "Načítání z %s…" + #. TRANSLATORS: reading from the flash chips msgid "Reading…" msgstr "Čte se…" +#. TRANSLATORS: console message when not using plymouth +msgid "Rebooting…" +msgstr "Restartování…" + #. TRANSLATORS: command description msgid "Refresh metadata from remote server" msgstr "Aktualizovat metadata ze vzdáleného serveru" @@ -549,6 +1033,10 @@ msgstr "Vyžaduje připojení k Internetu" msgid "Restart now?" msgstr "Restartovat nyní?" +#. TRANSLATORS: configuration changes only take effect on restart +msgid "Restart the daemon to make the change effective?" +msgstr "Restartovat proces služby, aby se změny uplatnily?" + #. TRANSLATORS: restarting the device to pick up new F/W msgid "Restarting device…" msgstr "Zařízení se restartuje…" @@ -557,6 +1045,21 @@ msgstr "Zařízení se restartuje…" msgid "Return all the hardware IDs for the machine" msgstr "Vrátit všechna ID hardwaru počítače" +msgid "Run `fwupdmgr get-upgrades` for more information." +msgstr "Podrobnosti získáte spuštěním `fwupdmgr get-upgrades`." + +#. TRANSLATORS: Title: SPI refers to the flash chip in the computer +msgid "SPI BIOS region" +msgstr "Oblast SPI BIOS" + +#. TRANSLATORS: Title: SPI refers to the flash chip in the computer +msgid "SPI lock" +msgstr "SPI uzamčení" + +#. TRANSLATORS: Title: SPI refers to the flash chip in the computer +msgid "SPI write" +msgstr "SPI zápis" + #. TRANSLATORS: command line option msgid "Schedule installation for next reboot when possible" msgstr "Pokud je to možné, naplánovat instalaci na příští restart" @@ -565,18 +1068,42 @@ msgstr "Pokud je to možné, naplánovat instalaci na příští restart" msgid "Scheduling…" msgstr "Plánuje se…" +#. TRANSLATORS: Device has been chosen by the daemon for the user +msgid "Selected device" +msgstr "Vybrané zařízení" + +#. TRANSLATORS: Volume has been chosen by the user +msgid "Selected volume" +msgstr "Vybraný svazek" + #. TRANSLATORS: command line option msgid "Set the debugging flag during update" msgstr "Během aktualizace nastavit příznak ladění" +#. TRANSLATORS: firmware approved by the admin +msgid "Sets the list of approved firmware" +msgstr "Nastavuje seznam schváleného firmware" + #. TRANSLATORS: command description msgid "Share firmware history with the developers" msgstr "Sdílet historii firmwaru s vývojáři" +#. TRANSLATORS: command line option +msgid "Show all results" +msgstr "Zobrazit všechny výsledky" + #. TRANSLATORS: command line option msgid "Show client and daemon versions" msgstr "Zobrazit verzi klienta a démona" +#. TRANSLATORS: this is for daemon development +msgid "Show daemon verbose information for a particular domain" +msgstr "Zobrazit podrobnější informace z procesu služby pro konkrétní oblast" + +#. TRANSLATORS: turn on all debugging +msgid "Show debugging information for all domains" +msgstr "Zapnout vypisování ladících informací pro všechny oblasti" + #. TRANSLATORS: for the --verbose arg msgid "Show debugging options" msgstr "Zobrazit volby ladění" @@ -597,6 +1124,10 @@ msgstr "Zobrazit historii aktualizací firmwaru" msgid "Show plugin verbose information" msgstr "Zobrazit podrobné informace o zásuvném modulu" +#. TRANSLATORS: command line option +msgid "Show the calculated version of the dbx" +msgstr "Zobrazit vypočtenou verzi dbx" + #. TRANSLATORS: command line option msgid "Show the debug log from the last attempted update" msgstr "Zobrazit ladicí záznam z posledního pokusu o aktualizaci" @@ -605,10 +1136,52 @@ msgstr "Zobrazit ladicí záznam z posledního pokusu o aktualizaci" msgid "Show the information of firmware update status" msgstr "Zobrazit informace o stavu aktualizace firmwaru" +#. TRANSLATORS: shutdown to apply the update +msgid "Shutdown now?" +msgstr "Vypnout nyní?" + +msgid "Sign data using the client certificate" +msgstr "Podepsat data klientským certifikátem" + +msgctxt "command-description" +msgid "Sign data using the client certificate" +msgstr "Podepsat data klientským certifikátem" + +msgid "Specify Vendor/Product ID(s) of DFU device" +msgstr "Zadejte identifikátor(y) výrobce/produktu DFU zařízení" + +#. TRANSLATORS: command line option +msgid "Specify the dbx database file" +msgstr "Zadejte soubor dbx databáze" + +msgid "Specify the number of bytes per USB transfer" +msgstr "Zadejte počet bajtů v jednotlivých přenosech přes USB sběrnici" + +#. TRANSLATORS: success message -- where activation is making the new +#. * firmware take effect, usually after updating offline +msgid "Successfully activated all devices" +msgstr "Všechna zařízení úspěšně aktivována" + +#. TRANSLATORS: success message -- a per-system setting value +msgid "Successfully modified configuration value" +msgstr "Hodnota v nastavení úspěšně změněna" + #. TRANSLATORS: one line summary of device msgid "Summary" msgstr "Souhrn" +#. TRANSLATORS: Suffix: the HSI result +msgid "Supported" +msgstr "Podporováno" + +#. TRANSLATORS: Title: the PCR is rebuilt from the TPM event log +msgid "TPM PCR0 reconstruction" +msgstr "Rekonstrukce TPM PCR0" + +#. TRANSLATORS: Title: TPM = Trusted Platform Module +msgid "TPM v2.0" +msgstr "TPM v2.0" + msgid "Target" msgstr "Cíl" @@ -616,6 +1189,15 @@ msgstr "Cíl" msgid "The LVFS is a free service that operates as an independent legal entity and has no connection with $OS_RELEASE:NAME$. Your distributor may not have verified any of the firmware updates for compatibility with your system or connected devices. All firmware is provided only by the original equipment manufacturer." msgstr "LVFS je svobodná služba, které funguje jako nezávislý právní subjekt a nemá žádné vazby na systém $OS_RELEASE:NAME$. Váš distributor nemusí některé z aktualizací firmwaru schválit kvůli kompatibilitě s vaším systémem nebo připojenými zařízeními. Veškerý firmware je poskytován pouze přímo výrobci daných zařízení." +#. TRANSLATORS: nothing to show +msgid "There are no blocked firmware files" +msgstr "Nejsou zde žádné blokované soubory s firmware" + +#. TRANSLATORS: approved firmware has been checked by +#. * the domain administrator +msgid "There is no approved firmware." +msgstr "Není k dispozici žádný schválený firmware" + #. TRANSLATORS: we're poking around as a power user msgid "This program may only work correctly as root" msgstr "Tento program může správně fungovat jen pod uživatelem root" @@ -623,6 +1205,14 @@ msgstr "Tento program může správně fungovat jen pod uživatelem root" msgid "This remote contains firmware which is not embargoed, but is still being tested by the hardware vendor. You should ensure you have a way to manually downgrade the firmware if the firmware update fails." msgstr "Tento zdroj obsahuje firmware, který není zakázaný, ale zatím je u výrobce stále ve stádiu testování. Měli byste se ujistit, že znáte způsob, jak se vrátit k předchozí verzi firmwaru, kdyby došlo k selhání." +#. TRANSLATORS: description of dbxtool +msgid "This tool allows an administrator to apply UEFI dbx updates." +msgstr "Tento nástroj správci umožňuje použít UEFI dbx aktualizace." + +#. TRANSLATORS: the user needs to stop playing with stuff +msgid "This tool can only be used by the root user" +msgstr "Tento nástroj může používat pouze uživatel s oprávněními na úrovni správce systému (root)" + #. TRANSLATORS: remote type, e.g. remote or local msgid "Type" msgstr "Typ" @@ -631,6 +1221,26 @@ msgstr "Typ" msgid "UEFI Firmware Utility" msgstr "Nástroj pro práci s firmwarem UEFI" +#. TRANSLATORS: program name +msgid "UEFI dbx Utility" +msgstr "Nástroj pro UEFI dbx" + +#. TRANSLATORS: error message +msgid "Unable to connect to service" +msgstr "Nedaří se připojit se ke službě" + +#. TRANSLATORS: command description +msgid "Unbind current driver" +msgstr "Odpojit stávající ovladač" + +#. TRANSLATORS: we will now offer this firmware to the user +msgid "Unblocking firmware:" +msgstr "Odblokovává se firmware:" + +#. TRANSLATORS: Suffix: the HSI result +msgid "Unencrypted" +msgstr "Nešifrované" + #. TRANSLATORS: current daemon status is unknown #. TRANSLATORS: we don't know the license of the update #. TRANSLATORS: unknown release urgency @@ -640,6 +1250,10 @@ msgstr "Neznámý" msgid "Unlock the device to allow access" msgstr "Odemknutí zařízení pro umožnění přístupu" +#. TRANSLATORS: Suffix: the HSI result +msgid "Unlocked" +msgstr "Odemčené" + #. TRANSLATORS: command description msgid "Unlocks the device for firmware access" msgstr "Odemknout zařízení pro přístup k firmwaru" @@ -648,6 +1262,15 @@ msgstr "Odemknout zařízení pro přístup k firmwaru" msgid "Unset the debugging flag during update" msgstr "Během aktualizace zrušit příznak ladění" +#. TRANSLATORS: error message +#, c-format +msgid "Unsupported daemon version %s, client version is %s" +msgstr "Nepodporovaná verze procesu služby %s, verze klienta je %s" + +#. TRANSLATORS: command description +msgid "Update all devices that match local metadata" +msgstr "Aktualizovat veškerá zařízení, která se shodují s místními metadaty" + #. TRANSLATORS: the server sent the user a small message msgid "Update failure is a known issue, visit this URL for more information:" msgstr "O selhání aktualizace se ví, více informací najdete na této adrese:" @@ -659,6 +1282,10 @@ msgstr "Aktualizovat nyní?" msgid "Update the stored device verification information" msgstr "Aktualizace uložené informace o ověření zařízení" +#. TRANSLATORS: command description +msgid "Update the stored metadata with current contents" +msgstr "Aktualizovat uložená metadata stávajícím obsahem" + #. TRANSLATORS: command description msgid "Updates all firmware to latest versions available" msgstr "Aktualizovat všechen firmware na nejnovější dostupné verze" @@ -670,9 +1297,10 @@ msgstr "Aktualizovat všechen firmware na nejnovější dostupné verze" msgid "Updating %s from %s to %s... " msgstr "Aktualizuje se %s z verze %s na %s…" -#. TRANSLATORS: the server sent the user a small message -msgid "Upload message:" -msgstr "Nahraná zpráva:" +#. TRANSLATORS: %1 is a device name +#, c-format +msgid "Updating %s…" +msgstr "Aktualizace %s…" #. TRANSLATORS: ask the user to upload msgid "Upload report now?" @@ -682,14 +1310,38 @@ msgstr "Nahrát hlášení nyní?" msgid "Uploading firmware reports helps hardware vendors to quickly identify failing and successful updates on real devices." msgstr "Když nahrajete hlášení o firmwaru, pomůžete tím výrobcům hardwaru rychle rozpoznat nezdařené a úspěšné aktualizace na reálných zařízeních." +#. TRANSLATORS: error message explaining command to run to how to get help +msgid "Use fwupdmgr --help for help" +msgstr "Pro zobrazení nápovědy použijte příkaz fwupdmgr --help" + +#. TRANSLATORS: command line option +msgid "Use quirk flags when installing firmware" +msgstr "Při instalaci firmware použít příznaky pro kompatibilitu" + #. TRANSLATORS: remote filename base msgid "Username" msgstr "Uživatelské jméno" +#. TRANSLATORS: Suffix: the HSI result +msgid "Valid" +msgstr "Platné" + +#. TRANSLATORS: ESP refers to the EFI System Partition +msgid "Validating ESP contents…" +msgstr "Ověřování obsahu ESP oddílu…" + #. TRANSLATORS: verifying we wrote the firmware correctly msgid "Verifying…" msgstr "Ověřuje se…" +#. TRANSLATORS: the detected version number of the dbx +msgid "Version" +msgstr "Verze" + +#. TRANSLATORS: this is a prefix on the console +msgid "WARNING:" +msgstr "VAROVÁNÍ:" + #. TRANSLATORS: waiting for device to do something msgid "Waiting…" msgstr "Čeká se…" @@ -710,6 +1362,10 @@ msgstr "Zapsat firmware ze souboru do zařízení" msgid "Write firmware from file into one partition" msgstr "Zapsat firmware ze souboru do jednoho oddílu" +#. TRANSLATORS: decompressing images from a container firmware +msgid "Writing file:" +msgstr "Zápis do souboru:" + #. TRANSLATORS: writing to the flash chips msgid "Writing…" msgstr "Zapisuje se…" @@ -717,3 +1373,11 @@ msgstr "Zapisuje se…" #. TRANSLATORS: show the user a warning msgid "Your distributor may not have verified any of the firmware updates for compatibility with your system or connected devices." msgstr "Váš distributor nemusí schválit některé aktualizace firmwaru kvůli kompatibilitě s vaším systémem nebo připojenými zařízeními." + +#. TRANSLATORS: program name +msgid "fwupd TPM event log utility" +msgstr "fwupd nástroj pro záznamy událostí v TPM" + +#. TRANSLATORS: Title: if the fwupd plugins are all present and correct +msgid "fwupd plugins" +msgstr "zásuvné moduly pro fwupd" diff --git a/po/da.po b/po/da.po index 7cc601529..3642c0fc3 100644 --- a/po/da.po +++ b/po/da.po @@ -23,6 +23,18 @@ msgid_plural "%.0f minutes remaining" msgstr[0] "%.0f minut tilbage" msgstr[1] "%.0f minutter tilbage" +#. TRANSLATORS: the CPU microcode is firmware loaded onto the CPU +#. * at system bootup +#, c-format +msgid "%s CPU Microcode Update" +msgstr "%s opdatering af CPU-mikrokode" + +#. TRANSLATORS: a specific part of hardware, +#. * the first %s is the device name, e.g. 'Secure Boot` +#, c-format +msgid "%s Configuration Update" +msgstr "Opdatering for konfiguration %s" + #. TRANSLATORS: ME stands for Management Engine, where #. * the first %s is the device name, e.g. 'ThinkPad P50` #, c-format @@ -86,6 +98,11 @@ msgstr "Opdatering for %s" msgid "%s and all connected devices may not be usable while updating." msgstr "%s og alle tilsluttede enheder vil måske ikke være anvendelige under opdatering." +#. TRANSLATORS: Title: %s is ME kind, e.g. CSME/TXT +#, c-format +msgid "%s manufacturing mode" +msgstr "%s-fabrikstilstand" + #. TRANSLATORS: warn the user before updating, %1 is a device name #, c-format msgid "%s must remain connected for the duration of the update to avoid damage." @@ -96,6 +113,21 @@ msgstr "%s skal være tilsluttet under hele opdateringen, for at undgå skade." msgid "%s must remain plugged into a power source for the duration of the update to avoid damage." msgstr "%s skal være tilsluttet en strømkilde under hele opdateringen, for at undgå skade." +#. TRANSLATORS: Title: %s is ME kind, e.g. CSME/TXT +#, c-format +msgid "%s override" +msgstr "%s-tilsidesættelse" + +#. TRANSLATORS: Title: %1 is ME kind, e.g. CSME/TXT, %2 is a version number +#, c-format +msgid "%s v%s" +msgstr "%s v%s" + +#. TRANSLATORS: Title: %s is ME kind, e.g. CSME/TXT +#, c-format +msgid "%s version" +msgstr "%s-version" + #. TRANSLATORS: duration in days! #, c-format msgid "%u day" @@ -137,6 +169,10 @@ msgid_plural "%u seconds" msgstr[0] "%u sekund" msgstr[1] "%u sekunder" +#. TRANSLATORS: this is shown as a suffix for obsoleted tests +msgid "(obsoleted)" +msgstr "(forældet)" + #. TRANSLATORS: command description msgid "Activate devices" msgstr "Aktivér enheder" @@ -181,6 +217,10 @@ msgstr "Tillad nedgradering af firmwareversioner" msgid "Allow reinstalling existing firmware versions" msgstr "Tillad geninstallering af eksisterende firmwareversioner" +#. TRANSLATORS: command line option +msgid "Allow switching firmware branch" +msgstr "Tillad skift af firmwaregren" + #. TRANSLATORS: explain why we want to reboot msgid "An update requires a reboot to complete." msgstr "For at fuldføre en opdatering skal systemet genstartes." @@ -197,6 +237,18 @@ msgstr "Svar ja til alle spørgsmål" msgid "Apply firmware updates" msgstr "Anvend firmwareopdateringer" +#. TRANSLATORS: command line option +msgid "Apply update even when not advised" +msgstr "Anvend opdatering, selv når det ikke tilrådes" + +#. TRANSLATORS: command line option +msgid "Apply update files" +msgstr "Anvend opdateringsfiler" + +#. TRANSLATORS: actually sending the update to the hardware +msgid "Applying update…" +msgstr "Anvender opdatering …" + #. TRANSLATORS: approved firmware has been checked by #. * the domain administrator msgid "Approved firmware:" @@ -204,6 +256,10 @@ msgid_plural "Approved firmware:" msgstr[0] "Godkendt firmware:" msgstr[1] "Godkendt firmware:" +#. TRANSLATORS: stop nagging the user +msgid "Ask again next time?" +msgstr "Spørg igen næste gang?" + #. TRANSLATORS: command description msgid "Attach to firmware mode" msgstr "Tilkobl til firmwaretilstand" @@ -260,10 +316,38 @@ msgstr "Der kræves autentifikation for at opdatere de gemte checksumme for enhe msgid "Automatic Reporting" msgstr "Automatisk rapportering" +#. TRANSLATORS: can we JFDI? +msgid "Automatically upload every time?" +msgstr "Upload automatisk hver gang?" + +#. TRANSLATORS: command description +msgid "Bind new kernel driver" +msgstr "Bind ny kernedriver" + +#. TRANSLATORS: there follows a list of hashes +msgid "Blocked firmware files:" +msgstr "Blokerede firmwarefiler:" + +#. TRANSLATORS: we will not offer this firmware to the user +msgid "Blocking firmware:" +msgstr "Blokerer firmware:" + +#. TRANSLATORS: command description +msgid "Blocks a specific firmware from being installed" +msgstr "Blokerer en bestemt firmware fra at blive installeret" + #. TRANSLATORS: firmware version of bootloader msgid "Bootloader Version" msgstr "Opstartsindlæser version" +#. TRANSLATORS: the stream of firmware, e.g. nonfree or open-source +msgid "Branch" +msgstr "Gren" + +#. TRANSLATORS: command description +msgid "Build a firmware file" +msgstr "Byg en firmwarefil" + #. TRANSLATORS: command description msgid "Build firmware using a sandbox" msgstr "Byg firmware med en sandkasse" @@ -276,6 +360,14 @@ msgstr "Annuller" msgid "Cancelled" msgstr "Annulleret" +#. TRANSLATORS: same or newer update already applied +msgid "Cannot apply as dbx update has already been applied." +msgstr "Kan ikke anvende eftersom dbx-opdatering allerede er blevet anvendt." + +#. TRANSLATORS: the user is using a LiveCD or LiveUSB install disk +msgid "Cannot apply updates on live media" +msgstr "Kan ikke anvende opdateringer på livemedier" + #. TRANSLATORS: this is when a device is hotplugged #. TRANSLATORS: this is when the daemon state changes msgid "Changed" @@ -289,6 +381,11 @@ msgstr "Tjekker om den kryptografiske hash passer med firmwaren" msgid "Checksum" msgstr "Checksum" +#. TRANSLATORS: get interactive prompt, where branch is the +#. * supplier of the firmware, e.g. "non-free" or "free" +msgid "Choose a branch:" +msgstr "Vælg en gren:" + #. TRANSLATORS: get interactive prompt msgid "Choose a device:" msgstr "Vælg en enhed:" @@ -301,6 +398,10 @@ msgstr "Vælg en firmwaretype:" msgid "Choose a release:" msgstr "Vælg en udgivelse:" +#. TRANSLATORS: get interactive prompt +msgid "Choose a volume:" +msgstr "Vælg et diskområde:" + #. TRANSLATORS: command description msgid "Clears any updates scheduled to be updated offline" msgstr "Rydder opdateringer som er planlagt til at blive opdateret offline" @@ -317,6 +418,18 @@ msgstr "Kommandoen blev ikke fundet" msgid "Continue with update?" msgstr "Fortsæt opdateringen?" +#. TRANSLATORS: command description +msgid "Convert a firmware file" +msgstr "Konverter en firmwarefil" + +#. TRANSLATORS: when the update was built +msgid "Created" +msgstr "Oprettet" + +#. TRANSLATORS: the release urgency +msgid "Critical" +msgstr "Kritisk" + #. TRANSLATORS: Device supports some form of checksum verification msgid "Cryptographic hash verification is available" msgstr "Bekræftelse af kryptografisk hash er tilgængelig" @@ -393,10 +506,18 @@ msgstr "Enhed fjernet:" msgid "Device stages updates" msgstr "Enhedstrin-opdateringer" +#. TRANSLATORS: there is more than one supplier of the firmware +msgid "Device supports switching to a different branch of firmware" +msgstr "Enheden undertøtter at der kan skiftes til en anden gren med firmware" + #. TRANSLATORS: Device update needs to be separately activated msgid "Device update needs activation" msgstr "Enhedsopdatering behøver aktivering" +#. TRANSLATORS: save the old firmware to disk before installing the new one +msgid "Device will backup firmware before installing" +msgstr "Enheden sikkerhedskopierer firmwaren inden installation" + #. TRANSLATORS: Device will not return after update completes msgid "Device will not re-appear after update completes" msgstr "Enheden vises ikke igen når opdateringen er færdig" @@ -409,6 +530,20 @@ msgstr "Enheder som det lykkedes at opdatere:" msgid "Devices that were not updated correctly:" msgstr "Enheder som ikke blev opdateret korrekt:" +#. TRANSLATORS: message letting the user know no device upgrade available due +#. to missing on LVFS +msgid "Devices with no available firmware updates: " +msgstr "Enheder uden nogen tilgængelige firmwareopdateringer: " + +#. TRANSLATORS: message letting the user know no device upgrade available +msgid "Devices with the latest available firmware version:" +msgstr "Enheder med den seneste tilgængelige firmwareversion:" + +#. TRANSLATORS: Suffix: the HSI result +#. TRANSLATORS: Plugin is inactive and not used +msgid "Disabled" +msgstr "Deaktiveret" + msgid "Disabled fwupdate debugging" msgstr "Deaktivér fejlsøgning af fwupdate" @@ -458,6 +593,11 @@ msgstr[1] "Upload ikke rapporter og spørg aldrig om at uploade rapporter om fre msgid "Do not write to the history database" msgstr "Skriv ikke til historikdatabasen" +#. TRANSLATORS: should the branch be changed +msgid "Do you understand the consequences of changing the firmware branch?" +msgstr "Forstår du de konsekvenser som er forbundet med ændring af firmwaregrenen?" + +#. TRANSLATORS: success #. success msgid "Done!" msgstr "Færdig!" @@ -502,6 +642,8 @@ msgstr "Aktivér understøttelse af firmwareopdateringer på systemer som unders msgid "Enable this remote?" msgstr "Aktivér fjernen?" +#. TRANSLATORS: Suffix: the HSI result +#. TRANSLATORS: Plugin is active and in use #. TRANSLATORS: if the remote is enabled msgid "Enabled" msgstr "Aktiveret" @@ -520,6 +662,14 @@ msgstr "Aktivering af funktionen sker på egen risiko. Det betydet at du skal ko msgid "Enabling this remote is done at your own risk." msgstr "Aktivering af fjernen sker på egen risiko." +#. TRANSLATORS: Suffix: the HSI result +msgid "Encrypted" +msgstr "Krypteret" + +#. TRANSLATORS: Title: Memory contents are encrypted, e.g. Intel TME +msgid "Encrypted RAM" +msgstr "Krypteret RAM" + #. TRANSLATORS: command description msgid "Erase all firmware update history" msgstr "Slet al historik over firmwareopdateringer" @@ -536,13 +686,25 @@ msgstr "Afslut efter en lille forsinkelse" msgid "Exit after the engine has loaded" msgstr "Afslut efter motoren er indlæst" +#. TRANSLATORS: command description +msgid "Extract a firmware blob to images" +msgstr "Udpak en firmwareblob til aftryk" + +#. TRANSLATORS: Suffix: the fallback HSI result +msgid "Failed" +msgstr "Mislykkedes" + +#. TRANSLATORS: dbx file failed to be applied as an update +msgid "Failed to apply update" +msgstr "Kunne ikke anvende opdatering" + #. TRANSLATORS: we could not talk to the fwupd daemon msgid "Failed to connect to daemon" msgstr "Kunne ikke oprette forbindelse til dæmonen" -#. TRANSLATORS: the server is rate-limiting downloads -msgid "Failed to download due to server limit" -msgstr "Kunne ikke downloade pga. begrænsning på server" +#. TRANSLATORS: could not parse file +msgid "Failed to extract local dbx " +msgstr "Kunne ikke udpakke lokal dbx " #. TRANSLATORS: we could not get the devices to update offline msgid "Failed to get pending devices" @@ -552,10 +714,19 @@ msgstr "Kunne ikke hente afventende enheder" msgid "Failed to install firmware update" msgstr "Kunne ikke installere firmwareopdateringen" +#. TRANSLATORS: could not read existing system data +#. TRANSLATORS: could not read file +msgid "Failed to load local dbx" +msgstr "Kunne ikke indlæse lokal dbx" + #. TRANSLATORS: quirks are device-specific workarounds msgid "Failed to load quirks" msgstr "Kunne ikke indlæse quirks" +#. TRANSLATORS: could not read existing system data +msgid "Failed to load system dbx" +msgstr "Kunne ikke indlæse systemets dbx" + #. TRANSLATORS: the user didn't read the man page msgid "Failed to parse arguments" msgstr "Kunne ikke fortolke argumenter" @@ -568,6 +739,10 @@ msgstr "Kunne ikke fortolke fil" msgid "Failed to parse flags for --filter" msgstr "Kunne ikke fortolke flag for --filter" +#. TRANSLATORS: could not parse file +msgid "Failed to parse local dbx" +msgstr "Kunne ikke fortolke lokal dbx" + #. TRANSLATORS: we could not reboot for some reason msgid "Failed to reboot" msgstr "Kunne ikke genstarte" @@ -576,21 +751,10 @@ msgstr "Kunne ikke genstarte" msgid "Failed to set splash mode" msgstr "Kunne ikke indstille splash-tilstand" -#. TRANSLATORS: downloading unknown file -msgid "Fetching file" -msgstr "Henter fil" - -#. TRANSLATORS: downloading new firmware file -msgid "Fetching firmware" -msgstr "Henter firmware" - -#. TRANSLATORS: downloading new metadata file -msgid "Fetching metadata" -msgstr "Henter metadata" - -#. TRANSLATORS: downloading new signing file -msgid "Fetching signature" -msgstr "Henter underskrift" +#. TRANSLATORS: something with a blocked hash exists +#. * in the users ESP -- which would be bad! +msgid "Failed to validate ESP contents" +msgstr "Kunne ikke validere ESP-indhold" #. TRANSLATORS: filename of the local file msgid "Filename" @@ -600,6 +764,10 @@ msgstr "Filnavn" msgid "Filename Signature" msgstr "Filnavnets underskrift" +#. TRANSLATORS: user did not include a filename parameter +msgid "Filename required" +msgstr "Filnavn kræves" + #. TRANSLATORS: command line option msgid "Filter with a set of device flags using a ~ prefix to exclude, e.g. 'internal,~needs-reboot'" msgstr "Filtrer med et sæt enhedsflag med et ~-præfiks for at udelukke, f.eks. 'intern,~behøver-genstart'" @@ -624,6 +792,22 @@ msgstr "Firmwareopdateringsdæmon" msgid "Firmware Utility" msgstr "Firmwareredskab" +#. TRANSLATORS: Title: if we can verify the firmware checksums +msgid "Firmware attestation" +msgstr "Firmwareattest" + +#. TRANSLATORS: system is not booted in UEFI mode +msgid "Firmware can not be updated in legacy BIOS mode" +msgstr "Firmwaren kan ikke opdateres i udgået BIOS-tilstand" + +#. TRANSLATORS: user selected something not possible +msgid "Firmware is already blocked" +msgstr "Firmware er allerede blokeret" + +#. TRANSLATORS: user selected something not possible +msgid "Firmware is not already blocked" +msgstr "Firmware er ikke allerede blokeret" + #. TRANSLATORS: the metadata is very out of date; %u is a number > 1 #, c-format msgid "Firmware metadata has not been updated for %u day and may not be up to date." @@ -631,18 +815,35 @@ msgid_plural "Firmware metadata has not been updated for %u days and may not be msgstr[0] "Firmwaremetadata er ikke blevet opdateret i %u dag og kan være forældet." msgstr[1] "Firmwaremetadata er ikke blevet opdateret i %u dage og kan være forældet." +#. TRANSLATORS: Title: if firmware updates are available +msgid "Firmware updates" +msgstr "Firmwareopdateringer" + msgid "Firmware updates are not supported on this machine." msgstr "Maskinen understøtter ikke firmwareopdateringer." msgid "Firmware updates are supported on this machine." msgstr "Maskinen understøtter firmwareopdateringer." +#. TRANSLATORS: user needs to run a command +msgid "Firmware updates disabled; run 'fwupdmgr unlock' to enable" +msgstr "Firewareopdateringer deaktiveret; kør 'fwupdmgr unlock' for at aktivere" + +#. TRANSLATORS: description of plugin state, e.g. disabled #. TRANSLATORS: release properties msgid "Flags" msgstr "Flag" +#. TRANSLATORS: command line option +msgid "Force the action by relaxing some runtime checks" +msgstr "Gennemtving handlingen ved at afslappe visse runtimetjek" + msgid "Force the action ignoring all warnings" -msgstr "Tving handlingen og ignorer alle advarsler" +msgstr "Gennemtving handlingen og ignorer alle advarsler" + +#. TRANSLATORS: Suffix: the HSI result +msgid "Found" +msgstr "Fundet" #. TRANSLATORS: global ID common to all similar hardware msgid "GUID" @@ -674,9 +875,17 @@ msgstr "Hent detaljer om en firmwarefil" msgid "Gets the configured remotes" msgstr "Henter de konfigurerede fjerne" +#. TRANSLATORS: command description +msgid "Gets the host security attributes" +msgstr "Henter værtens sikkerhedsattributter" + #. TRANSLATORS: firmware approved by the admin -msgid "Gets the list of approved firmware." -msgstr "Henter listen over godkendt firmware." +msgid "Gets the list of approved firmware" +msgstr "Henter listen over godkendt firmware" + +#. TRANSLATORS: command description +msgid "Gets the list of blocked firmware" +msgstr "Henter listen over blokerede firmware" #. TRANSLATORS: command description msgid "Gets the list of updates for connected hardware" @@ -694,6 +903,19 @@ msgstr "Henter resultaterne fra den sidste opdatering" msgid "Hardware is waiting to be replugged" msgstr "Hardwaren venter på at bliver gentilkoblet" +#. TRANSLATORS: the release urgency +msgid "High" +msgstr "Høj" + +#. TRANSLATORS: this is a string like 'HSI:2-U' +msgid "Host Security ID:" +msgstr "Værtens sikkerheds-ID:" + +#. TRANSLATORS: Title: +#. https://en.wikipedia.org/wiki/Input%E2%80%93output_memory_management_unit +msgid "IOMMU" +msgstr "IOMMU" + #. TRANSLATORS: daemon is inactive msgid "Idle…" msgstr "Inaktiv …" @@ -702,10 +924,26 @@ msgstr "Inaktiv …" msgid "Ignore SSL strict checks when downloading files" msgstr "Ignorer strikse SSL-tjek ved download af filer" +#. TRANSLATORS: command line option +msgid "Ignore firmware checksum failures" +msgstr "Ignorer mislykkede checksum for firmware" + +#. TRANSLATORS: command line option +msgid "Ignore firmware hardware mismatch failures" +msgstr "Ignorer mislykkedes firmwarehardware som ikke passer sammen" + +#. TRANSLATORS: command line option +msgid "Ignore requirement of external power source" +msgstr "Ignorer krav om ekstern strømkilde" + #. TRANSLATORS: Ignore validation safety checks when flashing this device msgid "Ignore validation safety checks" msgstr "Ignorer sikkerhedstjek af bekræftelse" +#. TRANSLATORS: try to help +msgid "Ignoring SSL strict checks, to do this automatically in the future export DISABLE_SSL_STRICT in your environment" +msgstr "Ignorerer strikse SSL-tjeks. Eksportér DISABLE_SSL_STRICT i dit miljø for at gøre det automatisk i fremtiden" + #. TRANSLATORS: length of time the update takes to apply msgid "Install Duration" msgstr "Varighed for installation" @@ -750,10 +988,57 @@ msgstr "Installerer firmwareopdateringer …" msgid "Installing on %s…" msgstr "Installerer på %s …" +#. TRANSLATORS: Title: BootGuard is a trademark from Intel +msgid "Intel BootGuard" +msgstr "Intel BootGuard" + +#. TRANSLATORS: Title: BootGuard is a trademark from Intel, +#. * ACM means to verify the integrity of Initial Boot Block +msgid "Intel BootGuard ACM protected" +msgstr "Intel BootGuard ACM-beskyttet" + +#. TRANSLATORS: Title: BootGuard is a trademark from Intel, +#. * OTP = one time programmable +msgid "Intel BootGuard OTP fuse" +msgstr "Intel BootGuard OTP-fuse" + +#. TRANSLATORS: Title: BootGuard is a trademark from Intel, +#. * error policy is what to do on failure +msgid "Intel BootGuard error policy" +msgstr "Intel BootGuard regler om fejl" + +#. TRANSLATORS: Title: BootGuard is a trademark from Intel, +#. * verified boot refers to the way the boot process is verified +msgid "Intel BootGuard verified boot" +msgstr "Intel BootGuard bekræftet start" + +#. TRANSLATORS: Title: CET = Control-flow Enforcement Technology, +#. * active means being used by the OS +msgid "Intel CET Active" +msgstr "Intel CET aktiv" + +#. TRANSLATORS: Title: CET = Control-flow Enforcement Technology, +#. * enabled means supported by the processor +msgid "Intel CET Enabled" +msgstr "Intel CET-aktiveret" + +#. TRANSLATORS: Title: Direct Connect Interface (DCI) allows +#. * debugging of Intel processors using the USB3 port +msgid "Intel DCI debugger" +msgstr "Intel DCI-fejlsøgning" + +#. TRANSLATORS: Title: SMAP = Supervisor Mode Access Prevention +msgid "Intel SMAP" +msgstr "Intel SMAP" + #. TRANSLATORS: Device cannot be removed easily msgid "Internal device" msgstr "Intern enhed" +#. TRANSLATORS: Suffix: the HSI result +msgid "Invalid" +msgstr "Ugyldig" + #. TRANSLATORS: Is currently in bootloader mode msgid "Is in bootloader mode" msgstr "Er i opstartsindlæsertilstand" @@ -785,6 +1070,22 @@ msgstr "Linux Vendor Firmware Service (stabilt firmware)" msgid "Linux Vendor Firmware Service (testing firmware)" msgstr "Linux Vendor Firmware Service (testning firmware)" +#. TRANSLATORS: Title: if it's tainted or not +msgid "Linux kernel" +msgstr "Linux-kerne" + +#. TRANSLATORS: Title: lockdown is a security mode of the kernel +msgid "Linux kernel lockdown" +msgstr "Nedlukning af Linux-kerne" + +#. TRANSLATORS: Title: swap space or swap partition +msgid "Linux swap" +msgstr "Linux-swap" + +#. TRANSLATORS: command line option +msgid "List entries in dbx" +msgstr "Vis poster i dbx" + #. TRANSLATORS: command line option msgid "List supported firmware updates" msgstr "Vis understøttede firmwareopdateringer" @@ -793,13 +1094,43 @@ msgstr "Vis understøttede firmwareopdateringer" msgid "List the available firmware types" msgstr "Vis de tilgængelige firmwaretyper" +#. TRANSLATORS: command description +msgid "Lists files on the ESP" +msgstr "Viser filer på ESP'en" + #. TRANSLATORS: parsing the firmware information msgid "Loading…" msgstr "Indlæser …" +#. TRANSLATORS: Suffix: the HSI result +msgid "Locked" +msgstr "Låst" + +#. TRANSLATORS: the release urgency +msgid "Low" +msgstr "Lav" + +#. TRANSLATORS: Title: MEI = Intel Management Engine +msgid "MEI manufacturing mode" +msgstr "MEI-fabrikstilstand" + +#. TRANSLATORS: Title: MEI = Intel Management Engine, and the +#. * "override" is the physical PIN that can be driven to +#. * logic high -- luckily it is probably not accessible to +#. * end users on consumer boards +msgid "MEI override" +msgstr "MEI-tilsidesættelse" + +msgid "MEI version" +msgstr "MEI-version" + #. TRANSLATORS: command line option -msgid "Manually whitelist specific plugins" -msgstr "Manuel hvidlistning af bestemte plugins" +msgid "Manually enable specific plugins" +msgstr "Aktivér bestemte plugins manuelt" + +#. TRANSLATORS: the release urgency +msgid "Medium" +msgstr "Mellem" #. TRANSLATORS: remote URI msgid "Metadata Signature" @@ -823,8 +1154,8 @@ msgid "Mismatched daemon and client, use %s instead" msgstr "Dæmon og klient passer ikke sammen, brug %s i stedet" #. TRANSLATORS: sets something in daemon.conf -msgid "Modifies a daemon configuration value." -msgstr "Rediger en værdi i dæmonkonfiguration." +msgid "Modifies a daemon configuration value" +msgstr "Rediger en værdi i dæmonkonfiguration" #. TRANSLATORS: command description msgid "Modifies a given remote" @@ -840,6 +1171,10 @@ msgstr "Rediger dæmonkonfiguration" msgid "Monitor the daemon for events" msgstr "Overvåg dæmonen for hændelser" +#. TRANSLATORS: command description +msgid "Mounts the ESP" +msgstr "Monterer ESP'en" + #. TRANSLATORS: Requires a reboot to apply firmware or to reload hardware msgid "Needs a reboot after installation" msgstr "Genstart efter installation er nødvendig" @@ -852,6 +1187,7 @@ msgstr "Nedlukning efter installation er nødvendig" msgid "New version" msgstr "Ny version" +#. TRANSLATORS: user did not tell the tool what to do msgid "No action specified!" msgstr "Der er ikke angivet nogen handling!" @@ -889,14 +1225,22 @@ msgstr "Ingen tilgængelige fjerne" msgid "No updates were applied" msgstr "Der blev ikke anvendt nogen opdateringer" +#. TRANSLATORS: Suffix: the HSI result +msgid "Not found" +msgstr "Ikke fundet" + +#. TRANSLATORS: Suffix: the HSI result +msgid "Not supported" +msgstr "Ikke-understøttet" + +#. TRANSLATORS: Suffix: the HSI result +msgid "OK" +msgstr "OK" + #. TRANSLATORS: command line option msgid "Only show single PCR value" msgstr "Vis kun én PCR-værdi" -#. TRANSLATORS: command line option -msgid "Override plugin warning" -msgstr "Tilsidesæt advarsel for plugin" - #. TRANSLATORS: command line option msgid "Override the default ESP path" msgstr "Tilsidesæt standard-ESP-stien" @@ -909,6 +1253,14 @@ msgstr "Tilsidesæt advarsler og gennemtving handlingen" msgid "Parse and show details about a firmware file" msgstr "Fortolk og vis deltaljer om en firmwarefil" +#. TRANSLATORS: reading new dbx from the update +msgid "Parsing dbx update…" +msgstr "Fortolker dbx-opdatering …" + +#. TRANSLATORS: reading existing dbx from the system +msgid "Parsing system dbx…" +msgstr "Fortolker systemets dbx …" + #. TRANSLATORS: remote filename base msgid "Password" msgstr "Adgangskode" @@ -925,6 +1277,14 @@ msgstr "Procent fuldført" msgid "Please enter a number from 0 to %u: " msgstr "Indtast venligst et tal nummer 0 og %u: " +#. TRANSLATORS: Failed to open plugin, hey Arch users +msgid "Plugin dependencies missing" +msgstr "Plugin-afhængigheder mangler" + +#. TRANSLATORS: Title: DMA as in https://en.wikipedia.org/wiki/DMA_attack +msgid "Pre-boot DMA protection" +msgstr "Præopstart DMA-beskyttelse" + #. TRANSLATORS: version number of previous firmware msgid "Previous version" msgstr "Forrige version" @@ -980,8 +1340,12 @@ msgid "Refresh metadata from remote server" msgstr "Genopfrisk metadata fra fjernserver" #. TRANSLATORS: command description -msgid "Reinstall current firmware on the device." -msgstr "Geninstaller den nuværende firmware på enheden." +msgid "Reinstall current firmware on the device" +msgstr "Geninstaller den nuværende firmware på enheden" + +#. TRANSLATORS: command description +msgid "Reinstall firmware on a device" +msgstr "Geninstaller firmware på en enhed" #. TRANSLATORS: the first replacement is a display name #. * e.g. "ColorHugALS" and the second is a version number @@ -1011,9 +1375,13 @@ msgstr "Rapport-URI" msgid "Reported to remote server" msgstr "Rapporteret til fjernserver" -#. TRANSLATORS: Must be plugged in to an outlet -msgid "Requires AC power" -msgstr "Kræver strømforsygning" +#. TRANSLATORS: the user is using Gentoo/Arch and has screwed something up +msgid "Required efivarfs filesystem was not found" +msgstr "Krævede efivarfs-filsystem blev ikke fundet" + +#. TRANSLATORS: not required for this system +msgid "Required hardware was not found" +msgstr "Det krævede hardware blev ikke fundet" #. TRANSLATORS: Requires a bootloader mode to be manually enabled by the user msgid "Requires a bootloader" @@ -1050,6 +1418,22 @@ msgstr "Kør oprydningsrutinen for pluginkomposition når install-blob bruges" msgid "Run the plugin composite prepare routine when using install-blob" msgstr "Kør forberedelsesrutinen for pluginkomposition når install-blob bruges" +#. TRANSLATORS: this is the HSI suffix +msgid "Runtime Suffix" +msgstr "Suffiks for runtime" + +#. TRANSLATORS: Title: SPI refers to the flash chip in the computer +msgid "SPI BIOS region" +msgstr "SPI BIOS-region" + +#. TRANSLATORS: Title: SPI refers to the flash chip in the computer +msgid "SPI lock" +msgstr "SPI-lås" + +#. TRANSLATORS: Title: SPI refers to the flash chip in the computer +msgid "SPI write" +msgstr "SPI-skriv" + #. TRANSLATORS: command line option msgid "Save device state into a JSON file between executions" msgstr "Gem enhedens tilstand i en JSON-fil mellem udførsler" @@ -1066,6 +1450,10 @@ msgstr "Planlægger …" msgid "Selected device" msgstr "Valgte enhed" +#. TRANSLATORS: Volume has been chosen by the user +msgid "Selected volume" +msgstr "Valgte diskområde" + #. TRANSLATORS: serial number of hardware msgid "Serial Number" msgstr "Serienummer" @@ -1074,17 +1462,18 @@ msgstr "Serienummer" msgid "Set the debugging flag during update" msgstr "Indstil fejlsøgningsflaget under opdatering" +#. TRANSLATORS: firmware approved by the admin msgid "Sets the list of approved firmware" msgstr "Indstiller listen over godkendt firmware" -#. TRANSLATORS: firmware approved by the admin -msgid "Sets the list of approved firmware." -msgstr "Indstiller listen over godkendt firmware." - #. TRANSLATORS: command description msgid "Share firmware history with the developers" msgstr "Del historik over firmware med udviklerne" +#. TRANSLATORS: command line option +msgid "Show all results" +msgstr "Vis alle resultater" + #. TRANSLATORS: command line option msgid "Show client and daemon versions" msgstr "Vis klient- og dæmonversioner" @@ -1117,6 +1506,10 @@ msgstr "Vis historik over firmwareopdateringer" msgid "Show plugin verbose information" msgstr "Vis uddybende information om plugin" +#. TRANSLATORS: command line option +msgid "Show the calculated version of the dbx" +msgstr "Vis den udregnede version af dbx'en" + #. TRANSLATORS: command line option msgid "Show the debug log from the last attempted update" msgstr "Vis fejlsøgningsloggen fra den opdatering der blev forsøgt sidst" @@ -1154,6 +1547,10 @@ msgstr "Kilde" msgid "Specify Vendor/Product ID(s) of DFU device" msgstr "Angiv producent-/produkt-id('er) for DFU-enhed" +#. TRANSLATORS: command line option +msgid "Specify the dbx database file" +msgstr "Angiv dbx-databasefilen" + msgid "Specify the number of bytes per USB transfer" msgstr "Angiv antal bytes pr. USB-overførsel" @@ -1211,10 +1608,42 @@ msgstr "Bekræftelse af enhedens tjeksumme lykkedes" msgid "Summary" msgstr "Opsummering" +#. TRANSLATORS: Suffix: the HSI result +msgid "Supported" +msgstr "Understøttet" + #. TRANSLATORS: Is found in current metadata msgid "Supported on remote server" msgstr "Understøttes på fjernserver" +#. TRANSLATORS: Title: a better sleep state +msgid "Suspend-to-idle" +msgstr "Suspender-til-inaktiv" + +#. TRANSLATORS: Title: sleep state +msgid "Suspend-to-ram" +msgstr "Suspender-til-ram" + +#. TRANSLATORS: command description +msgid "Switch the firmware branch on the device" +msgstr "Skift firmwaregrenen på enheden" + +#. TRANSLATORS: Must be plugged in to an outlet +msgid "System requires external power source" +msgstr "Systemet kræver ekstern strømkilde" + +#. TRANSLATORS: Title: the PCR is rebuilt from the TPM event log +msgid "TPM PCR0 reconstruction" +msgstr "TPM PCR0-rekonstruktion" + +#. TRANSLATORS: Title: TPM = Trusted Platform Module +msgid "TPM v2.0" +msgstr "TPM v2.0" + +#. TRANSLATORS: Suffix: the HSI result +msgid "Tainted" +msgstr "Tainted" + msgid "Target" msgstr "Mål" @@ -1222,6 +1651,23 @@ msgstr "Mål" msgid "The LVFS is a free service that operates as an independent legal entity and has no connection with $OS_RELEASE:NAME$. Your distributor may not have verified any of the firmware updates for compatibility with your system or connected devices. All firmware is provided only by the original equipment manufacturer." msgstr "LVFS'en er en gratis tjeneste der opererer som en selvstændig juridisk enhed og har ingen forbindelse med $OS_RELEASE:NAME$. Din distributør har måske ikke bekræftet nogen af firmwareopdateringerne for kompatibilitet med dit system eller tilsluttede enheder. Al firmware leveres kun af den oprindelige udstyrsproducent." +#. TRANSLATORS: this is more background on a security measurement problem +msgid "The TPM PCR0 differs from reconstruction." +msgstr "TPM PCR0'en er ikke magen til rekonstruktionen." + +#. TRANSLATORS: the user is SOL for support... +msgid "The daemon has loaded 3rd party code and is no longer supported by the upstream developers!" +msgstr "Dæmonen har indlæst tredjepartskode og understøttes ikke længere af opstrømsudviklerne!" + +#. TRANSLATORS: %1 is the firmware vendor, %2 is the device vendor name +#, c-format +msgid "The firmware from %s is not supplied by %s, the hardware vendor." +msgstr "Firmwaren fra %s leveres ikke af hardwareleverandøren %s." + +#. TRANSLATORS: nothing to show +msgid "There are no blocked firmware files" +msgstr "Der er ikke nogen blokerede firmwarefiler" + #. TRANSLATORS: approved firmware has been checked by #. * the domain administrator msgid "There is no approved firmware." @@ -1234,6 +1680,18 @@ msgstr "Programmet virker måske kun korrekt som root" msgid "This remote contains firmware which is not embargoed, but is still being tested by the hardware vendor. You should ensure you have a way to manually downgrade the firmware if the firmware update fails." msgstr "Fjernen indeholder firmware som der ikke er embargo på, men som stadigvæk testes af hardwareproducenten. Du skal sikre dig at du har en manuel måde til at nedgradere firmwaren på hvis firmwareopdateringen mislykkedes." +#. TRANSLATORS: this is instructions on how to improve the HSI suffix +msgid "This system has HSI runtime issues." +msgstr "Systemet har problemer med HSI-runtime." + +#. TRANSLATORS: this is instructions on how to improve the HSI security level +msgid "This system has a low HSI security level." +msgstr "Systemet har et lavt HSI-sikkerhedsniveau." + +#. TRANSLATORS: description of dbxtool +msgid "This tool allows an administrator to apply UEFI dbx updates." +msgstr "Værktøjet giver en administrator mulighed for at anvende UEFI-dbx-opdateringer." + #. TRANSLATORS: the user needs to stop playing with stuff msgid "This tool can only be used by the root user" msgstr "Værktøjet kan kun bruges af root-brugeren" @@ -1242,10 +1700,42 @@ msgstr "Værktøjet kan kun bruges af root-brugeren" msgid "Type" msgstr "Type" +#. TRANSLATORS: partition refers to something on disk, again, hey Arch users +msgid "UEFI ESP partition not detected or configured" +msgstr "UEFI ESP-partition ikke registreret eller konfigureret" + #. TRANSLATORS: program name msgid "UEFI Firmware Utility" msgstr "UEFI-firmwareredskab" +#. TRANSLATORS: capsule updates are an optional BIOS feature +msgid "UEFI capsule updates not available or enabled" +msgstr "UEFI-kapselopdateringer ikke tilgængelige eller aktiveret" + +#. TRANSLATORS: program name +msgid "UEFI dbx Utility" +msgstr "UEFI-dbx-redskab" + +#. TRANSLATORS: Title: SB is a way of locking down UEFI +msgid "UEFI secure boot" +msgstr "UEFI sikkeropstart" + +#. TRANSLATORS: error message +msgid "Unable to connect to service" +msgstr "Kan ikke oprette forbindelse til tjeneste" + +#. TRANSLATORS: command description +msgid "Unbind current driver" +msgstr "Fjern binding af nuværende driver" + +#. TRANSLATORS: we will now offer this firmware to the user +msgid "Unblocking firmware:" +msgstr "Fjerner blokering af firmware:" + +#. TRANSLATORS: Suffix: the HSI result +msgid "Unencrypted" +msgstr "Dekrypteret" + #. TRANSLATORS: current daemon status is unknown #. TRANSLATORS: we don't know the license of the update #. TRANSLATORS: unknown release urgency @@ -1259,10 +1749,18 @@ msgstr "Ukendt enhed" msgid "Unlock the device to allow access" msgstr "Lås enheden op for at tillade adgang" +#. TRANSLATORS: Suffix: the HSI result +msgid "Unlocked" +msgstr "Låst op" + #. TRANSLATORS: command description msgid "Unlocks the device for firmware access" msgstr "Låser op for enheden for at få adgang til firmwaren" +#. TRANSLATORS: command description +msgid "Unmounts the ESP" +msgstr "Afmonterer ESP'en" + #. TRANSLATORS: command line option msgid "Unset the debugging flag during update" msgstr "Fjern fejlsøgningsflaget under opdatering" @@ -1272,6 +1770,10 @@ msgstr "Fjern fejlsøgningsflaget under opdatering" msgid "Unsupported daemon version %s, client version is %s" msgstr "Uunderstøttet dæmonversion %s, klientversionen er %s" +#. TRANSLATORS: Suffix: the HSI result +msgid "Untainted" +msgstr "Untainted" + #. TRANSLATORS: Device is updatable in this or any other mode msgid "Updatable" msgstr "Kan opdateres" @@ -1320,6 +1822,9 @@ msgstr "Opdater det gemte metadata med det nuværende indhold" msgid "Updates all firmware to latest versions available" msgstr "Opdaterer alle firmware til de seneste versioner" +msgid "Updating" +msgstr "Opdaterer" + #. TRANSLATORS: the first replacement is a display name #. * e.g. "ColorHugALS" and the second and third are #. * version numbers e.g. "1.2.3" @@ -1338,10 +1843,6 @@ msgstr "Opdaterer %s …" msgid "Upgrade available for %s from %s to %s" msgstr "Opgradering tilgængelig for %s fra %s til %s" -#. TRANSLATORS: the server sent the user a small message -msgid "Upload message:" -msgstr "Uploadmeddelelse:" - msgid "Upload report just this one time, but prompt again for future updates" msgid_plural "Upload reports just this one time, but prompt again for future updates" msgstr[0] "Upload rapport denne ene gang men spørg igen om fremtidige opdateringer" @@ -1360,6 +1861,18 @@ msgstr[1] "Upload rapporter denne gang og upload automatisk rapporter efter fuld msgid "Uploading firmware reports helps hardware vendors to quickly identify failing and successful updates on real devices." msgstr "Upload af firmwarerapporter hjælper hardwareproducenter til hurtigt at identificere opdateringer som fejlede og lykkedes på rigtigt hardware." +#. TRANSLATORS: how important the release is +msgid "Urgency" +msgstr "Vigtighed" + +#. TRANSLATORS: error message explaining command to run to how to get help +msgid "Use fwupdmgr --help for help" +msgstr "Brug fwupdmgr --help for hjælp" + +#. TRANSLATORS: error message explaining command to run to how to get help +msgid "Use fwupdtool --help for help" +msgstr "Brug fwupdtool --help for hjælp" + #. TRANSLATORS: command line option msgid "Use quirk flags when installing firmware" msgstr "Brug quirk-flag ved installation af firmware" @@ -1372,6 +1885,14 @@ msgstr "Brugeren er blevet underrettet" msgid "Username" msgstr "Brugernavn" +#. TRANSLATORS: Suffix: the HSI result +msgid "Valid" +msgstr "Gyldig" + +#. TRANSLATORS: ESP refers to the EFI System Partition +msgid "Validating ESP contents…" +msgstr "Validerer ESP-indhold …" + #. TRANSLATORS: one line variant of release (e.g. 'Prerelease' or 'China') msgid "Variant" msgstr "Variant" @@ -1384,9 +1905,13 @@ msgstr "Producent" msgid "Verifying…" msgstr "Verificerer …" -#. TRANSLATORS: try to help -msgid "WARNING: Ignoring SSL strict checks, to do this automatically in the future export DISABLE_SSL_STRICT in your environment" -msgstr "ADVARSEL: Ignorerer strikse SSL-tjeks. Eksportér DISABLE_SSL_STRICT i dit miljø for at gøre det automatisk i fremtiden" +#. TRANSLATORS: the detected version number of the dbx +msgid "Version" +msgstr "Version" + +#. TRANSLATORS: this is a prefix on the console +msgid "WARNING:" +msgstr "ADVARSEL:" #. TRANSLATORS: waiting for device to do something msgid "Waiting…" @@ -1408,6 +1933,10 @@ msgstr "Skriv firmware fra fil ind i enhed" msgid "Write firmware from file into one partition" msgstr "Skriv firmware fra fil ind i en partition" +#. TRANSLATORS: decompressing images from a container firmware +msgid "Writing file:" +msgstr "Skriver fil:" + #. TRANSLATORS: writing to the flash chips msgid "Writing…" msgstr "Skriver …" @@ -1416,19 +1945,19 @@ msgstr "Skriver …" msgid "Your distributor may not have verified any of the firmware updates for compatibility with your system or connected devices." msgstr "Din distributør har måske ikke verificeret kompatibiliteten af firmwareopdateringerne med dit system eller tilsluttede enheder." +#. TRANSLATORS: %1 is the device vendor name +#, c-format +msgid "Your hardware may be damaged using this firmware, and installing this release may void any warranty with %s." +msgstr "Der er mulighed for at din hardware kan tage skade hvis firmwaren bruges og installation af udgivelsen kan ugyldiggøre garantien med %s." + +#. TRANSLATORS: this is the default branch name when unset +msgid "default" +msgstr "standard" + #. TRANSLATORS: program name msgid "fwupd TPM event log utility" msgstr "fwupd TPM-hændelseslogredskab" -#. TRANSLATORS: message letting the user know no device upgrade available due -#. to missing on LVFS -#. * %1 is the device name -#, c-format -msgid "• %s has no available firmware updates" -msgstr "• %s har ingen tilgængelige firmwareopdateringer" - -#. TRANSLATORS: message letting the user know no device upgrade available -#. * %1 is the device name -#, c-format -msgid "• %s has the latest available firmware version" -msgstr "• %s har den seneste tilgængelige firmwareversion" +#. TRANSLATORS: Title: if the fwupd plugins are all present and correct +msgid "fwupd plugins" +msgstr "fwupd-plugins" diff --git a/po/de.po b/po/de.po index f69da6082..b056bae89 100644 --- a/po/de.po +++ b/po/de.po @@ -17,7 +17,7 @@ msgstr "" "Language: de\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n" -#. TRANSLATORS: more than a minute remaining +#. more than a minute #, c-format msgid "%.0f minute remaining" msgid_plural "%.0f minutes remaining" @@ -177,6 +177,7 @@ msgstr "Nicht auf nicht erfassten Verlauf prüfen" msgid "Do not write to the history database" msgstr "Nicht in die Verlaufsdatenbank schreiben" +#. TRANSLATORS: success #. success msgid "Done!" msgstr "Fertig." @@ -213,6 +214,8 @@ msgstr "Das angegebene ESP war nicht gültig" msgid "Enable firmware update support on supported systems" msgstr "Firmware-Aktualisierungsunterstützung auf unterstützten Systemen aktivieren" +#. TRANSLATORS: Suffix: the HSI result +#. TRANSLATORS: Plugin is active and in use #. TRANSLATORS: if the remote is enabled msgid "Enabled" msgstr "Aktiviert" @@ -243,22 +246,6 @@ msgstr "Nach dem Laden der Engine beenden" msgid "Failed to parse arguments" msgstr "Verarbeitung der Argumente schlug fehl" -#. TRANSLATORS: downloading unknown file -msgid "Fetching file" -msgstr "Datei wird abgerufen" - -#. TRANSLATORS: downloading new firmware file -msgid "Fetching firmware" -msgstr "Firmware wird abgerufen" - -#. TRANSLATORS: downloading new metadata file -msgid "Fetching metadata" -msgstr "Metadaten werden abgerufen" - -#. TRANSLATORS: downloading new signing file -msgid "Fetching signature" -msgstr "Signatur wird abgerufen" - #. TRANSLATORS: filename of the local file msgid "Filename" msgstr "Dateiname" @@ -299,6 +286,10 @@ msgstr "Firmware-Aktualisierungen werden auf diesem System unterstützt." msgid "Force the action ignoring all warnings" msgstr "Aktion erzwingen, bei der alle Warnungen ignoriert werden" +#. TRANSLATORS: Suffix: the HSI result +msgid "Found" +msgstr "Gefunden" + #. TRANSLATORS: command description msgid "Get all devices that support firmware updates" msgstr "Alle Geräte ermitteln, die Firmware-Aktualisierungen unterstützen" @@ -392,6 +383,7 @@ msgstr "Metadaten können über den Linux Vendor Firmware Service bezogen werden msgid "Monitor the daemon for events" msgstr "Hintergrundprogramm auf Ereignisse überwachen" +#. TRANSLATORS: user did not tell the tool what to do msgid "No action specified!" msgstr "Keine Aktion angegeben!" @@ -403,9 +395,9 @@ msgstr "Es wurde keine Hardware erkannt, deren Firmware aktualisiert werden kann msgid "No plugins found" msgstr "Keine Plugins gefunden" -#. TRANSLATORS: command line option -msgid "Override plugin warning" -msgstr "Plugin-Warnung überschreiben" +#. TRANSLATORS: Suffix: the HSI result +msgid "OK" +msgstr "Ok" #. TRANSLATORS: command line option msgid "Override the default ESP path" @@ -601,10 +593,6 @@ msgstr "Aktualisieren von %s von %s nach %s …" msgid "Updating %s…" msgstr "%s wird aktualisiert …" -#. TRANSLATORS: the server sent the user a small message -msgid "Upload message:" -msgstr "Nachricht beim Hochladen:" - #. TRANSLATORS: ask the user to upload msgid "Upload report now?" msgstr "Bericht jetzt hochladen?" @@ -621,6 +609,10 @@ msgstr "Benutzername" msgid "Verifying…" msgstr "Überprüfung …" +#. TRANSLATORS: the detected version number of the dbx +msgid "Version" +msgstr "Version" + #. TRANSLATORS: waiting for device to do something msgid "Waiting…" msgstr "Warten …" diff --git a/po/en_GB.po b/po/en_GB.po index c59a85661..d1a3e46a2 100644 --- a/po/en_GB.po +++ b/po/en_GB.po @@ -3,8 +3,8 @@ # This file is distributed under the same license as the fwupd package. # # Translators: -# Andi Chandler , 2019 -# Richard Hughes , 2015,2017-2019 +# Andi Chandler , 2019-2020 +# Richard Hughes , 2015,2017-2020 msgid "" msgstr "" "Project-Id-Version: fwupd\n" @@ -23,6 +23,18 @@ msgid_plural "%.0f minutes remaining" msgstr[0] "%.0f minute remaining" msgstr[1] "%.0f minutes remaining" +#. TRANSLATORS: the CPU microcode is firmware loaded onto the CPU +#. * at system bootup +#, c-format +msgid "%s CPU Microcode Update" +msgstr "%s CPU Microcode Update" + +#. TRANSLATORS: a specific part of hardware, +#. * the first %s is the device name, e.g. 'Secure Boot` +#, c-format +msgid "%s Configuration Update" +msgstr "%s Configuration Update" + #. TRANSLATORS: ME stands for Management Engine, where #. * the first %s is the device name, e.g. 'ThinkPad P50` #, c-format @@ -86,6 +98,11 @@ msgstr "%s Update" msgid "%s and all connected devices may not be usable while updating." msgstr "%s and all connected devices may not be usable while updating." +#. TRANSLATORS: Title: %s is ME kind, e.g. CSME/TXT +#, c-format +msgid "%s manufacturing mode" +msgstr "%s manufacturing mode" + #. TRANSLATORS: warn the user before updating, %1 is a device name #, c-format msgid "%s must remain connected for the duration of the update to avoid damage." @@ -96,6 +113,21 @@ msgstr "%s must remain connected for the duration of the update to avoid damage. msgid "%s must remain plugged into a power source for the duration of the update to avoid damage." msgstr "%s must remain plugged into a power source for the duration of the update to avoid damage." +#. TRANSLATORS: Title: %s is ME kind, e.g. CSME/TXT +#, c-format +msgid "%s override" +msgstr "%s override" + +#. TRANSLATORS: Title: %1 is ME kind, e.g. CSME/TXT, %2 is a version number +#, c-format +msgid "%s v%s" +msgstr "%s v%s" + +#. TRANSLATORS: Title: %s is ME kind, e.g. CSME/TXT +#, c-format +msgid "%s version" +msgstr "%s version" + #. TRANSLATORS: duration in days! #, c-format msgid "%u day" @@ -103,6 +135,12 @@ msgid_plural "%u days" msgstr[0] "%u day" msgstr[1] "%u days" +#, c-format +msgid "%u device has a firmware upgrade available." +msgid_plural "%u devices have a firmware upgrade available." +msgstr[0] "%u device has a firmware upgrade available." +msgstr[1] "%u devices have a firmware upgrade available." + #. TRANSLATORS: duration in minutes #, c-format msgid "%u hour" @@ -131,6 +169,10 @@ msgid_plural "%u seconds" msgstr[0] "%u second" msgstr[1] "%u seconds" +#. TRANSLATORS: this is shown as a suffix for obsoleted tests +msgid "(obsoleted)" +msgstr "(obsoleted)" + #. TRANSLATORS: command description msgid "Activate devices" msgstr "Activate devices" @@ -175,6 +217,10 @@ msgstr "Allow downgrading firmware versions" msgid "Allow reinstalling existing firmware versions" msgstr "Allow reinstalling existing firmware versions" +#. TRANSLATORS: command line option +msgid "Allow switching firmware branch" +msgstr "Allow switching firmware branch" + #. TRANSLATORS: explain why we want to reboot msgid "An update requires a reboot to complete." msgstr "An update requires a reboot to complete." @@ -191,6 +237,18 @@ msgstr "Answer yes to all questions" msgid "Apply firmware updates" msgstr "Apply firmware updates" +#. TRANSLATORS: command line option +msgid "Apply update even when not advised" +msgstr "Apply update even when not advised" + +#. TRANSLATORS: command line option +msgid "Apply update files" +msgstr "Apply update files" + +#. TRANSLATORS: actually sending the update to the hardware +msgid "Applying update…" +msgstr "Applying update…" + #. TRANSLATORS: approved firmware has been checked by #. * the domain administrator msgid "Approved firmware:" @@ -198,6 +256,10 @@ msgid_plural "Approved firmware:" msgstr[0] "Approved firmware:" msgstr[1] "Approved firmware:" +#. TRANSLATORS: stop nagging the user +msgid "Ask again next time?" +msgstr "Ask again next time?" + #. TRANSLATORS: command description msgid "Attach to firmware mode" msgstr "Attach to firmware mode" @@ -254,10 +316,38 @@ msgstr "Authentication is required to update the stored checksums for the device msgid "Automatic Reporting" msgstr "Automatic Reporting" +#. TRANSLATORS: can we JFDI? +msgid "Automatically upload every time?" +msgstr "Automatically upload every time?" + +#. TRANSLATORS: command description +msgid "Bind new kernel driver" +msgstr "Bind new kernel driver" + +#. TRANSLATORS: there follows a list of hashes +msgid "Blocked firmware files:" +msgstr "Blocked firmware files:" + +#. TRANSLATORS: we will not offer this firmware to the user +msgid "Blocking firmware:" +msgstr "Blocking firmware:" + +#. TRANSLATORS: command description +msgid "Blocks a specific firmware from being installed" +msgstr "Blocks a specific firmware from being installed" + #. TRANSLATORS: firmware version of bootloader msgid "Bootloader Version" msgstr "Bootloader Version" +#. TRANSLATORS: the stream of firmware, e.g. nonfree or open-source +msgid "Branch" +msgstr "Branch" + +#. TRANSLATORS: command description +msgid "Build a firmware file" +msgstr "Build a firmware file" + #. TRANSLATORS: command description msgid "Build firmware using a sandbox" msgstr "Build firmware using a sandbox" @@ -270,6 +360,14 @@ msgstr "Cancel" msgid "Cancelled" msgstr "Cancelled" +#. TRANSLATORS: same or newer update already applied +msgid "Cannot apply as dbx update has already been applied." +msgstr "Cannot apply as dbx update has already been applied." + +#. TRANSLATORS: the user is using a LiveCD or LiveUSB install disk +msgid "Cannot apply updates on live media" +msgstr "Cannot apply updates on live media" + #. TRANSLATORS: this is when a device is hotplugged #. TRANSLATORS: this is when the daemon state changes msgid "Changed" @@ -283,6 +381,11 @@ msgstr "Checks cryptographic hash matches firmware" msgid "Checksum" msgstr "Checksum" +#. TRANSLATORS: get interactive prompt, where branch is the +#. * supplier of the firmware, e.g. "non-free" or "free" +msgid "Choose a branch:" +msgstr "Choose a branch:" + #. TRANSLATORS: get interactive prompt msgid "Choose a device:" msgstr "Choose a device:" @@ -295,6 +398,10 @@ msgstr "Choose a firmware type:" msgid "Choose a release:" msgstr "Choose a release:" +#. TRANSLATORS: get interactive prompt +msgid "Choose a volume:" +msgstr "Choose a volume:" + #. TRANSLATORS: command description msgid "Clears any updates scheduled to be updated offline" msgstr "Clears any updates scheduled to be updated offline" @@ -311,6 +418,18 @@ msgstr "Command not found" msgid "Continue with update?" msgstr "Continue with update?" +#. TRANSLATORS: command description +msgid "Convert a firmware file" +msgstr "Convert a firmware file" + +#. TRANSLATORS: when the update was built +msgid "Created" +msgstr "Created" + +#. TRANSLATORS: the release urgency +msgid "Critical" +msgstr "Critical" + #. TRANSLATORS: Device supports some form of checksum verification msgid "Cryptographic hash verification is available" msgstr "Cryptographic hash verification is available" @@ -363,10 +482,18 @@ msgstr "Device can recover flash failures" msgid "Device changed:" msgstr "Device changed:" +#. TRANSLATORS: a version check is required for all firmware +msgid "Device firmware is required to have a version check" +msgstr "Device firmware is required to have a version check" + #. TRANSLATORS: Is locked and can be unlocked msgid "Device is locked" msgstr "Device is locked" +#. TRANSLATORS: a version check is required for all firmware +msgid "Device is required to install all provided releases" +msgstr "Device is required to install all provided releases" + #. TRANSLATORS: Device remains usable during update msgid "Device is usable for the duration of the update" msgstr "Device is usable for the duration of the update" @@ -379,10 +506,18 @@ msgstr "Device removed:" msgid "Device stages updates" msgstr "Device stages updates" +#. TRANSLATORS: there is more than one supplier of the firmware +msgid "Device supports switching to a different branch of firmware" +msgstr "Device supports switching to a different branch of firmware" + #. TRANSLATORS: Device update needs to be separately activated msgid "Device update needs activation" msgstr "Device update needs activation" +#. TRANSLATORS: save the old firmware to disk before installing the new one +msgid "Device will backup firmware before installing" +msgstr "Device will backup firmware before installing" + #. TRANSLATORS: Device will not return after update completes msgid "Device will not re-appear after update completes" msgstr "Device will not re-appear after update completes" @@ -395,6 +530,20 @@ msgstr "Devices that have been updated successfully:" msgid "Devices that were not updated correctly:" msgstr "Devices that were not updated correctly:" +#. TRANSLATORS: message letting the user know no device upgrade available due +#. to missing on LVFS +msgid "Devices with no available firmware updates: " +msgstr "Devices with no available firmware updates: " + +#. TRANSLATORS: message letting the user know no device upgrade available +msgid "Devices with the latest available firmware version:" +msgstr "Devices with the latest available firmware version:" + +#. TRANSLATORS: Suffix: the HSI result +#. TRANSLATORS: Plugin is inactive and not used +msgid "Disabled" +msgstr "Disabled" + msgid "Disabled fwupdate debugging" msgstr "Disabled fwupdate debugging" @@ -444,6 +593,11 @@ msgstr[1] "Do not upload reports, and never ask to upload reports for future upd msgid "Do not write to the history database" msgstr "Do not write to the history database" +#. TRANSLATORS: should the branch be changed +msgid "Do you understand the consequences of changing the firmware branch?" +msgstr "Do you understand the consequences of changing the firmware branch?" + +#. TRANSLATORS: success #. success msgid "Done!" msgstr "Done!" @@ -488,6 +642,8 @@ msgstr "Enable firmware update support on supported systems" msgid "Enable this remote?" msgstr "Enable this remote?" +#. TRANSLATORS: Suffix: the HSI result +#. TRANSLATORS: Plugin is active and in use #. TRANSLATORS: if the remote is enabled msgid "Enabled" msgstr "Enabled" @@ -506,6 +662,14 @@ msgstr "Enabling this functionality is done at your own risk, which means you ha msgid "Enabling this remote is done at your own risk." msgstr "Enabling this remote is done at your own risk." +#. TRANSLATORS: Suffix: the HSI result +msgid "Encrypted" +msgstr "Encrypted" + +#. TRANSLATORS: Title: Memory contents are encrypted, e.g. Intel TME +msgid "Encrypted RAM" +msgstr "Encrypted RAM" + #. TRANSLATORS: command description msgid "Erase all firmware update history" msgstr "Erase all firmware update history" @@ -522,13 +686,25 @@ msgstr "Exit after a small delay" msgid "Exit after the engine has loaded" msgstr "Exit after the engine has loaded" +#. TRANSLATORS: command description +msgid "Extract a firmware blob to images" +msgstr "Extract a firmware blob to images" + +#. TRANSLATORS: Suffix: the fallback HSI result +msgid "Failed" +msgstr "Failed" + +#. TRANSLATORS: dbx file failed to be applied as an update +msgid "Failed to apply update" +msgstr "Failed to apply update" + #. TRANSLATORS: we could not talk to the fwupd daemon msgid "Failed to connect to daemon" msgstr "Failed to connect to daemon" -#. TRANSLATORS: the server is rate-limiting downloads -msgid "Failed to download due to server limit" -msgstr "Failed to download due to server limit" +#. TRANSLATORS: could not parse file +msgid "Failed to extract local dbx " +msgstr "Failed to extract local dbx " #. TRANSLATORS: we could not get the devices to update offline msgid "Failed to get pending devices" @@ -538,10 +714,19 @@ msgstr "Failed to get pending devices" msgid "Failed to install firmware update" msgstr "Failed to install firmware update" +#. TRANSLATORS: could not read existing system data +#. TRANSLATORS: could not read file +msgid "Failed to load local dbx" +msgstr "Failed to load local dbx" + #. TRANSLATORS: quirks are device-specific workarounds msgid "Failed to load quirks" msgstr "Failed to load quirks" +#. TRANSLATORS: could not read existing system data +msgid "Failed to load system dbx" +msgstr "Failed to load system dbx" + #. TRANSLATORS: the user didn't read the man page msgid "Failed to parse arguments" msgstr "Failed to parse arguments" @@ -554,6 +739,10 @@ msgstr "Failed to parse file" msgid "Failed to parse flags for --filter" msgstr "Failed to parse flags for --filter" +#. TRANSLATORS: could not parse file +msgid "Failed to parse local dbx" +msgstr "Failed to parse local dbx" + #. TRANSLATORS: we could not reboot for some reason msgid "Failed to reboot" msgstr "Failed to reboot" @@ -562,21 +751,10 @@ msgstr "Failed to reboot" msgid "Failed to set splash mode" msgstr "Failed to set splash mode" -#. TRANSLATORS: downloading unknown file -msgid "Fetching file" -msgstr "Fetching file" - -#. TRANSLATORS: downloading new firmware file -msgid "Fetching firmware" -msgstr "Fetching firmware" - -#. TRANSLATORS: downloading new metadata file -msgid "Fetching metadata" -msgstr "Fetching metadata" - -#. TRANSLATORS: downloading new signing file -msgid "Fetching signature" -msgstr "Fetching signature" +#. TRANSLATORS: something with a blocked hash exists +#. * in the users ESP -- which would be bad! +msgid "Failed to validate ESP contents" +msgstr "Failed to validate ESP contents" #. TRANSLATORS: filename of the local file msgid "Filename" @@ -586,6 +764,10 @@ msgstr "Filename" msgid "Filename Signature" msgstr "Filename Signature" +#. TRANSLATORS: user did not include a filename parameter +msgid "Filename required" +msgstr "Filename required" + #. TRANSLATORS: command line option msgid "Filter with a set of device flags using a ~ prefix to exclude, e.g. 'internal,~needs-reboot'" msgstr "Filter with a set of device flags using a ~ prefix to exclude, e.g. 'internal,~needs-reboot'" @@ -610,6 +792,22 @@ msgstr "Firmware Update Daemon" msgid "Firmware Utility" msgstr "Firmware Utility" +#. TRANSLATORS: Title: if we can verify the firmware checksums +msgid "Firmware attestation" +msgstr "Firmware attestation" + +#. TRANSLATORS: system is not booted in UEFI mode +msgid "Firmware can not be updated in legacy BIOS mode" +msgstr "Firmware can not be updated in legacy BIOS mode" + +#. TRANSLATORS: user selected something not possible +msgid "Firmware is already blocked" +msgstr "Firmware is already blocked" + +#. TRANSLATORS: user selected something not possible +msgid "Firmware is not already blocked" +msgstr "Firmware is not already blocked" + #. TRANSLATORS: the metadata is very out of date; %u is a number > 1 #, c-format msgid "Firmware metadata has not been updated for %u day and may not be up to date." @@ -617,19 +815,36 @@ msgid_plural "Firmware metadata has not been updated for %u days and may not be msgstr[0] "Firmware metadata has not been updated for %u day and may not be up to date." msgstr[1] "Firmware metadata has not been updated for %u days and may not be up to date." +#. TRANSLATORS: Title: if firmware updates are available +msgid "Firmware updates" +msgstr "Firmware updates" + msgid "Firmware updates are not supported on this machine." msgstr "Firmware updates are not supported on this machine." msgid "Firmware updates are supported on this machine." msgstr "Firmware updates are supported on this machine." +#. TRANSLATORS: user needs to run a command +msgid "Firmware updates disabled; run 'fwupdmgr unlock' to enable" +msgstr "Firmware updates disabled; run 'fwupdmgr unlock' to enable" + +#. TRANSLATORS: description of plugin state, e.g. disabled #. TRANSLATORS: release properties msgid "Flags" msgstr "Flags" +#. TRANSLATORS: command line option +msgid "Force the action by relaxing some runtime checks" +msgstr "Force the action by relaxing some runtime checks" + msgid "Force the action ignoring all warnings" msgstr "Force the action ignoring all warnings" +#. TRANSLATORS: Suffix: the HSI result +msgid "Found" +msgstr "Found" + #. TRANSLATORS: global ID common to all similar hardware msgid "GUID" msgid_plural "GUIDs" @@ -660,9 +875,17 @@ msgstr "Gets details about a firmware file" msgid "Gets the configured remotes" msgstr "Gets the configured remotes" +#. TRANSLATORS: command description +msgid "Gets the host security attributes" +msgstr "Gets the host security attributes" + #. TRANSLATORS: firmware approved by the admin -msgid "Gets the list of approved firmware." -msgstr "Gets the list of approved firmware." +msgid "Gets the list of approved firmware" +msgstr "Gets the list of approved firmware" + +#. TRANSLATORS: command description +msgid "Gets the list of blocked firmware" +msgstr "Gets the list of blocked firmware" #. TRANSLATORS: command description msgid "Gets the list of updates for connected hardware" @@ -680,6 +903,19 @@ msgstr "Gets the results from the last update" msgid "Hardware is waiting to be replugged" msgstr "Hardware is waiting to be replugged" +#. TRANSLATORS: the release urgency +msgid "High" +msgstr "High" + +#. TRANSLATORS: this is a string like 'HSI:2-U' +msgid "Host Security ID:" +msgstr "Host Security ID:" + +#. TRANSLATORS: Title: +#. https://en.wikipedia.org/wiki/Input%E2%80%93output_memory_management_unit +msgid "IOMMU" +msgstr "IOMMU" + #. TRANSLATORS: daemon is inactive msgid "Idle…" msgstr "Idle…" @@ -688,10 +924,26 @@ msgstr "Idle…" msgid "Ignore SSL strict checks when downloading files" msgstr "Ignore SSL strict checks when downloading files" +#. TRANSLATORS: command line option +msgid "Ignore firmware checksum failures" +msgstr "Ignore firmware checksum failures" + +#. TRANSLATORS: command line option +msgid "Ignore firmware hardware mismatch failures" +msgstr "Ignore firmware hardware mismatch failures" + +#. TRANSLATORS: command line option +msgid "Ignore requirement of external power source" +msgstr "Ignore requirement of external power source" + #. TRANSLATORS: Ignore validation safety checks when flashing this device msgid "Ignore validation safety checks" msgstr "Ignore validation safety checks" +#. TRANSLATORS: try to help +msgid "Ignoring SSL strict checks, to do this automatically in the future export DISABLE_SSL_STRICT in your environment" +msgstr "Ignoring SSL strict checks, to do this automatically in the future export DISABLE_SSL_STRICT in your environment" + #. TRANSLATORS: length of time the update takes to apply msgid "Install Duration" msgstr "Install Duration" @@ -736,10 +988,57 @@ msgstr "Installing firmware update…" msgid "Installing on %s…" msgstr "Installing on %s…" +#. TRANSLATORS: Title: BootGuard is a trademark from Intel +msgid "Intel BootGuard" +msgstr "Intel BootGuard" + +#. TRANSLATORS: Title: BootGuard is a trademark from Intel, +#. * ACM means to verify the integrity of Initial Boot Block +msgid "Intel BootGuard ACM protected" +msgstr "Intel BootGuard ACM protected" + +#. TRANSLATORS: Title: BootGuard is a trademark from Intel, +#. * OTP = one time programmable +msgid "Intel BootGuard OTP fuse" +msgstr "Intel BootGuard OTP fuse" + +#. TRANSLATORS: Title: BootGuard is a trademark from Intel, +#. * error policy is what to do on failure +msgid "Intel BootGuard error policy" +msgstr "Intel BootGuard error policy" + +#. TRANSLATORS: Title: BootGuard is a trademark from Intel, +#. * verified boot refers to the way the boot process is verified +msgid "Intel BootGuard verified boot" +msgstr "Intel BootGuard verified boot" + +#. TRANSLATORS: Title: CET = Control-flow Enforcement Technology, +#. * active means being used by the OS +msgid "Intel CET Active" +msgstr "Intel CET Active" + +#. TRANSLATORS: Title: CET = Control-flow Enforcement Technology, +#. * enabled means supported by the processor +msgid "Intel CET Enabled" +msgstr "Intel CET Enabled" + +#. TRANSLATORS: Title: Direct Connect Interface (DCI) allows +#. * debugging of Intel processors using the USB3 port +msgid "Intel DCI debugger" +msgstr "Intel DCI debugger" + +#. TRANSLATORS: Title: SMAP = Supervisor Mode Access Prevention +msgid "Intel SMAP" +msgstr "Intel SMAP" + #. TRANSLATORS: Device cannot be removed easily msgid "Internal device" msgstr "Internal device" +#. TRANSLATORS: Suffix: the HSI result +msgid "Invalid" +msgstr "Invalid" + #. TRANSLATORS: Is currently in bootloader mode msgid "Is in bootloader mode" msgstr "Is in bootloader mode" @@ -771,6 +1070,22 @@ msgstr "Linux Vendor Firmware Service (stable firmware)" msgid "Linux Vendor Firmware Service (testing firmware)" msgstr "Linux Vendor Firmware Service (testing firmware)" +#. TRANSLATORS: Title: if it's tainted or not +msgid "Linux kernel" +msgstr "Linux kernel" + +#. TRANSLATORS: Title: lockdown is a security mode of the kernel +msgid "Linux kernel lockdown" +msgstr "Linux kernel lockdown" + +#. TRANSLATORS: Title: swap space or swap partition +msgid "Linux swap" +msgstr "Linux swap" + +#. TRANSLATORS: command line option +msgid "List entries in dbx" +msgstr "List entries in dbx" + #. TRANSLATORS: command line option msgid "List supported firmware updates" msgstr "List supported firmware updates" @@ -779,13 +1094,43 @@ msgstr "List supported firmware updates" msgid "List the available firmware types" msgstr "List the available firmware types" +#. TRANSLATORS: command description +msgid "Lists files on the ESP" +msgstr "Lists files on the ESP" + #. TRANSLATORS: parsing the firmware information msgid "Loading…" msgstr "Loading…" +#. TRANSLATORS: Suffix: the HSI result +msgid "Locked" +msgstr "Locked" + +#. TRANSLATORS: the release urgency +msgid "Low" +msgstr "Low" + +#. TRANSLATORS: Title: MEI = Intel Management Engine +msgid "MEI manufacturing mode" +msgstr "MEI manufacturing mode" + +#. TRANSLATORS: Title: MEI = Intel Management Engine, and the +#. * "override" is the physical PIN that can be driven to +#. * logic high -- luckily it is probably not accessible to +#. * end users on consumer boards +msgid "MEI override" +msgstr "MEI override" + +msgid "MEI version" +msgstr "MEI version" + #. TRANSLATORS: command line option -msgid "Manually whitelist specific plugins" -msgstr "Manually whitelist specific plugins" +msgid "Manually enable specific plugins" +msgstr "Manually enable specific plugins" + +#. TRANSLATORS: the release urgency +msgid "Medium" +msgstr "Medium" #. TRANSLATORS: remote URI msgid "Metadata Signature" @@ -809,8 +1154,8 @@ msgid "Mismatched daemon and client, use %s instead" msgstr "Mismatched daemon and client, use %s instead" #. TRANSLATORS: sets something in daemon.conf -msgid "Modifies a daemon configuration value." -msgstr "Modifies a daemon configuration value." +msgid "Modifies a daemon configuration value" +msgstr "Modifies a daemon configuration value" #. TRANSLATORS: command description msgid "Modifies a given remote" @@ -826,6 +1171,10 @@ msgstr "Modify daemon configuration" msgid "Monitor the daemon for events" msgstr "Monitor the daemon for events" +#. TRANSLATORS: command description +msgid "Mounts the ESP" +msgstr "Mounts the ESP" + #. TRANSLATORS: Requires a reboot to apply firmware or to reload hardware msgid "Needs a reboot after installation" msgstr "Needs a reboot after installation" @@ -838,6 +1187,7 @@ msgstr "Needs shutdown after installation" msgid "New version" msgstr "New version" +#. TRANSLATORS: user did not tell the tool what to do msgid "No action specified!" msgstr "No action specified!" @@ -875,14 +1225,22 @@ msgstr "No remotes available" msgid "No updates were applied" msgstr "No updates were applied" +#. TRANSLATORS: Suffix: the HSI result +msgid "Not found" +msgstr "Not found" + +#. TRANSLATORS: Suffix: the HSI result +msgid "Not supported" +msgstr "Not supported" + +#. TRANSLATORS: Suffix: the HSI result +msgid "OK" +msgstr "OK" + #. TRANSLATORS: command line option msgid "Only show single PCR value" msgstr "Only show single PCR value" -#. TRANSLATORS: command line option -msgid "Override plugin warning" -msgstr "Override plugin warning" - #. TRANSLATORS: command line option msgid "Override the default ESP path" msgstr "Override the default ESP path" @@ -895,6 +1253,14 @@ msgstr "Override warnings and force the action" msgid "Parse and show details about a firmware file" msgstr "Parse and show details about a firmware file" +#. TRANSLATORS: reading new dbx from the update +msgid "Parsing dbx update…" +msgstr "Parsing dbx update…" + +#. TRANSLATORS: reading existing dbx from the system +msgid "Parsing system dbx…" +msgstr "Parsing system dbx…" + #. TRANSLATORS: remote filename base msgid "Password" msgstr "Password" @@ -911,6 +1277,14 @@ msgstr "Percentage complete" msgid "Please enter a number from 0 to %u: " msgstr "Please enter a number from 0 to %u: " +#. TRANSLATORS: Failed to open plugin, hey Arch users +msgid "Plugin dependencies missing" +msgstr "Plugin dependencies missing" + +#. TRANSLATORS: Title: DMA as in https://en.wikipedia.org/wiki/DMA_attack +msgid "Pre-boot DMA protection" +msgstr "Pre-boot DMA protection" + #. TRANSLATORS: version number of previous firmware msgid "Previous version" msgstr "Previous version" @@ -966,8 +1340,12 @@ msgid "Refresh metadata from remote server" msgstr "Refresh metadata from remote server" #. TRANSLATORS: command description -msgid "Reinstall current firmware on the device." -msgstr "Reinstall current firmware on the device." +msgid "Reinstall current firmware on the device" +msgstr "Reinstall current firmware on the device" + +#. TRANSLATORS: command description +msgid "Reinstall firmware on a device" +msgstr "Reinstall firmware on a device" #. TRANSLATORS: the first replacement is a display name #. * e.g. "ColorHugALS" and the second is a version number @@ -997,9 +1375,13 @@ msgstr "Report URI" msgid "Reported to remote server" msgstr "Reported to remote server" -#. TRANSLATORS: Must be plugged in to an outlet -msgid "Requires AC power" -msgstr "Requires AC power" +#. TRANSLATORS: the user is using Gentoo/Arch and has screwed something up +msgid "Required efivarfs filesystem was not found" +msgstr "Required efivarfs filesystem was not found" + +#. TRANSLATORS: not required for this system +msgid "Required hardware was not found" +msgstr "Required hardware was not found" #. TRANSLATORS: Requires a bootloader mode to be manually enabled by the user msgid "Requires a bootloader" @@ -1025,6 +1407,9 @@ msgstr "Restarting device…" msgid "Return all the hardware IDs for the machine" msgstr "Return all the hardware IDs for the machine" +msgid "Run `fwupdmgr get-upgrades` for more information." +msgstr "Run `fwupdmgr get-upgrades` for more information." + #. TRANSLATORS: command line option msgid "Run the plugin composite cleanup routine when using install-blob" msgstr "Run the plugin composite cleanup routine when using install-blob" @@ -1033,6 +1418,22 @@ msgstr "Run the plugin composite cleanup routine when using install-blob" msgid "Run the plugin composite prepare routine when using install-blob" msgstr "Run the plugin composite prepare routine when using install-blob" +#. TRANSLATORS: this is the HSI suffix +msgid "Runtime Suffix" +msgstr "Runtime Suffix" + +#. TRANSLATORS: Title: SPI refers to the flash chip in the computer +msgid "SPI BIOS region" +msgstr "SPI BIOS region" + +#. TRANSLATORS: Title: SPI refers to the flash chip in the computer +msgid "SPI lock" +msgstr "SPI lock" + +#. TRANSLATORS: Title: SPI refers to the flash chip in the computer +msgid "SPI write" +msgstr "SPI write" + #. TRANSLATORS: command line option msgid "Save device state into a JSON file between executions" msgstr "Save device state into a JSON file between executions" @@ -1049,6 +1450,10 @@ msgstr "Scheduling…" msgid "Selected device" msgstr "Selected device" +#. TRANSLATORS: Volume has been chosen by the user +msgid "Selected volume" +msgstr "Selected volume" + #. TRANSLATORS: serial number of hardware msgid "Serial Number" msgstr "Serial Number" @@ -1057,17 +1462,18 @@ msgstr "Serial Number" msgid "Set the debugging flag during update" msgstr "Set the debugging flag during update" +#. TRANSLATORS: firmware approved by the admin msgid "Sets the list of approved firmware" msgstr "Sets the list of approved firmware" -#. TRANSLATORS: firmware approved by the admin -msgid "Sets the list of approved firmware." -msgstr "Sets the list of approved firmware." - #. TRANSLATORS: command description msgid "Share firmware history with the developers" msgstr "Share firmware history with the developers" +#. TRANSLATORS: command line option +msgid "Show all results" +msgstr "Show all results" + #. TRANSLATORS: command line option msgid "Show client and daemon versions" msgstr "Show client and daemon versions" @@ -1100,6 +1506,10 @@ msgstr "Show history of firmware updates" msgid "Show plugin verbose information" msgstr "Show plugin verbose information" +#. TRANSLATORS: command line option +msgid "Show the calculated version of the dbx" +msgstr "Show the calculated version of the dbx" + #. TRANSLATORS: command line option msgid "Show the debug log from the last attempted update" msgstr "Show the debug log from the last attempted update" @@ -1137,6 +1547,10 @@ msgstr "Source" msgid "Specify Vendor/Product ID(s) of DFU device" msgstr "Specify Vendor/Product ID(s) of DFU device" +#. TRANSLATORS: command line option +msgid "Specify the dbx database file" +msgstr "Specify the dbx database file" + msgid "Specify the number of bytes per USB transfer" msgstr "Specify the number of bytes per USB transfer" @@ -1194,10 +1608,42 @@ msgstr "Successfully verified device checksums" msgid "Summary" msgstr "Summary" +#. TRANSLATORS: Suffix: the HSI result +msgid "Supported" +msgstr "Supported" + #. TRANSLATORS: Is found in current metadata msgid "Supported on remote server" msgstr "Supported on remote server" +#. TRANSLATORS: Title: a better sleep state +msgid "Suspend-to-idle" +msgstr "Suspend-to-idle" + +#. TRANSLATORS: Title: sleep state +msgid "Suspend-to-ram" +msgstr "Suspend-to-ram" + +#. TRANSLATORS: command description +msgid "Switch the firmware branch on the device" +msgstr "Switch the firmware branch on the device" + +#. TRANSLATORS: Must be plugged in to an outlet +msgid "System requires external power source" +msgstr "System requires external power source" + +#. TRANSLATORS: Title: the PCR is rebuilt from the TPM event log +msgid "TPM PCR0 reconstruction" +msgstr "TPM PCR0 reconstruction" + +#. TRANSLATORS: Title: TPM = Trusted Platform Module +msgid "TPM v2.0" +msgstr "TPM v2.0" + +#. TRANSLATORS: Suffix: the HSI result +msgid "Tainted" +msgstr "Tainted" + msgid "Target" msgstr "Target" @@ -1205,6 +1651,23 @@ msgstr "Target" msgid "The LVFS is a free service that operates as an independent legal entity and has no connection with $OS_RELEASE:NAME$. Your distributor may not have verified any of the firmware updates for compatibility with your system or connected devices. All firmware is provided only by the original equipment manufacturer." msgstr "The LVFS is a free service that operates as an independent legal entity and has no connection with $OS_RELEASE:NAME$. Your distributor may not have verified any of the firmware updates for compatibility with your system or connected devices. All firmware is provided only by the original equipment manufacturer." +#. TRANSLATORS: this is more background on a security measurement problem +msgid "The TPM PCR0 differs from reconstruction." +msgstr "The TPM PCR0 differs from reconstruction." + +#. TRANSLATORS: the user is SOL for support... +msgid "The daemon has loaded 3rd party code and is no longer supported by the upstream developers!" +msgstr "The daemon has loaded 3rd party code and is no longer supported by the upstream developers!" + +#. TRANSLATORS: %1 is the firmware vendor, %2 is the device vendor name +#, c-format +msgid "The firmware from %s is not supplied by %s, the hardware vendor." +msgstr "The firmware from %s is not supplied by %s, the hardware vendor." + +#. TRANSLATORS: nothing to show +msgid "There are no blocked firmware files" +msgstr "There are no blocked firmware files" + #. TRANSLATORS: approved firmware has been checked by #. * the domain administrator msgid "There is no approved firmware." @@ -1217,6 +1680,18 @@ msgstr "This program may only work correctly as root" msgid "This remote contains firmware which is not embargoed, but is still being tested by the hardware vendor. You should ensure you have a way to manually downgrade the firmware if the firmware update fails." msgstr "This remote contains firmware which is not embargoed, but is still being tested by the hardware vendor. You should ensure you have a way to manually downgrade the firmware if the firmware update fails." +#. TRANSLATORS: this is instructions on how to improve the HSI suffix +msgid "This system has HSI runtime issues." +msgstr "This system has HSI runtime issues." + +#. TRANSLATORS: this is instructions on how to improve the HSI security level +msgid "This system has a low HSI security level." +msgstr "This system has a low HSI security level." + +#. TRANSLATORS: description of dbxtool +msgid "This tool allows an administrator to apply UEFI dbx updates." +msgstr "This tool allows an administrator to apply UEFI dbx updates." + #. TRANSLATORS: the user needs to stop playing with stuff msgid "This tool can only be used by the root user" msgstr "This tool can only be used by the root user" @@ -1225,10 +1700,42 @@ msgstr "This tool can only be used by the root user" msgid "Type" msgstr "Type" +#. TRANSLATORS: partition refers to something on disk, again, hey Arch users +msgid "UEFI ESP partition not detected or configured" +msgstr "UEFI ESP partition not detected or configured" + #. TRANSLATORS: program name msgid "UEFI Firmware Utility" msgstr "UEFI Firmware Utility" +#. TRANSLATORS: capsule updates are an optional BIOS feature +msgid "UEFI capsule updates not available or enabled" +msgstr "UEFI capsule updates not available or enabled" + +#. TRANSLATORS: program name +msgid "UEFI dbx Utility" +msgstr "UEFI dbx Utility" + +#. TRANSLATORS: Title: SB is a way of locking down UEFI +msgid "UEFI secure boot" +msgstr "UEFI secure boot" + +#. TRANSLATORS: error message +msgid "Unable to connect to service" +msgstr "Unable to connect to service" + +#. TRANSLATORS: command description +msgid "Unbind current driver" +msgstr "Unbind current driver" + +#. TRANSLATORS: we will now offer this firmware to the user +msgid "Unblocking firmware:" +msgstr "Unblocking firmware:" + +#. TRANSLATORS: Suffix: the HSI result +msgid "Unencrypted" +msgstr "Unencrypted" + #. TRANSLATORS: current daemon status is unknown #. TRANSLATORS: we don't know the license of the update #. TRANSLATORS: unknown release urgency @@ -1242,10 +1749,18 @@ msgstr "Unknown Device" msgid "Unlock the device to allow access" msgstr "Unlock the device to allow access" +#. TRANSLATORS: Suffix: the HSI result +msgid "Unlocked" +msgstr "Unlocked" + #. TRANSLATORS: command description msgid "Unlocks the device for firmware access" msgstr "Unlocks the device for firmware access" +#. TRANSLATORS: command description +msgid "Unmounts the ESP" +msgstr "Unmounts the ESP" + #. TRANSLATORS: command line option msgid "Unset the debugging flag during update" msgstr "Unset the debugging flag during update" @@ -1255,6 +1770,10 @@ msgstr "Unset the debugging flag during update" msgid "Unsupported daemon version %s, client version is %s" msgstr "Unsupported daemon version %s, client version is %s" +#. TRANSLATORS: Suffix: the HSI result +msgid "Untainted" +msgstr "Untainted" + #. TRANSLATORS: Device is updatable in this or any other mode msgid "Updatable" msgstr "Updatable" @@ -1303,6 +1822,9 @@ msgstr "Update the stored metadata with current contents" msgid "Updates all firmware to latest versions available" msgstr "Updates all firmware to latest versions available" +msgid "Updating" +msgstr "Updating" + #. TRANSLATORS: the first replacement is a display name #. * e.g. "ColorHugALS" and the second and third are #. * version numbers e.g. "1.2.3" @@ -1321,10 +1843,6 @@ msgstr "Updating %s…" msgid "Upgrade available for %s from %s to %s" msgstr "Upgrade available for %s from %s to %s" -#. TRANSLATORS: the server sent the user a small message -msgid "Upload message:" -msgstr "Upload message:" - msgid "Upload report just this one time, but prompt again for future updates" msgid_plural "Upload reports just this one time, but prompt again for future updates" msgstr[0] "Upload report just this one time, but prompt again for future updates" @@ -1343,6 +1861,18 @@ msgstr[1] "Upload reports this time and automatically upload reports after compl msgid "Uploading firmware reports helps hardware vendors to quickly identify failing and successful updates on real devices." msgstr "Uploading firmware reports helps hardware vendors to quickly identify failing and successful updates on real devices." +#. TRANSLATORS: how important the release is +msgid "Urgency" +msgstr "Urgency" + +#. TRANSLATORS: error message explaining command to run to how to get help +msgid "Use fwupdmgr --help for help" +msgstr "Use fwupdmgr --help for help" + +#. TRANSLATORS: error message explaining command to run to how to get help +msgid "Use fwupdtool --help for help" +msgstr "Use fwupdtool --help for help" + #. TRANSLATORS: command line option msgid "Use quirk flags when installing firmware" msgstr "Use quirk flags when installing firmware" @@ -1355,6 +1885,14 @@ msgstr "User has been notified" msgid "Username" msgstr "Username" +#. TRANSLATORS: Suffix: the HSI result +msgid "Valid" +msgstr "Valid" + +#. TRANSLATORS: ESP refers to the EFI System Partition +msgid "Validating ESP contents…" +msgstr "Validating ESP contents…" + #. TRANSLATORS: one line variant of release (e.g. 'Prerelease' or 'China') msgid "Variant" msgstr "Variant" @@ -1367,9 +1905,13 @@ msgstr "Vendor" msgid "Verifying…" msgstr "Verifying…" -#. TRANSLATORS: try to help -msgid "WARNING: Ignoring SSL strict checks, to do this automatically in the future export DISABLE_SSL_STRICT in your environment" -msgstr "WARNING: Ignoring SSL strict checks, to do this automatically in the future export DISABLE_SSL_STRICT in your environment" +#. TRANSLATORS: the detected version number of the dbx +msgid "Version" +msgstr "Version" + +#. TRANSLATORS: this is a prefix on the console +msgid "WARNING:" +msgstr "WARNING:" #. TRANSLATORS: waiting for device to do something msgid "Waiting…" @@ -1391,6 +1933,10 @@ msgstr "Write firmware from file into device" msgid "Write firmware from file into one partition" msgstr "Write firmware from file into one partition" +#. TRANSLATORS: decompressing images from a container firmware +msgid "Writing file:" +msgstr "Writing file:" + #. TRANSLATORS: writing to the flash chips msgid "Writing…" msgstr "Writing…" @@ -1398,3 +1944,20 @@ msgstr "Writing…" #. TRANSLATORS: show the user a warning msgid "Your distributor may not have verified any of the firmware updates for compatibility with your system or connected devices." msgstr "Your distributor may not have verified any of the firmware updates for compatibility with your system or connected devices." + +#. TRANSLATORS: %1 is the device vendor name +#, c-format +msgid "Your hardware may be damaged using this firmware, and installing this release may void any warranty with %s." +msgstr "Your hardware may be damaged using this firmware, and installing this release may void any warranty with %s." + +#. TRANSLATORS: this is the default branch name when unset +msgid "default" +msgstr "default" + +#. TRANSLATORS: program name +msgid "fwupd TPM event log utility" +msgstr "fwupd TPM event log utility" + +#. TRANSLATORS: Title: if the fwupd plugins are all present and correct +msgid "fwupd plugins" +msgstr "fwupd plugins" diff --git a/po/fi.po b/po/fi.po index b8a961731..f4dc06f50 100644 --- a/po/fi.po +++ b/po/fi.po @@ -3,7 +3,7 @@ # This file is distributed under the same license as the fwupd package. # # Translators: -# Jiri Grönroos , 2017-2018 +# Jiri Grönroos , 2017-2018,2020 # Kimmo Kujansuu , 2019-2020 msgid "" msgstr "" @@ -20,64 +20,70 @@ msgstr "" #, c-format msgid "%.0f minute remaining" msgid_plural "%.0f minutes remaining" -msgstr[0] "%.0f minuuttia jäljellä" +msgstr[0] "%.0f minuutti jäljellä" msgstr[1] "%.0f minuuttia jäljellä" #. TRANSLATORS: the CPU microcode is firmware loaded onto the CPU #. * at system bootup #, c-format msgid "%s CPU Microcode Update" -msgstr "%s CPU Microcode päivitys" +msgstr "Laitteen %s suorittimen mikrokoodipäivitys" + +#. TRANSLATORS: a specific part of hardware, +#. * the first %s is the device name, e.g. 'Secure Boot` +#, c-format +msgid "%s Configuration Update" +msgstr "%s kokoonpanon päivitys" #. TRANSLATORS: ME stands for Management Engine, where #. * the first %s is the device name, e.g. 'ThinkPad P50` #, c-format msgid "%s Consumer ME Update" -msgstr "%sKuluttajan ME-päivitys" +msgstr "Laitteen %s kuluttajan ME-päivitys" #. TRANSLATORS: the controller is a device that has other devices #. * plugged into it, for example ThunderBolt, FireWire or USB, #. * the first %s is the device name, e.g. 'Intel ThunderBolt` #, c-format msgid "%s Controller Update" -msgstr "%sOhjaimen päivitys" +msgstr "Laitten %s ohjaimen päivitys" #. TRANSLATORS: ME stands for Management Engine (with Intel AMT), #. * where the first %s is the device name, e.g. 'ThinkPad P50` #, c-format msgid "%s Corporate ME Update" -msgstr "%sYrityksen ME-päivitys" +msgstr "Laitteen %s yrityksen ME-päivitys" #. TRANSLATORS: a specific part of hardware, #. * the first %s is the device name, e.g. 'Unifying Receiver` #, c-format msgid "%s Device Update" -msgstr "%sLaitteen päivitys" +msgstr "Laitteen %s laitepäivitys" #. TRANSLATORS: the EC is typically the keyboard controller chip, #. * the first %s is the device name, e.g. 'ThinkPad P50` #, c-format msgid "%s Embedded Controller Update" -msgstr "%sSulautetun ohjaimen päivitys" +msgstr "Laitteen %s sulautetun ohjaimen päivitys" #. TRANSLATORS: ME stands for Management Engine, the Intel AMT thing, #. * the first %s is the device name, e.g. 'ThinkPad P50` #, c-format msgid "%s ME Update" -msgstr "%sME päivitys" +msgstr "Laitteen %s ME-päivitys" #. TRANSLATORS: the entire system, e.g. all internal devices, #. * the first %s is the device name, e.g. 'ThinkPad P50` #, c-format msgid "%s System Update" -msgstr "%sJärjestelmän päivitys" +msgstr "Laitteen %s järjestelmäpäivitys" #. TRANSLATORS: the Thunderbolt controller is a device that #. * has other high speed Thunderbolt devices plugged into it; #. * the first %s is the system name, e.g. 'ThinkPad P50` #, c-format msgid "%s Thunderbolt Controller Update" -msgstr "%s Thunderbolt-ohjaimen päivitys" +msgstr "Laitteen %s Thunderbolt-ohjaimen päivitys" #. TRANSLATORS: this is the fallback where we don't know if the release #. * is updating the system, the device, or a device class, or something else @@ -85,13 +91,18 @@ msgstr "%s Thunderbolt-ohjaimen päivitys" #. * the first %s is the device name, e.g. 'ThinkPad P50` #, c-format msgid "%s Update" -msgstr "%sPäivitys" +msgstr "Laitteen %s päivitys" #. TRANSLATORS: warn the user before updating, %1 is a device name #, c-format msgid "%s and all connected devices may not be usable while updating." msgstr "%s ja kaikki kytketyt laitteet eivät välttämättä ole käyttökelpoisia päivityksen aikana." +#. TRANSLATORS: Title: %s is ME kind, e.g. CSME/TXT +#, c-format +msgid "%s manufacturing mode" +msgstr "%s tuotantotekniikka" + #. TRANSLATORS: warn the user before updating, %1 is a device name #, c-format msgid "%s must remain connected for the duration of the update to avoid damage." @@ -102,12 +113,27 @@ msgstr "%s on oltava kytkettynä päivityksen ajaksi vaurioiden välttämiseksi. msgid "%s must remain plugged into a power source for the duration of the update to avoid damage." msgstr "%s on oltava kytkettynä virtalähteeseen päivityksen ajaksi vaurioiden välttämiseksi." +#. TRANSLATORS: Title: %s is ME kind, e.g. CSME/TXT +#, c-format +msgid "%s override" +msgstr "%s ohita" + +#. TRANSLATORS: Title: %1 is ME kind, e.g. CSME/TXT, %2 is a version number +#, c-format +msgid "%s v%s" +msgstr "%s v%s" + +#. TRANSLATORS: Title: %s is ME kind, e.g. CSME/TXT +#, c-format +msgid "%s version" +msgstr "%s versio" + #. TRANSLATORS: duration in days! #, c-format msgid "%u day" msgid_plural "%u days" -msgstr[0] "%upäivää" -msgstr[1] "%upäivää" +msgstr[0] "%u päivä" +msgstr[1] "%u päivää" #, c-format msgid "%u device has a firmware upgrade available." @@ -119,8 +145,8 @@ msgstr[1] "%u laitteessa on saatavilla firmware -päivitys." #, c-format msgid "%u hour" msgid_plural "%u hours" -msgstr[0] "%u tuntia" -msgstr[1] "%utuntia" +msgstr[0] "%u tunti" +msgstr[1] "%u tuntia" #. TRANSLATORS: how many local devices can expect updates now #, c-format @@ -133,15 +159,19 @@ msgstr[1] "%upaikallisia laitteita tuettu" #, c-format msgid "%u minute" msgid_plural "%u minutes" -msgstr[0] "%u minuuttia" +msgstr[0] "%u minuutti" msgstr[1] "%u minuuttia" #. TRANSLATORS: duration in seconds #, c-format msgid "%u second" msgid_plural "%u seconds" -msgstr[0] "%u " -msgstr[1] "%u sekunttia" +msgstr[0] "%u sekunti" +msgstr[1] "%u sekuntia" + +#. TRANSLATORS: this is shown as a suffix for obsoleted tests +msgid "(obsoleted)" +msgstr "(vanhentunut)" #. TRANSLATORS: command description msgid "Activate devices" @@ -187,6 +217,10 @@ msgstr "Salli firmware-versioiden alentaminen" msgid "Allow reinstalling existing firmware versions" msgstr "Salli laiteohjelmiston versioiden asentaminen uudelleen" +#. TRANSLATORS: command line option +msgid "Allow switching firmware branch" +msgstr "Salli vaihtaa laiteohjelmiston haara" + #. TRANSLATORS: explain why we want to reboot msgid "An update requires a reboot to complete." msgstr "Päivitys vaatii uudelleenkäynnistyksen." @@ -201,7 +235,19 @@ msgstr "Vastaa kaikkiin kysymyksiin kyllä" #. TRANSLATORS: command line option msgid "Apply firmware updates" -msgstr "Käytä firmware-päivityksiä" +msgstr "Toteuta firmware-päivitykset" + +#. TRANSLATORS: command line option +msgid "Apply update even when not advised" +msgstr "Käytä päivitystä myös silloin, kun sitä ei suositella" + +#. TRANSLATORS: command line option +msgid "Apply update files" +msgstr "Käytä päivitystiedostoja" + +#. TRANSLATORS: actually sending the update to the hardware +msgid "Applying update…" +msgstr "Sovelletaan päivitystä..." #. TRANSLATORS: approved firmware has been checked by #. * the domain administrator @@ -210,6 +256,10 @@ msgid_plural "Approved firmware:" msgstr[0] "Hyväksytty laiteohjelmisto:" msgstr[1] "Hyväksytty laiteohjelmisto:" +#. TRANSLATORS: stop nagging the user +msgid "Ask again next time?" +msgstr "Kysy uudestaan ensi kerralla?" + #. TRANSLATORS: command description msgid "Attach to firmware mode" msgstr "Kiinnitä laiteohjelmistotilaan" @@ -224,7 +274,7 @@ msgstr "Todennus on tarpeen, jotta firmware voidaan alentaa siirrettävällä la #. TRANSLATORS: this is the PolicyKit modal dialog msgid "Authentication is required to downgrade the firmware on this machine" -msgstr "Todennus on tarpeen tämän laitteen firmwaren alentamiseksi" +msgstr "Tunnistautuminen vaaditaan tämän laitteen laiteohjelmiston version alentamiseksi" #. TRANSLATORS: this is the PolicyKit modal dialog msgid "Authentication is required to modify a configured remote used for firmware updates" @@ -232,7 +282,7 @@ msgstr "Todennusta tarvitaan firmware-päivityksiin käytettävän konfiguroidun #. TRANSLATORS: this is the PolicyKit modal dialog msgid "Authentication is required to modify daemon configuration" -msgstr "Todennusta tarvitaan taustaprosessin asetusten muokkaamiseen" +msgstr "Tunnistautuminen vaaditaan taustaprosessin asetusten muokkaamiseksi" #. TRANSLATORS: this is the PolicyKit modal dialog msgid "Authentication is required to set the list of approved firmware" @@ -266,10 +316,30 @@ msgstr "Todennus edellyttää laitteen tallennettujen tarkistussummien päivitt msgid "Automatic Reporting" msgstr "Automaattinen raportointi" +#. TRANSLATORS: can we JFDI? +msgid "Automatically upload every time?" +msgstr "Ladataan automaattisesti joka kerta?" + +#. TRANSLATORS: command description +msgid "Bind new kernel driver" +msgstr "Kytke uusi laiteohjain" + +#. TRANSLATORS: there follows a list of hashes +msgid "Blocked firmware files:" +msgstr "Estetyt laiteohjelmiston tiedostot:" + +#. TRANSLATORS: we will not offer this firmware to the user +msgid "Blocking firmware:" +msgstr "Laiteohjelmiston estäminen:" + #. TRANSLATORS: firmware version of bootloader msgid "Bootloader Version" msgstr "Käynnistyslataimen versio" +#. TRANSLATORS: command description +msgid "Build a firmware file" +msgstr "Luo laiteohjelmiston tiedosto" + #. TRANSLATORS: command description msgid "Build firmware using a sandbox" msgstr "Rakenna laiteohjelmisto hiekkalaatikon avulla" @@ -282,6 +352,14 @@ msgstr "Peru" msgid "Cancelled" msgstr "Peruttu" +#. TRANSLATORS: same or newer update already applied +msgid "Cannot apply as dbx update has already been applied." +msgstr "Ei voida käyttää, koska dbx-päivitys on jo asennettu." + +#. TRANSLATORS: the user is using a LiveCD or LiveUSB install disk +msgid "Cannot apply updates on live media" +msgstr "Päivityksiä ei voi käyttää asennus-mediassa" + #. TRANSLATORS: this is when a device is hotplugged #. TRANSLATORS: this is when the daemon state changes msgid "Changed" @@ -295,6 +373,11 @@ msgstr "Tarkistaa salaustekniikan, joka vastaa laiteohjelmistoa" msgid "Checksum" msgstr "Tarkistussumma" +#. TRANSLATORS: get interactive prompt, where branch is the +#. * supplier of the firmware, e.g. "non-free" or "free" +msgid "Choose a branch:" +msgstr "Valitse haara:" + #. TRANSLATORS: get interactive prompt msgid "Choose a device:" msgstr "Valitse laite:" @@ -307,6 +390,10 @@ msgstr "Valitse laiteohjelman tyyppi:" msgid "Choose a release:" msgstr "Valitse julkaisu:" +#. TRANSLATORS: get interactive prompt +msgid "Choose a volume:" +msgstr "Valitse asema:" + #. TRANSLATORS: command description msgid "Clears any updates scheduled to be updated offline" msgstr "Tyhjentää päivitykset, jotka on tarkoitus päivittää offline-tilassa" @@ -427,6 +514,20 @@ msgstr "Laitteet, jotka on päivitetty onnistuneesti:" msgid "Devices that were not updated correctly:" msgstr "Laitteet, joita ei päivitetty oikein:" +#. TRANSLATORS: message letting the user know no device upgrade available due +#. to missing on LVFS +msgid "Devices with no available firmware updates: " +msgstr "Laitteet, joista ei ole saatavilla firmware-päivityksiä:" + +#. TRANSLATORS: message letting the user know no device upgrade available +msgid "Devices with the latest available firmware version:" +msgstr "Laitteet, joista on saatavilla uusin firmware-versio:" + +#. TRANSLATORS: Suffix: the HSI result +#. TRANSLATORS: Plugin is inactive and not used +msgid "Disabled" +msgstr "Ei käytössä" + msgid "Disabled fwupdate debugging" msgstr "fw-päivityksen virheenkorjaus poistettu" @@ -476,6 +577,7 @@ msgstr[1] "Älä lähetä raportteja äläkä koskaan pyydä lähettämään rap msgid "Do not write to the history database" msgstr "Älä kirjoita historiatietokantaan" +#. TRANSLATORS: success #. success msgid "Done!" msgstr "Valmis!" @@ -494,7 +596,7 @@ msgstr "Alenee %s -sta %s tulos %s... " #. TRANSLATORS: %1 is a device name #, c-format msgid "Downgrading %s…" -msgstr "Alentaa %s…" +msgstr "Alennetaan laitetta %s…" #. TRANSLATORS: downloading from a remote server msgid "Downloading…" @@ -520,6 +622,8 @@ msgstr "Ota firmware-päivitystuki käyttöön tuetuissa järjestelmissä" msgid "Enable this remote?" msgstr "Ota etäyhteys käyttöön?" +#. TRANSLATORS: Suffix: the HSI result +#. TRANSLATORS: Plugin is active and in use #. TRANSLATORS: if the remote is enabled msgid "Enabled" msgstr "Käytössä" @@ -538,6 +642,14 @@ msgstr "Tämän toiminnon käyttöönotto tapahtuu omalla vastuullasi, joten sin msgid "Enabling this remote is done at your own risk." msgstr "Tämän etä-ohjaimen käyttöönotto tapahtuu omalla vastuullasi." +#. TRANSLATORS: Suffix: the HSI result +msgid "Encrypted" +msgstr "Salattu" + +#. TRANSLATORS: Title: Memory contents are encrypted, e.g. Intel TME +msgid "Encrypted RAM" +msgstr "Salattu RAM-muisti" + #. TRANSLATORS: command description msgid "Erase all firmware update history" msgstr "Poista kaikki laiteohjelmiston päivityshistoria" @@ -554,13 +666,21 @@ msgstr "Poistu pienen viiveen jälkeen" msgid "Exit after the engine has loaded" msgstr "Poistu kun moottori on ladattu" +#. TRANSLATORS: Suffix: the fallback HSI result +msgid "Failed" +msgstr "Epäonnistui" + +#. TRANSLATORS: dbx file failed to be applied as an update +msgid "Failed to apply update" +msgstr "Päivityksen asentaminen epäonnistui" + #. TRANSLATORS: we could not talk to the fwupd daemon msgid "Failed to connect to daemon" msgstr "Yhteys taustaprosessiin epäonnistui" -#. TRANSLATORS: the server is rate-limiting downloads -msgid "Failed to download due to server limit" -msgstr "Lataaminen epäonnistui palvelimen rajoituksen vuoksi" +#. TRANSLATORS: could not parse file +msgid "Failed to extract local dbx " +msgstr "Paikallisen dbx-tiedoston purkaminen epäonnistui" #. TRANSLATORS: we could not get the devices to update offline msgid "Failed to get pending devices" @@ -568,47 +688,49 @@ msgstr "Vireillä olevien laitteiden saaminen epäonnistui" #. TRANSLATORS: we could not install for some reason msgid "Failed to install firmware update" -msgstr "Laiteohjelmiston firmware päivityksen asennus epäonnistui" +msgstr "Laiteohjelmiston päivityksen asennus epäonnistui" + +#. TRANSLATORS: could not read existing system data +#. TRANSLATORS: could not read file +msgid "Failed to load local dbx" +msgstr "Paikallisen dbx-tiedoston lataus epäonnistui" #. TRANSLATORS: quirks are device-specific workarounds msgid "Failed to load quirks" msgstr "Quirksin lataaminen epäonnistui" +#. TRANSLATORS: could not read existing system data +msgid "Failed to load system dbx" +msgstr "Järjestelmän dbx-tiedoston lataus epäonnistui" + #. TRANSLATORS: the user didn't read the man page msgid "Failed to parse arguments" msgstr "Argumenttien jäsentäminen epäonnistui" #. TRANSLATORS: failed to read measurements file msgid "Failed to parse file" -msgstr "Tiedoston käsittely epäonnistui" +msgstr "Tiedoston jäsentäminen epäonnistui" #. TRANSLATORS: the user didn't read the man page msgid "Failed to parse flags for --filter" msgstr "Lippujen erittely ei onnistunut --suodatin" +#. TRANSLATORS: could not parse file +msgid "Failed to parse local dbx" +msgstr "Paikallisen dbx-tiedoston lukeminen epäonnistui" + #. TRANSLATORS: we could not reboot for some reason msgid "Failed to reboot" -msgstr "Käynnistys epäonnistui" +msgstr "Uudelleenkäynnistys epäonnistui" #. TRANSLATORS: we could not talk to plymouth msgid "Failed to set splash mode" msgstr "Splash-tilan asettaminen epäonnistui" -#. TRANSLATORS: downloading unknown file -msgid "Fetching file" -msgstr "Noudetaan tiedosto" - -#. TRANSLATORS: downloading new firmware file -msgid "Fetching firmware" -msgstr "Noudetaan firmware" - -#. TRANSLATORS: downloading new metadata file -msgid "Fetching metadata" -msgstr "Noudetaan metatietoja" - -#. TRANSLATORS: downloading new signing file -msgid "Fetching signature" -msgstr "Noudetaan allekirjoitus" +#. TRANSLATORS: something with a blocked hash exists +#. * in the users ESP -- which would be bad! +msgid "Failed to validate ESP contents" +msgstr "ESP-sisällön vahvistaminen epäonnistui" #. TRANSLATORS: filename of the local file msgid "Filename" @@ -618,6 +740,10 @@ msgstr "Tiedostonimi" msgid "Filename Signature" msgstr "Tiedoston allekirjoitus" +#. TRANSLATORS: user did not include a filename parameter +msgid "Filename required" +msgstr "Tiedostonimi vaaditaan" + #. TRANSLATORS: command line option msgid "Filter with a set of device flags using a ~ prefix to exclude, e.g. 'internal,~needs-reboot'" msgstr "Suodata laite lippuja käyttäen ~ etuliiteellä sulkea pois, esim. 'sisäiset, ~ vaatii käynnistyksen'" @@ -642,6 +768,18 @@ msgstr "Firmware-päivityksen taustaprosessi" msgid "Firmware Utility" msgstr "Firmware-työkalu" +#. TRANSLATORS: Title: if we can verify the firmware checksums +msgid "Firmware attestation" +msgstr "Firmware-aitoustodistus" + +#. TRANSLATORS: user selected something not possible +msgid "Firmware is already blocked" +msgstr "Laiteohjelmisto on jo estetty" + +#. TRANSLATORS: user selected something not possible +msgid "Firmware is not already blocked" +msgstr "Laiteohjelmistoa ei ole jo estetty" + #. TRANSLATORS: the metadata is very out of date; %u is a number > 1 #, c-format msgid "Firmware metadata has not been updated for %u day and may not be up to date." @@ -649,19 +787,32 @@ msgid_plural "Firmware metadata has not been updated for %u days and may not be msgstr[0] "Laiteohjelmiston metatietoja ei ole päivitetty %upäivään ja ne eivät välttämättä ole ajan tasalla." msgstr[1] "Laiteohjelmiston metatietoja ei ole päivitetty %upäivään ja ne eivät välttämättä ole ajan tasalla." +#. TRANSLATORS: Title: if firmware updates are available +msgid "Firmware updates" +msgstr "Firmware-päivitykset" + msgid "Firmware updates are not supported on this machine." msgstr "Ohjelmistopäivitys 'firmware' ei tue tätä laitetta" msgid "Firmware updates are supported on this machine." msgstr "Ohjelmistopäivitys 'firmware' tukee tätä laitetta" +#. TRANSLATORS: description of plugin state, e.g. disabled #. TRANSLATORS: release properties msgid "Flags" msgstr "Liput" +#. TRANSLATORS: command line option +msgid "Force the action by relaxing some runtime checks" +msgstr "Pakota toiminta vapauttamalla joitakin ajonaikaisia tarkistuksia" + msgid "Force the action ignoring all warnings" msgstr "Pakota toimenpide huomioimatta kaikki varoitukset" +#. TRANSLATORS: Suffix: the HSI result +msgid "Found" +msgstr "Löydetty" + #. TRANSLATORS: global ID common to all similar hardware msgid "GUID" msgid_plural "GUIDs" @@ -692,9 +843,9 @@ msgstr "Hae tietoja firmware-tiedostosta" msgid "Gets the configured remotes" msgstr "Määrittää konfiguroidut etäyhteydet" -#. TRANSLATORS: firmware approved by the admin -msgid "Gets the list of approved firmware." -msgstr "Hae hyväksytty laiteohjelmiston luettelo." +#. TRANSLATORS: command description +msgid "Gets the host security attributes" +msgstr "Hanki tietoturvan määritteet" #. TRANSLATORS: command description msgid "Gets the list of updates for connected hardware" @@ -716,6 +867,15 @@ msgstr "Laitteisto odottaa uudelleen kytkemistä" msgid "High" msgstr "Korkea" +#. TRANSLATORS: this is a string like 'HSI:2-U' +msgid "Host Security ID:" +msgstr "Koneen tietoturva ID:" + +#. TRANSLATORS: Title: +#. https://en.wikipedia.org/wiki/Input%E2%80%93output_memory_management_unit +msgid "IOMMU" +msgstr "IOMMU" + #. TRANSLATORS: daemon is inactive msgid "Idle…" msgstr "Jouten…" @@ -724,6 +884,18 @@ msgstr "Jouten…" msgid "Ignore SSL strict checks when downloading files" msgstr "Ohita tiukat SSL tarkistukset tiedostoja ladattaessa" +#. TRANSLATORS: command line option +msgid "Ignore firmware checksum failures" +msgstr "Ohita laiteohjelmiston tarkistussumman virheet" + +#. TRANSLATORS: command line option +msgid "Ignore firmware hardware mismatch failures" +msgstr "Ohita laitteiden yhteensopimattomuuden virheet" + +#. TRANSLATORS: command line option +msgid "Ignore requirement of external power source" +msgstr "Ohita ulkoisen virtalähteen vaatimus" + #. TRANSLATORS: Ignore validation safety checks when flashing this device msgid "Ignore validation safety checks" msgstr "Ohita turvatarkastukset" @@ -741,7 +913,7 @@ msgid "Install a firmware file on this hardware" msgstr "Asenna laiteohjelmisto tähän laitteistoon" msgid "Install old version of system firmware" -msgstr "Asenna vanha firmware versio" +msgstr "Asenna vanha firmware-versio" msgid "Install signed device firmware" msgstr "Asenna allekirjoitettu laitteen firmware" @@ -770,15 +942,62 @@ msgstr "Asennetaan firmware-päivitystä…" #. TRANSLATORS: %1 is a device name #, c-format msgid "Installing on %s…" -msgstr "Asentaa %s…" +msgstr "Asentaa laitteelle %s…" + +#. TRANSLATORS: Title: BootGuard is a trademark from Intel +msgid "Intel BootGuard" +msgstr "Intel BootGuard" + +#. TRANSLATORS: Title: BootGuard is a trademark from Intel, +#. * ACM means to verify the integrity of Initial Boot Block +msgid "Intel BootGuard ACM protected" +msgstr "Intel BootGuard ACM suojattu" + +#. TRANSLATORS: Title: BootGuard is a trademark from Intel, +#. * OTP = one time programmable +msgid "Intel BootGuard OTP fuse" +msgstr "Intel BootGuard OTP fuse" + +#. TRANSLATORS: Title: BootGuard is a trademark from Intel, +#. * error policy is what to do on failure +msgid "Intel BootGuard error policy" +msgstr "Intel BootGuard virhekäytäntö" + +#. TRANSLATORS: Title: BootGuard is a trademark from Intel, +#. * verified boot refers to the way the boot process is verified +msgid "Intel BootGuard verified boot" +msgstr "Intel BootGuard vahvistettu käynnistys" + +#. TRANSLATORS: Title: CET = Control-flow Enforcement Technology, +#. * active means being used by the OS +msgid "Intel CET Active" +msgstr "Intel CET aktiivinen" + +#. TRANSLATORS: Title: CET = Control-flow Enforcement Technology, +#. * enabled means supported by the processor +msgid "Intel CET Enabled" +msgstr "Intel CET käytössä" + +#. TRANSLATORS: Title: Direct Connect Interface (DCI) allows +#. * debugging of Intel processors using the USB3 port +msgid "Intel DCI debugger" +msgstr "Intel DCI virheenkorjaus" + +#. TRANSLATORS: Title: SMAP = Supervisor Mode Access Prevention +msgid "Intel SMAP" +msgstr "Intel SMAP" #. TRANSLATORS: Device cannot be removed easily msgid "Internal device" msgstr "Sisäinen laite" +#. TRANSLATORS: Suffix: the HSI result +msgid "Invalid" +msgstr "Virheellinen" + #. TRANSLATORS: Is currently in bootloader mode msgid "Is in bootloader mode" -msgstr "On käynnistyslatain moodissa" +msgstr "On käynnistyslataintilassa" #. TRANSLATORS: issue fixed with the release, e.g. CVE msgid "Issue" @@ -807,6 +1026,22 @@ msgstr "Linux-toimittajan laiteohjelmisto (vakaa firmware)" msgid "Linux Vendor Firmware Service (testing firmware)" msgstr "Linux-toimittajan laiteohjelmisto (firmware testaus)" +#. TRANSLATORS: Title: if it's tainted or not +msgid "Linux kernel" +msgstr "Linux kernel" + +#. TRANSLATORS: Title: lockdown is a security mode of the kernel +msgid "Linux kernel lockdown" +msgstr "Linux kernel lukitus" + +#. TRANSLATORS: Title: swap space or swap partition +msgid "Linux swap" +msgstr "Linux swap" + +#. TRANSLATORS: command line option +msgid "List entries in dbx" +msgstr "Listaa merkinnät dbx-muodossa" + #. TRANSLATORS: command line option msgid "List supported firmware updates" msgstr "Lista tuetuista firmware-päivityksistä" @@ -815,17 +1050,39 @@ msgstr "Lista tuetuista firmware-päivityksistä" msgid "List the available firmware types" msgstr "Luettelo käytettävissä olevista laiteohjelmistotyypeistä" +#. TRANSLATORS: command description +msgid "Lists files on the ESP" +msgstr "Listaa ESP:n tiedostot" + #. TRANSLATORS: parsing the firmware information msgid "Loading…" msgstr "Ladataan…" +#. TRANSLATORS: Suffix: the HSI result +msgid "Locked" +msgstr "Lukittu" + #. TRANSLATORS: the release urgency msgid "Low" msgstr "Matala" +#. TRANSLATORS: Title: MEI = Intel Management Engine +msgid "MEI manufacturing mode" +msgstr "MEI tuotantotekniikka" + +#. TRANSLATORS: Title: MEI = Intel Management Engine, and the +#. * "override" is the physical PIN that can be driven to +#. * logic high -- luckily it is probably not accessible to +#. * end users on consumer boards +msgid "MEI override" +msgstr "Ohita MEI" + +msgid "MEI version" +msgstr "MEI versio" + #. TRANSLATORS: command line option -msgid "Manually whitelist specific plugins" -msgstr "Luetteloi tiettyjä lisäosia manuaalisesti" +msgid "Manually enable specific plugins" +msgstr "Ota manuaalisesti tietyt laajennukset käyttöön" #. TRANSLATORS: the release urgency msgid "Medium" @@ -852,10 +1109,6 @@ msgstr "Vähimmäisversio" msgid "Mismatched daemon and client, use %s instead" msgstr "Virheellinen taustaprosessi ja asiakas, käytä sen sijaan %s" -#. TRANSLATORS: sets something in daemon.conf -msgid "Modifies a daemon configuration value." -msgstr "Muuta taustaprosessin määritysarvoja." - #. TRANSLATORS: command description msgid "Modifies a given remote" msgstr "Muuta annettua etäyhteyttä" @@ -870,6 +1123,10 @@ msgstr "Muokkaa taustaprosessin kokoonpanoa" msgid "Monitor the daemon for events" msgstr "Seuraa tapahtumien taustaprosessia" +#. TRANSLATORS: command description +msgid "Mounts the ESP" +msgstr "Kytkee ESP:n käyttöön" + #. TRANSLATORS: Requires a reboot to apply firmware or to reload hardware msgid "Needs a reboot after installation" msgstr "Tarvitsee käynnistyksen asennuksen jälkeen" @@ -882,6 +1139,7 @@ msgstr "Tarvitsee sammutuksen asennuksen jälkeen" msgid "New version" msgstr "Uusi versio" +#. TRANSLATORS: user did not tell the tool what to do msgid "No action specified!" msgstr "Toimintoa ei ole määritetty!" @@ -897,11 +1155,11 @@ msgstr "Laiteohjelmiston tunnuksia ei löytynyt" #. TRANSLATORS: nothing attached that can be upgraded msgid "No hardware detected with firmware update capability" -msgstr "Ei havaittu sopivaa laitteistoa firmware päivitykselle" +msgstr "Ei havaittu sopivaa laitteistoa firmware-päivitykselle" #. TRANSLATORS: nothing found msgid "No plugins found" -msgstr "Ei laajennuksia" +msgstr "Liitännäisiä ei löytynyt" #. TRANSLATORS: no repositories to download from msgid "No releases available" @@ -917,16 +1175,24 @@ msgstr "Kaukosäätimet ei saatavilla" #. TRANSLATORS: nothing was updated offline msgid "No updates were applied" -msgstr "Ei soveltuvia päivityksiä" +msgstr "Päivityksiä ei toteutettu" + +#. TRANSLATORS: Suffix: the HSI result +msgid "Not found" +msgstr "Ei löydy" + +#. TRANSLATORS: Suffix: the HSI result +msgid "Not supported" +msgstr "Ei tueta" + +#. TRANSLATORS: Suffix: the HSI result +msgid "OK" +msgstr "OK" #. TRANSLATORS: command line option msgid "Only show single PCR value" msgstr "Näytä vain yksi PCR-arvo" -#. TRANSLATORS: command line option -msgid "Override plugin warning" -msgstr "Ohita plugin-varoitus" - #. TRANSLATORS: command line option msgid "Override the default ESP path" msgstr "Ohita oletusarvoinen ESP-polku" @@ -939,6 +1205,14 @@ msgstr "Ohita varoitukset ja pakota toiminto" msgid "Parse and show details about a firmware file" msgstr "Analysoi ja näytä tiedot laiteohjelmiston tiedostosta" +#. TRANSLATORS: reading new dbx from the update +msgid "Parsing dbx update…" +msgstr "Luetaan dbx päivitys..." + +#. TRANSLATORS: reading existing dbx from the system +msgid "Parsing system dbx…" +msgstr "Luetaan järjestelmä dbx..." + #. TRANSLATORS: remote filename base msgid "Password" msgstr "Salasana" @@ -955,6 +1229,10 @@ msgstr "Prosenttiosuus valmis" msgid "Please enter a number from 0 to %u: " msgstr "Anna numero 0 -%u" +#. TRANSLATORS: Title: DMA as in https://en.wikipedia.org/wiki/DMA_attack +msgid "Pre-boot DMA protection" +msgstr "Pre-boot DMA-suojaus" + #. TRANSLATORS: version number of previous firmware msgid "Previous version" msgstr "Aiempi versio" @@ -974,7 +1252,7 @@ msgstr "Jatka lähettämistä?" #. TRANSLATORS: a non-free software license msgid "Proprietary" -msgstr "Patentoitu" +msgstr "Suljettu" #. TRANSLATORS: command line option msgid "Query for firmware update support" @@ -995,7 +1273,7 @@ msgstr "Lue firmware osiolta tiedostoon" #. TRANSLATORS: %1 is a device name #, c-format msgid "Reading from %s…" -msgstr "Lukeminen %s…" +msgstr "Lukee laitteelta %s…" #. TRANSLATORS: reading from the flash chips msgid "Reading…" @@ -1009,10 +1287,6 @@ msgstr "Käynnistää..." msgid "Refresh metadata from remote server" msgstr "Päivitä etäpalvelimen metatiedot" -#. TRANSLATORS: command description -msgid "Reinstall current firmware on the device." -msgstr "Asenna nykyinen laiteohjelmisto laitteeseen." - #. TRANSLATORS: command description msgid "Reinstall firmware on a device" msgstr "Asenna laiteohjelmisto 'firmware' uudelleen laitteelle" @@ -1045,17 +1319,13 @@ msgstr "Ilmoita URI" msgid "Reported to remote server" msgstr "Raportoitu etäpalvelimelle" -#. TRANSLATORS: Must be plugged in to an outlet -msgid "Requires AC power" -msgstr "Vaatii verkkovirtaa" - #. TRANSLATORS: Requires a bootloader mode to be manually enabled by the user msgid "Requires a bootloader" msgstr "Vaatii käynnistyslataimen" #. TRANSLATORS: metadata is downloaded from the Internet msgid "Requires internet connection" -msgstr "Vaatii Internet-yhteyden" +msgstr "Vaatii internetyhteyden" #. TRANSLATORS: reboot to apply the update msgid "Restart now?" @@ -1084,6 +1354,22 @@ msgstr "Suorita plugin-puhdistustoiminto, kun käytät asennus-blobia" msgid "Run the plugin composite prepare routine when using install-blob" msgstr "Asennus-blobia ajamalla käytät yhdistelmän valmiita laajennus rutiineja " +#. TRANSLATORS: this is the HSI suffix +msgid "Runtime Suffix" +msgstr "Suoritusaika" + +#. TRANSLATORS: Title: SPI refers to the flash chip in the computer +msgid "SPI BIOS region" +msgstr "SPI BIOS-alue" + +#. TRANSLATORS: Title: SPI refers to the flash chip in the computer +msgid "SPI lock" +msgstr "SPI-lukko" + +#. TRANSLATORS: Title: SPI refers to the flash chip in the computer +msgid "SPI write" +msgstr "SPI-kirjoitus" + #. TRANSLATORS: command line option msgid "Save device state into a JSON file between executions" msgstr "Tallenna laitteen tila JSON-tiedostoon suoritusten välillä" @@ -1100,6 +1386,10 @@ msgstr "Ajoitetaan…" msgid "Selected device" msgstr "Valittu laite" +#. TRANSLATORS: Volume has been chosen by the user +msgid "Selected volume" +msgstr "Valittu asema" + #. TRANSLATORS: serial number of hardware msgid "Serial Number" msgstr "Sarjanumero" @@ -1108,17 +1398,18 @@ msgstr "Sarjanumero" msgid "Set the debugging flag during update" msgstr "Aseta virheenkorjauksen lippu päivityksen aikana" +#. TRANSLATORS: firmware approved by the admin msgid "Sets the list of approved firmware" msgstr "Asettaa listan hyväksytyjä 'firmware' laiteohjelmistoja " -#. TRANSLATORS: firmware approved by the admin -msgid "Sets the list of approved firmware." -msgstr "Asettaa hyväksytyn laiteohjelmiston luettelon." - #. TRANSLATORS: command description msgid "Share firmware history with the developers" msgstr "Jaa laiteohjelmiston historia kehittäjien kanssa" +#. TRANSLATORS: command line option +msgid "Show all results" +msgstr "Näytä kaikki tulokset" + #. TRANSLATORS: command line option msgid "Show client and daemon versions" msgstr "Näytä asiakas- ja taustaprosessin versiot" @@ -1151,6 +1442,10 @@ msgstr "Näytä laiteohjelmiston päivitysten historia" msgid "Show plugin verbose information" msgstr "Näytä plugin tiedot" +#. TRANSLATORS: command line option +msgid "Show the calculated version of the dbx" +msgstr "Näytä dbx laskettu versio" + #. TRANSLATORS: command line option msgid "Show the debug log from the last attempted update" msgstr "Näytä virheenkorjausloki viimeisestä päivitysyrityksestä" @@ -1188,6 +1483,10 @@ msgstr "Lähde" msgid "Specify Vendor/Product ID(s) of DFU device" msgstr "Määritä DFU laitteen toimittaja/tuotetunnus(s)" +#. TRANSLATORS: command line option +msgid "Specify the dbx database file" +msgstr "Määritä dbx-tietokantatiedosto" + msgid "Specify the number of bytes per USB transfer" msgstr "Määritä tavujen määrä USB-siirtoa kohti" @@ -1245,10 +1544,34 @@ msgstr "Laitteiden tarkistussummat vahvistettu onnistuneesti" msgid "Summary" msgstr "Yhteenveto" +#. TRANSLATORS: Suffix: the HSI result +msgid "Supported" +msgstr "Tuettu" + #. TRANSLATORS: Is found in current metadata msgid "Supported on remote server" msgstr "Tuettu etäpalvelimella" +#. TRANSLATORS: Title: a better sleep state +msgid "Suspend-to-idle" +msgstr "Keskeytä-tyhjäkäynnille" + +#. TRANSLATORS: Title: sleep state +msgid "Suspend-to-ram" +msgstr "Keskeytä-muistiin" + +#. TRANSLATORS: Title: the PCR is rebuilt from the TPM event log +msgid "TPM PCR0 reconstruction" +msgstr "TPM PCR0 -jälleenrakennus" + +#. TRANSLATORS: Title: TPM = Trusted Platform Module +msgid "TPM v2.0" +msgstr "TPM v2.0" + +#. TRANSLATORS: Suffix: the HSI result +msgid "Tainted" +msgstr "Pilaantunut" + msgid "Target" msgstr "Kohde" @@ -1256,6 +1579,14 @@ msgstr "Kohde" msgid "The LVFS is a free service that operates as an independent legal entity and has no connection with $OS_RELEASE:NAME$. Your distributor may not have verified any of the firmware updates for compatibility with your system or connected devices. All firmware is provided only by the original equipment manufacturer." msgstr "LVFS on ilmainen palvelu, joka toimii itsenäisenä oikeushenkilönä eikä sillä ole yhteyttä $OS_RELEASE:NAME$. Jakelijasi ei ehkä ole tarkistanut mitään laiteohjelmistopäivityksiä, jotka ovat yhteensopivia järjestelmän tai liitettyjen laitteiden kanssa. Kaikki laiteohjelmistot on tarkoitettu vain alkuperäisen laitteen valmistajalle." +#. TRANSLATORS: this is more background on a security measurement problem +msgid "The TPM PCR0 differs from reconstruction." +msgstr "TPM PCR0 eroaa rakennettavasta." + +#. TRANSLATORS: nothing to show +msgid "There are no blocked firmware files" +msgstr "Estettyjä firmware-tiedostoja ei ole" + #. TRANSLATORS: approved firmware has been checked by #. * the domain administrator msgid "There is no approved firmware." @@ -1263,11 +1594,23 @@ msgstr "Hyväksyttyä laiteohjelmistoa ei ole." #. TRANSLATORS: we're poking around as a power user msgid "This program may only work correctly as root" -msgstr "Tämä ohjelma voi toimia vain juuressa 'root'" +msgstr "Tämä ohjelma toimii oikein vain root-käyttäjän oikeuksin" msgid "This remote contains firmware which is not embargoed, but is still being tested by the hardware vendor. You should ensure you have a way to manually downgrade the firmware if the firmware update fails." msgstr "Tämä sisältää firmwaren, jota ei ole vientikiellossa, mutta jota laitteistotoimittaja testaa edelleen. Varmista, että voit päivittää firmwaren manuaalisesti, jos päivitys epäonnistuu." +#. TRANSLATORS: this is instructions on how to improve the HSI suffix +msgid "This system has HSI runtime issues." +msgstr "Järjestelmässä on HSI-suoritusajan ongelma." + +#. TRANSLATORS: this is instructions on how to improve the HSI security level +msgid "This system has a low HSI security level." +msgstr "Tämän järjestelmän HSI-tietoturvataso on alhainen." + +#. TRANSLATORS: description of dbxtool +msgid "This tool allows an administrator to apply UEFI dbx updates." +msgstr "Tämän työkalun avulla järjestelmänvalvoja voi käyttää UEFI dbx-päivityksiä." + #. TRANSLATORS: the user needs to stop playing with stuff msgid "This tool can only be used by the root user" msgstr "Tätä työkalua voi käyttää vain root-käyttäjä" @@ -1280,6 +1623,30 @@ msgstr "Tyyppi" msgid "UEFI Firmware Utility" msgstr "UEFI firmware -apuohjelma" +#. TRANSLATORS: program name +msgid "UEFI dbx Utility" +msgstr "UEFI dbx-apuohjelma" + +#. TRANSLATORS: Title: SB is a way of locking down UEFI +msgid "UEFI secure boot" +msgstr "UEFI secure boot" + +#. TRANSLATORS: error message +msgid "Unable to connect to service" +msgstr "Yhteys palveluun ei onnistu" + +#. TRANSLATORS: command description +msgid "Unbind current driver" +msgstr "Pura nykyinen ohjain" + +#. TRANSLATORS: we will now offer this firmware to the user +msgid "Unblocking firmware:" +msgstr "Laiteohjelmiston poistaminen käytöstä:" + +#. TRANSLATORS: Suffix: the HSI result +msgid "Unencrypted" +msgstr "Salaamaton" + #. TRANSLATORS: current daemon status is unknown #. TRANSLATORS: we don't know the license of the update #. TRANSLATORS: unknown release urgency @@ -1291,12 +1658,20 @@ msgid "Unknown Device" msgstr "Tuntematon laite" msgid "Unlock the device to allow access" -msgstr "Sallia pääsy laitteeseen" +msgstr "Avaa laitteen lukitus salliaksesi käytön" + +#. TRANSLATORS: Suffix: the HSI result +msgid "Unlocked" +msgstr "Auki" #. TRANSLATORS: command description msgid "Unlocks the device for firmware access" msgstr "Avaa pääsy laitteen laiteohjelmistoon" +#. TRANSLATORS: command description +msgid "Unmounts the ESP" +msgstr "Poistaa ESP:n käytöstä" + #. TRANSLATORS: command line option msgid "Unset the debugging flag during update" msgstr "Poista virheenkorjauksen lippu päivityksen aikana" @@ -1306,13 +1681,17 @@ msgstr "Poista virheenkorjauksen lippu päivityksen aikana" msgid "Unsupported daemon version %s, client version is %s" msgstr "Ei tuettu taustaprosessin versio %s, asiakasversio on %s" +#. TRANSLATORS: Suffix: the HSI result +msgid "Untainted" +msgstr "Puhdistettu" + #. TRANSLATORS: Device is updatable in this or any other mode msgid "Updatable" msgstr "Päivitettävissä" #. TRANSLATORS: error message from last update attempt msgid "Update Error" -msgstr "Päivitys virhe" +msgstr "Päivitysvirhe" #. TRANSLATORS: helpful messages from last update #. TRANSLATORS: helpful messages for the update @@ -1337,7 +1716,7 @@ msgstr "Päivitä nyt?" #. TRANSLATORS: Update can only be done from offline mode msgid "Update requires a reboot" -msgstr "Päivitys edellyttää käynnistyksen" +msgstr "Päivitys edellyttää uudelleenkäynnistyksen" #. TRANSLATORS: command description msgid "Update the stored cryptographic hash with current ROM contents" @@ -1354,6 +1733,9 @@ msgstr "Päivitä tallennetut metatiedot nykyiseen sisältöön" msgid "Updates all firmware to latest versions available" msgstr "Päivittää kaikki laiteohjaimet uusimpiin saatavilla oleviin versioihin" +msgid "Updating" +msgstr "Päivittää" + #. TRANSLATORS: the first replacement is a display name #. * e.g. "ColorHugALS" and the second and third are #. * version numbers e.g. "1.2.3" @@ -1364,7 +1746,7 @@ msgstr "Korotus %s -sta %s tulos %s... " #. TRANSLATORS: %1 is a device name #, c-format msgid "Updating %s…" -msgstr "Päivittää %s…" +msgstr "Päivittää laitetta %s…" #. TRANSLATORS: message letting the user know an upgrade is available #. * %1 is the device name and %2 and %3 are version strings @@ -1372,10 +1754,6 @@ msgstr "Päivittää %s…" msgid "Upgrade available for %s from %s to %s" msgstr "Päivitys saatavilla %s alkaen %s kohde %s" -#. TRANSLATORS: the server sent the user a small message -msgid "Upload message:" -msgstr "Lähetä viesti:" - msgid "Upload report just this one time, but prompt again for future updates" msgid_plural "Upload reports just this one time, but prompt again for future updates" msgstr[0] "Lataa raportit vain tällä kertaa, mutta pyydä uudelleen tulevissa päivityksissä" @@ -1383,7 +1761,7 @@ msgstr[1] "Lataa raportit vain tällä kertaa, mutta pyydä uudelleen tulevissa #. TRANSLATORS: ask the user to upload msgid "Upload report now?" -msgstr "Lataa raportti nyt?" +msgstr "Lähetetäänkö raportti nyt?" msgid "Upload report this time and automatically upload reports after completing future updates" msgid_plural "Upload reports this time and automatically upload reports after completing future updates" @@ -1398,6 +1776,14 @@ msgstr "Firmware-raporttien lataaminen auttaa laitteistotoimittajia tunnistamaan msgid "Urgency" msgstr "Kiireellisyys" +#. TRANSLATORS: error message explaining command to run to how to get help +msgid "Use fwupdmgr --help for help" +msgstr "Suorita fwupdmgr --help nähdäksesi ohjeet" + +#. TRANSLATORS: error message explaining command to run to how to get help +msgid "Use fwupdtool --help for help" +msgstr "Suorita fwupdtool --help nähdäksesi ohjeet" + #. TRANSLATORS: command line option msgid "Use quirk flags when installing firmware" msgstr "Käytä Quirk-lippuja asennettaessa laiteohjelmistoa" @@ -1410,6 +1796,14 @@ msgstr "Käyttäjälle on ilmoitettu" msgid "Username" msgstr "Käyttäjätunnus" +#. TRANSLATORS: Suffix: the HSI result +msgid "Valid" +msgstr "Voimassa" + +#. TRANSLATORS: ESP refers to the EFI System Partition +msgid "Validating ESP contents…" +msgstr "Vahvistetaan ESP-sisältöä..." + #. TRANSLATORS: one line variant of release (e.g. 'Prerelease' or 'China') msgid "Variant" msgstr "Muunnelma" @@ -1422,9 +1816,13 @@ msgstr "Toimittaja" msgid "Verifying…" msgstr "Vahvistetaan…" -#. TRANSLATORS: try to help -msgid "WARNING: Ignoring SSL strict checks, to do this automatically in the future export DISABLE_SSL_STRICT in your environment" -msgstr "VAROITUS: SSL tarkistusten sivuuttaminen, jotta se tapahtuu automaattisesti tulevassa DISABLE_SSL_STRICT ympäristössä" +#. TRANSLATORS: the detected version number of the dbx +msgid "Version" +msgstr "Versio" + +#. TRANSLATORS: this is a prefix on the console +msgid "WARNING:" +msgstr "VAROITUS:" #. TRANSLATORS: waiting for device to do something msgid "Waiting…" @@ -1446,6 +1844,10 @@ msgstr "Kirjoita firmware tiedostosta laitteeseen" msgid "Write firmware from file into one partition" msgstr "Kirjoita firmware tiedostosta osioon" +#. TRANSLATORS: decompressing images from a container firmware +msgid "Writing file:" +msgstr "Kirjoitetaan tiedosto:" + #. TRANSLATORS: writing to the flash chips msgid "Writing…" msgstr "Kirjoitetaan…" @@ -1456,17 +1858,8 @@ msgstr "Jakelijasi ei ehkä ole tarkistanut mitään laiteohjelmistopäivityksi #. TRANSLATORS: program name msgid "fwupd TPM event log utility" -msgstr "fwupd TPM tapahtumalokin apuohjelma" +msgstr "fwupd:n TPM-tapahtumalokin apuohjelma" -#. TRANSLATORS: message letting the user know no device upgrade available due -#. to missing on LVFS -#. * %1 is the device name -#, c-format -msgid "• %s has no available firmware updates" -msgstr "• %s ei ole saatavilla firmware päivityksiä" - -#. TRANSLATORS: message letting the user know no device upgrade available -#. * %1 is the device name -#, c-format -msgid "• %s has the latest available firmware version" -msgstr "• %s on uusin saatavilla oleva firmware-versio" +#. TRANSLATORS: Title: if the fwupd plugins are all present and correct +msgid "fwupd plugins" +msgstr "fwupd-liitännäiset" diff --git a/po/fr.po b/po/fr.po index d6eae3871..ffadc821b 100644 --- a/po/fr.po +++ b/po/fr.po @@ -3,7 +3,9 @@ # This file is distributed under the same license as the fwupd package. # # Translators: +# Corentin Noël , 2020 # Franck , 2015 +# Julien Humbert , 2020 msgid "" msgstr "" "Project-Id-Version: fwupd\n" @@ -15,19 +17,135 @@ msgstr "" "Language: fr\n" "Plural-Forms: nplurals=2; plural=(n > 1);\n" +#. more than a minute +#, c-format +msgid "%.0f minute remaining" +msgid_plural "%.0f minutes remaining" +msgstr[0] "%.0f minute restante" +msgstr[1] "%.0f minutes restantes" + +#. TRANSLATORS: Title: %1 is ME kind, e.g. CSME/TXT, %2 is a version number +#, c-format +msgid "%s v%s" +msgstr "%s v%s" + +#. TRANSLATORS: Title: %s is ME kind, e.g. CSME/TXT +#, c-format +msgid "%s version" +msgstr "Version %s" + +#. TRANSLATORS: duration in days! +#, c-format +msgid "%u day" +msgid_plural "%u days" +msgstr[0] "%u jour" +msgstr[1] "%u jours" + +#. TRANSLATORS: duration in minutes +#, c-format +msgid "%u hour" +msgid_plural "%u hours" +msgstr[0] "%u heure" +msgstr[1] "%u heures" + +#. TRANSLATORS: duration in minutes +#, c-format +msgid "%u minute" +msgid_plural "%u minutes" +msgstr[0] "%u minute" +msgstr[1] "%u minutes" + +#. TRANSLATORS: duration in seconds +#, c-format +msgid "%u second" +msgid_plural "%u seconds" +msgstr[0] "%u seconde" +msgstr[1] "%u secondes" + +#. TRANSLATORS: this is when a device is hotplugged +msgid "Added" +msgstr "Ajouté" + +#. TRANSLATORS: the age of the metadata +msgid "Age" +msgstr "Âge" + #. TRANSLATORS: this is a command alias, e.g. 'get-devices' #, c-format msgid "Alias to %s" msgstr "Alias de %s" +#. TRANSLATORS: waiting for user to authenticate +msgid "Authenticating…" +msgstr "Authentification…" + #. TRANSLATORS: this is the PolicyKit modal dialog msgid "Authentication is required to update the firmware on this machine" msgstr "Une authentification est nécessaire pour mettre à jour le micrologiciel sur cette machine" +#. TRANSLATORS: this is to abort the interactive prompt +msgid "Cancel" +msgstr "Annuler" + +#. TRANSLATORS: this is when a device ctrl+c's a watch +msgid "Cancelled" +msgstr "Annulé" + +#. TRANSLATORS: this is when a device is hotplugged +#. TRANSLATORS: this is when the daemon state changes +msgid "Changed" +msgstr "Modifié" + +#. TRANSLATORS: remote checksum +msgid "Checksum" +msgstr "Somme de contrôle" + +#. TRANSLATORS: error message +msgid "Command not found" +msgstr "Commande non trouvée" + +#. TRANSLATORS: the release urgency +msgid "Critical" +msgstr "Critique" + +#. TRANSLATORS: version number of current firmware +msgid "Current version" +msgstr "Version actuelle" + #. TRANSLATORS: for the --verbose arg msgid "Debugging Options" msgstr "Options de débogage" +#. TRANSLATORS: decompressing the firmware file +msgid "Decompressing…" +msgstr "Décompression…" + +#. TRANSLATORS: multiline description of device +msgid "Description" +msgstr "Description" + +#. TRANSLATORS: more details about the update link +msgid "Details" +msgstr "Détails" + +#. TRANSLATORS: this is when a device is hotplugged +msgid "Device added:" +msgstr "Périphérique ajouté :" + +#. TRANSLATORS: this is when a device has been updated +msgid "Device changed:" +msgstr "Périphérique modifié :" + +#. TRANSLATORS: this is when a device is hotplugged +msgid "Device removed:" +msgstr "Périphérique retiré :" + +#. TRANSLATORS: Suffix: the HSI result +#. TRANSLATORS: Plugin is inactive and not used +msgid "Disabled" +msgstr "Désactivé" + +#. TRANSLATORS: success #. success msgid "Done!" msgstr "Terminé !" @@ -39,6 +157,24 @@ msgstr "Terminé !" msgid "Downgrading %s from %s to %s... " msgstr "Rétrogradation de %s de %s en %s" +#. TRANSLATORS: downloading from a remote server +msgid "Downloading…" +msgstr "Téléchargement…" + +#. TRANSLATORS: length of time the update takes to apply +msgid "Duration" +msgstr "Durée" + +#. TRANSLATORS: Suffix: the HSI result +#. TRANSLATORS: Plugin is active and in use +#. TRANSLATORS: if the remote is enabled +msgid "Enabled" +msgstr "Activé" + +#. TRANSLATORS: Suffix: the HSI result +msgid "Encrypted" +msgstr "Chiffré" + #. TRANSLATORS: exit after we've started up, used for user profiling msgid "Exit after a small delay" msgstr "Quitter après un bref délai" @@ -47,14 +183,31 @@ msgstr "Quitter après un bref délai" msgid "Exit after the engine has loaded" msgstr "Quitter après le chargement du moteur" +#. TRANSLATORS: Suffix: the fallback HSI result +msgid "Failed" +msgstr "Échec" + #. TRANSLATORS: the user didn't read the man page msgid "Failed to parse arguments" msgstr "Echec de l'analyse des paramètres" +#. TRANSLATORS: filename of the local file +msgid "Filename" +msgstr "Nom de fichier" + #. TRANSLATORS: program summary msgid "Firmware Update D-Bus Service" msgstr "Service D-Bus de mise à jour des micrologiciels" +#. TRANSLATORS: description of plugin state, e.g. disabled +#. TRANSLATORS: release properties +msgid "Flags" +msgstr "Drapeaux" + +#. TRANSLATORS: Suffix: the HSI result +msgid "Found" +msgstr "Trouvé" + #. TRANSLATORS: command description msgid "Get all devices that support firmware updates" msgstr "Obtenir la liste des périphériques supportant les mises à jour de micrologiciel" @@ -63,14 +216,127 @@ msgstr "Obtenir la liste des périphériques supportant les mises à jour de mic msgid "Gets details about a firmware file" msgstr "Obtenir les détails d'un fichier de micrologiciel" +#. TRANSLATORS: the release urgency +msgid "High" +msgstr "Haute" + +#. TRANSLATORS: Title: +#. https://en.wikipedia.org/wiki/Input%E2%80%93output_memory_management_unit +msgid "IOMMU" +msgstr "IOMMU" + #. TRANSLATORS: command description msgid "Install a firmware file on this hardware" msgstr "Installer un fichier de micrologiciel sur ce matériel" +#. TRANSLATORS: %1 is a device name +#, c-format +msgid "Installing on %s…" +msgstr "Installation sur %s…" + +#. TRANSLATORS: Title: BootGuard is a trademark from Intel +msgid "Intel BootGuard" +msgstr "Intel BootGuard" + +#. TRANSLATORS: Title: SMAP = Supervisor Mode Access Prevention +msgid "Intel SMAP" +msgstr "Intel SMAP" + +#. TRANSLATORS: Device cannot be removed easily +msgid "Internal device" +msgstr "Périphérique interne" + +#. TRANSLATORS: Suffix: the HSI result +msgid "Invalid" +msgstr "Invalide" + +#. TRANSLATORS: time remaining for completing firmware flash +msgid "Less than one minute remaining" +msgstr "Moins d’une minute restante" + +#. TRANSLATORS: e.g. GPLv2+, Proprietary etc +msgid "License" +msgstr "Licence" + +#. TRANSLATORS: Title: if it's tainted or not +msgid "Linux kernel" +msgstr "Noyau Linux" + +#. TRANSLATORS: parsing the firmware information +msgid "Loading…" +msgstr "Chargement…" + +#. TRANSLATORS: Suffix: the HSI result +msgid "Locked" +msgstr "Verrouillé" + +#. TRANSLATORS: the release urgency +msgid "Low" +msgstr "Faible" + +msgid "MEI version" +msgstr "Version MEI" + +#. TRANSLATORS: the release urgency +msgid "Medium" +msgstr "Moyenne" + +#. TRANSLATORS: smallest version number installable on device +msgid "Minimum Version" +msgstr "Version minimum" + +#. TRANSLATORS: version number of new firmware +msgid "New version" +msgstr "Nouvelle version" + #. TRANSLATORS: nothing attached that can be upgraded msgid "No hardware detected with firmware update capability" msgstr "Aucun matériel ayant des capacités de mise à jour du micrologiciel n'a été détecté" +#. TRANSLATORS: Suffix: the HSI result +msgid "Not found" +msgstr "Non trouvé" + +#. TRANSLATORS: Suffix: the HSI result +msgid "Not supported" +msgstr "Non pris en charge" + +#. TRANSLATORS: Suffix: the HSI result +msgid "OK" +msgstr "OK" + +#. TRANSLATORS: remote filename base +msgid "Password" +msgstr "Mot de passe" + +#. TRANSLATORS: version number of previous firmware +msgid "Previous version" +msgstr "Version précédente" + +msgid "Print the version number" +msgstr "Afficher le numéro de version" + +#. TRANSLATORS: the numeric priority +msgid "Priority" +msgstr "Priorité" + +#. TRANSLATORS: a non-free software license +msgid "Proprietary" +msgstr "Propriétaire" + +#. TRANSLATORS: %1 is a device name +#, c-format +msgid "Reading from %s…" +msgstr "Lecture depuis %s…" + +#. TRANSLATORS: reading from the flash chips +msgid "Reading…" +msgstr "Lecture…" + +#. TRANSLATORS: console message when not using plymouth +msgid "Rebooting…" +msgstr "Redémarrage…" + #. TRANSLATORS: the first replacement is a display name #. * e.g. "ColorHugALS" and the second is a version number #. * e.g. "1.2.3" @@ -78,6 +344,14 @@ msgstr "Aucun matériel ayant des capacités de mise à jour du micrologiciel n' msgid "Reinstalling %s with %s... " msgstr "Réinstallation de %s en %s" +#. TRANSLATORS: this is when a device is hotplugged +msgid "Removed" +msgstr "Retiré" + +#. TRANSLATORS: restarting the device to pick up new F/W +msgid "Restarting device…" +msgstr "Redémarrage du périphérique…" + #. TRANSLATORS: for the --verbose arg msgid "Show debugging options" msgstr "Montrer les options de débogage" @@ -86,9 +360,72 @@ msgstr "Montrer les options de débogage" msgid "Show extra debugging information" msgstr "Montre des informations de débogage complémentaires" +#. TRANSLATORS: file size of the download +msgid "Size" +msgstr "Taille" + +#. TRANSLATORS: source (as in code) link +msgid "Source" +msgstr "Source" + +#. TRANSLATORS: one line summary of device +msgid "Summary" +msgstr "Résumé" + +#. TRANSLATORS: Suffix: the HSI result +msgid "Supported" +msgstr "Pris en charge" + +#. TRANSLATORS: Title: TPM = Trusted Platform Module +msgid "TPM v2.0" +msgstr "TPM v2.0" + +#. TRANSLATORS: remote type, e.g. remote or local +msgid "Type" +msgstr "Type" + +#. TRANSLATORS: Suffix: the HSI result +msgid "Unencrypted" +msgstr "Déchiffré" + +#. TRANSLATORS: current daemon status is unknown +#. TRANSLATORS: we don't know the license of the update +#. TRANSLATORS: unknown release urgency +msgid "Unknown" +msgstr "Inconnu" + +#. TRANSLATORS: Suffix: the HSI result +msgid "Unlocked" +msgstr "Déverrouillé" + #. TRANSLATORS: the first replacement is a display name #. * e.g. "ColorHugALS" and the second and third are #. * version numbers e.g. "1.2.3" #, c-format msgid "Updating %s from %s to %s... " msgstr "Mise à jour de %s de %s en %s" + +#. TRANSLATORS: %1 is a device name +#, c-format +msgid "Updating %s…" +msgstr "Mise à jour de %s…" + +#. TRANSLATORS: remote filename base +msgid "Username" +msgstr "Nom d’utilisateur" + +#. TRANSLATORS: Suffix: the HSI result +msgid "Valid" +msgstr "Valide" + +#. TRANSLATORS: one line variant of release (e.g. 'Prerelease' or 'China') +msgid "Variant" +msgstr "Variante" + +#. TRANSLATORS: verifying we wrote the firmware correctly +msgid "Verifying…" +msgstr "Vérification…" + +#. TRANSLATORS: writing to the flash chips +msgid "Writing…" +msgstr "Écriture…" diff --git a/po/fur.po b/po/fur.po index f1e13964d..307107dde 100644 --- a/po/fur.po +++ b/po/fur.po @@ -252,6 +252,7 @@ msgid_plural "Do not upload reports, and never ask to upload reports for future msgstr[0] "No sta inviâ il rapuart e no sta domandâ plui di inviâ i rapuarts pai inzornaments futûrs" msgstr[1] "No sta inviâ i rapuarts e no sta domandâ plui di inviâ i rapuarts pai inzornaments futûrs" +#. TRANSLATORS: success #. success msgid "Done!" msgstr "Fat!" @@ -292,6 +293,8 @@ msgstr "Abilite il supuart dal inzornament dal firmware sui sistemis supuartâts msgid "Enable this remote?" msgstr "Abilitâ chest rimot?" +#. TRANSLATORS: Suffix: the HSI result +#. TRANSLATORS: Plugin is active and in use #. TRANSLATORS: if the remote is enabled msgid "Enabled" msgstr "Abilitât" @@ -394,6 +397,10 @@ msgstr "Su cheste machine a son supuartâts i inzornaments firmware." msgid "Force the action ignoring all warnings" msgstr "Sfuarce la azion ignorant ducj i avertiments" +#. TRANSLATORS: Suffix: the HSI result +msgid "Found" +msgstr "Cjatât" + #. TRANSLATORS: command description msgid "Get all devices and possible releases" msgstr "Oten ducj i dispositîfs e lis pussibilis publicazions" @@ -497,6 +504,7 @@ msgstr "Modifiche la configurazion dal demoni" msgid "Monitor the daemon for events" msgstr "Monitore il demoni pai events" +#. TRANSLATORS: user did not tell the tool what to do msgid "No action specified!" msgstr "Nissune azion specificade!" @@ -530,14 +538,14 @@ msgstr "Nissun rimot disponibil" msgid "No updates were applied" msgstr "Nol è stât aplicât nissun inzornament" +#. TRANSLATORS: Suffix: the HSI result +msgid "OK" +msgstr "Va ben" + #. TRANSLATORS: command line option msgid "Only show single PCR value" msgstr "Mostre dome il valôr PCR" -#. TRANSLATORS: command line option -msgid "Override plugin warning" -msgstr "Ignore i avertiments dal plugin" - #. TRANSLATORS: command line option msgid "Override the default ESP path" msgstr "Passe parsore al valôr dal percors ESP predefinît" @@ -664,6 +672,7 @@ msgstr "Dispositîf selezionât" msgid "Set the debugging flag during update" msgstr "Stabilìs la opzion di debug dilunc l'inzornament" +#. TRANSLATORS: firmware approved by the admin msgid "Sets the list of approved firmware" msgstr "Al stabilìs la liste dai firmware aprovâts" @@ -858,10 +867,6 @@ msgstr "Daûr a inzornâ %s…" msgid "Upgrade available for %s from %s to %s" msgstr "Inzornament disponibil par %s di %s a %s" -#. TRANSLATORS: the server sent the user a small message -msgid "Upload message:" -msgstr "Messaç dal inviament:" - msgid "Upload report just this one time, but prompt again for future updates" msgid_plural "Upload reports just this one time, but prompt again for future updates" msgstr[0] "Invie il rapuart dome cheste volte, ma torne domande pai inzornaments futûrs" @@ -888,6 +893,10 @@ msgstr "Non utent" msgid "Verifying…" msgstr "Daûr a verificâ…" +#. TRANSLATORS: the detected version number of the dbx +msgid "Version" +msgstr "Version" + #. TRANSLATORS: waiting for device to do something msgid "Waiting…" msgstr "In spiete…" diff --git a/po/gl.po b/po/gl.po new file mode 100644 index 000000000..1232a25f4 --- /dev/null +++ b/po/gl.po @@ -0,0 +1,1010 @@ +# SOME DESCRIPTIVE TITLE. +# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER +# This file is distributed under the same license as the fwupd package. +# +# Translators: +# Fran Diéguez , 2020 +msgid "" +msgstr "" +"Project-Id-Version: fwupd\n" +"Report-Msgid-Bugs-To: \n" +"Language-Team: Galician (http://www.transifex.com/freedesktop/fwupd/language/gl/)\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Language: gl\n" +"Plural-Forms: nplurals=2; plural=(n != 1);\n" + +#. more than a minute +#, c-format +msgid "%.0f minute remaining" +msgid_plural "%.0f minutes remaining" +msgstr[0] " Falta %.0f minuto" +msgstr[1] " Faltan %.0f minutos" + +#. TRANSLATORS: Title: %s is ME kind, e.g. CSME/TXT +#, c-format +msgid "%s manufacturing mode" +msgstr "Modo de fabricación %s" + +#. TRANSLATORS: Title: %1 is ME kind, e.g. CSME/TXT, %2 is a version number +#, c-format +msgid "%s v%s" +msgstr "%s v%s" + +#. TRANSLATORS: command description +msgid "Activate pending devices" +msgstr "Activar os dispositivos pendentes" + +msgid "Activate the new firmware on the device" +msgstr "Activar o novo firmware no dispositivo" + +#. TRANSLATORS: this is when a device is hotplugged +msgid "Added" +msgstr "Engadido" + +#. TRANSLATORS: should the remote still be enabled +msgid "Agree and enable the remote?" +msgstr "Aceptar e activar o remoto?" + +#. TRANSLATORS: this is a command alias, e.g. 'get-devices' +#, c-format +msgid "Alias to %s" +msgstr "Alias a %s" + +#. TRANSLATORS: command line option +msgid "Allow downgrading firmware versions" +msgstr "Permitir a desactualización de versións de firmware" + +#. TRANSLATORS: command line option +msgid "Allow reinstalling existing firmware versions" +msgstr "Permitir a reinstalación de versións de firmware existentes" + +#. TRANSLATORS: command line option +msgid "Apply firmware updates" +msgstr "Aplicar actualizacións de firmware" + +#. TRANSLATORS: command line option +msgid "Apply update even when not advised" +msgstr "Aplicar actualización incluso cando non se avise" + +#. TRANSLATORS: command line option +msgid "Apply update files" +msgstr "Aplicar ficheiros de actualización" + +#. TRANSLATORS: actually sending the update to the hardware +msgid "Applying update…" +msgstr "Aplicando actualización…" + +#. TRANSLATORS: approved firmware has been checked by +#. * the domain administrator +msgid "Approved firmware:" +msgid_plural "Approved firmware:" +msgstr[0] "Firmware aprovados:" +msgstr[1] "Firmware aprovado:" + +#. TRANSLATORS: stop nagging the user +msgid "Ask again next time?" +msgstr "Preguntar de novo a seguinte vez?" + +#. TRANSLATORS: command description +msgid "Attach to firmware mode" +msgstr "Anexarse ao modo de firmware" + +#. TRANSLATORS: waiting for user to authenticate +msgid "Authenticating…" +msgstr "Autenticando…" + +#. TRANSLATORS: this is the PolicyKit modal dialog +msgid "Authentication is required to downgrade the firmware on a removable device" +msgstr "Requírese autenticación para desactualizar o firmware nun dispositivo extraíbel" + +#. TRANSLATORS: this is the PolicyKit modal dialog +msgid "Authentication is required to downgrade the firmware on this machine" +msgstr "Requírese autenticación para desactualizar o firmware nesta máquina" + +#. TRANSLATORS: this is the PolicyKit modal dialog +msgid "Authentication is required to modify a configured remote used for firmware updates" +msgstr "Requírese autenticación para modificar a configuración do remoto usado para actualizar firmwares" + +#. TRANSLATORS: this is the PolicyKit modal dialog +msgid "Authentication is required to modify daemon configuration" +msgstr "Requírese autenticación para modificar a configuración do demonio" + +#. TRANSLATORS: this is the PolicyKit modal dialog +msgid "Authentication is required to set the list of approved firmware" +msgstr "Requírese autenticación para estabelecer a lista do firmware aprovado" + +#. TRANSLATORS: this is the PolicyKit modal dialog +msgid "Authentication is required to sign data using the client certificate" +msgstr "Requírese autenticación para asinar os datos usando o certificado do cliente" + +#. TRANSLATORS: this is the PolicyKit modal dialog +msgid "Authentication is required to switch to the new firmware version" +msgstr "Requírese autenticación para trocar a unha nova versión do firmware" + +#. TRANSLATORS: this is the PolicyKit modal dialog +msgid "Authentication is required to unlock a device" +msgstr "Requírese autenticación para desbloquear un dispositivo" + +#. TRANSLATORS: this is the PolicyKit modal dialog +msgid "Authentication is required to update the firmware on a removable device" +msgstr "Requírese autenticación para actualizar o firmware nun dispositivo extraíbel" + +#. TRANSLATORS: this is the PolicyKit modal dialog +msgid "Authentication is required to update the firmware on this machine" +msgstr "Requírese autenticación para actualizar o firmware nesta máquina" + +#. TRANSLATORS: this is the PolicyKit modal dialog +msgid "Authentication is required to update the stored checksums for the device" +msgstr "Requírese autenticación para actualizar as sumas de verificación para o dispositivo" + +#. TRANSLATORS: this is to abort the interactive prompt +msgid "Cancel" +msgstr "Cancelar" + +#. TRANSLATORS: this is when a device ctrl+c's a watch +msgid "Cancelled" +msgstr "Cancelado" + +#. TRANSLATORS: the user is using a LiveCD or LiveUSB install disk +msgid "Cannot apply updates on live media" +msgstr "Non foi posíbel aplicar as actualizacións no soporte multimedia" + +#. TRANSLATORS: this is when a device is hotplugged +#. TRANSLATORS: this is when the daemon state changes +msgid "Changed" +msgstr "Cambiado" + +#. TRANSLATORS: get interactive prompt +msgid "Choose a device:" +msgstr "Seleccione un dispositivo:" + +#. TRANSLATORS: get interactive prompt +msgid "Choose a firmware type:" +msgstr "Escolla o tipo de firmware:" + +#. TRANSLATORS: get interactive prompt +msgid "Choose a release:" +msgstr "Escolla a publicación:" + +#. TRANSLATORS: get interactive prompt +msgid "Choose a volume:" +msgstr "Escolla un volume:" + +#. TRANSLATORS: error message +msgid "Command not found" +msgstr "Orde non atopada" + +#. TRANSLATORS: command description +msgid "Convert a firmware file" +msgstr "Converter un ficheiro de firmware" + +#. TRANSLATORS: DFU stands for device firmware update +msgid "DFU Utility" +msgstr "Utilidad DFU" + +#. TRANSLATORS: for the --verbose arg +msgid "Debugging Options" +msgstr "Opcións de depuración" + +#. TRANSLATORS: decompressing the firmware file +msgid "Decompressing…" +msgstr "Descomprimindo…" + +#. TRANSLATORS: command description +msgid "Detach to bootloader mode" +msgstr "Desanexarse ao modo de firmware" + +#. TRANSLATORS: this is when a device is hotplugged +msgid "Device added:" +msgstr "Dispositivo engadido:" + +#. TRANSLATORS: this is when a device has been updated +msgid "Device changed:" +msgstr "Dispositivo cambiado" + +#. TRANSLATORS: this is when a device is hotplugged +msgid "Device removed:" +msgstr "Dispositivo retirado:" + +#. TRANSLATORS: a list of successful updates +msgid "Devices that have been updated successfully:" +msgstr "Dispositivos que foron actualizados con éxito:" + +#. TRANSLATORS: Suffix: the HSI result +#. TRANSLATORS: Plugin is inactive and not used +msgid "Disabled" +msgstr "Desactivado" + +msgid "Disabled fwupdate debugging" +msgstr "Desactivar a depuración de fwupdate" + +#. TRANSLATORS: command line option +msgid "Display version" +msgstr "Mostrar versión" + +#. TRANSLATORS: command line option +msgid "Do not check for reboot after update" +msgstr "Non marcar para reiniciar despois de actualizar" + +#. TRANSLATORS: turn on all debugging +msgid "Do not include log domain prefix" +msgstr "Non incluír o dominio do rexistro" + +#. TRANSLATORS: turn on all debugging +msgid "Do not include timestamp prefix" +msgstr "Non incluír o prefixo de marca de tempo" + +#. TRANSLATORS: command line option +msgid "Do not perform device safety checks" +msgstr "Non levar a cabo comprobacións de dispositivo" + +msgid "Do not upload report at this time, but prompt again for future updates" +msgid_plural "Do not upload reports at this time, but prompt again for future updates" +msgstr[0] "Non subir reporte esta vez, pero preguntar de novo en futuras actualizacións" +msgstr[1] "Non subir reportes esta vez, pero preguntar de novo en futuras actualizacións" + +#. TRANSLATORS: success +#. success +msgid "Done!" +msgstr "Feito!" + +#. TRANSLATORS: the first replacement is a display name +#. * e.g. "ColorHugALS" and the second and third are +#. * version numbers e.g. "1.2.3" +#, c-format +msgid "Downgrading %s from %s to %s... " +msgstr "Desactualizando %s desde %s a %s... " + +#. TRANSLATORS: %1 is a device name +#, c-format +msgid "Downgrading %s…" +msgstr "Desactualizando %s" + +#. TRANSLATORS: downloading from a remote server +msgid "Downloading…" +msgstr "Descargando…" + +#. TRANSLATORS: command description +msgid "Dump SMBIOS data from a file" +msgstr "Volcar os datos da SMBIOS desde un ficheiro " + +#. TRANSLATORS: ESP is EFI System Partition +msgid "ESP specified was not valid" +msgstr "O ESP especificado non é válido" + +#. TRANSLATORS: command line option +msgid "Enable firmware update support on supported systems" +msgstr "Activar a compatibilidade de actualización de firmware nos sistemas admitidos" + +#. TRANSLATORS: Turn on the remote +msgid "Enable this remote?" +msgstr "Desexa activar este remoto?" + +#. TRANSLATORS: Suffix: the HSI result +#. TRANSLATORS: Plugin is active and in use +#. TRANSLATORS: if the remote is enabled +msgid "Enabled" +msgstr "Activad" + +msgid "Enabled fwupdate debugging" +msgstr "Activar a depuración de fwupdate" + +msgid "Enabling this functionality is done at your own risk, which means you have to contact your original equipment manufacturer regarding any problems caused by these updates. Only problems with the update process itself should be filed at $OS_RELEASE:BUG_REPORT_URL$." +msgstr "Active esta funcionalidade baixo o seu risco, o que significa que ten que contactar co seu fabricante de equipamento orixinal se ten calquera problema con estas actualizacións. Só os problemas co proceso de actualización en si deberían enviarse en $OS_RELEASE:BUG_REPORT_URL$." + +#. TRANSLATORS: Suffix: the HSI result +msgid "Encrypted" +msgstr "Cifrad" + +#. TRANSLATORS: Title: Memory contents are encrypted, e.g. Intel TME +msgid "Encrypted RAM" +msgstr "RAM cifrada" + +#. TRANSLATORS: erasing contents of the flash chips +msgid "Erasing…" +msgstr "Borrando…" + +#. TRANSLATORS: exit after we've started up, used for user profiling +msgid "Exit after a small delay" +msgstr "Saír despois dun pequeno atraso" + +#. TRANSLATORS: exit straight away, used for automatic profiling +msgid "Exit after the engine has loaded" +msgstr "Saír despois de que se cargue o motor" + +#. TRANSLATORS: Suffix: the fallback HSI result +msgid "Failed" +msgstr "Fallido" + +#. TRANSLATORS: dbx file failed to be applied as an update +msgid "Failed to apply update" +msgstr "Produciuse un fallo ao aplicar a actualización" + +#. TRANSLATORS: we could not talk to the fwupd daemon +msgid "Failed to connect to daemon" +msgstr "Produciuse un fallo ao conectarse ao demoni" + +#. TRANSLATORS: could not parse file +msgid "Failed to extract local dbx " +msgstr "Produciuse un fallo ao extraer o dbx local" + +#. TRANSLATORS: we could not get the devices to update offline +msgid "Failed to get pending devices" +msgstr "Produciuse un fallo ao obter a lista de dispositivos pendentes" + +#. TRANSLATORS: we could not install for some reason +msgid "Failed to install firmware update" +msgstr "Produciuse un fallo ao instalar a actualización do firmware" + +#. TRANSLATORS: could not read existing system data +#. TRANSLATORS: could not read file +msgid "Failed to load local dbx" +msgstr "Produciuse un fallo ao cargar o dbx local" + +#. TRANSLATORS: could not read existing system data +msgid "Failed to load system dbx" +msgstr "Produciuse un fallo ao cargar o dbx do sistema" + +#. TRANSLATORS: the user didn't read the man page +msgid "Failed to parse arguments" +msgstr "Produciuse un fallo ao analizar os argumentos" + +#. TRANSLATORS: failed to read measurements file +msgid "Failed to parse file" +msgstr "Produciuse un fallo ao analizar o ficheiro" + +#. TRANSLATORS: the user didn't read the man page +msgid "Failed to parse flags for --filter" +msgstr "Produciuse un fallo ao analizar as bandeiras para --filter" + +#. TRANSLATORS: could not parse file +msgid "Failed to parse local dbx" +msgstr "Produciuse un fallo ao analizar a dbx local" + +#. TRANSLATORS: we could not reboot for some reason +msgid "Failed to reboot" +msgstr "Produciuse un fallo ao reiniciar" + +#. TRANSLATORS: we could not talk to plymouth +msgid "Failed to set splash mode" +msgstr "Produciuse un fallo ao modo splash" + +#. TRANSLATORS: something with a blocked hash exists +#. * in the users ESP -- which would be bad! +msgid "Failed to validate ESP contents" +msgstr "Produciuse un fallo ao validar os contidos do ESP" + +#. TRANSLATORS: user did not include a filename parameter +msgid "Filename required" +msgstr "Requírese un nome de ficheiro" + +#. TRANSLATORS: program name +msgid "Firmware Agent" +msgstr "Axente do firmware" + +#. TRANSLATORS: program summary +msgid "Firmware Update D-Bus Service" +msgstr "Servizo D-Bus da Actualización do Firmware" + +#. TRANSLATORS: program name +msgid "Firmware Update Daemon" +msgstr "Demonio de Actualización de Firmware" + +#. TRANSLATORS: program name +msgid "Firmware Utility" +msgstr "Utilidade de Firmware" + +#. TRANSLATORS: Title: if firmware updates are available +msgid "Firmware updates" +msgstr "Actualizacións de firmware" + +msgid "Firmware updates are not supported on this machine." +msgstr "Esta máquina non admite as actualizacións de firmware." + +msgid "Firmware updates are supported on this machine." +msgstr "Esta máquina admite as actualizacións de firmware." + +msgid "Force the action ignoring all warnings" +msgstr "Forzar a acción ignorando todas as advertencias" + +#. TRANSLATORS: Suffix: the HSI result +msgid "Found" +msgstr "Atopado" + +#. TRANSLATORS: command description +msgid "Get all device flags supported by fwupd" +msgstr "Obter todas as bandeiras de dispositivos admitidos por fwupd" + +#. TRANSLATORS: command description +msgid "Get all devices and possible releases" +msgstr "Obter todos os dispositivos e publicacións posíbeis" + +#. TRANSLATORS: command description +msgid "Get all devices that support firmware updates" +msgstr "Obtén todos os dispositivos que admiten actualizacións de firmware" + +#. TRANSLATORS: command description +msgid "Get all enabled plugins registered with the system" +msgstr "Obter todos os engadidos activos rexistrados no sistema" + +#. TRANSLATORS: command description +msgid "Gets details about a firmware file" +msgstr "Obtén a información sobre o ficheiro de firmware" + +#. TRANSLATORS: command description +msgid "Gets the configured remotes" +msgstr "Obten os remotos configurados" + +#. TRANSLATORS: command description +msgid "Gets the host security attributes" +msgstr "Obtén os atributos de seguranza do equipo" + +#. TRANSLATORS: command description +msgid "Gets the list of updates for connected hardware" +msgstr "Obtén a lista de actualizacións para o hardware conectado" + +#. TRANSLATORS: this is a string like 'HSI:2-U' +msgid "Host Security ID:" +msgstr "ID de seguranza do equipo:" + +#. TRANSLATORS: Title: +#. https://en.wikipedia.org/wiki/Input%E2%80%93output_memory_management_unit +msgid "IOMMU" +msgstr "IOMMU" + +#. TRANSLATORS: daemon is inactive +msgid "Idle…" +msgstr "Ocioso…" + +#. TRANSLATORS: command description +msgid "Install a firmware blob on a device" +msgstr "Instalar un blob de firmware nun dispositivo" + +#. TRANSLATORS: command description +msgid "Install a firmware file on this hardware" +msgstr "Instalar un ficheiro de firmware neste hardware" + +msgid "Install old version of system firmware" +msgstr "Instalar unha versión antiga do firmware do sistema" + +msgid "Install signed device firmware" +msgstr "Instalar firmware de dispositivo asinado" + +msgid "Install signed system firmware" +msgstr "Instalar firmware do sistema asinado" + +msgid "Install unsigned device firmware" +msgstr "Instalar firmware de dispositivo non asinado" + +msgid "Install unsigned system firmware" +msgstr "Instalar firmware do sistema non asinado" + +#. TRANSLATORS: console message when no Plymouth is installed +msgid "Installing Firmware…" +msgstr "Instalando Firmware…" + +#. TRANSLATORS: this is shown when updating the firmware after the reboot +msgid "Installing firmware update…" +msgstr "Instalando actualización do firmware…" + +#. TRANSLATORS: %1 is a device name +#, c-format +msgid "Installing on %s…" +msgstr "Instalando en %s…" + +#. TRANSLATORS: Title: BootGuard is a trademark from Intel +msgid "Intel BootGuard" +msgstr "Intel BootGuard" + +#. TRANSLATORS: Title: BootGuard is a trademark from Intel, +#. * ACM means to verify the integrity of Initial Boot Block +msgid "Intel BootGuard ACM protected" +msgstr "ACM protexido Intel BootGuard" + +#. TRANSLATORS: Title: BootGuard is a trademark from Intel, +#. * error policy is what to do on failure +msgid "Intel BootGuard error policy" +msgstr "Política de erro de Intel BootGuard" + +#. TRANSLATORS: Title: BootGuard is a trademark from Intel, +#. * verified boot refers to the way the boot process is verified +msgid "Intel BootGuard verified boot" +msgstr "Arrinque verificado de Intel BootGuard" + +#. TRANSLATORS: Title: CET = Control-flow Enforcement Technology, +#. * active means being used by the OS +msgid "Intel CET Active" +msgstr "Intel CET activo" + +#. TRANSLATORS: Title: CET = Control-flow Enforcement Technology, +#. * enabled means supported by the processor +msgid "Intel CET Enabled" +msgstr "Intel CET activado" + +#. TRANSLATORS: Title: Direct Connect Interface (DCI) allows +#. * debugging of Intel processors using the USB3 port +msgid "Intel DCI debugger" +msgstr "Depurador de Intel DCI" + +#. TRANSLATORS: Title: SMAP = Supervisor Mode Access Prevention +msgid "Intel SMAP" +msgstr "SMAP de Intel" + +#. TRANSLATORS: Suffix: the HSI result +msgid "Invalid" +msgstr "Non válido" + +#. TRANSLATORS: time remaining for completing firmware flash +msgid "Less than one minute remaining" +msgstr "Falta menos dun minuto" + +msgid "Linux Vendor Firmware Service (stable firmware)" +msgstr "Servizo de Linux Vendor Firmware (firmware estábel)" + +msgid "Linux Vendor Firmware Service (testing firmware)" +msgstr "Servizo de Linux Vendor Firmware (firmware de probas)" + +#. TRANSLATORS: Title: if it's tainted or not +msgid "Linux kernel" +msgstr "Núcleo de Linux" + +#. TRANSLATORS: Title: lockdown is a security mode of the kernel +msgid "Linux kernel lockdown" +msgstr "Bloqueo de kernel de Linux" + +#. TRANSLATORS: Title: swap space or swap partition +msgid "Linux swap" +msgstr "Swap de Linux" + +#. TRANSLATORS: command line option +msgid "List entries in dbx" +msgstr "Mostrar as entradas no dbx" + +#. TRANSLATORS: command line option +msgid "List supported firmware updates" +msgstr "Mostrar actualizacións de firmware compatíbeis" + +#. TRANSLATORS: command description +msgid "List the available firmware types" +msgstr "Lista todos os tipos de firmware dispoñíbeis" + +#. TRANSLATORS: parsing the firmware information +msgid "Loading…" +msgstr "Cargando…" + +#. TRANSLATORS: Suffix: the HSI result +msgid "Locked" +msgstr "Bloqueado" + +#. TRANSLATORS: Title: MEI = Intel Management Engine +msgid "MEI manufacturing mode" +msgstr "Modo de fabricación MEI" + +#. TRANSLATORS: Title: MEI = Intel Management Engine, and the +#. * "override" is the physical PIN that can be driven to +#. * logic high -- luckily it is probably not accessible to +#. * end users on consumer boards +msgid "MEI override" +msgstr "Omitir MEI" + +msgid "MEI version" +msgstr "Versión do MEI" + +#. TRANSLATORS: command line option +msgid "Manually enable specific plugins" +msgstr "Activar manualmente engadidos específicos" + +msgid "Modify a configured remote" +msgstr "Modificar un remoto configuración" + +msgid "Modify daemon configuration" +msgstr "Modificación configuración do demonio" + +#. TRANSLATORS: command description +msgid "Monitor the daemon for events" +msgstr "Monitorizar eventos no demonio" + +#. TRANSLATORS: user did not tell the tool what to do +msgid "No action specified!" +msgstr "Non se require ningunha acción!" + +#. TRANSLATORS: nothing found +msgid "No firmware IDs found" +msgstr "Non se atoparon IDs de firmware" + +#. TRANSLATORS: nothing found +msgid "No plugins found" +msgstr "Non se atoparon engadidos" + +#. TRANSLATORS: no repositories to download from +msgid "No releases available" +msgstr "Non hai publicacións dispoñíbeis" + +#. TRANSLATORS: no repositories to download from +msgid "No remotes available" +msgstr "Non hai remotos dispoñíbeis" + +#. TRANSLATORS: nothing was updated offline +msgid "No updates were applied" +msgstr "Non se aplicou ningunha actualización" + +#. TRANSLATORS: Suffix: the HSI result +msgid "Not found" +msgstr "Non atopado" + +#. TRANSLATORS: Suffix: the HSI result +msgid "Not supported" +msgstr "Non compatíbel" + +#. TRANSLATORS: Suffix: the HSI result +msgid "OK" +msgstr "OK" + +#. TRANSLATORS: command line option +msgid "Only show single PCR value" +msgstr "Mostrar só un valor de PCR" + +#. TRANSLATORS: command line option +msgid "Override the default ESP path" +msgstr "Sobrescribir a ruta predefinida do ESP" + +#. TRANSLATORS: command line option +msgid "Override warnings and force the action" +msgstr "Omitir avisos e forzar a acción" + +#. TRANSLATORS: command description +msgid "Parse and show details about a firmware file" +msgstr "Analixar e mostrar a información dun ficheiro de firmware" + +#. TRANSLATORS: reading new dbx from the update +msgid "Parsing dbx update…" +msgstr "Analizando a dbx de actualizacións…" + +#. TRANSLATORS: reading existing dbx from the system +msgid "Parsing system dbx…" +msgstr "Analizando o dbx do sistema…" + +#. TRANSLATORS: console message when not using plymouth +msgid "Percentage complete" +msgstr "Porcentaxe completado" + +#. TRANSLATORS: Title: DMA as in https://en.wikipedia.org/wiki/DMA_attack +msgid "Pre-boot DMA protection" +msgstr "Protección de DMA pre-arrinque" + +msgid "Print the version number" +msgstr "Imprime o número de versión" + +msgid "Print verbose debug statements" +msgstr "Imprime as sentencias de depuración verbosas" + +msgid "Proceed with upload?" +msgstr "Desexa seguir coa subida?" + +#. TRANSLATORS: command line option +msgid "Query for firmware update support" +msgstr "Consultar compatibilidade da actualización do firmware" + +#. TRANSLATORS: command description +msgid "Read a firmware blob from a device" +msgstr "Ler un blob de firmware desde un dispositivo" + +#. TRANSLATORS: command description +msgid "Read firmware from device into a file" +msgstr "Ler firmware desde o dispositivo nun ficheiro" + +#. TRANSLATORS: command description +msgid "Read firmware from one partition into a file" +msgstr "Ler firmware desde unha partición nun ficheiro" + +#. TRANSLATORS: %1 is a device name +#, c-format +msgid "Reading from %s…" +msgstr "Lendo de %s…" + +#. TRANSLATORS: reading from the flash chips +msgid "Reading…" +msgstr "Lendo…" + +#. TRANSLATORS: console message when not using plymouth +msgid "Rebooting…" +msgstr "Reiniciando…" + +#. TRANSLATORS: command description +msgid "Refresh metadata from remote server" +msgstr "Actualiza os metadatos desde un servidor remoto" + +#. TRANSLATORS: command description +msgid "Reinstall firmware on a device" +msgstr "Reinstalar firmware nun dispositivo" + +#. TRANSLATORS: the first replacement is a display name +#. * e.g. "ColorHugALS" and the second is a version number +#. * e.g. "1.2.3" +#, c-format +msgid "Reinstalling %s with %s... " +msgstr "Reinstalando %s con %s... " + +#. TRANSLATORS: this is when a device is hotplugged +msgid "Removed" +msgstr "Retirado" + +#. TRANSLATORS: command description +msgid "Replace data in an existing firmware file" +msgstr "Substituír datos nun ficheiro de firmware existente" + +#. TRANSLATORS: metadata is downloaded from the Internet +msgid "Requires internet connection" +msgstr "Require conexión a internet" + +#. TRANSLATORS: configuration changes only take effect on restart +msgid "Restart the daemon to make the change effective?" +msgstr "Desexa reiniciar o demonio para facer o cambio efectivo?" + +#. TRANSLATORS: restarting the device to pick up new F/W +msgid "Restarting device…" +msgstr "Reiniciando dispositivo…" + +#. TRANSLATORS: command description +msgid "Return all the hardware IDs for the machine" +msgstr "Devolve todos os IDs do hardware da máquina" + +#. TRANSLATORS: Title: SPI refers to the flash chip in the computer +msgid "SPI BIOS region" +msgstr "Rexión da BIOS Do SPI" + +#. TRANSLATORS: Title: SPI refers to the flash chip in the computer +msgid "SPI lock" +msgstr "Bloqueo do SPI" + +#. TRANSLATORS: Title: SPI refers to the flash chip in the computer +msgid "SPI write" +msgstr "Escritura do SPI" + +#. TRANSLATORS: scheduling an update to be done on the next boot +msgid "Scheduling…" +msgstr "Planificando…" + +#. TRANSLATORS: Device has been chosen by the daemon for the user +msgid "Selected device" +msgstr "Seleccionar un dispositivo" + +#. TRANSLATORS: Volume has been chosen by the user +msgid "Selected volume" +msgstr "Volume seleccionado" + +#. TRANSLATORS: command line option +msgid "Set the debugging flag during update" +msgstr "Establecer a bandeira de depuración durante a actualización" + +#. TRANSLATORS: firmware approved by the admin +msgid "Sets the list of approved firmware" +msgstr "Estabelece a lista do firmware aprobado" + +#. TRANSLATORS: command line option +msgid "Show client and daemon versions" +msgstr "Mostrar as versións de cliente e demonio" + +#. TRANSLATORS: for the --verbose arg +msgid "Show debugging options" +msgstr "Mostrar opcións de depuración" + +#. TRANSLATORS: command line option +msgid "Show devices that are not updatable" +msgstr "Mostrar os dispositivos que non son actualizábeis" + +#. TRANSLATORS: command line option +msgid "Show extra debugging information" +msgstr "Mostrar información de depuración adicional" + +#. TRANSLATORS: command description +msgid "Show history of firmware updates" +msgstr "Mostrar o historial das actualizacións de firmware" + +#. TRANSLATORS: this is for plugin development +msgid "Show plugin verbose information" +msgstr "Mostrar información de depuración do engadido" + +#. TRANSLATORS: command line option +msgid "Show the calculated version of the dbx" +msgstr "Mostrar a versión calculada do dbx" + +#. TRANSLATORS: command line option +msgid "Show the debug log from the last attempted update" +msgstr "Mostrar rexistro de depuración desde o último intento de actualización" + +#. TRANSLATORS: command line option +msgid "Show the information of firmware update status" +msgstr "Mostrar a información de estado da actualización do firmware" + +msgid "Sign data using the client certificate" +msgstr "Asinar os datos usando o certificafo do cliente" + +msgctxt "command-description" +msgid "Sign data using the client certificate" +msgstr "Asinar os datos usando o certificafo do cliente" + +msgid "Signature" +msgstr "Sinatura" + +msgid "Specify Vendor/Product ID(s) of DFU device" +msgstr "Especifique os IDs do Fabricante/Produto do dispositivo DFU" + +#. TRANSLATORS: command line option +msgid "Specify the dbx database file" +msgstr "Especificar o ficheiro de base de datos dbx" + +msgid "Specify the number of bytes per USB transfer" +msgstr "Especifique o número de bytes por transferenvia USB" + +#. TRANSLATORS: success message +msgid "Successfully disabled remote" +msgstr "Remoto desactivado correctamente" + +#. TRANSLATORS: success message +msgid "Successfully enabled remote" +msgstr "Remoto activado correctamente" + +#. TRANSLATORS: success message +msgid "Successfully installed firmware" +msgstr "Instalación do firmware exitosa" + +#. TRANSLATORS: success message for a per-remote setting change +msgid "Successfully modified remote" +msgstr "Remoto modficado correctamente" + +#. TRANSLATORS: success message when user verified device checksums +msgid "Successfully verified device checksums" +msgstr "Comprobáronse correctamente as sumas de verificación do dispositivo" + +#. TRANSLATORS: Suffix: the HSI result +msgid "Supported" +msgstr "Compatíbel" + +#. TRANSLATORS: Title: a better sleep state +msgid "Suspend-to-idle" +msgstr "Suspend-a-ocioso" + +#. TRANSLATORS: Title: sleep state +msgid "Suspend-to-ram" +msgstr "Suspender-a-ram" + +#. TRANSLATORS: Title: the PCR is rebuilt from the TPM event log +msgid "TPM PCR0 reconstruction" +msgstr "Reconstrución do PCR0 de TPM" + +#. TRANSLATORS: Title: TPM = Trusted Platform Module +msgid "TPM v2.0" +msgstr "TPM v2.0" + +msgid "Target" +msgstr "Obxectivo" + +#. TRANSLATORS: do not translate the variables marked using $ +msgid "The LVFS is a free service that operates as an independent legal entity and has no connection with $OS_RELEASE:NAME$. Your distributor may not have verified any of the firmware updates for compatibility with your system or connected devices. All firmware is provided only by the original equipment manufacturer." +msgstr "O LVFS é o servizo que opera como unha entidade legal independente e non ten ligazón con $OS_RELEASE:NAME$. O seu distribuidor podería non ter que comprobar se as actualizacións de firmware teñen compatibilidade co seu sistema ou dispositivos conectados. Todos os firmware son fornecidos por fabricantes de equipamento orixinal." + +#. TRANSLATORS: we're poking around as a power user +msgid "This program may only work correctly as root" +msgstr "Este programa podería funcionar correctamente só como root" + +#. TRANSLATORS: the user needs to stop playing with stuff +msgid "This tool can only be used by the root user" +msgstr "Esta ferrametne só pode ser usada por un usuario root" + +#. TRANSLATORS: program name +msgid "UEFI Firmware Utility" +msgstr "Utilidade de firmware de UEFI" + +#. TRANSLATORS: program name +msgid "UEFI dbx Utility" +msgstr "Utilidade UEFI dbx" + +#. TRANSLATORS: Title: SB is a way of locking down UEFI +msgid "UEFI secure boot" +msgstr "Arrinque seguro de UEFI" + +#. TRANSLATORS: Suffix: the HSI result +msgid "Unencrypted" +msgstr "Descifrado" + +#. TRANSLATORS: current daemon status is unknown +#. TRANSLATORS: we don't know the license of the update +#. TRANSLATORS: unknown release urgency +msgid "Unknown" +msgstr "Descoñecido" + +msgid "Unlock the device to allow access" +msgstr "Desbloquear o dispositivo para permitir o acceso" + +#. TRANSLATORS: Suffix: the HSI result +msgid "Unlocked" +msgstr "Desbloqueado" + +#. TRANSLATORS: command line option +msgid "Unset the debugging flag during update" +msgstr "Quitar a bandeira de depuración durante a actualización" + +#. TRANSLATORS: command description +msgid "Update all devices that match local metadata" +msgstr "Actualizar todos os dispositivos que coincidan os metadatos locais" + +#. TRANSLATORS: ask the user if we can update the metadata +msgid "Update now?" +msgstr "Actualizar agora" + +msgid "Update the stored device verification information" +msgstr "Actualizar a información de verificación almacenada no dispositivo" + +#. TRANSLATORS: command description +msgid "Update the stored metadata with current contents" +msgstr "Actualizaar os metadatos almacenados cos contidos actuais" + +msgid "Updating" +msgstr "Actualizando" + +#. TRANSLATORS: the first replacement is a display name +#. * e.g. "ColorHugALS" and the second and third are +#. * version numbers e.g. "1.2.3" +#, c-format +msgid "Updating %s from %s to %s... " +msgstr "Actualizando %s desde %s a %s... " + +#. TRANSLATORS: %1 is a device name +#, c-format +msgid "Updating %s…" +msgstr "Actualizando %s…" + +#. TRANSLATORS: ask the user to upload +msgid "Upload report now?" +msgstr "Desexa subir o informe agora?" + +#. TRANSLATORS: error message explaining command to run to how to get help +msgid "Use fwupdtool --help for help" +msgstr "Usar fwupdtool --help para obter axuda" + +#. TRANSLATORS: Suffix: the HSI result +msgid "Valid" +msgstr "Válido" + +#. TRANSLATORS: ESP refers to the EFI System Partition +msgid "Validating ESP contents…" +msgstr "Validando os contidos do ESP…" + +#. TRANSLATORS: verifying we wrote the firmware correctly +msgid "Verifying…" +msgstr "Verificando…" + +#. TRANSLATORS: the detected version number of the dbx +msgid "Version" +msgstr "Versión" + +#. TRANSLATORS: waiting for device to do something +msgid "Waiting…" +msgstr "Agardando…" + +#. TRANSLATORS: command description +msgid "Watch for hardware changes" +msgstr "Facer seguimento dos cambios de hardware" + +#. TRANSLATORS: command description +msgid "Write firmware from file into device" +msgstr "Escribir firmware desde un ficheiro nun dispositivo" + +#. TRANSLATORS: command description +msgid "Write firmware from file into one partition" +msgstr "Escribir firmware desde un ficheiro nunha partición" + +#. TRANSLATORS: writing to the flash chips +msgid "Writing…" +msgstr "Escribindo…" + +#. TRANSLATORS: program name +msgid "fwupd TPM event log utility" +msgstr "Utilidade de rexistro de eventos de TPM de fwupd" + +#. TRANSLATORS: Title: if the fwupd plugins are all present and correct +msgid "fwupd plugins" +msgstr "Engadidos de fwupd" diff --git a/po/he.po b/po/he.po index 4436ff1e8..6cbf390b9 100644 --- a/po/he.po +++ b/po/he.po @@ -41,6 +41,7 @@ msgstr "אפשרויות ניפוי שגיאות" msgid "Description" msgstr "תיאור" +#. TRANSLATORS: success #. success msgid "Done!" msgstr "הסתיים!" @@ -88,6 +89,10 @@ msgstr "מתקין קובץ קושחה בחומרה זו" msgid "No hardware detected with firmware update capability" msgstr "לא אותרה חומרה בעלת יכולת עדכון קושחה" +#. TRANSLATORS: Suffix: the HSI result +msgid "OK" +msgstr "אישור" + #. TRANSLATORS: the first replacement is a display name #. * e.g. "ColorHugALS" and the second is a version number #. * e.g. "1.2.3" @@ -109,3 +114,7 @@ msgstr "הצג מידע ניפוי שגיאות מורחב" #, c-format msgid "Updating %s from %s to %s... " msgstr "מעדכן %s מ־%s ל־%s..." + +#. TRANSLATORS: the detected version number of the dbx +msgid "Version" +msgstr "גרסא" diff --git a/po/hr.po b/po/hr.po index 0dc31ddc7..a060c9a7d 100644 --- a/po/hr.po +++ b/po/hr.po @@ -5,6 +5,7 @@ # Translators: # FIRST AUTHOR , 2016 # gogo , 2016 +# milotype , 2020 # gogo , 2016-2020 msgid "" msgstr "" @@ -31,6 +32,12 @@ msgstr[2] "%.0f minuta preostalo" msgid "%s CPU Microcode Update" msgstr "%s nadopuna CPU mikrokôda" +#. TRANSLATORS: a specific part of hardware, +#. * the first %s is the device name, e.g. 'Secure Boot` +#, c-format +msgid "%s Configuration Update" +msgstr "%s nadopuna podešavanja" + #. TRANSLATORS: ME stands for Management Engine, where #. * the first %s is the device name, e.g. 'ThinkPad P50` #, c-format @@ -94,6 +101,11 @@ msgstr "%s nadopuna" msgid "%s and all connected devices may not be usable while updating." msgstr "%s i svi spojeni uređaji možda neće biti upotrebljivi tijekom nadopune." +#. TRANSLATORS: Title: %s is ME kind, e.g. CSME/TXT +#, c-format +msgid "%s manufacturing mode" +msgstr "%s način rada za proizvođače" + #. TRANSLATORS: warn the user before updating, %1 is a device name #, c-format msgid "%s must remain connected for the duration of the update to avoid damage." @@ -104,6 +116,21 @@ msgstr "%s mora ostati spojen tijekom trajanja nadopune kako bi se izbjeglo ošt msgid "%s must remain plugged into a power source for the duration of the update to avoid damage." msgstr "%s mora ostati spojen s izvorom energije tijekom trajanja nadopune kako bi se izbjeglo oštećenje." +#. TRANSLATORS: Title: %s is ME kind, e.g. CSME/TXT +#, c-format +msgid "%s override" +msgstr "%s zaobilaženje" + +#. TRANSLATORS: Title: %1 is ME kind, e.g. CSME/TXT, %2 is a version number +#, c-format +msgid "%s v%s" +msgstr "%s v%s" + +#. TRANSLATORS: Title: %s is ME kind, e.g. CSME/TXT +#, c-format +msgid "%s version" +msgstr "%s inačica" + #. TRANSLATORS: duration in days! #, c-format msgid "%u day" @@ -151,6 +178,10 @@ msgstr[0] "%u sekunda" msgstr[1] "%u sekunde" msgstr[2] "%u sekundi" +#. TRANSLATORS: this is shown as a suffix for obsoleted tests +msgid "(obsoleted)" +msgstr "(zastarjelo)" + #. TRANSLATORS: command description msgid "Activate devices" msgstr "Aktiviraj uređaj" @@ -211,6 +242,18 @@ msgstr "Odgovori 'da' na sva pitanja" msgid "Apply firmware updates" msgstr "Primijeni nadopune firmvera" +#. TRANSLATORS: command line option +msgid "Apply update even when not advised" +msgstr "Primijeni nadopunu iako nije preporučljivo" + +#. TRANSLATORS: command line option +msgid "Apply update files" +msgstr "Primijeni nadopunu datoteka" + +#. TRANSLATORS: actually sending the update to the hardware +msgid "Applying update…" +msgstr "Primjena nadopuna…" + #. TRANSLATORS: approved firmware has been checked by #. * the domain administrator msgid "Approved firmware:" @@ -219,6 +262,10 @@ msgstr[0] "Odobreni firmver:" msgstr[1] "Odobreni firmveri:" msgstr[2] "Odobreni firmveri:" +#. TRANSLATORS: stop nagging the user +msgid "Ask again next time?" +msgstr "Upitaj ponovno sljedeći put?" + #. TRANSLATORS: command description msgid "Attach to firmware mode" msgstr "Prebaci u način firmvera" @@ -275,10 +322,26 @@ msgstr "Potrebna je ovjera za nadopunu spremljenog kontrolnog zbroja uređaja" msgid "Automatic Reporting" msgstr "Automatsko izvještavanje" +#. TRANSLATORS: can we JFDI? +msgid "Automatically upload every time?" +msgstr "Automatski pošalji svaki put?" + +#. TRANSLATORS: there follows a list of hashes +msgid "Blocked firmware files:" +msgstr "Datoteke blokiranog firmvera:" + +#. TRANSLATORS: we will not offer this firmware to the user +msgid "Blocking firmware:" +msgstr "Blokiranje firmvera:" + #. TRANSLATORS: firmware version of bootloader msgid "Bootloader Version" msgstr "Inačica učitača pokretanja" +#. TRANSLATORS: the stream of firmware, e.g. nonfree or open-source +msgid "Branch" +msgstr "Grana" + #. TRANSLATORS: command description msgid "Build firmware using a sandbox" msgstr "Izgradi firmver u osiguranom okruženju" @@ -291,6 +354,14 @@ msgstr "Odustani" msgid "Cancelled" msgstr "Prekinuto" +#. TRANSLATORS: same or newer update already applied +msgid "Cannot apply as dbx update has already been applied." +msgstr "Nemoguća primjena kao dbx nadopune jer je već primijenjeno." + +#. TRANSLATORS: the user is using a LiveCD or LiveUSB install disk +msgid "Cannot apply updates on live media" +msgstr "Nemoguća primjena na live medij" + #. TRANSLATORS: this is when a device is hotplugged #. TRANSLATORS: this is when the daemon state changes msgid "Changed" @@ -304,6 +375,11 @@ msgstr "Provjeri podudarnost kriptografske jedinstvene vrijednosti firmvera" msgid "Checksum" msgstr "Kontrolni zbroj" +#. TRANSLATORS: get interactive prompt, where branch is the +#. * supplier of the firmware, e.g. "non-free" or "free" +msgid "Choose a branch:" +msgstr "Odaberi granu:" + #. TRANSLATORS: get interactive prompt msgid "Choose a device:" msgstr "Odaberite uređaj:" @@ -316,6 +392,10 @@ msgstr "Odaberi vrstu firmvera:" msgid "Choose a release:" msgstr "Odaberi izdanje:" +#. TRANSLATORS: get interactive prompt +msgid "Choose a volume:" +msgstr "Odaberite uređaj:" + #. TRANSLATORS: command description msgid "Clears any updates scheduled to be updated offline" msgstr "Uklanja sve nadopune zakazne za izvanmrežno nadopunjivanje" @@ -436,6 +516,20 @@ msgstr "Uređaji koji su uspješno nadopunjeni:" msgid "Devices that were not updated correctly:" msgstr "Uređaji koji nisu ispravno nadopunjeni:" +#. TRANSLATORS: message letting the user know no device upgrade available due +#. to missing on LVFS +msgid "Devices with no available firmware updates: " +msgstr "Uređaji bez dostupnih nadopuna firmvera: " + +#. TRANSLATORS: message letting the user know no device upgrade available +msgid "Devices with the latest available firmware version:" +msgstr "Uređaji s najnovijom dostupnom inačicom firmvera:" + +#. TRANSLATORS: Suffix: the HSI result +#. TRANSLATORS: Plugin is inactive and not used +msgid "Disabled" +msgstr "Onemogućeno" + msgid "Disabled fwupdate debugging" msgstr "Onemogući fwupdate otklanjanje grešaka" @@ -487,6 +581,7 @@ msgstr[2] "Ne šaljite izvještaje, i nemoj nikada upitati za slanje izvještaja msgid "Do not write to the history database" msgstr "Ne zapisuj bazu podataka povijesti" +#. TRANSLATORS: success #. success msgid "Done!" msgstr "Završeno!" @@ -531,6 +626,8 @@ msgstr "Omogući podršku nadopune firmvera na podržanim sustavima" msgid "Enable this remote?" msgstr "Omogući ovu udaljenu lokaciju?" +#. TRANSLATORS: Suffix: the HSI result +#. TRANSLATORS: Plugin is active and in use #. TRANSLATORS: if the remote is enabled msgid "Enabled" msgstr "Omogućeno" @@ -549,6 +646,14 @@ msgstr "Omogućujete ovu funkcionalnost na vlastiti rizik, što znači da morate msgid "Enabling this remote is done at your own risk." msgstr "Ovu udaljenu lokaciju omogućavate na vlastiti rizik." +#. TRANSLATORS: Suffix: the HSI result +msgid "Encrypted" +msgstr "Šifrirano" + +#. TRANSLATORS: Title: Memory contents are encrypted, e.g. Intel TME +msgid "Encrypted RAM" +msgstr "Šifrirani RAM" + #. TRANSLATORS: command description msgid "Erase all firmware update history" msgstr "Obriši svu povijest nadopune firmvera" @@ -565,13 +670,21 @@ msgstr "Izađi nakon kratke odgode" msgid "Exit after the engine has loaded" msgstr "Izađi nakon učitavanja pogona" +#. TRANSLATORS: Suffix: the fallback HSI result +msgid "Failed" +msgstr "Neuspjelo" + +#. TRANSLATORS: dbx file failed to be applied as an update +msgid "Failed to apply update" +msgstr "Neuspjela primjena nadopune" + #. TRANSLATORS: we could not talk to the fwupd daemon msgid "Failed to connect to daemon" msgstr "Neuspjelo povezivanje s pozadinskim programom" -#. TRANSLATORS: the server is rate-limiting downloads -msgid "Failed to download due to server limit" -msgstr "Neuspjelo preuzimanje zbog ograničenja poslužitelja" +#. TRANSLATORS: could not parse file +msgid "Failed to extract local dbx " +msgstr "Neuspjelo raspakiravanje lokalnog dbx-a" #. TRANSLATORS: we could not get the devices to update offline msgid "Failed to get pending devices" @@ -581,10 +694,19 @@ msgstr "Neuspjeli prikaz uređaja na čekanju" msgid "Failed to install firmware update" msgstr "Neuspjela instalacija nadopune firmvera" +#. TRANSLATORS: could not read existing system data +#. TRANSLATORS: could not read file +msgid "Failed to load local dbx" +msgstr "Neuspjelo učitavanje lokalnog dbx-a" + #. TRANSLATORS: quirks are device-specific workarounds msgid "Failed to load quirks" msgstr "Neuspjelo učitavanje okolnosti uređaja" +#. TRANSLATORS: could not read existing system data +msgid "Failed to load system dbx" +msgstr "Neuspjelo učitavanje dbx-a sustava" + #. TRANSLATORS: the user didn't read the man page msgid "Failed to parse arguments" msgstr "Neuspjela obrada argumenata" @@ -597,6 +719,10 @@ msgstr "Neuspjela obrada datoteke" msgid "Failed to parse flags for --filter" msgstr "Neuspjela obrada oznake za --filter" +#. TRANSLATORS: could not parse file +msgid "Failed to parse local dbx" +msgstr "Neuspjela obrada lokalnog dbx-a" + #. TRANSLATORS: we could not reboot for some reason msgid "Failed to reboot" msgstr "Neuspjelo ponovno pokretanje" @@ -605,21 +731,10 @@ msgstr "Neuspjelo ponovno pokretanje" msgid "Failed to set splash mode" msgstr "Neuspjelo postavljanje splash načina" -#. TRANSLATORS: downloading unknown file -msgid "Fetching file" -msgstr "Dohvaćanje datoteke" - -#. TRANSLATORS: downloading new firmware file -msgid "Fetching firmware" -msgstr "Dohvaćanje firmvera" - -#. TRANSLATORS: downloading new metadata file -msgid "Fetching metadata" -msgstr "Dohvaćanje metapodataka" - -#. TRANSLATORS: downloading new signing file -msgid "Fetching signature" -msgstr "Dohvaćanje potpisa" +#. TRANSLATORS: something with a blocked hash exists +#. * in the users ESP -- which would be bad! +msgid "Failed to validate ESP contents" +msgstr "Neuspjela provjera ESP sadržaja" #. TRANSLATORS: filename of the local file msgid "Filename" @@ -629,6 +744,10 @@ msgstr "Naziv datoteke" msgid "Filename Signature" msgstr "Potpis naziva datoteke" +#. TRANSLATORS: user did not include a filename parameter +msgid "Filename required" +msgstr "Potreban je naziv datoteke" + #. TRANSLATORS: command line option msgid "Filter with a set of device flags using a ~ prefix to exclude, e.g. 'internal,~needs-reboot'" msgstr "Filter sa skupom oznaka uređaja koji koristi ~ prefiks za izuzimanje, npr. 'internal,~needs-reboot'" @@ -653,6 +772,18 @@ msgstr "Pozadinski program nadopune firmvera" msgid "Firmware Utility" msgstr "Firmver pomagalo" +#. TRANSLATORS: Title: if we can verify the firmware checksums +msgid "Firmware attestation" +msgstr "Frimver provjera" + +#. TRANSLATORS: user selected something not possible +msgid "Firmware is already blocked" +msgstr "Firmver je već blokiran" + +#. TRANSLATORS: user selected something not possible +msgid "Firmware is not already blocked" +msgstr "Firmver još nije blokiran" + #. TRANSLATORS: the metadata is very out of date; %u is a number > 1 #, c-format msgid "Firmware metadata has not been updated for %u day and may not be up to date." @@ -661,25 +792,34 @@ msgstr[0] "Metapodaci firmvera nisu nadopunjeni %u dan i možda nisu najnoviji." msgstr[1] "Metapodaci firmvera nisu nadopunjeni %u dana i možda nisu najnoviji." msgstr[2] "Metapodaci firmvera nisu nadopunjeni %u dana i možda nisu najnoviji." +#. TRANSLATORS: Title: if firmware updates are available +msgid "Firmware updates" +msgstr "Nadopune frimvera" + msgid "Firmware updates are not supported on this machine." msgstr "Nadopuna firmvera nije podržana na ovom računalu." msgid "Firmware updates are supported on this machine." msgstr "Nadopuna firmvera je podržana na ovom računalu." +#. TRANSLATORS: description of plugin state, e.g. disabled #. TRANSLATORS: release properties msgid "Flags" msgstr "Oznake" msgid "Force the action ignoring all warnings" -msgstr "Prisili radnju zanemarivanja svih upozorenja" +msgstr "Prisili radnju zanemarujući sva upozorenja" + +#. TRANSLATORS: Suffix: the HSI result +msgid "Found" +msgstr "Pronađeno" #. TRANSLATORS: global ID common to all similar hardware msgid "GUID" msgid_plural "GUIDs" -msgstr[0] "GUID" -msgstr[1] "GUID" -msgstr[2] "GUID" +msgstr[0] "Globalna jedinstvena oznaka" +msgstr[1] "Globalne jedinstvene oznake" +msgstr[2] "Globalne jedinstvene oznake" #. TRANSLATORS: command description msgid "Get all device flags supported by fwupd" @@ -705,9 +845,9 @@ msgstr "Prikaži pojedinosti datoteke firmvera" msgid "Gets the configured remotes" msgstr "Prikazuje udaljena podešavanja" -#. TRANSLATORS: firmware approved by the admin -msgid "Gets the list of approved firmware." -msgstr "Preuzima popis odobrenih firmvera." +#. TRANSLATORS: command description +msgid "Gets the host security attributes" +msgstr "Prikaži sigurnosne značajke poslužitelja" #. TRANSLATORS: command description msgid "Gets the list of updates for connected hardware" @@ -729,6 +869,15 @@ msgstr "Hardver čeka da ponovno bude spojen" msgid "High" msgstr "Visoka" +#. TRANSLATORS: this is a string like 'HSI:2-U' +msgid "Host Security ID:" +msgstr "Sigurnosni ID poslužitelja:" + +#. TRANSLATORS: Title: +#. https://en.wikipedia.org/wiki/Input%E2%80%93output_memory_management_unit +msgid "IOMMU" +msgstr "IOMMU" + #. TRANSLATORS: daemon is inactive msgid "Idle…" msgstr "Mirovanje..." @@ -785,10 +934,57 @@ msgstr "Instalacija nadopune firmvera..." msgid "Installing on %s…" msgstr "Instaliram na %s…" +#. TRANSLATORS: Title: BootGuard is a trademark from Intel +msgid "Intel BootGuard" +msgstr "Intel BootGuard" + +#. TRANSLATORS: Title: BootGuard is a trademark from Intel, +#. * ACM means to verify the integrity of Initial Boot Block +msgid "Intel BootGuard ACM protected" +msgstr "Intel BootGuard ACM zaštićen" + +#. TRANSLATORS: Title: BootGuard is a trademark from Intel, +#. * OTP = one time programmable +msgid "Intel BootGuard OTP fuse" +msgstr "Intel BootGuard OTP osigurač" + +#. TRANSLATORS: Title: BootGuard is a trademark from Intel, +#. * error policy is what to do on failure +msgid "Intel BootGuard error policy" +msgstr "Intel BootGuard pravilo greške" + +#. TRANSLATORS: Title: BootGuard is a trademark from Intel, +#. * verified boot refers to the way the boot process is verified +msgid "Intel BootGuard verified boot" +msgstr "Intel BootGuard provjereno pokretanje" + +#. TRANSLATORS: Title: CET = Control-flow Enforcement Technology, +#. * active means being used by the OS +msgid "Intel CET Active" +msgstr "Intel CET aktivan" + +#. TRANSLATORS: Title: CET = Control-flow Enforcement Technology, +#. * enabled means supported by the processor +msgid "Intel CET Enabled" +msgstr "Intel CET omogućen" + +#. TRANSLATORS: Title: Direct Connect Interface (DCI) allows +#. * debugging of Intel processors using the USB3 port +msgid "Intel DCI debugger" +msgstr "Intel DCI otklanatelj grešaka" + +#. TRANSLATORS: Title: SMAP = Supervisor Mode Access Prevention +msgid "Intel SMAP" +msgstr "Intel SMAP" + #. TRANSLATORS: Device cannot be removed easily msgid "Internal device" msgstr "Unutrašnji uređaj" +#. TRANSLATORS: Suffix: the HSI result +msgid "Invalid" +msgstr "Nevaljano" + #. TRANSLATORS: Is currently in bootloader mode msgid "Is in bootloader mode" msgstr "U načinu učitača pokretanja je" @@ -821,6 +1017,22 @@ msgstr "Firmver Usluga Linux Proizvođača (LVFS) (stabilni firmver)." msgid "Linux Vendor Firmware Service (testing firmware)" msgstr "Firmver Usluga Linux Proizvođača (LVFS) (testni firmver)." +#. TRANSLATORS: Title: if it's tainted or not +msgid "Linux kernel" +msgstr "Linux kernel" + +#. TRANSLATORS: Title: lockdown is a security mode of the kernel +msgid "Linux kernel lockdown" +msgstr "Linux kernel zaključavanje" + +#. TRANSLATORS: Title: swap space or swap partition +msgid "Linux swap" +msgstr "Linux swap" + +#. TRANSLATORS: command line option +msgid "List entries in dbx" +msgstr "Prikaži unose u dbx-u" + #. TRANSLATORS: command line option msgid "List supported firmware updates" msgstr "Prikaži nadopune podržanih firmvera" @@ -829,17 +1041,39 @@ msgstr "Prikaži nadopune podržanih firmvera" msgid "List the available firmware types" msgstr "Prikaži dostupne vrste firmvera" +#. TRANSLATORS: command description +msgid "Lists files on the ESP" +msgstr "Nabraja datoteke na ESP-u" + #. TRANSLATORS: parsing the firmware information msgid "Loading…" msgstr "Učitavanje..." +#. TRANSLATORS: Suffix: the HSI result +msgid "Locked" +msgstr "Zaključano" + #. TRANSLATORS: the release urgency msgid "Low" msgstr "Niska" +#. TRANSLATORS: Title: MEI = Intel Management Engine +msgid "MEI manufacturing mode" +msgstr "MEI način rada za proizvođače" + +#. TRANSLATORS: Title: MEI = Intel Management Engine, and the +#. * "override" is the physical PIN that can be driven to +#. * logic high -- luckily it is probably not accessible to +#. * end users on consumer boards +msgid "MEI override" +msgstr "MEI zaobilaženje" + +msgid "MEI version" +msgstr "MEI inačica" + #. TRANSLATORS: command line option -msgid "Manually whitelist specific plugins" -msgstr "Ručno dopusti određene priključke" +msgid "Manually enable specific plugins" +msgstr "Ručno omogući određene priključke" #. TRANSLATORS: the release urgency msgid "Medium" @@ -866,10 +1100,6 @@ msgstr "Najmanja inačica" msgid "Mismatched daemon and client, use %s instead" msgstr "Pozadinski program i klijent se ne podudaraju, umjesto koristite %s" -#. TRANSLATORS: sets something in daemon.conf -msgid "Modifies a daemon configuration value." -msgstr "Prilagođava vrijednost podešavanja pozadinskog programa." - #. TRANSLATORS: command description msgid "Modifies a given remote" msgstr "Promjena zadane udaljene lokacije" @@ -884,6 +1114,10 @@ msgstr "Prilagodi podešavanje pozadinskog programa" msgid "Monitor the daemon for events" msgstr "Nadgledaj događaje pozadinskim programom" +#. TRANSLATORS: command description +msgid "Mounts the ESP" +msgstr "Montira ESP" + #. TRANSLATORS: Requires a reboot to apply firmware or to reload hardware msgid "Needs a reboot after installation" msgstr "Potrebno je ponovno pokretanje nakon instalacije" @@ -896,6 +1130,7 @@ msgstr "Potrebno je isključivanje nakon instalacije" msgid "New version" msgstr "Nova inačica" +#. TRANSLATORS: user did not tell the tool what to do msgid "No action specified!" msgstr "Nema zadane radnje!" @@ -933,14 +1168,22 @@ msgstr "Nema dostupnih udaljenih lokacija" msgid "No updates were applied" msgstr "Nema primijenjenih nadopuna" +#. TRANSLATORS: Suffix: the HSI result +msgid "Not found" +msgstr "Nije pronađeno" + +#. TRANSLATORS: Suffix: the HSI result +msgid "Not supported" +msgstr "Nije podržano" + +#. TRANSLATORS: Suffix: the HSI result +msgid "OK" +msgstr "U redu" + #. TRANSLATORS: command line option msgid "Only show single PCR value" msgstr "Prikaži samo jednu PRC vrijednost" -#. TRANSLATORS: command line option -msgid "Override plugin warning" -msgstr "Zaobiđi upozorenja priključka" - #. TRANSLATORS: command line option msgid "Override the default ESP path" msgstr "Zaobiđi zadanu ESP putanju" @@ -953,10 +1196,21 @@ msgstr "Zaobiđi upozorenja i prisili radnju" msgid "Parse and show details about a firmware file" msgstr "Analiziraj i prikaži pojedinosti datoteke firmvera" +#. TRANSLATORS: reading new dbx from the update +msgid "Parsing dbx update…" +msgstr "Obrada dbx nadopune…" + +#. TRANSLATORS: reading existing dbx from the system +msgid "Parsing system dbx…" +msgstr "Obrada dbx-a sustava…" + #. TRANSLATORS: remote filename base msgid "Password" msgstr "Lozinka" +msgid "Payload" +msgstr "Sadržaj prijenosa" + #. TRANSLATORS: console message when not using plymouth msgid "Percentage complete" msgstr "Postotak završetka" @@ -966,6 +1220,14 @@ msgstr "Postotak završetka" msgid "Please enter a number from 0 to %u: " msgstr "Odaberite broj od 0 do %u: " +#. TRANSLATORS: Failed to open plugin, hey Arch users +msgid "Plugin dependencies missing" +msgstr "Nedostaju ovisnosti dodatka" + +#. TRANSLATORS: Title: DMA as in https://en.wikipedia.org/wiki/DMA_attack +msgid "Pre-boot DMA protection" +msgstr "DMA zaštita predpokretanja" + #. TRANSLATORS: version number of previous firmware msgid "Previous version" msgstr "Prijašnja inačica" @@ -1020,10 +1282,6 @@ msgstr "Ponovno pokretanje…" msgid "Refresh metadata from remote server" msgstr "Osvježi metapodatke s udaljenog poslužitelja" -#. TRANSLATORS: command description -msgid "Reinstall current firmware on the device." -msgstr "Ponovno instaliraj trenutni firmver na uređaju." - #. TRANSLATORS: command description msgid "Reinstall firmware on a device" msgstr "Ponovno instaliraj firmver na uređaj" @@ -1056,9 +1314,13 @@ msgstr "URI izvještaja" msgid "Reported to remote server" msgstr "Prijavljeno na udaljenom poslužitelju" -#. TRANSLATORS: Must be plugged in to an outlet -msgid "Requires AC power" -msgstr "Zahtijeva AC napajanje" +#. TRANSLATORS: the user is using Gentoo/Arch and has screwed something up +msgid "Required efivarfs filesystem was not found" +msgstr "Potrebni efivarfs datotečni sustav nije pronađen" + +#. TRANSLATORS: not required for this system +msgid "Required hardware was not found" +msgstr "Potrebni uređaj nije proneđen" #. TRANSLATORS: Requires a bootloader mode to be manually enabled by the user msgid "Requires a bootloader" @@ -1095,6 +1357,22 @@ msgstr "Pokreni rutinu čišćenja sastavljanja priključka kada se koristi inst msgid "Run the plugin composite prepare routine when using install-blob" msgstr "Pokreni rutinu pripreme sastavljanja priključka kada se koristi install-blob" +#. TRANSLATORS: this is the HSI suffix +msgid "Runtime Suffix" +msgstr "Sufiks vremenskog izvršavanja" + +#. TRANSLATORS: Title: SPI refers to the flash chip in the computer +msgid "SPI BIOS region" +msgstr "SPI BIOS područje" + +#. TRANSLATORS: Title: SPI refers to the flash chip in the computer +msgid "SPI lock" +msgstr "SPI zaključavanje" + +#. TRANSLATORS: Title: SPI refers to the flash chip in the computer +msgid "SPI write" +msgstr "SPI zapisivanje" + #. TRANSLATORS: command line option msgid "Save device state into a JSON file between executions" msgstr "Spremi stanje uređaja u JSON datoteku između izvršavanja" @@ -1111,6 +1389,10 @@ msgstr "Zakazivanje..." msgid "Selected device" msgstr "Odabrani uređaj" +#. TRANSLATORS: Volume has been chosen by the user +msgid "Selected volume" +msgstr "Odabrani uređaj" + #. TRANSLATORS: serial number of hardware msgid "Serial Number" msgstr "Serijski broj" @@ -1119,17 +1401,18 @@ msgstr "Serijski broj" msgid "Set the debugging flag during update" msgstr "Postavi oznaku otklanjanja grešaka tijekom nadopune" -msgid "Sets the list of approved firmware" -msgstr "Postavlja popis odobrenih firmvera" - #. TRANSLATORS: firmware approved by the admin -msgid "Sets the list of approved firmware." +msgid "Sets the list of approved firmware" msgstr "Postavlja popis odobrenih firmvera" #. TRANSLATORS: command description msgid "Share firmware history with the developers" msgstr "Podijeli povijest firmvera sa razvijateljima" +#. TRANSLATORS: command line option +msgid "Show all results" +msgstr "Prikaži sve rezultate" + #. TRANSLATORS: command line option msgid "Show client and daemon versions" msgstr "Prikaži inačicu klijenta i pozadinskog programa" @@ -1162,6 +1445,10 @@ msgstr "Prikaži povijest nadopune metapodataka" msgid "Show plugin verbose information" msgstr "Prikaži dodatne informacije priključka" +#. TRANSLATORS: command line option +msgid "Show the calculated version of the dbx" +msgstr "Prikaži predviđenu inčicu DBX-a" + #. TRANSLATORS: command line option msgid "Show the debug log from the last attempted update" msgstr "Prikaži zapis otklanjanja grešaka posljednjeg pokušaja nadopune" @@ -1199,6 +1486,10 @@ msgstr "Izvor" msgid "Specify Vendor/Product ID(s) of DFU device" msgstr "Odredi ID-ove Proizvođača/Proizvoda DFU uređaja" +#. TRANSLATORS: command line option +msgid "Specify the dbx database file" +msgstr "Odredi datoteku dbx baze podataka" + msgid "Specify the number of bytes per USB transfer" msgstr "Odredi broj bajtova po USB prijenosu" @@ -1257,10 +1548,38 @@ msgstr "Kontrolni zbroj uređaja je uspješno provjeren" msgid "Summary" msgstr "Sažetak" +#. TRANSLATORS: Suffix: the HSI result +msgid "Supported" +msgstr "Podržano" + #. TRANSLATORS: Is found in current metadata msgid "Supported on remote server" msgstr "Podržano na udaljenom poslužitelju" +#. TRANSLATORS: Title: a better sleep state +msgid "Suspend-to-idle" +msgstr "Suspendiraju-u-mirovanje" + +#. TRANSLATORS: Title: sleep state +msgid "Suspend-to-ram" +msgstr "Suspendiraju-u-ram" + +#. TRANSLATORS: Must be plugged in to an outlet +msgid "System requires external power source" +msgstr "Sustav zahtijeva vanjski izvor energije" + +#. TRANSLATORS: Title: the PCR is rebuilt from the TPM event log +msgid "TPM PCR0 reconstruction" +msgstr "TPM PCR0 rekonstrukcija" + +#. TRANSLATORS: Title: TPM = Trusted Platform Module +msgid "TPM v2.0" +msgstr "TPM v2.0" + +#. TRANSLATORS: Suffix: the HSI result +msgid "Tainted" +msgstr "Pokvareno" + msgid "Target" msgstr "Odredište" @@ -1268,6 +1587,14 @@ msgstr "Odredište" msgid "The LVFS is a free service that operates as an independent legal entity and has no connection with $OS_RELEASE:NAME$. Your distributor may not have verified any of the firmware updates for compatibility with your system or connected devices. All firmware is provided only by the original equipment manufacturer." msgstr "LVFS (Firmver Usluga Linux Proizvođača) je besplatna usluga koja djeluje kao neovisna pravna osoba i nema veze sa $OS_RELEASE:NAME$. Vaš distributer možda nije provjerio nadopune firmvera za kompatibilnost s vašim sustavom ili priključenim uređajima. Svi firmveri su pružani od strane izvornih proizvođača opreme." +#. TRANSLATORS: this is more background on a security measurement problem +msgid "The TPM PCR0 differs from reconstruction." +msgstr "TPM PCR0 razlikuje se od rekonstrukcije." + +#. TRANSLATORS: nothing to show +msgid "There are no blocked firmware files" +msgstr "Nema blokiranih firmvera" + #. TRANSLATORS: approved firmware has been checked by #. * the domain administrator msgid "There is no approved firmware." @@ -1280,6 +1607,18 @@ msgstr "Ovaj program možda radi ispravno samo ako je pokrenut kao korijenski ko msgid "This remote contains firmware which is not embargoed, but is still being tested by the hardware vendor. You should ensure you have a way to manually downgrade the firmware if the firmware update fails." msgstr "Ova udaljena lokacija sadrži firmver koji nije zabranjen, ali se još uvijek testira od strane proizvođača hardvera. Provjerite da imate način na ručno vraćanje starije inačice firmvera ako nadopuna firmvera ne uspije." +#. TRANSLATORS: this is instructions on how to improve the HSI suffix +msgid "This system has HSI runtime issues." +msgstr "Ovaj sustav ima HSI probleme s vremenskim izvršavanjem." + +#. TRANSLATORS: this is instructions on how to improve the HSI security level +msgid "This system has a low HSI security level." +msgstr "Ovaj sustav ima nisku HSI sigurnosnu razinu." + +#. TRANSLATORS: description of dbxtool +msgid "This tool allows an administrator to apply UEFI dbx updates." +msgstr "Ovaj alat omogućuje administratoru primjenu UEFI dbx nadopuna." + #. TRANSLATORS: the user needs to stop playing with stuff msgid "This tool can only be used by the root user" msgstr "Ovaj alat može koristiti samo korijenski korisnik" @@ -1288,10 +1627,34 @@ msgstr "Ovaj alat može koristiti samo korijenski korisnik" msgid "Type" msgstr "Vrsta" +#. TRANSLATORS: partition refers to something on disk, again, hey Arch users +msgid "UEFI ESP partition not detected or configured" +msgstr "UEFI ESP particija nije otkrivena ili konfigurirana" + #. TRANSLATORS: program name msgid "UEFI Firmware Utility" msgstr "UEFI firmver pomagalo" +#. TRANSLATORS: program name +msgid "UEFI dbx Utility" +msgstr "UEFI dbx pomagalo" + +#. TRANSLATORS: Title: SB is a way of locking down UEFI +msgid "UEFI secure boot" +msgstr "UEFI sigurno pokretanje (secure boot)" + +#. TRANSLATORS: error message +msgid "Unable to connect to service" +msgstr "Neuspjelo povezivanje s udaljenom uslugom" + +#. TRANSLATORS: we will now offer this firmware to the user +msgid "Unblocking firmware:" +msgstr "Neblokiranje firmvera:" + +#. TRANSLATORS: Suffix: the HSI result +msgid "Unencrypted" +msgstr "Nije šifrirano" + #. TRANSLATORS: current daemon status is unknown #. TRANSLATORS: we don't know the license of the update #. TRANSLATORS: unknown release urgency @@ -1305,10 +1668,18 @@ msgstr "Nepoznat uređaj" msgid "Unlock the device to allow access" msgstr "Otključaj uređaj za dopuštenje pristupa" +#. TRANSLATORS: Suffix: the HSI result +msgid "Unlocked" +msgstr "Otključano" + #. TRANSLATORS: command description msgid "Unlocks the device for firmware access" msgstr "Otključava uređaj za pristup firmveru" +#. TRANSLATORS: command description +msgid "Unmounts the ESP" +msgstr "Demontira ESP" + #. TRANSLATORS: command line option msgid "Unset the debugging flag during update" msgstr "Ukloni oznaku otklanjanja grešaka tijekom nadopune" @@ -1318,6 +1689,10 @@ msgstr "Ukloni oznaku otklanjanja grešaka tijekom nadopune" msgid "Unsupported daemon version %s, client version is %s" msgstr "Nepodržana inačica pozadinskog programa %s, inačica klijenta je %s" +#. TRANSLATORS: Suffix: the HSI result +msgid "Untainted" +msgstr "Ispravno" + #. TRANSLATORS: Device is updatable in this or any other mode msgid "Updatable" msgstr "Nadopunjivo" @@ -1366,6 +1741,9 @@ msgstr "Nadopuni pohranjene metapodatke s trenutnim sadržajem" msgid "Updates all firmware to latest versions available" msgstr "Nadopuni sav firmver na najnovije dostupne inačice" +msgid "Updating" +msgstr "Nadopunjivanje" + #. TRANSLATORS: the first replacement is a display name #. * e.g. "ColorHugALS" and the second and third are #. * version numbers e.g. "1.2.3" @@ -1384,10 +1762,6 @@ msgstr "Nadopunjujem %s…" msgid "Upgrade available for %s from %s to %s" msgstr "Nadopuna je dostupna za %s sa %s na %s" -#. TRANSLATORS: the server sent the user a small message -msgid "Upload message:" -msgstr "Pošalji poruku:" - msgid "Upload report just this one time, but prompt again for future updates" msgid_plural "Upload reports just this one time, but prompt again for future updates" msgstr[0] "Pošalji izvještaj samo ovaj puta, ali upitaj ponovno za buduće nadopune" @@ -1412,6 +1786,14 @@ msgstr "Slanje izvještaja firmvera pomaže proizvođačima hardvera brzo otkriv msgid "Urgency" msgstr "Hitnost" +#. TRANSLATORS: error message explaining command to run to how to get help +msgid "Use fwupdmgr --help for help" +msgstr "Koristite fwupdmgr --help za prikaz pomoći" + +#. TRANSLATORS: error message explaining command to run to how to get help +msgid "Use fwupdtool --help for help" +msgstr "Koristite fwupdtool --help za prikaz pomoći" + #. TRANSLATORS: command line option msgid "Use quirk flags when installing firmware" msgstr "Koristi oznake okolnosti računala tijekom instalacije firmvera" @@ -1424,6 +1806,14 @@ msgstr "Korisnik je obaviješten" msgid "Username" msgstr "Korisničko ime" +#. TRANSLATORS: Suffix: the HSI result +msgid "Valid" +msgstr "Valjano" + +#. TRANSLATORS: ESP refers to the EFI System Partition +msgid "Validating ESP contents…" +msgstr "Provjera ESP sadržaja…" + #. TRANSLATORS: one line variant of release (e.g. 'Prerelease' or 'China') msgid "Variant" msgstr "Varijanta" @@ -1436,9 +1826,13 @@ msgstr "Proizvođač" msgid "Verifying…" msgstr "Provjeravanje..." -#. TRANSLATORS: try to help -msgid "WARNING: Ignoring SSL strict checks, to do this automatically in the future export DISABLE_SSL_STRICT in your environment" -msgstr "UPOZORENJE: Zanemarivanje SSL ograničenja provjera, kako bi se ovo obavljalo ubuduće automatski postavite DISABLE_SSL_STRICT u vašem radnom okruženju" +#. TRANSLATORS: the detected version number of the dbx +msgid "Version" +msgstr "Inačica" + +#. TRANSLATORS: this is a prefix on the console +msgid "WARNING:" +msgstr "UPOZORENJE:" #. TRANSLATORS: waiting for device to do something msgid "Waiting…" @@ -1460,6 +1854,10 @@ msgstr "Zapiši firmver iz datoteke u uređaj" msgid "Write firmware from file into one partition" msgstr "Zapiši firmver iz datoteke u jednu particiju uređaja" +#. TRANSLATORS: decompressing images from a container firmware +msgid "Writing file:" +msgstr "Zapisivanje datoteke:" + #. TRANSLATORS: writing to the flash chips msgid "Writing…" msgstr "Zapisivanje..." @@ -1468,19 +1866,14 @@ msgstr "Zapisivanje..." msgid "Your distributor may not have verified any of the firmware updates for compatibility with your system or connected devices." msgstr "Vaš distributer možda nije provjerio nadopune firmvera za kompatibilnost s vašim sustavom ili priključenim uređajima." +#. TRANSLATORS: this is the default branch name when unset +msgid "default" +msgstr "standardno" + #. TRANSLATORS: program name msgid "fwupd TPM event log utility" msgstr "fwupd TPM pomagalo zapisa događaja" -#. TRANSLATORS: message letting the user know no device upgrade available due -#. to missing on LVFS -#. * %1 is the device name -#, c-format -msgid "• %s has no available firmware updates" -msgstr "• %s nema dostupnu nadopunu firmvera" - -#. TRANSLATORS: message letting the user know no device upgrade available -#. * %1 is the device name -#, c-format -msgid "• %s has the latest available firmware version" -msgstr "• %s ima najnoviju inačicu firmvera" +#. TRANSLATORS: Title: if the fwupd plugins are all present and correct +msgid "fwupd plugins" +msgstr "fwupd priključci" diff --git a/po/hu.po b/po/hu.po index 3fe3a811e..c11bdb354 100644 --- a/po/hu.po +++ b/po/hu.po @@ -3,7 +3,7 @@ # This file is distributed under the same license as the fwupd package. # # Translators: -# Balázs Meskó , 2017-2019 +# Balázs Meskó , 2017-2019 # Balázs Úr, 2015-2018 # Gabor Kelemen , 2016 # kelemeng , 2016 @@ -446,6 +446,7 @@ msgstr[1] "Ne töltsön fel jelentéseket, és sose kérdezzen rá a jövőben" msgid "Do not write to the history database" msgstr "Ne írjon az előzmények adatbázisába" +#. TRANSLATORS: success #. success msgid "Done!" msgstr "Kész!" @@ -490,6 +491,8 @@ msgstr "Firmware frissítési támogatás engedélyezése a támogatott rendszer msgid "Enable this remote?" msgstr "Engedélyezi ezt a távoli tárolót?" +#. TRANSLATORS: Suffix: the HSI result +#. TRANSLATORS: Plugin is active and in use #. TRANSLATORS: if the remote is enabled msgid "Enabled" msgstr "Engedélyezve" @@ -528,10 +531,6 @@ msgstr "Kilépés a motor betöltődése után" msgid "Failed to connect to daemon" msgstr "A démonhoz kapcsolódás sikertelen" -#. TRANSLATORS: the server is rate-limiting downloads -msgid "Failed to download due to server limit" -msgstr "A letöltés kiszolgálókorlát miatt meghiúsult" - #. TRANSLATORS: we could not get the devices to update offline msgid "Failed to get pending devices" msgstr "A függőben lévő eszközök lekérése sikertelen" @@ -560,22 +559,6 @@ msgstr "Újraindítás sikertelen" msgid "Failed to set splash mode" msgstr "Az indítóképernyő módjának beállítása sikertelen" -#. TRANSLATORS: downloading unknown file -msgid "Fetching file" -msgstr "Fájl lekérése" - -#. TRANSLATORS: downloading new firmware file -msgid "Fetching firmware" -msgstr "Firmware lekérése" - -#. TRANSLATORS: downloading new metadata file -msgid "Fetching metadata" -msgstr "Metaadatok lekérése" - -#. TRANSLATORS: downloading new signing file -msgid "Fetching signature" -msgstr "Aláírás lekérése" - #. TRANSLATORS: filename of the local file msgid "Filename" msgstr "Fájlnév" @@ -621,6 +604,7 @@ msgstr "A firmware frissítések nem támogatottak ezen a gépen." msgid "Firmware updates are supported on this machine." msgstr "A firmware frissítések támogatottak ezen a gépen." +#. TRANSLATORS: description of plugin state, e.g. disabled #. TRANSLATORS: release properties msgid "Flags" msgstr "Jelzők" @@ -628,6 +612,10 @@ msgstr "Jelzők" msgid "Force the action ignoring all warnings" msgstr "A művelet erőltetése, az összes figyelmeztetés mellőzése" +#. TRANSLATORS: Suffix: the HSI result +msgid "Found" +msgstr "Megtalálva" + #. TRANSLATORS: global ID common to all similar hardware msgid "GUID" msgid_plural "GUIDs" @@ -658,10 +646,6 @@ msgstr "Részleteket kér le egy firmware fájlról" msgid "Gets the configured remotes" msgstr "Lekéri a beállított távoli tárolókat" -#. TRANSLATORS: firmware approved by the admin -msgid "Gets the list of approved firmware." -msgstr "Lekéri a jóváhagyott firmwarek listáját." - #. TRANSLATORS: command description msgid "Gets the list of updates for connected hardware" msgstr "A frissítések listáját kéri le a csatlakoztatott hardverhez" @@ -781,10 +765,6 @@ msgstr "Az elérhető firmware típusok listázása" msgid "Loading…" msgstr "Betöltés…" -#. TRANSLATORS: command line option -msgid "Manually whitelist specific plugins" -msgstr "Egyes bővítmények kézi fehérlistára tétele" - #. TRANSLATORS: remote URI msgid "Metadata Signature" msgstr "Metaadatok aláírása" @@ -806,10 +786,6 @@ msgstr "Legkisebb verzió" msgid "Mismatched daemon and client, use %s instead" msgstr "Eltérő démon és kliens, inkább ezt használja: %s" -#. TRANSLATORS: sets something in daemon.conf -msgid "Modifies a daemon configuration value." -msgstr "Módosítja a démon egy konfigurációs értékét." - #. TRANSLATORS: command description msgid "Modifies a given remote" msgstr "A megadott távoli tároló módosítása" @@ -836,6 +812,7 @@ msgstr "A telepítés után kikapcsolást igényel" msgid "New version" msgstr "Új verzi" +#. TRANSLATORS: user did not tell the tool what to do msgid "No action specified!" msgstr "Nincs művelet megadva!" @@ -867,9 +844,9 @@ msgstr "Nincsenek elérhető távoli tárolók" msgid "No updates were applied" msgstr "Nem lett frissítés alkalmazva" -#. TRANSLATORS: command line option -msgid "Override plugin warning" -msgstr "Bővítmény figyelmeztetés felülbírálása" +#. TRANSLATORS: Suffix: the HSI result +msgid "OK" +msgstr "OK" #. TRANSLATORS: command line option msgid "Override the default ESP path" @@ -953,10 +930,6 @@ msgstr "Újraindítás…" msgid "Refresh metadata from remote server" msgstr "Metaadatok frissítése a távoli kiszolgálóról" -#. TRANSLATORS: command description -msgid "Reinstall current firmware on the device." -msgstr "Újratelepíti a jelenlegi firmware-t az eszközön." - #. TRANSLATORS: the first replacement is a display name #. * e.g. "ColorHugALS" and the second is a version number #. * e.g. "1.2.3" @@ -985,10 +958,6 @@ msgstr "Jelentési URI" msgid "Reported to remote server" msgstr "Jelentve a távoli kiszolgálónak" -#. TRANSLATORS: Must be plugged in to an outlet -msgid "Requires AC power" -msgstr "Hálózati áramforrás szükséges" - #. TRANSLATORS: Requires a bootloader mode to be manually enabled by the user msgid "Requires a bootloader" msgstr "Rendszerbetöltő szükséges" @@ -1045,13 +1014,10 @@ msgstr "Sorozatszám" msgid "Set the debugging flag during update" msgstr "A hibakeresési jelző beállítása frissítéskor" +#. TRANSLATORS: firmware approved by the admin msgid "Sets the list of approved firmware" msgstr "Beállítja a jóváhagyott firmwarek listáját" -#. TRANSLATORS: firmware approved by the admin -msgid "Sets the list of approved firmware." -msgstr "Beállítja a jóváhagyott firmwarek listáját." - #. TRANSLATORS: command description msgid "Share firmware history with the developers" msgstr "Firmware frissítése előzmények megosztása a fejlesztőkkel" @@ -1309,10 +1275,6 @@ msgstr "%s frissítése…" msgid "Upgrade available for %s from %s to %s" msgstr "%s frissítés érhető el, erről: %s, erre: %s" -#. TRANSLATORS: the server sent the user a small message -msgid "Upload message:" -msgstr "Feltöltési üzenet:" - msgid "Upload report just this one time, but prompt again for future updates" msgid_plural "Upload reports just this one time, but prompt again for future updates" msgstr[0] "Most töltse fel a jelentést, de kérdezzen rá a jövőben" @@ -1355,9 +1317,9 @@ msgstr "Gyártó" msgid "Verifying…" msgstr "Ellenőrzés…" -#. TRANSLATORS: try to help -msgid "WARNING: Ignoring SSL strict checks, to do this automatically in the future export DISABLE_SSL_STRICT in your environment" -msgstr "FIGYELMEZTETÉS: A szigorú SSL ellenőrzések mellőzése, ahhoz hogy ezt automatikusan megtegye a jövőben, exportálja a DISABLE_SSL_STRICT változót a környezetében" +#. TRANSLATORS: the detected version number of the dbx +msgid "Version" +msgstr "Verzió" #. TRANSLATORS: waiting for device to do something msgid "Waiting…" diff --git a/po/id.po b/po/id.po index c2f439b08..e9973c97a 100644 --- a/po/id.po +++ b/po/id.po @@ -447,6 +447,7 @@ msgstr[0] "Jangan unggah laporan, dan jangan pernah meminta untuk mengunggah lap msgid "Do not write to the history database" msgstr "Jangan menulis ke basis data riwayat" +#. TRANSLATORS: success #. success msgid "Done!" msgstr "Selesai!" @@ -491,6 +492,8 @@ msgstr "Aktifkan dukungan pembaruan firmware pada sistem yang didukung" msgid "Enable this remote?" msgstr "Aktifkan remote ini?" +#. TRANSLATORS: Suffix: the HSI result +#. TRANSLATORS: Plugin is active and in use #. TRANSLATORS: if the remote is enabled msgid "Enabled" msgstr "Difungsikan" @@ -529,10 +532,6 @@ msgstr "Keluar setelah mesin telah dimuat" msgid "Failed to connect to daemon" msgstr "Gagal menyambung ke daemon" -#. TRANSLATORS: the server is rate-limiting downloads -msgid "Failed to download due to server limit" -msgstr "Gagal mengunduh karena batas server" - #. TRANSLATORS: we could not get the devices to update offline msgid "Failed to get pending devices" msgstr "Gagal mendapatkan perangkat yang tertunda" @@ -565,22 +564,6 @@ msgstr "Gagal reboot" msgid "Failed to set splash mode" msgstr "Gagal mengatur mode splash" -#. TRANSLATORS: downloading unknown file -msgid "Fetching file" -msgstr "Sedang mengambil berkas" - -#. TRANSLATORS: downloading new firmware file -msgid "Fetching firmware" -msgstr "Sedang mengambil firmware" - -#. TRANSLATORS: downloading new metadata file -msgid "Fetching metadata" -msgstr "Sedang mengambil metadata" - -#. TRANSLATORS: downloading new signing file -msgid "Fetching signature" -msgstr "Sedang mengambil tanda tangan" - #. TRANSLATORS: filename of the local file msgid "Filename" msgstr "Nama Berkas" @@ -625,6 +608,7 @@ msgstr "Pembaruan firmware tidak didukung pada mesin ini." msgid "Firmware updates are supported on this machine." msgstr "Pembaruan firmware didukung pada mesin ini." +#. TRANSLATORS: description of plugin state, e.g. disabled #. TRANSLATORS: release properties msgid "Flags" msgstr "Flag" @@ -632,6 +616,10 @@ msgstr "Flag" msgid "Force the action ignoring all warnings" msgstr "Paksa tindakan mengabaikan semua peringatan" +#. TRANSLATORS: Suffix: the HSI result +msgid "Found" +msgstr "Ditemukan" + #. TRANSLATORS: global ID common to all similar hardware msgid "GUID" msgid_plural "GUIDs" @@ -661,10 +649,6 @@ msgstr "Dapatkan rincian tentang suatu berkas firmware" msgid "Gets the configured remotes" msgstr "Dapatkan remote-remote yang terkonfigurasi" -#. TRANSLATORS: firmware approved by the admin -msgid "Gets the list of approved firmware." -msgstr "Dapatkan daftar firmware yang disetujui." - #. TRANSLATORS: command description msgid "Gets the list of updates for connected hardware" msgstr "Dapatkan daftar pemutakhiran bagi perangkat keras yang tersambung" @@ -783,10 +767,6 @@ msgstr "Daftar tipe firmware yang tersedia" msgid "Loading…" msgstr "Memuat…" -#. TRANSLATORS: command line option -msgid "Manually whitelist specific plugins" -msgstr "Secara manual memasukkan daftar putih plugin tertentu" - #. TRANSLATORS: remote URI msgid "Metadata Signature" msgstr "Tanda Tangan Metadata" @@ -808,10 +788,6 @@ msgstr "Versi Minimum" msgid "Mismatched daemon and client, use %s instead" msgstr "Daemon dan klien tidak cocok, gunakan %s sebagai gantinya" -#. TRANSLATORS: sets something in daemon.conf -msgid "Modifies a daemon configuration value." -msgstr "Mengubah suatu nilai konfigurasi daemon." - #. TRANSLATORS: command description msgid "Modifies a given remote" msgstr "Mengubah suatu remote yang diberikan" @@ -838,6 +814,7 @@ msgstr "Perlu dimatikan setelah instalasi" msgid "New version" msgstr "Versi baru" +#. TRANSLATORS: user did not tell the tool what to do msgid "No action specified!" msgstr "Tidak ada tindakan yang ditentukan!" @@ -875,14 +852,14 @@ msgstr "Tidak ada remote yang tersedia" msgid "No updates were applied" msgstr "Tidak ada pembaruan yang diterapkan" +#. TRANSLATORS: Suffix: the HSI result +msgid "OK" +msgstr "OK" + #. TRANSLATORS: command line option msgid "Only show single PCR value" msgstr "Hanya tampilkan nilai PCR tunggal" -#. TRANSLATORS: command line option -msgid "Override plugin warning" -msgstr "Timpa peringatan plugin" - #. TRANSLATORS: command line option msgid "Override the default ESP path" msgstr "Timpa path ESP default" @@ -965,10 +942,6 @@ msgstr "Reboot…" msgid "Refresh metadata from remote server" msgstr "Segarkan metadata dari server remote" -#. TRANSLATORS: command description -msgid "Reinstall current firmware on the device." -msgstr "Menginstal ulang firmware saat ini di perangkat." - #. TRANSLATORS: the first replacement is a display name #. * e.g. "ColorHugALS" and the second is a version number #. * e.g. "1.2.3" @@ -997,10 +970,6 @@ msgstr "URI Lapor" msgid "Reported to remote server" msgstr "Dilaporkan ke server remote" -#. TRANSLATORS: Must be plugged in to an outlet -msgid "Requires AC power" -msgstr "Membutuhkan daya AC" - #. TRANSLATORS: Requires a bootloader mode to be manually enabled by the user msgid "Requires a bootloader" msgstr "Membutuhkan bootloader" @@ -1060,13 +1029,10 @@ msgstr "Nomor Seri" msgid "Set the debugging flag during update" msgstr "Atur flag debugging selama pembaruan" +#. TRANSLATORS: firmware approved by the admin msgid "Sets the list of approved firmware" msgstr "Setel daftar firmware yang disetujui" -#. TRANSLATORS: firmware approved by the admin -msgid "Sets the list of approved firmware." -msgstr "Tata daftar firmware yang disetujui." - #. TRANSLATORS: command description msgid "Share firmware history with the developers" msgstr "Membagikan riwayat firmware dengan para pengembang" @@ -1323,10 +1289,6 @@ msgstr "Memutakhirkan %s…" msgid "Upgrade available for %s from %s to %s" msgstr "Pembaruan tersedia untuk %s dari %s ke %s" -#. TRANSLATORS: the server sent the user a small message -msgid "Upload message:" -msgstr "Pesan unggah:" - msgid "Upload report just this one time, but prompt again for future updates" msgid_plural "Upload reports just this one time, but prompt again for future updates" msgstr[0] "Unggah laporan hanya sekali ini saja, tetapi minta lagi untuk pembaruan di masa mendatang" @@ -1367,9 +1329,9 @@ msgstr "Vendor" msgid "Verifying…" msgstr "Verifikasi…" -#. TRANSLATORS: try to help -msgid "WARNING: Ignoring SSL strict checks, to do this automatically in the future export DISABLE_SSL_STRICT in your environment" -msgstr "PERINGATAN: Mengabaikan pemeriksaan ketat SSL, untuk melakukan ini secara otomatis di masa mendatang ekspor DISABLE_SSL_STRICT dalam lingkungan Anda" +#. TRANSLATORS: the detected version number of the dbx +msgid "Version" +msgstr "Versi" #. TRANSLATORS: waiting for device to do something msgid "Waiting…" @@ -1402,16 +1364,3 @@ msgstr "Distributor Anda mungkin belum memverifikasi pembaruan firmware untuk ko #. TRANSLATORS: program name msgid "fwupd TPM event log utility" msgstr "Utilitas log kejadian TPM fwupd" - -#. TRANSLATORS: message letting the user know no device upgrade available due -#. to missing on LVFS -#. * %1 is the device name -#, c-format -msgid "• %s has no available firmware updates" -msgstr "• %s tidak memiliki pembaruan firmware yang tersedia" - -#. TRANSLATORS: message letting the user know no device upgrade available -#. * %1 is the device name -#, c-format -msgid "• %s has the latest available firmware version" -msgstr "• %s memiliki versi firmware terbaru yang tersedia" diff --git a/po/it.po b/po/it.po index 3b000ebfd..cc164a331 100644 --- a/po/it.po +++ b/po/it.po @@ -29,6 +29,12 @@ msgstr[1] "Mancano %.0f minuti" msgid "%s CPU Microcode Update" msgstr "Aggiornamento microcode CPU %s" +#. TRANSLATORS: a specific part of hardware, +#. * the first %s is the device name, e.g. 'Secure Boot` +#, c-format +msgid "%s Configuration Update" +msgstr "Aggiornamento configurazione %s" + #. TRANSLATORS: ME stands for Management Engine, where #. * the first %s is the device name, e.g. 'ThinkPad P50` #, c-format @@ -92,6 +98,11 @@ msgstr "Aggiornamento di %s" msgid "%s and all connected devices may not be usable while updating." msgstr "%s e tutti i dispositivi collegati potrebbero non essere utilizzabili durante l'aggiornamento." +#. TRANSLATORS: Title: %s is ME kind, e.g. CSME/TXT +#, c-format +msgid "%s manufacturing mode" +msgstr "Modalità costruttore %s" + #. TRANSLATORS: warn the user before updating, %1 is a device name #, c-format msgid "%s must remain connected for the duration of the update to avoid damage." @@ -102,6 +113,21 @@ msgstr "%s deve rimanere collegato durante l'aggiornamento per evitare possibili msgid "%s must remain plugged into a power source for the duration of the update to avoid damage." msgstr "%s deve rimanere collegato alla rete elettrica durante l'aggiornamento per evitare possibili danni." +#. TRANSLATORS: Title: %s is ME kind, e.g. CSME/TXT +#, c-format +msgid "%s override" +msgstr "Override %s" + +#. TRANSLATORS: Title: %1 is ME kind, e.g. CSME/TXT, %2 is a version number +#, c-format +msgid "%s v%s" +msgstr "%s v%s" + +#. TRANSLATORS: Title: %s is ME kind, e.g. CSME/TXT +#, c-format +msgid "%s version" +msgstr "Versione %s" + #. TRANSLATORS: duration in days! #, c-format msgid "%u day" @@ -143,6 +169,10 @@ msgid_plural "%u seconds" msgstr[0] "%u secondo" msgstr[1] "%u secondi" +#. TRANSLATORS: this is shown as a suffix for obsoleted tests +msgid "(obsoleted)" +msgstr "(obsoleto)" + #. TRANSLATORS: command description msgid "Activate devices" msgstr "Attiva dispositivi" @@ -187,6 +217,10 @@ msgstr "Consente di tornare alle precedenti versioni del firmware" msgid "Allow reinstalling existing firmware versions" msgstr "Consente la re-installazione di versioni esistenti del firmware" +#. TRANSLATORS: command line option +msgid "Allow switching firmware branch" +msgstr "Consente il cambio del ramo firmware" + #. TRANSLATORS: explain why we want to reboot msgid "An update requires a reboot to complete." msgstr "Per essere completato, un aggiornamento richiede un riavvio." @@ -203,6 +237,18 @@ msgstr "Risponde affermativamente a tutte le domande" msgid "Apply firmware updates" msgstr "Applica aggiornamenti firmware" +#. TRANSLATORS: command line option +msgid "Apply update even when not advised" +msgstr "Applica aggiornamento anche se non consigliato" + +#. TRANSLATORS: command line option +msgid "Apply update files" +msgstr "Applica file di aggiornamento" + +#. TRANSLATORS: actually sending the update to the hardware +msgid "Applying update…" +msgstr "Applicazione aggiornamento…" + #. TRANSLATORS: approved firmware has been checked by #. * the domain administrator msgid "Approved firmware:" @@ -210,6 +256,10 @@ msgid_plural "Approved firmware:" msgstr[0] "Firmware approvato:" msgstr[1] "Firmware approvati:" +#. TRANSLATORS: stop nagging the user +msgid "Ask again next time?" +msgstr "Chiedere ancora la prossima volta?" + #. TRANSLATORS: command description msgid "Attach to firmware mode" msgstr "Collega in modalità firmware" @@ -266,10 +316,34 @@ msgstr "È richiesto autenticarsi per aggiornare il codice di controllo del disp msgid "Automatic Reporting" msgstr "Rapporti automatici" +#. TRANSLATORS: can we JFDI? +msgid "Automatically upload every time?" +msgstr "Caricare automaticamente ogni volta?" + +#. TRANSLATORS: there follows a list of hashes +msgid "Blocked firmware files:" +msgstr "File di firmware bloccati:" + +#. TRANSLATORS: we will not offer this firmware to the user +msgid "Blocking firmware:" +msgstr "Firmware bloccato:" + +#. TRANSLATORS: command description +msgid "Blocks a specific firmware from being installed" +msgstr "Blocca un firmware specifico così da non installarlo" + #. TRANSLATORS: firmware version of bootloader msgid "Bootloader Version" msgstr "Versione bootloader" +#. TRANSLATORS: the stream of firmware, e.g. nonfree or open-source +msgid "Branch" +msgstr "Ramo" + +#. TRANSLATORS: command description +msgid "Build a firmware file" +msgstr "Compila una file firmware" + #. TRANSLATORS: command description msgid "Build firmware using a sandbox" msgstr "Compila il firmware utilizzando una sandbox" @@ -282,6 +356,14 @@ msgstr "Annulla" msgid "Cancelled" msgstr "Annullato" +#. TRANSLATORS: same or newer update already applied +msgid "Cannot apply as dbx update has already been applied." +msgstr "Impossibile applicare poiché l'aggiornamento dbx è già stato applicato." + +#. TRANSLATORS: the user is using a LiveCD or LiveUSB install disk +msgid "Cannot apply updates on live media" +msgstr "Impossibile applicare gli aggiornamenti su supporti live" + #. TRANSLATORS: this is when a device is hotplugged #. TRANSLATORS: this is when the daemon state changes msgid "Changed" @@ -295,6 +377,11 @@ msgstr "Verifica che l'hash crittografico corrisponda col firmware" msgid "Checksum" msgstr "Codice di controllo" +#. TRANSLATORS: get interactive prompt, where branch is the +#. * supplier of the firmware, e.g. "non-free" or "free" +msgid "Choose a branch:" +msgstr "Scegliere un ramo:" + #. TRANSLATORS: get interactive prompt msgid "Choose a device:" msgstr "Scegliere un dispositivo:" @@ -307,6 +394,10 @@ msgstr "Scegliere un tipo di firmware:" msgid "Choose a release:" msgstr "Scegliere un rilascio:" +#. TRANSLATORS: get interactive prompt +msgid "Choose a volume:" +msgstr "Scegliere un volume:" + #. TRANSLATORS: command description msgid "Clears any updates scheduled to be updated offline" msgstr "Annulla gli aggiornamenti pianificati per essere eseguiti offline" @@ -427,6 +518,20 @@ msgstr "Dispositivi aggiornati con successo:" msgid "Devices that were not updated correctly:" msgstr "Dispositivi non aggiornati correttamente:" +#. TRANSLATORS: message letting the user know no device upgrade available due +#. to missing on LVFS +msgid "Devices with no available firmware updates: " +msgstr "Dispositivi senza aggiornamenti firmware:" + +#. TRANSLATORS: message letting the user know no device upgrade available +msgid "Devices with the latest available firmware version:" +msgstr "Dispositivi con l'ultima versione disponibile del firmware:" + +#. TRANSLATORS: Suffix: the HSI result +#. TRANSLATORS: Plugin is inactive and not used +msgid "Disabled" +msgstr "Disabilitato" + msgid "Disabled fwupdate debugging" msgstr "Debug fwupdate disabilitato" @@ -476,6 +581,7 @@ msgstr[1] "Non caricare i rapporti e non chiedere nuovamente con i prossimi aggi msgid "Do not write to the history database" msgstr "Non scrive la cronologia" +#. TRANSLATORS: success #. success msgid "Done!" msgstr "Fatto." @@ -520,6 +626,8 @@ msgstr "Abilita il supporto all'aggiornamento firmware sui sistemi compatibili" msgid "Enable this remote?" msgstr "Abilitare questo remoto?" +#. TRANSLATORS: Suffix: the HSI result +#. TRANSLATORS: Plugin is active and in use #. TRANSLATORS: if the remote is enabled msgid "Enabled" msgstr "Abilitato" @@ -538,6 +646,14 @@ msgstr "Abilitare questa funzionalità a proprio rischio: in caso di problemi co msgid "Enabling this remote is done at your own risk." msgstr "Abilitare questo remoto a proprio rischio." +#. TRANSLATORS: Suffix: the HSI result +msgid "Encrypted" +msgstr "Cifrato" + +#. TRANSLATORS: Title: Memory contents are encrypted, e.g. Intel TME +msgid "Encrypted RAM" +msgstr "RAM cifrata" + #. TRANSLATORS: command description msgid "Erase all firmware update history" msgstr "Elimina tutta la cronologia degli aggiornamenti firmware" @@ -554,13 +670,25 @@ msgstr "Esce dopo una breve attesa" msgid "Exit after the engine has loaded" msgstr "Esce dopo che il motore è stato caricato" +#. TRANSLATORS: command description +msgid "Extract a firmware blob to images" +msgstr "Estrae un blob firmware in immagini" + +#. TRANSLATORS: Suffix: the fallback HSI result +msgid "Failed" +msgstr "Non riuscito" + +#. TRANSLATORS: dbx file failed to be applied as an update +msgid "Failed to apply update" +msgstr "Applicazione aggiornamento non riuscita" + #. TRANSLATORS: we could not talk to the fwupd daemon msgid "Failed to connect to daemon" msgstr "Connessione al demone non riuscita" -#. TRANSLATORS: the server is rate-limiting downloads -msgid "Failed to download due to server limit" -msgstr "Scaricamento non riuscito a causa di un limite sul server" +#. TRANSLATORS: could not parse file +msgid "Failed to extract local dbx " +msgstr "Estrazione dbx locale non riuscita" #. TRANSLATORS: we could not get the devices to update offline msgid "Failed to get pending devices" @@ -570,10 +698,19 @@ msgstr "Recupero dei dispositivi in attesa non riuscito" msgid "Failed to install firmware update" msgstr "Installazione aggiornamento firmware non riuscita" +#. TRANSLATORS: could not read existing system data +#. TRANSLATORS: could not read file +msgid "Failed to load local dbx" +msgstr "Caricamento dbx locale non riuscito" + #. TRANSLATORS: quirks are device-specific workarounds msgid "Failed to load quirks" msgstr "Caricamento stranezze non riuscito" +#. TRANSLATORS: could not read existing system data +msgid "Failed to load system dbx" +msgstr "Caricamento dbx di sistema non riuscito" + #. TRANSLATORS: the user didn't read the man page msgid "Failed to parse arguments" msgstr "Analisi degli argomenti non riuscita" @@ -586,6 +723,10 @@ msgstr "Lettura del file non riuscita" msgid "Failed to parse flags for --filter" msgstr "Analisi del flag --filter non riuscita" +#. TRANSLATORS: could not parse file +msgid "Failed to parse local dbx" +msgstr "Lettura dbx locale non riuscita" + #. TRANSLATORS: we could not reboot for some reason msgid "Failed to reboot" msgstr "Riavvio non riuscito" @@ -594,21 +735,10 @@ msgstr "Riavvio non riuscito" msgid "Failed to set splash mode" msgstr "Impostazione della modalità splash non riuscita" -#. TRANSLATORS: downloading unknown file -msgid "Fetching file" -msgstr "Recupero file" - -#. TRANSLATORS: downloading new firmware file -msgid "Fetching firmware" -msgstr "Recupero firmware" - -#. TRANSLATORS: downloading new metadata file -msgid "Fetching metadata" -msgstr "Recupero metadati" - -#. TRANSLATORS: downloading new signing file -msgid "Fetching signature" -msgstr "Recupero firma" +#. TRANSLATORS: something with a blocked hash exists +#. * in the users ESP -- which would be bad! +msgid "Failed to validate ESP contents" +msgstr "Verifica contenuti ESP non riuscita" #. TRANSLATORS: filename of the local file msgid "Filename" @@ -618,6 +748,10 @@ msgstr "Nome file" msgid "Filename Signature" msgstr "Firma nome file" +#. TRANSLATORS: user did not include a filename parameter +msgid "Filename required" +msgstr "Nome file richiesto" + #. TRANSLATORS: command line option msgid "Filter with a set of device flags using a ~ prefix to exclude, e.g. 'internal,~needs-reboot'" msgstr "Filtra tramite un insieme di flag utilizzando ~ per escludere, per esempio «internal, ~needs-reboot»" @@ -642,6 +776,18 @@ msgstr "Demone di aggiornamento firmware" msgid "Firmware Utility" msgstr "Strumento gestione firmware" +#. TRANSLATORS: Title: if we can verify the firmware checksums +msgid "Firmware attestation" +msgstr "Convalida firmware" + +#. TRANSLATORS: user selected something not possible +msgid "Firmware is already blocked" +msgstr "Il firmware è già bloccato" + +#. TRANSLATORS: user selected something not possible +msgid "Firmware is not already blocked" +msgstr "Il firmware non è bloccato" + #. TRANSLATORS: the metadata is very out of date; %u is a number > 1 #, c-format msgid "Firmware metadata has not been updated for %u day and may not be up to date." @@ -649,12 +795,17 @@ msgid_plural "Firmware metadata has not been updated for %u days and may not be msgstr[0] "I metadati del firmware non sono stati controllati per %u giorno e potrebbero non essere aggiornati." msgstr[1] "I metadati del firmware non sono stati controllati per %u giorni e potrebbero non essere aggiornati." +#. TRANSLATORS: Title: if firmware updates are available +msgid "Firmware updates" +msgstr "Aggiornamenti firmware" + msgid "Firmware updates are not supported on this machine." msgstr "Gli aggiornamenti firmware non sono supportati su questo dispositivo." msgid "Firmware updates are supported on this machine." msgstr "Gli aggiornamenti firmware sono supportati su questo dispositivo." +#. TRANSLATORS: description of plugin state, e.g. disabled #. TRANSLATORS: release properties msgid "Flags" msgstr "Flag" @@ -662,6 +813,10 @@ msgstr "Flag" msgid "Force the action ignoring all warnings" msgstr "Forza l'azione ignorando gli avvisi" +#. TRANSLATORS: Suffix: the HSI result +msgid "Found" +msgstr "Trovato" + #. TRANSLATORS: global ID common to all similar hardware msgid "GUID" msgid_plural "GUIDs" @@ -692,9 +847,17 @@ msgstr "Ottiene le informazioni su un file di firmware" msgid "Gets the configured remotes" msgstr "Ottiene i remoti configurati" +#. TRANSLATORS: command description +msgid "Gets the host security attributes" +msgstr "Recupera gli attributi di sicurezza dell'host" + #. TRANSLATORS: firmware approved by the admin -msgid "Gets the list of approved firmware." -msgstr "Recupera l'elenco dei firmware approvati." +msgid "Gets the list of approved firmware" +msgstr "Recupera l'elenco dei firmware approvati" + +#. TRANSLATORS: command description +msgid "Gets the list of blocked firmware" +msgstr "Recupera l'elenco del firmware bloccato" #. TRANSLATORS: command description msgid "Gets the list of updates for connected hardware" @@ -716,6 +879,15 @@ msgstr "L'hardware è in attesa di essere ricollegato" msgid "High" msgstr "Elevata" +#. TRANSLATORS: this is a string like 'HSI:2-U' +msgid "Host Security ID:" +msgstr "ID sicurezza host:" + +#. TRANSLATORS: Title: +#. https://en.wikipedia.org/wiki/Input%E2%80%93output_memory_management_unit +msgid "IOMMU" +msgstr "IOMMU" + #. TRANSLATORS: daemon is inactive msgid "Idle…" msgstr "Inattivo…" @@ -724,6 +896,10 @@ msgstr "Inattivo…" msgid "Ignore SSL strict checks when downloading files" msgstr "Ignora controlli SSL nello scaricare i file" +#. TRANSLATORS: command line option +msgid "Ignore firmware checksum failures" +msgstr "Ignora i checksum del firmware non riusciti" + #. TRANSLATORS: Ignore validation safety checks when flashing this device msgid "Ignore validation safety checks" msgstr "Ignora i controlli di sicurezza di validazione" @@ -772,10 +948,57 @@ msgstr "Installazione aggiornamento firmware…" msgid "Installing on %s…" msgstr "Installazione su %s…" +#. TRANSLATORS: Title: BootGuard is a trademark from Intel +msgid "Intel BootGuard" +msgstr "Intel BootGuard" + +#. TRANSLATORS: Title: BootGuard is a trademark from Intel, +#. * ACM means to verify the integrity of Initial Boot Block +msgid "Intel BootGuard ACM protected" +msgstr "ACM protetto da Intel BootGuard" + +#. TRANSLATORS: Title: BootGuard is a trademark from Intel, +#. * OTP = one time programmable +msgid "Intel BootGuard OTP fuse" +msgstr "Fusibile OTP Intel BootGuard" + +#. TRANSLATORS: Title: BootGuard is a trademark from Intel, +#. * error policy is what to do on failure +msgid "Intel BootGuard error policy" +msgstr "Regole di errore Intel BootGuard" + +#. TRANSLATORS: Title: BootGuard is a trademark from Intel, +#. * verified boot refers to the way the boot process is verified +msgid "Intel BootGuard verified boot" +msgstr "Avvio verificato da Intel BootGuard" + +#. TRANSLATORS: Title: CET = Control-flow Enforcement Technology, +#. * active means being used by the OS +msgid "Intel CET Active" +msgstr "Intel CET attivo" + +#. TRANSLATORS: Title: CET = Control-flow Enforcement Technology, +#. * enabled means supported by the processor +msgid "Intel CET Enabled" +msgstr "Intel CET abilitato" + +#. TRANSLATORS: Title: Direct Connect Interface (DCI) allows +#. * debugging of Intel processors using the USB3 port +msgid "Intel DCI debugger" +msgstr "Debugger Intel DCI" + +#. TRANSLATORS: Title: SMAP = Supervisor Mode Access Prevention +msgid "Intel SMAP" +msgstr "Intel SMAP" + #. TRANSLATORS: Device cannot be removed easily msgid "Internal device" msgstr "Dispositivo interno" +#. TRANSLATORS: Suffix: the HSI result +msgid "Invalid" +msgstr "Non valido" + #. TRANSLATORS: Is currently in bootloader mode msgid "Is in bootloader mode" msgstr "È in modalità bootloader" @@ -807,6 +1030,22 @@ msgstr "Linux Vendor Firmware Service (firmware stabile)" msgid "Linux Vendor Firmware Service (testing firmware)" msgstr "Linux Vendor Firmware Service (firmware in prova)" +#. TRANSLATORS: Title: if it's tainted or not +msgid "Linux kernel" +msgstr "Kernel Linux" + +#. TRANSLATORS: Title: lockdown is a security mode of the kernel +msgid "Linux kernel lockdown" +msgstr "Lockdown kernel Linux" + +#. TRANSLATORS: Title: swap space or swap partition +msgid "Linux swap" +msgstr "Swap Linux" + +#. TRANSLATORS: command line option +msgid "List entries in dbx" +msgstr "Elenca le voci nel dbx" + #. TRANSLATORS: command line option msgid "List supported firmware updates" msgstr "Elenca gli aggiornamenti firmware supportati" @@ -815,17 +1054,39 @@ msgstr "Elenca gli aggiornamenti firmware supportati" msgid "List the available firmware types" msgstr "Elenca tutti i tipi di firmware disponibili" +#. TRANSLATORS: command description +msgid "Lists files on the ESP" +msgstr "Elenca i file nell'ESP" + #. TRANSLATORS: parsing the firmware information msgid "Loading…" msgstr "Caricamento…" +#. TRANSLATORS: Suffix: the HSI result +msgid "Locked" +msgstr "Bloccato" + #. TRANSLATORS: the release urgency msgid "Low" msgstr "Bassa" +#. TRANSLATORS: Title: MEI = Intel Management Engine +msgid "MEI manufacturing mode" +msgstr "Modalità costruttore MEI" + +#. TRANSLATORS: Title: MEI = Intel Management Engine, and the +#. * "override" is the physical PIN that can be driven to +#. * logic high -- luckily it is probably not accessible to +#. * end users on consumer boards +msgid "MEI override" +msgstr "Override MEI" + +msgid "MEI version" +msgstr "Versione MEI" + #. TRANSLATORS: command line option -msgid "Manually whitelist specific plugins" -msgstr "Abilita manualmente plugin specifici" +msgid "Manually enable specific plugins" +msgstr "Abilita manualmente i plugin selezionati" #. TRANSLATORS: the release urgency msgid "Medium" @@ -853,7 +1114,7 @@ msgid "Mismatched daemon and client, use %s instead" msgstr "Versioni di demone e client non corrispondenti, usare %s" #. TRANSLATORS: sets something in daemon.conf -msgid "Modifies a daemon configuration value." +msgid "Modifies a daemon configuration value" msgstr "Modifica il valore della configurazione del demone" #. TRANSLATORS: command description @@ -870,6 +1131,10 @@ msgstr "Modifica la configurazione del demone" msgid "Monitor the daemon for events" msgstr "Controlla il demone per gli eventi" +#. TRANSLATORS: command description +msgid "Mounts the ESP" +msgstr "Monta l'ESP" + #. TRANSLATORS: Requires a reboot to apply firmware or to reload hardware msgid "Needs a reboot after installation" msgstr "Necessita un riavvio dopo l'installazione" @@ -882,6 +1147,7 @@ msgstr "Necessita l'arresto dopo l'installazione" msgid "New version" msgstr "Nuova versione" +#. TRANSLATORS: user did not tell the tool what to do msgid "No action specified!" msgstr "Nessuna azione specificata." @@ -919,14 +1185,22 @@ msgstr "Nessun server disponibile" msgid "No updates were applied" msgstr "Non è stato applicato alcun aggiornamento" +#. TRANSLATORS: Suffix: the HSI result +msgid "Not found" +msgstr "Non trovato" + +#. TRANSLATORS: Suffix: the HSI result +msgid "Not supported" +msgstr "Non supportato" + +#. TRANSLATORS: Suffix: the HSI result +msgid "OK" +msgstr "Fatto" + #. TRANSLATORS: command line option msgid "Only show single PCR value" msgstr "Mostra solo il valore PCR" -#. TRANSLATORS: command line option -msgid "Override plugin warning" -msgstr "Scavalca l'avviso sul plugin" - #. TRANSLATORS: command line option msgid "Override the default ESP path" msgstr "Sovrascrive il percorso ESP predefinito" @@ -939,6 +1213,14 @@ msgstr "Scavalca gli avvisi e forza l'azione" msgid "Parse and show details about a firmware file" msgstr "Legge e mostra i dettagli riguardo a un file firmware" +#. TRANSLATORS: reading new dbx from the update +msgid "Parsing dbx update…" +msgstr "Lettura aggiornamento dbx…" + +#. TRANSLATORS: reading existing dbx from the system +msgid "Parsing system dbx…" +msgstr "Lettura dbx di sistema…" + #. TRANSLATORS: remote filename base msgid "Password" msgstr "Password" @@ -955,6 +1237,14 @@ msgstr "Percentuale completamento" msgid "Please enter a number from 0 to %u: " msgstr "Inserire un numero tra 0 e %u:" +#. TRANSLATORS: Failed to open plugin, hey Arch users +msgid "Plugin dependencies missing" +msgstr "Dipendenze plugin mancanti" + +#. TRANSLATORS: Title: DMA as in https://en.wikipedia.org/wiki/DMA_attack +msgid "Pre-boot DMA protection" +msgstr "Protezione DMA pre-boot" + #. TRANSLATORS: version number of previous firmware msgid "Previous version" msgstr "Versione precedente" @@ -1010,7 +1300,7 @@ msgid "Refresh metadata from remote server" msgstr "Ricarica i metadati dal server remoto" #. TRANSLATORS: command description -msgid "Reinstall current firmware on the device." +msgid "Reinstall current firmware on the device" msgstr "Installa nuovamente il firmware attuale sul dispositivo" #. TRANSLATORS: command description @@ -1045,10 +1335,6 @@ msgstr "URI del rapporto" msgid "Reported to remote server" msgstr "Segnalato al server remoto" -#. TRANSLATORS: Must be plugged in to an outlet -msgid "Requires AC power" -msgstr "Richiede corrente elettrica" - #. TRANSLATORS: Requires a bootloader mode to be manually enabled by the user msgid "Requires a bootloader" msgstr "Richiede un bootloader" @@ -1084,6 +1370,22 @@ msgstr "Esegue la procedura di pulizia del plugin quando si utilizza install-blo msgid "Run the plugin composite prepare routine when using install-blob" msgstr "Esegue la procedura di preparazione del plugin quando si utilizza install-blob" +#. TRANSLATORS: this is the HSI suffix +msgid "Runtime Suffix" +msgstr "Suffisso di runtime" + +#. TRANSLATORS: Title: SPI refers to the flash chip in the computer +msgid "SPI BIOS region" +msgstr "Regione BIOS SPI" + +#. TRANSLATORS: Title: SPI refers to the flash chip in the computer +msgid "SPI lock" +msgstr "Blocco SPI" + +#. TRANSLATORS: Title: SPI refers to the flash chip in the computer +msgid "SPI write" +msgstr "Scrittura SPI" + #. TRANSLATORS: command line option msgid "Save device state into a JSON file between executions" msgstr "Salva lo stato del dispositivo tra le esecuzioni su un file JSON" @@ -1100,6 +1402,10 @@ msgstr "Pianificazione…" msgid "Selected device" msgstr "Dispositivo selezionato" +#. TRANSLATORS: Volume has been chosen by the user +msgid "Selected volume" +msgstr "Volume selezionato" + #. TRANSLATORS: serial number of hardware msgid "Serial Number" msgstr "Numero di serie" @@ -1108,17 +1414,18 @@ msgstr "Numero di serie" msgid "Set the debugging flag during update" msgstr "Imposta il flag di debug durante l'aggiornamento" +#. TRANSLATORS: firmware approved by the admin msgid "Sets the list of approved firmware" msgstr "Imposta l'elenco dei firmware approvati" -#. TRANSLATORS: firmware approved by the admin -msgid "Sets the list of approved firmware." -msgstr "Imposta l'elenco dei firmware approvati." - #. TRANSLATORS: command description msgid "Share firmware history with the developers" msgstr "Condivide la cronologia del firmware con gli sviluppatori" +#. TRANSLATORS: command line option +msgid "Show all results" +msgstr "Mostra tutti i risultati" + #. TRANSLATORS: command line option msgid "Show client and daemon versions" msgstr "Mostra la versione del client e del demone" @@ -1151,6 +1458,10 @@ msgstr "Mostra la cronologia degli aggiornamenti firmware" msgid "Show plugin verbose information" msgstr "Mostra informazioni dettagliate del plugin" +#. TRANSLATORS: command line option +msgid "Show the calculated version of the dbx" +msgstr "Mostra la versione calcolata del dbx" + #. TRANSLATORS: command line option msgid "Show the debug log from the last attempted update" msgstr "Mostra debug dell'ultimo tentativo di aggiornamento" @@ -1188,6 +1499,10 @@ msgstr "Sorgente" msgid "Specify Vendor/Product ID(s) of DFU device" msgstr "Specifica vendor/ID prodotto di un dispositivo DFU" +#. TRANSLATORS: command line option +msgid "Specify the dbx database file" +msgstr "Indica il file del database dbx" + msgid "Specify the number of bytes per USB transfer" msgstr "Specifica il numero di byte per trasferimento USB" @@ -1245,10 +1560,34 @@ msgstr "Codici di controllo del dispositivo verificati con successo" msgid "Summary" msgstr "Riepilogo" +#. TRANSLATORS: Suffix: the HSI result +msgid "Supported" +msgstr "Supportato" + #. TRANSLATORS: Is found in current metadata msgid "Supported on remote server" msgstr "Supportato sul server remoto" +#. TRANSLATORS: Title: a better sleep state +msgid "Suspend-to-idle" +msgstr "Suspend-to-idle" + +#. TRANSLATORS: Title: sleep state +msgid "Suspend-to-ram" +msgstr "Suspend-to-ram" + +#. TRANSLATORS: Title: the PCR is rebuilt from the TPM event log +msgid "TPM PCR0 reconstruction" +msgstr "Ricostruzione PCR0 TPM" + +#. TRANSLATORS: Title: TPM = Trusted Platform Module +msgid "TPM v2.0" +msgstr "TPM v2.0" + +#. TRANSLATORS: Suffix: the HSI result +msgid "Tainted" +msgstr "Non integro" + msgid "Target" msgstr "Obiettivo" @@ -1256,6 +1595,14 @@ msgstr "Obiettivo" msgid "The LVFS is a free service that operates as an independent legal entity and has no connection with $OS_RELEASE:NAME$. Your distributor may not have verified any of the firmware updates for compatibility with your system or connected devices. All firmware is provided only by the original equipment manufacturer." msgstr "LVFS è un servizio gratuito che opera come entità legale indipendente e non ha alcun legame con $OS_RELEASE:NAME$. Il distributore potrebbe non aver verificato la compatibilità degli aggiornamenti firmware col proprio sistema o con i propri dispositivi collegati. Il firmware viene fornito solamente dall'OEM." +#. TRANSLATORS: this is more background on a security measurement problem +msgid "The TPM PCR0 differs from reconstruction." +msgstr "TPM PCR0 è diverso dalla ricostruzione." + +#. TRANSLATORS: nothing to show +msgid "There are no blocked firmware files" +msgstr "Non ci sono file di firmware bloccati" + #. TRANSLATORS: approved firmware has been checked by #. * the domain administrator msgid "There is no approved firmware." @@ -1268,6 +1615,18 @@ msgstr "Questo programma può funzionare correttamente solo come utente root" msgid "This remote contains firmware which is not embargoed, but is still being tested by the hardware vendor. You should ensure you have a way to manually downgrade the firmware if the firmware update fails." msgstr "Questo remoto contiene firmware che non è bloccato, ma è ancora in fase di verifica dal produttore hardware. Assicurarsi di poter ripristinare, manualmente o con altre procedure, il vecchio firmware nel caso in cui l'aggiornamento non riuscisse." +#. TRANSLATORS: this is instructions on how to improve the HSI suffix +msgid "This system has HSI runtime issues." +msgstr "Questo sistema presenta dei problemi di runtime HSI." + +#. TRANSLATORS: this is instructions on how to improve the HSI security level +msgid "This system has a low HSI security level." +msgstr "Questo sistema ha un livello di sicurezza HSI basso." + +#. TRANSLATORS: description of dbxtool +msgid "This tool allows an administrator to apply UEFI dbx updates." +msgstr "Questo strumento consente a un amministratore di applicare aggiornamenti UEFI dbx." + #. TRANSLATORS: the user needs to stop playing with stuff msgid "This tool can only be used by the root user" msgstr "Questo strumento può essere usato solamente dall'utente root" @@ -1280,6 +1639,26 @@ msgstr "Tipo" msgid "UEFI Firmware Utility" msgstr "Strumento firmware UEFI" +#. TRANSLATORS: program name +msgid "UEFI dbx Utility" +msgstr "Strumento EUFI dbx" + +#. TRANSLATORS: Title: SB is a way of locking down UEFI +msgid "UEFI secure boot" +msgstr "Avvio sicuro UEFI" + +#. TRANSLATORS: error message +msgid "Unable to connect to service" +msgstr "Impossibile collegarsi al servizio" + +#. TRANSLATORS: we will now offer this firmware to the user +msgid "Unblocking firmware:" +msgstr "Sblocco del firmware:" + +#. TRANSLATORS: Suffix: the HSI result +msgid "Unencrypted" +msgstr "Non cifrato" + #. TRANSLATORS: current daemon status is unknown #. TRANSLATORS: we don't know the license of the update #. TRANSLATORS: unknown release urgency @@ -1293,10 +1672,18 @@ msgstr "Dispositivo sconosciuto" msgid "Unlock the device to allow access" msgstr "Sblocco del dispositivo per consentire l'accesso" +#. TRANSLATORS: Suffix: the HSI result +msgid "Unlocked" +msgstr "Sbloccato" + #. TRANSLATORS: command description msgid "Unlocks the device for firmware access" msgstr "Sblocca il dispositivo per accedere al firmware" +#. TRANSLATORS: command description +msgid "Unmounts the ESP" +msgstr "Smonta l'ESP" + #. TRANSLATORS: command line option msgid "Unset the debugging flag during update" msgstr "Ripristina il flag di debug durante l'aggiornamento" @@ -1306,6 +1693,10 @@ msgstr "Ripristina il flag di debug durante l'aggiornamento" msgid "Unsupported daemon version %s, client version is %s" msgstr "Demone versione %s non supportato, la versione del client è %s" +#. TRANSLATORS: Suffix: the HSI result +msgid "Untainted" +msgstr "Integro" + #. TRANSLATORS: Device is updatable in this or any other mode msgid "Updatable" msgstr "Aggiornabile" @@ -1354,6 +1745,9 @@ msgstr "Aggiorna i metadati salvati con il contenuto attuale" msgid "Updates all firmware to latest versions available" msgstr "Aggiorna tutti i firmware all'ultima versione disponibile" +msgid "Updating" +msgstr "Aggiornamento in corso" + #. TRANSLATORS: the first replacement is a display name #. * e.g. "ColorHugALS" and the second and third are #. * version numbers e.g. "1.2.3" @@ -1372,10 +1766,6 @@ msgstr "Aggiornamento di %s…" msgid "Upgrade available for %s from %s to %s" msgstr "Aggiornamento disponibile per %s da %s a %s" -#. TRANSLATORS: the server sent the user a small message -msgid "Upload message:" -msgstr "Messaggio di caricamento:" - msgid "Upload report just this one time, but prompt again for future updates" msgid_plural "Upload reports just this one time, but prompt again for future updates" msgstr[0] "Caricare il rapporto ora e chiedere nuovamente con i prossimi aggiornamenti" @@ -1398,6 +1788,14 @@ msgstr "Inviare resoconti sul firmware aiuta gli sviluppatori a identificare vel msgid "Urgency" msgstr "Urgenza" +#. TRANSLATORS: error message explaining command to run to how to get help +msgid "Use fwupdmgr --help for help" +msgstr "Usare «fwupdmgr --help» per maggiori informazioni" + +#. TRANSLATORS: error message explaining command to run to how to get help +msgid "Use fwupdtool --help for help" +msgstr "Usare «fwupdtool --help» per maggiori informazioni" + #. TRANSLATORS: command line option msgid "Use quirk flags when installing firmware" msgstr "Usa flag quirk nell'installare il firmware" @@ -1410,6 +1808,14 @@ msgstr "Notifica inviata all'utente" msgid "Username" msgstr "Nome utente" +#. TRANSLATORS: Suffix: the HSI result +msgid "Valid" +msgstr "Valido" + +#. TRANSLATORS: ESP refers to the EFI System Partition +msgid "Validating ESP contents…" +msgstr "Verifica contenuti ESP…" + #. TRANSLATORS: one line variant of release (e.g. 'Prerelease' or 'China') msgid "Variant" msgstr "Variante" @@ -1422,9 +1828,13 @@ msgstr "Fornitore" msgid "Verifying…" msgstr "Verifica…" -#. TRANSLATORS: try to help -msgid "WARNING: Ignoring SSL strict checks, to do this automatically in the future export DISABLE_SSL_STRICT in your environment" -msgstr "Attenzione: controlli SSL ignorati, per fare ciò automaticamente in futuro, esportare DISABLE_SSL_STRICT nel proprio ambiente" +#. TRANSLATORS: the detected version number of the dbx +msgid "Version" +msgstr "Versione" + +#. TRANSLATORS: this is a prefix on the console +msgid "WARNING:" +msgstr "Attenzione:" #. TRANSLATORS: waiting for device to do something msgid "Waiting…" @@ -1446,6 +1856,10 @@ msgstr "Scrive il firmware dal file nel dispositivo" msgid "Write firmware from file into one partition" msgstr "Scrive il firmware dal file in una partizione" +#. TRANSLATORS: decompressing images from a container firmware +msgid "Writing file:" +msgstr "Scrittura file:" + #. TRANSLATORS: writing to the flash chips msgid "Writing…" msgstr "Scrittura…" @@ -1454,19 +1868,14 @@ msgstr "Scrittura…" msgid "Your distributor may not have verified any of the firmware updates for compatibility with your system or connected devices." msgstr "La propria distribuzione potrebbe non aver verificato la compatibilità degli aggiornamenti firmware col proprio sistema o col dispositivo collegato." +#. TRANSLATORS: this is the default branch name when unset +msgid "default" +msgstr "predefinito" + #. TRANSLATORS: program name msgid "fwupd TPM event log utility" msgstr "Strumento registro eventi TPM fwupd" -#. TRANSLATORS: message letting the user know no device upgrade available due -#. to missing on LVFS -#. * %1 is the device name -#, c-format -msgid "• %s has no available firmware updates" -msgstr "• %s non ha alcun aggiornamento firmware disponibile" - -#. TRANSLATORS: message letting the user know no device upgrade available -#. * %1 is the device name -#, c-format -msgid "• %s has the latest available firmware version" -msgstr "• %s ha la versione più recente del firmware" +#. TRANSLATORS: Title: if the fwupd plugins are all present and correct +msgid "fwupd plugins" +msgstr "Plugin fwupd" diff --git a/po/ko.po b/po/ko.po index 00bcf5199..898a2e09b 100644 --- a/po/ko.po +++ b/po/ko.po @@ -22,6 +22,12 @@ msgid "%.0f minute remaining" msgid_plural "%.0f minutes remaining" msgstr[0] "%.0f분 남음" +#. TRANSLATORS: the CPU microcode is firmware loaded onto the CPU +#. * at system bootup +#, c-format +msgid "%s CPU Microcode Update" +msgstr "%s CPU 마이크로코드 업데이트" + #. TRANSLATORS: ME stands for Management Engine, where #. * the first %s is the device name, e.g. 'ThinkPad P50` #, c-format @@ -309,6 +315,18 @@ msgstr "명령을 찾을 수 없습니다" msgid "Continue with update?" msgstr "업데이트를 계속 진행하시겠습니까?" +#. TRANSLATORS: command description +msgid "Convert a firmware file" +msgstr "펌웨어 파일을 변환합니다" + +#. TRANSLATORS: when the update was built +msgid "Created" +msgstr "생성됨" + +#. TRANSLATORS: the release urgency +msgid "Critical" +msgstr "매우 높음" + #. TRANSLATORS: Device supports some form of checksum verification msgid "Cryptographic hash verification is available" msgstr "암호화 해시 검사 사용 가능" @@ -448,6 +466,7 @@ msgstr[0] "보고서를 업로드하지 않고 다음에 업데이트할 때에 msgid "Do not write to the history database" msgstr "과거 기록 데이터베이스에 기록하지 않기" +#. TRANSLATORS: success #. success msgid "Done!" msgstr "완료!" @@ -492,6 +511,8 @@ msgstr "지원하는 시스템의 펌웨어 업데이트 지원 활성화" msgid "Enable this remote?" msgstr "이 원격 설정을 활성화하시겠습니까?" +#. TRANSLATORS: Suffix: the HSI result +#. TRANSLATORS: Plugin is active and in use #. TRANSLATORS: if the remote is enabled msgid "Enabled" msgstr "활성화 여부" @@ -530,10 +551,6 @@ msgstr "엔진을 불러온 후 나가기" msgid "Failed to connect to daemon" msgstr "데몬에 연결할 수 없음" -#. TRANSLATORS: the server is rate-limiting downloads -msgid "Failed to download due to server limit" -msgstr "서버 제한으로 파일을 다운로드할 수 없음" - #. TRANSLATORS: we could not get the devices to update offline msgid "Failed to get pending devices" msgstr "대기 중인 장치를 가져올 수 없음" @@ -566,22 +583,6 @@ msgstr "다시 시작할 수 없음" msgid "Failed to set splash mode" msgstr "스플래시 모드를 설정할 수 없음" -#. TRANSLATORS: downloading unknown file -msgid "Fetching file" -msgstr "파일 가져오는 중" - -#. TRANSLATORS: downloading new firmware file -msgid "Fetching firmware" -msgstr "펌웨어 가져오는 중" - -#. TRANSLATORS: downloading new metadata file -msgid "Fetching metadata" -msgstr "메타데이터 가져오는 중" - -#. TRANSLATORS: downloading new signing file -msgid "Fetching signature" -msgstr "서명 가져오는 중" - #. TRANSLATORS: filename of the local file msgid "Filename" msgstr "파일 이름" @@ -626,6 +627,7 @@ msgstr "이 머신에서 펌웨어 업데이트를 지원하지 않습니다." msgid "Firmware updates are supported on this machine." msgstr "이 머신에서 펌웨어 업데이트를 지원합니다." +#. TRANSLATORS: description of plugin state, e.g. disabled #. TRANSLATORS: release properties msgid "Flags" msgstr "플래그" @@ -633,6 +635,10 @@ msgstr "플래그" msgid "Force the action ignoring all warnings" msgstr "모든 경고를 무시하고 작업 강제 진행" +#. TRANSLATORS: Suffix: the HSI result +msgid "Found" +msgstr "감지 장치" + #. TRANSLATORS: global ID common to all similar hardware msgid "GUID" msgid_plural "GUIDs" @@ -662,10 +668,6 @@ msgstr "펌웨어 파일 세부 정보를 가져옵니다" msgid "Gets the configured remotes" msgstr "원격 설정 정보를 가져옵니다" -#. TRANSLATORS: firmware approved by the admin -msgid "Gets the list of approved firmware." -msgstr "허용된 펌웨어 목록을 가져옵니다." - #. TRANSLATORS: command description msgid "Gets the list of updates for connected hardware" msgstr "연결한 하드웨어의 업데이트 목록을 가져옵니다" @@ -682,6 +684,10 @@ msgstr "최근 업데이트 결과를 가져옵니다" msgid "Hardware is waiting to be replugged" msgstr "하드웨어를 다시 연결해야 함" +#. TRANSLATORS: the release urgency +msgid "High" +msgstr "높음" + #. TRANSLATORS: daemon is inactive msgid "Idle…" msgstr "대기 중…" @@ -784,9 +790,13 @@ msgstr "사용 가능한 펌웨어 종류를 표시합니다" msgid "Loading…" msgstr "불러오는 중…" -#. TRANSLATORS: command line option -msgid "Manually whitelist specific plugins" -msgstr "지정한 플러그인을 수동으로 허용 목록에 추가" +#. TRANSLATORS: the release urgency +msgid "Low" +msgstr "낮음" + +#. TRANSLATORS: the release urgency +msgid "Medium" +msgstr "중간" #. TRANSLATORS: remote URI msgid "Metadata Signature" @@ -809,10 +819,6 @@ msgstr "최소 버전" msgid "Mismatched daemon and client, use %s instead" msgstr "데몬과 클라이언트가 일치하지 않음, %s을(를) 대신 사용함" -#. TRANSLATORS: sets something in daemon.conf -msgid "Modifies a daemon configuration value." -msgstr "데몬 설정값을 변경합니다." - #. TRANSLATORS: command description msgid "Modifies a given remote" msgstr "지정한 원격 정보를 수정합니다" @@ -839,6 +845,7 @@ msgstr "설치 후 종료 필요함" msgid "New version" msgstr "새 버전" +#. TRANSLATORS: user did not tell the tool what to do msgid "No action specified!" msgstr "동작을 지정하지 않았습니다!" @@ -876,14 +883,14 @@ msgstr "원격 저장소 없음" msgid "No updates were applied" msgstr "적용된 업데이트 없음" +#. TRANSLATORS: Suffix: the HSI result +msgid "OK" +msgstr "확인" + #. TRANSLATORS: command line option msgid "Only show single PCR value" msgstr "단일 PCR 값만 표시" -#. TRANSLATORS: command line option -msgid "Override plugin warning" -msgstr "플러그인 경고 무시" - #. TRANSLATORS: command line option msgid "Override the default ESP path" msgstr "기본 ESP 경로 재정의" @@ -967,8 +974,8 @@ msgid "Refresh metadata from remote server" msgstr "원격 서버의 메타데이터를 새로 고칩니다" #. TRANSLATORS: command description -msgid "Reinstall current firmware on the device." -msgstr "장치에 현재 펌웨어를 다시 설치합니다." +msgid "Reinstall firmware on a device" +msgstr "장치에 펌웨어를 다시 설치합니다" #. TRANSLATORS: the first replacement is a display name #. * e.g. "ColorHugALS" and the second is a version number @@ -998,10 +1005,6 @@ msgstr "보고서 URI" msgid "Reported to remote server" msgstr "원격 서버에 보고됨" -#. TRANSLATORS: Must be plugged in to an outlet -msgid "Requires AC power" -msgstr "AC 전원 필요함" - #. TRANSLATORS: Requires a bootloader mode to be manually enabled by the user msgid "Requires a bootloader" msgstr "부트로더 모드 진입 필요함" @@ -1061,13 +1064,10 @@ msgstr "일련 번호" msgid "Set the debugging flag during update" msgstr "업데이트 중 디버깅 플래그 설정" +#. TRANSLATORS: firmware approved by the admin msgid "Sets the list of approved firmware" msgstr "허용된 펌웨어 목록 설정" -#. TRANSLATORS: firmware approved by the admin -msgid "Sets the list of approved firmware." -msgstr "허용된 펌웨어 목록을 설정합니다." - #. TRANSLATORS: command description msgid "Share firmware history with the developers" msgstr "개발사와 펌웨어 업데이트 기록 공유하기" @@ -1324,10 +1324,6 @@ msgstr "%s 업데이트 중..." msgid "Upgrade available for %s from %s to %s" msgstr "%s 업그레이드 사용 가능: %s에서 %s(으)로" -#. TRANSLATORS: the server sent the user a small message -msgid "Upload message:" -msgstr "업로드 메시지:" - msgid "Upload report just this one time, but prompt again for future updates" msgid_plural "Upload reports just this one time, but prompt again for future updates" msgstr[0] "이번 한 번만 보고서를 업로드하고 다음에 업데이트할 때 묻기" @@ -1344,6 +1340,10 @@ msgstr[0] "이번 한 번 보고서를 업로드하고 다음에 업데이트할 msgid "Uploading firmware reports helps hardware vendors to quickly identify failing and successful updates on real devices." msgstr "펌웨어 보고서를 업로드하면 하드웨어 제작사에서 실제 장치에 업데이트를 적용했을 때 성공 및 실패 여부를 빠르게 알 수 있습니다." +#. TRANSLATORS: how important the release is +msgid "Urgency" +msgstr "중요도" + #. TRANSLATORS: command line option msgid "Use quirk flags when installing firmware" msgstr "펌웨어를 설치할 때 quirk 플래그 사용" @@ -1368,9 +1368,9 @@ msgstr "제조사" msgid "Verifying…" msgstr "검증 중…" -#. TRANSLATORS: try to help -msgid "WARNING: Ignoring SSL strict checks, to do this automatically in the future export DISABLE_SSL_STRICT in your environment" -msgstr "경고: SSL 엄격 검사를 건너뜁니다. 이 옵션을 자동으로 지정하려면 DISABLE_SSL_STRICT 환경 변수를 지정하십시오" +#. TRANSLATORS: the detected version number of the dbx +msgid "Version" +msgstr "버전" #. TRANSLATORS: waiting for device to do something msgid "Waiting…" @@ -1399,3 +1399,7 @@ msgstr "쓰는 중…" #. TRANSLATORS: show the user a warning msgid "Your distributor may not have verified any of the firmware updates for compatibility with your system or connected devices." msgstr "배포판 개발사에서 펌웨어 업데이트와 시스템 및 연결된 장치간의 호환성을 검증한다는 보장이 없습니다." + +#. TRANSLATORS: program name +msgid "fwupd TPM event log utility" +msgstr "fwupd TPM 이벤트 로그 유틸리티" diff --git a/po/lt.po b/po/lt.po index aeb628607..890923c06 100644 --- a/po/lt.po +++ b/po/lt.po @@ -270,6 +270,7 @@ msgstr "Netikrinti ar yra istorijos apie kurią nepranešta" msgid "Do not write to the history database" msgstr "Nerašyti į istorijos duomenų bazę" +#. TRANSLATORS: success #. success msgid "Done!" msgstr "Atlikta!" @@ -310,6 +311,8 @@ msgstr "Įjungti programinės aparatinės įrangos atnaujinimo palaikymą palaik msgid "Enable this remote?" msgstr "Įjungti šią nuotolinę saugyklą?" +#. TRANSLATORS: Suffix: the HSI result +#. TRANSLATORS: Plugin is active and in use #. TRANSLATORS: if the remote is enabled msgid "Enabled" msgstr "Įjungta" @@ -345,10 +348,6 @@ msgstr "Išeiti, įkėlus modulį" msgid "Failed to connect to daemon" msgstr "Nepavyko prisijungti prie tarnybos" -#. TRANSLATORS: the server is rate-limiting downloads -msgid "Failed to download due to server limit" -msgstr "Nepavyko atsisiųsti dėl serverio apribojimo" - #. TRANSLATORS: we could not get the devices to update offline msgid "Failed to get pending devices" msgstr "Nepavyko gauti laukiančių įrenginių" @@ -373,22 +372,6 @@ msgstr "Nepavyko paleisti iš naujo" msgid "Failed to set splash mode" msgstr "Nepavyko nustatyti prisistatymo lango veikseną" -#. TRANSLATORS: downloading unknown file -msgid "Fetching file" -msgstr "Gaunamas failas" - -#. TRANSLATORS: downloading new firmware file -msgid "Fetching firmware" -msgstr "Gaunama programinė aparatinė įranga" - -#. TRANSLATORS: downloading new metadata file -msgid "Fetching metadata" -msgstr "Gaunami metaduomenys" - -#. TRANSLATORS: downloading new signing file -msgid "Fetching signature" -msgstr "Gaunamas parašas" - #. TRANSLATORS: filename of the local file msgid "Filename" msgstr "Failo pavadinimas" @@ -423,6 +406,7 @@ msgstr "Šiame kompiuteryje programinės aparatinės įrangos atnaujinimai yra n msgid "Firmware updates are supported on this machine." msgstr "Šiame kompiuteryje yra prieinami programinės aparatinės įrangos atnaujinimai." +#. TRANSLATORS: description of plugin state, e.g. disabled #. TRANSLATORS: release properties msgid "Flags" msgstr "Vėliavėlės" @@ -430,6 +414,10 @@ msgstr "Vėliavėlės" msgid "Force the action ignoring all warnings" msgstr "Priverstinai atlikti veiksmą nepaisant visų įspėjimų" +#. TRANSLATORS: Suffix: the HSI result +msgid "Found" +msgstr "Rastas" + #. TRANSLATORS: command description msgid "Get all devices and possible releases" msgstr "Gauti visus įrenginius ir galimas laidas" @@ -450,10 +438,6 @@ msgstr "Gauna išsamesnę informaciją apie programinės aparatinės įrangos fa msgid "Gets the configured remotes" msgstr "Gauna sukonfigūruotas nuotolines saugyklas" -#. TRANSLATORS: firmware approved by the admin -msgid "Gets the list of approved firmware." -msgstr "Gauna patvirtintos programinės aparatinės įrangos sąrašą." - #. TRANSLATORS: command description msgid "Gets the list of updates for connected hardware" msgstr "Gauna atnaujinimų sąrašą prijungtai aparatinei įrangai" @@ -527,10 +511,6 @@ msgstr "Išvardyti prieinamus programinės aparatinės įrangos atnaujinimus" msgid "Loading…" msgstr "Įkeliama…" -#. TRANSLATORS: command line option -msgid "Manually whitelist specific plugins" -msgstr "Rankiniu būdu įtraukti tam tikrus įskiepius į baltąjį sąrašą" - #. TRANSLATORS: remote URI msgid "Metadata URI" msgstr "Metaduomenų URI" @@ -550,6 +530,7 @@ msgstr "Modifikuoti sukonfigūruotą nuotolinę saugyklą" msgid "Monitor the daemon for events" msgstr "Stebėti tarnybą, ar yra įvykių" +#. TRANSLATORS: user did not tell the tool what to do msgid "No action specified!" msgstr "Nenurodytas joks veiksmas!" @@ -569,9 +550,9 @@ msgstr "Šiuo metu nėra įjungtos jokios nuotolinės saugyklos, taigi, nėra pr msgid "No updates were applied" msgstr "Nebuvo pritaikyti jokie atnaujinimai" -#. TRANSLATORS: command line option -msgid "Override plugin warning" -msgstr "Nustelbti įskiepio įspėjimą" +#. TRANSLATORS: Suffix: the HSI result +msgid "OK" +msgstr "Gerai" #. TRANSLATORS: command line option msgid "Override the default ESP path" @@ -694,13 +675,10 @@ msgstr "Suplanuojama…" msgid "Set the debugging flag during update" msgstr "Atnaujinimo metu nustatyti derinimo vėliavėlę" +#. TRANSLATORS: firmware approved by the admin msgid "Sets the list of approved firmware" msgstr "Nustato patvirtintą programinės aparatinės įrangos sąrašą" -#. TRANSLATORS: firmware approved by the admin -msgid "Sets the list of approved firmware." -msgstr "Nustato patvirtintos programinės aparatinės įrangos sąrašą." - #. TRANSLATORS: command description msgid "Share firmware history with the developers" msgstr "Bendrinti programinės aparatinės įrangos istoriją su plėtotojais" @@ -841,10 +819,6 @@ msgstr "Atnaujinama %s iš %s į %s... " msgid "Updating %s…" msgstr "Atnaujinama %s…" -#. TRANSLATORS: the server sent the user a small message -msgid "Upload message:" -msgstr "Išsiuntimo žinutė:" - #. TRANSLATORS: ask the user to upload msgid "Upload report now?" msgstr "Išsiųsti ataskaitą dabar?" @@ -861,6 +835,10 @@ msgstr "Naudotojo vardas" msgid "Verifying…" msgstr "Patikrinama…" +#. TRANSLATORS: the detected version number of the dbx +msgid "Version" +msgstr "Versija" + #. TRANSLATORS: waiting for device to do something msgid "Waiting…" msgstr "Laukiama…" diff --git a/po/nl.po b/po/nl.po index 72283fbcd..ee7788bec 100644 --- a/po/nl.po +++ b/po/nl.po @@ -93,6 +93,7 @@ msgstr "Apparaat gewijzigd:" msgid "Device removed:" msgstr "Apparaat verwijderd:" +#. TRANSLATORS: success #. success msgid "Done!" msgstr "Afgerond!" @@ -128,6 +129,10 @@ msgstr "Firmware Update Daemon" msgid "Firmware Utility" msgstr "Firmware-hulpmiddel" +#. TRANSLATORS: Suffix: the HSI result +msgid "Found" +msgstr "Gevonden" + #. TRANSLATORS: command description msgid "Get all devices that support firmware updates" msgstr "Alle apparaten verkrijgen die firmware-updates ondersteunen" @@ -179,9 +184,9 @@ msgstr "De achtergrondservice controleren op gebeurtenissen" msgid "No hardware detected with firmware update capability" msgstr "Geen hardware aangetroffen die in staat is firmware bij te werken" -#. TRANSLATORS: command line option -msgid "Override plugin warning" -msgstr "Pluginwaarschuwing negeren" +#. TRANSLATORS: Suffix: the HSI result +msgid "OK" +msgstr "Oké" #. TRANSLATORS: command description msgid "Read firmware from device into a file" diff --git a/po/oc.po b/po/oc.po index 60c675d23..763fd72f8 100644 --- a/po/oc.po +++ b/po/oc.po @@ -50,6 +50,7 @@ msgstr "Opcions de desbugatge" msgid "Description" msgstr "Descripcion" +#. TRANSLATORS: success #. success msgid "Done!" msgstr "Acabat !" @@ -77,6 +78,10 @@ msgstr "Fracàs de l'analisi dels paramètres" msgid "Firmware Update D-Bus Service" msgstr "Servici D-Bus de mesa a jorn dels micrologicials" +#. TRANSLATORS: Suffix: the HSI result +msgid "Found" +msgstr "Trobat" + #. TRANSLATORS: command description msgid "Get all devices that support firmware updates" msgstr "Obténer la lista dels periferics que supòrtan las mesas a jorn de micrologicial" @@ -93,6 +98,10 @@ msgstr "Installar un fichièr de micrologicial sus aqueste material" msgid "No hardware detected with firmware update capability" msgstr "Cap de material amb de capacitats de mesa a jorn del micrologicial es pas estat detectat" +#. TRANSLATORS: Suffix: the HSI result +msgid "OK" +msgstr "D'acòrdi" + #. TRANSLATORS: the first replacement is a display name #. * e.g. "ColorHugALS" and the second is a version number #. * e.g. "1.2.3" @@ -118,3 +127,7 @@ msgstr "Mòstra d'informacions de desbugatge complementàrias" #, c-format msgid "Updating %s from %s to %s... " msgstr "Mesa a jorn de %s de %s en %s " + +#. TRANSLATORS: the detected version number of the dbx +msgid "Version" +msgstr "Version" diff --git a/po/pl.po b/po/pl.po index ed60f79c8..19e8a6a28 100644 --- a/po/pl.po +++ b/po/pl.po @@ -30,6 +30,12 @@ msgstr[3] "Pozostało %.0f minut" msgid "%s CPU Microcode Update" msgstr "Aktualizacja mikrokodu procesora %s" +#. TRANSLATORS: a specific part of hardware, +#. * the first %s is the device name, e.g. 'Secure Boot` +#, c-format +msgid "%s Configuration Update" +msgstr "Aktualizacja konfiguracji urządzenia %s" + #. TRANSLATORS: ME stands for Management Engine, where #. * the first %s is the device name, e.g. 'ThinkPad P50` #, c-format @@ -93,6 +99,11 @@ msgstr "Aktualizacja urządzenia %s" msgid "%s and all connected devices may not be usable while updating." msgstr "%s i wszystkie podłączone urządzenia nie będą mogły być używane podczas aktualizacji." +#. TRANSLATORS: Title: %s is ME kind, e.g. CSME/TXT +#, c-format +msgid "%s manufacturing mode" +msgstr "Tryb serwisowy %s" + #. TRANSLATORS: warn the user before updating, %1 is a device name #, c-format msgid "%s must remain connected for the duration of the update to avoid damage." @@ -103,6 +114,21 @@ msgstr "Urządzenie %s musi być podłączone podczas trwania aktualizacji, aby msgid "%s must remain plugged into a power source for the duration of the update to avoid damage." msgstr "Urządzenie %s musi być podłączone do prądu podczas trwania aktualizacji, aby uniknąć uszkodzenia." +#. TRANSLATORS: Title: %s is ME kind, e.g. CSME/TXT +#, c-format +msgid "%s override" +msgstr "Obejście %s" + +#. TRANSLATORS: Title: %1 is ME kind, e.g. CSME/TXT, %2 is a version number +#, c-format +msgid "%s v%s" +msgstr "%s v%s" + +#. TRANSLATORS: Title: %s is ME kind, e.g. CSME/TXT +#, c-format +msgid "%s version" +msgstr "Wersja %s" + #. TRANSLATORS: duration in days! #, c-format msgid "%u day" @@ -156,6 +182,10 @@ msgstr[1] "%u sekundy" msgstr[2] "%u sekund" msgstr[3] "%u sekund" +#. TRANSLATORS: this is shown as a suffix for obsoleted tests +msgid "(obsoleted)" +msgstr "(przestarzałe)" + #. TRANSLATORS: command description msgid "Activate devices" msgstr "Aktywuje urządzenia" @@ -200,6 +230,10 @@ msgstr "Umożliwia instalowanie poprzednich wersji oprogramowania sprzętowego" msgid "Allow reinstalling existing firmware versions" msgstr "Umożliwia ponowne instalowanie istniejących wersji oprogramowania sprzętowego" +#. TRANSLATORS: command line option +msgid "Allow switching firmware branch" +msgstr "Umożliwia przełączanie gałęzi oprogramowania sprzętowego" + #. TRANSLATORS: explain why we want to reboot msgid "An update requires a reboot to complete." msgstr "Ukończenie aktualizacji wymaga ponownego uruchomienia." @@ -216,6 +250,18 @@ msgstr "Odpowiada tak na wszystkie pytania" msgid "Apply firmware updates" msgstr "Zastosowuje aktualizacje oprogramowania sprzętowego" +#. TRANSLATORS: command line option +msgid "Apply update even when not advised" +msgstr "Zastosowuje aktualizację nawet, jeśli nie jest zalecana" + +#. TRANSLATORS: command line option +msgid "Apply update files" +msgstr "Zastosowuje pliki aktualizacji" + +#. TRANSLATORS: actually sending the update to the hardware +msgid "Applying update…" +msgstr "Zastosowywanie aktualizacji…" + #. TRANSLATORS: approved firmware has been checked by #. * the domain administrator msgid "Approved firmware:" @@ -225,6 +271,10 @@ msgstr[1] "Zatwierdzone oprogramowanie sprzętowe:" msgstr[2] "Zatwierdzone oprogramowanie sprzętowe:" msgstr[3] "Zatwierdzone oprogramowanie sprzętowe:" +#. TRANSLATORS: stop nagging the user +msgid "Ask again next time?" +msgstr "Zapytać ponownie następnym razem?" + #. TRANSLATORS: command description msgid "Attach to firmware mode" msgstr "Podłącza do trybu oprogramowania sprzętowego" @@ -281,10 +331,38 @@ msgstr "Wymagane jest uwierzytelnienie, aby zaktualizować przechowywane sumy ko msgid "Automatic Reporting" msgstr "Automatyczne zgłaszanie" +#. TRANSLATORS: can we JFDI? +msgid "Automatically upload every time?" +msgstr "Automatycznie wysyłać za każdym razem?" + +#. TRANSLATORS: command description +msgid "Bind new kernel driver" +msgstr "Dowiązuje nowy sterownik jądra" + +#. TRANSLATORS: there follows a list of hashes +msgid "Blocked firmware files:" +msgstr "Zablokowane pliki oprogramowania sprzętowego:" + +#. TRANSLATORS: we will not offer this firmware to the user +msgid "Blocking firmware:" +msgstr "Blokowanie oprogramowania sprzętowego:" + +#. TRANSLATORS: command description +msgid "Blocks a specific firmware from being installed" +msgstr "Blokuje instalację podanego oprogramowania sprzętowego" + #. TRANSLATORS: firmware version of bootloader msgid "Bootloader Version" msgstr "Wersja programu startowego" +#. TRANSLATORS: the stream of firmware, e.g. nonfree or open-source +msgid "Branch" +msgstr "Gałąź" + +#. TRANSLATORS: command description +msgid "Build a firmware file" +msgstr "Buduje plik oprogramowania sprzętowego" + #. TRANSLATORS: command description msgid "Build firmware using a sandbox" msgstr "Buduje oprogramowanie sprzętowe za pomocą piaskownicy" @@ -297,6 +375,14 @@ msgstr "Anuluj" msgid "Cancelled" msgstr "Anulowano" +#. TRANSLATORS: same or newer update already applied +msgid "Cannot apply as dbx update has already been applied." +msgstr "Nie można zastosować, ponieważ aktualizacja bazy dbx została już zastosowana." + +#. TRANSLATORS: the user is using a LiveCD or LiveUSB install disk +msgid "Cannot apply updates on live media" +msgstr "Nie można stosować aktualizacji na nośnikach typu Live" + #. TRANSLATORS: this is when a device is hotplugged #. TRANSLATORS: this is when the daemon state changes msgid "Changed" @@ -310,6 +396,11 @@ msgstr "Sprawdza, czy kryptograficzna suma kontrolna pasuje do oprogramowania sp msgid "Checksum" msgstr "Suma kontrolna" +#. TRANSLATORS: get interactive prompt, where branch is the +#. * supplier of the firmware, e.g. "non-free" or "free" +msgid "Choose a branch:" +msgstr "Wybór gałęzi:" + #. TRANSLATORS: get interactive prompt msgid "Choose a device:" msgstr "Wybór urządzenia:" @@ -322,6 +413,10 @@ msgstr "Wybór typu oprogramowania sprzętowego:" msgid "Choose a release:" msgstr "Wybór wydania:" +#. TRANSLATORS: get interactive prompt +msgid "Choose a volume:" +msgstr "Proszę wybrać wolumin:" + #. TRANSLATORS: command description msgid "Clears any updates scheduled to be updated offline" msgstr "Usuwa wszystkie zaplanowane aktualizacje w trybie offline" @@ -426,10 +521,18 @@ msgstr "Usunięto urządzenie:" msgid "Device stages updates" msgstr "Urządzenie przygotowuje aktualizacje" +#. TRANSLATORS: there is more than one supplier of the firmware +msgid "Device supports switching to a different branch of firmware" +msgstr "Urządzenie obsługuje przełączanie na inną gałąź oprogramowania sprzętowego" + #. TRANSLATORS: Device update needs to be separately activated msgid "Device update needs activation" msgstr "Aktualizacja urządzenia wymaga aktywacji" +#. TRANSLATORS: save the old firmware to disk before installing the new one +msgid "Device will backup firmware before installing" +msgstr "Urządzenie wykona kopię zapasową oprogramowania sprzętowego przez instalacją" + #. TRANSLATORS: Device will not return after update completes msgid "Device will not re-appear after update completes" msgstr "Urządzenie nie pojawi się z powrotem po ukończeniu aktualizacji" @@ -442,6 +545,20 @@ msgstr "Pomyślnie zaktualizowane urządzenia:" msgid "Devices that were not updated correctly:" msgstr "Urządzenia, które nie zostały poprawnie zaktualizowane:" +#. TRANSLATORS: message letting the user know no device upgrade available due +#. to missing on LVFS +msgid "Devices with no available firmware updates: " +msgstr "Urządzenia bez dostępnych aktualizacji oprogramowania sprzętowego: " + +#. TRANSLATORS: message letting the user know no device upgrade available +msgid "Devices with the latest available firmware version:" +msgstr "Urządzenia z najnowszą dostępną wersją oprogramowania sprzętowego:" + +#. TRANSLATORS: Suffix: the HSI result +#. TRANSLATORS: Plugin is inactive and not used +msgid "Disabled" +msgstr "Wyłączone" + msgid "Disabled fwupdate debugging" msgstr "Wyłączono debugowanie fwupdate" @@ -495,6 +612,11 @@ msgstr[3] "Bez wysyłania zgłoszeń i wyłączenie pytania o wysyłanie zgło msgid "Do not write to the history database" msgstr "Bez zapisywania do bazy danych historii" +#. TRANSLATORS: should the branch be changed +msgid "Do you understand the consequences of changing the firmware branch?" +msgstr "Czy rozumiesz konsekwencje zmiany gałęzi oprogramowania sprzętowego?" + +#. TRANSLATORS: success #. success msgid "Done!" msgstr "Gotowe." @@ -539,6 +661,8 @@ msgstr "Włącza obsługę aktualizacji oprogramowania sprzętowego na obsługiw msgid "Enable this remote?" msgstr "Włączyć to repozytorium?" +#. TRANSLATORS: Suffix: the HSI result +#. TRANSLATORS: Plugin is active and in use #. TRANSLATORS: if the remote is enabled msgid "Enabled" msgstr "Włączone" @@ -557,6 +681,14 @@ msgstr "Włączenie tej funkcjonalności jest wykonywane na własne ryzyko, co o msgid "Enabling this remote is done at your own risk." msgstr "Włączenie tego repozytorium wykonywane jest na własne ryzyko." +#. TRANSLATORS: Suffix: the HSI result +msgid "Encrypted" +msgstr "Zaszyfrowane" + +#. TRANSLATORS: Title: Memory contents are encrypted, e.g. Intel TME +msgid "Encrypted RAM" +msgstr "Zaszyfrowana pamięć RAM" + #. TRANSLATORS: command description msgid "Erase all firmware update history" msgstr "Usuwa całą historię aktualizacji oprogramowania sprzętowego" @@ -573,13 +705,25 @@ msgstr "Kończy działanie po małym opóźnieniu" msgid "Exit after the engine has loaded" msgstr "Kończy działanie po wczytaniu mechanizmu" +#. TRANSLATORS: command description +msgid "Extract a firmware blob to images" +msgstr "Rozpakowuje zamknięte oprogramowanie sprzętowe do obrazów" + +#. TRANSLATORS: Suffix: the fallback HSI result +msgid "Failed" +msgstr "Nie powiodło się" + +#. TRANSLATORS: dbx file failed to be applied as an update +msgid "Failed to apply update" +msgstr "Zastosowanie aktualizacji się nie powiodło" + #. TRANSLATORS: we could not talk to the fwupd daemon msgid "Failed to connect to daemon" msgstr "Połączenie z usługą się nie powiodło" -#. TRANSLATORS: the server is rate-limiting downloads -msgid "Failed to download due to server limit" -msgstr "Pobranie się nie powiodło z powodu ograniczenia serwera" +#. TRANSLATORS: could not parse file +msgid "Failed to extract local dbx " +msgstr "Rozpakowanie lokalnej bazy dbx się nie powiodło " #. TRANSLATORS: we could not get the devices to update offline msgid "Failed to get pending devices" @@ -589,10 +733,19 @@ msgstr "Uzyskanie oczekujących urządzeń się nie powiodło" msgid "Failed to install firmware update" msgstr "Zainstalowanie aktualizacji oprogramowania sprzętowego się nie powiodło" +#. TRANSLATORS: could not read existing system data +#. TRANSLATORS: could not read file +msgid "Failed to load local dbx" +msgstr "Wczytanie lokalnej bazy dbx się nie powiodło" + #. TRANSLATORS: quirks are device-specific workarounds msgid "Failed to load quirks" msgstr "Wczytanie poprawek się nie powiodło" +#. TRANSLATORS: could not read existing system data +msgid "Failed to load system dbx" +msgstr "Wczytanie systemowej bazy dbx się nie powiodło" + #. TRANSLATORS: the user didn't read the man page msgid "Failed to parse arguments" msgstr "Przetworzenie parametrów się nie powiodło" @@ -605,6 +758,10 @@ msgstr "Przetworzenie pliku się nie powiodło" msgid "Failed to parse flags for --filter" msgstr "Przetworzenie flag dla opcji --filter się nie powiodło" +#. TRANSLATORS: could not parse file +msgid "Failed to parse local dbx" +msgstr "Przetworzenie lokalnej bazy dbx się nie powiodło" + #. TRANSLATORS: we could not reboot for some reason msgid "Failed to reboot" msgstr "Ponowne uruchomienie się nie powiodło" @@ -613,21 +770,10 @@ msgstr "Ponowne uruchomienie się nie powiodło" msgid "Failed to set splash mode" msgstr "Ustawienie trybu ekranu wczytywania się nie powiodło" -#. TRANSLATORS: downloading unknown file -msgid "Fetching file" -msgstr "Pobieranie pliku" - -#. TRANSLATORS: downloading new firmware file -msgid "Fetching firmware" -msgstr "Pobieranie oprogramowania sprzętowego" - -#. TRANSLATORS: downloading new metadata file -msgid "Fetching metadata" -msgstr "Pobieranie metadanych" - -#. TRANSLATORS: downloading new signing file -msgid "Fetching signature" -msgstr "Pobieranie podpisu" +#. TRANSLATORS: something with a blocked hash exists +#. * in the users ESP -- which would be bad! +msgid "Failed to validate ESP contents" +msgstr "Sprawdzenie poprawności zawartości ESP się nie powiodło" #. TRANSLATORS: filename of the local file msgid "Filename" @@ -637,6 +783,10 @@ msgstr "Nazwa pliku" msgid "Filename Signature" msgstr "Podpis nazwy pliku" +#. TRANSLATORS: user did not include a filename parameter +msgid "Filename required" +msgstr "Wymagana jest nazwa pliku" + #. TRANSLATORS: command line option msgid "Filter with a set of device flags using a ~ prefix to exclude, e.g. 'internal,~needs-reboot'" msgstr "Filtruje za pomocą zestawu flag urządzeń, przedrostek ~ wyklucza, np. „internal,~needs-reboot”" @@ -661,6 +811,22 @@ msgstr "Usługa aktualizacji oprogramowania sprzętowego" msgid "Firmware Utility" msgstr "Narzędzie oprogramowania sprzętowego" +#. TRANSLATORS: Title: if we can verify the firmware checksums +msgid "Firmware attestation" +msgstr "Zaświadczenie oprogramowania sprzętowego" + +#. TRANSLATORS: system is not booted in UEFI mode +msgid "Firmware can not be updated in legacy BIOS mode" +msgstr "Nie można aktualizować oprogramowania sprzętowego w trybie przestarzałego BIOS-u" + +#. TRANSLATORS: user selected something not possible +msgid "Firmware is already blocked" +msgstr "Oprogramowanie sprzętowe jest już zablokowane" + +#. TRANSLATORS: user selected something not possible +msgid "Firmware is not already blocked" +msgstr "Oprogramowanie nie jest już zablokowane" + #. TRANSLATORS: the metadata is very out of date; %u is a number > 1 #, c-format msgid "Firmware metadata has not been updated for %u day and may not be up to date." @@ -670,19 +836,36 @@ msgstr[1] "Metadane oprogramowania sprzętowego nie zostały zaktualizowane prze msgstr[2] "Metadane oprogramowania sprzętowego nie zostały zaktualizowane przez %u dni i mogą nie być aktualne." msgstr[3] "Metadane oprogramowania sprzętowego nie zostały zaktualizowane przez %u dni i mogą nie być aktualne." +#. TRANSLATORS: Title: if firmware updates are available +msgid "Firmware updates" +msgstr "Aktualizacje oprogramowania sprzętowego" + msgid "Firmware updates are not supported on this machine." msgstr "Aktualizacje oprogramowania sprzętowego nie są obsługiwane na tym komputerze." msgid "Firmware updates are supported on this machine." msgstr "Aktualizacje oprogramowania sprzętowego są obsługiwane na tym komputerze." +#. TRANSLATORS: user needs to run a command +msgid "Firmware updates disabled; run 'fwupdmgr unlock' to enable" +msgstr "Aktualizacje oprogramowania sprzętowego są wyłączone; wykonanie polecenia „fwupdmgr unlock” je włączy" + +#. TRANSLATORS: description of plugin state, e.g. disabled #. TRANSLATORS: release properties msgid "Flags" msgstr "Flagi" +#. TRANSLATORS: command line option +msgid "Force the action by relaxing some runtime checks" +msgstr "Wymusza działanie przez rozluźnienie części testów uruchamiania" + msgid "Force the action ignoring all warnings" msgstr "Wymusza działanie ignorując wszystkie ostrzeżenia" +#. TRANSLATORS: Suffix: the HSI result +msgid "Found" +msgstr "Odnaleziono" + #. TRANSLATORS: global ID common to all similar hardware msgid "GUID" msgid_plural "GUIDs" @@ -715,9 +898,17 @@ msgstr "Uzyskuje informacje o pliku oprogramowania sprzętowego" msgid "Gets the configured remotes" msgstr "Uzyskuje skonfigurowane repozytoria" +#. TRANSLATORS: command description +msgid "Gets the host security attributes" +msgstr "Uzyskuje atrybuty zabezpieczeń komputera" + #. TRANSLATORS: firmware approved by the admin -msgid "Gets the list of approved firmware." -msgstr "Uzyskuje listę zatwierdzonego oprogramowania sprzętowego." +msgid "Gets the list of approved firmware" +msgstr "Uzyskuje listę zatwierdzonego oprogramowania sprzętowego" + +#. TRANSLATORS: command description +msgid "Gets the list of blocked firmware" +msgstr "Uzyskuje listę zablokowanego oprogramowania sprzętowego" #. TRANSLATORS: command description msgid "Gets the list of updates for connected hardware" @@ -739,6 +930,15 @@ msgstr "Sprzęt czeka na ponowne podłączenie" msgid "High" msgstr "Wysoka" +#. TRANSLATORS: this is a string like 'HSI:2-U' +msgid "Host Security ID:" +msgstr "Identyfikator zabezpieczeń komputera:" + +#. TRANSLATORS: Title: +#. https://en.wikipedia.org/wiki/Input%E2%80%93output_memory_management_unit +msgid "IOMMU" +msgstr "IOMMU" + #. TRANSLATORS: daemon is inactive msgid "Idle…" msgstr "Bezczynne…" @@ -747,10 +947,26 @@ msgstr "Bezczynne…" msgid "Ignore SSL strict checks when downloading files" msgstr "Ignoruje ścisłe testy SSL podczas pobierania plików" +#. TRANSLATORS: command line option +msgid "Ignore firmware checksum failures" +msgstr "Ignoruje niepowodzenia sum kontrolnych oprogramowania sprzętowego" + +#. TRANSLATORS: command line option +msgid "Ignore firmware hardware mismatch failures" +msgstr "Ignoruje niepowodzenia zgodności sprzętu z oprogramowaniem sprzętowym" + +#. TRANSLATORS: command line option +msgid "Ignore requirement of external power source" +msgstr "Ignoruje wymaganie zewnętrznego źródła zasilania" + #. TRANSLATORS: Ignore validation safety checks when flashing this device msgid "Ignore validation safety checks" msgstr "Ignoruje testy bezpieczeństwa i sprawdzanie poprawności" +#. TRANSLATORS: try to help +msgid "Ignoring SSL strict checks, to do this automatically in the future export DISABLE_SSL_STRICT in your environment" +msgstr "Ignorowanie ścisłych testów SSL, aby robić to automatycznie w przyszłości, należy wyeksportować zmienną DISABLE_SSL_STRICT w środowisku" + #. TRANSLATORS: length of time the update takes to apply msgid "Install Duration" msgstr "Czas trwania instalacji" @@ -795,10 +1011,57 @@ msgstr "Instalowanie aktualizacji oprogramowania sprzętowego…" msgid "Installing on %s…" msgstr "Instalowanie na urządzeniu %s…" +#. TRANSLATORS: Title: BootGuard is a trademark from Intel +msgid "Intel BootGuard" +msgstr "Intel BootGuard" + +#. TRANSLATORS: Title: BootGuard is a trademark from Intel, +#. * ACM means to verify the integrity of Initial Boot Block +msgid "Intel BootGuard ACM protected" +msgstr "ACM chronione przez Intel BootGuard" + +#. TRANSLATORS: Title: BootGuard is a trademark from Intel, +#. * OTP = one time programmable +msgid "Intel BootGuard OTP fuse" +msgstr "Bezpiecznik OTP Intel BootGuard" + +#. TRANSLATORS: Title: BootGuard is a trademark from Intel, +#. * error policy is what to do on failure +msgid "Intel BootGuard error policy" +msgstr "Błąd zasad postępowania Intel BootGuard w przypadku błędów" + +#. TRANSLATORS: Title: BootGuard is a trademark from Intel, +#. * verified boot refers to the way the boot process is verified +msgid "Intel BootGuard verified boot" +msgstr "Uruchamianie zweryfikowane przez Intel BootGuard" + +#. TRANSLATORS: Title: CET = Control-flow Enforcement Technology, +#. * active means being used by the OS +msgid "Intel CET Active" +msgstr "Intel CET jest aktywne" + +#. TRANSLATORS: Title: CET = Control-flow Enforcement Technology, +#. * enabled means supported by the processor +msgid "Intel CET Enabled" +msgstr "Intel CET jest włączone" + +#. TRANSLATORS: Title: Direct Connect Interface (DCI) allows +#. * debugging of Intel processors using the USB3 port +msgid "Intel DCI debugger" +msgstr "Debuger Intel DCI" + +#. TRANSLATORS: Title: SMAP = Supervisor Mode Access Prevention +msgid "Intel SMAP" +msgstr "Intel SMAP" + #. TRANSLATORS: Device cannot be removed easily msgid "Internal device" msgstr "Wewnętrzne urządzenie" +#. TRANSLATORS: Suffix: the HSI result +msgid "Invalid" +msgstr "Nieprawidłowe" + #. TRANSLATORS: Is currently in bootloader mode msgid "Is in bootloader mode" msgstr "Jest w trybie programu startowego" @@ -832,6 +1095,22 @@ msgstr "Linux Vendor Firmware Service (stabilne oprogramowanie sprzętowe)" msgid "Linux Vendor Firmware Service (testing firmware)" msgstr "Linux Vendor Firmware Service (testowe oprogramowanie sprzętowe)" +#. TRANSLATORS: Title: if it's tainted or not +msgid "Linux kernel" +msgstr "Jądro Linux" + +#. TRANSLATORS: Title: lockdown is a security mode of the kernel +msgid "Linux kernel lockdown" +msgstr "Blokada jądra Linux" + +#. TRANSLATORS: Title: swap space or swap partition +msgid "Linux swap" +msgstr "Obszar wymiany systemu Linux" + +#. TRANSLATORS: command line option +msgid "List entries in dbx" +msgstr "Wyświetla listę wpisów w bazie dbx" + #. TRANSLATORS: command line option msgid "List supported firmware updates" msgstr "Wyświetla listę obsługiwanych aktualizacji oprogramowania sprzętowego" @@ -840,17 +1119,39 @@ msgstr "Wyświetla listę obsługiwanych aktualizacji oprogramowania sprzętoweg msgid "List the available firmware types" msgstr "Wyświetla listę dostępnych typów oprogramowania sprzętowego" +#. TRANSLATORS: command description +msgid "Lists files on the ESP" +msgstr "Wyświetla listę plików na ESP" + #. TRANSLATORS: parsing the firmware information msgid "Loading…" msgstr "Wczytywanie…" +#. TRANSLATORS: Suffix: the HSI result +msgid "Locked" +msgstr "Zablokowane" + #. TRANSLATORS: the release urgency msgid "Low" msgstr "Niska" +#. TRANSLATORS: Title: MEI = Intel Management Engine +msgid "MEI manufacturing mode" +msgstr "Tryb produkcyjny MEI" + +#. TRANSLATORS: Title: MEI = Intel Management Engine, and the +#. * "override" is the physical PIN that can be driven to +#. * logic high -- luckily it is probably not accessible to +#. * end users on consumer boards +msgid "MEI override" +msgstr "Obejście MEI" + +msgid "MEI version" +msgstr "Wersja MEI" + #. TRANSLATORS: command line option -msgid "Manually whitelist specific plugins" -msgstr "Ręcznie wstawia podane wtyczki na białą listę" +msgid "Manually enable specific plugins" +msgstr "Ręcznie włącza podane wtyczki" #. TRANSLATORS: the release urgency msgid "Medium" @@ -878,8 +1179,8 @@ msgid "Mismatched daemon and client, use %s instead" msgstr "Niezgodna usługa i klient, proszę użyć %s zamiast tego" #. TRANSLATORS: sets something in daemon.conf -msgid "Modifies a daemon configuration value." -msgstr "Modyfikuje wartość konfiguracji usługi." +msgid "Modifies a daemon configuration value" +msgstr "Modyfikuje wartość konfiguracji usługi" #. TRANSLATORS: command description msgid "Modifies a given remote" @@ -895,6 +1196,10 @@ msgstr "Modyfikacja konfiguracji usługi" msgid "Monitor the daemon for events" msgstr "Monitoruje zdarzenia usługi" +#. TRANSLATORS: command description +msgid "Mounts the ESP" +msgstr "Montuje MSP" + #. TRANSLATORS: Requires a reboot to apply firmware or to reload hardware msgid "Needs a reboot after installation" msgstr "Wymaga ponownego uruchomienia po instalacji" @@ -907,6 +1212,7 @@ msgstr "Wymaga wyłączenia komputera po instalacji" msgid "New version" msgstr "Nowa wersja" +#. TRANSLATORS: user did not tell the tool what to do msgid "No action specified!" msgstr "Nie podano działania." @@ -944,14 +1250,22 @@ msgstr "Brak dostępnych repozytoriów" msgid "No updates were applied" msgstr "Nie zastosowano żadnych aktualizacji" +#. TRANSLATORS: Suffix: the HSI result +msgid "Not found" +msgstr "Nie odnaleziono" + +#. TRANSLATORS: Suffix: the HSI result +msgid "Not supported" +msgstr "Nieobsługiwane" + +#. TRANSLATORS: Suffix: the HSI result +msgid "OK" +msgstr "OK" + #. TRANSLATORS: command line option msgid "Only show single PCR value" msgstr "Wyświetla tylko jedną wartość PCR" -#. TRANSLATORS: command line option -msgid "Override plugin warning" -msgstr "Zastępuje ostrzeżenie wtyczki" - #. TRANSLATORS: command line option msgid "Override the default ESP path" msgstr "Zastępuje domyślną ścieżkę ESP" @@ -964,6 +1278,14 @@ msgstr "Zastępuje ostrzeżenia i wymusza działanie" msgid "Parse and show details about a firmware file" msgstr "Przetwarza i wyświetla informacje o pliku oprogramowania sprzętowego" +#. TRANSLATORS: reading new dbx from the update +msgid "Parsing dbx update…" +msgstr "Przetwarzanie aktualizacji bazy dbx…" + +#. TRANSLATORS: reading existing dbx from the system +msgid "Parsing system dbx…" +msgstr "Przetwarzanie systemowej bazy dbx…" + #. TRANSLATORS: remote filename base msgid "Password" msgstr "Hasło" @@ -980,6 +1302,14 @@ msgstr "Procent ukończenia" msgid "Please enter a number from 0 to %u: " msgstr "Proszę podać liczbę od 0 do %u: " +#. TRANSLATORS: Failed to open plugin, hey Arch users +msgid "Plugin dependencies missing" +msgstr "Brak zależności wtyczki" + +#. TRANSLATORS: Title: DMA as in https://en.wikipedia.org/wiki/DMA_attack +msgid "Pre-boot DMA protection" +msgstr "Ochrona DMA przed uruchomieniem" + #. TRANSLATORS: version number of previous firmware msgid "Previous version" msgstr "Poprzednia wersja" @@ -1035,8 +1365,8 @@ msgid "Refresh metadata from remote server" msgstr "Odświeża metadane ze zdalnego serwera" #. TRANSLATORS: command description -msgid "Reinstall current firmware on the device." -msgstr "Ponownie instaluje obecne oprogramowanie sprzętowe na urządzeniu." +msgid "Reinstall current firmware on the device" +msgstr "Ponownie instaluje obecne oprogramowanie sprzętowe na urządzeniu" #. TRANSLATORS: command description msgid "Reinstall firmware on a device" @@ -1070,9 +1400,13 @@ msgstr "Adres URI zgłoszenia" msgid "Reported to remote server" msgstr "Zgłoszone do zdalnego serwera" -#. TRANSLATORS: Must be plugged in to an outlet -msgid "Requires AC power" -msgstr "Wymaga zasilania z gniazdka" +#. TRANSLATORS: the user is using Gentoo/Arch and has screwed something up +msgid "Required efivarfs filesystem was not found" +msgstr "Nie odnaleziono wymaganego systemu plików „efivarfs”" + +#. TRANSLATORS: not required for this system +msgid "Required hardware was not found" +msgstr "Nie odnaleziono wymaganego oprogramowania sprzętowego" #. TRANSLATORS: Requires a bootloader mode to be manually enabled by the user msgid "Requires a bootloader" @@ -1109,6 +1443,22 @@ msgstr "Wykonuje procedurę czyszczenia składania wtyczki podczas używania „ msgid "Run the plugin composite prepare routine when using install-blob" msgstr "Wykonuje procedurę przygotowania składania wtyczki podczas używania „install-blob”" +#. TRANSLATORS: this is the HSI suffix +msgid "Runtime Suffix" +msgstr "Przyrostek uruchamiania" + +#. TRANSLATORS: Title: SPI refers to the flash chip in the computer +msgid "SPI BIOS region" +msgstr "Region BIOS-u SPI" + +#. TRANSLATORS: Title: SPI refers to the flash chip in the computer +msgid "SPI lock" +msgstr "Blokada SPI" + +#. TRANSLATORS: Title: SPI refers to the flash chip in the computer +msgid "SPI write" +msgstr "Zapis SPI" + #. TRANSLATORS: command line option msgid "Save device state into a JSON file between executions" msgstr "Zapisuje stan urządzenia do pliku JSON między wykonaniami" @@ -1125,6 +1475,10 @@ msgstr "Planowanie…" msgid "Selected device" msgstr "Wybrane urządzenie" +#. TRANSLATORS: Volume has been chosen by the user +msgid "Selected volume" +msgstr "Wybrany wolumin" + #. TRANSLATORS: serial number of hardware msgid "Serial Number" msgstr "Numer seryjny" @@ -1133,17 +1487,18 @@ msgstr "Numer seryjny" msgid "Set the debugging flag during update" msgstr "Ustawia flagę debugowania podczas aktualizacji" +#. TRANSLATORS: firmware approved by the admin msgid "Sets the list of approved firmware" msgstr "Ustawienie listy zatwierdzonego oprogramowania sprzętowego" -#. TRANSLATORS: firmware approved by the admin -msgid "Sets the list of approved firmware." -msgstr "Ustawia listę zatwierdzonego oprogramowania sprzętowego." - #. TRANSLATORS: command description msgid "Share firmware history with the developers" msgstr "Udostępnia historię oprogramowania sprzętowego programistom" +#. TRANSLATORS: command line option +msgid "Show all results" +msgstr "Wyświetla wszystkie wyniki" + #. TRANSLATORS: command line option msgid "Show client and daemon versions" msgstr "Wyświetla wersje klienta i usługi" @@ -1176,6 +1531,10 @@ msgstr "Wyświetla historię aktualizacji oprogramowania sprzętowego" msgid "Show plugin verbose information" msgstr "Wyświetla więcej informacji o wtyczkach" +#. TRANSLATORS: command line option +msgid "Show the calculated version of the dbx" +msgstr "Wyświetla obliczoną wersję bazy dbx" + #. TRANSLATORS: command line option msgid "Show the debug log from the last attempted update" msgstr "Wyświetla dziennik debugowania z ostatniej aktualizacji" @@ -1213,6 +1572,10 @@ msgstr "Źródło" msgid "Specify Vendor/Product ID(s) of DFU device" msgstr "Podaje identyfikatory dostawcy/produktu urządzenia DFU" +#. TRANSLATORS: command line option +msgid "Specify the dbx database file" +msgstr "Podaje plik bazy dbx" + msgid "Specify the number of bytes per USB transfer" msgstr "Podaje liczbę bajtów na przesyłanie USB" @@ -1272,10 +1635,42 @@ msgstr "Pomyślnie sprawdzono poprawność sum kontrolnych urządzenia" msgid "Summary" msgstr "Podsumowanie" +#. TRANSLATORS: Suffix: the HSI result +msgid "Supported" +msgstr "Obsługiwane" + #. TRANSLATORS: Is found in current metadata msgid "Supported on remote server" msgstr "Obsługiwane na zdalnym serwerze" +#. TRANSLATORS: Title: a better sleep state +msgid "Suspend-to-idle" +msgstr "Uśpienie do trybu bezczynności" + +#. TRANSLATORS: Title: sleep state +msgid "Suspend-to-ram" +msgstr "Uśpienie do pamięci RAM" + +#. TRANSLATORS: command description +msgid "Switch the firmware branch on the device" +msgstr "Przełącza gałąź oprogramowania sprzętowego na urządzeniu" + +#. TRANSLATORS: Must be plugged in to an outlet +msgid "System requires external power source" +msgstr "Komputer wymaga zewnętrznego źródła zasilania" + +#. TRANSLATORS: Title: the PCR is rebuilt from the TPM event log +msgid "TPM PCR0 reconstruction" +msgstr "Rekonstrukcja PCR0 TPM" + +#. TRANSLATORS: Title: TPM = Trusted Platform Module +msgid "TPM v2.0" +msgstr "TPM v2.0" + +#. TRANSLATORS: Suffix: the HSI result +msgid "Tainted" +msgstr "Skażone" + msgid "Target" msgstr "Cel" @@ -1283,6 +1678,23 @@ msgstr "Cel" msgid "The LVFS is a free service that operates as an independent legal entity and has no connection with $OS_RELEASE:NAME$. Your distributor may not have verified any of the firmware updates for compatibility with your system or connected devices. All firmware is provided only by the original equipment manufacturer." msgstr "LVFS to wolny serwis działający jako niezależny podmiot prawny niemający związków z systemem $OS_RELEASE:NAME$. Dystrybutor używanego systemu mógł nie zweryfikować żadnych aktualizacji oprogramowania sprzętowego pod kątem zgodności z używanym komputerem lub podłączonymi urządzeniami. Każde oprogramowanie sprzętowe jest dostarczane wyłącznie przez oryginalnego producenta sprzętu." +#. TRANSLATORS: this is more background on a security measurement problem +msgid "The TPM PCR0 differs from reconstruction." +msgstr "PCR0 TPM różni się od rekonstrukcji." + +#. TRANSLATORS: the user is SOL for support... +msgid "The daemon has loaded 3rd party code and is no longer supported by the upstream developers!" +msgstr "Usługa wczytała kod firmy trzeciej i nie jest już wspierana przez jej programistów!" + +#. TRANSLATORS: %1 is the firmware vendor, %2 is the device vendor name +#, c-format +msgid "The firmware from %s is not supplied by %s, the hardware vendor." +msgstr "Oprogramowanie sprzętowe od firmy %s nie jest dostarczane przez firmę %s, dostawcę sprzętu." + +#. TRANSLATORS: nothing to show +msgid "There are no blocked firmware files" +msgstr "Nie ma zablokowanych plików oprogramowania sprzętowego" + #. TRANSLATORS: approved firmware has been checked by #. * the domain administrator msgid "There is no approved firmware." @@ -1295,6 +1707,18 @@ msgstr "Ten program może działać poprawnie tylko jako root" msgid "This remote contains firmware which is not embargoed, but is still being tested by the hardware vendor. You should ensure you have a way to manually downgrade the firmware if the firmware update fails." msgstr "To repozytorium zawiera oprogramowanie sprzętowe nieobjęte embargo, ale nadal testowane przez dostawcę sprzętu. Należy upewnić się, że istnieje możliwość ręcznego zainstalowania poprzedniej wersji oprogramowania sprzętowego w razie niepowodzenia aktualizacji." +#. TRANSLATORS: this is instructions on how to improve the HSI suffix +msgid "This system has HSI runtime issues." +msgstr "Ten komputer ma problemy HSI uruchamiania." + +#. TRANSLATORS: this is instructions on how to improve the HSI security level +msgid "This system has a low HSI security level." +msgstr "Ten komputer ma niski poziom zabezpieczeń HSI." + +#. TRANSLATORS: description of dbxtool +msgid "This tool allows an administrator to apply UEFI dbx updates." +msgstr "To narzędzie umożliwia administratorowi zastosowywanie aktualizacji bazy dbx dla UEFI." + #. TRANSLATORS: the user needs to stop playing with stuff msgid "This tool can only be used by the root user" msgstr "To narzędzie może być używane tylko przez użytkownika root" @@ -1303,10 +1727,42 @@ msgstr "To narzędzie może być używane tylko przez użytkownika root" msgid "Type" msgstr "Typ" +#. TRANSLATORS: partition refers to something on disk, again, hey Arch users +msgid "UEFI ESP partition not detected or configured" +msgstr "Nie wykryto lub nie skonfigurowano partycji ESP UEFI" + #. TRANSLATORS: program name msgid "UEFI Firmware Utility" msgstr "Narzędzie oprogramowania sprzętowego UEFI" +#. TRANSLATORS: capsule updates are an optional BIOS feature +msgid "UEFI capsule updates not available or enabled" +msgstr "Aktualizacje kapsułowe UEFI są niedostępne lub wyłączone" + +#. TRANSLATORS: program name +msgid "UEFI dbx Utility" +msgstr "Narzędzie bazy dbx dla UEFI" + +#. TRANSLATORS: Title: SB is a way of locking down UEFI +msgid "UEFI secure boot" +msgstr "Zabezpieczone uruchamianie UEFI" + +#. TRANSLATORS: error message +msgid "Unable to connect to service" +msgstr "Nie można połączyć się z usługą" + +#. TRANSLATORS: command description +msgid "Unbind current driver" +msgstr "Odwiązuje bieżący sterownik" + +#. TRANSLATORS: we will now offer this firmware to the user +msgid "Unblocking firmware:" +msgstr "Odblokowywanie oprogramowania sprzętowego:" + +#. TRANSLATORS: Suffix: the HSI result +msgid "Unencrypted" +msgstr "Niezaszyfrowane" + #. TRANSLATORS: current daemon status is unknown #. TRANSLATORS: we don't know the license of the update #. TRANSLATORS: unknown release urgency @@ -1320,10 +1776,18 @@ msgstr "Nieznane urządzenie" msgid "Unlock the device to allow access" msgstr "Odblokowanie urządzenia" +#. TRANSLATORS: Suffix: the HSI result +msgid "Unlocked" +msgstr "Odblokowane" + #. TRANSLATORS: command description msgid "Unlocks the device for firmware access" msgstr "Odblokowuje urządzenie" +#. TRANSLATORS: command description +msgid "Unmounts the ESP" +msgstr "Odmontowuje ESP" + #. TRANSLATORS: command line option msgid "Unset the debugging flag during update" msgstr "Usuwa flagę debugowania podczas aktualizacji" @@ -1333,6 +1797,10 @@ msgstr "Usuwa flagę debugowania podczas aktualizacji" msgid "Unsupported daemon version %s, client version is %s" msgstr "Nieobsługiwana wersja usługi %s, wersja klienta to %s" +#. TRANSLATORS: Suffix: the HSI result +msgid "Untainted" +msgstr "Nieskażone" + #. TRANSLATORS: Device is updatable in this or any other mode msgid "Updatable" msgstr "Można aktualizować" @@ -1381,6 +1849,9 @@ msgstr "Aktualizuje przechowywane metadane obecną zawartością" msgid "Updates all firmware to latest versions available" msgstr "Aktualizuje całe oprogramowanie sprzętowe do najnowszych dostępnych wersji" +msgid "Updating" +msgstr "Aktualizowanie" + #. TRANSLATORS: the first replacement is a display name #. * e.g. "ColorHugALS" and the second and third are #. * version numbers e.g. "1.2.3" @@ -1399,10 +1870,6 @@ msgstr "Aktualizowanie urządzenia %s…" msgid "Upgrade available for %s from %s to %s" msgstr "Dostępna jest aktualizacja urządzenia %s z wersji %s do %s" -#. TRANSLATORS: the server sent the user a small message -msgid "Upload message:" -msgstr "Komunikat wysyłania:" - msgid "Upload report just this one time, but prompt again for future updates" msgid_plural "Upload reports just this one time, but prompt again for future updates" msgstr[0] "Wysłanie zgłoszenia tylko tym razem, ale pytanie ponownie przy przyszłych aktualizacjach" @@ -1429,6 +1896,14 @@ msgstr "Wysyłanie zgłoszeń o oprogramowaniu sprzętowym pomaga dostawcom spr msgid "Urgency" msgstr "Pilność" +#. TRANSLATORS: error message explaining command to run to how to get help +msgid "Use fwupdmgr --help for help" +msgstr "Polecenie fwupdmgr --help wyświetli pomoc" + +#. TRANSLATORS: error message explaining command to run to how to get help +msgid "Use fwupdtool --help for help" +msgstr "Polecenie fwupdtool --help wyświetli pomoc" + #. TRANSLATORS: command line option msgid "Use quirk flags when installing firmware" msgstr "Używa flag poprawek podczas instalowania oprogramowania sprzętowego" @@ -1441,21 +1916,33 @@ msgstr "Użytkownik został powiadomiony" msgid "Username" msgstr "Nazwa użytkownika" +#. TRANSLATORS: Suffix: the HSI result +msgid "Valid" +msgstr "Prawidłowe" + +#. TRANSLATORS: ESP refers to the EFI System Partition +msgid "Validating ESP contents…" +msgstr "Sprawdzanie poprawności zawartości ESP…" + #. TRANSLATORS: one line variant of release (e.g. 'Prerelease' or 'China') msgid "Variant" msgstr "Wariant" #. TRANSLATORS: manufacturer of hardware msgid "Vendor" -msgstr "Producent" +msgstr "Dostawca" #. TRANSLATORS: verifying we wrote the firmware correctly msgid "Verifying…" msgstr "Sprawdzanie poprawności…" -#. TRANSLATORS: try to help -msgid "WARNING: Ignoring SSL strict checks, to do this automatically in the future export DISABLE_SSL_STRICT in your environment" -msgstr "OSTRZEŻENIE: ignorowanie ścisłych testów SSL, aby robić to automatycznie w przyszłości, należy wyeksportować zmienną DISABLE_SSL_STRICT w środowisku" +#. TRANSLATORS: the detected version number of the dbx +msgid "Version" +msgstr "Wersja" + +#. TRANSLATORS: this is a prefix on the console +msgid "WARNING:" +msgstr "OSTRZEŻENIE:" #. TRANSLATORS: waiting for device to do something msgid "Waiting…" @@ -1477,6 +1964,10 @@ msgstr "Zapisuje oprogramowanie sprzętowe z pliku na urządzenie" msgid "Write firmware from file into one partition" msgstr "Zapisuje oprogramowanie sprzętowe z pliku na jedną partycję" +#. TRANSLATORS: decompressing images from a container firmware +msgid "Writing file:" +msgstr "Zapisywanie pliku:" + #. TRANSLATORS: writing to the flash chips msgid "Writing…" msgstr "Zapisywanie…" @@ -1485,19 +1976,19 @@ msgstr "Zapisywanie…" msgid "Your distributor may not have verified any of the firmware updates for compatibility with your system or connected devices." msgstr "Używana dystrybucja mogła nie sprawdzić zgodności aktualizacji oprogramowania sprzętowego z komputerem i podłączonymi urządzeniami." +#. TRANSLATORS: %1 is the device vendor name +#, c-format +msgid "Your hardware may be damaged using this firmware, and installing this release may void any warranty with %s." +msgstr "Sprzęt może zostać uszkodzony przez użycie tego oprogramowania sprzętowego, a zainstalowanie tego wydania może spowodować utratę gwarancji od firmy %s." + +#. TRANSLATORS: this is the default branch name when unset +msgid "default" +msgstr "domyślna" + #. TRANSLATORS: program name msgid "fwupd TPM event log utility" msgstr "Narzędzie dziennika zdarzeń TPM usługi fwupd" -#. TRANSLATORS: message letting the user know no device upgrade available due -#. to missing on LVFS -#. * %1 is the device name -#, c-format -msgid "• %s has no available firmware updates" -msgstr "• Urządzenie %s nie ma dostępnych aktualizacji oprogramowania sprzętowego" - -#. TRANSLATORS: message letting the user know no device upgrade available -#. * %1 is the device name -#, c-format -msgid "• %s has the latest available firmware version" -msgstr "• Urządzenie %s ma najnowszą dostępną wersję oprogramowania sprzętowego" +#. TRANSLATORS: Title: if the fwupd plugins are all present and correct +msgid "fwupd plugins" +msgstr "Wtyczki usługi fwupd" diff --git a/po/pt_BR.po b/po/pt_BR.po index 07b4fc1f3..18f347438 100644 --- a/po/pt_BR.po +++ b/po/pt_BR.po @@ -32,6 +32,12 @@ msgstr[1] "%.0f minutos restantes" msgid "%s CPU Microcode Update" msgstr "Atualização de microcódigo de CPU %s" +#. TRANSLATORS: a specific part of hardware, +#. * the first %s is the device name, e.g. 'Secure Boot` +#, c-format +msgid "%s Configuration Update" +msgstr "Atualização da configuração de %s " + #. TRANSLATORS: ME stands for Management Engine, where #. * the first %s is the device name, e.g. 'ThinkPad P50` #, c-format @@ -95,6 +101,11 @@ msgstr "Atualização de %s" msgid "%s and all connected devices may not be usable while updating." msgstr "%s e todos os dispositivos conectados não podem ser usados durante a atualização." +#. TRANSLATORS: Title: %s is ME kind, e.g. CSME/TXT +#, c-format +msgid "%s manufacturing mode" +msgstr "Modo de fabricação de %s" + #. TRANSLATORS: warn the user before updating, %1 is a device name #, c-format msgid "%s must remain connected for the duration of the update to avoid damage." @@ -105,6 +116,21 @@ msgstr "%s deve permanecer conectado durante a atualização para evitar danos." msgid "%s must remain plugged into a power source for the duration of the update to avoid damage." msgstr "%s deve permanecer conectado a uma fonte de energia durante a atualização para evitar danos." +#. TRANSLATORS: Title: %s is ME kind, e.g. CSME/TXT +#, c-format +msgid "%s override" +msgstr "substituição de %s" + +#. TRANSLATORS: Title: %1 is ME kind, e.g. CSME/TXT, %2 is a version number +#, c-format +msgid "%s v%s" +msgstr "%s v%s" + +#. TRANSLATORS: Title: %s is ME kind, e.g. CSME/TXT +#, c-format +msgid "%s version" +msgstr "versão %s " + #. TRANSLATORS: duration in days! #, c-format msgid "%u day" @@ -146,6 +172,10 @@ msgid_plural "%u seconds" msgstr[0] "%u segundo" msgstr[1] "%u segundos" +#. TRANSLATORS: this is shown as a suffix for obsoleted tests +msgid "(obsoleted)" +msgstr "(obsoleto)" + #. TRANSLATORS: command description msgid "Activate devices" msgstr "Habilita dispositivos" @@ -206,6 +236,18 @@ msgstr "Responde sim para todas as perguntas" msgid "Apply firmware updates" msgstr "Aplica atualizações de firmware" +#. TRANSLATORS: command line option +msgid "Apply update even when not advised" +msgstr "Aplica a atualização mesmo quando não aconselhável" + +#. TRANSLATORS: command line option +msgid "Apply update files" +msgstr "Aplica arquivos de atualização" + +#. TRANSLATORS: actually sending the update to the hardware +msgid "Applying update…" +msgstr "Aplicando atualização…" + #. TRANSLATORS: approved firmware has been checked by #. * the domain administrator msgid "Approved firmware:" @@ -213,6 +255,10 @@ msgid_plural "Approved firmware:" msgstr[0] "Firmware aprovado:" msgstr[1] "Firmwares aprovados:" +#. TRANSLATORS: stop nagging the user +msgid "Ask again next time?" +msgstr "Perguntar novamente da próxima vez?" + #. TRANSLATORS: command description msgid "Attach to firmware mode" msgstr "Modo anexar ao firmware" @@ -269,6 +315,18 @@ msgstr "Autenticação é necessária para atualizar as somas de verificação a msgid "Automatic Reporting" msgstr "Relatórios automáticos" +#. TRANSLATORS: can we JFDI? +msgid "Automatically upload every time?" +msgstr "Enviar automaticamente toda vez?" + +#. TRANSLATORS: there follows a list of hashes +msgid "Blocked firmware files:" +msgstr "Arquivos de firmware bloqueados:" + +#. TRANSLATORS: we will not offer this firmware to the user +msgid "Blocking firmware:" +msgstr "Bloqueando firmware:" + #. TRANSLATORS: firmware version of bootloader msgid "Bootloader Version" msgstr "Versão do gerenciador de boot" @@ -285,6 +343,14 @@ msgstr "Cancelar" msgid "Cancelled" msgstr "Cancelado" +#. TRANSLATORS: same or newer update already applied +msgid "Cannot apply as dbx update has already been applied." +msgstr "Não foi possível aplicar, pois a atualização de dbx já foi aplicada." + +#. TRANSLATORS: the user is using a LiveCD or LiveUSB install disk +msgid "Cannot apply updates on live media" +msgstr "Não é possível aplicar atualizações em uma mídia live" + #. TRANSLATORS: this is when a device is hotplugged #. TRANSLATORS: this is when the daemon state changes msgid "Changed" @@ -310,6 +376,10 @@ msgstr "Escolha um tipo de firmware:" msgid "Choose a release:" msgstr "Escolha um lançamento:" +#. TRANSLATORS: get interactive prompt +msgid "Choose a volume:" +msgstr "Escolha um volume:" + #. TRANSLATORS: command description msgid "Clears any updates scheduled to be updated offline" msgstr "Limpa quaisquer atualizações agendadas a serem atualizadas desconectadas" @@ -396,7 +466,7 @@ msgstr "Firmware de dispositivo é necessário para ter uma verificação de ver #. TRANSLATORS: Is locked and can be unlocked msgid "Device is locked" -msgstr "O dispositivo está travado" +msgstr "O dispositivo está desbloqueado" #. TRANSLATORS: a version check is required for all firmware msgid "Device is required to install all provided releases" @@ -430,6 +500,20 @@ msgstr "Dispositivos que foram atualizados com sucesso:" msgid "Devices that were not updated correctly:" msgstr "Dispositivos que não foram atualizados com sucesso:" +#. TRANSLATORS: message letting the user know no device upgrade available due +#. to missing on LVFS +msgid "Devices with no available firmware updates: " +msgstr "Dispositivos com nenhuma atualização de firmware disponível:" + +#. TRANSLATORS: message letting the user know no device upgrade available +msgid "Devices with the latest available firmware version:" +msgstr "Dispositivos com a versão mais recente do firmware disponível:" + +#. TRANSLATORS: Suffix: the HSI result +#. TRANSLATORS: Plugin is inactive and not used +msgid "Disabled" +msgstr "Desabilitado" + msgid "Disabled fwupdate debugging" msgstr "Depuração de fwupdate desabilitada" @@ -479,6 +563,7 @@ msgstr[1] "Não enviar relatórios e nunca solicitar para enviar relatórios em msgid "Do not write to the history database" msgstr "Não escreve no banco de dados de histórico" +#. TRANSLATORS: success #. success msgid "Done!" msgstr "Feito!" @@ -523,6 +608,8 @@ msgstr "Habilita suporte a atualização de firmware em sistemas suportados" msgid "Enable this remote?" msgstr "Habilitar esse remoto?" +#. TRANSLATORS: Suffix: the HSI result +#. TRANSLATORS: Plugin is active and in use #. TRANSLATORS: if the remote is enabled msgid "Enabled" msgstr "Habilitado" @@ -541,6 +628,14 @@ msgstr "A habilitação dessa funcionalidade é feita por sua conta e risco, o q msgid "Enabling this remote is done at your own risk." msgstr "A habilitação deste remoto é feito a seu próprio custo e risco." +#. TRANSLATORS: Suffix: the HSI result +msgid "Encrypted" +msgstr "Criptografado" + +#. TRANSLATORS: Title: Memory contents are encrypted, e.g. Intel TME +msgid "Encrypted RAM" +msgstr "RAM criptografada" + #. TRANSLATORS: command description msgid "Erase all firmware update history" msgstr "Apaga todo histórico de atualização de firmware" @@ -557,13 +652,21 @@ msgstr "Sair após pequeno atraso" msgid "Exit after the engine has loaded" msgstr "Sair após o carregamento do motor" +#. TRANSLATORS: Suffix: the fallback HSI result +msgid "Failed" +msgstr "Falhou" + +#. TRANSLATORS: dbx file failed to be applied as an update +msgid "Failed to apply update" +msgstr "Falha ao aplicar a atualização" + #. TRANSLATORS: we could not talk to the fwupd daemon msgid "Failed to connect to daemon" msgstr "Falha ao se conectar ao daemon" -#. TRANSLATORS: the server is rate-limiting downloads -msgid "Failed to download due to server limit" -msgstr "Falha ao baixar em razão de limite do servidor" +#. TRANSLATORS: could not parse file +msgid "Failed to extract local dbx " +msgstr "Falha ao extrair o dbx local" #. TRANSLATORS: we could not get the devices to update offline msgid "Failed to get pending devices" @@ -573,10 +676,19 @@ msgstr "Falha ao obter dispositivos pendentes" msgid "Failed to install firmware update" msgstr "Falha ao instalar a atualização de firmware" +#. TRANSLATORS: could not read existing system data +#. TRANSLATORS: could not read file +msgid "Failed to load local dbx" +msgstr "Falha ao carregar o dbx local" + #. TRANSLATORS: quirks are device-specific workarounds msgid "Failed to load quirks" msgstr "Falha ao carregar peculiaridades" +#. TRANSLATORS: could not read existing system data +msgid "Failed to load system dbx" +msgstr "Falha ao carregar o dbx do sistema" + #. TRANSLATORS: the user didn't read the man page msgid "Failed to parse arguments" msgstr "Falha ao interpretar argumentos" @@ -589,6 +701,10 @@ msgstr "Falha ao analisar o arquivo" msgid "Failed to parse flags for --filter" msgstr "Falha ao analisar opções para --filter" +#. TRANSLATORS: could not parse file +msgid "Failed to parse local dbx" +msgstr "Falha ao analisar o dbx local" + #. TRANSLATORS: we could not reboot for some reason msgid "Failed to reboot" msgstr "Falha ao reinicializar" @@ -597,21 +713,10 @@ msgstr "Falha ao reinicializar" msgid "Failed to set splash mode" msgstr "Falha ao definir o modo splash" -#. TRANSLATORS: downloading unknown file -msgid "Fetching file" -msgstr "Obtendo arquivo" - -#. TRANSLATORS: downloading new firmware file -msgid "Fetching firmware" -msgstr "Obtendo firmware" - -#. TRANSLATORS: downloading new metadata file -msgid "Fetching metadata" -msgstr "Obtendo metadados" - -#. TRANSLATORS: downloading new signing file -msgid "Fetching signature" -msgstr "Obtendo assinatura" +#. TRANSLATORS: something with a blocked hash exists +#. * in the users ESP -- which would be bad! +msgid "Failed to validate ESP contents" +msgstr "Falha ao validar o conteúdo da ESP" #. TRANSLATORS: filename of the local file msgid "Filename" @@ -621,6 +726,10 @@ msgstr "Nome de arquivo" msgid "Filename Signature" msgstr "Assinatura de nome de arquivo" +#. TRANSLATORS: user did not include a filename parameter +msgid "Filename required" +msgstr "Nome de arquivo necessário" + #. TRANSLATORS: command line option msgid "Filter with a set of device flags using a ~ prefix to exclude, e.g. 'internal,~needs-reboot'" msgstr "Filtra com um conjunto de opções de dispositivo usando um prefixo ~ para excluir, p.ex. \"internal,~needs-reboot\"" @@ -645,6 +754,18 @@ msgstr "Daemon de Atualização de Firmware" msgid "Firmware Utility" msgstr "Utilitário de Firmware" +#. TRANSLATORS: Title: if we can verify the firmware checksums +msgid "Firmware attestation" +msgstr "Atestação de firmware" + +#. TRANSLATORS: user selected something not possible +msgid "Firmware is already blocked" +msgstr "O firmware já está bloqueado" + +#. TRANSLATORS: user selected something not possible +msgid "Firmware is not already blocked" +msgstr "O firmware ainda não está bloqueado" + #. TRANSLATORS: the metadata is very out of date; %u is a number > 1 #, c-format msgid "Firmware metadata has not been updated for %u day and may not be up to date." @@ -652,12 +773,17 @@ msgid_plural "Firmware metadata has not been updated for %u days and may not be msgstr[0] "Os metadados do firmware não foram atualizados a %u dia e podem não estar atualizados." msgstr[1] "Os metadados do firmware não foram atualizados a %u dias e podem não estar atualizados." +#. TRANSLATORS: Title: if firmware updates are available +msgid "Firmware updates" +msgstr "Atualizações de firmware" + msgid "Firmware updates are not supported on this machine." msgstr "Não há suporte a atualizações de firmware nessa máquina." msgid "Firmware updates are supported on this machine." msgstr "Há suporte a atualizações de firmware nesta máquina." +#. TRANSLATORS: description of plugin state, e.g. disabled #. TRANSLATORS: release properties msgid "Flags" msgstr "Opções" @@ -665,6 +791,10 @@ msgstr "Opções" msgid "Force the action ignoring all warnings" msgstr "Força a ação ignorando todos avisos" +#. TRANSLATORS: Suffix: the HSI result +msgid "Found" +msgstr "Encontrado" + #. TRANSLATORS: global ID common to all similar hardware msgid "GUID" msgid_plural "GUIDs" @@ -695,9 +825,9 @@ msgstr "Obtém detalhes sobre um arquivo de firmware" msgid "Gets the configured remotes" msgstr "Obtém os remotos configurados" -#. TRANSLATORS: firmware approved by the admin -msgid "Gets the list of approved firmware." -msgstr "Obtém a lista de firmwares aprovados." +#. TRANSLATORS: command description +msgid "Gets the host security attributes" +msgstr "Obtém os atributos de segurança do host" #. TRANSLATORS: command description msgid "Gets the list of updates for connected hardware" @@ -719,6 +849,15 @@ msgstr "O hardware está aguardando para ser reconectado" msgid "High" msgstr "Alta" +#. TRANSLATORS: this is a string like 'HSI:2-U' +msgid "Host Security ID:" +msgstr "ID de segurança do host:" + +#. TRANSLATORS: Title: +#. https://en.wikipedia.org/wiki/Input%E2%80%93output_memory_management_unit +msgid "IOMMU" +msgstr "IOMMU" + #. TRANSLATORS: daemon is inactive msgid "Idle…" msgstr "Ocioso…" @@ -775,10 +914,57 @@ msgstr "Instalando atualização de firmware…" msgid "Installing on %s…" msgstr "Instalando em %s…" +#. TRANSLATORS: Title: BootGuard is a trademark from Intel +msgid "Intel BootGuard" +msgstr "Intel BootGuard" + +#. TRANSLATORS: Title: BootGuard is a trademark from Intel, +#. * ACM means to verify the integrity of Initial Boot Block +msgid "Intel BootGuard ACM protected" +msgstr "ACM protegido com Intel BootGuard" + +#. TRANSLATORS: Title: BootGuard is a trademark from Intel, +#. * OTP = one time programmable +msgid "Intel BootGuard OTP fuse" +msgstr "Fusível OTP do Intel BootGuard" + +#. TRANSLATORS: Title: BootGuard is a trademark from Intel, +#. * error policy is what to do on failure +msgid "Intel BootGuard error policy" +msgstr "Política de erro do Intel BootGuard" + +#. TRANSLATORS: Title: BootGuard is a trademark from Intel, +#. * verified boot refers to the way the boot process is verified +msgid "Intel BootGuard verified boot" +msgstr "Inicialização verificada com Intel BootGuard" + +#. TRANSLATORS: Title: CET = Control-flow Enforcement Technology, +#. * active means being used by the OS +msgid "Intel CET Active" +msgstr "Intel CET ativo" + +#. TRANSLATORS: Title: CET = Control-flow Enforcement Technology, +#. * enabled means supported by the processor +msgid "Intel CET Enabled" +msgstr "Habilitado para Intel CET" + +#. TRANSLATORS: Title: Direct Connect Interface (DCI) allows +#. * debugging of Intel processors using the USB3 port +msgid "Intel DCI debugger" +msgstr "Depurador Intel DCI" + +#. TRANSLATORS: Title: SMAP = Supervisor Mode Access Prevention +msgid "Intel SMAP" +msgstr "Intel SMAP" + #. TRANSLATORS: Device cannot be removed easily msgid "Internal device" msgstr "Dispositivo interno" +#. TRANSLATORS: Suffix: the HSI result +msgid "Invalid" +msgstr "Inválido" + #. TRANSLATORS: Is currently in bootloader mode msgid "Is in bootloader mode" msgstr "Está no modo gerenciador de boot" @@ -810,6 +996,22 @@ msgstr "Linux Vendor Firmware Service (firmware estável)" msgid "Linux Vendor Firmware Service (testing firmware)" msgstr "Linux Vendor Firmware Service (firmware de teste)" +#. TRANSLATORS: Title: if it's tainted or not +msgid "Linux kernel" +msgstr "Kernel Linux" + +#. TRANSLATORS: Title: lockdown is a security mode of the kernel +msgid "Linux kernel lockdown" +msgstr "Lockdown do kernel Linux" + +#. TRANSLATORS: Title: swap space or swap partition +msgid "Linux swap" +msgstr "Swap do Linux" + +#. TRANSLATORS: command line option +msgid "List entries in dbx" +msgstr "Lista entradas no dbx" + #. TRANSLATORS: command line option msgid "List supported firmware updates" msgstr "Lista atualizações de firmware suportadas" @@ -822,13 +1024,31 @@ msgstr "Lista os tipos de firmware disponível" msgid "Loading…" msgstr "Carregando…" +#. TRANSLATORS: Suffix: the HSI result +msgid "Locked" +msgstr "Bloqueado" + #. TRANSLATORS: the release urgency msgid "Low" msgstr "Baixa" +#. TRANSLATORS: Title: MEI = Intel Management Engine +msgid "MEI manufacturing mode" +msgstr "Modo de fabricação do MEI" + +#. TRANSLATORS: Title: MEI = Intel Management Engine, and the +#. * "override" is the physical PIN that can be driven to +#. * logic high -- luckily it is probably not accessible to +#. * end users on consumer boards +msgid "MEI override" +msgstr "substituição de MEI" + +msgid "MEI version" +msgstr "versão MEI" + #. TRANSLATORS: command line option -msgid "Manually whitelist specific plugins" -msgstr "Insere manualmente na lista branca plugins específicos" +msgid "Manually enable specific plugins" +msgstr "Habilita manualmente plugins específicos" #. TRANSLATORS: the release urgency msgid "Medium" @@ -855,10 +1075,6 @@ msgstr "Versão mínima" msgid "Mismatched daemon and client, use %s instead" msgstr "Daemon e cliente incompatíveis, use %s" -#. TRANSLATORS: sets something in daemon.conf -msgid "Modifies a daemon configuration value." -msgstr "Modifica o valor de uma configuração do daemon." - #. TRANSLATORS: command description msgid "Modifies a given remote" msgstr "Modifica um remoto dado" @@ -885,6 +1101,7 @@ msgstr "Precisa de desligamento após a instalação" msgid "New version" msgstr "Nova versão" +#. TRANSLATORS: user did not tell the tool what to do msgid "No action specified!" msgstr "Nenhuma ação especificada!" @@ -922,14 +1139,22 @@ msgstr "Nenhum remoto disponível" msgid "No updates were applied" msgstr "Nenhuma atualização foi aplicada" +#. TRANSLATORS: Suffix: the HSI result +msgid "Not found" +msgstr "Não encontrado" + +#. TRANSLATORS: Suffix: the HSI result +msgid "Not supported" +msgstr "Não suportado" + +#. TRANSLATORS: Suffix: the HSI result +msgid "OK" +msgstr "OK" + #. TRANSLATORS: command line option msgid "Only show single PCR value" msgstr "Mostra apenas valor único de PCR" -#. TRANSLATORS: command line option -msgid "Override plugin warning" -msgstr "Sobrepõe um aviso de plugin" - #. TRANSLATORS: command line option msgid "Override the default ESP path" msgstr "Substitui o caminho ESP padrão" @@ -942,6 +1167,14 @@ msgstr "Anula avisos e força a ação" msgid "Parse and show details about a firmware file" msgstr "Analisa e mostra detalhes sobre um arquivo de firmware" +#. TRANSLATORS: reading new dbx from the update +msgid "Parsing dbx update…" +msgstr "Analisando a atualização de dbx…" + +#. TRANSLATORS: reading existing dbx from the system +msgid "Parsing system dbx…" +msgstr "Analisando o dbx do sistema…" + #. TRANSLATORS: remote filename base msgid "Password" msgstr "Senha" @@ -958,6 +1191,10 @@ msgstr "Percentagem concluída" msgid "Please enter a number from 0 to %u: " msgstr "Por favor, insira um número de 0 a %u: " +#. TRANSLATORS: Title: DMA as in https://en.wikipedia.org/wiki/DMA_attack +msgid "Pre-boot DMA protection" +msgstr "Proteção de DMA pré-inicialização" + #. TRANSLATORS: version number of previous firmware msgid "Previous version" msgstr "Versão anterior" @@ -1012,10 +1249,6 @@ msgstr "Reinicializando…" msgid "Refresh metadata from remote server" msgstr "Renova metadados do servidor remoto" -#. TRANSLATORS: command description -msgid "Reinstall current firmware on the device." -msgstr "Reinstala o atual firmware no dispositivo." - #. TRANSLATORS: command description msgid "Reinstall firmware on a device" msgstr "Reinstala firmware em um dispositivo" @@ -1048,10 +1281,6 @@ msgstr "URI do relatório" msgid "Reported to remote server" msgstr "Relatado ao servidor remoto" -#. TRANSLATORS: Must be plugged in to an outlet -msgid "Requires AC power" -msgstr "Requer alimentação CA" - #. TRANSLATORS: Requires a bootloader mode to be manually enabled by the user msgid "Requires a bootloader" msgstr "Requer um gerenciador de boot" @@ -1087,6 +1316,22 @@ msgstr "Executa a rotina de limpeza da composição de plugin ao usar install-bl msgid "Run the plugin composite prepare routine when using install-blob" msgstr "Executa a rotina de preparação da composição de plugin ao usar install-blob" +#. TRANSLATORS: this is the HSI suffix +msgid "Runtime Suffix" +msgstr "Sufixo de tempo de execução" + +#. TRANSLATORS: Title: SPI refers to the flash chip in the computer +msgid "SPI BIOS region" +msgstr "Região BIOS do SPI" + +#. TRANSLATORS: Title: SPI refers to the flash chip in the computer +msgid "SPI lock" +msgstr "Bloqueio de SPI" + +#. TRANSLATORS: Title: SPI refers to the flash chip in the computer +msgid "SPI write" +msgstr "Escrita de SPI" + #. TRANSLATORS: command line option msgid "Save device state into a JSON file between executions" msgstr "Salva o estado do dispositivo em um arquivo JSON entre execuções" @@ -1103,6 +1348,10 @@ msgstr "Agendando…" msgid "Selected device" msgstr "Dispositivo selecionado" +#. TRANSLATORS: Volume has been chosen by the user +msgid "Selected volume" +msgstr "Volume selecionado" + #. TRANSLATORS: serial number of hardware msgid "Serial Number" msgstr "Número de série" @@ -1111,13 +1360,10 @@ msgstr "Número de série" msgid "Set the debugging flag during update" msgstr "Define a opção de depuração durante atualização" +#. TRANSLATORS: firmware approved by the admin msgid "Sets the list of approved firmware" msgstr "Define a lista de firmwares aprovados" -#. TRANSLATORS: firmware approved by the admin -msgid "Sets the list of approved firmware." -msgstr "Define a lista de firmwares aprovados." - #. TRANSLATORS: command description msgid "Share firmware history with the developers" msgstr "Compartilha histórico de firmware com os desenvolvedores" @@ -1154,6 +1400,10 @@ msgstr "Mostra histórico de atualizações de firmware" msgid "Show plugin verbose information" msgstr "Mostra informação verbosa de plugin" +#. TRANSLATORS: command line option +msgid "Show the calculated version of the dbx" +msgstr "Mostra a versão calculada do dbx" + #. TRANSLATORS: command line option msgid "Show the debug log from the last attempted update" msgstr "Mostra o registro log de depuração da tentativa mais recente de atualização" @@ -1191,6 +1441,10 @@ msgstr "Fonte" msgid "Specify Vendor/Product ID(s) of DFU device" msgstr "Especifica ID(s) de Fornecedor/Produto de dispositivo DFU" +#. TRANSLATORS: command line option +msgid "Specify the dbx database file" +msgstr "Especifica o arquivo de banco de dados dbx" + msgid "Specify the number of bytes per USB transfer" msgstr "Especifica o número de bytes por transferência USB" @@ -1206,7 +1460,7 @@ msgstr "Remoto desabilitado com sucesso" #. TRANSLATORS: success message -- where 'metadata' is information #. * about available firmware on the remote server msgid "Successfully downloaded new metadata: " -msgstr "Baixado com sucesso novos metadados:" +msgstr "Baixados com sucesso novos metadados:" #. TRANSLATORS: success message msgid "Successfully enabled remote" @@ -1248,10 +1502,34 @@ msgstr "Somas de verificação de dispositivo verificadas com sucesso" msgid "Summary" msgstr "Resumo" +#. TRANSLATORS: Suffix: the HSI result +msgid "Supported" +msgstr "Suportado" + #. TRANSLATORS: Is found in current metadata msgid "Supported on remote server" msgstr "Suporte no servidor remoto" +#. TRANSLATORS: Title: a better sleep state +msgid "Suspend-to-idle" +msgstr "Suspensão para inativo" + +#. TRANSLATORS: Title: sleep state +msgid "Suspend-to-ram" +msgstr "Suspensão para RAM" + +#. TRANSLATORS: Title: the PCR is rebuilt from the TPM event log +msgid "TPM PCR0 reconstruction" +msgstr "Reconstrução de PCR0 de TPM" + +#. TRANSLATORS: Title: TPM = Trusted Platform Module +msgid "TPM v2.0" +msgstr "TPM v2.0" + +#. TRANSLATORS: Suffix: the HSI result +msgid "Tainted" +msgstr "Contaminado" + msgid "Target" msgstr "Alvo" @@ -1259,6 +1537,14 @@ msgstr "Alvo" msgid "The LVFS is a free service that operates as an independent legal entity and has no connection with $OS_RELEASE:NAME$. Your distributor may not have verified any of the firmware updates for compatibility with your system or connected devices. All firmware is provided only by the original equipment manufacturer." msgstr "O LVFS é um serviço livre que opera como uma entidade legal independente e tem nenhuma conexão com $OS_RELEASE:NAME$. Seu distribuidor pode não ter verificado alguma das atualizações de firmware por compatibilidade com seu sistema ou dispositivos conectados. Todo firmware é fornecido apenas pelo fabricante do equipamento original." +#. TRANSLATORS: this is more background on a security measurement problem +msgid "The TPM PCR0 differs from reconstruction." +msgstr "O TPM PCR0 diverge da reconstrução." + +#. TRANSLATORS: nothing to show +msgid "There are no blocked firmware files" +msgstr "Não há arquivos de firmware bloqueados" + #. TRANSLATORS: approved firmware has been checked by #. * the domain administrator msgid "There is no approved firmware." @@ -1271,6 +1557,18 @@ msgstr "Esse programa só pode funcionar corretamente como root" msgid "This remote contains firmware which is not embargoed, but is still being tested by the hardware vendor. You should ensure you have a way to manually downgrade the firmware if the firmware update fails." msgstr "Este remoto contém firmware que não está embargado, mas ainda está sendo testado pelo fornecedor do hardware. Você deve garantir que você tenha uma maneira de fazer downgrade manual do firmware se a atualização do firmware falhar." +#. TRANSLATORS: this is instructions on how to improve the HSI suffix +msgid "This system has HSI runtime issues." +msgstr "Este sistema possui problemas de tempo de execução de HSI." + +#. TRANSLATORS: this is instructions on how to improve the HSI security level +msgid "This system has a low HSI security level." +msgstr "Este sistema possui um nível de segurança de HSI baixo." + +#. TRANSLATORS: description of dbxtool +msgid "This tool allows an administrator to apply UEFI dbx updates." +msgstr "Esta ferramenta permite que um administrador aplique atualizações de dbx UEFI." + #. TRANSLATORS: the user needs to stop playing with stuff msgid "This tool can only be used by the root user" msgstr "Essa ferramenta só pode ser usada pelo usuário root" @@ -1283,6 +1581,26 @@ msgstr "Tipo" msgid "UEFI Firmware Utility" msgstr "Utilitário de Firmware UEFI" +#. TRANSLATORS: program name +msgid "UEFI dbx Utility" +msgstr "Utilitário de dbx UEFI" + +#. TRANSLATORS: Title: SB is a way of locking down UEFI +msgid "UEFI secure boot" +msgstr "Secure boot de UEFI" + +#. TRANSLATORS: error message +msgid "Unable to connect to service" +msgstr "Não foi possível conectar ao serviço" + +#. TRANSLATORS: we will now offer this firmware to the user +msgid "Unblocking firmware:" +msgstr "Desbloqueando firmware:" + +#. TRANSLATORS: Suffix: the HSI result +msgid "Unencrypted" +msgstr "Descriptografado" + #. TRANSLATORS: current daemon status is unknown #. TRANSLATORS: we don't know the license of the update #. TRANSLATORS: unknown release urgency @@ -1296,6 +1614,10 @@ msgstr "Dispositivo desconhecido" msgid "Unlock the device to allow access" msgstr "Desbloquear o dispositivo para permitir acesso" +#. TRANSLATORS: Suffix: the HSI result +msgid "Unlocked" +msgstr "Desbloqueado" + #. TRANSLATORS: command description msgid "Unlocks the device for firmware access" msgstr "Desbloqueia o dispositivo para acesso do firmware" @@ -1309,6 +1631,10 @@ msgstr "Desativa a opção de depuração durante atualização" msgid "Unsupported daemon version %s, client version is %s" msgstr "Sem suporte ao daemon na versão %s, a versão do cliente é %s" +#. TRANSLATORS: Suffix: the HSI result +msgid "Untainted" +msgstr "Descontaminado" + #. TRANSLATORS: Device is updatable in this or any other mode msgid "Updatable" msgstr "Atualizável" @@ -1355,7 +1681,10 @@ msgstr "Atualiza os metadados armazenados com o conteúdo atual" #. TRANSLATORS: command description msgid "Updates all firmware to latest versions available" -msgstr "Atualiza todos os firmwares para a última versão disponível" +msgstr "Atualiza todos os firmwares para a versão mais recente disponível" + +msgid "Updating" +msgstr "Atualizando" #. TRANSLATORS: the first replacement is a display name #. * e.g. "ColorHugALS" and the second and third are @@ -1375,10 +1704,6 @@ msgstr "Atualizando %s…" msgid "Upgrade available for %s from %s to %s" msgstr "Atualização disponível para %s de %s para %s" -#. TRANSLATORS: the server sent the user a small message -msgid "Upload message:" -msgstr "Mensagem enviada:" - msgid "Upload report just this one time, but prompt again for future updates" msgid_plural "Upload reports just this one time, but prompt again for future updates" msgstr[0] "Enviar relatório apenas desta vez, mas solicitar novamente para atualizações futuras" @@ -1401,6 +1726,14 @@ msgstr "O envio de relatórios de firmware ajuda os fornecedores de hardware a i msgid "Urgency" msgstr "Urgência" +#. TRANSLATORS: error message explaining command to run to how to get help +msgid "Use fwupdmgr --help for help" +msgstr "Use fwupdmgr --help para ajuda" + +#. TRANSLATORS: error message explaining command to run to how to get help +msgid "Use fwupdtool --help for help" +msgstr "Use fwupdtool --help para ajuda" + #. TRANSLATORS: command line option msgid "Use quirk flags when installing firmware" msgstr "Usa opções de peculiaridades ao instalar firmware" @@ -1413,6 +1746,14 @@ msgstr "O usuário foi notificado" msgid "Username" msgstr "Nome de usuário" +#. TRANSLATORS: Suffix: the HSI result +msgid "Valid" +msgstr "Válido" + +#. TRANSLATORS: ESP refers to the EFI System Partition +msgid "Validating ESP contents…" +msgstr "Validando conteúdo da ESP…" + #. TRANSLATORS: one line variant of release (e.g. 'Prerelease' or 'China') msgid "Variant" msgstr "Variação" @@ -1425,9 +1766,13 @@ msgstr "Fornecedor" msgid "Verifying…" msgstr "Verificando…" -#. TRANSLATORS: try to help -msgid "WARNING: Ignoring SSL strict checks, to do this automatically in the future export DISABLE_SSL_STRICT in your environment" -msgstr "AVISO: Ignorando verificações estritas de SSL. Para fazer isso automaticamente no futuro, exporte DISABLE_SSL_STRICT em seu ambiente" +#. TRANSLATORS: the detected version number of the dbx +msgid "Version" +msgstr "Versão" + +#. TRANSLATORS: this is a prefix on the console +msgid "WARNING:" +msgstr "AVISO:" #. TRANSLATORS: waiting for device to do something msgid "Waiting…" @@ -1449,6 +1794,10 @@ msgstr "Escreve um firmware do arquivo para o dispositivo" msgid "Write firmware from file into one partition" msgstr "Escreve um firmware do arquivo para uma partição" +#. TRANSLATORS: decompressing images from a container firmware +msgid "Writing file:" +msgstr "Escrevendo arquivo:" + #. TRANSLATORS: writing to the flash chips msgid "Writing…" msgstr "Escrevendo…" @@ -1461,15 +1810,6 @@ msgstr "Seu distribuidor pode não ter verificado qualquer das atualizações de msgid "fwupd TPM event log utility" msgstr "Utilitário de registro de eventos TPM do fwupd" -#. TRANSLATORS: message letting the user know no device upgrade available due -#. to missing on LVFS -#. * %1 is the device name -#, c-format -msgid "• %s has no available firmware updates" -msgstr "• %s possui nenhuma atualização de firmware disponível" - -#. TRANSLATORS: message letting the user know no device upgrade available -#. * %1 is the device name -#, c-format -msgid "• %s has the latest available firmware version" -msgstr "• %s possui a última versão do firmware disponível" +#. TRANSLATORS: Title: if the fwupd plugins are all present and correct +msgid "fwupd plugins" +msgstr "Plugins do fwupd" diff --git a/po/ru.po b/po/ru.po index 27ea0794b..8ec7d25d2 100644 --- a/po/ru.po +++ b/po/ru.po @@ -341,6 +341,7 @@ msgstr "Не проверять незарегистрированную ист msgid "Do not write to the history database" msgstr "Не сохранять в базу данных истории" +#. TRANSLATORS: success #. success msgid "Done!" msgstr "Готово!" @@ -381,6 +382,8 @@ msgstr "Активировать поддержку обновлений про msgid "Enable this remote?" msgstr "Активировать этот репозиторий?" +#. TRANSLATORS: Suffix: the HSI result +#. TRANSLATORS: Plugin is active and in use #. TRANSLATORS: if the remote is enabled msgid "Enabled" msgstr "Активировано" @@ -419,10 +422,6 @@ msgstr "Выйти после загрузки движка" msgid "Failed to connect to daemon" msgstr "Не удалось подключиться к фоновой службе" -#. TRANSLATORS: the server is rate-limiting downloads -msgid "Failed to download due to server limit" -msgstr "Не удалось загрузить из-за ограничения сервера" - #. TRANSLATORS: we could not get the devices to update offline msgid "Failed to get pending devices" msgstr "Не удалось получить ожидающие устройства" @@ -447,22 +446,6 @@ msgstr "Не удалось перезагрузить" msgid "Failed to set splash mode" msgstr "Не удалось установить режим заставки" -#. TRANSLATORS: downloading unknown file -msgid "Fetching file" -msgstr "Получение файла" - -#. TRANSLATORS: downloading new firmware file -msgid "Fetching firmware" -msgstr "Получение прошивки" - -#. TRANSLATORS: downloading new metadata file -msgid "Fetching metadata" -msgstr "Получение метаданных" - -#. TRANSLATORS: downloading new signing file -msgid "Fetching signature" -msgstr "Получение подписи" - #. TRANSLATORS: filename of the local file msgid "Filename" msgstr "Имя файла" @@ -506,6 +489,7 @@ msgstr "Обновления прошивки не поддерживаются msgid "Firmware updates are supported on this machine." msgstr "Обновления прошивки поддерживаются на этой машине." +#. TRANSLATORS: description of plugin state, e.g. disabled #. TRANSLATORS: release properties msgid "Flags" msgstr "Флаги" @@ -513,6 +497,10 @@ msgstr "Флаги" msgid "Force the action ignoring all warnings" msgstr "Выполнить действие, игнорируя все предупреждения" +#. TRANSLATORS: Suffix: the HSI result +msgid "Found" +msgstr "Найдено" + #. TRANSLATORS: command description msgid "Get all devices and possible releases" msgstr "Получить все устройства и возможные выпуски" @@ -533,10 +521,6 @@ msgstr "Получить сведения о файле прошивки" msgid "Gets the configured remotes" msgstr "Получить настроенные репозитории" -#. TRANSLATORS: firmware approved by the admin -msgid "Gets the list of approved firmware." -msgstr "Получить список одобренных прошивок." - #. TRANSLATORS: command description msgid "Gets the list of updates for connected hardware" msgstr "Получить список обновлений для подключенного оборудования" @@ -610,10 +594,6 @@ msgstr "Вывести список поддерживаемых обновле msgid "Loading…" msgstr "Загрузка…" -#. TRANSLATORS: command line option -msgid "Manually whitelist specific plugins" -msgstr "Изменить вручную белый список определённых плагинов" - #. TRANSLATORS: remote URI msgid "Metadata URI" msgstr "URI метаданных" @@ -627,10 +607,6 @@ msgstr "Метаданные можно получить в Linux Vendor Firmwar msgid "Mismatched daemon and client, use %s instead" msgstr "Несовместимые фоновая служба и клиент, используйте %s" -#. TRANSLATORS: sets something in daemon.conf -msgid "Modifies a daemon configuration value." -msgstr "Изменить значение в конфигурации фоновой службы." - #. TRANSLATORS: command description msgid "Modifies a given remote" msgstr "Модифицировать данный репозиторий" @@ -645,6 +621,7 @@ msgstr "Изменить настройки фоновой службы" msgid "Monitor the daemon for events" msgstr "Следить за событиями в фоновой службе" +#. TRANSLATORS: user did not tell the tool what to do msgid "No action specified!" msgstr "Не определено никаких действий." @@ -664,9 +641,9 @@ msgstr "В настоящее время репозитории не актив msgid "No updates were applied" msgstr "Обновления не были применены" -#. TRANSLATORS: command line option -msgid "Override plugin warning" -msgstr "Переопределить предупреждение плагина" +#. TRANSLATORS: Suffix: the HSI result +msgid "OK" +msgstr "ОК" #. TRANSLATORS: command line option msgid "Override the default ESP path" @@ -797,13 +774,10 @@ msgstr "Планировка…" msgid "Set the debugging flag during update" msgstr "Установить флаг отладки во время обновления" +#. TRANSLATORS: firmware approved by the admin msgid "Sets the list of approved firmware" msgstr "Установить список одобренных прошивок" -#. TRANSLATORS: firmware approved by the admin -msgid "Sets the list of approved firmware." -msgstr "Установить список одобренных прошивок." - #. TRANSLATORS: command description msgid "Share firmware history with the developers" msgstr "Поделиться историей прошивки с разработчиками" @@ -964,10 +938,6 @@ msgstr "Обновление %s с %s на %s…" msgid "Updating %s…" msgstr "Обновление устройства %s…" -#. TRANSLATORS: the server sent the user a small message -msgid "Upload message:" -msgstr "Загрузить сообщение:" - #. TRANSLATORS: ask the user to upload msgid "Upload report now?" msgstr "Загрузить отчет сейчас?" @@ -984,6 +954,10 @@ msgstr "Имя пользователя" msgid "Verifying…" msgstr "Проверка…" +#. TRANSLATORS: the detected version number of the dbx +msgid "Version" +msgstr "Версия" + #. TRANSLATORS: waiting for device to do something msgid "Waiting…" msgstr "Ожидание…" diff --git a/po/sk.po b/po/sk.po index 3f74db8e0..31b031131 100644 --- a/po/sk.po +++ b/po/sk.po @@ -93,6 +93,7 @@ msgstr "Zmenené zariadenie:" msgid "Device removed:" msgstr "Odstránené zariadenie:" +#. TRANSLATORS: success #. success msgid "Done!" msgstr "Hotovo!" @@ -128,6 +129,10 @@ msgstr "Démon aktualizácie firmvéru" msgid "Firmware Utility" msgstr "Nástroj pre firmvéry" +#. TRANSLATORS: Suffix: the HSI result +msgid "Found" +msgstr "Nájdené" + #. TRANSLATORS: command description msgid "Get all devices that support firmware updates" msgstr "Získa všetky zariadenia, ktoré podporujú aktualizovanie firmvéru" @@ -171,6 +176,10 @@ msgstr "Sleduje démona kvôli udalostiam" msgid "No hardware detected with firmware update capability" msgstr "Nezistil sa žiadny hardvér s možnosťou aktualizácie firmvéru" +#. TRANSLATORS: Suffix: the HSI result +msgid "OK" +msgstr "OK" + #. TRANSLATORS: command description msgid "Read firmware from device into a file" msgstr "Prečíta firmvér zo zariadenia do súboru" @@ -220,6 +229,10 @@ msgstr "Aktualizuje všetok firmvér na najnovšiu dostupnú verziu" msgid "Updating %s from %s to %s... " msgstr "Aktualizuje sa %s z verzie %s na verziu %s... " +#. TRANSLATORS: the detected version number of the dbx +msgid "Version" +msgstr "Verzia" + #. TRANSLATORS: command description msgid "Watch DFU devices being hotplugged" msgstr "Sleduje pripojenie zariadení DFU" diff --git a/po/sr.po b/po/sr.po index 96b5443a3..8e8feb4d3 100644 --- a/po/sr.po +++ b/po/sr.po @@ -159,6 +159,7 @@ msgstr "Не проверавај да ли је потребно поновно msgid "Do not check for unreported history" msgstr "Не проверавај непослати историјат" +#. TRANSLATORS: success #. success msgid "Done!" msgstr "Урађено!" @@ -182,6 +183,8 @@ msgstr "Преузимам…" msgid "Dump SMBIOS data from a file" msgstr "Ишчитај SMBIOS податке из датотеке" +#. TRANSLATORS: Suffix: the HSI result +#. TRANSLATORS: Plugin is active and in use #. TRANSLATORS: if the remote is enabled msgid "Enabled" msgstr "Омогућено" @@ -210,22 +213,6 @@ msgstr "Нисам могао да учитам ћефове" msgid "Failed to parse arguments" msgstr "Не могу да обрадим аргументе" -#. TRANSLATORS: downloading unknown file -msgid "Fetching file" -msgstr "Добављам датотеку" - -#. TRANSLATORS: downloading new firmware file -msgid "Fetching firmware" -msgstr "Добављам фирмвер" - -#. TRANSLATORS: downloading new metadata file -msgid "Fetching metadata" -msgstr "Добављам мета-податке" - -#. TRANSLATORS: downloading new signing file -msgid "Fetching signature" -msgstr "Добављам потпис" - #. TRANSLATORS: filename of the local file msgid "Filename" msgstr "Назив датотеке" @@ -258,6 +245,10 @@ msgstr[0] "Метаподаци фирмвера нису ажурирани %u msgstr[1] "Метаподаци фирмвера нису ажурирани %u дана и можда су застарели." msgstr[2] "Метаподаци фирмвера нису ажурирани %u дана и можда су застарели." +#. TRANSLATORS: Suffix: the HSI result +msgid "Found" +msgstr "Нашао" + #. TRANSLATORS: command description msgid "Get all devices that support firmware updates" msgstr "Добави све уређаје који подржавају ажурирање фирмвера" @@ -335,9 +326,9 @@ msgstr "Прати демона за догађајима" msgid "No hardware detected with firmware update capability" msgstr "Нема хардвера којем се може ажурирати фирмвер" -#. TRANSLATORS: command line option -msgid "Override plugin warning" -msgstr "Превазилази упозорења прикључка" +#. TRANSLATORS: Suffix: the HSI result +msgid "OK" +msgstr "У реду" #. TRANSLATORS: remote filename base msgid "Password" @@ -487,10 +478,6 @@ msgstr "Ажурира сав фирмвер на последња доступ msgid "Updating %s from %s to %s... " msgstr "Ажурирам %s са %s на %s..." -#. TRANSLATORS: the server sent the user a small message -msgid "Upload message:" -msgstr "Отпремна порука:" - #. TRANSLATORS: ask the user to upload msgid "Upload report now?" msgstr "Отпремити извештај сада?" @@ -503,6 +490,10 @@ msgstr "Корисничко име" msgid "Verifying…" msgstr "Проверавам…" +#. TRANSLATORS: the detected version number of the dbx +msgid "Version" +msgstr "Издање" + #. TRANSLATORS: waiting for device to do something msgid "Waiting…" msgstr "Чекам…" diff --git a/po/sv.po b/po/sv.po index 2ff399a16..b1636586c 100644 --- a/po/sv.po +++ b/po/sv.po @@ -3,7 +3,7 @@ # This file is distributed under the same license as the fwupd package. # # Translators: -# Anders Jonsson , 2017,2019 +# Anders Jonsson , 2017,2019-2020 # Andreas Henriksson , 2017 # Josef Andersson , 2015,2017-2018 # Josef Andersson , 2015,2017 @@ -27,24 +27,30 @@ msgid_plural "%.0f minutes remaining" msgstr[0] "%.0fminut kvarstår" msgstr[1] "%.0f minuter kvarstår" +#. TRANSLATORS: the CPU microcode is firmware loaded onto the CPU +#. * at system bootup +#, c-format +msgid "%s CPU Microcode Update" +msgstr "%s CPU-mikrokodsuppdatering" + #. TRANSLATORS: ME stands for Management Engine, where #. * the first %s is the device name, e.g. 'ThinkPad P50` #, c-format msgid "%s Consumer ME Update" -msgstr "%s ME-uppdatering för konsument" +msgstr "%s Consumer ME-uppdatering" #. TRANSLATORS: the controller is a device that has other devices #. * plugged into it, for example ThunderBolt, FireWire or USB, #. * the first %s is the device name, e.g. 'Intel ThunderBolt` #, c-format msgid "%s Controller Update" -msgstr "%s Kontrolleruppdatering" +msgstr "%s-styrenhetsuppdatering" #. TRANSLATORS: ME stands for Management Engine (with Intel AMT), #. * where the first %s is the device name, e.g. 'ThinkPad P50` #, c-format msgid "%s Corporate ME Update" -msgstr "%s ME-uppdatering för företag" +msgstr "%s Corporate ME-uppdatering" #. TRANSLATORS: a specific part of hardware, #. * the first %s is the device name, e.g. 'Unifying Receiver` @@ -56,7 +62,7 @@ msgstr "%s Enhetsuppdatering" #. * the first %s is the device name, e.g. 'ThinkPad P50` #, c-format msgid "%s Embedded Controller Update" -msgstr "%s Uppdatering av inbäddadkontroller" +msgstr "%s inbäddad styrenhetsuppdatering" #. TRANSLATORS: ME stands for Management Engine, the Intel AMT thing, #. * the first %s is the device name, e.g. 'ThinkPad P50` @@ -75,7 +81,7 @@ msgstr "%s Systemuppdatering" #. * the first %s is the system name, e.g. 'ThinkPad P50` #, c-format msgid "%s Thunderbolt Controller Update" -msgstr "Thunderbolt-kontrolleruppdatering för %s" +msgstr "%s Thunderbolt-styrenhetsuppdatering" #. TRANSLATORS: this is the fallback where we don't know if the release #. * is updating the system, the device, or a device class, or something else @@ -462,6 +468,7 @@ msgstr[1] "Skicka inte rapporter, och fråga aldrig om att skicka rapporter vid msgid "Do not write to the history database" msgstr "Skriv inte till historikdatabasen" +#. TRANSLATORS: success #. success msgid "Done!" msgstr "Klar!" @@ -506,6 +513,8 @@ msgstr "Aktivera stöd för uppdatering av fast programvara på system som stöd msgid "Enable this remote?" msgstr "Aktivera denna fjärr?" +#. TRANSLATORS: Suffix: the HSI result +#. TRANSLATORS: Plugin is active and in use #. TRANSLATORS: if the remote is enabled msgid "Enabled" msgstr "Aktiverad" @@ -544,10 +553,6 @@ msgstr "Avsluta efter att motorn har lästs in" msgid "Failed to connect to daemon" msgstr "Misslyckades med att ansluta till demon" -#. TRANSLATORS: the server is rate-limiting downloads -msgid "Failed to download due to server limit" -msgstr "Misslyckades med hämtning på grund av servergräns" - #. TRANSLATORS: we could not get the devices to update offline msgid "Failed to get pending devices" msgstr "Misslyckades med att hämta väntande enheter" @@ -580,22 +585,6 @@ msgstr "Misslyckades med att starta om" msgid "Failed to set splash mode" msgstr "Misslyckades med att sätta uppstartsläge" -#. TRANSLATORS: downloading unknown file -msgid "Fetching file" -msgstr "Hämtar fil" - -#. TRANSLATORS: downloading new firmware file -msgid "Fetching firmware" -msgstr "Hämtar fast programvara" - -#. TRANSLATORS: downloading new metadata file -msgid "Fetching metadata" -msgstr "Hämtar metainformation" - -#. TRANSLATORS: downloading new signing file -msgid "Fetching signature" -msgstr "Hämtar signatur" - #. TRANSLATORS: filename of the local file msgid "Filename" msgstr "Filnamn" @@ -641,6 +630,7 @@ msgstr "Uppdateringar av fast programvara stöds inte på denna maskin." msgid "Firmware updates are supported on this machine." msgstr "Uppdateringar av fast programvara stöds på denna maskin." +#. TRANSLATORS: description of plugin state, e.g. disabled #. TRANSLATORS: release properties msgid "Flags" msgstr "Flaggor" @@ -648,6 +638,10 @@ msgstr "Flaggor" msgid "Force the action ignoring all warnings" msgstr "Tvinga åtgärden, ignorera alla varningar" +#. TRANSLATORS: Suffix: the HSI result +msgid "Found" +msgstr "Hittad" + #. TRANSLATORS: global ID common to all similar hardware msgid "GUID" msgid_plural "GUIDs" @@ -678,10 +672,6 @@ msgstr "Hämtar detaljer om en fast programvarufil" msgid "Gets the configured remotes" msgstr "Ger de konfigurerade fjärrkällorna" -#. TRANSLATORS: firmware approved by the admin -msgid "Gets the list of approved firmware." -msgstr "Hämtar listan över godkänd fast programvara." - #. TRANSLATORS: command description msgid "Gets the list of updates for connected hardware" msgstr "Hämtar listan över uppdateringar för ansluten hårdvara" @@ -801,10 +791,6 @@ msgstr "Lista tillgänliga fastprogramvutyper" msgid "Loading…" msgstr "Läser in…" -#. TRANSLATORS: command line option -msgid "Manually whitelist specific plugins" -msgstr "Vitlista manuellt specifika insticksmoduler" - #. TRANSLATORS: remote URI msgid "Metadata Signature" msgstr "Metadatasignatur" @@ -826,10 +812,6 @@ msgstr "Minimiversion" msgid "Mismatched daemon and client, use %s instead" msgstr "Demon och klient stämmer inte, använd %s istället" -#. TRANSLATORS: sets something in daemon.conf -msgid "Modifies a daemon configuration value." -msgstr "Modifierar ett konfigurationsvärde för en demon." - #. TRANSLATORS: command description msgid "Modifies a given remote" msgstr "Modifierar en given fjärrkälla" @@ -856,6 +838,7 @@ msgstr "Kräver en nedstängning efter installation" msgid "New version" msgstr "Ny version" +#. TRANSLATORS: user did not tell the tool what to do msgid "No action specified!" msgstr "Ingen åtgärd angiven!" @@ -893,14 +876,14 @@ msgstr "Inga fjärrarkiv tillgängliga" msgid "No updates were applied" msgstr "Inga uppdateringar applicerades" +#. TRANSLATORS: Suffix: the HSI result +msgid "OK" +msgstr "OK" + #. TRANSLATORS: command line option msgid "Only show single PCR value" msgstr "Visa endast enkelt PCR-värde" -#. TRANSLATORS: command line option -msgid "Override plugin warning" -msgstr "Åsidosätt insticksmodulvarning" - #. TRANSLATORS: command line option msgid "Override the default ESP path" msgstr "Åsidosätt standardsökväg för ESP" @@ -983,10 +966,6 @@ msgstr "Startar om…" msgid "Refresh metadata from remote server" msgstr "Uppdatera metadata från fjärrserver" -#. TRANSLATORS: command description -msgid "Reinstall current firmware on the device." -msgstr "Återinstallera aktuell fastprogrmvara på enheten." - #. TRANSLATORS: the first replacement is a display name #. * e.g. "ColorHugALS" and the second is a version number #. * e.g. "1.2.3" @@ -1015,10 +994,6 @@ msgstr "Rapport-uri" msgid "Reported to remote server" msgstr "Rapporterade till fjärrserver" -#. TRANSLATORS: Must be plugged in to an outlet -msgid "Requires AC power" -msgstr "Kräver AC-ström" - #. TRANSLATORS: Requires a bootloader mode to be manually enabled by the user msgid "Requires a bootloader" msgstr "Kräver en starthanterare" @@ -1078,13 +1053,10 @@ msgstr "Serienummer" msgid "Set the debugging flag during update" msgstr "Ställ in felsökningsflaggan under uppdatering" +#. TRANSLATORS: firmware approved by the admin msgid "Sets the list of approved firmware" msgstr "Sätter listan av godkända fasta programvaror" -#. TRANSLATORS: firmware approved by the admin -msgid "Sets the list of approved firmware." -msgstr "Sätter listan över godkänd fast programvara." - #. TRANSLATORS: command description msgid "Share firmware history with the developers" msgstr "Dela fast programvaruhistorik med utvecklarna" @@ -1342,10 +1314,6 @@ msgstr "Uppdaterar %s…" msgid "Upgrade available for %s from %s to %s" msgstr "Uppgradering tillgänglig för %s från %s till %s" -#. TRANSLATORS: the server sent the user a small message -msgid "Upload message:" -msgstr "Uppladdningsmeddelande:" - msgid "Upload report just this one time, but prompt again for future updates" msgid_plural "Upload reports just this one time, but prompt again for future updates" msgstr[0] "Skicka rapport endast denna gång, men fråga igen vid framtida uppdateringar" @@ -1388,9 +1356,9 @@ msgstr "Tillverkare" msgid "Verifying…" msgstr "Verifierar…" -#. TRANSLATORS: try to help -msgid "WARNING: Ignoring SSL strict checks, to do this automatically in the future export DISABLE_SSL_STRICT in your environment" -msgstr "VARNING: Ignorerar strikta SSL-kontroller, för att göra detta automatiskt i framtiden, expotera DISABLE_SSL_STRICT i din miljö" +#. TRANSLATORS: the detected version number of the dbx +msgid "Version" +msgstr "Version" #. TRANSLATORS: waiting for device to do something msgid "Waiting…" diff --git a/po/tr.po b/po/tr.po index d74be8f4b..fb6d78b0c 100644 --- a/po/tr.po +++ b/po/tr.po @@ -5,7 +5,7 @@ # Translators: # Emin Tufan , 2020 # Muhammet Kara , 2016 -# Sabri Ünal , 2019 +# Sabri Ünal , 2019-2020 # Sabri Ünal , 2020 # Serdar Sağlam , 2020 msgid "" @@ -284,6 +284,10 @@ msgstr "Komut bulunamadı" msgid "Continue with update?" msgstr "Güncellemeye devam edilsin mi?" +#. TRANSLATORS: the release urgency +msgid "Critical" +msgstr "Kritik" + #. TRANSLATORS: version number of current firmware msgid "Current version" msgstr "Var olan sürüm" @@ -367,6 +371,7 @@ msgstr "Cihaz güvenlik kontrolleri yapma" msgid "Do not write to the history database" msgstr "Geçmişi veritabanına yazma" +#. TRANSLATORS: success #. success msgid "Done!" msgstr "Tamamlandı!" @@ -407,6 +412,8 @@ msgstr "Desteklenen sistemlerde ürün yazılımı güncelleme desteğini etkinl msgid "Enable this remote?" msgstr "Bu uzaktan kumanda etkinleştirilsin mi?" +#. TRANSLATORS: Suffix: the HSI result +#. TRANSLATORS: Plugin is active and in use #. TRANSLATORS: if the remote is enabled msgid "Enabled" msgstr "Etkinleştirildi" @@ -434,10 +441,6 @@ msgstr "Küçük bir gecikme sonrası çık" msgid "Failed to connect to daemon" msgstr "Artalan sürecine bağlanamadı" -#. TRANSLATORS: the server is rate-limiting downloads -msgid "Failed to download due to server limit" -msgstr "Sunucu sınırı nedeniyle indirilemedi" - #. TRANSLATORS: we could not get the devices to update offline msgid "Failed to get pending devices" msgstr "Bekleyen aygıtlar alınamadı" @@ -466,22 +469,6 @@ msgstr "Yeniden başlatılamadı" msgid "Failed to set splash mode" msgstr "Sıçrama kipi ayarlanamadı" -#. TRANSLATORS: downloading unknown file -msgid "Fetching file" -msgstr "Dosya alınıyor" - -#. TRANSLATORS: downloading new firmware file -msgid "Fetching firmware" -msgstr "Ürün yazılımı alınıyor" - -#. TRANSLATORS: downloading new metadata file -msgid "Fetching metadata" -msgstr "Üstveri alınıyor" - -#. TRANSLATORS: downloading new signing file -msgid "Fetching signature" -msgstr "İmza alınıyor" - #. TRANSLATORS: filename of the local file msgid "Filename" msgstr "Dosya adı" @@ -516,6 +503,7 @@ msgstr "Ürün yazılımı güncellemeleri bu makinede desteklenmiyor." msgid "Firmware updates are supported on this machine." msgstr "Ürün yazılımı güncellemeleri bu makinede destekleniyor." +#. TRANSLATORS: description of plugin state, e.g. disabled #. TRANSLATORS: release properties msgid "Flags" msgstr "Bayraklar" @@ -523,6 +511,10 @@ msgstr "Bayraklar" msgid "Force the action ignoring all warnings" msgstr "Eylemi tüm uyarıları görmezden gelmeye zorla" +#. TRANSLATORS: Suffix: the HSI result +msgid "Found" +msgstr "Bulundu" + #. TRANSLATORS: global ID common to all similar hardware msgid "GUID" msgid_plural "GUIDs" @@ -545,10 +537,6 @@ msgstr "Etkinleştirilmiş tüm eklentileri sisteme kaydettir" msgid "Gets details about a firmware file" msgstr "Ürün yazılımı dosyasıyla ilgili ayrıntıları al" -#. TRANSLATORS: firmware approved by the admin -msgid "Gets the list of approved firmware." -msgstr "Onaylı ürün yazılımı listesini getirir." - #. TRANSLATORS: command description msgid "Gets the list of updates for connected hardware" msgstr "Bağlı donanım için güncelleme listesini al" @@ -565,6 +553,10 @@ msgstr "Son güncellemeden sonuçları alır" msgid "Hardware is waiting to be replugged" msgstr "Donanım yeniden takılmayı bekliyor" +#. TRANSLATORS: the release urgency +msgid "High" +msgstr "Yüksek" + #. TRANSLATORS: daemon is inactive msgid "Idle…" msgstr "Boşta…" @@ -648,9 +640,13 @@ msgstr "Kullanılabilir ürün yazılımı türlerini listele" msgid "Loading…" msgstr "Yükleniyor…" -#. TRANSLATORS: command line option -msgid "Manually whitelist specific plugins" -msgstr "El ile beyaz listeye özel eklentiler" +#. TRANSLATORS: the release urgency +msgid "Low" +msgstr "Düşük" + +#. TRANSLATORS: the release urgency +msgid "Medium" +msgstr "Orta" #. TRANSLATORS: remote URI msgid "Metadata Signature" @@ -673,10 +669,6 @@ msgstr "Asgari Sürüm" msgid "Mismatched daemon and client, use %s instead" msgstr "Artalan süreci ile istemci uyuşmadı, bunun yerine %s kullanın" -#. TRANSLATORS: sets something in daemon.conf -msgid "Modifies a daemon configuration value." -msgstr "Artalan süreci yapılandırma değerini değiştir." - msgid "Modify a configured remote" msgstr "Uzak yapılandırmayı değiştir" @@ -691,6 +683,7 @@ msgstr "Olaylar için artalan sürecini gözetle" msgid "New version" msgstr "Yeni sürüm" +#. TRANSLATORS: user did not tell the tool what to do msgid "No action specified!" msgstr "Eylem belirtilmedi!" @@ -722,14 +715,14 @@ msgstr "Uzaktan kumanda bulunamadı" msgid "No updates were applied" msgstr "Güncelleme uygulanmadı" +#. TRANSLATORS: Suffix: the HSI result +msgid "OK" +msgstr "Tamam" + #. TRANSLATORS: command line option msgid "Only show single PCR value" msgstr "Yalnızca tek PCR değerini göster" -#. TRANSLATORS: command line option -msgid "Override plugin warning" -msgstr "Eklenti uyarısını geçersiz yap" - #. TRANSLATORS: command line option msgid "Override the default ESP path" msgstr "Öntanımlı ESP yolunu geçersiz kıl" @@ -818,10 +811,6 @@ msgstr "Rapor URI" msgid "Reported to remote server" msgstr "Uzak sunucuya bildirildi" -#. TRANSLATORS: Must be plugged in to an outlet -msgid "Requires AC power" -msgstr "AC güç gerekli" - #. TRANSLATORS: metadata is downloaded from the Internet msgid "Requires internet connection" msgstr "İnternet bağlantısı gerektirir" @@ -858,13 +847,10 @@ msgstr "Seri Numarası" msgid "Set the debugging flag during update" msgstr "Güncelleme sırasında hata ayıklama bayrağını ayarla" +#. TRANSLATORS: firmware approved by the admin msgid "Sets the list of approved firmware" msgstr "Onaylı ürün yazılımı listesini ayarlar" -#. TRANSLATORS: firmware approved by the admin -msgid "Sets the list of approved firmware." -msgstr "Onaylı ürün yazılımı listesini ayarlar." - #. TRANSLATORS: command description msgid "Share firmware history with the developers" msgstr "Ürün yazılım geçmişini geliştiricilerle paylaş" @@ -1073,17 +1059,13 @@ msgstr "Tüm ürün yazılımlarını mevcut en son sürümlere güncelle" msgid "Updating %s…" msgstr "Güncelleniyor %s…" -#. TRANSLATORS: the server sent the user a small message -msgid "Upload message:" -msgstr "İleti yükle:" - #. TRANSLATORS: ask the user to upload msgid "Upload report now?" msgstr "Rapor şimdi karşıya yüklensin mi?" #. TRANSLATORS: command line option msgid "Use quirk flags when installing firmware" -msgstr "ürün yazılımı kurulurken quirk bayraklarını kullan" +msgstr "Ürün yazılımı kurulurken quirk bayraklarını kullan" #. TRANSLATORS: User has been notified msgid "User has been notified" @@ -1105,6 +1087,10 @@ msgstr "Üretici" msgid "Verifying…" msgstr "Doğrulanıyor…" +#. TRANSLATORS: the detected version number of the dbx +msgid "Version" +msgstr "Sürüm" + #. TRANSLATORS: waiting for device to do something msgid "Waiting…" msgstr "Bekliyor…" @@ -1136,16 +1122,3 @@ msgstr "Hizmet sağlayıcınız, sisteminizle veya bağlı aygıtlarla uyumluluk #. TRANSLATORS: program name msgid "fwupd TPM event log utility" msgstr "fwupd TPM olay günlüğü yardımcı aracı" - -#. TRANSLATORS: message letting the user know no device upgrade available due -#. to missing on LVFS -#. * %1 is the device name -#, c-format -msgid "• %s has no available firmware updates" -msgstr "• %s için mevcut ürün yazılımı güncellemesi yok" - -#. TRANSLATORS: message letting the user know no device upgrade available -#. * %1 is the device name -#, c-format -msgid "• %s has the latest available firmware version" -msgstr "• %s en son ürün yazılımı sürümüne sahip" diff --git a/po/uk.po b/po/uk.po index de9227402..143b95259 100644 --- a/po/uk.po +++ b/po/uk.po @@ -30,6 +30,12 @@ msgstr[3] "Лишилася %.0f хвилина" msgid "%s CPU Microcode Update" msgstr "Оновлення мікропрограми процесора %s" +#. TRANSLATORS: a specific part of hardware, +#. * the first %s is the device name, e.g. 'Secure Boot` +#, c-format +msgid "%s Configuration Update" +msgstr "Оновлення налаштувань %s" + #. TRANSLATORS: ME stands for Management Engine, where #. * the first %s is the device name, e.g. 'ThinkPad P50` #, c-format @@ -93,6 +99,11 @@ msgstr "Оновлення для %s" msgid "%s and all connected devices may not be usable while updating." msgstr "%s і усі з'єднані пристрою можуть бути недоступними протягом оновлення." +#. TRANSLATORS: Title: %s is ME kind, e.g. CSME/TXT +#, c-format +msgid "%s manufacturing mode" +msgstr "Режим виробництва %s" + #. TRANSLATORS: warn the user before updating, %1 is a device name #, c-format msgid "%s must remain connected for the duration of the update to avoid damage." @@ -103,6 +114,21 @@ msgstr "Для уникнення пошкоджень %s має лишатис msgid "%s must remain plugged into a power source for the duration of the update to avoid damage." msgstr "Для уникнення пошкоджень %s має лишатися з'єднаним із джерелом живлення протягом оновлення." +#. TRANSLATORS: Title: %s is ME kind, e.g. CSME/TXT +#, c-format +msgid "%s override" +msgstr "Перевизначення %s" + +#. TRANSLATORS: Title: %1 is ME kind, e.g. CSME/TXT, %2 is a version number +#, c-format +msgid "%s v%s" +msgstr "%s, версія %s" + +#. TRANSLATORS: Title: %s is ME kind, e.g. CSME/TXT +#, c-format +msgid "%s version" +msgstr "Версія %s" + #. TRANSLATORS: duration in days! #, c-format msgid "%u day" @@ -156,6 +182,10 @@ msgstr[1] "%u секунди" msgstr[2] "%u секунд" msgstr[3] "%u секунда" +#. TRANSLATORS: this is shown as a suffix for obsoleted tests +msgid "(obsoleted)" +msgstr "(є застарілим)" + #. TRANSLATORS: command description msgid "Activate devices" msgstr "Задіяти пристрої" @@ -200,6 +230,10 @@ msgstr "Дозволити зниження версій мікропрогра msgid "Allow reinstalling existing firmware versions" msgstr "Дозволити перевстановлення наявних версій мікропрограми" +#. TRANSLATORS: command line option +msgid "Allow switching firmware branch" +msgstr "Дозволити перемикання гілок мікропрограми" + #. TRANSLATORS: explain why we want to reboot msgid "An update requires a reboot to complete." msgstr "Для завершення оновлення слід перезавантажити систему." @@ -216,6 +250,18 @@ msgstr "Відповідати «так» на усі питання" msgid "Apply firmware updates" msgstr "Застосувати оновлення мікропрограми" +#. TRANSLATORS: command line option +msgid "Apply update even when not advised" +msgstr "Застосувати оновлення, навіть якщо воно не є рекомендованим" + +#. TRANSLATORS: command line option +msgid "Apply update files" +msgstr "Застосувати файли оновлень" + +#. TRANSLATORS: actually sending the update to the hardware +msgid "Applying update…" +msgstr "Застосовуємо оновлення…" + #. TRANSLATORS: approved firmware has been checked by #. * the domain administrator msgid "Approved firmware:" @@ -225,6 +271,10 @@ msgstr[1] "Схвалені мікропрограми:" msgstr[2] "Схвалені мікропрограми:" msgstr[3] "Схвалена мікропрограма:" +#. TRANSLATORS: stop nagging the user +msgid "Ask again next time?" +msgstr "Питати знову наступного разу?" + #. TRANSLATORS: command description msgid "Attach to firmware mode" msgstr "Долучитися до режиму мікропрограми" @@ -281,10 +331,38 @@ msgstr "Щоб отримати доступ до оновлення збере msgid "Automatic Reporting" msgstr "Автоматичне звітування" +#. TRANSLATORS: can we JFDI? +msgid "Automatically upload every time?" +msgstr "Автоматично вивантажувати кожного разу?" + +#. TRANSLATORS: command description +msgid "Bind new kernel driver" +msgstr "Пов'язати новий драйвер ядра" + +#. TRANSLATORS: there follows a list of hashes +msgid "Blocked firmware files:" +msgstr "Заблоковані файли мікропрограм:" + +#. TRANSLATORS: we will not offer this firmware to the user +msgid "Blocking firmware:" +msgstr "Блокуємо мікропрограму:" + +#. TRANSLATORS: command description +msgid "Blocks a specific firmware from being installed" +msgstr "Блокує встановлення певної мікропрограми" + #. TRANSLATORS: firmware version of bootloader msgid "Bootloader Version" msgstr "Версія завантажувача" +#. TRANSLATORS: the stream of firmware, e.g. nonfree or open-source +msgid "Branch" +msgstr "Гілка" + +#. TRANSLATORS: command description +msgid "Build a firmware file" +msgstr "Зібрати файл мікропрограми" + #. TRANSLATORS: command description msgid "Build firmware using a sandbox" msgstr "Зібрати мікропрограму за допомогою пісочниці" @@ -297,6 +375,14 @@ msgstr "Скасувати" msgid "Cancelled" msgstr "Скасовано" +#. TRANSLATORS: same or newer update already applied +msgid "Cannot apply as dbx update has already been applied." +msgstr "Не вдалося застосувати, оскільки оновлення dbx вже застосовано." + +#. TRANSLATORS: the user is using a LiveCD or LiveUSB install disk +msgid "Cannot apply updates on live media" +msgstr "Не можна застосовувати оновлення до портативного носія" + #. TRANSLATORS: this is when a device is hotplugged #. TRANSLATORS: this is when the daemon state changes msgid "Changed" @@ -310,6 +396,11 @@ msgstr "Перевірити відповідність криптографіч msgid "Checksum" msgstr "Контрольна сума" +#. TRANSLATORS: get interactive prompt, where branch is the +#. * supplier of the firmware, e.g. "non-free" or "free" +msgid "Choose a branch:" +msgstr "Виберіть гілку:" + #. TRANSLATORS: get interactive prompt msgid "Choose a device:" msgstr "Виберіть пристрій:" @@ -322,6 +413,10 @@ msgstr "Виберіть тип мікропрограми:" msgid "Choose a release:" msgstr "Виберіть випуск:" +#. TRANSLATORS: get interactive prompt +msgid "Choose a volume:" +msgstr "Виберіть том:" + #. TRANSLATORS: command description msgid "Clears any updates scheduled to be updated offline" msgstr "Спорожняє список усіх оновлень, які заплановано для автономного режиму" @@ -426,10 +521,18 @@ msgstr "Вилучено пристрій:" msgid "Device stages updates" msgstr "Пристрій із покроковим оновленням" +#. TRANSLATORS: there is more than one supplier of the firmware +msgid "Device supports switching to a different branch of firmware" +msgstr "У пристрої передбачено підтримку перемикання на іншу гілку мікропрограми" + #. TRANSLATORS: Device update needs to be separately activated msgid "Device update needs activation" msgstr "Оновлення пристрою потребує активації" +#. TRANSLATORS: save the old firmware to disk before installing the new one +msgid "Device will backup firmware before installing" +msgstr "Пристрій створить резервну копію мікропрограми перед встановленням" + #. TRANSLATORS: Device will not return after update completes msgid "Device will not re-appear after update completes" msgstr "Пристрій не з'явиться у списку пристроїв після завершення оновлення" @@ -442,6 +545,20 @@ msgstr "Пристрої, для яких вдалося успішно онов msgid "Devices that were not updated correctly:" msgstr "Пристрої, для яких не вдалося оновити дані належним чином:" +#. TRANSLATORS: message letting the user know no device upgrade available due +#. to missing on LVFS +msgid "Devices with no available firmware updates: " +msgstr "Пристрої, для яких немає оновлень мікропрограми:" + +#. TRANSLATORS: message letting the user know no device upgrade available +msgid "Devices with the latest available firmware version:" +msgstr "Пристрої із найсвіжішою доступною версією мікропрограми:" + +#. TRANSLATORS: Suffix: the HSI result +#. TRANSLATORS: Plugin is inactive and not used +msgid "Disabled" +msgstr "Вимкнено" + msgid "Disabled fwupdate debugging" msgstr "Вимкнено діагностику fwupdate" @@ -495,6 +612,11 @@ msgstr[3] "Не вивантажувати звіти цього разу і н msgid "Do not write to the history database" msgstr "Не записувати дані до бази даних журналу" +#. TRANSLATORS: should the branch be changed +msgid "Do you understand the consequences of changing the firmware branch?" +msgstr "Чи розумієте ви наслідки зміни гілки мікропрограми?" + +#. TRANSLATORS: success #. success msgid "Done!" msgstr "Виконано!" @@ -539,6 +661,8 @@ msgstr "Увімкнути підтримку оновлення мікропр msgid "Enable this remote?" msgstr "Увімкнути це віддалене сховище?" +#. TRANSLATORS: Suffix: the HSI result +#. TRANSLATORS: Plugin is active and in use #. TRANSLATORS: if the remote is enabled msgid "Enabled" msgstr "Увімкнено" @@ -557,6 +681,14 @@ msgstr "Наслідки вмикання цієї можливості покл msgid "Enabling this remote is done at your own risk." msgstr "Вмикання цього віддаленого сховища виконано під вашу відповідальність." +#. TRANSLATORS: Suffix: the HSI result +msgid "Encrypted" +msgstr "Зашировано" + +#. TRANSLATORS: Title: Memory contents are encrypted, e.g. Intel TME +msgid "Encrypted RAM" +msgstr "Шифрована пам'ять" + #. TRANSLATORS: command description msgid "Erase all firmware update history" msgstr "Витерти увесь журнал оновлень мікропрограми" @@ -573,13 +705,25 @@ msgstr "Завершити роботу з невеличкою затримко msgid "Exit after the engine has loaded" msgstr "Завершити роботу після завантаження рушія" +#. TRANSLATORS: command description +msgid "Extract a firmware blob to images" +msgstr "Видобувати бінарну мікропрограму до образів" + +#. TRANSLATORS: Suffix: the fallback HSI result +msgid "Failed" +msgstr "Помилка" + +#. TRANSLATORS: dbx file failed to be applied as an update +msgid "Failed to apply update" +msgstr "Не вдалося застосувати оновлення" + #. TRANSLATORS: we could not talk to the fwupd daemon msgid "Failed to connect to daemon" msgstr "Не вдалося встановити з'єднання із фоновою службою" -#. TRANSLATORS: the server is rate-limiting downloads -msgid "Failed to download due to server limit" -msgstr "Не вдалося отримати через обмеження сервера" +#. TRANSLATORS: could not parse file +msgid "Failed to extract local dbx " +msgstr "Не вдалося видобути локальний dbx" #. TRANSLATORS: we could not get the devices to update offline msgid "Failed to get pending devices" @@ -589,10 +733,19 @@ msgstr "Не вдалося отримати список пристроїв у msgid "Failed to install firmware update" msgstr "Не вдалося встановити оновлення мікропрограми" +#. TRANSLATORS: could not read existing system data +#. TRANSLATORS: could not read file +msgid "Failed to load local dbx" +msgstr "Не вдалося завантажити локальний dbx" + #. TRANSLATORS: quirks are device-specific workarounds msgid "Failed to load quirks" msgstr "Не вдалося завантажити коригування" +#. TRANSLATORS: could not read existing system data +msgid "Failed to load system dbx" +msgstr "Не вдалося завантажити системний dbx" + #. TRANSLATORS: the user didn't read the man page msgid "Failed to parse arguments" msgstr "Не вдалося обробити аргументи" @@ -605,6 +758,10 @@ msgstr "Не вдалося обробити файл" msgid "Failed to parse flags for --filter" msgstr "Не вдалося обробити прапорці до --filter" +#. TRANSLATORS: could not parse file +msgid "Failed to parse local dbx" +msgstr "Не вдалося обробити локальний dbx" + #. TRANSLATORS: we could not reboot for some reason msgid "Failed to reboot" msgstr "Не вдалося перезавантажити" @@ -613,21 +770,10 @@ msgstr "Не вдалося перезавантажити" msgid "Failed to set splash mode" msgstr "Не вдалося встановити режим вітання" -#. TRANSLATORS: downloading unknown file -msgid "Fetching file" -msgstr "Отримуємо файл" - -#. TRANSLATORS: downloading new firmware file -msgid "Fetching firmware" -msgstr "Отримуємо мікропрограму" - -#. TRANSLATORS: downloading new metadata file -msgid "Fetching metadata" -msgstr "Отримуємо метадані" - -#. TRANSLATORS: downloading new signing file -msgid "Fetching signature" -msgstr "Отримуємо підпис" +#. TRANSLATORS: something with a blocked hash exists +#. * in the users ESP -- which would be bad! +msgid "Failed to validate ESP contents" +msgstr "Не вдалося встановити чинність даних ESP" #. TRANSLATORS: filename of the local file msgid "Filename" @@ -637,6 +783,10 @@ msgstr "Назва файла" msgid "Filename Signature" msgstr "Підпис назви файла" +#. TRANSLATORS: user did not include a filename parameter +msgid "Filename required" +msgstr "Слід вказати назву файла" + #. TRANSLATORS: command line option msgid "Filter with a set of device flags using a ~ prefix to exclude, e.g. 'internal,~needs-reboot'" msgstr "Фільтрувати за набором прапорців пристроїв за допомогою префікса виключення ~, наприклад «internal,~needs-reboot»" @@ -661,6 +811,22 @@ msgstr "Служба оновлення мікропрограми" msgid "Firmware Utility" msgstr "Засіб роботи з мікропрограмами" +#. TRANSLATORS: Title: if we can verify the firmware checksums +msgid "Firmware attestation" +msgstr "Засвідчення мікропрограми" + +#. TRANSLATORS: system is not booted in UEFI mode +msgid "Firmware can not be updated in legacy BIOS mode" +msgstr "У режимі сумісності із застарілим BIOS не можна оновити мікропрограму" + +#. TRANSLATORS: user selected something not possible +msgid "Firmware is already blocked" +msgstr "Мікропрограму вже заблоковано" + +#. TRANSLATORS: user selected something not possible +msgid "Firmware is not already blocked" +msgstr "Мікропрограму ще не заблоковано" + #. TRANSLATORS: the metadata is very out of date; %u is a number > 1 #, c-format msgid "Firmware metadata has not been updated for %u day and may not be up to date." @@ -670,19 +836,36 @@ msgstr[1] "Метадані мікропрограми не оновлювали msgstr[2] "Метадані мікропрограми не оновлювалися %u днів, можливо, вони вже не є актуальними." msgstr[3] "Метадані мікропрограми не оновлювалися %u днів, можливо, вони вже не є актуальними." +#. TRANSLATORS: Title: if firmware updates are available +msgid "Firmware updates" +msgstr "Оновлення мікропрограми" + msgid "Firmware updates are not supported on this machine." msgstr "На цьому комп'ютері не передбачено підтримки оновлення мікропрограми." msgid "Firmware updates are supported on this machine." msgstr "На цьому комп'ютері передбачено підтримку оновлень мікропрограми." +#. TRANSLATORS: user needs to run a command +msgid "Firmware updates disabled; run 'fwupdmgr unlock' to enable" +msgstr "Оновлення мікропрограми вимкнено; віддайте команду 'fwupdmgr unlock', щоб їх увімкнути" + +#. TRANSLATORS: description of plugin state, e.g. disabled #. TRANSLATORS: release properties msgid "Flags" msgstr "Прапорці" +#. TRANSLATORS: command line option +msgid "Force the action by relaxing some runtime checks" +msgstr "Виконати дію примусово шляхом послаблення деяких перевірок під час виконання" + msgid "Force the action ignoring all warnings" msgstr "Виконати дію примусово, ігноруючи усі попередження" +#. TRANSLATORS: Suffix: the HSI result +msgid "Found" +msgstr "Знайдено" + #. TRANSLATORS: global ID common to all similar hardware msgid "GUID" msgid_plural "GUIDs" @@ -715,9 +898,17 @@ msgstr "Отримати параметри файла мікропрограм msgid "Gets the configured remotes" msgstr "Отримує налаштовані віддалені пристрої" +#. TRANSLATORS: command description +msgid "Gets the host security attributes" +msgstr "Отримує атрибути захисту основної системи" + #. TRANSLATORS: firmware approved by the admin -msgid "Gets the list of approved firmware." -msgstr "Отримує список схвалених мікропрограм." +msgid "Gets the list of approved firmware" +msgstr "Отримує список схвалених мікропрограм" + +#. TRANSLATORS: command description +msgid "Gets the list of blocked firmware" +msgstr "Отримує список заблокованих мікропрограм" #. TRANSLATORS: command description msgid "Gets the list of updates for connected hardware" @@ -739,6 +930,15 @@ msgstr "Обладнання очікує на повторне з'єднанн msgid "High" msgstr "Високий" +#. TRANSLATORS: this is a string like 'HSI:2-U' +msgid "Host Security ID:" +msgstr "Ід. захисту основної системи:" + +#. TRANSLATORS: Title: +#. https://en.wikipedia.org/wiki/Input%E2%80%93output_memory_management_unit +msgid "IOMMU" +msgstr "IOMMU" + #. TRANSLATORS: daemon is inactive msgid "Idle…" msgstr "Бездіяльність…" @@ -747,10 +947,26 @@ msgstr "Бездіяльність…" msgid "Ignore SSL strict checks when downloading files" msgstr "Ігнорувати результати строгої перевірки SSL під час отримання файлів" +#. TRANSLATORS: command line option +msgid "Ignore firmware checksum failures" +msgstr "Ігнорувати помилки при перевірці контрольної суми мікропрограми" + +#. TRANSLATORS: command line option +msgid "Ignore firmware hardware mismatch failures" +msgstr "Ігнорувати помилки, пов'язані із невідповідністю обладнання мікропрограмі" + +#. TRANSLATORS: command line option +msgid "Ignore requirement of external power source" +msgstr "Ігнорувати вимогу щодо наявності зовнішнього джерела живлення" + #. TRANSLATORS: Ignore validation safety checks when flashing this device msgid "Ignore validation safety checks" msgstr "Ігнорувати перевірки безпечності" +#. TRANSLATORS: try to help +msgid "Ignoring SSL strict checks, to do this automatically in the future export DISABLE_SSL_STRICT in your environment" +msgstr "Ігноруємо строгі перевірки SSL. Щоб зробити ігнорування у майбутньому автоматичним, експортуйте до вашого середовища змінну DISABLE_SSL_STRICT" + #. TRANSLATORS: length of time the update takes to apply msgid "Install Duration" msgstr "Тривалість встановлення" @@ -795,10 +1011,57 @@ msgstr "Встановлюємо оновлення мікропрограми msgid "Installing on %s…" msgstr "Встановлюємо на %s…" +#. TRANSLATORS: Title: BootGuard is a trademark from Intel +msgid "Intel BootGuard" +msgstr "Intel BootGuard" + +#. TRANSLATORS: Title: BootGuard is a trademark from Intel, +#. * ACM means to verify the integrity of Initial Boot Block +msgid "Intel BootGuard ACM protected" +msgstr "Intel BootGuard захищено ACM" + +#. TRANSLATORS: Title: BootGuard is a trademark from Intel, +#. * OTP = one time programmable +msgid "Intel BootGuard OTP fuse" +msgstr "OTP FUSE Intel BootGuard" + +#. TRANSLATORS: Title: BootGuard is a trademark from Intel, +#. * error policy is what to do on failure +msgid "Intel BootGuard error policy" +msgstr "Правила обробки помилок Intel BootGuard" + +#. TRANSLATORS: Title: BootGuard is a trademark from Intel, +#. * verified boot refers to the way the boot process is verified +msgid "Intel BootGuard verified boot" +msgstr "Перевірене завантаження Intel BootGuard" + +#. TRANSLATORS: Title: CET = Control-flow Enforcement Technology, +#. * active means being used by the OS +msgid "Intel CET Active" +msgstr "Активна Intel CET" + +#. TRANSLATORS: Title: CET = Control-flow Enforcement Technology, +#. * enabled means supported by the processor +msgid "Intel CET Enabled" +msgstr "Увімкнено Intel CET" + +#. TRANSLATORS: Title: Direct Connect Interface (DCI) allows +#. * debugging of Intel processors using the USB3 port +msgid "Intel DCI debugger" +msgstr "Діагностика DCI Intel" + +#. TRANSLATORS: Title: SMAP = Supervisor Mode Access Prevention +msgid "Intel SMAP" +msgstr "Intel SMAP" + #. TRANSLATORS: Device cannot be removed easily msgid "Internal device" msgstr "Внутрішній пристрій" +#. TRANSLATORS: Suffix: the HSI result +msgid "Invalid" +msgstr "Некоректна" + #. TRANSLATORS: Is currently in bootloader mode msgid "Is in bootloader mode" msgstr "Перебуває у режимі завантажувача" @@ -832,6 +1095,22 @@ msgstr "Служба надання мікропрограм для Linux від msgid "Linux Vendor Firmware Service (testing firmware)" msgstr "Служба надання мікропрограм для Linux від виробника (тестова мікропрограма)" +#. TRANSLATORS: Title: if it's tainted or not +msgid "Linux kernel" +msgstr "Ядро Linux" + +#. TRANSLATORS: Title: lockdown is a security mode of the kernel +msgid "Linux kernel lockdown" +msgstr "Блокування ядра Linux" + +#. TRANSLATORS: Title: swap space or swap partition +msgid "Linux swap" +msgstr "Рез. пам'ять Linux" + +#. TRANSLATORS: command line option +msgid "List entries in dbx" +msgstr "Вивести список записів у dbx" + #. TRANSLATORS: command line option msgid "List supported firmware updates" msgstr "Показати список підтримуваних оновлень мікропрограми" @@ -840,17 +1119,39 @@ msgstr "Показати список підтримуваних оновлен msgid "List the available firmware types" msgstr "Вивести список доступних типів мікропрограм" +#. TRANSLATORS: command description +msgid "Lists files on the ESP" +msgstr "Виводить список файлів у ESP" + #. TRANSLATORS: parsing the firmware information msgid "Loading…" msgstr "Завантаження…" +#. TRANSLATORS: Suffix: the HSI result +msgid "Locked" +msgstr "Заблоковано" + #. TRANSLATORS: the release urgency msgid "Low" msgstr "Низький" +#. TRANSLATORS: Title: MEI = Intel Management Engine +msgid "MEI manufacturing mode" +msgstr "Режим виробництва MEI" + +#. TRANSLATORS: Title: MEI = Intel Management Engine, and the +#. * "override" is the physical PIN that can be driven to +#. * logic high -- luckily it is probably not accessible to +#. * end users on consumer boards +msgid "MEI override" +msgstr "Перевизначення MEI" + +msgid "MEI version" +msgstr "Версія MEI" + #. TRANSLATORS: command line option -msgid "Manually whitelist specific plugins" -msgstr "Вручну додати певні додатки до «білого» списку" +msgid "Manually enable specific plugins" +msgstr "Увімкнути певні додатки вручну" #. TRANSLATORS: the release urgency msgid "Medium" @@ -878,8 +1179,8 @@ msgid "Mismatched daemon and client, use %s instead" msgstr "Невідповідність фонової служби і клієнта, скористайтеся краще %s" #. TRANSLATORS: sets something in daemon.conf -msgid "Modifies a daemon configuration value." -msgstr "Змінює значення налаштування фонової служби." +msgid "Modifies a daemon configuration value" +msgstr "Змінює значення налаштувань фонової служби" #. TRANSLATORS: command description msgid "Modifies a given remote" @@ -895,6 +1196,10 @@ msgstr "Зміна налаштувань фонової служби" msgid "Monitor the daemon for events" msgstr "Стежити за подіями у фоновій службі" +#. TRANSLATORS: command description +msgid "Mounts the ESP" +msgstr "Монтує ESP" + #. TRANSLATORS: Requires a reboot to apply firmware or to reload hardware msgid "Needs a reboot after installation" msgstr "Потребує перезавантаження після встановлення" @@ -907,6 +1212,7 @@ msgstr "Потребує вимикання після встановлення" msgid "New version" msgstr "Нова версія" +#. TRANSLATORS: user did not tell the tool what to do msgid "No action specified!" msgstr "Не вказано дії!" @@ -944,14 +1250,22 @@ msgstr "Немає доступних віддалених сховищ" msgid "No updates were applied" msgstr "Не застосовано жодного оновлення" +#. TRANSLATORS: Suffix: the HSI result +msgid "Not found" +msgstr "Не знайдено" + +#. TRANSLATORS: Suffix: the HSI result +msgid "Not supported" +msgstr "Немає підтримки" + +#. TRANSLATORS: Suffix: the HSI result +msgid "OK" +msgstr "Гаразд" + #. TRANSLATORS: command line option msgid "Only show single PCR value" msgstr "Показувати лише одне значення PCR" -#. TRANSLATORS: command line option -msgid "Override plugin warning" -msgstr "Перевизначити попередження для додатка" - #. TRANSLATORS: command line option msgid "Override the default ESP path" msgstr "Перевизначити типовий шлях до ESP" @@ -964,6 +1278,14 @@ msgstr "Не зважати на попередження і примусово msgid "Parse and show details about a firmware file" msgstr "Обробити і показати параметри файла мікропрограми" +#. TRANSLATORS: reading new dbx from the update +msgid "Parsing dbx update…" +msgstr "Обробляємо оновлення dbx…" + +#. TRANSLATORS: reading existing dbx from the system +msgid "Parsing system dbx…" +msgstr "Обробляємо системний dbx…" + #. TRANSLATORS: remote filename base msgid "Password" msgstr "Пароль" @@ -980,6 +1302,14 @@ msgstr "Відсоток виконання" msgid "Please enter a number from 0 to %u: " msgstr "Будь ласка, введіть число від 0 до %u: " +#. TRANSLATORS: Failed to open plugin, hey Arch users +msgid "Plugin dependencies missing" +msgstr "Не встановлено залежності додатка" + +#. TRANSLATORS: Title: DMA as in https://en.wikipedia.org/wiki/DMA_attack +msgid "Pre-boot DMA protection" +msgstr "Захист DMA до завантаження" + #. TRANSLATORS: version number of previous firmware msgid "Previous version" msgstr "Попередня версія" @@ -1035,8 +1365,8 @@ msgid "Refresh metadata from remote server" msgstr "Оновити метадані з віддаленого сервера" #. TRANSLATORS: command description -msgid "Reinstall current firmware on the device." -msgstr "Повторно встановити поточну мікропрограму на пристрій." +msgid "Reinstall current firmware on the device" +msgstr "Повторно встановити мікропрограму на пристрій" #. TRANSLATORS: command description msgid "Reinstall firmware on a device" @@ -1070,9 +1400,13 @@ msgstr "Адреса звіту" msgid "Reported to remote server" msgstr "Повідомлено на віддаленому сервері" -#. TRANSLATORS: Must be plugged in to an outlet -msgid "Requires AC power" -msgstr "Потребує сталого живлення" +#. TRANSLATORS: the user is using Gentoo/Arch and has screwed something up +msgid "Required efivarfs filesystem was not found" +msgstr "Не знайдено відповідної файлової системи efivarfs" + +#. TRANSLATORS: not required for this system +msgid "Required hardware was not found" +msgstr "Не знайдено відповідного обладнання" #. TRANSLATORS: Requires a bootloader mode to be manually enabled by the user msgid "Requires a bootloader" @@ -1109,6 +1443,22 @@ msgstr "Запустити процедуру чищення композиці msgid "Run the plugin composite prepare routine when using install-blob" msgstr "Запустити процедуру приготування композиції додатків при використанні install-blob" +#. TRANSLATORS: this is the HSI suffix +msgid "Runtime Suffix" +msgstr "Динамічний суфікс" + +#. TRANSLATORS: Title: SPI refers to the flash chip in the computer +msgid "SPI BIOS region" +msgstr "Регіон BIOS SPI" + +#. TRANSLATORS: Title: SPI refers to the flash chip in the computer +msgid "SPI lock" +msgstr "Блокування SPI" + +#. TRANSLATORS: Title: SPI refers to the flash chip in the computer +msgid "SPI write" +msgstr "Запис SPI" + #. TRANSLATORS: command line option msgid "Save device state into a JSON file between executions" msgstr "Зберігати стан пристрою до файла JSON між виконаннями" @@ -1125,6 +1475,10 @@ msgstr "Плануємо…" msgid "Selected device" msgstr "Вибрано пристрій" +#. TRANSLATORS: Volume has been chosen by the user +msgid "Selected volume" +msgstr "Вибраний том" + #. TRANSLATORS: serial number of hardware msgid "Serial Number" msgstr "Серійний номер" @@ -1133,17 +1487,18 @@ msgstr "Серійний номер" msgid "Set the debugging flag during update" msgstr "Встановити під час оновлення прапорець діагностики" +#. TRANSLATORS: firmware approved by the admin msgid "Sets the list of approved firmware" msgstr "Встановлення списку схвалених мікропрограм" -#. TRANSLATORS: firmware approved by the admin -msgid "Sets the list of approved firmware." -msgstr "Встановлює список схвалених мікропрограм." - #. TRANSLATORS: command description msgid "Share firmware history with the developers" msgstr "Поділитися журналом оновлень із розробниками" +#. TRANSLATORS: command line option +msgid "Show all results" +msgstr "Показати усі результати" + #. TRANSLATORS: command line option msgid "Show client and daemon versions" msgstr "Вивести дані щодо версій клієнат і фонової служби" @@ -1176,6 +1531,10 @@ msgstr "Показати журнал оновлень мікропрограм msgid "Show plugin verbose information" msgstr "Показати докладні відомості щодо додатків" +#. TRANSLATORS: command line option +msgid "Show the calculated version of the dbx" +msgstr "Вивести обчислену версію dbx" + #. TRANSLATORS: command line option msgid "Show the debug log from the last attempted update" msgstr "Показати діагностичний журнал щодо останньої спроби оновлення" @@ -1213,6 +1572,10 @@ msgstr "Джерело" msgid "Specify Vendor/Product ID(s) of DFU device" msgstr "Вказати ідентифікатори виробника/продукту пристрою DFU" +#. TRANSLATORS: command line option +msgid "Specify the dbx database file" +msgstr "Вказати файл бази даних dbx" + msgid "Specify the number of bytes per USB transfer" msgstr "Вказати кількість байтів на один пакет передавання даних USB" @@ -1272,10 +1635,42 @@ msgstr "Успішно перевірено контрольні суми при msgid "Summary" msgstr "Резюме" +#. TRANSLATORS: Suffix: the HSI result +msgid "Supported" +msgstr "Є підтримка" + #. TRANSLATORS: Is found in current metadata msgid "Supported on remote server" msgstr "Підтримуваний на віддаленому сервері" +#. TRANSLATORS: Title: a better sleep state +msgid "Suspend-to-idle" +msgstr "Присипляння бездіяльності" + +#. TRANSLATORS: Title: sleep state +msgid "Suspend-to-ram" +msgstr "Присипляння до пам'яті" + +#. TRANSLATORS: command description +msgid "Switch the firmware branch on the device" +msgstr "Перемкнути гілку мікропрограми на пристрої" + +#. TRANSLATORS: Must be plugged in to an outlet +msgid "System requires external power source" +msgstr "Система потребує зовнішнього джерела живлення" + +#. TRANSLATORS: Title: the PCR is rebuilt from the TPM event log +msgid "TPM PCR0 reconstruction" +msgstr "Відновлення PCR0 TPM" + +#. TRANSLATORS: Title: TPM = Trusted Platform Module +msgid "TPM v2.0" +msgstr "TPM 2.0" + +#. TRANSLATORS: Suffix: the HSI result +msgid "Tainted" +msgstr "Нечисте" + msgid "Target" msgstr "Ціль" @@ -1283,6 +1678,23 @@ msgstr "Ціль" msgid "The LVFS is a free service that operates as an independent legal entity and has no connection with $OS_RELEASE:NAME$. Your distributor may not have verified any of the firmware updates for compatibility with your system or connected devices. All firmware is provided only by the original equipment manufacturer." msgstr "LVFS є безкоштовною службою, яка працює як незалежна юридична одиниця і не має зв'язку з $OS_RELEASE:NAME$. Розробники вашої операційної системи, можливо, не перевіряли жодні з цих оновлень на сумісність із системою або з'єднаними із комп'ютером пристроями. Усі мікропрограми надаються лише самими виробниками обладнання." +#. TRANSLATORS: this is more background on a security measurement problem +msgid "The TPM PCR0 differs from reconstruction." +msgstr "PCR0 TPM відрізняється від реконструкції." + +#. TRANSLATORS: the user is SOL for support... +msgid "The daemon has loaded 3rd party code and is no longer supported by the upstream developers!" +msgstr "Ця фонова служба завантажила сторонній код — її підтримка більше не здійснюється розробниками основної гілки програми!" + +#. TRANSLATORS: %1 is the firmware vendor, %2 is the device vendor name +#, c-format +msgid "The firmware from %s is not supplied by %s, the hardware vendor." +msgstr "Мікропрограма з %s не постачається %s, постачальником обладнання." + +#. TRANSLATORS: nothing to show +msgid "There are no blocked firmware files" +msgstr "Заблокованих файлів мікропрограм немає" + #. TRANSLATORS: approved firmware has been checked by #. * the domain administrator msgid "There is no approved firmware." @@ -1295,6 +1707,18 @@ msgstr "Програма зможе працювати належними чин msgid "This remote contains firmware which is not embargoed, but is still being tested by the hardware vendor. You should ensure you have a way to manually downgrade the firmware if the firmware update fails." msgstr "У цьому сховищі міститься мікропрограма, встановлювати яку не заборонено, але яка усе ще перебуває у процесі тестування виробником обладнання. Вам слід переконатися, що ви зможете встановити стабільну версію мікропрограми, якщо процедура оновлення зазнає невдачі." +#. TRANSLATORS: this is instructions on how to improve the HSI suffix +msgid "This system has HSI runtime issues." +msgstr "Ця система має вади у роботі HSI." + +#. TRANSLATORS: this is instructions on how to improve the HSI security level +msgid "This system has a low HSI security level." +msgstr "Ця система має низький рівень захисту HSI." + +#. TRANSLATORS: description of dbxtool +msgid "This tool allows an administrator to apply UEFI dbx updates." +msgstr "За допомогою цієї програми адміністратор може застосувати оновлення до dbx UEFI." + #. TRANSLATORS: the user needs to stop playing with stuff msgid "This tool can only be used by the root user" msgstr "Цим інструментом може користуватися лише root" @@ -1303,10 +1727,42 @@ msgstr "Цим інструментом може користуватися ли msgid "Type" msgstr "Тип" +#. TRANSLATORS: partition refers to something on disk, again, hey Arch users +msgid "UEFI ESP partition not detected or configured" +msgstr "Розділ ESP UEFI не виявлено або не налаштовано" + #. TRANSLATORS: program name msgid "UEFI Firmware Utility" msgstr "Засіб роботи із мікропрограмами UEFI" +#. TRANSLATORS: capsule updates are an optional BIOS feature +msgid "UEFI capsule updates not available or enabled" +msgstr "Капсульні оновлення UEFI є недоступними або їх не увімкнено" + +#. TRANSLATORS: program name +msgid "UEFI dbx Utility" +msgstr "Засіб роботи з dbx UEFI" + +#. TRANSLATORS: Title: SB is a way of locking down UEFI +msgid "UEFI secure boot" +msgstr "UEFI secure boot" + +#. TRANSLATORS: error message +msgid "Unable to connect to service" +msgstr "Не вдалося встановити з'єднання зі службою" + +#. TRANSLATORS: command description +msgid "Unbind current driver" +msgstr "Відв'язати поточний драйвер" + +#. TRANSLATORS: we will now offer this firmware to the user +msgid "Unblocking firmware:" +msgstr "Розблокуємо мікропрограму:" + +#. TRANSLATORS: Suffix: the HSI result +msgid "Unencrypted" +msgstr "Розшифровано" + #. TRANSLATORS: current daemon status is unknown #. TRANSLATORS: we don't know the license of the update #. TRANSLATORS: unknown release urgency @@ -1320,10 +1776,18 @@ msgstr "Невідомий пристрій" msgid "Unlock the device to allow access" msgstr "Розблокування пристрою для отримання доступу" +#. TRANSLATORS: Suffix: the HSI result +msgid "Unlocked" +msgstr "Розблоковано" + #. TRANSLATORS: command description msgid "Unlocks the device for firmware access" msgstr "Розблоковує пристрій для доступу до мікропрограми" +#. TRANSLATORS: command description +msgid "Unmounts the ESP" +msgstr "Демонтує ESP" + #. TRANSLATORS: command line option msgid "Unset the debugging flag during update" msgstr "Зняти під час оновлення прапорець діагностики" @@ -1333,6 +1797,10 @@ msgstr "Зняти під час оновлення прапорець діаг msgid "Unsupported daemon version %s, client version is %s" msgstr "Непідтримувана версія фонової служби %s, версія клієнта — %s" +#. TRANSLATORS: Suffix: the HSI result +msgid "Untainted" +msgstr "Очищене" + #. TRANSLATORS: Device is updatable in this or any other mode msgid "Updatable" msgstr "Придатний до оновлення" @@ -1381,6 +1849,9 @@ msgstr "Оновити збережені метадані поточними д msgid "Updates all firmware to latest versions available" msgstr "Оновлює усі мікропрограми до найновіших доступних версій" +msgid "Updating" +msgstr "Оновлення" + #. TRANSLATORS: the first replacement is a display name #. * e.g. "ColorHugALS" and the second and third are #. * version numbers e.g. "1.2.3" @@ -1399,10 +1870,6 @@ msgstr "Оновлюємо %s…" msgid "Upgrade available for %s from %s to %s" msgstr "Виявлено оновлення для %s з %s до %s" -#. TRANSLATORS: the server sent the user a small message -msgid "Upload message:" -msgstr "Повідомлення про вивантаження:" - msgid "Upload report just this one time, but prompt again for future updates" msgid_plural "Upload reports just this one time, but prompt again for future updates" msgstr[0] "Вивантажити звіт цього разу, але запитати знову, якщо надалі з'являться оновлення" @@ -1429,6 +1896,14 @@ msgstr "Вивантаження звітів щодо мікропрограм msgid "Urgency" msgstr "Рівень важливості" +#. TRANSLATORS: error message explaining command to run to how to get help +msgid "Use fwupdmgr --help for help" +msgstr "Скористайтеся fwupdmgr --help, щоб дізнатися більше" + +#. TRANSLATORS: error message explaining command to run to how to get help +msgid "Use fwupdtool --help for help" +msgstr "Скористайтеся fwupdtool --help, щоб дізнатися більше" + #. TRANSLATORS: command line option msgid "Use quirk flags when installing firmware" msgstr "Використовувати варіативні прапорці при встановленні мікропрограми" @@ -1441,6 +1916,14 @@ msgstr "Сповіщено користувача" msgid "Username" msgstr "Користувач" +#. TRANSLATORS: Suffix: the HSI result +msgid "Valid" +msgstr "Коректна" + +#. TRANSLATORS: ESP refers to the EFI System Partition +msgid "Validating ESP contents…" +msgstr "Перевіряємо дані ESP…" + #. TRANSLATORS: one line variant of release (e.g. 'Prerelease' or 'China') msgid "Variant" msgstr "Варіант" @@ -1453,9 +1936,13 @@ msgstr "Виробник" msgid "Verifying…" msgstr "Перевіряємо…" -#. TRANSLATORS: try to help -msgid "WARNING: Ignoring SSL strict checks, to do this automatically in the future export DISABLE_SSL_STRICT in your environment" -msgstr "ПОПЕРЕДЖЕННЯ: ігноруємо строгі перевірки SSL. Щоб зробити ігнорування у майбутньому автоматичним, експортуйте до вашого середовища змінну DISABLE_SSL_STRICT" +#. TRANSLATORS: the detected version number of the dbx +msgid "Version" +msgstr "Версія" + +#. TRANSLATORS: this is a prefix on the console +msgid "WARNING:" +msgstr "УВАГА:" #. TRANSLATORS: waiting for device to do something msgid "Waiting…" @@ -1477,6 +1964,10 @@ msgstr "Записати мікропрограму з файла на прис msgid "Write firmware from file into one partition" msgstr "Записати мікропрограму з файла на один розділ" +#. TRANSLATORS: decompressing images from a container firmware +msgid "Writing file:" +msgstr "Записуємо файл:" + #. TRANSLATORS: writing to the flash chips msgid "Writing…" msgstr "Записуємо…" @@ -1485,19 +1976,19 @@ msgstr "Записуємо…" msgid "Your distributor may not have verified any of the firmware updates for compatibility with your system or connected devices." msgstr "Виробник вашого дистрибутива може не перевіряти усі оновлення мікропрограми на сумісність із вашою системою або з’єднаними із нею пристроями." +#. TRANSLATORS: %1 is the device vendor name +#, c-format +msgid "Your hardware may be damaged using this firmware, and installing this release may void any warranty with %s." +msgstr "Ваше обладнання може бути пошкоджено через використання цієї мікропрограми. Встановлення цього випуску може призвести до відмови %s від гарантійних зобов'язань." + +#. TRANSLATORS: this is the default branch name when unset +msgid "default" +msgstr "типова" + #. TRANSLATORS: program name msgid "fwupd TPM event log utility" msgstr "Допоміжна програма для роботи із записами подій журналу TPM fwupd" -#. TRANSLATORS: message letting the user know no device upgrade available due -#. to missing on LVFS -#. * %1 is the device name -#, c-format -msgid "• %s has no available firmware updates" -msgstr "• %s не має доступних оновлень мікропрограми" - -#. TRANSLATORS: message letting the user know no device upgrade available -#. * %1 is the device name -#, c-format -msgid "• %s has the latest available firmware version" -msgstr "• Для %s встановлено найсвіжішу доступну версію мікропрограми" +#. TRANSLATORS: Title: if the fwupd plugins are all present and correct +msgid "fwupd plugins" +msgstr "Додатки fwupd" diff --git a/po/zh_CN.po b/po/zh_CN.po index e2bd88fcf..850e8a711 100644 --- a/po/zh_CN.po +++ b/po/zh_CN.po @@ -3,7 +3,7 @@ # This file is distributed under the same license as the fwupd package. # # Translators: -# Boyuan Yang <073plan@gmail.com>, 2017 +# Boyuan Yang <073plan@gmail.com>, 2017,2020 # Dingzhong Chen , 2020 # Dingzhong Chen , 2016-2019 # Mingcong Bai , 2017-2018 @@ -452,6 +452,7 @@ msgstr[0] "不要上传报告,并且以后更新时也不再询问" msgid "Do not write to the history database" msgstr "不要写入历史数据库" +#. TRANSLATORS: success #. success msgid "Done!" msgstr "完成!" @@ -496,6 +497,8 @@ msgstr "在所支持的系统上启用固件更新的支持" msgid "Enable this remote?" msgstr "要启用此远程源吗?" +#. TRANSLATORS: Suffix: the HSI result +#. TRANSLATORS: Plugin is active and in use #. TRANSLATORS: if the remote is enabled msgid "Enabled" msgstr "已启用" @@ -534,10 +537,6 @@ msgstr "在引擎加载后退出" msgid "Failed to connect to daemon" msgstr "连接到守护进程失败" -#. TRANSLATORS: the server is rate-limiting downloads -msgid "Failed to download due to server limit" -msgstr "由于服务器限制而下载失败" - #. TRANSLATORS: we could not get the devices to update offline msgid "Failed to get pending devices" msgstr "获取待处理的设备失败" @@ -570,22 +569,6 @@ msgstr "重启失败" msgid "Failed to set splash mode" msgstr "设定启动屏幕模式失败" -#. TRANSLATORS: downloading unknown file -msgid "Fetching file" -msgstr "正在获取文件" - -#. TRANSLATORS: downloading new firmware file -msgid "Fetching firmware" -msgstr "正在获取固件" - -#. TRANSLATORS: downloading new metadata file -msgid "Fetching metadata" -msgstr "正在获取元信息" - -#. TRANSLATORS: downloading new signing file -msgid "Fetching signature" -msgstr "正在获取签名" - #. TRANSLATORS: filename of the local file msgid "Filename" msgstr "文件名" @@ -624,12 +607,17 @@ msgid "Firmware metadata has not been updated for %u day and may not be up to da msgid_plural "Firmware metadata has not been updated for %u days and may not be up to date." msgstr[0] "固件元数据已有 %u 天未更新,数据可能不是最新的。" +#. TRANSLATORS: Title: if firmware updates are available +msgid "Firmware updates" +msgstr "固件更新" + msgid "Firmware updates are not supported on this machine." msgstr "此机器不支持固件更新。" msgid "Firmware updates are supported on this machine." msgstr "此机器支持固件更新。" +#. TRANSLATORS: description of plugin state, e.g. disabled #. TRANSLATORS: release properties msgid "Flags" msgstr "标志" @@ -637,6 +625,10 @@ msgstr "标志" msgid "Force the action ignoring all warnings" msgstr "强制操作忽略所有警告" +#. TRANSLATORS: Suffix: the HSI result +msgid "Found" +msgstr "找到" + #. TRANSLATORS: global ID common to all similar hardware msgid "GUID" msgid_plural "GUIDs" @@ -666,10 +658,6 @@ msgstr "获取有关某固件文件的详细信息" msgid "Gets the configured remotes" msgstr "获取已配置的远程源" -#. TRANSLATORS: firmware approved by the admin -msgid "Gets the list of approved firmware." -msgstr "获取批准固件的列表。" - #. TRANSLATORS: command description msgid "Gets the list of updates for connected hardware" msgstr "获取已连接硬件的可用更新列表" @@ -776,6 +764,10 @@ msgstr "Linux 供应商固件服务(稳定固件)" msgid "Linux Vendor Firmware Service (testing firmware)" msgstr "Linux 供应商固件服务(测试固件)" +#. TRANSLATORS: Title: if it's tainted or not +msgid "Linux kernel" +msgstr "Linux 内核" + #. TRANSLATORS: command line option msgid "List supported firmware updates" msgstr "列出所支持固件的更新" @@ -788,10 +780,6 @@ msgstr "列出可用的固件类型" msgid "Loading…" msgstr "正在加载…" -#. TRANSLATORS: command line option -msgid "Manually whitelist specific plugins" -msgstr "将指定插件手动加入白名单" - #. TRANSLATORS: remote URI msgid "Metadata Signature" msgstr "元数据签名" @@ -813,10 +801,6 @@ msgstr "最小版本" msgid "Mismatched daemon and client, use %s instead" msgstr "守护进程与客户端不匹配,使用 %s 来代替" -#. TRANSLATORS: sets something in daemon.conf -msgid "Modifies a daemon configuration value." -msgstr "修改守护进程配置值。" - #. TRANSLATORS: command description msgid "Modifies a given remote" msgstr "修改给定的远程源" @@ -843,6 +827,7 @@ msgstr "安装完后需要关机" msgid "New version" msgstr "新版本" +#. TRANSLATORS: user did not tell the tool what to do msgid "No action specified!" msgstr "未指定操作!" @@ -880,14 +865,14 @@ msgstr "无可用远程源" msgid "No updates were applied" msgstr "没有应用任何更新" +#. TRANSLATORS: Suffix: the HSI result +msgid "OK" +msgstr "确定" + #. TRANSLATORS: command line option msgid "Only show single PCR value" msgstr "只显示单 PCR 值" -#. TRANSLATORS: command line option -msgid "Override plugin warning" -msgstr "忽略插件警告" - #. TRANSLATORS: command line option msgid "Override the default ESP path" msgstr "覆盖默认的 ESP 路径" @@ -970,10 +955,6 @@ msgstr "正在重启……" msgid "Refresh metadata from remote server" msgstr "刷新来自远程服务器的元数据" -#. TRANSLATORS: command description -msgid "Reinstall current firmware on the device." -msgstr "在设备上重新安装当前的固件。" - #. TRANSLATORS: the first replacement is a display name #. * e.g. "ColorHugALS" and the second is a version number #. * e.g. "1.2.3" @@ -1002,10 +983,6 @@ msgstr "报告 URI" msgid "Reported to remote server" msgstr "已报告到远程服务器" -#. TRANSLATORS: Must be plugged in to an outlet -msgid "Requires AC power" -msgstr "需要交流电源" - #. TRANSLATORS: Requires a bootloader mode to be manually enabled by the user msgid "Requires a bootloader" msgstr "需要引导程序" @@ -1065,13 +1042,10 @@ msgstr "序列号" msgid "Set the debugging flag during update" msgstr "更新期间设定调试标志" +#. TRANSLATORS: firmware approved by the admin msgid "Sets the list of approved firmware" msgstr "设定批准固件的列表" -#. TRANSLATORS: firmware approved by the admin -msgid "Sets the list of approved firmware." -msgstr "设定批准固件的列表。" - #. TRANSLATORS: command description msgid "Share firmware history with the developers" msgstr "与开发者分享固件历史" @@ -1236,6 +1210,10 @@ msgstr "类型" msgid "UEFI Firmware Utility" msgstr "固件 UEFI 实用工具" +#. TRANSLATORS: error message +msgid "Unable to connect to service" +msgstr "无法连接到服务" + #. TRANSLATORS: current daemon status is unknown #. TRANSLATORS: we don't know the license of the update #. TRANSLATORS: unknown release urgency @@ -1328,10 +1306,6 @@ msgstr "正在更新 %s……" msgid "Upgrade available for %s from %s to %s" msgstr "%s 有从版本 %s 到 %s 的升级" -#. TRANSLATORS: the server sent the user a small message -msgid "Upload message:" -msgstr "上传消息:" - msgid "Upload report just this one time, but prompt again for future updates" msgid_plural "Upload reports just this one time, but prompt again for future updates" msgstr[0] "仅这次上传报告,但以后更新时再次提示" @@ -1348,6 +1322,14 @@ msgstr[0] "此次上传报告,并且以后完成更新后自动上传报告" msgid "Uploading firmware reports helps hardware vendors to quickly identify failing and successful updates on real devices." msgstr "上传固件报告可帮助硬件供应商尽快确定真实设备上更新的成功及失败案例。" +#. TRANSLATORS: error message explaining command to run to how to get help +msgid "Use fwupdmgr --help for help" +msgstr "使用 fwupdmgr --help 获取帮助信息" + +#. TRANSLATORS: error message explaining command to run to how to get help +msgid "Use fwupdtool --help for help" +msgstr "使用 fwupdtool --help 获取帮助信息" + #. TRANSLATORS: command line option msgid "Use quirk flags when installing firmware" msgstr "安装固件时使用 quirk 标志" @@ -1372,9 +1354,9 @@ msgstr "供应商" msgid "Verifying…" msgstr "正在验证…" -#. TRANSLATORS: try to help -msgid "WARNING: Ignoring SSL strict checks, to do this automatically in the future export DISABLE_SSL_STRICT in your environment" -msgstr "警告:现忽略 SSL 严格检查,要在以后自动忽略请在你的环境变量里导出 DISABLE_SSL_STRICT" +#. TRANSLATORS: the detected version number of the dbx +msgid "Version" +msgstr "版本" #. TRANSLATORS: waiting for device to do something msgid "Waiting…" diff --git a/po/zh_TW.po b/po/zh_TW.po index 77fe91090..17a2ed119 100644 --- a/po/zh_TW.po +++ b/po/zh_TW.po @@ -198,6 +198,7 @@ msgstr "不要檢查是否有尚未報告的歷史" msgid "Do not write to the history database" msgstr "不要寫入歷史資料庫中" +#. TRANSLATORS: success #. success msgid "Done!" msgstr "完成!" @@ -233,6 +234,8 @@ msgstr "對支援的系統啟用韌體更新支援" msgid "Enable this remote?" msgstr "啟用此遠端站點?" +#. TRANSLATORS: Suffix: the HSI result +#. TRANSLATORS: Plugin is active and in use #. TRANSLATORS: if the remote is enabled msgid "Enabled" msgstr "啟用" @@ -267,10 +270,6 @@ msgstr "經過一段短暫延遲後便離開" msgid "Exit after the engine has loaded" msgstr "引擎載入後離開" -#. TRANSLATORS: the server is rate-limiting downloads -msgid "Failed to download due to server limit" -msgstr "因伺服器限制而下載失敗" - #. TRANSLATORS: quirks are device-specific workarounds msgid "Failed to load quirks" msgstr "無法載入奇技淫巧" @@ -279,22 +278,6 @@ msgstr "無法載入奇技淫巧" msgid "Failed to parse arguments" msgstr "無法解析引數" -#. TRANSLATORS: downloading unknown file -msgid "Fetching file" -msgstr "擷取檔案中" - -#. TRANSLATORS: downloading new firmware file -msgid "Fetching firmware" -msgstr "擷取韌體中" - -#. TRANSLATORS: downloading new metadata file -msgid "Fetching metadata" -msgstr "擷取中介資料中" - -#. TRANSLATORS: downloading new signing file -msgid "Fetching signature" -msgstr "擷取簽章中" - #. TRANSLATORS: filename of the local file msgid "Filename" msgstr "檔名" @@ -331,6 +314,10 @@ msgstr "此機器沒有韌體更新支援。" msgid "Firmware updates are supported on this machine." msgstr "此機器有韌體更新支援。" +#. TRANSLATORS: Suffix: the HSI result +msgid "Found" +msgstr "找到" + #. TRANSLATORS: command description msgid "Get all devices that support firmware updates" msgstr "取得所有支援韌體更新的裝置" @@ -416,10 +403,6 @@ msgstr "列出支援的韌體更新" msgid "Loading…" msgstr "載入中…" -#. TRANSLATORS: command line option -msgid "Manually whitelist specific plugins" -msgstr "手動白名單指定插件" - #. TRANSLATORS: remote URI msgid "Metadata URI" msgstr "中介資料 URI" @@ -439,6 +422,7 @@ msgstr "修改設定的遠端站點" msgid "Monitor the daemon for events" msgstr "監控幕後程式是否有活動" +#. TRANSLATORS: user did not tell the tool what to do msgid "No action specified!" msgstr "未指定動作!" @@ -454,9 +438,9 @@ msgstr "找不到插件" msgid "No remotes are currently enabled so no metadata is available." msgstr "目前沒有啟用的遠端站點,因而沒有中介資料可用。" -#. TRANSLATORS: command line option -msgid "Override plugin warning" -msgstr "凌駕插件警告" +#. TRANSLATORS: Suffix: the HSI result +msgid "OK" +msgstr "確定" #. TRANSLATORS: command line option msgid "Override the default ESP path" @@ -654,10 +638,6 @@ msgstr "將所有韌體更新至可用的最新版本" msgid "Updating %s from %s to %s... " msgstr "正將 %s 從 %s 版升級至 %s 版... " -#. TRANSLATORS: the server sent the user a small message -msgid "Upload message:" -msgstr "上傳訊息:" - #. TRANSLATORS: ask the user to upload msgid "Upload report now?" msgstr "是否立刻上傳報告?" @@ -674,6 +654,10 @@ msgstr "使用者名稱" msgid "Verifying…" msgstr "核驗中…" +#. TRANSLATORS: the detected version number of the dbx +msgid "Version" +msgstr "版本" + #. TRANSLATORS: waiting for device to do something msgid "Waiting…" msgstr "等候中…" From a2d8b94bf18e70f7ff7f6c3f20783b65ef3af6f2 Mon Sep 17 00:00:00 2001 From: Richard Hughes Date: Mon, 26 Oct 2020 11:52:16 +0000 Subject: [PATCH 581/607] trivial: post release version bump --- RELEASE | 4 ++-- meson.build | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/RELEASE b/RELEASE index 33c64d83a..c59276643 100644 --- a/RELEASE +++ b/RELEASE @@ -2,7 +2,7 @@ fwupd Release Notes Write release entries: -git log --format="%s" --cherry-pick --right-only 1.4.1... | grep -i -v trivial | grep -v Merge | sort | uniq +git log --format="%s" --cherry-pick --right-only 1.5.0... | grep -i -v trivial | grep -v Merge | sort | uniq Add any user visible changes into ../data/org.freedesktop.fwupd.metainfo.xml appstream-util appdata-to-news ../data/org.freedesktop.fwupd.metainfo.xml > NEWS @@ -17,7 +17,7 @@ git add ../po/*.po 2. Commit changes to git: # MAKE SURE THIS IS CORRECT -export release_ver="1.5.0" +export release_ver="1.5.1" git commit -a -m "Release fwupd ${release_ver}" git tag -s -f -m "Release fwupd ${release_ver}" "${release_ver}" diff --git a/meson.build b/meson.build index 772b7bbe6..1a61ed197 100644 --- a/meson.build +++ b/meson.build @@ -1,5 +1,5 @@ project('fwupd', 'c', - version : '1.5.0', + version : '1.5.1', license : 'LGPL-2.1+', meson_version : '>=0.47.0', default_options : ['warning_level=2', 'c_std=c99'], From 6fc11ec089075fe5cd4d71e6ceb934dad8253628 Mon Sep 17 00:00:00 2001 From: Mario Limonciello Date: Mon, 26 Oct 2020 08:56:28 -0500 Subject: [PATCH 582/607] trivial: fu-main: adjust polkit install flow The authentication happens earlier in `fu_main_install_with_helper` so no need to make recursive calls from `fu_main_authorize_install_cb` into `fu_main_authorize_install_queue`. Just simplify the code in the non-polkit case. --- src/fu-main.c | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) diff --git a/src/fu-main.c b/src/fu-main.c index b971d897c..175b0aef6 100644 --- a/src/fu-main.c +++ b/src/fu-main.c @@ -690,12 +690,12 @@ fu_main_authorize_modify_remote_cb (GObject *source, GAsyncResult *res, gpointer static void fu_main_authorize_install_queue (FuMainAuthHelper *helper); +#ifdef HAVE_POLKIT static void fu_main_authorize_install_cb (GObject *source, GAsyncResult *res, gpointer user_data) { g_autoptr(FuMainAuthHelper) helper = (FuMainAuthHelper *) user_data; g_autoptr(GError) error = NULL; -#ifdef HAVE_POLKIT g_autoptr(PolkitAuthorizationResult) auth = NULL; /* get result */ @@ -706,11 +706,11 @@ fu_main_authorize_install_cb (GObject *source, GAsyncResult *res, gpointer user_ g_dbus_method_invocation_return_gerror (helper->invocation, error); return; } -#endif /* HAVE_POLKIT */ /* do the next authentication action ID */ fu_main_authorize_install_queue (g_steal_pointer (&helper)); } +#endif /* HAVE_POLKIT */ static void fu_main_authorize_install_queue (FuMainAuthHelper *helper_ref) @@ -720,9 +720,9 @@ fu_main_authorize_install_queue (FuMainAuthHelper *helper_ref) g_autoptr(GError) error = NULL; gboolean ret; +#ifdef HAVE_POLKIT /* still more things to to authenticate */ if (helper->action_ids->len > 0) { -#ifdef HAVE_POLKIT g_autofree gchar *action_id = g_strdup (g_ptr_array_index (helper->action_ids, 0)); g_autoptr(PolkitSubject) subject = g_object_ref (helper->subject); g_ptr_array_remove_index (helper->action_ids, 0); @@ -732,12 +732,9 @@ fu_main_authorize_install_queue (FuMainAuthHelper *helper_ref) NULL, fu_main_authorize_install_cb, g_steal_pointer (&helper)); -#else - g_ptr_array_remove_index (helper->action_ids, 0); - fu_main_authorize_install_cb (NULL, NULL, g_steal_pointer (&helper)); -#endif /* HAVE_POLKIT */ return; } +#endif /* HAVE_POLKIT */ /* all authenticated, so install all the things */ priv->update_in_progress = TRUE; From 2409b302a6d1f9d4bed46be59e3c01ed2d1829ce Mon Sep 17 00:00:00 2001 From: Richard Hughes Date: Mon, 26 Oct 2020 15:17:39 +0000 Subject: [PATCH 583/607] trivial: Fix typo in HSI document --- docs/hsi.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/hsi.xml b/docs/hsi.xml index 4b3717b69..eb448d66c 100644 --- a/docs/hsi.xml +++ b/docs/hsi.xml @@ -238,7 +238,7 @@ - The kernel is not not + The kernel is not locked down. v1.5.0 From 8aa5d41eb7e26e4e7692ec9851c6159b2f636a77 Mon Sep 17 00:00:00 2001 From: Mario Limonciello Date: Mon, 26 Oct 2020 10:00:14 -0500 Subject: [PATCH 584/607] Add external interface messages --- plugins/acpi-dmar/README.md | 4 ++++ plugins/acpi-facp/README.md | 4 ++++ plugins/altos/README.md | 4 ++++ plugins/amt/README.md | 4 ++++ plugins/ata/README.md | 4 ++++ plugins/bcm57xx/README.md | 4 ++++ plugins/ccgx/README.md | 4 ++++ plugins/colorhug/README.md | 4 ++++ plugins/coreboot/README.md | 4 ++++ plugins/cpu/README.md | 4 ++++ plugins/cros-ec/README.md | 4 ++++ plugins/csr/README.md | 4 ++++ plugins/dell-dock/README.md | 4 ++++ plugins/dell-esrt/README.md | 6 ++++++ plugins/dell/README.md | 4 ++++ plugins/dfu/README.md | 4 ++++ plugins/ebitdo/README.md | 4 ++++ plugins/elantp/README.md | 6 +++++- plugins/emmc/README.md | 4 ++++ plugins/ep963x/README.md | 4 ++++ plugins/fastboot/README.md | 4 ++++ plugins/flashrom/README.md | 5 +++++ plugins/fresco-pd/README.md | 4 ++++ plugins/goodix-moc/README.md | 4 ++++ plugins/iommu/README.md | 4 ++++ plugins/jabra/README.md | 4 ++++ plugins/linux-lockdown/README.md | 4 ++++ plugins/linux-sleep/README.md | 4 ++++ plugins/linux-swap/README.md | 4 ++++ plugins/linux-tainted/README.md | 4 ++++ plugins/logind/README.md | 4 ++++ plugins/logitech-hidpp/README.md | 4 ++++ plugins/modem-manager/README.md | 4 ++++ plugins/msr/README.md | 4 ++++ plugins/nitrokey/README.md | 4 ++++ plugins/nvme/README.md | 4 ++++ plugins/optionrom/README.md | 4 ++++ plugins/pci-bcr/README.md | 4 ++++ plugins/pci-mei/README.md | 4 ++++ plugins/platform-integrity/README.md | 4 ++++ plugins/redfish/README.md | 4 ++++ plugins/rts54hid/README.md | 4 ++++ plugins/rts54hub/README.md | 4 ++++ plugins/solokey/README.md | 4 ++++ plugins/steelseries/README.md | 4 ++++ plugins/superio/README.md | 4 ++++ plugins/synaptics-cxaudio/README.md | 4 ++++ plugins/synaptics-mst/README.md | 4 ++++ plugins/synaptics-prometheus/README.md | 4 ++++ plugins/synaptics-rmi/README.md | 4 ++++ plugins/test/README.md | 4 ++++ plugins/thelio-io/README.md | 4 ++++ plugins/thunderbolt/README.md | 4 ++++ plugins/tpm-eventlog/README.md | 4 ++++ plugins/tpm/README.md | 4 ++++ plugins/uefi-dbx/README.md | 6 ++++++ plugins/uefi-recovery/README.md | 4 ++++ plugins/uefi/README.md | 8 ++++++++ plugins/upower/README.md | 4 ++++ plugins/vli/README.md | 4 ++++ plugins/wacom-raw/README.md | 4 ++++ plugins/wacom-usb/README.md | 4 ++++ 62 files changed, 258 insertions(+), 1 deletion(-) diff --git a/plugins/acpi-dmar/README.md b/plugins/acpi-dmar/README.md index da544cb50..226fabbc4 100644 --- a/plugins/acpi-dmar/README.md +++ b/plugins/acpi-dmar/README.md @@ -6,3 +6,7 @@ Introduction This plugin checks if DMA remapping for Thunderbolt devices is available. The result will be stored in an security attribute for HSI. + +External interface access +------------------------- +This plugin requires read access to `/sys/firmware/acpi/tables`. diff --git a/plugins/acpi-facp/README.md b/plugins/acpi-facp/README.md index 5a4bd120d..885d6368a 100644 --- a/plugins/acpi-facp/README.md +++ b/plugins/acpi-facp/README.md @@ -6,3 +6,7 @@ Introduction This plugin checks if S2I sleep is available. The result will be stored in an security attribute for HSI. + +External interface access +------------------------- +This plugin requires read access to `/sys/firmware/acpi/tables`. diff --git a/plugins/altos/README.md b/plugins/altos/README.md index a05734451..d8d28895c 100644 --- a/plugins/altos/README.md +++ b/plugins/altos/README.md @@ -67,3 +67,7 @@ Command: `W $addr\n` where `$addr` is a memory address `0x8001000->0x8008000` Command: `v\n` The device will reboot into application mode. This is typically performed after flashing firmware completes successfully. + +External interface access +------------------------- +This plugin requires read/write access to `/dev/bus/usb`. diff --git a/plugins/amt/README.md b/plugins/amt/README.md index e53d9d736..55ad2003c 100644 --- a/plugins/amt/README.md +++ b/plugins/amt/README.md @@ -25,3 +25,7 @@ Vendor ID Security ------------------ The device is not upgradable and thus requires no vendor ID set. + +External interface access +------------------------- +This plugin requires read only access to `/dev/mei0`. diff --git a/plugins/ata/README.md b/plugins/ata/README.md index 97240c8da..f9dbc87d5 100644 --- a/plugins/ata/README.md +++ b/plugins/ata/README.md @@ -47,3 +47,7 @@ This plugin uses the following plugin-specific quirks: |------------------------|-------------------------------------------|-----------------------| | `AtaTransferBlocks` | Blocks to transfer, or `0xffff` for max | 1.2.4 | | `AtaTransferMode` | The transfer mode, `0x3`, `0x7` or `0xe` | 1.2.4 | + +External interface access +------------------------- +This plugin requires the `SG_IO` ioctl interface. diff --git a/plugins/bcm57xx/README.md b/plugins/bcm57xx/README.md index 5cb0890d7..f8e85f1c1 100644 --- a/plugins/bcm57xx/README.md +++ b/plugins/bcm57xx/README.md @@ -26,3 +26,7 @@ Vendor ID Security ------------------ The vendor ID is set from the PCI vendor, in this instance set to `PCI:0x14E4` + +External interface access +------------------------- +This plugin requires the `SIOCETHTOOL` ioctl interface. diff --git a/plugins/ccgx/README.md b/plugins/ccgx/README.md index 8be26bdf8..67444e68f 100644 --- a/plugins/ccgx/README.md +++ b/plugins/ccgx/README.md @@ -97,3 +97,7 @@ Vendor ID Security ------------------ The vendor ID is set from the USB vendor, for example set to `USB:0x04B4` + +External interface access +------------------------- +This plugin requires read/write access to `/dev/bus/usb`. diff --git a/plugins/colorhug/README.md b/plugins/colorhug/README.md index c86db7516..9e19ec748 100644 --- a/plugins/colorhug/README.md +++ b/plugins/colorhug/README.md @@ -34,3 +34,7 @@ Vendor ID Security ------------------ The vendor ID is set from the USB vendor, in this instance set to `USB:0x273F` + +External interface access +------------------------- +This plugin requires read/write access to `/dev/bus/usb`. diff --git a/plugins/coreboot/README.md b/plugins/coreboot/README.md index beec31f75..c55ca55a3 100644 --- a/plugins/coreboot/README.md +++ b/plugins/coreboot/README.md @@ -57,3 +57,7 @@ Vendor ID Security ------------------ The vendor ID is set from the BIOS vendor, in this instance `DMI:coreboot` + +External interface access +------------------------- +This plugin does not currently use any external access. diff --git a/plugins/cpu/README.md b/plugins/cpu/README.md index 5ef8b88c5..b2f54c230 100644 --- a/plugins/cpu/README.md +++ b/plugins/cpu/README.md @@ -16,3 +16,7 @@ These devices add extra instance IDs from the CPUID values, e.g. * `CPUID\PRO_0&FAM_06` * `CPUID\PRO_0&FAM_06&MOD_0E` * `CPUID\PRO_0&FAM_06&MOD_0E&STP_3` + +External interface access +------------------------- +This plugin requires no extra access. diff --git a/plugins/cros-ec/README.md b/plugins/cros-ec/README.md index a16ac6dd0..5b348b004 100644 --- a/plugins/cros-ec/README.md +++ b/plugins/cros-ec/README.md @@ -38,6 +38,10 @@ values depending on the model and device mode. The list of USB VIDs used is: * `USB:0x18D1` +External interface access +------------------------- +This plugin requires read/write access to `/dev/bus/usb`. + [1] https://chromium.googlesource.com/chromiumos/platform/ec/+/master/extra/usb_updater/usb_updater2.c [2] https://chromium.googlesource.com/chromiumos/platform/ec/+/master/docs/usb_updater.md [3] https://www.chromium.org/chromium-os/firmware-porting-guide/fmap diff --git a/plugins/csr/README.md b/plugins/csr/README.md index 0d013af4b..72286c323 100644 --- a/plugins/csr/README.md +++ b/plugins/csr/README.md @@ -39,3 +39,7 @@ Vendor ID Security ------------------ The vendor ID is set from the USB vendor, in this instance set to `USB:0x0A12` + +External interface access +------------------------- +This plugin requires read/write access to `/dev/bus/usb`. diff --git a/plugins/dell-dock/README.md b/plugins/dell-dock/README.md index 67e213972..8866867ca 100644 --- a/plugins/dell-dock/README.md +++ b/plugins/dell-dock/README.md @@ -68,3 +68,7 @@ This plugin uses the following plugin-specific quirks: | `DellDockVersionLowest` | The minimum component version required to safely operate the plugin | 1.1.3 | | `DellDockBoard*` | The board description of a board revision | 1.1.3 | | `DellDockInstallDurationI2C` | The duration of time required to install a payload via I2C. | 1.1.3 | + +External interface access +------------------------- +This plugin requires read/write access to `/dev/bus/usb`. diff --git a/plugins/dell-esrt/README.md b/plugins/dell-esrt/README.md index 5c5aefc4a..b96120ac9 100644 --- a/plugins/dell-esrt/README.md +++ b/plugins/dell-esrt/README.md @@ -45,3 +45,9 @@ UEFI dummy device Version: 0 Created: 2018-06-25 ``` + +External interface access +------------------------- +This plugin requires: +* read/write access to `/dev/wmi/dell-smbios` and `/sys/bus/platform/devices/dcdbas`. +* read access to `/sys/firmware/efi/esrt`. diff --git a/plugins/dell/README.md b/plugins/dell/README.md index aa25bcfb9..c6e7a1058 100644 --- a/plugins/dell/README.md +++ b/plugins/dell/README.md @@ -181,3 +181,7 @@ These updates can be performed the standard method of using: Some components are updatable via other plugins in fwupd such as multi stream transport hub (MST) and thunderbolt NVM. + +External interface access +------------------------- +This plugin requires read/write access to `/dev/wmi/dell-smbios` and `/sys/bus/platform/devices/dcdbas`. diff --git a/plugins/dfu/README.md b/plugins/dfu/README.md index d3fce1b10..1170526ad 100644 --- a/plugins/dfu/README.md +++ b/plugins/dfu/README.md @@ -41,3 +41,7 @@ This plugin uses the following plugin-specific quirks: |`DfuFlags` | Optional quirks for a DFU device which doesn't follow the DFU 1.0 or 1.1 specification | 1.0.1| |`DfuForceVersion` | Forces a specific DFU version for the hardware device. This is required if the device does not set, or sets incorrectly, items in the DFU functional descriptor. |1.0.1| |`DfuForceTimeout` | Forces a specific device timeout, in ms | 1.4.0 | + +External interface access +------------------------- +This plugin requires read/write access to `/dev/bus/usb`. diff --git a/plugins/ebitdo/README.md b/plugins/ebitdo/README.md index c26bce02e..d2a63e49e 100644 --- a/plugins/ebitdo/README.md +++ b/plugins/ebitdo/README.md @@ -44,3 +44,7 @@ values depending on the model and device mode. The list of USB VIDs used is: * `USB:0x1235` * `USB:0x2002` * `USB:0x8000` + +External interface access +------------------------- +This plugin requires read/write access to `/dev/bus/usb`. diff --git a/plugins/elantp/README.md b/plugins/elantp/README.md index 5e4ea26d7..15bafcf40 100644 --- a/plugins/elantp/README.md +++ b/plugins/elantp/README.md @@ -31,7 +31,7 @@ Additionally another instance ID is added which corresponds to the module ID: These devices also use custom GUID values for the IC configuration, e.g. * `ELANTP\ICTYPE_09` - + Additionally another instance ID is added which corresponds to the IC type & module ID: * `ELANTP\ICTYPE_09&MOD_1234` @@ -50,3 +50,7 @@ This plugin uses the following plugin-specific quirks: |------------------------|-------------------------------------------|-----------------------| | `ElantpIcPageCount` | The IC page count | 1.4.6 | | `ElantpIapPassword` | The IAP password | 1.4.6 | + +External interface access +------------------------- +This plugin requires ioctl access to `HIDIOCSFEATURE` and `HIDIOCGFEATURE`. diff --git a/plugins/emmc/README.md b/plugins/emmc/README.md index 249f7056b..0ce5aa33c 100644 --- a/plugins/emmc/README.md +++ b/plugins/emmc/README.md @@ -24,3 +24,7 @@ Vendor ID Security ------------------ The vendor ID is set from the EMMC vendor, for example set to `EMMC:{$manfid}` + +External interface access +------------------------- +This plugin requires ioctl `MMC_IOC_CMD` and `MMC_IOC_MULTI_CMD` access. diff --git a/plugins/ep963x/README.md b/plugins/ep963x/README.md index c510cc19f..14bb362c9 100644 --- a/plugins/ep963x/README.md +++ b/plugins/ep963x/README.md @@ -29,3 +29,7 @@ Vendor ID Security ------------------ The vendor ID is set from the USB vendor, in this instance set to `USB:0x17EF` + +External interface access +------------------------- +This plugin requires read/write access to `/dev/bus/usb`. diff --git a/plugins/fastboot/README.md b/plugins/fastboot/README.md index 2850a9246..d99cc8012 100644 --- a/plugins/fastboot/README.md +++ b/plugins/fastboot/README.md @@ -43,3 +43,7 @@ Vendor ID Security ------------------ The vendor ID is set from the USB vendor, for example `USB:0x18D1` + +External interface access +------------------------- +This plugin requires read/write access to `/dev/bus/usb`. diff --git a/plugins/flashrom/README.md b/plugins/flashrom/README.md index f8b718244..b3fb1a257 100644 --- a/plugins/flashrom/README.md +++ b/plugins/flashrom/README.md @@ -28,3 +28,8 @@ Vendor ID Security ------------------ The vendor ID is set from the BIOS vendor, for example `DMI:Google` + +External interface access +--- +This plugin requires access to all interfaces that `libflashrom` has been compiled for. +This typically is `/sys/bus/spi` but there may be other interfaces as well. diff --git a/plugins/fresco-pd/README.md b/plugins/fresco-pd/README.md index c592e9059..6f87a3ea5 100644 --- a/plugins/fresco-pd/README.md +++ b/plugins/fresco-pd/README.md @@ -33,3 +33,7 @@ Vendor ID Security ------------------ The vendor ID is set from the USB vendor, in this instance set to `USB:0x1D5C` + +External interface access +------------------------- +This plugin requires read/write access to `/dev/bus/usb`. diff --git a/plugins/goodix-moc/README.md b/plugins/goodix-moc/README.md index 8c35edbc7..17c0cd700 100644 --- a/plugins/goodix-moc/README.md +++ b/plugins/goodix-moc/README.md @@ -29,3 +29,7 @@ Vendor ID Security ------------------ The vendor ID is set from the USB vendor, in this instance set to `USB:0x27C6` + +External interface access +------------------------- +This plugin requires read/write access to `/dev/bus/usb`. diff --git a/plugins/iommu/README.md b/plugins/iommu/README.md index 12574ffd6..407d55b8d 100644 --- a/plugins/iommu/README.md +++ b/plugins/iommu/README.md @@ -5,3 +5,7 @@ Introduction ------------ This plugin checks if an IOMMU is available on the system. + +External interface access +------------------------- +This plugin requires no extra access. diff --git a/plugins/jabra/README.md b/plugins/jabra/README.md index 3a5ab7fa8..f0466349e 100644 --- a/plugins/jabra/README.md +++ b/plugins/jabra/README.md @@ -26,3 +26,7 @@ Vendor ID Security ------------------ The vendor ID is set from the USB vendor, in this instance set to `USB:0x0A12` + +External interface access +------------------------- +This plugin requires read/write access to `/dev/bus/usb`. diff --git a/plugins/linux-lockdown/README.md b/plugins/linux-lockdown/README.md index 0cd58d6b9..8fef436f6 100644 --- a/plugins/linux-lockdown/README.md +++ b/plugins/linux-lockdown/README.md @@ -6,3 +6,7 @@ Introduction This plugin checks if the currently running kernel is locked down. The result will be stored in an security attribute for HSI. + +External interface access +------------------------- +This plugin requires read access to `/sys/sys/kernel/security`. diff --git a/plugins/linux-sleep/README.md b/plugins/linux-sleep/README.md index b7864933e..e87d422fa 100644 --- a/plugins/linux-sleep/README.md +++ b/plugins/linux-sleep/README.md @@ -6,3 +6,7 @@ Introduction This plugin checks if s3 sleep is available. The result will be stored in an security attribute for HSI. + +External interface access +------------------------- +This plugin requires read access to `/sys/power/mem_sleep`. diff --git a/plugins/linux-swap/README.md b/plugins/linux-swap/README.md index f7e28574a..f3b3f770d 100644 --- a/plugins/linux-swap/README.md +++ b/plugins/linux-swap/README.md @@ -6,3 +6,7 @@ Introduction This plugin checks if the currently available swap partitions and files are all encrypted. The result will be stored in an security attribute for HSI. + +External interface access +------------------------- +This plugin requires read access to `/proc` diff --git a/plugins/linux-tainted/README.md b/plugins/linux-tainted/README.md index 3c1a72d71..e240061df 100644 --- a/plugins/linux-tainted/README.md +++ b/plugins/linux-tainted/README.md @@ -6,3 +6,7 @@ Introduction This plugin checks if the currently running kernel is tainted. The result will be stored in an security attribute for HSI. + +External interface access +------------------------- +This plugin requires read access to `/sys/kernel/tainted`. diff --git a/plugins/logind/README.md b/plugins/logind/README.md index bd66d8bba..d7d5456ae 100644 --- a/plugins/logind/README.md +++ b/plugins/logind/README.md @@ -11,3 +11,7 @@ Vendor ID Security ------------------ This protocol does not create a device and thus requires no vendor ID set. + +External interface access +------------------------- +This plugin requires access to the dbus interface `org.freedesktop.login1`. diff --git a/plugins/logitech-hidpp/README.md b/plugins/logitech-hidpp/README.md index 89f918323..3a00e6ae0 100644 --- a/plugins/logitech-hidpp/README.md +++ b/plugins/logitech-hidpp/README.md @@ -58,3 +58,7 @@ paired devices. [1] https://www.mousejack.com/ [2] https://pwr-Solaar.github.io/Solaar/ + +External interface access +------------------------- +This plugin requires read/write access to `/dev/bus/usb`. diff --git a/plugins/modem-manager/README.md b/plugins/modem-manager/README.md index a2ab7645e..b97eeafe9 100644 --- a/plugins/modem-manager/README.md +++ b/plugins/modem-manager/README.md @@ -48,3 +48,7 @@ partition where the MCFG files are stored can be wiped out before installing the new ones. Update protocol: com.qualcomm.qmi_pdc + +External interface access +------------------------- +This plugin requires read/write access to `/dev/bus/usb`. diff --git a/plugins/msr/README.md b/plugins/msr/README.md index a5a245160..0fbfe725e 100644 --- a/plugins/msr/README.md +++ b/plugins/msr/README.md @@ -12,3 +12,7 @@ always be disabled and locked on production hardware as it allows the attacker to disable other firmware protection methods. The result will be stored in a security attribute for HSI. + +External interface access +------------------------- +This plugin requires read access to `/sys/class/msr`. diff --git a/plugins/nitrokey/README.md b/plugins/nitrokey/README.md index 852e88a43..e50b472e3 100644 --- a/plugins/nitrokey/README.md +++ b/plugins/nitrokey/README.md @@ -25,3 +25,7 @@ Vendor ID Security The vendor ID is set from the USB vendor, in this instance set to `USB:0x20A0` in runtime mode and `USB:0x03EB` in bootloader mode. + +External interface access +------------------------- +This plugin requires read/write access to `/dev/bus/usb`. diff --git a/plugins/nvme/README.md b/plugins/nvme/README.md index da5c86253..3005948e9 100644 --- a/plugins/nvme/README.md +++ b/plugins/nvme/README.md @@ -54,3 +54,7 @@ Vendor ID Security ------------------ The vendor ID is set from the udev vendor, for example set to `NVME:0x1179` + +External interface access +------------------------- +This plugin requires ioctl `NVME_IOCTL_ADMIN_CMD` access. diff --git a/plugins/optionrom/README.md b/plugins/optionrom/README.md index f07405c2b..d028e3ca3 100644 --- a/plugins/optionrom/README.md +++ b/plugins/optionrom/README.md @@ -24,3 +24,7 @@ Vendor ID Security ------------------ The device is not upgradable and thus requires no vendor ID set. + +External interface access +------------------------- +This plugin requires read access to the rom file of PCI devices (`/sys/class/pci_bus/*/device/rom`) diff --git a/plugins/pci-bcr/README.md b/plugins/pci-bcr/README.md index c838edea9..dae5c5974 100644 --- a/plugins/pci-bcr/README.md +++ b/plugins/pci-bcr/README.md @@ -6,3 +6,7 @@ Introduction This plugin checks if the system SPI chip is locked. The result will be stored in an security attribute for HSI. + +External interface access +------------------------- +This plugin requires read access to the config space of PCI devices (`/sys/class/pci_bus/*/device/config`) diff --git a/plugins/pci-mei/README.md b/plugins/pci-mei/README.md index 1744c6c4a..d52e8f005 100644 --- a/plugins/pci-mei/README.md +++ b/plugins/pci-mei/README.md @@ -6,3 +6,7 @@ Introduction This plugin checks if the ME is in Manufacturing Mode. The result will be stored in an security attribute for HSI. + +External interface access +------------------------- +This plugin requires read access to the config space of PCI devices (`/sys/class/pci_bus/*/device/config`) diff --git a/plugins/platform-integrity/README.md b/plugins/platform-integrity/README.md index aad353a5e..170e541a9 100644 --- a/plugins/platform-integrity/README.md +++ b/plugins/platform-integrity/README.md @@ -6,3 +6,7 @@ Introduction This plugin checks if the system SPI chip is locked. The result will be stored in an security attribute for HSI. + +External interface access +------------------------- +This plugin requires read access to `/sys/class/platform-integrity` diff --git a/plugins/redfish/README.md b/plugins/redfish/README.md index 55b3cca0b..b46dd525a 100644 --- a/plugins/redfish/README.md +++ b/plugins/redfish/README.md @@ -73,3 +73,7 @@ and verify the uri with or $ curl -k https://192.168.0.133:443/redfish/v1/ + +External interface access +------------------------- +This requires HTTP access to a given URL. diff --git a/plugins/rts54hid/README.md b/plugins/rts54hid/README.md index 9a5b6a679..9cb52a604 100644 --- a/plugins/rts54hid/README.md +++ b/plugins/rts54hid/README.md @@ -47,3 +47,7 @@ This plugin uses the following plugin-specific quirks: | `Rts54TargetAddr` | The target address of a child module. | 1.1.3 | | `Rts54I2cSpeed` | The I2C speed to operate at (0, 1, 2). | 1.1.3 | | `Rts54RegisterAddrLen` | The I2C register address length of commands | 1.1.3 | + +External interface access +------------------------- +This plugin requires read/write access to `/dev/bus/usb`. diff --git a/plugins/rts54hub/README.md b/plugins/rts54hub/README.md index be4818da4..c0c231d51 100644 --- a/plugins/rts54hub/README.md +++ b/plugins/rts54hub/README.md @@ -33,3 +33,7 @@ Vendor ID Security ------------------ The vendor ID is set from the USB vendor, in this instance set to `USB:0x0BDA` + +External interface access +------------------------- +This plugin requires read/write access to `/dev/bus/usb`. diff --git a/plugins/solokey/README.md b/plugins/solokey/README.md index 5f72e8d76..b32a0a48f 100644 --- a/plugins/solokey/README.md +++ b/plugins/solokey/README.md @@ -31,3 +31,7 @@ Vendor ID Security ------------------ The vendor ID is set from the USB vendor, in this instance set to `USB:0x0483` + +External interface access +------------------------- +This plugin requires read/write access to `/dev/bus/usb`. diff --git a/plugins/steelseries/README.md b/plugins/steelseries/README.md index dd3c745f5..9ea70cf40 100644 --- a/plugins/steelseries/README.md +++ b/plugins/steelseries/README.md @@ -21,3 +21,7 @@ Vendor ID Security ------------------ The device is not upgradable and thus requires no vendor ID set. + +External interface access +------------------------- +This plugin requires read/write access to `/dev/bus/usb`. diff --git a/plugins/superio/README.md b/plugins/superio/README.md index 79c97efd8..8ef8f91c9 100644 --- a/plugins/superio/README.md +++ b/plugins/superio/README.md @@ -27,3 +27,7 @@ Vendor ID Security ------------------ The vendor ID is set from the baseboard vendor, for example `DMI:Star Labs` + +External interface access +------------------------- +This plugin requires access to raw system memory via `inb`/`outb`. diff --git a/plugins/synaptics-cxaudio/README.md b/plugins/synaptics-cxaudio/README.md index ac32c8886..1bd7d2c15 100644 --- a/plugins/synaptics-cxaudio/README.md +++ b/plugins/synaptics-cxaudio/README.md @@ -47,3 +47,7 @@ This plugin uses the following plugin-specific quirks: | `IsSoftwareResetSupported` | If the chip supports self-reset | 1.3.2 | | `EepromPatchValidAddr` | Address of patch location #1 | 1.3.2 | | `EepromPatch2ValidAddr` | Address of patch location #2 | 1.3.2 | + +External interface access +------------------------- +This plugin requires read/write access to `/dev/bus/usb`. diff --git a/plugins/synaptics-mst/README.md b/plugins/synaptics-mst/README.md index a821455f3..1a9ecfa32 100644 --- a/plugins/synaptics-mst/README.md +++ b/plugins/synaptics-mst/README.md @@ -84,3 +84,7 @@ Here is a sample list of systems known to support them however: * Latitude Rugged 5414 * Latitude Rugged 7214 * Latitude Rugged 7414 + +External interface access +------------------------- +This plugin requires read/write access to `/dev/drm_dp_aux*`. diff --git a/plugins/synaptics-prometheus/README.md b/plugins/synaptics-prometheus/README.md index c448680eb..993ff031c 100644 --- a/plugins/synaptics-prometheus/README.md +++ b/plugins/synaptics-prometheus/README.md @@ -31,3 +31,7 @@ Vendor ID Security ------------------ The vendor ID is set from the USB vendor, in this instance set to `USB:0x06CB` + +External interface access +------------------------- +This plugin requires read/write access to `/dev/bus/usb`. diff --git a/plugins/synaptics-rmi/README.md b/plugins/synaptics-rmi/README.md index e2c8fdddc..d3e6ea919 100644 --- a/plugins/synaptics-rmi/README.md +++ b/plugins/synaptics-rmi/README.md @@ -31,3 +31,7 @@ a proprietary (but docucumented) file format. This plugin supports the following protocol ID: * com.synaptics.rmi + +External interface access +------------------------- +This plugin requires ioctl access to `HIDIOCSFEATURE` and `HIDIOCGFEATURE`. diff --git a/plugins/test/README.md b/plugins/test/README.md index 3ab0229c8..4691cce0a 100644 --- a/plugins/test/README.md +++ b/plugins/test/README.md @@ -16,3 +16,7 @@ Vendor ID Security ------------------ The fake device is only for local testing and thus requires no vendor ID set. + +External interface access +------------------------- +This plugin requires no extra access. diff --git a/plugins/thelio-io/README.md b/plugins/thelio-io/README.md index f85e8735e..812f62571 100644 --- a/plugins/thelio-io/README.md +++ b/plugins/thelio-io/README.md @@ -20,3 +20,7 @@ Vendor ID Security ------------------ The vendor ID is set from the USB vendor, in this instance set to `USB:0x1209` + +External interface access +------------------------- +This plugin requires read/write access to `/dev/bus/usb`. diff --git a/plugins/thunderbolt/README.md b/plugins/thunderbolt/README.md index bcc54550d..4823a2ac9 100644 --- a/plugins/thunderbolt/README.md +++ b/plugins/thunderbolt/README.md @@ -92,3 +92,7 @@ DROM and exposed in the relevant sysfs attributes. If the controller is in native enumeration mode, the string "-native" is added at the end so the format is "TBT-vvvvdddd-native". + +External interface access +------------------------- +This plugin requires read/write access to `/sys/bus/thunderbolt`. diff --git a/plugins/tpm-eventlog/README.md b/plugins/tpm-eventlog/README.md index 603b21995..af62cb55a 100644 --- a/plugins/tpm-eventlog/README.md +++ b/plugins/tpm-eventlog/README.md @@ -15,3 +15,7 @@ Vendor ID Security ------------------ The device is not upgradable and thus requires no vendor ID set. + +External interface access +------------------------- +This plugin requires read only access to `/sys/kernel/security/tpm0/binary_bios_measurements`. diff --git a/plugins/tpm/README.md b/plugins/tpm/README.md index f37561bd7..32fceeee3 100644 --- a/plugins/tpm/README.md +++ b/plugins/tpm/README.md @@ -30,3 +30,7 @@ Vendor ID Security ------------------ The device is not upgradable and thus requires no vendor ID set. + +External interface access +------------------------- +This plugin uses the tpm2-tss library to access the TPM. It requires access to `/sys/class/tpm`. diff --git a/plugins/uefi-dbx/README.md b/plugins/uefi-dbx/README.md index 3607a8d19..69ac99507 100644 --- a/plugins/uefi-dbx/README.md +++ b/plugins/uefi-dbx/README.md @@ -39,3 +39,9 @@ Vendor ID Security ------------------ The vendor ID is hardcoded to `UEFI:Microsoft` for all devices. + + +External interface access +------------------------- +This plugin requires: +* read/write access to `/sys/firmware/efi/efivars` diff --git a/plugins/uefi-recovery/README.md b/plugins/uefi-recovery/README.md index 4e3f5d70c..33ff21434 100644 --- a/plugins/uefi-recovery/README.md +++ b/plugins/uefi-recovery/README.md @@ -20,3 +20,7 @@ Vendor ID Security ------------------ The vendor ID is set from the BIOS vendor, for example `DMI:LENOVO` + +External interface access +------------------------- +This plugin requires no extra access. diff --git a/plugins/uefi/README.md b/plugins/uefi/README.md index 10d06c918..0b973a441 100644 --- a/plugins/uefi/README.md +++ b/plugins/uefi/README.md @@ -58,3 +58,11 @@ Since version 1.1.0 fwupd will autodetect the ESP when it is mounted on used by modifying *OverrideESPMountPoint* in `/etc/fwupd/uefi.conf`. Setting an invalid directory will disable the fwupd plugin. + +External interface access +------------------------- +This plugin requires: +* read/write access to the EFI system partition. +* read access to `/sys/firmware/efi/esrt/` +* read access to `/sys/firmware/efi/fw_platform_size` +* read/write access to `/sys/firmware/efi/efivars` diff --git a/plugins/upower/README.md b/plugins/upower/README.md index 3940be144..e27863dd0 100644 --- a/plugins/upower/README.md +++ b/plugins/upower/README.md @@ -10,3 +10,7 @@ Vendor ID Security ------------------ This protocol does not create a device and thus requires no vendor ID set. + +External interface access +------------------------- +This plugin requires access to the dbus interface `org.freedesktop.UPower`. diff --git a/plugins/vli/README.md b/plugins/vli/README.md index 71f459b65..14a47a70c 100644 --- a/plugins/vli/README.md +++ b/plugins/vli/README.md @@ -80,3 +80,7 @@ the other flash chip parameters. For example: [Guid=VLI_USBHUB\\SPI_37303840] SpiCmdChipErase = 0xc7 SpiCmdSectorErase = 0x20 + +External interface access +------------------------- +This plugin requires read/write access to `/dev/bus/usb`. diff --git a/plugins/wacom-raw/README.md b/plugins/wacom-raw/README.md index 24eb155d9..0bf6afae0 100644 --- a/plugins/wacom-raw/README.md +++ b/plugins/wacom-raw/README.md @@ -36,3 +36,7 @@ Vendor ID Security ------------------ The vendor ID is set from the udev vendor, in this instance set to `HIDRAW:0x056A` + +External interface access +------------------------- +This plugin requires ioctl `HIDIOCSFEATURE` access. diff --git a/plugins/wacom-usb/README.md b/plugins/wacom-usb/README.md index 7db56c244..46eaddfc6 100644 --- a/plugins/wacom-usb/README.md +++ b/plugins/wacom-usb/README.md @@ -44,3 +44,7 @@ Vendor ID Security ------------------ The vendor ID is set from the USB vendor, for example set to `USB:0x056A` + +External interface access +------------------------- +This plugin requires read/write access to `/dev/bus/usb`. From 49c2a78c99b401a1918be37cb8bcdda7a426379c Mon Sep 17 00:00:00 2001 From: Richard Hughes Date: Tue, 27 Oct 2020 10:26:30 +0000 Subject: [PATCH 585/607] Include the amount of NVRAM size in use in the LVFS failure report --- libfwupdplugin/fu-efivar.c | 45 +++++++++++++++++++++++++++ libfwupdplugin/fu-efivar.h | 1 + libfwupdplugin/fu-self-test.c | 6 ++++ libfwupdplugin/fwupdplugin.map | 6 ++++ plugins/uefi-dbx/fu-plugin-uefi-dbx.c | 1 + plugins/uefi/fu-plugin-uefi.c | 7 +++++ 6 files changed, 66 insertions(+) diff --git a/libfwupdplugin/fu-efivar.c b/libfwupdplugin/fu-efivar.c index 39f738990..8e266f571 100644 --- a/libfwupdplugin/fu-efivar.c +++ b/libfwupdplugin/fu-efivar.c @@ -395,6 +395,51 @@ fu_efivar_get_names (const gchar *guid, GError **error) return g_steal_pointer (&names); } +/** + * fu_efivar_space_used: + * @error: A #GError + * + * Gets the total size used by all EFI variables. This may be less than the size reported by the + * kernel as some (hopefully small) variables are hidden from userspace. + * + * Returns: total allocated size of all visible variables, or %G_MAXUINT64 on error + * + * Since: 1.5.1 + **/ +guint64 +fu_efivar_space_used (GError **error) +{ + const gchar *fn; + guint64 total = 0; + g_autoptr(GDir) dir = NULL; + g_autofree gchar *path = fu_efivar_get_path (); + + /* stat each file */ + dir = g_dir_open (path, 0, error); + if (dir == NULL) + return G_MAXUINT64; + while ((fn = g_dir_read_name (dir)) != NULL) { + guint64 sz; + g_autofree gchar *pathfn = g_build_filename (path, fn, NULL); + g_autoptr(GFile) file = g_file_new_for_path (pathfn); + g_autoptr(GFileInfo) info = NULL; + + info = g_file_query_info (file, + G_FILE_ATTRIBUTE_STANDARD_ALLOCATED_SIZE "," + G_FILE_ATTRIBUTE_STANDARD_SIZE, + G_FILE_QUERY_INFO_NONE, + NULL, error); + if (info == NULL) + return G_MAXUINT64; + sz = g_file_info_get_attribute_uint64 (info, G_FILE_ATTRIBUTE_STANDARD_ALLOCATED_SIZE); + if (sz == 0) + sz = g_file_info_get_attribute_uint64 (info, G_FILE_ATTRIBUTE_STANDARD_SIZE); + total += sz; + } + + /* success */ + return total; +} /** * fu_efivar_set_data: * @guid: Globally unique identifier diff --git a/libfwupdplugin/fu-efivar.h b/libfwupdplugin/fu-efivar.h index 688fd2319..9269db117 100644 --- a/libfwupdplugin/fu-efivar.h +++ b/libfwupdplugin/fu-efivar.h @@ -24,6 +24,7 @@ #define FU_EFIVAR_ATTR_APPEND_WRITE (1 << 6) gboolean fu_efivar_supported (GError **error); +guint64 fu_efivar_space_used (GError **error); gboolean fu_efivar_exists (const gchar *guid, const gchar *name); gboolean fu_efivar_get_data (const gchar *guid, diff --git a/libfwupdplugin/fu-self-test.c b/libfwupdplugin/fu-self-test.c index beaa866ec..57af04951 100644 --- a/libfwupdplugin/fu-self-test.c +++ b/libfwupdplugin/fu-self-test.c @@ -1824,6 +1824,7 @@ fu_efivar_func (void) gboolean ret; gsize sz = 0; guint32 attr = 0; + guint64 total; g_autofree guint8 *data = NULL; g_autoptr(GError) error = NULL; g_autoptr(GPtrArray) names = NULL; @@ -1833,6 +1834,11 @@ fu_efivar_func (void) g_assert_no_error (error); g_assert_true (ret); + /* check we can get the space used */ + total = fu_efivar_space_used (&error); + g_assert_no_error (error); + g_assert_cmpint (total, ==, 0x2000); + /* check existing keys */ g_assert_false (fu_efivar_exists (FU_EFIVAR_GUID_EFI_GLOBAL, "NotGoingToExist")); g_assert_true (fu_efivar_exists (FU_EFIVAR_GUID_EFI_GLOBAL, "SecureBoot")); diff --git a/libfwupdplugin/fwupdplugin.map b/libfwupdplugin/fwupdplugin.map index 22007b07a..4ff42bc00 100644 --- a/libfwupdplugin/fwupdplugin.map +++ b/libfwupdplugin/fwupdplugin.map @@ -669,3 +669,9 @@ LIBFWUPDPLUGIN_1.5.0 { fu_udev_device_get_subsystem_vendor; local: *; } LIBFWUPDPLUGIN_1.4.7; + +LIBFWUPDPLUGIN_1.5.1 { + global: + fu_efivar_space_used; + local: *; +} LIBFWUPDPLUGIN_1.5.0; diff --git a/plugins/uefi-dbx/fu-plugin-uefi-dbx.c b/plugins/uefi-dbx/fu-plugin-uefi-dbx.c index 9b9315eb2..4a418cd93 100644 --- a/plugins/uefi-dbx/fu-plugin-uefi-dbx.c +++ b/plugins/uefi-dbx/fu-plugin-uefi-dbx.c @@ -18,6 +18,7 @@ void 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"); } gboolean diff --git a/plugins/uefi/fu-plugin-uefi.c b/plugins/uefi/fu-plugin-uefi.c index ba0b683ab..f4891cb26 100644 --- a/plugins/uefi/fu-plugin-uefi.c +++ b/plugins/uefi/fu-plugin-uefi.c @@ -608,7 +608,9 @@ gboolean fu_plugin_startup (FuPlugin *plugin, GError **error) { FuPluginData *data = fu_plugin_get_data (plugin); + guint64 nvram_total; g_autofree gchar *esp_path = NULL; + g_autofree gchar *nvram_total_str = NULL; g_autoptr(GError) error_local = NULL; /* some platforms have broken SMBIOS data */ @@ -632,6 +634,11 @@ fu_plugin_startup (FuPlugin *plugin, GError **error) /* are the EFI dirs set up so we can update each device */ if (!fu_efivar_supported (error)) return FALSE; + nvram_total = fu_efivar_space_used (error); + if (nvram_total == G_MAXUINT64) + return FALSE; + nvram_total_str = g_format_size_full (nvram_total, G_FORMAT_SIZE_LONG_FORMAT); + fu_plugin_add_report_metadata (plugin, "EfivarNvramUsed", nvram_total_str); /* override the default ESP path */ esp_path = fu_plugin_get_config_value (plugin, "OverrideESPMountPoint"); From 6d257cbe7fdb9444776092583dbe9a22d2b18574 Mon Sep 17 00:00:00 2001 From: Richard Hughes Date: Tue, 27 Oct 2020 09:41:43 +0000 Subject: [PATCH 586/607] Fix probe warning for the Logitech Unifying device The same plugin name was being added to the device from the quirk file more than once, and so we enumerated the device *again* and tried to add a duplicate device -- the device list correctly refusing to do so. Check the plugin name does not already exist before adding it, and add a self test to catch this for the future. --- libfwupdplugin/fu-device-private.h | 2 ++ libfwupdplugin/fu-device.c | 14 ++++++++++++-- libfwupdplugin/fu-self-test.c | 14 ++++++++++++++ libfwupdplugin/fwupdplugin.map | 1 + 4 files changed, 29 insertions(+), 2 deletions(-) diff --git a/libfwupdplugin/fu-device-private.h b/libfwupdplugin/fu-device-private.h index eb64c3633..4937e216f 100644 --- a/libfwupdplugin/fu-device-private.h +++ b/libfwupdplugin/fu-device-private.h @@ -28,3 +28,5 @@ void fu_device_incorporate_from_component (FuDevice *device, void fu_device_convert_instance_ids (FuDevice *self); gchar *fu_device_get_guids_as_str (FuDevice *self); GPtrArray *fu_device_get_possible_plugins (FuDevice *self); +void fu_device_add_possible_plugin (FuDevice *self, + const gchar *plugin); diff --git a/libfwupdplugin/fu-device.c b/libfwupdplugin/fu-device.c index cb6d6a3c4..9f0a6f539 100644 --- a/libfwupdplugin/fu-device.c +++ b/libfwupdplugin/fu-device.c @@ -169,12 +169,22 @@ fu_device_get_possible_plugins (FuDevice *self) * Adds a plugin name to the list of plugins that *might* be able to handle this * device. This is tyically called from a quirk handler. * - * Since: 1.3.3 + * Duplicate plugin names are ignored. + * + * Since: 1.5.1 **/ -static void +void fu_device_add_possible_plugin (FuDevice *self, const gchar *plugin) { FuDevicePrivate *priv = GET_PRIVATE (self); + + g_return_if_fail (FU_IS_DEVICE (self)); + g_return_if_fail (plugin != NULL); + + /* add if it does not already exist */ + if (g_ptr_array_find_with_equal_func (priv->possible_plugins, plugin, + g_str_equal, NULL)) + return; g_ptr_array_add (priv->possible_plugins, g_strdup (plugin)); } diff --git a/libfwupdplugin/fu-self-test.c b/libfwupdplugin/fu-self-test.c index 57af04951..6d808e2e6 100644 --- a/libfwupdplugin/fu-self-test.c +++ b/libfwupdplugin/fu-self-test.c @@ -1065,6 +1065,19 @@ fu_device_poll_func (void) g_assert_cmpint (fu_device_get_metadata_integer (device, "cnt"), ==, cnt); } +static void +fu_device_func (void) +{ + g_autoptr(FuDevice) device = fu_device_new (); + g_autoptr(GPtrArray) possible_plugins = NULL; + + /* only add one plugin name of the same type */ + fu_device_add_possible_plugin (device, "test"); + fu_device_add_possible_plugin (device, "test"); + possible_plugins = fu_device_get_possible_plugins (device); + g_assert_cmpint (possible_plugins->len, ==, 1); +} + static void fu_device_flags_func (void) { @@ -2138,6 +2151,7 @@ main (int argc, char **argv) g_test_add_func ("/fwupd/firmware{dfu}", fu_firmware_dfu_func); g_test_add_func ("/fwupd/archive{invalid}", fu_archive_invalid_func); g_test_add_func ("/fwupd/archive{cab}", fu_archive_cab_func); + g_test_add_func ("/fwupd/device", fu_device_func); g_test_add_func ("/fwupd/device{flags}", fu_device_flags_func); g_test_add_func ("/fwupd/device{parent}", fu_device_parent_func); g_test_add_func ("/fwupd/device{incorporate}", fu_device_incorporate_func); diff --git a/libfwupdplugin/fwupdplugin.map b/libfwupdplugin/fwupdplugin.map index 4ff42bc00..2856a7862 100644 --- a/libfwupdplugin/fwupdplugin.map +++ b/libfwupdplugin/fwupdplugin.map @@ -672,6 +672,7 @@ LIBFWUPDPLUGIN_1.5.0 { LIBFWUPDPLUGIN_1.5.1 { global: + fu_device_add_possible_plugin; fu_efivar_space_used; local: *; } LIBFWUPDPLUGIN_1.5.0; From ded5410f6d80df9f332bf0ba3260a0d4489ba9ed Mon Sep 17 00:00:00 2001 From: Richard Hughes Date: Mon, 26 Oct 2020 16:54:28 +0000 Subject: [PATCH 587/607] Delete unused EFI variables when deploying firmware Unconditionally delete FWUPDATE_VERBOSE and FWUPDATE_DEBUG_LOG when deploying the update using fwupdtool or fwupd and leave it to fwupdate. If you want to debug the efi binary you then have to use fwupdate and squirt the .cap file rather than using all the other layers. --- plugins/uefi/fu-uefi-device.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/plugins/uefi/fu-uefi-device.c b/plugins/uefi/fu-uefi-device.c index 80f204125..9fe66de28 100644 --- a/plugins/uefi/fu-uefi-device.c +++ b/plugins/uefi/fu-uefi-device.c @@ -571,6 +571,10 @@ fu_uefi_device_write_firmware (FuDevice *device, if (!fu_common_set_contents_bytes (fn, fixed_fw, error)) return FALSE; + /* delete the logs to save space; use fwupdate to debug the EFI binary */ + fu_efivar_delete (FU_EFIVAR_GUID_FWUPDATE, "FWUPDATE_VERBOSE", NULL); + fu_efivar_delete (FU_EFIVAR_GUID_FWUPDATE, "FWUPDATE_DEBUG_LOG", NULL); + /* set the blob header shared with fwupd.efi */ if (!fu_uefi_device_write_update_info (self, fn, varname, self->fw_class, error)) return FALSE; From 8087b2c9e0bcd7ed7d85a961500b17d0c83ca14f Mon Sep 17 00:00:00 2001 From: Richard Hughes Date: Tue, 27 Oct 2020 19:35:41 +0000 Subject: [PATCH 588/607] trivial: Set the 'downloading' state when starting the download For small files we might not get progress callbacks and so we stay in IDLE status forever. Fixes https://github.com/fwupd/fwupd/issues/2522 --- libfwupd/fwupd-client.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/libfwupd/fwupd-client.c b/libfwupd/fwupd-client.c index 769031665..e5e360a20 100644 --- a/libfwupd/fwupd-client.c +++ b/libfwupd/fwupd-client.c @@ -3919,7 +3919,6 @@ fwupd_client_download_chunk_cb (SoupMessage *msg, SoupBuffer *chunk, gpointer us /* calculate percentage */ percentage = (guint) ((100 * body_length) / header_size); g_debug ("progress: %u%%", percentage); - fwupd_client_set_status (self, FWUPD_STATUS_DOWNLOADING); fwupd_client_set_percentage (self, percentage); } @@ -3957,6 +3956,7 @@ fwupd_client_download_bytes_cb (GObject *source, SoupMessage *msg = g_task_get_task_data (task); /* get the result */ + fwupd_client_set_status (self, FWUPD_STATUS_IDLE); istr = soup_session_send_finish (priv->soup_session, res, &error); if (istr == NULL) { g_task_return_error (task, g_steal_pointer (&error)); @@ -4046,7 +4046,7 @@ fwupd_client_download_bytes_async (FwupdClient *self, G_CALLBACK (fwupd_client_download_chunk_cb), self); g_task_set_task_data (task, g_object_ref (msg), (GDestroyNotify) g_object_unref); - fwupd_client_set_status (self, FWUPD_STATUS_IDLE); + fwupd_client_set_status (self, FWUPD_STATUS_DOWNLOADING); soup_session_send_async (priv->soup_session, msg, cancellable, fwupd_client_download_bytes_cb, From 267dbd16129a413e0a3c08154d54bf5a97c9fa20 Mon Sep 17 00:00:00 2001 From: Jonas Witschel Date: Wed, 28 Oct 2020 12:02:28 +0100 Subject: [PATCH 589/607] contrib/ci: switch TPM simulator from ibmswtpm to swtpm Upstream tpm2-tss is moving from ibmswtpm to swtpm as the default TPM simulator. ibmswtpm still works fine and will be kept around for the foreseeable future, but adapt to the upstream decision in case ibmswtpm should ever get dropped from the official Arch Linux repositories (currently there are no plans to do so). --- contrib/ci/arch.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/contrib/ci/arch.sh b/contrib/ci/arch.sh index f4d0ce0fd..81522ab51 100755 --- a/contrib/ci/arch.sh +++ b/contrib/ci/arch.sh @@ -19,8 +19,8 @@ popd chown nobody . -R # install and run TPM simulator necessary for plugins/uefi/uefi-self-test -pacman -S --noconfirm ibm-sw-tpm2 tpm2-tools -tpm_server & +pacman -S --noconfirm swtpm tpm2-tools +swtpm socket --tpm2 --server port=2321 --ctrl type=tcp,port=2322 --flags not-need-init --tpmstate "dir=$PWD" & trap "kill $!" EXIT # extend a PCR0 value for test suite sleep 2 From e98845d6cfba70b932d631a4585a52b12c6933d7 Mon Sep 17 00:00:00 2001 From: Richard Hughes Date: Thu, 29 Oct 2020 11:12:49 +0000 Subject: [PATCH 590/607] Revert "Fix regression when filtering different priorities" This reverts commit f630678b6fbbdc75e58fe7f1303e99cc3f4c9930. --- src/fu-device-list.c | 2 +- src/fu-self-test.c | 11 +++-------- 2 files changed, 4 insertions(+), 9 deletions(-) diff --git a/src/fu-device-list.c b/src/fu-device-list.c index 3582e6487..6f24ed8eb 100644 --- a/src/fu-device-list.c +++ b/src/fu-device-list.c @@ -678,7 +678,7 @@ fu_device_list_add (FuDeviceList *self, FuDevice *device) /* is the device waiting to be replugged? */ item = fu_device_list_find_by_id (self, fu_device_get_id (device), NULL); - if (item != NULL && item->remove_id != 0) { + if (item != NULL) { g_debug ("found existing device %s, reusing item", fu_device_get_id (item->device)); fu_device_list_replace (self, item, device); diff --git a/src/fu-self-test.c b/src/fu-self-test.c index 8434df162..aaa3cd26c 100644 --- a/src/fu-self-test.c +++ b/src/fu-self-test.c @@ -1981,23 +1981,18 @@ fu_device_list_delay_func (gconstpointer user_data) g_assert_cmpint (changed_cnt, ==, 0); /* add the same device again */ - g_test_expect_message ("FuDeviceList", G_LOG_LEVEL_WARNING, - "ignoring device*existing device*already exists"); fu_device_list_add (device_list, device1); g_assert_cmpint (added_cnt, ==, 1); g_assert_cmpint (removed_cnt, ==, 0); - g_assert_cmpint (changed_cnt, ==, 0); + g_assert_cmpint (changed_cnt, ==, 1); - /* remove device */ - fu_device_list_remove (device_list, device1); - - /* add a different device with the same ID */ + /* add a device with the same ID */ fu_device_set_id (device2, "device1"); fu_device_list_add (device_list, device2); fu_device_set_remove_delay (device2, 100); g_assert_cmpint (added_cnt, ==, 1); g_assert_cmpint (removed_cnt, ==, 0); - g_assert_cmpint (changed_cnt, ==, 1); + g_assert_cmpint (changed_cnt, ==, 2); /* spin a bit */ fu_test_loop_run_with_timeout (10); From a78b13fb7172cbdc78116249a48f156f245e6c09 Mon Sep 17 00:00:00 2001 From: Richard Hughes Date: Thu, 29 Oct 2020 11:20:30 +0000 Subject: [PATCH 591/607] Use a different Device ID for the OptionROM devices We want to continue to dedupe the ID, and the priority should be decided on the GUID match. Fixes https://github.com/fwupd/fwupd/issues/2510 in a different way --- data/device-tests/devices/broadcom-bcm5719.json | 12 ++++++++++++ plugins/optionrom/fu-optionrom-device.c | 1 + 2 files changed, 13 insertions(+) create mode 100644 data/device-tests/devices/broadcom-bcm5719.json diff --git a/data/device-tests/devices/broadcom-bcm5719.json b/data/device-tests/devices/broadcom-bcm5719.json new file mode 100644 index 000000000..052dc7e59 --- /dev/null +++ b/data/device-tests/devices/broadcom-bcm5719.json @@ -0,0 +1,12 @@ +{ + "name": "NetXtreme BCM5719", + "guids": [ + "ec5b8a9e-973b-58cc-935b-8322fabaebe9" + ], + "releases": [ + { + "version": "0.4.44", + "file": "dfbb6529d3f7051497cc7e736848b5b6e276ff93b39bc765948663606dc87c25-bcm5719-0.4.44.cab" + } + ] +} diff --git a/plugins/optionrom/fu-optionrom-device.c b/plugins/optionrom/fu-optionrom-device.c index 4a2690e1b..8f84b8300 100644 --- a/plugins/optionrom/fu-optionrom-device.c +++ b/plugins/optionrom/fu-optionrom-device.c @@ -103,6 +103,7 @@ fu_optionrom_device_init (FuOptionromDevice *self) fu_device_add_flag (FU_DEVICE (self), FWUPD_DEVICE_FLAG_INTERNAL); fu_device_add_icon (FU_DEVICE (self), "audio-card"); fu_device_add_flag (FU_DEVICE (self), FWUPD_DEVICE_FLAG_CAN_VERIFY_IMAGE); + fu_device_set_logical_id (FU_DEVICE (self), "rom"); fu_udev_device_set_flags (FU_UDEV_DEVICE (self), FU_UDEV_DEVICE_FLAG_OPEN_READ | FU_UDEV_DEVICE_FLAG_VENDOR_FROM_PARENT); From 94e3d24f5590d2a9c91ef4c93553dd2bc56f16e1 Mon Sep 17 00:00:00 2001 From: Richard Hughes Date: Thu, 29 Oct 2020 12:56:29 +0000 Subject: [PATCH 592/607] bcm57xx: Make hotplug more reliable Although hotpluggging PCIe cards isn't common, it's how I'm testing this in the device test enclosure. Add a tiny delay to wait for the kernel to populate the net class on hotplug. --- plugins/bcm57xx/fu-bcm57xx-device.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/plugins/bcm57xx/fu-bcm57xx-device.c b/plugins/bcm57xx/fu-bcm57xx-device.c index 6b9ded167..5e2907e4a 100644 --- a/plugins/bcm57xx/fu-bcm57xx-device.c +++ b/plugins/bcm57xx/fu-bcm57xx-device.c @@ -75,6 +75,10 @@ fu_bcm57xx_device_probe (FuUdevDevice *device, GError **error) /* only if has an interface */ fn = g_build_filename (fu_udev_device_get_sysfs_path (device), "net", NULL); + if (!g_file_test (fn, G_FILE_TEST_EXISTS)) { + g_debug ("waiting for net devices to appear"); + g_usleep (50 * 1000); + } ifaces = fu_common_filename_glob (fn, "en*", NULL); if (ifaces == NULL || ifaces->len == 0) { fu_device_add_child (FU_DEVICE (self), FU_DEVICE (self->recovery)); From 3c4e57463a68b352e299af99f09dc67a3e108036 Mon Sep 17 00:00:00 2001 From: Mario Limonciello Date: Thu, 29 Oct 2020 13:14:15 -0500 Subject: [PATCH 593/607] thunderbolt: recognize authorized value of '2' as well This means that the user performed a challenge to authorize the device. Fixes: #2526 --- plugins/thunderbolt/fu-thunderbolt-device.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugins/thunderbolt/fu-thunderbolt-device.c b/plugins/thunderbolt/fu-thunderbolt-device.c index e51d83a44..5fa22bdb2 100644 --- a/plugins/thunderbolt/fu-thunderbolt-device.c +++ b/plugins/thunderbolt/fu-thunderbolt-device.c @@ -137,7 +137,7 @@ fu_thunderbolt_device_check_authorized (FuThunderboltDevice *self, GError **erro g_strerror (errno)); return FALSE; } - if (status == 1) + if (status == 1 || status == 2) fu_device_add_flag (FU_DEVICE (self), FWUPD_DEVICE_FLAG_UPDATABLE); else update_error = "Not authorized"; From b5d6aacf9f3d448ec4d4647aac0d23e4e849461a Mon Sep 17 00:00:00 2001 From: Richard Hughes Date: Fri, 30 Oct 2020 10:19:17 +0000 Subject: [PATCH 594/607] Show a less scary fwupdate output for devices without info Before: Information for the update status entry 0: Information Version: 7 Firmware GUID: {ddc0ee61-e7f0-4e7d-acc5-c070a398838e} Capsule Flags: 0x00000000x Hardware Instance: 0 Update Status: attempted Capsule File Path: /EFI/fedora/fw/fwupd-ddc0ee61-e7f0-4e7d-acc5-c070a398838e.cap failed: Error opening file /sys/firmware/efi/efivars/fwupd-671d19d0-43c- 4852-98d9-1ce16f9967e4-0-0abba7dc-e516-4167-bbf5-4d9d1c739416: No such file or directory failed: Error opening file /sys/firmware/efi/efivars/fwupd-a9971959-9246- 4a5b-b2f2-ba6fdcb19349-0-0abba7dc-e516-4167-bbf5-4d9d1c739416: No such file or directory After: Information for the update status entry 0: Information Version: 7 Firmware GUID: {ddc0ee61-e7f0-4e7d-acc5-c070a398838e} Capsule Flags: 0x00000000x Hardware Instance: 0 Update Status: attempted Capsule File Path: /EFI/fedora/fw/fwupd-ddc0ee61-e7f0-4e7d-acc5-c070a398838e.cap Information for the update status entry 1: Firmware GUID: {671d19d0-d43c-4852-98d9-1ce16f9967e4} Update Status: No update info found Information for the update status entry 2: Firmware GUID: {a9971959-9246-4a5b-b2f2-ba6fdcb19349} Update Status: No update info found Fixes https://github.com/fwupd/fwupd/issues/2530 --- plugins/uefi/fu-uefi-tool.c | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/plugins/uefi/fu-uefi-tool.c b/plugins/uefi/fu-uefi-tool.c index 52b262240..b5f80203c 100644 --- a/plugins/uefi/fu-uefi-tool.c +++ b/plugins/uefi/fu-uefi-tool.c @@ -257,11 +257,19 @@ main (int argc, char *argv[]) /* load any existing update info */ info = fu_uefi_device_load_update_info (dev, &error_local); + g_print ("Information for the update status entry %u:\n", i); if (info == NULL) { - g_printerr ("failed: %s\n", error_local->message); + if (g_error_matches (error_local, + G_IO_ERROR, + G_IO_ERROR_NOT_FOUND)) { + g_print (" Firmware GUID: {%s}\n", + fu_uefi_device_get_guid (dev)); + g_print (" Update Status: No update info found\n\n"); + } else { + g_printerr ("Failed: %s\n\n", error_local->message); + } continue; } - g_print ("Information for the update status entry %u:\n", i); g_print (" Information Version: %" G_GUINT32_FORMAT "\n", fu_uefi_update_info_get_version (info)); g_print (" Firmware GUID: {%s}\n", From e612078b8d9c8f04f34d7e3bf0ff3e29c6e44824 Mon Sep 17 00:00:00 2001 From: Richard Hughes Date: Fri, 30 Oct 2020 20:00:53 +0000 Subject: [PATCH 595/607] Remove the duplicate parent-child data in FwupdDevice and FuDevice The FuDevice derives from FwupdDevice, and yet both objects have a (potentially different) parent and set of children. This is super confusing, and just not required. Removing the duplication also removes a sizable memory leak when hotplugging composite devices as the parent was ref'd by the child and the child was ref'd by the parent in different objects... Fun to debug... --- libfwupd/fwupd-device.c | 58 +++++++++++++++++++++++--- libfwupd/fwupd-device.h | 2 + libfwupd/fwupd.map | 6 +++ libfwupdplugin/fu-device.c | 84 ++++++++++++-------------------------- 4 files changed, 86 insertions(+), 64 deletions(-) diff --git a/libfwupd/fwupd-device.c b/libfwupd/fwupd-device.c index 99810a460..2db08cfb2 100644 --- a/libfwupd/fwupd-device.c +++ b/libfwupd/fwupd-device.c @@ -63,7 +63,7 @@ typedef struct { gchar *update_image; FwupdStatus status; GPtrArray *releases; - FwupdDevice *parent; + FwupdDevice *parent; /* noref */ } FwupdDevicePrivate; enum { @@ -72,6 +72,7 @@ enum { PROP_FLAGS, PROP_PROTOCOL, PROP_STATUS, + PROP_PARENT, PROP_LAST }; @@ -348,10 +349,40 @@ void fwupd_device_set_parent (FwupdDevice *device, FwupdDevice *parent) { FwupdDevicePrivate *priv = GET_PRIVATE (device); - FwupdDevicePrivate *priv_parent = GET_PRIVATE (parent); g_return_if_fail (FWUPD_IS_DEVICE (device)); - g_set_object (&priv->parent, parent); - g_ptr_array_add (priv_parent->children, g_object_ref (device)); + + if (priv->parent != NULL) + g_object_remove_weak_pointer (G_OBJECT (priv->parent), (gpointer *) &priv->parent); + if (parent != NULL) + g_object_add_weak_pointer (G_OBJECT (parent), (gpointer *) &priv->parent); + priv->parent = parent; + + /* this is what goes over D-Bus */ + fwupd_device_set_parent_id (device, parent != NULL ? fwupd_device_get_id (parent) : NULL); +} + +/** + * fwupd_device_add_child: + * @self: A #FwupdDevice + * @child: Another #FwupdDevice + * + * Adds a child device. An child device is logically linked to the primary + * device in some way. + * + * Since: 1.5.1 + **/ +void +fwupd_device_add_child (FwupdDevice *device, FwupdDevice *child) +{ + FwupdDevicePrivate *priv = GET_PRIVATE (device); + + /* add if the child does not already exist */ + for (guint i = 0; i < priv->children->len; i++) { + FwupdDevice *devtmp = g_ptr_array_index (priv->children, i); + if (devtmp == child) + return; + } + g_ptr_array_add (priv->children, g_object_ref (child)); } /** @@ -2297,6 +2328,9 @@ fwupd_device_get_property (GObject *object, guint prop_id, case PROP_STATUS: g_value_set_uint (value, priv->status); break; + case PROP_PARENT: + g_value_set_object (value, priv->parent); + break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); break; @@ -2321,6 +2355,9 @@ fwupd_device_set_property (GObject *object, guint prop_id, case PROP_STATUS: fwupd_device_set_status (self, g_value_get_uint (value)); break; + case PROP_PARENT: + fwupd_device_set_parent (self, g_value_get_object (value)); + break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); break; @@ -2365,6 +2402,13 @@ fwupd_device_class_init (FwupdDeviceClass *klass) G_PARAM_READWRITE | G_PARAM_STATIC_NAME); g_object_class_install_property (object_class, PROP_STATUS, pspec); + + pspec = g_param_spec_object ("parent", NULL, NULL, + FWUPD_TYPE_DEVICE, + G_PARAM_READWRITE | + G_PARAM_CONSTRUCT | + G_PARAM_STATIC_NAME); + g_object_class_install_property (object_class, PROP_PARENT, pspec); } static void @@ -2386,7 +2430,7 @@ fwupd_device_finalize (GObject *object) FwupdDevicePrivate *priv = GET_PRIVATE (device); if (priv->parent != NULL) - g_object_unref (priv->parent); + g_object_remove_weak_pointer (G_OBJECT (priv->parent), (gpointer *) &priv->parent); g_free (priv->description); g_free (priv->id); g_free (priv->parent_id); @@ -2489,8 +2533,10 @@ fwupd_device_array_ensure_parents (GPtrArray *devices) if (parent_id != NULL) { FwupdDevice *dev_tmp; dev_tmp = g_hash_table_lookup (devices_by_id, parent_id); - if (dev_tmp != NULL) + if (dev_tmp != NULL) { + fwupd_device_add_child (dev_tmp, dev); fwupd_device_set_parent (dev, dev_tmp); + } } } } diff --git a/libfwupd/fwupd-device.h b/libfwupd/fwupd-device.h index db8c8adf3..0744fd8a0 100644 --- a/libfwupd/fwupd-device.h +++ b/libfwupd/fwupd-device.h @@ -41,6 +41,8 @@ void fwupd_device_set_parent_id (FwupdDevice *device, FwupdDevice *fwupd_device_get_parent (FwupdDevice *device); void fwupd_device_set_parent (FwupdDevice *device, FwupdDevice *parent); +void fwupd_device_add_child (FwupdDevice *device, + FwupdDevice *child); GPtrArray *fwupd_device_get_children (FwupdDevice *device); const gchar *fwupd_device_get_name (FwupdDevice *device); void fwupd_device_set_name (FwupdDevice *device, diff --git a/libfwupd/fwupd.map b/libfwupd/fwupd.map index 097d967ea..632f26faa 100644 --- a/libfwupd/fwupd.map +++ b/libfwupd/fwupd.map @@ -610,3 +610,9 @@ LIBFWUPD_1.5.0 { fwupd_security_attr_to_variant; local: *; } LIBFWUPD_1.4.6; + +LIBFWUPD_1.5.1 { + global: + fwupd_device_add_child; + local: *; +} LIBFWUPD_1.5.0; diff --git a/libfwupdplugin/fu-device.c b/libfwupdplugin/fu-device.c index 9f0a6f539..71f00bc59 100644 --- a/libfwupdplugin/fu-device.c +++ b/libfwupdplugin/fu-device.c @@ -38,14 +38,12 @@ typedef struct { gchar *logical_id; gchar *proxy_guid; FuDevice *alternate; - FuDevice *parent; /* noref */ FuDevice *proxy; /* noref */ FuQuirks *quirks; GHashTable *metadata; /* (nullable) */ GRWLock metadata_mutex; GPtrArray *parent_guids; GRWLock parent_guids_mutex; - GPtrArray *children; guint remove_delay; /* ms */ guint progress; gint order; @@ -75,7 +73,6 @@ enum { PROP_PHYSICAL_ID, PROP_LOGICAL_ID, PROP_QUIRKS, - PROP_PARENT, PROP_PROXY, PROP_LAST }; @@ -102,9 +99,6 @@ fu_device_get_property (GObject *object, guint prop_id, case PROP_QUIRKS: g_value_set_object (value, priv->quirks); break; - case PROP_PARENT: - g_value_set_object (value, priv->parent); - break; case PROP_PROXY: g_value_set_object (value, priv->proxy); break; @@ -132,9 +126,6 @@ fu_device_set_property (GObject *object, guint prop_id, case PROP_QUIRKS: fu_device_set_quirks (self, g_value_get_object (value)); break; - case PROP_PARENT: - fu_device_set_parent (self, g_value_get_object (value)); - break; case PROP_PROXY: fu_device_set_proxy (self, g_value_get_object (value)); break; @@ -613,9 +604,8 @@ fu_device_set_alternate (FuDevice *self, FuDevice *alternate) FuDevice * fu_device_get_parent (FuDevice *self) { - FuDevicePrivate *priv = GET_PRIVATE (self); g_return_val_if_fail (FU_IS_DEVICE (self), NULL); - return priv->parent; + return FU_DEVICE (fwupd_device_get_parent (FWUPD_DEVICE (self))); } /** @@ -634,12 +624,13 @@ fu_device_get_parent (FuDevice *self) FuDevice * fu_device_get_root (FuDevice *self) { - FuDevicePrivate *priv = GET_PRIVATE (self); + FuDevice *parent; g_return_val_if_fail (FU_IS_DEVICE (self), NULL); - while (priv->parent != NULL) { - self = priv->parent; - priv = GET_PRIVATE (self); - } + do { + parent = fu_device_get_parent (self); + if (parent != NULL) + self = parent; + } while (parent != NULL); return g_object_ref (self); } @@ -659,8 +650,6 @@ fu_device_get_root (FuDevice *self) void fu_device_set_parent (FuDevice *self, FuDevice *parent) { - FuDevicePrivate *priv = GET_PRIVATE (self); - g_return_if_fail (FU_IS_DEVICE (self)); /* if the parent has quirks, make the child inherit it */ @@ -670,15 +659,7 @@ fu_device_set_parent (FuDevice *self, FuDevice *parent) fu_device_set_quirks (self, fu_device_get_quirks (parent)); } - if (priv->parent != NULL) - g_object_remove_weak_pointer (G_OBJECT (priv->parent), (gpointer *) &priv->parent); - if (parent != NULL) - g_object_add_weak_pointer (G_OBJECT (parent), (gpointer *) &priv->parent); - priv->parent = parent; - - /* this is what goes over D-Bus */ - fwupd_device_set_parent_id (FWUPD_DEVICE (self), - parent != NULL ? fu_device_get_id (parent) : NULL); + fwupd_device_set_parent (FWUPD_DEVICE (self), FWUPD_DEVICE (parent)); } /** @@ -743,9 +724,8 @@ fu_device_get_proxy (FuDevice *self) GPtrArray * fu_device_get_children (FuDevice *self) { - FuDevicePrivate *priv = GET_PRIVATE (self); g_return_val_if_fail (FU_IS_DEVICE (self), NULL); - return priv->children; + return fwupd_device_get_children (FWUPD_DEVICE (self)); } /** @@ -762,20 +742,18 @@ void fu_device_add_child (FuDevice *self, FuDevice *child) { FuDevicePrivate *priv = GET_PRIVATE (self); + GPtrArray *children; + g_return_if_fail (FU_IS_DEVICE (self)); g_return_if_fail (FU_IS_DEVICE (child)); /* add if the child does not already exist */ - for (guint i = 0; i < priv->children->len; i++) { - FuDevice *devtmp = g_ptr_array_index (priv->children, i); - if (devtmp == child) - return; - } - g_ptr_array_add (priv->children, g_object_ref (child)); + fwupd_device_add_child (FWUPD_DEVICE (self), FWUPD_DEVICE (child)); /* ensure the parent has the MAX() of the childrens removal delay */ - for (guint i = 0; i < priv->children->len; i++) { - FuDevice *child_tmp = g_ptr_array_index (priv->children, i); + children = fu_device_get_children (self); + for (guint i = 0; i < children->len; i++) { + FuDevice *child_tmp = g_ptr_array_index (children, i); guint remove_delay = fu_device_get_remove_delay (child_tmp); if (remove_delay > priv->remove_delay) { g_debug ("setting remove delay to %u as child is greater than %u", @@ -1627,6 +1605,7 @@ void fu_device_set_id (FuDevice *self, const gchar *id) { FuDevicePrivate *priv = GET_PRIVATE (self); + GPtrArray *children; g_autofree gchar *id_hash = NULL; g_return_if_fail (FU_IS_DEVICE (self)); @@ -1643,8 +1622,9 @@ fu_device_set_id (FuDevice *self, const gchar *id) priv->device_id_valid = TRUE; /* ensure the parent ID is set */ - for (guint i = 0; i < priv->children->len; i++) { - FuDevice *devtmp = g_ptr_array_index (priv->children, i); + children = fu_device_get_children (self); + for (guint i = 0; i < children->len; i++) { + FuDevice *devtmp = g_ptr_array_index (children, i); fwupd_device_set_parent_id (FWUPD_DEVICE (devtmp), id_hash); } } @@ -2342,11 +2322,9 @@ fu_device_add_string (FuDevice *self, guint idt, GString *str) /* print children also */ children = fu_device_get_children (self); - if (children != NULL) { - for (guint i = 0; i < children->len; i++) { - FuDevice *child = g_ptr_array_index (children, i); - fu_device_add_string (child, idt + 1, str); - } + for (guint i = 0; i < children->len; i++) { + FuDevice *child = g_ptr_array_index (children, i); + fu_device_add_string (child, idt + 1, str); } } @@ -2962,7 +2940,7 @@ fu_device_rescan (FuDevice *self, GError **error) void fu_device_convert_instance_ids (FuDevice *self) { - FuDevicePrivate *priv = GET_PRIVATE (self); + GPtrArray *children; GPtrArray *instance_ids = fwupd_device_get_instance_ids (FWUPD_DEVICE (self)); /* OEM specific hardware */ @@ -2975,8 +2953,9 @@ fu_device_convert_instance_ids (FuDevice *self) } /* convert all children too */ - for (guint i = 0; i < priv->children->len; i++) { - FuDevice *devtmp = g_ptr_array_index (priv->children, i); + children = fu_device_get_children (self); + for (guint i = 0; i < children->len; i++) { + FuDevice *devtmp = g_ptr_array_index (children, i); fu_device_convert_instance_ids (devtmp); } } @@ -3351,13 +3330,6 @@ fu_device_class_init (FuDeviceClass *klass) G_PARAM_STATIC_NAME); g_object_class_install_property (object_class, PROP_QUIRKS, pspec); - pspec = g_param_spec_object ("parent", NULL, NULL, - FU_TYPE_DEVICE, - G_PARAM_READWRITE | - G_PARAM_CONSTRUCT | - G_PARAM_STATIC_NAME); - g_object_class_install_property (object_class, PROP_PARENT, pspec); - pspec = g_param_spec_object ("proxy", NULL, NULL, FU_TYPE_DEVICE, G_PARAM_READWRITE | @@ -3371,7 +3343,6 @@ fu_device_init (FuDevice *self) { FuDevicePrivate *priv = GET_PRIVATE (self); priv->order = G_MAXINT; - priv->children = g_ptr_array_new_with_free_func ((GDestroyNotify) g_object_unref); priv->parent_guids = g_ptr_array_new_with_free_func (g_free); priv->possible_plugins = g_ptr_array_new_with_free_func (g_free); priv->retry_recs = g_ptr_array_new_with_free_func (g_free); @@ -3390,8 +3361,6 @@ fu_device_finalize (GObject *object) if (priv->alternate != NULL) g_object_unref (priv->alternate); - if (priv->parent != NULL) - g_object_remove_weak_pointer (G_OBJECT (priv->parent), (gpointer *) &priv->parent); if (priv->proxy != NULL) g_object_remove_weak_pointer (G_OBJECT (priv->proxy), (gpointer *) &priv->proxy); if (priv->quirks != NULL) @@ -3400,7 +3369,6 @@ fu_device_finalize (GObject *object) g_source_remove (priv->poll_id); if (priv->metadata != NULL) g_hash_table_unref (priv->metadata); - g_ptr_array_unref (priv->children); g_ptr_array_unref (priv->parent_guids); g_ptr_array_unref (priv->possible_plugins); g_ptr_array_unref (priv->retry_recs); From 7f2ab39c98c397da1b287fc671b7968cf132ccf2 Mon Sep 17 00:00:00 2001 From: exploide Date: Sun, 1 Nov 2020 12:58:29 +0100 Subject: [PATCH 596/607] updated fish completions to 1.5.0 --- data/fish-completion/fwupdmgr.fish | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) diff --git a/data/fish-completion/fwupdmgr.fish b/data/fish-completion/fwupdmgr.fish index 57e084c59..b1ba41e29 100644 --- a/data/fish-completion/fwupdmgr.fish +++ b/data/fish-completion/fwupdmgr.fish @@ -18,7 +18,8 @@ complete -c fwupdmgr -l version -d 'Show client and daemon versions' complete -c fwupdmgr -l offline -d 'Schedule installation for next reboot when possible' complete -c fwupdmgr -l allow-reinstall -d 'Allow reinstalling existing firmware versions' complete -c fwupdmgr -l allow-older -d 'Allow downgrading firmware versions' -complete -c fwupdmgr -l force -d 'Override warnings and force the action' +complete -c fwupdmgr -l allow-branch-switch -d 'Allow switching firmware branch' +complete -c fwupdmgr -l force -d 'Force the action by relaxing some runtime checks' complete -c fwupdmgr -s y -l assume-yes -d 'Answer yes to all questions' complete -c fwupdmgr -l sign -d 'Sign the uploaded data with the client certificate' complete -c fwupdmgr -l no-unreported-check -d 'Do not check for unreported history' @@ -29,9 +30,11 @@ complete -c fwupdmgr -l no-history -d 'Do not write to the history database' complete -c fwupdmgr -l show-all -d 'Show all results' complete -c fwupdmgr -l disable-ssl-strict -d 'Ignore SSL strict checks when downloading files' complete -c fwupdmgr -l filter -d 'Filter with a set of device flags' +complete -c fwupdmgr -l ignore-power -d 'Ignore requirement of external power source' # complete subcommands complete -c fwupdmgr -n '__fish_use_subcommand' -x -a activate -d 'Activate devices' +complete -c fwupdmgr -n '__fish_use_subcommand' -x -a block-firmware -d 'Blocks a specific firmware from being installed' complete -c fwupdmgr -n '__fish_use_subcommand' -x -a clear-history -d 'Erase all firmware update history' complete -c fwupdmgr -n '__fish_use_subcommand' -x -a clear-offline -d 'Clears any updates scheduled to be updated offline' complete -c fwupdmgr -n '__fish_use_subcommand' -x -a clear-results -d 'Clears the results from the last update' @@ -39,6 +42,7 @@ complete -c fwupdmgr -n '__fish_use_subcommand' -x -a disable-remote -d 'Disable complete -c fwupdmgr -n '__fish_use_subcommand' -x -a downgrade -d 'Downgrades the firmware on a device' complete -c fwupdmgr -n '__fish_use_subcommand' -x -a enable-remote -d 'Enables a given remote' complete -c fwupdmgr -n '__fish_use_subcommand' -x -a get-approved-firmware -d 'Gets the list of approved firmware' +complete -c fwupdmgr -n '__fish_use_subcommand' -x -a get-blocked-firmware -d 'Gets the list of blocked firmware' complete -c fwupdmgr -n '__fish_use_subcommand' -x -a get-details -d 'Gets details about a firmware file' complete -c fwupdmgr -n '__fish_use_subcommand' -x -a get-devices -d 'Get all devices that support firmware updates' complete -c fwupdmgr -n '__fish_use_subcommand' -x -a get-history -d 'Show history of firmware updates' @@ -47,20 +51,22 @@ complete -c fwupdmgr -n '__fish_use_subcommand' -x -a get-remotes -d 'Gets the c complete -c fwupdmgr -n '__fish_use_subcommand' -x -a get-results -d 'Gets the results from the last update' complete -c fwupdmgr -n '__fish_use_subcommand' -x -a get-updates -d 'Gets the list of updates for connected hardware' complete -c fwupdmgr -n '__fish_use_subcommand' -x -a install -d 'Install a firmware file on this hardware' -complete -c fwupdmgr -n '__fish_use_subcommand' -x -a modify-config -d 'Modifies a daemon configuration value.' +complete -c fwupdmgr -n '__fish_use_subcommand' -x -a modify-config -d 'Modifies a daemon configuration value' complete -c fwupdmgr -n '__fish_use_subcommand' -x -a modify-remote -d 'Modifies a given remote' complete -c fwupdmgr -n '__fish_use_subcommand' -x -a refresh -d 'Refresh metadata from remote server' -complete -c fwupdmgr -n '__fish_use_subcommand' -x -a reinstall -d 'Reinstall current firmware on the device.' +complete -c fwupdmgr -n '__fish_use_subcommand' -x -a reinstall -d 'Reinstall current firmware on the device' complete -c fwupdmgr -n '__fish_use_subcommand' -x -a report-history -d 'Share firmware history with the developers' -complete -c fwupdmgr -n '__fish_use_subcommand' -x -a set-approved-firmware -d 'Sets the list of approved firmware.' -complete -c fwupdmgr -n '__fish_use_subcommand' -x -a switch-branch -d 'Switch the firmware branch on the device.' +complete -c fwupdmgr -n '__fish_use_subcommand' -x -a security -d 'Gets the host security attributes' +complete -c fwupdmgr -n '__fish_use_subcommand' -x -a set-approved-firmware -d 'Sets the list of approved firmware' +complete -c fwupdmgr -n '__fish_use_subcommand' -x -a switch-branch -d 'Switch the firmware branch on the device' +complete -c fwupdmgr -n '__fish_use_subcommand' -x -a unblock-firmware -d 'Blocks a specific firmware from being installed' complete -c fwupdmgr -n '__fish_use_subcommand' -x -a unlock -d 'Unlocks the device for firmware access' complete -c fwupdmgr -n '__fish_use_subcommand' -x -a update -d 'Updates all firmware to latest versions available' complete -c fwupdmgr -n '__fish_use_subcommand' -x -a verify -d 'Checks cryptographic hash matches firmware' complete -c fwupdmgr -n '__fish_use_subcommand' -x -a verify-update -d 'Update the stored cryptographic hash with current ROM contents' # commands exclusively consuming device IDs -set -l deviceid_consumers activate clear-results downgrade get-releases get-results reinstall unlock update verify verify-update +set -l deviceid_consumers activate clear-results downgrade get-releases get-results get-updates reinstall switch-branch unlock update verify verify-update # complete device IDs complete -c fwupdmgr -n "__fish_seen_subcommand_from $deviceid_consumers" -x -a "(__fish_fwupdmgr_devices)" # complete files and device IDs From 0c10507219f60e259e144b2068dff32e6dd3cf8c Mon Sep 17 00:00:00 2001 From: exploide Date: Sun, 1 Nov 2020 19:30:58 +0100 Subject: [PATCH 597/607] trivial: fix description of unblock-firmware --- data/fish-completion/fwupdmgr.fish | 2 +- src/fu-util.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/data/fish-completion/fwupdmgr.fish b/data/fish-completion/fwupdmgr.fish index b1ba41e29..3bee509ad 100644 --- a/data/fish-completion/fwupdmgr.fish +++ b/data/fish-completion/fwupdmgr.fish @@ -59,7 +59,7 @@ complete -c fwupdmgr -n '__fish_use_subcommand' -x -a report-history -d 'Share f complete -c fwupdmgr -n '__fish_use_subcommand' -x -a security -d 'Gets the host security attributes' complete -c fwupdmgr -n '__fish_use_subcommand' -x -a set-approved-firmware -d 'Sets the list of approved firmware' complete -c fwupdmgr -n '__fish_use_subcommand' -x -a switch-branch -d 'Switch the firmware branch on the device' -complete -c fwupdmgr -n '__fish_use_subcommand' -x -a unblock-firmware -d 'Blocks a specific firmware from being installed' +complete -c fwupdmgr -n '__fish_use_subcommand' -x -a unblock-firmware -d 'Unblocks a specific firmware from being installed' complete -c fwupdmgr -n '__fish_use_subcommand' -x -a unlock -d 'Unlocks the device for firmware access' complete -c fwupdmgr -n '__fish_use_subcommand' -x -a update -d 'Updates all firmware to latest versions available' complete -c fwupdmgr -n '__fish_use_subcommand' -x -a verify -d 'Checks cryptographic hash matches firmware' diff --git a/src/fu-util.c b/src/fu-util.c index 70c7b8336..190294f16 100644 --- a/src/fu-util.c +++ b/src/fu-util.c @@ -2950,7 +2950,7 @@ main (int argc, char *argv[]) "unblock-firmware", "[CHECKSUM]", /* TRANSLATORS: command description */ - _("Blocks a specific firmware from being installed"), + _("Unblocks a specific firmware from being installed"), fu_util_unblock_firmware); fu_util_cmd_array_add (cmd_array, "get-blocked-firmware", From 1df9b82046ec61442f0a74054e0f76a905503056 Mon Sep 17 00:00:00 2001 From: Richard Hughes Date: Fri, 30 Oct 2020 15:18:45 +0000 Subject: [PATCH 598/607] Show a link to discover more information about a specific plugin failure Fixes bugs like https://github.com/fwupd/fwupd/issues/2531 --- src/fu-tool.c | 15 +++++++++++++-- src/fu-util.c | 17 ++++++++++++++--- 2 files changed, 27 insertions(+), 5 deletions(-) diff --git a/src/fu-tool.c b/src/fu-tool.c index 0bbb293e3..46e4fefd9 100644 --- a/src/fu-tool.c +++ b/src/fu-tool.c @@ -141,16 +141,27 @@ fu_util_show_plugin_warnings (FuUtilPrivate *priv) /* print */ for (guint i = 0; i < 64; i++) { + FwupdPluginFlags flag = (guint64) 1 << i; const gchar *tmp; g_autofree gchar *fmt = NULL; - if ((flags & ((guint64) 1 << i)) == 0) + g_autofree gchar *url= NULL; + g_autoptr(GString) str = g_string_new (NULL); + if ((flags & flag) == 0) continue; tmp = fu_util_plugin_flag_to_string ((guint64) 1 << i); if (tmp == NULL) continue; /* TRANSLATORS: this is a prefix on the console */ fmt = fu_util_term_format (_("WARNING:"), FU_UTIL_TERM_COLOR_RED); - g_printerr ("%s %s\n", fmt, tmp); + g_string_append_printf (str, "%s %s\n", fmt, tmp); + + url = g_strdup_printf ("https://github.com/fwupd/fwupd/wiki/PluginFlag:%s", + fwupd_plugin_flag_to_string (flag)); + g_string_append (str, " "); + /* TRANSLATORS: %s is a link to a website */ + g_string_append_printf (str, _("See %s for more information."), url); + g_string_append (str, "\n"); + g_printerr ("%s", str->str); } } diff --git a/src/fu-util.c b/src/fu-util.c index 190294f16..bc4c7a3c4 100644 --- a/src/fu-util.c +++ b/src/fu-util.c @@ -2663,16 +2663,27 @@ fu_util_show_plugin_warnings (FuUtilPrivate *priv) /* print */ for (guint i = 0; i < 64; i++) { + FwupdPluginFlags flag = (guint64) 1 << i; const gchar *tmp; g_autofree gchar *fmt = NULL; - if ((flags & ((guint64) 1 << i)) == 0) + g_autofree gchar *url= NULL; + g_autoptr(GString) str = g_string_new (NULL); + if ((flags & flag) == 0) continue; - tmp = fu_util_plugin_flag_to_string ((guint64) 1 << i); + tmp = fu_util_plugin_flag_to_string (flag); if (tmp == NULL) continue; /* TRANSLATORS: this is a prefix on the console */ fmt = fu_util_term_format (_("WARNING:"), FU_UTIL_TERM_COLOR_RED); - g_printerr ("%s %s\n", fmt, tmp); + g_string_append_printf (str, "%s %s\n", fmt, tmp); + + url = g_strdup_printf ("https://github.com/fwupd/fwupd/wiki/PluginFlag:%s", + fwupd_plugin_flag_to_string (flag)); + g_string_append (str, " "); + /* TRANSLATORS: %s is a link to a website */ + g_string_append_printf (str, _("See %s for more information."), url); + g_string_append (str, "\n"); + g_printerr ("%s", str->str); } } From f9fcf47749d5f237ef4120ec0000aac3302aed14 Mon Sep 17 00:00:00 2001 From: Richard Hughes Date: Mon, 2 Nov 2020 12:01:41 +0000 Subject: [PATCH 599/607] trivial: Add device tests for the Lenovo 40au0065 device --- .../devices/lenovo-40au0065-vli-tier1.json | 16 ++++++++++++++++ .../devices/lenovo-40au0065-vli-tier2.json | 16 ++++++++++++++++ .../devices/lenovo-40au0065-vli-tier3.json | 16 ++++++++++++++++ 3 files changed, 48 insertions(+) create mode 100644 data/device-tests/devices/lenovo-40au0065-vli-tier1.json create mode 100644 data/device-tests/devices/lenovo-40au0065-vli-tier2.json create mode 100644 data/device-tests/devices/lenovo-40au0065-vli-tier3.json diff --git a/data/device-tests/devices/lenovo-40au0065-vli-tier1.json b/data/device-tests/devices/lenovo-40au0065-vli-tier1.json new file mode 100644 index 000000000..968b07e29 --- /dev/null +++ b/data/device-tests/devices/lenovo-40au0065-vli-tier1.json @@ -0,0 +1,16 @@ +{ + "name": "Lenovo USB-C Mini Dock [VL817]", + "guids": [ + "f281c1df-c3d5-5f8a-984d-e9548ffc95fe" + ], + "releases": [ + { + "version": "4.154", + "file": "c782946a9cf743abc37edefe35dec1b8b2d2a88b29f7058091b0a7ae3fa38e49-Lenovo-Mini_Dock_New.cab" + }, + { + "version": "4.94", + "file": "39da9917934ce162baefa3a67adfccd338bfd054933d6c40c0c887ab0d48e83f-Lenovo-Mini_Dock_Old.cab" + } + ] +} diff --git a/data/device-tests/devices/lenovo-40au0065-vli-tier2.json b/data/device-tests/devices/lenovo-40au0065-vli-tier2.json new file mode 100644 index 000000000..40fe46189 --- /dev/null +++ b/data/device-tests/devices/lenovo-40au0065-vli-tier2.json @@ -0,0 +1,16 @@ +{ + "name": "Lenovo USB-C Mini Dock [VL211]", + "guids": [ + "d636c717-44c4-5fcf-9d7f-b96f9c5f6608" + ], + "releases": [ + { + "version": "4.43", + "file": "c782946a9cf743abc37edefe35dec1b8b2d2a88b29f7058091b0a7ae3fa38e49-Lenovo-Mini_Dock_New.cab" + }, + { + "version": "4.33", + "file": "39da9917934ce162baefa3a67adfccd338bfd054933d6c40c0c887ab0d48e83f-Lenovo-Mini_Dock_Old.cab" + } + ] +} diff --git a/data/device-tests/devices/lenovo-40au0065-vli-tier3.json b/data/device-tests/devices/lenovo-40au0065-vli-tier3.json new file mode 100644 index 000000000..aafa032cb --- /dev/null +++ b/data/device-tests/devices/lenovo-40au0065-vli-tier3.json @@ -0,0 +1,16 @@ +{ + "name": "Lenovo USB-C Mini Dock [VL103]", + "guids": [ + "3ae6610b-5c33-5714-96e3-05735eb9b2a5" + ], + "releases": [ + { + "version": "138.4.24.38", + "file": "c782946a9cf743abc37edefe35dec1b8b2d2a88b29f7058091b0a7ae3fa38e49-Lenovo-Mini_Dock_New.cab" + }, + { + "version": "138.4.23.38", + "file": "39da9917934ce162baefa3a67adfccd338bfd054933d6c40c0c887ab0d48e83f-Lenovo-Mini_Dock_Old.cab" + } + ] +} From c57a8f5726c773a17c5c8b82eb1545d08c713681 Mon Sep 17 00:00:00 2001 From: Richard Hughes Date: Fri, 30 Oct 2020 14:42:42 +0000 Subject: [PATCH 600/607] trivial: Fix GtkDoc for fu_common_get_block_devices() --- libfwupdplugin/fu-common.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/libfwupdplugin/fu-common.c b/libfwupdplugin/fu-common.c index 8c8709a41..dbb6b073f 100644 --- a/libfwupdplugin/fu-common.c +++ b/libfwupdplugin/fu-common.c @@ -2204,9 +2204,7 @@ fu_common_get_block_devices (GDBusConnection *connection, GError **error) * @kind: A volume kind, typically a GUID * @error: A #GError or NULL * - * Call into the plugin's get results routine - * - * Finds all volumes of a specific type + * Finds all volumes of a specific partition type * * Returns: (transfer container) (element-type FuVolume): a #GPtrArray, or %NULL if the kind was not found * From 43417b2a95f706215a0c416acaacd1267c114f4e Mon Sep 17 00:00:00 2001 From: Richard Hughes Date: Fri, 30 Oct 2020 14:46:16 +0000 Subject: [PATCH 601/607] trivial: Return GDBusProxy objects from fu_common_get_block_devices() This allows us to reuse the GDBusConnection without passing it to all places a new interface proxy is created. --- libfwupdplugin/fu-common.c | 82 +++++++++++++++++++++++--------------- 1 file changed, 49 insertions(+), 33 deletions(-) diff --git a/libfwupdplugin/fu-common.c b/libfwupdplugin/fu-common.c index dbb6b073f..23a5b9566 100644 --- a/libfwupdplugin/fu-common.c +++ b/libfwupdplugin/fu-common.c @@ -35,11 +35,12 @@ #include "fu-common.h" #include "fu-volume-private.h" -#define UDISKS_DBUS_SERVICE "org.freedesktop.UDisks2" -#define UDISKS_DBUS_PATH "/org/freedesktop/UDisks2/Manager" -#define UDISKS_DBUS_MANAGER_INTERFACE "org.freedesktop.UDisks2.Manager" -#define UDISKS_DBUS_PART_INTERFACE "org.freedesktop.UDisks2.Partition" -#define UDISKS_DBUS_FILE_INTERFACE "org.freedesktop.UDisks2.Filesystem" +#define UDISKS_DBUS_SERVICE "org.freedesktop.UDisks2" +#define UDISKS_DBUS_PATH "/org/freedesktop/UDisks2/Manager" +#define UDISKS_DBUS_MANAGER_INTERFACE "org.freedesktop.UDisks2.Manager" +#define UDISKS_DBUS_INTERFACE_PARTITION "org.freedesktop.UDisks2.Partition" +#define UDISKS_DBUS_INTERFACE_FILESYSTEM "org.freedesktop.UDisks2.Filesystem" +#define UDISKS_DBUS_INTERFACE_BLOCK "org.freedesktop.UDisks2.Block" /** * SECTION:fu-common @@ -2164,7 +2165,7 @@ fu_common_is_live_media (void) } static GPtrArray * -fu_common_get_block_devices (GDBusConnection *connection, GError **error) +fu_common_get_block_devices (GError **error) { GVariantBuilder builder; const gchar *obj; @@ -2172,7 +2173,13 @@ fu_common_get_block_devices (GDBusConnection *connection, GError **error) g_autoptr(GDBusProxy) proxy = NULL; g_autoptr(GPtrArray) devices = NULL; g_autoptr(GVariantIter) iter = NULL; + g_autoptr(GDBusConnection) connection = NULL; + connection = g_bus_get_sync (G_BUS_TYPE_SYSTEM, NULL, error); + if (connection == NULL) { + g_prefix_error (error, "failed to get system bus: "); + return NULL; + } proxy = g_dbus_proxy_new_sync (connection, G_DBUS_PROXY_FLAGS_NONE, NULL, UDISKS_DBUS_SERVICE, @@ -2191,10 +2198,23 @@ fu_common_get_block_devices (GDBusConnection *connection, GError **error) -1, NULL, error); if (output == NULL) return NULL; - devices = g_ptr_array_new_with_free_func (g_free); + devices = g_ptr_array_new_with_free_func ((GDestroyNotify) g_object_unref); g_variant_get (output, "(ao)", &iter); - while (g_variant_iter_next (iter, "&o", &obj)) - g_ptr_array_add (devices, g_strdup (obj)); + while (g_variant_iter_next (iter, "&o", &obj)) { + g_autoptr(GDBusProxy) proxy_blk = NULL; + proxy_blk = g_dbus_proxy_new_sync (connection, + G_DBUS_PROXY_FLAGS_NONE, NULL, + UDISKS_DBUS_SERVICE, + obj, + UDISKS_DBUS_INTERFACE_BLOCK, + NULL, error); + if (proxy_blk == NULL) { + g_prefix_error (error, "failed to initialize d-bus proxy for %s: ", obj); + return NULL; + } + g_ptr_array_add (devices, g_steal_pointer (&proxy_blk)); + } + return g_steal_pointer (&devices); } @@ -2213,35 +2233,29 @@ fu_common_get_block_devices (GDBusConnection *connection, GError **error) GPtrArray * fu_common_get_volumes_by_kind (const gchar *kind, GError **error) { - g_autoptr(GDBusConnection) connection = NULL; g_autoptr(GPtrArray) devices = NULL; g_autoptr(GPtrArray) volumes = NULL; - connection = g_bus_get_sync (G_BUS_TYPE_SYSTEM, NULL, error); - if (connection == NULL) { - g_prefix_error (error, "failed to get system bus: "); - return NULL; - } - devices = fu_common_get_block_devices (connection, error); + devices = fu_common_get_block_devices (error); if (devices == NULL) return NULL; volumes = g_ptr_array_new_with_free_func ((GDestroyNotify) g_object_unref); for (guint i = 0; i < devices->len; i++) { - const gchar *obj = g_ptr_array_index (devices, i); + GDBusProxy *proxy_blk = g_ptr_array_index (devices, i); const gchar *type_str; g_autoptr(GDBusProxy) proxy_part = NULL; - g_autoptr(GDBusProxy) proxy_file = NULL; - g_autoptr(GError) error_local = NULL; + g_autoptr(GDBusProxy) proxy_fs = NULL; g_autoptr(GVariant) val = NULL; - proxy_part = g_dbus_proxy_new_sync (connection, + proxy_part = g_dbus_proxy_new_sync (g_dbus_proxy_get_connection (proxy_blk), G_DBUS_PROXY_FLAGS_NONE, NULL, UDISKS_DBUS_SERVICE, - obj, - UDISKS_DBUS_PART_INTERFACE, + g_dbus_proxy_get_object_path (proxy_blk), + UDISKS_DBUS_INTERFACE_PARTITION, NULL, error); if (proxy_part == NULL) { - g_prefix_error (error, "failed to initialize d-bus proxy %s: ", obj); + g_prefix_error (error, "failed to initialize d-bus proxy %s: ", + g_dbus_proxy_get_object_path (proxy_blk)); return NULL; } val = g_dbus_proxy_get_cached_property (proxy_part, "Type"); @@ -2249,20 +2263,22 @@ fu_common_get_volumes_by_kind (const gchar *kind, GError **error) continue; g_variant_get (val, "&s", &type_str); - g_debug ("device %s, type: %s", obj, type_str); + g_debug ("device %s, type: %s", + g_dbus_proxy_get_object_path (proxy_blk), type_str); if (g_strcmp0 (type_str, kind) != 0) continue; - proxy_file = g_dbus_proxy_new_sync (connection, - G_DBUS_PROXY_FLAGS_NONE, NULL, - UDISKS_DBUS_SERVICE, - obj, - UDISKS_DBUS_FILE_INTERFACE, - NULL, error); - if (proxy_file == NULL) { - g_prefix_error (error, "failed to initialize d-bus proxy %s: ", obj); + proxy_fs = g_dbus_proxy_new_sync (g_dbus_proxy_get_connection (proxy_blk), + G_DBUS_PROXY_FLAGS_NONE, NULL, + UDISKS_DBUS_SERVICE, + g_dbus_proxy_get_object_path (proxy_blk), + UDISKS_DBUS_INTERFACE_FILESYSTEM, + NULL, error); + if (proxy_fs == NULL) { + g_prefix_error (error, "failed to initialize d-bus proxy %s: ", + g_dbus_proxy_get_object_path (proxy_blk)); return NULL; } - g_ptr_array_add (volumes, fu_volume_new_from_proxy (proxy_file)); + g_ptr_array_add (volumes, fu_volume_new_from_proxy (proxy_fs)); } if (volumes->len == 0) { g_set_error (error, From f3993a6b9692b1e3815a1de7c688dd77e9c9347e Mon Sep 17 00:00:00 2001 From: Richard Hughes Date: Fri, 30 Oct 2020 14:49:52 +0000 Subject: [PATCH 602/607] trivial: Add GObject properties to FuVolume This will allow us to add other properties in the future. --- libfwupdplugin/fu-common.c | 5 +- libfwupdplugin/fu-volume-private.h | 3 +- libfwupdplugin/fu-volume.c | 89 +++++++++++++++++++++++------- 3 files changed, 75 insertions(+), 22 deletions(-) diff --git a/libfwupdplugin/fu-common.c b/libfwupdplugin/fu-common.c index 23a5b9566..4533565b2 100644 --- a/libfwupdplugin/fu-common.c +++ b/libfwupdplugin/fu-common.c @@ -2278,7 +2278,10 @@ fu_common_get_volumes_by_kind (const gchar *kind, GError **error) g_dbus_proxy_get_object_path (proxy_blk)); return NULL; } - g_ptr_array_add (volumes, fu_volume_new_from_proxy (proxy_fs)); + g_ptr_array_add (volumes, + g_object_new (FU_TYPE_VOLUME, + "proxy-filesystem", proxy_fs, + NULL)); } if (volumes->len == 0) { g_set_error (error, diff --git a/libfwupdplugin/fu-volume-private.h b/libfwupdplugin/fu-volume-private.h index 88d6f6699..d1c8f99c3 100644 --- a/libfwupdplugin/fu-volume-private.h +++ b/libfwupdplugin/fu-volume-private.h @@ -7,9 +7,8 @@ #pragma once -#include +#include #include "fu-volume.h" -FuVolume *fu_volume_new_from_proxy (GDBusProxy *proxy); FuVolume *fu_volume_new_from_mount_path (const gchar *mount_path); diff --git a/libfwupdplugin/fu-volume.c b/libfwupdplugin/fu-volume.c index 0ce53c511..097875667 100644 --- a/libfwupdplugin/fu-volume.c +++ b/libfwupdplugin/fu-volume.c @@ -23,10 +23,17 @@ struct _FuVolume { GObject parent_instance; - GDBusProxy *proxy; + GDBusProxy *proxy_fs; gchar *mount_path; /* only when mounted ourselves */ }; +enum { + PROP_0, + PROP_MOUNT_PATH, + PROP_PROXY_FILESYSTEM, + PROP_LAST +}; + G_DEFINE_TYPE (FuVolume, fu_volume, G_TYPE_OBJECT) static void @@ -34,16 +41,68 @@ fu_volume_finalize (GObject *obj) { FuVolume *self = FU_VOLUME (obj); g_free (self->mount_path); - if (self->proxy != NULL) - g_object_unref (self->proxy); + if (self->proxy_fs != NULL) + g_object_unref (self->proxy_fs); G_OBJECT_CLASS (fu_volume_parent_class)->finalize (obj); } +static void +fu_volume_get_property (GObject *object, guint prop_id, + GValue *value, GParamSpec *pspec) +{ + FuVolume *self = FU_VOLUME (object); + switch (prop_id) { + case PROP_MOUNT_PATH: + g_value_set_string (value, self->mount_path); + break; + case PROP_PROXY_FILESYSTEM: + g_value_set_object (value, self->proxy_fs); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} + +static void +fu_volume_set_property (GObject *object, guint prop_id, + const GValue *value, GParamSpec *pspec) +{ + FuVolume *self = FU_VOLUME (object); + switch (prop_id) { + case PROP_MOUNT_PATH: + self->mount_path = g_value_dup_string (value); + break; + case PROP_PROXY_FILESYSTEM: + self->proxy_fs = g_value_dup_object (value); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} + static void fu_volume_class_init (FuVolumeClass *klass) { + GParamSpec *pspec; GObjectClass *object_class = G_OBJECT_CLASS (klass); + object_class->finalize = fu_volume_finalize; + object_class->get_property = fu_volume_get_property; + object_class->set_property = fu_volume_set_property; + + pspec = g_param_spec_object ("proxy-filesystem", NULL, NULL, G_TYPE_DBUS_PROXY, + G_PARAM_CONSTRUCT_ONLY | + G_PARAM_READWRITE | + G_PARAM_STATIC_NAME); + g_object_class_install_property (object_class, PROP_PROXY_FILESYSTEM, pspec); + + pspec = g_param_spec_string ("mount-path", NULL, NULL, NULL, + G_PARAM_CONSTRUCT_ONLY | + G_PARAM_READWRITE | + G_PARAM_STATIC_NAME); + g_object_class_install_property (object_class, PROP_MOUNT_PATH, pspec); } static void @@ -65,7 +124,7 @@ const gchar * fu_volume_get_id (FuVolume *self) { g_return_val_if_fail (FU_IS_VOLUME (self), NULL); - return g_dbus_proxy_get_object_path (self->proxy); + return g_dbus_proxy_get_object_path (self->proxy_fs); } /** @@ -92,7 +151,9 @@ fu_volume_get_mount_point (FuVolume *self) return g_strdup (self->mount_path); /* something else mounted it */ - val = g_dbus_proxy_get_cached_property (self->proxy, "MountPoints"); + if (self->proxy_fs == NULL) + return NULL; + val = g_dbus_proxy_get_cached_property (self->proxy_fs, "MountPoints"); if (val == NULL) return NULL; mountpoints = g_variant_get_bytestring_array (val, NULL); @@ -185,12 +246,12 @@ fu_volume_mount (FuVolume *self, GError **error) g_return_val_if_fail (FU_IS_VOLUME (self), FALSE); /* device from the self tests */ - if (self->proxy == NULL) + if (self->proxy_fs == NULL) return TRUE; g_debug ("mounting %s", fu_volume_get_id (self)); g_variant_builder_init (&builder, G_VARIANT_TYPE_VARDICT); - val = g_dbus_proxy_call_sync (self->proxy, + val = g_dbus_proxy_call_sync (self->proxy_fs, "Mount", g_variant_new ("(a{sv})", &builder), G_DBUS_CALL_FLAGS_NONE, -1, NULL, error); @@ -220,12 +281,12 @@ fu_volume_unmount (FuVolume *self, GError **error) g_return_val_if_fail (FU_IS_VOLUME (self), FALSE); /* device from the self tests */ - if (self->proxy == NULL) + if (self->proxy_fs == NULL) return TRUE; g_debug ("unmounting %s", fu_volume_get_id (self)); g_variant_builder_init (&builder, G_VARIANT_TYPE_VARDICT); - val = g_dbus_proxy_call_sync (self->proxy, + val = g_dbus_proxy_call_sync (self->proxy_fs, "Unmount", g_variant_new ("(a{sv})", &builder), G_DBUS_CALL_FLAGS_NONE, @@ -261,16 +322,6 @@ fu_volume_locker (FuVolume *self, GError **error) error); } -/* private */ -FuVolume * -fu_volume_new_from_proxy (GDBusProxy *proxy) -{ - g_autoptr(FuVolume) self = g_object_new (FU_TYPE_VOLUME, NULL); - g_return_val_if_fail (proxy != NULL, NULL); - g_set_object (&self->proxy, proxy); - return g_steal_pointer (&self); -} - /* private */ FuVolume * fu_volume_new_from_mount_path (const gchar *mount_path) From 2b188c8488bc96a1894e0789563ca83efa2222e8 Mon Sep 17 00:00:00 2001 From: Richard Hughes Date: Fri, 30 Oct 2020 14:52:36 +0000 Subject: [PATCH 603/607] trivial: Export if the volume is encrypted This requires passing in the udisks block proxy when creating the object. --- libfwupdplugin/fu-common.c | 1 + libfwupdplugin/fu-volume.c | 50 ++++++++++++++++++++++++++++++++-- libfwupdplugin/fu-volume.h | 1 + libfwupdplugin/fwupdplugin.map | 1 + 4 files changed, 51 insertions(+), 2 deletions(-) diff --git a/libfwupdplugin/fu-common.c b/libfwupdplugin/fu-common.c index 4533565b2..6b3140898 100644 --- a/libfwupdplugin/fu-common.c +++ b/libfwupdplugin/fu-common.c @@ -2280,6 +2280,7 @@ fu_common_get_volumes_by_kind (const gchar *kind, GError **error) } g_ptr_array_add (volumes, g_object_new (FU_TYPE_VOLUME, + "proxy-block", proxy_blk, "proxy-filesystem", proxy_fs, NULL)); } diff --git a/libfwupdplugin/fu-volume.c b/libfwupdplugin/fu-volume.c index 097875667..55ef98762 100644 --- a/libfwupdplugin/fu-volume.c +++ b/libfwupdplugin/fu-volume.c @@ -23,6 +23,7 @@ struct _FuVolume { GObject parent_instance; + GDBusProxy *proxy_blk; GDBusProxy *proxy_fs; gchar *mount_path; /* only when mounted ourselves */ }; @@ -30,6 +31,7 @@ struct _FuVolume { enum { PROP_0, PROP_MOUNT_PATH, + PROP_PROXY_BLOCK, PROP_PROXY_FILESYSTEM, PROP_LAST }; @@ -41,6 +43,8 @@ fu_volume_finalize (GObject *obj) { FuVolume *self = FU_VOLUME (obj); g_free (self->mount_path); + if (self->proxy_blk != NULL) + g_object_unref (self->proxy_blk); if (self->proxy_fs != NULL) g_object_unref (self->proxy_fs); G_OBJECT_CLASS (fu_volume_parent_class)->finalize (obj); @@ -55,6 +59,9 @@ fu_volume_get_property (GObject *object, guint prop_id, case PROP_MOUNT_PATH: g_value_set_string (value, self->mount_path); break; + case PROP_PROXY_BLOCK: + g_value_set_object (value, self->proxy_blk); + break; case PROP_PROXY_FILESYSTEM: g_value_set_object (value, self->proxy_fs); break; @@ -73,6 +80,9 @@ fu_volume_set_property (GObject *object, guint prop_id, case PROP_MOUNT_PATH: self->mount_path = g_value_dup_string (value); break; + case PROP_PROXY_BLOCK: + self->proxy_blk = g_value_dup_object (value); + break; case PROP_PROXY_FILESYSTEM: self->proxy_fs = g_value_dup_object (value); break; @@ -92,6 +102,12 @@ fu_volume_class_init (FuVolumeClass *klass) object_class->get_property = fu_volume_get_property; object_class->set_property = fu_volume_set_property; + pspec = g_param_spec_object ("proxy-block", NULL, NULL, G_TYPE_DBUS_PROXY, + G_PARAM_CONSTRUCT_ONLY | + G_PARAM_READWRITE | + G_PARAM_STATIC_NAME); + g_object_class_install_property (object_class, PROP_PROXY_BLOCK, pspec); + pspec = g_param_spec_object ("proxy-filesystem", NULL, NULL, G_TYPE_DBUS_PROXY, G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE | @@ -124,7 +140,11 @@ const gchar * fu_volume_get_id (FuVolume *self) { g_return_val_if_fail (FU_IS_VOLUME (self), NULL); - return g_dbus_proxy_get_object_path (self->proxy_fs); + if (self->proxy_fs != NULL) + return g_dbus_proxy_get_object_path (self->proxy_fs); + if (self->proxy_blk != NULL) + return g_dbus_proxy_get_object_path (self->proxy_blk); + return NULL; } /** @@ -142,7 +162,6 @@ fu_volume_get_mount_point (FuVolume *self) { g_autofree const gchar **mountpoints = NULL; g_autoptr(GVariant) val = NULL; - g_autoptr(GError) error_local = NULL; g_return_val_if_fail (FU_IS_VOLUME (self), NULL); @@ -226,6 +245,33 @@ fu_volume_is_mounted (FuVolume *self) return mount_point != NULL; } +/** + * fu_volume_is_encrypted: + * @self: a @FuVolume + * + * Checks if the VOLUME is currently encrypted. + * + * Returns: %TRUE for success + * + * Since: 1.5.1 + **/ +gboolean +fu_volume_is_encrypted (FuVolume *self) +{ + g_autoptr(GVariant) val = NULL; + + g_return_val_if_fail (FU_IS_VOLUME (self), FALSE); + + if (self->proxy_blk == NULL) + return FALSE; + val = g_dbus_proxy_get_cached_property (self->proxy_blk, "CryptoBackingDevice"); + if (val == NULL) + return FALSE; + if (g_strcmp0 (g_variant_get_string (val, NULL), "/") == 0) + return FALSE; + return TRUE; +} + /** * fu_volume_mount: * @self: a @FuVolume diff --git a/libfwupdplugin/fu-volume.h b/libfwupdplugin/fu-volume.h index 5d1340799..0f12edf9c 100644 --- a/libfwupdplugin/fu-volume.h +++ b/libfwupdplugin/fu-volume.h @@ -22,6 +22,7 @@ gboolean fu_volume_check_free_space (FuVolume *self, guint64 required, GError **error); gboolean fu_volume_is_mounted (FuVolume *self); +gboolean fu_volume_is_encrypted (FuVolume *self); gchar *fu_volume_get_mount_point (FuVolume *self); gboolean fu_volume_mount (FuVolume *self, GError **error); diff --git a/libfwupdplugin/fwupdplugin.map b/libfwupdplugin/fwupdplugin.map index 2856a7862..31e049d9f 100644 --- a/libfwupdplugin/fwupdplugin.map +++ b/libfwupdplugin/fwupdplugin.map @@ -674,5 +674,6 @@ LIBFWUPDPLUGIN_1.5.1 { global: fu_device_add_possible_plugin; fu_efivar_space_used; + fu_volume_is_encrypted; local: *; } LIBFWUPDPLUGIN_1.5.0; From 0bdf561035f4a4f83f33f16b19f4d17b58fb5161 Mon Sep 17 00:00:00 2001 From: Richard Hughes Date: Fri, 30 Oct 2020 14:56:22 +0000 Subject: [PATCH 604/607] Use UDisks to find out if swap devices are encrypted Using a heuristic is certainly not awesome. --- libfwupdplugin/fu-common.c | 92 ++++++++++++++++++++++++- libfwupdplugin/fu-common.h | 4 ++ libfwupdplugin/fwupdplugin.map | 2 + plugins/linux-swap/fu-linux-swap.c | 106 ++++++++++++++++++++++++++--- plugins/linux-swap/fu-self-test.c | 17 ++++- 5 files changed, 209 insertions(+), 12 deletions(-) diff --git a/libfwupdplugin/fu-common.c b/libfwupdplugin/fu-common.c index 6b3140898..01b688a08 100644 --- a/libfwupdplugin/fu-common.c +++ b/libfwupdplugin/fu-common.c @@ -2196,8 +2196,14 @@ fu_common_get_block_devices (GError **error) g_variant_new ("(a{sv})", &builder), G_DBUS_CALL_FLAGS_NONE, -1, NULL, error); - if (output == NULL) + if (output == NULL) { + if (error != NULL) + g_dbus_error_strip_remote_error (*error); + g_prefix_error (error, "failed to call %s.%s(): ", + UDISKS_DBUS_SERVICE, + "GetBlockDevices"); return NULL; + } devices = g_ptr_array_new_with_free_func ((GDestroyNotify) g_object_unref); g_variant_get (output, "(ao)", &iter); while (g_variant_iter_next (iter, "&o", &obj)) { @@ -2294,6 +2300,90 @@ fu_common_get_volumes_by_kind (const gchar *kind, GError **error) return g_steal_pointer (&volumes); } +/** + * fu_common_get_volume_by_device: + * @device: A device string, typcically starting with `/dev/` + * @error: A #GError or NULL + * + * Finds the first volume from the specified device. + * + * Returns: (transfer full): a #GPtrArray, or %NULL if the kind was not found + * + * Since: 1.5.1 + **/ +FuVolume * +fu_common_get_volume_by_device (const gchar *device, GError **error) +{ + g_autoptr(GPtrArray) devices = NULL; + + /* find matching block device */ + devices = fu_common_get_block_devices (error); + if (devices == NULL) + return NULL; + for (guint i = 0; i < devices->len; i++) { + GDBusProxy *proxy_blk = g_ptr_array_index (devices, i); + g_autoptr(GVariant) val = NULL; + val = g_dbus_proxy_get_cached_property (proxy_blk, "Device"); + if (val == NULL) + continue; + if (g_strcmp0 (g_variant_get_bytestring (val), device) == 0) { + return g_object_new (FU_TYPE_VOLUME, + "proxy-block", proxy_blk, + NULL); + } + } + + /* failed */ + g_set_error (error, + G_IO_ERROR, + G_IO_ERROR_NOT_FOUND, + "no volumes for device %s", + device); + return NULL; +} + +/** + * fu_common_get_volume_by_devnum: + * @devicenum: A device number + * @error: A #GError or NULL + * + * Finds the first volume from the specified device. + * + * Returns: (transfer full): a #GPtrArray, or %NULL if the kind was not found + * + * Since: 1.5.1 + **/ +FuVolume * +fu_common_get_volume_by_devnum (guint32 devnum, GError **error) +{ + g_autoptr(GPtrArray) devices = NULL; + + /* find matching block device */ + devices = fu_common_get_block_devices (error); + if (devices == NULL) + return NULL; + for (guint i = 0; i < devices->len; i++) { + GDBusProxy *proxy_blk = g_ptr_array_index (devices, i); + g_autoptr(GVariant) val = NULL; + val = g_dbus_proxy_get_cached_property (proxy_blk, "DeviceNumber"); + if (val == NULL) + continue; + if (devnum == g_variant_get_uint64 (val)) { + return g_object_new (FU_TYPE_VOLUME, + "proxy-block", proxy_blk, + NULL); + } + } + + /* failed */ + g_set_error (error, + G_IO_ERROR, + G_IO_ERROR_NOT_FOUND, + "no volumes for devnum %u", + devnum); + return NULL; +} + /** * fu_common_get_esp_default: * @error: A #GError or NULL diff --git a/libfwupdplugin/fu-common.h b/libfwupdplugin/fu-common.h index 97c4638ba..8a454fa0d 100644 --- a/libfwupdplugin/fu-common.h +++ b/libfwupdplugin/fu-common.h @@ -238,6 +238,10 @@ gboolean fu_common_is_cpu_intel (void); gboolean fu_common_is_live_media (void); GPtrArray *fu_common_get_volumes_by_kind (const gchar *kind, GError **error); +FuVolume *fu_common_get_volume_by_device (const gchar *device, + GError **error); +FuVolume *fu_common_get_volume_by_devnum (guint32 devnum, + GError **error); FuVolume *fu_common_get_esp_for_path (const gchar *esp_path, GError **error); FuVolume *fu_common_get_esp_default (GError **error); diff --git a/libfwupdplugin/fwupdplugin.map b/libfwupdplugin/fwupdplugin.map index 31e049d9f..a58bcc015 100644 --- a/libfwupdplugin/fwupdplugin.map +++ b/libfwupdplugin/fwupdplugin.map @@ -672,6 +672,8 @@ LIBFWUPDPLUGIN_1.5.0 { LIBFWUPDPLUGIN_1.5.1 { global: + fu_common_get_volume_by_device; + fu_common_get_volume_by_devnum; fu_device_add_possible_plugin; fu_efivar_space_used; fu_volume_is_encrypted; diff --git a/plugins/linux-swap/fu-linux-swap.c b/plugins/linux-swap/fu-linux-swap.c index fd7aab915..12e724dc0 100644 --- a/plugins/linux-swap/fu-linux-swap.c +++ b/plugins/linux-swap/fu-linux-swap.c @@ -13,46 +13,134 @@ struct _FuLinuxSwap { GObject parent_instance; - gboolean encrypted; - gboolean enabled; + guint encrypted_cnt; + guint enabled_cnt; }; G_DEFINE_TYPE (FuLinuxSwap, fu_linux_swap, G_TYPE_OBJECT) +static gchar * +fu_strdup_nospaces (const gchar *line) +{ + GString *str = g_string_new (NULL); + for (guint i = 0; line[i] != '\0' && !g_ascii_isspace (line[i]); i++) + g_string_append_c (str, line[i]); + return g_string_free (str, FALSE); +} + +static gboolean +fu_linux_swap_verify_partition (FuLinuxSwap *self, const gchar *fn, GError **error) +{ + g_autoptr(FuVolume) volume = NULL; + + /* find the device */ + volume = fu_common_get_volume_by_device (fn, error); + if (volume == NULL) + return FALSE; + + /* this isn't technically encrypted, but isn't on disk in plaintext */ + if (g_str_has_prefix (fn, "/dev/zram")) { + g_debug ("%s is zram, assuming encrypted", fn); + self->encrypted_cnt++; + return TRUE; + } + + /* is this mount point encrypted */ + if (fu_volume_is_encrypted (volume)) { + g_debug ("%s partition is encrypted", fn); + self->encrypted_cnt++; + } else { + g_debug ("%s partition is unencrypted", fn); + } + + /* success */ + return TRUE; +} + +static gboolean +fu_linux_swap_verify_file (FuLinuxSwap *self, const gchar *fn, GError **error) +{ + guint32 devnum; + g_autoptr(GFile) file = NULL; + g_autoptr(GFileInfo) info = NULL; + g_autoptr(FuVolume) volume = NULL; + + /* get the device number for the file */ + file = g_file_new_for_path (fn); + info = g_file_query_info (file, G_FILE_ATTRIBUTE_UNIX_DEVICE, + G_FILE_QUERY_INFO_NONE, NULL, error); + if (info == NULL) + return FALSE; + devnum = g_file_info_get_attribute_uint32 (info, G_FILE_ATTRIBUTE_UNIX_DEVICE); + + /* find the device */ + volume = fu_common_get_volume_by_devnum (devnum, error); + if (volume == NULL) + return FALSE; + + /* is this mount point encrypted */ + if (fu_volume_is_encrypted (volume)) { + g_debug ("%s file is encrypted", fn); + self->encrypted_cnt++; + } else { + g_debug ("%s file is unencrypted", fn); + } + + /* success */ + return TRUE; +} + FuLinuxSwap * fu_linux_swap_new (const gchar *buf, gsize bufsz, GError **error) { FuLinuxSwap *self = g_object_new (FU_TYPE_LINUX_SWAP, NULL); g_auto(GStrv) lines = NULL; + /* look at each line in /proc/swaps */ if (bufsz == 0) bufsz = strlen (buf); lines = fu_common_strnsplit (buf, bufsz, "\n", -1); if (g_strv_length (lines) > 2) { - self->enabled = TRUE; for (guint i = 1; lines[i] != NULL && lines[i][0] != '\0'; i++) { - if (g_str_has_prefix (lines[i], "/dev/dm-") || - g_str_has_prefix (lines[i], "/dev/mapper")) { - self->encrypted = TRUE; - break; + g_autofree gchar *fn = NULL; + g_autofree gchar *ty = NULL; + + /* split */ + if (g_utf8_strlen (lines[i], -1) < 45) + continue; + fn = fu_strdup_nospaces (lines[i]); + ty = fu_strdup_nospaces (lines[i] + 40); + + /* partition, so use UDisks to see if backed by crypto */ + if (g_strcmp0 (ty, "partition") == 0) { + self->enabled_cnt++; + if (!fu_linux_swap_verify_partition (self, fn, error)) + return NULL; + } else if (g_strcmp0 (ty, "file") == 0) { + self->enabled_cnt++; + if (!fu_linux_swap_verify_file (self, fn, error)) + return NULL; + } else { + g_warning ("unknown swap type: %s [%s]", ty, fn); } } } return self; } +/* success if *all* the swap devices are encrypted */ gboolean fu_linux_swap_get_encrypted (FuLinuxSwap *self) { g_return_val_if_fail (FU_IS_LINUX_SWAP (self), FALSE); - return self->encrypted; + return self->enabled_cnt > 0 && self->enabled_cnt == self->encrypted_cnt; } gboolean fu_linux_swap_get_enabled (FuLinuxSwap *self) { g_return_val_if_fail (FU_IS_LINUX_SWAP (self), FALSE); - return self->enabled; + return self->enabled_cnt > 0; } static void diff --git a/plugins/linux-swap/fu-self-test.c b/plugins/linux-swap/fu-self-test.c index fccc3f457..3d02805d8 100644 --- a/plugins/linux-swap/fu-self-test.c +++ b/plugins/linux-swap/fu-self-test.c @@ -32,8 +32,16 @@ fu_linux_swap_plain_func (void) g_autoptr(GError) error = NULL; swap = fu_linux_swap_new ("Filename\t\t\t\tType\t\tSize\tUsed\tPriority\n" - "/dev/nvme0n1p4 partition\t5962748\t0\t-2\n", + "/dev/nvme0n1p4 partition\t5962748\t0\t-2\n", 0, &error); + if (g_error_matches (error, G_IO_ERROR, G_IO_ERROR_NOT_FOUND)) { + g_test_skip (error->message); + return; + } + if (g_error_matches (error, G_DBUS_ERROR, G_DBUS_ERROR_SERVICE_UNKNOWN)) { + g_test_skip (error->message); + return; + } g_assert_no_error (error); g_assert_nonnull (swap); g_assert_true (fu_linux_swap_get_enabled (swap)); @@ -47,8 +55,13 @@ fu_linux_swap_encrypted_func (void) g_autoptr(GError) error = NULL; swap = fu_linux_swap_new ("Filename\t\t\t\tType\t\tSize\tUsed\tPriority\n" - "/dev/dm-1 partition\t5962748\t0\t-2\n", + "/dev/dm-1 partition\t5962748\t0\t-2\n", 0, &error); + if (g_error_matches (error, G_IO_ERROR, G_IO_ERROR_NOT_FOUND) || + g_error_matches (error, G_DBUS_ERROR, G_DBUS_ERROR_SERVICE_UNKNOWN)) { + g_test_skip (error->message); + return; + } g_assert_no_error (error); g_assert_nonnull (swap); g_assert_true (fu_linux_swap_get_enabled (swap)); From bde99ef4bc73a3f2161b83b5f3522ecc58fc9f90 Mon Sep 17 00:00:00 2001 From: Richard Hughes Date: Mon, 2 Nov 2020 13:34:08 +0000 Subject: [PATCH 605/607] trivial: Fix Debian CI failure --- contrib/ci/debian.sh | 3 +++ 1 file changed, 3 insertions(+) diff --git a/contrib/ci/debian.sh b/contrib/ci/debian.sh index 64d77c6ae..782c49e60 100755 --- a/contrib/ci/debian.sh +++ b/contrib/ci/debian.sh @@ -2,6 +2,9 @@ set -e set -x +# remove when tpm2-tss is fixed +mkdir -p /usr/include/tss + #although it's debian, we don't build packages if [ "$OS" = "debian-s390x" ]; then ./contrib/ci/debian_s390x.sh From 203ed841da7bddc12bd73eab71f7f9a88404ca31 Mon Sep 17 00:00:00 2001 From: Richard Hughes Date: Mon, 2 Nov 2020 14:25:13 +0000 Subject: [PATCH 606/607] trivial: Codespell fixes --- README.md | 4 ++-- SECURITY.md | 2 +- contrib/firmware_packager/firmware_packager.py | 4 ++-- data/fish-completion/fwupdmgr.fish | 2 +- data/org.freedesktop.fwupd.metainfo.xml | 2 +- libfwupdplugin/fu-plugin.c | 4 ++-- libfwupdplugin/fu-quirks.c | 2 +- libfwupdplugin/fu-security-attrs.c | 4 ++-- libfwupdplugin/fu-self-test.c | 10 +++++----- meson.build | 14 ++++++++++++++ plugins/bcm57xx/fu-bcm57xx-common.c | 2 +- plugins/bcm57xx/fu-bcm57xx-device.c | 4 ++-- plugins/bcm57xx/fu-bcm57xx-recovery-device.c | 2 +- plugins/dell/fu-self-test.c | 2 +- plugins/wacom-usb/README.md | 2 +- po/make-images | 8 ++++---- src/fu-history.c | 2 +- 17 files changed, 42 insertions(+), 28 deletions(-) diff --git a/README.md b/README.md index 9bcafb0fa..b5548e714 100644 --- a/README.md +++ b/README.md @@ -78,7 +78,7 @@ Enterprise use The flow of updates can be controlled in the enterprise using the "approved updates" feature. This allows the domain administrator to filter the possible updates from a central server (e.g. the LVFS, or a mirror) -to only firmware that have been tested specifically in your organisation. +to only firmware that have been tested specifically in your organization. The list of approved updates can be enabled by adding `ApprovalRequired=true` to the remote configuration file, e.g. `lvfs.conf`. Once enabled, the @@ -103,7 +103,7 @@ Other frontends After the firmware has been downloaded a popup will be displayed in GNOME Software to perform the update. -2. [KDE Discover](https://userbase.kde.org/Discover) is the software centre, +2. [KDE Discover](https://userbase.kde.org/Discover) is the software center, generally bundled with KDE Plasma. With the release of [KDE Plasma 5.14](https://www.kde.org/announcements/plasma-5.14.0.php), a new fwupd backend has been implemented in KDE Discover for firmware updates. diff --git a/SECURITY.md b/SECURITY.md index 850248c95..a09bbd58a 100644 --- a/SECURITY.md +++ b/SECURITY.md @@ -31,5 +31,5 @@ this repository. Failing that, please report the issue against the `fwupd` component in Red Hat bugzilla, with the security checkbox set. You should get a response within 3 -days. We have no bug bountry program, but we're happy to credit you in updates +days. We have no bug bounty program, but we're happy to credit you in updates if this is what you would like us to do. diff --git a/contrib/firmware_packager/firmware_packager.py b/contrib/firmware_packager/firmware_packager.py index 45b268ebe..4deaafc5d 100755 --- a/contrib/firmware_packager/firmware_packager.py +++ b/contrib/firmware_packager/firmware_packager.py @@ -1,6 +1,6 @@ #!/usr/bin/python3 # -# Copyright (C) 2017 Max Ehrlich max.ehr@gmail.com +# Copyright (C) 2017 Max Ehrlich maxehr@gmail.com # # SPDX-License-Identifier: LGPL-2.1+ # @@ -107,7 +107,7 @@ def main(args): print('Creating metainfo') make_firmware_metainfo(args, dir) - print('Cabbing firmware files') + print('Creating cabinet file') create_firmware_cab(args, dir) print('Done') diff --git a/data/fish-completion/fwupdmgr.fish b/data/fish-completion/fwupdmgr.fish index 3bee509ad..b63bbcf86 100644 --- a/data/fish-completion/fwupdmgr.fish +++ b/data/fish-completion/fwupdmgr.fish @@ -28,7 +28,7 @@ complete -c fwupdmgr -l no-reboot-check -d 'Do not check for reboot after update complete -c fwupdmgr -l no-safety-check -d 'Do not perform device safety checks' complete -c fwupdmgr -l no-history -d 'Do not write to the history database' complete -c fwupdmgr -l show-all -d 'Show all results' -complete -c fwupdmgr -l disable-ssl-strict -d 'Ignore SSL strict checks when downloading files' +complete -c fwupdmgr -l disable-ssl-strict -d 'Ignore SSL strict checks when downloading' complete -c fwupdmgr -l filter -d 'Filter with a set of device flags' complete -c fwupdmgr -l ignore-power -d 'Ignore requirement of external power source' diff --git a/data/org.freedesktop.fwupd.metainfo.xml b/data/org.freedesktop.fwupd.metainfo.xml index 9bf3afd7f..0027d85cd 100644 --- a/data/org.freedesktop.fwupd.metainfo.xml +++ b/data/org.freedesktop.fwupd.metainfo.xml @@ -54,7 +54,7 @@
    31. Add support for ThunderBolt retimers
    32. Add switch-branch command to fwupdtool and fwupdmgr
    33. Allow blocking specific firmware releases by checksum
    34. -
    35. Allow contructing a firmware with multiple images
    36. +
    37. Allow constructing a firmware with multiple images
    38. Allow firmware to require specific features from front-end clients
    39. Allow updating the dbx using the LVFS, validating it is safe to apply
    40. Include the HSI results and attributes in the uploaded report
    41. diff --git a/libfwupdplugin/fu-plugin.c b/libfwupdplugin/fu-plugin.c index a13a64518..d24f6a740 100644 --- a/libfwupdplugin/fu-plugin.c +++ b/libfwupdplugin/fu-plugin.c @@ -452,7 +452,7 @@ fu_plugin_open (FuPlugin *self, const gchar *filename, GError **error) return TRUE; } -/* order of usefullness to the user */ +/* order of usefulness to the user */ static const gchar * fu_plugin_build_device_update_error (FuPlugin *self) { @@ -1020,7 +1020,7 @@ fu_plugin_set_smbios (FuPlugin *self, FuSmbios *smbios) * * Set the minimum time that should be waited in-between the call to * fu_plugin_coldplug_prepare() and fu_plugin_coldplug(). This is usually going - * to be the minimum hardware initialisation time from a datasheet. + * to be the minimum hardware initialization time from a datasheet. * * It is better to use this function rather than using a sleep() in the plugin * itself as then only one delay is done in the daemon rather than waiting for diff --git a/libfwupdplugin/fu-quirks.c b/libfwupdplugin/fu-quirks.c index 792534d25..1ed3cf669 100644 --- a/libfwupdplugin/fu-quirks.c +++ b/libfwupdplugin/fu-quirks.c @@ -25,7 +25,7 @@ * SECTION:fu-quirks * @short_description: device quirks * - * Quirks can be used to modify device behaviour. + * Quirks can be used to modify device behavior. * When fwupd is installed in long-term support distros it's very hard to * backport new versions as new hardware is released. * diff --git a/libfwupdplugin/fu-security-attrs.c b/libfwupdplugin/fu-security-attrs.c index d6df40ca8..b35835f95 100644 --- a/libfwupdplugin/fu-security-attrs.c +++ b/libfwupdplugin/fu-security-attrs.c @@ -17,7 +17,7 @@ struct _FuSecurityAttrs { GPtrArray *attrs; }; -/* probaly sane to *not* make this part of the ABI */ +/* probably sane to *not* make this part of the ABI */ #define FWUPD_SECURITY_ATTR_ID_DOC_URL "https://fwupd.github.io/hsi.html" G_DEFINE_TYPE (FuSecurityAttrs, fu_security_attrs, G_TYPE_OBJECT) @@ -145,7 +145,7 @@ fu_security_attrs_remove_all (FuSecurityAttrs *self) * @self: A #FuSecurityAttrs * @flags: Flags to use while calcuating the HSI * - * Calculates the HSI string from the appended attribues. + * Calculates the HSI string from the appended attributes. * * Returns: (transfer full): a string or %NULL * diff --git a/libfwupdplugin/fu-self-test.c b/libfwupdplugin/fu-self-test.c index 6d808e2e6..20de92455 100644 --- a/libfwupdplugin/fu-self-test.c +++ b/libfwupdplugin/fu-self-test.c @@ -221,14 +221,14 @@ fu_device_metadata_func (void) g_assert_false (fu_device_get_metadata_boolean (device, "unknown")); /* integer */ - fu_device_set_metadata_integer (device, "dum", 12345); - g_assert_cmpstr (fu_device_get_metadata (device, "dum"), ==, "12345"); - g_assert_cmpint (fu_device_get_metadata_integer (device, "dum"), ==, 12345); + fu_device_set_metadata_integer (device, "bam", 12345); + g_assert_cmpstr (fu_device_get_metadata (device, "bam"), ==, "12345"); + g_assert_cmpint (fu_device_get_metadata_integer (device, "bam"), ==, 12345); g_assert_cmpint (fu_device_get_metadata_integer (device, "unknown"), ==, G_MAXUINT); /* broken integer */ - fu_device_set_metadata (device, "dum", "123junk"); - g_assert_cmpint (fu_device_get_metadata_integer (device, "dum"), ==, G_MAXUINT); + fu_device_set_metadata (device, "bam", "123junk"); + g_assert_cmpint (fu_device_get_metadata_integer (device, "bam"), ==, G_MAXUINT); fu_device_set_metadata (device, "huge", "4294967296"); /* not 32 bit */ g_assert_cmpint (fu_device_get_metadata_integer (device, "huge"), ==, G_MAXUINT); } diff --git a/meson.build b/meson.build index 1a61ed197..1996f1cb4 100644 --- a/meson.build +++ b/meson.build @@ -477,3 +477,17 @@ if makensis.found() join_paths(meson.source_root(), 'contrib', 'setup-win32.nsi'), ]) endif + +codespell = find_program('codespell', required : false) +if codespell.found() +run_target('codespell', + command: [ + codespell, + meson.source_root(), + '--write-changes', + '--builtin', 'en-GB_to_en-US', + '--skip', '*.po,*.csv,*.svg,*.p7c,subprojects,.git,pcrs,build*', + '--ignore-words-list', 'conexant,Conexant,gir,GIR,hsi,HSI,cancelled,Cancelled', + ] +) +endif diff --git a/plugins/bcm57xx/fu-bcm57xx-common.c b/plugins/bcm57xx/fu-bcm57xx-common.c index be2068db9..42434c661 100644 --- a/plugins/bcm57xx/fu-bcm57xx-common.c +++ b/plugins/bcm57xx/fu-bcm57xx-common.c @@ -91,7 +91,7 @@ fu_bcm57xx_veritem_new (const guint8 *buf, gsize bufsz) { NULL, NULL, 0 } }; - /* dont assume this is NUL terminated */ + /* do not assume this is NUL terminated */ tmp = g_strndup ((const gchar *) buf, bufsz); if (tmp == NULL || tmp[0] == '\0') return NULL; diff --git a/plugins/bcm57xx/fu-bcm57xx-device.c b/plugins/bcm57xx/fu-bcm57xx-device.c index 5e2907e4a..b06cc66bd 100644 --- a/plugins/bcm57xx/fu-bcm57xx-device.c +++ b/plugins/bcm57xx/fu-bcm57xx-device.c @@ -426,7 +426,7 @@ fu_bcm57xx_device_prepare_firmware (FuDevice *device, } if (g_getenv ("FWUPD_BCM57XX_VERBOSE") != NULL) { g_autofree gchar *str = fu_firmware_to_string (firmware); - g_debug ("existing device firware: %s", str); + g_debug ("existing device firmware: %s", str); } /* merge in all the provided images into the existing firmware */ @@ -451,7 +451,7 @@ fu_bcm57xx_device_prepare_firmware (FuDevice *device, } if (g_getenv ("FWUPD_BCM57XX_VERBOSE") != NULL) { g_autofree gchar *str = fu_firmware_to_string (firmware); - g_debug ("proposed device firware: %s", str); + g_debug ("proposed device firmware: %s", str); } /* success */ diff --git a/plugins/bcm57xx/fu-bcm57xx-recovery-device.c b/plugins/bcm57xx/fu-bcm57xx-recovery-device.c index 7616f75d3..a2e4d12f2 100644 --- a/plugins/bcm57xx/fu-bcm57xx-recovery-device.c +++ b/plugins/bcm57xx/fu-bcm57xx-recovery-device.c @@ -668,7 +668,7 @@ fu_bcm57xx_recovery_device_open (FuDevice *device, GError **error) g_set_error (error, G_IO_ERROR, G_IO_ERROR_NOT_SUPPORTED, - "cound not mmap %s: %s", + "could not mmap %s: %s", fn, strerror(errno)); return FALSE; } diff --git a/plugins/dell/fu-self-test.c b/plugins/dell/fu-self-test.c index 159673f1c..007092086 100644 --- a/plugins/dell/fu-self-test.c +++ b/plugins/dell/fu-self-test.c @@ -526,7 +526,7 @@ main (int argc, char **argv) /* change path */ g_setenv ("FWUPD_SYSFSFWDIR", TESTDATADIR, TRUE); - /* change behaviour */ + /* change behavior */ sysfsdir = fu_common_get_path (FU_PATH_KIND_SYSFSDIR_FW); g_setenv ("FWUPD_UEFI_ESP_PATH", sysfsdir, TRUE); g_setenv ("FWUPD_UEFI_TEST", "1", TRUE); diff --git a/plugins/wacom-usb/README.md b/plugins/wacom-usb/README.md index 46eaddfc6..5f75ba0e3 100644 --- a/plugins/wacom-usb/README.md +++ b/plugins/wacom-usb/README.md @@ -9,7 +9,7 @@ inspire everyone make the world a more creative place. From 2016 Wacom has been using a HID-based proprietary flashing algorithm which has been documented by support team at Wacom and provided under NDA under the -understanding it would be used to build a plugin under a LGPLv2+ licence. +understanding it would be used to build a plugin under a LGPLv2+ license. Wacom devices are actually composite devices, with the main ARM CPU being programmed using a more complicated erase, write, verify algorithm based diff --git a/po/make-images b/po/make-images index 8394e16eb..b1097bc25 100755 --- a/po/make-images +++ b/po/make-images @@ -66,8 +66,8 @@ class Rasterizer: font_desc = "Sans %fpx" % (height / 32,) fd = Pango.FontDescription(font_desc) - fo = cairo.FontOptions() - fo.set_antialias(cairo.ANTIALIAS_SUBPIXEL) + font_option = cairo.FontOptions() + font_option.set_antialias(cairo.ANTIALIAS_SUBPIXEL) l = Pango.Language.from_string(language) img = cairo.ImageSurface(cairo.FORMAT_RGB24, 1, 1) @@ -77,7 +77,7 @@ class Rasterizer: pctx.set_font_description(fd) pctx.set_language(l) fs = pctx.load_fontset(fd, l) - PangoCairo.context_set_font_options(pctx, fo) + PangoCairo.context_set_font_options(pctx, font_option) attrs = Pango.AttrList() length = len(bytes(string, "utf8")) @@ -112,7 +112,7 @@ class Rasterizer: cctx = cairo.Context(img) layout = PangoCairo.create_layout(cctx) pctx = layout.get_context() - PangoCairo.context_set_font_options(pctx, fo) + PangoCairo.context_set_font_options(pctx, font_option) cctx.set_source_rgb(1, 1, 1) cctx.move_to(x, y) diff --git a/src/fu-history.c b/src/fu-history.c index 703e37d94..25627ed6e 100644 --- a/src/fu-history.c +++ b/src/fu-history.c @@ -288,7 +288,7 @@ fu_history_migrate_database_v5 (FuHistory *self, GError **error) return TRUE; } -/* returns 0 if database is not initialised */ +/* returns 0 if database is not initialized */ static guint fu_history_get_schema_version (FuHistory *self) { From bbb1a8136ec3fb88a659cb2ac632128f516d13ad Mon Sep 17 00:00:00 2001 From: Richard Hughes Date: Mon, 2 Nov 2020 14:52:43 +0000 Subject: [PATCH 607/607] Release fwupd 1.5.1 --- .editorconfig | 14 ++ data/org.freedesktop.fwupd.metainfo.xml | 20 ++ po/cs.po | 190 ++++++++++++++++ po/en_GB.po | 4 + po/fi.po | 98 +++++++++ po/it.po | 86 ++++++++ po/lt.po | 4 + po/sv.po | 278 ++++++++++++++++++++++++ po/uk.po | 4 + 9 files changed, 698 insertions(+) create mode 100644 .editorconfig diff --git a/.editorconfig b/.editorconfig new file mode 100644 index 000000000..8abc7283f --- /dev/null +++ b/.editorconfig @@ -0,0 +1,14 @@ +root = true + +[*] +charset = utf-8 +end_of_line = lf + +[*.py] +indent_style = space +indent_size = 4 + +[*.{c|h}] +indent_style = tab +indent_size = 8 + diff --git a/data/org.freedesktop.fwupd.metainfo.xml b/data/org.freedesktop.fwupd.metainfo.xml index 0027d85cd..c912e26a5 100644 --- a/data/org.freedesktop.fwupd.metainfo.xml +++ b/data/org.freedesktop.fwupd.metainfo.xml @@ -35,6 +35,26 @@ fwupdagent + + +

      This release adds the following features:

      +
        +
      • Include the amount of NVRAM size in use in the LVFS failure report
      • +
      +

      This release fixes the following bugs:

      +
        +
      • Delete unused EFI variables when deploying firmware
      • +
      • Fix probe warning for the Logitech Unifying device
      • +
      • Make bcm57xx hotplug more reliable
      • +
      • Recognize authorized thunderbolt value of 2
      • +
      • Remove the duplicate parent-child data in FwupdDevice and FuDevice
      • +
      • Show a less scary fwupdate output for devices without info
      • +
      • Show a link to discover more information about a specific plugin failure
      • +
      • Use a different Device ID for the OptionROM devices
      • +
      • Use UDisks to find out if swap devices are encrypted
      • +
      +
      +

      This release adds the following features:

      diff --git a/po/cs.po b/po/cs.po index d36cce475..6e5dd07c2 100644 --- a/po/cs.po +++ b/po/cs.po @@ -117,6 +117,15 @@ msgstr "%s verze %s" msgid "%s version" msgstr "Verze %s" +#. TRANSLATORS: duration in days! +#, c-format +msgid "%u day" +msgid_plural "%u days" +msgstr[0] "%u den" +msgstr[1] "%u dny" +msgstr[2] "%u dnů" +msgstr[3] "%u dny" + #, c-format msgid "%u device has a firmware upgrade available." msgid_plural "%u devices have a firmware upgrade available." @@ -125,6 +134,24 @@ msgstr[1] "Jsou k dispozici novější firmware pro %u zařízení." msgstr[2] "Jsou k dispozici novější firmware pro %u zařízení." msgstr[3] "Jsou k dispozici novější firmware pro %u zařízení." +#. TRANSLATORS: duration in minutes +#, c-format +msgid "%u hour" +msgid_plural "%u hours" +msgstr[0] "%u hodina" +msgstr[1] "%u hodiny" +msgstr[2] "%u hodin" +msgstr[3] "%u hodiny" + +#. TRANSLATORS: duration in minutes +#, c-format +msgid "%u minute" +msgid_plural "%u minutes" +msgstr[0] "%u minuta" +msgstr[1] "%u minuty" +msgstr[2] "%u minut" +msgstr[3] "%u minuty" + #. TRANSLATORS: duration in seconds #, c-format msgid "%u second" @@ -134,6 +161,10 @@ msgstr[1] "%u sekundy" msgstr[2] "%u sekund" msgstr[3] "%u sekundy" +#. TRANSLATORS: command description +msgid "Activate devices" +msgstr "Aktivovat zařízení" + #. TRANSLATORS: command description msgid "Activate pending devices" msgstr "Aktivovat čekající zařízení" @@ -275,10 +306,18 @@ msgstr "Pokaždé automaticky nahrát?" msgid "Bind new kernel driver" msgstr "Napojit nový ovladač jádra" +#. TRANSLATORS: there follows a list of hashes +msgid "Blocked firmware files:" +msgstr "Blokované soubory s firmware:" + #. TRANSLATORS: we will not offer this firmware to the user msgid "Blocking firmware:" msgstr "Blokuje se firmware:" +#. TRANSLATORS: command description +msgid "Blocks a specific firmware from being installed" +msgstr "Blokuje instalaci konkrétního firmware" + #. TRANSLATORS: command description msgid "Build a firmware file" msgstr "Sestavit soubor s firmware" @@ -353,6 +392,10 @@ msgstr "Pokračovat v aktualizaci?" msgid "Convert a firmware file" msgstr "Převést soubor s firmware" +#. TRANSLATORS: Device supports some form of checksum verification +msgid "Cryptographic hash verification is available" +msgstr "Je k dispozici kryptografické ověření otisku" + #. TRANSLATORS: DFU stands for device firmware update msgid "DFU Utility" msgstr "Nástroj pro práci s DFU" @@ -373,6 +416,10 @@ msgstr "Popis" msgid "Detach to bootloader mode" msgstr "Odpojit do režimu zavaděče" +#. TRANSLATORS: ID for hardware, typically a SHA1 sum +msgid "Device ID" +msgstr "Identifikátor zařízení" + #. TRANSLATORS: this is when a device is hotplugged msgid "Device added:" msgstr "Přidáno zařízení:" @@ -381,10 +428,22 @@ msgstr "Přidáno zařízení:" msgid "Device changed:" msgstr "Změněno zařízení:" +#. TRANSLATORS: Is locked and can be unlocked +msgid "Device is locked" +msgstr "Zařízení je uzamčeno" + #. TRANSLATORS: this is when a device is hotplugged msgid "Device removed:" msgstr "Odebráno zařízení:" +#. TRANSLATORS: Device update needs to be separately activated +msgid "Device update needs activation" +msgstr "Zařízení je pro aktualizaci třeba aktivovat" + +#. TRANSLATORS: Device will not return after update completes +msgid "Device will not re-appear after update completes" +msgstr "Po dokončení aktualizace se zařízení hned znovu neobjeví" + #. TRANSLATORS: a list of successful updates msgid "Devices that have been updated successfully:" msgstr "Zařízení, která byla úspěšně aktualizována:" @@ -457,6 +516,11 @@ msgstr "Přejít na nižší verzi firmwaru na zařízení" msgid "Downgrading %s from %s to %s... " msgstr "Převádí se %s z verze %s na %s…" +#. TRANSLATORS: %1 is a device name +#, c-format +msgid "Downgrading %s…" +msgstr "Vracení %s na starší verzi…" + #. TRANSLATORS: downloading from a remote server msgid "Downloading…" msgstr "Stahuje se…" @@ -521,6 +585,10 @@ msgstr "Skončit po krátké prodlevě" msgid "Exit after the engine has loaded" msgstr "Skončit po načtení výkonné části" +#. TRANSLATORS: command description +msgid "Extract a firmware blob to images" +msgstr "Rozbalit firmware z blobu do obrazů" + #. TRANSLATORS: Suffix: the fallback HSI result msgid "Failed" msgstr "Nezdařilo se" @@ -566,6 +634,10 @@ msgstr "Selhalo zpracování argumentů" msgid "Failed to parse file" msgstr "Soubor se nepodařilo zpracovat" +#. TRANSLATORS: the user didn't read the man page +msgid "Failed to parse flags for --filter" +msgstr "Nepodařilo se zpracovat příznaky pro --filter" + #. TRANSLATORS: could not parse file msgid "Failed to parse local dbx" msgstr "Nepodařilo se zpracovat místní dbx" @@ -681,6 +753,14 @@ msgstr "Vypsat nastavené vzdálené zdroje" msgid "Gets the host security attributes" msgstr "Zjistit atributy zabezpečení hostitele" +#. TRANSLATORS: firmware approved by the admin +msgid "Gets the list of approved firmware" +msgstr "Získá seznam schválených firmware" + +#. TRANSLATORS: command description +msgid "Gets the list of blocked firmware" +msgstr "Získá seznam blokovaných firmware" + #. TRANSLATORS: command description msgid "Gets the list of updates for connected hardware" msgstr "Vypsat seznam aktualizací pro připojený hardware" @@ -693,6 +773,10 @@ msgstr "Vypsat vydání pro zařízení" msgid "Gets the results from the last update" msgstr "Vypsat výsledky z poslední aktualizace" +#. TRANSLATORS: The hardware is waiting to be replugged +msgid "Hardware is waiting to be replugged" +msgstr "Hardware čeká na opětovné připojení" + #. TRANSLATORS: this is a string like 'HSI:2-U' msgid "Host Security ID:" msgstr "Identifikátor zabezpečení hostitele:" @@ -722,6 +806,10 @@ msgstr "Ignorovat neshody firmware s hardware" msgid "Ignore requirement of external power source" msgstr "Ignorovat požadavek na přítomnost externího napájení" +#. TRANSLATORS: Ignore validation safety checks when flashing this device +msgid "Ignore validation safety checks" +msgstr "Ignorovat výsledky kontrol ověření" + #. TRANSLATORS: command description msgid "Install a firmware blob on a device" msgstr "Nainstalovat na zařízení binární soubor s firmwarem" @@ -739,6 +827,10 @@ msgstr "Instalace podepsaného firmwaru zařízení" msgid "Install signed system firmware" msgstr "Instalace podepsaného systémového firmwaru" +#. TRANSLATORS: Install composite firmware on the parent before the child +msgid "Install to parent device first" +msgstr "Nejprve nainstalovat do nadřazeného zařízení" + msgid "Install unsigned device firmware" msgstr "Instalace nepodepsaného firmwaru zařízení" @@ -791,10 +883,18 @@ msgstr "Ladící nástroj Intel DCI" msgid "Intel SMAP" msgstr "Intel SMAP" +#. TRANSLATORS: Device cannot be removed easily +msgid "Internal device" +msgstr "Vestavěné zařízení" + #. TRANSLATORS: Suffix: the HSI result msgid "Invalid" msgstr "Neplatné" +#. TRANSLATORS: Is currently in bootloader mode +msgid "Is in bootloader mode" +msgstr "Je v režimu zavaděče" + msgid "Keyring" msgstr "Klíčenka" @@ -828,6 +928,14 @@ msgstr "Vypsat položky v dbx" msgid "List supported firmware updates" msgstr "Vypsat podporované aktualizace firmwarů" +#. TRANSLATORS: command description +msgid "List the available firmware types" +msgstr "Vypsat typy firmware, které jsou k dispozici" + +#. TRANSLATORS: command description +msgid "Lists files on the ESP" +msgstr "Vypíše soubory na ESP oddílu" + #. TRANSLATORS: parsing the firmware information msgid "Loading…" msgstr "Načítá se…" @@ -865,6 +973,18 @@ msgstr "Upravit nastavení procesu služby" msgid "Monitor the daemon for events" msgstr "Sledovat události démona" +#. TRANSLATORS: command description +msgid "Mounts the ESP" +msgstr "Připojí ESP oddíl" + +#. TRANSLATORS: Requires a reboot to apply firmware or to reload hardware +msgid "Needs a reboot after installation" +msgstr "Po instalaci vyžaduje restart" + +#. TRANSLATORS: Requires system shutdown to apply firmware +msgid "Needs shutdown after installation" +msgstr "Po instalaci vyžaduje vypnutí" + #. TRANSLATORS: user did not tell the tool what to do msgid "No action specified!" msgstr "Není určena žádné akce!" @@ -887,10 +1007,18 @@ msgstr "Nebylo nalezeno žádné zařízení schopné aktualizace firmwaru" msgid "No plugins found" msgstr "Nebyl nalezen žádný zásuvný modul" +#. TRANSLATORS: no repositories to download from +msgid "No releases available" +msgstr "Nejsou k dispozici žádná vydání" + #. TRANSLATORS: explain why no metadata available msgid "No remotes are currently enabled so no metadata is available." msgstr "Zrovna nejsou povolené žádné vzdálené zdroje, takže nejsou k dispozici žádná metadata." +#. TRANSLATORS: no repositories to download from +msgid "No remotes available" +msgstr "Nejsou k dispozici žádné protějšky" + #. TRANSLATORS: nothing was updated offline msgid "No updates were applied" msgstr "Nebyly nainstalovány žádné aktualizace" @@ -997,6 +1125,10 @@ msgstr "Restartování…" msgid "Refresh metadata from remote server" msgstr "Aktualizovat metadata ze vzdáleného serveru" +#. TRANSLATORS: command description +msgid "Reinstall current firmware on the device" +msgstr "Přeinstaluje stávající firmware na zařízení" + #. TRANSLATORS: command description msgid "Reinstall firmware on a device" msgstr "Přeinstalovat firmware na zařízení" @@ -1025,6 +1157,14 @@ msgstr "Nahradit data ve stávajícím souboru s firmwarem" msgid "Report URI" msgstr "URI hlášení" +#. TRANSLATORS: Has been reported to a metadata server +msgid "Reported to remote server" +msgstr "Nahlášeno na vzdálený server" + +#. TRANSLATORS: Requires a bootloader mode to be manually enabled by the user +msgid "Requires a bootloader" +msgstr "Vyžaduje zavaděč systému" + #. TRANSLATORS: metadata is downloaded from the Internet msgid "Requires internet connection" msgstr "Vyžaduje připojení k Internetu" @@ -1147,6 +1287,9 @@ msgctxt "command-description" msgid "Sign data using the client certificate" msgstr "Podepsat data klientským certifikátem" +msgid "Signature" +msgstr "Podpis" + msgid "Specify Vendor/Product ID(s) of DFU device" msgstr "Zadejte identifikátor(y) výrobce/produktu DFU zařízení" @@ -1166,6 +1309,10 @@ msgstr "Všechna zařízení úspěšně aktivována" msgid "Successfully modified configuration value" msgstr "Hodnota v nastavení úspěšně změněna" +#. TRANSLATORS: success message when user refreshes device checksums +msgid "Successfully updated device checksums" +msgstr "Kontrolní součty zařízení úspěšně zaktualizovány" + #. TRANSLATORS: one line summary of device msgid "Summary" msgstr "Souhrn" @@ -1174,6 +1321,14 @@ msgstr "Souhrn" msgid "Supported" msgstr "Podporováno" +#. TRANSLATORS: Is found in current metadata +msgid "Supported on remote server" +msgstr "Podporováno na vzdáleném serveru" + +#. TRANSLATORS: Must be plugged in to an outlet +msgid "System requires external power source" +msgstr "Počítač vyžaduje externí napájení" + #. TRANSLATORS: Title: the PCR is rebuilt from the TPM event log msgid "TPM PCR0 reconstruction" msgstr "Rekonstrukce TPM PCR0" @@ -1189,6 +1344,10 @@ msgstr "Cíl" msgid "The LVFS is a free service that operates as an independent legal entity and has no connection with $OS_RELEASE:NAME$. Your distributor may not have verified any of the firmware updates for compatibility with your system or connected devices. All firmware is provided only by the original equipment manufacturer." msgstr "LVFS je svobodná služba, které funguje jako nezávislý právní subjekt a nemá žádné vazby na systém $OS_RELEASE:NAME$. Váš distributor nemusí některé z aktualizací firmwaru schválit kvůli kompatibilitě s vaším systémem nebo připojenými zařízeními. Veškerý firmware je poskytován pouze přímo výrobci daných zařízení." +#. TRANSLATORS: the user is SOL for support... +msgid "The daemon has loaded 3rd party code and is no longer supported by the upstream developers!" +msgstr "Proces služby načetl kód třetí strany a není už podporován původními vývojáři!" + #. TRANSLATORS: nothing to show msgid "There are no blocked firmware files" msgstr "Nejsou zde žádné blokované soubory s firmware" @@ -1247,6 +1406,10 @@ msgstr "Nešifrované" msgid "Unknown" msgstr "Neznámý" +#. TRANSLATORS: Name of hardware +msgid "Unknown Device" +msgstr "Neznámé zařízení" + msgid "Unlock the device to allow access" msgstr "Odemknutí zařízení pro umožnění přístupu" @@ -1258,6 +1421,10 @@ msgstr "Odemčené" msgid "Unlocks the device for firmware access" msgstr "Odemknout zařízení pro přístup k firmwaru" +#. TRANSLATORS: command description +msgid "Unmounts the ESP" +msgstr "Odpojí ESP oddíl" + #. TRANSLATORS: command line option msgid "Unset the debugging flag during update" msgstr "Během aktualizace zrušit příznak ladění" @@ -1267,6 +1434,10 @@ msgstr "Během aktualizace zrušit příznak ladění" msgid "Unsupported daemon version %s, client version is %s" msgstr "Nepodporovaná verze procesu služby %s, verze klienta je %s" +#. TRANSLATORS: Device is updatable in this or any other mode +msgid "Updatable" +msgstr "Možné aktualizovat" + #. TRANSLATORS: command description msgid "Update all devices that match local metadata" msgstr "Aktualizovat veškerá zařízení, která se shodují s místními metadaty" @@ -1279,6 +1450,10 @@ msgstr "O selhání aktualizace se ví, více informací najdete na této adrese msgid "Update now?" msgstr "Aktualizovat nyní?" +#. TRANSLATORS: Update can only be done from offline mode +msgid "Update requires a reboot" +msgstr "Aktualizace vyžaduje restart" + msgid "Update the stored device verification information" msgstr "Aktualizace uložené informace o ověření zařízení" @@ -1290,6 +1465,9 @@ msgstr "Aktualizovat uložená metadata stávajícím obsahem" msgid "Updates all firmware to latest versions available" msgstr "Aktualizovat všechen firmware na nejnovější dostupné verze" +msgid "Updating" +msgstr "Aktualizuje se" + #. TRANSLATORS: the first replacement is a display name #. * e.g. "ColorHugALS" and the second and third are #. * version numbers e.g. "1.2.3" @@ -1314,10 +1492,18 @@ msgstr "Když nahrajete hlášení o firmwaru, pomůžete tím výrobcům hardwa msgid "Use fwupdmgr --help for help" msgstr "Pro zobrazení nápovědy použijte příkaz fwupdmgr --help" +#. TRANSLATORS: error message explaining command to run to how to get help +msgid "Use fwupdtool --help for help" +msgstr "Nápovědu obdržíte spuštěním fwupdtool --help" + #. TRANSLATORS: command line option msgid "Use quirk flags when installing firmware" msgstr "Při instalaci firmware použít příznaky pro kompatibilitu" +#. TRANSLATORS: User has been notified +msgid "User has been notified" +msgstr "Uživatel byl upozorněn" + #. TRANSLATORS: remote filename base msgid "Username" msgstr "Uživatelské jméno" @@ -1374,6 +1560,10 @@ msgstr "Zapisuje se…" msgid "Your distributor may not have verified any of the firmware updates for compatibility with your system or connected devices." msgstr "Váš distributor nemusí schválit některé aktualizace firmwaru kvůli kompatibilitě s vaším systémem nebo připojenými zařízeními." +#. TRANSLATORS: this is the default branch name when unset +msgid "default" +msgstr "výchozí" + #. TRANSLATORS: program name msgid "fwupd TPM event log utility" msgstr "fwupd nástroj pro záznamy událostí v TPM" diff --git a/po/en_GB.po b/po/en_GB.po index d1a3e46a2..bc1463ea2 100644 --- a/po/en_GB.po +++ b/po/en_GB.po @@ -1732,6 +1732,10 @@ msgstr "Unbind current driver" msgid "Unblocking firmware:" msgstr "Unblocking firmware:" +#. TRANSLATORS: command description +msgid "Unblocks a specific firmware from being installed" +msgstr "Unblocks a specific firmware from being installed" + #. TRANSLATORS: Suffix: the HSI result msgid "Unencrypted" msgstr "Unencrypted" diff --git a/po/fi.po b/po/fi.po index f4dc06f50..98de5cb20 100644 --- a/po/fi.po +++ b/po/fi.po @@ -332,10 +332,18 @@ msgstr "Estetyt laiteohjelmiston tiedostot:" msgid "Blocking firmware:" msgstr "Laiteohjelmiston estäminen:" +#. TRANSLATORS: command description +msgid "Blocks a specific firmware from being installed" +msgstr "Estää tietyn laiteohjelmiston asentamisen" + #. TRANSLATORS: firmware version of bootloader msgid "Bootloader Version" msgstr "Käynnistyslataimen versio" +#. TRANSLATORS: the stream of firmware, e.g. nonfree or open-source +msgid "Branch" +msgstr "Haara" + #. TRANSLATORS: command description msgid "Build a firmware file" msgstr "Luo laiteohjelmiston tiedosto" @@ -498,10 +506,18 @@ msgstr "Laite poistettu:" msgid "Device stages updates" msgstr "Laitevyöhykkeen päivitykset" +#. TRANSLATORS: there is more than one supplier of the firmware +msgid "Device supports switching to a different branch of firmware" +msgstr "Laite tukee vaihtamista toiseen laiteohjelmiston haaraan" + #. TRANSLATORS: Device update needs to be separately activated msgid "Device update needs activation" msgstr "Laitteen päivitys tarvitsee aktivointia" +#. TRANSLATORS: save the old firmware to disk before installing the new one +msgid "Device will backup firmware before installing" +msgstr "Laite varmuuskopioi laiteohjelmiston ennen asennusta" + #. TRANSLATORS: Device will not return after update completes msgid "Device will not re-appear after update completes" msgstr "Laitetta ei näytetä uudelleen päivityksen päätyttyä" @@ -577,6 +593,10 @@ msgstr[1] "Älä lähetä raportteja äläkä koskaan pyydä lähettämään rap msgid "Do not write to the history database" msgstr "Älä kirjoita historiatietokantaan" +#. TRANSLATORS: should the branch be changed +msgid "Do you understand the consequences of changing the firmware branch?" +msgstr "Ymmärrätkö laiteohjelmiston haaran vaihtamisen seuraukset?" + #. TRANSLATORS: success #. success msgid "Done!" @@ -666,6 +686,10 @@ msgstr "Poistu pienen viiveen jälkeen" msgid "Exit after the engine has loaded" msgstr "Poistu kun moottori on ladattu" +#. TRANSLATORS: command description +msgid "Extract a firmware blob to images" +msgstr "Laiteohjelmiston blob purkaminen kuvaksi " + #. TRANSLATORS: Suffix: the fallback HSI result msgid "Failed" msgstr "Epäonnistui" @@ -772,6 +796,10 @@ msgstr "Firmware-työkalu" msgid "Firmware attestation" msgstr "Firmware-aitoustodistus" +#. TRANSLATORS: system is not booted in UEFI mode +msgid "Firmware can not be updated in legacy BIOS mode" +msgstr "Laiteohjelmistoa ei voi päivittää legacy BIOS-tilassa" + #. TRANSLATORS: user selected something not possible msgid "Firmware is already blocked" msgstr "Laiteohjelmisto on jo estetty" @@ -797,6 +825,10 @@ msgstr "Ohjelmistopäivitys 'firmware' ei tue tätä laitetta" msgid "Firmware updates are supported on this machine." msgstr "Ohjelmistopäivitys 'firmware' tukee tätä laitetta" +#. TRANSLATORS: user needs to run a command +msgid "Firmware updates disabled; run 'fwupdmgr unlock' to enable" +msgstr "Laiteohjelmiston päivitykset poistettu käytöstä; suorita 'fwupdmgr unlock' ottaaksesi käyttöön" + #. TRANSLATORS: description of plugin state, e.g. disabled #. TRANSLATORS: release properties msgid "Flags" @@ -847,6 +879,14 @@ msgstr "Määrittää konfiguroidut etäyhteydet" msgid "Gets the host security attributes" msgstr "Hanki tietoturvan määritteet" +#. TRANSLATORS: firmware approved by the admin +msgid "Gets the list of approved firmware" +msgstr "Hae hyväksytty laiteohjelmiston luettelo" + +#. TRANSLATORS: command description +msgid "Gets the list of blocked firmware" +msgstr "Hakee estettyjen laiteohjelmistojen luettelon" + #. TRANSLATORS: command description msgid "Gets the list of updates for connected hardware" msgstr "Antaa luettelon liitettyjen laitteiden päivityksistä" @@ -900,6 +940,10 @@ msgstr "Ohita ulkoisen virtalähteen vaatimus" msgid "Ignore validation safety checks" msgstr "Ohita turvatarkastukset" +#. TRANSLATORS: try to help +msgid "Ignoring SSL strict checks, to do this automatically in the future export DISABLE_SSL_STRICT in your environment" +msgstr "Ohitetaan tiukat SSL-tarkistukset, jos haluat tehdä tämän tulevaisuudessa automaattisesti tee DISABLE_SSL_STRICT ympäristöösi" + #. TRANSLATORS: length of time the update takes to apply msgid "Install Duration" msgstr "Asennuksen kesto" @@ -1109,6 +1153,10 @@ msgstr "Vähimmäisversio" msgid "Mismatched daemon and client, use %s instead" msgstr "Virheellinen taustaprosessi ja asiakas, käytä sen sijaan %s" +#. TRANSLATORS: sets something in daemon.conf +msgid "Modifies a daemon configuration value" +msgstr "Muuta taustaprosessin määritysarvoja" + #. TRANSLATORS: command description msgid "Modifies a given remote" msgstr "Muuta annettua etäyhteyttä" @@ -1229,6 +1277,10 @@ msgstr "Prosenttiosuus valmis" msgid "Please enter a number from 0 to %u: " msgstr "Anna numero 0 -%u" +#. TRANSLATORS: Failed to open plugin, hey Arch users +msgid "Plugin dependencies missing" +msgstr "Laajennuksen riippuvuudet puuttuvat" + #. TRANSLATORS: Title: DMA as in https://en.wikipedia.org/wiki/DMA_attack msgid "Pre-boot DMA protection" msgstr "Pre-boot DMA-suojaus" @@ -1287,6 +1339,10 @@ msgstr "Käynnistää..." msgid "Refresh metadata from remote server" msgstr "Päivitä etäpalvelimen metatiedot" +#. TRANSLATORS: command description +msgid "Reinstall current firmware on the device" +msgstr "Asenna nykyinen laiteohjelmisto laitteeseen" + #. TRANSLATORS: command description msgid "Reinstall firmware on a device" msgstr "Asenna laiteohjelmisto 'firmware' uudelleen laitteelle" @@ -1319,6 +1375,14 @@ msgstr "Ilmoita URI" msgid "Reported to remote server" msgstr "Raportoitu etäpalvelimelle" +#. TRANSLATORS: the user is using Gentoo/Arch and has screwed something up +msgid "Required efivarfs filesystem was not found" +msgstr "Vaadittua efivarfs-tiedostojärjestelmää ei löytynyt" + +#. TRANSLATORS: not required for this system +msgid "Required hardware was not found" +msgstr "Vaadittavaa laitteistoa ei löytynyt" + #. TRANSLATORS: Requires a bootloader mode to be manually enabled by the user msgid "Requires a bootloader" msgstr "Vaatii käynnistyslataimen" @@ -1560,6 +1624,14 @@ msgstr "Keskeytä-tyhjäkäynnille" msgid "Suspend-to-ram" msgstr "Keskeytä-muistiin" +#. TRANSLATORS: command description +msgid "Switch the firmware branch on the device" +msgstr "Vaihda laitteen laiteohjelmiston haaraa" + +#. TRANSLATORS: Must be plugged in to an outlet +msgid "System requires external power source" +msgstr "Järjestelmä vaatii ulkoisen virtalähteen" + #. TRANSLATORS: Title: the PCR is rebuilt from the TPM event log msgid "TPM PCR0 reconstruction" msgstr "TPM PCR0 -jälleenrakennus" @@ -1583,6 +1655,15 @@ msgstr "LVFS on ilmainen palvelu, joka toimii itsenäisenä oikeushenkilönä ei msgid "The TPM PCR0 differs from reconstruction." msgstr "TPM PCR0 eroaa rakennettavasta." +#. TRANSLATORS: the user is SOL for support... +msgid "The daemon has loaded 3rd party code and is no longer supported by the upstream developers!" +msgstr "Palvelu on ladannut 3-osapuolen koodin, eikä kehittäjät enää jatkossa tue sitä!" + +#. TRANSLATORS: %1 is the firmware vendor, %2 is the device vendor name +#, c-format +msgid "The firmware from %s is not supplied by %s, the hardware vendor." +msgstr "Laitteistotoimittaja %s ei toimita ohjelmistoa kohteesta %s." + #. TRANSLATORS: nothing to show msgid "There are no blocked firmware files" msgstr "Estettyjä firmware-tiedostoja ei ole" @@ -1619,10 +1700,18 @@ msgstr "Tätä työkalua voi käyttää vain root-käyttäjä" msgid "Type" msgstr "Tyyppi" +#. TRANSLATORS: partition refers to something on disk, again, hey Arch users +msgid "UEFI ESP partition not detected or configured" +msgstr "UEFI ESP-osiota ei havaittu tai määritetty" + #. TRANSLATORS: program name msgid "UEFI Firmware Utility" msgstr "UEFI firmware -apuohjelma" +#. TRANSLATORS: capsule updates are an optional BIOS feature +msgid "UEFI capsule updates not available or enabled" +msgstr "UEFI-päivitykset eivät ole saatavilla tai käytössä" + #. TRANSLATORS: program name msgid "UEFI dbx Utility" msgstr "UEFI dbx-apuohjelma" @@ -1856,6 +1945,15 @@ msgstr "Kirjoitetaan…" msgid "Your distributor may not have verified any of the firmware updates for compatibility with your system or connected devices." msgstr "Jakelijasi ei ehkä ole tarkistanut mitään laiteohjelmistopäivityksiä, jotka ovat yhteensopivia järjestelmän tai liitettyjen laitteiden kanssa." +#. TRANSLATORS: %1 is the device vendor name +#, c-format +msgid "Your hardware may be damaged using this firmware, and installing this release may void any warranty with %s." +msgstr "Laitteistosi saattaa vaurioitua tämän laiteohjelmiston avulla ja asentaminen voi mitätöidä %stakuun." + +#. TRANSLATORS: this is the default branch name when unset +msgid "default" +msgstr "oletus" + #. TRANSLATORS: program name msgid "fwupd TPM event log utility" msgstr "fwupd:n TPM-tapahtumalokin apuohjelma" diff --git a/po/it.po b/po/it.po index cc164a331..aa0e495bd 100644 --- a/po/it.po +++ b/po/it.po @@ -320,6 +320,10 @@ msgstr "Rapporti automatici" msgid "Automatically upload every time?" msgstr "Caricare automaticamente ogni volta?" +#. TRANSLATORS: command description +msgid "Bind new kernel driver" +msgstr "Vincola in nuovo driver kernel" + #. TRANSLATORS: there follows a list of hashes msgid "Blocked firmware files:" msgstr "File di firmware bloccati:" @@ -502,10 +506,18 @@ msgstr "Dispositivo rimosso:" msgid "Device stages updates" msgstr "Il dispositivo applica gli aggiornamenti a fasi" +#. TRANSLATORS: there is more than one supplier of the firmware +msgid "Device supports switching to a different branch of firmware" +msgstr "Il dispositivo supporta il passaggio a un ramo diverso del firmware" + #. TRANSLATORS: Device update needs to be separately activated msgid "Device update needs activation" msgstr "L'aggiornamento del dispositivo richiede l'attivazione" +#. TRANSLATORS: save the old firmware to disk before installing the new one +msgid "Device will backup firmware before installing" +msgstr "Il dispositivo eseguirà un backup del firmware prima dell'installazione" + #. TRANSLATORS: Device will not return after update completes msgid "Device will not re-appear after update completes" msgstr "Il dispositivo non comparirà nuovamente dopo l'aggiornamento" @@ -581,6 +593,10 @@ msgstr[1] "Non caricare i rapporti e non chiedere nuovamente con i prossimi aggi msgid "Do not write to the history database" msgstr "Non scrive la cronologia" +#. TRANSLATORS: should the branch be changed +msgid "Do you understand the consequences of changing the firmware branch?" +msgstr "Le conseguenze del cambio di ramo del firmware sono state comprese?" + #. TRANSLATORS: success #. success msgid "Done!" @@ -780,6 +796,10 @@ msgstr "Strumento gestione firmware" msgid "Firmware attestation" msgstr "Convalida firmware" +#. TRANSLATORS: system is not booted in UEFI mode +msgid "Firmware can not be updated in legacy BIOS mode" +msgstr "Impossibile aggiornare il firmware in modalità BIOS legacy" + #. TRANSLATORS: user selected something not possible msgid "Firmware is already blocked" msgstr "Il firmware è già bloccato" @@ -805,11 +825,19 @@ msgstr "Gli aggiornamenti firmware non sono supportati su questo dispositivo." msgid "Firmware updates are supported on this machine." msgstr "Gli aggiornamenti firmware sono supportati su questo dispositivo." +#. TRANSLATORS: user needs to run a command +msgid "Firmware updates disabled; run 'fwupdmgr unlock' to enable" +msgstr "Aggiornamenti firmware disabilitati; eseguire «fwupdmgr unlock» per abilitarli" + #. TRANSLATORS: description of plugin state, e.g. disabled #. TRANSLATORS: release properties msgid "Flags" msgstr "Flag" +#. TRANSLATORS: command line option +msgid "Force the action by relaxing some runtime checks" +msgstr "Forza l'azione riducendo alcuni controlli runtime" + msgid "Force the action ignoring all warnings" msgstr "Forza l'azione ignorando gli avvisi" @@ -900,10 +928,22 @@ msgstr "Ignora controlli SSL nello scaricare i file" msgid "Ignore firmware checksum failures" msgstr "Ignora i checksum del firmware non riusciti" +#. TRANSLATORS: command line option +msgid "Ignore firmware hardware mismatch failures" +msgstr "Ignora corrispondenze errate firmware hardware" + +#. TRANSLATORS: command line option +msgid "Ignore requirement of external power source" +msgstr "Ignora richiesta di sorgente elettrica esterna" + #. TRANSLATORS: Ignore validation safety checks when flashing this device msgid "Ignore validation safety checks" msgstr "Ignora i controlli di sicurezza di validazione" +#. TRANSLATORS: try to help +msgid "Ignoring SSL strict checks, to do this automatically in the future export DISABLE_SSL_STRICT in your environment" +msgstr "Controlli SSL ignorati, per fare ciò automaticamente in futuro, esportare DISABLE_SSL_STRICT nel proprio ambiente" + #. TRANSLATORS: length of time the update takes to apply msgid "Install Duration" msgstr "Tempo di installazione" @@ -1335,6 +1375,14 @@ msgstr "URI del rapporto" msgid "Reported to remote server" msgstr "Segnalato al server remoto" +#. TRANSLATORS: the user is using Gentoo/Arch and has screwed something up +msgid "Required efivarfs filesystem was not found" +msgstr "Il file system richiesto efivarfs non è stato trovato" + +#. TRANSLATORS: not required for this system +msgid "Required hardware was not found" +msgstr "L'hardware richiesto non è stato trovato" + #. TRANSLATORS: Requires a bootloader mode to be manually enabled by the user msgid "Requires a bootloader" msgstr "Richiede un bootloader" @@ -1576,6 +1624,14 @@ msgstr "Suspend-to-idle" msgid "Suspend-to-ram" msgstr "Suspend-to-ram" +#. TRANSLATORS: command description +msgid "Switch the firmware branch on the device" +msgstr "Cambia il ramo del firmware sul dispositivo" + +#. TRANSLATORS: Must be plugged in to an outlet +msgid "System requires external power source" +msgstr "Il sistema richiede una sorgente elettrica esterna" + #. TRANSLATORS: Title: the PCR is rebuilt from the TPM event log msgid "TPM PCR0 reconstruction" msgstr "Ricostruzione PCR0 TPM" @@ -1599,6 +1655,15 @@ msgstr "LVFS è un servizio gratuito che opera come entità legale indipendente msgid "The TPM PCR0 differs from reconstruction." msgstr "TPM PCR0 è diverso dalla ricostruzione." +#. TRANSLATORS: the user is SOL for support... +msgid "The daemon has loaded 3rd party code and is no longer supported by the upstream developers!" +msgstr "Il demone ha caricato codice di terze parti e non è più supportato dagli sviluppatori." + +#. TRANSLATORS: %1 is the firmware vendor, %2 is the device vendor name +#, c-format +msgid "The firmware from %s is not supplied by %s, the hardware vendor." +msgstr "Il firmware su %s non è fornito da %s, il fornitore dell'hardware." + #. TRANSLATORS: nothing to show msgid "There are no blocked firmware files" msgstr "Non ci sono file di firmware bloccati" @@ -1635,10 +1700,18 @@ msgstr "Questo strumento può essere usato solamente dall'utente root" msgid "Type" msgstr "Tipo" +#. TRANSLATORS: partition refers to something on disk, again, hey Arch users +msgid "UEFI ESP partition not detected or configured" +msgstr "Partizione ESP UEFI non rilavata o non configurata" + #. TRANSLATORS: program name msgid "UEFI Firmware Utility" msgstr "Strumento firmware UEFI" +#. TRANSLATORS: capsule updates are an optional BIOS feature +msgid "UEFI capsule updates not available or enabled" +msgstr "Aggiornamenti capsula UEFI non disponibili o non abilitati" + #. TRANSLATORS: program name msgid "UEFI dbx Utility" msgstr "Strumento EUFI dbx" @@ -1651,10 +1724,18 @@ msgstr "Avvio sicuro UEFI" msgid "Unable to connect to service" msgstr "Impossibile collegarsi al servizio" +#. TRANSLATORS: command description +msgid "Unbind current driver" +msgstr "Svincola il driver attuale" + #. TRANSLATORS: we will now offer this firmware to the user msgid "Unblocking firmware:" msgstr "Sblocco del firmware:" +#. TRANSLATORS: command description +msgid "Unblocks a specific firmware from being installed" +msgstr "Sblocca un firmware specifico dal non essere installato" + #. TRANSLATORS: Suffix: the HSI result msgid "Unencrypted" msgstr "Non cifrato" @@ -1868,6 +1949,11 @@ msgstr "Scrittura…" msgid "Your distributor may not have verified any of the firmware updates for compatibility with your system or connected devices." msgstr "La propria distribuzione potrebbe non aver verificato la compatibilità degli aggiornamenti firmware col proprio sistema o col dispositivo collegato." +#. TRANSLATORS: %1 is the device vendor name +#, c-format +msgid "Your hardware may be damaged using this firmware, and installing this release may void any warranty with %s." +msgstr "Utilizzando questo firmware, l'hardware potrebbe danneggiarsi; inoltre, l'installazione di questa versione potrebbe annullare la garanzia con %s." + #. TRANSLATORS: this is the default branch name when unset msgid "default" msgstr "predefinito" diff --git a/po/lt.po b/po/lt.po index 890923c06..6fabbd50f 100644 --- a/po/lt.po +++ b/po/lt.po @@ -4,6 +4,7 @@ # # Translators: # Moo, 2019 +# Moo, 2020 msgid "" msgstr "" "Project-Id-Version: fwupd\n" @@ -526,6 +527,9 @@ msgstr "Modifikuoja nurodytą nuotolinę saugyklą" msgid "Modify a configured remote" msgstr "Modifikuoti sukonfigūruotą nuotolinę saugyklą" +msgid "Modify daemon configuration" +msgstr "Modifikuoti tarnybos konfigūraciją" + #. TRANSLATORS: command description msgid "Monitor the daemon for events" msgstr "Stebėti tarnybą, ar yra įvykių" diff --git a/po/sv.po b/po/sv.po index b1636586c..772350cb2 100644 --- a/po/sv.po +++ b/po/sv.po @@ -7,6 +7,7 @@ # Andreas Henriksson , 2017 # Josef Andersson , 2015,2017-2018 # Josef Andersson , 2015,2017 +# Luna Jernberg , 2020 # Sebastian Rasmussen , 2019-2020 # Sebastian Rasmussen , 2018 msgid "" @@ -33,6 +34,12 @@ msgstr[1] "%.0f minuter kvarstår" msgid "%s CPU Microcode Update" msgstr "%s CPU-mikrokodsuppdatering" +#. TRANSLATORS: a specific part of hardware, +#. * the first %s is the device name, e.g. 'Secure Boot` +#, c-format +msgid "%s Configuration Update" +msgstr "%s Konfigurationsuppdatering" + #. TRANSLATORS: ME stands for Management Engine, where #. * the first %s is the device name, e.g. 'ThinkPad P50` #, c-format @@ -106,6 +113,16 @@ msgstr "%s måste förbli anslutna under tiden som uppgraderingen pågår för a msgid "%s must remain plugged into a power source for the duration of the update to avoid damage." msgstr "%s måste förbli ansluten till en strömkälla under tiden som uppgraderingen pågår för att undvika skada." +#. TRANSLATORS: Title: %1 is ME kind, e.g. CSME/TXT, %2 is a version number +#, c-format +msgid "%s v%s" +msgstr "%s v%s" + +#. TRANSLATORS: Title: %s is ME kind, e.g. CSME/TXT +#, c-format +msgid "%s version" +msgstr "%s version" + #. TRANSLATORS: duration in days! #, c-format msgid "%u day" @@ -147,6 +164,10 @@ msgid_plural "%u seconds" msgstr[0] "%u sekund" msgstr[1] "%u sekunder" +#. TRANSLATORS: this is shown as a suffix for obsoleted tests +msgid "(obsoleted)" +msgstr "(föråldrad)" + #. TRANSLATORS: command description msgid "Activate devices" msgstr "Aktivera enheter" @@ -207,6 +228,14 @@ msgstr "Svara ja på alla frågor" msgid "Apply firmware updates" msgstr "Tillämpa uppdateringar för fast programvara" +#. TRANSLATORS: command line option +msgid "Apply update files" +msgstr "Tillämpa uppdateringsfiler" + +#. TRANSLATORS: actually sending the update to the hardware +msgid "Applying update…" +msgstr "Tillämpar uppdatering…" + #. TRANSLATORS: approved firmware has been checked by #. * the domain administrator msgid "Approved firmware:" @@ -214,6 +243,10 @@ msgid_plural "Approved firmware:" msgstr[0] "Godkänd fast programvara:" msgstr[1] "Godkänd fast programvara:" +#. TRANSLATORS: stop nagging the user +msgid "Ask again next time?" +msgstr "Fråga igen nästa gång?" + #. TRANSLATORS: command description msgid "Attach to firmware mode" msgstr "Fäst till fast programvaruläge" @@ -270,10 +303,26 @@ msgstr "Autentisering krävs för att uppdatera den lagrade kontrollsumman för msgid "Automatic Reporting" msgstr "Automatisk rapportering" +#. TRANSLATORS: there follows a list of hashes +msgid "Blocked firmware files:" +msgstr "Blockerad fast programvaru fil:" + +#. TRANSLATORS: we will not offer this firmware to the user +msgid "Blocking firmware:" +msgstr "Blockera fast programvara: " + #. TRANSLATORS: firmware version of bootloader msgid "Bootloader Version" msgstr "Starthanterarversion" +#. TRANSLATORS: the stream of firmware, e.g. nonfree or open-source +msgid "Branch" +msgstr "Gren" + +#. TRANSLATORS: command description +msgid "Build a firmware file" +msgstr "Bygg en fast programvaru fil" + #. TRANSLATORS: command description msgid "Build firmware using a sandbox" msgstr "Bygg fast programvara med en sandlåda" @@ -299,6 +348,11 @@ msgstr "Kontrollerar att kryptografisk hash matchar fastprogramvara" msgid "Checksum" msgstr "Kontrollsumma" +#. TRANSLATORS: get interactive prompt, where branch is the +#. * supplier of the firmware, e.g. "non-free" or "free" +msgid "Choose a branch:" +msgstr "Välj en gren:" + #. TRANSLATORS: get interactive prompt msgid "Choose a device:" msgstr "Välj en enhet:" @@ -311,6 +365,10 @@ msgstr "Välj en typ av fastprogravara:" msgid "Choose a release:" msgstr "Välj en utgåva:" +#. TRANSLATORS: get interactive prompt +msgid "Choose a volume:" +msgstr "Välj en volym:" + #. TRANSLATORS: command description msgid "Clears any updates scheduled to be updated offline" msgstr "Rensa eventuella uppdateringar som schemalagts att bli tillämpade frånkopplade" @@ -327,6 +385,18 @@ msgstr "Kommandot hittades inte" msgid "Continue with update?" msgstr "Fortsätta med uppdatering?" +#. TRANSLATORS: command description +msgid "Convert a firmware file" +msgstr "Konvertera en fast programvaru fil" + +#. TRANSLATORS: when the update was built +msgid "Created" +msgstr "Skapad" + +#. TRANSLATORS: the release urgency +msgid "Critical" +msgstr "Kritisk" + #. TRANSLATORS: Device supports some form of checksum verification msgid "Cryptographic hash verification is available" msgstr "Kryptografiskt hashverifiering är tillgänglig" @@ -419,6 +489,16 @@ msgstr "Enheter som har uppdaterats:" msgid "Devices that were not updated correctly:" msgstr "Enheter som inte uppdaterades korrekt:" +#. TRANSLATORS: message letting the user know no device upgrade available due +#. to missing on LVFS +msgid "Devices with no available firmware updates: " +msgstr "Enheter med inga tillgängliga uppdateringar för fast programvara" + +#. TRANSLATORS: Suffix: the HSI result +#. TRANSLATORS: Plugin is inactive and not used +msgid "Disabled" +msgstr "Inaktiverad" + msgid "Disabled fwupdate debugging" msgstr "Inaktiverade fwupdate-felsökning" @@ -533,6 +613,14 @@ msgstr "Att aktivera denna funktionalitet görs på egen risk, vilket betyder at msgid "Enabling this remote is done at your own risk." msgstr "Att aktivera denna fjärr görs på egen risk." +#. TRANSLATORS: Suffix: the HSI result +msgid "Encrypted" +msgstr "Krypterad" + +#. TRANSLATORS: Title: Memory contents are encrypted, e.g. Intel TME +msgid "Encrypted RAM" +msgstr "Krypterat RAM" + #. TRANSLATORS: command description msgid "Erase all firmware update history" msgstr "Ta bort alla historik för fast programvara" @@ -549,6 +637,14 @@ msgstr "Avsluta efter en kort fördröjning" msgid "Exit after the engine has loaded" msgstr "Avsluta efter att motorn har lästs in" +#. TRANSLATORS: Suffix: the fallback HSI result +msgid "Failed" +msgstr "Misslyckades" + +#. TRANSLATORS: dbx file failed to be applied as an update +msgid "Failed to apply update" +msgstr "Misslyckades med att tillämpa uppdatering" + #. TRANSLATORS: we could not talk to the fwupd daemon msgid "Failed to connect to daemon" msgstr "Misslyckades med att ansluta till demon" @@ -561,6 +657,11 @@ msgstr "Misslyckades med att hämta väntande enheter" msgid "Failed to install firmware update" msgstr "Misslyckades med att installera uppdatering av fast programvara" +#. TRANSLATORS: could not read existing system data +#. TRANSLATORS: could not read file +msgid "Failed to load local dbx" +msgstr "Misslyckades med att läsa in lokal dbx" + #. TRANSLATORS: quirks are device-specific workarounds msgid "Failed to load quirks" msgstr "Misslyckades med att läsa in speciallösning" @@ -593,6 +694,10 @@ msgstr "Filnamn" msgid "Filename Signature" msgstr "Filnamn Signatur" +#. TRANSLATORS: user did not include a filename parameter +msgid "Filename required" +msgstr "Filnamn krävs" + #. TRANSLATORS: command line option msgid "Filter with a set of device flags using a ~ prefix to exclude, e.g. 'internal,~needs-reboot'" msgstr "Filtrera via en uppsättning av enhetsflaggor genom att använda ett ~-prefix för att exkludera, t.e.x ”internal,~needs-reboot”" @@ -617,6 +722,10 @@ msgstr "Uppgraderingsdemon för fast programvara" msgid "Firmware Utility" msgstr "Fast programvaruverktyg" +#. TRANSLATORS: user selected something not possible +msgid "Firmware is already blocked" +msgstr "fast programvara är redan blockerad" + #. TRANSLATORS: the metadata is very out of date; %u is a number > 1 #, c-format msgid "Firmware metadata has not been updated for %u day and may not be up to date." @@ -624,6 +733,10 @@ msgid_plural "Firmware metadata has not been updated for %u days and may not be msgstr[0] "Metadata för fast programvara har inte uppdaterats på %udag och kan vara utdaterad." msgstr[1] "Metadata för fast programvara har inte uppdaterats på %udagar och kan vara utdaterad." +#. TRANSLATORS: Title: if firmware updates are available +msgid "Firmware updates" +msgstr "Fastprogramvaru uppdateringar" + msgid "Firmware updates are not supported on this machine." msgstr "Uppdateringar av fast programvara stöds inte på denna maskin." @@ -672,6 +785,14 @@ msgstr "Hämtar detaljer om en fast programvarufil" msgid "Gets the configured remotes" msgstr "Ger de konfigurerade fjärrkällorna" +#. TRANSLATORS: firmware approved by the admin +msgid "Gets the list of approved firmware" +msgstr "Hämtar lista över godkänd fast programvara." + +#. TRANSLATORS: command description +msgid "Gets the list of blocked firmware" +msgstr "Hämtar lista över blockerad fast programvara." + #. TRANSLATORS: command description msgid "Gets the list of updates for connected hardware" msgstr "Hämtar listan över uppdateringar för ansluten hårdvara" @@ -688,6 +809,15 @@ msgstr "Hämtar resultaten från senaste uppdateringen" msgid "Hardware is waiting to be replugged" msgstr "Hårdvara väntar på att bli utdragen/återinsatt" +#. TRANSLATORS: the release urgency +msgid "High" +msgstr "Hög" + +#. TRANSLATORS: Title: +#. https://en.wikipedia.org/wiki/Input%E2%80%93output_memory_management_unit +msgid "IOMMU" +msgstr "IOMMU" + #. TRANSLATORS: daemon is inactive msgid "Idle…" msgstr "Väntar…" @@ -744,10 +874,32 @@ msgstr "Installerar uppdatering för fast programvara…" msgid "Installing on %s…" msgstr "Installerar på %s…" +#. TRANSLATORS: Title: BootGuard is a trademark from Intel +msgid "Intel BootGuard" +msgstr "Intel BootGuard" + +#. TRANSLATORS: Title: CET = Control-flow Enforcement Technology, +#. * active means being used by the OS +msgid "Intel CET Active" +msgstr "Intel CET Aktiv" + +#. TRANSLATORS: Title: CET = Control-flow Enforcement Technology, +#. * enabled means supported by the processor +msgid "Intel CET Enabled" +msgstr "Intel CET Aktiverad" + +#. TRANSLATORS: Title: SMAP = Supervisor Mode Access Prevention +msgid "Intel SMAP" +msgstr "Intel SMAP" + #. TRANSLATORS: Device cannot be removed easily msgid "Internal device" msgstr "Intern enhet" +#. TRANSLATORS: Suffix: the HSI result +msgid "Invalid" +msgstr "Ogiltig" + #. TRANSLATORS: Is currently in bootloader mode msgid "Is in bootloader mode" msgstr "Är i starthanterarläge" @@ -779,6 +931,18 @@ msgstr "Linux Vendor Firmware Service (stabil fastprogramvara)" msgid "Linux Vendor Firmware Service (testing firmware)" msgstr "Linux Vendor Firmware Service (fastprogramvara för testning)" +#. TRANSLATORS: Title: if it's tainted or not +msgid "Linux kernel" +msgstr "Linux kärna" + +#. TRANSLATORS: Title: swap space or swap partition +msgid "Linux swap" +msgstr "Linux swap" + +#. TRANSLATORS: command line option +msgid "List entries in dbx" +msgstr "Lista poster i dbx" + #. TRANSLATORS: command line option msgid "List supported firmware updates" msgstr "Lista uppdateringar för fast programvara som stöds" @@ -791,6 +955,17 @@ msgstr "Lista tillgänliga fastprogramvutyper" msgid "Loading…" msgstr "Läser in…" +#. TRANSLATORS: Suffix: the HSI result +msgid "Locked" +msgstr "Låst" + +#. TRANSLATORS: the release urgency +msgid "Low" +msgstr "Låg" + +msgid "MEI version" +msgstr "MEI version" + #. TRANSLATORS: remote URI msgid "Metadata Signature" msgstr "Metadatasignatur" @@ -876,6 +1051,14 @@ msgstr "Inga fjärrarkiv tillgängliga" msgid "No updates were applied" msgstr "Inga uppdateringar applicerades" +#. TRANSLATORS: Suffix: the HSI result +msgid "Not found" +msgstr "Hittades inte" + +#. TRANSLATORS: Suffix: the HSI result +msgid "Not supported" +msgstr "Stöds inte" + #. TRANSLATORS: Suffix: the HSI result msgid "OK" msgstr "OK" @@ -966,6 +1149,14 @@ msgstr "Startar om…" msgid "Refresh metadata from remote server" msgstr "Uppdatera metadata från fjärrserver" +#. TRANSLATORS: command description +msgid "Reinstall current firmware on the device" +msgstr "Återinstallera aktuell fast programvara på enheten." + +#. TRANSLATORS: command description +msgid "Reinstall firmware on a device" +msgstr "Installera om fast programvara på en enhet" + #. TRANSLATORS: the first replacement is a display name #. * e.g. "ColorHugALS" and the second is a version number #. * e.g. "1.2.3" @@ -1029,6 +1220,14 @@ msgstr "Kör uppstädningssammansättningsrutinen för insticksmodule när insta msgid "Run the plugin composite prepare routine when using install-blob" msgstr "Kör förberedelsesammansättningsrutinen för insticksmodule när install-blob används" +#. TRANSLATORS: Title: SPI refers to the flash chip in the computer +msgid "SPI lock" +msgstr "SPI lås" + +#. TRANSLATORS: Title: SPI refers to the flash chip in the computer +msgid "SPI write" +msgstr "SPI skriv" + #. TRANSLATORS: command line option msgid "Save device state into a JSON file between executions" msgstr "Spara enhetstillstånd i en JSON-fil mellan körningar" @@ -1045,6 +1244,10 @@ msgstr "Schemalägger…" msgid "Selected device" msgstr "Vald enhet" +#. TRANSLATORS: Volume has been chosen by the user +msgid "Selected volume" +msgstr "Vald volym" + #. TRANSLATORS: serial number of hardware msgid "Serial Number" msgstr "Serienummer" @@ -1061,6 +1264,10 @@ msgstr "Sätter listan av godkända fasta programvaror" msgid "Share firmware history with the developers" msgstr "Dela fast programvaruhistorik med utvecklarna" +#. TRANSLATORS: command line option +msgid "Show all results" +msgstr "Visa alla resultat" + #. TRANSLATORS: command line option msgid "Show client and daemon versions" msgstr "Visa klient- och demon-version" @@ -1093,6 +1300,10 @@ msgstr "Visa historik över fasta programvaruuppdateringar" msgid "Show plugin verbose information" msgstr "Visa utförlig information om insticksmodul" +#. TRANSLATORS: command line option +msgid "Show the calculated version of the dbx" +msgstr "Visa den beräknade versionen av dbx" + #. TRANSLATORS: command line option msgid "Show the debug log from the last attempted update" msgstr "Visa felsökningsloggen från det senaste uppdateringsförsöket" @@ -1187,10 +1398,22 @@ msgstr "Verifierade framgångsrikt enhetskontrollsummor" msgid "Summary" msgstr "Sammanfattning" +#. TRANSLATORS: Suffix: the HSI result +msgid "Supported" +msgstr "Stöds" + #. TRANSLATORS: Is found in current metadata msgid "Supported on remote server" msgstr "Stöds på fjärrserver" +#. TRANSLATORS: Must be plugged in to an outlet +msgid "System requires external power source" +msgstr "Systemet kräver extern strömkälla" + +#. TRANSLATORS: Title: TPM = Trusted Platform Module +msgid "TPM v2.0" +msgstr "TPM v2.0" + msgid "Target" msgstr "Mål" @@ -1198,6 +1421,10 @@ msgstr "Mål" msgid "The LVFS is a free service that operates as an independent legal entity and has no connection with $OS_RELEASE:NAME$. Your distributor may not have verified any of the firmware updates for compatibility with your system or connected devices. All firmware is provided only by the original equipment manufacturer." msgstr "LVFS är en fri tjänst som fungerar som en oberoende juridisk person och har ingen koppling till $OS_RELEASE:NAME$. Din distributör kanske inte har bekräftat att någon av de fasta programvaruuppdateringarna är kompatibla med ditt system eller anslutna enheter. All fast programvara tillhandahålls endast av den ursprungliga tillverkaren av utrustning." +#. TRANSLATORS: nothing to show +msgid "There are no blocked firmware files" +msgstr "Det finns inga blockerade fast programvaru filer" + #. TRANSLATORS: approved firmware has been checked by #. * the domain administrator msgid "There is no approved firmware." @@ -1210,6 +1437,10 @@ msgstr "Detta program kommer endast fungera korrekt som root" msgid "This remote contains firmware which is not embargoed, but is still being tested by the hardware vendor. You should ensure you have a way to manually downgrade the firmware if the firmware update fails." msgstr "Denna fjärrkälla innehåller fast programvara som inte är under embargo, men fortfarande testas av hårdvarutillverkare. Du bör säkerställa att du har ett sätt att manuellt nedgradera den fasta programvaran om uppdateringen misslyckas." +#. TRANSLATORS: this is instructions on how to improve the HSI security level +msgid "This system has a low HSI security level." +msgstr "Detta system har en låg HSI-säkerhetsnivå." + #. TRANSLATORS: the user needs to stop playing with stuff msgid "This tool can only be used by the root user" msgstr "Detta verktyg kan endast användas av administratörsanvändaren" @@ -1222,6 +1453,22 @@ msgstr "Typ" msgid "UEFI Firmware Utility" msgstr "Verktyg för fast UEFI-programvara" +#. TRANSLATORS: program name +msgid "UEFI dbx Utility" +msgstr "UEFI dbx-verktyg" + +#. TRANSLATORS: error message +msgid "Unable to connect to service" +msgstr "Misslyckades med att ansluta till tjänst" + +#. TRANSLATORS: we will now offer this firmware to the user +msgid "Unblocking firmware:" +msgstr "Avblockera fast programvara:" + +#. TRANSLATORS: Suffix: the HSI result +msgid "Unencrypted" +msgstr "Okrypterad" + #. TRANSLATORS: current daemon status is unknown #. TRANSLATORS: we don't know the license of the update #. TRANSLATORS: unknown release urgency @@ -1235,6 +1482,10 @@ msgstr "Okänd enhet" msgid "Unlock the device to allow access" msgstr "Lås upp enheten för att tillåta åtkomst" +#. TRANSLATORS: Suffix: the HSI result +msgid "Unlocked" +msgstr "Upplåst" + #. TRANSLATORS: command description msgid "Unlocks the device for firmware access" msgstr "Låser upp enheten för fast programvaruåtkomst" @@ -1296,6 +1547,9 @@ msgstr "Uppdatera lagrad metadata med aktuellt innehåll" msgid "Updates all firmware to latest versions available" msgstr "Uppdaterar all fast programvara till de senast tillgängliga versionerna" +msgid "Updating" +msgstr "Uppdaterar" + #. TRANSLATORS: the first replacement is a display name #. * e.g. "ColorHugALS" and the second and third are #. * version numbers e.g. "1.2.3" @@ -1332,6 +1586,14 @@ msgstr[1] "Skicka rapporter och skicka dem automatiskt efter att framtida uppdat msgid "Uploading firmware reports helps hardware vendors to quickly identify failing and successful updates on real devices." msgstr "Att skicka upp rapporter för fastprogramvara hjälper hårdvaruförsäljare att snabbt identifiera trasiga och fungerande uppdateringar på riktiga enheter." +#. TRANSLATORS: error message explaining command to run to how to get help +msgid "Use fwupdmgr --help for help" +msgstr "Använd fwupdmgr --help för hjälp" + +#. TRANSLATORS: error message explaining command to run to how to get help +msgid "Use fwupdtool --help for help" +msgstr "Använd fwupdtool --help för hjälp" + #. TRANSLATORS: command line option msgid "Use quirk flags when installing firmware" msgstr "Använd specialflaggor vid installation av fastprogramvara" @@ -1344,6 +1606,10 @@ msgstr "Användare har aviserats" msgid "Username" msgstr "Användarnamn" +#. TRANSLATORS: Suffix: the HSI result +msgid "Valid" +msgstr "Giltig" + #. TRANSLATORS: one line variant of release (e.g. 'Prerelease' or 'China') msgid "Variant" msgstr "Variant" @@ -1360,6 +1626,10 @@ msgstr "Verifierar…" msgid "Version" msgstr "Version" +#. TRANSLATORS: this is a prefix on the console +msgid "WARNING:" +msgstr "VARNING:" + #. TRANSLATORS: waiting for device to do something msgid "Waiting…" msgstr "Väntar..." @@ -1380,6 +1650,10 @@ msgstr "Skriv fast programvara från fil till enhet" msgid "Write firmware from file into one partition" msgstr "Skriv fast programvara från fil till partition" +#. TRANSLATORS: decompressing images from a container firmware +msgid "Writing file:" +msgstr "Skriver fil:" + #. TRANSLATORS: writing to the flash chips msgid "Writing…" msgstr "Skriver…" @@ -1387,3 +1661,7 @@ msgstr "Skriver…" #. TRANSLATORS: show the user a warning msgid "Your distributor may not have verified any of the firmware updates for compatibility with your system or connected devices." msgstr "Din distributör kanske inte har verifierat någon av uppdateringarna av fastprogramvara för kompatibilitet med ditt system eller anslutna enheter." + +#. TRANSLATORS: this is the default branch name when unset +msgid "default" +msgstr "standard" diff --git a/po/uk.po b/po/uk.po index 143b95259..2c02c358a 100644 --- a/po/uk.po +++ b/po/uk.po @@ -1759,6 +1759,10 @@ msgstr "Відв'язати поточний драйвер" msgid "Unblocking firmware:" msgstr "Розблокуємо мікропрограму:" +#. TRANSLATORS: command description +msgid "Unblocks a specific firmware from being installed" +msgstr "Розблоковує встановлення певної мікропрограми" + #. TRANSLATORS: Suffix: the HSI result msgid "Unencrypted" msgstr "Розшифровано"