Skip to content

Commit 6b64e84

Browse files
committed
Fix potential OOB-read in delta diff
F/434
1 parent a910645 commit 6b64e84

2 files changed

Lines changed: 68 additions & 16 deletions

File tree

src/delta.c

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -302,7 +302,9 @@ int wb_diff(WB_DIFF_CTX *ctx, uint8_t *patch, uint32_t len)
302302
b_start = ctx->off_b;
303303
pa+= BLOCK_HDR_SIZE;
304304
ctx->off_b += BLOCK_HDR_SIZE;
305-
while (*pa == *(ctx->src_b + ctx->off_b)) {
305+
while (((uintptr_t)(pa - ctx->src_a) < (uintptr_t)ctx->size_a) &&
306+
(ctx->off_b < ctx->size_b) &&
307+
(*pa == *(ctx->src_b + ctx->off_b))) {
306308
/* Extend matching block if possible, as long as the
307309
* identical sequence continues.
308310
*/
@@ -360,7 +362,9 @@ int wb_diff(WB_DIFF_CTX *ctx, uint8_t *patch, uint32_t len)
360362
blk_start = pb - ctx->src_b;
361363
pb+= BLOCK_HDR_SIZE;
362364
ctx->off_b += BLOCK_HDR_SIZE;
363-
while (*pb == *(ctx->src_b + ctx->off_b)) {
365+
while (((uintptr_t)(pb - ctx->src_b) < pb_end) &&
366+
(ctx->off_b < ctx->size_b) &&
367+
(*pb == *(ctx->src_b + ctx->off_b))) {
364368
/* Extend match as long as the areas have the
365369
* same content. Block skipping in this case is
366370
* not a problem since the distance between the patched

tools/unit-tests/unit-delta.c

Lines changed: 62 additions & 14 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,65 @@ 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+
uint32_t sector_size;
171+
int ret;
172+
173+
sector_size = wb_diff_get_sector_size();
174+
ck_assert_uint_gt(sector_size, BLOCK_HDR_SIZE);
175+
176+
src_a = calloc(1, sector_size + BLOCK_HDR_SIZE);
177+
src_b = calloc(1, sector_size + BLOCK_HDR_SIZE + 1);
178+
ck_assert_ptr_nonnull(src_a);
179+
ck_assert_ptr_nonnull(src_b);
180+
181+
ret = wb_diff_init(&diff_ctx, src_a, sector_size + BLOCK_HDR_SIZE,
182+
src_b, sector_size + BLOCK_HDR_SIZE + 1);
183+
ck_assert_int_eq(ret, 0);
184+
185+
memset(src_a + sector_size, 0x11, BLOCK_HDR_SIZE);
186+
memset(src_b, 0x22, BLOCK_HDR_SIZE + 1);
187+
memset(src_b + sector_size, 0x22, BLOCK_HDR_SIZE + 1);
188+
diff_ctx.off_b = sector_size;
189+
190+
ret = wb_diff(&diff_ctx, patch, sizeof(patch));
191+
ck_assert_int_gt(ret, 0);
192+
193+
free(src_a);
194+
free(src_b);
195+
}
196+
END_TEST
197+
198+
static void initialize_buffers(uint8_t *src_a, uint8_t *src_b, size_t size)
146199
{
147200
uint32_t pseudo_rand = 0;
148-
uint8_t tmp[128];
149-
for (int i = 0; i < SRC_SIZE; ++i) {
201+
size_t i;
202+
203+
for (i = 0; i < size; ++i) {
150204
src_a[i] = pseudo_rand % 256;
151205
src_b[i] = pseudo_rand % 256;
152206
if ((i % 100) == 42) {
@@ -166,16 +220,8 @@ static void initialize_buffers(uint8_t *src_a, uint8_t *src_b)
166220
src_b[i] = src_a[i] + 3;
167221
}
168222

169-
170-
/* Copy a sequence from A to B, behind */
171223
src_a[510] = ESC;
172-
memcpy(src_b + 4090, src_a + 500, 20);
173-
174-
175-
/* Copy a sequence from B to itself, ahead */
176224
src_b[1022] = ESC;
177-
memcpy(tmp, src_b + 1020, 30);
178-
memcpy(src_b + 7163, tmp, 30);
179225

180226
}
181227

@@ -192,7 +238,7 @@ START_TEST(test_wb_patch_and_diff)
192238
uint32_t p_written = 0;
193239

194240

195-
initialize_buffers(src_a, src_b);
241+
initialize_buffers(src_a, src_b, SRC_SIZE);
196242

197243
ret = wb_diff_init(&diff_ctx, src_a, SRC_SIZE, src_b, SRC_SIZE);
198244
ck_assert_int_eq(ret, 0);
@@ -224,7 +270,7 @@ START_TEST(test_wb_patch_and_diff)
224270
ck_assert_int_eq(i, SRC_SIZE); // The patched length should match the buffer size
225271

226272
/* Verify that the patched destination matches src_b */
227-
for (int i = 0; i < SRC_SIZE; ++i) {
273+
for (i = 0; i < SRC_SIZE; ++i) {
228274
ck_assert_uint_eq(patched_dst[i], src_b[i]);
229275
}
230276
}
@@ -247,6 +293,8 @@ Suite *patch_diff_suite(void)
247293
tcase_add_test(tc_wolfboot_delta, test_wb_patch_resume_bounds_invalid);
248294
tcase_add_test(tc_wolfboot_delta, test_wb_patch_resume_large_len);
249295
tcase_add_test(tc_wolfboot_delta, test_wb_patch_trailing_escape_invalid);
296+
tcase_add_test(tc_wolfboot_delta, test_wb_diff_match_extends_to_src_b_end);
297+
tcase_add_test(tc_wolfboot_delta, test_wb_diff_self_match_extends_to_src_b_end);
250298
tcase_add_test(tc_wolfboot_delta, test_wb_patch_and_diff);
251299
suite_add_tcase(s, tc_wolfboot_delta);
252300

0 commit comments

Comments
 (0)