Skip to content

fix(native): block attestation leak when interceptor is dead#120

Closed
Enginex0 wants to merge 1 commit intoJingMatrix:mainfrom
Enginex0:fix/attestation-leak
Closed

fix(native): block attestation leak when interceptor is dead#120
Enginex0 wants to merge 1 commit intoJingMatrix:mainfrom
Enginex0:fix/attestation-leak

Conversation

@Enginex0
Copy link
Contributor

@Enginex0 Enginex0 commented Feb 3, 2026

When the Java interceptor process dies, callback->transact() returns DEAD_OBJECT but execution falls through to the real keystore, exposing genuine TEE attestation state to requesting apps.

This is a security-critical path — any app polling attestation during the window between interceptor death and restart receives authentic device state.

Fix

Added pingBinder() liveness check before forwarding. If the interceptor is confirmed dead, return DEAD_OBJECT to the caller instead of forwarding to real hardware. Apps see a transient service error rather than actual device attestation.


Scope: 1 file, 12 insertions, 4 deletions

When the Java interceptor process dies, callback->transact() returns
DEAD_OBJECT but the code fell through to the real keystore, exposing
genuine TEE state to requesting apps.

Add pingBinder() liveness check on pre-transact failure. If the
interceptor is confirmed dead, return DEAD_OBJECT to the caller
instead of forwarding to real hardware. Apps see a transient service
error rather than the actual device attestation state.
@JingMatrix
Copy link
Owner

Who has ever experienced such interceptor death ? Could you trigger it?

Don't base your code on imaginary scenario. It has the potential of introducing more bugs and confusions in the future.

@Enginex0
Copy link
Contributor Author

Enginex0 commented Feb 3, 2026

Yes , I experienced this scenario twice as it leaked , that's why I added an external daemon watcher to automatically restart service.sh if for any reason it dies , it's just an harm watcher with no race conditions

@JingMatrix
Copy link
Owner

Could you please upload your logs when you were experiencing this ?

I don't want to hide a potentially deeper issue.

@JingMatrix
Copy link
Owner

@Enginex0 Maybe your crashes were related to #122 ?

@Enginex0
Copy link
Contributor Author

Enginex0 commented Feb 4, 2026

Thanks for merging #119 — the KeyUsage mapping is correct now.

Reproduced the leak scenario you asked about. Here's what I found:

Test setup:

Reproduction steps:

  1. Kill TEESimulator process (kill -9)
  2. Launch Key Attestation immediately
  3. Capture result before daemon restarts

Results:

Build Daemon state Attestation result
Upstream (no guard) dead "Bootloader is unlocked" — real TEE state exposed
Fork (with guard) dead "Unable to attest" — fails gracefully

The window is short (~2-5s before restart), but any app polling attestation during that gap gets authentic device state.

Why I prefer this approach:

On a real device, unexpected daemon death happens — OOM killer, ANR watchdog, low memory pressure, or even a user debugging with kill. The question is: what should happen when the interceptor isn't there?

Two options:

  1. Fall through to real hardware — attestation succeeds but leaks genuine state
  2. Fail closed — return error, app retries later when daemon is back

I'd rather have apps see a transient error than expose the real bootloader/TEE state even once. Belt and suspenders. The pingBinder() check is cheap and the failure mode is recoverable (app just retries).

#122 fixes the ref counting crash — solid fix. But this is a separate path. Both issues can exist independently.

Enginex0 added a commit to Enginex0/TEESimulator that referenced this pull request Feb 4, 2026
@Enginex0
Copy link
Contributor Author

Enginex0 commented Feb 4, 2026

Evidence screenshots:

Upstream v3.1-62-3a5002e (no guard) — TEESimulator dead:
upstream_leak

Real device state exposed: "Bootloader is unlocked"


Fork with pingBinder() guard — TEESimulator dead:
fork_blocked

Fails gracefully: "Unable to attest" — no leak, app retries when daemon returns.

Enginex0 added a commit to Enginex0/TEESimulator that referenced this pull request Feb 4, 2026
Enginex0 added a commit to Enginex0/TEESimulator that referenced this pull request Feb 4, 2026
@Enginex0 Enginex0 closed this Feb 6, 2026
@Enginex0 Enginex0 deleted the fix/attestation-leak branch February 6, 2026 20:11
@ale5000-git
Copy link

Why closing this?

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