fwupd/libfwupdplugin/fu-efi-firmware-common.c
2021-08-24 11:18:40 -05:00

132 lines
2.9 KiB
C

/*
* Copyright (C) 2021 Richard Hughes <richard@hughsie.com>
*
* SPDX-License-Identifier: LGPL-2.1+
*/
#include "config.h"
#ifdef HAVE_LZMA
#include <lzma.h>
#endif
#include <fwupdplugin.h>
#include "fu-efi-firmware-common.h"
#include "fu-efi-firmware-section.h"
/**
* fu_efi_firmware_parse_sections:
* @firmware: #FuFirmware
* @fw: data
* @flags: flags
* @error: (nullable): optional return location for an error
*
* Parses a UEFI section.
*
* Returns: %TRUE for success
*
* Since: 1.6.2
**/
gboolean
fu_efi_firmware_parse_sections(FuFirmware *firmware,
GBytes *fw,
FwupdInstallFlags flags,
GError **error)
{
gsize offset = 0;
gsize bufsz = g_bytes_get_size(fw);
while (offset < bufsz) {
g_autoptr(FuFirmware) img = fu_efi_firmware_section_new();
g_autoptr(GBytes) blob = NULL;
/* maximum payload */
blob = fu_common_bytes_new_offset(fw, offset, bufsz - offset, error);
if (blob == NULL)
return FALSE;
/* parse section */
if (!fu_firmware_parse(img, blob, flags, error))
return FALSE;
fu_firmware_set_offset(img, offset);
fu_firmware_add_image(firmware, img);
/* next! */
offset += fu_firmware_get_size(img);
}
if (offset != g_bytes_get_size(fw)) {
g_set_error(error,
FWUPD_ERROR,
FWUPD_ERROR_INTERNAL,
"EFI sections overflow 0x%x of 0x%x",
(guint)offset,
(guint)g_bytes_get_size(fw));
return FALSE;
}
/* success */
return TRUE;
}
/**
* fu_efi_firmware_decompress_lzma:
* @blob: data
* @error: (nullable): optional return location for an error
*
* Decompresses a LZMA stream.
*
* Returns: decompressed data
*
* Since: 1.6.2
**/
GBytes *
fu_efi_firmware_decompress_lzma(GBytes *blob, GError **error)
{
#ifdef HAVE_LZMA
const gsize tmpbufsz = 0x20000;
lzma_ret rc;
lzma_stream strm = LZMA_STREAM_INIT;
uint64_t memlimit = G_MAXUINT32;
g_autofree guint8 *tmpbuf = g_malloc0(tmpbufsz);
g_autoptr(GByteArray) buf = g_byte_array_new();
strm.next_in = g_bytes_get_data(blob, NULL);
strm.avail_in = g_bytes_get_size(blob);
rc = lzma_auto_decoder(&strm, memlimit, LZMA_TELL_UNSUPPORTED_CHECK);
if (rc != LZMA_OK) {
lzma_end(&strm);
g_set_error(error,
G_IO_ERROR,
G_IO_ERROR_NOT_SUPPORTED,
"failed to set up LZMA decoder rc=%u",
rc);
return NULL;
}
do {
strm.next_out = tmpbuf;
strm.avail_out = tmpbufsz;
rc = lzma_code(&strm, LZMA_RUN);
if (rc != LZMA_OK && rc != LZMA_STREAM_END)
break;
g_byte_array_append(buf, tmpbuf, tmpbufsz - strm.avail_out);
} while (rc == LZMA_OK);
lzma_end(&strm);
/* success */
if (rc != LZMA_OK && rc != LZMA_STREAM_END) {
g_set_error(error,
G_IO_ERROR,
G_IO_ERROR_NOT_SUPPORTED,
"failed to decode LZMA data rc=%u",
rc);
return NULL;
}
return g_byte_array_free_to_bytes(g_steal_pointer(&buf));
#else
g_set_error_literal(error, G_IO_ERROR, G_IO_ERROR_NOT_SUPPORTED, "missing lzma support");
return NULL;
#endif
}