wpasupplicant: Disable D-Bus auto-activation on all calls
Every method call and property access to fi.w1.wpa_supplicant1 used flag 0, leaving D-Bus service activation enabled. Any stray request — a startup race before `service wpa_supplicant start` takes effect, or a leaked call while the Ethernet uplink is the chosen path — would make the bus daemon spawn `wpa_supplicant -u` from its .service file, bypassing repeater's own launch of the daemon. Route every interaction through callNoAutoStart/getPropNoAutoStart/ setPropNoAutoStart, which set dbus.FlagNoAutoStart. A leaked call now fails cleanly with ServiceUnknown instead of resurrecting the daemon, leaving repeater as the sole launcher. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
parent
15d17ed35e
commit
11ae69de56
5 changed files with 85 additions and 25 deletions
60
internal/wifi/wpasupplicant/dbusutil.go
Normal file
60
internal/wifi/wpasupplicant/dbusutil.go
Normal file
|
|
@ -0,0 +1,60 @@
|
|||
package wpasupplicant
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
"github.com/godbus/dbus/v5"
|
||||
)
|
||||
|
||||
// D-Bus interactions with the fi.w1.wpa_supplicant1 name must never trigger
|
||||
// service activation. repeater is the sole launcher of the daemon (via
|
||||
// `service wpa_supplicant start` in the app layer); if a call reached the bus
|
||||
// name while the daemon was down — a startup race, or a stray call in
|
||||
// Ethernet-uplink mode — the bus would auto-activate it from its .service
|
||||
// file, spawning `wpa_supplicant -u` and bypassing repeater's own launch.
|
||||
//
|
||||
// godbus only suppresses activation when FlagNoAutoStart is set on the message
|
||||
// (msg.Flags = flags & (FlagNoAutoStart | FlagNoReplyExpected)); the default
|
||||
// flag value of 0 leaves activation enabled. The helpers below set the flag on
|
||||
// every method call and property access. A leaked call then fails cleanly with
|
||||
// a ServiceUnknown error instead of resurrecting the daemon.
|
||||
|
||||
// callNoAutoStart performs a method call with D-Bus auto-activation disabled.
|
||||
func callNoAutoStart(obj dbus.BusObject, method string, args ...interface{}) *dbus.Call {
|
||||
return obj.Call(method, dbus.FlagNoAutoStart, args...)
|
||||
}
|
||||
|
||||
// getPropNoAutoStart reads a property (interface.member notation) with
|
||||
// auto-activation disabled. It mirrors dbus.Object.GetProperty, which
|
||||
// otherwise issues Properties.Get with the activation-enabling flag 0.
|
||||
func getPropNoAutoStart(obj dbus.BusObject, p string) (dbus.Variant, error) {
|
||||
var result dbus.Variant
|
||||
iface, prop, err := splitProperty(p)
|
||||
if err != nil {
|
||||
return result, err
|
||||
}
|
||||
err = obj.Call("org.freedesktop.DBus.Properties.Get", dbus.FlagNoAutoStart, iface, prop).Store(&result)
|
||||
return result, err
|
||||
}
|
||||
|
||||
// setPropNoAutoStart writes a property with auto-activation disabled. The value
|
||||
// is passed through as-is, so callers wrap it in a dbus.Variant just as they
|
||||
// would for dbus.Object.SetProperty.
|
||||
func setPropNoAutoStart(obj dbus.BusObject, p string, v interface{}) error {
|
||||
iface, prop, err := splitProperty(p)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return obj.Call("org.freedesktop.DBus.Properties.Set", dbus.FlagNoAutoStart, iface, prop, v).Err
|
||||
}
|
||||
|
||||
// splitProperty splits an "interface.member" property name into its interface
|
||||
// and member parts, matching godbus's own parsing.
|
||||
func splitProperty(p string) (iface, prop string, err error) {
|
||||
idx := strings.LastIndex(p, ".")
|
||||
if idx == -1 || idx+1 == len(p) {
|
||||
return "", "", fmt.Errorf("dbus: invalid property %s", p)
|
||||
}
|
||||
return p[:idx], p[idx+1:], nil
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue