Balloon parallelism wraps flexible thread-array sizing on 32-bit
Balloon KDF does not bound its public parallelism parameter before sizing a flexible trailing array. On a 32-bit build, the context-size product and the later block-count conversion can both wrap to one small allocation, while the initialization loop still uses the original lane count and immediately writes past the heap object.
Vulnerable code
cipher/kdf.c, ballon_context_size and balloon_open:
c
static size_t
ballon_context_size (unsigned int parallelism)
{
size_t n;
n = offsetof (struct balloon_context, thread_data)
+ parallelism * sizeof (struct balloon_thread_data);
return n;
}c n = ballon_context_size (parallelism); b = xtrymalloc (n);
c
block = xtrycalloc (parallelism * b->n_blocks, b->blklen);
if (!block)
{
ec = gpg_err_code_from_errno (errno);
xfree (b);
return ec;
}
b->block = block;
for (i = 0; i < parallelism; i++)
{
struct balloon_thread_data *t = &b->thread_data[i];
t->b = b;
t->ec = 0;
t->idx = i;
t->block = block;Why it matters
On 32-bit systems with SHA-256, s_cost = 1 and parallelism = 0x10000001 wrap the flexible-array size to one thread entry. The 64-bit block product is then narrowed to 32-bit size_t at xtrycalloc, also producing a small allocation. Writing thread_data[1] is already out of bounds. A 64-bit process generally fails the huge allocation safely, so the impact is confined to 32-bit POSIX and Windows builds whose applications accept external Balloon parameters.
Proposed fix
Reject zero and excessive parallelism, then check parallelism <= (SIZE_MAX - offsetof(...)) / sizeof(thread_data[0]) before allocating. Independently prove that parallelism * n_blocks and its byte count fit size_t; use the validated value as the loop bound. Add a 32-bit ASan regression for the values above and boundary tests around each checked multiplication.