Skip to content

[SECURITY] Missing lower-bound validation in CI_LAB_DecodeInputMessage allows zero-length packets #985

@linerfan5114

Description

@linerfan5114

Describe the bug
CI_LAB_DecodeInputMessage() in ci_lab_passthru_decode.c validates the CCSDS MsgSize from the packet header against the received SourceSize using only an upper-bound check (MsgSize > SourceSize). There is no lower-bound validation.

An attacker can send a deliberately malformed CCSDS Space Packet with Length=0 (total MsgSize = 7 bytes, which is less than sizeof(CFE_MSG_Message_t) = 16 bytes for telemetry or 8 bytes for commands). Because 0 > 768 is false, the malformed packet passes validation with CFE_SUCCESS and is forwarded directly to the Software Bus via CFE_SB_TransmitBuffer().

This is the same root cause as:

  • cFE #2697: Integer underflow in CFE_SB_GetUserDataLength
  • cFE #2698: Heap exfiltration via undersized CCSDS Length in TO_LAB
  • cFE #2699: Unbounded loop in CFE_MSG_ComputeCheckSum

All of these stem from the cFE Message layer trusting the attacker-controlled CCSDS Length field without lower-bound validation.

To Reproduce

  1. Send a single UDP datagram to the CI_LAB ingest port (default UDP/5012) containing only a CCSDS Primary Header:
    • StreamId = any valid command MsgId
    • Sequence = arbitrary
    • Length = 0x0000 (decoded total = 7 bytes)
  2. CI_LAB_ReadUpLink() receives the packet via OS_SocketRecvFrom()
  3. CI_LAB_DecodeInputMessage() checks MsgSize > SourceSize7 > 768false → passes validation
  4. The 7-byte buffer is cast to CFE_SB_Buffer_t * and sent to CFE_SB_TransmitBuffer()
  5. Any subscriber that reads the message size via CFE_MSG_GetSize() and uses it for memcpy, loop iteration, or buffer allocation will perform an out-of-bounds read or integer underflow

Expected behavior
CI_LAB_DecodeInputMessage() should validate that MsgSize >= sizeof(CFE_MSG_Header_t) (the minimum valid CCSDS Space Packet size) before accepting the packet. The check should be:

CFE_MSG_GetSize(&MsgBufPtr->Msg, &MsgSize);

if (MsgSize < sizeof(CFE_MSG_Message_t) || MsgSize > SourceSize)
{
    Status = CFE_STATUS_WRONG_MSG_LENGTH;
}
else
{
    Status = CFE_SUCCESS;
}

This is consistent with the fix applied in CFE_SB_MessageTxn_SetContentSize() (cFE PR #2702) which added the lower-bound check.

Code snips

File: apps/ci_lab/fsw/src/ci_lab_passthru_decode.c, lines 68-82:

CFE_MSG_GetSize(&MsgBufPtr->Msg, &MsgSize);

if (MsgSize > SourceSize)          // ← Only upper bound
                                    // ← No lower bound check!
{
    Status = CFE_STATUS_WRONG_MSG_LENGTH;
    CFE_EVS_SendEvent(CI_LAB_INGEST_LEN_ERR_EID, CFE_EVS_EventType_ERROR,
                      "CI: cmd dropped - length mismatch, ...");
}
else
{
    Status = CFE_SUCCESS;          // ← Attacker reaches here with MsgSize=7
}

System observed on

  • Hardware: x86-64 (POSIX cFS / NOS3 simulator)
  • OS: Linux 6.8.0 (Ubuntu 24.04)
  • Versions: cFE v7.0.0-rc4+dev370 (bundle cFS Draco v7.0.0, commit 432c9302)

Additional context

Reporter Info
Erfan, Independent Space Software Security Researcher

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions