Skip to content

Commit ee23e8b

Browse files
committed
Peer review fixes
1 parent c06ce26 commit ee23e8b

5 files changed

Lines changed: 143 additions & 59 deletions

File tree

docs/Targets.md

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1257,7 +1257,7 @@ MACHINE=mpfs-video-kit bitbake mchp-base-image-sdk
12571257
12581258
Build images are output to: `./tmp-glibc/deploy/images/mpfs-video-kit/`
12591259
1260-
#### Custom FIT image, signing and coping to SDCard
1260+
#### Custom FIT image, signing and copying to SDCard
12611261
12621262
wolfBoot can either decompress a gzipped kernel at boot time (`GZIP=1`,
12631263
the default for `polarfire_mpfs250.config` and `polarfire_mpfs250_qspi.config`)
@@ -3455,6 +3455,13 @@ and the `bl31`/`fsbl` versus `bl31`/`plm` boot chain. Set `GZIP=0` in
34553455
`.config` if you want to keep using an uncompressed `Image` plus
34563456
`compression = "none"`.
34573457

3458+
The decompressed-output bound for any single FIT subimage defaults to
3459+
`WOLFBOOT_FIT_MAX_DECOMP = 256 MB`. Override per target via
3460+
`CFLAGS+=-DWOLFBOOT_FIT_MAX_DECOMP=...` if a kernel/ramdisk legitimately
3461+
expands beyond that. The outer wolfBoot signature still authenticates the
3462+
entire FIT; this cap is defense-in-depth against a malformed-but-signed
3463+
stream.
3464+
34583465
**FIT ramdisk (initramfs)**
34593466

34603467
When PetaLinux is built with `INITRAMFS_IMAGE_BUNDLE = "0"` the rootfs cpio
@@ -3497,6 +3504,7 @@ images {
34973504
data = /incbin/("rootfs.cpio.gz");
34983505
type = "ramdisk";
34993506
compression = "gzip"; /* or "none" */
3507+
load = <0x40000000>; /* required for decompression / relocation */
35003508
hash-1 { algo = "sha256"; };
35013509
};
35023510
};

src/fdt.c

Lines changed: 101 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,16 @@
4040
#endif
4141
#endif /* WOLFBOOT_GZIP */
4242

