Skip to content

Release the GVL during hashing and verification#16

Merged
mudge merged 3 commits into
mainfrom
bank-holiday
Apr 6, 2026
Merged

Release the GVL during hashing and verification#16
mudge merged 3 commits into
mainfrom
bank-holiday

Conversation

@mudge
Copy link
Copy Markdown
Owner

@mudge mudge commented Apr 6, 2026

  • Ensure we coerce and freeze strings ASAP
  • Freeze public strings to prevent mutation
  • Release the GVL lock when hashing and verifying

@mudge mudge marked this pull request as ready for review April 6, 2026 13:38
mudge added 2 commits April 6, 2026 15:14
Freeze pwd, salt, and encoded strings with rb_str_new_frozen before any
Ruby code can execute via callbacks (NUM2UINT's #to_int or
StringValue's #to_str). Without this, a malicious coercion could mutate
strings before they are passed to the reference C implementation.

Also reduce the amount of casting of various numeric types by using
Ruby's NUM2UINT to convert numbers directly to uint32_t rather than
going via other types such a size_t.

Avoid the truncation of a very long password and salt by ensuring it
will fit in a uint32_t and raising a RangeError if not.
Argon2id::Password#encoded, #salt, and #output are exposed via public
attr_readers, returning the live String objects. Without freezing, a
caller holding that reference can replace them in place (e.g.
encoded.replace(attacker_hash)), causing subsequent verification to
check against the wrong hash.
To align with the bcrypt gem, release Ruby's Global VM Lock when
performing the intentionally slow computations for hashing and verifying
passwords. To do this, we effectively serialise the required arguments
into a struct and invoke rb_thread_call_without_gvl. Note we don't pass
an unblocking function when we do so because Argon2 provides no API to
cancel a hash mid-computation so the only safe thing to do is to let it
complete (this matches bcrypt).

To prevent memory leaks if encoding raises (which would longjmp before
the encoded string is freed), we wrap it in an ensure block.

Note we defensively use ARGON2_MISSING_ARGS as a sentinel result value
in case the rb_thread_call_without_gvl call ever returns without running
our nogvl function.

With this change, mark the extension as safe to use with Ractors.
@mudge mudge merged commit 2718bb0 into main Apr 6, 2026
76 checks passed
@mudge mudge deleted the bank-holiday branch April 6, 2026 19:50
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant