Repository navigation
Description
1. Describe the bug
A Denial of Service (DoS) vulnerability exists in the Checksum (CS) application of the NASA core Flight System (cFS). The issue stems from insufficient memory address validation in the CS_OneShotCmd() function.
While the application uses CFE_PSP_MemValidateRange() to check user-supplied addresses, this function may return CFE_SUCCESS for non-existent or invalid memory regions depending on the PSP implementation. Consequently, the child task CS_OneShotChildTask() attempts to calculate a CRC on an invalid pointer, leading to a Segmentation Fault and the abnormal termination of the CS application.
2. System observed on
Hardware: x86_64 / ARM (Generic)
OS: Linux
Versions: cFE (core Flight Executive) & CS Application (Latest versions)
Component: Checksum (CS) Application
3. Vulnerability Analysis
3.1. Technical Details
The vulnerability occurs during the processing of a "OneShot" checksum command.
- Inadequate Validation: In
CS_OneShotCmd(), the payload address and size are validated usingCFE_PSP_MemValidateRange(). In many environments, this function lacks strict boundary checks for the entire physical/virtual memory map.
- Pointer Dereference in Child Task: The validated (but actually invalid) address is stored in
CS_AppData.HkPacket.Payload.LastOneShotAddressand passed to the child task. - The Crash: Inside
CS_OneShotChildTask(), the function callsCFE_ES_CalculateCRC()with the unverified address. WhenCFE_ES_CalculateCRC()attempts to read from this memory location, the system triggers a segmentation fault.
3.2. Code Snippets
Location: CS_OneShotCmd()
void CS_OneShotCmd(const CS_OneShotCmd_t *CmdPtr)
{
CFE_Status_t Status;
/* Insufficient validation: returns CFE_SUCCESS for some invalid addresses */
Status = CFE_PSP_MemValidateRange(CmdPtr->Payload.Address, CmdPtr->Payload.Size, CFE_PSP_MEM_ANY);
if (Status == CFE_SUCCESS) {
/* Proceed to spawn child task with invalid Address */
}
}Location: CS_OneShotChildTask()
void CS_OneShotChildTask(void)
{
cpuaddr FirstAddrThisCycle = CS_AppData.HkPacket.Payload.LastOneShotAddress;
// ...
/* CRASH: Direct memory access to invalid FirstAddrThisCycle */
NewChecksumValue = CFE_ES_CalculateCRC((void *)(FirstAddrThisCycle),
NumBytesThisCycle,
NewChecksumValue,
CS_DEFAULT_ALGORITHM);
// ...
}4. To Reproduce (PoC)
- Preparation: Deploy the cFS framework with the CS application enabled.
- Craft Packet: Create a
CS_OneShotCmdground command packet. - Inject Payload: Set the
Addressfield to a known non-mapped memory address (e.g.,0xDEADBEEF) and a validSize(e.g.,100). - Send Command: Dispatch the command to the cFS software bus.
- Observe: The CS child task will trigger a Segmentation Fault, causing the CS application to crash or the OS to terminate the process.
5. Expected behavior
The CS_OneShotCmd() should perform a more rigorous check against the actual available memory map. If an address is outside the permitted operational memory range, the command should be rejected with an error telemetry packet, and no child task should be spawned.
6. Mitigation & Recommendations
- Enhanced PSP Validation: Strengthen the logic within
CFE_PSP_MemValidateRange()to strictly adhere to the specific hardware's memory map. - Application-Level Bounds Checking: Implement a secondary check within the CS application that compares the requested address against a "Safe Memory Table" defined for the specific mission.
- Error Handling: Implement robust exception handling or memory access guards (if supported by the OSAL/PSP) within the CRC calculation loop to prevent a full application crash.
Reporter Info
Space Cybersecurity Council
Activity
Shrey-N commentedon Mar 7, 2026
Proposed Fix
I have reproduced this DoS vulnerability locally in a Linux environment.
Mechanism:-
Bypass: The
pc-linuximplementation ofCFE_PSP_MemValidateRange()frequently returnsCFE_SUCCESSfor user space addresses because it lacks a strict hardware backed memory map.Trigger: Sending a CS_OneShotCmd with an unmapped address bypasses the initial PSP check.
Result: The child task attempts to dereference the pointer via
CFE_ES_CalculateCRC(), resulting in a SIGSEGV which terminates the entire application.My Analysis:
The issue is a "Defense in Depth" failure. The current implementation of CS_OneShotCmd relies exclusively on CFE_PSP_MemValidateRange. On many platforms, this check is not strict enough to guarantee that an address is actually mapped or safe to read. This allows unmapped addresses to be passed into the CS_OneShotChildTask.
When the child task calls CFE_ES_CalculateCRC, it attempts to dereference the invalid pointer, triggering a SIGSEGV and causing an abnormal termination of the CS application.
I have am implementing a fix that would introduce a secondary, application level validation layer before any child task is spawned:
I am finalizing the tests for this logic and will submit a Pull Request shortly @k-spacesec.
keegan-moore commentedon Apr 3, 2026
@dzbaker, @dmolock-NASA, & @jphickey - I'd like to get your thoughts on this. To me, it seems like this is more like a problem with our PSP, rather than an issue with CS. Perhaps we could restrict the valid address range better?
Shrey-N commentedon Apr 4, 2026
Hi @keegan-moore I believe you are correct this is a problem with the PSP. The
pc-linuximplementation ofCFE_PSP_MemValidateRangeis currently a stub that validates the entire address space (0toSIZE_MAX) as RAM:I believe fixing this in the PSP should protect all applications system wide :)
I am happy to write a PR in PSP, asap!
k-spacesec commentedon Apr 7, 2026
Thanks @keegan-moore for the insight — I agree that this is fundamentally a PSP-level issue rather than a CS application bug. Building on @Shrey-N’s analysis, I’d like to provide a detailed root cause breakdown and explain why addressing this in the PSP is important, even for a development-only platform.
1. Source-to-Sink Flow Analysis
To clarify the vulnerability path:
Source (Attacker-Controlled Input):
AddressandSizefields inCS_OneShotCmd_t, received via the Software Bus.Broken Validation (Ineffective Policy Enforcement):
CS_OneShotCmd()forwards these values toCFE_PSP_MemValidateRange().On the pc-linux PSP, this always returns
CFE_PSP_SUCCESSdue to a permissive memory table (0 → SIZE_MAX), effectively bypassing validation.Sink (Unsafe Memory Dereference):
The unchecked address is passed to a child task invoking
CFE_ES_CalculateCRC(), resulting in a dereference of attacker-controlled memory and an immediateSIGSEGV.Summary:
Attacker-controlled input → ineffective PSP validation → unsafe memory dereference.
The CS application correctly follows a validate-then-use pattern. However, the security failure arises because the PSP validation layer does not enforce any real constraints on the Linux platform.
In scenarios where the supplied address is mapped, this may lead to unintended memory access, including potential disclosure or corruption.
2. Root Cause: Inconsistent PSP Memory Table Initialization
The issue originates from how different PSP platforms initialize the
SysMemoryTable.While the shared validation logic in
cfe_psp_memrange.cis sound, the pc-linux implementation effectively nullifies the validation mechanism by using an overly permissive memory range.This is explicitly acknowledged in the source:
This design prioritizes functional compatibility, but removes any meaningful protection against invalid memory access.
3. Why This Matters (Even for a Development PSP)
Although pc-linux is not intended for flight, this behavior has several important implications:
Failure Mode Masking ("Test as You Fly" gap):
Invalid memory accesses will consistently pass validation on pc-linux but fail on real hardware, masking critical memory safety issues during development.
Propagation of Insecure Defaults:
The pc-linux PSP is often used as a reference for new platforms, increasing the risk that the
0 → SIZE_MAXpattern is unintentionally reused.Reduced Simulation Fidelity:
The lack of realistic memory validation undermines the reliability of integration and security testing in HITL/SITL environments.
4. Suggested Approach: Platform-Native Memory Validation
This can be treated as a hardening opportunity to align the pc-linux PSP with the intent of flight-ready implementations.
Each platform’s
CFE_PSP_SetupReservedMemoryMap()should populate the memory table using platform-native mechanisms:Linux (pc-linux):
Use
/proc/self/mapsor equivalent OS-provided mechanisms to identify mapped and accessible virtual address regions.VxWorks:
Use APIs such as
vxMemProbe().RTEMS / Bare-metal:
Use BSP-provided linker symbols (e.g.,
_end,_stack).The goal is to enforce basic accessibility and boundary checks consistent with actual runtime behavior, rather than allowing all addresses by default.
If this direction aligns with the project's goals, I'd be glad to contribute a PR for the pc-linux PSP. Please feel free to reach out if any further analysis or clarification would be helpful.
Shrey-N commentedon Jul 1, 2026
Hi, just checking in on this issue. I submitted the proposed PSP level fix in PSP#469 a while back. Please let me know if there is any feedback or if you need me to make any adjustments to get this merged!
ddstewar commentedon Oct 27, 2026
@dzbaker This has been confirmed by the reworking of the CS test script. This was found and then the search brought up this issue. I'll have @harun1e provide more details he found as well for this while developing the test.
harun1e commentedon Oct 27, 2026
Here are my findings while writing the CS test script.
Any address other than
0x0000in the one-shot command's argument causes a segmentation fault.The address
0x0000works because inCFE_ES_CalculateCRC, if theDataPtrisNULL, it safely returnsInputCRC(which is0in the first iteration). This is the case for all sizes up to the defaultMaxBytesPerCycle = (1024 * 16)or0x4000(the default is selected when theMaxBytesPerCycleparameter is0). Any size greater than this limit will cause a segmentation fault because onlyMaxBytesPerCyclebytes are passed into the first cycle, and any remaining bytes are executed in subsequent cycles with an incremented address.For example, if
size = 0x4008:address = 0x0000andsize = 0x4000.address = 0x4000andsize = 0x0008.Operating on the incremented, non-
NULLaddress0x4000then triggers the segmentation fault.The same behavior applies to the
MaxBytesPerCycleparameter itself. Size andMaxBytesPerCyclego hand in hand: as long asSize > MaxBytesPerCycle, a segmentation fault will occur.This issue is unique to the Linux platform due to user-space memory protection. The MM application exhibits the same behavior, where attempting to PEEK into an address like
0x0000also causes a segmentation fault as expected.Everything else I've found is already covered in this Issue
jphickey commentedon Oct 30, 2026
I like the idea of offering an implementation of the
CFE_PSP_MemValidateRange()for Linux that checks the address against/proc/$PID/mapsThis would also be beneficial for MD and any other app that works on memory addresses.
The current implementation of
CFE_PSP_MemValidateRange()in the PSP is nothing more than a placeholder. It does not do anything. Therefore the possibility of a segfault/bad address due to this is understood - thepc-linuxPSP is an example and absolutely not a hardened implementation.Shrey-N commentedon Oct 31, 2026
@jphickey I have already implemented this design a couple of months ago in nasa/PSP#469, it parses /proc/self/maps at startup to populate the pc-linux memory validation table.