diff --git a/data/fwupd.service.in b/data/fwupd.service.in index 0110ea8c..49d84153 100644 --- a/data/fwupd.service.in +++ b/data/fwupd.service.in @@ -10,11 +10,3 @@ BusName=org.freedesktop.fwupd ExecStart=@libexecdir@/fwupd/fwupd MemoryDenyWriteExecute=yes PrivateTmp=yes -ProtectControlGroups=yes -ProtectHome=yes -ProtectKernelModules=yes -ProtectSystem=full -RestrictAddressFamilies=AF_NETLINK AF_UNIX -RestrictRealtime=yes -ReadWritePaths=@localstatedir@/lib/fwupd @sysconfdir@/fwupd/remotes.d -@bootdir@ -SystemCallFilter=~@mount diff --git a/meson.build b/meson.build index 7cc6fe85..8d58bd45 100644 --- a/meson.build +++ b/meson.build @@ -145,7 +145,11 @@ gudev = dependency('gudev-1.0') if gudev.version().version_compare('>= 232') conf.set('HAVE_GUDEV_232', '1') endif -appstream_glib = dependency('appstream-glib', version : '>= 0.6.13') +appstream_glib = dependency('appstream-glib', version : '>= 0.6.10') + +# only for appstream <= 0.6.13 +uuid = dependency('uuid') + gusb = dependency('gusb', version : '>= 0.2.9') sqlite = dependency('sqlite3') libarchive = dependency('libarchive') @@ -215,7 +219,7 @@ if get_option('enable-thunderbolt') endif if get_option('enable-systemd') - systemd = dependency('systemd', version : '>= 231') + systemd = dependency('systemd') conf.set('HAVE_SYSTEMD' , '1') endif diff --git a/src/fu-engine.c b/src/fu-engine.c index 79b0a147..bcc18350 100644 --- a/src/fu-engine.c +++ b/src/fu-engine.c @@ -54,6 +54,131 @@ #include "fu-keyring-pkcs7.h" #endif +#if !AS_CHECK_VERSION(0,6,12) +#include +#endif + +#if AS_CHECK_VERSION(0,6,13) +static gint +as_utils_vercmp_SAFE (const gchar *version_a, const gchar *version_b) +{ + return as_utils_vercmp (version_a, version_b); +} +#else + +static gchar * +as_utils_version_parse_SAFE (const gchar *version) +{ + const gchar *version_noprefix = version; + gchar *endptr = NULL; + guint64 tmp; + guint base; + guint i; + + /* already dotted decimal */ + if (g_strstr_len (version, -1, ".") != NULL) + return g_strdup (version); + + /* is a date */ + if (g_str_has_prefix (version, "20") && + strlen (version) == 8) + return g_strdup (version); + + /* convert 0x prefixed strings to dotted decimal */ + if (g_str_has_prefix (version, "0x")) { + version_noprefix += 2; + base = 16; + } else { + /* for non-numeric content, just return the string */ + for (i = 0; version[i] != '\0'; i++) { + if (!g_ascii_isdigit (version[i])) + return g_strdup (version); + } + base = 10; + } + + /* convert */ + tmp = g_ascii_strtoull (version_noprefix, &endptr, base); + if (endptr != NULL && endptr[0] != '\0') + return g_strdup (version); + if (tmp == 0) + return g_strdup (version); + return as_utils_version_from_uint32 ((guint32) tmp, AS_VERSION_PARSE_FLAG_USE_TRIPLET); +} + +static gint +as_utils_vercmp_SAFE (const gchar *version_a, const gchar *version_b) +{ + gchar *endptr; + gint64 ver_a; + gint64 ver_b; + guint i; + guint longest_split; + g_autofree gchar *str_a = NULL; + g_autofree gchar *str_b = NULL; + g_auto(GStrv) split_a = NULL; + g_auto(GStrv) split_b = NULL; + + /* sanity check */ + if (version_a == NULL || version_b == NULL) + return G_MAXINT; + + /* optimisation */ + if (g_strcmp0 (version_a, version_b) == 0) + return 0; + + /* split into sections, and try to parse */ + str_a = as_utils_version_parse_SAFE (version_a); + str_b = as_utils_version_parse_SAFE (version_b); + split_a = g_strsplit (str_a, ".", -1); + split_b = g_strsplit (str_b, ".", -1); + longest_split = MAX (g_strv_length (split_a), g_strv_length (split_b)); + for (i = 0; i < longest_split; i++) { + gboolean isnum_a = TRUE; + gboolean isnum_b = TRUE; + + /* we lost or gained a dot */ + if (split_a[i] == NULL) + return -1; + if (split_b[i] == NULL) + return 1; + + /* compare integers */ + ver_a = g_ascii_strtoll (split_a[i], &endptr, 10); + if (endptr != NULL && endptr[0] != '\0') + isnum_a = FALSE; + if (ver_a < 0) + isnum_a = FALSE; + ver_b = g_ascii_strtoll (split_b[i], &endptr, 10); + if (endptr != NULL && endptr[0] != '\0') + isnum_b = FALSE; + if (ver_b < 0) + isnum_b = FALSE; + + /* can't compare integer with string */ + if (isnum_a != isnum_b) + return G_MAXINT; + + /* compare strings */ + if (!isnum_a) { + gint rc = g_strcmp0 (split_a[i], split_b[i]); + if (rc != 0) + return rc; + + /* compare integers */ + } else { + if (ver_a < ver_b) + return -1; + if (ver_a > ver_b) + return 1; + } + } + + /* we really shouldn't get here */ + return 0; +} +#endif + static void fu_engine_finalize (GObject *obj); struct _FuEngine @@ -811,6 +936,77 @@ _as_app_get_screenshot_default (AsApp *app) #endif } +#if !AS_CHECK_VERSION(0,6,12) +static gboolean +as_require_version_compare_SAFE (AsRequire *require, + const gchar *version, + GError **error) +{ + const gchar *priv__version = as_require_get_version (require); + AsRequireCompare priv__compare = as_require_get_compare (require); + gboolean ret = FALSE; + gint rc = 0; + + switch (priv__compare) { + case AS_REQUIRE_COMPARE_EQ: + rc = as_utils_vercmp_SAFE (version, priv__version); + ret = rc == 0; + break; + case AS_REQUIRE_COMPARE_NE: + rc = as_utils_vercmp_SAFE (version, priv__version); + ret = rc != 0; + break; + case AS_REQUIRE_COMPARE_LT: + rc = as_utils_vercmp_SAFE (version, priv__version); + ret = rc < 0; + break; + case AS_REQUIRE_COMPARE_GT: + rc = as_utils_vercmp_SAFE (version, priv__version); + ret = rc > 0; + break; + case AS_REQUIRE_COMPARE_LE: + rc = as_utils_vercmp_SAFE (version, priv__version); + ret = rc <= 0; + break; + case AS_REQUIRE_COMPARE_GE: + rc = as_utils_vercmp_SAFE (version, priv__version); + ret = rc >= 0; + break; + case AS_REQUIRE_COMPARE_GLOB: + ret = fnmatch (priv__version, version, 0) == 0; + break; + case AS_REQUIRE_COMPARE_REGEX: + ret = g_regex_match_simple (priv__version, version, 0, 0); + break; + default: + break; + } + + /* could not compare */ + if (rc == G_MAXINT) { + g_set_error (error, + AS_UTILS_ERROR, + AS_UTILS_ERROR_FAILED, + "failed to compare [%s] and [%s]", + priv__version, + version); + return FALSE; + } + + /* set error */ + if (!ret && error != NULL) { + g_set_error (error, + AS_UTILS_ERROR, + AS_UTILS_ERROR_FAILED, + "failed predicate [%s %s %s]", + priv__version, + as_require_compare_to_string (priv__compare), + version); + } + return ret; +} +#endif + static gboolean fu_engine_check_version_requirement (AsApp *app, AsRequireKind kind, @@ -836,7 +1032,11 @@ fu_engine_check_version_requirement (AsApp *app, } /* check version */ +#if AS_CHECK_VERSION(0,6,12) if (!as_require_version_compare (req, version, error)) { +#else + if (!as_require_version_compare_SAFE (req, version, error)) { +#endif g_prefix_error (error, "Value of %s incorrect: ", id); return FALSE; } @@ -1221,7 +1421,7 @@ fu_engine_install (FuEngine *self, /* compare to the lowest supported version, if it exists */ tmp = fu_device_get_version_lowest (item->device); - if (tmp != NULL && as_utils_vercmp (tmp, version) > 0) { + if (tmp != NULL && as_utils_vercmp_SAFE (tmp, version) > 0) { g_set_error (error, FWUPD_ERROR, FWUPD_ERROR_VERSION_NEWER, @@ -1240,7 +1440,7 @@ fu_engine_install (FuEngine *self, device_id); return FALSE; } - vercmp = as_utils_vercmp (tmp, version); + vercmp = as_utils_vercmp_SAFE (tmp, version); if (vercmp == 0 && (flags & FWUPD_INSTALL_FLAG_ALLOW_REINSTALL) == 0) { g_set_error (error, FWUPD_ERROR, @@ -1476,7 +1676,7 @@ fu_engine_get_action_id_for_device (FuEngine *self, "Release has no firmware version"); return NULL; } - vercmp = as_utils_vercmp (version, version_release); + vercmp = as_utils_vercmp_SAFE (version, version_release); if (vercmp == 0 && (flags & FWUPD_INSTALL_FLAG_ALLOW_REINSTALL) == 0) { g_set_error (error, FWUPD_ERROR, @@ -2099,7 +2299,7 @@ fu_engine_sort_releases_cb (gconstpointer a, gconstpointer b) { FwupdRelease *rel_a = FWUPD_RELEASE (*((FwupdRelease **) a)); FwupdRelease *rel_b = FWUPD_RELEASE (*((FwupdRelease **) b)); - return as_utils_vercmp (fwupd_release_get_version (rel_a), + return as_utils_vercmp_SAFE (fwupd_release_get_version (rel_a), fwupd_release_get_version (rel_b)); } @@ -2246,7 +2446,7 @@ fu_engine_get_downgrades (FuEngine *self, const gchar *device_id, GError **error gint vercmp; /* only include older firmware */ - vercmp = as_utils_vercmp (fwupd_release_get_version (rel_tmp), + vercmp = as_utils_vercmp_SAFE (fwupd_release_get_version (rel_tmp), fu_device_get_version (item->device)); if (vercmp == 0) { g_string_append_printf (error_str, "%s=same, ", @@ -2267,7 +2467,7 @@ fu_engine_get_downgrades (FuEngine *self, const gchar *device_id, GError **error /* don't show releases we are not allowed to dowgrade to */ if (fu_device_get_version_lowest (item->device) != NULL) { - if (as_utils_vercmp (fwupd_release_get_version (rel_tmp), + if (as_utils_vercmp_SAFE (fwupd_release_get_version (rel_tmp), fu_device_get_version_lowest (item->device)) <= 0) { g_string_append_printf (error_str, "%s=lowest, ", fwupd_release_get_version (rel_tmp)); @@ -2339,7 +2539,7 @@ fu_engine_get_upgrades (FuEngine *self, const gchar *device_id, GError **error) gint vercmp; /* only include older firmware */ - vercmp = as_utils_vercmp (fwupd_release_get_version (rel_tmp), + vercmp = as_utils_vercmp_SAFE (fwupd_release_get_version (rel_tmp), fu_device_get_version (item->device)); if (vercmp == 0) { g_string_append_printf (error_str, "%s=same, ", diff --git a/src/fu-hwids.c b/src/fu-hwids.c index 5e7aa923..92d0afdf 100644 --- a/src/fu-hwids.c +++ b/src/fu-hwids.c @@ -69,6 +69,56 @@ fu_hwids_has_guid (FuHwids *self, const gchar *guid) return g_hash_table_lookup (self->hash_guid, guid) != NULL; } +#if !AS_CHECK_VERSION(0,6,13) +#include +static gchar * +as_utils_guid_from_data (const gchar *namespace_id, + const guint8 *data, + gsize data_len, + GError **error) +{ + gchar guid_new[37]; /* 36 plus NUL */ + gsize digestlen = 20; + guint8 hash[20]; + gint rc; + uuid_t uu_namespace; + uuid_t uu_new; + g_autoptr(GChecksum) csum = NULL; + + g_return_val_if_fail (namespace_id != NULL, FALSE); + g_return_val_if_fail (data != NULL, FALSE); + g_return_val_if_fail (data_len != 0, FALSE); + + /* convert the namespace to binary */ + rc = uuid_parse (namespace_id, uu_namespace); + if (rc != 0) { + g_set_error (error, + AS_UTILS_ERROR, + AS_UTILS_ERROR_FAILED, + "namespace '%s' is invalid", + namespace_id); + return FALSE; + } + + /* hash the namespace and then the string */ + csum = g_checksum_new (G_CHECKSUM_SHA1); + g_checksum_update (csum, (guchar *) uu_namespace, 16); + g_checksum_update (csum, (guchar *) data, (gssize) data_len); + g_checksum_get_digest (csum, hash, &digestlen); + + /* copy most parts of the hash 1:1 */ + memcpy (uu_new, hash, 16); + + /* set specific bits according to Section 4.1.3 */ + uu_new[6] = (guint8) ((uu_new[6] & 0x0f) | (5 << 4)); + uu_new[8] = (guint8) ((uu_new[8] & 0x3f) | 0x80); + + /* return as a string */ + uuid_unparse (uu_new, guid_new); + return g_strdup (guid_new); +} +#endif + static gchar * fu_hwids_get_guid_for_str (const gchar *str, GError **error) { diff --git a/src/meson.build b/src/meson.build index 3d35dd87..9788f529 100644 --- a/src/meson.build +++ b/src/meson.build @@ -38,6 +38,7 @@ libfwupdprivate = static_library( ], dependencies : [ appstream_glib, + uuid, giounix, gudev, gusb, @@ -67,6 +68,7 @@ fwupdmgr = executable( ], dependencies : [ appstream_glib, + uuid, giounix, gudev, gusb, @@ -141,6 +143,7 @@ executable( dependencies : [ keyring_deps, appstream_glib, + uuid, giounix, gmodule, gudev, @@ -203,6 +206,7 @@ if get_option('enable-tests') dependencies : [ keyring_deps, appstream_glib, + uuid, giounix, gmodule, gudev, @@ -260,6 +264,7 @@ if get_option('enable-introspection') ], dependencies : [ appstream_glib, + uuid, gir_dep, giounix, gusb,