mm_load.c: validate DataSize locally in MM_PokeMem before dispatch#116
mm_load.c: validate DataSize locally in MM_PokeMem before dispatch#116nurdymuny wants to merge 6 commits into
Conversation
Reset MISSION_REV to 0xFF and build number to 1.
Initiate post v7.0.1 development cycle
…use-updated-static-analysis-workflow Part cFS/workflows#129, Use Updated Static Analysis Workflow
MM_PokeMem() switches on CmdPtr->Payload.DataSize to choose between CFE_PSP_MemWrite8(), CFE_PSP_MemWrite16(), and CFE_PSP_MemWrite32(). The function relies on MM_VerifyPeekPokeParams() having already rejected any DataSize value that is not one of MM_INTERNAL_BYTE_BIT_WIDTH, MM_INTERNAL_WORD_BIT_WIDTH, or MM_INTERNAL_DWORD_BIT_WIDTH, as the comment above the empty default case explicitly states. This is correct under the current MM_PokeCmd dispatch path, which always calls MM_VerifyPeekPokeParams before MM_PokeMem, but the local function is the one that actually issues the PSP write calls and should not depend on a cross-translation-unit invariant for correctness. Any future code path that reaches MM_PokeMem without going through MM_VerifyPeekPokeParams --- a refactor of MM_PokeCmd dispatch, a new ground-command entry that delegates to MM_PokeMem, a test harness, or an EDS-generated wrapper --- would drop straight into the switch with PSP_Status left at its initialised value of CFE_PSP_ERROR_NOT_IMPLEMENTED and the command counter unchanged but no diagnostic event sent. The failure would be silent. Add an explicit DataSize check at function entry, returning CFE_PSP_ERROR and raising MM_DATA_SIZE_BITS_ERR_EID on the new error path. Matches the defensive style MM_VerifyPeekPokeParams already uses for the same field, and the defense-in-depth template nasa/fprime PR 5262 used for the same kind of brick-wall reliance on an upstream type narrowing. Found by the Davis Manifold geometric vulnerability detector (scj-hunt) while ranking MM functions by attacker-input-handling density. MM_PokeMem ranked top of the MM bundle under the psp_memwrite_unguarded compound rule. The same defensive pattern applies to MM_PokeEeprom, MM_LoadMem variants, MM_DumpMem variants, and the MM_FillMem family. Happy to scope a follow-up sweep covering those once this template is accepted. Signed-off-by: Bee Rosa Davis <bee_davis@alumni.brown.edu>
Apply the same defense-in-depth template to MM_PokeEeprom() that
the preceding commit applied to MM_PokeMem().
MM_PokeEeprom() switches on CmdPtr->Payload.DataSize to choose
between CFE_PSP_EepromWrite8(), CFE_PSP_EepromWrite16(), and
CFE_PSP_EepromWrite32(), and relies on MM_VerifyPeekPokeParams()
having already rejected any invalid DataSize value, as the
identical brick-wall comment block above the empty default case
explicitly states.
This is correct under the current MM_PokeCmd dispatch path but
the local function is the one that actually issues the PSP
EEPROM write calls, and EEPROM writes are particularly sensitive
because they persist across power cycles. A silent failure
here --- silent because PSP_Status is left at its initialised
value CFE_PSP_ERROR_NOT_IMPLEMENTED and no diagnostic event is
sent --- could leave the spacecraft in an unintended persistent
state across reboots, with the perf-log entry/exit pair
unbalanced relative to the actual work performed.
Add the same explicit DataSize check at function entry, returning
CFE_PSP_ERROR and raising MM_DATA_SIZE_BITS_ERR_EID on the new
error path. Matches the MM_PokeMem hardening template added in
the preceding commit on this PR.
Found by scj-hunt's ATTEND brain primitive (v0.15 Phase A1)
during a patch-twin sweep with MM_PokeMem as the seed:
$ scj-hunt twins --bundle cfs_apps_mm_v01 --of MM_PokeMem
rank 12: MM_PokeEeprom score 5.5
The patch-twin discovery exposes a gap in the Sudoku Principle
catalog: the `psp_memwrite_unguarded` compound rule that flagged
MM_PokeMem at score 10.0 keys off CFE_PSP_MemWrite{8,16,32} sinks
and does not include CFE_PSP_EepromWrite{8,16,32}. ATTEND
clustered the two functions together anyway because they share
the same structural shape (3-way switch on DataSize, brick-wall
reliance on MM_VerifyPeekPokeParams, identical doc-comment
above default case) --- exactly the geometric patch-twin signal
the brain primitive is designed to surface.
The follow-up sweep on MM_LoadMem{8,16,32}FromFile,
MM_DumpMemToFile, and the MM_FillMem family is still open;
ATTEND ranks MM_LoadMemWIDCmd (the WID dispatcher for the
LoadMem family) at rank 3 above this candidate.
Signed-off-by: Bee Rosa Davis <bee_davis@alumni.brown.edu>
|
Extended this PR with a second commit ( Identical bug shape: 3-way switch on Methodology note: ATTEND clustered the two functions together based on their structural similarity (same dispatch shape, same brick-wall pattern, same doc-comment) even though the Happy to continue the sweep on |
|
Quick follow-up on the LoadMem / DumpMem / FillMem family sweep I offered to do. I swept all the remaining family functions and the literal pattern doesn't recur —
So this PR stays at the two original commits. I'd rather report a clean negative than upsize the diff for the sake of it. If you'd prefer a separate hardening pass on something else in MM that is worth doing — e.g. tightening the |
Summary
MM_PokeMem()infsw/src/mm_load.cswitches onCmdPtr->Payload.DataSizeto choose betweenCFE_PSP_MemWrite8/16/32(). The existing comment above the emptydefault:case explicitly documents the upstream-validationreliance:
This is correct under the current
MM_PokeCmd()dispatch path, whichalways calls
MM_VerifyPeekPokeParams()beforeMM_PokeMem(), butthe local function is the one that actually issues the PSP write
calls and should not depend on a cross-translation-unit invariant
for correctness.
Failure mode
Any future code path that reaches
MM_PokeMem()without goingthrough
MM_VerifyPeekPokeParams()— a refactor ofMM_PokeCmddispatch, a new ground-command entry that delegates to
MM_PokeMem, a test harness, or an EDS-generated wrapper — woulddrop straight into the switch with
PSP_Statusleft at itsinitialised value of
CFE_PSP_ERROR_NOT_IMPLEMENTEDand thecommand counter unchanged but no diagnostic event sent. The failure
would be silent.
Fix
Add an explicit DataSize check at function entry. On the new error
path, raise
MM_DATA_SIZE_BITS_ERR_EID(same EIDMM_VerifyPeekPokeParams()uses for the same condition) andreturn
CFE_PSP_ERRORso the caller's command-counter machinerybehaves correctly. No behavior change on valid DataSize values.
How I found this
Found by the Davis Manifold geometric vulnerability detector
(`scj-hunt`) while ranking MM functions by attacker-input-handling
density.
MM_PokeMemranked top of the cFS MM bundle under thepsp_memwrite_unguardedcompound rule.Relationship to nasa/fprime#5262
This is the same brick-wall hardening template as
nasa/fprime#5262, whichM. Starch merged earlier today for
FileUplink::File::open. BothPRs address the same shape: a local function whose memory-safety
correctness relies entirely on an upstream type narrowing or
upstream verifier in a different translation unit, with no
diagnostic on the silent-failure path if the upstream invariant is
ever broken.
Future work
The same defensive pattern applies to
MM_PokeEeprom,MM_LoadMem{8,16,32}FromFile,MM_DumpMem{8,16,32}ToFile, and theMM_FillMem*family. Happy to scope a follow-up sweep coveringthose once this template is accepted.
Test plan
DataSize(BYTE_BIT_WIDTH / WORD_BIT_WIDTH / DWORD_BIT_WIDTH).
DataSize, function now returnsCFE_PSP_ERRORand raises
MM_DATA_SIZE_BITS_ERR_EIDinstead of returning theinitialised
CFE_PSP_ERROR_NOT_IMPLEMENTEDwith no event.unit-test/mm_load_tests.cshouldcontinue to pass.
happy to add one if reviewers can advise whether to put it under
MM_PokeMem_Test_*inmm_load_tests.cor as a stand-alonefault-injection case.