Skip to content

CCSDS File Delivery Protocol - CfdpManager#5138

Open
Brian-Campuzano wants to merge 276 commits into
nasa:develfrom
FireflySpace:cfdp-merge
Open

CCSDS File Delivery Protocol - CfdpManager#5138
Brian-Campuzano wants to merge 276 commits into
nasa:develfrom
FireflySpace:cfdp-merge

Conversation

@Brian-Campuzano

Copy link
Copy Markdown
Collaborator
Related Issue(s) #2768
Has Unit Tests (y/n) y
Documentation Included (y/n) y
Generative AI was used in this contribution (y/n) y

Change Description

This PR adds the CfdpManager component, an F´ implementation of the CCSDS File Delivery Protocol (CFDP) standard ported from NASA's Core Flight System (cFS) CFDP Application v3.0.0. CfdpManager provides both Class 1 (unacknowledged) and Class 2 (acknowledged) file transfer capabilities, designed to replace the standard FileUplink and FileDownlink components with guaranteed file delivery support.

Attribution and License:

  • Substantial portions ported from: NASA Core Flight System (cFS) CFDP (CF) Application v3.0.0
  • Original License: Apache License 2.0
  • Original Copyright: Copyright (c) 2019 United States Government as represented by the Administrator of the National Aeronautics and Space Administration
  • NASA Docket: GSC-18,447-1

Ported components (retain original NASA copyright):

  • Core CFDP engine and transaction management logic (Engine.cpp, Transaction.hpp, TransactionTx.cpp, TransactionRx.cpp)
  • Protocol state machines for transmit and receive operations
  • Utility functions for file handling and resource management (Utils.cpp, Channel.cpp)
  • Chunk and gap tracking for Class 2 transfers (Chunk.cpp, Clist.cpp)

New F´-specific implementations:

  • CfdpManager component wrapper with F´ ports, commands, events, telemetry, and parameters
  • Object-oriented PDU encoding/decoding classes based on F´ Serializable interface
  • Timer implementation using F´ time primitives
  • FileHandlingCfdp subtopology for integration

See ATTRIBUTION.md for complete file-by-file attribution breakdown.

Summary of changes:

  • Full PDU support: Metadata, FileData, EOF, FIN, ACK, NAK
  • Multi-channel support with configurable throttling and timer parameters
  • Port-based file transfer interface compatible with existing F´ components (e.g., DpCatalog)
  • Comprehensive unit tests covering Class 1/2 transactions, PDU handling, and edge cases
  • Complete SDD documentation with architecture diagrams, sequence diagrams, and usage examples

Rationale

Current F´ file transfer components (FileUplink/FileDownlink) lack reliable delivery guarantees over lossy or intermittent links, automatic retransmission and gap detection, and industry-standard CFDP protocol compliance required for interoperability with ground systems and other spacecraft.

CfdpManager addresses these gaps by implementing the CCSDS CFDP standard, which is specifically designed for space missions with long propagation delays, high error rates, and disruption-tolerant requirements. By porting NASA's proven CF application from cFS, this implementation leverages flight-proven CFDP logic while adapting it to F´'s architecture and component model.

Testing/Review Recommendations

Unit Test Coverage:

  • CfdpManagerTester.cpp: Component-level tests with Class 1/2 TX/RX transactions, NAK handling, timer expiration, and throttling
  • PduTester.cpp: PDU serialization/deserialization tests for all PDU types

Areas to focus on:

  1. Port connections & buffer management: Verify buffer allocation/deallocation patterns in uplink/downlink paths (particularly dataOut/dataReturnIn and bufferAllocate/bufferDeallocate)
  2. Timer logic: Review 1Hz scheduler integration and protocol timer handling (inactivity, ACK, NAK timers)
  3. Multi-channel support: Validate channel isolation and resource limits (transactions per channel)
  4. Configuration parameters: Review default values in CfdpCfg.hpp and CfdpCfg.fpp
  5. File I/O error handling: Verify proper cleanup on file open/read/write failures
  6. CF→F´ port quality: Review adaptations from cFS to F´ (e.g., replacing CFE OS calls with F´ Os abstraction)
  7. Documentation accuracy: Cross-check SDD against implementation

Future Work

  • Add support for offset/partial file transfers in fileIn port
  • Implement additional TLV (Type-Length-Value) options (e.g., flow label, fault handler overrides)
  • Add command-line parameter validation for remote entity IDs
  • Consider performance optimizations for high-throughput scenarios
  • Add integration tests with ComQueue and deframing components

AI Usage (see policy)

Generative AI (Claude Code) was used for:

  • Code generation: Assisted with boilerplate for PDU class implementations, unit test scaffolding, and F´ component port wiring
  • Documentation: Assisted with drafting and formatting the SDD markdown (including sequence diagrams and tables) and generating this PR description
  • Refactoring: Suggested improvements during CF→F´ port (e.g., replacing void* with typed pointers, modernizing C→C++ patterns)
  • Debugging: Assisted in diagnosing unit test failures and identifying edge cases in transaction state machines

Important note: AI was NOT used to generate the core CFDP protocol logic. The core engine, transaction state machines, and protocol logic were ported directly from NASA's CF application v3.0.0 (human-written, flight-proven code). AI assistance was limited to F´-specific integration code, documentation, and port quality improvements.

@github-advanced-security github-advanced-security AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

CodeQL found more than 20 potential problems in the proposed changes. Check the Files changed tab for more details.

Comment thread Svc/Ccsds/CfdpManager/Channel.cpp Fixed
Comment thread Svc/Ccsds/CfdpManager/Channel.hpp Fixed
Comment thread Svc/Ccsds/CfdpManager/Clist.cpp Fixed
Comment thread Svc/Ccsds/CfdpManager/Clist.cpp Fixed
Comment thread Svc/Ccsds/CfdpManager/Clist.cpp Fixed
Comment thread Svc/Ccsds/CfdpManager/Types/PduBase.hpp Fixed
Comment thread Svc/Ccsds/CfdpManager/Types/PduBase.hpp Fixed
Comment thread Svc/Ccsds/CfdpManager/Types/test/ut/PduTests.cpp Fixed
Comment thread Svc/Ccsds/CfdpManager/Utils.cpp Fixed
Comment thread default/config/CfdpCfg.hpp Fixed

@thomas-bc thomas-bc left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

A few AI finds that seemed relevant, and one big question about how to handle file paths.

Comment thread Svc/Ccsds/CfdpManager/Engine.cpp Outdated
Comment thread Svc/Ccsds/CfdpManager/Types/PduHeader.cpp Outdated

/* store the filenames in transaction - validation already done during deserialization */
txn->m_history->fnames.src_filename = md.getSourceFilename();
txn->m_history->fnames.dst_filename = md.getDestFilename();

@thomas-bc thomas-bc May 12, 2026

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

One security issue that we've had reported a lot on the F Prime Svc.FileUplink component is that it allows to write files at any location on the filesystem, potentially overwriting critical system files etc.
This is risky for in case of operator oversight (shrug) but also if you receive unauthenticated (potentially malicious) commands.
My understanding is this CfdpManager has the same capability.

Did you find that CFDP makes recommendation on how to deal with that? If not, we should agree on a rationale so that we stop the spam of "hey you have a critical vulnerability here". Maybe the answer is "encrypt/authenticate your comms". But we should agree on something.

cc @bitWarrior , if you have recommendations.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

CfdpManager was patterned using the same security model as FileUplink/FileDownlink. Authentication is expected to happen at the physical or network layers, not in the application itself. In out use-cases, CFDP traffic is being sent over authenticated channels such as encrypted radios or Bundle Protocol Security, so CfdpManager assumes the source is already trusted. That matches the assumptions generally made by the CCSDS 727.0-B-5 CFDP standard.

I understand the defense-in-depth argument for adding application-layer path validation. The tradeoff is additional configuration complexity and possible conflicts with legitimate use cases like firmware updates or system file management. It also does not solve the underlying problem if the CFDP traffic itself is unauthenticated.

