<#43 Identify osqueryd by root ownership or Window...
# osctrl
g
#43 Identify osqueryd by root ownership or Windows service state, and make verify exit non-zero when any check fails Pull request opened by javuto Problem • (High): a same-name process can spoof osquery health.
isOsquerydRunning
counted any process named `osqueryd`/`osqueryd.exe` as the managed agent. A lower-privileged local user could run a process with that name while the real service was down. Flags and upgrade checks would then accept a failed change, and the endpoint would report osquery as healthy. • (Medium):
verify
reports success for an unhealthy endpoint.
verifyNode
logged mismatches, missing install files, a bad version and a stopped osqueryd, then returned
nil
. Anything relying on the exit code saw success. Its process check (a
"/osqueryd "
substring in the command line) also never matched on Windows. Change osqueryd identity • Linux/macOS: osqueryd counts only when its process's real uid is root. An unprivileged user cannot start such a process, including by running a setuid-root binary under the name
osqueryd
, because the real uid stays theirs. • Windows:
isOsquerydRunning
asks the service manager whether the osquery service is
Running
. A missing service counts as not running; other service-manager errors are returned. •
openOsqueryService
now wraps its errors with
%w
, so a missing service can be told apart from other errors. • All callers (flags guard, health watcher, service loop, upgrade) get the fix through the existing
osquerydRunning
seam. • I chose not to match on the executable path. Any user can run the real binary, and a strict path match would mark osquery as down on non-standard installs, which would roll back good flags across the fleet.
verify
• Every check is still reported. The command now returns
verification failed - <list>
when any check fails: secret, flags or cert mismatch, osquery not installed, version too low or unknown, osqueryd not running. • It uses the same osqueryd check as the daemon, and
osqueryVersionReader
for the version. Docs:
ARCHITECTURE.md
and
README.md
describe the new osqueryd check and the
verify
exit code. Security / operational impact •
verify
now exits non-zero on drift or a stopped agent. Scripts that ignored its exit code are unaffected; anything checking it will now see failures it used to miss. • osqueryd running as a non-root user on POSIX no longer counts as running. Standard systemd and launchd installs run it as root. • The process ID is no longer included in `verify`'s "osqueryd is running" log line. Validation •
go test ./cmd/osctrld/ -race
passes •
golangci-lint run ./...
and `GOOS=windows golangci-lint run ./...`: 0 issues • New tests: • `TestVerifyNode`: a healthy case and one case per failure • `TestRootOwned`: covers a setuid binary run by a normal user • `TestListRootProcessNamesSkipsOwnProcess`: the non-root test process is filtered out (skipped when run as root) • Not run on a real Windows endpoint:
windowsServiceRunning
is only compiled and linted, because CI runs tests on Linux only. jmpsec/osctrld