Argon2 parallelism arithmetic underallocates lane storage on 32-bit
Closed, ResolvedPublic

Assigned To
Authored By
werner
Tue, Aug 4, 4:42 PM

Description

Argon2 parallelism arithmetic underallocates lane storage on 32-bit

Argon2 accepts an arbitrary nonzero 32-bit lane count and performs its geometry and allocation products without checked arithmetic. On a 32-bit build, public KDF parameters such as parallelism = 0x40000001 wrap those products to small allocations while a->lanes retains the original value, so initialization writes beyond both the block buffer and thread-data array.

Vulnerable code

cipher/kdf.c, argon2_init:

c
  memory_blocks = m_cost;
  if (memory_blocks < 8 * parallelism)
    memory_blocks = 8 * parallelism;

  segment_length = memory_blocks / (parallelism * 4);
  memory_blocks = segment_length * parallelism * 4;

  a->passes = t_cost;
  a->memory_blocks = memory_blocks;
  a->segment_length = segment_length;
  a->lane_length = segment_length * 4;
  a->lanes = parallelism;

  a->block = NULL;
  a->thread_data = NULL;

  if (U64_C(1024) * memory_blocks > SIZE_MAX)
    return GPG_ERR_INV_VALUE;

  memory_bytes = 1024 * (size_t)memory_blocks;
  block = xtrymalloc (memory_bytes);

The later allocation has the same issue:

c
  thread_data = xtrymalloc (a->lanes * sizeof (struct argon2_thread_data));

Why it matters

This is specific to supported targets with 32-bit size_t; a 64-bit build will normally reject an enormous allocation instead. With m_cost = 1 and the lane count above, the unsigned geometry collapses to eight 1-KiB blocks, yet argon2_fill_first_blocks immediately iterates over more than a billion lanes. The second lane already indexes outside the small block allocation. Applications that forward Argon2 parameters from password records or protocols can therefore be crashed or corrupted deterministically.

Proposed fix

Validate parallelism against the implementation's supported Argon2 lane maximum before any arithmetic. Use checked size_t multiplication for scaled lane counts, memory bytes, and thread-array bytes, and store only that validated count in a->lanes. Add a 32-bit sanitizer regression using 0x40000001 and assert clean GPG_ERR_INV_VALUE before allocation or writes.

Revisions and Commits

Event Timeline

werner created this task.
werner created this object with visibility "Public (No Login Required)".
werner created this object with edit policy "Contributor (Project)".
werner renamed this task from argon2 parallelism arithmetic underallocates lane storage on 32 bit to Argon2 parallelism arithmetic underallocates lane storage on 32-bit.Tue, Aug 4, 5:10 PM

In RFC9106, it says:

Degree of parallelism p determines how many independent (but synchronizing) computational chains (lanes) can be run. It MUST be an integer value from 1 to 2^(24)-1.

So, validating parallelism against this value is the fix.

werner lowered the priority of this task from High to Normal.Thu, Aug 6, 9:21 AM
werner added a project: Bug Report.
gniibe mentioned this in Unknown Object (Maniphest Task).Mon, Aug 10, 3:55 AM
gniibe changed the task status from Open to Testing.Tue, Aug 11, 4:08 AM
gniibe mentioned this in Unknown Object (Maniphest Task).Mon, Aug 24, 8:26 AM
werner shifted this object from the Restricted Space space to the S1 Public space.