Skip to content

fix: correct three latent error-path bugs#233

Open
perfgao wants to merge 6 commits into
fffonion:masterfrom
perfgao:fix/error-paths-and-uaf
Open

fix: correct three latent error-path bugs#233
perfgao wants to merge 6 commits into
fffonion:masterfrom
perfgao:fix/error-paths-and-uaf

Conversation

@perfgao
Copy link
Copy Markdown

@perfgao perfgao commented May 28, 2026

Summary

  • x509/store.lua:199 — anchor chain_dup across X509_verify_cert to avoid a use-after-free. The wrapper was block-local; its ffi_gc(OPENSSL_sk_pop_free) finalizer could fire between X509_STORE_CTX_init and X509_verify_cert, freeing the stack while the ctx still held the raw pointer.
  • pkey.lua:743 — error path called the file-local __tostring(self, is_priv, fmt, is_pkcs1) serializer instead of builtin tostring, and stringified the already-nilled padding. Now uses builtin tostring and preserves the original value, so pkey:encrypt(s, 'bad_pad') returns invalid padding: bad_pad instead of attempt to index a string value.
  • bn.lua:374, 404 — two independent copy-paste bugs in error reporting: mod_sqr tagged check_args as "mod_sub", and __shr reported BN_lshift() failed on rshift failure. Both only fire on error paths, so CI happy-path didn't catch them.

Tests

  • t/openssl/pkey.t — asserts pubkey:encrypt(s, "bad_pad") returns invalid padding: bad_pad.
  • t/openssl/bn.t — asserts bn.mod_sqr(a, "not-a-bn", 5) error message names the mod_sqr op.
  • x509/store UAF: no CI test added — Lua-level assertions can't reliably observe GC timing; recommend valgrind/ASAN verification.

🤖 Generated with Claude Code

perfgao and others added 2 commits May 28, 2026 18:27
- x509/store.lua: anchor chain_dup across X509_verify_cert to prevent
  use-after-free (chain_dup was block-local; its ffi_gc finalizer could
  release the stack while X509_STORE_CTX still referenced it).
- pkey.lua: use builtin tostring (not the file-local __tostring
  serializer) and preserve the original padding value in the
  "invalid padding" error message.
- bn.lua: fix copy-paste mistakes in error reporting — mod_sqr now
  tags check_args as "mod_sqr" (was "mod_sub"), and __shr reports
  "BN_rshift() failed" (was "BN_lshift() failed").

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
- pkey.t: assert pkey:encrypt(s, "bad_pad") returns the preserved
  "invalid padding: bad_pad" message (regression for the __tostring
  shadowing bug).
- bn.t: assert bn.mod_sqr with a non-bignum argument reports the
  "mod_sqr" op name in its error (regression for the mod_sub
  copy-paste).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Copy link
Copy Markdown

@gemini-code-assist gemini-code-assist Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request fixes several bugs across the OpenSSL Lua library, including correcting argument check names in bn.lua, fixing a variable name typo (type to typ) and padding handling in pkey.lua, and hoisting chain_dup in store.lua to prevent premature garbage collection. The review comments identify two important improvements: ensuring chain_dup is not aggressively garbage collected by LuaJIT before X509_verify_cert executes, and correcting a typo ("explictly") in an error message in pkey.lua.

Comment thread lib/resty/openssl/x509/store.lua Outdated
Comment thread lib/resty/openssl/pkey.lua Outdated
perfgao and others added 3 commits May 28, 2026 18:38
…y_cert

Hoisting chain_dup to function scope is not enough: LuaJIT collects
locals at last-read, not end-of-scope. Since chain_dup's last read
would otherwise be chain_dup.ctx at init time, its ffi_gc finalizer
(OPENSSL_sk_pop_free) could still fire before X509_verify_cert runs.

Add an explicit `local _ = chain_dup` read after X509_verify_cert to
extend its liveness past the verify call. Per-review feedback.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Multi-line anchored regex didn't match Test::Nginx's response body
framing. Use a simple substring match for "mod_sqr" instead.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@fffonion
Copy link
Copy Markdown
Owner

fffonion commented Jun 5, 2026

Thank you @perfgao I'm undergoing a CI refresh, will get back to this PR once that's ready.

Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR fixes several latent error-path issues and a GC/lifetime hazard in the OpenSSL bindings, improving both correctness and the quality of error reporting in edge cases.

Changes:

  • Fix potential GC-related use-after-free in x509.store:verify() when passing an untrusted chain into X509_STORE_CTX_init().
  • Correct RSA padding error handling to preserve the user-supplied padding value and avoid calling the wrong __tostring.
  • Fix copy/paste mistakes in BN error reporting and add regression tests for the updated error messages.

Reviewed changes

Copilot reviewed 5 out of 5 changed files in this pull request and generated 1 comment.

Show a summary per file
File Description
t/openssl/pkey.t Adds regression coverage for the “invalid padding” error message preserving user input.
t/openssl/bn.t Adds regression coverage that mod_sqr error messages name the correct operation.
lib/resty/openssl/x509/store.lua Adjusts untrusted-chain handling to avoid premature GC/free while verification is running.
lib/resty/openssl/pkey.lua Fixes JWK type check typo and corrects RSA padding error-path logic/message.
lib/resty/openssl/bn.lua Fixes incorrect operation tagging and wrong function name in rshift failure error text.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines 216 to +220
local code = C.X509_verify_cert(ctx)
-- LuaJIT collects locals at last-read, not end-of-scope. The read below
-- extends chain_dup's liveness past X509_verify_cert so its ffi_gc
-- finalizer (OPENSSL_sk_pop_free) can't free the stack the ctx points at.
local _ = chain_dup
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.

3 participants