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:
@@ -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] = ðernetDeviceInfo{
|
||||
b.setEthernetDeviceInfo(iface, ðernetDeviceInfo{
|
||||
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] = ðernetDeviceInfo{
|
||||
b.setEthernetDeviceInfo(iface, ðernetDeviceInfo{
|
||||
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
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user