From a46d4bb769230f5049024180e26b77fc7d50a3d7 Mon Sep 17 00:00:00 2001 From: Rebecca Mahany-Horton Date: Tue, 7 Nov 2023 09:38:42 -0500 Subject: [PATCH 01/30] Add package to perform path lookups and validations for commands --- pkg/allowedpaths/cmd.go | 85 ++++++++++++++ pkg/allowedpaths/cmd_darwin.go | 81 +++++++++++++ pkg/allowedpaths/cmd_linux.go | 60 ++++++++++ pkg/allowedpaths/cmd_test.go | 201 ++++++++++++++++++++++++++++++++ pkg/allowedpaths/cmd_windows.go | 32 +++++ 5 files changed, 459 insertions(+) create mode 100644 pkg/allowedpaths/cmd.go create mode 100644 pkg/allowedpaths/cmd_darwin.go create mode 100644 pkg/allowedpaths/cmd_linux.go create mode 100644 pkg/allowedpaths/cmd_test.go create mode 100644 pkg/allowedpaths/cmd_windows.go diff --git a/pkg/allowedpaths/cmd.go b/pkg/allowedpaths/cmd.go new file mode 100644 index 000000000..c93a58e7a --- /dev/null +++ b/pkg/allowedpaths/cmd.go @@ -0,0 +1,85 @@ +package allowedpaths + +import ( + "context" + "fmt" + "os/exec" + "path/filepath" + "strings" +) + +// CommandWithLookup should be used when the full path to the command is not known and it is +// likely to be found in PATH. +func CommandWithLookup(name string, arg ...string) (*exec.Cmd, error) { + fullPathToCommand, err := exec.LookPath(name) + if err != nil { + return nil, fmt.Errorf("looking up path to %s: %w", name, err) + } + + return CommandWithPath(fullPathToCommand, arg...) +} + +// CommandWithPath should be used when the full path to the command is known, or unlikely to be +// found in PATH. +func CommandWithPath(fullPathToCommand string, arg ...string) (*exec.Cmd, error) { + fullPathToCommand = filepath.Clean(fullPathToCommand) + + if err := pathIsAllowed(fullPathToCommand); err != nil { + return nil, fmt.Errorf("path is not allowed: %w", err) + } + + return exec.Command(fullPathToCommand, arg...), nil +} + +// CommandContextWithLookup should be used when the full path to the command is not known and it is +// likely to be found in PATH. +func CommandContextWithLookup(ctx context.Context, name string, arg ...string) (*exec.Cmd, error) { + fullPathToCommand, err := exec.LookPath(name) + if err != nil { + return nil, fmt.Errorf("looking up path to %s: %w", name, err) + } + + return CommandContextWithPath(ctx, fullPathToCommand, arg...) +} + +// CommandContextWithPath should be used when the full path to the command is known, or unlikely to be +// found in PATH. +func CommandContextWithPath(ctx context.Context, fullPathToCommand string, arg ...string) (*exec.Cmd, error) { + fullPathToCommand = filepath.Clean(fullPathToCommand) + + if err := pathIsAllowed(fullPathToCommand); err != nil { + return nil, fmt.Errorf("path is not allowed: %w", err) + } + + return exec.CommandContext(ctx, fullPathToCommand, arg...), nil +} + +// pathIsAllowed validates the path to the command against our allowlist. +func pathIsAllowed(fullPathToCommand string) error { + cmdName := strings.ToLower(filepath.Base(fullPathToCommand)) + + // We trust the autoupdate libraries to select the correct paths + if cmdName == "launcher" || cmdName == "launcher.exe" || cmdName == "osqueryd" || cmdName == "osqueryd.exe" { + return nil + } + + // Check that we have known paths for the given command + knownCmdPaths, ok := knownPaths[cmdName] + if !ok { + return fmt.Errorf("no known paths for command %s, cannot validate path %s", cmdName, fullPathToCommand) + } + + // Check if this path is registered + if _, ok := knownCmdPaths[fullPathToCommand]; ok { + return nil + } + + // Check to make sure the command is at least in a known directory + for _, knownPathPrefix := range knownPathPrefixes { + if strings.HasPrefix(fullPathToCommand, knownPathPrefix) { + return nil + } + } + + return fmt.Errorf("%s not in known paths and does not have known prefix", fullPathToCommand) +} diff --git a/pkg/allowedpaths/cmd_darwin.go b/pkg/allowedpaths/cmd_darwin.go new file mode 100644 index 000000000..e93889cd3 --- /dev/null +++ b/pkg/allowedpaths/cmd_darwin.go @@ -0,0 +1,81 @@ +//go:build darwin +// +build darwin + +package allowedpaths + +var knownPaths = map[string]map[string]bool{ + "bioutil": { + "/usr/bin/bioutil": true, + }, + "diskutil": { + "/usr/sbin/diskutil": true, + }, + "falconctl": { + "/Applications/Falcon.app/Contents/Resources/falconctl": true, + }, + "firmwarepasswd": { + "/usr/sbin/firmwarepasswd": true, + }, + "ifconfig": { + "/sbin/ifconfig": true, + }, + "launchctl": { + "/bin/launchctl": true, + }, + "lsof": { + "/usr/sbin/lsof": true, + }, + "mdfind": { + "/usr/bin/mdfind": true, + }, + "netstat": { + "/usr/sbin/netstat": true, + }, + "open": { + "/usr/bin/open": true, + }, + "pkgutil": { + "/usr/sbin/pkgutil": true, + }, + "powermetrics": { + "/usr/bin/powermetrics": true, + }, + "profiles": { + "/usr/bin/profiles": true, + }, + "ps": { + "/bin/ps": true, + }, + "pwpolicy": { + "/usr/bin/pwpolicy": true, + }, + "remotectl": { + "/usr/libexec/remotectl": true, + }, + "repcli": { + "/Applications/VMware Carbon Black Cloud/repcli.bundle/Contents/MacOS/repcli": true, + }, + "scutil": { + "/usr/sbin/scutil": true, + }, + "softwareupdate": { + "/usr/sbin/softwareupdate": true, + }, + "system_profiler": { + "/usr/sbin/system_profiler": true, + }, + "tmutil": { + "/usr/bin/tmutil": true, + }, + "zerotier-cli": { + "/usr/local/bin/zerotier-cli": true, + }, +} + +var knownPathPrefixes = []string{ + "/bin", + "/usr/bin", + "/usr/libexec", + "/usr/local/bin", + "/usr/sbin", +} diff --git a/pkg/allowedpaths/cmd_linux.go b/pkg/allowedpaths/cmd_linux.go new file mode 100644 index 000000000..e452c8f9b --- /dev/null +++ b/pkg/allowedpaths/cmd_linux.go @@ -0,0 +1,60 @@ +//go:build linux +// +build linux + +package allowedpaths + +var knownPaths = map[string]map[string]bool{ + "dpkg": { + "/usr/bin/dpkg": true, + }, + "lsof": { + "/usr/bin/lsof": true, + }, + "gnome-extensions": { + "/usr/bin/gnome-extensions": true, + }, + "gsettings": { + "/usr/bin/gsettings": true, + }, + "ifconfig": { + "/usr/sbin/ifconfig": true, + }, + "ip": { + "/usr/sbin/ip": true, + }, + "loginctl": { + "/usr/bin/loginctl": true, + }, + "notify-send": { + "/usr/bin/notify-send": true, + }, + "ps": { + "/usr/bin/ps": true, + }, + "rpm": { + "/bin/rpm": true, + }, + "systemctl": { + "/usr/bin/systemctl": true, + }, + "x-www-browser": { + "/usr/bin/x-www-browser": true, + }, + "xdg-open": { + "/usr/bin/xdg-open": true, + }, + "xrdb": { + "/usr/bin/xrdb": true, + }, + "zerotier-cli": { + "/usr/local/bin/zerotier-cli": true, + }, +} + +var knownPathPrefixes = []string{ + "/bin", + "/nix/store", // NixOS support + "/usr/bin", + "/usr/local/bin", + "/usr/sbin", +} diff --git a/pkg/allowedpaths/cmd_test.go b/pkg/allowedpaths/cmd_test.go new file mode 100644 index 000000000..8dc5b0796 --- /dev/null +++ b/pkg/allowedpaths/cmd_test.go @@ -0,0 +1,201 @@ +package allowedpaths + +import ( + "context" + "path/filepath" + "runtime" + "strings" + "testing" + + "github.com/stretchr/testify/require" +) + +func TestCommandWithLookup(t *testing.T) { + t.Parallel() + + var cmdName string + if runtime.GOOS == "windows" { + cmdName = "powershell.exe" + } else { + // On Linux and Darwin we expect ps to be available, even on the CI runner + cmdName = "ps" + } + + cmd, err := CommandWithLookup(cmdName) + require.NoError(t, err, "expected to find command") + require.True(t, strings.HasSuffix(cmd.Path, cmdName)) +} + +func TestCommandWithLookup_NotFound(t *testing.T) { + t.Parallel() + + cmdName := "some-cmd" + _, err := CommandWithLookup(cmdName) + require.Error(t, err, "should not have found cmd") +} + +func TestCommandWithPath_Allowed(t *testing.T) { + t.Parallel() + + for cmdName, cmdPaths := range knownPaths { + cmdName := cmdName + cmdPaths := cmdPaths + t.Run(cmdName, func(t *testing.T) { + t.Parallel() + + for p := range cmdPaths { + cmd, err := CommandWithPath(p) + require.NoError(t, err, "expected no error with known path") + require.Equal(t, p, cmd.Path) + } + }) + } +} + +func TestCommandWithPath_Denied(t *testing.T) { + t.Parallel() + + // Unknown command + _, err := CommandWithPath(filepath.Join("some", "path", "to", "not-a-real-command")) + require.Error(t, err, "expected unknown command to be denylisted") + + // Known command, unknown path + for cmdName := range knownPaths { + _, err := CommandWithPath(filepath.Join("some", "incorrect", "path", "to", cmdName)) + require.Error(t, err, "expected unknown path to be denylisted") + + // We don't need to perform this same test against every known path + break + } +} + +func TestCommandWithPath_AutoupdatePaths(t *testing.T) { + t.Parallel() + + for _, b := range []string{"launcher", "launcher.exe", "osqueryd", "osqueryd.exe"} { + b := b + t.Run(b, func(t *testing.T) { + t.Parallel() + + autoupdatedBinaryPath := filepath.Join("some", "autoupdate", "path", "to", b) + cmd, err := CommandWithPath(autoupdatedBinaryPath) + require.NoError(t, err, "expected autoupdated binaries to be allowed") + require.Equal(t, autoupdatedBinaryPath, cmd.Path) + }) + } +} + +func TestCommandWithPath_KnownPrefix(t *testing.T) { + t.Parallel() + + for cmdName := range knownPaths { + cmdName := cmdName + t.Run(cmdName, func(t *testing.T) { + t.Parallel() + + for _, p := range knownPathPrefixes { + pathToCmdWithKnownPrefix := filepath.Join(p, cmdName) + cmd, err := CommandWithPath(pathToCmdWithKnownPrefix) + require.NoError(t, err, "expected no error with known command and directory prefix") + require.Equal(t, pathToCmdWithKnownPrefix, cmd.Path) + } + }) + } +} + +func TestCommandContextWithLookup(t *testing.T) { + t.Parallel() + + var cmdName string + if runtime.GOOS == "windows" { + cmdName = "powershell.exe" + } else { + // On Linux and Darwin we expect ps to be available, even on the CI runner + cmdName = "ps" + } + + cmd, err := CommandContextWithLookup(context.TODO(), cmdName) + require.NoError(t, err, "expected to find command") + require.True(t, strings.HasSuffix(cmd.Path, cmdName)) + require.NotNil(t, cmd.Cancel, "context not set on command") +} + +func TestCommandContextWithLookup_NotFound(t *testing.T) { + t.Parallel() + + cmdName := "some-cmd" + _, err := CommandContextWithLookup(context.TODO(), cmdName) + require.Error(t, err, "should not have found cmd") +} + +func TestCommandContextWithPath_Allowed(t *testing.T) { + t.Parallel() + + for cmdName, cmdPaths := range knownPaths { + cmdName := cmdName + cmdPaths := cmdPaths + t.Run(cmdName, func(t *testing.T) { + t.Parallel() + + for p := range cmdPaths { + cmd, err := CommandContextWithPath(context.TODO(), p) + require.NoError(t, err, "expected no error with known path") + require.Equal(t, p, cmd.Path) + require.NotNil(t, cmd.Cancel, "context not set on command") + } + }) + } +} + +func TestCommandContextWithPath_Denied(t *testing.T) { + t.Parallel() + + // Unknown command + _, err := CommandContextWithPath(context.TODO(), filepath.Join("some", "path", "to", "not-a-real-command")) + require.Error(t, err, "expected unknown command to be denylisted") + + // Known command, unknown path + for cmdName := range knownPaths { + _, err := CommandContextWithPath(context.TODO(), filepath.Join("some", "incorrect", "path", "to", cmdName)) + require.Error(t, err, "expected unknown path to be denylisted") + + // We don't need to perform this same test against every known path + break + } +} + +func TestCommandContextWithPath_AutoupdatePaths(t *testing.T) { + t.Parallel() + + for _, b := range []string{"launcher", "launcher.exe", "osqueryd", "osqueryd.exe"} { + b := b + t.Run(b, func(t *testing.T) { + t.Parallel() + + autoupdatedBinaryPath := filepath.Join("some", "autoupdate", "path", "to", b) + cmd, err := CommandContextWithPath(context.TODO(), autoupdatedBinaryPath) + require.NoError(t, err, "expected autoupdated binaries to be allowed") + require.Equal(t, autoupdatedBinaryPath, cmd.Path) + require.NotNil(t, cmd.Cancel, "context not set on command") + }) + } +} + +func TestCommandContextWithPath_KnownPrefix(t *testing.T) { + t.Parallel() + + for cmdName := range knownPaths { + cmdName := cmdName + t.Run(cmdName, func(t *testing.T) { + t.Parallel() + + for _, p := range knownPathPrefixes { + pathToCmdWithKnownPrefix := filepath.Join(p, cmdName) + cmd, err := CommandContextWithPath(context.TODO(), pathToCmdWithKnownPrefix) + require.NoError(t, err, "expected no error with known command and directory prefix") + require.Equal(t, pathToCmdWithKnownPrefix, cmd.Path) + require.NotNil(t, cmd.Cancel, "context not set on command") + } + }) + } +} diff --git a/pkg/allowedpaths/cmd_windows.go b/pkg/allowedpaths/cmd_windows.go new file mode 100644 index 000000000..56e0d250b --- /dev/null +++ b/pkg/allowedpaths/cmd_windows.go @@ -0,0 +1,32 @@ +//go:build windows +// +build windows + +package allowedpaths + +var knownPaths = map[string]map[string]bool{ + "cmd.exe": { + `C:\Windows\System32\cmd.exe`: true, + }, + "dism.exe": { + `C:\Windows\System32\Dism.exe`: true, + }, + "ipconfig.exe": { + `C:\Windows\System32\ipconfig.exe`: true, + }, + "powercfg.exe": { + `C:\Windows\System32\powercfg.exe`: true, + }, + "powershell.exe": { + `C:\Windows\System32\WindowsPowerShell\v1.0\powershell.exe`: true, + }, + "secedit.exe": { + `C:\Windows\System32\SecEdit.exe`: true, + }, + "taskkill.exe": { + `C:\Windows\System32\taskkill.exe`: true, + }, +} + +var knownPathPrefixes = []string{ + `C:\Windows\System32`, +} From 26bbbeebce7c22c54be2679d889d57fc476a784e Mon Sep 17 00:00:00 2001 From: Rebecca Mahany-Horton Date: Tue, 7 Nov 2023 10:47:57 -0500 Subject: [PATCH 02/30] Add linter for use of exec.Command* functions --- .golangci.yml | 5 +++++ pkg/allowedpaths/cmd.go | 4 ++-- 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/.golangci.yml b/.golangci.yml index 63b19c205..03a70916e 100644 --- a/.golangci.yml +++ b/.golangci.yml @@ -15,6 +15,7 @@ linters: - sqlclosecheck - unconvert - paralleltest + - forbidigo disable: - errcheck - gosec @@ -32,6 +33,10 @@ linters-settings: ignore: github.com/go-kit/kit/log:Log gofmt: simplify: false + forbidigo: + forbid: + - p: ^exec\.Command.*$ + msg: use pkg/allowedpaths functions instead issues: exclude-rules: diff --git a/pkg/allowedpaths/cmd.go b/pkg/allowedpaths/cmd.go index c93a58e7a..414ffcc79 100644 --- a/pkg/allowedpaths/cmd.go +++ b/pkg/allowedpaths/cmd.go @@ -28,7 +28,7 @@ func CommandWithPath(fullPathToCommand string, arg ...string) (*exec.Cmd, error) return nil, fmt.Errorf("path is not allowed: %w", err) } - return exec.Command(fullPathToCommand, arg...), nil + return exec.Command(fullPathToCommand, arg...), nil //nolint:forbidigo } // CommandContextWithLookup should be used when the full path to the command is not known and it is @@ -51,7 +51,7 @@ func CommandContextWithPath(ctx context.Context, fullPathToCommand string, arg . return nil, fmt.Errorf("path is not allowed: %w", err) } - return exec.CommandContext(ctx, fullPathToCommand, arg...), nil + return exec.CommandContext(ctx, fullPathToCommand, arg...), nil //nolint:forbidigo } // pathIsAllowed validates the path to the command against our allowlist. From 5f2e0b38d3185d9037f8917a959d4416728bc70a Mon Sep 17 00:00:00 2001 From: Rebecca Mahany-Horton Date: Tue, 7 Nov 2023 13:30:28 -0500 Subject: [PATCH 03/30] Add some missing commands --- pkg/allowedpaths/cmd_darwin.go | 15 +++++++++++++++ pkg/allowedpaths/cmd_linux.go | 16 ++++++++++++++++ 2 files changed, 31 insertions(+) diff --git a/pkg/allowedpaths/cmd_darwin.go b/pkg/allowedpaths/cmd_darwin.go index e93889cd3..eec235e32 100644 --- a/pkg/allowedpaths/cmd_darwin.go +++ b/pkg/allowedpaths/cmd_darwin.go @@ -4,21 +4,33 @@ package allowedpaths var knownPaths = map[string]map[string]bool{ + "airport": { + "/System/Library/PrivateFrameworks/Apple80211.framework/Versions/Current/Resources/airport": true, + }, "bioutil": { "/usr/bin/bioutil": true, }, + "bputil": { + "/usr/bin/bputil": true, + }, "diskutil": { "/usr/sbin/diskutil": true, }, "falconctl": { "/Applications/Falcon.app/Contents/Resources/falconctl": true, }, + "fdsetup": { + "/usr/bin/fdesetup": true, + }, "firmwarepasswd": { "/usr/sbin/firmwarepasswd": true, }, "ifconfig": { "/sbin/ifconfig": true, }, + "ioreg": { + "/usr/sbin/ioreg": true, + }, "launchctl": { "/bin/launchctl": true, }, @@ -28,6 +40,9 @@ var knownPaths = map[string]map[string]bool{ "mdfind": { "/usr/bin/mdfind": true, }, + "mdmclient": { + "/usr/libexec/mdmclient": true, + }, "netstat": { "/usr/sbin/netstat": true, }, diff --git a/pkg/allowedpaths/cmd_linux.go b/pkg/allowedpaths/cmd_linux.go index e452c8f9b..a253d6ffd 100644 --- a/pkg/allowedpaths/cmd_linux.go +++ b/pkg/allowedpaths/cmd_linux.go @@ -4,12 +4,19 @@ package allowedpaths var knownPaths = map[string]map[string]bool{ + "cryptsetup": { + "/usr/sbin/cryptsetup": true, + "/sbin/cryptsetup", true + }, "dpkg": { "/usr/bin/dpkg": true, }, "lsof": { "/usr/bin/lsof": true, }, + "falcon-kernel-check": { + "/opt/CrowdStrike/falcon-kernel-check": true, + }, "gnome-extensions": { "/usr/bin/gnome-extensions": true, }, @@ -25,6 +32,9 @@ var knownPaths = map[string]map[string]bool{ "loginctl": { "/usr/bin/loginctl": true, }, + "mdmclient": { + "/usr/libexec/mdmclient": true, + }, "notify-send": { "/usr/bin/notify-send": true, }, @@ -49,6 +59,12 @@ var knownPaths = map[string]map[string]bool{ "zerotier-cli": { "/usr/local/bin/zerotier-cli": true, }, + "zfs": { + "/usr/sbin/zfs": true, + }, + "zpool": { + "/usr/sbin/zpool": true, + } } var knownPathPrefixes = []string{ From 60dfafa6928f468c04964da52089ee301ddbb79e Mon Sep 17 00:00:00 2001 From: Rebecca Mahany-Horton Date: Tue, 7 Nov 2023 14:40:32 -0500 Subject: [PATCH 04/30] Fix typo --- pkg/allowedpaths/cmd_darwin.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pkg/allowedpaths/cmd_darwin.go b/pkg/allowedpaths/cmd_darwin.go index eec235e32..64001572b 100644 --- a/pkg/allowedpaths/cmd_darwin.go +++ b/pkg/allowedpaths/cmd_darwin.go @@ -19,7 +19,7 @@ var knownPaths = map[string]map[string]bool{ "falconctl": { "/Applications/Falcon.app/Contents/Resources/falconctl": true, }, - "fdsetup": { + "fdesetup": { "/usr/bin/fdesetup": true, }, "firmwarepasswd": { From bf5f04ec7bfe7aa3fee1d53b2a6e1f602a69275f Mon Sep 17 00:00:00 2001 From: Rebecca Mahany-Horton Date: Tue, 7 Nov 2023 15:06:52 -0500 Subject: [PATCH 05/30] Update to use allowedpaths over exec --- cmd/launcher/uninstall_darwin.go | 16 ++++++--- cmd/launcher/uninstall_linux.go | 21 +++++++----- ee/consoleuser/consoleuser_darwin.go | 8 +++-- ee/consoleuser/consoleuser_linux.go | 15 +++++++-- ee/desktop/runner/runner.go | 6 +++- ee/desktop/runner/runner_linux.go | 33 +++++++++++++++++-- ee/desktop/runner/runner_test.go | 3 +- .../user/menu/action_open_url_darwin.go | 11 +++++-- ee/desktop/user/menu/action_open_url_linux.go | 11 +++++-- .../user/menu/action_open_url_windows.go | 10 ++++-- ee/desktop/user/notify/notify_linux.go | 18 +++++----- ee/ui/assets/generator/generator.go | 6 ++-- pkg/autoupdate/findnew.go | 4 ++- pkg/debug/checkups/gnome-extensions.go | 8 +++-- pkg/debug/checkups/launchd.go | 12 +++++-- pkg/debug/checkups/network.go | 8 +++-- pkg/debug/checkups/osquery.go | 12 +++++-- pkg/debug/checkups/power_windows.go | 7 ++-- pkg/debug/checkups/services_windows.go | 7 ++-- pkg/execwrapper/exec_windows.go | 7 ++-- pkg/log/log.go | 29 +++++++++++++--- pkg/make/builder.go | 2 +- pkg/make/builder_test.go | 1 + pkg/osquery/runsimple/osqueryrunner.go | 14 ++++++-- pkg/osquery/runtime/osqueryinstance.go | 4 ++- .../runtime/runtime_helpers_windows.go | 7 +++- pkg/osquery/table/mdfind_darwin.go | 12 ++++--- pkg/osquery/table/mdm.go | 12 +++++-- pkg/osquery/table/platform_tables_darwin.go | 16 ++++----- pkg/osquery/table/touchid_system_darwin.go | 12 +++++-- pkg/osquery/table/touchid_user_darwin.go | 12 ++++--- .../apple_silicon_security_policy/table.go | 3 +- pkg/osquery/tables/cryptsetup/table.go | 7 +--- pkg/osquery/tables/dataflattentable/exec.go | 14 +++++++- .../dsim_default_associations.go | 7 ++-- pkg/osquery/tables/filevault/filevault.go | 4 +-- .../tables/firmwarepasswd/firmwarepasswd.go | 7 ++-- pkg/osquery/tables/gsettings/gsettings.go | 9 ++--- pkg/osquery/tables/gsettings/metadata.go | 7 ++-- pkg/osquery/tables/ioreg/ioreg.go | 4 +-- pkg/osquery/tables/mdmclient/mdmclient.go | 4 +-- pkg/osquery/tables/profiles/profiles.go | 3 +- pkg/osquery/tables/pwpolicy/pwpolicy.go | 11 ++++--- pkg/osquery/tables/pwpolicy/pwpolicy_test.go | 7 ++-- pkg/osquery/tables/secedit/secedit.go | 9 +++-- .../tables/systemprofiler/systemprofiler.go | 9 ++--- pkg/osquery/tables/tablehelpers/exec.go | 20 ++++++++++- .../tablehelpers/exec_osquery_launchctl.go | 7 ++-- pkg/osquery/tables/tablehelpers/exec_test.go | 24 ++------------ .../tables/wifi_networks/wifi_networks.go | 10 +++--- pkg/osquery/tables/xrdb/xrdb.go | 9 ++--- pkg/osquery/tables/zfs/tables.go | 9 ++--- .../applenotarization/applenotarization.go | 1 + .../authenticode/authenticode_test.go | 1 + .../authenticode/authenticode_windows.go | 1 + pkg/packagekit/package_fpm.go | 1 + pkg/packagekit/package_pkg.go | 1 + pkg/packagekit/wix/wix.go | 1 + pkg/packagekit/wix/wix_test.go | 1 + pkg/packaging/packaging.go | 1 + pkg/packaging/packaging_test.go | 1 + pkg/ptycmd/command.go | 7 ++-- 62 files changed, 366 insertions(+), 178 deletions(-) diff --git a/cmd/launcher/uninstall_darwin.go b/cmd/launcher/uninstall_darwin.go index 57567931c..cd2d35fa5 100644 --- a/cmd/launcher/uninstall_darwin.go +++ b/cmd/launcher/uninstall_darwin.go @@ -7,9 +7,10 @@ import ( "context" "fmt" "os" - "os/exec" "strings" "time" + + "github.com/kolide/launcher/pkg/allowedpaths" ) func removeLauncher(ctx context.Context, identifier string) error { @@ -19,12 +20,15 @@ func removeLauncher(ctx context.Context, identifier string) error { } launchDaemonPList := fmt.Sprintf("/Library/LaunchDaemons/com.%s.launcher.plist", identifier) - launchCtlPath := "/bin/launchctl" launchCtlArgs := []string{"unload", launchDaemonPList} launchctlCtx, cancel := context.WithTimeout(ctx, 30*time.Second) defer cancel() - cmd := exec.CommandContext(launchctlCtx, launchCtlPath, launchCtlArgs...) + cmd, err := allowedpaths.CommandContextWithLookup(launchctlCtx, "launchctl", launchCtlArgs...) + if err != nil { + fmt.Printf("could not find launchctl: %s\n", err) + return err + } if out, err := cmd.Output(); err != nil { fmt.Printf("error occurred while unloading launcher daemon, launchctl output %s: err: %s\n", out, err) return err @@ -55,7 +59,11 @@ func removeLauncher(ctx context.Context, identifier string) error { pkgutiltCtx, cancel := context.WithTimeout(ctx, 30*time.Second) defer cancel() - pkgUtilcmd := exec.CommandContext(pkgutiltCtx, "/usr/sbin/pkgutil", "--forget", fmt.Sprintf("com.%s.launcher", identifier)) + pkgUtilcmd, err := allowedpaths.CommandContextWithLookup(pkgutiltCtx, "pkgutil", "--forget", fmt.Sprintf("com.%s.launcher", identifier)) + if err != nil { + fmt.Printf("could not find pkgutil: %s\n", err) + return err + } if out, err := pkgUtilcmd.Output(); err != nil { fmt.Printf("error occurred while forgetting package: output %s: err: %s\n", out, err) diff --git a/cmd/launcher/uninstall_linux.go b/cmd/launcher/uninstall_linux.go index 490ddade9..8ce9041c6 100644 --- a/cmd/launcher/uninstall_linux.go +++ b/cmd/launcher/uninstall_linux.go @@ -5,10 +5,12 @@ package main import ( "context" + "errors" "fmt" "os" - "os/exec" "strings" + + "github.com/kolide/launcher/pkg/allowedpaths" ) func removeLauncher(ctx context.Context, identifier string) error { @@ -21,7 +23,11 @@ func removeLauncher(ctx context.Context, identifier string) error { packageName := fmt.Sprintf("launcher-%s", identifier) // Stop and disable launcher service - cmd := exec.CommandContext(ctx, "systemctl", []string{"disable", "--now", serviceName}...) + cmd, err := allowedpaths.CommandContextWithLookup(ctx, "systemctl", []string{"disable", "--now", serviceName}...) + if err != nil { + fmt.Printf("could not find systemctl: %s\n", err) + return err + } if out, err := cmd.CombinedOutput(); err != nil { // Don't exit. Log and move on to the next uninstall command fmt.Printf("error occurred while stopping/disabling launcher service, systemctl output %s: err: %s\n", string(out), err) @@ -35,19 +41,16 @@ func removeLauncher(ctx context.Context, identifier string) error { } // Tell the appropriate package manager to remove launcher - switch { - case fileExists("/usr/bin/dpkg"): - cmd = exec.CommandContext(ctx, "/usr/bin/dpkg", []string{"--purge", packageName}...) + if cmd, err := allowedpaths.CommandContextWithLookup("dpkg", []string{"--purge", packageName}...); err == nil { if out, err := cmd.CombinedOutput(); err != nil { fmt.Printf("error occurred while running dpkg --purge, output %s: err: %s\n", string(out), err) } - case fileExists("/bin/rpm"): - cmd = exec.CommandContext(ctx, "/bin/rpm", []string{"-e", packageName}...) + } else if cmd, err := allowedpaths.CommandContextWithLookup("rpm", []string{"-e", packageName}...); err == nil { if out, err := cmd.CombinedOutput(); err != nil { fmt.Printf("error occurred while running rpm -e, output %s: err: %s\n", string(out), err) } - default: - return fmt.Errorf("unsupported package manager") + } else { + return errors.New("unsupported package manager") } pathsToRemove := []string{ diff --git a/ee/consoleuser/consoleuser_darwin.go b/ee/consoleuser/consoleuser_darwin.go index 04639aab0..5d97c971a 100644 --- a/ee/consoleuser/consoleuser_darwin.go +++ b/ee/consoleuser/consoleuser_darwin.go @@ -8,9 +8,10 @@ import ( "bytes" "context" "fmt" - "os/exec" "strconv" "strings" + + "github.com/kolide/launcher/pkg/allowedpaths" ) // example scutil output @@ -90,7 +91,10 @@ const ( ) func CurrentUids(ctx context.Context) ([]string, error) { - cmd := exec.CommandContext(ctx, "scutil") + cmd, err := allowedpaths.CommandContextWithLookup(ctx, "scutil") + if err != nil { + return nil, fmt.Errorf("creating scutil command: %w", err) + } cmd.Stdin = strings.NewReader("show State:/Users/ConsoleUser") output, err := cmd.CombinedOutput() diff --git a/ee/consoleuser/consoleuser_linux.go b/ee/consoleuser/consoleuser_linux.go index 325cdb574..dc1a3f948 100644 --- a/ee/consoleuser/consoleuser_linux.go +++ b/ee/consoleuser/consoleuser_linux.go @@ -7,8 +7,9 @@ import ( "context" "encoding/json" "fmt" - "os/exec" "strings" + + "github.com/kolide/launcher/pkg/allowedpaths" ) type listSessionsResult []struct { @@ -18,7 +19,11 @@ type listSessionsResult []struct { } func CurrentUids(ctx context.Context) ([]string, error) { - output, err := exec.CommandContext(ctx, "loginctl", "list-sessions", "--no-legend", "--no-pager", "--output=json").Output() + cmd, err := allowedpaths.CommandContextWithLookup(ctx, "loginctl", "list-sessions", "--no-legend", "--no-pager", "--output=json") + if err != nil { + return nil, fmt.Errorf("creating loginctl command: %w", err) + } + output, err := cmd.Output() if err != nil { return nil, fmt.Errorf("loginctl list-sessions: %w", err) } @@ -42,7 +47,11 @@ func CurrentUids(ctx context.Context) ([]string, error) { } // get the active property of the session, this command does not respect the --output=json flag - output, err := exec.CommandContext(ctx, "loginctl", "show-session", s.Session, "--value", "--property=Active").Output() + cmd, err := allowedpaths.CommandContextWithLookup(ctx, "loginctl", "show-session", s.Session, "--value", "--property=Active") + if err != nil { + return nil, fmt.Errorf("creating loginctl command: %w", err) + } + output, err := cmd.Output() if err != nil { return nil, fmt.Errorf("loginctl show-session (for uid %d): %w", s.UID, err) } diff --git a/ee/desktop/runner/runner.go b/ee/desktop/runner/runner.go index 9c3c30e5d..0bf9acb1f 100644 --- a/ee/desktop/runner/runner.go +++ b/ee/desktop/runner/runner.go @@ -32,6 +32,7 @@ import ( "github.com/kolide/launcher/pkg/agent" "github.com/kolide/launcher/pkg/agent/flags/keys" "github.com/kolide/launcher/pkg/agent/types" + "github.com/kolide/launcher/pkg/allowedpaths" "github.com/kolide/launcher/pkg/backoff" "github.com/kolide/launcher/pkg/traces" "github.com/shirou/gopsutil/v3/process" @@ -755,7 +756,10 @@ func (r *DesktopUsersProcessesRunner) menuTemplatePath() string { // desktopCommand invokes the launcher desktop executable with the appropriate env vars func (r *DesktopUsersProcessesRunner) desktopCommand(executablePath, uid, socketPath, menuPath string) (*exec.Cmd, error) { - cmd := exec.Command(executablePath, "desktop") + cmd, err := allowedpaths.CommandWithPath(executablePath, "desktop") + if err != nil { + return nil, fmt.Errorf("creating command: %w", err) + } cmd.Env = []string{ // When we set cmd.Env (as we're doing here/below), cmd will no longer include the default cmd.Environ() diff --git a/ee/desktop/runner/runner_linux.go b/ee/desktop/runner/runner_linux.go index 5373bee14..cd7970342 100644 --- a/ee/desktop/runner/runner_linux.go +++ b/ee/desktop/runner/runner_linux.go @@ -16,6 +16,7 @@ import ( "syscall" "github.com/go-kit/kit/log/level" + "github.com/kolide/launcher/pkg/allowedpaths" "github.com/kolide/launcher/pkg/traces" "github.com/shirou/gopsutil/v3/process" ) @@ -90,7 +91,16 @@ func (r *DesktopUsersProcessesRunner) userEnvVars(ctx context.Context, uid strin } // Get the user's session so we can get their display (needed for opening notification action URLs in browser) - sessionOutput, err := exec.CommandContext(ctx, "loginctl", "show-user", uid, "--value", "--property=Sessions").Output() + cmd, err := allowedpaths.CommandContextWithLookup(ctx, "loginctl", "show-user", uid, "--value", "--property=Sessions") + if err != nil { + level.Debug(r.logger).Log( + "msg", "could not create loginctl command", + "uid", uid, + "err", err, + ) + return envVars + } + sessionOutput, err := cmd.Output() if err != nil { level.Debug(r.logger).Log( "msg", "could not get user session", @@ -108,7 +118,16 @@ func (r *DesktopUsersProcessesRunner) userEnvVars(ctx context.Context, uid strin sessionList := strings.Split(sessions, " ") for _, session := range sessionList { // Figure out what type of graphical session the user has -- x11, wayland? - typeOutput, err := exec.CommandContext(ctx, "loginctl", "show-session", session, "--value", "--property=Type").Output() + cmd, err := allowedpaths.CommandContextWithLookup(ctx, "loginctl", "show-session", session, "--value", "--property=Type") + if err != nil { + level.Debug(r.logger).Log( + "msg", "could not create loginctl command to get session type", + "uid", uid, + "err", err, + ) + continue + } + typeOutput, err := cmd.Output() if err != nil { level.Debug(r.logger).Log( "msg", "could not get session type", @@ -150,7 +169,15 @@ func (r *DesktopUsersProcessesRunner) userEnvVars(ctx context.Context, uid strin func (r *DesktopUsersProcessesRunner) displayFromX11(ctx context.Context, session string) string { // We can read $DISPLAY from the session properties - xDisplayOutput, err := exec.CommandContext(ctx, "loginctl", "show-session", session, "--value", "--property=Display").Output() + cmd, err := allowedpaths.CommandContextWithLookup(ctx, "loginctl", "show-session", session, "--value", "--property=Display") + if err != nil { + level.Debug(r.logger).Log( + "msg", "could not create command to get Display from user session", + "err", err, + ) + return defaultDisplay + } + xDisplayOutput, err := cmd.Output() if err != nil { level.Debug(r.logger).Log( "msg", "could not get Display from user session", diff --git a/ee/desktop/runner/runner_test.go b/ee/desktop/runner/runner_test.go index 2b934cb04..338179dd6 100644 --- a/ee/desktop/runner/runner_test.go +++ b/ee/desktop/runner/runner_test.go @@ -1,3 +1,4 @@ +//nolint:forbidigo package runner import ( @@ -33,7 +34,7 @@ func TestDesktopUserProcessRunner_Execute(t *testing.T) { // CPU consumption go way up. // To get around the issue mentioned above, build the binary first and set its path as the executable path on the runner. - executablePath := filepath.Join(t.TempDir(), "desktop-test") + executablePath := filepath.Join(t.TempDir(), "desktop-test", "launcher") if runtime.GOOS == "windows" { executablePath = fmt.Sprintf("%s.exe", executablePath) diff --git a/ee/desktop/user/menu/action_open_url_darwin.go b/ee/desktop/user/menu/action_open_url_darwin.go index 5ccb2c219..bf8e3cf7c 100644 --- a/ee/desktop/user/menu/action_open_url_darwin.go +++ b/ee/desktop/user/menu/action_open_url_darwin.go @@ -4,11 +4,18 @@ package menu import ( - "os/exec" + "fmt" + + "github.com/kolide/launcher/pkg/allowedpaths" ) // open opens the specified URL in the default browser of the user // See https://stackoverflow.com/a/39324149/1705598 func open(url string) error { - return exec.Command("/usr/bin/open", url).Start() + cmd, err := allowedpaths.CommandWithLookup("open", url) + if err != nil { + return fmt.Errorf("creating command: %w", err) + } + + return cmd.Start() } diff --git a/ee/desktop/user/menu/action_open_url_linux.go b/ee/desktop/user/menu/action_open_url_linux.go index 813bf5ab3..8f5e78f13 100644 --- a/ee/desktop/user/menu/action_open_url_linux.go +++ b/ee/desktop/user/menu/action_open_url_linux.go @@ -4,11 +4,18 @@ package menu import ( - "os/exec" + "fmt" + + "github.com/kolide/launcher/pkg/allowedpaths" ) // open opens the specified URL in the default browser of the user // See https://stackoverflow.com/a/39324149/1705598 func open(url string) error { - return exec.Command("xdg-open", url).Start() + cmd, err := allowedpaths.CommandWithLookup("xdg-open", url) + if err != nil { + return fmt.Errorf("creating command: %w", err) + } + + return cmd.Start() } diff --git a/ee/desktop/user/menu/action_open_url_windows.go b/ee/desktop/user/menu/action_open_url_windows.go index 0fb31cd6c..a677507d0 100644 --- a/ee/desktop/user/menu/action_open_url_windows.go +++ b/ee/desktop/user/menu/action_open_url_windows.go @@ -4,14 +4,20 @@ package menu import ( - "os/exec" + "fmt" "syscall" + + "github.com/kolide/launcher/pkg/allowedpaths" ) // open opens the specified URL in the default browser of the user // See https://stackoverflow.com/a/39324149/1705598 func open(url string) error { - cmd := exec.Command("cmd", "/C", "start", url) + cmd, err := allowedpaths.CommandWithLookup("cmd.exe", "/C", "start", url) + if err != nil { + return fmt.Errorf("creating command: %w", err) + } + // https://stackoverflow.com/questions/42500570/how-to-hide-command-prompt-window-when-using-exec-in-golang // Otherwise the cmd window will appear briefly cmd.SysProcAttr = &syscall.SysProcAttr{HideWindow: true} diff --git a/ee/desktop/user/notify/notify_linux.go b/ee/desktop/user/notify/notify_linux.go index 946b3cf73..50cf88c4d 100644 --- a/ee/desktop/user/notify/notify_linux.go +++ b/ee/desktop/user/notify/notify_linux.go @@ -6,7 +6,6 @@ package notify import ( "context" "fmt" - "os/exec" "sync" "time" @@ -89,7 +88,11 @@ func (d *dbusNotifier) Listen() error { for _, browserLauncher := range browserLaunchers { ctx, cancel := context.WithTimeout(context.Background(), time.Second*5) defer cancel() - cmd := exec.CommandContext(ctx, browserLauncher, actionUri) + cmd, err := allowedpaths.CommandContextWithLookup(ctx, browserLauncher, actionUri) + if err != nil { + level.Warn(d.logger).Log("msg", "couldn't create command to start process", "err", err, "browser_launcher", browserLauncher) + continue + } if err := cmd.Start(); err != nil { level.Error(d.logger).Log("msg", "couldn't start process", "err", err, "browser_launcher", browserLauncher) } else { @@ -166,12 +169,6 @@ func (d *dbusNotifier) sendNotificationViaDbus(n Notification) error { } func (d *dbusNotifier) sendNotificationViaNotifySend(n Notification) error { - notifySend, err := exec.LookPath("notify-send") - if err != nil { - level.Debug(d.logger).Log("msg", "notify-send not installed", "err", err) - return fmt.Errorf("notify-send not installed: %w", err) - } - // notify-send doesn't support actions, but URLs in notifications are clickable in at least // some desktop environments. if n.ActionUri != "" { @@ -183,7 +180,10 @@ func (d *dbusNotifier) sendNotificationViaNotifySend(n Notification) error { args = append(args, "-i", d.iconFilepath) } - cmd := exec.Command(notifySend, args...) + cmd, err := allowedpaths.Command("notify-send", args...) + if err != nil { + return fmt.Errorf("creating command: %w", err) + } if out, err := cmd.CombinedOutput(); err != nil { level.Error(d.logger).Log("msg", "could not send notification via notify-send", "output", string(out), "err", err) return fmt.Errorf("could not send notification via notify-send: %s: %w", string(out), err) diff --git a/ee/ui/assets/generator/generator.go b/ee/ui/assets/generator/generator.go index 250898b3a..4f531a647 100644 --- a/ee/ui/assets/generator/generator.go +++ b/ee/ui/assets/generator/generator.go @@ -152,7 +152,7 @@ func generatePng(ctx context.Context, logger log.Logger, name string) error { } // Scaling these doesn't seem to be a win for space or resolution. So leave them as is - cmd := exec.CommandContext(ctx, "cp", input, output) + cmd := exec.CommandContext(ctx, "cp", input, output) //nolint:forbidigo if err := cmd.Run(); err != nil { return fmt.Errorf("copy: %w", err) } @@ -178,7 +178,7 @@ func generateIco(ctx context.Context, logger log.Logger, name string) error { // First, we need to generate all the sizes for _, size := range icoSizes { - cmd := exec.CommandContext( + cmd := exec.CommandContext( //nolint:forbidigo ctx, "convert", "-resize", fmt.Sprintf("%sx%s", size, size), @@ -192,7 +192,7 @@ func generateIco(ctx context.Context, logger log.Logger, name string) error { } // Now that we have the intermediary sizes, we can stich them into a single ico - cmd := exec.CommandContext(ctx, "convert", fmt.Sprintf("%s/%s-*.ico", tmpDir, name), output) + cmd := exec.CommandContext(ctx, "convert", fmt.Sprintf("%s/%s-*.ico", tmpDir, name), output) // nolint:forbidigo level.Debug(logger).Log("msg", "Consolodating ico with", "cmd", cmd.String()) if err := cmd.Run(); err != nil { diff --git a/pkg/autoupdate/findnew.go b/pkg/autoupdate/findnew.go index 34909504e..e5a91a539 100644 --- a/pkg/autoupdate/findnew.go +++ b/pkg/autoupdate/findnew.go @@ -371,7 +371,9 @@ func CheckExecutable(ctx context.Context, potentialBinary string, args ...string ctx, cancel := context.WithTimeout(ctx, 5*time.Second) defer cancel() - cmd := exec.CommandContext(ctx, potentialBinary, args...) + // Since we trust the autoupdate library to find binaries in the correct location, + // we don't require the use of allowedpaths.CommandContextWithPath here. + cmd := exec.CommandContext(ctx, potentialBinary, args...) //nolint:forbidigo // Set env, this should prevent launcher for fork-bombing cmd.Env = append(cmd.Env, "LAUNCHER_SKIP_UPDATES=TRUE") diff --git a/pkg/debug/checkups/gnome-extensions.go b/pkg/debug/checkups/gnome-extensions.go index 17b9a9d11..cccd0b4a0 100644 --- a/pkg/debug/checkups/gnome-extensions.go +++ b/pkg/debug/checkups/gnome-extensions.go @@ -6,11 +6,12 @@ import ( "fmt" "io" "os" - "os/exec" "path/filepath" "runtime" "strings" "time" + + "github.com/kolide/launcher/pkg/allowedpaths" ) type gnomeExtensions struct { @@ -94,7 +95,10 @@ func execGnomeExtension(ctx context.Context, extraWriter io.Writer, rundir strin // pkg/osquery/tables/gsettings/gsettings.go probably has appropriate prior art. // But do we really want the forloop? - cmd := exec.CommandContext(ctx, "/usr/bin/gnome-extensions", args...) + cmd, err := allowedpaths.CommandContextWithLookup(ctx, "gnome-extensions", args...) + if err != nil { + return nil, fmt.Errorf("creating gnome-extensions command: %w", err) + } // gnome seems to do things through this env cmd.Env = append(cmd.Env, fmt.Sprintf("XDG_RUNTIME_DIR=%s", rundir)) diff --git a/pkg/debug/checkups/launchd.go b/pkg/debug/checkups/launchd.go index 4cd6c1b08..1a5f0fb9c 100644 --- a/pkg/debug/checkups/launchd.go +++ b/pkg/debug/checkups/launchd.go @@ -7,10 +7,11 @@ import ( "fmt" "io" "os" - "os/exec" "path/filepath" "runtime" "strings" + + "github.com/kolide/launcher/pkg/allowedpaths" ) const ( @@ -59,13 +60,18 @@ func (c *launchdCheckup) Run(ctx context.Context, extraWriter io.Writer) error { c.status = Erroring c.summary = fmt.Sprintf("unable to write extra information: %s", err) return nil - } // run launchctl to check status var printOut bytes.Buffer - cmd := exec.CommandContext(ctx, "/bin/launchctl", "print", launchdServiceName) + cmd, err := allowedpaths.CommandContextWithLookup(ctx, "launchctl", "print", launchdServiceName) + if err != nil { + c.status = Erroring + c.summary = fmt.Sprintf("unable to create launchctl command: %s", err) + return nil + } + cmd.Stdout = &printOut cmd.Stderr = &printOut if err := cmd.Run(); err != nil { diff --git a/pkg/debug/checkups/network.go b/pkg/debug/checkups/network.go index a0c546c1e..bdeff67f2 100644 --- a/pkg/debug/checkups/network.go +++ b/pkg/debug/checkups/network.go @@ -6,9 +6,10 @@ import ( "fmt" "io" "net" - "os/exec" "runtime" "time" + + "github.com/kolide/launcher/pkg/allowedpaths" ) type networkCheckup struct { @@ -55,7 +56,10 @@ func (n *networkCheckup) Run(ctx context.Context, extraWriter io.Writer) error { ctx, cancel := context.WithTimeout(ctx, 5*time.Second) defer cancel() - cmd := exec.CommandContext(ctx, commandArr[0], commandArr[1:]...) + cmd, err := allowedpaths.CommandContextWithLookup(ctx, commandArr[0], commandArr[1:]...) + if err != nil { + continue + } _ = runCmdMarkdownLogged(cmd, commandOutput) } diff --git a/pkg/debug/checkups/osquery.go b/pkg/debug/checkups/osquery.go index 20a49330b..eb23b7f66 100644 --- a/pkg/debug/checkups/osquery.go +++ b/pkg/debug/checkups/osquery.go @@ -4,12 +4,12 @@ import ( "context" "fmt" "io" - "os/exec" "runtime" "strings" "time" "github.com/kolide/launcher/pkg/agent/types" + "github.com/kolide/launcher/pkg/allowedpaths" ) type osqueryCheckup struct { @@ -48,7 +48,10 @@ func (o *osqueryCheckup) version(ctx context.Context) (string, error) { cmdCtx, cmdCancel := context.WithTimeout(ctx, 10*time.Second) defer cmdCancel() - cmd := exec.CommandContext(cmdCtx, osquerydPath, "--version") + cmd, err := allowedpaths.CommandContextWithPath(cmdCtx, osquerydPath, "--version") + if err != nil { + return "", fmt.Errorf("creating osqueryd command: %w", err) + } hideWindow(cmd) startTime := time.Now().UnixMilli() out, err := cmd.CombinedOutput() @@ -72,7 +75,10 @@ func (o *osqueryCheckup) interactive(ctx context.Context) error { cmdCtx, cmdCancel := context.WithTimeout(ctx, 20*time.Second) defer cmdCancel() - cmd := exec.CommandContext(cmdCtx, launcherPath, "interactive") + cmd, err := allowedpaths.CommandContextWithPath(cmdCtx, launcherPath, "interactive") + if err != nil { + return fmt.Errorf("creating launcher command: %w", err) + } hideWindow(cmd) cmd.Stdin = strings.NewReader(`select * from osquery_info;`) diff --git a/pkg/debug/checkups/power_windows.go b/pkg/debug/checkups/power_windows.go index c63ab1ce7..111ceb8ee 100644 --- a/pkg/debug/checkups/power_windows.go +++ b/pkg/debug/checkups/power_windows.go @@ -8,9 +8,9 @@ import ( "fmt" "io" "os" - "os/exec" "github.com/kolide/launcher/pkg/agent" + "github.com/kolide/launcher/pkg/allowedpaths" ) type powerCheckup struct{} @@ -25,7 +25,10 @@ func (p *powerCheckup) Run(ctx context.Context, extraWriter io.Writer) error { defer os.Remove(tmpFilePath) // See: https://learn.microsoft.com/en-us/windows-hardware/design/device-experiences/powercfg-command-line-options#option_systempowerreport - powerCfgCmd := exec.CommandContext(ctx, "powercfg.exe", "/systempowerreport", "/output", tmpFilePath) + powerCfgCmd, err := allowedpaths.CommandContextWithLookup(ctx, "powercfg.exe", "/systempowerreport", "/output", tmpFilePath) + if err != nil { + return fmt.Errorf("creating powercfg command: %w", err) + } hideWindow(powerCfgCmd) if out, err := powerCfgCmd.CombinedOutput(); err != nil { return fmt.Errorf("running powercfg.exe: error %w, output %s", err, string(out)) diff --git a/pkg/debug/checkups/services_windows.go b/pkg/debug/checkups/services_windows.go index ea5b8c7fc..69c52cd8b 100644 --- a/pkg/debug/checkups/services_windows.go +++ b/pkg/debug/checkups/services_windows.go @@ -9,8 +9,8 @@ import ( "encoding/json" "fmt" "io" - "os/exec" + "github.com/kolide/launcher/pkg/allowedpaths" "golang.org/x/sys/windows" "golang.org/x/sys/windows/svc" "golang.org/x/sys/windows/svc/mgr" @@ -244,7 +244,10 @@ func gatherServiceManagerEventLogs(ctx context.Context, z *zip.Writer) error { "Format-Table", "-Wrap", "-AutoSize", // ensure output doesn't get truncated } - getEventLogCmd := exec.CommandContext(ctx, "powershell.exe", cmdletArgs...) + getEventLogCmd, err := allowedpaths.CommandContextWithLookup(ctx, "powershell.exe", cmdletArgs...) + if err != nil { + return fmt.Errorf("creating powershell command: %w", err) + } hideWindow(getEventLogCmd) getEventLogCmd.Stdout = eventLogOut // write directly to zip if err := getEventLogCmd.Run(); err != nil { diff --git a/pkg/execwrapper/exec_windows.go b/pkg/execwrapper/exec_windows.go index bbb273527..a6916866f 100644 --- a/pkg/execwrapper/exec_windows.go +++ b/pkg/execwrapper/exec_windows.go @@ -8,18 +8,21 @@ import ( "errors" "fmt" "os" - "os/exec" "strings" "github.com/go-kit/kit/log" "github.com/go-kit/kit/log/level" + "github.com/kolide/launcher/pkg/allowedpaths" "github.com/kolide/launcher/pkg/contexts/ctxlog" ) func Exec(ctx context.Context, argv0 string, argv []string, envv []string) error { logger := log.With(ctxlog.FromContext(ctx), "caller", log.DefaultCaller) - cmd := exec.CommandContext(ctx, argv0, argv[1:]...) + cmd, err := allowedpaths.CommandContextWithPath(ctx, argv0, argv[1:]...) + if err != nil { + return fmt.Errorf("creating command: %w", err) + } cmd.Env = envv cmd.Stdin = os.Stdin diff --git a/pkg/log/log.go b/pkg/log/log.go index 7caec0ccd..b580619ae 100644 --- a/pkg/log/log.go +++ b/pkg/log/log.go @@ -5,7 +5,6 @@ import ( "context" "fmt" "os" - "os/exec" "path/filepath" "regexp" "runtime" @@ -15,6 +14,7 @@ import ( kitlog "github.com/go-kit/kit/log" "github.com/go-kit/kit/log/level" + "github.com/kolide/launcher/pkg/allowedpaths" "github.com/shirou/gopsutil/v3/host" "github.com/shirou/gopsutil/v3/process" ) @@ -169,7 +169,14 @@ func (l *OsqueryLogAdapter) runAndLogPs(pidStr string) { ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second) defer cancel() - cmd := exec.CommandContext(ctx, "ps", "-p", pidStr, "-o", "user,pid,ppid,pgid,stat,time,command") + cmd, err := allowedpaths.CommandContextWithLookup(ctx, "ps", "-p", pidStr, "-o", "user,pid,ppid,pgid,stat,time,command") + if err != nil { + level.Debug(l.logger).Log( + "msg", "error creating command to run ps on osqueryd pidfile", + "err", err, + ) + return + } out, err := cmd.CombinedOutput() if err != nil { level.Debug(l.logger).Log( @@ -196,7 +203,14 @@ func (l *OsqueryLogAdapter) runAndLogLsofByPID(pidStr string) { ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second) defer cancel() - cmd := exec.CommandContext(ctx, "lsof", "-R", "-n", "-p", pidStr) + cmd, err := allowedpaths.CommandContextWithLookup(ctx, "lsof", "-R", "-n", "-p", pidStr) + if err != nil { + level.Debug(l.logger).Log( + "msg", "error creating command to run lsof on osqueryd pidfile", + "err", err, + ) + return + } out, err := cmd.CombinedOutput() if err != nil { level.Debug(l.logger).Log( @@ -226,7 +240,14 @@ func (l *OsqueryLogAdapter) runAndLogLsofOnPidfile() { ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second) defer cancel() - cmd := exec.CommandContext(ctx, "lsof", "-R", "-n", fullPidfile) + cmd, err := allowedpaths.CommandContextWithLookup(ctx, "lsof", "-R", "-n", fullPidfile) + if err != nil { + level.Debug(l.logger).Log( + "msg", "error creating command to run lsof on osqueryd pidfile", + "err", err, + ) + return + } out, err := cmd.CombinedOutput() if err != nil { level.Debug(l.logger).Log( diff --git a/pkg/make/builder.go b/pkg/make/builder.go index c71adf073..352e3475f 100644 --- a/pkg/make/builder.go +++ b/pkg/make/builder.go @@ -5,7 +5,7 @@ We used to do this with gnumake rules, but as we added windows compatibility, we found make too limiting. Moving this into go allows us to write cleaner cross-platform code. */ - +//nolint:forbidigo package make import ( diff --git a/pkg/make/builder_test.go b/pkg/make/builder_test.go index 987732243..12f5d33e8 100644 --- a/pkg/make/builder_test.go +++ b/pkg/make/builder_test.go @@ -1,3 +1,4 @@ +//nolint:forbidigo package make import ( diff --git a/pkg/osquery/runsimple/osqueryrunner.go b/pkg/osquery/runsimple/osqueryrunner.go index e409d85f9..8d02333bf 100644 --- a/pkg/osquery/runsimple/osqueryrunner.go +++ b/pkg/osquery/runsimple/osqueryrunner.go @@ -6,9 +6,11 @@ package runsimple import ( "bytes" "context" + "fmt" "io" - "os/exec" "runtime" + + "github.com/kolide/launcher/pkg/allowedpaths" ) // osqueryProcess is a very simple osquery runtime manager. It's designed to start and stop osquery. It has @@ -88,7 +90,10 @@ func (p osqueryProcess) RunSql(ctx context.Context, sql []byte) error { p.stdin = bytes.NewReader(sql) - cmd := exec.CommandContext(ctx, p.osquerydPath, args...) + cmd, err := allowedpaths.CommandContextWithPath(ctx, p.osquerydPath, args...) + if err != nil { + return fmt.Errorf("creating osqueryd command: %w", err) + } // It's okay for these to be nil, so we can just set them without checking. cmd.Stdin = p.stdin @@ -103,7 +108,10 @@ func (p osqueryProcess) RunVersion(ctx context.Context) error { "--version", } - cmd := exec.CommandContext(ctx, p.osquerydPath, args...) + cmd, err := allowedpaths.CommandContextWithPath(ctx, p.osquerydPath, args...) + if err != nil { + return fmt.Errorf("creating osqueryd command: %w", err) + } // It's okay for these to be nil, so we can just set them without checking. cmd.Stdin = p.stdin diff --git a/pkg/osquery/runtime/osqueryinstance.go b/pkg/osquery/runtime/osqueryinstance.go index b7ebb6f5b..eb6349ad2 100644 --- a/pkg/osquery/runtime/osqueryinstance.go +++ b/pkg/osquery/runtime/osqueryinstance.go @@ -480,7 +480,9 @@ func (opts *osqueryOptions) createOsquerydCommand(osquerydBinary string, paths * if !opts.enableWatchdog { args = append(args, "--disable_watchdog") } - cmd := exec.Command( + // Since we trust the autoupdate library to find binaries in the correct location, + // we don't require the use of allowedpaths.CommandContextWithPath here. + cmd := exec.Command( //nolint:forbidigo osquerydBinary, args..., ) diff --git a/pkg/osquery/runtime/runtime_helpers_windows.go b/pkg/osquery/runtime/runtime_helpers_windows.go index 4a4ffb18e..5cefe65eb 100644 --- a/pkg/osquery/runtime/runtime_helpers_windows.go +++ b/pkg/osquery/runtime/runtime_helpers_windows.go @@ -9,6 +9,7 @@ import ( "syscall" "github.com/kolide/kit/ulid" + "github.com/kolide/launcher/pkg/allowedpaths" "github.com/pkg/errors" ) @@ -21,7 +22,11 @@ func setpgid() *syscall.SysProcAttr { func killProcessGroup(cmd *exec.Cmd) error { // some discussion here https://github.com/golang/dep/pull/857 // TODO: should we check err? - exec.Command("taskkill", "/F", "/T", "/PID", fmt.Sprint(cmd.Process.Pid)).Run() + cmd, err := allowedpaths.CommandWithLookup("taskkill.exe", "/F", "/T", "/PID", fmt.Sprint(cmd.Process.Pid)) + if err != nil { + return fmt.Errorf("creating command: %w", err) + } + cmd.Run() return nil } diff --git a/pkg/osquery/table/mdfind_darwin.go b/pkg/osquery/table/mdfind_darwin.go index bd8811b7d..c12ec7b99 100644 --- a/pkg/osquery/table/mdfind_darwin.go +++ b/pkg/osquery/table/mdfind_darwin.go @@ -7,18 +7,22 @@ import ( "bufio" "bytes" "context" + "fmt" "io" - "os/exec" "time" + + "github.com/kolide/launcher/pkg/allowedpaths" ) func mdfind(args ...string) ([]string, error) { ctx, cancel := context.WithTimeout(context.Background(), 60*time.Second) defer cancel() - path := "/usr/bin/mdfind" - - out, err := exec.CommandContext(ctx, path, args...).Output() + cmd, err := allowedpaths.CommandContextWithLookup(ctx, "mdfind", args...) + if err != nil { + return nil, fmt.Errorf("creating mdfind command: %w", err) + } + out, err := cmd.Output() if err != nil { return nil, err } diff --git a/pkg/osquery/table/mdm.go b/pkg/osquery/table/mdm.go index d5dec77f1..380a83fa0 100644 --- a/pkg/osquery/table/mdm.go +++ b/pkg/osquery/table/mdm.go @@ -4,12 +4,12 @@ import ( "bytes" "context" "fmt" - "os/exec" "strconv" "time" "github.com/go-kit/kit/log" "github.com/groob/plist" + "github.com/kolide/launcher/pkg/allowedpaths" "github.com/osquery/osquery-go/plugin/table" ) @@ -89,7 +89,10 @@ func getMDMProfile(ctx context.Context) (*profilesOutput, error) { ctx, cancel := context.WithTimeout(ctx, 10*time.Second) defer cancel() - cmd := exec.CommandContext(ctx, "/usr/bin/profiles", "-L", "-o", "stdout-xml") + cmd, err := allowedpaths.CommandContextWithLookup(ctx, "profiles", "-L", "-o", "stdout-xml") + if err != nil { + return nil, fmt.Errorf("creating profiles command: %w", err) + } out, err := cmd.Output() if err != nil { return nil, fmt.Errorf("calling /usr/bin/profiles to get MDM profile payload: %w", err) @@ -132,7 +135,10 @@ func getMDMProfileStatus(ctx context.Context) (profileStatus, error) { ctx, cancel := context.WithTimeout(ctx, 10*time.Second) defer cancel() - cmd := exec.CommandContext(ctx, "/usr/bin/profiles", "status", "-type", "enrollment") + cmd, err := allowedpaths.CommandContextWithLookup(ctx, "profiles", "status", "-type", "enrollment") + if err != nil { + return profileStatus{}, fmt.Errorf("creating profiles command: %w", err) + } out, err := cmd.Output() if err != nil { return profileStatus{}, fmt.Errorf("calling /usr/bin/profiles to get MDM profile status: %w", err) diff --git a/pkg/osquery/table/platform_tables_darwin.go b/pkg/osquery/table/platform_tables_darwin.go index fd618527e..88174a6e3 100644 --- a/pkg/osquery/table/platform_tables_darwin.go +++ b/pkg/osquery/table/platform_tables_darwin.go @@ -99,25 +99,25 @@ func platformTables(logger log.Logger, currentOsquerydBinaryPath string) []osque apple_silicon_security_policy.TablePlugin(logger), legacyexec.TablePlugin(), dataflattentable.TablePluginExec(logger, - "kolide_diskutil_list", dataflattentable.PlistType, []string{"/usr/sbin/diskutil", "list", "-plist"}), + "kolide_diskutil_list", dataflattentable.PlistType, []string{"diskutil", "list", "-plist"}), dataflattentable.TablePluginExec(logger, "kolide_falconctl_stats", dataflattentable.PlistType, []string{"/Applications/Falcon.app/Contents/Resources/falconctl", "stats", "-p"}), dataflattentable.TablePluginExec(logger, - "kolide_apfs_list", dataflattentable.PlistType, []string{"/usr/sbin/diskutil", "apfs", "list", "-plist"}), + "kolide_apfs_list", dataflattentable.PlistType, []string{"diskutil", "apfs", "list", "-plist"}), dataflattentable.TablePluginExec(logger, - "kolide_apfs_users", dataflattentable.PlistType, []string{"/usr/sbin/diskutil", "apfs", "listUsers", "/", "-plist"}), + "kolide_apfs_users", dataflattentable.PlistType, []string{"diskutil", "apfs", "listUsers", "/", "-plist"}), dataflattentable.TablePluginExec(logger, - "kolide_tmutil_destinationinfo", dataflattentable.PlistType, []string{"/usr/bin/tmutil", "destinationinfo", "-X"}), + "kolide_tmutil_destinationinfo", dataflattentable.PlistType, []string{"tmutil", "destinationinfo", "-X"}), dataflattentable.TablePluginExec(logger, - "kolide_powermetrics", dataflattentable.PlistType, []string{"/usr/bin/powermetrics", "-n", "1", "-f", "plist"}), + "kolide_powermetrics", dataflattentable.PlistType, []string{"powermetrics", "-n", "1", "-f", "plist"}), screenlockTable, pwpolicy.TablePlugin(logger), systemprofiler.TablePlugin(logger), munki.ManagedInstalls(logger), munki.MunkiReport(logger), - dataflattentable.NewExecAndParseTable(logger, "kolide_remotectl", remotectl.Parser, []string{`/usr/libexec/remotectl`, `dumpstate`}), - dataflattentable.NewExecAndParseTable(logger, "kolide_softwareupdate", softwareupdate.Parser, []string{`/usr/sbin/softwareupdate`, `--list`, `--no-scan`}, dataflattentable.WithIncludeStderr()), - dataflattentable.NewExecAndParseTable(logger, "kolide_softwareupdate_scan", softwareupdate.Parser, []string{`/usr/sbin/softwareupdate`, `--list`}, dataflattentable.WithIncludeStderr()), + dataflattentable.NewExecAndParseTable(logger, "kolide_remotectl", remotectl.Parser, []string{`remotectl`, `dumpstate`}), + dataflattentable.NewExecAndParseTable(logger, "kolide_softwareupdate", softwareupdate.Parser, []string{`softwareupdate`, `--list`, `--no-scan`}, dataflattentable.WithIncludeStderr()), + dataflattentable.NewExecAndParseTable(logger, "kolide_softwareupdate_scan", softwareupdate.Parser, []string{`softwareupdate`, `--list`}, dataflattentable.WithIncludeStderr()), dataflattentable.NewExecAndParseTable(logger, "kolide_carbonblack_repcli_status", repcli.Parser, []string{"/Applications/VMware Carbon Black Cloud/repcli.bundle/Contents/MacOS/repcli", "status"}, dataflattentable.WithIncludeStderr()), } } diff --git a/pkg/osquery/table/touchid_system_darwin.go b/pkg/osquery/table/touchid_system_darwin.go index 93e6ce120..d8ae48fb8 100644 --- a/pkg/osquery/table/touchid_system_darwin.go +++ b/pkg/osquery/table/touchid_system_darwin.go @@ -4,12 +4,12 @@ import ( "bytes" "context" "fmt" - "os/exec" "regexp" "strings" "time" "github.com/go-kit/kit/log" + "github.com/kolide/launcher/pkg/allowedpaths" "github.com/osquery/osquery-go/plugin/table" ) @@ -41,7 +41,10 @@ func (t *touchIDSystemConfigTable) generate(ctx context.Context, queryContext ta // Read the security chip from system_profiler var stdout bytes.Buffer - cmd := exec.CommandContext(ctx, "/usr/sbin/system_profiler", "SPiBridgeDataType") + cmd, err := allowedpaths.CommandContextWithLookup(ctx, "system_profiler", "SPiBridgeDataType") + if err != nil { + return nil, fmt.Errorf("creating system_profiler command: %w", err) + } cmd.Stdout = &stdout if err := cmd.Run(); err != nil { return nil, fmt.Errorf("calling system_profiler: %w", err) @@ -57,7 +60,10 @@ func (t *touchIDSystemConfigTable) generate(ctx context.Context, queryContext ta // Read the system's bioutil configuration stdout.Reset() - cmd = exec.CommandContext(ctx, "/usr/bin/bioutil", "-r", "-s") + cmd, err = allowedpaths.CommandContextWithLookup(ctx, "bioutil", "-r", "-s") + if err != nil { + return nil, fmt.Errorf("creating bioutil command: %w", err) + } cmd.Stdout = &stdout if err := cmd.Run(); err != nil { return nil, fmt.Errorf("calling bioutil for system configuration: %w", err) diff --git a/pkg/osquery/table/touchid_user_darwin.go b/pkg/osquery/table/touchid_user_darwin.go index 99af08515..b3041a431 100644 --- a/pkg/osquery/table/touchid_user_darwin.go +++ b/pkg/osquery/table/touchid_user_darwin.go @@ -4,7 +4,7 @@ import ( "bytes" "context" "errors" - "os/exec" + "fmt" "os/user" "strconv" "strings" @@ -13,6 +13,7 @@ import ( "github.com/go-kit/kit/log" "github.com/go-kit/kit/log/level" + "github.com/kolide/launcher/pkg/allowedpaths" "github.com/osquery/osquery-go/plugin/table" ) @@ -64,7 +65,7 @@ func (t *touchIDUserConfigTable) generate(ctx context.Context, queryContext tabl uid, _ := strconv.Atoi(constraint.Expression) // Get the user's TouchID config - configOutput, err := runCommandContext(ctx, uid, "/usr/bin/bioutil", "-r") + configOutput, err := runCommandContext(ctx, uid, "bioutil", "-r") if err != nil { level.Debug(t.logger).Log( "msg", "could not run bioutil -r", @@ -94,7 +95,7 @@ func (t *touchIDUserConfigTable) generate(ctx context.Context, queryContext tabl } // Grab the fingerprint count - countOutStr, err := runCommandContext(ctx, uid, "/usr/bin/bioutil", "-c") + countOutStr, err := runCommandContext(ctx, uid, "bioutil", "-c") if err != nil { level.Debug(t.logger).Log( "msg", "could not run bioutil -c", @@ -134,7 +135,10 @@ func runCommandContext(ctx context.Context, uid int, cmd string, args ...string) // Set up the command var stdout bytes.Buffer - c := exec.CommandContext(ctx, cmd, args...) + c, err := allowedpaths.CommandContextWithLookup(ctx, cmd, args...) + if err != nil { + return "", fmt.Errorf("creating command: %w", err) + } c.Stdout = &stdout // Check if the supplied UID is that of the current user diff --git a/pkg/osquery/tables/apple_silicon_security_policy/table.go b/pkg/osquery/tables/apple_silicon_security_policy/table.go index 1ca2d67da..13921dba3 100644 --- a/pkg/osquery/tables/apple_silicon_security_policy/table.go +++ b/pkg/osquery/tables/apple_silicon_security_policy/table.go @@ -16,7 +16,6 @@ import ( "github.com/osquery/osquery-go/plugin/table" ) -const bootPolicyUtilPath = "/usr/bin/bputil" const bootPolicyUtilArgs = "--display-all-policies" type Table struct { @@ -38,7 +37,7 @@ func TablePlugin(logger log.Logger) *table.Plugin { func (t *Table) generate(ctx context.Context, queryContext table.QueryContext) ([]map[string]string, error) { var results []map[string]string - output, err := tablehelpers.Exec(ctx, t.logger, 30, []string{bootPolicyUtilPath}, []string{bootPolicyUtilArgs}, false) + output, err := tablehelpers.Exec(ctx, t.logger, 30, []string{"bputil"}, []string{bootPolicyUtilArgs}, false) if err != nil { level.Info(t.logger).Log("msg", "bputil failed", "err", err) return nil, nil diff --git a/pkg/osquery/tables/cryptsetup/table.go b/pkg/osquery/tables/cryptsetup/table.go index 05bd01dcc..f5a9c7721 100644 --- a/pkg/osquery/tables/cryptsetup/table.go +++ b/pkg/osquery/tables/cryptsetup/table.go @@ -13,11 +13,6 @@ import ( "github.com/osquery/osquery-go/plugin/table" ) -var cryptsetupPaths = []string{ - "/usr/sbin/cryptsetup", - "/sbin/cryptsetup", -} - const allowedNameCharacters = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789-/_" type Table struct { @@ -51,7 +46,7 @@ func (t *Table) generate(ctx context.Context, queryContext table.QueryContext) ( } for _, name := range requestedNames { - output, err := tablehelpers.Exec(ctx, t.logger, 15, cryptsetupPaths, []string{"--readonly", "status", name}, false) + output, err := tablehelpers.Exec(ctx, t.logger, 15, []string{"cryptsetup"}, []string{"--readonly", "status", name}, false) if err != nil { level.Debug(t.logger).Log("msg", "Error execing for status", "name", name, "err", err) continue diff --git a/pkg/osquery/tables/dataflattentable/exec.go b/pkg/osquery/tables/dataflattentable/exec.go index f270f759d..5826f5e3d 100644 --- a/pkg/osquery/tables/dataflattentable/exec.go +++ b/pkg/osquery/tables/dataflattentable/exec.go @@ -13,6 +13,7 @@ import ( "github.com/go-kit/kit/log" "github.com/go-kit/kit/log/level" + "github.com/kolide/launcher/pkg/allowedpaths" "github.com/kolide/launcher/pkg/dataflatten" "github.com/kolide/launcher/pkg/osquery/tables/tablehelpers" "github.com/osquery/osquery-go/plugin/table" @@ -117,7 +118,18 @@ func (t *Table) exec(ctx context.Context) ([]byte, error) { var stdout bytes.Buffer var stderr bytes.Buffer - cmd := exec.CommandContext(ctx, execPath, t.execArgs[1:]...) + var cmd *exec.Cmd + var err error + if execPath == filepath.Base(execPath) { + cmd, err = allowedpaths.CommandContextWithLookup(ctx, execPath, t.execArgs[1:]...) + } else { + cmd, err = allowedpaths.CommandContextWithPath(ctx, execPath, t.execArgs[1:]...) + } + if err != nil { + // Binary that the binary was not found, try the next one + continue + } + cmd.Stdout = &stdout cmd.Stderr = &stderr diff --git a/pkg/osquery/tables/dsim_default_associations/dsim_default_associations.go b/pkg/osquery/tables/dsim_default_associations/dsim_default_associations.go index f22984d53..cd9163bdd 100644 --- a/pkg/osquery/tables/dsim_default_associations/dsim_default_associations.go +++ b/pkg/osquery/tables/dsim_default_associations/dsim_default_associations.go @@ -8,7 +8,6 @@ import ( "context" "fmt" "os" - "os/exec" "path/filepath" "strings" "time" @@ -16,6 +15,7 @@ import ( "github.com/go-kit/kit/log" "github.com/go-kit/kit/log/level" "github.com/kolide/launcher/pkg/agent" + "github.com/kolide/launcher/pkg/allowedpaths" "github.com/kolide/launcher/pkg/dataflatten" "github.com/kolide/launcher/pkg/osquery/tables/dataflattentable" "github.com/kolide/launcher/pkg/osquery/tables/tablehelpers" @@ -84,7 +84,10 @@ func (t *Table) execDism(ctx context.Context) ([]byte, error) { args := []string{"/online", "/Export-DefaultAppAssociations:" + dstFile} - cmd := exec.CommandContext(ctx, dismCmd, args...) + cmd, err := allowedpaths.CommandContextWithLookup(ctx, dismCmd, args...) + if err != nil { + return nil, fmt.Errorf("creating command: %w", err) + } cmd.Dir = dir cmd.Stdout = &stdout cmd.Stderr = &stderr diff --git a/pkg/osquery/tables/filevault/filevault.go b/pkg/osquery/tables/filevault/filevault.go index 2ec6ad8c4..9484ddcd2 100644 --- a/pkg/osquery/tables/filevault/filevault.go +++ b/pkg/osquery/tables/filevault/filevault.go @@ -16,8 +16,6 @@ import ( "github.com/pkg/errors" ) -const fdesetupPath = "/usr/bin/fdesetup" - type Table struct { logger log.Logger } @@ -35,7 +33,7 @@ func TablePlugin(logger log.Logger) *table.Plugin { } func (t *Table) generate(ctx context.Context, queryContext table.QueryContext) ([]map[string]string, error) { - output, err := tablehelpers.Exec(ctx, t.logger, 10, []string{fdesetupPath}, []string{"status"}, false) + output, err := tablehelpers.Exec(ctx, t.logger, 10, []string{"fdsetup"}, []string{"status"}, false) if err != nil { level.Info(t.logger).Log("msg", "fdesetup failed", "err", err) diff --git a/pkg/osquery/tables/firmwarepasswd/firmwarepasswd.go b/pkg/osquery/tables/firmwarepasswd/firmwarepasswd.go index 93e77b655..6323bfdec 100644 --- a/pkg/osquery/tables/firmwarepasswd/firmwarepasswd.go +++ b/pkg/osquery/tables/firmwarepasswd/firmwarepasswd.go @@ -9,13 +9,13 @@ import ( "context" "fmt" "os" - "os/exec" "strings" "time" "github.com/go-kit/kit/log" "github.com/go-kit/kit/log/level" "github.com/kolide/launcher/pkg/agent" + "github.com/kolide/launcher/pkg/allowedpaths" "github.com/osquery/osquery-go/plugin/table" ) @@ -92,7 +92,10 @@ func (t *Table) runFirmwarepasswd(ctx context.Context, subcommand string, output ctx, cancel := context.WithTimeout(ctx, 1*time.Second) defer cancel() - cmd := exec.CommandContext(ctx, "/usr/sbin/firmwarepasswd", subcommand) + cmd, err := allowedpaths.CommandContextWithLookup(ctx, "firmwarepasswd", subcommand) + if err != nil { + return fmt.Errorf("creating command: %w", err) + } dir, err := agent.MkdirTemp("osq-firmwarepasswd") if err != nil { diff --git a/pkg/osquery/tables/gsettings/gsettings.go b/pkg/osquery/tables/gsettings/gsettings.go index 21d4cc57a..f2775a2a2 100644 --- a/pkg/osquery/tables/gsettings/gsettings.go +++ b/pkg/osquery/tables/gsettings/gsettings.go @@ -11,7 +11,6 @@ import ( "fmt" "io" "os" - "os/exec" "os/user" "strconv" "strings" @@ -21,12 +20,11 @@ import ( "github.com/go-kit/kit/log" "github.com/go-kit/kit/log/level" "github.com/kolide/launcher/pkg/agent" + "github.com/kolide/launcher/pkg/allowedpaths" "github.com/kolide/launcher/pkg/osquery/tables/tablehelpers" "github.com/osquery/osquery-go/plugin/table" ) -const gsettingsPath = "/usr/bin/gsettings" - const allowedCharacters = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_-." type gsettingsExecer func(ctx context.Context, username string, buf *bytes.Buffer) error @@ -92,7 +90,10 @@ func execGsettings(ctx context.Context, username string, buf *bytes.Buffer) erro return fmt.Errorf("finding user by username '%s': %w", username, err) } - cmd := exec.CommandContext(ctx, gsettingsPath, "list-recursively") + cmd, err := allowedpaths.CommandContextWithLookup(ctx, "gsettings", "list-recursively") + if err != nil { + return fmt.Errorf("creating gsettings command: %w", err) + } // set the HOME for the the cmd so that gsettings is exec'd properly as the // new user. diff --git a/pkg/osquery/tables/gsettings/metadata.go b/pkg/osquery/tables/gsettings/metadata.go index 7e8f1a6e2..a2cdbebb9 100644 --- a/pkg/osquery/tables/gsettings/metadata.go +++ b/pkg/osquery/tables/gsettings/metadata.go @@ -10,13 +10,13 @@ import ( "errors" "fmt" "os" - "os/exec" "strings" "time" "github.com/go-kit/kit/log" "github.com/go-kit/kit/log/level" "github.com/kolide/launcher/pkg/agent" + "github.com/kolide/launcher/pkg/allowedpaths" "github.com/kolide/launcher/pkg/osquery/tables/tablehelpers" "github.com/osquery/osquery-go/plugin/table" ) @@ -221,7 +221,10 @@ func execGsettingsCommand(ctx context.Context, args []string, tmpdir string, out defer cancel() command := args[0] - cmd := exec.CommandContext(ctx, gsettingsPath, args...) + cmd, err := allowedpaths.CommandContextWithLookup(ctx, "gsettings", args...) + if err != nil { + return fmt.Errorf("creating gsettings command: %w", err) + } cmd.Dir = tmpdir cmd.Stderr = new(bytes.Buffer) diff --git a/pkg/osquery/tables/ioreg/ioreg.go b/pkg/osquery/tables/ioreg/ioreg.go index eff0703fc..1f17d4351 100644 --- a/pkg/osquery/tables/ioreg/ioreg.go +++ b/pkg/osquery/tables/ioreg/ioreg.go @@ -22,8 +22,6 @@ import ( "github.com/osquery/osquery-go/plugin/table" ) -const ioregPath = "/usr/sbin/ioreg" - const allowedCharacters = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789" type Table struct { @@ -102,7 +100,7 @@ func (t *Table) generate(ctx context.Context, queryContext table.QueryContext) ( for _, dataQuery := range tablehelpers.GetConstraints(queryContext, "query", tablehelpers.WithDefaults("*")) { // Finally, an inner loop - ioregOutput, err := tablehelpers.Exec(ctx, t.logger, 30, []string{ioregPath}, ioregArgs, false) + ioregOutput, err := tablehelpers.Exec(ctx, t.logger, 30, []string{"ioreg"}, ioregArgs, false) if err != nil { level.Info(t.logger).Log("msg", "ioreg failed", "err", err) continue diff --git a/pkg/osquery/tables/mdmclient/mdmclient.go b/pkg/osquery/tables/mdmclient/mdmclient.go index 634880c37..b6d04f3b6 100644 --- a/pkg/osquery/tables/mdmclient/mdmclient.go +++ b/pkg/osquery/tables/mdmclient/mdmclient.go @@ -24,8 +24,6 @@ import ( "github.com/osquery/osquery-go/plugin/table" ) -const mdmclientPath = "/usr/libexec/mdmclient" - const allowedCharacters = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789" // headerRegex matches the header that may be included at the beginning of the mdmclient response, @@ -92,7 +90,7 @@ func (t *Table) generate(ctx context.Context, queryContext table.QueryContext) ( for _, dataQuery := range tablehelpers.GetConstraints(queryContext, "query", tablehelpers.WithDefaults("*")) { - mdmclientOutput, err := tablehelpers.Exec(ctx, t.logger, 30, []string{mdmclientPath}, []string{mdmclientCommand}, false) + mdmclientOutput, err := tablehelpers.Exec(ctx, t.logger, 30, []string{"mdmclient"}, []string{mdmclientCommand}, false) if err != nil { level.Info(t.logger).Log("msg", "mdmclient failed", "err", err) continue diff --git a/pkg/osquery/tables/profiles/profiles.go b/pkg/osquery/tables/profiles/profiles.go index 7dacd12f2..e27b066a4 100644 --- a/pkg/osquery/tables/profiles/profiles.go +++ b/pkg/osquery/tables/profiles/profiles.go @@ -28,7 +28,6 @@ import ( ) const ( - profilesPath = "/usr/bin/profiles" userAllowedCharacters = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789-_" typeAllowedCharacters = "abcdefghijklmnopqrstuvwxyz" ) @@ -103,7 +102,7 @@ func (t *Table) generate(ctx context.Context, queryContext table.QueryContext) ( return nil, fmt.Errorf("Unknown user argument: %s", user) } - output, err := tablehelpers.Exec(ctx, t.logger, 30, []string{profilesPath}, profileArgs, false) + output, err := tablehelpers.Exec(ctx, t.logger, 30, []string{"profiles"}, profileArgs, false) if err != nil { level.Info(t.logger).Log("msg", "ioreg exec failed", "err", err) continue diff --git a/pkg/osquery/tables/pwpolicy/pwpolicy.go b/pkg/osquery/tables/pwpolicy/pwpolicy.go index a4332b76b..6c8a60195 100644 --- a/pkg/osquery/tables/pwpolicy/pwpolicy.go +++ b/pkg/osquery/tables/pwpolicy/pwpolicy.go @@ -20,19 +20,19 @@ import ( "github.com/go-kit/kit/log" "github.com/go-kit/kit/log/level" + "github.com/kolide/launcher/pkg/allowedpaths" "github.com/kolide/launcher/pkg/dataflatten" "github.com/kolide/launcher/pkg/osquery/tables/dataflattentable" "github.com/kolide/launcher/pkg/osquery/tables/tablehelpers" "github.com/osquery/osquery-go/plugin/table" ) -const pwpolicyPath = "/usr/bin/pwpolicy" const pwpolicyCmd = "getaccountpolicies" type Table struct { logger log.Logger tableName string - execCC func(context.Context, string, ...string) *exec.Cmd + execCC func(context.Context, string, ...string) (*exec.Cmd, error) } func TablePlugin(logger log.Logger) *table.Plugin { @@ -44,7 +44,7 @@ func TablePlugin(logger log.Logger) *table.Plugin { t := &Table{ logger: logger, tableName: "kolide_pwpolicy", - execCC: exec.CommandContext, + execCC: allowedpaths.CommandContextWithLookup, } return table.NewPlugin(t.tableName, columns, t.generate) @@ -96,7 +96,10 @@ func (t *Table) execPwpolicy(ctx context.Context, args []string) ([]byte, error) ctx, cancel := context.WithTimeout(ctx, 30*time.Second) defer cancel() - cmd := t.execCC(ctx, pwpolicyPath, args...) + cmd, err := t.execCC(ctx, "pwpolicy", args...) + if err != nil { + return nil, fmt.Errorf("creating command: %w", err) + } cmd.Stdout = &stdout cmd.Stderr = &stderr diff --git a/pkg/osquery/tables/pwpolicy/pwpolicy_test.go b/pkg/osquery/tables/pwpolicy/pwpolicy_test.go index 84d6e60ff..52c1a3490 100644 --- a/pkg/osquery/tables/pwpolicy/pwpolicy_test.go +++ b/pkg/osquery/tables/pwpolicy/pwpolicy_test.go @@ -1,6 +1,7 @@ //go:build darwin // +build darwin +//nolint:forbidigo package pwpolicy import ( @@ -71,8 +72,8 @@ func TestQueries(t *testing.T) { } -func execFaker(filename string) func(context.Context, string, ...string) *exec.Cmd { - return func(ctx context.Context, _ string, _ ...string) *exec.Cmd { - return exec.CommandContext(ctx, "/bin/cat", filename) +func execFaker(filename string) func(context.Context, string, ...string) (*exec.Cmd, error) { + return func(ctx context.Context, _ string, _ ...string) (*exec.Cmd, error) { + return exec.CommandContext(ctx, "/bin/cat", filename), nil } } diff --git a/pkg/osquery/tables/secedit/secedit.go b/pkg/osquery/tables/secedit/secedit.go index b6d6c3873..fbfde2dbc 100644 --- a/pkg/osquery/tables/secedit/secedit.go +++ b/pkg/osquery/tables/secedit/secedit.go @@ -9,7 +9,6 @@ import ( "fmt" "io" "os" - "os/exec" "path/filepath" "strconv" "strings" @@ -18,6 +17,7 @@ import ( "github.com/go-kit/kit/log" "github.com/go-kit/kit/log/level" "github.com/kolide/launcher/pkg/agent" + "github.com/kolide/launcher/pkg/allowedpaths" "github.com/kolide/launcher/pkg/dataflatten" "github.com/kolide/launcher/pkg/osquery/tables/dataflattentable" "github.com/kolide/launcher/pkg/osquery/tables/tablehelpers" @@ -27,7 +27,7 @@ import ( "golang.org/x/text/transform" ) -const seceditCmd = "secedit" +const seceditCmd = "secedit.exe" type Table struct { logger log.Logger @@ -109,7 +109,10 @@ func (t *Table) execSecedit(ctx context.Context, mergedPolicy bool) ([]byte, err args = append(args, "/mergedpolicy") } - cmd := exec.CommandContext(ctx, seceditCmd, args...) + cmd, err := allowedpaths.CommandContextWithLookup(ctx, seceditCmd, args...) + if err != nil { + return nil, fmt.Errorf("creating secedit command: %w", err) + } cmd.Stdout = &stdout cmd.Stderr = &stderr diff --git a/pkg/osquery/tables/systemprofiler/systemprofiler.go b/pkg/osquery/tables/systemprofiler/systemprofiler.go index 9ed47cf40..c798793b6 100644 --- a/pkg/osquery/tables/systemprofiler/systemprofiler.go +++ b/pkg/osquery/tables/systemprofiler/systemprofiler.go @@ -41,20 +41,18 @@ import ( "bytes" "context" "fmt" - "os/exec" "strings" "time" "github.com/go-kit/kit/log" "github.com/go-kit/kit/log/level" "github.com/groob/plist" + "github.com/kolide/launcher/pkg/allowedpaths" "github.com/kolide/launcher/pkg/dataflatten" "github.com/kolide/launcher/pkg/osquery/tables/dataflattentable" "github.com/osquery/osquery-go/plugin/table" ) -const systemprofilerPath = "/usr/sbin/system_profiler" - var knownDetailLevels = []string{ "mini", // short report (contains no identifying or personal information) "basic", // basic hardware and network information @@ -208,7 +206,10 @@ func (t *Table) execSystemProfiler(ctx context.Context, detailLevel string, subc args = append(args, subcommands...) - cmd := exec.CommandContext(ctx, systemprofilerPath, args...) + cmd, err := allowedpaths.CommandContextWithLookup(ctx, "system_profiler", args...) + if err != nil { + return nil, fmt.Errorf("creating system_profiler command: %w", err) + } cmd.Stdout = &stdout cmd.Stderr = &stderr diff --git a/pkg/osquery/tables/tablehelpers/exec.go b/pkg/osquery/tables/tablehelpers/exec.go index 0ab9440c1..c5bd1aef9 100644 --- a/pkg/osquery/tables/tablehelpers/exec.go +++ b/pkg/osquery/tables/tablehelpers/exec.go @@ -6,10 +6,12 @@ import ( "fmt" "os" "os/exec" + "path/filepath" "time" "github.com/go-kit/kit/log" "github.com/go-kit/kit/log/level" + "github.com/kolide/launcher/pkg/allowedpaths" "github.com/kolide/launcher/pkg/traces" ) @@ -21,6 +23,10 @@ import ( // 3. It moves the stderr into the return error, if needed. // // This is not suitable for high performance work -- it allocates new buffers each time. +// +// `possibleBins` can be either a list of command names, or a list of paths to commands. +// Where reasonable, `possibleBins` should be command names only, so that we can perform +// lookup against PATH. func Exec(ctx context.Context, logger log.Logger, timeoutSeconds int, possibleBins []string, args []string, includeStderr bool) ([]byte, error) { ctx, span := traces.StartSpan(ctx, "possible_binaries", possibleBins, @@ -37,7 +43,19 @@ func Exec(ctx context.Context, logger log.Logger, timeoutSeconds int, possibleBi stdout.Reset() stderr.Reset() - cmd := exec.CommandContext(ctx, bin, args...) + var cmd *exec.Cmd + var err error + // If we only have the binary name and not the path, try to perform lookup + if filepath.Base(bin) == bin { + cmd, err = allowedpaths.CommandContextWithLookup(ctx, bin, args...) + } else { + cmd, err = allowedpaths.CommandContextWithPath(ctx, bin, args...) + } + if err != nil { + // Likely that binary was not found -- try the next + continue + } + cmd.Stdout = &stdout if includeStderr { cmd.Stderr = &stdout diff --git a/pkg/osquery/tables/tablehelpers/exec_osquery_launchctl.go b/pkg/osquery/tables/tablehelpers/exec_osquery_launchctl.go index d3a9ac48b..2b2726f87 100644 --- a/pkg/osquery/tables/tablehelpers/exec_osquery_launchctl.go +++ b/pkg/osquery/tables/tablehelpers/exec_osquery_launchctl.go @@ -8,13 +8,13 @@ import ( "encoding/json" "fmt" "os" - "os/exec" "os/user" "time" "github.com/go-kit/kit/log" "github.com/go-kit/kit/log/level" "github.com/kolide/launcher/pkg/agent" + "github.com/kolide/launcher/pkg/allowedpaths" ) // ExecOsqueryLaunchctl runs osquery under launchctl, in a user context. @@ -27,7 +27,7 @@ func ExecOsqueryLaunchctl(ctx context.Context, logger log.Logger, timeoutSeconds return nil, fmt.Errorf("looking up username %s: %w", username, err) } - cmd := exec.CommandContext(ctx, + cmd, err := allowedpaths.CommandContextWithLookup(ctx, "launchctl", "asuser", targetUser.Uid, @@ -41,6 +41,9 @@ func ExecOsqueryLaunchctl(ctx context.Context, logger log.Logger, timeoutSeconds "--json", query, ) + if err != nil { + return nil, fmt.Errorf("creating launchctl command: %w", err) + } dir, err := agent.MkdirTemp("osq-launchctl") if err != nil { diff --git a/pkg/osquery/tables/tablehelpers/exec_test.go b/pkg/osquery/tables/tablehelpers/exec_test.go index e4a303f34..455b986dc 100644 --- a/pkg/osquery/tables/tablehelpers/exec_test.go +++ b/pkg/osquery/tables/tablehelpers/exec_test.go @@ -20,34 +20,15 @@ func TestExec(t *testing.T) { bins []string args []string err bool - output string }{ - { - name: "timeout", - timeout: 1, - bins: []string{"/bin/sleep", "/usr/bin/sleep"}, - args: []string{"30"}, - err: true, - }, { name: "no binaries", bins: []string{"/hello/world", "/hello/friends"}, err: true, }, - { - name: "false", - bins: []string{"/bin/false", "/usr/bin/false"}, - err: true, - }, { name: "eventually finds binary", - bins: []string{"/hello/world", "/bin/true", "/usr/bin/true"}, - }, - { - name: "output", - bins: []string{"/bin/echo"}, - args: []string{"hello"}, - output: "hello\n", + bins: []string{"/hello/world", "/bin/ps", "/usr/bin/ps"}, }, } @@ -68,9 +49,8 @@ func TestExec(t *testing.T) { assert.Empty(t, output) } else { assert.NoError(t, err) - assert.Equal(t, []byte(tt.output), output) + assert.Less(t, 0, len(output)) } - }) } } diff --git a/pkg/osquery/tables/wifi_networks/wifi_networks.go b/pkg/osquery/tables/wifi_networks/wifi_networks.go index f3e2881dd..0c04d9465 100644 --- a/pkg/osquery/tables/wifi_networks/wifi_networks.go +++ b/pkg/osquery/tables/wifi_networks/wifi_networks.go @@ -9,13 +9,13 @@ import ( _ "embed" "fmt" "os" - "os/exec" "path/filepath" "time" "github.com/go-kit/kit/log" "github.com/go-kit/kit/log/level" "github.com/kolide/launcher/pkg/agent" + "github.com/kolide/launcher/pkg/allowedpaths" "github.com/kolide/launcher/pkg/dataflatten" "github.com/kolide/launcher/pkg/osquery/tables/dataflattentable" "github.com/osquery/osquery-go/plugin/table" @@ -90,13 +90,11 @@ func execPwsh(logger log.Logger) execer { return fmt.Errorf("writing native wifi code: %w", err) } - pwsh, err := exec.LookPath("powershell.exe") + args := append([]string{"-NoProfile", "-NonInteractive"}, string(pwshScript)) + cmd, err := allowedpaths.CommandContextWithLookup(ctx, "powershell.exe", args...) if err != nil { - return fmt.Errorf("finding powershell.exe path: %w", err) + return fmt.Errorf("creating powershell command: %w", err) } - - args := append([]string{"-NoProfile", "-NonInteractive"}, string(pwshScript)) - cmd := exec.CommandContext(ctx, pwsh, args...) cmd.Dir = dir var stderr bytes.Buffer cmd.Stdout = buf diff --git a/pkg/osquery/tables/xrdb/xrdb.go b/pkg/osquery/tables/xrdb/xrdb.go index 97f86e49c..85fddfa96 100644 --- a/pkg/osquery/tables/xrdb/xrdb.go +++ b/pkg/osquery/tables/xrdb/xrdb.go @@ -11,7 +11,6 @@ import ( "fmt" "io" "os" - "os/exec" "os/user" "strconv" "strings" @@ -21,12 +20,11 @@ import ( "github.com/go-kit/kit/log" "github.com/go-kit/kit/log/level" "github.com/kolide/launcher/pkg/agent" + "github.com/kolide/launcher/pkg/allowedpaths" "github.com/kolide/launcher/pkg/osquery/tables/tablehelpers" "github.com/osquery/osquery-go/plugin/table" ) -var xrdbPath = "/usr/bin/xrdb" - const allowedUsernameCharacters = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_-." const allowedDisplayCharacters = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789:." @@ -97,7 +95,10 @@ func execXRDB(ctx context.Context, displayNum, username string, buf *bytes.Buffe return fmt.Errorf("finding user by username '%s': %w", username, err) } - cmd := exec.CommandContext(ctx, xrdbPath, "-display", displayNum, "-global", "-query") + cmd, err := allowedpaths.CommandContextWithLookup(ctx, "xrdb", "-display", displayNum, "-global", "-query") + if err != nil { + return fmt.Errorf("creating xrdb command: %w", err) + } // set the HOME cmd so that xrdb is exec'd properly as the new user. cmd.Env = append(cmd.Env, fmt.Sprintf("HOME=%s", u.HomeDir)) diff --git a/pkg/osquery/tables/zfs/tables.go b/pkg/osquery/tables/zfs/tables.go index 449f8b238..bc6b6c637 100644 --- a/pkg/osquery/tables/zfs/tables.go +++ b/pkg/osquery/tables/zfs/tables.go @@ -15,11 +15,6 @@ import ( "github.com/pkg/errors" ) -const ( - zfsPath = "/usr/sbin/zfs" - zpoolPath = "/usr/sbin/zpool" -) - const allowedCharacters = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_-.@/" type Table struct { @@ -39,7 +34,7 @@ func columns() []table.ColumnDefinition { func ZfsPropertiesPlugin(logger log.Logger) *table.Plugin { t := &Table{ logger: logger, - cmd: zfsPath, + cmd: "zfs", } return table.NewPlugin("kolide_zfs_properties", columns(), t.generate) @@ -48,7 +43,7 @@ func ZfsPropertiesPlugin(logger log.Logger) *table.Plugin { func ZpoolPropertiesPlugin(logger log.Logger) *table.Plugin { t := &Table{ logger: logger, - cmd: zpoolPath, + cmd: "zpool", } return table.NewPlugin("kolide_zpool_properties", columns(), t.generate) diff --git a/pkg/packagekit/applenotarization/applenotarization.go b/pkg/packagekit/applenotarization/applenotarization.go index 4640aeac4..3c15118ae 100644 --- a/pkg/packagekit/applenotarization/applenotarization.go +++ b/pkg/packagekit/applenotarization/applenotarization.go @@ -1,3 +1,4 @@ +// nolint:forbidigo // Package applenotarization is a wrapper around the apple // notarization tools. // diff --git a/pkg/packagekit/authenticode/authenticode_test.go b/pkg/packagekit/authenticode/authenticode_test.go index 40ee4c494..80ed3dd89 100644 --- a/pkg/packagekit/authenticode/authenticode_test.go +++ b/pkg/packagekit/authenticode/authenticode_test.go @@ -1,6 +1,7 @@ //go:build windows // +build windows +// nolint:forbidigo package authenticode import ( diff --git a/pkg/packagekit/authenticode/authenticode_windows.go b/pkg/packagekit/authenticode/authenticode_windows.go index 5ab933627..b6d512d99 100644 --- a/pkg/packagekit/authenticode/authenticode_windows.go +++ b/pkg/packagekit/authenticode/authenticode_windows.go @@ -7,6 +7,7 @@ // // https://docs.microsoft.com/en-us/dotnet/framework/tools/signtool-exe +// nolint:forbidigo package authenticode import ( diff --git a/pkg/packagekit/package_fpm.go b/pkg/packagekit/package_fpm.go index 520fa8ec7..55510890a 100644 --- a/pkg/packagekit/package_fpm.go +++ b/pkg/packagekit/package_fpm.go @@ -1,3 +1,4 @@ +// nolint:forbidigo package packagekit import ( diff --git a/pkg/packagekit/package_pkg.go b/pkg/packagekit/package_pkg.go index 165a08cc8..6d6ef2d47 100644 --- a/pkg/packagekit/package_pkg.go +++ b/pkg/packagekit/package_pkg.go @@ -1,3 +1,4 @@ +// nolint:forbidigo package packagekit import ( diff --git a/pkg/packagekit/wix/wix.go b/pkg/packagekit/wix/wix.go index 8a0f720ea..1dfc303b8 100644 --- a/pkg/packagekit/wix/wix.go +++ b/pkg/packagekit/wix/wix.go @@ -1,3 +1,4 @@ +// nolint:forbidigo package wix import ( diff --git a/pkg/packagekit/wix/wix_test.go b/pkg/packagekit/wix/wix_test.go index 8adcf61bb..47f7f1420 100644 --- a/pkg/packagekit/wix/wix_test.go +++ b/pkg/packagekit/wix/wix_test.go @@ -1,3 +1,4 @@ +//nolint:forbidigo package wix import ( diff --git a/pkg/packaging/packaging.go b/pkg/packaging/packaging.go index 7e9367ded..fe90f4643 100644 --- a/pkg/packaging/packaging.go +++ b/pkg/packaging/packaging.go @@ -1,3 +1,4 @@ +//nolint:forbidigo package packaging import ( diff --git a/pkg/packaging/packaging_test.go b/pkg/packaging/packaging_test.go index fd958d649..e3e38739e 100644 --- a/pkg/packaging/packaging_test.go +++ b/pkg/packaging/packaging_test.go @@ -1,3 +1,4 @@ +//nolint:forbidigo package packaging import ( diff --git a/pkg/ptycmd/command.go b/pkg/ptycmd/command.go index 00aa8ee78..7fa9de5ac 100644 --- a/pkg/ptycmd/command.go +++ b/pkg/ptycmd/command.go @@ -6,18 +6,21 @@ package ptycmd import ( "fmt" "os" - "os/exec" "syscall" "time" "unsafe" + "github.com/kolide/launcher/pkg/allowedpaths" "github.com/kr/pty" ) // NewCmd creates a new command attached to a pty func NewCmd(command string, argv []string, options ...Option) (*Cmd, error) { // create the command - cmd := exec.Command(command, argv...) + cmd, err := allowedpaths.CommandWithLookup(command, argv...) + if err != nil { + return nil, fmt.Errorf("creating command: %w", err) + } // open a pty pty, tty, err := pty.Open() From cd716001db694a624057a2f0f3cf2aecea9ff1ef Mon Sep 17 00:00:00 2001 From: Rebecca Mahany-Horton Date: Tue, 7 Nov 2023 15:12:25 -0500 Subject: [PATCH 06/30] Fix typos --- cmd/launcher/uninstall_linux.go | 11 ++--------- ee/desktop/user/notify/notify_linux.go | 3 ++- pkg/allowedpaths/cmd_linux.go | 4 ++-- pkg/execwrapper/exec_windows.go | 2 +- 4 files changed, 7 insertions(+), 13 deletions(-) diff --git a/cmd/launcher/uninstall_linux.go b/cmd/launcher/uninstall_linux.go index 8ce9041c6..441f07dd1 100644 --- a/cmd/launcher/uninstall_linux.go +++ b/cmd/launcher/uninstall_linux.go @@ -33,19 +33,12 @@ func removeLauncher(ctx context.Context, identifier string) error { fmt.Printf("error occurred while stopping/disabling launcher service, systemctl output %s: err: %s\n", string(out), err) } - fileExists := func(f string) bool { - if _, err := os.Stat(f); err == nil { - return true - } - return false - } - // Tell the appropriate package manager to remove launcher - if cmd, err := allowedpaths.CommandContextWithLookup("dpkg", []string{"--purge", packageName}...); err == nil { + if cmd, err := allowedpaths.CommandContextWithLookup(ctx, "dpkg", []string{"--purge", packageName}...); err == nil { if out, err := cmd.CombinedOutput(); err != nil { fmt.Printf("error occurred while running dpkg --purge, output %s: err: %s\n", string(out), err) } - } else if cmd, err := allowedpaths.CommandContextWithLookup("rpm", []string{"-e", packageName}...); err == nil { + } else if cmd, err := allowedpaths.CommandContextWithLookup(ctx, "rpm", []string{"-e", packageName}...); err == nil { if out, err := cmd.CombinedOutput(); err != nil { fmt.Printf("error occurred while running rpm -e, output %s: err: %s\n", string(out), err) } diff --git a/ee/desktop/user/notify/notify_linux.go b/ee/desktop/user/notify/notify_linux.go index 50cf88c4d..01afe24df 100644 --- a/ee/desktop/user/notify/notify_linux.go +++ b/ee/desktop/user/notify/notify_linux.go @@ -12,6 +12,7 @@ import ( "github.com/go-kit/kit/log" "github.com/go-kit/kit/log/level" "github.com/godbus/dbus/v5" + "github.com/kolide/launcher/pkg/allowedpaths" ) type dbusNotifier struct { @@ -180,7 +181,7 @@ func (d *dbusNotifier) sendNotificationViaNotifySend(n Notification) error { args = append(args, "-i", d.iconFilepath) } - cmd, err := allowedpaths.Command("notify-send", args...) + cmd, err := allowedpaths.CommandWithLookup("notify-send", args...) if err != nil { return fmt.Errorf("creating command: %w", err) } diff --git a/pkg/allowedpaths/cmd_linux.go b/pkg/allowedpaths/cmd_linux.go index a253d6ffd..5c13190a3 100644 --- a/pkg/allowedpaths/cmd_linux.go +++ b/pkg/allowedpaths/cmd_linux.go @@ -6,7 +6,7 @@ package allowedpaths var knownPaths = map[string]map[string]bool{ "cryptsetup": { "/usr/sbin/cryptsetup": true, - "/sbin/cryptsetup", true + "/sbin/cryptsetup": true, }, "dpkg": { "/usr/bin/dpkg": true, @@ -64,7 +64,7 @@ var knownPaths = map[string]map[string]bool{ }, "zpool": { "/usr/sbin/zpool": true, - } + }, } var knownPathPrefixes = []string{ diff --git a/pkg/execwrapper/exec_windows.go b/pkg/execwrapper/exec_windows.go index a6916866f..72d980baf 100644 --- a/pkg/execwrapper/exec_windows.go +++ b/pkg/execwrapper/exec_windows.go @@ -37,7 +37,7 @@ func Exec(ctx context.Context, argv0 string, argv []string, envv []string) error // Now run it. This is faking exec, we need to distinguish // between a failure to execute, and a failure in in the called program. // I think https://github.com/golang/go/issues/26539 adds this functionality. - err := cmd.Run() + err = cmd.Run() if cmd.ProcessState.ExitCode() == -1 { if err == nil { From c8165f69f9426db1cf288f05b360821f6b93816d Mon Sep 17 00:00:00 2001 From: Rebecca Mahany-Horton Date: Tue, 7 Nov 2023 15:50:43 -0500 Subject: [PATCH 07/30] Add more missing commands --- pkg/allowedpaths/cmd_linux.go | 25 +++++++++++++++++++- pkg/allowedpaths/cmd_windows.go | 3 +++ pkg/osquery/table/platform_tables_linux.go | 23 +++++++++--------- pkg/osquery/table/platform_tables_windows.go | 2 +- 4 files changed, 39 insertions(+), 14 deletions(-) diff --git a/pkg/allowedpaths/cmd_linux.go b/pkg/allowedpaths/cmd_linux.go index 5c13190a3..6d7a03afd 100644 --- a/pkg/allowedpaths/cmd_linux.go +++ b/pkg/allowedpaths/cmd_linux.go @@ -4,10 +4,16 @@ package allowedpaths var knownPaths = map[string]map[string]bool{ + "apt": { + "/usr/bin/apt": true, + }, "cryptsetup": { "/usr/sbin/cryptsetup": true, "/sbin/cryptsetup": true, }, + "dnf": { + "/usr/bin/dnf": true, + }, "dpkg": { "/usr/bin/dpkg": true, }, @@ -17,6 +23,9 @@ var knownPaths = map[string]map[string]bool{ "falcon-kernel-check": { "/opt/CrowdStrike/falcon-kernel-check": true, }, + "falconctl": { + "/opt/CrowdStrike/falconctl": true, + }, "gnome-extensions": { "/usr/bin/gnome-extensions": true, }, @@ -32,17 +41,31 @@ var knownPaths = map[string]map[string]bool{ "loginctl": { "/usr/bin/loginctl": true, }, + "lsblk": { + "/bin/lsblk", + "/usr/bin/lsblk", + }, "mdmclient": { "/usr/libexec/mdmclient": true, }, + "nmcli": { + "/usr/bin/nmcli": true, + }, "notify-send": { "/usr/bin/notify-send": true, }, + "pacman": { + "/usr/bin/pacman": true, + }, "ps": { "/usr/bin/ps": true, }, + "repcli": { + "/opt/carbonblack/psc/bin/repcli": true, + }, "rpm": { - "/bin/rpm": true, + "/usr/bin/rpm": true, + "/bin/rpm": true, }, "systemctl": { "/usr/bin/systemctl": true, diff --git a/pkg/allowedpaths/cmd_windows.go b/pkg/allowedpaths/cmd_windows.go index 56e0d250b..fc02af0be 100644 --- a/pkg/allowedpaths/cmd_windows.go +++ b/pkg/allowedpaths/cmd_windows.go @@ -10,6 +10,9 @@ var knownPaths = map[string]map[string]bool{ "dism.exe": { `C:\Windows\System32\Dism.exe`: true, }, + "dsregcmd.exe": { + `C:\Windows\System32\dsregcmd.exe`: true, + }, "ipconfig.exe": { `C:\Windows\System32\ipconfig.exe`: true, }, diff --git a/pkg/osquery/table/platform_tables_linux.go b/pkg/osquery/table/platform_tables_linux.go index d6572cb0d..b77d330d5 100644 --- a/pkg/osquery/table/platform_tables_linux.go +++ b/pkg/osquery/table/platform_tables_linux.go @@ -12,9 +12,9 @@ import ( "github.com/kolide/launcher/pkg/osquery/tables/execparsers/apt" "github.com/kolide/launcher/pkg/osquery/tables/execparsers/dnf" "github.com/kolide/launcher/pkg/osquery/tables/execparsers/dpkg" - "github.com/kolide/launcher/pkg/osquery/tables/execparsers/pacman/group" - "github.com/kolide/launcher/pkg/osquery/tables/execparsers/pacman/info" - "github.com/kolide/launcher/pkg/osquery/tables/execparsers/pacman/upgradeable" + pacman_group "github.com/kolide/launcher/pkg/osquery/tables/execparsers/pacman/group" + pacman_info "github.com/kolide/launcher/pkg/osquery/tables/execparsers/pacman/info" + pacman_upgradeable "github.com/kolide/launcher/pkg/osquery/tables/execparsers/pacman/upgradeable" "github.com/kolide/launcher/pkg/osquery/tables/execparsers/repcli" "github.com/kolide/launcher/pkg/osquery/tables/execparsers/rpm" "github.com/kolide/launcher/pkg/osquery/tables/execparsers/simple_array" @@ -40,20 +40,19 @@ func platformTables(logger log.Logger, currentOsquerydBinaryPath string) []osque dataflattentable.TablePluginExec(logger, "kolide_nmcli_wifi", dataflattentable.KeyValueType, - []string{"/usr/bin/nmcli", "--mode=multiline", "--fields=all", "device", "wifi", "list"}, + []string{"nmcli", "--mode=multiline", "--fields=all", "device", "wifi", "list"}, dataflattentable.WithKVSeparator(":")), dataflattentable.TablePluginExec(logger, "kolide_lsblk", dataflattentable.JsonType, []string{"lsblk", "-J"}, - dataflattentable.WithBinDirs("/usr/bin", "/bin"), ), dataflattentable.NewExecAndParseTable(logger, "kolide_falconctl_systags", simple_array.New("systags"), []string{"/opt/CrowdStrike/falconctl", "-g", "--systags"}), - dataflattentable.NewExecAndParseTable(logger, "kolide_apt_upgradeable", apt.Parser, []string{"/usr/bin/apt", "list", "--upgradeable"}, dataflattentable.WithIncludeStderr()), - dataflattentable.NewExecAndParseTable(logger, "kolide_dnf_upgradeable", dnf.Parser, []string{"/usr/bin/dnf", "check-update"}, dataflattentable.WithIncludeStderr()), - dataflattentable.NewExecAndParseTable(logger, "kolide_dpkg_version_info", dpkg.Parser, []string{"/usr/bin/dpkg", "-p"}, dataflattentable.WithIncludeStderr()), - dataflattentable.NewExecAndParseTable(logger, "kolide_pacman_group", pacman_group.Parser, []string{"/usr/bin/pacman", "-Qg"}, dataflattentable.WithIncludeStderr()), - dataflattentable.NewExecAndParseTable(logger, "kolide_pacman_version_info", pacman_info.Parser, []string{"/usr/bin/pacman", "-Qi"}, dataflattentable.WithIncludeStderr()), - dataflattentable.NewExecAndParseTable(logger, "kolide_pacman_upgradeable", pacman_upgradeable.Parser, []string{"/usr/bin/pacman", "-Qu"}, dataflattentable.WithIncludeStderr()), - dataflattentable.NewExecAndParseTable(logger, "kolide_rpm_version_info", rpm.Parser, []string{"/usr/bin/rpm", "-qai"}, dataflattentable.WithIncludeStderr()), + dataflattentable.NewExecAndParseTable(logger, "kolide_apt_upgradeable", apt.Parser, []string{"apt", "list", "--upgradeable"}, dataflattentable.WithIncludeStderr()), + dataflattentable.NewExecAndParseTable(logger, "kolide_dnf_upgradeable", dnf.Parser, []string{"dnf", "check-update"}, dataflattentable.WithIncludeStderr()), + dataflattentable.NewExecAndParseTable(logger, "kolide_dpkg_version_info", dpkg.Parser, []string{"dpkg", "-p"}, dataflattentable.WithIncludeStderr()), + dataflattentable.NewExecAndParseTable(logger, "kolide_pacman_group", pacman_group.Parser, []string{"pacman", "-Qg"}, dataflattentable.WithIncludeStderr()), + dataflattentable.NewExecAndParseTable(logger, "kolide_pacman_version_info", pacman_info.Parser, []string{"pacman", "-Qi"}, dataflattentable.WithIncludeStderr()), + dataflattentable.NewExecAndParseTable(logger, "kolide_pacman_upgradeable", pacman_upgradeable.Parser, []string{"pacman", "-Qu"}, dataflattentable.WithIncludeStderr()), + dataflattentable.NewExecAndParseTable(logger, "kolide_rpm_version_info", rpm.Parser, []string{"rpm", "-qai"}, dataflattentable.WithIncludeStderr()), dataflattentable.NewExecAndParseTable(logger, "kolide_carbonblack_repcli_status", repcli.Parser, []string{"/opt/carbonblack/psc/bin/repcli", "status"}, dataflattentable.WithIncludeStderr()), } } diff --git a/pkg/osquery/table/platform_tables_windows.go b/pkg/osquery/table/platform_tables_windows.go index 4e241366f..869e5a397 100644 --- a/pkg/osquery/table/platform_tables_windows.go +++ b/pkg/osquery/table/platform_tables_windows.go @@ -25,6 +25,6 @@ func platformTables(logger log.Logger, currentOsquerydBinaryPath string) []osque windowsupdatetable.TablePlugin(windowsupdatetable.UpdatesTable, logger), windowsupdatetable.TablePlugin(windowsupdatetable.HistoryTable, logger), wmitable.TablePlugin(logger), - dataflattentable.NewExecAndParseTable(logger, "kolide_dsregcmd", dsregcmd.Parser, []string{`/Windows/System32/dsregcmd.exe`, `/status`}), + dataflattentable.NewExecAndParseTable(logger, "kolide_dsregcmd", dsregcmd.Parser, []string{`dsregcmd.exe`, `/status`}), } } From baaad8609fb887445fa55cbc02eed09d4e11917c Mon Sep 17 00:00:00 2001 From: Rebecca Mahany-Horton Date: Tue, 7 Nov 2023 15:54:11 -0500 Subject: [PATCH 08/30] Another typo --- pkg/osquery/tables/filevault/filevault.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pkg/osquery/tables/filevault/filevault.go b/pkg/osquery/tables/filevault/filevault.go index 9484ddcd2..9c57ee45a 100644 --- a/pkg/osquery/tables/filevault/filevault.go +++ b/pkg/osquery/tables/filevault/filevault.go @@ -33,7 +33,7 @@ func TablePlugin(logger log.Logger) *table.Plugin { } func (t *Table) generate(ctx context.Context, queryContext table.QueryContext) ([]map[string]string, error) { - output, err := tablehelpers.Exec(ctx, t.logger, 10, []string{"fdsetup"}, []string{"status"}, false) + output, err := tablehelpers.Exec(ctx, t.logger, 10, []string{"fdesetup"}, []string{"status"}, false) if err != nil { level.Info(t.logger).Log("msg", "fdesetup failed", "err", err) From 5ab945047779c79bf57b81c11114c7f430d580f4 Mon Sep 17 00:00:00 2001 From: Rebecca Mahany-Horton Date: Tue, 7 Nov 2023 16:28:08 -0500 Subject: [PATCH 09/30] libexec is not in path --- pkg/osquery/table/platform_tables_darwin.go | 2 +- pkg/osquery/tables/mdmclient/mdmclient.go | 4 +++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/pkg/osquery/table/platform_tables_darwin.go b/pkg/osquery/table/platform_tables_darwin.go index 88174a6e3..97885ceaa 100644 --- a/pkg/osquery/table/platform_tables_darwin.go +++ b/pkg/osquery/table/platform_tables_darwin.go @@ -115,7 +115,7 @@ func platformTables(logger log.Logger, currentOsquerydBinaryPath string) []osque systemprofiler.TablePlugin(logger), munki.ManagedInstalls(logger), munki.MunkiReport(logger), - dataflattentable.NewExecAndParseTable(logger, "kolide_remotectl", remotectl.Parser, []string{`remotectl`, `dumpstate`}), + dataflattentable.NewExecAndParseTable(logger, "kolide_remotectl", remotectl.Parser, []string{`/usr/libexec/remotectl`, `dumpstate`}), dataflattentable.NewExecAndParseTable(logger, "kolide_softwareupdate", softwareupdate.Parser, []string{`softwareupdate`, `--list`, `--no-scan`}, dataflattentable.WithIncludeStderr()), dataflattentable.NewExecAndParseTable(logger, "kolide_softwareupdate_scan", softwareupdate.Parser, []string{`softwareupdate`, `--list`}, dataflattentable.WithIncludeStderr()), dataflattentable.NewExecAndParseTable(logger, "kolide_carbonblack_repcli_status", repcli.Parser, []string{"/Applications/VMware Carbon Black Cloud/repcli.bundle/Contents/MacOS/repcli", "status"}, dataflattentable.WithIncludeStderr()), diff --git a/pkg/osquery/tables/mdmclient/mdmclient.go b/pkg/osquery/tables/mdmclient/mdmclient.go index b6d04f3b6..634880c37 100644 --- a/pkg/osquery/tables/mdmclient/mdmclient.go +++ b/pkg/osquery/tables/mdmclient/mdmclient.go @@ -24,6 +24,8 @@ import ( "github.com/osquery/osquery-go/plugin/table" ) +const mdmclientPath = "/usr/libexec/mdmclient" + const allowedCharacters = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789" // headerRegex matches the header that may be included at the beginning of the mdmclient response, @@ -90,7 +92,7 @@ func (t *Table) generate(ctx context.Context, queryContext table.QueryContext) ( for _, dataQuery := range tablehelpers.GetConstraints(queryContext, "query", tablehelpers.WithDefaults("*")) { - mdmclientOutput, err := tablehelpers.Exec(ctx, t.logger, 30, []string{"mdmclient"}, []string{mdmclientCommand}, false) + mdmclientOutput, err := tablehelpers.Exec(ctx, t.logger, 30, []string{mdmclientPath}, []string{mdmclientCommand}, false) if err != nil { level.Info(t.logger).Log("msg", "mdmclient failed", "err", err) continue From 292338ccc1afa769e808ad0eddb7021710bfeaaf Mon Sep 17 00:00:00 2001 From: Rebecca Mahany-Horton Date: Tue, 7 Nov 2023 16:49:35 -0500 Subject: [PATCH 10/30] More typos --- pkg/allowedpaths/cmd_linux.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pkg/allowedpaths/cmd_linux.go b/pkg/allowedpaths/cmd_linux.go index 6d7a03afd..d2529bd30 100644 --- a/pkg/allowedpaths/cmd_linux.go +++ b/pkg/allowedpaths/cmd_linux.go @@ -42,8 +42,8 @@ var knownPaths = map[string]map[string]bool{ "/usr/bin/loginctl": true, }, "lsblk": { - "/bin/lsblk", - "/usr/bin/lsblk", + "/bin/lsblk": true, + "/usr/bin/lsblk": true, }, "mdmclient": { "/usr/libexec/mdmclient": true, From e5dba569a946b57b763dda992e98e21421b723df Mon Sep 17 00:00:00 2001 From: Rebecca Mahany-Horton Date: Wed, 8 Nov 2023 16:07:54 -0500 Subject: [PATCH 11/30] New and improved --- cmd/launcher/uninstall_darwin.go | 4 +- cmd/launcher/uninstall_linux.go | 6 +- ee/consoleuser/consoleuser_darwin.go | 2 +- ee/consoleuser/consoleuser_linux.go | 4 +- ee/desktop/runner/runner.go | 7 +- ee/desktop/runner/runner_linux.go | 6 +- .../user/menu/action_open_url_darwin.go | 3 +- ee/desktop/user/menu/action_open_url_linux.go | 3 +- .../user/menu/action_open_url_windows.go | 3 +- ee/desktop/user/notify/notify_linux.go | 6 +- pkg/allowedpaths/cmd.go | 789 +++++++++++++++++- pkg/allowedpaths/cmd_darwin.go | 96 --- pkg/allowedpaths/cmd_linux.go | 99 --- pkg/allowedpaths/cmd_test.go | 195 +---- pkg/allowedpaths/cmd_windows.go | 35 - pkg/debug/checkups/gnome-extensions.go | 2 +- pkg/debug/checkups/launchd.go | 2 +- pkg/debug/checkups/network.go | 51 +- pkg/debug/checkups/osquery.go | 14 +- pkg/debug/checkups/power_windows.go | 2 +- pkg/debug/checkups/services_windows.go | 2 +- pkg/execwrapper/exec_windows.go | 11 +- pkg/log/log.go | 6 +- pkg/osquery/runsimple/osqueryrunner.go | 16 +- .../runtime/runtime_helpers_windows.go | 2 +- pkg/osquery/table/mdfind_darwin.go | 2 +- pkg/osquery/table/mdm.go | 4 +- pkg/osquery/table/platform_tables_darwin.go | 21 +- pkg/osquery/table/platform_tables_linux.go | 24 +- pkg/osquery/table/platform_tables_windows.go | 3 +- pkg/osquery/table/table.go | 7 +- pkg/osquery/table/touchid_system_darwin.go | 4 +- pkg/osquery/table/touchid_user_darwin.go | 8 +- pkg/osquery/table/zerotier.go | 11 - pkg/osquery/table/zerotier_windows.go | 19 - pkg/osquery/tables/airport/table_darwin.go | 6 +- .../apple_silicon_security_policy/table.go | 3 +- .../crowdstrike/falcon_kernel_check/table.go | 5 +- .../tables/crowdstrike/falconctl/table.go | 7 +- .../crowdstrike/falconctl/table_test.go | 3 +- pkg/osquery/tables/cryptsetup/table.go | 3 +- pkg/osquery/tables/dataflattentable/exec.go | 62 +- .../tables/dataflattentable/exec_and_parse.go | 17 +- pkg/osquery/tables/dataflattentable/tables.go | 3 +- .../dev_table_tooling/commands_darwin.go | 15 - .../dev_table_tooling/commands_linux.go | 15 - .../dev_table_tooling/commands_windows.go | 17 - pkg/osquery/tables/dev_table_tooling/table.go | 18 +- pkg/osquery/tables/filevault/filevault.go | 3 +- .../tables/firmwarepasswd/firmwarepasswd.go | 2 +- pkg/osquery/tables/gsettings/gsettings.go | 2 +- pkg/osquery/tables/gsettings/metadata.go | 2 +- pkg/osquery/tables/ioreg/ioreg.go | 3 +- pkg/osquery/tables/mdmclient/mdmclient.go | 5 +- pkg/osquery/tables/profiles/profiles.go | 3 +- pkg/osquery/tables/pwpolicy/pwpolicy.go | 7 +- pkg/osquery/tables/pwpolicy/pwpolicy_test.go | 4 +- .../tables/systemprofiler/systemprofiler.go | 2 +- pkg/osquery/tables/tablehelpers/exec.go | 70 +- .../tablehelpers/exec_osquery_launchctl.go | 3 +- pkg/osquery/tables/tablehelpers/exec_test.go | 19 +- pkg/osquery/tables/zfs/tables.go | 9 +- pkg/ptycmd/command.go | 132 --- pkg/ptycmd/command_windows.go | 34 - pkg/ptycmd/options.go | 51 -- 65 files changed, 985 insertions(+), 1009 deletions(-) delete mode 100644 pkg/allowedpaths/cmd_darwin.go delete mode 100644 pkg/allowedpaths/cmd_linux.go delete mode 100644 pkg/allowedpaths/cmd_windows.go delete mode 100644 pkg/osquery/table/zerotier.go delete mode 100644 pkg/osquery/table/zerotier_windows.go delete mode 100644 pkg/osquery/tables/dev_table_tooling/commands_darwin.go delete mode 100644 pkg/osquery/tables/dev_table_tooling/commands_linux.go delete mode 100644 pkg/osquery/tables/dev_table_tooling/commands_windows.go delete mode 100644 pkg/ptycmd/command.go delete mode 100644 pkg/ptycmd/command_windows.go delete mode 100644 pkg/ptycmd/options.go diff --git a/cmd/launcher/uninstall_darwin.go b/cmd/launcher/uninstall_darwin.go index cd2d35fa5..80d9210d6 100644 --- a/cmd/launcher/uninstall_darwin.go +++ b/cmd/launcher/uninstall_darwin.go @@ -24,7 +24,7 @@ func removeLauncher(ctx context.Context, identifier string) error { launchctlCtx, cancel := context.WithTimeout(ctx, 30*time.Second) defer cancel() - cmd, err := allowedpaths.CommandContextWithLookup(launchctlCtx, "launchctl", launchCtlArgs...) + cmd, err := allowedpaths.Launchctl(launchctlCtx, launchCtlArgs...) if err != nil { fmt.Printf("could not find launchctl: %s\n", err) return err @@ -59,7 +59,7 @@ func removeLauncher(ctx context.Context, identifier string) error { pkgutiltCtx, cancel := context.WithTimeout(ctx, 30*time.Second) defer cancel() - pkgUtilcmd, err := allowedpaths.CommandContextWithLookup(pkgutiltCtx, "pkgutil", "--forget", fmt.Sprintf("com.%s.launcher", identifier)) + pkgUtilcmd, err := allowedpaths.Pkgutil(pkgutiltCtx, "--forget", fmt.Sprintf("com.%s.launcher", identifier)) if err != nil { fmt.Printf("could not find pkgutil: %s\n", err) return err diff --git a/cmd/launcher/uninstall_linux.go b/cmd/launcher/uninstall_linux.go index 441f07dd1..829f12e7c 100644 --- a/cmd/launcher/uninstall_linux.go +++ b/cmd/launcher/uninstall_linux.go @@ -23,7 +23,7 @@ func removeLauncher(ctx context.Context, identifier string) error { packageName := fmt.Sprintf("launcher-%s", identifier) // Stop and disable launcher service - cmd, err := allowedpaths.CommandContextWithLookup(ctx, "systemctl", []string{"disable", "--now", serviceName}...) + cmd, err := allowedpaths.Systemctl(ctx, []string{"disable", "--now", serviceName}...) if err != nil { fmt.Printf("could not find systemctl: %s\n", err) return err @@ -34,11 +34,11 @@ func removeLauncher(ctx context.Context, identifier string) error { } // Tell the appropriate package manager to remove launcher - if cmd, err := allowedpaths.CommandContextWithLookup(ctx, "dpkg", []string{"--purge", packageName}...); err == nil { + if cmd, err := allowedpaths.Dpkg(ctx, []string{"--purge", packageName}...); err == nil { if out, err := cmd.CombinedOutput(); err != nil { fmt.Printf("error occurred while running dpkg --purge, output %s: err: %s\n", string(out), err) } - } else if cmd, err := allowedpaths.CommandContextWithLookup(ctx, "rpm", []string{"-e", packageName}...); err == nil { + } else if cmd, err := allowedpaths.Rpm(ctx, []string{"-e", packageName}...); err == nil { if out, err := cmd.CombinedOutput(); err != nil { fmt.Printf("error occurred while running rpm -e, output %s: err: %s\n", string(out), err) } diff --git a/ee/consoleuser/consoleuser_darwin.go b/ee/consoleuser/consoleuser_darwin.go index 5d97c971a..c724e2784 100644 --- a/ee/consoleuser/consoleuser_darwin.go +++ b/ee/consoleuser/consoleuser_darwin.go @@ -91,7 +91,7 @@ const ( ) func CurrentUids(ctx context.Context) ([]string, error) { - cmd, err := allowedpaths.CommandContextWithLookup(ctx, "scutil") + cmd, err := allowedpaths.Scutil(ctx) if err != nil { return nil, fmt.Errorf("creating scutil command: %w", err) } diff --git a/ee/consoleuser/consoleuser_linux.go b/ee/consoleuser/consoleuser_linux.go index dc1a3f948..e3d6b3ef4 100644 --- a/ee/consoleuser/consoleuser_linux.go +++ b/ee/consoleuser/consoleuser_linux.go @@ -19,7 +19,7 @@ type listSessionsResult []struct { } func CurrentUids(ctx context.Context) ([]string, error) { - cmd, err := allowedpaths.CommandContextWithLookup(ctx, "loginctl", "list-sessions", "--no-legend", "--no-pager", "--output=json") + cmd, err := allowedpaths.Loginctl(ctx, "list-sessions", "--no-legend", "--no-pager", "--output=json") if err != nil { return nil, fmt.Errorf("creating loginctl command: %w", err) } @@ -47,7 +47,7 @@ func CurrentUids(ctx context.Context) ([]string, error) { } // get the active property of the session, this command does not respect the --output=json flag - cmd, err := allowedpaths.CommandContextWithLookup(ctx, "loginctl", "show-session", s.Session, "--value", "--property=Active") + cmd, err := allowedpaths.Loginctl(ctx, "show-session", s.Session, "--value", "--property=Active") if err != nil { return nil, fmt.Errorf("creating loginctl command: %w", err) } diff --git a/ee/desktop/runner/runner.go b/ee/desktop/runner/runner.go index 0bf9acb1f..c14a240e0 100644 --- a/ee/desktop/runner/runner.go +++ b/ee/desktop/runner/runner.go @@ -32,7 +32,6 @@ import ( "github.com/kolide/launcher/pkg/agent" "github.com/kolide/launcher/pkg/agent/flags/keys" "github.com/kolide/launcher/pkg/agent/types" - "github.com/kolide/launcher/pkg/allowedpaths" "github.com/kolide/launcher/pkg/backoff" "github.com/kolide/launcher/pkg/traces" "github.com/shirou/gopsutil/v3/process" @@ -756,10 +755,8 @@ func (r *DesktopUsersProcessesRunner) menuTemplatePath() string { // desktopCommand invokes the launcher desktop executable with the appropriate env vars func (r *DesktopUsersProcessesRunner) desktopCommand(executablePath, uid, socketPath, menuPath string) (*exec.Cmd, error) { - cmd, err := allowedpaths.CommandWithPath(executablePath, "desktop") - if err != nil { - return nil, fmt.Errorf("creating command: %w", err) - } + // We trust that launcher executable path is correct, so we don't need to use allowedpaths + cmd := exec.Command(executablePath, "desktop") //nolint:forbidigo cmd.Env = []string{ // When we set cmd.Env (as we're doing here/below), cmd will no longer include the default cmd.Environ() diff --git a/ee/desktop/runner/runner_linux.go b/ee/desktop/runner/runner_linux.go index cd7970342..a10895083 100644 --- a/ee/desktop/runner/runner_linux.go +++ b/ee/desktop/runner/runner_linux.go @@ -91,7 +91,7 @@ func (r *DesktopUsersProcessesRunner) userEnvVars(ctx context.Context, uid strin } // Get the user's session so we can get their display (needed for opening notification action URLs in browser) - cmd, err := allowedpaths.CommandContextWithLookup(ctx, "loginctl", "show-user", uid, "--value", "--property=Sessions") + cmd, err := allowedpaths.Loginctl(ctx, "show-user", uid, "--value", "--property=Sessions") if err != nil { level.Debug(r.logger).Log( "msg", "could not create loginctl command", @@ -118,7 +118,7 @@ func (r *DesktopUsersProcessesRunner) userEnvVars(ctx context.Context, uid strin sessionList := strings.Split(sessions, " ") for _, session := range sessionList { // Figure out what type of graphical session the user has -- x11, wayland? - cmd, err := allowedpaths.CommandContextWithLookup(ctx, "loginctl", "show-session", session, "--value", "--property=Type") + cmd, err := allowedpaths.Loginctl(ctx, "show-session", session, "--value", "--property=Type") if err != nil { level.Debug(r.logger).Log( "msg", "could not create loginctl command to get session type", @@ -169,7 +169,7 @@ func (r *DesktopUsersProcessesRunner) userEnvVars(ctx context.Context, uid strin func (r *DesktopUsersProcessesRunner) displayFromX11(ctx context.Context, session string) string { // We can read $DISPLAY from the session properties - cmd, err := allowedpaths.CommandContextWithLookup(ctx, "loginctl", "show-session", session, "--value", "--property=Display") + cmd, err := allowedpaths.Loginctl(ctx, "show-session", session, "--value", "--property=Display") if err != nil { level.Debug(r.logger).Log( "msg", "could not create command to get Display from user session", diff --git a/ee/desktop/user/menu/action_open_url_darwin.go b/ee/desktop/user/menu/action_open_url_darwin.go index bf8e3cf7c..316f6bdd0 100644 --- a/ee/desktop/user/menu/action_open_url_darwin.go +++ b/ee/desktop/user/menu/action_open_url_darwin.go @@ -4,6 +4,7 @@ package menu import ( + "context" "fmt" "github.com/kolide/launcher/pkg/allowedpaths" @@ -12,7 +13,7 @@ import ( // open opens the specified URL in the default browser of the user // See https://stackoverflow.com/a/39324149/1705598 func open(url string) error { - cmd, err := allowedpaths.CommandWithLookup("open", url) + cmd, err := allowedpaths.Open(context.TODO(), url) if err != nil { return fmt.Errorf("creating command: %w", err) } diff --git a/ee/desktop/user/menu/action_open_url_linux.go b/ee/desktop/user/menu/action_open_url_linux.go index 8f5e78f13..1a8a1559a 100644 --- a/ee/desktop/user/menu/action_open_url_linux.go +++ b/ee/desktop/user/menu/action_open_url_linux.go @@ -4,6 +4,7 @@ package menu import ( + "context" "fmt" "github.com/kolide/launcher/pkg/allowedpaths" @@ -12,7 +13,7 @@ import ( // open opens the specified URL in the default browser of the user // See https://stackoverflow.com/a/39324149/1705598 func open(url string) error { - cmd, err := allowedpaths.CommandWithLookup("xdg-open", url) + cmd, err := allowedpaths.Xdgopen(context.TODO(), url) if err != nil { return fmt.Errorf("creating command: %w", err) } diff --git a/ee/desktop/user/menu/action_open_url_windows.go b/ee/desktop/user/menu/action_open_url_windows.go index a677507d0..67f2a0071 100644 --- a/ee/desktop/user/menu/action_open_url_windows.go +++ b/ee/desktop/user/menu/action_open_url_windows.go @@ -4,6 +4,7 @@ package menu import ( + "context" "fmt" "syscall" @@ -13,7 +14,7 @@ import ( // open opens the specified URL in the default browser of the user // See https://stackoverflow.com/a/39324149/1705598 func open(url string) error { - cmd, err := allowedpaths.CommandWithLookup("cmd.exe", "/C", "start", url) + cmd, err := allowedpaths.Commandprompt(context.TODO(), "/C", "start", url) if err != nil { return fmt.Errorf("creating command: %w", err) } diff --git a/ee/desktop/user/notify/notify_linux.go b/ee/desktop/user/notify/notify_linux.go index 01afe24df..6c799322d 100644 --- a/ee/desktop/user/notify/notify_linux.go +++ b/ee/desktop/user/notify/notify_linux.go @@ -33,7 +33,7 @@ const ( // We default to xdg-open first because, if available, it appears to be better at picking // the correct default browser. -var browserLaunchers = []string{"xdg-open", "x-www-browser"} +var browserLaunchers = []allowedpaths.AllowedCommand{allowedpaths.Xdgopen, allowedpaths.Xwwwbrowser} func NewDesktopNotifier(logger log.Logger, iconFilepath string) *dbusNotifier { conn, err := dbus.ConnectSessionBus() @@ -89,7 +89,7 @@ func (d *dbusNotifier) Listen() error { for _, browserLauncher := range browserLaunchers { ctx, cancel := context.WithTimeout(context.Background(), time.Second*5) defer cancel() - cmd, err := allowedpaths.CommandContextWithLookup(ctx, browserLauncher, actionUri) + cmd, err := browserLauncher(ctx, actionUri) if err != nil { level.Warn(d.logger).Log("msg", "couldn't create command to start process", "err", err, "browser_launcher", browserLauncher) continue @@ -181,7 +181,7 @@ func (d *dbusNotifier) sendNotificationViaNotifySend(n Notification) error { args = append(args, "-i", d.iconFilepath) } - cmd, err := allowedpaths.CommandWithLookup("notify-send", args...) + cmd, err := allowedpaths.Notifysend(context.TODO(), args...) if err != nil { return fmt.Errorf("creating command: %w", err) } diff --git a/pkg/allowedpaths/cmd.go b/pkg/allowedpaths/cmd.go index 414ffcc79..06cb1ef9a 100644 --- a/pkg/allowedpaths/cmd.go +++ b/pkg/allowedpaths/cmd.go @@ -2,84 +2,783 @@ package allowedpaths import ( "context" + "errors" "fmt" + "os" "os/exec" + "path" "path/filepath" - "strings" + "runtime" ) -// CommandWithLookup should be used when the full path to the command is not known and it is -// likely to be found in PATH. -func CommandWithLookup(name string, arg ...string) (*exec.Cmd, error) { - fullPathToCommand, err := exec.LookPath(name) +type AllowedCommand func(ctx context.Context, arg ...string) (*exec.Cmd, error) + +func Airport(ctx context.Context, arg ...string) (*exec.Cmd, error) { + if runtime.GOOS != "darwin" { + return nil, errors.New("airport supported on darwin only") + } + + fullPathToCmdValidated, err := validatedPath("/System/Library/PrivateFrameworks/Apple80211.framework/Versions/Current/Resources/airport") + if err != nil { + return nil, fmt.Errorf("airport not found: %w", err) + } + return newCmd(fullPathToCmdValidated, arg...), nil +} + +func Apt(ctx context.Context, arg ...string) (*exec.Cmd, error) { + if runtime.GOOS != "linux" { + return nil, errors.New("apt supported on linux only") + } + + fullPathToCmdValidated, err := validatedPath("/usr/bin/apt") + if err != nil { + return nil, fmt.Errorf("apt not found: %w", err) + } + return newCmd(fullPathToCmdValidated, arg...), nil +} + +func Bioutil(ctx context.Context, arg ...string) (*exec.Cmd, error) { + if runtime.GOOS != "darwin" { + return nil, errors.New("bioutil supported on darwin only") + } + + fullPathToCmdValidated, err := validatedPath("/usr/bin/bioutil") + if err != nil { + return nil, fmt.Errorf("bioutil not found: %w", err) + } + return newCmd(fullPathToCmdValidated, arg...), nil +} + +func Bputil(ctx context.Context, arg ...string) (*exec.Cmd, error) { + if runtime.GOOS != "darwin" { + return nil, errors.New("bputil supported on darwin only") + } + + fullPathToCmdValidated, err := validatedPath("/usr/bin/bputil") + if err != nil { + return nil, fmt.Errorf("bputil not found: %w", err) + } + return newCmd(fullPathToCmdValidated, arg...), nil +} + +func Commandprompt(ctx context.Context, arg ...string) (*exec.Cmd, error) { + if runtime.GOOS != "windows" { + return nil, errors.New("cmd.exe supported on windows only") + } + + fullPathToCmdValidated, err := validatedPath(`C:\Windows\System32\cmd.exe`) + if err != nil { + return nil, fmt.Errorf("cmd.exe not found: %w", err) + } + return newCmd(fullPathToCmdValidated, arg...), nil +} + +func Cryptsetup(ctx context.Context, arg ...string) (*exec.Cmd, error) { + if runtime.GOOS != "linux" { + return nil, errors.New("cryptsetup supported on linux only") + } + + for _, p := range []string{"/usr/sbin/cryptsetup", "/sbin/cryptsetup"} { + fullPathToCmdValidated, err := validatedPath(p) + if err != nil { + continue + } + + return newCmd(fullPathToCmdValidated, arg...), nil + } + + return nil, errors.New("cryptsetup not found") +} + +func Diskutil(ctx context.Context, arg ...string) (*exec.Cmd, error) { + if runtime.GOOS != "darwin" { + return nil, errors.New("diskutil supported on darwin only") + } + + fullPathToCmdValidated, err := validatedPath("/usr/sbin/diskutil") + if err != nil { + return nil, fmt.Errorf("diskutil not found: %w", err) + } + return newCmd(fullPathToCmdValidated, arg...), nil +} + +func Dism(ctx context.Context, arg ...string) (*exec.Cmd, error) { + if runtime.GOOS != "windows" { + return nil, errors.New("dism.exe supported on windows only") + } + + fullPathToCmdValidated, err := validatedPath(`C:\Windows\System32\Dism.exe`) + if err != nil { + return nil, fmt.Errorf("dism.exe not found: %w", err) + } + return newCmd(fullPathToCmdValidated, arg...), nil +} + +func Dnf(ctx context.Context, arg ...string) (*exec.Cmd, error) { + if runtime.GOOS != "linux" { + return nil, errors.New("dnf supported on linux only") + } + + fullPathToCmdValidated, err := validatedPath("/usr/bin/dnf") + if err != nil { + return nil, fmt.Errorf("dnf not found: %w", err) + } + return newCmd(fullPathToCmdValidated, arg...), nil +} + +func Dpkg(ctx context.Context, arg ...string) (*exec.Cmd, error) { + if runtime.GOOS != "linux" { + return nil, errors.New("dpkg supported on linux only") + } + + fullPathToCmdValidated, err := validatedPath("/usr/bin/dpkg") + if err != nil { + return nil, fmt.Errorf("dpkg not found: %w", err) + } + return newCmd(fullPathToCmdValidated, arg...), nil +} + +func Dsregcmd(ctx context.Context, arg ...string) (*exec.Cmd, error) { + if runtime.GOOS != "windows" { + return nil, errors.New("dsregcmd.exe supported on windows only") + } + + fullPathToCmdValidated, err := validatedPath(`C:\Windows\System32\dsregcmd.exe`) + if err != nil { + return nil, fmt.Errorf("dsregcmd.exe not found: %w", err) + } + return newCmd(fullPathToCmdValidated, arg...), nil +} + +func Echo(ctx context.Context, arg ...string) (*exec.Cmd, error) { + // echo on Windows is only available as a command in cmd.exe + if runtime.GOOS == "windows" { + return Commandprompt(ctx, append([]string{"echo"}, arg...)...) + } + + var fullPathToCmd string + switch runtime.GOOS { + case "darwin": + fullPathToCmd = "/bin/echo" + case "linux": + fullPathToCmd = "/usr/bin/echo" + } + + fullPathToCmdValidated, err := validatedPath(fullPathToCmd) + if err != nil { + return nil, fmt.Errorf("echo not found: %w", err) + } + return newCmd(fullPathToCmdValidated, arg...), nil +} + +func Falconctl(ctx context.Context, arg ...string) (*exec.Cmd, error) { + if runtime.GOOS != "darwin" && runtime.GOOS != "linux" { + return nil, errors.New("falconctl supported on darwin and linux only") + } + + var fullPathToCmd string + switch runtime.GOOS { + case "darwin": + fullPathToCmd = "/Applications/Falcon.app/Contents/Resources/falconctl" + case "linux": + fullPathToCmd = "/opt/CrowdStrike/falconctl" + } + + fullPathToCmdValidated, err := validatedPath(fullPathToCmd) + if err != nil { + return nil, fmt.Errorf("falconctl not found: %w", err) + } + return newCmd(fullPathToCmdValidated, arg...), nil +} + +func Falconkernelcheck(ctx context.Context, arg ...string) (*exec.Cmd, error) { + if runtime.GOOS != "linux" { + return nil, errors.New("falcon-kernel-check supported on linux only") + } + + fullPathToCmdValidated, err := validatedPath("/opt/CrowdStrike/falcon-kernel-check") if err != nil { - return nil, fmt.Errorf("looking up path to %s: %w", name, err) + return nil, fmt.Errorf("falcon-kernel-check not found: %w", err) + } + return newCmd(fullPathToCmdValidated, arg...), nil +} + +func Fdesetup(ctx context.Context, arg ...string) (*exec.Cmd, error) { + if runtime.GOOS != "darwin" { + return nil, errors.New("fdesetup supported on darwin only") } - return CommandWithPath(fullPathToCommand, arg...) + fullPathToCmdValidated, err := validatedPath("/usr/bin/fdesetup") + if err != nil { + return nil, fmt.Errorf("fdesetup not found: %w", err) + } + return newCmd(fullPathToCmdValidated, arg...), nil } -// CommandWithPath should be used when the full path to the command is known, or unlikely to be -// found in PATH. -func CommandWithPath(fullPathToCommand string, arg ...string) (*exec.Cmd, error) { - fullPathToCommand = filepath.Clean(fullPathToCommand) +func Firmwarepasswd(ctx context.Context, arg ...string) (*exec.Cmd, error) { + if runtime.GOOS != "darwin" { + return nil, errors.New("firmwarepasswd supported on darwin only") + } - if err := pathIsAllowed(fullPathToCommand); err != nil { - return nil, fmt.Errorf("path is not allowed: %w", err) + fullPathToCmdValidated, err := validatedPath("/usr/sbin/firmwarepasswd") + if err != nil { + return nil, fmt.Errorf("firmwarepasswd not found: %w", err) } + return newCmd(fullPathToCmdValidated, arg...), nil +} - return exec.Command(fullPathToCommand, arg...), nil //nolint:forbidigo +func Gnomeextensions(ctx context.Context, arg ...string) (*exec.Cmd, error) { + if runtime.GOOS != "linux" { + return nil, errors.New("gnome-extensions supported on linux only") + } + + fullPathToCmdValidated, err := validatedPath("/usr/bin/gnome-extensions") + if err != nil { + return nil, fmt.Errorf("gnome-extensions not found: %w", err) + } + return newCmd(fullPathToCmdValidated, arg...), nil +} + +func Gsettings(ctx context.Context, arg ...string) (*exec.Cmd, error) { + if runtime.GOOS != "linux" { + return nil, errors.New("gsettings supported on linux only") + } + + fullPathToCmdValidated, err := validatedPath("/usr/bin/gsettings") + if err != nil { + return nil, fmt.Errorf("gsettings not found: %w", err) + } + return newCmd(fullPathToCmdValidated, arg...), nil } -// CommandContextWithLookup should be used when the full path to the command is not known and it is -// likely to be found in PATH. -func CommandContextWithLookup(ctx context.Context, name string, arg ...string) (*exec.Cmd, error) { - fullPathToCommand, err := exec.LookPath(name) +func Ifconfig(ctx context.Context, arg ...string) (*exec.Cmd, error) { + if runtime.GOOS != "darwin" && runtime.GOOS != "linux" { + return nil, errors.New("ifconfig supported on darwin and linux only") + } + + var fullPathToCmd string + switch runtime.GOOS { + case "darwin": + fullPathToCmd = "/sbin/ifconfig" + case "linux": + fullPathToCmd = "/usr/sbin/ifconfig" + } + + fullPathToCmdValidated, err := validatedPath(fullPathToCmd) if err != nil { - return nil, fmt.Errorf("looking up path to %s: %w", name, err) + return nil, fmt.Errorf("ifconfig not found: %w", err) } + return newCmd(fullPathToCmdValidated, arg...), nil +} - return CommandContextWithPath(ctx, fullPathToCommand, arg...) +func Ioreg(ctx context.Context, arg ...string) (*exec.Cmd, error) { + if runtime.GOOS != "darwin" { + return nil, errors.New("ioreg supported on darwin only") + } + + fullPathToCmdValidated, err := validatedPath("/usr/sbin/ioreg") + if err != nil { + return nil, fmt.Errorf("ioreg not found: %w", err) + } + return newCmd(fullPathToCmdValidated, arg...), nil } -// CommandContextWithPath should be used when the full path to the command is known, or unlikely to be -// found in PATH. -func CommandContextWithPath(ctx context.Context, fullPathToCommand string, arg ...string) (*exec.Cmd, error) { - fullPathToCommand = filepath.Clean(fullPathToCommand) +func Ip(ctx context.Context, arg ...string) (*exec.Cmd, error) { + if runtime.GOOS != "linux" { + return nil, errors.New("ip supported on linux only") + } - if err := pathIsAllowed(fullPathToCommand); err != nil { - return nil, fmt.Errorf("path is not allowed: %w", err) + fullPathToCmdValidated, err := validatedPath("/usr/sbin/ip") + if err != nil { + return nil, fmt.Errorf("ip not found: %w", err) + } + return newCmd(fullPathToCmdValidated, arg...), nil +} + +func Ipconfig(ctx context.Context, arg ...string) (*exec.Cmd, error) { + if runtime.GOOS != "windows" { + return nil, errors.New("ipconfig.exe supported on windows only") } - return exec.CommandContext(ctx, fullPathToCommand, arg...), nil //nolint:forbidigo + fullPathToCmdValidated, err := validatedPath(`C:\Windows\System32\ipconfig.exe`) + if err != nil { + return nil, fmt.Errorf("ipconfig.exe not found: %w", err) + } + return newCmd(fullPathToCmdValidated, arg...), nil } -// pathIsAllowed validates the path to the command against our allowlist. -func pathIsAllowed(fullPathToCommand string) error { - cmdName := strings.ToLower(filepath.Base(fullPathToCommand)) +func Launchctl(ctx context.Context, arg ...string) (*exec.Cmd, error) { + if runtime.GOOS != "darwin" { + return nil, errors.New("launchctl supported on darwin only") + } + + fullPathToCmdValidated, err := validatedPath("/bin/launchctl") + if err != nil { + return nil, fmt.Errorf("launchctl not found: %w", err) + } + return newCmd(fullPathToCmdValidated, arg...), nil +} - // We trust the autoupdate libraries to select the correct paths - if cmdName == "launcher" || cmdName == "launcher.exe" || cmdName == "osqueryd" || cmdName == "osqueryd.exe" { - return nil +func Loginctl(ctx context.Context, arg ...string) (*exec.Cmd, error) { + if runtime.GOOS != "linux" { + return nil, errors.New("loginctl supported on linux only") } - // Check that we have known paths for the given command - knownCmdPaths, ok := knownPaths[cmdName] - if !ok { - return fmt.Errorf("no known paths for command %s, cannot validate path %s", cmdName, fullPathToCommand) + fullPathToCmdValidated, err := validatedPath("/usr/bin/loginctl") + if err != nil { + return nil, fmt.Errorf("loginctl not found: %w", err) } + return newCmd(fullPathToCmdValidated, arg...), nil +} - // Check if this path is registered - if _, ok := knownCmdPaths[fullPathToCommand]; ok { - return nil +func Lsblk(ctx context.Context, arg ...string) (*exec.Cmd, error) { + if runtime.GOOS != "linux" { + return nil, errors.New("lsblk supported on linux only") } - // Check to make sure the command is at least in a known directory - for _, knownPathPrefix := range knownPathPrefixes { - if strings.HasPrefix(fullPathToCommand, knownPathPrefix) { - return nil + for _, p := range []string{"/bin/lsblk", "/usr/bin/lsblk"} { + fullPathToCmdValidated, err := validatedPath(p) + if err != nil { + continue } + + return newCmd(fullPathToCmdValidated, arg...), nil + } + + return nil, errors.New("lsblk not found") +} + +func Lsof(ctx context.Context, arg ...string) (*exec.Cmd, error) { + if runtime.GOOS != "darwin" && runtime.GOOS != "linux" { + return nil, errors.New("lsof supported on darwin and linux only") + } + + var fullPathToCmd string + switch runtime.GOOS { + case "darwin": + fullPathToCmd = "/usr/sbin/lsof" + case "linux": + fullPathToCmd = "/usr/bin/lsof" + } + + fullPathToCmdValidated, err := validatedPath(fullPathToCmd) + if err != nil { + return nil, fmt.Errorf("lsof not found: %w", err) + } + return newCmd(fullPathToCmdValidated, arg...), nil +} + +func Mdfind(ctx context.Context, arg ...string) (*exec.Cmd, error) { + if runtime.GOOS != "darwin" { + return nil, errors.New("mdfind supported on darwin only") + } + + fullPathToCmdValidated, err := validatedPath("/usr/bin/mdfind") + if err != nil { + return nil, fmt.Errorf("mdfind not found: %w", err) + } + return newCmd(fullPathToCmdValidated, arg...), nil +} + +func Mdmclient(ctx context.Context, arg ...string) (*exec.Cmd, error) { + if runtime.GOOS != "darwin" { + return nil, errors.New("mdmclient supported on darwin only") + } + + fullPathToCmdValidated, err := validatedPath("/usr/libexec/mdmclient") + if err != nil { + return nil, fmt.Errorf("mdmclient not found: %w", err) + } + return newCmd(fullPathToCmdValidated, arg...), nil +} + +func Netstat(ctx context.Context, arg ...string) (*exec.Cmd, error) { + if runtime.GOOS != "darwin" { + return nil, errors.New("netstat supported on darwin only") + } + + fullPathToCmdValidated, err := validatedPath("/usr/sbin/netstat") + if err != nil { + return nil, fmt.Errorf("netstat not found: %w", err) + } + return newCmd(fullPathToCmdValidated, arg...), nil +} + +func Nmcli(ctx context.Context, arg ...string) (*exec.Cmd, error) { + if runtime.GOOS != "linux" { + return nil, errors.New("nmcli supported on linux only") + } + + fullPathToCmdValidated, err := validatedPath("/usr/bin/nmcli") + if err != nil { + return nil, fmt.Errorf("nmcli not found: %w", err) + } + return newCmd(fullPathToCmdValidated, arg...), nil +} + +func Notifysend(ctx context.Context, arg ...string) (*exec.Cmd, error) { + if runtime.GOOS != "linux" { + return nil, errors.New("notify-send supported on linux only") + } + + fullPathToCmdValidated, err := validatedPath("/usr/bin/notify-send") + if err != nil { + return nil, fmt.Errorf("notify-send not found: %w", err) + } + return newCmd(fullPathToCmdValidated, arg...), nil +} + +func Open(ctx context.Context, arg ...string) (*exec.Cmd, error) { + if runtime.GOOS != "darwin" { + return nil, errors.New("open supported on darwin only") + } + + fullPathToCmdValidated, err := validatedPath("/usr/bin/open") + if err != nil { + return nil, fmt.Errorf("open not found: %w", err) + } + return newCmd(fullPathToCmdValidated, arg...), nil +} + +func Pacman(ctx context.Context, arg ...string) (*exec.Cmd, error) { + if runtime.GOOS != "linux" { + return nil, errors.New("pacman supported on linux only") + } + + fullPathToCmdValidated, err := validatedPath("/usr/bin/pacman") + if err != nil { + return nil, fmt.Errorf("pacman not found: %w", err) + } + return newCmd(fullPathToCmdValidated, arg...), nil +} + +func Pkgutil(ctx context.Context, arg ...string) (*exec.Cmd, error) { + if runtime.GOOS != "darwin" { + return nil, errors.New("pkgutil supported on darwin only") + } + + fullPathToCmdValidated, err := validatedPath("/usr/sbin/pkgutil") + if err != nil { + return nil, fmt.Errorf("pkgutil not found: %w", err) + } + return newCmd(fullPathToCmdValidated, arg...), nil +} + +func Powercfg(ctx context.Context, arg ...string) (*exec.Cmd, error) { + if runtime.GOOS != "windows" { + return nil, errors.New("powercfg.exe supported on windows only") + } + + fullPathToCmdValidated, err := validatedPath(`C:\Windows\System32\powercfg.exe`) + if err != nil { + return nil, fmt.Errorf("powercfg.exe not found: %w", err) + } + return newCmd(fullPathToCmdValidated, arg...), nil +} + +func Powermetrics(ctx context.Context, arg ...string) (*exec.Cmd, error) { + if runtime.GOOS != "darwin" { + return nil, errors.New("powermetrics supported on darwin only") + } + + fullPathToCmdValidated, err := validatedPath("/usr/bin/powermetrics") + if err != nil { + return nil, fmt.Errorf("powermetrics not found: %w", err) + } + return newCmd(fullPathToCmdValidated, arg...), nil +} + +func Powershell(ctx context.Context, arg ...string) (*exec.Cmd, error) { + if runtime.GOOS != "windows" { + return nil, errors.New("powershell.exe supported on windows only") + } + + fullPathToCmdValidated, err := validatedPath(`C:\Windows\System32\WindowsPowerShell\v1.0\powershell.exe`) + if err != nil { + return nil, fmt.Errorf("powershell.exe not found: %w", err) + } + return newCmd(fullPathToCmdValidated, arg...), nil +} + +func Profiles(ctx context.Context, arg ...string) (*exec.Cmd, error) { + if runtime.GOOS != "darwin" { + return nil, errors.New("profiles supported on darwin only") + } + + fullPathToCmdValidated, err := validatedPath("/usr/bin/profiles") + if err != nil { + return nil, fmt.Errorf("profiles not found: %w", err) + } + return newCmd(fullPathToCmdValidated, arg...), nil +} + +func Ps(ctx context.Context, arg ...string) (*exec.Cmd, error) { + if runtime.GOOS != "darwin" && runtime.GOOS != "linux" { + return nil, errors.New("ps supported on darwin and linux only") + } + + var fullPathToCmd string + switch runtime.GOOS { + case "darwin": + fullPathToCmd = "/bin/ps" + case "linux": + fullPathToCmd = "/usr/bin/ps" + } + + fullPathToCmdValidated, err := validatedPath(fullPathToCmd) + if err != nil { + return nil, fmt.Errorf("ps not found: %w", err) + } + return newCmd(fullPathToCmdValidated, arg...), nil +} + +func Pwpolicy(ctx context.Context, arg ...string) (*exec.Cmd, error) { + if runtime.GOOS != "darwin" { + return nil, errors.New("pwpolicy supported on darwin only") + } + + fullPathToCmdValidated, err := validatedPath("/usr/bin/pwpolicy") + if err != nil { + return nil, fmt.Errorf("pwpolicy not found: %w", err) + } + return newCmd(fullPathToCmdValidated, arg...), nil +} + +func Remotectl(ctx context.Context, arg ...string) (*exec.Cmd, error) { + if runtime.GOOS != "darwin" { + return nil, errors.New("remotectl supported on darwin only") + } + + fullPathToCmdValidated, err := validatedPath("/usr/libexec/remotectl") + if err != nil { + return nil, fmt.Errorf("remotectl not found: %w", err) + } + return newCmd(fullPathToCmdValidated, arg...), nil +} + +func Repcli(ctx context.Context, arg ...string) (*exec.Cmd, error) { + var fullPathToCmd string + switch runtime.GOOS { + case "darwin": + fullPathToCmd = "/Applications/VMware Carbon Black Cloud/repcli.bundle/Contents/MacOS/repcli" + case "linux": + fullPathToCmd = "/opt/carbonblack/psc/bin/repcli" + case "windows": + fullPathToCmd = filepath.Join("Program Files", "Confer", "repcli") + } + + fullPathToCmdValidated, err := validatedPath(fullPathToCmd) + if err != nil { + return nil, fmt.Errorf("repcli not found: %w", err) + } + return newCmd(fullPathToCmdValidated, arg...), nil +} + +func Rpm(ctx context.Context, arg ...string) (*exec.Cmd, error) { + if runtime.GOOS != "linux" { + return nil, errors.New("rpm supported on linux only") + } + + for _, p := range []string{"/bin/rpm", "/usr/bin/rpm"} { + fullPathToCmdValidated, err := validatedPath(p) + if err != nil { + continue + } + + return newCmd(fullPathToCmdValidated, arg...), nil + } + + return nil, errors.New("rpm not found") +} + +func Scutil(ctx context.Context, arg ...string) (*exec.Cmd, error) { + if runtime.GOOS != "darwin" { + return nil, errors.New("scutil supported on darwin only") + } + + fullPathToCmdValidated, err := validatedPath("/usr/sbin/scutil") + if err != nil { + return nil, fmt.Errorf("scutil not found: %w", err) + } + return newCmd(fullPathToCmdValidated, arg...), nil +} + +func Secedit(ctx context.Context, arg ...string) (*exec.Cmd, error) { + if runtime.GOOS != "windows" { + return nil, errors.New("secedit.exe supported on windows only") + } + + fullPathToCmdValidated, err := validatedPath(`C:\Windows\System32\SecEdit.exe`) + if err != nil { + return nil, fmt.Errorf("secedit.exe not found: %w", err) + } + return newCmd(fullPathToCmdValidated, arg...), nil +} + +func Softwareupdate(ctx context.Context, arg ...string) (*exec.Cmd, error) { + if runtime.GOOS != "darwin" { + return nil, errors.New("softwareupdate supported on darwin only") + } + + fullPathToCmdValidated, err := validatedPath("/usr/sbin/softwareupdate") + if err != nil { + return nil, fmt.Errorf("softwareupdate not found: %w", err) + } + return newCmd(fullPathToCmdValidated, arg...), nil +} + +func Systemctl(ctx context.Context, arg ...string) (*exec.Cmd, error) { + if runtime.GOOS != "linux" { + return nil, errors.New("systemctl supported on linux only") + } + + fullPathToCmdValidated, err := validatedPath("/usr/bin/systemctl") + if err != nil { + return nil, fmt.Errorf("systemctl not found: %w", err) + } + return newCmd(fullPathToCmdValidated, arg...), nil +} + +func Systemprofiler(ctx context.Context, arg ...string) (*exec.Cmd, error) { + if runtime.GOOS != "darwin" { + return nil, errors.New("system_profiler supported on darwin only") + } + + fullPathToCmdValidated, err := validatedPath("/usr/sbin/system_profiler") + if err != nil { + return nil, fmt.Errorf("system_profiler not found: %w", err) + } + return newCmd(fullPathToCmdValidated, arg...), nil +} + +func Taskkill(ctx context.Context, arg ...string) (*exec.Cmd, error) { + if runtime.GOOS != "windows" { + return nil, errors.New("taskkill.exe supported on windows only") + } + + fullPathToCmdValidated, err := validatedPath(`C:\Windows\System32\taskkill.exe`) + if err != nil { + return nil, fmt.Errorf("taskkill.exe not found: %w", err) + } + return newCmd(fullPathToCmdValidated, arg...), nil +} + +func Tmutil(ctx context.Context, arg ...string) (*exec.Cmd, error) { + if runtime.GOOS != "darwin" { + return nil, errors.New("tmutil supported on darwin only") + } + + fullPathToCmdValidated, err := validatedPath("/usr/bin/tmutil") + if err != nil { + return nil, fmt.Errorf("tmutil not found: %w", err) + } + return newCmd(fullPathToCmdValidated, arg...), nil +} + +func Xdgopen(ctx context.Context, arg ...string) (*exec.Cmd, error) { + if runtime.GOOS != "linux" { + return nil, errors.New("xdg-open supported on linux only") + } + + fullPathToCmdValidated, err := validatedPath("/usr/bin/xdg-open") + if err != nil { + return nil, fmt.Errorf("xdg-open not found: %w", err) + } + return newCmd(fullPathToCmdValidated, arg...), nil +} + +func Xrdb(ctx context.Context, arg ...string) (*exec.Cmd, error) { + if runtime.GOOS != "linux" { + return nil, errors.New("xrdb supported on linux only") + } + + fullPathToCmdValidated, err := validatedPath("/usr/bin/xrdb") + if err != nil { + return nil, fmt.Errorf("xrdb not found: %w", err) + } + return newCmd(fullPathToCmdValidated, arg...), nil +} + +func Xwwwbrowser(ctx context.Context, arg ...string) (*exec.Cmd, error) { + if runtime.GOOS != "linux" { + return nil, errors.New("x-www-browser supported on linux only") + } + + fullPathToCmdValidated, err := validatedPath("/usr/bin/x-www-browser") + if err != nil { + return nil, fmt.Errorf("x-www-browser not found: %w", err) + } + return newCmd(fullPathToCmdValidated, arg...), nil +} + +func Zerotiercli(ctx context.Context, arg ...string) (*exec.Cmd, error) { + var fullPathToCmd string + switch runtime.GOOS { + case "darwin", "linux": + fullPathToCmd = "/usr/local/bin/zerotier-cli" + case "windows": + fullPathToCmd = path.Join(os.Getenv("SYSTEMROOT"), "ProgramData", "ZeroTier", "One", "zerotier-one_x64.exe") + } + + fullPathToCmdValidated, err := validatedPath(fullPathToCmd) + if err != nil { + return nil, fmt.Errorf("zerotier-cli not found: %w", err) + } + + // For windows, "-q" should be prepended before all other args + if runtime.GOOS == "windows" { + arg = append([]string{"-q"}, arg...) + } + + return newCmd(fullPathToCmdValidated, arg...), nil +} + +func Zfs(ctx context.Context, arg ...string) (*exec.Cmd, error) { + if runtime.GOOS != "linux" { + return nil, errors.New("zfs supported on linux only") + } + + fullPathToCmdValidated, err := validatedPath("/usr/sbin/zfs") + if err != nil { + return nil, fmt.Errorf("zfs not found: %w", err) + } + return newCmd(fullPathToCmdValidated, arg...), nil +} + +func Zpool(ctx context.Context, arg ...string) (*exec.Cmd, error) { + if runtime.GOOS != "linux" { + return nil, errors.New("zpool supported on linux only") + } + + fullPathToCmdValidated, err := validatedPath("/usr/sbin/zpool") + if err != nil { + return nil, fmt.Errorf("zpool not found: %w", err) + } + return newCmd(fullPathToCmdValidated, arg...), nil +} + +func newCmd(fullPathToCmd string, arg ...string) *exec.Cmd { + return exec.Command(fullPathToCmd, arg...) //nolint:forbidigo +} + +func validatedPath(knownPath string) (string, error) { + knownPath = filepath.Clean(knownPath) + + if _, err := os.Stat(knownPath); err == nil { + return knownPath, nil + } + + // Not found at known location -- return error for darwin and windows. + // We expect to know the exact location for allowlisted commands on all + // OSes except for a few Linux distros. + if runtime.GOOS != "linux" { + return "", fmt.Errorf("not found: %s", knownPath) + } + + cmdName := filepath.Base(knownPath) + if foundPath, err := exec.LookPath(cmdName); err == nil { + return foundPath, nil } - return fmt.Errorf("%s not in known paths and does not have known prefix", fullPathToCommand) + return "", fmt.Errorf("%s not found at %s and could not be located elsewhere", cmdName, knownPath) } diff --git a/pkg/allowedpaths/cmd_darwin.go b/pkg/allowedpaths/cmd_darwin.go deleted file mode 100644 index 64001572b..000000000 --- a/pkg/allowedpaths/cmd_darwin.go +++ /dev/null @@ -1,96 +0,0 @@ -//go:build darwin -// +build darwin - -package allowedpaths - -var knownPaths = map[string]map[string]bool{ - "airport": { - "/System/Library/PrivateFrameworks/Apple80211.framework/Versions/Current/Resources/airport": true, - }, - "bioutil": { - "/usr/bin/bioutil": true, - }, - "bputil": { - "/usr/bin/bputil": true, - }, - "diskutil": { - "/usr/sbin/diskutil": true, - }, - "falconctl": { - "/Applications/Falcon.app/Contents/Resources/falconctl": true, - }, - "fdesetup": { - "/usr/bin/fdesetup": true, - }, - "firmwarepasswd": { - "/usr/sbin/firmwarepasswd": true, - }, - "ifconfig": { - "/sbin/ifconfig": true, - }, - "ioreg": { - "/usr/sbin/ioreg": true, - }, - "launchctl": { - "/bin/launchctl": true, - }, - "lsof": { - "/usr/sbin/lsof": true, - }, - "mdfind": { - "/usr/bin/mdfind": true, - }, - "mdmclient": { - "/usr/libexec/mdmclient": true, - }, - "netstat": { - "/usr/sbin/netstat": true, - }, - "open": { - "/usr/bin/open": true, - }, - "pkgutil": { - "/usr/sbin/pkgutil": true, - }, - "powermetrics": { - "/usr/bin/powermetrics": true, - }, - "profiles": { - "/usr/bin/profiles": true, - }, - "ps": { - "/bin/ps": true, - }, - "pwpolicy": { - "/usr/bin/pwpolicy": true, - }, - "remotectl": { - "/usr/libexec/remotectl": true, - }, - "repcli": { - "/Applications/VMware Carbon Black Cloud/repcli.bundle/Contents/MacOS/repcli": true, - }, - "scutil": { - "/usr/sbin/scutil": true, - }, - "softwareupdate": { - "/usr/sbin/softwareupdate": true, - }, - "system_profiler": { - "/usr/sbin/system_profiler": true, - }, - "tmutil": { - "/usr/bin/tmutil": true, - }, - "zerotier-cli": { - "/usr/local/bin/zerotier-cli": true, - }, -} - -var knownPathPrefixes = []string{ - "/bin", - "/usr/bin", - "/usr/libexec", - "/usr/local/bin", - "/usr/sbin", -} diff --git a/pkg/allowedpaths/cmd_linux.go b/pkg/allowedpaths/cmd_linux.go deleted file mode 100644 index d2529bd30..000000000 --- a/pkg/allowedpaths/cmd_linux.go +++ /dev/null @@ -1,99 +0,0 @@ -//go:build linux -// +build linux - -package allowedpaths - -var knownPaths = map[string]map[string]bool{ - "apt": { - "/usr/bin/apt": true, - }, - "cryptsetup": { - "/usr/sbin/cryptsetup": true, - "/sbin/cryptsetup": true, - }, - "dnf": { - "/usr/bin/dnf": true, - }, - "dpkg": { - "/usr/bin/dpkg": true, - }, - "lsof": { - "/usr/bin/lsof": true, - }, - "falcon-kernel-check": { - "/opt/CrowdStrike/falcon-kernel-check": true, - }, - "falconctl": { - "/opt/CrowdStrike/falconctl": true, - }, - "gnome-extensions": { - "/usr/bin/gnome-extensions": true, - }, - "gsettings": { - "/usr/bin/gsettings": true, - }, - "ifconfig": { - "/usr/sbin/ifconfig": true, - }, - "ip": { - "/usr/sbin/ip": true, - }, - "loginctl": { - "/usr/bin/loginctl": true, - }, - "lsblk": { - "/bin/lsblk": true, - "/usr/bin/lsblk": true, - }, - "mdmclient": { - "/usr/libexec/mdmclient": true, - }, - "nmcli": { - "/usr/bin/nmcli": true, - }, - "notify-send": { - "/usr/bin/notify-send": true, - }, - "pacman": { - "/usr/bin/pacman": true, - }, - "ps": { - "/usr/bin/ps": true, - }, - "repcli": { - "/opt/carbonblack/psc/bin/repcli": true, - }, - "rpm": { - "/usr/bin/rpm": true, - "/bin/rpm": true, - }, - "systemctl": { - "/usr/bin/systemctl": true, - }, - "x-www-browser": { - "/usr/bin/x-www-browser": true, - }, - "xdg-open": { - "/usr/bin/xdg-open": true, - }, - "xrdb": { - "/usr/bin/xrdb": true, - }, - "zerotier-cli": { - "/usr/local/bin/zerotier-cli": true, - }, - "zfs": { - "/usr/sbin/zfs": true, - }, - "zpool": { - "/usr/sbin/zpool": true, - }, -} - -var knownPathPrefixes = []string{ - "/bin", - "/nix/store", // NixOS support - "/usr/bin", - "/usr/local/bin", - "/usr/sbin", -} diff --git a/pkg/allowedpaths/cmd_test.go b/pkg/allowedpaths/cmd_test.go index 8dc5b0796..ca13f12d5 100644 --- a/pkg/allowedpaths/cmd_test.go +++ b/pkg/allowedpaths/cmd_test.go @@ -1,201 +1,34 @@ package allowedpaths import ( - "context" "path/filepath" "runtime" - "strings" "testing" "github.com/stretchr/testify/require" ) -func TestCommandWithLookup(t *testing.T) { +func Test_newCmd(t *testing.T) { t.Parallel() - var cmdName string - if runtime.GOOS == "windows" { - cmdName = "powershell.exe" - } else { - // On Linux and Darwin we expect ps to be available, even on the CI runner - cmdName = "ps" - } - - cmd, err := CommandWithLookup(cmdName) - require.NoError(t, err, "expected to find command") - require.True(t, strings.HasSuffix(cmd.Path, cmdName)) -} - -func TestCommandWithLookup_NotFound(t *testing.T) { - t.Parallel() - - cmdName := "some-cmd" - _, err := CommandWithLookup(cmdName) - require.Error(t, err, "should not have found cmd") -} - -func TestCommandWithPath_Allowed(t *testing.T) { - t.Parallel() - - for cmdName, cmdPaths := range knownPaths { - cmdName := cmdName - cmdPaths := cmdPaths - t.Run(cmdName, func(t *testing.T) { - t.Parallel() - - for p := range cmdPaths { - cmd, err := CommandWithPath(p) - require.NoError(t, err, "expected no error with known path") - require.Equal(t, p, cmd.Path) - } - }) - } -} - -func TestCommandWithPath_Denied(t *testing.T) { - t.Parallel() - - // Unknown command - _, err := CommandWithPath(filepath.Join("some", "path", "to", "not-a-real-command")) - require.Error(t, err, "expected unknown command to be denylisted") - - // Known command, unknown path - for cmdName := range knownPaths { - _, err := CommandWithPath(filepath.Join("some", "incorrect", "path", "to", cmdName)) - require.Error(t, err, "expected unknown path to be denylisted") - - // We don't need to perform this same test against every known path - break - } + cmdPath := filepath.Join("some", "path", "to", "a", "command") + cmd := newCmd(cmdPath) + require.Equal(t, cmdPath, cmd.Path) } -func TestCommandWithPath_AutoupdatePaths(t *testing.T) { +func Test_validatedPath(t *testing.T) { t.Parallel() - for _, b := range []string{"launcher", "launcher.exe", "osqueryd", "osqueryd.exe"} { - b := b - t.Run(b, func(t *testing.T) { - t.Parallel() - - autoupdatedBinaryPath := filepath.Join("some", "autoupdate", "path", "to", b) - cmd, err := CommandWithPath(autoupdatedBinaryPath) - require.NoError(t, err, "expected autoupdated binaries to be allowed") - require.Equal(t, autoupdatedBinaryPath, cmd.Path) - }) + var cmdPath string + switch runtime.GOOS { + case "darwin", "linux": + cmdPath = "/bin/bash" + case "windows": + cmdPath = `C:\Windows\System32\WindowsPowerShell\v1.0\powershell.exe` } -} - -func TestCommandWithPath_KnownPrefix(t *testing.T) { - t.Parallel() - for cmdName := range knownPaths { - cmdName := cmdName - t.Run(cmdName, func(t *testing.T) { - t.Parallel() - - for _, p := range knownPathPrefixes { - pathToCmdWithKnownPrefix := filepath.Join(p, cmdName) - cmd, err := CommandWithPath(pathToCmdWithKnownPrefix) - require.NoError(t, err, "expected no error with known command and directory prefix") - require.Equal(t, pathToCmdWithKnownPrefix, cmd.Path) - } - }) - } -} - -func TestCommandContextWithLookup(t *testing.T) { - t.Parallel() - - var cmdName string - if runtime.GOOS == "windows" { - cmdName = "powershell.exe" - } else { - // On Linux and Darwin we expect ps to be available, even on the CI runner - cmdName = "ps" - } + p, err := validatedPath(cmdPath) - cmd, err := CommandContextWithLookup(context.TODO(), cmdName) - require.NoError(t, err, "expected to find command") - require.True(t, strings.HasSuffix(cmd.Path, cmdName)) - require.NotNil(t, cmd.Cancel, "context not set on command") -} - -func TestCommandContextWithLookup_NotFound(t *testing.T) { - t.Parallel() - - cmdName := "some-cmd" - _, err := CommandContextWithLookup(context.TODO(), cmdName) - require.Error(t, err, "should not have found cmd") -} - -func TestCommandContextWithPath_Allowed(t *testing.T) { - t.Parallel() - - for cmdName, cmdPaths := range knownPaths { - cmdName := cmdName - cmdPaths := cmdPaths - t.Run(cmdName, func(t *testing.T) { - t.Parallel() - - for p := range cmdPaths { - cmd, err := CommandContextWithPath(context.TODO(), p) - require.NoError(t, err, "expected no error with known path") - require.Equal(t, p, cmd.Path) - require.NotNil(t, cmd.Cancel, "context not set on command") - } - }) - } -} - -func TestCommandContextWithPath_Denied(t *testing.T) { - t.Parallel() - - // Unknown command - _, err := CommandContextWithPath(context.TODO(), filepath.Join("some", "path", "to", "not-a-real-command")) - require.Error(t, err, "expected unknown command to be denylisted") - - // Known command, unknown path - for cmdName := range knownPaths { - _, err := CommandContextWithPath(context.TODO(), filepath.Join("some", "incorrect", "path", "to", cmdName)) - require.Error(t, err, "expected unknown path to be denylisted") - - // We don't need to perform this same test against every known path - break - } -} - -func TestCommandContextWithPath_AutoupdatePaths(t *testing.T) { - t.Parallel() - - for _, b := range []string{"launcher", "launcher.exe", "osqueryd", "osqueryd.exe"} { - b := b - t.Run(b, func(t *testing.T) { - t.Parallel() - - autoupdatedBinaryPath := filepath.Join("some", "autoupdate", "path", "to", b) - cmd, err := CommandContextWithPath(context.TODO(), autoupdatedBinaryPath) - require.NoError(t, err, "expected autoupdated binaries to be allowed") - require.Equal(t, autoupdatedBinaryPath, cmd.Path) - require.NotNil(t, cmd.Cancel, "context not set on command") - }) - } -} - -func TestCommandContextWithPath_KnownPrefix(t *testing.T) { - t.Parallel() - - for cmdName := range knownPaths { - cmdName := cmdName - t.Run(cmdName, func(t *testing.T) { - t.Parallel() - - for _, p := range knownPathPrefixes { - pathToCmdWithKnownPrefix := filepath.Join(p, cmdName) - cmd, err := CommandContextWithPath(context.TODO(), pathToCmdWithKnownPrefix) - require.NoError(t, err, "expected no error with known command and directory prefix") - require.Equal(t, pathToCmdWithKnownPrefix, cmd.Path) - require.NotNil(t, cmd.Cancel, "context not set on command") - } - }) - } + require.NoError(t, err) + require.Equal(t, cmdPath, p) } diff --git a/pkg/allowedpaths/cmd_windows.go b/pkg/allowedpaths/cmd_windows.go deleted file mode 100644 index fc02af0be..000000000 --- a/pkg/allowedpaths/cmd_windows.go +++ /dev/null @@ -1,35 +0,0 @@ -//go:build windows -// +build windows - -package allowedpaths - -var knownPaths = map[string]map[string]bool{ - "cmd.exe": { - `C:\Windows\System32\cmd.exe`: true, - }, - "dism.exe": { - `C:\Windows\System32\Dism.exe`: true, - }, - "dsregcmd.exe": { - `C:\Windows\System32\dsregcmd.exe`: true, - }, - "ipconfig.exe": { - `C:\Windows\System32\ipconfig.exe`: true, - }, - "powercfg.exe": { - `C:\Windows\System32\powercfg.exe`: true, - }, - "powershell.exe": { - `C:\Windows\System32\WindowsPowerShell\v1.0\powershell.exe`: true, - }, - "secedit.exe": { - `C:\Windows\System32\SecEdit.exe`: true, - }, - "taskkill.exe": { - `C:\Windows\System32\taskkill.exe`: true, - }, -} - -var knownPathPrefixes = []string{ - `C:\Windows\System32`, -} diff --git a/pkg/debug/checkups/gnome-extensions.go b/pkg/debug/checkups/gnome-extensions.go index cccd0b4a0..e07bed383 100644 --- a/pkg/debug/checkups/gnome-extensions.go +++ b/pkg/debug/checkups/gnome-extensions.go @@ -95,7 +95,7 @@ func execGnomeExtension(ctx context.Context, extraWriter io.Writer, rundir strin // pkg/osquery/tables/gsettings/gsettings.go probably has appropriate prior art. // But do we really want the forloop? - cmd, err := allowedpaths.CommandContextWithLookup(ctx, "gnome-extensions", args...) + cmd, err := allowedpaths.Gnomeextensions(ctx, args...) if err != nil { return nil, fmt.Errorf("creating gnome-extensions command: %w", err) } diff --git a/pkg/debug/checkups/launchd.go b/pkg/debug/checkups/launchd.go index 1a5f0fb9c..3dd4deff9 100644 --- a/pkg/debug/checkups/launchd.go +++ b/pkg/debug/checkups/launchd.go @@ -65,7 +65,7 @@ func (c *launchdCheckup) Run(ctx context.Context, extraWriter io.Writer) error { // run launchctl to check status var printOut bytes.Buffer - cmd, err := allowedpaths.CommandContextWithLookup(ctx, "launchctl", "print", launchdServiceName) + cmd, err := allowedpaths.Launchctl(ctx, "print", launchdServiceName) if err != nil { c.status = Erroring c.summary = fmt.Sprintf("unable to create launchctl command: %s", err) diff --git a/pkg/debug/checkups/network.go b/pkg/debug/checkups/network.go index bdeff67f2..9a6e80890 100644 --- a/pkg/debug/checkups/network.go +++ b/pkg/debug/checkups/network.go @@ -48,15 +48,11 @@ func (n *networkCheckup) Run(ctx context.Context, extraWriter io.Writer) error { return fmt.Errorf("creating zip file: %w", err) } - for _, commandArr := range listCommands() { - if len(commandArr) < 1 { - // how did this happen - continue - } + for _, c := range listCommands() { ctx, cancel := context.WithTimeout(ctx, 5*time.Second) defer cancel() - cmd, err := allowedpaths.CommandContextWithLookup(ctx, commandArr[0], commandArr[1:]...) + cmd, err := c.cmd(ctx, c.args...) if err != nil { continue } @@ -86,22 +82,45 @@ func (n *networkCheckup) Data() any { return nil } -func listCommands() [][]string { +type networkCommand struct { + cmd allowedpaths.AllowedCommand + args []string +} + +func listCommands() []networkCommand { switch runtime.GOOS { case "darwin": - return [][]string{ - {"ifconfig", "-a"}, - {"netstat", "-nr"}, + return []networkCommand{ + { + cmd: allowedpaths.Ifconfig, + args: []string{"-a"}, + }, + { + cmd: allowedpaths.Netstat, + args: []string{"-nr"}, + }, } case "linux": - return [][]string{ - {"ifconfig", "-a"}, - {"ip", "-N", "-d", "-h", "-a", "address"}, - {"ip", "-N", "-d", "-h", "-a", "route"}, + return []networkCommand{ + { + cmd: allowedpaths.Ifconfig, + args: []string{"-a"}, + }, + { + cmd: allowedpaths.Ip, + args: []string{"-N", "-d", "-h", "-a", "address"}, + }, + { + cmd: allowedpaths.Ip, + args: []string{"-N", "-d", "-h", "-a", "route"}, + }, } case "windows": - return [][]string{ - {"ipconfig", "/all"}, + return []networkCommand{ + { + cmd: allowedpaths.Ipconfig, + args: []string{"/all"}, + }, } default: return nil diff --git a/pkg/debug/checkups/osquery.go b/pkg/debug/checkups/osquery.go index eb23b7f66..50f60894b 100644 --- a/pkg/debug/checkups/osquery.go +++ b/pkg/debug/checkups/osquery.go @@ -4,12 +4,12 @@ import ( "context" "fmt" "io" + "os/exec" "runtime" "strings" "time" "github.com/kolide/launcher/pkg/agent/types" - "github.com/kolide/launcher/pkg/allowedpaths" ) type osqueryCheckup struct { @@ -48,10 +48,8 @@ func (o *osqueryCheckup) version(ctx context.Context) (string, error) { cmdCtx, cmdCancel := context.WithTimeout(ctx, 10*time.Second) defer cmdCancel() - cmd, err := allowedpaths.CommandContextWithPath(cmdCtx, osquerydPath, "--version") - if err != nil { - return "", fmt.Errorf("creating osqueryd command: %w", err) - } + // We trust the autoupdate library to find the correct path + cmd := exec.CommandContext(cmdCtx, osquerydPath, "--version") //nolint:forbidigo hideWindow(cmd) startTime := time.Now().UnixMilli() out, err := cmd.CombinedOutput() @@ -75,10 +73,8 @@ func (o *osqueryCheckup) interactive(ctx context.Context) error { cmdCtx, cmdCancel := context.WithTimeout(ctx, 20*time.Second) defer cmdCancel() - cmd, err := allowedpaths.CommandContextWithPath(cmdCtx, launcherPath, "interactive") - if err != nil { - return fmt.Errorf("creating launcher command: %w", err) - } + // We trust the autoupdate library to find the correct path + cmd := exec.CommandContext(cmdCtx, launcherPath, "interactive") //nolint:forbidigo hideWindow(cmd) cmd.Stdin = strings.NewReader(`select * from osquery_info;`) diff --git a/pkg/debug/checkups/power_windows.go b/pkg/debug/checkups/power_windows.go index 111ceb8ee..7afc05e65 100644 --- a/pkg/debug/checkups/power_windows.go +++ b/pkg/debug/checkups/power_windows.go @@ -25,7 +25,7 @@ func (p *powerCheckup) Run(ctx context.Context, extraWriter io.Writer) error { defer os.Remove(tmpFilePath) // See: https://learn.microsoft.com/en-us/windows-hardware/design/device-experiences/powercfg-command-line-options#option_systempowerreport - powerCfgCmd, err := allowedpaths.CommandContextWithLookup(ctx, "powercfg.exe", "/systempowerreport", "/output", tmpFilePath) + powerCfgCmd, err := allowedpaths.Powercfg(ctx, "/systempowerreport", "/output", tmpFilePath) if err != nil { return fmt.Errorf("creating powercfg command: %w", err) } diff --git a/pkg/debug/checkups/services_windows.go b/pkg/debug/checkups/services_windows.go index 69c52cd8b..6509b8068 100644 --- a/pkg/debug/checkups/services_windows.go +++ b/pkg/debug/checkups/services_windows.go @@ -244,7 +244,7 @@ func gatherServiceManagerEventLogs(ctx context.Context, z *zip.Writer) error { "Format-Table", "-Wrap", "-AutoSize", // ensure output doesn't get truncated } - getEventLogCmd, err := allowedpaths.CommandContextWithLookup(ctx, "powershell.exe", cmdletArgs...) + getEventLogCmd, err := allowedpaths.Powershell(ctx, cmdletArgs...) if err != nil { return fmt.Errorf("creating powershell command: %w", err) } diff --git a/pkg/execwrapper/exec_windows.go b/pkg/execwrapper/exec_windows.go index 72d980baf..a05d93fce 100644 --- a/pkg/execwrapper/exec_windows.go +++ b/pkg/execwrapper/exec_windows.go @@ -8,21 +8,20 @@ import ( "errors" "fmt" "os" + "os/exec" "strings" "github.com/go-kit/kit/log" "github.com/go-kit/kit/log/level" - "github.com/kolide/launcher/pkg/allowedpaths" "github.com/kolide/launcher/pkg/contexts/ctxlog" ) func Exec(ctx context.Context, argv0 string, argv []string, envv []string) error { logger := log.With(ctxlog.FromContext(ctx), "caller", log.DefaultCaller) - cmd, err := allowedpaths.CommandContextWithPath(ctx, argv0, argv[1:]...) - if err != nil { - return fmt.Errorf("creating command: %w", err) - } + // execwrapper is used exclusively to exec launcher, and we trust the autoupdate + // library to find the correct path. + cmd := exec.CommandContext(ctx, argv0, argv[1:]...) //nolint:forbidigo cmd.Env = envv cmd.Stdin = os.Stdin @@ -37,7 +36,7 @@ func Exec(ctx context.Context, argv0 string, argv []string, envv []string) error // Now run it. This is faking exec, we need to distinguish // between a failure to execute, and a failure in in the called program. // I think https://github.com/golang/go/issues/26539 adds this functionality. - err = cmd.Run() + err := cmd.Run() if cmd.ProcessState.ExitCode() == -1 { if err == nil { diff --git a/pkg/log/log.go b/pkg/log/log.go index b580619ae..1f03dcbc2 100644 --- a/pkg/log/log.go +++ b/pkg/log/log.go @@ -169,7 +169,7 @@ func (l *OsqueryLogAdapter) runAndLogPs(pidStr string) { ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second) defer cancel() - cmd, err := allowedpaths.CommandContextWithLookup(ctx, "ps", "-p", pidStr, "-o", "user,pid,ppid,pgid,stat,time,command") + cmd, err := allowedpaths.Ps(ctx, "-p", pidStr, "-o", "user,pid,ppid,pgid,stat,time,command") if err != nil { level.Debug(l.logger).Log( "msg", "error creating command to run ps on osqueryd pidfile", @@ -203,7 +203,7 @@ func (l *OsqueryLogAdapter) runAndLogLsofByPID(pidStr string) { ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second) defer cancel() - cmd, err := allowedpaths.CommandContextWithLookup(ctx, "lsof", "-R", "-n", "-p", pidStr) + cmd, err := allowedpaths.Lsof(ctx, "-R", "-n", "-p", pidStr) if err != nil { level.Debug(l.logger).Log( "msg", "error creating command to run lsof on osqueryd pidfile", @@ -240,7 +240,7 @@ func (l *OsqueryLogAdapter) runAndLogLsofOnPidfile() { ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second) defer cancel() - cmd, err := allowedpaths.CommandContextWithLookup(ctx, "lsof", "-R", "-n", fullPidfile) + cmd, err := allowedpaths.Lsof(ctx, "-R", "-n", fullPidfile) if err != nil { level.Debug(l.logger).Log( "msg", "error creating command to run lsof on osqueryd pidfile", diff --git a/pkg/osquery/runsimple/osqueryrunner.go b/pkg/osquery/runsimple/osqueryrunner.go index 8d02333bf..336e891fd 100644 --- a/pkg/osquery/runsimple/osqueryrunner.go +++ b/pkg/osquery/runsimple/osqueryrunner.go @@ -6,11 +6,9 @@ package runsimple import ( "bytes" "context" - "fmt" "io" + "os/exec" "runtime" - - "github.com/kolide/launcher/pkg/allowedpaths" ) // osqueryProcess is a very simple osquery runtime manager. It's designed to start and stop osquery. It has @@ -90,10 +88,8 @@ func (p osqueryProcess) RunSql(ctx context.Context, sql []byte) error { p.stdin = bytes.NewReader(sql) - cmd, err := allowedpaths.CommandContextWithPath(ctx, p.osquerydPath, args...) - if err != nil { - return fmt.Errorf("creating osqueryd command: %w", err) - } + // We trust the autoupdate library to find the correct path + cmd := exec.CommandContext(ctx, p.osquerydPath, args...) //nolint:forbidigo // It's okay for these to be nil, so we can just set them without checking. cmd.Stdin = p.stdin @@ -108,10 +104,8 @@ func (p osqueryProcess) RunVersion(ctx context.Context) error { "--version", } - cmd, err := allowedpaths.CommandContextWithPath(ctx, p.osquerydPath, args...) - if err != nil { - return fmt.Errorf("creating osqueryd command: %w", err) - } + // We trust the autoupdate library to find the correct path + cmd := exec.CommandContext(ctx, p.osquerydPath, args...) //nolint:forbidigo // It's okay for these to be nil, so we can just set them without checking. cmd.Stdin = p.stdin diff --git a/pkg/osquery/runtime/runtime_helpers_windows.go b/pkg/osquery/runtime/runtime_helpers_windows.go index 5cefe65eb..c651e9065 100644 --- a/pkg/osquery/runtime/runtime_helpers_windows.go +++ b/pkg/osquery/runtime/runtime_helpers_windows.go @@ -22,7 +22,7 @@ func setpgid() *syscall.SysProcAttr { func killProcessGroup(cmd *exec.Cmd) error { // some discussion here https://github.com/golang/dep/pull/857 // TODO: should we check err? - cmd, err := allowedpaths.CommandWithLookup("taskkill.exe", "/F", "/T", "/PID", fmt.Sprint(cmd.Process.Pid)) + cmd, err := allowedpaths.Taskkill("/F", "/T", "/PID", fmt.Sprint(cmd.Process.Pid)) if err != nil { return fmt.Errorf("creating command: %w", err) } diff --git a/pkg/osquery/table/mdfind_darwin.go b/pkg/osquery/table/mdfind_darwin.go index c12ec7b99..408eec4d5 100644 --- a/pkg/osquery/table/mdfind_darwin.go +++ b/pkg/osquery/table/mdfind_darwin.go @@ -18,7 +18,7 @@ func mdfind(args ...string) ([]string, error) { ctx, cancel := context.WithTimeout(context.Background(), 60*time.Second) defer cancel() - cmd, err := allowedpaths.CommandContextWithLookup(ctx, "mdfind", args...) + cmd, err := allowedpaths.Mdfind(ctx, args...) if err != nil { return nil, fmt.Errorf("creating mdfind command: %w", err) } diff --git a/pkg/osquery/table/mdm.go b/pkg/osquery/table/mdm.go index 380a83fa0..d11733299 100644 --- a/pkg/osquery/table/mdm.go +++ b/pkg/osquery/table/mdm.go @@ -89,7 +89,7 @@ func getMDMProfile(ctx context.Context) (*profilesOutput, error) { ctx, cancel := context.WithTimeout(ctx, 10*time.Second) defer cancel() - cmd, err := allowedpaths.CommandContextWithLookup(ctx, "profiles", "-L", "-o", "stdout-xml") + cmd, err := allowedpaths.Profiles(ctx, "-L", "-o", "stdout-xml") if err != nil { return nil, fmt.Errorf("creating profiles command: %w", err) } @@ -135,7 +135,7 @@ func getMDMProfileStatus(ctx context.Context) (profileStatus, error) { ctx, cancel := context.WithTimeout(ctx, 10*time.Second) defer cancel() - cmd, err := allowedpaths.CommandContextWithLookup(ctx, "profiles", "status", "-type", "enrollment") + cmd, err := allowedpaths.Profiles(ctx, "status", "-type", "enrollment") if err != nil { return profileStatus{}, fmt.Errorf("creating profiles command: %w", err) } diff --git a/pkg/osquery/table/platform_tables_darwin.go b/pkg/osquery/table/platform_tables_darwin.go index 97885ceaa..880239378 100644 --- a/pkg/osquery/table/platform_tables_darwin.go +++ b/pkg/osquery/table/platform_tables_darwin.go @@ -7,6 +7,7 @@ import ( "github.com/go-kit/kit/log" "github.com/knightsc/system_policy/osquery/table/kextpolicy" "github.com/knightsc/system_policy/osquery/table/legacyexec" + "github.com/kolide/launcher/pkg/allowedpaths" "github.com/kolide/launcher/pkg/osquery/tables/airport" appicons "github.com/kolide/launcher/pkg/osquery/tables/app-icons" "github.com/kolide/launcher/pkg/osquery/tables/apple_silicon_security_policy" @@ -99,25 +100,25 @@ func platformTables(logger log.Logger, currentOsquerydBinaryPath string) []osque apple_silicon_security_policy.TablePlugin(logger), legacyexec.TablePlugin(), dataflattentable.TablePluginExec(logger, - "kolide_diskutil_list", dataflattentable.PlistType, []string{"diskutil", "list", "-plist"}), + "kolide_diskutil_list", dataflattentable.PlistType, allowedpaths.Diskutil, []string{"list", "-plist"}), dataflattentable.TablePluginExec(logger, - "kolide_falconctl_stats", dataflattentable.PlistType, []string{"/Applications/Falcon.app/Contents/Resources/falconctl", "stats", "-p"}), + "kolide_falconctl_stats", dataflattentable.PlistType, allowedpaths.Falconctl, []string{"stats", "-p"}), dataflattentable.TablePluginExec(logger, - "kolide_apfs_list", dataflattentable.PlistType, []string{"diskutil", "apfs", "list", "-plist"}), + "kolide_apfs_list", dataflattentable.PlistType, allowedpaths.Diskutil, []string{"apfs", "list", "-plist"}), dataflattentable.TablePluginExec(logger, - "kolide_apfs_users", dataflattentable.PlistType, []string{"diskutil", "apfs", "listUsers", "/", "-plist"}), + "kolide_apfs_users", dataflattentable.PlistType, allowedpaths.Diskutil, []string{"apfs", "listUsers", "/", "-plist"}), dataflattentable.TablePluginExec(logger, - "kolide_tmutil_destinationinfo", dataflattentable.PlistType, []string{"tmutil", "destinationinfo", "-X"}), + "kolide_tmutil_destinationinfo", dataflattentable.PlistType, allowedpaths.Tmutil, []string{"destinationinfo", "-X"}), dataflattentable.TablePluginExec(logger, - "kolide_powermetrics", dataflattentable.PlistType, []string{"powermetrics", "-n", "1", "-f", "plist"}), + "kolide_powermetrics", dataflattentable.PlistType, allowedpaths.Powermetrics, []string{"-n", "1", "-f", "plist"}), screenlockTable, pwpolicy.TablePlugin(logger), systemprofiler.TablePlugin(logger), munki.ManagedInstalls(logger), munki.MunkiReport(logger), - dataflattentable.NewExecAndParseTable(logger, "kolide_remotectl", remotectl.Parser, []string{`/usr/libexec/remotectl`, `dumpstate`}), - dataflattentable.NewExecAndParseTable(logger, "kolide_softwareupdate", softwareupdate.Parser, []string{`softwareupdate`, `--list`, `--no-scan`}, dataflattentable.WithIncludeStderr()), - dataflattentable.NewExecAndParseTable(logger, "kolide_softwareupdate_scan", softwareupdate.Parser, []string{`softwareupdate`, `--list`}, dataflattentable.WithIncludeStderr()), - dataflattentable.NewExecAndParseTable(logger, "kolide_carbonblack_repcli_status", repcli.Parser, []string{"/Applications/VMware Carbon Black Cloud/repcli.bundle/Contents/MacOS/repcli", "status"}, dataflattentable.WithIncludeStderr()), + dataflattentable.NewExecAndParseTable(logger, "kolide_remotectl", remotectl.Parser, allowedpaths.Remotectl, []string{`dumpstate`}), + dataflattentable.NewExecAndParseTable(logger, "kolide_softwareupdate", softwareupdate.Parser, allowedpaths.Softwareupdate, []string{`--list`, `--no-scan`}, dataflattentable.WithIncludeStderr()), + dataflattentable.NewExecAndParseTable(logger, "kolide_softwareupdate_scan", softwareupdate.Parser, allowedpaths.Softwareupdate, []string{`--list`}, dataflattentable.WithIncludeStderr()), + dataflattentable.NewExecAndParseTable(logger, "kolide_carbonblack_repcli_status", repcli.Parser, allowedpaths.Repcli, []string{"status"}, dataflattentable.WithIncludeStderr()), } } diff --git a/pkg/osquery/table/platform_tables_linux.go b/pkg/osquery/table/platform_tables_linux.go index b77d330d5..5ee13ce4f 100644 --- a/pkg/osquery/table/platform_tables_linux.go +++ b/pkg/osquery/table/platform_tables_linux.go @@ -5,6 +5,7 @@ package table import ( "github.com/go-kit/kit/log" + "github.com/kolide/launcher/pkg/allowedpaths" "github.com/kolide/launcher/pkg/osquery/tables/crowdstrike/falcon_kernel_check" "github.com/kolide/launcher/pkg/osquery/tables/crowdstrike/falconctl" "github.com/kolide/launcher/pkg/osquery/tables/cryptsetup" @@ -40,19 +41,20 @@ func platformTables(logger log.Logger, currentOsquerydBinaryPath string) []osque dataflattentable.TablePluginExec(logger, "kolide_nmcli_wifi", dataflattentable.KeyValueType, - []string{"nmcli", "--mode=multiline", "--fields=all", "device", "wifi", "list"}, + allowedpaths.Nmcli, + []string{"--mode=multiline", "--fields=all", "device", "wifi", "list"}, dataflattentable.WithKVSeparator(":")), dataflattentable.TablePluginExec(logger, "kolide_lsblk", dataflattentable.JsonType, - []string{"lsblk", "-J"}, + allowedpaths.Lsblk, []string{"-J"}, ), - dataflattentable.NewExecAndParseTable(logger, "kolide_falconctl_systags", simple_array.New("systags"), []string{"/opt/CrowdStrike/falconctl", "-g", "--systags"}), - dataflattentable.NewExecAndParseTable(logger, "kolide_apt_upgradeable", apt.Parser, []string{"apt", "list", "--upgradeable"}, dataflattentable.WithIncludeStderr()), - dataflattentable.NewExecAndParseTable(logger, "kolide_dnf_upgradeable", dnf.Parser, []string{"dnf", "check-update"}, dataflattentable.WithIncludeStderr()), - dataflattentable.NewExecAndParseTable(logger, "kolide_dpkg_version_info", dpkg.Parser, []string{"dpkg", "-p"}, dataflattentable.WithIncludeStderr()), - dataflattentable.NewExecAndParseTable(logger, "kolide_pacman_group", pacman_group.Parser, []string{"pacman", "-Qg"}, dataflattentable.WithIncludeStderr()), - dataflattentable.NewExecAndParseTable(logger, "kolide_pacman_version_info", pacman_info.Parser, []string{"pacman", "-Qi"}, dataflattentable.WithIncludeStderr()), - dataflattentable.NewExecAndParseTable(logger, "kolide_pacman_upgradeable", pacman_upgradeable.Parser, []string{"pacman", "-Qu"}, dataflattentable.WithIncludeStderr()), - dataflattentable.NewExecAndParseTable(logger, "kolide_rpm_version_info", rpm.Parser, []string{"rpm", "-qai"}, dataflattentable.WithIncludeStderr()), - dataflattentable.NewExecAndParseTable(logger, "kolide_carbonblack_repcli_status", repcli.Parser, []string{"/opt/carbonblack/psc/bin/repcli", "status"}, dataflattentable.WithIncludeStderr()), + dataflattentable.NewExecAndParseTable(logger, "kolide_falconctl_systags", simple_array.New("systags"), allowedpaths.Falconctl, []string{"-g", "--systags"}), + dataflattentable.NewExecAndParseTable(logger, "kolide_apt_upgradeable", apt.Parser, allowedpaths.Apt, []string{"list", "--upgradeable"}, dataflattentable.WithIncludeStderr()), + dataflattentable.NewExecAndParseTable(logger, "kolide_dnf_upgradeable", dnf.Parser, allowedpaths.Dnf, []string{"check-update"}, dataflattentable.WithIncludeStderr()), + dataflattentable.NewExecAndParseTable(logger, "kolide_dpkg_version_info", dpkg.Parser, allowedpaths.Dpkg, []string{"-p"}, dataflattentable.WithIncludeStderr()), + dataflattentable.NewExecAndParseTable(logger, "kolide_pacman_group", pacman_group.Parser, allowedpaths.Pacman, []string{"-Qg"}, dataflattentable.WithIncludeStderr()), + dataflattentable.NewExecAndParseTable(logger, "kolide_pacman_version_info", pacman_info.Parser, allowedpaths.Pacman, []string{"-Qi"}, dataflattentable.WithIncludeStderr()), + dataflattentable.NewExecAndParseTable(logger, "kolide_pacman_upgradeable", pacman_upgradeable.Parser, allowedpaths.Pacman, []string{"-Qu"}, dataflattentable.WithIncludeStderr()), + dataflattentable.NewExecAndParseTable(logger, "kolide_rpm_version_info", rpm.Parser, allowedpaths.Rpm, []string{"-qai"}, dataflattentable.WithIncludeStderr()), + dataflattentable.NewExecAndParseTable(logger, "kolide_carbonblack_repcli_status", repcli.Parser, allowedpaths.Repcli, []string{"status"}, dataflattentable.WithIncludeStderr()), } } diff --git a/pkg/osquery/table/platform_tables_windows.go b/pkg/osquery/table/platform_tables_windows.go index 869e5a397..11f2d86f6 100644 --- a/pkg/osquery/table/platform_tables_windows.go +++ b/pkg/osquery/table/platform_tables_windows.go @@ -4,6 +4,7 @@ package table import ( + "github.com/kolide/launcher/pkg/allowedpaths" "github.com/kolide/launcher/pkg/osquery/tables/dataflattentable" "github.com/kolide/launcher/pkg/osquery/tables/dsim_default_associations" "github.com/kolide/launcher/pkg/osquery/tables/execparsers/dsregcmd" @@ -25,6 +26,6 @@ func platformTables(logger log.Logger, currentOsquerydBinaryPath string) []osque windowsupdatetable.TablePlugin(windowsupdatetable.UpdatesTable, logger), windowsupdatetable.TablePlugin(windowsupdatetable.HistoryTable, logger), wmitable.TablePlugin(logger), - dataflattentable.NewExecAndParseTable(logger, "kolide_dsregcmd", dsregcmd.Parser, []string{`dsregcmd.exe`, `/status`}), + dataflattentable.NewExecAndParseTable(logger, "kolide_dsregcmd", dsregcmd.Parser, allowedpaths.Dsregcmd, []string{`/status`}), } } diff --git a/pkg/osquery/table/table.go b/pkg/osquery/table/table.go index f42930708..76019ef19 100644 --- a/pkg/osquery/table/table.go +++ b/pkg/osquery/table/table.go @@ -2,6 +2,7 @@ package table import ( "github.com/kolide/launcher/pkg/agent/types" + "github.com/kolide/launcher/pkg/allowedpaths" "github.com/kolide/launcher/pkg/osquery/tables/cryptoinfotable" "github.com/kolide/launcher/pkg/osquery/tables/dataflattentable" "github.com/kolide/launcher/pkg/osquery/tables/desktopprocs" @@ -48,11 +49,11 @@ func PlatformTables(logger log.Logger, currentOsquerydBinaryPath string) []osque dev_table_tooling.TablePlugin(logger), firefox_preferences.TablePlugin(logger), dataflattentable.TablePluginExec(logger, - "kolide_zerotier_info", dataflattentable.JsonType, zerotierCli("info")), + "kolide_zerotier_info", dataflattentable.JsonType, allowedpaths.Zerotiercli, []string{"info"}), dataflattentable.TablePluginExec(logger, - "kolide_zerotier_networks", dataflattentable.JsonType, zerotierCli("listnetworks")), + "kolide_zerotier_networks", dataflattentable.JsonType, allowedpaths.Zerotiercli, []string{"listnetworks"}), dataflattentable.TablePluginExec(logger, - "kolide_zerotier_peers", dataflattentable.JsonType, zerotierCli("listpeers")), + "kolide_zerotier_peers", dataflattentable.JsonType, allowedpaths.Zerotiercli, []string{"listpeers"}), tdebug.LauncherGcInfo(logger), zfs.ZfsPropertiesPlugin(logger), zfs.ZpoolPropertiesPlugin(logger), diff --git a/pkg/osquery/table/touchid_system_darwin.go b/pkg/osquery/table/touchid_system_darwin.go index d8ae48fb8..5b1518cfa 100644 --- a/pkg/osquery/table/touchid_system_darwin.go +++ b/pkg/osquery/table/touchid_system_darwin.go @@ -41,7 +41,7 @@ func (t *touchIDSystemConfigTable) generate(ctx context.Context, queryContext ta // Read the security chip from system_profiler var stdout bytes.Buffer - cmd, err := allowedpaths.CommandContextWithLookup(ctx, "system_profiler", "SPiBridgeDataType") + cmd, err := allowedpaths.Systemprofiler(ctx, "SPiBridgeDataType") if err != nil { return nil, fmt.Errorf("creating system_profiler command: %w", err) } @@ -60,7 +60,7 @@ func (t *touchIDSystemConfigTable) generate(ctx context.Context, queryContext ta // Read the system's bioutil configuration stdout.Reset() - cmd, err = allowedpaths.CommandContextWithLookup(ctx, "bioutil", "-r", "-s") + cmd, err = allowedpaths.Bioutil(ctx, "-r", "-s") if err != nil { return nil, fmt.Errorf("creating bioutil command: %w", err) } diff --git a/pkg/osquery/table/touchid_user_darwin.go b/pkg/osquery/table/touchid_user_darwin.go index b3041a431..9674944be 100644 --- a/pkg/osquery/table/touchid_user_darwin.go +++ b/pkg/osquery/table/touchid_user_darwin.go @@ -65,7 +65,7 @@ func (t *touchIDUserConfigTable) generate(ctx context.Context, queryContext tabl uid, _ := strconv.Atoi(constraint.Expression) // Get the user's TouchID config - configOutput, err := runCommandContext(ctx, uid, "bioutil", "-r") + configOutput, err := runCommandContext(ctx, uid, allowedpaths.Bioutil, "-r") if err != nil { level.Debug(t.logger).Log( "msg", "could not run bioutil -r", @@ -95,7 +95,7 @@ func (t *touchIDUserConfigTable) generate(ctx context.Context, queryContext tabl } // Grab the fingerprint count - countOutStr, err := runCommandContext(ctx, uid, "bioutil", "-c") + countOutStr, err := runCommandContext(ctx, uid, allowedpaths.Bioutil, "-c") if err != nil { level.Debug(t.logger).Log( "msg", "could not run bioutil -c", @@ -129,13 +129,13 @@ func (t *touchIDUserConfigTable) generate(ctx context.Context, queryContext tabl } // runCommand runs a given command and arguments as the supplied user -func runCommandContext(ctx context.Context, uid int, cmd string, args ...string) (string, error) { +func runCommandContext(ctx context.Context, uid int, cmd allowedpaths.AllowedCommand, args ...string) (string, error) { ctx, cancel := context.WithTimeout(ctx, 10*time.Second) defer cancel() // Set up the command var stdout bytes.Buffer - c, err := allowedpaths.CommandContextWithLookup(ctx, cmd, args...) + c, err := cmd(ctx, args...) if err != nil { return "", fmt.Errorf("creating command: %w", err) } diff --git a/pkg/osquery/table/zerotier.go b/pkg/osquery/table/zerotier.go deleted file mode 100644 index 9ec32b920..000000000 --- a/pkg/osquery/table/zerotier.go +++ /dev/null @@ -1,11 +0,0 @@ -//go:build !windows -// +build !windows - -package table - -// zerotierCli returns the path to the CLI executable. -func zerotierCli(args ...string) []string { - cmd := []string{"/usr/local/bin/zerotier-cli"} - - return append(cmd, args...) -} diff --git a/pkg/osquery/table/zerotier_windows.go b/pkg/osquery/table/zerotier_windows.go deleted file mode 100644 index ae94fb357..000000000 --- a/pkg/osquery/table/zerotier_windows.go +++ /dev/null @@ -1,19 +0,0 @@ -//go:build windows -// +build windows - -package table - -import ( - "os" - "path" -) - -// zerotierCli returns the path to the CLI executable. -func zerotierCli(args ...string) []string { - cmd := []string{ - path.Join(os.Getenv("SYSTEMROOT"), "ProgramData", "ZeroTier", "One", "zerotier-one_x64.exe"), - "-q", - } - - return append(cmd, args...) -} diff --git a/pkg/osquery/tables/airport/table_darwin.go b/pkg/osquery/tables/airport/table_darwin.go index 629805b53..e9bae95cc 100644 --- a/pkg/osquery/tables/airport/table_darwin.go +++ b/pkg/osquery/tables/airport/table_darwin.go @@ -13,6 +13,7 @@ import ( "github.com/go-kit/kit/log" "github.com/go-kit/kit/log/level" + "github.com/kolide/launcher/pkg/allowedpaths" "github.com/kolide/launcher/pkg/dataflatten" "github.com/kolide/launcher/pkg/osquery/tables/dataflattentable" "github.com/kolide/launcher/pkg/osquery/tables/tablehelpers" @@ -21,7 +22,6 @@ import ( var ( allowedOptions = []string{"getinfo", "scan"} - airportPaths = []string{"/System/Library/PrivateFrameworks/Apple80211.framework/Versions/Current/Resources/airport"} ) type Table struct { @@ -47,11 +47,10 @@ func TablePlugin(logger log.Logger) *table.Plugin { type airportExecutor struct { ctx context.Context // nolint:containedctx logger log.Logger - paths []string } func (a *airportExecutor) Exec(option string) ([]byte, error) { - return tablehelpers.Exec(a.ctx, a.logger, 30, airportPaths, []string{"--" + option}, false) + return tablehelpers.Exec(a.ctx, a.logger, 30, allowedpaths.Airport, []string{"--" + option}, false) } type executor interface { @@ -63,7 +62,6 @@ func (t *Table) generate(ctx context.Context, queryContext table.QueryContext) ( airportExecutor := &airportExecutor{ ctx: ctx, logger: t.logger, - paths: airportPaths, } return generateAirportData(queryContext, airportExecutor, t.logger) diff --git a/pkg/osquery/tables/apple_silicon_security_policy/table.go b/pkg/osquery/tables/apple_silicon_security_policy/table.go index 13921dba3..4b118c9d0 100644 --- a/pkg/osquery/tables/apple_silicon_security_policy/table.go +++ b/pkg/osquery/tables/apple_silicon_security_policy/table.go @@ -10,6 +10,7 @@ import ( "github.com/go-kit/kit/log" "github.com/go-kit/kit/log/level" + "github.com/kolide/launcher/pkg/allowedpaths" "github.com/kolide/launcher/pkg/dataflatten" "github.com/kolide/launcher/pkg/osquery/tables/dataflattentable" "github.com/kolide/launcher/pkg/osquery/tables/tablehelpers" @@ -37,7 +38,7 @@ func TablePlugin(logger log.Logger) *table.Plugin { func (t *Table) generate(ctx context.Context, queryContext table.QueryContext) ([]map[string]string, error) { var results []map[string]string - output, err := tablehelpers.Exec(ctx, t.logger, 30, []string{"bputil"}, []string{bootPolicyUtilArgs}, false) + output, err := tablehelpers.Exec(ctx, t.logger, 30, allowedpaths.Bputil, []string{bootPolicyUtilArgs}, false) if err != nil { level.Info(t.logger).Log("msg", "bputil failed", "err", err) return nil, nil diff --git a/pkg/osquery/tables/crowdstrike/falcon_kernel_check/table.go b/pkg/osquery/tables/crowdstrike/falcon_kernel_check/table.go index 092cb5ff6..bb74d93af 100644 --- a/pkg/osquery/tables/crowdstrike/falcon_kernel_check/table.go +++ b/pkg/osquery/tables/crowdstrike/falcon_kernel_check/table.go @@ -7,12 +7,11 @@ import ( "github.com/go-kit/kit/log" "github.com/go-kit/kit/log/level" + "github.com/kolide/launcher/pkg/allowedpaths" "github.com/kolide/launcher/pkg/osquery/tables/tablehelpers" "github.com/osquery/osquery-go/plugin/table" ) -const kernelCheckUtilPath = "/opt/CrowdStrike/falcon-kernel-check" - type Table struct { logger log.Logger } @@ -34,7 +33,7 @@ func TablePlugin(logger log.Logger) *table.Plugin { } func (t *Table) generate(ctx context.Context, queryContext table.QueryContext) ([]map[string]string, error) { - output, err := tablehelpers.Exec(ctx, t.logger, 5, []string{kernelCheckUtilPath}, []string{}, false) + output, err := tablehelpers.Exec(ctx, t.logger, 5, allowedpaths.Falconkernelcheck, []string{}, false) if err != nil { level.Info(t.logger).Log("msg", "exec failed", "err", err) return nil, err diff --git a/pkg/osquery/tables/crowdstrike/falconctl/table.go b/pkg/osquery/tables/crowdstrike/falconctl/table.go index c0710b4af..54a7a253f 100644 --- a/pkg/osquery/tables/crowdstrike/falconctl/table.go +++ b/pkg/osquery/tables/crowdstrike/falconctl/table.go @@ -8,6 +8,7 @@ import ( "github.com/go-kit/kit/log" "github.com/go-kit/kit/log/level" + "github.com/kolide/launcher/pkg/allowedpaths" "github.com/kolide/launcher/pkg/dataflatten" "github.com/kolide/launcher/pkg/osquery/tables/dataflattentable" "github.com/kolide/launcher/pkg/osquery/tables/tablehelpers" @@ -15,8 +16,6 @@ import ( ) var ( - falconctlPaths = []string{"/opt/CrowdStrike/falconctl"} - // allowedOptions is the list of options this table is allowed to query. Notable exceptions // are `systags` (which is parsed seperatedly) and `provisioning-token` (which is a secret). allowedOptions = []string{ @@ -36,7 +35,7 @@ var ( defaultOption = strings.Join(allowedOptions, " ") ) -type execFunc func(context.Context, log.Logger, int, []string, []string, bool) ([]byte, error) +type execFunc func(context.Context, log.Logger, int, allowedpaths.AllowedCommand, []string, bool) ([]byte, error) type falconctlOptionsTable struct { logger log.Logger @@ -87,7 +86,7 @@ OUTER: // then the list of options to fetch. Set the command line thusly. args := append([]string{"-g"}, options...) - output, err := t.execFunc(ctx, t.logger, 30, falconctlPaths, args, false) + output, err := t.execFunc(ctx, t.logger, 30, allowedpaths.Falconctl, args, false) if err != nil { level.Info(t.logger).Log("msg", "exec failed", "err", err) synthesizedData := map[string]string{ diff --git a/pkg/osquery/tables/crowdstrike/falconctl/table_test.go b/pkg/osquery/tables/crowdstrike/falconctl/table_test.go index 5b5731f52..979c1f624 100644 --- a/pkg/osquery/tables/crowdstrike/falconctl/table_test.go +++ b/pkg/osquery/tables/crowdstrike/falconctl/table_test.go @@ -7,6 +7,7 @@ import ( "testing" "github.com/go-kit/kit/log" + "github.com/kolide/launcher/pkg/allowedpaths" "github.com/kolide/launcher/pkg/osquery/tables/tablehelpers" "github.com/stretchr/testify/require" ) @@ -81,7 +82,7 @@ func TestOptionRestrictions(t *testing.T) { } } -func noopExec(_ context.Context, log log.Logger, _ int, _ []string, args []string, _ bool) ([]byte, error) { +func noopExec(_ context.Context, log log.Logger, _ int, _ allowedpaths.AllowedCommand, args []string, _ bool) ([]byte, error) { log.Log("exec", "exec-in-test", "args", strings.Join(args, " ")) return []byte{}, nil } diff --git a/pkg/osquery/tables/cryptsetup/table.go b/pkg/osquery/tables/cryptsetup/table.go index f5a9c7721..a26773b9c 100644 --- a/pkg/osquery/tables/cryptsetup/table.go +++ b/pkg/osquery/tables/cryptsetup/table.go @@ -7,6 +7,7 @@ import ( "github.com/go-kit/kit/log" "github.com/go-kit/kit/log/level" + "github.com/kolide/launcher/pkg/allowedpaths" "github.com/kolide/launcher/pkg/dataflatten" "github.com/kolide/launcher/pkg/osquery/tables/dataflattentable" "github.com/kolide/launcher/pkg/osquery/tables/tablehelpers" @@ -46,7 +47,7 @@ func (t *Table) generate(ctx context.Context, queryContext table.QueryContext) ( } for _, name := range requestedNames { - output, err := tablehelpers.Exec(ctx, t.logger, 15, []string{"cryptsetup"}, []string{"--readonly", "status", name}, false) + output, err := tablehelpers.Exec(ctx, t.logger, 15, allowedpaths.Cryptsetup, []string{"--readonly", "status", name}, false) if err != nil { level.Debug(t.logger).Log("msg", "Error execing for status", "name", name, "err", err) continue diff --git a/pkg/osquery/tables/dataflattentable/exec.go b/pkg/osquery/tables/dataflattentable/exec.go index 5826f5e3d..506e4aee1 100644 --- a/pkg/osquery/tables/dataflattentable/exec.go +++ b/pkg/osquery/tables/dataflattentable/exec.go @@ -6,8 +6,6 @@ import ( "fmt" "os" - "os/exec" - "path/filepath" "strings" "time" @@ -30,18 +28,13 @@ func WithKVSeparator(separator string) ExecTableOpt { } } -func WithBinDirs(binDirs ...string) ExecTableOpt { - return func(t *Table) { - t.binDirs = binDirs - } -} - -func TablePluginExec(logger log.Logger, tableName string, dataSourceType DataSourceType, execArgs []string, opts ...ExecTableOpt) *table.Plugin { +func TablePluginExec(logger log.Logger, tableName string, dataSourceType DataSourceType, cmd allowedpaths.AllowedCommand, execArgs []string, opts ...ExecTableOpt) *table.Plugin { columns := Columns() t := &Table{ logger: level.NewFilter(logger, level.AllowInfo()), tableName: tableName, + cmd: cmd, execArgs: execArgs, keyValueSeparator: ":", } @@ -104,48 +97,25 @@ func (t *Table) exec(ctx context.Context) ([]byte, error) { ctx, cancel := context.WithTimeout(ctx, 50*time.Second) defer cancel() - possibleBinaries := []string{} + var stdout bytes.Buffer + var stderr bytes.Buffer - if t.binDirs == nil || len(t.binDirs) == 0 { - possibleBinaries = []string{t.execArgs[0]} - } else { - for _, possiblePath := range t.binDirs { - possibleBinaries = append(possibleBinaries, filepath.Join(possiblePath, t.execArgs[0])) - } + cmd, err := t.cmd(ctx, t.execArgs...) + if err != nil { + return nil, fmt.Errorf("creating command: %w", err) } - for _, execPath := range possibleBinaries { - var stdout bytes.Buffer - var stderr bytes.Buffer + cmd.Stdout = &stdout + cmd.Stderr = &stderr - var cmd *exec.Cmd - var err error - if execPath == filepath.Base(execPath) { - cmd, err = allowedpaths.CommandContextWithLookup(ctx, execPath, t.execArgs[1:]...) - } else { - cmd, err = allowedpaths.CommandContextWithPath(ctx, execPath, t.execArgs[1:]...) - } - if err != nil { - // Binary that the binary was not found, try the next one - continue - } - - cmd.Stdout = &stdout - cmd.Stderr = &stderr - - level.Debug(t.logger).Log("msg", "calling %s", "args", cmd.String()) - - if err := cmd.Run(); os.IsNotExist(err) { - // try the next binary - continue - } else if err != nil { - return nil, fmt.Errorf("calling %s. Got: %s: %w", t.execArgs[0], string(stderr.Bytes()), err) - } + level.Debug(t.logger).Log("msg", "calling %s", "args", cmd.String()) - // success! - return stdout.Bytes(), nil + if err := cmd.Run(); os.IsNotExist(err) { + return nil, fmt.Errorf("command %s not found: %w", cmd.Path, err) + } else if err != nil { + return nil, fmt.Errorf("calling %s. Got: %s: %w", cmd.Path, string(stderr.Bytes()), err) } - // None of the possible execs were found - return nil, fmt.Errorf("Unable to exec '%s'. No binary found is specified paths", t.execArgs[0]) + // success! + return stdout.Bytes(), nil } diff --git a/pkg/osquery/tables/dataflattentable/exec_and_parse.go b/pkg/osquery/tables/dataflattentable/exec_and_parse.go index 4bdb1afc6..6acabe0a4 100644 --- a/pkg/osquery/tables/dataflattentable/exec_and_parse.go +++ b/pkg/osquery/tables/dataflattentable/exec_and_parse.go @@ -7,6 +7,7 @@ import ( "github.com/go-kit/kit/log" "github.com/go-kit/kit/log/level" + "github.com/kolide/launcher/pkg/allowedpaths" "github.com/kolide/launcher/pkg/dataflatten" "github.com/kolide/launcher/pkg/osquery/tables/tablehelpers" "github.com/kolide/launcher/pkg/traces" @@ -26,7 +27,7 @@ type execTableV2 struct { timeoutSeconds int tabledebug bool includeStderr bool - execPaths []string + cmd allowedpaths.AllowedCommand execArgs []string } @@ -44,26 +45,20 @@ func WithTableDebug() execTableV2Opt { } } -func WithAdditionalExecPaths(paths ...string) execTableV2Opt { - return func(t *execTableV2) { - t.execPaths = append(t.execPaths, paths...) - } -} - func WithIncludeStderr() execTableV2Opt { return func(t *execTableV2) { t.includeStderr = true } } -func NewExecAndParseTable(logger log.Logger, tableName string, p parser, execCmd []string, opts ...execTableV2Opt) *table.Plugin { +func NewExecAndParseTable(logger log.Logger, tableName string, p parser, cmd allowedpaths.AllowedCommand, execArgs []string, opts ...execTableV2Opt) *table.Plugin { t := &execTableV2{ logger: level.NewFilter(log.With(logger, "table", tableName), level.AllowInfo()), tableName: tableName, flattener: flattenerFromParser(p), timeoutSeconds: 30, - execPaths: execCmd[:1], - execArgs: execCmd[1:], + cmd: cmd, + execArgs: execArgs, } for _, opt := range opts { @@ -83,7 +78,7 @@ func (t *execTableV2) generate(ctx context.Context, queryContext table.QueryCont var results []map[string]string - execOutput, err := tablehelpers.Exec(ctx, t.logger, t.timeoutSeconds, t.execPaths, t.execArgs, t.includeStderr) + execOutput, err := tablehelpers.Exec(ctx, t.logger, t.timeoutSeconds, t.cmd, t.execArgs, t.includeStderr) if err != nil { // exec will error if there's no binary, so we never want to record that if os.IsNotExist(errors.Cause(err)) { diff --git a/pkg/osquery/tables/dataflattentable/tables.go b/pkg/osquery/tables/dataflattentable/tables.go index a2249bce5..91be9a156 100644 --- a/pkg/osquery/tables/dataflattentable/tables.go +++ b/pkg/osquery/tables/dataflattentable/tables.go @@ -8,6 +8,7 @@ import ( "github.com/go-kit/kit/log" "github.com/go-kit/kit/log/level" + "github.com/kolide/launcher/pkg/allowedpaths" "github.com/kolide/launcher/pkg/dataflatten" "github.com/kolide/launcher/pkg/osquery/tables/tablehelpers" "github.com/osquery/osquery-go" @@ -34,8 +35,8 @@ type Table struct { flattenFileFunc func(string, ...dataflatten.FlattenOpts) ([]dataflatten.Row, error) flattenBytesFunc func([]byte, ...dataflatten.FlattenOpts) ([]dataflatten.Row, error) + cmd allowedpaths.AllowedCommand execArgs []string - binDirs []string keyValueSeparator string } diff --git a/pkg/osquery/tables/dev_table_tooling/commands_darwin.go b/pkg/osquery/tables/dev_table_tooling/commands_darwin.go deleted file mode 100644 index 7cab3f504..000000000 --- a/pkg/osquery/tables/dev_table_tooling/commands_darwin.go +++ /dev/null @@ -1,15 +0,0 @@ -//go:build darwin -// +build darwin - -package dev_table_tooling - -var allowedCommands = map[string]allowedCommand{ - "echo": { - binPaths: []string{"echo"}, - args: []string{"hello"}, - }, - "cb_repcli": { - binPaths: []string{"/Applications/VMware Carbon Black Cloud/repcli.bundle/Contents/MacOS/repcli"}, - args: []string{"status"}, - }, -} diff --git a/pkg/osquery/tables/dev_table_tooling/commands_linux.go b/pkg/osquery/tables/dev_table_tooling/commands_linux.go deleted file mode 100644 index 08650b21e..000000000 --- a/pkg/osquery/tables/dev_table_tooling/commands_linux.go +++ /dev/null @@ -1,15 +0,0 @@ -//go:build linux -// +build linux - -package dev_table_tooling - -var allowedCommands = map[string]allowedCommand{ - "echo": { - binPaths: []string{"echo"}, - args: []string{"hello"}, - }, - "cb_repcli": { - binPaths: []string{"/opt/carbonblack/psc/bin/repcli"}, - args: []string{"status"}, - }, -} diff --git a/pkg/osquery/tables/dev_table_tooling/commands_windows.go b/pkg/osquery/tables/dev_table_tooling/commands_windows.go deleted file mode 100644 index bd84e12ab..000000000 --- a/pkg/osquery/tables/dev_table_tooling/commands_windows.go +++ /dev/null @@ -1,17 +0,0 @@ -//go:build windows -// +build windows - -package dev_table_tooling - -import "path/filepath" - -var allowedCommands = map[string]allowedCommand{ - "echo": { - binPaths: []string{"echo"}, - args: []string{"hello"}, - }, - "cb_repcli": { - binPaths: []string{filepath.Join("Program Files", "Confer", "repcli")}, - args: []string{"status"}, - }, -} diff --git a/pkg/osquery/tables/dev_table_tooling/table.go b/pkg/osquery/tables/dev_table_tooling/table.go index 179bb44b8..d12dd52d5 100644 --- a/pkg/osquery/tables/dev_table_tooling/table.go +++ b/pkg/osquery/tables/dev_table_tooling/table.go @@ -7,6 +7,7 @@ import ( "github.com/go-kit/kit/log" "github.com/go-kit/kit/log/level" + "github.com/kolide/launcher/pkg/allowedpaths" "github.com/kolide/launcher/pkg/osquery/tables/tablehelpers" "github.com/osquery/osquery-go/plugin/table" ) @@ -14,8 +15,19 @@ import ( // allowedCommand encapsulates the possible binary path(s) of a command allowed to execute // along with a strict list of arguments. type allowedCommand struct { - binPaths []string - args []string + bin allowedpaths.AllowedCommand + args []string +} + +var allowedCommands = map[string]allowedCommand{ + "echo": { + bin: allowedpaths.Echo, + args: []string{"hello"}, + }, + "cb_repcli": { + bin: allowedpaths.Repcli, + args: []string{"status"}, + }, } type Table struct { @@ -62,7 +74,7 @@ func (t *Table) generate(ctx context.Context, queryContext table.QueryContext) ( "error": "", } - if output, err := tablehelpers.Exec(ctx, t.logger, 30, cmd.binPaths, cmd.args, false); err != nil { + if output, err := tablehelpers.Exec(ctx, t.logger, 30, cmd.bin, cmd.args, false); err != nil { level.Info(t.logger).Log("msg", "execution failed", "name", name, "err", err) result["error"] = err.Error() } else { diff --git a/pkg/osquery/tables/filevault/filevault.go b/pkg/osquery/tables/filevault/filevault.go index 9c57ee45a..deb6530ad 100644 --- a/pkg/osquery/tables/filevault/filevault.go +++ b/pkg/osquery/tables/filevault/filevault.go @@ -11,6 +11,7 @@ import ( "github.com/go-kit/kit/log" "github.com/go-kit/kit/log/level" + "github.com/kolide/launcher/pkg/allowedpaths" "github.com/kolide/launcher/pkg/osquery/tables/tablehelpers" "github.com/osquery/osquery-go/plugin/table" "github.com/pkg/errors" @@ -33,7 +34,7 @@ func TablePlugin(logger log.Logger) *table.Plugin { } func (t *Table) generate(ctx context.Context, queryContext table.QueryContext) ([]map[string]string, error) { - output, err := tablehelpers.Exec(ctx, t.logger, 10, []string{"fdesetup"}, []string{"status"}, false) + output, err := tablehelpers.Exec(ctx, t.logger, 10, allowedpaths.Fdesetup, []string{"status"}, false) if err != nil { level.Info(t.logger).Log("msg", "fdesetup failed", "err", err) diff --git a/pkg/osquery/tables/firmwarepasswd/firmwarepasswd.go b/pkg/osquery/tables/firmwarepasswd/firmwarepasswd.go index 6323bfdec..53fcdca02 100644 --- a/pkg/osquery/tables/firmwarepasswd/firmwarepasswd.go +++ b/pkg/osquery/tables/firmwarepasswd/firmwarepasswd.go @@ -92,7 +92,7 @@ func (t *Table) runFirmwarepasswd(ctx context.Context, subcommand string, output ctx, cancel := context.WithTimeout(ctx, 1*time.Second) defer cancel() - cmd, err := allowedpaths.CommandContextWithLookup(ctx, "firmwarepasswd", subcommand) + cmd, err := allowedpaths.Firmwarepasswd(ctx, subcommand) if err != nil { return fmt.Errorf("creating command: %w", err) } diff --git a/pkg/osquery/tables/gsettings/gsettings.go b/pkg/osquery/tables/gsettings/gsettings.go index f2775a2a2..eca96d0d4 100644 --- a/pkg/osquery/tables/gsettings/gsettings.go +++ b/pkg/osquery/tables/gsettings/gsettings.go @@ -90,7 +90,7 @@ func execGsettings(ctx context.Context, username string, buf *bytes.Buffer) erro return fmt.Errorf("finding user by username '%s': %w", username, err) } - cmd, err := allowedpaths.CommandContextWithLookup(ctx, "gsettings", "list-recursively") + cmd, err := allowedpaths.Gsettings(ctx, "list-recursively") if err != nil { return fmt.Errorf("creating gsettings command: %w", err) } diff --git a/pkg/osquery/tables/gsettings/metadata.go b/pkg/osquery/tables/gsettings/metadata.go index a2cdbebb9..efaca20af 100644 --- a/pkg/osquery/tables/gsettings/metadata.go +++ b/pkg/osquery/tables/gsettings/metadata.go @@ -221,7 +221,7 @@ func execGsettingsCommand(ctx context.Context, args []string, tmpdir string, out defer cancel() command := args[0] - cmd, err := allowedpaths.CommandContextWithLookup(ctx, "gsettings", args...) + cmd, err := allowedpaths.Gsettings(ctx, args...) if err != nil { return fmt.Errorf("creating gsettings command: %w", err) } diff --git a/pkg/osquery/tables/ioreg/ioreg.go b/pkg/osquery/tables/ioreg/ioreg.go index 1f17d4351..915064f64 100644 --- a/pkg/osquery/tables/ioreg/ioreg.go +++ b/pkg/osquery/tables/ioreg/ioreg.go @@ -16,6 +16,7 @@ import ( "github.com/go-kit/kit/log" "github.com/go-kit/kit/log/level" + "github.com/kolide/launcher/pkg/allowedpaths" "github.com/kolide/launcher/pkg/dataflatten" "github.com/kolide/launcher/pkg/osquery/tables/dataflattentable" "github.com/kolide/launcher/pkg/osquery/tables/tablehelpers" @@ -100,7 +101,7 @@ func (t *Table) generate(ctx context.Context, queryContext table.QueryContext) ( for _, dataQuery := range tablehelpers.GetConstraints(queryContext, "query", tablehelpers.WithDefaults("*")) { // Finally, an inner loop - ioregOutput, err := tablehelpers.Exec(ctx, t.logger, 30, []string{"ioreg"}, ioregArgs, false) + ioregOutput, err := tablehelpers.Exec(ctx, t.logger, 30, allowedpaths.Ioreg, ioregArgs, false) if err != nil { level.Info(t.logger).Log("msg", "ioreg failed", "err", err) continue diff --git a/pkg/osquery/tables/mdmclient/mdmclient.go b/pkg/osquery/tables/mdmclient/mdmclient.go index 634880c37..1327d24f3 100644 --- a/pkg/osquery/tables/mdmclient/mdmclient.go +++ b/pkg/osquery/tables/mdmclient/mdmclient.go @@ -18,14 +18,13 @@ import ( "github.com/go-kit/kit/log" "github.com/go-kit/kit/log/level" + "github.com/kolide/launcher/pkg/allowedpaths" "github.com/kolide/launcher/pkg/dataflatten" "github.com/kolide/launcher/pkg/osquery/tables/dataflattentable" "github.com/kolide/launcher/pkg/osquery/tables/tablehelpers" "github.com/osquery/osquery-go/plugin/table" ) -const mdmclientPath = "/usr/libexec/mdmclient" - const allowedCharacters = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789" // headerRegex matches the header that may be included at the beginning of the mdmclient response, @@ -92,7 +91,7 @@ func (t *Table) generate(ctx context.Context, queryContext table.QueryContext) ( for _, dataQuery := range tablehelpers.GetConstraints(queryContext, "query", tablehelpers.WithDefaults("*")) { - mdmclientOutput, err := tablehelpers.Exec(ctx, t.logger, 30, []string{mdmclientPath}, []string{mdmclientCommand}, false) + mdmclientOutput, err := tablehelpers.Exec(ctx, t.logger, 30, allowedpaths.Mdmclient, []string{mdmclientCommand}, false) if err != nil { level.Info(t.logger).Log("msg", "mdmclient failed", "err", err) continue diff --git a/pkg/osquery/tables/profiles/profiles.go b/pkg/osquery/tables/profiles/profiles.go index e27b066a4..24f83da42 100644 --- a/pkg/osquery/tables/profiles/profiles.go +++ b/pkg/osquery/tables/profiles/profiles.go @@ -21,6 +21,7 @@ import ( "github.com/go-kit/kit/log" "github.com/go-kit/kit/log/level" "github.com/kolide/launcher/pkg/agent" + "github.com/kolide/launcher/pkg/allowedpaths" "github.com/kolide/launcher/pkg/dataflatten" "github.com/kolide/launcher/pkg/osquery/tables/dataflattentable" "github.com/kolide/launcher/pkg/osquery/tables/tablehelpers" @@ -102,7 +103,7 @@ func (t *Table) generate(ctx context.Context, queryContext table.QueryContext) ( return nil, fmt.Errorf("Unknown user argument: %s", user) } - output, err := tablehelpers.Exec(ctx, t.logger, 30, []string{"profiles"}, profileArgs, false) + output, err := tablehelpers.Exec(ctx, t.logger, 30, allowedpaths.Profiles, profileArgs, false) if err != nil { level.Info(t.logger).Log("msg", "ioreg exec failed", "err", err) continue diff --git a/pkg/osquery/tables/pwpolicy/pwpolicy.go b/pkg/osquery/tables/pwpolicy/pwpolicy.go index 6c8a60195..dbc7a98fc 100644 --- a/pkg/osquery/tables/pwpolicy/pwpolicy.go +++ b/pkg/osquery/tables/pwpolicy/pwpolicy.go @@ -14,7 +14,6 @@ import ( "bytes" "context" "fmt" - "os/exec" "strings" "time" @@ -32,7 +31,7 @@ const pwpolicyCmd = "getaccountpolicies" type Table struct { logger log.Logger tableName string - execCC func(context.Context, string, ...string) (*exec.Cmd, error) + execCC allowedpaths.AllowedCommand } func TablePlugin(logger log.Logger) *table.Plugin { @@ -44,7 +43,7 @@ func TablePlugin(logger log.Logger) *table.Plugin { t := &Table{ logger: logger, tableName: "kolide_pwpolicy", - execCC: allowedpaths.CommandContextWithLookup, + execCC: allowedpaths.Pwpolicy, } return table.NewPlugin(t.tableName, columns, t.generate) @@ -96,7 +95,7 @@ func (t *Table) execPwpolicy(ctx context.Context, args []string) ([]byte, error) ctx, cancel := context.WithTimeout(ctx, 30*time.Second) defer cancel() - cmd, err := t.execCC(ctx, "pwpolicy", args...) + cmd, err := t.execCC(ctx, args...) if err != nil { return nil, fmt.Errorf("creating command: %w", err) } diff --git a/pkg/osquery/tables/pwpolicy/pwpolicy_test.go b/pkg/osquery/tables/pwpolicy/pwpolicy_test.go index 52c1a3490..cdea2c7a4 100644 --- a/pkg/osquery/tables/pwpolicy/pwpolicy_test.go +++ b/pkg/osquery/tables/pwpolicy/pwpolicy_test.go @@ -72,8 +72,8 @@ func TestQueries(t *testing.T) { } -func execFaker(filename string) func(context.Context, string, ...string) (*exec.Cmd, error) { - return func(ctx context.Context, _ string, _ ...string) (*exec.Cmd, error) { +func execFaker(filename string) func(context.Context, ...string) (*exec.Cmd, error) { + return func(ctx context.Context, _ ...string) (*exec.Cmd, error) { return exec.CommandContext(ctx, "/bin/cat", filename), nil } } diff --git a/pkg/osquery/tables/systemprofiler/systemprofiler.go b/pkg/osquery/tables/systemprofiler/systemprofiler.go index c798793b6..ef3913bfb 100644 --- a/pkg/osquery/tables/systemprofiler/systemprofiler.go +++ b/pkg/osquery/tables/systemprofiler/systemprofiler.go @@ -206,7 +206,7 @@ func (t *Table) execSystemProfiler(ctx context.Context, detailLevel string, subc args = append(args, subcommands...) - cmd, err := allowedpaths.CommandContextWithLookup(ctx, "system_profiler", args...) + cmd, err := allowedpaths.Systemprofiler(ctx, args...) if err != nil { return nil, fmt.Errorf("creating system_profiler command: %w", err) } diff --git a/pkg/osquery/tables/tablehelpers/exec.go b/pkg/osquery/tables/tablehelpers/exec.go index c5bd1aef9..941d943e2 100644 --- a/pkg/osquery/tables/tablehelpers/exec.go +++ b/pkg/osquery/tables/tablehelpers/exec.go @@ -5,8 +5,6 @@ import ( "context" "fmt" "os" - "os/exec" - "path/filepath" "time" "github.com/go-kit/kit/log" @@ -27,10 +25,8 @@ import ( // `possibleBins` can be either a list of command names, or a list of paths to commands. // Where reasonable, `possibleBins` should be command names only, so that we can perform // lookup against PATH. -func Exec(ctx context.Context, logger log.Logger, timeoutSeconds int, possibleBins []string, args []string, includeStderr bool) ([]byte, error) { - ctx, span := traces.StartSpan(ctx, - "possible_binaries", possibleBins, - "args", args) +func Exec(ctx context.Context, logger log.Logger, timeoutSeconds int, execCmd allowedpaths.AllowedCommand, args []string, includeStderr bool) ([]byte, error) { + ctx, span := traces.StartSpan(ctx) defer span.End() ctx, cancel := context.WithTimeout(ctx, time.Duration(timeoutSeconds)*time.Second) @@ -39,48 +35,30 @@ func Exec(ctx context.Context, logger log.Logger, timeoutSeconds int, possibleBi var stdout bytes.Buffer var stderr bytes.Buffer - for _, bin := range possibleBins { - stdout.Reset() - stderr.Reset() - - var cmd *exec.Cmd - var err error - // If we only have the binary name and not the path, try to perform lookup - if filepath.Base(bin) == bin { - cmd, err = allowedpaths.CommandContextWithLookup(ctx, bin, args...) - } else { - cmd, err = allowedpaths.CommandContextWithPath(ctx, bin, args...) - } - if err != nil { - // Likely that binary was not found -- try the next - continue - } - - cmd.Stdout = &stdout - if includeStderr { - cmd.Stderr = &stdout - } else { - cmd.Stderr = &stderr - } + cmd, err := execCmd(ctx, args...) + if err != nil { + return nil, fmt.Errorf("creating command: %w", err) + } - level.Debug(logger).Log( - "msg", "execing", - "cmd", cmd.String(), - ) + cmd.Stdout = &stdout + if includeStderr { + cmd.Stderr = &stdout + } else { + cmd.Stderr = &stderr + } - switch err := cmd.Run(); { - case err == nil: - return stdout.Bytes(), nil - case os.IsNotExist(err): - // try the next binary - continue - default: - // an actual error - traces.SetError(span, err) - return nil, fmt.Errorf("exec '%s'. Got: '%s': %w", cmd.String(), string(stderr.Bytes()), err) - } + level.Debug(logger).Log( + "msg", "execing", + "cmd", cmd.String(), + ) + switch err := cmd.Run(); { + case err == nil: + return stdout.Bytes(), nil + case os.IsNotExist(err): + return nil, fmt.Errorf("could not find %s to run: %w", cmd.Path, err) + default: + traces.SetError(span, err) + return nil, fmt.Errorf("exec '%s'. Got: '%s': %w", cmd.String(), string(stderr.Bytes()), err) } - // Getting here means no binary was found - return nil, fmt.Errorf("No binary found in specified paths: %v: %w", possibleBins, os.ErrNotExist) } diff --git a/pkg/osquery/tables/tablehelpers/exec_osquery_launchctl.go b/pkg/osquery/tables/tablehelpers/exec_osquery_launchctl.go index 2b2726f87..5971a9035 100644 --- a/pkg/osquery/tables/tablehelpers/exec_osquery_launchctl.go +++ b/pkg/osquery/tables/tablehelpers/exec_osquery_launchctl.go @@ -27,8 +27,7 @@ func ExecOsqueryLaunchctl(ctx context.Context, logger log.Logger, timeoutSeconds return nil, fmt.Errorf("looking up username %s: %w", username, err) } - cmd, err := allowedpaths.CommandContextWithLookup(ctx, - "launchctl", + cmd, err := allowedpaths.Launchctl(ctx, "asuser", targetUser.Uid, osqueryPath, diff --git a/pkg/osquery/tables/tablehelpers/exec_test.go b/pkg/osquery/tables/tablehelpers/exec_test.go index 455b986dc..eca2f3ee6 100644 --- a/pkg/osquery/tables/tablehelpers/exec_test.go +++ b/pkg/osquery/tables/tablehelpers/exec_test.go @@ -8,6 +8,7 @@ import ( "testing" "github.com/go-kit/kit/log" + "github.com/kolide/launcher/pkg/allowedpaths" "github.com/stretchr/testify/assert" ) @@ -17,18 +18,16 @@ func TestExec(t *testing.T) { var tests = []struct { name string timeout int - bins []string + bin allowedpaths.AllowedCommand args []string err bool + output string }{ { - name: "no binaries", - bins: []string{"/hello/world", "/hello/friends"}, - err: true, - }, - { - name: "eventually finds binary", - bins: []string{"/hello/world", "/bin/ps", "/usr/bin/ps"}, + name: "output", + bin: allowedpaths.Echo, + args: []string{"hello"}, + output: "hello\n", }, } @@ -43,13 +42,13 @@ func TestExec(t *testing.T) { if tt.timeout == 0 { tt.timeout = 30 } - output, err := Exec(ctx, logger, tt.timeout, tt.bins, tt.args, false) + output, err := Exec(ctx, logger, tt.timeout, tt.bin, tt.args, false) if tt.err { assert.Error(t, err) assert.Empty(t, output) } else { assert.NoError(t, err) - assert.Less(t, 0, len(output)) + assert.Equal(t, []byte(tt.output), output) } }) } diff --git a/pkg/osquery/tables/zfs/tables.go b/pkg/osquery/tables/zfs/tables.go index bc6b6c637..975ef02d8 100644 --- a/pkg/osquery/tables/zfs/tables.go +++ b/pkg/osquery/tables/zfs/tables.go @@ -10,6 +10,7 @@ import ( "github.com/go-kit/kit/log" "github.com/go-kit/kit/log/level" + "github.com/kolide/launcher/pkg/allowedpaths" "github.com/kolide/launcher/pkg/osquery/tables/tablehelpers" "github.com/osquery/osquery-go/plugin/table" "github.com/pkg/errors" @@ -19,7 +20,7 @@ const allowedCharacters = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0 type Table struct { logger log.Logger - cmd string + cmd allowedpaths.AllowedCommand } func columns() []table.ColumnDefinition { @@ -34,7 +35,7 @@ func columns() []table.ColumnDefinition { func ZfsPropertiesPlugin(logger log.Logger) *table.Plugin { t := &Table{ logger: logger, - cmd: "zfs", + cmd: allowedpaths.Zfs, } return table.NewPlugin("kolide_zfs_properties", columns(), t.generate) @@ -43,7 +44,7 @@ func ZfsPropertiesPlugin(logger log.Logger) *table.Plugin { func ZpoolPropertiesPlugin(logger log.Logger) *table.Plugin { t := &Table{ logger: logger, - cmd: "zpool", + cmd: allowedpaths.Zpool, } return table.NewPlugin("kolide_zpool_properties", columns(), t.generate) @@ -70,7 +71,7 @@ func (t *Table) generate(ctx context.Context, queryContext table.QueryContext) ( args = append(args, names...) - output, err := tablehelpers.Exec(ctx, t.logger, 15, []string{t.cmd}, args, false) + output, err := tablehelpers.Exec(ctx, t.logger, 15, t.cmd, args, false) if err != nil { // exec will error if there's no binary, so we never want to record that if os.IsNotExist(errors.Cause(err)) { diff --git a/pkg/ptycmd/command.go b/pkg/ptycmd/command.go deleted file mode 100644 index 7fa9de5ac..000000000 --- a/pkg/ptycmd/command.go +++ /dev/null @@ -1,132 +0,0 @@ -//go:build !windows -// +build !windows - -package ptycmd - -import ( - "fmt" - "os" - "syscall" - "time" - "unsafe" - - "github.com/kolide/launcher/pkg/allowedpaths" - "github.com/kr/pty" -) - -// NewCmd creates a new command attached to a pty -func NewCmd(command string, argv []string, options ...Option) (*Cmd, error) { - // create the command - cmd, err := allowedpaths.CommandWithLookup(command, argv...) - if err != nil { - return nil, fmt.Errorf("creating command: %w", err) - } - - // open a pty - pty, tty, err := pty.Open() - if err != nil { - return nil, fmt.Errorf("opening pty: %w", err) - } - defer tty.Close() - - // attach the stdin/stdout/stderr of the pty's tty to the cmd - cmd.Stdout = tty - cmd.Stdin = tty - cmd.Stderr = tty - - // start the cmd, closing the PTY if there's an error - if err := cmd.Start(); err != nil { - return nil, fmt.Errorf("starting command `%s`: %w", command, err) - } - - ptyClosed := make(chan struct{}) - - // create the command with default options - ptyCmd := &Cmd{ - command: command, - argv: argv, - cmd: cmd, - pty: pty, - ptyClosed: ptyClosed, - closeSignal: syscall.SIGINT, - closeTimeout: 10 * time.Second, - } - - // apply the given options using the functional opts pattern - for _, option := range options { - option(ptyCmd) - } - - // if the process is closed, close the pty - go func() { - ptyCmd.cmd.Wait() - ptyCmd.pty.Close() - close(ptyCmd.ptyClosed) - }() - - return ptyCmd, nil -} - -// Read reads into the specified buffer from the pty -func (c *Cmd) Read(p []byte) (n int, err error) { - return c.pty.Read(p) -} - -// Write writes from the specified buffer into the pty -func (c *Cmd) Write(p []byte) (n int, err error) { - return c.pty.Write(p) -} - -// Close closes the underlying process and the pty -func (c *Cmd) Close() error { - // if the process exists, send the close signal - if c.cmd != nil && c.cmd.Process != nil { - c.cmd.Process.Signal(c.closeSignal) - } - for { - select { - // either it was closed - case <-c.ptyClosed: - return nil - - // or timeout - case <-time.After(c.closeTimeout): - c.cmd.Process.Signal(syscall.SIGKILL) - return nil - } - } -} - -// Title returns a title for the TTY window -func (c *Cmd) Title() string { - hostName, err := os.Hostname() - if err != nil { - hostName = "remote-host" - } - return fmt.Sprintf("%s@%s", c.command, hostName) -} - -// Resize resizes the terminal of the process -func (c *Cmd) Resize(width int, height int) error { - window := struct { - row uint16 - col uint16 - x uint16 - y uint16 - }{ - uint16(height), - uint16(width), - 0, - 0, - } - _, _, errno := syscall.Syscall( - syscall.SYS_IOCTL, - c.pty.Fd(), - syscall.TIOCSWINSZ, - uintptr(unsafe.Pointer(&window)), - ) - if errno != 0 { - return errno - } - return nil -} diff --git a/pkg/ptycmd/command_windows.go b/pkg/ptycmd/command_windows.go deleted file mode 100644 index b20623f94..000000000 --- a/pkg/ptycmd/command_windows.go +++ /dev/null @@ -1,34 +0,0 @@ -//go:build windows -// +build windows - -package ptycmd - -import ( - "errors" -) - -// NewCmd creates a new command attached to a pty -func NewCmd(command string, argv []string, options ...Option) (*Cmd, error) { - return nil, errors.New("Not supported on windows") -} - -func (c *Cmd) Close() error { - return errors.New("Not supported on windows") -} - -func (c *Cmd) Read(p []byte) (n int, err error) { - return c.pty.Read(p) -} - -// Write writes from the specified buffer into the pty -func (c *Cmd) Write(p []byte) (n int, err error) { - return c.pty.Write(p) -} - -func (c *Cmd) Resize(width int, height int) error { - return nil -} - -func (c *Cmd) Title() string { - return "" -} diff --git a/pkg/ptycmd/options.go b/pkg/ptycmd/options.go deleted file mode 100644 index 00e25f141..000000000 --- a/pkg/ptycmd/options.go +++ /dev/null @@ -1,51 +0,0 @@ -package ptycmd - -import ( - "os" - "os/exec" - "syscall" - "time" -) - -// Option is a configuration option for a Cmd -type Option func(*Cmd) - -// Cmd is a shelled out command and an attached pty -type Cmd struct { - // the command that is being relayed - command string // nolint:unused - - // args passed to the command - argv []string // nolint:unused - - // the external command struct - cmd *exec.Cmd // nolint:unused - - // the pseudoterminal attached to the command - pty *os.File - - // channel to signal closing the pty - ptyClosed chan struct{} // nolint:unused - - // signal to close process - closeSignal syscall.Signal - - // time to wait to close process - closeTimeout time.Duration -} - -// WithCloseSignal lets you specify the signal to send to the -// underlying process on close -func WithCloseSignal(signal syscall.Signal) Option { - return func(c *Cmd) { - c.closeSignal = signal - } -} - -// WithCloseTimeout lets you specify how long to wait for the -// underlying process to terminate before sending a SIGKILL -func WithCloseTimeout(timeout time.Duration) Option { - return func(c *Cmd) { - c.closeTimeout = timeout - } -} From d244dcf95a05674d9bc259a426f0f979a061dade Mon Sep 17 00:00:00 2001 From: Rebecca Mahany-Horton Date: Wed, 8 Nov 2023 16:14:12 -0500 Subject: [PATCH 12/30] Fix comments, add test --- pkg/allowedpaths/cmd_test.go | 11 +++++++++++ pkg/autoupdate/findnew.go | 2 +- pkg/osquery/runtime/osqueryinstance.go | 2 +- 3 files changed, 13 insertions(+), 2 deletions(-) diff --git a/pkg/allowedpaths/cmd_test.go b/pkg/allowedpaths/cmd_test.go index ca13f12d5..dc2404ba4 100644 --- a/pkg/allowedpaths/cmd_test.go +++ b/pkg/allowedpaths/cmd_test.go @@ -1,6 +1,7 @@ package allowedpaths import ( + "context" "path/filepath" "runtime" "testing" @@ -8,6 +9,16 @@ import ( "github.com/stretchr/testify/require" ) +func TestEcho(t *testing.T) { + t.Parallel() + + // echo is the only one available on all platforms and likely to be available in CI + cmd, err := Echo(context.TODO(), "hello") + require.NoError(t, err) + require.Contains(t, cmd.Path, "echo") + require.Contains(t, cmd.Args, "hello") +} + func Test_newCmd(t *testing.T) { t.Parallel() diff --git a/pkg/autoupdate/findnew.go b/pkg/autoupdate/findnew.go index e5a91a539..57af49af1 100644 --- a/pkg/autoupdate/findnew.go +++ b/pkg/autoupdate/findnew.go @@ -372,7 +372,7 @@ func CheckExecutable(ctx context.Context, potentialBinary string, args ...string defer cancel() // Since we trust the autoupdate library to find binaries in the correct location, - // we don't require the use of allowedpaths.CommandContextWithPath here. + // we don't require the use of allowedpaths here. cmd := exec.CommandContext(ctx, potentialBinary, args...) //nolint:forbidigo // Set env, this should prevent launcher for fork-bombing diff --git a/pkg/osquery/runtime/osqueryinstance.go b/pkg/osquery/runtime/osqueryinstance.go index eb6349ad2..d7d059f9d 100644 --- a/pkg/osquery/runtime/osqueryinstance.go +++ b/pkg/osquery/runtime/osqueryinstance.go @@ -481,7 +481,7 @@ func (opts *osqueryOptions) createOsquerydCommand(osquerydBinary string, paths * args = append(args, "--disable_watchdog") } // Since we trust the autoupdate library to find binaries in the correct location, - // we don't require the use of allowedpaths.CommandContextWithPath here. + // we don't require the use of allowedpaths here. cmd := exec.Command( //nolint:forbidigo osquerydBinary, args..., From 7538a55cfff8313995a29fe3674ee2b537f09265 Mon Sep 17 00:00:00 2001 From: Rebecca Mahany-Horton Date: Wed, 8 Nov 2023 16:16:24 -0500 Subject: [PATCH 13/30] Some stragglers --- .../dsim_default_associations/dsim_default_associations.go | 4 +--- pkg/osquery/tables/secedit/secedit.go | 4 +--- pkg/osquery/tables/wifi_networks/wifi_networks.go | 2 +- pkg/osquery/tables/xrdb/xrdb.go | 2 +- 4 files changed, 4 insertions(+), 8 deletions(-) diff --git a/pkg/osquery/tables/dsim_default_associations/dsim_default_associations.go b/pkg/osquery/tables/dsim_default_associations/dsim_default_associations.go index cd9163bdd..a427754a0 100644 --- a/pkg/osquery/tables/dsim_default_associations/dsim_default_associations.go +++ b/pkg/osquery/tables/dsim_default_associations/dsim_default_associations.go @@ -22,8 +22,6 @@ import ( "github.com/osquery/osquery-go/plugin/table" ) -const dismCmd = "dism.exe" - type Table struct { logger log.Logger } @@ -84,7 +82,7 @@ func (t *Table) execDism(ctx context.Context) ([]byte, error) { args := []string{"/online", "/Export-DefaultAppAssociations:" + dstFile} - cmd, err := allowedpaths.CommandContextWithLookup(ctx, dismCmd, args...) + cmd, err := allowedpaths.Dism(ctx, args...) if err != nil { return nil, fmt.Errorf("creating command: %w", err) } diff --git a/pkg/osquery/tables/secedit/secedit.go b/pkg/osquery/tables/secedit/secedit.go index fbfde2dbc..cadfbf6b1 100644 --- a/pkg/osquery/tables/secedit/secedit.go +++ b/pkg/osquery/tables/secedit/secedit.go @@ -27,8 +27,6 @@ import ( "golang.org/x/text/transform" ) -const seceditCmd = "secedit.exe" - type Table struct { logger log.Logger } @@ -109,7 +107,7 @@ func (t *Table) execSecedit(ctx context.Context, mergedPolicy bool) ([]byte, err args = append(args, "/mergedpolicy") } - cmd, err := allowedpaths.CommandContextWithLookup(ctx, seceditCmd, args...) + cmd, err := allowedpaths.Secedit(ctx, args...) if err != nil { return nil, fmt.Errorf("creating secedit command: %w", err) } diff --git a/pkg/osquery/tables/wifi_networks/wifi_networks.go b/pkg/osquery/tables/wifi_networks/wifi_networks.go index 0c04d9465..9287390e9 100644 --- a/pkg/osquery/tables/wifi_networks/wifi_networks.go +++ b/pkg/osquery/tables/wifi_networks/wifi_networks.go @@ -91,7 +91,7 @@ func execPwsh(logger log.Logger) execer { } args := append([]string{"-NoProfile", "-NonInteractive"}, string(pwshScript)) - cmd, err := allowedpaths.CommandContextWithLookup(ctx, "powershell.exe", args...) + cmd, err := allowedpaths.Powershell(ctx, args...) if err != nil { return fmt.Errorf("creating powershell command: %w", err) } diff --git a/pkg/osquery/tables/xrdb/xrdb.go b/pkg/osquery/tables/xrdb/xrdb.go index 85fddfa96..b36996773 100644 --- a/pkg/osquery/tables/xrdb/xrdb.go +++ b/pkg/osquery/tables/xrdb/xrdb.go @@ -95,7 +95,7 @@ func execXRDB(ctx context.Context, displayNum, username string, buf *bytes.Buffe return fmt.Errorf("finding user by username '%s': %w", username, err) } - cmd, err := allowedpaths.CommandContextWithLookup(ctx, "xrdb", "-display", displayNum, "-global", "-query") + cmd, err := allowedpaths.Xrdb(ctx, "-display", displayNum, "-global", "-query") if err != nil { return fmt.Errorf("creating xrdb command: %w", err) } From 64a1fc1b1c74a34ad494ae7e194e149ef8c7e7c2 Mon Sep 17 00:00:00 2001 From: Rebecca Mahany-Horton Date: Wed, 8 Nov 2023 16:21:26 -0500 Subject: [PATCH 14/30] Missing context --- pkg/osquery/runtime/runtime_helpers_windows.go | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/pkg/osquery/runtime/runtime_helpers_windows.go b/pkg/osquery/runtime/runtime_helpers_windows.go index c651e9065..1963abe6f 100644 --- a/pkg/osquery/runtime/runtime_helpers_windows.go +++ b/pkg/osquery/runtime/runtime_helpers_windows.go @@ -4,6 +4,7 @@ package runtime import ( + "context" "fmt" "os/exec" "syscall" @@ -22,7 +23,7 @@ func setpgid() *syscall.SysProcAttr { func killProcessGroup(cmd *exec.Cmd) error { // some discussion here https://github.com/golang/dep/pull/857 // TODO: should we check err? - cmd, err := allowedpaths.Taskkill("/F", "/T", "/PID", fmt.Sprint(cmd.Process.Pid)) + cmd, err := allowedpaths.Taskkill(context.TODO(), "/F", "/T", "/PID", fmt.Sprint(cmd.Process.Pid)) if err != nil { return fmt.Errorf("creating command: %w", err) } From 4cf335846c1d94a7090e1da38785b6f58ff420e9 Mon Sep 17 00:00:00 2001 From: Rebecca Mahany-Horton Date: Wed, 8 Nov 2023 16:46:31 -0500 Subject: [PATCH 15/30] Using CommandContext instead of Command --- pkg/allowedpaths/cmd.go | 118 +++++++++++++++++------------------ pkg/allowedpaths/cmd_test.go | 2 +- 2 files changed, 60 insertions(+), 60 deletions(-) diff --git a/pkg/allowedpaths/cmd.go b/pkg/allowedpaths/cmd.go index 06cb1ef9a..e5a5db865 100644 --- a/pkg/allowedpaths/cmd.go +++ b/pkg/allowedpaths/cmd.go @@ -22,7 +22,7 @@ func Airport(ctx context.Context, arg ...string) (*exec.Cmd, error) { if err != nil { return nil, fmt.Errorf("airport not found: %w", err) } - return newCmd(fullPathToCmdValidated, arg...), nil + return newCmd(ctx, fullPathToCmdValidated, arg...), nil } func Apt(ctx context.Context, arg ...string) (*exec.Cmd, error) { @@ -34,7 +34,7 @@ func Apt(ctx context.Context, arg ...string) (*exec.Cmd, error) { if err != nil { return nil, fmt.Errorf("apt not found: %w", err) } - return newCmd(fullPathToCmdValidated, arg...), nil + return newCmd(ctx, fullPathToCmdValidated, arg...), nil } func Bioutil(ctx context.Context, arg ...string) (*exec.Cmd, error) { @@ -46,7 +46,7 @@ func Bioutil(ctx context.Context, arg ...string) (*exec.Cmd, error) { if err != nil { return nil, fmt.Errorf("bioutil not found: %w", err) } - return newCmd(fullPathToCmdValidated, arg...), nil + return newCmd(ctx, fullPathToCmdValidated, arg...), nil } func Bputil(ctx context.Context, arg ...string) (*exec.Cmd, error) { @@ -58,7 +58,7 @@ func Bputil(ctx context.Context, arg ...string) (*exec.Cmd, error) { if err != nil { return nil, fmt.Errorf("bputil not found: %w", err) } - return newCmd(fullPathToCmdValidated, arg...), nil + return newCmd(ctx, fullPathToCmdValidated, arg...), nil } func Commandprompt(ctx context.Context, arg ...string) (*exec.Cmd, error) { @@ -70,7 +70,7 @@ func Commandprompt(ctx context.Context, arg ...string) (*exec.Cmd, error) { if err != nil { return nil, fmt.Errorf("cmd.exe not found: %w", err) } - return newCmd(fullPathToCmdValidated, arg...), nil + return newCmd(ctx, fullPathToCmdValidated, arg...), nil } func Cryptsetup(ctx context.Context, arg ...string) (*exec.Cmd, error) { @@ -84,7 +84,7 @@ func Cryptsetup(ctx context.Context, arg ...string) (*exec.Cmd, error) { continue } - return newCmd(fullPathToCmdValidated, arg...), nil + return newCmd(ctx, fullPathToCmdValidated, arg...), nil } return nil, errors.New("cryptsetup not found") @@ -99,7 +99,7 @@ func Diskutil(ctx context.Context, arg ...string) (*exec.Cmd, error) { if err != nil { return nil, fmt.Errorf("diskutil not found: %w", err) } - return newCmd(fullPathToCmdValidated, arg...), nil + return newCmd(ctx, fullPathToCmdValidated, arg...), nil } func Dism(ctx context.Context, arg ...string) (*exec.Cmd, error) { @@ -111,7 +111,7 @@ func Dism(ctx context.Context, arg ...string) (*exec.Cmd, error) { if err != nil { return nil, fmt.Errorf("dism.exe not found: %w", err) } - return newCmd(fullPathToCmdValidated, arg...), nil + return newCmd(ctx, fullPathToCmdValidated, arg...), nil } func Dnf(ctx context.Context, arg ...string) (*exec.Cmd, error) { @@ -123,7 +123,7 @@ func Dnf(ctx context.Context, arg ...string) (*exec.Cmd, error) { if err != nil { return nil, fmt.Errorf("dnf not found: %w", err) } - return newCmd(fullPathToCmdValidated, arg...), nil + return newCmd(ctx, fullPathToCmdValidated, arg...), nil } func Dpkg(ctx context.Context, arg ...string) (*exec.Cmd, error) { @@ -135,7 +135,7 @@ func Dpkg(ctx context.Context, arg ...string) (*exec.Cmd, error) { if err != nil { return nil, fmt.Errorf("dpkg not found: %w", err) } - return newCmd(fullPathToCmdValidated, arg...), nil + return newCmd(ctx, fullPathToCmdValidated, arg...), nil } func Dsregcmd(ctx context.Context, arg ...string) (*exec.Cmd, error) { @@ -147,13 +147,13 @@ func Dsregcmd(ctx context.Context, arg ...string) (*exec.Cmd, error) { if err != nil { return nil, fmt.Errorf("dsregcmd.exe not found: %w", err) } - return newCmd(fullPathToCmdValidated, arg...), nil + return newCmd(ctx, fullPathToCmdValidated, arg...), nil } func Echo(ctx context.Context, arg ...string) (*exec.Cmd, error) { // echo on Windows is only available as a command in cmd.exe if runtime.GOOS == "windows" { - return Commandprompt(ctx, append([]string{"echo"}, arg...)...) + return newCmd(ctx, "echo", arg...), nil } var fullPathToCmd string @@ -168,7 +168,7 @@ func Echo(ctx context.Context, arg ...string) (*exec.Cmd, error) { if err != nil { return nil, fmt.Errorf("echo not found: %w", err) } - return newCmd(fullPathToCmdValidated, arg...), nil + return newCmd(ctx, fullPathToCmdValidated, arg...), nil } func Falconctl(ctx context.Context, arg ...string) (*exec.Cmd, error) { @@ -188,7 +188,7 @@ func Falconctl(ctx context.Context, arg ...string) (*exec.Cmd, error) { if err != nil { return nil, fmt.Errorf("falconctl not found: %w", err) } - return newCmd(fullPathToCmdValidated, arg...), nil + return newCmd(ctx, fullPathToCmdValidated, arg...), nil } func Falconkernelcheck(ctx context.Context, arg ...string) (*exec.Cmd, error) { @@ -200,7 +200,7 @@ func Falconkernelcheck(ctx context.Context, arg ...string) (*exec.Cmd, error) { if err != nil { return nil, fmt.Errorf("falcon-kernel-check not found: %w", err) } - return newCmd(fullPathToCmdValidated, arg...), nil + return newCmd(ctx, fullPathToCmdValidated, arg...), nil } func Fdesetup(ctx context.Context, arg ...string) (*exec.Cmd, error) { @@ -212,7 +212,7 @@ func Fdesetup(ctx context.Context, arg ...string) (*exec.Cmd, error) { if err != nil { return nil, fmt.Errorf("fdesetup not found: %w", err) } - return newCmd(fullPathToCmdValidated, arg...), nil + return newCmd(ctx, fullPathToCmdValidated, arg...), nil } func Firmwarepasswd(ctx context.Context, arg ...string) (*exec.Cmd, error) { @@ -224,7 +224,7 @@ func Firmwarepasswd(ctx context.Context, arg ...string) (*exec.Cmd, error) { if err != nil { return nil, fmt.Errorf("firmwarepasswd not found: %w", err) } - return newCmd(fullPathToCmdValidated, arg...), nil + return newCmd(ctx, fullPathToCmdValidated, arg...), nil } func Gnomeextensions(ctx context.Context, arg ...string) (*exec.Cmd, error) { @@ -236,7 +236,7 @@ func Gnomeextensions(ctx context.Context, arg ...string) (*exec.Cmd, error) { if err != nil { return nil, fmt.Errorf("gnome-extensions not found: %w", err) } - return newCmd(fullPathToCmdValidated, arg...), nil + return newCmd(ctx, fullPathToCmdValidated, arg...), nil } func Gsettings(ctx context.Context, arg ...string) (*exec.Cmd, error) { @@ -248,7 +248,7 @@ func Gsettings(ctx context.Context, arg ...string) (*exec.Cmd, error) { if err != nil { return nil, fmt.Errorf("gsettings not found: %w", err) } - return newCmd(fullPathToCmdValidated, arg...), nil + return newCmd(ctx, fullPathToCmdValidated, arg...), nil } func Ifconfig(ctx context.Context, arg ...string) (*exec.Cmd, error) { @@ -268,7 +268,7 @@ func Ifconfig(ctx context.Context, arg ...string) (*exec.Cmd, error) { if err != nil { return nil, fmt.Errorf("ifconfig not found: %w", err) } - return newCmd(fullPathToCmdValidated, arg...), nil + return newCmd(ctx, fullPathToCmdValidated, arg...), nil } func Ioreg(ctx context.Context, arg ...string) (*exec.Cmd, error) { @@ -280,7 +280,7 @@ func Ioreg(ctx context.Context, arg ...string) (*exec.Cmd, error) { if err != nil { return nil, fmt.Errorf("ioreg not found: %w", err) } - return newCmd(fullPathToCmdValidated, arg...), nil + return newCmd(ctx, fullPathToCmdValidated, arg...), nil } func Ip(ctx context.Context, arg ...string) (*exec.Cmd, error) { @@ -292,7 +292,7 @@ func Ip(ctx context.Context, arg ...string) (*exec.Cmd, error) { if err != nil { return nil, fmt.Errorf("ip not found: %w", err) } - return newCmd(fullPathToCmdValidated, arg...), nil + return newCmd(ctx, fullPathToCmdValidated, arg...), nil } func Ipconfig(ctx context.Context, arg ...string) (*exec.Cmd, error) { @@ -304,7 +304,7 @@ func Ipconfig(ctx context.Context, arg ...string) (*exec.Cmd, error) { if err != nil { return nil, fmt.Errorf("ipconfig.exe not found: %w", err) } - return newCmd(fullPathToCmdValidated, arg...), nil + return newCmd(ctx, fullPathToCmdValidated, arg...), nil } func Launchctl(ctx context.Context, arg ...string) (*exec.Cmd, error) { @@ -316,7 +316,7 @@ func Launchctl(ctx context.Context, arg ...string) (*exec.Cmd, error) { if err != nil { return nil, fmt.Errorf("launchctl not found: %w", err) } - return newCmd(fullPathToCmdValidated, arg...), nil + return newCmd(ctx, fullPathToCmdValidated, arg...), nil } func Loginctl(ctx context.Context, arg ...string) (*exec.Cmd, error) { @@ -328,7 +328,7 @@ func Loginctl(ctx context.Context, arg ...string) (*exec.Cmd, error) { if err != nil { return nil, fmt.Errorf("loginctl not found: %w", err) } - return newCmd(fullPathToCmdValidated, arg...), nil + return newCmd(ctx, fullPathToCmdValidated, arg...), nil } func Lsblk(ctx context.Context, arg ...string) (*exec.Cmd, error) { @@ -342,7 +342,7 @@ func Lsblk(ctx context.Context, arg ...string) (*exec.Cmd, error) { continue } - return newCmd(fullPathToCmdValidated, arg...), nil + return newCmd(ctx, fullPathToCmdValidated, arg...), nil } return nil, errors.New("lsblk not found") @@ -365,7 +365,7 @@ func Lsof(ctx context.Context, arg ...string) (*exec.Cmd, error) { if err != nil { return nil, fmt.Errorf("lsof not found: %w", err) } - return newCmd(fullPathToCmdValidated, arg...), nil + return newCmd(ctx, fullPathToCmdValidated, arg...), nil } func Mdfind(ctx context.Context, arg ...string) (*exec.Cmd, error) { @@ -377,7 +377,7 @@ func Mdfind(ctx context.Context, arg ...string) (*exec.Cmd, error) { if err != nil { return nil, fmt.Errorf("mdfind not found: %w", err) } - return newCmd(fullPathToCmdValidated, arg...), nil + return newCmd(ctx, fullPathToCmdValidated, arg...), nil } func Mdmclient(ctx context.Context, arg ...string) (*exec.Cmd, error) { @@ -389,7 +389,7 @@ func Mdmclient(ctx context.Context, arg ...string) (*exec.Cmd, error) { if err != nil { return nil, fmt.Errorf("mdmclient not found: %w", err) } - return newCmd(fullPathToCmdValidated, arg...), nil + return newCmd(ctx, fullPathToCmdValidated, arg...), nil } func Netstat(ctx context.Context, arg ...string) (*exec.Cmd, error) { @@ -401,7 +401,7 @@ func Netstat(ctx context.Context, arg ...string) (*exec.Cmd, error) { if err != nil { return nil, fmt.Errorf("netstat not found: %w", err) } - return newCmd(fullPathToCmdValidated, arg...), nil + return newCmd(ctx, fullPathToCmdValidated, arg...), nil } func Nmcli(ctx context.Context, arg ...string) (*exec.Cmd, error) { @@ -413,7 +413,7 @@ func Nmcli(ctx context.Context, arg ...string) (*exec.Cmd, error) { if err != nil { return nil, fmt.Errorf("nmcli not found: %w", err) } - return newCmd(fullPathToCmdValidated, arg...), nil + return newCmd(ctx, fullPathToCmdValidated, arg...), nil } func Notifysend(ctx context.Context, arg ...string) (*exec.Cmd, error) { @@ -425,7 +425,7 @@ func Notifysend(ctx context.Context, arg ...string) (*exec.Cmd, error) { if err != nil { return nil, fmt.Errorf("notify-send not found: %w", err) } - return newCmd(fullPathToCmdValidated, arg...), nil + return newCmd(ctx, fullPathToCmdValidated, arg...), nil } func Open(ctx context.Context, arg ...string) (*exec.Cmd, error) { @@ -437,7 +437,7 @@ func Open(ctx context.Context, arg ...string) (*exec.Cmd, error) { if err != nil { return nil, fmt.Errorf("open not found: %w", err) } - return newCmd(fullPathToCmdValidated, arg...), nil + return newCmd(ctx, fullPathToCmdValidated, arg...), nil } func Pacman(ctx context.Context, arg ...string) (*exec.Cmd, error) { @@ -449,7 +449,7 @@ func Pacman(ctx context.Context, arg ...string) (*exec.Cmd, error) { if err != nil { return nil, fmt.Errorf("pacman not found: %w", err) } - return newCmd(fullPathToCmdValidated, arg...), nil + return newCmd(ctx, fullPathToCmdValidated, arg...), nil } func Pkgutil(ctx context.Context, arg ...string) (*exec.Cmd, error) { @@ -461,7 +461,7 @@ func Pkgutil(ctx context.Context, arg ...string) (*exec.Cmd, error) { if err != nil { return nil, fmt.Errorf("pkgutil not found: %w", err) } - return newCmd(fullPathToCmdValidated, arg...), nil + return newCmd(ctx, fullPathToCmdValidated, arg...), nil } func Powercfg(ctx context.Context, arg ...string) (*exec.Cmd, error) { @@ -473,7 +473,7 @@ func Powercfg(ctx context.Context, arg ...string) (*exec.Cmd, error) { if err != nil { return nil, fmt.Errorf("powercfg.exe not found: %w", err) } - return newCmd(fullPathToCmdValidated, arg...), nil + return newCmd(ctx, fullPathToCmdValidated, arg...), nil } func Powermetrics(ctx context.Context, arg ...string) (*exec.Cmd, error) { @@ -485,7 +485,7 @@ func Powermetrics(ctx context.Context, arg ...string) (*exec.Cmd, error) { if err != nil { return nil, fmt.Errorf("powermetrics not found: %w", err) } - return newCmd(fullPathToCmdValidated, arg...), nil + return newCmd(ctx, fullPathToCmdValidated, arg...), nil } func Powershell(ctx context.Context, arg ...string) (*exec.Cmd, error) { @@ -497,7 +497,7 @@ func Powershell(ctx context.Context, arg ...string) (*exec.Cmd, error) { if err != nil { return nil, fmt.Errorf("powershell.exe not found: %w", err) } - return newCmd(fullPathToCmdValidated, arg...), nil + return newCmd(ctx, fullPathToCmdValidated, arg...), nil } func Profiles(ctx context.Context, arg ...string) (*exec.Cmd, error) { @@ -509,7 +509,7 @@ func Profiles(ctx context.Context, arg ...string) (*exec.Cmd, error) { if err != nil { return nil, fmt.Errorf("profiles not found: %w", err) } - return newCmd(fullPathToCmdValidated, arg...), nil + return newCmd(ctx, fullPathToCmdValidated, arg...), nil } func Ps(ctx context.Context, arg ...string) (*exec.Cmd, error) { @@ -529,7 +529,7 @@ func Ps(ctx context.Context, arg ...string) (*exec.Cmd, error) { if err != nil { return nil, fmt.Errorf("ps not found: %w", err) } - return newCmd(fullPathToCmdValidated, arg...), nil + return newCmd(ctx, fullPathToCmdValidated, arg...), nil } func Pwpolicy(ctx context.Context, arg ...string) (*exec.Cmd, error) { @@ -541,7 +541,7 @@ func Pwpolicy(ctx context.Context, arg ...string) (*exec.Cmd, error) { if err != nil { return nil, fmt.Errorf("pwpolicy not found: %w", err) } - return newCmd(fullPathToCmdValidated, arg...), nil + return newCmd(ctx, fullPathToCmdValidated, arg...), nil } func Remotectl(ctx context.Context, arg ...string) (*exec.Cmd, error) { @@ -553,7 +553,7 @@ func Remotectl(ctx context.Context, arg ...string) (*exec.Cmd, error) { if err != nil { return nil, fmt.Errorf("remotectl not found: %w", err) } - return newCmd(fullPathToCmdValidated, arg...), nil + return newCmd(ctx, fullPathToCmdValidated, arg...), nil } func Repcli(ctx context.Context, arg ...string) (*exec.Cmd, error) { @@ -571,7 +571,7 @@ func Repcli(ctx context.Context, arg ...string) (*exec.Cmd, error) { if err != nil { return nil, fmt.Errorf("repcli not found: %w", err) } - return newCmd(fullPathToCmdValidated, arg...), nil + return newCmd(ctx, fullPathToCmdValidated, arg...), nil } func Rpm(ctx context.Context, arg ...string) (*exec.Cmd, error) { @@ -585,7 +585,7 @@ func Rpm(ctx context.Context, arg ...string) (*exec.Cmd, error) { continue } - return newCmd(fullPathToCmdValidated, arg...), nil + return newCmd(ctx, fullPathToCmdValidated, arg...), nil } return nil, errors.New("rpm not found") @@ -600,7 +600,7 @@ func Scutil(ctx context.Context, arg ...string) (*exec.Cmd, error) { if err != nil { return nil, fmt.Errorf("scutil not found: %w", err) } - return newCmd(fullPathToCmdValidated, arg...), nil + return newCmd(ctx, fullPathToCmdValidated, arg...), nil } func Secedit(ctx context.Context, arg ...string) (*exec.Cmd, error) { @@ -612,7 +612,7 @@ func Secedit(ctx context.Context, arg ...string) (*exec.Cmd, error) { if err != nil { return nil, fmt.Errorf("secedit.exe not found: %w", err) } - return newCmd(fullPathToCmdValidated, arg...), nil + return newCmd(ctx, fullPathToCmdValidated, arg...), nil } func Softwareupdate(ctx context.Context, arg ...string) (*exec.Cmd, error) { @@ -624,7 +624,7 @@ func Softwareupdate(ctx context.Context, arg ...string) (*exec.Cmd, error) { if err != nil { return nil, fmt.Errorf("softwareupdate not found: %w", err) } - return newCmd(fullPathToCmdValidated, arg...), nil + return newCmd(ctx, fullPathToCmdValidated, arg...), nil } func Systemctl(ctx context.Context, arg ...string) (*exec.Cmd, error) { @@ -636,7 +636,7 @@ func Systemctl(ctx context.Context, arg ...string) (*exec.Cmd, error) { if err != nil { return nil, fmt.Errorf("systemctl not found: %w", err) } - return newCmd(fullPathToCmdValidated, arg...), nil + return newCmd(ctx, fullPathToCmdValidated, arg...), nil } func Systemprofiler(ctx context.Context, arg ...string) (*exec.Cmd, error) { @@ -648,7 +648,7 @@ func Systemprofiler(ctx context.Context, arg ...string) (*exec.Cmd, error) { if err != nil { return nil, fmt.Errorf("system_profiler not found: %w", err) } - return newCmd(fullPathToCmdValidated, arg...), nil + return newCmd(ctx, fullPathToCmdValidated, arg...), nil } func Taskkill(ctx context.Context, arg ...string) (*exec.Cmd, error) { @@ -660,7 +660,7 @@ func Taskkill(ctx context.Context, arg ...string) (*exec.Cmd, error) { if err != nil { return nil, fmt.Errorf("taskkill.exe not found: %w", err) } - return newCmd(fullPathToCmdValidated, arg...), nil + return newCmd(ctx, fullPathToCmdValidated, arg...), nil } func Tmutil(ctx context.Context, arg ...string) (*exec.Cmd, error) { @@ -672,7 +672,7 @@ func Tmutil(ctx context.Context, arg ...string) (*exec.Cmd, error) { if err != nil { return nil, fmt.Errorf("tmutil not found: %w", err) } - return newCmd(fullPathToCmdValidated, arg...), nil + return newCmd(ctx, fullPathToCmdValidated, arg...), nil } func Xdgopen(ctx context.Context, arg ...string) (*exec.Cmd, error) { @@ -684,7 +684,7 @@ func Xdgopen(ctx context.Context, arg ...string) (*exec.Cmd, error) { if err != nil { return nil, fmt.Errorf("xdg-open not found: %w", err) } - return newCmd(fullPathToCmdValidated, arg...), nil + return newCmd(ctx, fullPathToCmdValidated, arg...), nil } func Xrdb(ctx context.Context, arg ...string) (*exec.Cmd, error) { @@ -696,7 +696,7 @@ func Xrdb(ctx context.Context, arg ...string) (*exec.Cmd, error) { if err != nil { return nil, fmt.Errorf("xrdb not found: %w", err) } - return newCmd(fullPathToCmdValidated, arg...), nil + return newCmd(ctx, fullPathToCmdValidated, arg...), nil } func Xwwwbrowser(ctx context.Context, arg ...string) (*exec.Cmd, error) { @@ -708,7 +708,7 @@ func Xwwwbrowser(ctx context.Context, arg ...string) (*exec.Cmd, error) { if err != nil { return nil, fmt.Errorf("x-www-browser not found: %w", err) } - return newCmd(fullPathToCmdValidated, arg...), nil + return newCmd(ctx, fullPathToCmdValidated, arg...), nil } func Zerotiercli(ctx context.Context, arg ...string) (*exec.Cmd, error) { @@ -730,7 +730,7 @@ func Zerotiercli(ctx context.Context, arg ...string) (*exec.Cmd, error) { arg = append([]string{"-q"}, arg...) } - return newCmd(fullPathToCmdValidated, arg...), nil + return newCmd(ctx, fullPathToCmdValidated, arg...), nil } func Zfs(ctx context.Context, arg ...string) (*exec.Cmd, error) { @@ -742,7 +742,7 @@ func Zfs(ctx context.Context, arg ...string) (*exec.Cmd, error) { if err != nil { return nil, fmt.Errorf("zfs not found: %w", err) } - return newCmd(fullPathToCmdValidated, arg...), nil + return newCmd(ctx, fullPathToCmdValidated, arg...), nil } func Zpool(ctx context.Context, arg ...string) (*exec.Cmd, error) { @@ -754,11 +754,11 @@ func Zpool(ctx context.Context, arg ...string) (*exec.Cmd, error) { if err != nil { return nil, fmt.Errorf("zpool not found: %w", err) } - return newCmd(fullPathToCmdValidated, arg...), nil + return newCmd(ctx, fullPathToCmdValidated, arg...), nil } -func newCmd(fullPathToCmd string, arg ...string) *exec.Cmd { - return exec.Command(fullPathToCmd, arg...) //nolint:forbidigo +func newCmd(ctx context.Context, fullPathToCmd string, arg ...string) *exec.Cmd { + return exec.CommandContext(ctx, fullPathToCmd, arg...) //nolint:forbidigo } func validatedPath(knownPath string) (string, error) { diff --git a/pkg/allowedpaths/cmd_test.go b/pkg/allowedpaths/cmd_test.go index dc2404ba4..364e2b697 100644 --- a/pkg/allowedpaths/cmd_test.go +++ b/pkg/allowedpaths/cmd_test.go @@ -23,7 +23,7 @@ func Test_newCmd(t *testing.T) { t.Parallel() cmdPath := filepath.Join("some", "path", "to", "a", "command") - cmd := newCmd(cmdPath) + cmd := newCmd(context.TODO(), cmdPath) require.Equal(t, cmdPath, cmd.Path) } From ce32ff44b55ba310c0d89647490a1c229cdb4dcb Mon Sep 17 00:00:00 2001 From: Rebecca Mahany-Horton Date: Wed, 8 Nov 2023 17:00:58 -0500 Subject: [PATCH 16/30] Add test --- pkg/allowedpaths/cmd_test.go | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/pkg/allowedpaths/cmd_test.go b/pkg/allowedpaths/cmd_test.go index 364e2b697..4c8bc1b31 100644 --- a/pkg/allowedpaths/cmd_test.go +++ b/pkg/allowedpaths/cmd_test.go @@ -43,3 +43,17 @@ func Test_validatedPath(t *testing.T) { require.NoError(t, err) require.Equal(t, cmdPath, p) } + +func Test_validatedPath_findsCorrectPath(t *testing.T) { + t.Parallel() + + if runtime.GOOS != "linux" { + t.SkipNow() + } + + cmdPath := "/not/the/real/path/to/bash" + p, err := validatedPath(cmdPath) + + require.NoError(t, err) + require.NotEqual(t, cmdPath, p) +} From 17de2d151c8fbbdc2fe8b6ee4548e52a9069124d Mon Sep 17 00:00:00 2001 From: Rebecca Mahany-Horton Date: Thu, 9 Nov 2023 09:58:33 -0500 Subject: [PATCH 17/30] Make all commands platform-specific --- pkg/allowedpaths/cmd.go | 746 ------------------ pkg/allowedpaths/cmd_darwin.go | 251 ++++++ pkg/allowedpaths/cmd_linux.go | 242 ++++++ pkg/allowedpaths/cmd_windows.go | 100 +++ ...xtensions.go => gnome_extensions_linux.go} | 8 +- pkg/debug/checkups/gnome_extensions_other.go | 36 + pkg/debug/checkups/network.go | 61 -- pkg/debug/checkups/network_darwin.go | 26 + pkg/debug/checkups/network_linux.go | 31 + pkg/debug/checkups/network_windows.go | 19 + pkg/osquery/table/platform_tables_darwin.go | 3 + pkg/osquery/table/platform_tables_linux.go | 3 + pkg/osquery/table/table.go | 3 - .../crowdstrike/falcon_kernel_check/table.go | 3 + .../falcon_kernel_check/table_test.go | 3 + pkg/osquery/tables/cryptsetup/parser.go | 3 + pkg/osquery/tables/cryptsetup/parser_test.go | 3 + pkg/osquery/tables/cryptsetup/table.go | 3 + pkg/osquery/tables/gsettings/gsettings.go | 4 +- .../tables/gsettings/gsettings_test.go | 4 +- pkg/osquery/tables/gsettings/metadata.go | 4 +- pkg/osquery/tables/zfs/tables.go | 3 + pkg/osquery/tables/zfs/tables_test.go | 3 + 23 files changed, 741 insertions(+), 821 deletions(-) create mode 100644 pkg/allowedpaths/cmd_darwin.go create mode 100644 pkg/allowedpaths/cmd_linux.go create mode 100644 pkg/allowedpaths/cmd_windows.go rename pkg/debug/checkups/{gnome-extensions.go => gnome_extensions_linux.go} (98%) create mode 100644 pkg/debug/checkups/gnome_extensions_other.go create mode 100644 pkg/debug/checkups/network_darwin.go create mode 100644 pkg/debug/checkups/network_linux.go create mode 100644 pkg/debug/checkups/network_windows.go diff --git a/pkg/allowedpaths/cmd.go b/pkg/allowedpaths/cmd.go index e5a5db865..bea19177a 100644 --- a/pkg/allowedpaths/cmd.go +++ b/pkg/allowedpaths/cmd.go @@ -2,761 +2,15 @@ package allowedpaths import ( "context" - "errors" "fmt" "os" "os/exec" - "path" "path/filepath" "runtime" ) type AllowedCommand func(ctx context.Context, arg ...string) (*exec.Cmd, error) -func Airport(ctx context.Context, arg ...string) (*exec.Cmd, error) { - if runtime.GOOS != "darwin" { - return nil, errors.New("airport supported on darwin only") - } - - fullPathToCmdValidated, err := validatedPath("/System/Library/PrivateFrameworks/Apple80211.framework/Versions/Current/Resources/airport") - if err != nil { - return nil, fmt.Errorf("airport not found: %w", err) - } - return newCmd(ctx, fullPathToCmdValidated, arg...), nil -} - -func Apt(ctx context.Context, arg ...string) (*exec.Cmd, error) { - if runtime.GOOS != "linux" { - return nil, errors.New("apt supported on linux only") - } - - fullPathToCmdValidated, err := validatedPath("/usr/bin/apt") - if err != nil { - return nil, fmt.Errorf("apt not found: %w", err) - } - return newCmd(ctx, fullPathToCmdValidated, arg...), nil -} - -func Bioutil(ctx context.Context, arg ...string) (*exec.Cmd, error) { - if runtime.GOOS != "darwin" { - return nil, errors.New("bioutil supported on darwin only") - } - - fullPathToCmdValidated, err := validatedPath("/usr/bin/bioutil") - if err != nil { - return nil, fmt.Errorf("bioutil not found: %w", err) - } - return newCmd(ctx, fullPathToCmdValidated, arg...), nil -} - -func Bputil(ctx context.Context, arg ...string) (*exec.Cmd, error) { - if runtime.GOOS != "darwin" { - return nil, errors.New("bputil supported on darwin only") - } - - fullPathToCmdValidated, err := validatedPath("/usr/bin/bputil") - if err != nil { - return nil, fmt.Errorf("bputil not found: %w", err) - } - return newCmd(ctx, fullPathToCmdValidated, arg...), nil -} - -func Commandprompt(ctx context.Context, arg ...string) (*exec.Cmd, error) { - if runtime.GOOS != "windows" { - return nil, errors.New("cmd.exe supported on windows only") - } - - fullPathToCmdValidated, err := validatedPath(`C:\Windows\System32\cmd.exe`) - if err != nil { - return nil, fmt.Errorf("cmd.exe not found: %w", err) - } - return newCmd(ctx, fullPathToCmdValidated, arg...), nil -} - -func Cryptsetup(ctx context.Context, arg ...string) (*exec.Cmd, error) { - if runtime.GOOS != "linux" { - return nil, errors.New("cryptsetup supported on linux only") - } - - for _, p := range []string{"/usr/sbin/cryptsetup", "/sbin/cryptsetup"} { - fullPathToCmdValidated, err := validatedPath(p) - if err != nil { - continue - } - - return newCmd(ctx, fullPathToCmdValidated, arg...), nil - } - - return nil, errors.New("cryptsetup not found") -} - -func Diskutil(ctx context.Context, arg ...string) (*exec.Cmd, error) { - if runtime.GOOS != "darwin" { - return nil, errors.New("diskutil supported on darwin only") - } - - fullPathToCmdValidated, err := validatedPath("/usr/sbin/diskutil") - if err != nil { - return nil, fmt.Errorf("diskutil not found: %w", err) - } - return newCmd(ctx, fullPathToCmdValidated, arg...), nil -} - -func Dism(ctx context.Context, arg ...string) (*exec.Cmd, error) { - if runtime.GOOS != "windows" { - return nil, errors.New("dism.exe supported on windows only") - } - - fullPathToCmdValidated, err := validatedPath(`C:\Windows\System32\Dism.exe`) - if err != nil { - return nil, fmt.Errorf("dism.exe not found: %w", err) - } - return newCmd(ctx, fullPathToCmdValidated, arg...), nil -} - -func Dnf(ctx context.Context, arg ...string) (*exec.Cmd, error) { - if runtime.GOOS != "linux" { - return nil, errors.New("dnf supported on linux only") - } - - fullPathToCmdValidated, err := validatedPath("/usr/bin/dnf") - if err != nil { - return nil, fmt.Errorf("dnf not found: %w", err) - } - return newCmd(ctx, fullPathToCmdValidated, arg...), nil -} - -func Dpkg(ctx context.Context, arg ...string) (*exec.Cmd, error) { - if runtime.GOOS != "linux" { - return nil, errors.New("dpkg supported on linux only") - } - - fullPathToCmdValidated, err := validatedPath("/usr/bin/dpkg") - if err != nil { - return nil, fmt.Errorf("dpkg not found: %w", err) - } - return newCmd(ctx, fullPathToCmdValidated, arg...), nil -} - -func Dsregcmd(ctx context.Context, arg ...string) (*exec.Cmd, error) { - if runtime.GOOS != "windows" { - return nil, errors.New("dsregcmd.exe supported on windows only") - } - - fullPathToCmdValidated, err := validatedPath(`C:\Windows\System32\dsregcmd.exe`) - if err != nil { - return nil, fmt.Errorf("dsregcmd.exe not found: %w", err) - } - return newCmd(ctx, fullPathToCmdValidated, arg...), nil -} - -func Echo(ctx context.Context, arg ...string) (*exec.Cmd, error) { - // echo on Windows is only available as a command in cmd.exe - if runtime.GOOS == "windows" { - return newCmd(ctx, "echo", arg...), nil - } - - var fullPathToCmd string - switch runtime.GOOS { - case "darwin": - fullPathToCmd = "/bin/echo" - case "linux": - fullPathToCmd = "/usr/bin/echo" - } - - fullPathToCmdValidated, err := validatedPath(fullPathToCmd) - if err != nil { - return nil, fmt.Errorf("echo not found: %w", err) - } - return newCmd(ctx, fullPathToCmdValidated, arg...), nil -} - -func Falconctl(ctx context.Context, arg ...string) (*exec.Cmd, error) { - if runtime.GOOS != "darwin" && runtime.GOOS != "linux" { - return nil, errors.New("falconctl supported on darwin and linux only") - } - - var fullPathToCmd string - switch runtime.GOOS { - case "darwin": - fullPathToCmd = "/Applications/Falcon.app/Contents/Resources/falconctl" - case "linux": - fullPathToCmd = "/opt/CrowdStrike/falconctl" - } - - fullPathToCmdValidated, err := validatedPath(fullPathToCmd) - if err != nil { - return nil, fmt.Errorf("falconctl not found: %w", err) - } - return newCmd(ctx, fullPathToCmdValidated, arg...), nil -} - -func Falconkernelcheck(ctx context.Context, arg ...string) (*exec.Cmd, error) { - if runtime.GOOS != "linux" { - return nil, errors.New("falcon-kernel-check supported on linux only") - } - - fullPathToCmdValidated, err := validatedPath("/opt/CrowdStrike/falcon-kernel-check") - if err != nil { - return nil, fmt.Errorf("falcon-kernel-check not found: %w", err) - } - return newCmd(ctx, fullPathToCmdValidated, arg...), nil -} - -func Fdesetup(ctx context.Context, arg ...string) (*exec.Cmd, error) { - if runtime.GOOS != "darwin" { - return nil, errors.New("fdesetup supported on darwin only") - } - - fullPathToCmdValidated, err := validatedPath("/usr/bin/fdesetup") - if err != nil { - return nil, fmt.Errorf("fdesetup not found: %w", err) - } - return newCmd(ctx, fullPathToCmdValidated, arg...), nil -} - -func Firmwarepasswd(ctx context.Context, arg ...string) (*exec.Cmd, error) { - if runtime.GOOS != "darwin" { - return nil, errors.New("firmwarepasswd supported on darwin only") - } - - fullPathToCmdValidated, err := validatedPath("/usr/sbin/firmwarepasswd") - if err != nil { - return nil, fmt.Errorf("firmwarepasswd not found: %w", err) - } - return newCmd(ctx, fullPathToCmdValidated, arg...), nil -} - -func Gnomeextensions(ctx context.Context, arg ...string) (*exec.Cmd, error) { - if runtime.GOOS != "linux" { - return nil, errors.New("gnome-extensions supported on linux only") - } - - fullPathToCmdValidated, err := validatedPath("/usr/bin/gnome-extensions") - if err != nil { - return nil, fmt.Errorf("gnome-extensions not found: %w", err) - } - return newCmd(ctx, fullPathToCmdValidated, arg...), nil -} - -func Gsettings(ctx context.Context, arg ...string) (*exec.Cmd, error) { - if runtime.GOOS != "linux" { - return nil, errors.New("gsettings supported on linux only") - } - - fullPathToCmdValidated, err := validatedPath("/usr/bin/gsettings") - if err != nil { - return nil, fmt.Errorf("gsettings not found: %w", err) - } - return newCmd(ctx, fullPathToCmdValidated, arg...), nil -} - -func Ifconfig(ctx context.Context, arg ...string) (*exec.Cmd, error) { - if runtime.GOOS != "darwin" && runtime.GOOS != "linux" { - return nil, errors.New("ifconfig supported on darwin and linux only") - } - - var fullPathToCmd string - switch runtime.GOOS { - case "darwin": - fullPathToCmd = "/sbin/ifconfig" - case "linux": - fullPathToCmd = "/usr/sbin/ifconfig" - } - - fullPathToCmdValidated, err := validatedPath(fullPathToCmd) - if err != nil { - return nil, fmt.Errorf("ifconfig not found: %w", err) - } - return newCmd(ctx, fullPathToCmdValidated, arg...), nil -} - -func Ioreg(ctx context.Context, arg ...string) (*exec.Cmd, error) { - if runtime.GOOS != "darwin" { - return nil, errors.New("ioreg supported on darwin only") - } - - fullPathToCmdValidated, err := validatedPath("/usr/sbin/ioreg") - if err != nil { - return nil, fmt.Errorf("ioreg not found: %w", err) - } - return newCmd(ctx, fullPathToCmdValidated, arg...), nil -} - -func Ip(ctx context.Context, arg ...string) (*exec.Cmd, error) { - if runtime.GOOS != "linux" { - return nil, errors.New("ip supported on linux only") - } - - fullPathToCmdValidated, err := validatedPath("/usr/sbin/ip") - if err != nil { - return nil, fmt.Errorf("ip not found: %w", err) - } - return newCmd(ctx, fullPathToCmdValidated, arg...), nil -} - -func Ipconfig(ctx context.Context, arg ...string) (*exec.Cmd, error) { - if runtime.GOOS != "windows" { - return nil, errors.New("ipconfig.exe supported on windows only") - } - - fullPathToCmdValidated, err := validatedPath(`C:\Windows\System32\ipconfig.exe`) - if err != nil { - return nil, fmt.Errorf("ipconfig.exe not found: %w", err) - } - return newCmd(ctx, fullPathToCmdValidated, arg...), nil -} - -func Launchctl(ctx context.Context, arg ...string) (*exec.Cmd, error) { - if runtime.GOOS != "darwin" { - return nil, errors.New("launchctl supported on darwin only") - } - - fullPathToCmdValidated, err := validatedPath("/bin/launchctl") - if err != nil { - return nil, fmt.Errorf("launchctl not found: %w", err) - } - return newCmd(ctx, fullPathToCmdValidated, arg...), nil -} - -func Loginctl(ctx context.Context, arg ...string) (*exec.Cmd, error) { - if runtime.GOOS != "linux" { - return nil, errors.New("loginctl supported on linux only") - } - - fullPathToCmdValidated, err := validatedPath("/usr/bin/loginctl") - if err != nil { - return nil, fmt.Errorf("loginctl not found: %w", err) - } - return newCmd(ctx, fullPathToCmdValidated, arg...), nil -} - -func Lsblk(ctx context.Context, arg ...string) (*exec.Cmd, error) { - if runtime.GOOS != "linux" { - return nil, errors.New("lsblk supported on linux only") - } - - for _, p := range []string{"/bin/lsblk", "/usr/bin/lsblk"} { - fullPathToCmdValidated, err := validatedPath(p) - if err != nil { - continue - } - - return newCmd(ctx, fullPathToCmdValidated, arg...), nil - } - - return nil, errors.New("lsblk not found") -} - -func Lsof(ctx context.Context, arg ...string) (*exec.Cmd, error) { - if runtime.GOOS != "darwin" && runtime.GOOS != "linux" { - return nil, errors.New("lsof supported on darwin and linux only") - } - - var fullPathToCmd string - switch runtime.GOOS { - case "darwin": - fullPathToCmd = "/usr/sbin/lsof" - case "linux": - fullPathToCmd = "/usr/bin/lsof" - } - - fullPathToCmdValidated, err := validatedPath(fullPathToCmd) - if err != nil { - return nil, fmt.Errorf("lsof not found: %w", err) - } - return newCmd(ctx, fullPathToCmdValidated, arg...), nil -} - -func Mdfind(ctx context.Context, arg ...string) (*exec.Cmd, error) { - if runtime.GOOS != "darwin" { - return nil, errors.New("mdfind supported on darwin only") - } - - fullPathToCmdValidated, err := validatedPath("/usr/bin/mdfind") - if err != nil { - return nil, fmt.Errorf("mdfind not found: %w", err) - } - return newCmd(ctx, fullPathToCmdValidated, arg...), nil -} - -func Mdmclient(ctx context.Context, arg ...string) (*exec.Cmd, error) { - if runtime.GOOS != "darwin" { - return nil, errors.New("mdmclient supported on darwin only") - } - - fullPathToCmdValidated, err := validatedPath("/usr/libexec/mdmclient") - if err != nil { - return nil, fmt.Errorf("mdmclient not found: %w", err) - } - return newCmd(ctx, fullPathToCmdValidated, arg...), nil -} - -func Netstat(ctx context.Context, arg ...string) (*exec.Cmd, error) { - if runtime.GOOS != "darwin" { - return nil, errors.New("netstat supported on darwin only") - } - - fullPathToCmdValidated, err := validatedPath("/usr/sbin/netstat") - if err != nil { - return nil, fmt.Errorf("netstat not found: %w", err) - } - return newCmd(ctx, fullPathToCmdValidated, arg...), nil -} - -func Nmcli(ctx context.Context, arg ...string) (*exec.Cmd, error) { - if runtime.GOOS != "linux" { - return nil, errors.New("nmcli supported on linux only") - } - - fullPathToCmdValidated, err := validatedPath("/usr/bin/nmcli") - if err != nil { - return nil, fmt.Errorf("nmcli not found: %w", err) - } - return newCmd(ctx, fullPathToCmdValidated, arg...), nil -} - -func Notifysend(ctx context.Context, arg ...string) (*exec.Cmd, error) { - if runtime.GOOS != "linux" { - return nil, errors.New("notify-send supported on linux only") - } - - fullPathToCmdValidated, err := validatedPath("/usr/bin/notify-send") - if err != nil { - return nil, fmt.Errorf("notify-send not found: %w", err) - } - return newCmd(ctx, fullPathToCmdValidated, arg...), nil -} - -func Open(ctx context.Context, arg ...string) (*exec.Cmd, error) { - if runtime.GOOS != "darwin" { - return nil, errors.New("open supported on darwin only") - } - - fullPathToCmdValidated, err := validatedPath("/usr/bin/open") - if err != nil { - return nil, fmt.Errorf("open not found: %w", err) - } - return newCmd(ctx, fullPathToCmdValidated, arg...), nil -} - -func Pacman(ctx context.Context, arg ...string) (*exec.Cmd, error) { - if runtime.GOOS != "linux" { - return nil, errors.New("pacman supported on linux only") - } - - fullPathToCmdValidated, err := validatedPath("/usr/bin/pacman") - if err != nil { - return nil, fmt.Errorf("pacman not found: %w", err) - } - return newCmd(ctx, fullPathToCmdValidated, arg...), nil -} - -func Pkgutil(ctx context.Context, arg ...string) (*exec.Cmd, error) { - if runtime.GOOS != "darwin" { - return nil, errors.New("pkgutil supported on darwin only") - } - - fullPathToCmdValidated, err := validatedPath("/usr/sbin/pkgutil") - if err != nil { - return nil, fmt.Errorf("pkgutil not found: %w", err) - } - return newCmd(ctx, fullPathToCmdValidated, arg...), nil -} - -func Powercfg(ctx context.Context, arg ...string) (*exec.Cmd, error) { - if runtime.GOOS != "windows" { - return nil, errors.New("powercfg.exe supported on windows only") - } - - fullPathToCmdValidated, err := validatedPath(`C:\Windows\System32\powercfg.exe`) - if err != nil { - return nil, fmt.Errorf("powercfg.exe not found: %w", err) - } - return newCmd(ctx, fullPathToCmdValidated, arg...), nil -} - -func Powermetrics(ctx context.Context, arg ...string) (*exec.Cmd, error) { - if runtime.GOOS != "darwin" { - return nil, errors.New("powermetrics supported on darwin only") - } - - fullPathToCmdValidated, err := validatedPath("/usr/bin/powermetrics") - if err != nil { - return nil, fmt.Errorf("powermetrics not found: %w", err) - } - return newCmd(ctx, fullPathToCmdValidated, arg...), nil -} - -func Powershell(ctx context.Context, arg ...string) (*exec.Cmd, error) { - if runtime.GOOS != "windows" { - return nil, errors.New("powershell.exe supported on windows only") - } - - fullPathToCmdValidated, err := validatedPath(`C:\Windows\System32\WindowsPowerShell\v1.0\powershell.exe`) - if err != nil { - return nil, fmt.Errorf("powershell.exe not found: %w", err) - } - return newCmd(ctx, fullPathToCmdValidated, arg...), nil -} - -func Profiles(ctx context.Context, arg ...string) (*exec.Cmd, error) { - if runtime.GOOS != "darwin" { - return nil, errors.New("profiles supported on darwin only") - } - - fullPathToCmdValidated, err := validatedPath("/usr/bin/profiles") - if err != nil { - return nil, fmt.Errorf("profiles not found: %w", err) - } - return newCmd(ctx, fullPathToCmdValidated, arg...), nil -} - -func Ps(ctx context.Context, arg ...string) (*exec.Cmd, error) { - if runtime.GOOS != "darwin" && runtime.GOOS != "linux" { - return nil, errors.New("ps supported on darwin and linux only") - } - - var fullPathToCmd string - switch runtime.GOOS { - case "darwin": - fullPathToCmd = "/bin/ps" - case "linux": - fullPathToCmd = "/usr/bin/ps" - } - - fullPathToCmdValidated, err := validatedPath(fullPathToCmd) - if err != nil { - return nil, fmt.Errorf("ps not found: %w", err) - } - return newCmd(ctx, fullPathToCmdValidated, arg...), nil -} - -func Pwpolicy(ctx context.Context, arg ...string) (*exec.Cmd, error) { - if runtime.GOOS != "darwin" { - return nil, errors.New("pwpolicy supported on darwin only") - } - - fullPathToCmdValidated, err := validatedPath("/usr/bin/pwpolicy") - if err != nil { - return nil, fmt.Errorf("pwpolicy not found: %w", err) - } - return newCmd(ctx, fullPathToCmdValidated, arg...), nil -} - -func Remotectl(ctx context.Context, arg ...string) (*exec.Cmd, error) { - if runtime.GOOS != "darwin" { - return nil, errors.New("remotectl supported on darwin only") - } - - fullPathToCmdValidated, err := validatedPath("/usr/libexec/remotectl") - if err != nil { - return nil, fmt.Errorf("remotectl not found: %w", err) - } - return newCmd(ctx, fullPathToCmdValidated, arg...), nil -} - -func Repcli(ctx context.Context, arg ...string) (*exec.Cmd, error) { - var fullPathToCmd string - switch runtime.GOOS { - case "darwin": - fullPathToCmd = "/Applications/VMware Carbon Black Cloud/repcli.bundle/Contents/MacOS/repcli" - case "linux": - fullPathToCmd = "/opt/carbonblack/psc/bin/repcli" - case "windows": - fullPathToCmd = filepath.Join("Program Files", "Confer", "repcli") - } - - fullPathToCmdValidated, err := validatedPath(fullPathToCmd) - if err != nil { - return nil, fmt.Errorf("repcli not found: %w", err) - } - return newCmd(ctx, fullPathToCmdValidated, arg...), nil -} - -func Rpm(ctx context.Context, arg ...string) (*exec.Cmd, error) { - if runtime.GOOS != "linux" { - return nil, errors.New("rpm supported on linux only") - } - - for _, p := range []string{"/bin/rpm", "/usr/bin/rpm"} { - fullPathToCmdValidated, err := validatedPath(p) - if err != nil { - continue - } - - return newCmd(ctx, fullPathToCmdValidated, arg...), nil - } - - return nil, errors.New("rpm not found") -} - -func Scutil(ctx context.Context, arg ...string) (*exec.Cmd, error) { - if runtime.GOOS != "darwin" { - return nil, errors.New("scutil supported on darwin only") - } - - fullPathToCmdValidated, err := validatedPath("/usr/sbin/scutil") - if err != nil { - return nil, fmt.Errorf("scutil not found: %w", err) - } - return newCmd(ctx, fullPathToCmdValidated, arg...), nil -} - -func Secedit(ctx context.Context, arg ...string) (*exec.Cmd, error) { - if runtime.GOOS != "windows" { - return nil, errors.New("secedit.exe supported on windows only") - } - - fullPathToCmdValidated, err := validatedPath(`C:\Windows\System32\SecEdit.exe`) - if err != nil { - return nil, fmt.Errorf("secedit.exe not found: %w", err) - } - return newCmd(ctx, fullPathToCmdValidated, arg...), nil -} - -func Softwareupdate(ctx context.Context, arg ...string) (*exec.Cmd, error) { - if runtime.GOOS != "darwin" { - return nil, errors.New("softwareupdate supported on darwin only") - } - - fullPathToCmdValidated, err := validatedPath("/usr/sbin/softwareupdate") - if err != nil { - return nil, fmt.Errorf("softwareupdate not found: %w", err) - } - return newCmd(ctx, fullPathToCmdValidated, arg...), nil -} - -func Systemctl(ctx context.Context, arg ...string) (*exec.Cmd, error) { - if runtime.GOOS != "linux" { - return nil, errors.New("systemctl supported on linux only") - } - - fullPathToCmdValidated, err := validatedPath("/usr/bin/systemctl") - if err != nil { - return nil, fmt.Errorf("systemctl not found: %w", err) - } - return newCmd(ctx, fullPathToCmdValidated, arg...), nil -} - -func Systemprofiler(ctx context.Context, arg ...string) (*exec.Cmd, error) { - if runtime.GOOS != "darwin" { - return nil, errors.New("system_profiler supported on darwin only") - } - - fullPathToCmdValidated, err := validatedPath("/usr/sbin/system_profiler") - if err != nil { - return nil, fmt.Errorf("system_profiler not found: %w", err) - } - return newCmd(ctx, fullPathToCmdValidated, arg...), nil -} - -func Taskkill(ctx context.Context, arg ...string) (*exec.Cmd, error) { - if runtime.GOOS != "windows" { - return nil, errors.New("taskkill.exe supported on windows only") - } - - fullPathToCmdValidated, err := validatedPath(`C:\Windows\System32\taskkill.exe`) - if err != nil { - return nil, fmt.Errorf("taskkill.exe not found: %w", err) - } - return newCmd(ctx, fullPathToCmdValidated, arg...), nil -} - -func Tmutil(ctx context.Context, arg ...string) (*exec.Cmd, error) { - if runtime.GOOS != "darwin" { - return nil, errors.New("tmutil supported on darwin only") - } - - fullPathToCmdValidated, err := validatedPath("/usr/bin/tmutil") - if err != nil { - return nil, fmt.Errorf("tmutil not found: %w", err) - } - return newCmd(ctx, fullPathToCmdValidated, arg...), nil -} - -func Xdgopen(ctx context.Context, arg ...string) (*exec.Cmd, error) { - if runtime.GOOS != "linux" { - return nil, errors.New("xdg-open supported on linux only") - } - - fullPathToCmdValidated, err := validatedPath("/usr/bin/xdg-open") - if err != nil { - return nil, fmt.Errorf("xdg-open not found: %w", err) - } - return newCmd(ctx, fullPathToCmdValidated, arg...), nil -} - -func Xrdb(ctx context.Context, arg ...string) (*exec.Cmd, error) { - if runtime.GOOS != "linux" { - return nil, errors.New("xrdb supported on linux only") - } - - fullPathToCmdValidated, err := validatedPath("/usr/bin/xrdb") - if err != nil { - return nil, fmt.Errorf("xrdb not found: %w", err) - } - return newCmd(ctx, fullPathToCmdValidated, arg...), nil -} - -func Xwwwbrowser(ctx context.Context, arg ...string) (*exec.Cmd, error) { - if runtime.GOOS != "linux" { - return nil, errors.New("x-www-browser supported on linux only") - } - - fullPathToCmdValidated, err := validatedPath("/usr/bin/x-www-browser") - if err != nil { - return nil, fmt.Errorf("x-www-browser not found: %w", err) - } - return newCmd(ctx, fullPathToCmdValidated, arg...), nil -} - -func Zerotiercli(ctx context.Context, arg ...string) (*exec.Cmd, error) { - var fullPathToCmd string - switch runtime.GOOS { - case "darwin", "linux": - fullPathToCmd = "/usr/local/bin/zerotier-cli" - case "windows": - fullPathToCmd = path.Join(os.Getenv("SYSTEMROOT"), "ProgramData", "ZeroTier", "One", "zerotier-one_x64.exe") - } - - fullPathToCmdValidated, err := validatedPath(fullPathToCmd) - if err != nil { - return nil, fmt.Errorf("zerotier-cli not found: %w", err) - } - - // For windows, "-q" should be prepended before all other args - if runtime.GOOS == "windows" { - arg = append([]string{"-q"}, arg...) - } - - return newCmd(ctx, fullPathToCmdValidated, arg...), nil -} - -func Zfs(ctx context.Context, arg ...string) (*exec.Cmd, error) { - if runtime.GOOS != "linux" { - return nil, errors.New("zfs supported on linux only") - } - - fullPathToCmdValidated, err := validatedPath("/usr/sbin/zfs") - if err != nil { - return nil, fmt.Errorf("zfs not found: %w", err) - } - return newCmd(ctx, fullPathToCmdValidated, arg...), nil -} - -func Zpool(ctx context.Context, arg ...string) (*exec.Cmd, error) { - if runtime.GOOS != "linux" { - return nil, errors.New("zpool supported on linux only") - } - - fullPathToCmdValidated, err := validatedPath("/usr/sbin/zpool") - if err != nil { - return nil, fmt.Errorf("zpool not found: %w", err) - } - return newCmd(ctx, fullPathToCmdValidated, arg...), nil -} - func newCmd(ctx context.Context, fullPathToCmd string, arg ...string) *exec.Cmd { return exec.CommandContext(ctx, fullPathToCmd, arg...) //nolint:forbidigo } diff --git a/pkg/allowedpaths/cmd_darwin.go b/pkg/allowedpaths/cmd_darwin.go new file mode 100644 index 000000000..6252ae1a9 --- /dev/null +++ b/pkg/allowedpaths/cmd_darwin.go @@ -0,0 +1,251 @@ +//go:build darwin +// +build darwin + +package allowedpaths + +import ( + "context" + "fmt" + "os/exec" +) + +func Airport(ctx context.Context, arg ...string) (*exec.Cmd, error) { + fullPathToCmdValidated, err := validatedPath("/System/Library/PrivateFrameworks/Apple80211.framework/Versions/Current/Resources/airport") + if err != nil { + return nil, fmt.Errorf("airport not found: %w", err) + } + return newCmd(ctx, fullPathToCmdValidated, arg...), nil +} + +func Bioutil(ctx context.Context, arg ...string) (*exec.Cmd, error) { + fullPathToCmdValidated, err := validatedPath("/usr/bin/bioutil") + if err != nil { + return nil, fmt.Errorf("bioutil not found: %w", err) + } + return newCmd(ctx, fullPathToCmdValidated, arg...), nil +} + +func Bputil(ctx context.Context, arg ...string) (*exec.Cmd, error) { + fullPathToCmdValidated, err := validatedPath("/usr/bin/bputil") + if err != nil { + return nil, fmt.Errorf("bputil not found: %w", err) + } + return newCmd(ctx, fullPathToCmdValidated, arg...), nil +} + +func Diskutil(ctx context.Context, arg ...string) (*exec.Cmd, error) { + fullPathToCmdValidated, err := validatedPath("/usr/sbin/diskutil") + if err != nil { + return nil, fmt.Errorf("diskutil not found: %w", err) + } + return newCmd(ctx, fullPathToCmdValidated, arg...), nil +} + +func Echo(ctx context.Context, arg ...string) (*exec.Cmd, error) { + fullPathToCmdValidated, err := validatedPath("/bin/echo") + if err != nil { + return nil, fmt.Errorf("echo not found: %w", err) + } + return newCmd(ctx, fullPathToCmdValidated, arg...), nil +} + +func Falconctl(ctx context.Context, arg ...string) (*exec.Cmd, error) { + fullPathToCmdValidated, err := validatedPath("/Applications/Falcon.app/Contents/Resources/falconctl") + if err != nil { + return nil, fmt.Errorf("falconctl not found: %w", err) + } + return newCmd(ctx, fullPathToCmdValidated, arg...), nil +} + +func Fdesetup(ctx context.Context, arg ...string) (*exec.Cmd, error) { + fullPathToCmdValidated, err := validatedPath("/usr/bin/fdesetup") + if err != nil { + return nil, fmt.Errorf("fdesetup not found: %w", err) + } + return newCmd(ctx, fullPathToCmdValidated, arg...), nil +} + +func Firmwarepasswd(ctx context.Context, arg ...string) (*exec.Cmd, error) { + fullPathToCmdValidated, err := validatedPath("/usr/sbin/firmwarepasswd") + if err != nil { + return nil, fmt.Errorf("firmwarepasswd not found: %w", err) + } + return newCmd(ctx, fullPathToCmdValidated, arg...), nil +} + +func Ifconfig(ctx context.Context, arg ...string) (*exec.Cmd, error) { + fullPathToCmdValidated, err := validatedPath("/sbin/ifconfig") + if err != nil { + return nil, fmt.Errorf("ifconfig not found: %w", err) + } + return newCmd(ctx, fullPathToCmdValidated, arg...), nil +} + +func Ioreg(ctx context.Context, arg ...string) (*exec.Cmd, error) { + fullPathToCmdValidated, err := validatedPath("/usr/sbin/ioreg") + if err != nil { + return nil, fmt.Errorf("ioreg not found: %w", err) + } + return newCmd(ctx, fullPathToCmdValidated, arg...), nil +} + +func Launchctl(ctx context.Context, arg ...string) (*exec.Cmd, error) { + fullPathToCmdValidated, err := validatedPath("/bin/launchctl") + if err != nil { + return nil, fmt.Errorf("launchctl not found: %w", err) + } + return newCmd(ctx, fullPathToCmdValidated, arg...), nil +} + +func Lsof(ctx context.Context, arg ...string) (*exec.Cmd, error) { + fullPathToCmdValidated, err := validatedPath("/usr/sbin/lsof") + if err != nil { + return nil, fmt.Errorf("lsof not found: %w", err) + } + return newCmd(ctx, fullPathToCmdValidated, arg...), nil +} + +func Mdfind(ctx context.Context, arg ...string) (*exec.Cmd, error) { + fullPathToCmdValidated, err := validatedPath("/usr/bin/mdfind") + if err != nil { + return nil, fmt.Errorf("mdfind not found: %w", err) + } + return newCmd(ctx, fullPathToCmdValidated, arg...), nil +} + +func Mdmclient(ctx context.Context, arg ...string) (*exec.Cmd, error) { + fullPathToCmdValidated, err := validatedPath("/usr/libexec/mdmclient") + if err != nil { + return nil, fmt.Errorf("mdmclient not found: %w", err) + } + return newCmd(ctx, fullPathToCmdValidated, arg...), nil +} + +func Netstat(ctx context.Context, arg ...string) (*exec.Cmd, error) { + fullPathToCmdValidated, err := validatedPath("/usr/sbin/netstat") + if err != nil { + return nil, fmt.Errorf("netstat not found: %w", err) + } + return newCmd(ctx, fullPathToCmdValidated, arg...), nil +} + +func Open(ctx context.Context, arg ...string) (*exec.Cmd, error) { + fullPathToCmdValidated, err := validatedPath("/usr/bin/open") + if err != nil { + return nil, fmt.Errorf("open not found: %w", err) + } + return newCmd(ctx, fullPathToCmdValidated, arg...), nil +} + +func Pkgutil(ctx context.Context, arg ...string) (*exec.Cmd, error) { + fullPathToCmdValidated, err := validatedPath("/usr/sbin/pkgutil") + if err != nil { + return nil, fmt.Errorf("pkgutil not found: %w", err) + } + return newCmd(ctx, fullPathToCmdValidated, arg...), nil +} + +func Powermetrics(ctx context.Context, arg ...string) (*exec.Cmd, error) { + fullPathToCmdValidated, err := validatedPath("/usr/bin/powermetrics") + if err != nil { + return nil, fmt.Errorf("powermetrics not found: %w", err) + } + return newCmd(ctx, fullPathToCmdValidated, arg...), nil +} + +func Profiles(ctx context.Context, arg ...string) (*exec.Cmd, error) { + fullPathToCmdValidated, err := validatedPath("/usr/bin/profiles") + if err != nil { + return nil, fmt.Errorf("profiles not found: %w", err) + } + return newCmd(ctx, fullPathToCmdValidated, arg...), nil +} + +func Ps(ctx context.Context, arg ...string) (*exec.Cmd, error) { + fullPathToCmdValidated, err := validatedPath("/bin/ps") + if err != nil { + return nil, fmt.Errorf("ps not found: %w", err) + } + return newCmd(ctx, fullPathToCmdValidated, arg...), nil +} + +func Pwpolicy(ctx context.Context, arg ...string) (*exec.Cmd, error) { + fullPathToCmdValidated, err := validatedPath("/usr/bin/pwpolicy") + if err != nil { + return nil, fmt.Errorf("pwpolicy not found: %w", err) + } + return newCmd(ctx, fullPathToCmdValidated, arg...), nil +} + +func Remotectl(ctx context.Context, arg ...string) (*exec.Cmd, error) { + fullPathToCmdValidated, err := validatedPath("/usr/libexec/remotectl") + if err != nil { + return nil, fmt.Errorf("remotectl not found: %w", err) + } + return newCmd(ctx, fullPathToCmdValidated, arg...), nil +} + +func Repcli(ctx context.Context, arg ...string) (*exec.Cmd, error) { + fullPathToCmdValidated, err := validatedPath("/Applications/VMware Carbon Black Cloud/repcli.bundle/Contents/MacOS/repcli") + if err != nil { + return nil, fmt.Errorf("repcli not found: %w", err) + } + return newCmd(ctx, fullPathToCmdValidated, arg...), nil +} + +func Scutil(ctx context.Context, arg ...string) (*exec.Cmd, error) { + fullPathToCmdValidated, err := validatedPath("/usr/sbin/scutil") + if err != nil { + return nil, fmt.Errorf("scutil not found: %w", err) + } + return newCmd(ctx, fullPathToCmdValidated, arg...), nil +} + +func Softwareupdate(ctx context.Context, arg ...string) (*exec.Cmd, error) { + fullPathToCmdValidated, err := validatedPath("/usr/sbin/softwareupdate") + if err != nil { + return nil, fmt.Errorf("softwareupdate not found: %w", err) + } + return newCmd(ctx, fullPathToCmdValidated, arg...), nil +} + +func Systemprofiler(ctx context.Context, arg ...string) (*exec.Cmd, error) { + fullPathToCmdValidated, err := validatedPath("/usr/sbin/system_profiler") + if err != nil { + return nil, fmt.Errorf("system_profiler not found: %w", err) + } + return newCmd(ctx, fullPathToCmdValidated, arg...), nil +} + +func Tmutil(ctx context.Context, arg ...string) (*exec.Cmd, error) { + fullPathToCmdValidated, err := validatedPath("/usr/bin/tmutil") + if err != nil { + return nil, fmt.Errorf("tmutil not found: %w", err) + } + return newCmd(ctx, fullPathToCmdValidated, arg...), nil +} + +func Zerotiercli(ctx context.Context, arg ...string) (*exec.Cmd, error) { + fullPathToCmdValidated, err := validatedPath("/usr/local/bin/zerotier-cli") + if err != nil { + return nil, fmt.Errorf("zerotier-cli not found: %w", err) + } + + return newCmd(ctx, fullPathToCmdValidated, arg...), nil +} + +func Zfs(ctx context.Context, arg ...string) (*exec.Cmd, error) { + fullPathToCmdValidated, err := validatedPath("/usr/sbin/zfs") + if err != nil { + return nil, fmt.Errorf("zfs not found: %w", err) + } + return newCmd(ctx, fullPathToCmdValidated, arg...), nil +} + +func Zpool(ctx context.Context, arg ...string) (*exec.Cmd, error) { + fullPathToCmdValidated, err := validatedPath("/usr/sbin/zpool") + if err != nil { + return nil, fmt.Errorf("zpool not found: %w", err) + } + return newCmd(ctx, fullPathToCmdValidated, arg...), nil +} diff --git a/pkg/allowedpaths/cmd_linux.go b/pkg/allowedpaths/cmd_linux.go new file mode 100644 index 000000000..cd8575046 --- /dev/null +++ b/pkg/allowedpaths/cmd_linux.go @@ -0,0 +1,242 @@ +//go:build linux +// +build linux + +package allowedpaths + +import ( + "context" + "errors" + "fmt" + "os/exec" +) + +func Apt(ctx context.Context, arg ...string) (*exec.Cmd, error) { + fullPathToCmdValidated, err := validatedPath("/usr/bin/apt") + if err != nil { + return nil, fmt.Errorf("apt not found: %w", err) + } + return newCmd(ctx, fullPathToCmdValidated, arg...), nil +} + +func Cryptsetup(ctx context.Context, arg ...string) (*exec.Cmd, error) { + for _, p := range []string{"/usr/sbin/cryptsetup", "/sbin/cryptsetup"} { + fullPathToCmdValidated, err := validatedPath(p) + if err != nil { + continue + } + + return newCmd(ctx, fullPathToCmdValidated, arg...), nil + } + + return nil, errors.New("cryptsetup not found") +} + +func Dnf(ctx context.Context, arg ...string) (*exec.Cmd, error) { + fullPathToCmdValidated, err := validatedPath("/usr/bin/dnf") + if err != nil { + return nil, fmt.Errorf("dnf not found: %w", err) + } + return newCmd(ctx, fullPathToCmdValidated, arg...), nil +} + +func Dpkg(ctx context.Context, arg ...string) (*exec.Cmd, error) { + fullPathToCmdValidated, err := validatedPath("/usr/bin/dpkg") + if err != nil { + return nil, fmt.Errorf("dpkg not found: %w", err) + } + return newCmd(ctx, fullPathToCmdValidated, arg...), nil +} + +func Echo(ctx context.Context, arg ...string) (*exec.Cmd, error) { + fullPathToCmdValidated, err := validatedPath("/usr/bin/echo") + if err != nil { + return nil, fmt.Errorf("echo not found: %w", err) + } + return newCmd(ctx, fullPathToCmdValidated, arg...), nil +} + +func Falconctl(ctx context.Context, arg ...string) (*exec.Cmd, error) { + fullPathToCmdValidated, err := validatedPath("/opt/CrowdStrike/falconctl") + if err != nil { + return nil, fmt.Errorf("falconctl not found: %w", err) + } + return newCmd(ctx, fullPathToCmdValidated, arg...), nil +} + +func Falconkernelcheck(ctx context.Context, arg ...string) (*exec.Cmd, error) { + fullPathToCmdValidated, err := validatedPath("/opt/CrowdStrike/falcon-kernel-check") + if err != nil { + return nil, fmt.Errorf("falcon-kernel-check not found: %w", err) + } + return newCmd(ctx, fullPathToCmdValidated, arg...), nil +} + +func Gnomeextensions(ctx context.Context, arg ...string) (*exec.Cmd, error) { + fullPathToCmdValidated, err := validatedPath("/usr/bin/gnome-extensions") + if err != nil { + return nil, fmt.Errorf("gnome-extensions not found: %w", err) + } + return newCmd(ctx, fullPathToCmdValidated, arg...), nil +} + +func Gsettings(ctx context.Context, arg ...string) (*exec.Cmd, error) { + fullPathToCmdValidated, err := validatedPath("/usr/bin/gsettings") + if err != nil { + return nil, fmt.Errorf("gsettings not found: %w", err) + } + return newCmd(ctx, fullPathToCmdValidated, arg...), nil +} + +func Ifconfig(ctx context.Context, arg ...string) (*exec.Cmd, error) { + fullPathToCmdValidated, err := validatedPath("/usr/sbin/ifconfig") + if err != nil { + return nil, fmt.Errorf("ifconfig not found: %w", err) + } + return newCmd(ctx, fullPathToCmdValidated, arg...), nil +} + +func Ip(ctx context.Context, arg ...string) (*exec.Cmd, error) { + fullPathToCmdValidated, err := validatedPath("/usr/sbin/ip") + if err != nil { + return nil, fmt.Errorf("ip not found: %w", err) + } + return newCmd(ctx, fullPathToCmdValidated, arg...), nil +} + +func Loginctl(ctx context.Context, arg ...string) (*exec.Cmd, error) { + fullPathToCmdValidated, err := validatedPath("/usr/bin/loginctl") + if err != nil { + return nil, fmt.Errorf("loginctl not found: %w", err) + } + return newCmd(ctx, fullPathToCmdValidated, arg...), nil +} + +func Lsblk(ctx context.Context, arg ...string) (*exec.Cmd, error) { + for _, p := range []string{"/bin/lsblk", "/usr/bin/lsblk"} { + fullPathToCmdValidated, err := validatedPath(p) + if err != nil { + continue + } + + return newCmd(ctx, fullPathToCmdValidated, arg...), nil + } + + return nil, errors.New("lsblk not found") +} + +func Lsof(ctx context.Context, arg ...string) (*exec.Cmd, error) { + fullPathToCmdValidated, err := validatedPath("/usr/bin/lsof") + if err != nil { + return nil, fmt.Errorf("lsof not found: %w", err) + } + return newCmd(ctx, fullPathToCmdValidated, arg...), nil +} + +func Nmcli(ctx context.Context, arg ...string) (*exec.Cmd, error) { + fullPathToCmdValidated, err := validatedPath("/usr/bin/nmcli") + if err != nil { + return nil, fmt.Errorf("nmcli not found: %w", err) + } + return newCmd(ctx, fullPathToCmdValidated, arg...), nil +} + +func Notifysend(ctx context.Context, arg ...string) (*exec.Cmd, error) { + fullPathToCmdValidated, err := validatedPath("/usr/bin/notify-send") + if err != nil { + return nil, fmt.Errorf("notify-send not found: %w", err) + } + return newCmd(ctx, fullPathToCmdValidated, arg...), nil +} + +func Pacman(ctx context.Context, arg ...string) (*exec.Cmd, error) { + fullPathToCmdValidated, err := validatedPath("/usr/bin/pacman") + if err != nil { + return nil, fmt.Errorf("pacman not found: %w", err) + } + return newCmd(ctx, fullPathToCmdValidated, arg...), nil +} + +func Ps(ctx context.Context, arg ...string) (*exec.Cmd, error) { + fullPathToCmdValidated, err := validatedPath("/usr/bin/ps") + if err != nil { + return nil, fmt.Errorf("ps not found: %w", err) + } + return newCmd(ctx, fullPathToCmdValidated, arg...), nil +} + +func Repcli(ctx context.Context, arg ...string) (*exec.Cmd, error) { + fullPathToCmdValidated, err := validatedPath("/opt/carbonblack/psc/bin/repcli") + if err != nil { + return nil, fmt.Errorf("repcli not found: %w", err) + } + return newCmd(ctx, fullPathToCmdValidated, arg...), nil +} + +func Rpm(ctx context.Context, arg ...string) (*exec.Cmd, error) { + for _, p := range []string{"/bin/rpm", "/usr/bin/rpm"} { + fullPathToCmdValidated, err := validatedPath(p) + if err != nil { + continue + } + + return newCmd(ctx, fullPathToCmdValidated, arg...), nil + } + + return nil, errors.New("rpm not found") +} + +func Systemctl(ctx context.Context, arg ...string) (*exec.Cmd, error) { + fullPathToCmdValidated, err := validatedPath("/usr/bin/systemctl") + if err != nil { + return nil, fmt.Errorf("systemctl not found: %w", err) + } + return newCmd(ctx, fullPathToCmdValidated, arg...), nil +} + +func Xdgopen(ctx context.Context, arg ...string) (*exec.Cmd, error) { + fullPathToCmdValidated, err := validatedPath("/usr/bin/xdg-open") + if err != nil { + return nil, fmt.Errorf("xdg-open not found: %w", err) + } + return newCmd(ctx, fullPathToCmdValidated, arg...), nil +} + +func Xrdb(ctx context.Context, arg ...string) (*exec.Cmd, error) { + fullPathToCmdValidated, err := validatedPath("/usr/bin/xrdb") + if err != nil { + return nil, fmt.Errorf("xrdb not found: %w", err) + } + return newCmd(ctx, fullPathToCmdValidated, arg...), nil +} + +func Xwwwbrowser(ctx context.Context, arg ...string) (*exec.Cmd, error) { + fullPathToCmdValidated, err := validatedPath("/usr/bin/x-www-browser") + if err != nil { + return nil, fmt.Errorf("x-www-browser not found: %w", err) + } + return newCmd(ctx, fullPathToCmdValidated, arg...), nil +} + +func Zerotiercli(ctx context.Context, arg ...string) (*exec.Cmd, error) { + fullPathToCmdValidated, err := validatedPath("/usr/local/bin/zerotier-cli") + if err != nil { + return nil, fmt.Errorf("zerotier-cli not found: %w", err) + } + return newCmd(ctx, fullPathToCmdValidated, arg...), nil +} + +func Zfs(ctx context.Context, arg ...string) (*exec.Cmd, error) { + fullPathToCmdValidated, err := validatedPath("/usr/sbin/zfs") + if err != nil { + return nil, fmt.Errorf("zfs not found: %w", err) + } + return newCmd(ctx, fullPathToCmdValidated, arg...), nil +} + +func Zpool(ctx context.Context, arg ...string) (*exec.Cmd, error) { + fullPathToCmdValidated, err := validatedPath("/usr/sbin/zpool") + if err != nil { + return nil, fmt.Errorf("zpool not found: %w", err) + } + return newCmd(ctx, fullPathToCmdValidated, arg...), nil +} diff --git a/pkg/allowedpaths/cmd_windows.go b/pkg/allowedpaths/cmd_windows.go new file mode 100644 index 000000000..754090786 --- /dev/null +++ b/pkg/allowedpaths/cmd_windows.go @@ -0,0 +1,100 @@ +//go:build windows +// +build windows + +package allowedpaths + +import ( + "context" + "fmt" + "os" + "os/exec" + "path" + "path/filepath" +) + +func Commandprompt(ctx context.Context, arg ...string) (*exec.Cmd, error) { + fullPathToCmdValidated, err := validatedPath(`C:\Windows\System32\cmd.exe`) + if err != nil { + return nil, fmt.Errorf("cmd.exe not found: %w", err) + } + return newCmd(ctx, fullPathToCmdValidated, arg...), nil +} + +func Dism(ctx context.Context, arg ...string) (*exec.Cmd, error) { + fullPathToCmdValidated, err := validatedPath(`C:\Windows\System32\Dism.exe`) + if err != nil { + return nil, fmt.Errorf("dism.exe not found: %w", err) + } + return newCmd(ctx, fullPathToCmdValidated, arg...), nil +} + +func Dsregcmd(ctx context.Context, arg ...string) (*exec.Cmd, error) { + fullPathToCmdValidated, err := validatedPath(`C:\Windows\System32\dsregcmd.exe`) + if err != nil { + return nil, fmt.Errorf("dsregcmd.exe not found: %w", err) + } + return newCmd(ctx, fullPathToCmdValidated, arg...), nil +} + +func Echo(ctx context.Context, arg ...string) (*exec.Cmd, error) { + // echo on Windows is only available as a command in cmd.exe + return newCmd(ctx, "echo", arg...), nil +} + +func Ipconfig(ctx context.Context, arg ...string) (*exec.Cmd, error) { + fullPathToCmdValidated, err := validatedPath(`C:\Windows\System32\ipconfig.exe`) + if err != nil { + return nil, fmt.Errorf("ipconfig.exe not found: %w", err) + } + return newCmd(ctx, fullPathToCmdValidated, arg...), nil +} + +func Powercfg(ctx context.Context, arg ...string) (*exec.Cmd, error) { + fullPathToCmdValidated, err := validatedPath(`C:\Windows\System32\powercfg.exe`) + if err != nil { + return nil, fmt.Errorf("powercfg.exe not found: %w", err) + } + return newCmd(ctx, fullPathToCmdValidated, arg...), nil +} + +func Powershell(ctx context.Context, arg ...string) (*exec.Cmd, error) { + fullPathToCmdValidated, err := validatedPath(`C:\Windows\System32\WindowsPowerShell\v1.0\powershell.exe`) + if err != nil { + return nil, fmt.Errorf("powershell.exe not found: %w", err) + } + return newCmd(ctx, fullPathToCmdValidated, arg...), nil +} + +func Repcli(ctx context.Context, arg ...string) (*exec.Cmd, error) { + fullPathToCmdValidated, err := validatedPath(filepath.Join("Program Files", "Confer", "repcli")) + if err != nil { + return nil, fmt.Errorf("repcli not found: %w", err) + } + return newCmd(ctx, fullPathToCmdValidated, arg...), nil +} + +func Secedit(ctx context.Context, arg ...string) (*exec.Cmd, error) { + fullPathToCmdValidated, err := validatedPath(`C:\Windows\System32\SecEdit.exe`) + if err != nil { + return nil, fmt.Errorf("secedit.exe not found: %w", err) + } + return newCmd(ctx, fullPathToCmdValidated, arg...), nil +} + +func Taskkill(ctx context.Context, arg ...string) (*exec.Cmd, error) { + fullPathToCmdValidated, err := validatedPath(`C:\Windows\System32\taskkill.exe`) + if err != nil { + return nil, fmt.Errorf("taskkill.exe not found: %w", err) + } + return newCmd(ctx, fullPathToCmdValidated, arg...), nil +} + +func Zerotiercli(ctx context.Context, arg ...string) (*exec.Cmd, error) { + fullPathToCmdValidated, err := validatedPath(path.Join(os.Getenv("SYSTEMROOT"), "ProgramData", "ZeroTier", "One", "zerotier-one_x64.exe")) + if err != nil { + return nil, fmt.Errorf("zerotier-cli not found: %w", err) + } + + // For windows, "-q" should be prepended before all other args + return newCmd(ctx, fullPathToCmdValidated, []string{"-q"}, arg...), nil +} diff --git a/pkg/debug/checkups/gnome-extensions.go b/pkg/debug/checkups/gnome_extensions_linux.go similarity index 98% rename from pkg/debug/checkups/gnome-extensions.go rename to pkg/debug/checkups/gnome_extensions_linux.go index e07bed383..7095177ca 100644 --- a/pkg/debug/checkups/gnome-extensions.go +++ b/pkg/debug/checkups/gnome_extensions_linux.go @@ -1,3 +1,6 @@ +//go:build linux +// +build linux + package checkups import ( @@ -7,7 +10,6 @@ import ( "io" "os" "path/filepath" - "runtime" "strings" "time" @@ -28,10 +30,6 @@ const ( ) func (c *gnomeExtensions) Name() string { - if runtime.GOOS != "linux" { - return "" - } - return "Gnome Extensions" } diff --git a/pkg/debug/checkups/gnome_extensions_other.go b/pkg/debug/checkups/gnome_extensions_other.go new file mode 100644 index 000000000..67ba77913 --- /dev/null +++ b/pkg/debug/checkups/gnome_extensions_other.go @@ -0,0 +1,36 @@ +//go:build !linux +// +build !linux + +package checkups + +import ( + "context" + "io" +) + +type gnomeExtensions struct { +} + +func (c *gnomeExtensions) Name() string { + return "" +} + +func (c *gnomeExtensions) ExtraFileName() string { + return "" +} + +func (c *gnomeExtensions) Run(_ context.Context, _ io.Writer) error { + return nil +} + +func (c *gnomeExtensions) Status() Status { + return Informational +} + +func (c *gnomeExtensions) Summary() string { + return "" +} + +func (c *gnomeExtensions) Data() any { + return nil +} diff --git a/pkg/debug/checkups/network.go b/pkg/debug/checkups/network.go index 9a6e80890..06b0f0aa6 100644 --- a/pkg/debug/checkups/network.go +++ b/pkg/debug/checkups/network.go @@ -6,7 +6,6 @@ import ( "fmt" "io" "net" - "runtime" "time" "github.com/kolide/launcher/pkg/allowedpaths" @@ -86,63 +85,3 @@ type networkCommand struct { cmd allowedpaths.AllowedCommand args []string } - -func listCommands() []networkCommand { - switch runtime.GOOS { - case "darwin": - return []networkCommand{ - { - cmd: allowedpaths.Ifconfig, - args: []string{"-a"}, - }, - { - cmd: allowedpaths.Netstat, - args: []string{"-nr"}, - }, - } - case "linux": - return []networkCommand{ - { - cmd: allowedpaths.Ifconfig, - args: []string{"-a"}, - }, - { - cmd: allowedpaths.Ip, - args: []string{"-N", "-d", "-h", "-a", "address"}, - }, - { - cmd: allowedpaths.Ip, - args: []string{"-N", "-d", "-h", "-a", "route"}, - }, - } - case "windows": - return []networkCommand{ - { - cmd: allowedpaths.Ipconfig, - args: []string{"/all"}, - }, - } - default: - return nil - } -} - -func listFiles() []string { - switch runtime.GOOS { - case "darwin": - return []string{ - "/etc/hosts", - "/etc/resolv.conf", - } - case "linux": - return []string{ - "/etc/nsswitch.conf", - "/etc/hosts", - "/etc/resolv.conf", - } - case "windows": - return []string{} - default: - return nil - } -} diff --git a/pkg/debug/checkups/network_darwin.go b/pkg/debug/checkups/network_darwin.go new file mode 100644 index 000000000..e8dccd020 --- /dev/null +++ b/pkg/debug/checkups/network_darwin.go @@ -0,0 +1,26 @@ +//go:build darwin +// +build darwin + +package checkups + +import "github.com/kolide/launcher/pkg/allowedpaths" + +func listCommands() []networkCommand { + return []networkCommand{ + { + cmd: allowedpaths.Ifconfig, + args: []string{"-a"}, + }, + { + cmd: allowedpaths.Netstat, + args: []string{"-nr"}, + }, + } +} + +func listFiles() []string { + return []string{ + "/etc/hosts", + "/etc/resolv.conf", + } +} diff --git a/pkg/debug/checkups/network_linux.go b/pkg/debug/checkups/network_linux.go new file mode 100644 index 000000000..77f91bdd2 --- /dev/null +++ b/pkg/debug/checkups/network_linux.go @@ -0,0 +1,31 @@ +//go:build linux +// +build linux + +package checkups + +import "github.com/kolide/launcher/pkg/allowedpaths" + +func listCommands() []networkCommand { + return []networkCommand{ + { + cmd: allowedpaths.Ifconfig, + args: []string{"-a"}, + }, + { + cmd: allowedpaths.Ip, + args: []string{"-N", "-d", "-h", "-a", "address"}, + }, + { + cmd: allowedpaths.Ip, + args: []string{"-N", "-d", "-h", "-a", "route"}, + }, + } +} + +func listFiles() []string { + return []string{ + "/etc/nsswitch.conf", + "/etc/hosts", + "/etc/resolv.conf", + } +} diff --git a/pkg/debug/checkups/network_windows.go b/pkg/debug/checkups/network_windows.go new file mode 100644 index 000000000..a6e970c85 --- /dev/null +++ b/pkg/debug/checkups/network_windows.go @@ -0,0 +1,19 @@ +//go:build windows +// +build windows + +package checkups + +import "github.com/kolide/launcher/pkg/allowedpaths" + +func listCommands() []networkCommand { + return []networkCommand{ + { + cmd: allowedpaths.Ipconfig, + args: []string{"/all"}, + }, + } +} + +func listFiles() []string { + return []string{} +} diff --git a/pkg/osquery/table/platform_tables_darwin.go b/pkg/osquery/table/platform_tables_darwin.go index 880239378..6ab620d3c 100644 --- a/pkg/osquery/table/platform_tables_darwin.go +++ b/pkg/osquery/table/platform_tables_darwin.go @@ -25,6 +25,7 @@ import ( "github.com/kolide/launcher/pkg/osquery/tables/profiles" "github.com/kolide/launcher/pkg/osquery/tables/pwpolicy" "github.com/kolide/launcher/pkg/osquery/tables/systemprofiler" + "github.com/kolide/launcher/pkg/osquery/tables/zfs" _ "github.com/mattn/go-sqlite3" osquery "github.com/osquery/osquery-go" "github.com/osquery/osquery-go/plugin/table" @@ -120,5 +121,7 @@ func platformTables(logger log.Logger, currentOsquerydBinaryPath string) []osque dataflattentable.NewExecAndParseTable(logger, "kolide_softwareupdate", softwareupdate.Parser, allowedpaths.Softwareupdate, []string{`--list`, `--no-scan`}, dataflattentable.WithIncludeStderr()), dataflattentable.NewExecAndParseTable(logger, "kolide_softwareupdate_scan", softwareupdate.Parser, allowedpaths.Softwareupdate, []string{`--list`}, dataflattentable.WithIncludeStderr()), dataflattentable.NewExecAndParseTable(logger, "kolide_carbonblack_repcli_status", repcli.Parser, allowedpaths.Repcli, []string{"status"}, dataflattentable.WithIncludeStderr()), + zfs.ZfsPropertiesPlugin(logger), + zfs.ZpoolPropertiesPlugin(logger), } } diff --git a/pkg/osquery/table/platform_tables_linux.go b/pkg/osquery/table/platform_tables_linux.go index 5ee13ce4f..dc8ef7443 100644 --- a/pkg/osquery/table/platform_tables_linux.go +++ b/pkg/osquery/table/platform_tables_linux.go @@ -24,6 +24,7 @@ import ( "github.com/kolide/launcher/pkg/osquery/tables/secureboot" "github.com/kolide/launcher/pkg/osquery/tables/xfconf" "github.com/kolide/launcher/pkg/osquery/tables/xrdb" + "github.com/kolide/launcher/pkg/osquery/tables/zfs" osquery "github.com/osquery/osquery-go" ) @@ -56,5 +57,7 @@ func platformTables(logger log.Logger, currentOsquerydBinaryPath string) []osque dataflattentable.NewExecAndParseTable(logger, "kolide_pacman_upgradeable", pacman_upgradeable.Parser, allowedpaths.Pacman, []string{"-Qu"}, dataflattentable.WithIncludeStderr()), dataflattentable.NewExecAndParseTable(logger, "kolide_rpm_version_info", rpm.Parser, allowedpaths.Rpm, []string{"-qai"}, dataflattentable.WithIncludeStderr()), dataflattentable.NewExecAndParseTable(logger, "kolide_carbonblack_repcli_status", repcli.Parser, allowedpaths.Repcli, []string{"status"}, dataflattentable.WithIncludeStderr()), + zfs.ZfsPropertiesPlugin(logger), + zfs.ZpoolPropertiesPlugin(logger), } } diff --git a/pkg/osquery/table/table.go b/pkg/osquery/table/table.go index 76019ef19..e78e9ffe8 100644 --- a/pkg/osquery/table/table.go +++ b/pkg/osquery/table/table.go @@ -12,7 +12,6 @@ import ( "github.com/kolide/launcher/pkg/osquery/tables/osquery_instance_history" "github.com/kolide/launcher/pkg/osquery/tables/tdebug" "github.com/kolide/launcher/pkg/osquery/tables/tufinfo" - "github.com/kolide/launcher/pkg/osquery/tables/zfs" "github.com/go-kit/kit/log" osquery "github.com/osquery/osquery-go" @@ -55,8 +54,6 @@ func PlatformTables(logger log.Logger, currentOsquerydBinaryPath string) []osque dataflattentable.TablePluginExec(logger, "kolide_zerotier_peers", dataflattentable.JsonType, allowedpaths.Zerotiercli, []string{"listpeers"}), tdebug.LauncherGcInfo(logger), - zfs.ZfsPropertiesPlugin(logger), - zfs.ZpoolPropertiesPlugin(logger), } // The dataflatten tables diff --git a/pkg/osquery/tables/crowdstrike/falcon_kernel_check/table.go b/pkg/osquery/tables/crowdstrike/falcon_kernel_check/table.go index bb74d93af..79f8f7a9f 100644 --- a/pkg/osquery/tables/crowdstrike/falcon_kernel_check/table.go +++ b/pkg/osquery/tables/crowdstrike/falcon_kernel_check/table.go @@ -1,3 +1,6 @@ +//go:build linux +// +build linux + package falcon_kernel_check import ( diff --git a/pkg/osquery/tables/crowdstrike/falcon_kernel_check/table_test.go b/pkg/osquery/tables/crowdstrike/falcon_kernel_check/table_test.go index 01392b92e..6b9136e53 100644 --- a/pkg/osquery/tables/crowdstrike/falcon_kernel_check/table_test.go +++ b/pkg/osquery/tables/crowdstrike/falcon_kernel_check/table_test.go @@ -1,3 +1,6 @@ +//go:build linux +// +build linux + package falcon_kernel_check import ( diff --git a/pkg/osquery/tables/cryptsetup/parser.go b/pkg/osquery/tables/cryptsetup/parser.go index 18c97ec39..5d80d9c95 100644 --- a/pkg/osquery/tables/cryptsetup/parser.go +++ b/pkg/osquery/tables/cryptsetup/parser.go @@ -1,3 +1,6 @@ +//go:build linux +// +build linux + package cryptsetup import ( diff --git a/pkg/osquery/tables/cryptsetup/parser_test.go b/pkg/osquery/tables/cryptsetup/parser_test.go index 82632fa67..e141b2cda 100644 --- a/pkg/osquery/tables/cryptsetup/parser_test.go +++ b/pkg/osquery/tables/cryptsetup/parser_test.go @@ -1,3 +1,6 @@ +//go:build linux +// +build linux + package cryptsetup import ( diff --git a/pkg/osquery/tables/cryptsetup/table.go b/pkg/osquery/tables/cryptsetup/table.go index a26773b9c..5b8d7c336 100644 --- a/pkg/osquery/tables/cryptsetup/table.go +++ b/pkg/osquery/tables/cryptsetup/table.go @@ -1,3 +1,6 @@ +//go:build linux +// +build linux + package cryptsetup import ( diff --git a/pkg/osquery/tables/gsettings/gsettings.go b/pkg/osquery/tables/gsettings/gsettings.go index eca96d0d4..6de0a58d7 100644 --- a/pkg/osquery/tables/gsettings/gsettings.go +++ b/pkg/osquery/tables/gsettings/gsettings.go @@ -1,5 +1,5 @@ -//go:build !windows -// +build !windows +//go:build linux +// +build linux package gsettings diff --git a/pkg/osquery/tables/gsettings/gsettings_test.go b/pkg/osquery/tables/gsettings/gsettings_test.go index 8bad6ae8c..f3eacacda 100644 --- a/pkg/osquery/tables/gsettings/gsettings_test.go +++ b/pkg/osquery/tables/gsettings/gsettings_test.go @@ -1,5 +1,5 @@ -//go:build !windows -// +build !windows +//go:build linux +// +build linux package gsettings diff --git a/pkg/osquery/tables/gsettings/metadata.go b/pkg/osquery/tables/gsettings/metadata.go index efaca20af..3bfa0d1f8 100644 --- a/pkg/osquery/tables/gsettings/metadata.go +++ b/pkg/osquery/tables/gsettings/metadata.go @@ -1,5 +1,5 @@ -//go:build !windows -// +build !windows +//go:build linux +// +build linux package gsettings diff --git a/pkg/osquery/tables/zfs/tables.go b/pkg/osquery/tables/zfs/tables.go index 975ef02d8..4e659dc9f 100644 --- a/pkg/osquery/tables/zfs/tables.go +++ b/pkg/osquery/tables/zfs/tables.go @@ -1,3 +1,6 @@ +//go:build !windows +// +build !windows + package zfs import ( diff --git a/pkg/osquery/tables/zfs/tables_test.go b/pkg/osquery/tables/zfs/tables_test.go index f5c2e3d6c..5977ce34d 100644 --- a/pkg/osquery/tables/zfs/tables_test.go +++ b/pkg/osquery/tables/zfs/tables_test.go @@ -1,3 +1,6 @@ +//go:build !windows +// +build !windows + package zfs import ( From 9241dbf71307b810915a5f6495641a5bd87048d7 Mon Sep 17 00:00:00 2001 From: Rebecca Mahany-Horton Date: Thu, 9 Nov 2023 10:15:29 -0500 Subject: [PATCH 18/30] Combine helper functions --- pkg/allowedpaths/cmd.go | 10 +- pkg/allowedpaths/cmd_darwin.go | 182 ++++++-------------------------- pkg/allowedpaths/cmd_linux.go | 157 ++++++--------------------- pkg/allowedpaths/cmd_test.go | 12 +-- pkg/allowedpaths/cmd_windows.go | 62 ++--------- 5 files changed, 81 insertions(+), 342 deletions(-) diff --git a/pkg/allowedpaths/cmd.go b/pkg/allowedpaths/cmd.go index bea19177a..75b77066a 100644 --- a/pkg/allowedpaths/cmd.go +++ b/pkg/allowedpaths/cmd.go @@ -15,24 +15,24 @@ func newCmd(ctx context.Context, fullPathToCmd string, arg ...string) *exec.Cmd return exec.CommandContext(ctx, fullPathToCmd, arg...) //nolint:forbidigo } -func validatedPath(knownPath string) (string, error) { +func validatedCommand(ctx context.Context, knownPath string, arg ...string) (*exec.Cmd, error) { knownPath = filepath.Clean(knownPath) if _, err := os.Stat(knownPath); err == nil { - return knownPath, nil + return newCmd(ctx, knownPath, arg...), nil } // Not found at known location -- return error for darwin and windows. // We expect to know the exact location for allowlisted commands on all // OSes except for a few Linux distros. if runtime.GOOS != "linux" { - return "", fmt.Errorf("not found: %s", knownPath) + return nil, fmt.Errorf("not found: %s", knownPath) } cmdName := filepath.Base(knownPath) if foundPath, err := exec.LookPath(cmdName); err == nil { - return foundPath, nil + return newCmd(ctx, foundPath, arg...), nil } - return "", fmt.Errorf("%s not found at %s and could not be located elsewhere", cmdName, knownPath) + return nil, fmt.Errorf("%s not found at %s and could not be located elsewhere", cmdName, knownPath) } diff --git a/pkg/allowedpaths/cmd_darwin.go b/pkg/allowedpaths/cmd_darwin.go index 6252ae1a9..efab3025a 100644 --- a/pkg/allowedpaths/cmd_darwin.go +++ b/pkg/allowedpaths/cmd_darwin.go @@ -5,247 +5,125 @@ package allowedpaths import ( "context" - "fmt" "os/exec" ) func Airport(ctx context.Context, arg ...string) (*exec.Cmd, error) { - fullPathToCmdValidated, err := validatedPath("/System/Library/PrivateFrameworks/Apple80211.framework/Versions/Current/Resources/airport") - if err != nil { - return nil, fmt.Errorf("airport not found: %w", err) - } - return newCmd(ctx, fullPathToCmdValidated, arg...), nil + return validatedCommand(ctx, "/System/Library/PrivateFrameworks/Apple80211.framework/Versions/Current/Resources/airport", arg...) } func Bioutil(ctx context.Context, arg ...string) (*exec.Cmd, error) { - fullPathToCmdValidated, err := validatedPath("/usr/bin/bioutil") - if err != nil { - return nil, fmt.Errorf("bioutil not found: %w", err) - } - return newCmd(ctx, fullPathToCmdValidated, arg...), nil + return validatedCommand(ctx, "/usr/bin/bioutil", arg...) } func Bputil(ctx context.Context, arg ...string) (*exec.Cmd, error) { - fullPathToCmdValidated, err := validatedPath("/usr/bin/bputil") - if err != nil { - return nil, fmt.Errorf("bputil not found: %w", err) - } - return newCmd(ctx, fullPathToCmdValidated, arg...), nil + return validatedCommand(ctx, "/usr/bin/bputil", arg...) } func Diskutil(ctx context.Context, arg ...string) (*exec.Cmd, error) { - fullPathToCmdValidated, err := validatedPath("/usr/sbin/diskutil") - if err != nil { - return nil, fmt.Errorf("diskutil not found: %w", err) - } - return newCmd(ctx, fullPathToCmdValidated, arg...), nil + return validatedCommand(ctx, "/usr/sbin/diskutil", arg...) } func Echo(ctx context.Context, arg ...string) (*exec.Cmd, error) { - fullPathToCmdValidated, err := validatedPath("/bin/echo") - if err != nil { - return nil, fmt.Errorf("echo not found: %w", err) - } - return newCmd(ctx, fullPathToCmdValidated, arg...), nil + return validatedCommand(ctx, "/bin/echo", arg...) } func Falconctl(ctx context.Context, arg ...string) (*exec.Cmd, error) { - fullPathToCmdValidated, err := validatedPath("/Applications/Falcon.app/Contents/Resources/falconctl") - if err != nil { - return nil, fmt.Errorf("falconctl not found: %w", err) - } - return newCmd(ctx, fullPathToCmdValidated, arg...), nil + return validatedCommand(ctx, "/Applications/Falcon.app/Contents/Resources/falconctl", arg...) } func Fdesetup(ctx context.Context, arg ...string) (*exec.Cmd, error) { - fullPathToCmdValidated, err := validatedPath("/usr/bin/fdesetup") - if err != nil { - return nil, fmt.Errorf("fdesetup not found: %w", err) - } - return newCmd(ctx, fullPathToCmdValidated, arg...), nil + return validatedCommand(ctx, "/usr/bin/fdesetup", arg...) } func Firmwarepasswd(ctx context.Context, arg ...string) (*exec.Cmd, error) { - fullPathToCmdValidated, err := validatedPath("/usr/sbin/firmwarepasswd") - if err != nil { - return nil, fmt.Errorf("firmwarepasswd not found: %w", err) - } - return newCmd(ctx, fullPathToCmdValidated, arg...), nil + return validatedCommand(ctx, "/usr/sbin/firmwarepasswd", arg...) } func Ifconfig(ctx context.Context, arg ...string) (*exec.Cmd, error) { - fullPathToCmdValidated, err := validatedPath("/sbin/ifconfig") - if err != nil { - return nil, fmt.Errorf("ifconfig not found: %w", err) - } - return newCmd(ctx, fullPathToCmdValidated, arg...), nil + return validatedCommand(ctx, "/sbin/ifconfig", arg...) } func Ioreg(ctx context.Context, arg ...string) (*exec.Cmd, error) { - fullPathToCmdValidated, err := validatedPath("/usr/sbin/ioreg") - if err != nil { - return nil, fmt.Errorf("ioreg not found: %w", err) - } - return newCmd(ctx, fullPathToCmdValidated, arg...), nil + return validatedCommand(ctx, "/usr/sbin/ioreg", arg...) } func Launchctl(ctx context.Context, arg ...string) (*exec.Cmd, error) { - fullPathToCmdValidated, err := validatedPath("/bin/launchctl") - if err != nil { - return nil, fmt.Errorf("launchctl not found: %w", err) - } - return newCmd(ctx, fullPathToCmdValidated, arg...), nil + return validatedCommand(ctx, "/bin/launchctl", arg...) } func Lsof(ctx context.Context, arg ...string) (*exec.Cmd, error) { - fullPathToCmdValidated, err := validatedPath("/usr/sbin/lsof") - if err != nil { - return nil, fmt.Errorf("lsof not found: %w", err) - } - return newCmd(ctx, fullPathToCmdValidated, arg...), nil + return validatedCommand(ctx, "/usr/sbin/lsof", arg...) } func Mdfind(ctx context.Context, arg ...string) (*exec.Cmd, error) { - fullPathToCmdValidated, err := validatedPath("/usr/bin/mdfind") - if err != nil { - return nil, fmt.Errorf("mdfind not found: %w", err) - } - return newCmd(ctx, fullPathToCmdValidated, arg...), nil + return validatedCommand(ctx, "/usr/bin/mdfind", arg...) } func Mdmclient(ctx context.Context, arg ...string) (*exec.Cmd, error) { - fullPathToCmdValidated, err := validatedPath("/usr/libexec/mdmclient") - if err != nil { - return nil, fmt.Errorf("mdmclient not found: %w", err) - } - return newCmd(ctx, fullPathToCmdValidated, arg...), nil + return validatedCommand(ctx, "/usr/libexec/mdmclient", arg...) } func Netstat(ctx context.Context, arg ...string) (*exec.Cmd, error) { - fullPathToCmdValidated, err := validatedPath("/usr/sbin/netstat") - if err != nil { - return nil, fmt.Errorf("netstat not found: %w", err) - } - return newCmd(ctx, fullPathToCmdValidated, arg...), nil + return validatedCommand(ctx, "/usr/sbin/netstat", arg...) } func Open(ctx context.Context, arg ...string) (*exec.Cmd, error) { - fullPathToCmdValidated, err := validatedPath("/usr/bin/open") - if err != nil { - return nil, fmt.Errorf("open not found: %w", err) - } - return newCmd(ctx, fullPathToCmdValidated, arg...), nil + return validatedCommand(ctx, "/usr/bin/open", arg...) } func Pkgutil(ctx context.Context, arg ...string) (*exec.Cmd, error) { - fullPathToCmdValidated, err := validatedPath("/usr/sbin/pkgutil") - if err != nil { - return nil, fmt.Errorf("pkgutil not found: %w", err) - } - return newCmd(ctx, fullPathToCmdValidated, arg...), nil + return validatedCommand(ctx, "/usr/sbin/pkgutil", arg...) } func Powermetrics(ctx context.Context, arg ...string) (*exec.Cmd, error) { - fullPathToCmdValidated, err := validatedPath("/usr/bin/powermetrics") - if err != nil { - return nil, fmt.Errorf("powermetrics not found: %w", err) - } - return newCmd(ctx, fullPathToCmdValidated, arg...), nil + return validatedCommand(ctx, "/usr/bin/powermetrics", arg...) } func Profiles(ctx context.Context, arg ...string) (*exec.Cmd, error) { - fullPathToCmdValidated, err := validatedPath("/usr/bin/profiles") - if err != nil { - return nil, fmt.Errorf("profiles not found: %w", err) - } - return newCmd(ctx, fullPathToCmdValidated, arg...), nil + return validatedCommand(ctx, "/usr/bin/profiles", arg...) } func Ps(ctx context.Context, arg ...string) (*exec.Cmd, error) { - fullPathToCmdValidated, err := validatedPath("/bin/ps") - if err != nil { - return nil, fmt.Errorf("ps not found: %w", err) - } - return newCmd(ctx, fullPathToCmdValidated, arg...), nil + return validatedCommand(ctx, "/bin/ps", arg...) } func Pwpolicy(ctx context.Context, arg ...string) (*exec.Cmd, error) { - fullPathToCmdValidated, err := validatedPath("/usr/bin/pwpolicy") - if err != nil { - return nil, fmt.Errorf("pwpolicy not found: %w", err) - } - return newCmd(ctx, fullPathToCmdValidated, arg...), nil + return validatedCommand(ctx, "/usr/bin/pwpolicy", arg...) } func Remotectl(ctx context.Context, arg ...string) (*exec.Cmd, error) { - fullPathToCmdValidated, err := validatedPath("/usr/libexec/remotectl") - if err != nil { - return nil, fmt.Errorf("remotectl not found: %w", err) - } - return newCmd(ctx, fullPathToCmdValidated, arg...), nil + return validatedCommand(ctx, "/usr/libexec/remotectl", arg...) } func Repcli(ctx context.Context, arg ...string) (*exec.Cmd, error) { - fullPathToCmdValidated, err := validatedPath("/Applications/VMware Carbon Black Cloud/repcli.bundle/Contents/MacOS/repcli") - if err != nil { - return nil, fmt.Errorf("repcli not found: %w", err) - } - return newCmd(ctx, fullPathToCmdValidated, arg...), nil + return validatedCommand(ctx, "/Applications/VMware Carbon Black Cloud/repcli.bundle/Contents/MacOS/repcli", arg...) } func Scutil(ctx context.Context, arg ...string) (*exec.Cmd, error) { - fullPathToCmdValidated, err := validatedPath("/usr/sbin/scutil") - if err != nil { - return nil, fmt.Errorf("scutil not found: %w", err) - } - return newCmd(ctx, fullPathToCmdValidated, arg...), nil + return validatedCommand(ctx, "/usr/sbin/scutil", arg...) } func Softwareupdate(ctx context.Context, arg ...string) (*exec.Cmd, error) { - fullPathToCmdValidated, err := validatedPath("/usr/sbin/softwareupdate") - if err != nil { - return nil, fmt.Errorf("softwareupdate not found: %w", err) - } - return newCmd(ctx, fullPathToCmdValidated, arg...), nil + return validatedCommand(ctx, "/usr/sbin/softwareupdate", arg...) } func Systemprofiler(ctx context.Context, arg ...string) (*exec.Cmd, error) { - fullPathToCmdValidated, err := validatedPath("/usr/sbin/system_profiler") - if err != nil { - return nil, fmt.Errorf("system_profiler not found: %w", err) - } - return newCmd(ctx, fullPathToCmdValidated, arg...), nil + return validatedCommand(ctx, "/usr/sbin/system_profiler", arg...) } func Tmutil(ctx context.Context, arg ...string) (*exec.Cmd, error) { - fullPathToCmdValidated, err := validatedPath("/usr/bin/tmutil") - if err != nil { - return nil, fmt.Errorf("tmutil not found: %w", err) - } - return newCmd(ctx, fullPathToCmdValidated, arg...), nil + return validatedCommand(ctx, "/usr/bin/tmutil", arg...) } func Zerotiercli(ctx context.Context, arg ...string) (*exec.Cmd, error) { - fullPathToCmdValidated, err := validatedPath("/usr/local/bin/zerotier-cli") - if err != nil { - return nil, fmt.Errorf("zerotier-cli not found: %w", err) - } - - return newCmd(ctx, fullPathToCmdValidated, arg...), nil + return validatedCommand(ctx, "/usr/local/bin/zerotier-cli", arg...) } func Zfs(ctx context.Context, arg ...string) (*exec.Cmd, error) { - fullPathToCmdValidated, err := validatedPath("/usr/sbin/zfs") - if err != nil { - return nil, fmt.Errorf("zfs not found: %w", err) - } - return newCmd(ctx, fullPathToCmdValidated, arg...), nil + return validatedCommand(ctx, "/usr/sbin/zfs", arg...) } func Zpool(ctx context.Context, arg ...string) (*exec.Cmd, error) { - fullPathToCmdValidated, err := validatedPath("/usr/sbin/zpool") - if err != nil { - return nil, fmt.Errorf("zpool not found: %w", err) - } - return newCmd(ctx, fullPathToCmdValidated, arg...), nil + return validatedCommand(ctx, "/usr/sbin/zpool", arg...) } diff --git a/pkg/allowedpaths/cmd_linux.go b/pkg/allowedpaths/cmd_linux.go index cd8575046..2c3ece39a 100644 --- a/pkg/allowedpaths/cmd_linux.go +++ b/pkg/allowedpaths/cmd_linux.go @@ -6,237 +6,140 @@ package allowedpaths import ( "context" "errors" - "fmt" "os/exec" ) func Apt(ctx context.Context, arg ...string) (*exec.Cmd, error) { - fullPathToCmdValidated, err := validatedPath("/usr/bin/apt") - if err != nil { - return nil, fmt.Errorf("apt not found: %w", err) - } - return newCmd(ctx, fullPathToCmdValidated, arg...), nil + return validatedCommand(ctx, "/usr/bin/apt", arg...) } func Cryptsetup(ctx context.Context, arg ...string) (*exec.Cmd, error) { for _, p := range []string{"/usr/sbin/cryptsetup", "/sbin/cryptsetup"} { - fullPathToCmdValidated, err := validatedPath(p) + validatedCmd, err := validatedCommand(ctx, p, arg...) if err != nil { continue } - return newCmd(ctx, fullPathToCmdValidated, arg...), nil + return validatedCmd, nil } return nil, errors.New("cryptsetup not found") } func Dnf(ctx context.Context, arg ...string) (*exec.Cmd, error) { - fullPathToCmdValidated, err := validatedPath("/usr/bin/dnf") - if err != nil { - return nil, fmt.Errorf("dnf not found: %w", err) - } - return newCmd(ctx, fullPathToCmdValidated, arg...), nil + return validatedCommand(ctx, "/usr/bin/dnf", arg...) } func Dpkg(ctx context.Context, arg ...string) (*exec.Cmd, error) { - fullPathToCmdValidated, err := validatedPath("/usr/bin/dpkg") - if err != nil { - return nil, fmt.Errorf("dpkg not found: %w", err) - } - return newCmd(ctx, fullPathToCmdValidated, arg...), nil + return validatedCommand(ctx, "/usr/bin/dpkg", arg...) } func Echo(ctx context.Context, arg ...string) (*exec.Cmd, error) { - fullPathToCmdValidated, err := validatedPath("/usr/bin/echo") - if err != nil { - return nil, fmt.Errorf("echo not found: %w", err) - } - return newCmd(ctx, fullPathToCmdValidated, arg...), nil + return validatedCommand(ctx, "/usr/bin/echo", arg...) } func Falconctl(ctx context.Context, arg ...string) (*exec.Cmd, error) { - fullPathToCmdValidated, err := validatedPath("/opt/CrowdStrike/falconctl") - if err != nil { - return nil, fmt.Errorf("falconctl not found: %w", err) - } - return newCmd(ctx, fullPathToCmdValidated, arg...), nil + return validatedCommand(ctx, "/opt/CrowdStrike/falconctl", arg...) } func Falconkernelcheck(ctx context.Context, arg ...string) (*exec.Cmd, error) { - fullPathToCmdValidated, err := validatedPath("/opt/CrowdStrike/falcon-kernel-check") - if err != nil { - return nil, fmt.Errorf("falcon-kernel-check not found: %w", err) - } - return newCmd(ctx, fullPathToCmdValidated, arg...), nil + return validatedCommand(ctx, "/opt/CrowdStrike/falcon-kernel-check", arg...) } func Gnomeextensions(ctx context.Context, arg ...string) (*exec.Cmd, error) { - fullPathToCmdValidated, err := validatedPath("/usr/bin/gnome-extensions") - if err != nil { - return nil, fmt.Errorf("gnome-extensions not found: %w", err) - } - return newCmd(ctx, fullPathToCmdValidated, arg...), nil + return validatedCommand(ctx, "/usr/bin/gnome-extensions", arg...) } func Gsettings(ctx context.Context, arg ...string) (*exec.Cmd, error) { - fullPathToCmdValidated, err := validatedPath("/usr/bin/gsettings") - if err != nil { - return nil, fmt.Errorf("gsettings not found: %w", err) - } - return newCmd(ctx, fullPathToCmdValidated, arg...), nil + return validatedCommand(ctx, "/usr/bin/gsettings", arg...) } func Ifconfig(ctx context.Context, arg ...string) (*exec.Cmd, error) { - fullPathToCmdValidated, err := validatedPath("/usr/sbin/ifconfig") - if err != nil { - return nil, fmt.Errorf("ifconfig not found: %w", err) - } - return newCmd(ctx, fullPathToCmdValidated, arg...), nil + return validatedCommand(ctx, "/usr/sbin/ifconfig", arg...) } func Ip(ctx context.Context, arg ...string) (*exec.Cmd, error) { - fullPathToCmdValidated, err := validatedPath("/usr/sbin/ip") - if err != nil { - return nil, fmt.Errorf("ip not found: %w", err) - } - return newCmd(ctx, fullPathToCmdValidated, arg...), nil + return validatedCommand(ctx, "/usr/sbin/ip", arg...) } func Loginctl(ctx context.Context, arg ...string) (*exec.Cmd, error) { - fullPathToCmdValidated, err := validatedPath("/usr/bin/loginctl") - if err != nil { - return nil, fmt.Errorf("loginctl not found: %w", err) - } - return newCmd(ctx, fullPathToCmdValidated, arg...), nil + return validatedCommand(ctx, "/usr/bin/loginctl", arg...) } func Lsblk(ctx context.Context, arg ...string) (*exec.Cmd, error) { for _, p := range []string{"/bin/lsblk", "/usr/bin/lsblk"} { - fullPathToCmdValidated, err := validatedPath(p) + validatedCmd, err := validatedCommand(ctx, p, arg...) if err != nil { continue } - return newCmd(ctx, fullPathToCmdValidated, arg...), nil + return validatedCmd, nil } return nil, errors.New("lsblk not found") } func Lsof(ctx context.Context, arg ...string) (*exec.Cmd, error) { - fullPathToCmdValidated, err := validatedPath("/usr/bin/lsof") - if err != nil { - return nil, fmt.Errorf("lsof not found: %w", err) - } - return newCmd(ctx, fullPathToCmdValidated, arg...), nil + return validatedCommand(ctx, "/usr/bin/lsof", arg...) } func Nmcli(ctx context.Context, arg ...string) (*exec.Cmd, error) { - fullPathToCmdValidated, err := validatedPath("/usr/bin/nmcli") - if err != nil { - return nil, fmt.Errorf("nmcli not found: %w", err) - } - return newCmd(ctx, fullPathToCmdValidated, arg...), nil + return validatedCommand(ctx, "/usr/bin/nmcli", arg...) } func Notifysend(ctx context.Context, arg ...string) (*exec.Cmd, error) { - fullPathToCmdValidated, err := validatedPath("/usr/bin/notify-send") - if err != nil { - return nil, fmt.Errorf("notify-send not found: %w", err) - } - return newCmd(ctx, fullPathToCmdValidated, arg...), nil + return validatedCommand(ctx, "/usr/bin/notify-send", arg...) } func Pacman(ctx context.Context, arg ...string) (*exec.Cmd, error) { - fullPathToCmdValidated, err := validatedPath("/usr/bin/pacman") - if err != nil { - return nil, fmt.Errorf("pacman not found: %w", err) - } - return newCmd(ctx, fullPathToCmdValidated, arg...), nil + return validatedCommand(ctx, "/usr/bin/pacman", arg...) } func Ps(ctx context.Context, arg ...string) (*exec.Cmd, error) { - fullPathToCmdValidated, err := validatedPath("/usr/bin/ps") - if err != nil { - return nil, fmt.Errorf("ps not found: %w", err) - } - return newCmd(ctx, fullPathToCmdValidated, arg...), nil + return validatedCommand(ctx, "/usr/bin/ps", arg...) } func Repcli(ctx context.Context, arg ...string) (*exec.Cmd, error) { - fullPathToCmdValidated, err := validatedPath("/opt/carbonblack/psc/bin/repcli") - if err != nil { - return nil, fmt.Errorf("repcli not found: %w", err) - } - return newCmd(ctx, fullPathToCmdValidated, arg...), nil + return validatedCommand(ctx, "/opt/carbonblack/psc/bin/repcli", arg...) } func Rpm(ctx context.Context, arg ...string) (*exec.Cmd, error) { for _, p := range []string{"/bin/rpm", "/usr/bin/rpm"} { - fullPathToCmdValidated, err := validatedPath(p) + validatedCmd, err := validatedCommand(ctx, p, arg...) if err != nil { continue } - return newCmd(ctx, fullPathToCmdValidated, arg...), nil + return validatedCmd, nil } return nil, errors.New("rpm not found") } func Systemctl(ctx context.Context, arg ...string) (*exec.Cmd, error) { - fullPathToCmdValidated, err := validatedPath("/usr/bin/systemctl") - if err != nil { - return nil, fmt.Errorf("systemctl not found: %w", err) - } - return newCmd(ctx, fullPathToCmdValidated, arg...), nil + return validatedCommand(ctx, "/usr/bin/systemctl", arg...) } func Xdgopen(ctx context.Context, arg ...string) (*exec.Cmd, error) { - fullPathToCmdValidated, err := validatedPath("/usr/bin/xdg-open") - if err != nil { - return nil, fmt.Errorf("xdg-open not found: %w", err) - } - return newCmd(ctx, fullPathToCmdValidated, arg...), nil + return validatedCommand(ctx, "/usr/bin/xdg-open", arg...) } func Xrdb(ctx context.Context, arg ...string) (*exec.Cmd, error) { - fullPathToCmdValidated, err := validatedPath("/usr/bin/xrdb") - if err != nil { - return nil, fmt.Errorf("xrdb not found: %w", err) - } - return newCmd(ctx, fullPathToCmdValidated, arg...), nil + return validatedCommand(ctx, "/usr/bin/xrdb", arg...) } func Xwwwbrowser(ctx context.Context, arg ...string) (*exec.Cmd, error) { - fullPathToCmdValidated, err := validatedPath("/usr/bin/x-www-browser") - if err != nil { - return nil, fmt.Errorf("x-www-browser not found: %w", err) - } - return newCmd(ctx, fullPathToCmdValidated, arg...), nil + return validatedCommand(ctx, "/usr/bin/x-www-browser", arg...) } func Zerotiercli(ctx context.Context, arg ...string) (*exec.Cmd, error) { - fullPathToCmdValidated, err := validatedPath("/usr/local/bin/zerotier-cli") - if err != nil { - return nil, fmt.Errorf("zerotier-cli not found: %w", err) - } - return newCmd(ctx, fullPathToCmdValidated, arg...), nil + return validatedCommand(ctx, "/usr/local/bin/zerotier-cli", arg...) } func Zfs(ctx context.Context, arg ...string) (*exec.Cmd, error) { - fullPathToCmdValidated, err := validatedPath("/usr/sbin/zfs") - if err != nil { - return nil, fmt.Errorf("zfs not found: %w", err) - } - return newCmd(ctx, fullPathToCmdValidated, arg...), nil + return validatedCommand(ctx, "/usr/sbin/zfs", arg...) } func Zpool(ctx context.Context, arg ...string) (*exec.Cmd, error) { - fullPathToCmdValidated, err := validatedPath("/usr/sbin/zpool") - if err != nil { - return nil, fmt.Errorf("zpool not found: %w", err) - } - return newCmd(ctx, fullPathToCmdValidated, arg...), nil + return validatedCommand(ctx, "/usr/sbin/zpool", arg...) } diff --git a/pkg/allowedpaths/cmd_test.go b/pkg/allowedpaths/cmd_test.go index 4c8bc1b31..20a4094cc 100644 --- a/pkg/allowedpaths/cmd_test.go +++ b/pkg/allowedpaths/cmd_test.go @@ -27,7 +27,7 @@ func Test_newCmd(t *testing.T) { require.Equal(t, cmdPath, cmd.Path) } -func Test_validatedPath(t *testing.T) { +func Test_validatedCommand(t *testing.T) { t.Parallel() var cmdPath string @@ -38,13 +38,13 @@ func Test_validatedPath(t *testing.T) { cmdPath = `C:\Windows\System32\WindowsPowerShell\v1.0\powershell.exe` } - p, err := validatedPath(cmdPath) + p, err := validatedCommand(context.TODO(), cmdPath) require.NoError(t, err) - require.Equal(t, cmdPath, p) + require.Equal(t, cmdPath, p.Path) } -func Test_validatedPath_findsCorrectPath(t *testing.T) { +func Test_validatedCommand_findsCorrectPath(t *testing.T) { t.Parallel() if runtime.GOOS != "linux" { @@ -52,8 +52,8 @@ func Test_validatedPath_findsCorrectPath(t *testing.T) { } cmdPath := "/not/the/real/path/to/bash" - p, err := validatedPath(cmdPath) + p, err := validatedCommand(context.TODO(), cmdPath) require.NoError(t, err) - require.NotEqual(t, cmdPath, p) + require.NotEqual(t, cmdPath, p.Path) } diff --git a/pkg/allowedpaths/cmd_windows.go b/pkg/allowedpaths/cmd_windows.go index 754090786..393be9091 100644 --- a/pkg/allowedpaths/cmd_windows.go +++ b/pkg/allowedpaths/cmd_windows.go @@ -5,7 +5,6 @@ package allowedpaths import ( "context" - "fmt" "os" "os/exec" "path" @@ -13,27 +12,15 @@ import ( ) func Commandprompt(ctx context.Context, arg ...string) (*exec.Cmd, error) { - fullPathToCmdValidated, err := validatedPath(`C:\Windows\System32\cmd.exe`) - if err != nil { - return nil, fmt.Errorf("cmd.exe not found: %w", err) - } - return newCmd(ctx, fullPathToCmdValidated, arg...), nil + return validatedCommand(ctx, `C:\Windows\System32\cmd.exe`, arg...) } func Dism(ctx context.Context, arg ...string) (*exec.Cmd, error) { - fullPathToCmdValidated, err := validatedPath(`C:\Windows\System32\Dism.exe`) - if err != nil { - return nil, fmt.Errorf("dism.exe not found: %w", err) - } - return newCmd(ctx, fullPathToCmdValidated, arg...), nil + return validatedCommand(ctx, `C:\Windows\System32\Dism.exe`, arg...) } func Dsregcmd(ctx context.Context, arg ...string) (*exec.Cmd, error) { - fullPathToCmdValidated, err := validatedPath(`C:\Windows\System32\dsregcmd.exe`) - if err != nil { - return nil, fmt.Errorf("dsregcmd.exe not found: %w", err) - } - return newCmd(ctx, fullPathToCmdValidated, arg...), nil + return validatedCommand(ctx, `C:\Windows\System32\dsregcmd.exe`, arg...) } func Echo(ctx context.Context, arg ...string) (*exec.Cmd, error) { @@ -42,59 +29,30 @@ func Echo(ctx context.Context, arg ...string) (*exec.Cmd, error) { } func Ipconfig(ctx context.Context, arg ...string) (*exec.Cmd, error) { - fullPathToCmdValidated, err := validatedPath(`C:\Windows\System32\ipconfig.exe`) - if err != nil { - return nil, fmt.Errorf("ipconfig.exe not found: %w", err) - } - return newCmd(ctx, fullPathToCmdValidated, arg...), nil + return validatedCommand(ctx, `C:\Windows\System32\ipconfig.exe`, arg...) } func Powercfg(ctx context.Context, arg ...string) (*exec.Cmd, error) { - fullPathToCmdValidated, err := validatedPath(`C:\Windows\System32\powercfg.exe`) - if err != nil { - return nil, fmt.Errorf("powercfg.exe not found: %w", err) - } - return newCmd(ctx, fullPathToCmdValidated, arg...), nil + return validatedCommand(ctx, `C:\Windows\System32\powercfg.exe`, arg...) } func Powershell(ctx context.Context, arg ...string) (*exec.Cmd, error) { - fullPathToCmdValidated, err := validatedPath(`C:\Windows\System32\WindowsPowerShell\v1.0\powershell.exe`) - if err != nil { - return nil, fmt.Errorf("powershell.exe not found: %w", err) - } - return newCmd(ctx, fullPathToCmdValidated, arg...), nil + return validatedCommand(ctx, `C:\Windows\System32\WindowsPowerShell\v1.0\powershell.exe`, arg...) } func Repcli(ctx context.Context, arg ...string) (*exec.Cmd, error) { - fullPathToCmdValidated, err := validatedPath(filepath.Join("Program Files", "Confer", "repcli")) - if err != nil { - return nil, fmt.Errorf("repcli not found: %w", err) - } - return newCmd(ctx, fullPathToCmdValidated, arg...), nil + return validatedCommand(ctx, filepath.Join("Program Files", "Confer", "repcli"), arg...) } func Secedit(ctx context.Context, arg ...string) (*exec.Cmd, error) { - fullPathToCmdValidated, err := validatedPath(`C:\Windows\System32\SecEdit.exe`) - if err != nil { - return nil, fmt.Errorf("secedit.exe not found: %w", err) - } - return newCmd(ctx, fullPathToCmdValidated, arg...), nil + return validatedCommand(ctx, `C:\Windows\System32\SecEdit.exe`, arg...) } func Taskkill(ctx context.Context, arg ...string) (*exec.Cmd, error) { - fullPathToCmdValidated, err := validatedPath(`C:\Windows\System32\taskkill.exe`) - if err != nil { - return nil, fmt.Errorf("taskkill.exe not found: %w", err) - } - return newCmd(ctx, fullPathToCmdValidated, arg...), nil + return validatedCommand(ctx, `C:\Windows\System32\taskkill.exe`, arg...) } func Zerotiercli(ctx context.Context, arg ...string) (*exec.Cmd, error) { - fullPathToCmdValidated, err := validatedPath(path.Join(os.Getenv("SYSTEMROOT"), "ProgramData", "ZeroTier", "One", "zerotier-one_x64.exe")) - if err != nil { - return nil, fmt.Errorf("zerotier-cli not found: %w", err) - } - // For windows, "-q" should be prepended before all other args - return newCmd(ctx, fullPathToCmdValidated, []string{"-q"}, arg...), nil + return validatedCommand(ctx, path.Join(os.Getenv("SYSTEMROOT"), "ProgramData", "ZeroTier", "One", "zerotier-one_x64.exe"), []string{"-q"}, arg...) } From 7eca23e835dd7dbd6f0b4bb07c89fa6cff31d24d Mon Sep 17 00:00:00 2001 From: Rebecca Mahany-Horton Date: Thu, 9 Nov 2023 10:24:39 -0500 Subject: [PATCH 19/30] Some more platform fixups --- pkg/allowedpaths/cmd_windows.go | 2 +- .../{launchd.go => launchd_darwin.go} | 8 +- pkg/debug/checkups/launchd_other.go | 36 ++++++ pkg/log/log.go | 110 ------------------ pkg/log/log_posix.go | 106 +++++++++++++++++ pkg/log/log_windows.go | 16 +++ pkg/osquery/table/mdm.go | 3 + .../tables/crowdstrike/falconctl/parser.go | 3 + .../crowdstrike/falconctl/parser_test.go | 3 + .../tables/crowdstrike/falconctl/table.go | 3 + .../crowdstrike/falconctl/table_test.go | 3 + .../tables/firmwarepasswd/firmwarepasswd.go | 3 + .../firmwarepasswd/firmwarepasswd_test.go | 3 + pkg/osquery/tables/firmwarepasswd/parser.go | 3 + pkg/osquery/tables/mdmclient/mdmclient.go | 6 +- .../tables/mdmclient/mdmclient_test.go | 6 +- .../tablehelpers/exec_osquery_launchctl.go | 3 +- 17 files changed, 192 insertions(+), 125 deletions(-) rename pkg/debug/checkups/{launchd.go => launchd_darwin.go} (97%) create mode 100644 pkg/debug/checkups/launchd_other.go create mode 100644 pkg/log/log_posix.go create mode 100644 pkg/log/log_windows.go diff --git a/pkg/allowedpaths/cmd_windows.go b/pkg/allowedpaths/cmd_windows.go index 393be9091..51d6b9734 100644 --- a/pkg/allowedpaths/cmd_windows.go +++ b/pkg/allowedpaths/cmd_windows.go @@ -54,5 +54,5 @@ func Taskkill(ctx context.Context, arg ...string) (*exec.Cmd, error) { func Zerotiercli(ctx context.Context, arg ...string) (*exec.Cmd, error) { // For windows, "-q" should be prepended before all other args - return validatedCommand(ctx, path.Join(os.Getenv("SYSTEMROOT"), "ProgramData", "ZeroTier", "One", "zerotier-one_x64.exe"), []string{"-q"}, arg...) + return validatedCommand(ctx, path.Join(os.Getenv("SYSTEMROOT"), "ProgramData", "ZeroTier", "One", "zerotier-one_x64.exe"), append([]string{"-q"}, arg...)...) } diff --git a/pkg/debug/checkups/launchd.go b/pkg/debug/checkups/launchd_darwin.go similarity index 97% rename from pkg/debug/checkups/launchd.go rename to pkg/debug/checkups/launchd_darwin.go index 3dd4deff9..867331498 100644 --- a/pkg/debug/checkups/launchd.go +++ b/pkg/debug/checkups/launchd_darwin.go @@ -1,3 +1,6 @@ +//go:build darwin +// +build darwin + package checkups import ( @@ -8,7 +11,6 @@ import ( "io" "os" "path/filepath" - "runtime" "strings" "github.com/kolide/launcher/pkg/allowedpaths" @@ -25,10 +27,6 @@ type launchdCheckup struct { } func (c *launchdCheckup) Name() string { - if runtime.GOOS != "darwin" { - return "" - } - return "Launchd" } diff --git a/pkg/debug/checkups/launchd_other.go b/pkg/debug/checkups/launchd_other.go new file mode 100644 index 000000000..59af86cab --- /dev/null +++ b/pkg/debug/checkups/launchd_other.go @@ -0,0 +1,36 @@ +//go:build !darwin +// +build !darwin + +package checkups + +import ( + "context" + "io" +) + +type launchdCheckup struct { +} + +func (c *launchdCheckup) Name() string { + return "" +} + +func (c *launchdCheckup) Run(_ context.Context, _ io.Writer) error { + return nil +} + +func (c *launchdCheckup) ExtraFileName() string { + return "" +} + +func (c *launchdCheckup) Status() Status { + return Informational +} + +func (c *launchdCheckup) Summary() string { + return "" +} + +func (c *launchdCheckup) Data() any { + return nil +} diff --git a/pkg/log/log.go b/pkg/log/log.go index 1f03dcbc2..b728f8f5e 100644 --- a/pkg/log/log.go +++ b/pkg/log/log.go @@ -2,19 +2,14 @@ package log import ( "bytes" - "context" "fmt" "os" - "path/filepath" "regexp" - "runtime" "strconv" "strings" - "time" kitlog "github.com/go-kit/kit/log" "github.com/go-kit/kit/log/level" - "github.com/kolide/launcher/pkg/allowedpaths" "github.com/shirou/gopsutil/v3/host" "github.com/shirou/gopsutil/v3/process" ) @@ -160,111 +155,6 @@ func (l *OsqueryLogAdapter) logInfoAboutUnrecognizedProcessLockingPidfile(p []by level.Debug(l.logger).Log(append(processInfo, "msg", "detected non-osqueryd process using pidfile")...) } -// runAndLogPs runs ps filtering on the given PID, and logs the output. -func (l *OsqueryLogAdapter) runAndLogPs(pidStr string) { - if runtime.GOOS == "windows" { - return - } - - ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second) - defer cancel() - - cmd, err := allowedpaths.Ps(ctx, "-p", pidStr, "-o", "user,pid,ppid,pgid,stat,time,command") - if err != nil { - level.Debug(l.logger).Log( - "msg", "error creating command to run ps on osqueryd pidfile", - "err", err, - ) - return - } - out, err := cmd.CombinedOutput() - if err != nil { - level.Debug(l.logger).Log( - "msg", "error running ps on non-osqueryd process using pidfile", - "pid", pidStr, - "err", err, - ) - return - } - - level.Debug(l.logger).Log( - "msg", "ran ps on non-osqueryd process using pidfile", - "pid", pidStr, - "output", string(out), - ) -} - -// runAndLogLsofByPID runs lsof filtering on the given PID, and logs the output. -func (l *OsqueryLogAdapter) runAndLogLsofByPID(pidStr string) { - if runtime.GOOS == "windows" { - return - } - - ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second) - defer cancel() - - cmd, err := allowedpaths.Lsof(ctx, "-R", "-n", "-p", pidStr) - if err != nil { - level.Debug(l.logger).Log( - "msg", "error creating command to run lsof on osqueryd pidfile", - "err", err, - ) - return - } - out, err := cmd.CombinedOutput() - if err != nil { - level.Debug(l.logger).Log( - "msg", "error running lsof on non-osqueryd process using pidfile", - "pid", pidStr, - "err", err, - ) - return - } - - level.Debug(l.logger).Log( - "msg", "ran lsof on non-osqueryd process using pidfile", - "pid", pidStr, - "output", string(out), - ) -} - -// runAndLogLsofOnPidfile runs lsof filtering by the osquery pidfile, and logs -// the output. -func (l *OsqueryLogAdapter) runAndLogLsofOnPidfile() { - if runtime.GOOS == "windows" { - return - } - - fullPidfile := filepath.Join(l.rootDirectory, "osquery.pid") - - ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second) - defer cancel() - - cmd, err := allowedpaths.Lsof(ctx, "-R", "-n", fullPidfile) - if err != nil { - level.Debug(l.logger).Log( - "msg", "error creating command to run lsof on osqueryd pidfile", - "err", err, - ) - return - } - out, err := cmd.CombinedOutput() - if err != nil { - level.Debug(l.logger).Log( - "msg", "error running lsof on osqueryd pidfile", - "pidfile", fullPidfile, - "err", err, - ) - return - } - - level.Debug(l.logger).Log( - "msg", "ran lsof on osqueryd pidfile", - "pidfile", fullPidfile, - "output", string(out), - ) -} - // getStringStat is a small wrapper around gopsutil/process functions // to return the stat if available, or an error message if not, so // that either way the info will be captured in the log. diff --git a/pkg/log/log_posix.go b/pkg/log/log_posix.go new file mode 100644 index 000000000..ef4786780 --- /dev/null +++ b/pkg/log/log_posix.go @@ -0,0 +1,106 @@ +//go:build !windows +// +build !windows + +package log + +import ( + "context" + "path/filepath" + "time" + + "github.com/go-kit/kit/log/level" + "github.com/kolide/launcher/pkg/allowedpaths" +) + +// runAndLogPs runs ps filtering on the given PID, and logs the output. +func (l *OsqueryLogAdapter) runAndLogPs(pidStr string) { + ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second) + defer cancel() + + cmd, err := allowedpaths.Ps(ctx, "-p", pidStr, "-o", "user,pid,ppid,pgid,stat,time,command") + if err != nil { + level.Debug(l.logger).Log( + "msg", "error creating command to run ps on osqueryd pidfile", + "err", err, + ) + return + } + out, err := cmd.CombinedOutput() + if err != nil { + level.Debug(l.logger).Log( + "msg", "error running ps on non-osqueryd process using pidfile", + "pid", pidStr, + "err", err, + ) + return + } + + level.Debug(l.logger).Log( + "msg", "ran ps on non-osqueryd process using pidfile", + "pid", pidStr, + "output", string(out), + ) +} + +// runAndLogLsofByPID runs lsof filtering on the given PID, and logs the output. +func (l *OsqueryLogAdapter) runAndLogLsofByPID(pidStr string) { + ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second) + defer cancel() + + cmd, err := allowedpaths.Lsof(ctx, "-R", "-n", "-p", pidStr) + if err != nil { + level.Debug(l.logger).Log( + "msg", "error creating command to run lsof on osqueryd pidfile", + "err", err, + ) + return + } + out, err := cmd.CombinedOutput() + if err != nil { + level.Debug(l.logger).Log( + "msg", "error running lsof on non-osqueryd process using pidfile", + "pid", pidStr, + "err", err, + ) + return + } + + level.Debug(l.logger).Log( + "msg", "ran lsof on non-osqueryd process using pidfile", + "pid", pidStr, + "output", string(out), + ) +} + +// runAndLogLsofOnPidfile runs lsof filtering by the osquery pidfile, and logs +// the output. +func (l *OsqueryLogAdapter) runAndLogLsofOnPidfile() { + fullPidfile := filepath.Join(l.rootDirectory, "osquery.pid") + + ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second) + defer cancel() + + cmd, err := allowedpaths.Lsof(ctx, "-R", "-n", fullPidfile) + if err != nil { + level.Debug(l.logger).Log( + "msg", "error creating command to run lsof on osqueryd pidfile", + "err", err, + ) + return + } + out, err := cmd.CombinedOutput() + if err != nil { + level.Debug(l.logger).Log( + "msg", "error running lsof on osqueryd pidfile", + "pidfile", fullPidfile, + "err", err, + ) + return + } + + level.Debug(l.logger).Log( + "msg", "ran lsof on osqueryd pidfile", + "pidfile", fullPidfile, + "output", string(out), + ) +} diff --git a/pkg/log/log_windows.go b/pkg/log/log_windows.go new file mode 100644 index 000000000..7d0dee265 --- /dev/null +++ b/pkg/log/log_windows.go @@ -0,0 +1,16 @@ +//go:build windows +// +build windows + +package log + +func (l *OsqueryLogAdapter) runAndLogPs(_ string) { + return +} + +func (l *OsqueryLogAdapter) runAndLogLsofByPID(_ string) { + return +} + +func (l *OsqueryLogAdapter) runAndLogLsofOnPidfile() { + return +} diff --git a/pkg/osquery/table/mdm.go b/pkg/osquery/table/mdm.go index d11733299..a94f0881b 100644 --- a/pkg/osquery/table/mdm.go +++ b/pkg/osquery/table/mdm.go @@ -1,3 +1,6 @@ +//go:build darwin +// +build darwin + package table import ( diff --git a/pkg/osquery/tables/crowdstrike/falconctl/parser.go b/pkg/osquery/tables/crowdstrike/falconctl/parser.go index b5313758d..5b1bc115e 100644 --- a/pkg/osquery/tables/crowdstrike/falconctl/parser.go +++ b/pkg/osquery/tables/crowdstrike/falconctl/parser.go @@ -1,3 +1,6 @@ +//go:build !windows +// +build !windows + package falconctl import ( diff --git a/pkg/osquery/tables/crowdstrike/falconctl/parser_test.go b/pkg/osquery/tables/crowdstrike/falconctl/parser_test.go index 22df1f915..1f1768175 100644 --- a/pkg/osquery/tables/crowdstrike/falconctl/parser_test.go +++ b/pkg/osquery/tables/crowdstrike/falconctl/parser_test.go @@ -1,3 +1,6 @@ +//go:build !windows +// +build !windows + package falconctl import ( diff --git a/pkg/osquery/tables/crowdstrike/falconctl/table.go b/pkg/osquery/tables/crowdstrike/falconctl/table.go index 54a7a253f..adab701a1 100644 --- a/pkg/osquery/tables/crowdstrike/falconctl/table.go +++ b/pkg/osquery/tables/crowdstrike/falconctl/table.go @@ -1,3 +1,6 @@ +//go:build !windows +// +build !windows + package falconctl import ( diff --git a/pkg/osquery/tables/crowdstrike/falconctl/table_test.go b/pkg/osquery/tables/crowdstrike/falconctl/table_test.go index 979c1f624..ce5abcc60 100644 --- a/pkg/osquery/tables/crowdstrike/falconctl/table_test.go +++ b/pkg/osquery/tables/crowdstrike/falconctl/table_test.go @@ -1,3 +1,6 @@ +//go:build !windows +// +build !windows + package falconctl import ( diff --git a/pkg/osquery/tables/firmwarepasswd/firmwarepasswd.go b/pkg/osquery/tables/firmwarepasswd/firmwarepasswd.go index 53fcdca02..10619c8c4 100644 --- a/pkg/osquery/tables/firmwarepasswd/firmwarepasswd.go +++ b/pkg/osquery/tables/firmwarepasswd/firmwarepasswd.go @@ -1,3 +1,6 @@ +//go:build darwin +// +build darwin + // firmwarepasswd is a simple wrapper around the // `/usr/sbin/firmwarepasswd` tool. This should be considered beta at // best. It serves a bit as a pattern for future exec work. diff --git a/pkg/osquery/tables/firmwarepasswd/firmwarepasswd_test.go b/pkg/osquery/tables/firmwarepasswd/firmwarepasswd_test.go index 5f8311a6c..fd6cdef28 100644 --- a/pkg/osquery/tables/firmwarepasswd/firmwarepasswd_test.go +++ b/pkg/osquery/tables/firmwarepasswd/firmwarepasswd_test.go @@ -1,3 +1,6 @@ +//go:build darwin +// +build darwin + package firmwarepasswd import ( diff --git a/pkg/osquery/tables/firmwarepasswd/parser.go b/pkg/osquery/tables/firmwarepasswd/parser.go index f3f46c64d..34a5a85ac 100644 --- a/pkg/osquery/tables/firmwarepasswd/parser.go +++ b/pkg/osquery/tables/firmwarepasswd/parser.go @@ -1,3 +1,6 @@ +//go:build darwin +// +build darwin + package firmwarepasswd import ( diff --git a/pkg/osquery/tables/mdmclient/mdmclient.go b/pkg/osquery/tables/mdmclient/mdmclient.go index 1327d24f3..b23039738 100644 --- a/pkg/osquery/tables/mdmclient/mdmclient.go +++ b/pkg/osquery/tables/mdmclient/mdmclient.go @@ -1,7 +1,5 @@ -//go:build !windows -// +build !windows - -// (skip building windows, since the newline replacement doesn't work there) +//go:build darwin +// +build darwin // Package mdmclient provides a table that parses the mdmclient // output. Empirically, this seems to be an almost gnustep diff --git a/pkg/osquery/tables/mdmclient/mdmclient_test.go b/pkg/osquery/tables/mdmclient/mdmclient_test.go index 0b89fd455..65628451e 100644 --- a/pkg/osquery/tables/mdmclient/mdmclient_test.go +++ b/pkg/osquery/tables/mdmclient/mdmclient_test.go @@ -1,7 +1,5 @@ -//go:build !windows -// +build !windows - -// (skip building windows, since the newline replacement doesn't work there) +//go:build darwin +// +build darwin package mdmclient diff --git a/pkg/osquery/tables/tablehelpers/exec_osquery_launchctl.go b/pkg/osquery/tables/tablehelpers/exec_osquery_launchctl.go index 5971a9035..a9779c73f 100644 --- a/pkg/osquery/tables/tablehelpers/exec_osquery_launchctl.go +++ b/pkg/osquery/tables/tablehelpers/exec_osquery_launchctl.go @@ -1,4 +1,5 @@ -// build +darwin +//go:build darwin +// +build darwin package tablehelpers From 73286490f7614e2c813ae16109a07b37e2026b02 Mon Sep 17 00:00:00 2001 From: Rebecca Mahany-Horton Date: Thu, 9 Nov 2023 12:34:23 -0500 Subject: [PATCH 20/30] LookPath on NixOS only --- pkg/allowedpaths/cmd.go | 15 ++++++++++++++- pkg/allowedpaths/cmd_test.go | 7 +++---- 2 files changed, 17 insertions(+), 5 deletions(-) diff --git a/pkg/allowedpaths/cmd.go b/pkg/allowedpaths/cmd.go index 75b77066a..9b9797f3e 100644 --- a/pkg/allowedpaths/cmd.go +++ b/pkg/allowedpaths/cmd.go @@ -25,7 +25,7 @@ func validatedCommand(ctx context.Context, knownPath string, arg ...string) (*ex // Not found at known location -- return error for darwin and windows. // We expect to know the exact location for allowlisted commands on all // OSes except for a few Linux distros. - if runtime.GOOS != "linux" { + if allowSearchPath() { return nil, fmt.Errorf("not found: %s", knownPath) } @@ -36,3 +36,16 @@ func validatedCommand(ctx context.Context, knownPath string, arg ...string) (*ex return nil, fmt.Errorf("%s not found at %s and could not be located elsewhere", cmdName, knownPath) } + +func allowSearchPath() bool { + if runtime.GOOS != "linux" { + return false + } + + // We only allow searching for binaries in PATH on NixOS + if _, err := os.Stat("/etc/NIXOS"); err == nil { + return true + } + + return false +} diff --git a/pkg/allowedpaths/cmd_test.go b/pkg/allowedpaths/cmd_test.go index 20a4094cc..1c1c594a6 100644 --- a/pkg/allowedpaths/cmd_test.go +++ b/pkg/allowedpaths/cmd_test.go @@ -44,7 +44,7 @@ func Test_validatedCommand(t *testing.T) { require.Equal(t, cmdPath, p.Path) } -func Test_validatedCommand_findsCorrectPath(t *testing.T) { +func Test_validatedCommand_doesNotSearchPathOnNonNixOS(t *testing.T) { t.Parallel() if runtime.GOOS != "linux" { @@ -52,8 +52,7 @@ func Test_validatedCommand_findsCorrectPath(t *testing.T) { } cmdPath := "/not/the/real/path/to/bash" - p, err := validatedCommand(context.TODO(), cmdPath) + _, err := validatedCommand(context.TODO(), cmdPath) - require.NoError(t, err) - require.NotEqual(t, cmdPath, p.Path) + require.Error(t, err) } From 263a1266082f5852a964eaeb35b114fb0d0e1f5c Mon Sep 17 00:00:00 2001 From: Rebecca Mahany-Horton Date: Thu, 9 Nov 2023 14:40:43 -0500 Subject: [PATCH 21/30] Fix check --- pkg/allowedpaths/cmd.go | 2 +- pkg/allowedpaths/cmd_test.go | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/pkg/allowedpaths/cmd.go b/pkg/allowedpaths/cmd.go index 9b9797f3e..9805bf852 100644 --- a/pkg/allowedpaths/cmd.go +++ b/pkg/allowedpaths/cmd.go @@ -25,7 +25,7 @@ func validatedCommand(ctx context.Context, knownPath string, arg ...string) (*ex // Not found at known location -- return error for darwin and windows. // We expect to know the exact location for allowlisted commands on all // OSes except for a few Linux distros. - if allowSearchPath() { + if !allowSearchPath() { return nil, fmt.Errorf("not found: %s", knownPath) } diff --git a/pkg/allowedpaths/cmd_test.go b/pkg/allowedpaths/cmd_test.go index 1c1c594a6..8d2590ef0 100644 --- a/pkg/allowedpaths/cmd_test.go +++ b/pkg/allowedpaths/cmd_test.go @@ -38,10 +38,10 @@ func Test_validatedCommand(t *testing.T) { cmdPath = `C:\Windows\System32\WindowsPowerShell\v1.0\powershell.exe` } - p, err := validatedCommand(context.TODO(), cmdPath) + cmd, err := validatedCommand(context.TODO(), cmdPath) require.NoError(t, err) - require.Equal(t, cmdPath, p.Path) + require.Equal(t, cmdPath, cmd.Path) } func Test_validatedCommand_doesNotSearchPathOnNonNixOS(t *testing.T) { From c012de8c04cf7f4d822f9e6decba161ed20408fa Mon Sep 17 00:00:00 2001 From: Rebecca Mahany-Horton Date: Thu, 9 Nov 2023 16:19:58 -0500 Subject: [PATCH 22/30] Renamed allowedpaths to allowedcmd --- .golangci.yml | 2 +- cmd/launcher/uninstall_darwin.go | 6 ++--- cmd/launcher/uninstall_linux.go | 8 +++---- ee/consoleuser/consoleuser_darwin.go | 4 ++-- ee/consoleuser/consoleuser_linux.go | 6 ++--- ee/desktop/runner/runner.go | 2 +- ee/desktop/runner/runner_linux.go | 8 +++---- .../user/menu/action_open_url_darwin.go | 4 ++-- ee/desktop/user/menu/action_open_url_linux.go | 4 ++-- .../user/menu/action_open_url_windows.go | 4 ++-- ee/desktop/user/notify/notify_linux.go | 6 ++--- pkg/{allowedpaths => allowedcmd}/cmd.go | 2 +- .../cmd_darwin.go | 2 +- pkg/{allowedpaths => allowedcmd}/cmd_linux.go | 2 +- pkg/{allowedpaths => allowedcmd}/cmd_test.go | 2 +- .../cmd_windows.go | 2 +- pkg/autoupdate/findnew.go | 2 +- pkg/dataflatten/testdata/secdata.ini | 2 +- pkg/debug/checkups/gnome_extensions_linux.go | 4 ++-- pkg/debug/checkups/launchd_darwin.go | 4 ++-- pkg/debug/checkups/network.go | 4 ++-- pkg/debug/checkups/network_darwin.go | 6 ++--- pkg/debug/checkups/network_linux.go | 8 +++---- pkg/debug/checkups/network_windows.go | 4 ++-- pkg/debug/checkups/power_windows.go | 4 ++-- pkg/debug/checkups/services_windows.go | 4 ++-- pkg/log/log_posix.go | 8 +++---- pkg/osquery/runtime/osqueryinstance.go | 2 +- .../runtime/runtime_helpers_windows.go | 4 ++-- pkg/osquery/table/mdfind_darwin.go | 4 ++-- pkg/osquery/table/mdm.go | 6 ++--- pkg/osquery/table/platform_tables_darwin.go | 22 ++++++++--------- pkg/osquery/table/platform_tables_linux.go | 24 +++++++++---------- pkg/osquery/table/platform_tables_windows.go | 4 ++-- pkg/osquery/table/table.go | 8 +++---- pkg/osquery/table/touchid_system_darwin.go | 6 ++--- pkg/osquery/table/touchid_user_darwin.go | 8 +++---- pkg/osquery/tables/airport/table_darwin.go | 4 ++-- .../apple_silicon_security_policy/table.go | 4 ++-- .../crowdstrike/falcon_kernel_check/table.go | 4 ++-- .../tables/crowdstrike/falconctl/table.go | 6 ++--- .../crowdstrike/falconctl/table_test.go | 4 ++-- pkg/osquery/tables/cryptsetup/table.go | 4 ++-- pkg/osquery/tables/dataflattentable/exec.go | 4 ++-- .../tables/dataflattentable/exec_and_parse.go | 6 ++--- pkg/osquery/tables/dataflattentable/tables.go | 4 ++-- .../dataflattentable/testdata/secdata.ini | 2 +- pkg/osquery/tables/dev_table_tooling/table.go | 8 +++---- .../dsim_default_associations.go | 4 ++-- pkg/osquery/tables/filevault/filevault.go | 4 ++-- .../tables/firmwarepasswd/firmwarepasswd.go | 4 ++-- pkg/osquery/tables/gsettings/gsettings.go | 4 ++-- pkg/osquery/tables/gsettings/metadata.go | 4 ++-- pkg/osquery/tables/ioreg/ioreg.go | 4 ++-- pkg/osquery/tables/mdmclient/mdmclient.go | 4 ++-- pkg/osquery/tables/profiles/profiles.go | 4 ++-- pkg/osquery/tables/pwpolicy/pwpolicy.go | 6 ++--- pkg/osquery/tables/secedit/secedit.go | 4 ++-- .../tables/systemprofiler/systemprofiler.go | 4 ++-- pkg/osquery/tables/tablehelpers/exec.go | 4 ++-- .../tablehelpers/exec_osquery_launchctl.go | 4 ++-- pkg/osquery/tables/tablehelpers/exec_test.go | 6 ++--- .../tables/wifi_networks/wifi_networks.go | 4 ++-- pkg/osquery/tables/xrdb/xrdb.go | 4 ++-- pkg/osquery/tables/zfs/tables.go | 8 +++---- 65 files changed, 164 insertions(+), 164 deletions(-) rename pkg/{allowedpaths => allowedcmd}/cmd.go (98%) rename pkg/{allowedpaths => allowedcmd}/cmd_darwin.go (99%) rename pkg/{allowedpaths => allowedcmd}/cmd_linux.go (99%) rename pkg/{allowedpaths => allowedcmd}/cmd_test.go (98%) rename pkg/{allowedpaths => allowedcmd}/cmd_windows.go (98%) diff --git a/.golangci.yml b/.golangci.yml index 03f3d4b21..81c84ca09 100644 --- a/.golangci.yml +++ b/.golangci.yml @@ -38,7 +38,7 @@ linters-settings: forbidigo: forbid: - p: ^exec\.Command.*$ - msg: use pkg/allowedpaths functions instead + msg: use pkg/allowedcmd functions instead sloglint: kv-only: true context-only: true diff --git a/cmd/launcher/uninstall_darwin.go b/cmd/launcher/uninstall_darwin.go index 80d9210d6..4927188fd 100644 --- a/cmd/launcher/uninstall_darwin.go +++ b/cmd/launcher/uninstall_darwin.go @@ -10,7 +10,7 @@ import ( "strings" "time" - "github.com/kolide/launcher/pkg/allowedpaths" + "github.com/kolide/launcher/pkg/allowedcmd" ) func removeLauncher(ctx context.Context, identifier string) error { @@ -24,7 +24,7 @@ func removeLauncher(ctx context.Context, identifier string) error { launchctlCtx, cancel := context.WithTimeout(ctx, 30*time.Second) defer cancel() - cmd, err := allowedpaths.Launchctl(launchctlCtx, launchCtlArgs...) + cmd, err := allowedcmd.Launchctl(launchctlCtx, launchCtlArgs...) if err != nil { fmt.Printf("could not find launchctl: %s\n", err) return err @@ -59,7 +59,7 @@ func removeLauncher(ctx context.Context, identifier string) error { pkgutiltCtx, cancel := context.WithTimeout(ctx, 30*time.Second) defer cancel() - pkgUtilcmd, err := allowedpaths.Pkgutil(pkgutiltCtx, "--forget", fmt.Sprintf("com.%s.launcher", identifier)) + pkgUtilcmd, err := allowedcmd.Pkgutil(pkgutiltCtx, "--forget", fmt.Sprintf("com.%s.launcher", identifier)) if err != nil { fmt.Printf("could not find pkgutil: %s\n", err) return err diff --git a/cmd/launcher/uninstall_linux.go b/cmd/launcher/uninstall_linux.go index 829f12e7c..aad211565 100644 --- a/cmd/launcher/uninstall_linux.go +++ b/cmd/launcher/uninstall_linux.go @@ -10,7 +10,7 @@ import ( "os" "strings" - "github.com/kolide/launcher/pkg/allowedpaths" + "github.com/kolide/launcher/pkg/allowedcmd" ) func removeLauncher(ctx context.Context, identifier string) error { @@ -23,7 +23,7 @@ func removeLauncher(ctx context.Context, identifier string) error { packageName := fmt.Sprintf("launcher-%s", identifier) // Stop and disable launcher service - cmd, err := allowedpaths.Systemctl(ctx, []string{"disable", "--now", serviceName}...) + cmd, err := allowedcmd.Systemctl(ctx, []string{"disable", "--now", serviceName}...) if err != nil { fmt.Printf("could not find systemctl: %s\n", err) return err @@ -34,11 +34,11 @@ func removeLauncher(ctx context.Context, identifier string) error { } // Tell the appropriate package manager to remove launcher - if cmd, err := allowedpaths.Dpkg(ctx, []string{"--purge", packageName}...); err == nil { + if cmd, err := allowedcmd.Dpkg(ctx, []string{"--purge", packageName}...); err == nil { if out, err := cmd.CombinedOutput(); err != nil { fmt.Printf("error occurred while running dpkg --purge, output %s: err: %s\n", string(out), err) } - } else if cmd, err := allowedpaths.Rpm(ctx, []string{"-e", packageName}...); err == nil { + } else if cmd, err := allowedcmd.Rpm(ctx, []string{"-e", packageName}...); err == nil { if out, err := cmd.CombinedOutput(); err != nil { fmt.Printf("error occurred while running rpm -e, output %s: err: %s\n", string(out), err) } diff --git a/ee/consoleuser/consoleuser_darwin.go b/ee/consoleuser/consoleuser_darwin.go index c724e2784..fe1f0ae51 100644 --- a/ee/consoleuser/consoleuser_darwin.go +++ b/ee/consoleuser/consoleuser_darwin.go @@ -11,7 +11,7 @@ import ( "strconv" "strings" - "github.com/kolide/launcher/pkg/allowedpaths" + "github.com/kolide/launcher/pkg/allowedcmd" ) // example scutil output @@ -91,7 +91,7 @@ const ( ) func CurrentUids(ctx context.Context) ([]string, error) { - cmd, err := allowedpaths.Scutil(ctx) + cmd, err := allowedcmd.Scutil(ctx) if err != nil { return nil, fmt.Errorf("creating scutil command: %w", err) } diff --git a/ee/consoleuser/consoleuser_linux.go b/ee/consoleuser/consoleuser_linux.go index e3d6b3ef4..6b36756b5 100644 --- a/ee/consoleuser/consoleuser_linux.go +++ b/ee/consoleuser/consoleuser_linux.go @@ -9,7 +9,7 @@ import ( "fmt" "strings" - "github.com/kolide/launcher/pkg/allowedpaths" + "github.com/kolide/launcher/pkg/allowedcmd" ) type listSessionsResult []struct { @@ -19,7 +19,7 @@ type listSessionsResult []struct { } func CurrentUids(ctx context.Context) ([]string, error) { - cmd, err := allowedpaths.Loginctl(ctx, "list-sessions", "--no-legend", "--no-pager", "--output=json") + cmd, err := allowedcmd.Loginctl(ctx, "list-sessions", "--no-legend", "--no-pager", "--output=json") if err != nil { return nil, fmt.Errorf("creating loginctl command: %w", err) } @@ -47,7 +47,7 @@ func CurrentUids(ctx context.Context) ([]string, error) { } // get the active property of the session, this command does not respect the --output=json flag - cmd, err := allowedpaths.Loginctl(ctx, "show-session", s.Session, "--value", "--property=Active") + cmd, err := allowedcmd.Loginctl(ctx, "show-session", s.Session, "--value", "--property=Active") if err != nil { return nil, fmt.Errorf("creating loginctl command: %w", err) } diff --git a/ee/desktop/runner/runner.go b/ee/desktop/runner/runner.go index c14a240e0..40cc90d0d 100644 --- a/ee/desktop/runner/runner.go +++ b/ee/desktop/runner/runner.go @@ -755,7 +755,7 @@ func (r *DesktopUsersProcessesRunner) menuTemplatePath() string { // desktopCommand invokes the launcher desktop executable with the appropriate env vars func (r *DesktopUsersProcessesRunner) desktopCommand(executablePath, uid, socketPath, menuPath string) (*exec.Cmd, error) { - // We trust that launcher executable path is correct, so we don't need to use allowedpaths + // We trust that launcher executable path is correct, so we don't need to use allowedcmd cmd := exec.Command(executablePath, "desktop") //nolint:forbidigo cmd.Env = []string{ diff --git a/ee/desktop/runner/runner_linux.go b/ee/desktop/runner/runner_linux.go index e8ba5e5d6..188d78ae7 100644 --- a/ee/desktop/runner/runner_linux.go +++ b/ee/desktop/runner/runner_linux.go @@ -16,7 +16,7 @@ import ( "syscall" "github.com/go-kit/kit/log/level" - "github.com/kolide/launcher/pkg/allowedpaths" + "github.com/kolide/launcher/pkg/allowedcmd" "github.com/kolide/launcher/pkg/traces" "github.com/shirou/gopsutil/v3/process" ) @@ -91,7 +91,7 @@ func (r *DesktopUsersProcessesRunner) userEnvVars(ctx context.Context, uid strin } // Get the user's session so we can get their display (needed for opening notification action URLs in browser) - cmd, err := allowedpaths.Loginctl(ctx, "show-user", uid, "--value", "--property=Sessions") + cmd, err := allowedcmd.Loginctl(ctx, "show-user", uid, "--value", "--property=Sessions") if err != nil { level.Debug(r.logger).Log( "msg", "could not create loginctl command", @@ -118,7 +118,7 @@ func (r *DesktopUsersProcessesRunner) userEnvVars(ctx context.Context, uid strin sessionList := strings.Split(sessions, " ") for _, session := range sessionList { // Figure out what type of graphical session the user has -- x11, wayland? - cmd, err := allowedpaths.Loginctl(ctx, "show-session", session, "--value", "--property=Type") + cmd, err := allowedcmd.Loginctl(ctx, "show-session", session, "--value", "--property=Type") if err != nil { level.Debug(r.logger).Log( "msg", "could not create loginctl command to get session type", @@ -166,7 +166,7 @@ func (r *DesktopUsersProcessesRunner) userEnvVars(ctx context.Context, uid strin func (r *DesktopUsersProcessesRunner) displayFromX11(ctx context.Context, session string) string { // We can read $DISPLAY from the session properties - cmd, err := allowedpaths.Loginctl(ctx, "show-session", session, "--value", "--property=Display") + cmd, err := allowedcmd.Loginctl(ctx, "show-session", session, "--value", "--property=Display") if err != nil { level.Debug(r.logger).Log( "msg", "could not create command to get Display from user session", diff --git a/ee/desktop/user/menu/action_open_url_darwin.go b/ee/desktop/user/menu/action_open_url_darwin.go index 316f6bdd0..e5d9236ea 100644 --- a/ee/desktop/user/menu/action_open_url_darwin.go +++ b/ee/desktop/user/menu/action_open_url_darwin.go @@ -7,13 +7,13 @@ import ( "context" "fmt" - "github.com/kolide/launcher/pkg/allowedpaths" + "github.com/kolide/launcher/pkg/allowedcmd" ) // open opens the specified URL in the default browser of the user // See https://stackoverflow.com/a/39324149/1705598 func open(url string) error { - cmd, err := allowedpaths.Open(context.TODO(), url) + cmd, err := allowedcmd.Open(context.TODO(), url) if err != nil { return fmt.Errorf("creating command: %w", err) } diff --git a/ee/desktop/user/menu/action_open_url_linux.go b/ee/desktop/user/menu/action_open_url_linux.go index 1a8a1559a..ffbef3e2a 100644 --- a/ee/desktop/user/menu/action_open_url_linux.go +++ b/ee/desktop/user/menu/action_open_url_linux.go @@ -7,13 +7,13 @@ import ( "context" "fmt" - "github.com/kolide/launcher/pkg/allowedpaths" + "github.com/kolide/launcher/pkg/allowedcmd" ) // open opens the specified URL in the default browser of the user // See https://stackoverflow.com/a/39324149/1705598 func open(url string) error { - cmd, err := allowedpaths.Xdgopen(context.TODO(), url) + cmd, err := allowedcmd.Xdgopen(context.TODO(), url) if err != nil { return fmt.Errorf("creating command: %w", err) } diff --git a/ee/desktop/user/menu/action_open_url_windows.go b/ee/desktop/user/menu/action_open_url_windows.go index 67f2a0071..e668de672 100644 --- a/ee/desktop/user/menu/action_open_url_windows.go +++ b/ee/desktop/user/menu/action_open_url_windows.go @@ -8,13 +8,13 @@ import ( "fmt" "syscall" - "github.com/kolide/launcher/pkg/allowedpaths" + "github.com/kolide/launcher/pkg/allowedcmd" ) // open opens the specified URL in the default browser of the user // See https://stackoverflow.com/a/39324149/1705598 func open(url string) error { - cmd, err := allowedpaths.Commandprompt(context.TODO(), "/C", "start", url) + cmd, err := allowedcmd.Commandprompt(context.TODO(), "/C", "start", url) if err != nil { return fmt.Errorf("creating command: %w", err) } diff --git a/ee/desktop/user/notify/notify_linux.go b/ee/desktop/user/notify/notify_linux.go index 6c799322d..9cc588d82 100644 --- a/ee/desktop/user/notify/notify_linux.go +++ b/ee/desktop/user/notify/notify_linux.go @@ -12,7 +12,7 @@ import ( "github.com/go-kit/kit/log" "github.com/go-kit/kit/log/level" "github.com/godbus/dbus/v5" - "github.com/kolide/launcher/pkg/allowedpaths" + "github.com/kolide/launcher/pkg/allowedcmd" ) type dbusNotifier struct { @@ -33,7 +33,7 @@ const ( // We default to xdg-open first because, if available, it appears to be better at picking // the correct default browser. -var browserLaunchers = []allowedpaths.AllowedCommand{allowedpaths.Xdgopen, allowedpaths.Xwwwbrowser} +var browserLaunchers = []allowedcmd.AllowedCommand{allowedcmd.Xdgopen, allowedcmd.Xwwwbrowser} func NewDesktopNotifier(logger log.Logger, iconFilepath string) *dbusNotifier { conn, err := dbus.ConnectSessionBus() @@ -181,7 +181,7 @@ func (d *dbusNotifier) sendNotificationViaNotifySend(n Notification) error { args = append(args, "-i", d.iconFilepath) } - cmd, err := allowedpaths.Notifysend(context.TODO(), args...) + cmd, err := allowedcmd.Notifysend(context.TODO(), args...) if err != nil { return fmt.Errorf("creating command: %w", err) } diff --git a/pkg/allowedpaths/cmd.go b/pkg/allowedcmd/cmd.go similarity index 98% rename from pkg/allowedpaths/cmd.go rename to pkg/allowedcmd/cmd.go index 9805bf852..c86c4f7b8 100644 --- a/pkg/allowedpaths/cmd.go +++ b/pkg/allowedcmd/cmd.go @@ -1,4 +1,4 @@ -package allowedpaths +package allowedcmd import ( "context" diff --git a/pkg/allowedpaths/cmd_darwin.go b/pkg/allowedcmd/cmd_darwin.go similarity index 99% rename from pkg/allowedpaths/cmd_darwin.go rename to pkg/allowedcmd/cmd_darwin.go index efab3025a..38f5d870a 100644 --- a/pkg/allowedpaths/cmd_darwin.go +++ b/pkg/allowedcmd/cmd_darwin.go @@ -1,7 +1,7 @@ //go:build darwin // +build darwin -package allowedpaths +package allowedcmd import ( "context" diff --git a/pkg/allowedpaths/cmd_linux.go b/pkg/allowedcmd/cmd_linux.go similarity index 99% rename from pkg/allowedpaths/cmd_linux.go rename to pkg/allowedcmd/cmd_linux.go index 2c3ece39a..1b8cfd830 100644 --- a/pkg/allowedpaths/cmd_linux.go +++ b/pkg/allowedcmd/cmd_linux.go @@ -1,7 +1,7 @@ //go:build linux // +build linux -package allowedpaths +package allowedcmd import ( "context" diff --git a/pkg/allowedpaths/cmd_test.go b/pkg/allowedcmd/cmd_test.go similarity index 98% rename from pkg/allowedpaths/cmd_test.go rename to pkg/allowedcmd/cmd_test.go index 8d2590ef0..9f071ba57 100644 --- a/pkg/allowedpaths/cmd_test.go +++ b/pkg/allowedcmd/cmd_test.go @@ -1,4 +1,4 @@ -package allowedpaths +package allowedcmd import ( "context" diff --git a/pkg/allowedpaths/cmd_windows.go b/pkg/allowedcmd/cmd_windows.go similarity index 98% rename from pkg/allowedpaths/cmd_windows.go rename to pkg/allowedcmd/cmd_windows.go index 51d6b9734..58c5af782 100644 --- a/pkg/allowedpaths/cmd_windows.go +++ b/pkg/allowedcmd/cmd_windows.go @@ -1,7 +1,7 @@ //go:build windows // +build windows -package allowedpaths +package allowedcmd import ( "context" diff --git a/pkg/autoupdate/findnew.go b/pkg/autoupdate/findnew.go index 57af49af1..9551ad744 100644 --- a/pkg/autoupdate/findnew.go +++ b/pkg/autoupdate/findnew.go @@ -372,7 +372,7 @@ func CheckExecutable(ctx context.Context, potentialBinary string, args ...string defer cancel() // Since we trust the autoupdate library to find binaries in the correct location, - // we don't require the use of allowedpaths here. + // we don't require the use of allowedcmd here. cmd := exec.CommandContext(ctx, potentialBinary, args...) //nolint:forbidigo // Set env, this should prevent launcher for fork-bombing diff --git a/pkg/dataflatten/testdata/secdata.ini b/pkg/dataflatten/testdata/secdata.ini index 7b653c36e..725f4dc5e 100644 --- a/pkg/dataflatten/testdata/secdata.ini +++ b/pkg/dataflatten/testdata/secdata.ini @@ -66,7 +66,7 @@ MACHINE\System\CurrentControlSet\Control\Lsa\RestrictAnonymous=4,0 MACHINE\System\CurrentControlSet\Control\Lsa\RestrictAnonymousSAM=4,1 MACHINE\System\CurrentControlSet\Control\Print\Providers\LanMan Print Services\Servers\AddPrinterDrivers=4,0 MACHINE\System\CurrentControlSet\Control\SecurePipeServers\Winreg\AllowedExactPaths\Machine=7,System\CurrentControlSet\Control\ProductOptions,System\CurrentControlSet\Control\Server Applications,Software\Microsoft\Windows NT\CurrentVersion -MACHINE\System\CurrentControlSet\Control\SecurePipeServers\Winreg\AllowedPaths\Machine=7,System\CurrentControlSet\Control\Print\Printers,System\CurrentControlSet\Services\Eventlog,Software\Microsoft\OLAP Server,Software\Microsoft\Windows NT\CurrentVersion\Print,Software\Microsoft\Windows NT\CurrentVersion\Windows,System\CurrentControlSet\Control\ContentIndex,System\CurrentControlSet\Control\Terminal Server,System\CurrentControlSet\Control\Terminal Server\UserConfig,System\CurrentControlSet\Control\Terminal Server\DefaultUserConfiguration,Software\Microsoft\Windows NT\CurrentVersion\Perflib,System\CurrentControlSet\Services\SysmonLog +MACHINE\System\CurrentControlSet\Control\SecurePipeServers\Winreg\allowedcmd\Machine=7,System\CurrentControlSet\Control\Print\Printers,System\CurrentControlSet\Services\Eventlog,Software\Microsoft\OLAP Server,Software\Microsoft\Windows NT\CurrentVersion\Print,Software\Microsoft\Windows NT\CurrentVersion\Windows,System\CurrentControlSet\Control\ContentIndex,System\CurrentControlSet\Control\Terminal Server,System\CurrentControlSet\Control\Terminal Server\UserConfig,System\CurrentControlSet\Control\Terminal Server\DefaultUserConfiguration,Software\Microsoft\Windows NT\CurrentVersion\Perflib,System\CurrentControlSet\Services\SysmonLog MACHINE\System\CurrentControlSet\Control\Session Manager\Kernel\ObCaseInsensitive=4,1 MACHINE\System\CurrentControlSet\Control\Session Manager\Memory Management\ClearPageFileAtShutdown=4,0 MACHINE\System\CurrentControlSet\Control\Session Manager\ProtectionMode=4,1 diff --git a/pkg/debug/checkups/gnome_extensions_linux.go b/pkg/debug/checkups/gnome_extensions_linux.go index 7095177ca..eade396a5 100644 --- a/pkg/debug/checkups/gnome_extensions_linux.go +++ b/pkg/debug/checkups/gnome_extensions_linux.go @@ -13,7 +13,7 @@ import ( "strings" "time" - "github.com/kolide/launcher/pkg/allowedpaths" + "github.com/kolide/launcher/pkg/allowedcmd" ) type gnomeExtensions struct { @@ -93,7 +93,7 @@ func execGnomeExtension(ctx context.Context, extraWriter io.Writer, rundir strin // pkg/osquery/tables/gsettings/gsettings.go probably has appropriate prior art. // But do we really want the forloop? - cmd, err := allowedpaths.Gnomeextensions(ctx, args...) + cmd, err := allowedcmd.Gnomeextensions(ctx, args...) if err != nil { return nil, fmt.Errorf("creating gnome-extensions command: %w", err) } diff --git a/pkg/debug/checkups/launchd_darwin.go b/pkg/debug/checkups/launchd_darwin.go index 867331498..e8bfa1255 100644 --- a/pkg/debug/checkups/launchd_darwin.go +++ b/pkg/debug/checkups/launchd_darwin.go @@ -13,7 +13,7 @@ import ( "path/filepath" "strings" - "github.com/kolide/launcher/pkg/allowedpaths" + "github.com/kolide/launcher/pkg/allowedcmd" ) const ( @@ -63,7 +63,7 @@ func (c *launchdCheckup) Run(ctx context.Context, extraWriter io.Writer) error { // run launchctl to check status var printOut bytes.Buffer - cmd, err := allowedpaths.Launchctl(ctx, "print", launchdServiceName) + cmd, err := allowedcmd.Launchctl(ctx, "print", launchdServiceName) if err != nil { c.status = Erroring c.summary = fmt.Sprintf("unable to create launchctl command: %s", err) diff --git a/pkg/debug/checkups/network.go b/pkg/debug/checkups/network.go index 06b0f0aa6..a2da238ef 100644 --- a/pkg/debug/checkups/network.go +++ b/pkg/debug/checkups/network.go @@ -8,7 +8,7 @@ import ( "net" "time" - "github.com/kolide/launcher/pkg/allowedpaths" + "github.com/kolide/launcher/pkg/allowedcmd" ) type networkCheckup struct { @@ -82,6 +82,6 @@ func (n *networkCheckup) Data() any { } type networkCommand struct { - cmd allowedpaths.AllowedCommand + cmd allowedcmd.AllowedCommand args []string } diff --git a/pkg/debug/checkups/network_darwin.go b/pkg/debug/checkups/network_darwin.go index e8dccd020..a61ef6d6f 100644 --- a/pkg/debug/checkups/network_darwin.go +++ b/pkg/debug/checkups/network_darwin.go @@ -3,16 +3,16 @@ package checkups -import "github.com/kolide/launcher/pkg/allowedpaths" +import "github.com/kolide/launcher/pkg/allowedcmd" func listCommands() []networkCommand { return []networkCommand{ { - cmd: allowedpaths.Ifconfig, + cmd: allowedcmd.Ifconfig, args: []string{"-a"}, }, { - cmd: allowedpaths.Netstat, + cmd: allowedcmd.Netstat, args: []string{"-nr"}, }, } diff --git a/pkg/debug/checkups/network_linux.go b/pkg/debug/checkups/network_linux.go index 77f91bdd2..fd7654467 100644 --- a/pkg/debug/checkups/network_linux.go +++ b/pkg/debug/checkups/network_linux.go @@ -3,20 +3,20 @@ package checkups -import "github.com/kolide/launcher/pkg/allowedpaths" +import "github.com/kolide/launcher/pkg/allowedcmd" func listCommands() []networkCommand { return []networkCommand{ { - cmd: allowedpaths.Ifconfig, + cmd: allowedcmd.Ifconfig, args: []string{"-a"}, }, { - cmd: allowedpaths.Ip, + cmd: allowedcmd.Ip, args: []string{"-N", "-d", "-h", "-a", "address"}, }, { - cmd: allowedpaths.Ip, + cmd: allowedcmd.Ip, args: []string{"-N", "-d", "-h", "-a", "route"}, }, } diff --git a/pkg/debug/checkups/network_windows.go b/pkg/debug/checkups/network_windows.go index a6e970c85..996c8b3e7 100644 --- a/pkg/debug/checkups/network_windows.go +++ b/pkg/debug/checkups/network_windows.go @@ -3,12 +3,12 @@ package checkups -import "github.com/kolide/launcher/pkg/allowedpaths" +import "github.com/kolide/launcher/pkg/allowedcmd" func listCommands() []networkCommand { return []networkCommand{ { - cmd: allowedpaths.Ipconfig, + cmd: allowedcmd.Ipconfig, args: []string{"/all"}, }, } diff --git a/pkg/debug/checkups/power_windows.go b/pkg/debug/checkups/power_windows.go index 7afc05e65..cc31608a2 100644 --- a/pkg/debug/checkups/power_windows.go +++ b/pkg/debug/checkups/power_windows.go @@ -10,7 +10,7 @@ import ( "os" "github.com/kolide/launcher/pkg/agent" - "github.com/kolide/launcher/pkg/allowedpaths" + "github.com/kolide/launcher/pkg/allowedcmd" ) type powerCheckup struct{} @@ -25,7 +25,7 @@ func (p *powerCheckup) Run(ctx context.Context, extraWriter io.Writer) error { defer os.Remove(tmpFilePath) // See: https://learn.microsoft.com/en-us/windows-hardware/design/device-experiences/powercfg-command-line-options#option_systempowerreport - powerCfgCmd, err := allowedpaths.Powercfg(ctx, "/systempowerreport", "/output", tmpFilePath) + powerCfgCmd, err := allowedcmd.Powercfg(ctx, "/systempowerreport", "/output", tmpFilePath) if err != nil { return fmt.Errorf("creating powercfg command: %w", err) } diff --git a/pkg/debug/checkups/services_windows.go b/pkg/debug/checkups/services_windows.go index 6509b8068..a971ce2de 100644 --- a/pkg/debug/checkups/services_windows.go +++ b/pkg/debug/checkups/services_windows.go @@ -10,7 +10,7 @@ import ( "fmt" "io" - "github.com/kolide/launcher/pkg/allowedpaths" + "github.com/kolide/launcher/pkg/allowedcmd" "golang.org/x/sys/windows" "golang.org/x/sys/windows/svc" "golang.org/x/sys/windows/svc/mgr" @@ -244,7 +244,7 @@ func gatherServiceManagerEventLogs(ctx context.Context, z *zip.Writer) error { "Format-Table", "-Wrap", "-AutoSize", // ensure output doesn't get truncated } - getEventLogCmd, err := allowedpaths.Powershell(ctx, cmdletArgs...) + getEventLogCmd, err := allowedcmd.Powershell(ctx, cmdletArgs...) if err != nil { return fmt.Errorf("creating powershell command: %w", err) } diff --git a/pkg/log/log_posix.go b/pkg/log/log_posix.go index ef4786780..412676523 100644 --- a/pkg/log/log_posix.go +++ b/pkg/log/log_posix.go @@ -9,7 +9,7 @@ import ( "time" "github.com/go-kit/kit/log/level" - "github.com/kolide/launcher/pkg/allowedpaths" + "github.com/kolide/launcher/pkg/allowedcmd" ) // runAndLogPs runs ps filtering on the given PID, and logs the output. @@ -17,7 +17,7 @@ func (l *OsqueryLogAdapter) runAndLogPs(pidStr string) { ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second) defer cancel() - cmd, err := allowedpaths.Ps(ctx, "-p", pidStr, "-o", "user,pid,ppid,pgid,stat,time,command") + cmd, err := allowedcmd.Ps(ctx, "-p", pidStr, "-o", "user,pid,ppid,pgid,stat,time,command") if err != nil { level.Debug(l.logger).Log( "msg", "error creating command to run ps on osqueryd pidfile", @@ -47,7 +47,7 @@ func (l *OsqueryLogAdapter) runAndLogLsofByPID(pidStr string) { ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second) defer cancel() - cmd, err := allowedpaths.Lsof(ctx, "-R", "-n", "-p", pidStr) + cmd, err := allowedcmd.Lsof(ctx, "-R", "-n", "-p", pidStr) if err != nil { level.Debug(l.logger).Log( "msg", "error creating command to run lsof on osqueryd pidfile", @@ -80,7 +80,7 @@ func (l *OsqueryLogAdapter) runAndLogLsofOnPidfile() { ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second) defer cancel() - cmd, err := allowedpaths.Lsof(ctx, "-R", "-n", fullPidfile) + cmd, err := allowedcmd.Lsof(ctx, "-R", "-n", fullPidfile) if err != nil { level.Debug(l.logger).Log( "msg", "error creating command to run lsof on osqueryd pidfile", diff --git a/pkg/osquery/runtime/osqueryinstance.go b/pkg/osquery/runtime/osqueryinstance.go index d7d059f9d..680428978 100644 --- a/pkg/osquery/runtime/osqueryinstance.go +++ b/pkg/osquery/runtime/osqueryinstance.go @@ -481,7 +481,7 @@ func (opts *osqueryOptions) createOsquerydCommand(osquerydBinary string, paths * args = append(args, "--disable_watchdog") } // Since we trust the autoupdate library to find binaries in the correct location, - // we don't require the use of allowedpaths here. + // we don't require the use of allowedcmd here. cmd := exec.Command( //nolint:forbidigo osquerydBinary, args..., diff --git a/pkg/osquery/runtime/runtime_helpers_windows.go b/pkg/osquery/runtime/runtime_helpers_windows.go index 1963abe6f..9c82c52e7 100644 --- a/pkg/osquery/runtime/runtime_helpers_windows.go +++ b/pkg/osquery/runtime/runtime_helpers_windows.go @@ -10,7 +10,7 @@ import ( "syscall" "github.com/kolide/kit/ulid" - "github.com/kolide/launcher/pkg/allowedpaths" + "github.com/kolide/launcher/pkg/allowedcmd" "github.com/pkg/errors" ) @@ -23,7 +23,7 @@ func setpgid() *syscall.SysProcAttr { func killProcessGroup(cmd *exec.Cmd) error { // some discussion here https://github.com/golang/dep/pull/857 // TODO: should we check err? - cmd, err := allowedpaths.Taskkill(context.TODO(), "/F", "/T", "/PID", fmt.Sprint(cmd.Process.Pid)) + cmd, err := allowedcmd.Taskkill(context.TODO(), "/F", "/T", "/PID", fmt.Sprint(cmd.Process.Pid)) if err != nil { return fmt.Errorf("creating command: %w", err) } diff --git a/pkg/osquery/table/mdfind_darwin.go b/pkg/osquery/table/mdfind_darwin.go index 408eec4d5..b71417a6c 100644 --- a/pkg/osquery/table/mdfind_darwin.go +++ b/pkg/osquery/table/mdfind_darwin.go @@ -11,14 +11,14 @@ import ( "io" "time" - "github.com/kolide/launcher/pkg/allowedpaths" + "github.com/kolide/launcher/pkg/allowedcmd" ) func mdfind(args ...string) ([]string, error) { ctx, cancel := context.WithTimeout(context.Background(), 60*time.Second) defer cancel() - cmd, err := allowedpaths.Mdfind(ctx, args...) + cmd, err := allowedcmd.Mdfind(ctx, args...) if err != nil { return nil, fmt.Errorf("creating mdfind command: %w", err) } diff --git a/pkg/osquery/table/mdm.go b/pkg/osquery/table/mdm.go index a94f0881b..65a8920d7 100644 --- a/pkg/osquery/table/mdm.go +++ b/pkg/osquery/table/mdm.go @@ -12,7 +12,7 @@ import ( "github.com/go-kit/kit/log" "github.com/groob/plist" - "github.com/kolide/launcher/pkg/allowedpaths" + "github.com/kolide/launcher/pkg/allowedcmd" "github.com/osquery/osquery-go/plugin/table" ) @@ -92,7 +92,7 @@ func getMDMProfile(ctx context.Context) (*profilesOutput, error) { ctx, cancel := context.WithTimeout(ctx, 10*time.Second) defer cancel() - cmd, err := allowedpaths.Profiles(ctx, "-L", "-o", "stdout-xml") + cmd, err := allowedcmd.Profiles(ctx, "-L", "-o", "stdout-xml") if err != nil { return nil, fmt.Errorf("creating profiles command: %w", err) } @@ -138,7 +138,7 @@ func getMDMProfileStatus(ctx context.Context) (profileStatus, error) { ctx, cancel := context.WithTimeout(ctx, 10*time.Second) defer cancel() - cmd, err := allowedpaths.Profiles(ctx, "status", "-type", "enrollment") + cmd, err := allowedcmd.Profiles(ctx, "status", "-type", "enrollment") if err != nil { return profileStatus{}, fmt.Errorf("creating profiles command: %w", err) } diff --git a/pkg/osquery/table/platform_tables_darwin.go b/pkg/osquery/table/platform_tables_darwin.go index 6ab620d3c..d6522213b 100644 --- a/pkg/osquery/table/platform_tables_darwin.go +++ b/pkg/osquery/table/platform_tables_darwin.go @@ -7,7 +7,7 @@ import ( "github.com/go-kit/kit/log" "github.com/knightsc/system_policy/osquery/table/kextpolicy" "github.com/knightsc/system_policy/osquery/table/legacyexec" - "github.com/kolide/launcher/pkg/allowedpaths" + "github.com/kolide/launcher/pkg/allowedcmd" "github.com/kolide/launcher/pkg/osquery/tables/airport" appicons "github.com/kolide/launcher/pkg/osquery/tables/app-icons" "github.com/kolide/launcher/pkg/osquery/tables/apple_silicon_security_policy" @@ -101,26 +101,26 @@ func platformTables(logger log.Logger, currentOsquerydBinaryPath string) []osque apple_silicon_security_policy.TablePlugin(logger), legacyexec.TablePlugin(), dataflattentable.TablePluginExec(logger, - "kolide_diskutil_list", dataflattentable.PlistType, allowedpaths.Diskutil, []string{"list", "-plist"}), + "kolide_diskutil_list", dataflattentable.PlistType, allowedcmd.Diskutil, []string{"list", "-plist"}), dataflattentable.TablePluginExec(logger, - "kolide_falconctl_stats", dataflattentable.PlistType, allowedpaths.Falconctl, []string{"stats", "-p"}), + "kolide_falconctl_stats", dataflattentable.PlistType, allowedcmd.Falconctl, []string{"stats", "-p"}), dataflattentable.TablePluginExec(logger, - "kolide_apfs_list", dataflattentable.PlistType, allowedpaths.Diskutil, []string{"apfs", "list", "-plist"}), + "kolide_apfs_list", dataflattentable.PlistType, allowedcmd.Diskutil, []string{"apfs", "list", "-plist"}), dataflattentable.TablePluginExec(logger, - "kolide_apfs_users", dataflattentable.PlistType, allowedpaths.Diskutil, []string{"apfs", "listUsers", "/", "-plist"}), + "kolide_apfs_users", dataflattentable.PlistType, allowedcmd.Diskutil, []string{"apfs", "listUsers", "/", "-plist"}), dataflattentable.TablePluginExec(logger, - "kolide_tmutil_destinationinfo", dataflattentable.PlistType, allowedpaths.Tmutil, []string{"destinationinfo", "-X"}), + "kolide_tmutil_destinationinfo", dataflattentable.PlistType, allowedcmd.Tmutil, []string{"destinationinfo", "-X"}), dataflattentable.TablePluginExec(logger, - "kolide_powermetrics", dataflattentable.PlistType, allowedpaths.Powermetrics, []string{"-n", "1", "-f", "plist"}), + "kolide_powermetrics", dataflattentable.PlistType, allowedcmd.Powermetrics, []string{"-n", "1", "-f", "plist"}), screenlockTable, pwpolicy.TablePlugin(logger), systemprofiler.TablePlugin(logger), munki.ManagedInstalls(logger), munki.MunkiReport(logger), - dataflattentable.NewExecAndParseTable(logger, "kolide_remotectl", remotectl.Parser, allowedpaths.Remotectl, []string{`dumpstate`}), - dataflattentable.NewExecAndParseTable(logger, "kolide_softwareupdate", softwareupdate.Parser, allowedpaths.Softwareupdate, []string{`--list`, `--no-scan`}, dataflattentable.WithIncludeStderr()), - dataflattentable.NewExecAndParseTable(logger, "kolide_softwareupdate_scan", softwareupdate.Parser, allowedpaths.Softwareupdate, []string{`--list`}, dataflattentable.WithIncludeStderr()), - dataflattentable.NewExecAndParseTable(logger, "kolide_carbonblack_repcli_status", repcli.Parser, allowedpaths.Repcli, []string{"status"}, dataflattentable.WithIncludeStderr()), + dataflattentable.NewExecAndParseTable(logger, "kolide_remotectl", remotectl.Parser, allowedcmd.Remotectl, []string{`dumpstate`}), + dataflattentable.NewExecAndParseTable(logger, "kolide_softwareupdate", softwareupdate.Parser, allowedcmd.Softwareupdate, []string{`--list`, `--no-scan`}, dataflattentable.WithIncludeStderr()), + dataflattentable.NewExecAndParseTable(logger, "kolide_softwareupdate_scan", softwareupdate.Parser, allowedcmd.Softwareupdate, []string{`--list`}, dataflattentable.WithIncludeStderr()), + dataflattentable.NewExecAndParseTable(logger, "kolide_carbonblack_repcli_status", repcli.Parser, allowedcmd.Repcli, []string{"status"}, dataflattentable.WithIncludeStderr()), zfs.ZfsPropertiesPlugin(logger), zfs.ZpoolPropertiesPlugin(logger), } diff --git a/pkg/osquery/table/platform_tables_linux.go b/pkg/osquery/table/platform_tables_linux.go index dc8ef7443..a55f5a1cb 100644 --- a/pkg/osquery/table/platform_tables_linux.go +++ b/pkg/osquery/table/platform_tables_linux.go @@ -5,7 +5,7 @@ package table import ( "github.com/go-kit/kit/log" - "github.com/kolide/launcher/pkg/allowedpaths" + "github.com/kolide/launcher/pkg/allowedcmd" "github.com/kolide/launcher/pkg/osquery/tables/crowdstrike/falcon_kernel_check" "github.com/kolide/launcher/pkg/osquery/tables/crowdstrike/falconctl" "github.com/kolide/launcher/pkg/osquery/tables/cryptsetup" @@ -42,21 +42,21 @@ func platformTables(logger log.Logger, currentOsquerydBinaryPath string) []osque dataflattentable.TablePluginExec(logger, "kolide_nmcli_wifi", dataflattentable.KeyValueType, - allowedpaths.Nmcli, + allowedcmd.Nmcli, []string{"--mode=multiline", "--fields=all", "device", "wifi", "list"}, dataflattentable.WithKVSeparator(":")), dataflattentable.TablePluginExec(logger, "kolide_lsblk", dataflattentable.JsonType, - allowedpaths.Lsblk, []string{"-J"}, + allowedcmd.Lsblk, []string{"-J"}, ), - dataflattentable.NewExecAndParseTable(logger, "kolide_falconctl_systags", simple_array.New("systags"), allowedpaths.Falconctl, []string{"-g", "--systags"}), - dataflattentable.NewExecAndParseTable(logger, "kolide_apt_upgradeable", apt.Parser, allowedpaths.Apt, []string{"list", "--upgradeable"}, dataflattentable.WithIncludeStderr()), - dataflattentable.NewExecAndParseTable(logger, "kolide_dnf_upgradeable", dnf.Parser, allowedpaths.Dnf, []string{"check-update"}, dataflattentable.WithIncludeStderr()), - dataflattentable.NewExecAndParseTable(logger, "kolide_dpkg_version_info", dpkg.Parser, allowedpaths.Dpkg, []string{"-p"}, dataflattentable.WithIncludeStderr()), - dataflattentable.NewExecAndParseTable(logger, "kolide_pacman_group", pacman_group.Parser, allowedpaths.Pacman, []string{"-Qg"}, dataflattentable.WithIncludeStderr()), - dataflattentable.NewExecAndParseTable(logger, "kolide_pacman_version_info", pacman_info.Parser, allowedpaths.Pacman, []string{"-Qi"}, dataflattentable.WithIncludeStderr()), - dataflattentable.NewExecAndParseTable(logger, "kolide_pacman_upgradeable", pacman_upgradeable.Parser, allowedpaths.Pacman, []string{"-Qu"}, dataflattentable.WithIncludeStderr()), - dataflattentable.NewExecAndParseTable(logger, "kolide_rpm_version_info", rpm.Parser, allowedpaths.Rpm, []string{"-qai"}, dataflattentable.WithIncludeStderr()), - dataflattentable.NewExecAndParseTable(logger, "kolide_carbonblack_repcli_status", repcli.Parser, allowedpaths.Repcli, []string{"status"}, dataflattentable.WithIncludeStderr()), + dataflattentable.NewExecAndParseTable(logger, "kolide_falconctl_systags", simple_array.New("systags"), allowedcmd.Falconctl, []string{"-g", "--systags"}), + dataflattentable.NewExecAndParseTable(logger, "kolide_apt_upgradeable", apt.Parser, allowedcmd.Apt, []string{"list", "--upgradeable"}, dataflattentable.WithIncludeStderr()), + dataflattentable.NewExecAndParseTable(logger, "kolide_dnf_upgradeable", dnf.Parser, allowedcmd.Dnf, []string{"check-update"}, dataflattentable.WithIncludeStderr()), + dataflattentable.NewExecAndParseTable(logger, "kolide_dpkg_version_info", dpkg.Parser, allowedcmd.Dpkg, []string{"-p"}, dataflattentable.WithIncludeStderr()), + dataflattentable.NewExecAndParseTable(logger, "kolide_pacman_group", pacman_group.Parser, allowedcmd.Pacman, []string{"-Qg"}, dataflattentable.WithIncludeStderr()), + dataflattentable.NewExecAndParseTable(logger, "kolide_pacman_version_info", pacman_info.Parser, allowedcmd.Pacman, []string{"-Qi"}, dataflattentable.WithIncludeStderr()), + dataflattentable.NewExecAndParseTable(logger, "kolide_pacman_upgradeable", pacman_upgradeable.Parser, allowedcmd.Pacman, []string{"-Qu"}, dataflattentable.WithIncludeStderr()), + dataflattentable.NewExecAndParseTable(logger, "kolide_rpm_version_info", rpm.Parser, allowedcmd.Rpm, []string{"-qai"}, dataflattentable.WithIncludeStderr()), + dataflattentable.NewExecAndParseTable(logger, "kolide_carbonblack_repcli_status", repcli.Parser, allowedcmd.Repcli, []string{"status"}, dataflattentable.WithIncludeStderr()), zfs.ZfsPropertiesPlugin(logger), zfs.ZpoolPropertiesPlugin(logger), } diff --git a/pkg/osquery/table/platform_tables_windows.go b/pkg/osquery/table/platform_tables_windows.go index 11f2d86f6..4d2289600 100644 --- a/pkg/osquery/table/platform_tables_windows.go +++ b/pkg/osquery/table/platform_tables_windows.go @@ -4,7 +4,7 @@ package table import ( - "github.com/kolide/launcher/pkg/allowedpaths" + "github.com/kolide/launcher/pkg/allowedcmd" "github.com/kolide/launcher/pkg/osquery/tables/dataflattentable" "github.com/kolide/launcher/pkg/osquery/tables/dsim_default_associations" "github.com/kolide/launcher/pkg/osquery/tables/execparsers/dsregcmd" @@ -26,6 +26,6 @@ func platformTables(logger log.Logger, currentOsquerydBinaryPath string) []osque windowsupdatetable.TablePlugin(windowsupdatetable.UpdatesTable, logger), windowsupdatetable.TablePlugin(windowsupdatetable.HistoryTable, logger), wmitable.TablePlugin(logger), - dataflattentable.NewExecAndParseTable(logger, "kolide_dsregcmd", dsregcmd.Parser, allowedpaths.Dsregcmd, []string{`/status`}), + dataflattentable.NewExecAndParseTable(logger, "kolide_dsregcmd", dsregcmd.Parser, allowedcmd.Dsregcmd, []string{`/status`}), } } diff --git a/pkg/osquery/table/table.go b/pkg/osquery/table/table.go index e78e9ffe8..c012487d0 100644 --- a/pkg/osquery/table/table.go +++ b/pkg/osquery/table/table.go @@ -2,7 +2,7 @@ package table import ( "github.com/kolide/launcher/pkg/agent/types" - "github.com/kolide/launcher/pkg/allowedpaths" + "github.com/kolide/launcher/pkg/allowedcmd" "github.com/kolide/launcher/pkg/osquery/tables/cryptoinfotable" "github.com/kolide/launcher/pkg/osquery/tables/dataflattentable" "github.com/kolide/launcher/pkg/osquery/tables/desktopprocs" @@ -48,11 +48,11 @@ func PlatformTables(logger log.Logger, currentOsquerydBinaryPath string) []osque dev_table_tooling.TablePlugin(logger), firefox_preferences.TablePlugin(logger), dataflattentable.TablePluginExec(logger, - "kolide_zerotier_info", dataflattentable.JsonType, allowedpaths.Zerotiercli, []string{"info"}), + "kolide_zerotier_info", dataflattentable.JsonType, allowedcmd.Zerotiercli, []string{"info"}), dataflattentable.TablePluginExec(logger, - "kolide_zerotier_networks", dataflattentable.JsonType, allowedpaths.Zerotiercli, []string{"listnetworks"}), + "kolide_zerotier_networks", dataflattentable.JsonType, allowedcmd.Zerotiercli, []string{"listnetworks"}), dataflattentable.TablePluginExec(logger, - "kolide_zerotier_peers", dataflattentable.JsonType, allowedpaths.Zerotiercli, []string{"listpeers"}), + "kolide_zerotier_peers", dataflattentable.JsonType, allowedcmd.Zerotiercli, []string{"listpeers"}), tdebug.LauncherGcInfo(logger), } diff --git a/pkg/osquery/table/touchid_system_darwin.go b/pkg/osquery/table/touchid_system_darwin.go index 5b1518cfa..4cb4e2805 100644 --- a/pkg/osquery/table/touchid_system_darwin.go +++ b/pkg/osquery/table/touchid_system_darwin.go @@ -9,7 +9,7 @@ import ( "time" "github.com/go-kit/kit/log" - "github.com/kolide/launcher/pkg/allowedpaths" + "github.com/kolide/launcher/pkg/allowedcmd" "github.com/osquery/osquery-go/plugin/table" ) @@ -41,7 +41,7 @@ func (t *touchIDSystemConfigTable) generate(ctx context.Context, queryContext ta // Read the security chip from system_profiler var stdout bytes.Buffer - cmd, err := allowedpaths.Systemprofiler(ctx, "SPiBridgeDataType") + cmd, err := allowedcmd.Systemprofiler(ctx, "SPiBridgeDataType") if err != nil { return nil, fmt.Errorf("creating system_profiler command: %w", err) } @@ -60,7 +60,7 @@ func (t *touchIDSystemConfigTable) generate(ctx context.Context, queryContext ta // Read the system's bioutil configuration stdout.Reset() - cmd, err = allowedpaths.Bioutil(ctx, "-r", "-s") + cmd, err = allowedcmd.Bioutil(ctx, "-r", "-s") if err != nil { return nil, fmt.Errorf("creating bioutil command: %w", err) } diff --git a/pkg/osquery/table/touchid_user_darwin.go b/pkg/osquery/table/touchid_user_darwin.go index 9674944be..9818ff3ae 100644 --- a/pkg/osquery/table/touchid_user_darwin.go +++ b/pkg/osquery/table/touchid_user_darwin.go @@ -13,7 +13,7 @@ import ( "github.com/go-kit/kit/log" "github.com/go-kit/kit/log/level" - "github.com/kolide/launcher/pkg/allowedpaths" + "github.com/kolide/launcher/pkg/allowedcmd" "github.com/osquery/osquery-go/plugin/table" ) @@ -65,7 +65,7 @@ func (t *touchIDUserConfigTable) generate(ctx context.Context, queryContext tabl uid, _ := strconv.Atoi(constraint.Expression) // Get the user's TouchID config - configOutput, err := runCommandContext(ctx, uid, allowedpaths.Bioutil, "-r") + configOutput, err := runCommandContext(ctx, uid, allowedcmd.Bioutil, "-r") if err != nil { level.Debug(t.logger).Log( "msg", "could not run bioutil -r", @@ -95,7 +95,7 @@ func (t *touchIDUserConfigTable) generate(ctx context.Context, queryContext tabl } // Grab the fingerprint count - countOutStr, err := runCommandContext(ctx, uid, allowedpaths.Bioutil, "-c") + countOutStr, err := runCommandContext(ctx, uid, allowedcmd.Bioutil, "-c") if err != nil { level.Debug(t.logger).Log( "msg", "could not run bioutil -c", @@ -129,7 +129,7 @@ func (t *touchIDUserConfigTable) generate(ctx context.Context, queryContext tabl } // runCommand runs a given command and arguments as the supplied user -func runCommandContext(ctx context.Context, uid int, cmd allowedpaths.AllowedCommand, args ...string) (string, error) { +func runCommandContext(ctx context.Context, uid int, cmd allowedcmd.AllowedCommand, args ...string) (string, error) { ctx, cancel := context.WithTimeout(ctx, 10*time.Second) defer cancel() diff --git a/pkg/osquery/tables/airport/table_darwin.go b/pkg/osquery/tables/airport/table_darwin.go index e9bae95cc..5f2cb579c 100644 --- a/pkg/osquery/tables/airport/table_darwin.go +++ b/pkg/osquery/tables/airport/table_darwin.go @@ -13,7 +13,7 @@ import ( "github.com/go-kit/kit/log" "github.com/go-kit/kit/log/level" - "github.com/kolide/launcher/pkg/allowedpaths" + "github.com/kolide/launcher/pkg/allowedcmd" "github.com/kolide/launcher/pkg/dataflatten" "github.com/kolide/launcher/pkg/osquery/tables/dataflattentable" "github.com/kolide/launcher/pkg/osquery/tables/tablehelpers" @@ -50,7 +50,7 @@ type airportExecutor struct { } func (a *airportExecutor) Exec(option string) ([]byte, error) { - return tablehelpers.Exec(a.ctx, a.logger, 30, allowedpaths.Airport, []string{"--" + option}, false) + return tablehelpers.Exec(a.ctx, a.logger, 30, allowedcmd.Airport, []string{"--" + option}, false) } type executor interface { diff --git a/pkg/osquery/tables/apple_silicon_security_policy/table.go b/pkg/osquery/tables/apple_silicon_security_policy/table.go index 4b118c9d0..017300d29 100644 --- a/pkg/osquery/tables/apple_silicon_security_policy/table.go +++ b/pkg/osquery/tables/apple_silicon_security_policy/table.go @@ -10,7 +10,7 @@ import ( "github.com/go-kit/kit/log" "github.com/go-kit/kit/log/level" - "github.com/kolide/launcher/pkg/allowedpaths" + "github.com/kolide/launcher/pkg/allowedcmd" "github.com/kolide/launcher/pkg/dataflatten" "github.com/kolide/launcher/pkg/osquery/tables/dataflattentable" "github.com/kolide/launcher/pkg/osquery/tables/tablehelpers" @@ -38,7 +38,7 @@ func TablePlugin(logger log.Logger) *table.Plugin { func (t *Table) generate(ctx context.Context, queryContext table.QueryContext) ([]map[string]string, error) { var results []map[string]string - output, err := tablehelpers.Exec(ctx, t.logger, 30, allowedpaths.Bputil, []string{bootPolicyUtilArgs}, false) + output, err := tablehelpers.Exec(ctx, t.logger, 30, allowedcmd.Bputil, []string{bootPolicyUtilArgs}, false) if err != nil { level.Info(t.logger).Log("msg", "bputil failed", "err", err) return nil, nil diff --git a/pkg/osquery/tables/crowdstrike/falcon_kernel_check/table.go b/pkg/osquery/tables/crowdstrike/falcon_kernel_check/table.go index 79f8f7a9f..9779d4dc5 100644 --- a/pkg/osquery/tables/crowdstrike/falcon_kernel_check/table.go +++ b/pkg/osquery/tables/crowdstrike/falcon_kernel_check/table.go @@ -10,7 +10,7 @@ import ( "github.com/go-kit/kit/log" "github.com/go-kit/kit/log/level" - "github.com/kolide/launcher/pkg/allowedpaths" + "github.com/kolide/launcher/pkg/allowedcmd" "github.com/kolide/launcher/pkg/osquery/tables/tablehelpers" "github.com/osquery/osquery-go/plugin/table" ) @@ -36,7 +36,7 @@ func TablePlugin(logger log.Logger) *table.Plugin { } func (t *Table) generate(ctx context.Context, queryContext table.QueryContext) ([]map[string]string, error) { - output, err := tablehelpers.Exec(ctx, t.logger, 5, allowedpaths.Falconkernelcheck, []string{}, false) + output, err := tablehelpers.Exec(ctx, t.logger, 5, allowedcmd.Falconkernelcheck, []string{}, false) if err != nil { level.Info(t.logger).Log("msg", "exec failed", "err", err) return nil, err diff --git a/pkg/osquery/tables/crowdstrike/falconctl/table.go b/pkg/osquery/tables/crowdstrike/falconctl/table.go index adab701a1..11acfae1e 100644 --- a/pkg/osquery/tables/crowdstrike/falconctl/table.go +++ b/pkg/osquery/tables/crowdstrike/falconctl/table.go @@ -11,7 +11,7 @@ import ( "github.com/go-kit/kit/log" "github.com/go-kit/kit/log/level" - "github.com/kolide/launcher/pkg/allowedpaths" + "github.com/kolide/launcher/pkg/allowedcmd" "github.com/kolide/launcher/pkg/dataflatten" "github.com/kolide/launcher/pkg/osquery/tables/dataflattentable" "github.com/kolide/launcher/pkg/osquery/tables/tablehelpers" @@ -38,7 +38,7 @@ var ( defaultOption = strings.Join(allowedOptions, " ") ) -type execFunc func(context.Context, log.Logger, int, allowedpaths.AllowedCommand, []string, bool) ([]byte, error) +type execFunc func(context.Context, log.Logger, int, allowedcmd.AllowedCommand, []string, bool) ([]byte, error) type falconctlOptionsTable struct { logger log.Logger @@ -89,7 +89,7 @@ OUTER: // then the list of options to fetch. Set the command line thusly. args := append([]string{"-g"}, options...) - output, err := t.execFunc(ctx, t.logger, 30, allowedpaths.Falconctl, args, false) + output, err := t.execFunc(ctx, t.logger, 30, allowedcmd.Falconctl, args, false) if err != nil { level.Info(t.logger).Log("msg", "exec failed", "err", err) synthesizedData := map[string]string{ diff --git a/pkg/osquery/tables/crowdstrike/falconctl/table_test.go b/pkg/osquery/tables/crowdstrike/falconctl/table_test.go index ce5abcc60..81c6b7421 100644 --- a/pkg/osquery/tables/crowdstrike/falconctl/table_test.go +++ b/pkg/osquery/tables/crowdstrike/falconctl/table_test.go @@ -10,7 +10,7 @@ import ( "testing" "github.com/go-kit/kit/log" - "github.com/kolide/launcher/pkg/allowedpaths" + "github.com/kolide/launcher/pkg/allowedcmd" "github.com/kolide/launcher/pkg/osquery/tables/tablehelpers" "github.com/stretchr/testify/require" ) @@ -85,7 +85,7 @@ func TestOptionRestrictions(t *testing.T) { } } -func noopExec(_ context.Context, log log.Logger, _ int, _ allowedpaths.AllowedCommand, args []string, _ bool) ([]byte, error) { +func noopExec(_ context.Context, log log.Logger, _ int, _ allowedcmd.AllowedCommand, args []string, _ bool) ([]byte, error) { log.Log("exec", "exec-in-test", "args", strings.Join(args, " ")) return []byte{}, nil } diff --git a/pkg/osquery/tables/cryptsetup/table.go b/pkg/osquery/tables/cryptsetup/table.go index 5b8d7c336..d0c5575db 100644 --- a/pkg/osquery/tables/cryptsetup/table.go +++ b/pkg/osquery/tables/cryptsetup/table.go @@ -10,7 +10,7 @@ import ( "github.com/go-kit/kit/log" "github.com/go-kit/kit/log/level" - "github.com/kolide/launcher/pkg/allowedpaths" + "github.com/kolide/launcher/pkg/allowedcmd" "github.com/kolide/launcher/pkg/dataflatten" "github.com/kolide/launcher/pkg/osquery/tables/dataflattentable" "github.com/kolide/launcher/pkg/osquery/tables/tablehelpers" @@ -50,7 +50,7 @@ func (t *Table) generate(ctx context.Context, queryContext table.QueryContext) ( } for _, name := range requestedNames { - output, err := tablehelpers.Exec(ctx, t.logger, 15, allowedpaths.Cryptsetup, []string{"--readonly", "status", name}, false) + output, err := tablehelpers.Exec(ctx, t.logger, 15, allowedcmd.Cryptsetup, []string{"--readonly", "status", name}, false) if err != nil { level.Debug(t.logger).Log("msg", "Error execing for status", "name", name, "err", err) continue diff --git a/pkg/osquery/tables/dataflattentable/exec.go b/pkg/osquery/tables/dataflattentable/exec.go index 506e4aee1..c7fe51a35 100644 --- a/pkg/osquery/tables/dataflattentable/exec.go +++ b/pkg/osquery/tables/dataflattentable/exec.go @@ -11,7 +11,7 @@ import ( "github.com/go-kit/kit/log" "github.com/go-kit/kit/log/level" - "github.com/kolide/launcher/pkg/allowedpaths" + "github.com/kolide/launcher/pkg/allowedcmd" "github.com/kolide/launcher/pkg/dataflatten" "github.com/kolide/launcher/pkg/osquery/tables/tablehelpers" "github.com/osquery/osquery-go/plugin/table" @@ -28,7 +28,7 @@ func WithKVSeparator(separator string) ExecTableOpt { } } -func TablePluginExec(logger log.Logger, tableName string, dataSourceType DataSourceType, cmd allowedpaths.AllowedCommand, execArgs []string, opts ...ExecTableOpt) *table.Plugin { +func TablePluginExec(logger log.Logger, tableName string, dataSourceType DataSourceType, cmd allowedcmd.AllowedCommand, execArgs []string, opts ...ExecTableOpt) *table.Plugin { columns := Columns() t := &Table{ diff --git a/pkg/osquery/tables/dataflattentable/exec_and_parse.go b/pkg/osquery/tables/dataflattentable/exec_and_parse.go index 6acabe0a4..9d3239239 100644 --- a/pkg/osquery/tables/dataflattentable/exec_and_parse.go +++ b/pkg/osquery/tables/dataflattentable/exec_and_parse.go @@ -7,7 +7,7 @@ import ( "github.com/go-kit/kit/log" "github.com/go-kit/kit/log/level" - "github.com/kolide/launcher/pkg/allowedpaths" + "github.com/kolide/launcher/pkg/allowedcmd" "github.com/kolide/launcher/pkg/dataflatten" "github.com/kolide/launcher/pkg/osquery/tables/tablehelpers" "github.com/kolide/launcher/pkg/traces" @@ -27,7 +27,7 @@ type execTableV2 struct { timeoutSeconds int tabledebug bool includeStderr bool - cmd allowedpaths.AllowedCommand + cmd allowedcmd.AllowedCommand execArgs []string } @@ -51,7 +51,7 @@ func WithIncludeStderr() execTableV2Opt { } } -func NewExecAndParseTable(logger log.Logger, tableName string, p parser, cmd allowedpaths.AllowedCommand, execArgs []string, opts ...execTableV2Opt) *table.Plugin { +func NewExecAndParseTable(logger log.Logger, tableName string, p parser, cmd allowedcmd.AllowedCommand, execArgs []string, opts ...execTableV2Opt) *table.Plugin { t := &execTableV2{ logger: level.NewFilter(log.With(logger, "table", tableName), level.AllowInfo()), tableName: tableName, diff --git a/pkg/osquery/tables/dataflattentable/tables.go b/pkg/osquery/tables/dataflattentable/tables.go index 91be9a156..b39748e8b 100644 --- a/pkg/osquery/tables/dataflattentable/tables.go +++ b/pkg/osquery/tables/dataflattentable/tables.go @@ -8,7 +8,7 @@ import ( "github.com/go-kit/kit/log" "github.com/go-kit/kit/log/level" - "github.com/kolide/launcher/pkg/allowedpaths" + "github.com/kolide/launcher/pkg/allowedcmd" "github.com/kolide/launcher/pkg/dataflatten" "github.com/kolide/launcher/pkg/osquery/tables/tablehelpers" "github.com/osquery/osquery-go" @@ -35,7 +35,7 @@ type Table struct { flattenFileFunc func(string, ...dataflatten.FlattenOpts) ([]dataflatten.Row, error) flattenBytesFunc func([]byte, ...dataflatten.FlattenOpts) ([]dataflatten.Row, error) - cmd allowedpaths.AllowedCommand + cmd allowedcmd.AllowedCommand execArgs []string keyValueSeparator string diff --git a/pkg/osquery/tables/dataflattentable/testdata/secdata.ini b/pkg/osquery/tables/dataflattentable/testdata/secdata.ini index 7b653c36e..725f4dc5e 100644 --- a/pkg/osquery/tables/dataflattentable/testdata/secdata.ini +++ b/pkg/osquery/tables/dataflattentable/testdata/secdata.ini @@ -66,7 +66,7 @@ MACHINE\System\CurrentControlSet\Control\Lsa\RestrictAnonymous=4,0 MACHINE\System\CurrentControlSet\Control\Lsa\RestrictAnonymousSAM=4,1 MACHINE\System\CurrentControlSet\Control\Print\Providers\LanMan Print Services\Servers\AddPrinterDrivers=4,0 MACHINE\System\CurrentControlSet\Control\SecurePipeServers\Winreg\AllowedExactPaths\Machine=7,System\CurrentControlSet\Control\ProductOptions,System\CurrentControlSet\Control\Server Applications,Software\Microsoft\Windows NT\CurrentVersion -MACHINE\System\CurrentControlSet\Control\SecurePipeServers\Winreg\AllowedPaths\Machine=7,System\CurrentControlSet\Control\Print\Printers,System\CurrentControlSet\Services\Eventlog,Software\Microsoft\OLAP Server,Software\Microsoft\Windows NT\CurrentVersion\Print,Software\Microsoft\Windows NT\CurrentVersion\Windows,System\CurrentControlSet\Control\ContentIndex,System\CurrentControlSet\Control\Terminal Server,System\CurrentControlSet\Control\Terminal Server\UserConfig,System\CurrentControlSet\Control\Terminal Server\DefaultUserConfiguration,Software\Microsoft\Windows NT\CurrentVersion\Perflib,System\CurrentControlSet\Services\SysmonLog +MACHINE\System\CurrentControlSet\Control\SecurePipeServers\Winreg\allowedcmd\Machine=7,System\CurrentControlSet\Control\Print\Printers,System\CurrentControlSet\Services\Eventlog,Software\Microsoft\OLAP Server,Software\Microsoft\Windows NT\CurrentVersion\Print,Software\Microsoft\Windows NT\CurrentVersion\Windows,System\CurrentControlSet\Control\ContentIndex,System\CurrentControlSet\Control\Terminal Server,System\CurrentControlSet\Control\Terminal Server\UserConfig,System\CurrentControlSet\Control\Terminal Server\DefaultUserConfiguration,Software\Microsoft\Windows NT\CurrentVersion\Perflib,System\CurrentControlSet\Services\SysmonLog MACHINE\System\CurrentControlSet\Control\Session Manager\Kernel\ObCaseInsensitive=4,1 MACHINE\System\CurrentControlSet\Control\Session Manager\Memory Management\ClearPageFileAtShutdown=4,0 MACHINE\System\CurrentControlSet\Control\Session Manager\ProtectionMode=4,1 diff --git a/pkg/osquery/tables/dev_table_tooling/table.go b/pkg/osquery/tables/dev_table_tooling/table.go index d12dd52d5..0e474bf42 100644 --- a/pkg/osquery/tables/dev_table_tooling/table.go +++ b/pkg/osquery/tables/dev_table_tooling/table.go @@ -7,7 +7,7 @@ import ( "github.com/go-kit/kit/log" "github.com/go-kit/kit/log/level" - "github.com/kolide/launcher/pkg/allowedpaths" + "github.com/kolide/launcher/pkg/allowedcmd" "github.com/kolide/launcher/pkg/osquery/tables/tablehelpers" "github.com/osquery/osquery-go/plugin/table" ) @@ -15,17 +15,17 @@ import ( // allowedCommand encapsulates the possible binary path(s) of a command allowed to execute // along with a strict list of arguments. type allowedCommand struct { - bin allowedpaths.AllowedCommand + bin allowedcmd.AllowedCommand args []string } var allowedCommands = map[string]allowedCommand{ "echo": { - bin: allowedpaths.Echo, + bin: allowedcmd.Echo, args: []string{"hello"}, }, "cb_repcli": { - bin: allowedpaths.Repcli, + bin: allowedcmd.Repcli, args: []string{"status"}, }, } diff --git a/pkg/osquery/tables/dsim_default_associations/dsim_default_associations.go b/pkg/osquery/tables/dsim_default_associations/dsim_default_associations.go index a427754a0..4e84be115 100644 --- a/pkg/osquery/tables/dsim_default_associations/dsim_default_associations.go +++ b/pkg/osquery/tables/dsim_default_associations/dsim_default_associations.go @@ -15,7 +15,7 @@ import ( "github.com/go-kit/kit/log" "github.com/go-kit/kit/log/level" "github.com/kolide/launcher/pkg/agent" - "github.com/kolide/launcher/pkg/allowedpaths" + "github.com/kolide/launcher/pkg/allowedcmd" "github.com/kolide/launcher/pkg/dataflatten" "github.com/kolide/launcher/pkg/osquery/tables/dataflattentable" "github.com/kolide/launcher/pkg/osquery/tables/tablehelpers" @@ -82,7 +82,7 @@ func (t *Table) execDism(ctx context.Context) ([]byte, error) { args := []string{"/online", "/Export-DefaultAppAssociations:" + dstFile} - cmd, err := allowedpaths.Dism(ctx, args...) + cmd, err := allowedcmd.Dism(ctx, args...) if err != nil { return nil, fmt.Errorf("creating command: %w", err) } diff --git a/pkg/osquery/tables/filevault/filevault.go b/pkg/osquery/tables/filevault/filevault.go index deb6530ad..d018eda94 100644 --- a/pkg/osquery/tables/filevault/filevault.go +++ b/pkg/osquery/tables/filevault/filevault.go @@ -11,7 +11,7 @@ import ( "github.com/go-kit/kit/log" "github.com/go-kit/kit/log/level" - "github.com/kolide/launcher/pkg/allowedpaths" + "github.com/kolide/launcher/pkg/allowedcmd" "github.com/kolide/launcher/pkg/osquery/tables/tablehelpers" "github.com/osquery/osquery-go/plugin/table" "github.com/pkg/errors" @@ -34,7 +34,7 @@ func TablePlugin(logger log.Logger) *table.Plugin { } func (t *Table) generate(ctx context.Context, queryContext table.QueryContext) ([]map[string]string, error) { - output, err := tablehelpers.Exec(ctx, t.logger, 10, allowedpaths.Fdesetup, []string{"status"}, false) + output, err := tablehelpers.Exec(ctx, t.logger, 10, allowedcmd.Fdesetup, []string{"status"}, false) if err != nil { level.Info(t.logger).Log("msg", "fdesetup failed", "err", err) diff --git a/pkg/osquery/tables/firmwarepasswd/firmwarepasswd.go b/pkg/osquery/tables/firmwarepasswd/firmwarepasswd.go index 10619c8c4..281f14c63 100644 --- a/pkg/osquery/tables/firmwarepasswd/firmwarepasswd.go +++ b/pkg/osquery/tables/firmwarepasswd/firmwarepasswd.go @@ -18,7 +18,7 @@ import ( "github.com/go-kit/kit/log" "github.com/go-kit/kit/log/level" "github.com/kolide/launcher/pkg/agent" - "github.com/kolide/launcher/pkg/allowedpaths" + "github.com/kolide/launcher/pkg/allowedcmd" "github.com/osquery/osquery-go/plugin/table" ) @@ -95,7 +95,7 @@ func (t *Table) runFirmwarepasswd(ctx context.Context, subcommand string, output ctx, cancel := context.WithTimeout(ctx, 1*time.Second) defer cancel() - cmd, err := allowedpaths.Firmwarepasswd(ctx, subcommand) + cmd, err := allowedcmd.Firmwarepasswd(ctx, subcommand) if err != nil { return fmt.Errorf("creating command: %w", err) } diff --git a/pkg/osquery/tables/gsettings/gsettings.go b/pkg/osquery/tables/gsettings/gsettings.go index 6de0a58d7..e78cb84ec 100644 --- a/pkg/osquery/tables/gsettings/gsettings.go +++ b/pkg/osquery/tables/gsettings/gsettings.go @@ -20,7 +20,7 @@ import ( "github.com/go-kit/kit/log" "github.com/go-kit/kit/log/level" "github.com/kolide/launcher/pkg/agent" - "github.com/kolide/launcher/pkg/allowedpaths" + "github.com/kolide/launcher/pkg/allowedcmd" "github.com/kolide/launcher/pkg/osquery/tables/tablehelpers" "github.com/osquery/osquery-go/plugin/table" ) @@ -90,7 +90,7 @@ func execGsettings(ctx context.Context, username string, buf *bytes.Buffer) erro return fmt.Errorf("finding user by username '%s': %w", username, err) } - cmd, err := allowedpaths.Gsettings(ctx, "list-recursively") + cmd, err := allowedcmd.Gsettings(ctx, "list-recursively") if err != nil { return fmt.Errorf("creating gsettings command: %w", err) } diff --git a/pkg/osquery/tables/gsettings/metadata.go b/pkg/osquery/tables/gsettings/metadata.go index 3bfa0d1f8..d4d6d3bd4 100644 --- a/pkg/osquery/tables/gsettings/metadata.go +++ b/pkg/osquery/tables/gsettings/metadata.go @@ -16,7 +16,7 @@ import ( "github.com/go-kit/kit/log" "github.com/go-kit/kit/log/level" "github.com/kolide/launcher/pkg/agent" - "github.com/kolide/launcher/pkg/allowedpaths" + "github.com/kolide/launcher/pkg/allowedcmd" "github.com/kolide/launcher/pkg/osquery/tables/tablehelpers" "github.com/osquery/osquery-go/plugin/table" ) @@ -221,7 +221,7 @@ func execGsettingsCommand(ctx context.Context, args []string, tmpdir string, out defer cancel() command := args[0] - cmd, err := allowedpaths.Gsettings(ctx, args...) + cmd, err := allowedcmd.Gsettings(ctx, args...) if err != nil { return fmt.Errorf("creating gsettings command: %w", err) } diff --git a/pkg/osquery/tables/ioreg/ioreg.go b/pkg/osquery/tables/ioreg/ioreg.go index 915064f64..2325df387 100644 --- a/pkg/osquery/tables/ioreg/ioreg.go +++ b/pkg/osquery/tables/ioreg/ioreg.go @@ -16,7 +16,7 @@ import ( "github.com/go-kit/kit/log" "github.com/go-kit/kit/log/level" - "github.com/kolide/launcher/pkg/allowedpaths" + "github.com/kolide/launcher/pkg/allowedcmd" "github.com/kolide/launcher/pkg/dataflatten" "github.com/kolide/launcher/pkg/osquery/tables/dataflattentable" "github.com/kolide/launcher/pkg/osquery/tables/tablehelpers" @@ -101,7 +101,7 @@ func (t *Table) generate(ctx context.Context, queryContext table.QueryContext) ( for _, dataQuery := range tablehelpers.GetConstraints(queryContext, "query", tablehelpers.WithDefaults("*")) { // Finally, an inner loop - ioregOutput, err := tablehelpers.Exec(ctx, t.logger, 30, allowedpaths.Ioreg, ioregArgs, false) + ioregOutput, err := tablehelpers.Exec(ctx, t.logger, 30, allowedcmd.Ioreg, ioregArgs, false) if err != nil { level.Info(t.logger).Log("msg", "ioreg failed", "err", err) continue diff --git a/pkg/osquery/tables/mdmclient/mdmclient.go b/pkg/osquery/tables/mdmclient/mdmclient.go index b23039738..3b48cf2c5 100644 --- a/pkg/osquery/tables/mdmclient/mdmclient.go +++ b/pkg/osquery/tables/mdmclient/mdmclient.go @@ -16,7 +16,7 @@ import ( "github.com/go-kit/kit/log" "github.com/go-kit/kit/log/level" - "github.com/kolide/launcher/pkg/allowedpaths" + "github.com/kolide/launcher/pkg/allowedcmd" "github.com/kolide/launcher/pkg/dataflatten" "github.com/kolide/launcher/pkg/osquery/tables/dataflattentable" "github.com/kolide/launcher/pkg/osquery/tables/tablehelpers" @@ -89,7 +89,7 @@ func (t *Table) generate(ctx context.Context, queryContext table.QueryContext) ( for _, dataQuery := range tablehelpers.GetConstraints(queryContext, "query", tablehelpers.WithDefaults("*")) { - mdmclientOutput, err := tablehelpers.Exec(ctx, t.logger, 30, allowedpaths.Mdmclient, []string{mdmclientCommand}, false) + mdmclientOutput, err := tablehelpers.Exec(ctx, t.logger, 30, allowedcmd.Mdmclient, []string{mdmclientCommand}, false) if err != nil { level.Info(t.logger).Log("msg", "mdmclient failed", "err", err) continue diff --git a/pkg/osquery/tables/profiles/profiles.go b/pkg/osquery/tables/profiles/profiles.go index 24f83da42..e029c263a 100644 --- a/pkg/osquery/tables/profiles/profiles.go +++ b/pkg/osquery/tables/profiles/profiles.go @@ -21,7 +21,7 @@ import ( "github.com/go-kit/kit/log" "github.com/go-kit/kit/log/level" "github.com/kolide/launcher/pkg/agent" - "github.com/kolide/launcher/pkg/allowedpaths" + "github.com/kolide/launcher/pkg/allowedcmd" "github.com/kolide/launcher/pkg/dataflatten" "github.com/kolide/launcher/pkg/osquery/tables/dataflattentable" "github.com/kolide/launcher/pkg/osquery/tables/tablehelpers" @@ -103,7 +103,7 @@ func (t *Table) generate(ctx context.Context, queryContext table.QueryContext) ( return nil, fmt.Errorf("Unknown user argument: %s", user) } - output, err := tablehelpers.Exec(ctx, t.logger, 30, allowedpaths.Profiles, profileArgs, false) + output, err := tablehelpers.Exec(ctx, t.logger, 30, allowedcmd.Profiles, profileArgs, false) if err != nil { level.Info(t.logger).Log("msg", "ioreg exec failed", "err", err) continue diff --git a/pkg/osquery/tables/pwpolicy/pwpolicy.go b/pkg/osquery/tables/pwpolicy/pwpolicy.go index dbc7a98fc..08276418c 100644 --- a/pkg/osquery/tables/pwpolicy/pwpolicy.go +++ b/pkg/osquery/tables/pwpolicy/pwpolicy.go @@ -19,7 +19,7 @@ import ( "github.com/go-kit/kit/log" "github.com/go-kit/kit/log/level" - "github.com/kolide/launcher/pkg/allowedpaths" + "github.com/kolide/launcher/pkg/allowedcmd" "github.com/kolide/launcher/pkg/dataflatten" "github.com/kolide/launcher/pkg/osquery/tables/dataflattentable" "github.com/kolide/launcher/pkg/osquery/tables/tablehelpers" @@ -31,7 +31,7 @@ const pwpolicyCmd = "getaccountpolicies" type Table struct { logger log.Logger tableName string - execCC allowedpaths.AllowedCommand + execCC allowedcmd.AllowedCommand } func TablePlugin(logger log.Logger) *table.Plugin { @@ -43,7 +43,7 @@ func TablePlugin(logger log.Logger) *table.Plugin { t := &Table{ logger: logger, tableName: "kolide_pwpolicy", - execCC: allowedpaths.Pwpolicy, + execCC: allowedcmd.Pwpolicy, } return table.NewPlugin(t.tableName, columns, t.generate) diff --git a/pkg/osquery/tables/secedit/secedit.go b/pkg/osquery/tables/secedit/secedit.go index cadfbf6b1..d43fe284a 100644 --- a/pkg/osquery/tables/secedit/secedit.go +++ b/pkg/osquery/tables/secedit/secedit.go @@ -17,7 +17,7 @@ import ( "github.com/go-kit/kit/log" "github.com/go-kit/kit/log/level" "github.com/kolide/launcher/pkg/agent" - "github.com/kolide/launcher/pkg/allowedpaths" + "github.com/kolide/launcher/pkg/allowedcmd" "github.com/kolide/launcher/pkg/dataflatten" "github.com/kolide/launcher/pkg/osquery/tables/dataflattentable" "github.com/kolide/launcher/pkg/osquery/tables/tablehelpers" @@ -107,7 +107,7 @@ func (t *Table) execSecedit(ctx context.Context, mergedPolicy bool) ([]byte, err args = append(args, "/mergedpolicy") } - cmd, err := allowedpaths.Secedit(ctx, args...) + cmd, err := allowedcmd.Secedit(ctx, args...) if err != nil { return nil, fmt.Errorf("creating secedit command: %w", err) } diff --git a/pkg/osquery/tables/systemprofiler/systemprofiler.go b/pkg/osquery/tables/systemprofiler/systemprofiler.go index ef3913bfb..4671daf0f 100644 --- a/pkg/osquery/tables/systemprofiler/systemprofiler.go +++ b/pkg/osquery/tables/systemprofiler/systemprofiler.go @@ -47,7 +47,7 @@ import ( "github.com/go-kit/kit/log" "github.com/go-kit/kit/log/level" "github.com/groob/plist" - "github.com/kolide/launcher/pkg/allowedpaths" + "github.com/kolide/launcher/pkg/allowedcmd" "github.com/kolide/launcher/pkg/dataflatten" "github.com/kolide/launcher/pkg/osquery/tables/dataflattentable" "github.com/osquery/osquery-go/plugin/table" @@ -206,7 +206,7 @@ func (t *Table) execSystemProfiler(ctx context.Context, detailLevel string, subc args = append(args, subcommands...) - cmd, err := allowedpaths.Systemprofiler(ctx, args...) + cmd, err := allowedcmd.Systemprofiler(ctx, args...) if err != nil { return nil, fmt.Errorf("creating system_profiler command: %w", err) } diff --git a/pkg/osquery/tables/tablehelpers/exec.go b/pkg/osquery/tables/tablehelpers/exec.go index 941d943e2..02aedb4be 100644 --- a/pkg/osquery/tables/tablehelpers/exec.go +++ b/pkg/osquery/tables/tablehelpers/exec.go @@ -9,7 +9,7 @@ import ( "github.com/go-kit/kit/log" "github.com/go-kit/kit/log/level" - "github.com/kolide/launcher/pkg/allowedpaths" + "github.com/kolide/launcher/pkg/allowedcmd" "github.com/kolide/launcher/pkg/traces" ) @@ -25,7 +25,7 @@ import ( // `possibleBins` can be either a list of command names, or a list of paths to commands. // Where reasonable, `possibleBins` should be command names only, so that we can perform // lookup against PATH. -func Exec(ctx context.Context, logger log.Logger, timeoutSeconds int, execCmd allowedpaths.AllowedCommand, args []string, includeStderr bool) ([]byte, error) { +func Exec(ctx context.Context, logger log.Logger, timeoutSeconds int, execCmd allowedcmd.AllowedCommand, args []string, includeStderr bool) ([]byte, error) { ctx, span := traces.StartSpan(ctx) defer span.End() diff --git a/pkg/osquery/tables/tablehelpers/exec_osquery_launchctl.go b/pkg/osquery/tables/tablehelpers/exec_osquery_launchctl.go index a9779c73f..bfda01704 100644 --- a/pkg/osquery/tables/tablehelpers/exec_osquery_launchctl.go +++ b/pkg/osquery/tables/tablehelpers/exec_osquery_launchctl.go @@ -15,7 +15,7 @@ import ( "github.com/go-kit/kit/log" "github.com/go-kit/kit/log/level" "github.com/kolide/launcher/pkg/agent" - "github.com/kolide/launcher/pkg/allowedpaths" + "github.com/kolide/launcher/pkg/allowedcmd" ) // ExecOsqueryLaunchctl runs osquery under launchctl, in a user context. @@ -28,7 +28,7 @@ func ExecOsqueryLaunchctl(ctx context.Context, logger log.Logger, timeoutSeconds return nil, fmt.Errorf("looking up username %s: %w", username, err) } - cmd, err := allowedpaths.Launchctl(ctx, + cmd, err := allowedcmd.Launchctl(ctx, "asuser", targetUser.Uid, osqueryPath, diff --git a/pkg/osquery/tables/tablehelpers/exec_test.go b/pkg/osquery/tables/tablehelpers/exec_test.go index eca2f3ee6..9b2f8abae 100644 --- a/pkg/osquery/tables/tablehelpers/exec_test.go +++ b/pkg/osquery/tables/tablehelpers/exec_test.go @@ -8,7 +8,7 @@ import ( "testing" "github.com/go-kit/kit/log" - "github.com/kolide/launcher/pkg/allowedpaths" + "github.com/kolide/launcher/pkg/allowedcmd" "github.com/stretchr/testify/assert" ) @@ -18,14 +18,14 @@ func TestExec(t *testing.T) { var tests = []struct { name string timeout int - bin allowedpaths.AllowedCommand + bin allowedcmd.AllowedCommand args []string err bool output string }{ { name: "output", - bin: allowedpaths.Echo, + bin: allowedcmd.Echo, args: []string{"hello"}, output: "hello\n", }, diff --git a/pkg/osquery/tables/wifi_networks/wifi_networks.go b/pkg/osquery/tables/wifi_networks/wifi_networks.go index 9287390e9..e5a1e5d2b 100644 --- a/pkg/osquery/tables/wifi_networks/wifi_networks.go +++ b/pkg/osquery/tables/wifi_networks/wifi_networks.go @@ -15,7 +15,7 @@ import ( "github.com/go-kit/kit/log" "github.com/go-kit/kit/log/level" "github.com/kolide/launcher/pkg/agent" - "github.com/kolide/launcher/pkg/allowedpaths" + "github.com/kolide/launcher/pkg/allowedcmd" "github.com/kolide/launcher/pkg/dataflatten" "github.com/kolide/launcher/pkg/osquery/tables/dataflattentable" "github.com/osquery/osquery-go/plugin/table" @@ -91,7 +91,7 @@ func execPwsh(logger log.Logger) execer { } args := append([]string{"-NoProfile", "-NonInteractive"}, string(pwshScript)) - cmd, err := allowedpaths.Powershell(ctx, args...) + cmd, err := allowedcmd.Powershell(ctx, args...) if err != nil { return fmt.Errorf("creating powershell command: %w", err) } diff --git a/pkg/osquery/tables/xrdb/xrdb.go b/pkg/osquery/tables/xrdb/xrdb.go index b36996773..2fc027339 100644 --- a/pkg/osquery/tables/xrdb/xrdb.go +++ b/pkg/osquery/tables/xrdb/xrdb.go @@ -20,7 +20,7 @@ import ( "github.com/go-kit/kit/log" "github.com/go-kit/kit/log/level" "github.com/kolide/launcher/pkg/agent" - "github.com/kolide/launcher/pkg/allowedpaths" + "github.com/kolide/launcher/pkg/allowedcmd" "github.com/kolide/launcher/pkg/osquery/tables/tablehelpers" "github.com/osquery/osquery-go/plugin/table" ) @@ -95,7 +95,7 @@ func execXRDB(ctx context.Context, displayNum, username string, buf *bytes.Buffe return fmt.Errorf("finding user by username '%s': %w", username, err) } - cmd, err := allowedpaths.Xrdb(ctx, "-display", displayNum, "-global", "-query") + cmd, err := allowedcmd.Xrdb(ctx, "-display", displayNum, "-global", "-query") if err != nil { return fmt.Errorf("creating xrdb command: %w", err) } diff --git a/pkg/osquery/tables/zfs/tables.go b/pkg/osquery/tables/zfs/tables.go index 4e659dc9f..4e8abd884 100644 --- a/pkg/osquery/tables/zfs/tables.go +++ b/pkg/osquery/tables/zfs/tables.go @@ -13,7 +13,7 @@ import ( "github.com/go-kit/kit/log" "github.com/go-kit/kit/log/level" - "github.com/kolide/launcher/pkg/allowedpaths" + "github.com/kolide/launcher/pkg/allowedcmd" "github.com/kolide/launcher/pkg/osquery/tables/tablehelpers" "github.com/osquery/osquery-go/plugin/table" "github.com/pkg/errors" @@ -23,7 +23,7 @@ const allowedCharacters = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0 type Table struct { logger log.Logger - cmd allowedpaths.AllowedCommand + cmd allowedcmd.AllowedCommand } func columns() []table.ColumnDefinition { @@ -38,7 +38,7 @@ func columns() []table.ColumnDefinition { func ZfsPropertiesPlugin(logger log.Logger) *table.Plugin { t := &Table{ logger: logger, - cmd: allowedpaths.Zfs, + cmd: allowedcmd.Zfs, } return table.NewPlugin("kolide_zfs_properties", columns(), t.generate) @@ -47,7 +47,7 @@ func ZfsPropertiesPlugin(logger log.Logger) *table.Plugin { func ZpoolPropertiesPlugin(logger log.Logger) *table.Plugin { t := &Table{ logger: logger, - cmd: allowedpaths.Zpool, + cmd: allowedcmd.Zpool, } return table.NewPlugin("kolide_zpool_properties", columns(), t.generate) From 3772a28bd85674dcaf9fbc405f3d656b54fcffea Mon Sep 17 00:00:00 2001 From: Rebecca Mahany-Horton Date: Thu, 9 Nov 2023 16:35:57 -0500 Subject: [PATCH 23/30] Use env vars for windows paths --- pkg/allowedcmd/cmd_windows.go | 21 ++++++++++----------- 1 file changed, 10 insertions(+), 11 deletions(-) diff --git a/pkg/allowedcmd/cmd_windows.go b/pkg/allowedcmd/cmd_windows.go index 58c5af782..be67fd7b7 100644 --- a/pkg/allowedcmd/cmd_windows.go +++ b/pkg/allowedcmd/cmd_windows.go @@ -7,20 +7,19 @@ import ( "context" "os" "os/exec" - "path" "path/filepath" ) func Commandprompt(ctx context.Context, arg ...string) (*exec.Cmd, error) { - return validatedCommand(ctx, `C:\Windows\System32\cmd.exe`, arg...) + return validatedCommand(ctx, filepath.Join(os.Getenv("SYSTEM32"), "cmd.exe"), arg...) } func Dism(ctx context.Context, arg ...string) (*exec.Cmd, error) { - return validatedCommand(ctx, `C:\Windows\System32\Dism.exe`, arg...) + return validatedCommand(ctx, filepath.Join(os.Getenv("SYSTEM32"), "Dism.exe"), arg...) } func Dsregcmd(ctx context.Context, arg ...string) (*exec.Cmd, error) { - return validatedCommand(ctx, `C:\Windows\System32\dsregcmd.exe`, arg...) + return validatedCommand(ctx, filepath.Join(os.Getenv("SYSTEM32"), "dsregcmd.exe"), arg...) } func Echo(ctx context.Context, arg ...string) (*exec.Cmd, error) { @@ -29,30 +28,30 @@ func Echo(ctx context.Context, arg ...string) (*exec.Cmd, error) { } func Ipconfig(ctx context.Context, arg ...string) (*exec.Cmd, error) { - return validatedCommand(ctx, `C:\Windows\System32\ipconfig.exe`, arg...) + return validatedCommand(ctx, filepath.Join(os.Getenv("SYSTEM32"), "ipconfig.exe"), arg...) } func Powercfg(ctx context.Context, arg ...string) (*exec.Cmd, error) { - return validatedCommand(ctx, `C:\Windows\System32\powercfg.exe`, arg...) + return validatedCommand(ctx, filepath.Join(os.Getenv("SYSTEM32"), "powercfg.exe"), arg...) } func Powershell(ctx context.Context, arg ...string) (*exec.Cmd, error) { - return validatedCommand(ctx, `C:\Windows\System32\WindowsPowerShell\v1.0\powershell.exe`, arg...) + return validatedCommand(ctx, filepath.Join(os.Getenv("SYSTEM32"), "WindowsPowerShell", "v1.0", "powershell.exe"), arg...) } func Repcli(ctx context.Context, arg ...string) (*exec.Cmd, error) { - return validatedCommand(ctx, filepath.Join("Program Files", "Confer", "repcli"), arg...) + return validatedCommand(ctx, filepath.Join(os.Getenv("PROGRAMFILES"), "Confer", "repcli"), arg...) } func Secedit(ctx context.Context, arg ...string) (*exec.Cmd, error) { - return validatedCommand(ctx, `C:\Windows\System32\SecEdit.exe`, arg...) + return validatedCommand(ctx, filepath.Join(os.Getenv("SYSTEM32"), "SecEdit.exe"), arg...) } func Taskkill(ctx context.Context, arg ...string) (*exec.Cmd, error) { - return validatedCommand(ctx, `C:\Windows\System32\taskkill.exe`, arg...) + return validatedCommand(ctx, filepath.Join(os.Getenv("SYSTEM32"), "taskkill.exe"), arg...) } func Zerotiercli(ctx context.Context, arg ...string) (*exec.Cmd, error) { // For windows, "-q" should be prepended before all other args - return validatedCommand(ctx, path.Join(os.Getenv("SYSTEMROOT"), "ProgramData", "ZeroTier", "One", "zerotier-one_x64.exe"), append([]string{"-q"}, arg...)...) + return validatedCommand(ctx, filepath.Join(os.Getenv("SYSTEMROOT"), "ProgramData", "ZeroTier", "One", "zerotier-one_x64.exe"), append([]string{"-q"}, arg...)...) } From 25c351e57706456aefa463e9769f878f7d04b8d1 Mon Sep 17 00:00:00 2001 From: Rebecca Mahany-Horton Date: Thu, 9 Nov 2023 16:58:50 -0500 Subject: [PATCH 24/30] Fix overzealous find-and-replace --- pkg/dataflatten/testdata/secdata.ini | 2 +- pkg/osquery/tables/dataflattentable/testdata/secdata.ini | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/pkg/dataflatten/testdata/secdata.ini b/pkg/dataflatten/testdata/secdata.ini index 725f4dc5e..7b653c36e 100644 --- a/pkg/dataflatten/testdata/secdata.ini +++ b/pkg/dataflatten/testdata/secdata.ini @@ -66,7 +66,7 @@ MACHINE\System\CurrentControlSet\Control\Lsa\RestrictAnonymous=4,0 MACHINE\System\CurrentControlSet\Control\Lsa\RestrictAnonymousSAM=4,1 MACHINE\System\CurrentControlSet\Control\Print\Providers\LanMan Print Services\Servers\AddPrinterDrivers=4,0 MACHINE\System\CurrentControlSet\Control\SecurePipeServers\Winreg\AllowedExactPaths\Machine=7,System\CurrentControlSet\Control\ProductOptions,System\CurrentControlSet\Control\Server Applications,Software\Microsoft\Windows NT\CurrentVersion -MACHINE\System\CurrentControlSet\Control\SecurePipeServers\Winreg\allowedcmd\Machine=7,System\CurrentControlSet\Control\Print\Printers,System\CurrentControlSet\Services\Eventlog,Software\Microsoft\OLAP Server,Software\Microsoft\Windows NT\CurrentVersion\Print,Software\Microsoft\Windows NT\CurrentVersion\Windows,System\CurrentControlSet\Control\ContentIndex,System\CurrentControlSet\Control\Terminal Server,System\CurrentControlSet\Control\Terminal Server\UserConfig,System\CurrentControlSet\Control\Terminal Server\DefaultUserConfiguration,Software\Microsoft\Windows NT\CurrentVersion\Perflib,System\CurrentControlSet\Services\SysmonLog +MACHINE\System\CurrentControlSet\Control\SecurePipeServers\Winreg\AllowedPaths\Machine=7,System\CurrentControlSet\Control\Print\Printers,System\CurrentControlSet\Services\Eventlog,Software\Microsoft\OLAP Server,Software\Microsoft\Windows NT\CurrentVersion\Print,Software\Microsoft\Windows NT\CurrentVersion\Windows,System\CurrentControlSet\Control\ContentIndex,System\CurrentControlSet\Control\Terminal Server,System\CurrentControlSet\Control\Terminal Server\UserConfig,System\CurrentControlSet\Control\Terminal Server\DefaultUserConfiguration,Software\Microsoft\Windows NT\CurrentVersion\Perflib,System\CurrentControlSet\Services\SysmonLog MACHINE\System\CurrentControlSet\Control\Session Manager\Kernel\ObCaseInsensitive=4,1 MACHINE\System\CurrentControlSet\Control\Session Manager\Memory Management\ClearPageFileAtShutdown=4,0 MACHINE\System\CurrentControlSet\Control\Session Manager\ProtectionMode=4,1 diff --git a/pkg/osquery/tables/dataflattentable/testdata/secdata.ini b/pkg/osquery/tables/dataflattentable/testdata/secdata.ini index 725f4dc5e..7b653c36e 100644 --- a/pkg/osquery/tables/dataflattentable/testdata/secdata.ini +++ b/pkg/osquery/tables/dataflattentable/testdata/secdata.ini @@ -66,7 +66,7 @@ MACHINE\System\CurrentControlSet\Control\Lsa\RestrictAnonymous=4,0 MACHINE\System\CurrentControlSet\Control\Lsa\RestrictAnonymousSAM=4,1 MACHINE\System\CurrentControlSet\Control\Print\Providers\LanMan Print Services\Servers\AddPrinterDrivers=4,0 MACHINE\System\CurrentControlSet\Control\SecurePipeServers\Winreg\AllowedExactPaths\Machine=7,System\CurrentControlSet\Control\ProductOptions,System\CurrentControlSet\Control\Server Applications,Software\Microsoft\Windows NT\CurrentVersion -MACHINE\System\CurrentControlSet\Control\SecurePipeServers\Winreg\allowedcmd\Machine=7,System\CurrentControlSet\Control\Print\Printers,System\CurrentControlSet\Services\Eventlog,Software\Microsoft\OLAP Server,Software\Microsoft\Windows NT\CurrentVersion\Print,Software\Microsoft\Windows NT\CurrentVersion\Windows,System\CurrentControlSet\Control\ContentIndex,System\CurrentControlSet\Control\Terminal Server,System\CurrentControlSet\Control\Terminal Server\UserConfig,System\CurrentControlSet\Control\Terminal Server\DefaultUserConfiguration,Software\Microsoft\Windows NT\CurrentVersion\Perflib,System\CurrentControlSet\Services\SysmonLog +MACHINE\System\CurrentControlSet\Control\SecurePipeServers\Winreg\AllowedPaths\Machine=7,System\CurrentControlSet\Control\Print\Printers,System\CurrentControlSet\Services\Eventlog,Software\Microsoft\OLAP Server,Software\Microsoft\Windows NT\CurrentVersion\Print,Software\Microsoft\Windows NT\CurrentVersion\Windows,System\CurrentControlSet\Control\ContentIndex,System\CurrentControlSet\Control\Terminal Server,System\CurrentControlSet\Control\Terminal Server\UserConfig,System\CurrentControlSet\Control\Terminal Server\DefaultUserConfiguration,Software\Microsoft\Windows NT\CurrentVersion\Perflib,System\CurrentControlSet\Services\SysmonLog MACHINE\System\CurrentControlSet\Control\Session Manager\Kernel\ObCaseInsensitive=4,1 MACHINE\System\CurrentControlSet\Control\Session Manager\Memory Management\ClearPageFileAtShutdown=4,0 MACHINE\System\CurrentControlSet\Control\Session Manager\ProtectionMode=4,1 From 6df84bd6e7b841642c393f2fa40cf5f581a206c7 Mon Sep 17 00:00:00 2001 From: Rebecca Mahany-Horton Date: Mon, 13 Nov 2023 09:38:06 -0500 Subject: [PATCH 25/30] cmd => cmdGen --- pkg/osquery/tables/dataflattentable/exec.go | 6 +++--- pkg/osquery/tables/dataflattentable/tables.go | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/pkg/osquery/tables/dataflattentable/exec.go b/pkg/osquery/tables/dataflattentable/exec.go index c7fe51a35..5261c3fba 100644 --- a/pkg/osquery/tables/dataflattentable/exec.go +++ b/pkg/osquery/tables/dataflattentable/exec.go @@ -28,13 +28,13 @@ func WithKVSeparator(separator string) ExecTableOpt { } } -func TablePluginExec(logger log.Logger, tableName string, dataSourceType DataSourceType, cmd allowedcmd.AllowedCommand, execArgs []string, opts ...ExecTableOpt) *table.Plugin { +func TablePluginExec(logger log.Logger, tableName string, dataSourceType DataSourceType, cmdGen allowedcmd.AllowedCommand, execArgs []string, opts ...ExecTableOpt) *table.Plugin { columns := Columns() t := &Table{ logger: level.NewFilter(logger, level.AllowInfo()), tableName: tableName, - cmd: cmd, + cmdGen: cmdGen, execArgs: execArgs, keyValueSeparator: ":", } @@ -100,7 +100,7 @@ func (t *Table) exec(ctx context.Context) ([]byte, error) { var stdout bytes.Buffer var stderr bytes.Buffer - cmd, err := t.cmd(ctx, t.execArgs...) + cmd, err := t.cmdGen(ctx, t.execArgs...) if err != nil { return nil, fmt.Errorf("creating command: %w", err) } diff --git a/pkg/osquery/tables/dataflattentable/tables.go b/pkg/osquery/tables/dataflattentable/tables.go index b39748e8b..3d32c9a9e 100644 --- a/pkg/osquery/tables/dataflattentable/tables.go +++ b/pkg/osquery/tables/dataflattentable/tables.go @@ -35,7 +35,7 @@ type Table struct { flattenFileFunc func(string, ...dataflatten.FlattenOpts) ([]dataflatten.Row, error) flattenBytesFunc func([]byte, ...dataflatten.FlattenOpts) ([]dataflatten.Row, error) - cmd allowedcmd.AllowedCommand + cmdGen allowedcmd.AllowedCommand execArgs []string keyValueSeparator string From 0511ca8c626ee2da6aefaf45732c42a939ab76e5 Mon Sep 17 00:00:00 2001 From: Rebecca Mahany-Horton Date: Mon, 13 Nov 2023 09:46:40 -0500 Subject: [PATCH 26/30] Log and return empty results on command creation failure --- pkg/osquery/table/touchid_system_darwin.go | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/pkg/osquery/table/touchid_system_darwin.go b/pkg/osquery/table/touchid_system_darwin.go index 4cb4e2805..a1533a7e5 100644 --- a/pkg/osquery/table/touchid_system_darwin.go +++ b/pkg/osquery/table/touchid_system_darwin.go @@ -9,6 +9,7 @@ import ( "time" "github.com/go-kit/kit/log" + "github.com/go-kit/kit/log/level" "github.com/kolide/launcher/pkg/allowedcmd" "github.com/osquery/osquery-go/plugin/table" ) @@ -43,7 +44,8 @@ func (t *touchIDSystemConfigTable) generate(ctx context.Context, queryContext ta var stdout bytes.Buffer cmd, err := allowedcmd.Systemprofiler(ctx, "SPiBridgeDataType") if err != nil { - return nil, fmt.Errorf("creating system_profiler command: %w", err) + level.Debug(t.logger).Log("msg", "could not create system_profiler command", "err", err) + return results, nil } cmd.Stdout = &stdout if err := cmd.Run(); err != nil { @@ -62,7 +64,8 @@ func (t *touchIDSystemConfigTable) generate(ctx context.Context, queryContext ta stdout.Reset() cmd, err = allowedcmd.Bioutil(ctx, "-r", "-s") if err != nil { - return nil, fmt.Errorf("creating bioutil command: %w", err) + level.Debug(t.logger).Log("msg", "could not create bioutil command", "err", err) + return results, nil } cmd.Stdout = &stdout if err := cmd.Run(); err != nil { From 0a3fd905a2b482b8528dfdf4c14825e8045685f3 Mon Sep 17 00:00:00 2001 From: Rebecca Mahany-Horton Date: Mon, 13 Nov 2023 09:53:15 -0500 Subject: [PATCH 27/30] Don't unify dev table tooling commands --- .../tables/dev_table_tooling/commands_darwin.go | 17 +++++++++++++++++ .../tables/dev_table_tooling/commands_linux.go | 17 +++++++++++++++++ .../dev_table_tooling/commands_windows.go | 17 +++++++++++++++++ pkg/osquery/tables/dev_table_tooling/table.go | 11 ----------- 4 files changed, 51 insertions(+), 11 deletions(-) create mode 100644 pkg/osquery/tables/dev_table_tooling/commands_darwin.go create mode 100644 pkg/osquery/tables/dev_table_tooling/commands_linux.go create mode 100644 pkg/osquery/tables/dev_table_tooling/commands_windows.go diff --git a/pkg/osquery/tables/dev_table_tooling/commands_darwin.go b/pkg/osquery/tables/dev_table_tooling/commands_darwin.go new file mode 100644 index 000000000..f09c77ceb --- /dev/null +++ b/pkg/osquery/tables/dev_table_tooling/commands_darwin.go @@ -0,0 +1,17 @@ +//go:build darwin +// +build darwin + +package dev_table_tooling + +import "github.com/kolide/launcher/pkg/allowedcmd" + +var allowedCommands = map[string]allowedCommand{ + "echo": { + bin: allowedcmd.Echo, + args: []string{"hello"}, + }, + "cb_repcli": { + bin: allowedcmd.Repcli, + args: []string{"status"}, + }, +} diff --git a/pkg/osquery/tables/dev_table_tooling/commands_linux.go b/pkg/osquery/tables/dev_table_tooling/commands_linux.go new file mode 100644 index 000000000..573ce4d05 --- /dev/null +++ b/pkg/osquery/tables/dev_table_tooling/commands_linux.go @@ -0,0 +1,17 @@ +//go:build linux +// +build linux + +package dev_table_tooling + +import "github.com/kolide/launcher/pkg/allowedcmd" + +var allowedCommands = map[string]allowedCommand{ + "echo": { + bin: allowedcmd.Echo, + args: []string{"hello"}, + }, + "cb_repcli": { + bin: allowedcmd.Repcli, + args: []string{"status"}, + }, +} diff --git a/pkg/osquery/tables/dev_table_tooling/commands_windows.go b/pkg/osquery/tables/dev_table_tooling/commands_windows.go new file mode 100644 index 000000000..25e242f09 --- /dev/null +++ b/pkg/osquery/tables/dev_table_tooling/commands_windows.go @@ -0,0 +1,17 @@ +//go:build windows +// +build windows + +package dev_table_tooling + +import "github.com/kolide/launcher/pkg/allowedcmd" + +var allowedCommands = map[string]allowedCommand{ + "echo": { + bin: allowedcmd.Echo, + args: []string{"hello"}, + }, + "cb_repcli": { + bin: allowedcmd.Repcli, + args: []string{"status"}, + }, +} diff --git a/pkg/osquery/tables/dev_table_tooling/table.go b/pkg/osquery/tables/dev_table_tooling/table.go index 0e474bf42..5d9028c84 100644 --- a/pkg/osquery/tables/dev_table_tooling/table.go +++ b/pkg/osquery/tables/dev_table_tooling/table.go @@ -19,17 +19,6 @@ type allowedCommand struct { args []string } -var allowedCommands = map[string]allowedCommand{ - "echo": { - bin: allowedcmd.Echo, - args: []string{"hello"}, - }, - "cb_repcli": { - bin: allowedcmd.Repcli, - args: []string{"status"}, - }, -} - type Table struct { logger log.Logger } From 7d39c006ab5d15431268057a0eb7f44b75dc3d37 Mon Sep 17 00:00:00 2001 From: Rebecca Mahany-Horton Date: Mon, 13 Nov 2023 10:03:57 -0500 Subject: [PATCH 28/30] Fix casing for some commands --- ee/desktop/user/menu/action_open_url_linux.go | 2 +- ee/desktop/user/menu/action_open_url_windows.go | 2 +- ee/desktop/user/notify/notify_linux.go | 4 ++-- pkg/allowedcmd/cmd_darwin.go | 4 ++-- pkg/allowedcmd/cmd_linux.go | 12 ++++++------ pkg/allowedcmd/cmd_windows.go | 4 ++-- pkg/debug/checkups/gnome_extensions_linux.go | 2 +- pkg/osquery/table/table.go | 6 +++--- pkg/osquery/table/touchid_system_darwin.go | 2 +- .../tables/crowdstrike/falcon_kernel_check/table.go | 2 +- pkg/osquery/tables/systemprofiler/systemprofiler.go | 2 +- 11 files changed, 21 insertions(+), 21 deletions(-) diff --git a/ee/desktop/user/menu/action_open_url_linux.go b/ee/desktop/user/menu/action_open_url_linux.go index ffbef3e2a..338cf9ab8 100644 --- a/ee/desktop/user/menu/action_open_url_linux.go +++ b/ee/desktop/user/menu/action_open_url_linux.go @@ -13,7 +13,7 @@ import ( // open opens the specified URL in the default browser of the user // See https://stackoverflow.com/a/39324149/1705598 func open(url string) error { - cmd, err := allowedcmd.Xdgopen(context.TODO(), url) + cmd, err := allowedcmd.XdgOpen(context.TODO(), url) if err != nil { return fmt.Errorf("creating command: %w", err) } diff --git a/ee/desktop/user/menu/action_open_url_windows.go b/ee/desktop/user/menu/action_open_url_windows.go index e668de672..54b16c879 100644 --- a/ee/desktop/user/menu/action_open_url_windows.go +++ b/ee/desktop/user/menu/action_open_url_windows.go @@ -14,7 +14,7 @@ import ( // open opens the specified URL in the default browser of the user // See https://stackoverflow.com/a/39324149/1705598 func open(url string) error { - cmd, err := allowedcmd.Commandprompt(context.TODO(), "/C", "start", url) + cmd, err := allowedcmd.CommandPrompt(context.TODO(), "/C", "start", url) if err != nil { return fmt.Errorf("creating command: %w", err) } diff --git a/ee/desktop/user/notify/notify_linux.go b/ee/desktop/user/notify/notify_linux.go index 9cc588d82..c39cda5fe 100644 --- a/ee/desktop/user/notify/notify_linux.go +++ b/ee/desktop/user/notify/notify_linux.go @@ -33,7 +33,7 @@ const ( // We default to xdg-open first because, if available, it appears to be better at picking // the correct default browser. -var browserLaunchers = []allowedcmd.AllowedCommand{allowedcmd.Xdgopen, allowedcmd.Xwwwbrowser} +var browserLaunchers = []allowedcmd.AllowedCommand{allowedcmd.XdgOpen, allowedcmd.XWwwBrowser} func NewDesktopNotifier(logger log.Logger, iconFilepath string) *dbusNotifier { conn, err := dbus.ConnectSessionBus() @@ -181,7 +181,7 @@ func (d *dbusNotifier) sendNotificationViaNotifySend(n Notification) error { args = append(args, "-i", d.iconFilepath) } - cmd, err := allowedcmd.Notifysend(context.TODO(), args...) + cmd, err := allowedcmd.NotifySend(context.TODO(), args...) if err != nil { return fmt.Errorf("creating command: %w", err) } diff --git a/pkg/allowedcmd/cmd_darwin.go b/pkg/allowedcmd/cmd_darwin.go index 38f5d870a..4cc898f50 100644 --- a/pkg/allowedcmd/cmd_darwin.go +++ b/pkg/allowedcmd/cmd_darwin.go @@ -108,7 +108,7 @@ func Softwareupdate(ctx context.Context, arg ...string) (*exec.Cmd, error) { return validatedCommand(ctx, "/usr/sbin/softwareupdate", arg...) } -func Systemprofiler(ctx context.Context, arg ...string) (*exec.Cmd, error) { +func SystemProfiler(ctx context.Context, arg ...string) (*exec.Cmd, error) { return validatedCommand(ctx, "/usr/sbin/system_profiler", arg...) } @@ -116,7 +116,7 @@ func Tmutil(ctx context.Context, arg ...string) (*exec.Cmd, error) { return validatedCommand(ctx, "/usr/bin/tmutil", arg...) } -func Zerotiercli(ctx context.Context, arg ...string) (*exec.Cmd, error) { +func ZerotierCli(ctx context.Context, arg ...string) (*exec.Cmd, error) { return validatedCommand(ctx, "/usr/local/bin/zerotier-cli", arg...) } diff --git a/pkg/allowedcmd/cmd_linux.go b/pkg/allowedcmd/cmd_linux.go index 1b8cfd830..4923644ed 100644 --- a/pkg/allowedcmd/cmd_linux.go +++ b/pkg/allowedcmd/cmd_linux.go @@ -42,11 +42,11 @@ func Falconctl(ctx context.Context, arg ...string) (*exec.Cmd, error) { return validatedCommand(ctx, "/opt/CrowdStrike/falconctl", arg...) } -func Falconkernelcheck(ctx context.Context, arg ...string) (*exec.Cmd, error) { +func FalconKernelCheck(ctx context.Context, arg ...string) (*exec.Cmd, error) { return validatedCommand(ctx, "/opt/CrowdStrike/falcon-kernel-check", arg...) } -func Gnomeextensions(ctx context.Context, arg ...string) (*exec.Cmd, error) { +func GnomeExtensions(ctx context.Context, arg ...string) (*exec.Cmd, error) { return validatedCommand(ctx, "/usr/bin/gnome-extensions", arg...) } @@ -87,7 +87,7 @@ func Nmcli(ctx context.Context, arg ...string) (*exec.Cmd, error) { return validatedCommand(ctx, "/usr/bin/nmcli", arg...) } -func Notifysend(ctx context.Context, arg ...string) (*exec.Cmd, error) { +func NotifySend(ctx context.Context, arg ...string) (*exec.Cmd, error) { return validatedCommand(ctx, "/usr/bin/notify-send", arg...) } @@ -120,7 +120,7 @@ func Systemctl(ctx context.Context, arg ...string) (*exec.Cmd, error) { return validatedCommand(ctx, "/usr/bin/systemctl", arg...) } -func Xdgopen(ctx context.Context, arg ...string) (*exec.Cmd, error) { +func XdgOpen(ctx context.Context, arg ...string) (*exec.Cmd, error) { return validatedCommand(ctx, "/usr/bin/xdg-open", arg...) } @@ -128,11 +128,11 @@ func Xrdb(ctx context.Context, arg ...string) (*exec.Cmd, error) { return validatedCommand(ctx, "/usr/bin/xrdb", arg...) } -func Xwwwbrowser(ctx context.Context, arg ...string) (*exec.Cmd, error) { +func XWwwBrowser(ctx context.Context, arg ...string) (*exec.Cmd, error) { return validatedCommand(ctx, "/usr/bin/x-www-browser", arg...) } -func Zerotiercli(ctx context.Context, arg ...string) (*exec.Cmd, error) { +func ZerotierCli(ctx context.Context, arg ...string) (*exec.Cmd, error) { return validatedCommand(ctx, "/usr/local/bin/zerotier-cli", arg...) } diff --git a/pkg/allowedcmd/cmd_windows.go b/pkg/allowedcmd/cmd_windows.go index be67fd7b7..7527a051c 100644 --- a/pkg/allowedcmd/cmd_windows.go +++ b/pkg/allowedcmd/cmd_windows.go @@ -10,7 +10,7 @@ import ( "path/filepath" ) -func Commandprompt(ctx context.Context, arg ...string) (*exec.Cmd, error) { +func CommandPrompt(ctx context.Context, arg ...string) (*exec.Cmd, error) { return validatedCommand(ctx, filepath.Join(os.Getenv("SYSTEM32"), "cmd.exe"), arg...) } @@ -51,7 +51,7 @@ func Taskkill(ctx context.Context, arg ...string) (*exec.Cmd, error) { return validatedCommand(ctx, filepath.Join(os.Getenv("SYSTEM32"), "taskkill.exe"), arg...) } -func Zerotiercli(ctx context.Context, arg ...string) (*exec.Cmd, error) { +func ZerotierCli(ctx context.Context, arg ...string) (*exec.Cmd, error) { // For windows, "-q" should be prepended before all other args return validatedCommand(ctx, filepath.Join(os.Getenv("SYSTEMROOT"), "ProgramData", "ZeroTier", "One", "zerotier-one_x64.exe"), append([]string{"-q"}, arg...)...) } diff --git a/pkg/debug/checkups/gnome_extensions_linux.go b/pkg/debug/checkups/gnome_extensions_linux.go index eade396a5..f79e2ed18 100644 --- a/pkg/debug/checkups/gnome_extensions_linux.go +++ b/pkg/debug/checkups/gnome_extensions_linux.go @@ -93,7 +93,7 @@ func execGnomeExtension(ctx context.Context, extraWriter io.Writer, rundir strin // pkg/osquery/tables/gsettings/gsettings.go probably has appropriate prior art. // But do we really want the forloop? - cmd, err := allowedcmd.Gnomeextensions(ctx, args...) + cmd, err := allowedcmd.GnomeExtensions(ctx, args...) if err != nil { return nil, fmt.Errorf("creating gnome-extensions command: %w", err) } diff --git a/pkg/osquery/table/table.go b/pkg/osquery/table/table.go index c012487d0..2afc9da33 100644 --- a/pkg/osquery/table/table.go +++ b/pkg/osquery/table/table.go @@ -48,11 +48,11 @@ func PlatformTables(logger log.Logger, currentOsquerydBinaryPath string) []osque dev_table_tooling.TablePlugin(logger), firefox_preferences.TablePlugin(logger), dataflattentable.TablePluginExec(logger, - "kolide_zerotier_info", dataflattentable.JsonType, allowedcmd.Zerotiercli, []string{"info"}), + "kolide_zerotier_info", dataflattentable.JsonType, allowedcmd.ZerotierCli, []string{"info"}), dataflattentable.TablePluginExec(logger, - "kolide_zerotier_networks", dataflattentable.JsonType, allowedcmd.Zerotiercli, []string{"listnetworks"}), + "kolide_zerotier_networks", dataflattentable.JsonType, allowedcmd.ZerotierCli, []string{"listnetworks"}), dataflattentable.TablePluginExec(logger, - "kolide_zerotier_peers", dataflattentable.JsonType, allowedcmd.Zerotiercli, []string{"listpeers"}), + "kolide_zerotier_peers", dataflattentable.JsonType, allowedcmd.ZerotierCli, []string{"listpeers"}), tdebug.LauncherGcInfo(logger), } diff --git a/pkg/osquery/table/touchid_system_darwin.go b/pkg/osquery/table/touchid_system_darwin.go index a1533a7e5..0a750381d 100644 --- a/pkg/osquery/table/touchid_system_darwin.go +++ b/pkg/osquery/table/touchid_system_darwin.go @@ -42,7 +42,7 @@ func (t *touchIDSystemConfigTable) generate(ctx context.Context, queryContext ta // Read the security chip from system_profiler var stdout bytes.Buffer - cmd, err := allowedcmd.Systemprofiler(ctx, "SPiBridgeDataType") + cmd, err := allowedcmd.SystemProfiler(ctx, "SPiBridgeDataType") if err != nil { level.Debug(t.logger).Log("msg", "could not create system_profiler command", "err", err) return results, nil diff --git a/pkg/osquery/tables/crowdstrike/falcon_kernel_check/table.go b/pkg/osquery/tables/crowdstrike/falcon_kernel_check/table.go index 9779d4dc5..79b60d3a9 100644 --- a/pkg/osquery/tables/crowdstrike/falcon_kernel_check/table.go +++ b/pkg/osquery/tables/crowdstrike/falcon_kernel_check/table.go @@ -36,7 +36,7 @@ func TablePlugin(logger log.Logger) *table.Plugin { } func (t *Table) generate(ctx context.Context, queryContext table.QueryContext) ([]map[string]string, error) { - output, err := tablehelpers.Exec(ctx, t.logger, 5, allowedcmd.Falconkernelcheck, []string{}, false) + output, err := tablehelpers.Exec(ctx, t.logger, 5, allowedcmd.FalconKernelCheck, []string{}, false) if err != nil { level.Info(t.logger).Log("msg", "exec failed", "err", err) return nil, err diff --git a/pkg/osquery/tables/systemprofiler/systemprofiler.go b/pkg/osquery/tables/systemprofiler/systemprofiler.go index 4671daf0f..24755c04f 100644 --- a/pkg/osquery/tables/systemprofiler/systemprofiler.go +++ b/pkg/osquery/tables/systemprofiler/systemprofiler.go @@ -206,7 +206,7 @@ func (t *Table) execSystemProfiler(ctx context.Context, detailLevel string, subc args = append(args, subcommands...) - cmd, err := allowedcmd.Systemprofiler(ctx, args...) + cmd, err := allowedcmd.SystemProfiler(ctx, args...) if err != nil { return nil, fmt.Errorf("creating system_profiler command: %w", err) } From 53bcf57fe70de232cc7f7b8e6adbe38828243449 Mon Sep 17 00:00:00 2001 From: Rebecca Mahany-Horton Date: Mon, 13 Nov 2023 15:32:22 -0500 Subject: [PATCH 29/30] Make nolint:forbidigo directives more specific and add documentation --- ee/desktop/runner/runner.go | 3 +-- ee/desktop/runner/runner_test.go | 3 +-- ee/ui/assets/generator/generator.go | 6 +++--- pkg/allowedcmd/cmd.go | 2 +- pkg/autoupdate/findnew.go | 4 +--- pkg/debug/checkups/osquery.go | 5 ++--- pkg/execwrapper/exec_windows.go | 4 +--- pkg/make/builder.go | 7 ++++--- pkg/make/builder_test.go | 3 +-- pkg/osquery/runsimple/osqueryrunner.go | 6 ++---- pkg/osquery/runtime/osqueryinstance.go | 4 +--- pkg/osquery/tables/pwpolicy/pwpolicy_test.go | 3 +-- pkg/packagekit/applenotarization/applenotarization.go | 3 +-- pkg/packagekit/authenticode/authenticode_test.go | 3 +-- pkg/packagekit/authenticode/authenticode_windows.go | 3 +-- pkg/packagekit/package_fpm.go | 3 +-- pkg/packagekit/package_pkg.go | 9 ++++----- pkg/packagekit/wix/wix.go | 3 +-- pkg/packagekit/wix/wix_test.go | 3 +-- pkg/packaging/packaging.go | 3 +-- pkg/packaging/packaging_test.go | 3 +-- 21 files changed, 31 insertions(+), 52 deletions(-) diff --git a/ee/desktop/runner/runner.go b/ee/desktop/runner/runner.go index 40cc90d0d..cf7fa1c65 100644 --- a/ee/desktop/runner/runner.go +++ b/ee/desktop/runner/runner.go @@ -755,8 +755,7 @@ func (r *DesktopUsersProcessesRunner) menuTemplatePath() string { // desktopCommand invokes the launcher desktop executable with the appropriate env vars func (r *DesktopUsersProcessesRunner) desktopCommand(executablePath, uid, socketPath, menuPath string) (*exec.Cmd, error) { - // We trust that launcher executable path is correct, so we don't need to use allowedcmd - cmd := exec.Command(executablePath, "desktop") //nolint:forbidigo + cmd := exec.Command(executablePath, "desktop") //nolint:forbidigo // We trust that the launcher executable path is correct, so we don't need to use allowedcmd cmd.Env = []string{ // When we set cmd.Env (as we're doing here/below), cmd will no longer include the default cmd.Environ() diff --git a/ee/desktop/runner/runner_test.go b/ee/desktop/runner/runner_test.go index 338179dd6..7ca7cb4d4 100644 --- a/ee/desktop/runner/runner_test.go +++ b/ee/desktop/runner/runner_test.go @@ -1,4 +1,3 @@ -//nolint:forbidigo package runner import ( @@ -45,7 +44,7 @@ func TestDesktopUserProcessRunner_Execute(t *testing.T) { ctx, cancel := context.WithTimeout(context.Background(), timeout) defer cancel() - cmd := exec.CommandContext(ctx, "go", "build", "-o", executablePath, "../../../cmd/launcher") + cmd := exec.CommandContext(ctx, "go", "build", "-o", executablePath, "../../../cmd/launcher") //nolint:forbidigo // Fine to use exec.CommandContext in test buildStartTime := time.Now() out, err := cmd.CombinedOutput() if err != nil { diff --git a/ee/ui/assets/generator/generator.go b/ee/ui/assets/generator/generator.go index 4f531a647..d4935598a 100644 --- a/ee/ui/assets/generator/generator.go +++ b/ee/ui/assets/generator/generator.go @@ -152,7 +152,7 @@ func generatePng(ctx context.Context, logger log.Logger, name string) error { } // Scaling these doesn't seem to be a win for space or resolution. So leave them as is - cmd := exec.CommandContext(ctx, "cp", input, output) //nolint:forbidigo + cmd := exec.CommandContext(ctx, "cp", input, output) //nolint:forbidigo // Fine to use exec.CommandContext since it's not in launcher proper if err := cmd.Run(); err != nil { return fmt.Errorf("copy: %w", err) } @@ -178,7 +178,7 @@ func generateIco(ctx context.Context, logger log.Logger, name string) error { // First, we need to generate all the sizes for _, size := range icoSizes { - cmd := exec.CommandContext( //nolint:forbidigo + cmd := exec.CommandContext( //nolint:forbidigo // Fine to use exec.CommandContext since it's not in launcher proper ctx, "convert", "-resize", fmt.Sprintf("%sx%s", size, size), @@ -192,7 +192,7 @@ func generateIco(ctx context.Context, logger log.Logger, name string) error { } // Now that we have the intermediary sizes, we can stich them into a single ico - cmd := exec.CommandContext(ctx, "convert", fmt.Sprintf("%s/%s-*.ico", tmpDir, name), output) // nolint:forbidigo + cmd := exec.CommandContext(ctx, "convert", fmt.Sprintf("%s/%s-*.ico", tmpDir, name), output) //nolint:forbidigo // Fine to use exec.CommandContext since it's not in launcher proper level.Debug(logger).Log("msg", "Consolodating ico with", "cmd", cmd.String()) if err := cmd.Run(); err != nil { diff --git a/pkg/allowedcmd/cmd.go b/pkg/allowedcmd/cmd.go index c86c4f7b8..eb054b761 100644 --- a/pkg/allowedcmd/cmd.go +++ b/pkg/allowedcmd/cmd.go @@ -12,7 +12,7 @@ import ( type AllowedCommand func(ctx context.Context, arg ...string) (*exec.Cmd, error) func newCmd(ctx context.Context, fullPathToCmd string, arg ...string) *exec.Cmd { - return exec.CommandContext(ctx, fullPathToCmd, arg...) //nolint:forbidigo + return exec.CommandContext(ctx, fullPathToCmd, arg...) //nolint:forbidigo // This is our approved usage of exec.CommandContext } func validatedCommand(ctx context.Context, knownPath string, arg ...string) (*exec.Cmd, error) { diff --git a/pkg/autoupdate/findnew.go b/pkg/autoupdate/findnew.go index 9551ad744..4162be642 100644 --- a/pkg/autoupdate/findnew.go +++ b/pkg/autoupdate/findnew.go @@ -371,9 +371,7 @@ func CheckExecutable(ctx context.Context, potentialBinary string, args ...string ctx, cancel := context.WithTimeout(ctx, 5*time.Second) defer cancel() - // Since we trust the autoupdate library to find binaries in the correct location, - // we don't require the use of allowedcmd here. - cmd := exec.CommandContext(ctx, potentialBinary, args...) //nolint:forbidigo + cmd := exec.CommandContext(ctx, potentialBinary, args...) //nolint:forbidigo // We trust the autoupdate library to find the correct location so we don't need allowedcmd // Set env, this should prevent launcher for fork-bombing cmd.Env = append(cmd.Env, "LAUNCHER_SKIP_UPDATES=TRUE") diff --git a/pkg/debug/checkups/osquery.go b/pkg/debug/checkups/osquery.go index 50f60894b..981d843d6 100644 --- a/pkg/debug/checkups/osquery.go +++ b/pkg/debug/checkups/osquery.go @@ -48,8 +48,7 @@ func (o *osqueryCheckup) version(ctx context.Context) (string, error) { cmdCtx, cmdCancel := context.WithTimeout(ctx, 10*time.Second) defer cmdCancel() - // We trust the autoupdate library to find the correct path - cmd := exec.CommandContext(cmdCtx, osquerydPath, "--version") //nolint:forbidigo + cmd := exec.CommandContext(cmdCtx, osquerydPath, "--version") //nolint:forbidigo // We trust the autoupdate library to find the correct path hideWindow(cmd) startTime := time.Now().UnixMilli() out, err := cmd.CombinedOutput() @@ -74,7 +73,7 @@ func (o *osqueryCheckup) interactive(ctx context.Context) error { defer cmdCancel() // We trust the autoupdate library to find the correct path - cmd := exec.CommandContext(cmdCtx, launcherPath, "interactive") //nolint:forbidigo + cmd := exec.CommandContext(cmdCtx, launcherPath, "interactive") //nolint:forbidigo // We trust the autoupdate library to find the correct path hideWindow(cmd) cmd.Stdin = strings.NewReader(`select * from osquery_info;`) diff --git a/pkg/execwrapper/exec_windows.go b/pkg/execwrapper/exec_windows.go index a05d93fce..09f37637c 100644 --- a/pkg/execwrapper/exec_windows.go +++ b/pkg/execwrapper/exec_windows.go @@ -19,9 +19,7 @@ import ( func Exec(ctx context.Context, argv0 string, argv []string, envv []string) error { logger := log.With(ctxlog.FromContext(ctx), "caller", log.DefaultCaller) - // execwrapper is used exclusively to exec launcher, and we trust the autoupdate - // library to find the correct path. - cmd := exec.CommandContext(ctx, argv0, argv[1:]...) //nolint:forbidigo + cmd := exec.CommandContext(ctx, argv0, argv[1:]...) //nolint:forbidigo // execwrapper is used exclusively to exec launcher, and we trust the autoupdate library to find the correct path. cmd.Env = envv cmd.Stdin = os.Stdin diff --git a/pkg/make/builder.go b/pkg/make/builder.go index 352e3475f..2dfd1669d 100644 --- a/pkg/make/builder.go +++ b/pkg/make/builder.go @@ -1,11 +1,12 @@ -/* Package make provides some simple functions to handle build and go +/* + Package make provides some simple functions to handle build and go + dependencies. We used to do this with gnumake rules, but as we added windows compatibility, we found make too limiting. Moving this into go allows us to write cleaner cross-platform code. */ -//nolint:forbidigo package make import ( @@ -128,7 +129,7 @@ func New(opts ...Option) *Builder { goPath: "go", goVer: strings.TrimPrefix(runtime.Version(), "go"), - execCC: exec.CommandContext, + execCC: exec.CommandContext, //nolint:forbidigo // Fine to use exec.CommandContext outside of launcher proper } for _, opt := range opts { diff --git a/pkg/make/builder_test.go b/pkg/make/builder_test.go index 12f5d33e8..e21b6bc13 100644 --- a/pkg/make/builder_test.go +++ b/pkg/make/builder_test.go @@ -1,4 +1,3 @@ -//nolint:forbidigo package make import ( @@ -21,7 +20,7 @@ import ( func helperCommandContext(ctx context.Context, command string, args ...string) (cmd *exec.Cmd) { cs := []string{"-test.run=TestHelperProcess", "--", command} cs = append(cs, args...) - cmd = exec.CommandContext(ctx, os.Args[0], cs...) + cmd = exec.CommandContext(ctx, os.Args[0], cs...) //nolint:forbidigo // Fine to use exec.CommandContext in tests cmd.Env = []string{"GO_WANT_HELPER_PROCESS=1"} // Do we have an ENV key? (type assert) diff --git a/pkg/osquery/runsimple/osqueryrunner.go b/pkg/osquery/runsimple/osqueryrunner.go index 336e891fd..783a0cdf5 100644 --- a/pkg/osquery/runsimple/osqueryrunner.go +++ b/pkg/osquery/runsimple/osqueryrunner.go @@ -88,8 +88,7 @@ func (p osqueryProcess) RunSql(ctx context.Context, sql []byte) error { p.stdin = bytes.NewReader(sql) - // We trust the autoupdate library to find the correct path - cmd := exec.CommandContext(ctx, p.osquerydPath, args...) //nolint:forbidigo + cmd := exec.CommandContext(ctx, p.osquerydPath, args...) //nolint:forbidigo // We trust the autoupdate library to find the correct path // It's okay for these to be nil, so we can just set them without checking. cmd.Stdin = p.stdin @@ -104,8 +103,7 @@ func (p osqueryProcess) RunVersion(ctx context.Context) error { "--version", } - // We trust the autoupdate library to find the correct path - cmd := exec.CommandContext(ctx, p.osquerydPath, args...) //nolint:forbidigo + cmd := exec.CommandContext(ctx, p.osquerydPath, args...) //nolint:forbidigo // We trust the autoupdate library to find the correct path // It's okay for these to be nil, so we can just set them without checking. cmd.Stdin = p.stdin diff --git a/pkg/osquery/runtime/osqueryinstance.go b/pkg/osquery/runtime/osqueryinstance.go index 680428978..274cbae7b 100644 --- a/pkg/osquery/runtime/osqueryinstance.go +++ b/pkg/osquery/runtime/osqueryinstance.go @@ -480,9 +480,7 @@ func (opts *osqueryOptions) createOsquerydCommand(osquerydBinary string, paths * if !opts.enableWatchdog { args = append(args, "--disable_watchdog") } - // Since we trust the autoupdate library to find binaries in the correct location, - // we don't require the use of allowedcmd here. - cmd := exec.Command( //nolint:forbidigo + cmd := exec.Command( //nolint:forbidigo // We trust the autoupdate library to find the correct path osquerydBinary, args..., ) diff --git a/pkg/osquery/tables/pwpolicy/pwpolicy_test.go b/pkg/osquery/tables/pwpolicy/pwpolicy_test.go index cdea2c7a4..dd193af6c 100644 --- a/pkg/osquery/tables/pwpolicy/pwpolicy_test.go +++ b/pkg/osquery/tables/pwpolicy/pwpolicy_test.go @@ -1,7 +1,6 @@ //go:build darwin // +build darwin -//nolint:forbidigo package pwpolicy import ( @@ -74,6 +73,6 @@ func TestQueries(t *testing.T) { func execFaker(filename string) func(context.Context, ...string) (*exec.Cmd, error) { return func(ctx context.Context, _ ...string) (*exec.Cmd, error) { - return exec.CommandContext(ctx, "/bin/cat", filename), nil + return exec.CommandContext(ctx, "/bin/cat", filename), nil //nolint:forbidigo // Fine to use exec.CommandContext in test } } diff --git a/pkg/packagekit/applenotarization/applenotarization.go b/pkg/packagekit/applenotarization/applenotarization.go index 3c15118ae..a6312ffd2 100644 --- a/pkg/packagekit/applenotarization/applenotarization.go +++ b/pkg/packagekit/applenotarization/applenotarization.go @@ -1,4 +1,3 @@ -// nolint:forbidigo // Package applenotarization is a wrapper around the apple // notarization tools. // @@ -107,7 +106,7 @@ func (n *Notarizer) runNotarytool(ctx context.Context, command string, target st return []byte(n.fakeResponse), nil } - cmd := exec.CommandContext(ctx, "xcrun", baseArgs...) + cmd := exec.CommandContext(ctx, "xcrun", baseArgs...) //nolint:forbidigo // Fine to use exec.CommandContext outside of launcher proper out, err := cmd.CombinedOutput() if err != nil { diff --git a/pkg/packagekit/authenticode/authenticode_test.go b/pkg/packagekit/authenticode/authenticode_test.go index 80ed3dd89..a472f1a5a 100644 --- a/pkg/packagekit/authenticode/authenticode_test.go +++ b/pkg/packagekit/authenticode/authenticode_test.go @@ -1,7 +1,6 @@ //go:build windows // +build windows -// nolint:forbidigo package authenticode import ( @@ -30,7 +29,7 @@ func TestSign(t *testing.T) { // create a signtoolOptions object so we can call the exec method so := &signtoolOptions{ - execCC: exec.CommandContext, + execCC: exec.CommandContext, //nolint:forbidigo // Fine to use exec.CommandContext in test } ctx, ctxCancel := context.WithTimeout(context.Background(), 120*time.Second) diff --git a/pkg/packagekit/authenticode/authenticode_windows.go b/pkg/packagekit/authenticode/authenticode_windows.go index b6d512d99..a5aef243e 100644 --- a/pkg/packagekit/authenticode/authenticode_windows.go +++ b/pkg/packagekit/authenticode/authenticode_windows.go @@ -7,7 +7,6 @@ // // https://docs.microsoft.com/en-us/dotnet/framework/tools/signtool-exe -// nolint:forbidigo package authenticode import ( @@ -47,7 +46,7 @@ func Sign(ctx context.Context, file string, opts ...SigntoolOpt) error { signtoolPath: "signtool.exe", timestampServer: "http://timestamp.verisign.com/scripts/timstamp.dll", rfc3161Server: "http://sha256timestamp.ws.symantec.com/sha256/timestamp", - execCC: exec.CommandContext, + execCC: exec.CommandContext, //nolint:forbidigo // Fine to use exec.CommandContext outside of launcher proper } for _, opt := range opts { diff --git a/pkg/packagekit/package_fpm.go b/pkg/packagekit/package_fpm.go index 55510890a..bebd766a3 100644 --- a/pkg/packagekit/package_fpm.go +++ b/pkg/packagekit/package_fpm.go @@ -1,4 +1,3 @@ -// nolint:forbidigo package packagekit import ( @@ -144,7 +143,7 @@ func PackageFPM(ctx context.Context, w io.Writer, po *PackageOptions, fpmOpts .. "kolide/fpm:latest", } - cmd := exec.CommandContext(ctx, "docker", append(dockerArgs, fpmCommand...)...) + cmd := exec.CommandContext(ctx, "docker", append(dockerArgs, fpmCommand...)...) //nolint:forbidigo // Fine to use exec.CommandContext outside of launcher proper stderr := new(bytes.Buffer) stdout := new(bytes.Buffer) diff --git a/pkg/packagekit/package_pkg.go b/pkg/packagekit/package_pkg.go index 6d6ef2d47..82ffad135 100644 --- a/pkg/packagekit/package_pkg.go +++ b/pkg/packagekit/package_pkg.go @@ -1,4 +1,3 @@ -// nolint:forbidigo package packagekit import ( @@ -105,7 +104,7 @@ func runPkbuild(ctx context.Context, outputPath string, po *PackageOptions) erro // Run analyze to generate our component plist componentPlist := "./launcher.plist" - analyzeCmd := exec.CommandContext(ctx, "pkgbuild", "--analyze", "--root", po.Root, componentPlist) + analyzeCmd := exec.CommandContext(ctx, "pkgbuild", "--analyze", "--root", po.Root, componentPlist) //nolint:forbidigo // Fine to use exec.CommandContext outside of launcher proper if err := analyzeCmd.Run(); err != nil { return fmt.Errorf("running analyze: %w", err) } @@ -122,7 +121,7 @@ func runPkbuild(ctx context.Context, outputPath string, po *PackageOptions) erro // Set BundleIsRelocatable in the component plist to false -- this makes sure that the installer // will install Kolide.app to the location that we expect - replaceCmd := exec.CommandContext(ctx, "plutil", "-replace", "BundleIsRelocatable", "-bool", "false", componentPlist) + replaceCmd := exec.CommandContext(ctx, "plutil", "-replace", "BundleIsRelocatable", "-bool", "false", componentPlist) //nolint:forbidigo // Fine to use exec.CommandContext outside of launcher proper if err := replaceCmd.Run(); err != nil { return fmt.Errorf("running plutil -replace: %w", err) } @@ -149,7 +148,7 @@ func runPkbuild(ctx context.Context, outputPath string, po *PackageOptions) erro "args", fmt.Sprintf("%v", args), ) - cmd := exec.CommandContext(ctx, "pkgbuild", args...) + cmd := exec.CommandContext(ctx, "pkgbuild", args...) //nolint:forbidigo // Fine to use exec.CommandContext outside of launcher proper stderr := new(bytes.Buffer) cmd.Stderr = stderr @@ -228,7 +227,7 @@ func runProductbuild(ctx context.Context, flatPkgPath, distributionPkgPath strin "args", fmt.Sprintf("%v", args), ) - cmd := exec.CommandContext(ctx, "productbuild", args...) + cmd := exec.CommandContext(ctx, "productbuild", args...) //nolint:forbidigo // Fine to use exec.CommandContext outside of launcher proper stderr := new(bytes.Buffer) cmd.Stderr = stderr diff --git a/pkg/packagekit/wix/wix.go b/pkg/packagekit/wix/wix.go index 1dfc303b8..9c7c41343 100644 --- a/pkg/packagekit/wix/wix.go +++ b/pkg/packagekit/wix/wix.go @@ -1,4 +1,3 @@ -// nolint:forbidigo package wix import ( @@ -108,7 +107,7 @@ func New(packageRoot string, mainWxsContent []byte, wixOpts ...WixOpt) (*wixTool wixPath: FindWixInstall(), packageRoot: packageRoot, - execCC: exec.CommandContext, + execCC: exec.CommandContext, //nolint:forbidigo // Fine to use exec.CommandContext outside of launcher proper } for _, opt := range wixOpts { diff --git a/pkg/packagekit/wix/wix_test.go b/pkg/packagekit/wix/wix_test.go index 47f7f1420..a0c86bab3 100644 --- a/pkg/packagekit/wix/wix_test.go +++ b/pkg/packagekit/wix/wix_test.go @@ -1,4 +1,3 @@ -//nolint:forbidigo package wix import ( @@ -63,7 +62,7 @@ func TestWixPackage(t *testing.T) { // which can mostly read MSI files. func verifyMsi(ctx context.Context, t *testing.T, outMsi string) { // Use the wix struct for its execOut - execWix := &wixTool{execCC: exec.CommandContext} + execWix := &wixTool{execCC: exec.CommandContext} //nolint:forbidigo // Fine to use exec.CommandContext in test fileContents, err := execWix.execOut(ctx, "7z", "x", "-so", outMsi) require.NoError(t, err) diff --git a/pkg/packaging/packaging.go b/pkg/packaging/packaging.go index fe90f4643..84a8cf589 100644 --- a/pkg/packaging/packaging.go +++ b/pkg/packaging/packaging.go @@ -1,4 +1,3 @@ -//nolint:forbidigo package packaging import ( @@ -753,7 +752,7 @@ func (p *PackageOptions) setupDirectories() error { func (p *PackageOptions) execOut(ctx context.Context, argv0 string, args ...string) (string, error) { // Since PackageOptions is sometimes instantiated directly, set execCC if it's nil. if p.execCC == nil { - p.execCC = exec.CommandContext + p.execCC = exec.CommandContext //nolint:forbidigo // Fine to use exec.CommandContext outside of launcher proper } cmd := p.execCC(ctx, argv0, args...) diff --git a/pkg/packaging/packaging_test.go b/pkg/packaging/packaging_test.go index e3e38739e..dc147cf32 100644 --- a/pkg/packaging/packaging_test.go +++ b/pkg/packaging/packaging_test.go @@ -1,4 +1,3 @@ -//nolint:forbidigo package packaging import ( @@ -20,7 +19,7 @@ import ( func helperCommandContext(ctx context.Context, command string, args ...string) (cmd *exec.Cmd) { cs := []string{"-test.run=TestHelperProcess", "--", command} cs = append(cs, args...) - cmd = exec.CommandContext(ctx, os.Args[0], cs...) + cmd = exec.CommandContext(ctx, os.Args[0], cs...) //nolint:forbidigo // Fine to use exec.CommandContext in test cmd.Env = []string{"GO_WANT_HELPER_PROCESS=1"} return cmd } From 0ce1ec46b60230d31ffbe6b281edac1325c88730 Mon Sep 17 00:00:00 2001 From: Rebecca Mahany-Horton Date: Tue, 14 Nov 2023 09:44:49 -0500 Subject: [PATCH 30/30] SYSTEM32 env var not available when running flare, use WINDIR instead --- pkg/allowedcmd/cmd_windows.go | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/pkg/allowedcmd/cmd_windows.go b/pkg/allowedcmd/cmd_windows.go index 7527a051c..5425a5926 100644 --- a/pkg/allowedcmd/cmd_windows.go +++ b/pkg/allowedcmd/cmd_windows.go @@ -11,15 +11,15 @@ import ( ) func CommandPrompt(ctx context.Context, arg ...string) (*exec.Cmd, error) { - return validatedCommand(ctx, filepath.Join(os.Getenv("SYSTEM32"), "cmd.exe"), arg...) + return validatedCommand(ctx, filepath.Join(os.Getenv("WINDIR"), "System32", "cmd.exe"), arg...) } func Dism(ctx context.Context, arg ...string) (*exec.Cmd, error) { - return validatedCommand(ctx, filepath.Join(os.Getenv("SYSTEM32"), "Dism.exe"), arg...) + return validatedCommand(ctx, filepath.Join(os.Getenv("WINDIR"), "System32", "Dism.exe"), arg...) } func Dsregcmd(ctx context.Context, arg ...string) (*exec.Cmd, error) { - return validatedCommand(ctx, filepath.Join(os.Getenv("SYSTEM32"), "dsregcmd.exe"), arg...) + return validatedCommand(ctx, filepath.Join(os.Getenv("WINDIR"), "System32", "dsregcmd.exe"), arg...) } func Echo(ctx context.Context, arg ...string) (*exec.Cmd, error) { @@ -28,15 +28,15 @@ func Echo(ctx context.Context, arg ...string) (*exec.Cmd, error) { } func Ipconfig(ctx context.Context, arg ...string) (*exec.Cmd, error) { - return validatedCommand(ctx, filepath.Join(os.Getenv("SYSTEM32"), "ipconfig.exe"), arg...) + return validatedCommand(ctx, filepath.Join(os.Getenv("WINDIR"), "System32", "ipconfig.exe"), arg...) } func Powercfg(ctx context.Context, arg ...string) (*exec.Cmd, error) { - return validatedCommand(ctx, filepath.Join(os.Getenv("SYSTEM32"), "powercfg.exe"), arg...) + return validatedCommand(ctx, filepath.Join(os.Getenv("WINDIR"), "System32", "powercfg.exe"), arg...) } func Powershell(ctx context.Context, arg ...string) (*exec.Cmd, error) { - return validatedCommand(ctx, filepath.Join(os.Getenv("SYSTEM32"), "WindowsPowerShell", "v1.0", "powershell.exe"), arg...) + return validatedCommand(ctx, filepath.Join(os.Getenv("WINDIR"), "System32", "WindowsPowerShell", "v1.0", "powershell.exe"), arg...) } func Repcli(ctx context.Context, arg ...string) (*exec.Cmd, error) { @@ -44,11 +44,11 @@ func Repcli(ctx context.Context, arg ...string) (*exec.Cmd, error) { } func Secedit(ctx context.Context, arg ...string) (*exec.Cmd, error) { - return validatedCommand(ctx, filepath.Join(os.Getenv("SYSTEM32"), "SecEdit.exe"), arg...) + return validatedCommand(ctx, filepath.Join(os.Getenv("WINDIR"), "System32", "SecEdit.exe"), arg...) } func Taskkill(ctx context.Context, arg ...string) (*exec.Cmd, error) { - return validatedCommand(ctx, filepath.Join(os.Getenv("SYSTEM32"), "taskkill.exe"), arg...) + return validatedCommand(ctx, filepath.Join(os.Getenv("WINDIR"), "System32", "taskkill.exe"), arg...) } func ZerotierCli(ctx context.Context, arg ...string) (*exec.Cmd, error) {