scratch: reject sizes that overflow when added to header
What changed, and why it matters
This commit fixes a low-level arithmetic overflow check in a special internal memory-pool helper called 'scratch space'. Because the scratch API is no longer exposed to users, the bug cannot be triggered by normal callers today. The change adds a guard so that an impossibly large requested size does not silently wrap around and produce a smaller memory allocation than intended.
No urgent action is required for end users because the scratch API is internal-only. Downstream integrators should update to a version containing this commit as part of routine maintenance, especially if they maintain a fork that still exposes scratch-space functions.
Security signals we found
Integer overflow in size calculation
Potential heap buffer under-allocation
Defensive hardening of internal allocator helper
API no longer public, reducing practical exposure
Evidence from the diff
In secp256k1_scratch_create(), the aligned header size (base_alloc) is added to the caller-supplied size before passing the sum to checked_malloc(). On platforms where size_t wraps, a very large ‘size’ could cause base_alloc + size to wrap to a small value, leading to an undersized allocation and subsequent out-of-bounds access. The patch rejects sizes where size > SIZE_MAX - base_alloc and returns NULL. Tests are added for SIZE_MAX and the smallest wrapping value.
Changed components
src/scratch_impl.hsrc/tests.csecp256k1_scratch_create()Internal scratch-space allocatorInspect captured patch +14 / −2
### src/scratch_impl.h
@@ -12,8 +12,14 @@
static secp256k1_scratch* secp256k1_scratch_create(const secp256k1_callback* error_callback, size_t size) {
const size_t base_alloc = ROUND_TO_ALIGN(sizeof(secp256k1_scratch));
- void *alloc = checked_malloc(error_callback, base_alloc + size);
- secp256k1_scratch* ret = (secp256k1_scratch *)alloc;
+ void *alloc;
+ secp256k1_scratch* ret;
+ /* Reject sizes that would wrap when added to the aligned header. */
+ if (size > SIZE_MAX - base_alloc) {
+ return NULL;
+ }
+ alloc = checked_malloc(error_callback, base_alloc + size);
+ ret = (secp256k1_scratch *)alloc;
if (ret != NULL) {
memset(ret, 0, sizeof(*ret));
memcpy(ret->magic, "scratch", 8);
### src/tests.c
@@ -420,6 +420,12 @@ static void run_scratch_tests(void) {
CHECK(secp256k1_scratch_alloc(&CTX->error_callback, scratch, SIZE_MAX) == NULL);
secp256k1_scratch_space_destroy(CTX, scratch);
+ /* Creating a scratch space whose size would wrap around when the aligned
+ * header size is added to it fails, both for SIZE_MAX and for the smallest
+ * size that still wraps. */
+ CHECK(secp256k1_scratch_space_create(CTX, SIZE_MAX) == NULL);
+ CHECK(secp256k1_scratch_space_create(CTX, SIZE_MAX - ROUND_TO_ALIGN(sizeof(secp256k1_scratch)) + 1) == NULL);
+
/* cleanup */
secp256k1_scratch_space_destroy(CTX, NULL); /* no-op */
}Why this scored 23/100
Community notes
Notes can correct, qualify, or add evidence to the AI analysis. Every note shown here has been validated by a human moderator.
The AI analysis stands alone for now. Submit a note if you can add evidence or important context.