fix(tee): harden entry_std parameter handling - #255
Merged
tdrozdovsky merged 1 commit intoAug 28, 2026
Merged
Conversation
Three independent defects on the Non-Secure entry path, found while
investigating the HOTP key-size overflow. None is HOTP-specific, so they
are split out from that fix.
1. pt[] is used uninitialised. copy_in_params() declares
uint8_t pt[TEE_NUM_PARAMS] and assigns only pt[0..num_params-1], but
all four entries are read when building ta_param->types. num_params is
Non-Secure controlled, so a caller sending num_params < 4 hands the TA
stale secure-stack bytes as parameter types; ta_param->u[] is zeroed,
so a TA can observe e.g. MEMREF_INOUT with {buffer = NULL, size = 0}.
Not reachable from the stock client, which always sends 4, but it is
the hostile-caller model 27e314c addressed. Initialise to
TEE_PARAM_TYPE_NONE (0).
2. Zero-length validation bypass in nsec_check(). The function returned
its pointer unvalidated when len == 0, so a memref of
{buffer = <secure address>, size = 0} reached a TA with a secure
pointer intact. The kernel does not dereference it, but the TA might,
if it does not consult the size. Attribution-check non-NULL pointers
one byte at a time; NULL and legitimate zero-length Non-Secure memrefs
still pass.
3. Dead func snapshot. tee_ioctl_invoke() snapshots func = arg->func then
passes arg->func, re-reading Non-Secure memory after validation.
Harmless today, but it defeats the single-fetch discipline of 27e314c
and leaves an unused variable. Pass the snapshot.
Verified under QEMU (mps2-an505, cortex-m33): the NS->S attribution
negative test still rejects all five crafted secure-pointer cases with
ACCESS_DENIED, and the AES example still completes ("Clear text and
decoded text match"), which is the guard against 2 over-tightening
nsec_check. numaker_pfm_m2351 (armv8-m.base) builds clean.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Description
Three independent defects on the
entry_std.cnon-secure entry path, found whileinvestigating the HOTP key-size issue (#253). None is HOTP-specific; they are split out
from that fix (#254) so each can be reviewed on its own merits.
1.
pt[]is used uninitialised.copy_in_params()declaresuint8_t pt[TEE_NUM_PARAMS];and assigns onlypt[0..num_params-1], but all fourentries are read when building
ta_param->types.num_paramsis non-securecontrolled, so a caller sending
num_params < 4hands the TA stale secure-stack bytesas parameter types — while
ta_param->u[]is zeroed, so a TA can observe e.g.MEMREF_INOUTwith{buffer = NULL, size = 0}. Not reachable from the stock client,which always sends 4, but it is exactly the hostile-caller model #250 addressed. This
touches code introduced in #250. Fixed by initialising to
TEE_PARAM_TYPE_NONE(0).2. Zero-length validation bypass in
nsec_check(). The function returned itspointer unvalidated when
len == 0, so a memref of{buffer = <secure address>, size = 0}reached a TA with a secure pointer intact. Thepointer is not dereferenced by the kernel, but it is handed to the TA, and a TA that
does not consult the size would dereference it. Non-NULL pointers are now
attribution-checked one byte at a time; NULL and legitimate zero-length Non-Secure
memrefs still pass.
3. Dead
funcsnapshot.tee_ioctl_invoke()snapshotsfunc = arg->funcbut thenpasses
arg->func, re-reading non-secure memory after validation. Harmless today, butit defeats the single-fetch discipline established by #250 and leaves an unused
variable. Now passes the snapshot.
Relates to #253.
Type of change
How Has This Been Tested?
Same QEMU harness as the HOTP fix.
still rejects all five crafted secure-pointer cases with
0xFFFF0001 (ACCESS_DENIED).user of
MEMREF_INPUT/OUTPUTbuffers) completes with"Clear text and decoded text match". This is the specific guard against change 2
over-tightening
nsec_check.numaker_pfm_m2351(armv8-m.base) builds clean.Note on coverage: only change 2 is exercised by a test, and then only indirectly via
the AES positive path. Changes 1 and 3 are not directly observable from the non-secure
menu and rest on code review.
Test Configuration:
mps2-an505(Cortex-M33); build-only check onnumaker_pfm_m2351(Cortex-M23)Checklist: