Skip to content

[Bug] randomBytes on Linux can return non-random, uninitialized memory #103

Description

@cryo2010

Summary

In the Linux implementation of randomBytes (nimcrypto/sysrand.nim), the retry loop for partial getrandom(2) reads computes the resume pointer p but then passes the original buffer start pbytes to the syscall:

if srng.getRandomPresent:
  var res = 0
  while res < nbytes:
    p = cast[pointer](cast[uint](pbytes) + uint(res))
    let bytesRead = syscall(SYS_getrandom, pbytes, nbytes - res, 0)  # <-- should be `p`
    if bytesRead > 0:
      res += bytesRead

When getrandom returns a partial read, the next iteration overwrites the beginning of the buffer instead of continuing where the previous read stopped. Meanwhile res keeps accumulating until it reaches nbytes, so the function returns full success.

Impact

If the first read returns k < nbytes bytes, the loop's subsequent reads fill [0, nbytes - k) again, and the region [max(k, nbytes - k), nbytes) is never written at all. The caller receives a return value indicating the whole buffer was filled with random data, while its tail still contains whatever was in memory before the call (uninitialized stack/heap contents).

For a CSPRNG API this is a silent failure: keys, nonces, or salts generated through this path can contain predictable bytes.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions