Allow quirking devices that always require a version check

These are devices that we have to be careful with the version numbers, for
instance only updating from versions that have already had data migration
completed.

The new flag can be set in quirk files or on the objects directly.
This commit is contained in:
Richard Hughes 2020-01-07 10:58:32 +00:00
parent 603e4f6956
commit 1eb7c7443e
5 changed files with 97 additions and 0 deletions

View File

@ -179,6 +179,8 @@ fwupd_device_flag_to_string (FwupdDeviceFlags device_flag)
return "self-recovery";
if (device_flag == FWUPD_DEVICE_FLAG_USABLE_DURING_UPDATE)
return "usable-during-update";
if (device_flag == FWUPD_DEVICE_FLAG_VERSION_CHECK_REQUIRED)
return "version-check-required";
if (device_flag == FWUPD_DEVICE_FLAG_UNKNOWN)
return "unknown";
return NULL;
@ -259,6 +261,8 @@ fwupd_device_flag_from_string (const gchar *device_flag)
return FWUPD_DEVICE_FLAG_SELF_RECOVERY;
if (g_strcmp0 (device_flag, "usable-during-update") == 0)
return FWUPD_DEVICE_FLAG_USABLE_DURING_UPDATE;
if (g_strcmp0 (device_flag, "version-check-required") == 0)
return FWUPD_DEVICE_FLAG_VERSION_CHECK_REQUIRED;
return FWUPD_DEVICE_FLAG_UNKNOWN;
}

View File

@ -97,6 +97,7 @@ typedef enum {
* @FWUPD_DEVICE_FLAG_DUAL_IMAGE: Device update architecture uses A/B partitions for updates
* @FWUPD_DEVICE_FLAG_SELF_RECOVERY: In flashing mode device will only accept intended payloads
* @FWUPD_DEVICE_FLAG_USABLE_DURING_UPDATE: Device remains usable while fwupd flashes or schedules the update
* @FWUPD_DEVICE_FLAG_VERSION_CHECK_REQUIRED: All firmware updates for this device require a firmware version check
*
* The device flags.
**/
@ -131,6 +132,7 @@ typedef enum {
#define FWUPD_DEVICE_FLAG_DUAL_IMAGE (1u << 27) /* Since: 1.3.3 */
#define FWUPD_DEVICE_FLAG_SELF_RECOVERY (1u << 28) /* Since: 1.3.3 */
#define FWUPD_DEVICE_FLAG_USABLE_DURING_UPDATE (1u << 29) /* Since: 1.3.3 */
#define FWUPD_DEVICE_FLAG_VERSION_CHECK_REQUIRED (1u << 30) /* Since: 1.3.7 */
#define FWUPD_DEVICE_FLAG_UNKNOWN G_MAXUINT64 /* Since: 0.7.3 */
typedef guint64 FwupdDeviceFlags;

View File

@ -152,6 +152,35 @@ fu_install_task_check_verfmt (FuInstallTask *self,
return TRUE;
}
static gboolean
fu_install_task_check_requirements_version_check (FuInstallTask *self, GError **error)
{
g_autoptr(GError) error_local = NULL;
g_autoptr(GPtrArray) reqs = NULL;
reqs = xb_node_query (fu_install_task_get_component (self),
"requires/*", 0, &error_local);
if (reqs == NULL) {
g_set_error_literal (error,
FWUPD_ERROR,
FWUPD_ERROR_NOT_SUPPORTED,
error_local->message);
return FALSE;
}
for (guint i = 0; i < reqs->len; i++) {
XbNode *req = g_ptr_array_index (reqs, i);
if (g_strcmp0 (xb_node_get_element (req), "firmware") == 0 &&
xb_node_get_text (req) == NULL) {
return TRUE;
}
}
g_set_error_literal (error,
FWUPD_ERROR,
FWUPD_ERROR_NOT_SUPPORTED,
"no firmware requirement");
return FALSE;
}
/**
* fu_install_task_check_requirements:
* @self: A #FuInstallTask
@ -211,6 +240,14 @@ fu_install_task_check_requirements (FuInstallTask *self,
return FALSE;
}
/* device requries a version check */
if (fu_device_has_flag (self->device, FWUPD_DEVICE_FLAG_VERSION_CHECK_REQUIRED)) {
if (!fu_install_task_check_requirements_version_check (self, error)) {
g_prefix_error (error, "device requires firmware with a version check: ");
return FALSE;
}
}
/* does the protocol match */
protocol = xb_node_query_text (self->component,
"custom/value[@key='LVFS::UpdateProtocol']",

View File

@ -225,6 +225,53 @@ fu_engine_requirements_missing_func (gconstpointer user_data)
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(FuInstallTask) task = NULL;
g_autoptr(GError) error = NULL;
g_autoptr(XbNode) component = NULL;
g_autoptr(XbSilo) silo = NULL;
const gchar *xml =
"<component>"
" <provides>"
" <firmware type=\"flashed\">12345678-1234-1234-1234-123456789012</firmware>"
" </provides>"
" <releases>"
" <release version=\"1.2.4\">"
" </release>"
" </releases>"
"</component>";
/* set up a dummy device */
fu_device_set_version (device, "1.2.3", FWUPD_VERSION_FORMAT_TRIPLET);
fu_device_set_version_bootloader (device, "4.5.6");
fu_device_set_vendor_id (device, "FFFF");
fu_device_add_flag (device, FWUPD_DEVICE_FLAG_UPDATABLE);
fu_device_add_flag (device, FWUPD_DEVICE_FLAG_VERSION_CHECK_REQUIRED);
fu_device_add_guid (device, "12345678-1234-1234-1234-123456789012");
/* 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 (device, component);
ret = fu_engine_check_requirements (engine, task,
FWUPD_INSTALL_FLAG_NONE,
&error);
g_assert_error (error, FWUPD_ERROR, FWUPD_ERROR_NOT_SUPPORTED);
g_assert (g_str_has_prefix (error->message, "device requires firmware with a version check"));
g_assert (!ret);
}
static void
fu_engine_requirements_unsupported_func (gconstpointer user_data)
{
@ -439,6 +486,7 @@ fu_engine_requirements_device_func (gconstpointer user_data)
fu_device_set_version_bootloader (device, "4.5.6");
fu_device_set_vendor_id (device, "FFFF");
fu_device_add_flag (device, FWUPD_DEVICE_FLAG_UPDATABLE);
fu_device_add_flag (device, FWUPD_DEVICE_FLAG_VERSION_CHECK_REQUIRED);
fu_device_add_guid (device, "12345678-1234-1234-1234-123456789012");
/* make the component require three things */
@ -2902,6 +2950,8 @@ 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-version-require}", self,
fu_engine_requirements_version_require_func);
g_test_add_data_func ("/fwupd/engine{requirements-parent-device}", self,
fu_engine_requirements_parent_device_func);
g_test_add_data_func ("/fwupd/engine{requirements-not-child}", self,

View File

@ -1066,6 +1066,10 @@ fu_util_device_flag_to_string (guint64 device_flag)
/* TRANSLATORS: Device remains usable during update */
return _("Device is usable for the duration of the update");
}
if (device_flag == FWUPD_DEVICE_FLAG_VERSION_CHECK_REQUIRED) {
/* TRANSLATORS: a version check is required for all firmware */
return _("Device firmware is required to have a version check");
}
if (device_flag == FWUPD_DEVICE_FLAG_UNKNOWN) {
return NULL;
}