mirror of
https://git.proxmox.com/git/fwupd
synced 2025-05-29 18:43:18 +00:00
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:
parent
8f89cf04fb
commit
deea2da041
@ -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
327
src/fu-common-cab.c
Normal 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
30
src/fu-common-cab.h
Normal 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 */
|
@ -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);
|
||||
|
@ -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 ();
|
||||
|
@ -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,
|
||||
|
Loading…
Reference in New Issue
Block a user