43+
/* Default upper bound on a single FIT subimage's decompressed size.
44+
* The outer wolfBoot signature already authenticates the FIT, but a
45+
* concrete cap defends against a malformed-but-signed FIT scribbling
46+
* across unrelated memory. Override per target via:
47+
* CFLAGS+=-DWOLFBOOT_FIT_MAX_DECOMP=...
48+
*/
49+
#ifndef WOLFBOOT_FIT_MAX_DECOMP
50+
#define WOLFBOOT_FIT_MAX_DECOMP (256U * 1024U * 1024U)
51+
#endif
52+
4353
uint32_t cpu_to_fdt32(uint32_t x)
4454
{
4555
#ifdef BIG_ENDIAN_ORDER
@@ -911,6 +921,9 @@ static int fit_verify_hash(const void *fdt, int img_off,
911921
int hash_off, len = 0;
912922
const char *algo = NULL;
913923
const uint8_t *value = NULL;
924+
#if defined(WOLFBOOT_HASH_SHA256) || defined(WOLFBOOT_HASH_SHA384)
925+
int did_init = 0;
926+
#endif
914927
#ifdef WOLFBOOT_HASH_SHA256
915928
wc_Sha256 sha256_ctx;
916929
uint8_t sha256_digest[WC_SHA256_DIGEST_SIZE];
@@ -950,14 +963,20 @@ static int fit_verify_hash(const void *fdt, int img_off,
950963
}
951964
if (ret == 0) {
952965
ret = wc_InitSha256(&sha256_ctx);
966+
if (ret == 0) {
967+
did_init = 1;
968+
}
953969
}
954970
if (ret == 0) {
955971
ret = wc_Sha256Update(&sha256_ctx, data, (word32)data_len);
956972
}
957973
if (ret == 0) {
958974
ret = wc_Sha256Final(&sha256_ctx, sha256_digest);
959975
}
960-
wc_Sha256Free(&sha256_ctx);
976+
if (did_init) {
977+
wc_Sha256Free(&sha256_ctx);
978+
did_init = 0;
979+
}
961980
if (ret != 0) {
962981
wolfBoot_printf("FIT hash-1 (sha256): wc_Sha256 failed rc=%d\n",
963982
ret);
@@ -982,14 +1001,20 @@ static int fit_verify_hash(const void *fdt, int img_off,
9821001
}
9831002
if (ret == 0) {
9841003
ret = wc_InitSha384(&sha384_ctx);
1004+
if (ret == 0) {
1005+
did_init = 1;
1006+
}
9851007
}
9861008
if (ret == 0) {
9871009
ret = wc_Sha384Update(&sha384_ctx, data, (word32)data_len);
9881010
}
9891011
if (ret == 0) {
9901012
ret = wc_Sha384Final(&sha384_ctx, sha384_digest);
9911013
}
992-
wc_Sha384Free(&sha384_ctx);
1014+
if (did_init) {
1015+
wc_Sha384Free(&sha384_ctx);
1016+
did_init = 0;
1017+
}
9931018
if (ret != 0) {
9941019
wolfBoot_printf("FIT hash-1 (sha384): wc_Sha384 failed rc=%d\n",
9951020
ret);
@@ -1031,53 +1056,88 @@ void* fit_load_image_ex(void* fdt, const char* image, int* lenp,
10311056
data = (void*)fdt_getprop(fdt, off, "data", &len);
10321057
load = fdt_getprop_address(fdt, off, "load");
10331058
entry = fdt_getprop_address(fdt, off, "entry");
1034-
if (data != NULL && load != NULL && data != load) {
1035-
/* Detect compression unconditionally so we can warn (and fail
1036-
* closed) when the build lacks support for it instead of
1037-
* silently copying compressed bytes as if they were raw. */
1059+
if (data != NULL) {
1060+
int is_gzip = 0;
1061+
int is_unknown_comp = 0;
1062+
/* Detect compression unconditionally (independent of whether
1063+
* a valid distinct load destination is available) so we can
1064+
* fail closed when the build lacks support, when the scheme
1065+
* is unknown, or when there is no place to decompress to -
1066+
* instead of silently passing compressed bytes through as
1067+
* raw. */
10381068
comp = (const char*)fdt_getprop(fdt, off, "compression",
10391069
&complen);
1040-
if (comp != NULL && complen > 0 && strcmp(comp, "gzip") == 0) {
1041-
#ifdef WOLFBOOT_GZIP
1042-
uint32_t out_len = 0;
1043-
int rc;
1044-
wolfBoot_printf("Decompressing Image %s (gzip): "
1045-
"%p -> %p (%d bytes)\n", image, data, load, len);
1046-
rc = wolfBoot_gunzip((const uint8_t*)data, (uint32_t)len,
1047-
(uint8_t*)load, out_max, &out_len);
1048-
if (rc != 0) {
1049-
wolfBoot_printf("FIT gunzip failed for %s: rc=%d "
1050-
"(wrote %u bytes)\n", image, rc, out_len);
1051-
return NULL;
1070+
if (comp != NULL && complen > 0) {
1071+
if (strcmp(comp, "gzip") == 0) {
1072+
is_gzip = 1;
1073+
}
1074+
else if (strcmp(comp, "none") != 0) {
1075+
is_unknown_comp = 1;
10521076
}
1053-
len = (int)out_len;
1054-
wolfBoot_printf("Decompressed %s: %u bytes\n", image,
1055-
out_len);
1077+
}
1078+
if (load != NULL && data != load) {
1079+
if (is_gzip) {
1080+
#ifdef WOLFBOOT_GZIP
1081+
uint32_t out_len = 0;
1082+
int rc;
1083+
wolfBoot_printf("Decompressing Image %s (gzip): "
1084+
"%p -> %p (%d bytes)\n", image, data, load, len);
1085+
rc = wolfBoot_gunzip((const uint8_t*)data,
1086+
(uint32_t)len, (uint8_t*)load, out_max, &out_len);
1087+
if (rc != 0) {
1088+
wolfBoot_printf("FIT gunzip failed for %s: rc=%d "
1089+
"(wrote %u bytes)\n", image, rc, out_len);
1090+
return NULL;
1091+
}
1092+
len = (int)out_len;
1093+
wolfBoot_printf("Decompressed %s: %u bytes\n", image,
1094+
out_len);
10561095
#else
1057-
wolfBoot_printf("FIT: subimage '%s' has compression="
1058-
"\"gzip\" but WOLFBOOT_GZIP is not enabled in this "
1059-
"build (rebuild with GZIP=1)\n", image);
1060-
return NULL;
1096+
wolfBoot_printf("FIT: subimage '%s' has compression="
1097+
"\"gzip\" but WOLFBOOT_GZIP is not enabled in "
1098+
"this build (rebuild with GZIP=1)\n", image);
1099+
return NULL;
10611100
#endif
1062-
}
1063-
else {
1064-
wolfBoot_printf("Loading Image %s: %p -> %p (%d bytes)\n",
1065-
image, data, load, len);
1066-
memcpy(load, data, len);
1067-
}
1101+
}
1102+
else if (is_unknown_comp) {
1103+
/* Unknown compression scheme; fail closed rather
1104+
* than silently memcpy compressed bytes as raw. */
1105+
wolfBoot_printf("FIT: subimage '%s' has unsupported "
1106+
"compression=\"%s\"\n", image, comp);
1107+
return NULL;
1108+
}
1109+
else {
1110+
wolfBoot_printf("Loading Image %s: %p -> %p "
1111+
"(%d bytes)\n", image, data, load, len);
1112+
memcpy(load, data, len);
1113+
}
10681114

10691115
#ifdef WOLFBOOT_GZIP
1070-
/* Defense-in-depth: verify FIT hash-1 against loaded bytes */
1071-
if (fit_verify_hash(fdt, off, (const uint8_t*)load,
1072-
(uint32_t)len) != 0) {
1073-
wolfBoot_printf("FIT hash verification failed for %s\n",
1074-
image);
1075-
return NULL;
1076-
}
1116+
/* Defense-in-depth: verify FIT hash-1 against loaded
1117+
* bytes */
1118+
if (fit_verify_hash(fdt, off, (const uint8_t*)load,
1119+
(uint32_t)len) != 0) {
1120+
wolfBoot_printf("FIT hash verification failed for "
1121+
"%s\n", image);
1122+
return NULL;
1123+
}
10771124
#endif
10781125

1079-
/* load should always have entry, but if not use load address */
1080-
data = (entry != NULL) ? entry : load;
1126+
/* load should always have entry, but if not use load
1127+
* address */
1128+
data = (entry != NULL) ? entry : load;
1129+
}
1130+
else if (is_gzip || is_unknown_comp) {
1131+
/* Compression declared but no distinct destination to
1132+
* decompress into. Refuse rather than hand the caller
1133+
* a pointer to still-compressed bytes. */
1134+
wolfBoot_printf("FIT: subimage '%s' declares "
1135+
"compression=\"%s\" but has no distinct load "
1136+
"destination (load=%p, data=%p); refusing to pass "
1137+
"compressed bytes through as raw\n",
1138+
image, comp, load, data);
1139+
return NULL;
1140+
}
10811141
}
10821142
wolfBoot_printf("Image %s: %p (%d bytes)\n", image, data, len);
10831143
}
@@ -1093,7 +1153,7 @@ void* fit_load_image_ex(void* fdt, const char* image, int* lenp,
10931153

10941154
void* fit_load_image(void* fdt, const char* image, int* lenp)
10951155
{
1096-
return fit_load_image_ex(fdt, image, lenp, 0xFFFFFFFFU);
1156+
return fit_load_image_ex(fdt, image, lenp, WOLFBOOT_FIT_MAX_DECOMP);
10971157
}
10981158

10991159
#endif /* (MMU || WOLFBOOT_FDT) && !BUILD_LOADER_STAGE1 */

src/gzip.c

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -206,10 +206,12 @@ static int gz_huff_build(gz_huff_t *h, const uint8_t *lengths, int n)
206206
left = 1;
207207
for (len = 1; (len <= GZIP_MAX_HUFF_BITS) && (ret == 0); len++) {
208208
left <<= 1;
209-
left -= (int)h->counts[len];
210-
if (left < 0) {
209+
if ((int)h->counts[len] > left) {
211210
ret = WOLFBOOT_GZIP_E_HUFFMAN;
212211
}
212+
else {
213+
left -= (int)h->counts[len];
214+
}
213215
}
214216
}
215217

@@ -428,6 +430,10 @@ static int gz_inflate_dynamic(gz_state_t *s)
428430
int i, total, idx, sym;
429431
uint8_t prev = 0;
430432

433+
for (i = 0; i < (int)(sizeof(code_lens) / sizeof(code_lens[0])); i++) {
434+
code_lens[i] = 0;
435+
}
436+
431437
ret = gz_get_bits(s, GZIP_HLIT_BITS, &hlit);
432438
if (ret == 0) {
433439
hlit += GZIP_HLIT_BASE;

tools/config.mk

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -76,7 +76,6 @@ ifeq ($(ARCH),)
7676
WOLFBOOT_DTS_UPDATE_ADDRESS=0x50000
7777
WOLFBOOT_LOAD_ADDRESS?=0x200000
7878
WOLFBOOT_LOAD_DTS_ADDRESS?=0x400000
79-
WOLFBOOT_LOAD_RAMDISK_ADDRESS?=0
8079
WOLFBOOT_SMALL_STACK?=0
8180
DELTA_UPDATES?=0
8281
DELTA_BLOCK_SIZE?=256
@@ -94,6 +93,11 @@ ifeq ($(ARCH),)
9493
WOLFHSM_CLIENT_LOCAL_KEYS=0
9594
endif
9695

96+
# Global default: 0 means "use the FIT image's `load` property verbatim".
97+
# Defaulted globally (outside the CI ifeq block above) so RAMDISK=1 can
98+
# be toggled on any target without forcing an explicit address.
99+
WOLFBOOT_LOAD_RAMDISK_ADDRESS?=0
100+
97101
CONFIG_VARS:= ARCH TARGET SIGN HASH MCUXSDK MCUXPRESSO MCUXPRESSO_CPU MCUXPRESSO_DRIVERS \
98102
MCUXPRESSO_CMSIS FREEDOM_E_SDK STM32CUBE CYPRESS_PDL CYPRESS_CORE_LIB CYPRESS_TARGET_LIB DEBUG VTOR \
99103
CORTEX_M0 CORTEX_M7 CORTEX_M33 NO_ASM EXT_FLASH SPI_FLASH NO_XIP UART_FLASH ALLOW_DOWNGRADE NVM_FLASH_WRITEONCE \

tools/unit-tests/unit-gzip.c

Lines changed: 20 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@
3535
#include "gzip.h"
3636

3737
/* Pull in the implementation under test directly */
38-
#include "gzip.c"
38+
#include "../../src/gzip.c"
3939

4040
/* ------------------------------------------------------------------------- */
4141
/* Helpers: gzip(1) on the host produces our test fixtures */
@@ -45,41 +45,47 @@ static uint8_t *gz_compress_buf(const uint8_t *in, size_t in_len, size_t *out_le
4545
{
4646
char in_path[64], out_path[64];
4747
char cmd[256];
48-
FILE *f;
48+
FILE *f = NULL;
4949
long n;
50-
uint8_t *buf;
50+
uint8_t *buf = NULL;
5151

5252
snprintf(in_path, sizeof(in_path), "/tmp/wb-gz-in-%d.bin", getpid());
5353
snprintf(out_path, sizeof(out_path), "/tmp/wb-gz-out-%d.gz", getpid());
5454

5555
f = fopen(in_path, "wb");
56-
if (f == NULL) return NULL;
56+
if (f == NULL) goto cleanup;
5757
if (in_len > 0) {
5858
if (fwrite(in, 1, in_len, f) != in_len) {
5959
fclose(f);
60-
return NULL;
60+
f = NULL;
61+
goto cleanup;
6162
}
6263
}
6364
fclose(f);
65+
f = NULL;
6466

6567
snprintf(cmd, sizeof(cmd), "gzip -nc %s > %s", in_path, out_path);
66-
if (system(cmd) != 0) return NULL;
68+
if (system(cmd) != 0) goto cleanup;
6769

6870
f = fopen(out_path, "rb");
69-
if (f == NULL) return NULL;
70-
fseek(f, 0, SEEK_END);
71+
if (f == NULL) goto cleanup;
72+
if (fseek(f, 0, SEEK_END) != 0) goto cleanup;
7173
n = ftell(f);
72-
fseek(f, 0, SEEK_SET);
74+
if (n < 0) goto cleanup;
75+
if (fseek(f, 0, SEEK_SET) != 0) goto cleanup;
7376
buf = (uint8_t*)malloc((size_t)n);
74-
if (buf == NULL) { fclose(f); return NULL; }
77+
if (buf == NULL) goto cleanup;
7578
if (fread(buf, 1, (size_t)n, f) != (size_t)n) {
76-
free(buf); fclose(f);
77-
return NULL;
79+
free(buf);
80+
buf = NULL;
81+
goto cleanup;
7882
}
79-
fclose(f);
83+
*out_len = (size_t)n;
84+
85+
cleanup:
86+
if (f != NULL) fclose(f);
8087
unlink(in_path);
8188
unlink(out_path);
82-
*out_len = (size_t)n;
8389
return buf;
8490
}
8591

0 commit comments

Comments
 (0)