mirror of
https://github.com/AvengeMedia/DankMaterialShell.git
synced 2026-08-07 05:58:28 -04:00
core: fix security and concurrency issues found in a backend audit (#2805)
* core: fix security and concurrency issues found in backend audit Security: - privesc: pipe the sudo password via stdin (sudo -S) instead of embedding it in the command string, so it no longer appears in argv (readable by any local user via /proc/<pid>/cmdline or ps) - greeter: tokenize a session .desktop Exec= line into argv and execve directly instead of running it through /bin/sh -c, closing a command- injection path via user-writable ~/.local/share/wayland-sessions - plugins: reject path-separator/.. in plugin id/name before joining into a filesystem path, closing an arbitrary-directory-delete in the uninstall/update fallback - keybinds/hyprland: always quote unrecognized bind actions/keys when writing generated Lua; only re-emit genuine round-tripped custom Lua verbatim (tracked via an explicit flag), closing a Lua-injection path - desktop/mimeapps: reject newline/bracket in mime/desktop-id fields so they can't inject fake sections into the shared mimeapps.list Robustness / concurrency: - server: recover panics in the request-dispatch path so one bad handler can't crash the daemon and drop every client - go-wayland: recover panics in the shared dispatch choke point so a malformed compositor event can't crash CLI tools / the daemon - server: per-connection D-Bus client ID instead of a shared constant, fixing cross-client signal delivery and subscription teardown - network: guard the NetworkManager device maps with a mutex (a concurrent map read/write here is an unrecoverable fatal error) - cups: close the event channel on Stop() so Unsubscribe() of the last subscriber no longer deadlocks; allocate the fresh channel in Start() - freedesktop: reuse the shared session conn for the settings watcher and tear it down in Close(), fixing a per-Manager conn+goroutine leak - clipboard: mutex-guard lazy dbusConn creation - geolocation: use WithMatchMember for the GeoClue2 LocationUpdated signal (was WithMatchSender with an interface.member string, so the match never fired and live location updates never arrived) - screenshot: set failed=true on buffer/pool creation errors so the dispatch loop doesn't wait forever for a ready/failed that never comes * apply code review comments --------- Co-authored-by: bbedward <bbedward@gmail.com>
This commit is contained in:
@@ -135,15 +135,14 @@ func EscapeSingleQuotes(s string) string {
|
||||
}
|
||||
|
||||
// MakeCommand returns a bash command string that runs `command` with the
|
||||
// detected tool. When the tool supports stdin passwords and password is
|
||||
// non-empty, the password is piped in. Otherwise the tool is invoked with
|
||||
// no non-interactive flag so that an interactive TTY prompt is still
|
||||
// possible for CLI callers.
|
||||
// detected tool, prompting interactively on a TTY where applicable. The
|
||||
// sudo-with-password case lives in ExecCommand, which pipes the password via
|
||||
// stdin so it never lands in argv.
|
||||
//
|
||||
// If detection fails, the returned shell string exits 1 with an error
|
||||
// message so callers that treat the *exec.Cmd as infallible still fail
|
||||
// deterministically.
|
||||
func MakeCommand(password, command string) string {
|
||||
func MakeCommand(command string) string {
|
||||
t, err := Detect()
|
||||
if err != nil {
|
||||
return failingShell(err)
|
||||
@@ -151,9 +150,6 @@ func MakeCommand(password, command string) string {
|
||||
|
||||
switch t {
|
||||
case ToolSudo:
|
||||
if password != "" {
|
||||
return fmt.Sprintf("echo '%s' | sudo -S %s", EscapeSingleQuotes(password), command)
|
||||
}
|
||||
return fmt.Sprintf("sudo %s", command)
|
||||
case ToolDoas:
|
||||
return fmt.Sprintf("doas sh -c '%s'", EscapeSingleQuotes(command))
|
||||
@@ -166,9 +162,19 @@ func MakeCommand(password, command string) string {
|
||||
|
||||
// ExecCommand builds an exec.Cmd that runs `command` as root via the
|
||||
// detected tool. Detection errors surface at Run() time as a failing
|
||||
// command writing a clear error to stderr.
|
||||
// command writing a clear error to stderr. A sudo password is piped via
|
||||
// stdin (sudo -S) so it never appears in argv.
|
||||
func ExecCommand(ctx context.Context, password, command string) *exec.Cmd {
|
||||
return exec.CommandContext(ctx, "bash", "-c", MakeCommand(password, command))
|
||||
t, err := Detect()
|
||||
if err != nil {
|
||||
return exec.CommandContext(ctx, "bash", "-c", failingShell(err))
|
||||
}
|
||||
if t == ToolSudo && password != "" {
|
||||
cmd := exec.CommandContext(ctx, "sudo", "-S", "sh", "-c", command)
|
||||
cmd.Stdin = strings.NewReader(password + "\n")
|
||||
return cmd
|
||||
}
|
||||
return exec.CommandContext(ctx, "bash", "-c", MakeCommand(command))
|
||||
}
|
||||
|
||||
// ExecArgv builds an exec.Cmd that runs argv as root via the detected tool.
|
||||
|
||||
Reference in New Issue
Block a user