Use the new functionality in libgcab >= 1.0 to avoid writing temp files

Using old versions of gcab we could only do one thing: extract the files in the
cabinet archive to a new directory in /tmp, and then fwupd would have to read
them back in to memory to parse them. This was both inelegant and wasteful, and
probably not an awesome idea from a security or privacy point of view.

Using libgcab >= 1.0 we can decompress to a GBytes blob, and then verify the
firmware and metainfo file without anything being written to disk.

As this is a security sensitive operation, move the fwupd-specific helper code
out of libappstream-glib and also add a lot of internal self tests.

The gcab code will have to remain in libappstream-glib for a long time, but we
don't have to use it. Handling the cab file here also allows us to fix two
long-standing bugs:

 * MetaInfo or firmware files in a subdirectory are handled correctly

 * The archive can also be self-signed using PKCS7 instead of using GPG
This commit is contained in:
Richard Hughes 2017-12-15 15:40:44 +00:00
parent 8f89cf04fb
commit deea2da041
6 changed files with 690 additions and 13 deletions

View File

@ -163,10 +163,13 @@ endif
libm = cc.find_library('m', required: false)
udev = dependency('udev')
uuid = dependency('uuid')
gcab = dependency('libgcab-1.0')
if gcab.version().version_compare('>= 0.8')
libgcab = dependency('libgcab-1.0')
if libgcab.version().version_compare('>= 0.8')
conf.set('HAVE_GCAB_0_8', '1')
endif
if libgcab.version().version_compare('>= 1.0')
conf.set('HAVE_GCAB_1_0', '1')
endif
if get_option('plugin_uefi_labels')
cairo = dependency('cairo')

327
src/fu-common-cab.c Normal file
View File

@ -0,0 +1,327 @@
/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*-
*
* Copyright (C) 2017 Richard Hughes <richard@hughsie.com>
*
* Licensed under the GNU Lesser General Public License Version 2.1
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include "config.h"
#include <libgcab.h>
#include "fu-common-cab.h"
#include "fu-common.h"
#include "fwupd-error.h"
#ifdef HAVE_GCAB_1_0
/* sets the firmware and signature blobs on AsRelease */
static gboolean
fu_common_store_from_cab_release (AsRelease *release, GCabFolder *cabfolder, GError **error)
{
AsChecksum *csum_tmp;
GCabFile *cabfile;
GBytes *blob;
guint64 size;
g_autofree gchar *basename = NULL;
g_autofree gchar *checksum = NULL;
const gchar *suffixes[] = { "asc", "p7b", "p7c", NULL };
/* ensure we always have a content checksum */
csum_tmp = as_release_get_checksum_by_target (release, AS_CHECKSUM_TARGET_CONTENT);
if (csum_tmp == NULL) {
g_autoptr(AsChecksum) csum = as_checksum_new ();
as_checksum_set_target (csum, AS_CHECKSUM_TARGET_CONTENT);
/* if this isn't true, a firmware needs to set in
* the metainfo.xml file something like:
* <checksum target="content" filename="FLASH.ROM"/> */
as_checksum_set_filename (csum, "firmware.bin");
as_release_add_checksum (release, csum);
csum_tmp = csum;
}
/* get the main firmware file */
basename = g_path_get_basename (as_checksum_get_filename (csum_tmp));
cabfile = gcab_folder_get_file_by_name (cabfolder, basename);
if (cabfile == NULL) {
g_set_error (error,
FWUPD_ERROR,
FWUPD_ERROR_INVALID_FILE,
"cannot find %s in archive",
as_checksum_get_filename (csum_tmp));
return FALSE;
}
blob = gcab_file_get_bytes (cabfile);
if (blob == NULL) {
g_set_error_literal (error,
FWUPD_ERROR,
FWUPD_ERROR_INVALID_FILE,
"no GBytes from GCabFile firmware");
return FALSE;
}
/* set the blob */
as_release_set_blob (release, basename, blob);
/* set if unspecified, but error out if specified and incorrect */
size = as_release_get_size (release, AS_SIZE_KIND_INSTALLED);
if (size == 0) {
as_release_set_size (release, AS_SIZE_KIND_INSTALLED,
g_bytes_get_size (blob));
} else if (size != g_bytes_get_size (blob)) {
g_set_error (error,
FWUPD_ERROR,
FWUPD_ERROR_INVALID_FILE,
"contents size invalid, expected "
"%" G_GUINT64_FORMAT ", got %" G_GUINT64_FORMAT,
g_bytes_get_size (blob), size);
return FALSE;
}
/* set if unspecified, but error out if specified and incorrect */
checksum = g_compute_checksum_for_bytes (G_CHECKSUM_SHA1, blob);
if (as_checksum_get_value (csum_tmp) == NULL) {
as_checksum_set_value (csum_tmp, checksum);
} else if (g_strcmp0 (checksum, as_checksum_get_value (csum_tmp)) != 0) {
g_set_error (error,
FWUPD_ERROR,
FWUPD_ERROR_INVALID_FILE,
"contents checksum invalid, expected %s, got %s",
checksum,
as_checksum_get_value (csum_tmp));
return FALSE;
}
/* if the signing file exists, set that too */
for (guint i = 0; suffixes[i] != NULL; i++) {
g_autofree gchar *basename_sig = NULL;
basename_sig = g_strdup_printf ("%s.%s", basename, suffixes[i]);
cabfile = gcab_folder_get_file_by_name (cabfolder, basename_sig);
if (cabfile != NULL) {
blob = gcab_file_get_bytes (cabfile);
if (blob == NULL) {
g_set_error (error,
FWUPD_ERROR,
FWUPD_ERROR_INVALID_FILE,
"no GBytes from GCabFile %s",
basename_sig);
return FALSE;
}
as_release_set_blob (release, basename_sig, blob);
}
}
/* success */
return TRUE;
}
/* adds each GCabFile to the store */
static gboolean
fu_common_store_from_cab_file (AsStore *store, GCabFolder *cabfolder,
GCabFile *cabfile, GError **error)
{
GBytes *blob;
GPtrArray *releases;
g_autoptr(AsApp) app = NULL;
g_autoptr(GError) error_local = NULL;
#if !AS_CHECK_VERSION(0,7,5)
g_autofree gchar *cache_fn = NULL;
#endif
/* parse file */
blob = gcab_file_get_bytes (cabfile);
if (blob == NULL) {
g_set_error_literal (error,
FWUPD_ERROR,
FWUPD_ERROR_INVALID_FILE,
"no GBytes from GCabFile");
return FALSE;
}
app = as_app_new ();
#if AS_CHECK_VERSION(0,7,5)
if (!as_app_parse_data (app, blob, AS_APP_PARSE_FLAG_NONE, &error_local)) {
g_set_error (error,
FWUPD_ERROR,
FWUPD_ERROR_INVALID_FILE,
"counld not parse MetaInfo XML: %s",
error_local->message);
return FALSE;
}
#else
cache_fn = g_build_filename (LOCALSTATEDIR, "cache", "fwupd",
gcab_file_get_extract_name (cabfile), NULL);
if (!fu_common_mkdir_parent (cache_fn, error))
return FALSE;
if (!g_file_set_contents (cache_fn, g_bytes_get_data (blob, NULL),
g_bytes_get_size (blob), &error_local)) {
g_set_error (error,
FWUPD_ERROR,
FWUPD_ERROR_WRITE,
"counld not save temporary MetaInfo XML to %s: %s",
cache_fn, error_local->message);
return FALSE;
}
if (!as_app_parse_file (app, cache_fn, AS_APP_PARSE_FLAG_NONE, &error_local)) {
g_set_error (error,
FWUPD_ERROR,
FWUPD_ERROR_INVALID_FILE,
"counld not parse MetaInfo XML: %s",
error_local->message);
return FALSE;
}
#endif
/* process each listed release */
releases = as_app_get_releases (app);
if (releases->len == 0) {
g_set_error_literal (error,
FWUPD_ERROR,
FWUPD_ERROR_INVALID_FILE,
"no releases in metainfo file");
return FALSE;
}
for (guint i = 0; i < releases->len; i++) {
AsRelease *release = g_ptr_array_index (releases, i);
g_debug ("processing release: %s", as_release_get_version (release));
if (!fu_common_store_from_cab_release (release, cabfolder, error))
return FALSE;
}
/* success */
as_store_add_app (store, app);
return TRUE;
}
/* adds each GCabFolder to the store */
static gboolean
fu_common_store_from_cab_folder (AsStore *store, GCabFolder *cabfolder, GError **error)
{
g_autoptr(GSList) cabfiles = gcab_folder_get_files (cabfolder);
for (GSList *l = cabfiles; l != NULL; l = l->next) {
GCabFile *cabfile = GCAB_FILE (l->data);
const gchar *fn = gcab_file_get_extract_name (cabfile);
g_debug ("processing file: %s", fn);
if (as_format_guess_kind (fn) == AS_FORMAT_KIND_METAINFO) {
if (!fu_common_store_from_cab_file (store, cabfolder, cabfile, error)) {
g_prefix_error (error, "%s could not be loaded: ",
gcab_file_get_extract_name (cabfile));
return FALSE;
}
}
}
return TRUE;
}
static gboolean
as_cab_store_file_cb (GCabFile *file, gpointer user_data)
{
g_autofree gchar *basename = NULL;
g_autofree gchar *name = NULL;
/* convert to UNIX paths */
name = g_strdup (gcab_file_get_name (file));
g_strdelimit (name, "\\", '/');
/* ignore the dirname completely */
basename = g_path_get_basename (name);
gcab_file_set_extract_name (file, basename);
return TRUE;
}
/**
* fu_common_store_from_cab_bytes:
* @blob: A readable blob
* @error: A #FuEndianType, e.g. %G_LITTLE_ENDIAN
*
* Create an AppStream store from a cabinet archive.
*
* Returns: a store, or %NULL on error
**/
AsStore *
fu_common_store_from_cab_bytes (GBytes *blob, GError **error)
{
GPtrArray *folders;
g_autoptr(AsStore) store = as_store_new ();
g_autoptr(GCabCabinet) cabinet = gcab_cabinet_new ();
g_autoptr(GError) error_local = NULL;
g_autoptr(GInputStream) ip = NULL;
/* decompress the file to memory */
ip = g_memory_input_stream_new_from_bytes (blob);
if (!gcab_cabinet_load (cabinet, ip, NULL, error))
return FALSE;
if (!gcab_cabinet_extract_simple (cabinet, NULL,
as_cab_store_file_cb, NULL,
NULL, &error_local)) {
g_set_error_literal (error,
FWUPD_ERROR,
FWUPD_ERROR_INVALID_FILE,
error_local->message);
return NULL;
}
/* look at each folder */
folders = gcab_cabinet_get_folders (cabinet);
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_common_store_from_cab_folder (store, cabfolder, error))
return NULL;
}
/* did we get any valid AsApps */
if (as_store_get_size (store) == 0) {
g_set_error_literal (error,
FWUPD_ERROR,
FWUPD_ERROR_INVALID_FILE,
"archive contained no valid metadata");
return FALSE;
}
/* success */
return g_steal_pointer (&store);
}
#else
AsStore *
fu_common_store_from_cab_bytes (GBytes *blob, GError **error)
{
g_autoptr(AsStore) store = as_store_new ();
g_autoptr(GError) error_local = NULL;
/* this is klunky as we have to write actual files to /tmp */
if (!as_store_from_bytes (store, blob, NULL, &error_local)) {
g_set_error_literal (error,
FWUPD_ERROR,
FWUPD_ERROR_INVALID_FILE,
error_local->message);
return NULL;
}
/* did we get any valid AsApps */
if (as_store_get_size (store) == 0) {
g_set_error_literal (error,
FWUPD_ERROR,
FWUPD_ERROR_INVALID_FILE,
"archive contained no valid metadata");
return FALSE;
}
return g_steal_pointer (&store);
}
#endif

30
src/fu-common-cab.h Normal file
View File

@ -0,0 +1,30 @@
/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*-
*
* Copyright (C) 2017 Richard Hughes <richard@hughsie.com>
*
* Licensed under the GNU Lesser General Public License Version 2.1
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#ifndef __FU_COMMON_CAB_H
#define __FU_COMMON_CAB_H
#include <appstream-glib.h>
AsStore *fu_common_store_from_cab_bytes (GBytes *blob,
GError **error);
#endif /* __FU_COMMON_CAB_H */

View File

@ -34,6 +34,7 @@
#include "fwupd-remote-private.h"
#include "fwupd-resources.h"
#include "fu-common-cab.h"
#include "fu-common.h"
#include "fu-config.h"
#include "fu-debug.h"
@ -1973,27 +1974,19 @@ fu_engine_get_store_from_blob (FuEngine *self, GBytes *blob_cab, GError **error)
{
g_autofree gchar *checksum = NULL;
g_autoptr(AsStore) store = NULL;
g_autoptr(GError) error_local = NULL;
g_return_val_if_fail (FU_IS_ENGINE (self), NULL);
g_return_val_if_fail (blob_cab != NULL, NULL);
g_return_val_if_fail (error == NULL || *error == NULL, NULL);
/* load file */
store = as_store_new ();
fu_engine_set_status (self, FWUPD_STATUS_DECOMPRESSING);
if (!as_store_from_bytes (store, blob_cab, NULL, &error_local)) {
g_set_error_literal (error,
FWUPD_ERROR,
FWUPD_ERROR_INVALID_FILE,
error_local->message);
store = fu_common_store_from_cab_bytes (blob_cab, error);
if (store == NULL)
return NULL;
}
/* get a checksum of the file and use it as the origin */
checksum = g_compute_checksum_for_data (G_CHECKSUM_SHA256,
g_bytes_get_data (blob_cab, NULL),
g_bytes_get_size (blob_cab));
checksum = g_compute_checksum_for_bytes (G_CHECKSUM_SHA256, blob_cab);
as_store_set_origin (store, checksum);
fu_engine_set_status (self, FWUPD_STATUS_IDLE);

View File

@ -26,9 +26,11 @@
#include <glib-object.h>
#include <glib/gstdio.h>
#include <gio/gfiledescriptorbased.h>
#include <libgcab.h>
#include <stdlib.h>
#include <string.h>
#include "fu-common-cab.h"
#include "fu-config.h"
#include "fu-device-list.h"
#include "fu-device-private.h"
@ -1358,6 +1360,317 @@ fu_common_endian_func (void)
g_assert_cmpint (fu_common_read_uint16 (buf, G_BIG_ENDIAN), ==, 0x1234);
}
static GBytes *
_build_cab (GCabCompression compression, ...)
{
#ifdef HAVE_GCAB_1_0
gboolean ret;
va_list args;
g_autoptr(GCabCabinet) cabinet = NULL;
g_autoptr(GCabFolder) cabfolder = NULL;
g_autoptr(GError) error = NULL;
g_autoptr(GOutputStream) op = NULL;
/* create a new archive */
cabinet = gcab_cabinet_new ();
cabfolder = gcab_folder_new (compression);
ret = gcab_cabinet_add_folder (cabinet, cabfolder, &error);
g_assert_no_error (error);
g_assert (ret);
/* add each file */
va_start (args, compression);
do {
const gchar *fn;
const gchar *text;
g_autoptr(GCabFile) cabfile = NULL;
g_autoptr(GBytes) blob = NULL;
/* get filename */
fn = va_arg (args, const gchar *);
if (fn == NULL)
break;
/* get contents */
text = va_arg (args, const gchar *);
if (text == NULL)
break;
g_debug ("creating %s with %s", fn, text);
/* add a GCabFile to the cabinet */
blob = g_bytes_new_static (text, strlen (text));
cabfile = gcab_file_new_with_bytes (fn, blob);
ret = gcab_folder_add_file (cabfolder, cabfile, FALSE, NULL, &error);
g_assert_no_error (error);
g_assert (ret);
} while (TRUE);
va_end (args);
/* write the archive to a blob */
op = g_memory_output_stream_new_resizable ();
ret = gcab_cabinet_write_simple (cabinet, op, NULL, NULL, NULL, &error);
g_assert_no_error (error);
g_assert (ret);
ret = g_output_stream_close (op, NULL, &error);
g_assert_no_error (error);
g_assert (ret);
return g_memory_output_stream_steal_as_bytes (G_MEMORY_OUTPUT_STREAM (op));
#else
return NULL;
#endif
}
static void
fu_common_store_cab_func (void)
{
AsApp *app;
AsChecksum *csum;
AsRelease *rel;
AsRequire *req;
GBytes *blob_tmp;
g_autoptr(AsStore) store = NULL;
g_autoptr(GBytes) blob = NULL;
g_autoptr(GError) error = NULL;
/* create store */
blob = _build_cab (GCAB_COMPRESSION_NONE,
"acme.metainfo.xml",
"<component type=\"firmware\">\n"
" <id>com.acme.example.firmware</id>\n"
" <name>ACME Firmware</name>\n"
" <provides>\n"
" <firmware type=\"flashed\">ae56e3fb-6528-5bc4-8b03-012f124075d7</firmware>\n"
" </provides>\n"
" <releases>\n"
" <release version=\"1.2.3\" date=\"2017-09-06\">\n"
" <checksum filename=\"firmware.dfu\" target=\"content\"/>\n"
" <size type=\"installed\">5</size>\n"
" <checksum filename=\"firmware.bin\" target=\"content\" type=\"sha1\">7c211433f02071597741e6ff5a8ea34789abbf43</checksum>\n"
" <description><p>We fixed things</p></description>\n"
" </release>\n"
" </releases>\n"
" <requires>\n"
" <id compare=\"ge\" version=\"1.0.1\">org.freedesktop.fwupd</id>\n"
" </requires>\n"
"</component>",
"firmware.dfu", "world",
"firmware.dfu.asc", "signature",
NULL);
if (blob == NULL) {
g_test_skip ("libgcab too old");
return;
}
store = fu_common_store_from_cab_bytes (blob, &error);
g_assert_no_error (error);
g_assert (store != NULL);
/* verify */
app = as_store_get_app_by_id (store, "com.acme.example.firmware");
g_assert_nonnull (app);
rel = as_app_get_release_default (app);
g_assert_nonnull (rel);
g_assert_cmpstr (as_release_get_version (rel), ==, "1.2.3");
csum = as_release_get_checksum_by_target (rel, AS_CHECKSUM_TARGET_CONTENT);
g_assert_cmpstr (as_checksum_get_value (csum), ==, "7c211433f02071597741e6ff5a8ea34789abbf43");
blob_tmp = as_release_get_blob (rel, "firmware.dfu");
g_assert_nonnull (blob_tmp);
blob_tmp = as_release_get_blob (rel, "firmware.dfu.asc");
g_assert_nonnull (blob_tmp);
req = as_app_get_require_by_value (app, AS_REQUIRE_KIND_ID, "org.freedesktop.fwupd");
g_assert_nonnull (req);
}
static void
fu_common_store_cab_unsigned_func (void)
{
AsApp *app;
AsChecksum *csum;
AsRelease *rel;
GBytes *blob_tmp;
g_autoptr(AsStore) store = NULL;
g_autoptr(GBytes) blob = NULL;
g_autoptr(GError) error = NULL;
/* create store */
blob = _build_cab (GCAB_COMPRESSION_NONE,
"acme.metainfo.xml",
"<component type=\"firmware\">\n"
" <id>com.acme.example.firmware</id>\n"
" <releases>\n"
" <release version=\"1.2.3\"/>\n"
" </releases>\n"
"</component>",
"firmware.bin", "world",
NULL);
if (blob == NULL) {
g_test_skip ("libgcab too old");
return;
}
store = fu_common_store_from_cab_bytes (blob, &error);
g_assert_no_error (error);
g_assert (store != NULL);
/* verify */
app = as_store_get_app_by_id (store, "com.acme.example.firmware");
g_assert_nonnull (app);
rel = as_app_get_release_default (app);
g_assert_nonnull (rel);
g_assert_cmpstr (as_release_get_version (rel), ==, "1.2.3");
csum = as_release_get_checksum_by_target (rel, AS_CHECKSUM_TARGET_CONTENT);
g_assert_cmpstr (as_checksum_get_value (csum), ==, "7c211433f02071597741e6ff5a8ea34789abbf43");
blob_tmp = as_release_get_blob (rel, "firmware.bin");
g_assert_nonnull (blob_tmp);
blob_tmp = as_release_get_blob (rel, "firmware.bin.asc");
g_assert_null (blob_tmp);
}
static void
fu_common_store_cab_folder_func (void)
{
AsApp *app;
AsChecksum *csum;
AsRelease *rel;
GBytes *blob_tmp;
g_autoptr(AsStore) store = NULL;
g_autoptr(GBytes) blob = NULL;
g_autoptr(GError) error = NULL;
/* create store */
blob = _build_cab (GCAB_COMPRESSION_NONE,
"lvfs\\acme.metainfo.xml",
"<component type=\"firmware\">\n"
" <id>com.acme.example.firmware</id>\n"
" <releases>\n"
" <release version=\"1.2.3\"/>\n"
" </releases>\n"
"</component>",
"lvfs\\firmware.bin", "world",
NULL);
if (blob == NULL) {
g_test_skip ("libgcab too old");
return;
}
store = fu_common_store_from_cab_bytes (blob, &error);
g_assert_no_error (error);
g_assert (store != NULL);
/* verify */
app = as_store_get_app_by_id (store, "com.acme.example.firmware");
g_assert_nonnull (app);
rel = as_app_get_release_default (app);
g_assert_nonnull (rel);
g_assert_cmpstr (as_release_get_version (rel), ==, "1.2.3");
csum = as_release_get_checksum_by_target (rel, AS_CHECKSUM_TARGET_CONTENT);
g_assert_cmpstr (as_checksum_get_value (csum), ==, "7c211433f02071597741e6ff5a8ea34789abbf43");
blob_tmp = as_release_get_blob (rel, "firmware.bin");
g_assert_nonnull (blob_tmp);
}
static void
fu_common_store_cab_error_no_metadata_func (void)
{
g_autoptr(AsStore) store = NULL;
g_autoptr(GBytes) blob = NULL;
g_autoptr(GError) error = NULL;
blob = _build_cab (GCAB_COMPRESSION_NONE,
"foo.txt", "hello",
"bar.txt", "world",
NULL);
if (blob == NULL) {
g_test_skip ("libgcab too old");
return;
}
store = fu_common_store_from_cab_bytes (blob, &error);
g_assert_error (error, FWUPD_ERROR, FWUPD_ERROR_INVALID_FILE);
g_assert (store == NULL);
}
static void
fu_common_store_cab_error_wrong_size_func (void)
{
g_autoptr(AsStore) store = NULL;
g_autoptr(GBytes) blob = NULL;
g_autoptr(GError) error = NULL;
blob = _build_cab (GCAB_COMPRESSION_NONE,
"acme.metainfo.xml",
"<component type=\"firmware\">\n"
" <id>com.acme.example.firmware</id>\n"
" <releases>\n"
" <release version=\"1.2.3\">\n"
" <size type=\"installed\">7004701</size>\n"
" <checksum filename=\"firmware.bin\" target=\"content\" type=\"sha1\">deadbeef</checksum>\n"
" </release>\n"
" </releases>\n"
"</component>",
"firmware.bin", "world",
NULL);
if (blob == NULL) {
g_test_skip ("libgcab too old");
return;
}
store = fu_common_store_from_cab_bytes (blob, &error);
g_assert_error (error, FWUPD_ERROR, FWUPD_ERROR_INVALID_FILE);
g_assert (store == NULL);
}
static void
fu_common_store_cab_error_missing_file_func (void)
{
g_autoptr(AsStore) store = NULL;
g_autoptr(GBytes) blob = NULL;
g_autoptr(GError) error = NULL;
blob = _build_cab (GCAB_COMPRESSION_NONE,
"acme.metainfo.xml",
"<component type=\"firmware\">\n"
" <id>com.acme.example.firmware</id>\n"
" <releases>\n"
" <release version=\"1.2.3\">\n"
" <checksum filename=\"firmware.dfu\" target=\"content\"/>\n"
" </release>\n"
" </releases>\n"
"</component>",
"firmware.bin", "world",
NULL);
if (blob == NULL) {
g_test_skip ("libgcab too old");
return;
}
store = fu_common_store_from_cab_bytes (blob, &error);
g_assert_error (error, FWUPD_ERROR, FWUPD_ERROR_INVALID_FILE);
g_assert (store == NULL);
}
static void
fu_common_store_cab_error_wrong_checksum_func (void)
{
g_autoptr(AsStore) store = NULL;
g_autoptr(GBytes) blob = NULL;
g_autoptr(GError) error = NULL;
blob = _build_cab (GCAB_COMPRESSION_NONE,
"acme.metainfo.xml",
"<component type=\"firmware\">\n"
" <id>com.acme.example.firmware</id>\n"
" <releases>\n"
" <release version=\"1.2.3\">\n"
" <checksum filename=\"firmware.bin\" target=\"content\" type=\"sha1\">deadbeef</checksum>\n"
" </release>\n"
" </releases>\n"
"</component>",
"firmware.bin", "world",
NULL);
if (blob == NULL) {
g_test_skip ("libgcab too old");
return;
}
store = fu_common_store_from_cab_bytes (blob, &error);
g_assert_error (error, FWUPD_ERROR, FWUPD_ERROR_INVALID_FILE);
g_assert (store == NULL);
}
int
main (int argc, char **argv)
{
@ -1393,6 +1706,13 @@ main (int argc, char **argv)
g_test_add_func ("/fwupd/keyring{gpg}", fu_keyring_gpg_func);
g_test_add_func ("/fwupd/keyring{pkcs7}", fu_keyring_pkcs7_func);
g_test_add_func ("/fwupd/common{endian}", fu_common_endian_func);
g_test_add_func ("/fwupd/common{cab-success}", fu_common_store_cab_func);
g_test_add_func ("/fwupd/common{cab-success-unsigned}", fu_common_store_cab_unsigned_func);
g_test_add_func ("/fwupd/common{cab-success-folder}", fu_common_store_cab_folder_func);
g_test_add_func ("/fwupd/common{cab-error-no-metadata}", fu_common_store_cab_error_no_metadata_func);
g_test_add_func ("/fwupd/common{cab-error-wrong-size}", fu_common_store_cab_error_wrong_size_func);
g_test_add_func ("/fwupd/common{cab-error-wrong-checksum}", fu_common_store_cab_error_wrong_checksum_func);
g_test_add_func ("/fwupd/common{cab-error-missing-file}", fu_common_store_cab_error_missing_file_func);
g_test_add_func ("/fwupd/common{spawn)", fu_common_spawn_func);
g_test_add_func ("/fwupd/common{firmware-builder}", fu_common_firmware_builder_func);
return g_test_run ();

View File

@ -120,6 +120,7 @@ executable(
sources : [
keyring_src,
'fu-common.c',
'fu-common-cab.c',
'fu-config.c',
'fu-keyring.c',
'fu-keyring-result.c',
@ -145,6 +146,7 @@ executable(
dependencies : [
keyring_deps,
appstream_glib,
libgcab,
giounix,
gmodule,
gudev,
@ -185,6 +187,7 @@ if get_option('tests')
keyring_src,
'fu-self-test.c',
'fu-common.c',
'fu-common-cab.c',
'fu-config.c',
'fu-engine.c',
'fu-keyring.c',
@ -210,6 +213,7 @@ if get_option('tests')
dependencies : [
keyring_deps,
appstream_glib,
libgcab,
giounix,
gmodule,
gudev,