Skip to content

Commit 756d569

Browse files
authored
Merge pull request #719 from danielinux/fixes-20260310
Fix potential OOB-read in delta diff
2 parents fd371d5 + e99fc24 commit 756d569

File tree

3 files changed

+88
-24
lines changed

3 files changed

+88
-24
lines changed

src/delta.c

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -293,6 +293,7 @@ int wb_diff(WB_DIFF_CTX *ctx, uint8_t *patch, uint32_t len)
293293
break;
294294
if ((memcmp(pa, (ctx->src_b + ctx->off_b), BLOCK_HDR_SIZE) == 0)) {
295295
uintptr_t b_start;
296+
uint8_t *pa_limit = ctx->src_a + ctx->size_a;
296297
/* Identical areas of BLOCK_HDR_SIZE bytes match between the images.
297298
* initialize match_len; blk_start is the relative offset within
298299
* the src image.
@@ -302,11 +303,13 @@ int wb_diff(WB_DIFF_CTX *ctx, uint8_t *patch, uint32_t len)
302303
b_start = ctx->off_b;
303304
pa+= BLOCK_HDR_SIZE;
304305
ctx->off_b += BLOCK_HDR_SIZE;
305-
while (*pa == *(ctx->src_b + ctx->off_b)) {
306+
while ((pa < pa_limit) &&
307+
(ctx->off_b < ctx->size_b) &&
308+
(*pa == *(ctx->src_b + ctx->off_b))) {
306309
/* Extend matching block if possible, as long as the
307310
* identical sequence continues.
308311
*/
309-
if ((uint32_t)(pa + 1 - ctx->src_a) >= ctx->size_a) {
312+
if ((pa + 1) >= pa_limit) {
310313
/* Stop matching if the source image size limit is hit. */
311314
break;
312315
}
@@ -335,6 +338,7 @@ int wb_diff(WB_DIFF_CTX *ctx, uint8_t *patch, uint32_t len)
335338
if (!found) {
336339
/* Try matching an earlier section in the resulting image */
337340
uintptr_t pb_end = page_start * wolfboot_sector_size;
341+
uint8_t *pb_limit = ctx->src_b + pb_end;
338342
pb = ctx->src_b;
339343
while (((uintptr_t)(pb - ctx->src_b) < pb_end) && (p_off < len)) {
340344
/* Check image boundary */
@@ -360,15 +364,17 @@ int wb_diff(WB_DIFF_CTX *ctx, uint8_t *patch, uint32_t len)
360364
blk_start = pb - ctx->src_b;
361365
pb+= BLOCK_HDR_SIZE;
362366
ctx->off_b += BLOCK_HDR_SIZE;
363-
while (*pb == *(ctx->src_b + ctx->off_b)) {
367+
while ((pb < pb_limit) &&
368+
(ctx->off_b < ctx->size_b) &&
369+
(*pb == *(ctx->src_b + ctx->off_b))) {
364370
/* Extend match as long as the areas have the
365371
* same content. Block skipping in this case is
366372
* not a problem since the distance between the patched
367373
* area and the area to patch is always larger than one
368374
* block size.
369375
*/
370376
pb++;
371-
if ((uint32_t)(pb - ctx->src_b) >= pb_end) {
377+
if (pb >= pb_limit) {
372378
pb--;
373379
break;
374380
}

src/libwolfboot.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -112,7 +112,7 @@ int wolfBoot_initialize_encryption(void)
112112
/* MAGIC (4B) + PART_FLAG (1B) + ENCRYPT_KEY_SIZE + ENCRYPT_NONCE_SIZE */
113113
#else
114114
#define ENCRYPT_TMP_SECRET_OFFSET (WOLFBOOT_PARTITION_SIZE - (TRAILER_SKIP))
115-
#define SECTOR_FLAGS_SIZE WOLFBOOT_SECTOR_SIZE - (4 + 1)
115+
#define SECTOR_FLAGS_SIZE (WOLFBOOT_SECTOR_SIZE - (4 + 1))
116116
/* MAGIC (4B) + PART_FLAG (1B) */
117117
#endif /* EXT_FLASH && EXT_ENCRYPTED */
118118

tools/unit-tests/unit-delta.c

Lines changed: 77 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@
2424
#include <stdint.h>
2525
#include <string.h>
2626
#include <stdio.h>
27+
#include <stdlib.h>
2728

2829
#include "delta.h"
2930
#define WC_RSA_BLINDING
@@ -35,7 +36,6 @@
3536
#define DIFF_SIZE 8192
3637

3738

38-
3939
START_TEST(test_wb_patch_init_invalid)
4040
{
4141
WB_PATCH_CTX ctx;
@@ -142,11 +142,67 @@ START_TEST(test_wb_diff_init_invalid)
142142
}
143143
END_TEST
144144

145-
static void initialize_buffers(uint8_t *src_a, uint8_t *src_b)
145+
START_TEST(test_wb_diff_match_extends_to_src_b_end)
146+
{
147+
WB_DIFF_CTX diff_ctx;
148+
uint8_t src_a[BLOCK_HDR_SIZE + 2] = {0};
149+
uint8_t src_b[BLOCK_HDR_SIZE + 1] = {0};
150+
uint8_t patch[DELTA_BLOCK_SIZE] = {0};
151+
int ret;
152+
153+
memset(src_a, 0x41, sizeof(src_a));
154+
memset(src_b, 0x41, sizeof(src_b));
155+
156+
ret = wb_diff_init(&diff_ctx, src_a, sizeof(src_a), src_b, sizeof(src_b));
157+
ck_assert_int_eq(ret, 0);
158+
159+
ret = wb_diff(&diff_ctx, patch, sizeof(patch));
160+
ck_assert_int_gt(ret, 0);
161+
}
162+
END_TEST
163+
164+
START_TEST(test_wb_diff_self_match_extends_to_src_b_end)
165+
{
166+
WB_DIFF_CTX diff_ctx;
167+
uint8_t *src_a;
168+
uint8_t *src_b;
169+
uint8_t patch[DELTA_BLOCK_SIZE] = {0};
170+
int sector_size_ret;
171+
size_t sector_size;
172+
int ret;
173+
174+
sector_size_ret = wb_diff_get_sector_size();
175+
ck_assert_int_gt(sector_size_ret, BLOCK_HDR_SIZE);
176+
sector_size = (size_t)sector_size_ret;
177+
178+
src_a = calloc(1, sector_size + BLOCK_HDR_SIZE);
179+
src_b = calloc(1, sector_size + BLOCK_HDR_SIZE + 1);
180+
ck_assert_ptr_nonnull(src_a);
181+
ck_assert_ptr_nonnull(src_b);
182+
183+
ret = wb_diff_init(&diff_ctx, src_a, sector_size + BLOCK_HDR_SIZE,
184+
src_b, sector_size + BLOCK_HDR_SIZE + 1);
185+
ck_assert_int_eq(ret, 0);
186+
187+
memset(src_a + sector_size, 0x11, BLOCK_HDR_SIZE);
188+
memset(src_b, 0x22, BLOCK_HDR_SIZE + 1);
189+
memset(src_b + sector_size, 0x22, BLOCK_HDR_SIZE + 1);
190+
diff_ctx.off_b = sector_size;
191+
192+
ret = wb_diff(&diff_ctx, patch, sizeof(patch));
193+
ck_assert_int_gt(ret, 0);
194+
195+
free(src_a);
196+
free(src_b);
197+
}
198+
END_TEST
199+
200+
static void initialize_buffers(uint8_t *src_a, uint8_t *src_b, size_t size)
146201
{
147202
uint32_t pseudo_rand = 0;
148-
uint8_t tmp[128];
149-
for (int i = 0; i < SRC_SIZE; ++i) {
203+
size_t i;
204+
205+
for (i = 0; i < size; ++i) {
150206
src_a[i] = pseudo_rand % 256;
151207
src_b[i] = pseudo_rand % 256;
152208
if ((i % 100) == 42) {
@@ -158,24 +214,24 @@ static void initialize_buffers(uint8_t *src_a, uint8_t *src_b)
158214
}
159215

160216
/* Introduce differences */
161-
src_b[100] = src_a[100] + 1;
162-
src_b[200] = src_a[200] + 2;
217+
if (size > 100) {
218+
src_b[100] = src_a[100] + 1;
219+
}
220+
if (size > 200) {
221+
src_b[200] = src_a[200] + 2;
222+
}
163223

164224
/* 10-bytes difference across two blocks */
165-
for (int i = 1020; i < 1040; ++i) {
225+
for (int i = 1020; i < 1040 && (size_t)i < size; ++i) {
166226
src_b[i] = src_a[i] + 3;
167227
}
168228

169-
170-
/* Copy a sequence from A to B, behind */
171-
src_a[510] = ESC;
172-
memcpy(src_b + 4090, src_a + 500, 20);
173-
174-
175-
/* Copy a sequence from B to itself, ahead */
176-
src_b[1022] = ESC;
177-
memcpy(tmp, src_b + 1020, 30);
178-
memcpy(src_b + 7163, tmp, 30);
229+
if (size > 510) {
230+
src_a[510] = ESC;
231+
}
232+
if (size > 1022) {
233+
src_b[1022] = ESC;
234+
}
179235

180236
}
181237

@@ -192,7 +248,7 @@ START_TEST(test_wb_patch_and_diff)
192248
uint32_t p_written = 0;
193249

194250

195-
initialize_buffers(src_a, src_b);
251+
initialize_buffers(src_a, src_b, SRC_SIZE);
196252

197253
ret = wb_diff_init(&diff_ctx, src_a, SRC_SIZE, src_b, SRC_SIZE);
198254
ck_assert_int_eq(ret, 0);
@@ -224,7 +280,7 @@ START_TEST(test_wb_patch_and_diff)
224280
ck_assert_int_eq(i, SRC_SIZE); // The patched length should match the buffer size
225281

226282
/* Verify that the patched destination matches src_b */
227-
for (int i = 0; i < SRC_SIZE; ++i) {
283+
for (i = 0; i < SRC_SIZE; ++i) {
228284
ck_assert_uint_eq(patched_dst[i], src_b[i]);
229285
}
230286
}
@@ -247,6 +303,8 @@ Suite *patch_diff_suite(void)
247303
tcase_add_test(tc_wolfboot_delta, test_wb_patch_resume_bounds_invalid);
248304
tcase_add_test(tc_wolfboot_delta, test_wb_patch_resume_large_len);
249305
tcase_add_test(tc_wolfboot_delta, test_wb_patch_trailing_escape_invalid);
306+
tcase_add_test(tc_wolfboot_delta, test_wb_diff_match_extends_to_src_b_end);
307+
tcase_add_test(tc_wolfboot_delta, test_wb_diff_self_match_extends_to_src_b_end);
250308
tcase_add_test(tc_wolfboot_delta, test_wb_patch_and_diff);
251309
suite_add_tcase(s, tc_wolfboot_delta);
252310

0 commit comments

Comments
 (0)