Skip to content

Match the handle when removing an object by handle - #252

Merged
Frauschi merged 2 commits into
wolfSSL:masterfrom
LinuxJedi:fix-destroy-object-aba
Oct 16, 2026
Merged

Frauschi merged 2 commits into
wolfSSL:masterfrom
LinuxJedi:fix-destroy-object-aba

Conversation

@LinuxJedi

Copy link
Copy Markdown
Member

WP11_Session_RemoveObjectByHandle found the object to unlink by pointer identity only, despite its name. C_DestroyObject resolves the handle with WP11_Object_Find, drops the lock, then removes by that pointer. If another thread destroyed the object in between and a third thread created an object that landed at the same address, the first caller would unlink and free the new object and return CKR_OK for the old handle.

  • WP11_Session_RemoveObjectByHandle now takes the handle instead of onToken, derives onToken from it, and only matches a list node when both the pointer and the handle are equal. The handle of a linked node is safe to read under the token lock, and published handles come from a counter that is never reused, so a recycled address no longer matches.
  • C_DestroyObject passes hObject; the cleanup wrapper WP11_Session_RemoveObject passes the object's own handle.
  • NSS builds: the cross-session fallback still reads object->session before it knows the object is linked. The pointer-and-handle match stops a stale or reused object being removed, but the read itself can touch freed memory. Avoiding it needs the slot lock, which this function cannot take because wp11_Session_Final calls it with the slot lock already held. This is noted in the code.

Address reuse cannot be forced through the PKCS#11 API (and ASAN quarantines freed memory), so this adds a DEBUG_WOLFPKCS11-only hook, WP11_Test_RemoveObjectStale, following the existing WP11_Slot_TokenKeyIsZero pattern, and tests/destroy_stale_handle_test.c. The test pairs a live object's pointer with the handle of an already destroyed object, for both token and session objects, and checks that the removal is refused and the object survives. A control call with matching handles checks the hook does remove. It runs in --enable-debug builds (the unit-test.yml debug job) and skips otherwise.

Testing:

  • destroy_stale_handle_test passes all 18 checks. With the handle comparison removed (pointer-only, as on master) 2 checks fail and the live object is freed.
  • Pre-commit hook make test passes (debug and default configs); also make check with --enable-nss --enable-debug under ASAN.

WP11_Session_RemoveObjectByHandle found the object to unlink by pointer
identity only. C_DestroyObject resolves the handle to a pointer, drops
the lock and then removes by that pointer, so if another thread
destroyed the object and a new object was allocated at the same
address, the new object would be unlinked and freed instead, and
C_DestroyObject would report success for the old handle.

Pass the handle instead of onToken and require both the pointer and
the handle to match. Handles are never reused, so a recycled address
no longer matches. onToken is now derived from the handle inside the
function.

Address reuse cannot be forced through the PKCS#11 API, so add a
DEBUG_WOLFPKCS11-only hook, WP11_Test_RemoveObjectStale, and
destroy_stale_handle_test, which drives the removal with a live
object's pointer and a destroyed object's handle, for token and
session objects.
Copilot AI balanced review requested due to automatic review settings October 15, 2026 15:27

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🔵 Needs a closer look

The concurrency-sensitive removal path retains an acknowledged NSS lifetime hazard that warrants human review.

1 open finding
What changed in this PR

Protects object destruction from address reuse by requiring both pointer and handle identity before unlinking an object.

Changes:

  • Passes the original handle through removal paths.
  • Adds a debug-only hook and regression tests for stale token and session handles.
  • Documents the existing NSS lifetime limitation.
File Description
wolfpkcs11/​internal.h Updates removal signature and declares the debug hook.
tests/​include.am Registers and links the regression test.
tests/​destroy_stale_handle_test.c Tests stale-handle rejection and matching-handle removal.
src/​internal.c Checks pointer and handle identity; implements the hook.
src/​crypto.c Passes the original handle from C_DestroyObject.

🧠 Review effort: Balanced


💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

Comment thread tests/destroy_stale_handle_test.c Resolved
Without DEBUG_WOLFPKCS11 or AES the test returned 0, so automake
counted it as a pass although no check ran. Return 77, as
debug_test and empty_pin_store_test do, so it is reported as skipped.
@Frauschi
Frauschi merged commit 427a22c into wolfSSL:master Oct 16, 2026
88 checks passed
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.

4 participants