fortify/system/dbus.go
Ophestra 5979d8b1e0
All checks were successful
Test / Create distribution (push) Successful in 27s
Test / Sandbox (push) Successful in 1m50s
Test / Fortify (push) Successful in 2m49s
Test / Sandbox (race detector) (push) Successful in 3m4s
Test / Fpkg (push) Successful in 3m35s
Test / Fortify (race detector) (push) Successful in 4m13s
Test / Flake checks (push) Successful in 1m3s
dbus: clean up wrapper implementation
The dbus proxy wrapper haven't been updated much ever since the helper interface was introduced.

Signed-off-by: Ophestra <cat@gensokyo.uk>
2025-04-16 23:35:17 +09:00

162 lines
3.8 KiB
Go

package system
import (
"bytes"
"context"
"errors"
"log"
"strings"
"sync"
"syscall"
"git.gensokyo.uk/security/fortify/dbus"
)
var (
ErrDBusConfig = errors.New("dbus config not supplied")
)
func (sys *I) MustProxyDBus(sessionPath string, session *dbus.Config, systemPath string, system *dbus.Config) *I {
if _, err := sys.ProxyDBus(session, system, sessionPath, systemPath); err != nil {
panic(err.Error())
} else {
return sys
}
}
func (sys *I) ProxyDBus(session, system *dbus.Config, sessionPath, systemPath string) (func(), error) {
d := new(DBus)
// session bus is required as otherwise this is effectively a very expensive noop
if session == nil {
return nil, msg.WrapErr(ErrDBusConfig,
"attempted to create message bus proxy args without session bus config")
}
// system bus is optional
d.system = system != nil
d.sessionBus[0], d.systemBus[0] = dbus.Address()
d.sessionBus[1], d.systemBus[1] = sessionPath, systemPath
d.out = &scanToFmsg{msg: new(strings.Builder)}
if final, err := dbus.Finalise(d.sessionBus, d.systemBus, session, system); err != nil {
if errors.Is(err, syscall.EINVAL) {
return nil, msg.WrapErr(err, "message bus proxy configuration contains NUL byte")
}
return nil, wrapErrSuffix(err, "cannot finalise message bus proxy:")
} else {
if msg.IsVerbose() {
msg.Verbose("session bus proxy:", session.Args(d.sessionBus))
if system != nil {
msg.Verbose("system bus proxy:", system.Args(d.systemBus))
}
// this calls the argsWt String method
msg.Verbose("message bus proxy final args:", final.WriterTo)
}
d.final = final
}
sys.ops = append(sys.ops, d)
return d.out.Dump, nil
}
type DBus struct {
proxy *dbus.Proxy // populated during apply
final *dbus.Final
out *scanToFmsg
// whether system bus proxy is enabled
system bool
sessionBus, systemBus dbus.ProxyPair
}
func (d *DBus) Type() Enablement { return Process }
func (d *DBus) apply(sys *I) error {
msg.Verbosef("session bus proxy on %q for upstream %q", d.sessionBus[1], d.sessionBus[0])
if d.system {
msg.Verbosef("system bus proxy on %q for upstream %q", d.systemBus[1], d.systemBus[0])
}
d.proxy = dbus.New(sys.ctx, d.final, d.out)
if err := d.proxy.Start(); err != nil {
d.out.Dump()
return wrapErrSuffix(err,
"cannot start message bus proxy:")
}
msg.Verbose("starting message bus proxy", d.proxy)
return nil
}
func (d *DBus) revert(*I, *Criteria) error {
// criteria ignored here since dbus is always process-scoped
msg.Verbose("terminating message bus proxy")
d.proxy.Close()
defer msg.Verbose("message bus proxy exit")
err := d.proxy.Wait()
if errors.Is(err, context.Canceled) {
msg.Verbose("message bus proxy canceled upstream")
err = nil
}
return wrapErrSuffix(err, "message bus proxy error:")
}
func (d *DBus) Is(o Op) bool {
d0, ok := o.(*DBus)
return ok && d0 != nil &&
((d.proxy == nil && d0.proxy == nil) ||
(d.proxy != nil && d0.proxy != nil && d.proxy.String() == d0.proxy.String()))
}
func (d *DBus) Path() string {
return "(dbus proxy)"
}
func (d *DBus) String() string {
return d.proxy.String()
}
type scanToFmsg struct {
msg *strings.Builder
msgbuf []string
mu sync.RWMutex
}
func (s *scanToFmsg) Write(p []byte) (n int, err error) {
s.mu.Lock()
defer s.mu.Unlock()
return s.write(p, 0)
}
func (s *scanToFmsg) write(p []byte, a int) (int, error) {
if i := bytes.IndexByte(p, '\n'); i == -1 {
n, _ := s.msg.Write(p)
return a + n, nil
} else {
n, _ := s.msg.Write(p[:i])
// allow container init messages through
v := s.msg.String()
if strings.HasPrefix(v, "init: ") {
log.Println("(dbus) " + v)
} else {
s.msgbuf = append(s.msgbuf, v)
}
s.msg.Reset()
return s.write(p[i+1:], a+n+1)
}
}
func (s *scanToFmsg) Dump() {
s.mu.RLock()
for _, msg := range s.msgbuf {
log.Println("(dbus) " + msg)
}
s.mu.RUnlock()
}