I added a “Security Considerations” section to the SDD to document the design rationale more clearly.

If there is interest in revisiting the design or discussing path validation for F´ components more broadly, I’d be happy to join that discussion.

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I agree with everything you've said. I think this is the correct long-term approach. Leaving this thread open for awareness.

Comment thread Svc/Ccsds/CfdpManager/Engine.hpp Fixed
@github-actions

This comment was marked as resolved.

@Brian-Campuzano

Copy link
Copy Markdown
Collaborator Author

@LeStarch @thomas-bc this PR has the updated UT coverage changes and is ready for review.

@thomas-bc

Copy link
Copy Markdown
Collaborator

Thanks for the update. We'll dive into this...

} else {
// Get parameters for fileIn port-initiated transfers
Fw::ParamValid valid;
U8 channelId = this->paramGet_FileInDefaultChannel(valid);

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[Security] must fix FileInDefaultChannel parameter is not range-checked before use, so an out-of-range value asserts in Engine::txFile.

channelId comes from a ground-settable parameter and is passed straight to Engine::txFile, which executes FW_ASSERT(chan_num < Cfdp::NumChannels, ...). Setting the parameter to any value >= Cfdp::NumChannels makes the next fileIn port invocation crash the component (DoS via parameter update). Validate it the way checkCommandChannelIndex() guards the command handlers and return STATUS_INVALID instead of asserting.

// Write file data
if (ret == Cfdp::Status::SUCCESS) {
FwSizeType write_size = dataSize;
Os::File::Status status = this->m_fd.write(dataPtr, write_size, Os::File::WaitType::WAIT);

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[Security] must fix File Data PDU offset/length are written to disk with no bound check against the transaction file size, enabling remote disk exhaustion.

offset and dataSize come directly from the received PDU and are never validated against the metadata-declared m_fsize (or any configured maximum) before the seek/write above. A misbehaving peer can send FD PDUs with offsets up to 0xFFFFFFFF and withhold EOF, growing the receive file toward 4 GiB per transaction until the filesystem fills. Consider rejecting FD PDUs where offset + dataSize exceeds the declared/expected file size.

cc @LeStarch @thomas-bc @bitWarrior — low-confidence finding, please confirm.


## Telemetry

**Note:** Telemetry channels are currently **proposals** defined in [Telemetry.fppi](../Telemetry.fppi) but not yet implemented. Proposals are based on the CF implementation.

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[Documentation] must fix SDD Telemetry section is stale: it states telemetry is "not yet implemented," but ChannelTelemetry is fully implemented and downlinked.

CfdpManager.cpp calls tlmWrite_ChannelTelemetry (lines 72, 473) and per-channel counters are incremented throughout CfdpManager.hpp. This note wrongly tells operators CFDP telemetry is unavailable. The tables also omit 4 emitted fields: recvEofCanceled, sentEofCanceled, faultRxEofError, faultTxEofError.

Suggested change
**Note:** Telemetry channels are currently **proposals** defined in [Telemetry.fppi](../Telemetry.fppi) but not yet implemented. Proposals are based on the CF implementation.
The following telemetry channels are emitted per CFDP channel as the `ChannelTelemetry` array (see [Telemetry.fppi](../Telemetry.fppi)).


Fw::SerializeStatus FileDataPdu::serializeTo(Fw::SerialBufferBase& buffer, Fw::Endianness mode) const {
// Cast to SerialBuffer and delegate to toSerialBuffer
Fw::SerialBuffer* serialBuffer = dynamic_cast<Fw::SerialBuffer*>(&buffer);

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[C++ Design] must fix CPP-25/RTTI — dynamic_cast requires RTTI, which is disabled in F´ flight builds (-fno-rtti); it will not compile.

dynamic_cast is a banned C++ feature (CPP-25). Every sibling PDU (Ack/Eof/Fin/Metadata/Nak) takes Fw::SerialBufferBase& and never downcasts. FileDataPdu needs the concrete SerialBuffer API, so downcast without RTTI. SerialBuffer : LinearBufferBase : SerialBufferBase, so static_cast is valid; the caller contract guarantees a SerialBuffer, which makes the null-check below dead (safe to drop).

Suggested change
Fw::SerialBuffer* serialBuffer = dynamic_cast<Fw::SerialBuffer*>(&buffer);
Fw::SerialBuffer* serialBuffer = static_cast<Fw::SerialBuffer*>(&buffer);


Fw::SerializeStatus FileDataPdu::deserializeFrom(Fw::SerialBufferBase& buffer, Fw::Endianness mode) {
// Cast to SerialBuffer and delegate to fromSerialBuffer
Fw::SerialBuffer* serialBuffer = dynamic_cast<Fw::SerialBuffer*>(&buffer);

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[C++ Design] must fix CPP-25/RTTI — dynamic_cast requires RTTI, which is disabled in F´ flight builds (-fno-rtti); it will not compile.

Same banned-feature issue as in serializeTo above (CPP-25). Sibling PDUs take Fw::SerialBufferBase& and never downcast. Since SerialBuffer : LinearBufferBase : SerialBufferBase, use static_cast; the caller guarantees a SerialBuffer, so the null-check below becomes dead (safe to drop).

Suggested change
Fw::SerialBuffer* serialBuffer = dynamic_cast<Fw::SerialBuffer*>(&buffer);
Fw::SerialBuffer* serialBuffer = static_cast<Fw::SerialBuffer*>(&buffer);

@lestarch-autobot lestarch-autobot left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Automated review summary (run 2)

Per-agent results

Agent must fix suggestion could fix future work outstanding Verdict
Security Vulnerabilities 4 2 1 0 3 No-Go
Supply Chain / Runner Safety 0 0 1 0 1 Go
F Prime C/C++ Design 9 6 1 0 4 No-Go
Documentation Currency 2 2 3 0 3 No-Go
Design 2 0 0 0 0 Go
Architecture 0 0 0 0 0 Go
Test Quality 5 1 1 0 1 Go
CI safety Go
Totals 22 11 7 0 12 No-Go
Since last run
Agent resolved still open newly added incorrect-fix follow-ups improperly resolved disagreements escalated
Security Vulnerabilities 4 1 2 0 0 1
Supply Chain / Runner Safety 0 0 1 0 0 0
F Prime C/C++ Design 12 2 2 0 0 0
Documentation Currency 4 0 3 0 0 0
Design 2 0 0 0 0 0
Architecture 0 0 0 0 0 0
Test Quality 6 1 0 0 0 0
Supply-chain surfaces
Surface Outstanding
Dependencies clean
Vendored / submodule 1 could-fix — ATTRIBUTION lists Types/Types.hpp as ported yet its header carries no NASA notice
Build / test infrastructure clean
Workflows / actions / scripts clean
Generator output clean
Prompt-injection clean
Review-system integrity clean
Outstanding must-fix items (5)

Security Vulnerabilities

  • FileInDefaultChannel parameter not range-checked before use — out-of-range value asserts in Engine::txFile (DoS) — #5138 (comment)
  • File Data PDU offset/length written to disk with no bound check against transaction file size — remote disk exhaustion — #5138 (comment)

F Prime C/C++ Design

  • CPP-25/RTTI — dynamic_cast in FileDataPdu::serializeTo won't compile under -fno-rtti; use static_cast#5138 (comment)
  • CPP-25/RTTI — second dynamic_cast in FileDataPdu.cpp won't compile under -fno-rtti; use static_cast#5138 (comment)

Documentation Currency

  • SDD Telemetry section stale: states telemetry "not yet implemented," but ChannelTelemetry is implemented and downlinked — #5138 (comment)

Merge readiness

Merge readiness: No-Go — Security, C/C++ Design, and Documentation each have outstanding must-fix findings (2, 2, and 1 respectively).

Agents that did not run on this PR

  • None — all seven registered reviewers ran this run.

Steady progress this orbit: twelve findings cleared since run 1, five must-fix contacts remain on the scope — clear them and we're go for the next window.

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.

6 participants