mirror of https://github.com/wolfSSL/wolfBoot.git
Peer review fixes (copilot)
src/fdt.c, include/fdt.h
- Propagate fdt_fixup_initrd error in fit_load_ramdisk so a /chosen
patch failure no longer silently boots a kernel with no initrd.
- Add fit_load_image_to(): decompress (or memcpy) directly to a
caller-supplied destination buffer instead of going through the
FIT-declared `load` address. fit_load_ramdisk now uses this when
WOLFBOOT_LOAD_RAMDISK_ADDRESS is set, so the override is a real
safety bound for compressed ramdisks (previously the gzip stream
was still inflated to the FIT `load` and only memcpy'd afterward).
- Refactor fit_load_image_ex into a shared inner helper.
- Reword the WOLFBOOT_FIT_MAX_DECOMP comment: the cap is a sanity
ceiling, not a per-destination memory-safety bound. Authenticity
is provided by the outer wolfBoot signature; tighter bounds need
fit_load_image_ex / _to with an explicit out_max / dst_max.
- Add WOLFBOOT_FIT_MAX_RAMDISK (defaults to WOLFBOOT_FIT_MAX_DECOMP)
so targets can pin a tighter ramdisk decompression bound.
src/update_ram.c, src/update_disk.c
- Panic when fit_load_image() returns NULL for the kernel subimage
instead of letting load_address=NULL propagate into do_boot().
tools/unit-tests/unit-gzip.c
- Add deterministic stored / fixed-Huffman / dynamic-Huffman gzip
fixtures so the inflater's BTYPE 00/01/10 paths are exercised
independent of host gzip(1) heuristics.
- Add FEXTRA / FNAME / FCOMMENT / FHCRC and combined-flag fixtures
plus a truncated-FEXTRA negative case to cover the optional gzip
header parser.
tools/unit-tests/unit-fit-gzip.c (new), tools/unit-tests/Makefile
- New libcheck binary covering the FIT loader's compression
branches: gzip success, gzip stream corruption, unknown
compression, compression="none" baseline, and the no-load
fail-closed path. Built twice from the same source - once with
WOLFBOOT_GZIP for the success / runtime-failure paths, and once
without it so the compile-time fail-closed branch is also tested.
pull/772/head
parent
d92053037c
commit
9ca1d435b9
|
|
@ -172,6 +172,12 @@ const char* fit_find_images(void* fdt, const char** pkernel, const char** pflat_
|
|||
const char** pramdisk);
|
||||
void* fit_load_image(void* fdt, const char* image, int* lenp);
|
||||
void* fit_load_image_ex(void* fdt, const char* image, int* lenp, uint32_t out_max);
|
||||
/* Load (and, if compressed, decompress) a FIT subimage directly to a
|
||||
* caller-supplied destination buffer. Overrides the FIT image's
|
||||
* `load` and `entry` properties - dst is both the destination and the
|
||||
* value returned. dst_max bounds the decompressed size. */
|
||||
void* fit_load_image_to(void* fdt, const char* image, void* dst,
|
||||
uint32_t dst_max, int* lenp);
|
||||
|
||||
/* FDT initrd fixup: writes /chosen/linux,initrd-{start,end} as 64-bit
|
||||
* big-endian properties. Creates /chosen if missing. Returns 0 on success
|
||||
|
|
|
|||
98
src/fdt.c
98
src/fdt.c
|
|
@ -34,10 +34,15 @@
|
|||
#include "gzip.h"
|
||||
#endif
|
||||
|
||||
/* Default upper bound on a single FIT subimage's decompressed size.
|
||||
* The outer wolfBoot signature already authenticates the FIT, but a
|
||||
* concrete cap defends against a malformed-but-signed FIT scribbling
|
||||
* across unrelated memory. Override per target via:
|
||||
/* Coarse upper bound on a single FIT subimage's decompressed size.
|
||||
* This is a sanity ceiling, not a per-destination memory-safety
|
||||
* bound. Authenticity of the FIT bytes is provided by the outer
|
||||
* wolfBoot signature; this cap is a belt-and-suspenders limit so a
|
||||
* malformed-but-signed gzip stream cannot inflate without bound.
|
||||
* Callers that need a tighter, RAM-window-aware bound should use
|
||||
* fit_load_image_ex() (FIT-`load` destination + explicit out_max)
|
||||
* or fit_load_image_to() (caller-supplied destination + dst_max).
|
||||
* Override per target via:
|
||||
* CFLAGS+=-DWOLFBOOT_FIT_MAX_DECOMP=...
|
||||
*/
|
||||
#ifndef WOLFBOOT_FIT_MAX_DECOMP
|
||||
|
|
@ -904,13 +909,22 @@ int fdt_fixup_initrd(void* fdt, uint64_t start, uint64_t size)
|
|||
#define WOLFBOOT_LOAD_RAMDISK_ADDRESS 0
|
||||
#endif
|
||||
|
||||
/* Upper bound on the (decompressed) ramdisk size. Defaults to the
|
||||
* generic FIT decompression cap. Targets with a tighter known-safe
|
||||
* RAM window for the ramdisk should override this. */
|
||||
#ifndef WOLFBOOT_FIT_MAX_RAMDISK
|
||||
#define WOLFBOOT_FIT_MAX_RAMDISK WOLFBOOT_FIT_MAX_DECOMP
|
||||
#endif
|
||||
|
||||
/* Load a FIT ramdisk subimage and patch the DTB's /chosen
|
||||
* linux,initrd-{start,end} to point at it. If
|
||||
* WOLFBOOT_LOAD_RAMDISK_ADDRESS is nonzero, the ramdisk is relocated
|
||||
* to that fixed address (overrides the FIT's `load` property);
|
||||
* otherwise the address fit_load_image returned (FIT-specified or
|
||||
* in-FIT pointer) is used as-is. Caller passes the DTB pointer for
|
||||
* the initrd fixup, or NULL to skip the fixup.
|
||||
* WOLFBOOT_LOAD_RAMDISK_ADDRESS is nonzero, the ramdisk is loaded
|
||||
* directly to that fixed address - bypassing the FIT's `load`
|
||||
* property entirely - so a gzip-compressed ramdisk is decompressed
|
||||
* straight into the override (with the override capacity acting as
|
||||
* the safety bound). Otherwise the address fit_load_image returned
|
||||
* (FIT-specified or in-FIT pointer) is used as-is. Caller passes the
|
||||
* DTB pointer for the initrd fixup, or NULL to skip the fixup.
|
||||
*
|
||||
* Returns 0 on success, -1 if the ramdisk node was found but the
|
||||
* load failed. The current callers ignore the return value
|
||||
|
|
@ -926,41 +940,52 @@ int fit_load_ramdisk(void* fit, const char* ramdisk_node, void* dts_addr)
|
|||
return -1;
|
||||
}
|
||||
|
||||
rd_ptr = (uint8_t*)fit_load_image(fit, ramdisk_node, &rd_size);
|
||||
if (rd_ptr == NULL || rd_size <= 0) {
|
||||
wolfBoot_printf("FIT: ramdisk node present but load failed\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (WOLFBOOT_LOAD_RAMDISK_ADDRESS != 0) {
|
||||
rd_dst = (uint8_t*)WOLFBOOT_LOAD_RAMDISK_ADDRESS;
|
||||
if (rd_ptr != rd_dst) {
|
||||
wolfBoot_printf("Loading ramdisk: %p -> %p (%d bytes)\n",
|
||||
rd_ptr, rd_dst, rd_size);
|
||||
memcpy(rd_dst, rd_ptr, rd_size);
|
||||
}
|
||||
else {
|
||||
wolfBoot_printf("Loaded ramdisk: %p (%d bytes)\n",
|
||||
rd_dst, rd_size);
|
||||
rd_ptr = (uint8_t*)fit_load_image_to(fit, ramdisk_node,
|
||||
rd_dst, (uint32_t)WOLFBOOT_FIT_MAX_RAMDISK, &rd_size);
|
||||
if (rd_ptr == NULL || rd_size <= 0) {
|
||||
wolfBoot_printf("FIT: ramdisk node present but load failed\n");
|
||||
return -1;
|
||||
}
|
||||
wolfBoot_printf("Loaded ramdisk: %p (%d bytes)\n",
|
||||
rd_dst, rd_size);
|
||||
}
|
||||
else {
|
||||
rd_ptr = (uint8_t*)fit_load_image(fit, ramdisk_node, &rd_size);
|
||||
if (rd_ptr == NULL || rd_size <= 0) {
|
||||
wolfBoot_printf("FIT: ramdisk node present but load failed\n");
|
||||
return -1;
|
||||
}
|
||||
rd_dst = rd_ptr;
|
||||
wolfBoot_printf("Loaded ramdisk: %p (%d bytes)\n",
|
||||
rd_dst, rd_size);
|
||||
}
|
||||
|
||||
if (dts_addr != NULL) {
|
||||
(void)fdt_fixup_initrd(dts_addr,
|
||||
int frc = fdt_fixup_initrd(dts_addr,
|
||||
(uint64_t)(uintptr_t)rd_dst, (uint64_t)rd_size);
|
||||
if (frc != 0) {
|
||||
wolfBoot_printf("FIT: fdt_fixup_initrd failed (rc=%d); "
|
||||
"kernel will not see initrd\n", frc);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
#endif /* WOLFBOOT_FIT_RAMDISK */
|
||||
|
||||
void* fit_load_image_ex(void* fdt, const char* image, int* lenp,
|
||||
uint32_t out_max)
|
||||
/* Inner implementation shared by fit_load_image_ex and fit_load_image_to.
|
||||
* When dst_override is non-NULL it replaces the FIT image's `load`
|
||||
* property as the destination, so a compressed (gzip) payload is
|
||||
* decompressed directly into the caller's buffer rather than being
|
||||
* routed through the FIT-declared address. The `entry` property is
|
||||
* also ignored when dst_override is in effect, since the caller wants
|
||||
* the override address back.
|
||||
*/
|
||||
static void* fit_load_image_inner(void* fdt, const char* image, int* lenp,
|
||||
uint32_t out_max, void* dst_override)
|
||||
{
|
||||
void *load, *entry, *data = NULL;
|
||||
int off, len = 0;
|
||||
|
|
@ -976,6 +1001,12 @@ void* fit_load_image_ex(void* fdt, const char* image, int* lenp,
|
|||
data = (void*)fdt_getprop(fdt, off, "data", &len);
|
||||
load = fdt_getprop_address(fdt, off, "load");
|
||||
entry = fdt_getprop_address(fdt, off, "entry");
|
||||
if (dst_override != NULL) {
|
||||
/* Caller-supplied destination replaces the FIT load
|
||||
* property and disables `entry` resolution. */
|
||||
load = dst_override;
|
||||
entry = NULL;
|
||||
}
|
||||
if (data != NULL) {
|
||||
int is_gzip = 0;
|
||||
int is_unknown_comp = 0;
|
||||
|
|
@ -1073,9 +1104,24 @@ void* fit_load_image_ex(void* fdt, const char* image, int* lenp,
|
|||
|
||||
}
|
||||
|
||||
void* fit_load_image_ex(void* fdt, const char* image, int* lenp,
|
||||
uint32_t out_max)
|
||||
{
|
||||
return fit_load_image_inner(fdt, image, lenp, out_max, NULL);
|
||||
}
|
||||
|
||||
void* fit_load_image(void* fdt, const char* image, int* lenp)
|
||||
{
|
||||
return fit_load_image_ex(fdt, image, lenp, WOLFBOOT_FIT_MAX_DECOMP);
|
||||
}
|
||||
|
||||
void* fit_load_image_to(void* fdt, const char* image, void* dst,
|
||||
uint32_t dst_max, int* lenp)
|
||||
{
|
||||
if (dst == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
return fit_load_image_inner(fdt, image, lenp, dst_max, dst);
|
||||
}
|
||||
|
||||
#endif /* (MMU || WOLFBOOT_FDT) && !BUILD_LOADER_STAGE1 */
|
||||
|
|
|
|||
|
|
@ -548,7 +548,13 @@ void RAMFUNCTION wolfBoot_start(void)
|
|||
|
||||
(void)fit_find_images(fit, &kernel, &flat_dt, &ramdisk);
|
||||
if (kernel != NULL) {
|
||||
load_address = fit_load_image(fit, kernel, NULL);
|
||||
void *new_load = fit_load_image(fit, kernel, NULL);
|
||||
if (new_load == NULL) {
|
||||
wolfBoot_printf("FIT: failed to load kernel '%s'\r\n",
|
||||
kernel);
|
||||
wolfBoot_panic();
|
||||
}
|
||||
load_address = new_load;
|
||||
}
|
||||
if (flat_dt != NULL) {
|
||||
uint8_t *dts_ptr = fit_load_image(fit, flat_dt, (int*)&dts_size);
|
||||
|
|
|
|||
|
|
@ -375,7 +375,12 @@ backup_on_failure:
|
|||
|
||||
(void)fit_find_images(fit, &kernel, &flat_dt, &ramdisk);
|
||||
if (kernel != NULL) {
|
||||
load_address = fit_load_image(fit, kernel, NULL);
|
||||
void *new_load = fit_load_image(fit, kernel, NULL);
|
||||
if (new_load == NULL) {
|
||||
wolfBoot_printf("FIT: failed to load kernel '%s'\n", kernel);
|
||||
wolfBoot_panic();
|
||||
}
|
||||
load_address = new_load;
|
||||
}
|
||||
if (flat_dt != NULL) {
|
||||
uint8_t *dts_ptr = fit_load_image(fit, flat_dt, (int*)&dts_size);
|
||||
|
|
|
|||
|
|
@ -59,6 +59,7 @@ TESTS:=unit-parser unit-fdt unit-extflash unit-string unit-spi-flash unit-aes128
|
|||
unit-keygen-xmss-params
|
||||
TESTS+=unit-tpm-check-rot-auth
|
||||
TESTS+=unit-tpm-api-names
|
||||
TESTS+=unit-fit-gzip unit-fit-nogzip
|
||||
|
||||
include unit-sign-encrypted-output.mkfrag
|
||||
|
||||
|
|
@ -324,6 +325,19 @@ unit-delta: ../../include/target.h unit-delta.c
|
|||
unit-gzip: ../../include/target.h unit-gzip.c
|
||||
gcc -o $@ unit-gzip.c $(CFLAGS) -DWOLFBOOT_GZIP $(LDFLAGS)
|
||||
|
||||
# FIT-loader gzip / unsupported-compression branch coverage. Built twice
|
||||
# from the same source: once with WOLFBOOT_GZIP (success + decompress
|
||||
# failure paths) and once without (compile-time fail-closed path).
|
||||
unit-fit-gzip: ../../include/target.h unit-fit-gzip.c
|
||||
gcc -o $@ unit-fit-gzip.c $(CFLAGS) -DWOLFBOOT_FDT -DWOLFBOOT_GZIP \
|
||||
-DWOLFBOOT_NO_PRINTF \
|
||||
-ffunction-sections -fdata-sections $(LDFLAGS) -Wl,--gc-sections
|
||||
|
||||
unit-fit-nogzip: ../../include/target.h unit-fit-gzip.c
|
||||
gcc -o $@ unit-fit-gzip.c $(CFLAGS) -DWOLFBOOT_FDT \
|
||||
-DWOLFBOOT_NO_PRINTF \
|
||||
-ffunction-sections -fdata-sections $(LDFLAGS) -Wl,--gc-sections
|
||||
|
||||
unit-update-flash: ../../include/target.h unit-update-flash.c
|
||||
gcc -o $@ unit-update-flash.c ../../src/image.c $(WOLFBOOT_LIB_WOLFSSL)/wolfcrypt/src/sha256.c $(CFLAGS) $(LDFLAGS)
|
||||
|
||||
|
|
|
|||
|
|
@ -0,0 +1,317 @@
|
|||
/* unit-fit-gzip.c
|
||||
*
|
||||
* Unit tests for the FIT-image loader's gzip / unsupported-compression
|
||||
* branches in src/fdt.c. The tests drive fit_load_image_to() and
|
||||
* fit_load_image_ex() against minimal hand-built FIT blobs so the new
|
||||
* fail-closed paths (gzip success, gzip corruption, unknown
|
||||
* compression, and the WOLFBOOT_GZIP-disabled build) all have
|
||||
* deterministic coverage.
|
||||
*
|
||||
* The test binary is built twice from the same source:
|
||||
* - unit-fit-gzip (WOLFBOOT_GZIP defined -> gzip path enabled)
|
||||
* - unit-fit-nogzip (WOLFBOOT_GZIP undefined -> compile-time fail-closed)
|
||||
*
|
||||
* Copyright (C) 2026 wolfSSL Inc.
|
||||
*
|
||||
* This file is part of wolfBoot.
|
||||
*
|
||||
* wolfBoot is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* wolfBoot 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 General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335, USA
|
||||
*/
|
||||
|
||||
#include <check.h>
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "../../include/fdt.h"
|
||||
|
||||
/* fdt.c calls wolfBoot_printf; supply a silent stub. */
|
||||
void wolfBoot_printf(const char *fmt, ...)
|
||||
{
|
||||
(void)fmt;
|
||||
}
|
||||
|
||||
/* Pull in the production code under test. fdt.c's body is gated on
|
||||
* WOLFBOOT_FDT; the Makefile defines that for both build variants.
|
||||
* gzip.c is only needed for the WOLFBOOT_GZIP build. */
|
||||
#include "../../src/fdt.c"
|
||||
#ifdef WOLFBOOT_GZIP
|
||||
#include "../../src/gzip.c"
|
||||
#endif
|
||||
|
||||
/* ------------------------------------------------------------------------- */
|
||||
/* Pre-built FIT fixtures (generated with python; see commit message) */
|
||||
/* ------------------------------------------------------------------------- */
|
||||
/* Each FIT contains a single /images/kernel-1 node. The `data` property */
|
||||
/* is either a gzip-compressed or plain copy of `fit_plain_payload`. The */
|
||||
/* `compression` property selects the path under test. `load` is set to */
|
||||
/* 0xC0001000 in most fixtures - tests use fit_load_image_to() which */
|
||||
/* overrides that with a real heap buffer, so the address never gets */
|
||||
/* dereferenced. */
|
||||
|
||||
static const char fit_plain_payload[] = "hello fit test payload\n";
|
||||
#define FIT_PLAIN_LEN 23
|
||||
|
||||
/* gzip-compressed kernel, load=0xC0001000 */
|
||||
static const uint8_t fit_with_gzip_kernel[] = {
|
||||
0xd0, 0x0d, 0xfe, 0xed, 0x00, 0x00, 0x00, 0xe2, 0x00, 0x00, 0x00, 0x38,
|
||||
0x00, 0x00, 0x00, 0xcc, 0x00, 0x00, 0x00, 0x28, 0x00, 0x00, 0x00, 0x11,
|
||||
0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x16,
|
||||
0x00, 0x00, 0x00, 0x94, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x69, 0x6d, 0x61, 0x67,
|
||||
0x65, 0x73, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x6b, 0x65, 0x72, 0x6e,
|
||||
0x65, 0x6c, 0x2d, 0x31, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03,
|
||||
0x00, 0x00, 0x00, 0x2b, 0x00, 0x00, 0x00, 0x00, 0x1f, 0x8b, 0x08, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x02, 0x03, 0xcb, 0x48, 0xcd, 0xc9, 0xc9, 0x57,
|
||||
0x48, 0xcb, 0x2c, 0x51, 0x28, 0x49, 0x2d, 0x2e, 0x51, 0x28, 0x48, 0xac,
|
||||
0xcc, 0xc9, 0x4f, 0x4c, 0xe1, 0x02, 0x00, 0x54, 0x03, 0xc1, 0x3a, 0x17,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x05,
|
||||
0x00, 0x00, 0x00, 0x05, 0x67, 0x7a, 0x69, 0x70, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x11,
|
||||
0x00, 0x00, 0x00, 0x00, 0xc0, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x02,
|
||||
0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x09,
|
||||
0x64, 0x61, 0x74, 0x61, 0x00, 0x63, 0x6f, 0x6d, 0x70, 0x72, 0x65, 0x73,
|
||||
0x73, 0x69, 0x6f, 0x6e, 0x00, 0x6c, 0x6f, 0x61, 0x64, 0x00,
|
||||
};
|
||||
|
||||
/* Same as above but one byte of the deflate body is flipped */
|
||||
static const uint8_t fit_with_corrupt_gzip[] = {
|
||||
0xd0, 0x0d, 0xfe, 0xed, 0x00, 0x00, 0x00, 0xe2, 0x00, 0x00, 0x00, 0x38,
|
||||
0x00, 0x00, 0x00, 0xcc, 0x00, 0x00, 0x00, 0x28, 0x00, 0x00, 0x00, 0x11,
|
||||
0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x16,
|
||||
0x00, 0x00, 0x00, 0x94, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x69, 0x6d, 0x61, 0x67,
|
||||
0x65, 0x73, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x6b, 0x65, 0x72, 0x6e,
|
||||
0x65, 0x6c, 0x2d, 0x31, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03,
|
||||
0x00, 0x00, 0x00, 0x2b, 0x00, 0x00, 0x00, 0x00, 0x1f, 0x8b, 0x08, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x02, 0x03, 0xcb, 0x48, 0xcd, 0xc9, 0xc9, 0xa8,
|
||||
0x48, 0xcb, 0x2c, 0x51, 0x28, 0x49, 0x2d, 0x2e, 0x51, 0x28, 0x48, 0xac,
|
||||
0xcc, 0xc9, 0x4f, 0x4c, 0xe1, 0x02, 0x00, 0x54, 0x03, 0xc1, 0x3a, 0x17,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x05,
|
||||
0x00, 0x00, 0x00, 0x05, 0x67, 0x7a, 0x69, 0x70, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x11,
|
||||
0x00, 0x00, 0x00, 0x00, 0xc0, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x02,
|
||||
0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x09,
|
||||
0x64, 0x61, 0x74, 0x61, 0x00, 0x63, 0x6f, 0x6d, 0x70, 0x72, 0x65, 0x73,
|
||||
0x73, 0x69, 0x6f, 0x6e, 0x00, 0x6c, 0x6f, 0x61, 0x64, 0x00,
|
||||
};
|
||||
|
||||
/* compression="lzma" - unknown to the loader, must fail closed */
|
||||
static const uint8_t fit_with_lzma[] = {
|
||||
0xd0, 0x0d, 0xfe, 0xed, 0x00, 0x00, 0x00, 0xce, 0x00, 0x00, 0x00, 0x38,
|
||||
0x00, 0x00, 0x00, 0xb8, 0x00, 0x00, 0x00, 0x28, 0x00, 0x00, 0x00, 0x11,
|
||||
0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x16,
|
||||
0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x69, 0x6d, 0x61, 0x67,
|
||||
0x65, 0x73, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x6b, 0x65, 0x72, 0x6e,
|
||||
0x65, 0x6c, 0x2d, 0x31, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03,
|
||||
0x00, 0x00, 0x00, 0x17, 0x00, 0x00, 0x00, 0x00, 0x68, 0x65, 0x6c, 0x6c,
|
||||
0x6f, 0x20, 0x66, 0x69, 0x74, 0x20, 0x74, 0x65, 0x73, 0x74, 0x20, 0x70,
|
||||
0x61, 0x79, 0x6c, 0x6f, 0x61, 0x64, 0x0a, 0x00, 0x00, 0x00, 0x00, 0x03,
|
||||
0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x05, 0x6c, 0x7a, 0x6d, 0x61,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x08,
|
||||
0x00, 0x00, 0x00, 0x11, 0x00, 0x00, 0x00, 0x00, 0xc0, 0x00, 0x10, 0x00,
|
||||
0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x02,
|
||||
0x00, 0x00, 0x00, 0x09, 0x64, 0x61, 0x74, 0x61, 0x00, 0x63, 0x6f, 0x6d,
|
||||
0x70, 0x72, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x00, 0x6c, 0x6f, 0x61,
|
||||
0x64, 0x00,
|
||||
};
|
||||
|
||||
/* compression="none" - sanity baseline (plain memcpy) */
|
||||
static const uint8_t fit_with_none_comp[] = {
|
||||
0xd0, 0x0d, 0xfe, 0xed, 0x00, 0x00, 0x00, 0xce, 0x00, 0x00, 0x00, 0x38,
|
||||
0x00, 0x00, 0x00, 0xb8, 0x00, 0x00, 0x00, 0x28, 0x00, 0x00, 0x00, 0x11,
|
||||
0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x16,
|
||||
0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x69, 0x6d, 0x61, 0x67,
|
||||
0x65, 0x73, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x6b, 0x65, 0x72, 0x6e,
|
||||
0x65, 0x6c, 0x2d, 0x31, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03,
|
||||
0x00, 0x00, 0x00, 0x17, 0x00, 0x00, 0x00, 0x00, 0x68, 0x65, 0x6c, 0x6c,
|
||||
0x6f, 0x20, 0x66, 0x69, 0x74, 0x20, 0x74, 0x65, 0x73, 0x74, 0x20, 0x70,
|
||||
0x61, 0x79, 0x6c, 0x6f, 0x61, 0x64, 0x0a, 0x00, 0x00, 0x00, 0x00, 0x03,
|
||||
0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x05, 0x6e, 0x6f, 0x6e, 0x65,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x08,
|
||||
0x00, 0x00, 0x00, 0x11, 0x00, 0x00, 0x00, 0x00, 0xc0, 0x00, 0x10, 0x00,
|
||||
0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x02,
|
||||
0x00, 0x00, 0x00, 0x09, 0x64, 0x61, 0x74, 0x61, 0x00, 0x63, 0x6f, 0x6d,
|
||||
0x70, 0x72, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x00, 0x6c, 0x6f, 0x61,
|
||||
0x64, 0x00,
|
||||
};
|
||||
|
||||
/* gzip-compressed kernel WITHOUT a `load` property -> exercises the
|
||||
* "compression declared but no destination" fail-closed branch when
|
||||
* called via fit_load_image_ex() (which has no override). */
|
||||
static const uint8_t fit_gzip_no_load[] = {
|
||||
0xd0, 0x0d, 0xfe, 0xed, 0x00, 0x00, 0x00, 0xc9, 0x00, 0x00, 0x00, 0x38,
|
||||
0x00, 0x00, 0x00, 0xb8, 0x00, 0x00, 0x00, 0x28, 0x00, 0x00, 0x00, 0x11,
|
||||
0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x11,
|
||||
0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x69, 0x6d, 0x61, 0x67,
|
||||
0x65, 0x73, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x6b, 0x65, 0x72, 0x6e,
|
||||
0x65, 0x6c, 0x2d, 0x31, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03,
|
||||
0x00, 0x00, 0x00, 0x2b, 0x00, 0x00, 0x00, 0x00, 0x1f, 0x8b, 0x08, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x02, 0x03, 0xcb, 0x48, 0xcd, 0xc9, 0xc9, 0x57,
|
||||
0x48, 0xcb, 0x2c, 0x51, 0x28, 0x49, 0x2d, 0x2e, 0x51, 0x28, 0x48, 0xac,
|
||||
0xcc, 0xc9, 0x4f, 0x4c, 0xe1, 0x02, 0x00, 0x54, 0x03, 0xc1, 0x3a, 0x17,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x05,
|
||||
0x00, 0x00, 0x00, 0x05, 0x67, 0x7a, 0x69, 0x70, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x02,
|
||||
0x00, 0x00, 0x00, 0x09, 0x64, 0x61, 0x74, 0x61, 0x00, 0x63, 0x6f, 0x6d,
|
||||
0x70, 0x72, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x00,
|
||||
};
|
||||
|
||||
/* ------------------------------------------------------------------------- */
|
||||
/* Test cases */
|
||||
/* ------------------------------------------------------------------------- */
|
||||
|
||||
#ifdef WOLFBOOT_GZIP
|
||||
|
||||
START_TEST(test_fit_to_gzip_success)
|
||||
{
|
||||
uint8_t buf[64];
|
||||
int len = -1;
|
||||
void *ret;
|
||||
|
||||
memset(buf, 0xa5, sizeof(buf));
|
||||
/* fit_with_gzip_kernel is read-only; copy into a writable scratch
|
||||
* since fit_load_image_to() does not modify the FIT, but we still
|
||||
* want a clean buffer per test. */
|
||||
static uint8_t fit_scratch[sizeof(fit_with_gzip_kernel)];
|
||||
memcpy(fit_scratch, fit_with_gzip_kernel, sizeof(fit_scratch));
|
||||
|
||||
ret = fit_load_image_to(fit_scratch, "kernel-1",
|
||||
buf, (uint32_t)sizeof(buf), &len);
|
||||
ck_assert_ptr_eq(ret, buf);
|
||||
ck_assert_int_eq(len, FIT_PLAIN_LEN);
|
||||
ck_assert_int_eq(memcmp(buf, fit_plain_payload, FIT_PLAIN_LEN), 0);
|
||||
}
|
||||
END_TEST
|
||||
|
||||
START_TEST(test_fit_to_gzip_corrupt_returns_null)
|
||||
{
|
||||
uint8_t buf[64];
|
||||
int len = -1;
|
||||
void *ret;
|
||||
static uint8_t fit_scratch[sizeof(fit_with_corrupt_gzip)];
|
||||
memcpy(fit_scratch, fit_with_corrupt_gzip, sizeof(fit_scratch));
|
||||
|
||||
ret = fit_load_image_to(fit_scratch, "kernel-1",
|
||||
buf, (uint32_t)sizeof(buf), &len);
|
||||
ck_assert_ptr_null(ret);
|
||||
}
|
||||
END_TEST
|
||||
|
||||
START_TEST(test_fit_to_none_compression_copies_plain)
|
||||
{
|
||||
uint8_t buf[64];
|
||||
int len = -1;
|
||||
void *ret;
|
||||
static uint8_t fit_scratch[sizeof(fit_with_none_comp)];
|
||||
memcpy(fit_scratch, fit_with_none_comp, sizeof(fit_scratch));
|
||||
|
||||
ret = fit_load_image_to(fit_scratch, "kernel-1",
|
||||
buf, (uint32_t)sizeof(buf), &len);
|
||||
ck_assert_ptr_eq(ret, buf);
|
||||
ck_assert_int_eq(len, FIT_PLAIN_LEN);
|
||||
ck_assert_int_eq(memcmp(buf, fit_plain_payload, FIT_PLAIN_LEN), 0);
|
||||
}
|
||||
END_TEST
|
||||
|
||||
START_TEST(test_fit_ex_gzip_no_load_returns_null)
|
||||
{
|
||||
/* fit_load_image_ex() with no override and no FIT `load` property
|
||||
* must refuse rather than pass compressed bytes through as raw. */
|
||||
int len = -1;
|
||||
void *ret;
|
||||
static uint8_t fit_scratch[sizeof(fit_gzip_no_load)];
|
||||
memcpy(fit_scratch, fit_gzip_no_load, sizeof(fit_scratch));
|
||||
|
||||
ret = fit_load_image_ex(fit_scratch, "kernel-1", &len, 64 * 1024);
|
||||
ck_assert_ptr_null(ret);
|
||||
}
|
||||
END_TEST
|
||||
|
||||
#else /* !WOLFBOOT_GZIP */
|
||||
|
||||
START_TEST(test_fit_to_gzip_disabled_returns_null)
|
||||
{
|
||||
/* With WOLFBOOT_GZIP undefined, even a perfectly valid gzip stream
|
||||
* must fail closed - the loader has no inflater linked in. */
|
||||
uint8_t buf[64];
|
||||
int len = -1;
|
||||
void *ret;
|
||||
static uint8_t fit_scratch[sizeof(fit_with_gzip_kernel)];
|
||||
memcpy(fit_scratch, fit_with_gzip_kernel, sizeof(fit_scratch));
|
||||
|
||||
ret = fit_load_image_to(fit_scratch, "kernel-1",
|
||||
buf, (uint32_t)sizeof(buf), &len);
|
||||
ck_assert_ptr_null(ret);
|
||||
}
|
||||
END_TEST
|
||||
|
||||
#endif /* WOLFBOOT_GZIP */
|
||||
|
||||
START_TEST(test_fit_to_lzma_unknown_returns_null)
|
||||
{
|
||||
/* Independent of WOLFBOOT_GZIP - any unknown compression scheme is
|
||||
* always rejected. */
|
||||
uint8_t buf[64];
|
||||
int len = -1;
|
||||
void *ret;
|
||||
static uint8_t fit_scratch[sizeof(fit_with_lzma)];
|
||||
memcpy(fit_scratch, fit_with_lzma, sizeof(fit_scratch));
|
||||
|
||||
ret = fit_load_image_to(fit_scratch, "kernel-1",
|
||||
buf, (uint32_t)sizeof(buf), &len);
|
||||
ck_assert_ptr_null(ret);
|
||||
}
|
||||
END_TEST
|
||||
|
||||
/* ------------------------------------------------------------------------- */
|
||||
|
||||
static Suite *fit_gzip_suite(void)
|
||||
{
|
||||
Suite *s = suite_create("fit_gzip");
|
||||
TCase *tc = tcase_create("fit_gzip");
|
||||
|
||||
#ifdef WOLFBOOT_GZIP
|
||||
tcase_add_test(tc, test_fit_to_gzip_success);
|
||||
tcase_add_test(tc, test_fit_to_gzip_corrupt_returns_null);
|
||||
tcase_add_test(tc, test_fit_to_none_compression_copies_plain);
|
||||
tcase_add_test(tc, test_fit_ex_gzip_no_load_returns_null);
|
||||
#else
|
||||
tcase_add_test(tc, test_fit_to_gzip_disabled_returns_null);
|
||||
#endif
|
||||
tcase_add_test(tc, test_fit_to_lzma_unknown_returns_null);
|
||||
|
||||
suite_add_tcase(s, tc);
|
||||
return s;
|
||||
}
|
||||
|
||||
int main(void)
|
||||
{
|
||||
int fails;
|
||||
SRunner *sr = srunner_create(fit_gzip_suite());
|
||||
srunner_run_all(sr, CK_NORMAL);
|
||||
fails = srunner_ntests_failed(sr);
|
||||
srunner_free(sr);
|
||||
return fails ? 1 : 0;
|
||||
}
|
||||
|
|
@ -325,6 +325,203 @@ START_TEST(test_neg_null_args)
|
|||
}
|
||||
END_TEST
|
||||
|
||||
/* ------------------------------------------------------------------------- */
|
||||
/* Deterministic byte-level fixtures */
|
||||
/* ------------------------------------------------------------------------- */
|
||||
/* These cover three concerns that round-tripping through host gzip(1) */
|
||||
/* cannot guarantee: */
|
||||
/* 1. block-type coverage (BTYPE 00/01/10 in the deflate stream) */
|
||||
/* 2. optional gzip header flags (FEXTRA / FNAME / FCOMMENT / FHCRC) */
|
||||
/* 3. malformed FEXTRA xlen handling */
|
||||
/* All fixtures were pre-generated with Python's gzip / zlib modules so the */
|
||||
/* exact byte layout (and therefore the BTYPE / FLG bits being exercised) */
|
||||
/* is independent of the host gzip(1) version. Any change in fixture */
|
||||
/* content should be regenerated and the BTYPE/FLG comments updated. */
|
||||
|
||||
/* ---------- Stored block (BTYPE = 00) ----------------------------------- */
|
||||
static const char stored_input[] =
|
||||
"hello stored block, this is exactly verbatim.\n";
|
||||
static const uint8_t stored_gz[] = {
|
||||
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x03, 0x01, 0x2e,
|
||||
0x00, 0xd1, 0xff, 0x68, 0x65, 0x6c, 0x6c, 0x6f, 0x20, 0x73, 0x74, 0x6f,
|
||||
0x72, 0x65, 0x64, 0x20, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x2c, 0x20, 0x74,
|
||||
0x68, 0x69, 0x73, 0x20, 0x69, 0x73, 0x20, 0x65, 0x78, 0x61, 0x63, 0x74,
|
||||
0x6c, 0x79, 0x20, 0x76, 0x65, 0x72, 0x62, 0x61, 0x74, 0x69, 0x6d, 0x2e,
|
||||
0x0a, 0xe3, 0x07, 0x71, 0xdd, 0x2e, 0x00, 0x00, 0x00,
|
||||
};
|
||||
|
||||
/* ---------- Fixed Huffman (BTYPE = 01), zlib Z_FIXED strategy ----------- */
|
||||
static const char fixed_input[] = "the lazy dog";
|
||||
static const uint8_t fixed_gz[] = {
|
||||
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x2b, 0xc9,
|
||||
0x48, 0x55, 0xc8, 0x49, 0xac, 0xaa, 0x54, 0x48, 0xc9, 0x4f, 0x07, 0x00,
|
||||
0xe3, 0x57, 0x10, 0x29, 0x0c, 0x00, 0x00, 0x00,
|
||||
};
|
||||
|
||||
/* ---------- Dynamic Huffman (BTYPE = 10) -------------------------------- */
|
||||
static const char dyn_input[] =
|
||||
"alpha beta gamma delta epsilon zeta eta theta iota kappa lambda "
|
||||
"mu nu xi omicron pi rho sigma tau upsilon phi chi psi omega";
|
||||
static const uint8_t dyn_gz[] = {
|
||||
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x03, 0x2d, 0x4c,
|
||||
0x5b, 0x0a, 0xc0, 0x20, 0x0c, 0xbb, 0x4a, 0xae, 0x96, 0xa9, 0x68, 0x99,
|
||||
0xd5, 0xe2, 0x03, 0xc6, 0x4e, 0xbf, 0x0a, 0xfb, 0x48, 0x48, 0xc8, 0x83,
|
||||
0xd5, 0x0a, 0x71, 0xa5, 0x45, 0x64, 0xaa, 0x12, 0x31, 0x55, 0xd7, 0xc9,
|
||||
0xa6, 0xd4, 0xde, 0xf0, 0x9e, 0xe0, 0x60, 0x95, 0xc3, 0xd2, 0x9d, 0x6e,
|
||||
0x9a, 0x11, 0x95, 0x7a, 0x45, 0x42, 0x37, 0xda, 0xc6, 0x23, 0xe8, 0x2a,
|
||||
0x61, 0xf8, 0xc2, 0x04, 0xa3, 0x74, 0x4c, 0xc9, 0x7e, 0xb6, 0xb8, 0xb1,
|
||||
0xff, 0x2b, 0x2b, 0x82, 0xe0, 0x70, 0xeb, 0xe5, 0x94, 0xf9, 0x01, 0xc3,
|
||||
0x9e, 0x9a, 0x49, 0x7b, 0x00, 0x00, 0x00,
|
||||
};
|
||||
|
||||
/* ---------- Optional gzip header flags ---------------------------------- */
|
||||
/* All five fixtures decompress to "hello flag-test" (15 bytes). They share */
|
||||
/* the same deflate body + trailer; only the gzip header varies. */
|
||||
static const char flag_payload[] = "hello flag-test";
|
||||
#define FLAG_PAYLOAD_LEN 15
|
||||
|
||||
/* FLG = 0x04 (FEXTRA) - 5 bytes of extra field */
|
||||
static const uint8_t gz_fextra[] = {
|
||||
0x1f, 0x8b, 0x08, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x05, 0x00,
|
||||
0xab, 0xcd, 0xef, 0x01, 0x02, 0xcb, 0x48, 0xcd, 0xc9, 0xc9, 0x57, 0x48,
|
||||
0xcb, 0x49, 0x4c, 0xd7, 0x2d, 0x49, 0x2d, 0x2e, 0x01, 0x00, 0x09, 0x37,
|
||||
0x1d, 0x37, 0x0f, 0x00, 0x00, 0x00,
|
||||
};
|
||||
|
||||
/* FLG = 0x08 (FNAME) - "my-fname.bin\0" */
|
||||
static const uint8_t gz_fname[] = {
|
||||
0x1f, 0x8b, 0x08, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x6d, 0x79,
|
||||
0x2d, 0x66, 0x6e, 0x61, 0x6d, 0x65, 0x2e, 0x62, 0x69, 0x6e, 0x00, 0xcb,
|
||||
0x48, 0xcd, 0xc9, 0xc9, 0x57, 0x48, 0xcb, 0x49, 0x4c, 0xd7, 0x2d, 0x49,
|
||||
0x2d, 0x2e, 0x01, 0x00, 0x09, 0x37, 0x1d, 0x37, 0x0f, 0x00, 0x00, 0x00,
|
||||
};
|
||||
|
||||
/* FLG = 0x10 (FCOMMENT) - "some comment\0" */
|
||||
static const uint8_t gz_fcomment[] = {
|
||||
0x1f, 0x8b, 0x08, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x73, 0x6f,
|
||||
0x6d, 0x65, 0x20, 0x63, 0x6f, 0x6d, 0x6d, 0x65, 0x6e, 0x74, 0x00, 0xcb,
|
||||
0x48, 0xcd, 0xc9, 0xc9, 0x57, 0x48, 0xcb, 0x49, 0x4c, 0xd7, 0x2d, 0x49,
|
||||
0x2d, 0x2e, 0x01, 0x00, 0x09, 0x37, 0x1d, 0x37, 0x0f, 0x00, 0x00, 0x00,
|
||||
};
|
||||
|
||||
/* FLG = 0x02 (FHCRC) - 2-byte header CRC (we do not validate it) */
|
||||
static const uint8_t gz_fhcrc[] = {
|
||||
0x1f, 0x8b, 0x08, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xde, 0xad,
|
||||
0xcb, 0x48, 0xcd, 0xc9, 0xc9, 0x57, 0x48, 0xcb, 0x49, 0x4c, 0xd7, 0x2d,
|
||||
0x49, 0x2d, 0x2e, 0x01, 0x00, 0x09, 0x37, 0x1d, 0x37, 0x0f, 0x00, 0x00,
|
||||
0x00,
|
||||
};
|
||||
|
||||
/* FLG = FEXTRA | FNAME | FCOMMENT | FHCRC - all four set at once */
|
||||
static const uint8_t gz_all_flags[] = {
|
||||
0x1f, 0x8b, 0x08, 0x1e, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x05, 0x00,
|
||||
0xab, 0xcd, 0xef, 0x01, 0x02, 0x6d, 0x79, 0x2d, 0x66, 0x6e, 0x61, 0x6d,
|
||||
0x65, 0x2e, 0x62, 0x69, 0x6e, 0x00, 0x73, 0x6f, 0x6d, 0x65, 0x20, 0x63,
|
||||
0x6f, 0x6d, 0x6d, 0x65, 0x6e, 0x74, 0x00, 0x12, 0x34, 0xcb, 0x48, 0xcd,
|
||||
0xc9, 0xc9, 0x57, 0x48, 0xcb, 0x49, 0x4c, 0xd7, 0x2d, 0x49, 0x2d, 0x2e,
|
||||
0x01, 0x00, 0x09, 0x37, 0x1d, 0x37, 0x0f, 0x00, 0x00, 0x00,
|
||||
};
|
||||
|
||||
/* FEXTRA xlen claims 100 bytes but only 3 are actually present -> truncated */
|
||||
static const uint8_t gz_trunc_fextra[] = {
|
||||
0x1f, 0x8b, 0x08, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x64, 0x00,
|
||||
0x61, 0x62, 0x63,
|
||||
};
|
||||
|
||||
/* Helper: extract BTYPE from the first byte of the deflate stream right
|
||||
* after a (no-flags) gzip header. The header is fixed at 10 bytes when
|
||||
* FLG=0; the first deflate byte's bits 1-2 are BTYPE. */
|
||||
static unsigned gz_btype_after_plain_header(const uint8_t *gz)
|
||||
{
|
||||
return (unsigned)((gz[10] >> 1) & 0x03);
|
||||
}
|
||||
|
||||
START_TEST(test_fixture_stored_block)
|
||||
{
|
||||
uint8_t out[128]; uint32_t out_len = 0;
|
||||
int rc;
|
||||
ck_assert_uint_eq(gz_btype_after_plain_header(stored_gz), 0);
|
||||
rc = wolfBoot_gunzip(stored_gz, sizeof(stored_gz), out, sizeof(out),
|
||||
&out_len);
|
||||
ck_assert_int_eq(rc, 0);
|
||||
ck_assert_uint_eq(out_len, sizeof(stored_input) - 1);
|
||||
ck_assert_int_eq(memcmp(out, stored_input, out_len), 0);
|
||||
}
|
||||
END_TEST
|
||||
|
||||
START_TEST(test_fixture_fixed_huffman)
|
||||
{
|
||||
uint8_t out[64]; uint32_t out_len = 0;
|
||||
int rc;
|
||||
ck_assert_uint_eq(gz_btype_after_plain_header(fixed_gz), 1);
|
||||
rc = wolfBoot_gunzip(fixed_gz, sizeof(fixed_gz), out, sizeof(out),
|
||||
&out_len);
|
||||
ck_assert_int_eq(rc, 0);
|
||||
ck_assert_uint_eq(out_len, sizeof(fixed_input) - 1);
|
||||
ck_assert_int_eq(memcmp(out, fixed_input, out_len), 0);
|
||||
}
|
||||
END_TEST
|
||||
|
||||
START_TEST(test_fixture_dynamic_huffman)
|
||||
{
|
||||
uint8_t out[256]; uint32_t out_len = 0;
|
||||
int rc;
|
||||
ck_assert_uint_eq(gz_btype_after_plain_header(dyn_gz), 2);
|
||||
rc = wolfBoot_gunzip(dyn_gz, sizeof(dyn_gz), out, sizeof(out), &out_len);
|
||||
ck_assert_int_eq(rc, 0);
|
||||
ck_assert_uint_eq(out_len, sizeof(dyn_input) - 1);
|
||||
ck_assert_int_eq(memcmp(out, dyn_input, out_len), 0);
|
||||
}
|
||||
END_TEST
|
||||
|
||||
static void check_flag_fixture(const uint8_t *gz, size_t gz_len)
|
||||
{
|
||||
uint8_t out[64]; uint32_t out_len = 0;
|
||||
int rc = wolfBoot_gunzip(gz, (uint32_t)gz_len, out, sizeof(out), &out_len);
|
||||
ck_assert_int_eq(rc, 0);
|
||||
ck_assert_uint_eq(out_len, FLAG_PAYLOAD_LEN);
|
||||
ck_assert_int_eq(memcmp(out, flag_payload, out_len), 0);
|
||||
}
|
||||
|
||||
START_TEST(test_fixture_fextra)
|
||||
{
|
||||
check_flag_fixture(gz_fextra, sizeof(gz_fextra));
|
||||
}
|
||||
END_TEST
|
||||
|
||||
START_TEST(test_fixture_fname)
|
||||
{
|
||||
check_flag_fixture(gz_fname, sizeof(gz_fname));
|
||||
}
|
||||
END_TEST
|
||||
|
||||
START_TEST(test_fixture_fcomment)
|
||||
{
|
||||
check_flag_fixture(gz_fcomment, sizeof(gz_fcomment));
|
||||
}
|
||||
END_TEST
|
||||
|
||||
START_TEST(test_fixture_fhcrc)
|
||||
{
|
||||
check_flag_fixture(gz_fhcrc, sizeof(gz_fhcrc));
|
||||
}
|
||||
END_TEST
|
||||
|
||||
START_TEST(test_fixture_all_flags)
|
||||
{
|
||||
check_flag_fixture(gz_all_flags, sizeof(gz_all_flags));
|
||||
}
|
||||
END_TEST
|
||||
|
||||
START_TEST(test_fixture_truncated_fextra)
|
||||
{
|
||||
uint8_t out[16]; uint32_t out_len = 0;
|
||||
int rc = wolfBoot_gunzip(gz_trunc_fextra, sizeof(gz_trunc_fextra),
|
||||
out, sizeof(out), &out_len);
|
||||
ck_assert_int_eq(rc, WOLFBOOT_GZIP_E_TRUNCATED);
|
||||
}
|
||||
END_TEST
|
||||
|
||||
/* ------------------------------------------------------------------------- */
|
||||
/* Test runner */
|
||||
/* ------------------------------------------------------------------------- */
|
||||
|
|
@ -334,10 +531,12 @@ static Suite *gzip_suite(void)
|
|||
Suite *s = suite_create("gzip");
|
||||
TCase *tc_pos = tcase_create("roundtrip");
|
||||
TCase *tc_neg = tcase_create("negative");
|
||||
TCase *tc_fix = tcase_create("fixtures");
|
||||
|
||||
/* The 2 MB test pushes past the default 4-second per-test budget */
|
||||
tcase_set_timeout(tc_pos, 30);
|
||||
tcase_set_timeout(tc_neg, 10);
|
||||
tcase_set_timeout(tc_fix, 10);
|
||||
|
||||
tcase_add_test(tc_pos, test_roundtrip_empty);
|
||||
tcase_add_test(tc_pos, test_roundtrip_short_text);
|
||||
|
|
@ -356,8 +555,19 @@ static Suite *gzip_suite(void)
|
|||
tcase_add_test(tc_neg, test_neg_output_overflow);
|
||||
tcase_add_test(tc_neg, test_neg_null_args);
|
||||
|
||||
tcase_add_test(tc_fix, test_fixture_stored_block);
|
||||
tcase_add_test(tc_fix, test_fixture_fixed_huffman);
|
||||
tcase_add_test(tc_fix, test_fixture_dynamic_huffman);
|
||||
tcase_add_test(tc_fix, test_fixture_fextra);
|
||||
tcase_add_test(tc_fix, test_fixture_fname);
|
||||
tcase_add_test(tc_fix, test_fixture_fcomment);
|
||||
tcase_add_test(tc_fix, test_fixture_fhcrc);
|
||||
tcase_add_test(tc_fix, test_fixture_all_flags);
|
||||
tcase_add_test(tc_fix, test_fixture_truncated_fextra);
|
||||
|
||||
suite_add_tcase(s, tc_pos);
|
||||
suite_add_tcase(s, tc_neg);
|
||||
suite_add_tcase(s, tc_fix);
|
||||
return s;
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Reference in New Issue