Skip to content

Commit aabf00c

Browse files
Merge #648: Prevent ints from wrapping around in scratch space functions
60f7f2d Don't assume that ALIGNMENT > 1 in tests (Tim Ruffing) ada6361 Use ROUND_TO_ALIGN in scratch_create (Jonas Nick) 8ecc6ce Add check preventing rounding to alignment from wrapping around in scratch_alloc (Jonas Nick) 4edaf06 Add check preventing integer multiplication wrapping around in scratch_max_allocation (Jonas Nick) Pull request description: This PR increases the general robustness of scratch spaces. It does not fix an existing vulnerability because scratch spaces aren't used anywhere in master. Additionally, it must be prevented anyway that an attacker has (indirect) control over the arguments touched in this PR. ACKs for top commit: sipa: ACK 60f7f2d Tree-SHA512: ecdd794b55a01d1d6d24098f3abff34cb8bb6f33737ec4ec93714aa631c9d397b213cc3603a916ad79f4b09d6b2f8973bf87fc07b81b25a530cc72c4dbafaba9
2 parents f5adab1 + 60f7f2d commit aabf00c

File tree

2 files changed

+27
-4
lines changed

2 files changed

+27
-4
lines changed

src/scratch_impl.h

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@
1111
#include "scratch.h"
1212

1313
static secp256k1_scratch* secp256k1_scratch_create(const secp256k1_callback* error_callback, size_t size) {
14-
const size_t base_alloc = ((sizeof(secp256k1_scratch) + ALIGNMENT - 1) / ALIGNMENT) * ALIGNMENT;
14+
const size_t base_alloc = ROUND_TO_ALIGN(sizeof(secp256k1_scratch));
1515
void *alloc = checked_malloc(error_callback, base_alloc + size);
1616
secp256k1_scratch* ret = (secp256k1_scratch *)alloc;
1717
if (ret != NULL) {
@@ -60,6 +60,10 @@ static size_t secp256k1_scratch_max_allocation(const secp256k1_callback* error_c
6060
secp256k1_callback_call(error_callback, "invalid scratch space");
6161
return 0;
6262
}
63+
/* Ensure that multiplication will not wrap around */
64+
if (ALIGNMENT > 1 && objects > SIZE_MAX/(ALIGNMENT - 1)) {
65+
return 0;
66+
}
6367
if (scratch->max_size - scratch->alloc_size <= objects * (ALIGNMENT - 1)) {
6468
return 0;
6569
}
@@ -68,7 +72,14 @@ static size_t secp256k1_scratch_max_allocation(const secp256k1_callback* error_c
6872

6973
static void *secp256k1_scratch_alloc(const secp256k1_callback* error_callback, secp256k1_scratch* scratch, size_t size) {
7074
void *ret;
71-
size = ROUND_TO_ALIGN(size);
75+
size_t rounded_size;
76+
77+
rounded_size = ROUND_TO_ALIGN(size);
78+
/* Check that rounding did not wrap around */
79+
if (rounded_size < size) {
80+
return NULL;
81+
}
82+
size = rounded_size;
7283

7384
if (memcmp(scratch->magic, "scratch", 8) != 0) {
7485
secp256k1_callback_call(error_callback, "invalid scratch space");

src/tests.c

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -364,8 +364,8 @@ void run_scratch_tests(void) {
364364
CHECK(scratch->alloc_size != 0);
365365
CHECK(scratch->alloc_size % ALIGNMENT == 0);
366366

367-
/* Allocating another 500 bytes fails */
368-
CHECK(secp256k1_scratch_alloc(&none->error_callback, scratch, 500) == NULL);
367+
/* Allocating another 501 bytes fails */
368+
CHECK(secp256k1_scratch_alloc(&none->error_callback, scratch, 501) == NULL);
369369
CHECK(secp256k1_scratch_max_allocation(&none->error_callback, scratch, 0) == 1000 - adj_alloc);
370370
CHECK(secp256k1_scratch_max_allocation(&none->error_callback, scratch, 1) == 1000 - adj_alloc - (ALIGNMENT - 1));
371371
CHECK(scratch->alloc_size != 0);
@@ -398,6 +398,18 @@ void run_scratch_tests(void) {
398398
secp256k1_scratch_space_destroy(none, scratch);
399399
CHECK(ecount == 5);
400400

401+
/* Test that large integers do not wrap around in a bad way */
402+
scratch = secp256k1_scratch_space_create(none, 1000);
403+
/* Try max allocation with a large number of objects. Only makes sense if
404+
* ALIGNMENT is greater than 1 because otherwise the objects take no extra
405+
* space. */
406+
CHECK(ALIGNMENT <= 1 || !secp256k1_scratch_max_allocation(&none->error_callback, scratch, (SIZE_MAX / (ALIGNMENT - 1)) + 1));
407+
/* Try allocating SIZE_MAX to test wrap around which only happens if
408+
* ALIGNMENT > 1, otherwise it returns NULL anyway because the scratch
409+
* space is too small. */
410+
CHECK(secp256k1_scratch_alloc(&none->error_callback, scratch, SIZE_MAX) == NULL);
411+
secp256k1_scratch_space_destroy(none, scratch);
412+
401413
/* cleanup */
402414
secp256k1_scratch_space_destroy(none, NULL); /* no-op */
403415
secp256k1_context_destroy(none);

0 commit comments

Comments
 (0)