Conversation
daf28d3 to
bcdec55
Compare
e66be4b to
3843315
Compare
| activate Orch | ||
| Orch->>FD: channel_transact: QueryStatus | ||
| FD-->>Orch: Status::ActivationPending | ||
| Note right of Orch: bump SVN (irreversible),<br/>close SMC write filter |
There was a problem hiding this comment.
Iirc, the SVN bumping should not happen automatically but only via a manual invocation, once the firmware is considered proven in use? @FerralCoder
4242d48 to
f1b64a2
Compare
f1b64a2 to
493bd7d
Compare
|
|
||
| Design decisions: | ||
|
|
||
| - ServiceCall is the universal IPC primitive. Every cross-process request |
There was a problem hiding this comment.
Worth naming which pw_kernel syscalls start()/signal()/try_recv() map to — e.g. channel_async_transact + channel_async_transact_complete, with the initiator handle added to the caller's WaitGroup for signal().
One implication worth calling out here:
channel_async_transact is unsafe specifically because its send/recv buffers must stay "pinned" until the transaction completes, so ServiceCall<Req, Resp> can't hand start() transient stack buffers — it needs to own Req/Resp for the call's lifetime.
struct IpcPlatform {
// Pinned until try_complete() -- can't share one scratch buffer across
// in-flight channels; each gets its own fixed-size buffer, held here.
gpio_buf: (SendBuf, RecvBuf),
wdt_buf: (SendBuf, RecvBuf),
mailbox_buf: (SendBuf, RecvBuf),
power_buf: (SendBuf, RecvBuf),
}
0840dbc to
583182b
Compare
|
@chrysh, I believe this is a more suitable design than the original proposal. If we are in agreement, given you stated that we should agree as a group to move on from that proposal, we can declare the orchestrator as a channel handler defunct and converge on this. Let's present this to the pigweed team so they can give us advice. |
@rusty1968 sounds good. We also had a look together with @leongross at osfc2026. How do we present it to the pigweed people? Can you do that? And how can I help? |
Alternative to OpenPRoT#458. The FD owns the dispatch loop and the PLDM state machine; the orchestrator is its client and grants or denies each phase (AcceptOffer, GrantVerify, GrantApply, GrantActivate, GrantSvnCommit). Firmware bytes never pass through the orchestrator: FdOps::download_fw_data writes via the device server and FdOps::verify delegates to the crypto service, which reads the staged image from the device server itself. Every cross-process request is a ServiceCall whose completion signal sits in the caller's WaitGroup, so no process blocks on another and the orchestrator stays reactive to CompromiseDetected and its boot watchdogs. The grant gates add no PLDM states: pldm-lib polls verify and apply through fd_progress and our implementation reports 0% until the grant arrives, which keeps the MCTP responder live during the wait. The security revision is not bumped at activation. Bumping there would put the superseded image below the floor and make a trial-boot revert impossible, so the UA sets Security Revision Number Delayed Update and sends UpdateSecurityRevision (0x22) once it is satisfied with the running image. Five crates, only the server-runtime and the client-ipc kernel-tagged, so the wire and dispatch run host-side against a loopback. Write containment has two layers, a device-server staging window and the SMC write filter. Both close before GrantVerify, because a verdict over flash that can still be written does not match the image that apply commits. Both cover staging only; apply and activate stay reachable by a compromised FD and that gap is stated, not closed. Open questions are listed at the end of the doc, FD death answered with restart-and-nudge. Assisted-by: Claude
583182b to
d330e8b
Compare
Summary
Alternative to #458. PLDM-FD is the IPC server and owns the protocol state
machine; the orchestrator is its client and grants or denies each phase.
Firmware bytes never pass through the orchestrator.
AcceptOffer/RejectOffer, GrantVerify, GrantApply, GrantActivate,
GrantSvnCommit
channel_async_transact, with completion signalsin a WaitGroup, so no process blocks on another and the FD never parks
FdOps::activateissynchronous and what it returns is the UA's completion code
describes the image apply commits
(0x22) and the orchestrator advances the floor only on a confirmed trial
Full design:
docs/src/design/orchestrator/pldm-server-ipc.md. Open questionsare listed at the end of that file.
In-transport sequence
sequenceDiagram participant UA as UA (BMC)<br/>remote, over MCTP participant FD as PLDM-FD (server)<br/>dispatch loop + run_terminus participant Orch as Orchestrator (client)<br/>ServiceCall participant DevSrv as Device Server<br/>manages the SPI flash participant Crypto as Crypto Service<br/>hash + signature verification Note over UA, Crypto: Blue background: orchestrator IPC. Green background: FdOps service IPC. Note over UA, Orch: NEGOTIATION (PLDM protocol, MCTP only) UA->>FD: RequestUpdate (MCTP) FD-->>UA: RequestUpdate response (accepted) UA->>FD: PassComponentTable (MCTP) FD-->>UA: PassComponentTable response UA->>FD: UpdateComponent (MCTP) FD-->>UA: UpdateComponent response Note over FD, Orch: FD has an offer, nudge the orchestrator FD->>Orch: USER signal (nudge: offer ready) rect rgb(230, 240, 255) activate Orch Orch->>FD: ServiceCall: QueryStatus FD-->>Orch: Status::OfferPending { target, total, mode: InTransport } Note right of Orch: validate target + total,<br/>platform driver picks<br/>staging address,<br/>reserve staging,<br/>open staging window Orch->>FD: ServiceCall: AcceptOffer { base: FlashAddress } FD-->>Orch: Ok deactivate Orch end Note over UA, DevSrv: TRANSFER (FD pulls from UA, FdOps writes to flash) rect rgb(230, 255, 230) loop FdOps::download_fw_data per chunk FD->>UA: RequestFirmwareData (MCTP) UA-->>FD: firmware chunk FD->>DevSrv: ServiceCall: write chunk DevSrv-->>FD: signal: Ok end end Note over FD, Orch: transfer done, ask orchestrator to grant verify FD->>UA: TransferComplete (MCTP) FD->>Orch: USER signal (nudge: verify pending) rect rgb(230, 240, 255) activate Orch Orch->>FD: ServiceCall: QueryStatus FD-->>Orch: Status::VerifyPending Note right of Orch: check isolation, update policy,<br/>close staging window Orch->>FD: ServiceCall: GrantVerify FD-->>Orch: Ok deactivate Orch end Note over FD, Crypto: FdOps::verify rect rgb(230, 255, 230) FD->>Crypto: ServiceCall::start(VerifyRequest { addr, size }) Crypto->>DevSrv: read staged image DevSrv-->>Crypto: image data loop fd_progress poll Note over FD: verify() returns 0%, no signal yet end Crypto-->>FD: signal: Verdict Note over FD: verify() poll: try_recv -> 100% + verdict end FD->>UA: VerifyComplete (MCTP) Note over FD, Orch: verify done, ask orchestrator to grant apply FD->>Orch: USER signal (nudge: apply pending) rect rgb(230, 240, 255) activate Orch Orch->>FD: ServiceCall: QueryStatus FD-->>Orch: Status::ApplyPending Orch->>FD: ServiceCall: GrantApply FD-->>Orch: Ok deactivate Orch end Note over FD, DevSrv: FdOps::apply rect rgb(230, 255, 230) FD->>DevSrv: ServiceCall::start(apply: commit staged image) loop fd_progress poll Note over FD: apply() returns 0%, no signal yet end DevSrv-->>FD: signal: Ok Note over FD: apply() poll: try_recv -> 100% end FD->>UA: ApplyComplete (MCTP) Note over FD, Orch: apply done, decide activation before the UA asks FD->>Orch: USER signal (nudge: activation decision) rect rgb(230, 240, 255) activate Orch Orch->>FD: ServiceCall: QueryStatus FD-->>Orch: Status::ActivationPending Note right of Orch: check isolation, update policy Orch->>FD: ServiceCall: GrantActivate FD-->>Orch: Ok deactivate Orch end Note over UA, Orch: ACTIVATION (FdOps::activate, any time later) UA->>FD: ActivateFirmware (MCTP) FD-->>UA: ActivateFirmware response (accepted, from the stored grant) rect rgb(230, 255, 230) FD->>DevSrv: ServiceCall: FdOps::activate: set boot preference DevSrv-->>FD: signal: Ok end FD->>Orch: USER signal (nudge: activated) rect rgb(230, 240, 255) activate Orch Orch->>FD: ServiceCall: QueryStatus FD-->>Orch: Status::Idle { reason: ActivateFw } Note right of Orch: release staging,<br/>start judging the boot deactivate Orch end Note over UA, DevSrv: SVN COMMIT (later, FD back in IDLE, new image running) Note right of Orch: judge the boot, then<br/>TrialBoot::confirm or revert UA->>FD: UpdateSecurityRevision (MCTP, 0x22) FD->>Orch: USER signal (nudge: SVN commit requested) rect rgb(230, 240, 255) activate Orch Orch->>FD: ServiceCall: QueryStatus FD-->>Orch: Status::SvnCommitPending { component } Note right of Orch: a confirmed trial only,<br/>else DenySvnCommit Orch->>DevSrv: ServiceCall: SvnFloor::advance DevSrv-->>Orch: signal: Ok Orch->>FD: ServiceCall: GrantSvnCommit FD-->>Orch: Ok deactivate Orch end FD-->>UA: UpdateSecurityRevision response (success) Note over UA, Orch: CANCEL (between AcceptOffer and activation) UA->>FD: CancelUpdate (MCTP) rect rgb(230, 255, 230) FD->>DevSrv: ServiceCall: FdOps::cancel_update_component DevSrv-->>FD: signal: Ok end FD-->>UA: CancelUpdate response FD->>Orch: USER signal (nudge: cancelled) rect rgb(230, 240, 255) activate Orch Orch->>FD: ServiceCall: QueryStatus FD-->>Orch: Status::Cancelled Note right of Orch: release staging,<br/>close staging window Orch->>FD: ServiceCall: AckCancel FD-->>Orch: Ok deactivate Orch endOut-of-transport sequence
sequenceDiagram participant UA as UA (BMC)<br/>remote, over MCTP participant FD as PLDM-FD (server)<br/>dispatch loop + run_terminus participant Orch as Orchestrator (client)<br/>ServiceCall participant DevSrv as Device Server<br/>manages the SPI flash participant Crypto as Crypto Service<br/>hash + signature verification Note over UA, Crypto: Blue background: orchestrator IPC. Green background: FdOps service IPC. Note over UA, Orch: NEGOTIATION (same as in-transport) UA->>FD: RequestUpdate (MCTP) FD-->>UA: RequestUpdate response (accepted) UA->>FD: PassComponentTable (MCTP) FD-->>UA: PassComponentTable response UA->>FD: UpdateComponent (MCTP, out-of-transport) FD-->>UA: UpdateComponent response Note over FD, Orch: FD has an offer, nudge the orchestrator FD->>Orch: USER signal (nudge: offer ready) rect rgb(230, 240, 255) activate Orch Orch->>FD: ServiceCall: QueryStatus FD-->>Orch: Status::OfferPending { target, total, mode: OutOfTransport } Note right of Orch: validate target + total,<br/>platform driver picks<br/>staging address Orch->>FD: ServiceCall: AcceptOffer { base: FlashAddress } Note left of FD: FD does not write in<br/>out-of-transport; a third party<br/>pre-stages the image, and how it<br/>learns the address is open FD-->>Orch: Ok deactivate Orch end Note over FD, Orch: no transfer phase, image already staged FD->>UA: TransferComplete (MCTP) Note over FD, Orch: ask orchestrator to grant verify FD->>Orch: USER signal (nudge: verify pending) rect rgb(230, 240, 255) activate Orch Orch->>FD: ServiceCall: QueryStatus FD-->>Orch: Status::VerifyPending Note right of Orch: check isolation, update policy,<br/>close staging window Orch->>FD: ServiceCall: GrantVerify FD-->>Orch: Ok deactivate Orch end Note over FD, Crypto: FdOps::verify rect rgb(230, 255, 230) FD->>Crypto: ServiceCall::start(VerifyRequest { addr, size }) Crypto->>DevSrv: read staged image DevSrv-->>Crypto: image data loop fd_progress poll Note over FD: verify() returns 0%, no signal yet end Crypto-->>FD: signal: Verdict Note over FD: verify() poll: try_recv -> 100% + verdict end FD->>UA: VerifyComplete (MCTP) Note over FD, Orch: verify done, ask orchestrator to grant apply FD->>Orch: USER signal (nudge: apply pending) rect rgb(230, 240, 255) activate Orch Orch->>FD: ServiceCall: QueryStatus FD-->>Orch: Status::ApplyPending Orch->>FD: ServiceCall: GrantApply FD-->>Orch: Ok deactivate Orch end Note over FD, DevSrv: FdOps::apply rect rgb(230, 255, 230) FD->>DevSrv: ServiceCall::start(apply: commit staged image) loop fd_progress poll Note over FD: apply() returns 0%, no signal yet end DevSrv-->>FD: signal: Ok Note over FD: apply() poll: try_recv -> 100% end FD->>UA: ApplyComplete (MCTP) Note over FD, Orch: apply done, decide activation before the UA asks FD->>Orch: USER signal (nudge: activation decision) rect rgb(230, 240, 255) activate Orch Orch->>FD: ServiceCall: QueryStatus FD-->>Orch: Status::ActivationPending Note right of Orch: check isolation, update policy Orch->>FD: ServiceCall: GrantActivate FD-->>Orch: Ok deactivate Orch end Note over UA, Orch: ACTIVATION (same as in-transport) UA->>FD: ActivateFirmware (MCTP) FD-->>UA: ActivateFirmware response (accepted, from the stored grant) rect rgb(230, 255, 230) FD->>DevSrv: ServiceCall: FdOps::activate: set boot preference DevSrv-->>FD: signal: Ok end FD->>Orch: USER signal (nudge: activated) rect rgb(230, 240, 255) activate Orch Orch->>FD: ServiceCall: QueryStatus FD-->>Orch: Status::Idle { reason: ActivateFw } Note right of Orch: release staging,<br/>start judging the boot deactivate Orch end Note over UA, DevSrv: SVN COMMIT (later, FD back in IDLE, new image running) Note right of Orch: judge the boot, then<br/>TrialBoot::confirm or revert UA->>FD: UpdateSecurityRevision (MCTP, 0x22) FD->>Orch: USER signal (nudge: SVN commit requested) rect rgb(230, 240, 255) activate Orch Orch->>FD: ServiceCall: QueryStatus FD-->>Orch: Status::SvnCommitPending { component } Note right of Orch: a confirmed trial only,<br/>else DenySvnCommit Orch->>DevSrv: ServiceCall: SvnFloor::advance DevSrv-->>Orch: signal: Ok Orch->>FD: ServiceCall: GrantSvnCommit FD-->>Orch: Ok deactivate Orch end FD-->>UA: UpdateSecurityRevision response (success) Note over UA, Orch: CANCEL (between AcceptOffer and activation) UA->>FD: CancelUpdate (MCTP) rect rgb(230, 255, 230) FD->>DevSrv: ServiceCall: FdOps::cancel_update_component DevSrv-->>FD: signal: Ok end FD-->>UA: CancelUpdate response FD->>Orch: USER signal (nudge: cancelled) rect rgb(230, 240, 255) activate Orch Orch->>FD: ServiceCall: QueryStatus FD-->>Orch: Status::Cancelled Note right of Orch: discard the accepted offer Orch->>FD: ServiceCall: AckCancel FD-->>Orch: Ok deactivate Orch endAssisted-by: Claude