Skip to content

Prevent double free in concurrent C_DestroyObject on shared token object#205

Merged
philljj merged 3 commits into
wolfSSL:masterfrom
LinuxJedi:concurrent-destroy-object-double-free
Jul 15, 2026
Merged

Prevent double free in concurrent C_DestroyObject on shared token object#205
philljj merged 3 commits into
wolfSSL:masterfrom
LinuxJedi:concurrent-destroy-object-double-free

Conversation

@LinuxJedi

Copy link
Copy Markdown
Member

C_DestroyObject resolved a handle to a raw WP11_Object* under a released read lock and then unconditionally freed it. Token objects are shared across sessions, so two sessions destroying the same handle at once (a supported concurrent use under CKF_OS_LOCKING_OK) could both reach WP11_Object_Free on the same pointer, and the losing thread also dereferenced the freed object inside WP11_Session_RemoveObject.

WP11_Session_RemoveObject now takes an onToken argument derived from the handle rather than the object, confirms the object is still linked using pointer identity under the token lock (never dereferencing a possibly freed object on the token path), and returns WP11_OBJECT_ALREADY_REMOVED when a concurrent caller already unlinked it. C_DestroyObject gates the free on that result: the loser returns CKR_OBJECT_HANDLE_INVALID without touching the object again. The successful-removal path is unchanged. Only the token lock is taken, since wp11_Session_Final already calls WP11_Session_RemoveObject while holding the slot lock.

Add WP11_Object_HandleOnToken to derive onToken from a handle, update the remaining callers to pass onToken, and add
tests/concurrent_destroy_object_test.c which races two sessions destroying one token object and checks exactly one winner per round with no double free.

F-5252

C_DestroyObject resolved a handle to a raw WP11_Object* under a released
read lock and then unconditionally freed it. Token objects are shared
across sessions, so two sessions destroying the same handle at once (a
supported concurrent use under CKF_OS_LOCKING_OK) could both reach
WP11_Object_Free on the same pointer, and the losing thread also
dereferenced the freed object inside WP11_Session_RemoveObject.

WP11_Session_RemoveObject now takes an onToken argument derived from the
handle rather than the object, confirms the object is still linked using
pointer identity under the token lock (never dereferencing a possibly
freed object on the token path), and returns WP11_OBJECT_ALREADY_REMOVED
when a concurrent caller already unlinked it. C_DestroyObject gates the
free on that result: the loser returns CKR_OBJECT_HANDLE_INVALID without
touching the object again. The successful-removal path is unchanged. Only
the token lock is taken, since wp11_Session_Final already calls
WP11_Session_RemoveObject while holding the slot lock.

Add WP11_Object_HandleOnToken to derive onToken from a handle, update the
remaining callers to pass onToken, and add
tests/concurrent_destroy_object_test.c which races two sessions destroying
one token object and checks exactly one winner per round with no double
free.

F-5252
Copilot AI review requested due to automatic review settings July 10, 2026 13:25

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.

Pull request overview

This PR hardens C_DestroyObject against concurrent destruction of shared token objects (valid under CKF_OS_LOCKING_OK) by preventing a double-free / use-after-free when two sessions destroy the same handle at the same time.

Changes:

  • Extend WP11_Session_RemoveObject() to accept an onToken argument and return WP11_OBJECT_ALREADY_REMOVED when a concurrent caller already unlinked the object.
  • Add WP11_Object_HandleOnToken() and update C_DestroyObject to derive onToken from the handle and avoid freeing on the “already removed” path.
  • Add a new multithreaded regression test and wire it into the test build.

Reviewed changes

Copilot reviewed 5 out of 5 changed files in this pull request and generated 4 comments.

Show a summary per file
File Description
wolfpkcs11/internal.h Updates WP11_Session_RemoveObject API and introduces WP11_OBJECT_ALREADY_REMOVED and WP11_Object_HandleOnToken() declaration.
src/internal.c Implements the new remove semantics under the token lock and adds WP11_Object_HandleOnToken().
src/crypto.c Updates callers for new signature and adjusts C_DestroyObject to avoid double-free on concurrent destroys.
tests/include.am Adds the new concurrent destroy test target to the test build.
tests/concurrent_destroy_object_test.c Adds a race-focused regression test for concurrent C_DestroyObject on a shared token object.

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

Comment thread src/crypto.c Outdated
Comment thread tests/concurrent_destroy_object_test.c
Comment thread src/internal.c Outdated
Comment thread src/crypto.c Outdated
Address review feedback on the concurrent-destroy fix:

- Perform the CKA_DESTROYABLE check inside WP11_Session_RemoveObject, under
  the token lock and only after the object is confirmed still linked (and
  therefore alive), via a new checkDestroyable argument. Previously
  C_DestroyObject dereferenced the object for WP11_Object_IsDestroyable
  before removal could confirm liveness, which could read freed memory when
  another thread destroyed the same handle first.

- Look up session objects on the caller's own session list first, by
  pointer identity, and only fall back to object->session under NSS. This
  avoids dereferencing a possibly freed object on the common path; the
  remaining NSS cross-session fallback is the same out-of-contract case as
  a single-session concurrent misuse.

- Return CKR_FUNCTION_FAILED from C_DestroyObject when the object was
  unlinked but persisting the token afterwards failed, instead of always
  reporting CKR_OK and masking the error.

- Include <stdlib.h> in the regression test for atoi().

@philljj philljj 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.

Look good and tests good!

Just some suggestions to remove complexity and document changes a bit better.

Comment thread src/internal.c
Comment thread wolfpkcs11/internal.h
Comment thread tests/concurrent_destroy_object_test.c
Comment thread src/internal.c Outdated
Comment thread src/crypto.c Outdated
Comment thread src/crypto.c Outdated
@philljj philljj assigned LinuxJedi and unassigned wolfSSL-Bot Jul 14, 2026
Address review feedback on the concurrent C_DestroyObject fix.

Rename the full removal routine to WP11_Session_RemoveObjectByHandle, which
takes a handle-derived onToken and a checkDestroyable flag. This is the entry
point for C_DestroyObject, where a concurrent destroy of the same shared
token-object handle may free the object, so onToken must come from the handle
rather than from a dereference of the object.

Add a WP11_Session_RemoveObject(session, object) wrapper for cleanup paths that
hold the only reference to a live object. It reads onToken from the object
itself, which removes the risk of passing the wrong object's onToken, and drops
the repeated (void)..., 0 boilerplate at the six cleanup call sites.

Document both params and every return code (WP11_OBJECT_ALREADY_REMOVED,
WP11_OBJECT_NOT_DESTROYABLE, negative store status, 0) in the function comment
and header so callers know what to do in each case.
@LinuxJedi
LinuxJedi requested a review from philljj July 15, 2026 13:29
@LinuxJedi LinuxJedi removed their assignment Jul 15, 2026

@philljj philljj 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.

Looks good to me!

@philljj
philljj merged commit d974a0d into wolfSSL:master Jul 15, 2026
78 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