Skip to content

fix(dgw,agent): fix Windows service crash at startup - #2069

Merged
Benoît Cortier (CBenoit) merged 2 commits into
masterfrom
claude/elegant-shannon-n2p8sa
Oct 14, 2026
Merged

Benoît Cortier (CBenoit) merged 2 commits into
masterfrom
claude/elegant-shannon-n2p8sa

Conversation

@CBenoit

@CBenoit Benoît Cortier (CBenoit) commented Oct 13, 2026 •

Copy link
Copy Markdown
Member

Fixes a crash that could stop the Devolutions Gateway Windows service from starting: after updating to 2026.3.2 on Windows Server 2016, the service crashed immediately (access violation in ntdll.dll) and never came up, while running the same binary in a console worked.

The cause was a bug in the service-registration library both the Gateway and the Agent use, which could make Windows read garbage while registering the service. Whether it crashed depended on the exact build, so the Agent carried the same latent risk. Both now use the fixed library.

When the service fails to start (for example because of an invalid configuration), the Gateway and Agent processes now exit with a nonzero status instead of 0, so service managers such as systemd can detect the failure and restart the service.

Issue: DGW-460

Bump ceviche to 0.8.0, which passes a properly terminated service table
to StartServiceCtrlDispatcherW. ceviche 0.7.0 passed a table without its
null terminator entry, so Windows read leftover stack data as extra
service entries. With the 2026.3.2 build, that made the Gateway service
crash at startup on Windows Server 2016 (access violation in ntdll.dll).

ceviche 0.8.0 also changes the service main function to return a u8
exit code, so the Gateway and Agent service entry points are updated
accordingly.

Issue: DGW-460

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_013S6heAK1x7hF1rZDgpabwB
Copilot AI balanced review requested due to automatic review settings October 13, 2026 16:55

Copy link
Copy Markdown
Member Author

Implementation notes:

  • Root cause (from the customer's crash dump): ceviche 0.7.0's Controller::register passed StartServiceCtrlDispatcherW a pointer to a single SERVICE_TABLE_ENTRYW, without the {NULL, NULL} terminator entry. In the 2026.3.2 binary, the stack slot after the entry held {0x4, …}. On Server 2016, sechost!ScCheckServiceSids passed that "name" (0x4) to RtlInitUnicodeString, which crashed at ntdll+0x44156. Console mode never calls the dispatcher, which is why it worked. ceviche was already 0.7.0 in 2026.2.4; that build most likely had zeros in that slot by chance. The fix is fix(windows): terminate the service table passed to StartServiceCtrlDispatcherW ceviche-rs#37, released in 0.8.0.
  • Breaking API changes in ceviche 0.8.0: the service main function now returns u8 instead of u32, so the exit code constants and both entry points are updated. Controller::register now returns Result<u8, Error>. On Windows, ceviche already reports the exit code to the SCM. The Gateway still discards the returned code and the Agent still ignores the result. Propagating it as the process exit code (useful for systemd Restart=on-failure) would be a separate change.
  • Other behavior changes in 0.8.0: service status reporting is hardened (fix(windows)!: harden service status reporting ceviche-rs#39). STOP_PENDING now has a 30 s wait hint, START_PENDING has a 5 s wait hint, and no controls are accepted while pending.
  • Cargo.lock: cargo update -p ceviche also re-pointed some existing dependency edges, e.g. hyper-util → socket2 0.6.5, several crates → windows-sys 0.61.2. No package versions were added or removed besides ceviche. This is cargo's own resolution; plain cargo metadata produces the same lockfile.
  • Testing: cargo clippy -p devolutions-gateway -p devolutions-agent --tests -- -D warnings and cargo +nightly fmt --all -- --check pass on Linux. A Windows-target cargo check isn't possible from the Linux container because ring and aws-lc-sys need MSVC, so Windows CI is the real compile check. A Windows Server 2016 repro (service start as NetworkService) would confirm the fix end to end.

Generated by Claude Code

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🟡 Changes recommended

Non-Windows service exit codes are discarded, and the lockfile includes unrelated dependency churn.

2 open findings
What changed in this PR

Updates Gateway and Agent to Ceviche 0.8, fixing invalid Windows service registration memory.

Changes:

  • Upgrades Ceviche to 0.8.
  • Adapts service callbacks to u8 exit codes.
  • Refreshes dependency resolution.

External-contract and documentation passes were not applicable.

File Description
devolutions-gateway/​src/​main.rs Adapts Gateway service exit codes.
devolutions-gateway/​Cargo.toml Upgrades Ceviche.
devolutions-agent/​src/​main.rs Adapts Agent service exit codes.
devolutions-agent/​Cargo.toml Upgrades Ceviche.
Cargo.lock Locks Ceviche 0.8 and resolved dependencies.

🧠 Review effort: Balanced


💡 Configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

Comment thread devolutions-agent/src/main.rs
Comment thread devolutions-gateway/src/main.rs
ceviche 0.8 returns the service main exit code from
`Controller::register`. Use it as the process exit status, so that a
configuration or startup failure no longer exits with status 0 and
service managers such as systemd (`Restart=on-failure`) see it.

The Agent now also reports a registration failure and exits with
status 1 instead of exiting silently with status 0.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_013S6heAK1x7hF1rZDgpabwB

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🟢 Approval recommended

The library upgrade addresses the reported crash, and both consumers correctly implement its updated exit-code contract.

0 open findings

2 resolved since last review

🧠 Review effort: Balanced

@CBenoit
Benoît Cortier (CBenoit) merged commit 20c0119 into master Oct 14, 2026
47 checks passed
@CBenoit
Benoît Cortier (CBenoit) deleted the claude/elegant-shannon-n2p8sa branch October 14, 2026 07:49
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Development

Successfully merging this pull request may close these issues.

3 participants