Skip to content

Restart osctrld on every platform - #25

Merged
javuto merged 1 commit into
developfrom
osctrld-restart-service
Oct 16, 2026
Merged

javuto merged 1 commit into
developfrom
osctrld-restart-service

Conversation

@javuto

@javuto javuto commented Oct 16, 2026

Copy link
Copy Markdown
Contributor

Restart osqueryd on every platform, run the service as root, harden extensions and HTTP

Two changes, one per repo, make an operator's flag edits in osctrl reach osquery on every node. jmpsec/osctrl#1089 makes the server serve the flags operators actually edit. This PR makes osctrld apply them on every platform: it writes the flagfile and restarts osqueryd. It builds on #24, which aligned osctrld's requests with the current server.

Server side: jmpsec/osctrl#1089

Before #1089, osctrl's osctrld endpoints served a freshly generated default flag set, so an operator's edits to an environment's flags never reached nodes managed by osctrld.

  • FlagsHandler and VerifyHandler now use the new NodeFlags. It serves the environment's stored, operator-edited flags with the secret and certificate paths filled in. Environments with no stored flags still get the generated defaults.
  • FillFlagPaths is shared. It replaces __SECRET_FILE__ and __CERT_FILE__; an empty path keeps its placeholder, the same as the generated flags. osctrl-api's per-platform flag substitution now uses it too.
  • Verify compares against the same flags the flags endpoint serves, so osctrld's verify no longer reports a mismatch against defaults nobody deployed.
  • osctrld_flags_test.go covers four cases: stored flags are served with paths filled, placeholders are kept when no paths are given, generated flags are the fallback when nothing is stored, and a wrong secret is rejected.

Client side: this PR (osctrld)

Problems

  • Linux restart only tried systemctl, so hosts without systemd never applied new flags.
  • Windows restart wasn't implemented, even though install already managed the service through the Windows service manager.
  • The packaged systemd unit never started. It required /opt/osctrld, but the deb, rpm and apk packages install to /usr/bin/osctrld.
  • The unit ran as User=osctrld, which can't write /etc/osquery or restart osqueryd, the daemon's whole job.
  • The macOS plist shipped with /path/to/ placeholders.
  • Extension names went unchecked into filepath.Join, so a manifest entry named ../x could write anywhere the daemon can.
  • HTTP requests had no timeout, so a server that never answered hung the service loop forever.

Changes

  • Restart:
    • Linux tries systemctl, then service, then /etc/init.d/osqueryd, the same chain install uses for stop and start.
    • Windows stops the service, waits until it has stopped, then starts it.
    • macOS is unchanged.
  • Extensions: a manifest entry must be a plain file name. Others are logged and skipped, and the rest still install.
  • HTTP: a 10-minute timeout per request, body included. It's that long because the same client downloads osquery packages of around 100 MB.
  • systemd unit: runs /usr/bin/osctrld as root after network-online.target, and logs to journald.
  • macOS plist: runs /usr/local/bin/osctrld and logs to /var/log/osctrld.log.
  • Packaging and README: /etc/osctrld/osctrld.yaml is installed 0600, since it holds the osctrl secret. The README install steps match the packaged paths.

Security and operational impact

  • Root: osctrld runs as root under systemd. It already needed equivalent privileges on macOS and Windows.
  • Path traversal: extension names can no longer write outside the extensions directory.
  • Manual installs: hosts installed to /opt/osctrld per the old README must move the binary to /usr/bin/osctrld or edit the unit.
  • Restart behaviour: Windows hosts and hosts without systemd now restart osqueryd when the flags, certificate or extensions change. Before, the restart failed and logged an error.

Validation

  • go test ./cmd/osctrld/ -race: all 109 tests ran, 0 failures
  • go vet and golangci-lint run ./... for GOOS=darwin, linux and windows: clean, 0 issues
  • plutil -lint on the plist: OK
  • New tests:
    • TestOsqueryRestartCandidates, TestRestartOsqueryDarwin, TestSyncExtensions_RejectsNamesOutsideTheDirectory and TestSendRequestTimesOut pass.
    • TestRestartOsqueryFallsBackWithoutSystemd is Linux-only; it runs in CI on ubuntu-latest and skips on macOS.
  • goreleaser check: the config is valid. The check still fails on the existing brews deprecation, which this PR doesn't touch.

@javuto javuto added the ✨ enhancement New feature or request label Oct 16, 2026
@javuto
javuto merged commit d6a43a9 into develop Oct 16, 2026
2 checks passed
@javuto
javuto deleted the osctrld-restart-service branch October 16, 2026 21:54
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

✨ enhancement New feature or request

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant