1
0
mirror of https://github.com/AvengeMedia/DankMaterialShell.git synced 2026-08-06 05:28:29 -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>
(cherry picked from commit ca89e12963)
This commit is contained in:
Rafi
2026-07-13 15:44:42 -04:00
committed by bbedward
parent 7f37799e53
commit d96559f7df
25 changed files with 522 additions and 132 deletions
@@ -2,6 +2,7 @@ package network
import (
"fmt"
"maps"
"sync"
"github.com/AvengeMedia/DankMaterialShell/core/internal/log"
@@ -57,6 +58,11 @@ type NetworkManagerBackend struct {
wifiDev any
wifiDevices map[string]*wifiDeviceInfo
// devMutex guards ethernetDevices/wifiDevices (written by the signal pump,
// read by request handlers). Not reentrant — never hold it across calls
// into other backend methods.
devMutex sync.RWMutex
dbusConn *dbus.Conn
signals chan *dbus.Signal
sigWG sync.WaitGroup
@@ -185,12 +191,12 @@ func (b *NetworkManagerBackend) Initialize() error {
}
hwAddr, _ := w.GetPropertyHwAddress()
b.ethernetDevices[iface] = &ethernetDeviceInfo{
b.setEthernetDeviceInfo(iface, &ethernetDeviceInfo{
device: dev,
wired: w,
name: iface,
hwAddress: hwAddr,
}
})
if b.ethernetDevice == nil {
b.ethernetDevice = dev
@@ -214,12 +220,12 @@ func (b *NetworkManagerBackend) Initialize() error {
}
hwAddr, _ := w.GetPropertyHwAddress()
b.wifiDevices[iface] = &wifiDeviceInfo{
b.setWifiDeviceInfo(iface, &wifiDeviceInfo{
device: dev,
wireless: w,
name: iface,
hwAddress: hwAddr,
}
})
if b.wifiDevice == nil {
b.wifiDevice = dev
@@ -267,6 +273,80 @@ func (b *NetworkManagerBackend) Initialize() error {
return nil
}
func (b *NetworkManagerBackend) ethernetDevicesSnapshot() map[string]*ethernetDeviceInfo {
b.devMutex.RLock()
defer b.devMutex.RUnlock()
out := make(map[string]*ethernetDeviceInfo, len(b.ethernetDevices))
maps.Copy(out, b.ethernetDevices)
return out
}
func (b *NetworkManagerBackend) wifiDevicesSnapshot() map[string]*wifiDeviceInfo {
b.devMutex.RLock()
defer b.devMutex.RUnlock()
out := make(map[string]*wifiDeviceInfo, len(b.wifiDevices))
maps.Copy(out, b.wifiDevices)
return out
}
func (b *NetworkManagerBackend) ethernetDeviceByIface(iface string) (*ethernetDeviceInfo, bool) {
b.devMutex.RLock()
defer b.devMutex.RUnlock()
info, ok := b.ethernetDevices[iface]
return info, ok
}
func (b *NetworkManagerBackend) wifiDeviceByIface(iface string) (*wifiDeviceInfo, bool) {
b.devMutex.RLock()
defer b.devMutex.RUnlock()
info, ok := b.wifiDevices[iface]
return info, ok
}
func (b *NetworkManagerBackend) setEthernetDeviceInfo(iface string, info *ethernetDeviceInfo) {
b.devMutex.Lock()
b.ethernetDevices[iface] = info
b.devMutex.Unlock()
}
func (b *NetworkManagerBackend) setWifiDeviceInfo(iface string, info *wifiDeviceInfo) {
b.devMutex.Lock()
b.wifiDevices[iface] = info
b.devMutex.Unlock()
}
// removeEthernetDeviceByPath deletes the device and returns a snapshot of
// what's left so the caller can pick a replacement without holding devMutex
func (b *NetworkManagerBackend) removeEthernetDeviceByPath(path dbus.ObjectPath) (removed *ethernetDeviceInfo, remaining map[string]*ethernetDeviceInfo, found bool) {
b.devMutex.Lock()
defer b.devMutex.Unlock()
for iface, info := range b.ethernetDevices {
if info.device.GetPath() != path {
continue
}
delete(b.ethernetDevices, iface)
remaining = make(map[string]*ethernetDeviceInfo, len(b.ethernetDevices))
maps.Copy(remaining, b.ethernetDevices)
return info, remaining, true
}
return nil, nil, false
}
func (b *NetworkManagerBackend) removeWifiDeviceByPath(path dbus.ObjectPath) (removed *wifiDeviceInfo, remaining map[string]*wifiDeviceInfo, found bool) {
b.devMutex.Lock()
defer b.devMutex.Unlock()
for iface, info := range b.wifiDevices {
if info.device.GetPath() != path {
continue
}
delete(b.wifiDevices, iface)
remaining = make(map[string]*wifiDeviceInfo, len(b.wifiDevices))
maps.Copy(remaining, b.wifiDevices)
return info, remaining, true
}
return nil, nil, false
}
func (b *NetworkManagerBackend) Close() {
close(b.stopChan)
b.StopMonitoring()
@@ -323,7 +323,7 @@ func (b *NetworkManagerBackend) GetEthernetDevices() []EthernetDevice {
}
func (b *NetworkManagerBackend) DisconnectEthernetDevice(device string) error {
info, ok := b.ethernetDevices[device]
info, ok := b.ethernetDeviceByIface(device)
if !ok {
return fmt.Errorf("ethernet device %s not found", device)
}
@@ -345,9 +345,10 @@ func (b *NetworkManagerBackend) DisconnectEthernetDevice(device string) error {
}
func (b *NetworkManagerBackend) updateAllEthernetDevices() {
devices := make([]EthernetDevice, 0, len(b.ethernetDevices))
ethernetDevices := b.ethernetDevicesSnapshot()
devices := make([]EthernetDevice, 0, len(ethernetDevices))
for name, info := range b.ethernetDevices {
for name, info := range ethernetDevices {
state, _ := info.device.GetPropertyState()
connected := state == gonetworkmanager.NmDeviceStateActivated
driver, _ := info.device.GetPropertyDriver()
@@ -112,7 +112,7 @@ func (b *NetworkManagerBackend) startSignalPump() error {
return err
}
for _, info := range b.wifiDevices {
for _, info := range b.wifiDevicesSnapshot() {
if err := conn.AddMatchSignal(
dbus.WithMatchObjectPath(dbus.ObjectPath(info.device.GetPath())),
dbus.WithMatchInterface(dbusPropsInterface),
@@ -124,7 +124,7 @@ func (b *NetworkManagerBackend) startSignalPump() error {
}
}
for _, info := range b.ethernetDevices {
for _, info := range b.ethernetDevicesSnapshot() {
if err := conn.AddMatchSignal(
dbus.WithMatchObjectPath(dbus.ObjectPath(info.device.GetPath())),
dbus.WithMatchInterface(dbusPropsInterface),
@@ -227,7 +227,7 @@ func (b *NetworkManagerBackend) stopSignalPump() {
dbus.WithMatchMember("StateChanged"),
)
for _, info := range b.wifiDevices {
for _, info := range b.wifiDevicesSnapshot() {
b.dbusConn.RemoveMatchSignal(
dbus.WithMatchObjectPath(dbus.ObjectPath(info.device.GetPath())),
dbus.WithMatchInterface(dbusPropsInterface),
@@ -235,7 +235,7 @@ func (b *NetworkManagerBackend) stopSignalPump() {
)
}
for _, info := range b.ethernetDevices {
for _, info := range b.ethernetDevicesSnapshot() {
b.dbusConn.RemoveMatchSignal(
dbus.WithMatchObjectPath(dbus.ObjectPath(info.device.GetPath())),
dbus.WithMatchInterface(dbusPropsInterface),
@@ -550,12 +550,12 @@ func (b *NetworkManagerBackend) handleDeviceAdded(devicePath dbus.ObjectPath) {
}
hwAddr, _ := w.GetPropertyHwAddress()
b.ethernetDevices[iface] = &ethernetDeviceInfo{
b.setEthernetDeviceInfo(iface, &ethernetDeviceInfo{
device: dev,
wired: w,
name: iface,
hwAddress: hwAddr,
}
})
if b.ethernetDevice == nil {
b.ethernetDevice = dev
@@ -573,12 +573,12 @@ func (b *NetworkManagerBackend) handleDeviceAdded(devicePath dbus.ObjectPath) {
}
hwAddr, _ := w.GetPropertyHwAddress()
b.wifiDevices[iface] = &wifiDeviceInfo{
b.setWifiDeviceInfo(iface, &wifiDeviceInfo{
device: dev,
wireless: w,
name: iface,
hwAddress: hwAddr,
}
})
if b.wifiDevice == nil {
b.wifiDevice = dev
@@ -603,57 +603,49 @@ func (b *NetworkManagerBackend) handleDeviceRemoved(devicePath dbus.ObjectPath)
)
}
for iface, info := range b.ethernetDevices {
if info.device.GetPath() == devicePath {
delete(b.ethernetDevices, iface)
if b.ethernetDevice != nil {
dev := b.ethernetDevice.(gonetworkmanager.Device)
if dev.GetPath() == devicePath {
b.ethernetDevice = nil
for _, remaining := range b.ethernetDevices {
b.ethernetDevice = remaining.device
break
}
if _, remaining, found := b.removeEthernetDeviceByPath(devicePath); found {
if b.ethernetDevice != nil {
dev := b.ethernetDevice.(gonetworkmanager.Device)
if dev.GetPath() == devicePath {
b.ethernetDevice = nil
for _, r := range remaining {
b.ethernetDevice = r.device
break
}
}
b.updateAllEthernetDevices()
b.updateEthernetState()
b.listEthernetConnections()
b.updatePrimaryConnection()
if b.onStateChange != nil {
b.onStateChange()
}
return
}
b.updateAllEthernetDevices()
b.updateEthernetState()
b.listEthernetConnections()
b.updatePrimaryConnection()
if b.onStateChange != nil {
b.onStateChange()
}
return
}
for iface, info := range b.wifiDevices {
if info.device.GetPath() == devicePath {
delete(b.wifiDevices, iface)
if b.wifiDevice != nil {
dev := b.wifiDevice.(gonetworkmanager.Device)
if dev.GetPath() == devicePath {
b.wifiDevice = nil
b.wifiDev = nil
for _, remaining := range b.wifiDevices {
b.wifiDevice = remaining.device
b.wifiDev = remaining.wireless
break
}
if _, remaining, found := b.removeWifiDeviceByPath(devicePath); found {
if b.wifiDevice != nil {
dev := b.wifiDevice.(gonetworkmanager.Device)
if dev.GetPath() == devicePath {
b.wifiDevice = nil
b.wifiDev = nil
for _, r := range remaining {
b.wifiDevice = r.device
b.wifiDev = r.wireless
break
}
}
b.updateAllWiFiDevices()
b.updateWiFiState()
if b.onStateChange != nil {
b.onStateChange()
}
return
}
b.updateAllWiFiDevices()
b.updateWiFiState()
if b.onStateChange != nil {
b.onStateChange()
}
return
}
}
@@ -76,7 +76,7 @@ func (b *NetworkManagerBackend) updateEthernetState() error {
var connectedIP string
var anyConnected bool
for name, info := range b.ethernetDevices {
for name, info := range b.ethernetDevicesSnapshot() {
state, err := info.device.GetPropertyState()
if err != nil {
continue
@@ -973,7 +973,7 @@ func (b *NetworkManagerBackend) SetWiFiAutoconnect(ssid string, autoconnect bool
}
func (b *NetworkManagerBackend) ScanWiFiDevice(device string) error {
devInfo, ok := b.wifiDevices[device]
devInfo, ok := b.wifiDeviceByIface(device)
if !ok {
return fmt.Errorf("WiFi device not found: %s", device)
}
@@ -995,7 +995,7 @@ func (b *NetworkManagerBackend) ScanWiFiDevice(device string) error {
}
func (b *NetworkManagerBackend) DisconnectWiFiDevice(device string) error {
devInfo, ok := b.wifiDevices[device]
devInfo, ok := b.wifiDeviceByIface(device)
if !ok {
return fmt.Errorf("WiFi device not found: %s", device)
}
@@ -1047,7 +1047,7 @@ func (b *NetworkManagerBackend) updateAllWiFiDevices() {
wifiConnected := b.state.WiFiConnected
b.stateMutex.RUnlock()
for name, devInfo := range b.wifiDevices {
for name, devInfo := range b.wifiDevicesSnapshot() {
state, _ := devInfo.device.GetPropertyState()
connected := state == gonetworkmanager.NmDeviceStateActivated
@@ -1211,7 +1211,7 @@ func (b *NetworkManagerBackend) updateAllWiFiDevices() {
func (b *NetworkManagerBackend) getWifiDeviceForConnection(deviceName string) (*wifiDeviceInfo, error) {
if deviceName != "" {
devInfo, ok := b.wifiDevices[deviceName]
devInfo, ok := b.wifiDeviceByIface(deviceName)
if !ok {
return nil, fmt.Errorf("WiFi device not found: %s", deviceName)
}
@@ -1224,7 +1224,7 @@ func (b *NetworkManagerBackend) getWifiDeviceForConnection(deviceName string) (*
dev := b.wifiDevice.(gonetworkmanager.Device)
iface, _ := dev.GetPropertyInterface()
if devInfo, ok := b.wifiDevices[iface]; ok {
if devInfo, ok := b.wifiDeviceByIface(iface); ok {
return devInfo, nil
}