dbus: run in native sandbox
Signed-off-by: Ophestra <cat@gensokyo.uk>
This commit is contained in:
parent
bc54db54d2
commit
44277dc0f1
@ -1,6 +1,7 @@
|
|||||||
package dbus_test
|
package dbus_test
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"bytes"
|
||||||
"context"
|
"context"
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
@ -12,6 +13,8 @@ import (
|
|||||||
|
|
||||||
"git.gensokyo.uk/security/fortify/dbus"
|
"git.gensokyo.uk/security/fortify/dbus"
|
||||||
"git.gensokyo.uk/security/fortify/helper"
|
"git.gensokyo.uk/security/fortify/helper"
|
||||||
|
"git.gensokyo.uk/security/fortify/internal"
|
||||||
|
"git.gensokyo.uk/security/fortify/internal/sandbox"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestNew(t *testing.T) {
|
func TestNew(t *testing.T) {
|
||||||
@ -103,6 +106,10 @@ func TestProxy_Seal(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func TestProxy_Start_Wait_Close_String(t *testing.T) {
|
func TestProxy_Start_Wait_Close_String(t *testing.T) {
|
||||||
|
oldWaitDelay := helper.WaitDelay
|
||||||
|
helper.WaitDelay = 16 * time.Second
|
||||||
|
t.Cleanup(func() { helper.WaitDelay = oldWaitDelay })
|
||||||
|
|
||||||
t.Run("sandbox", func(t *testing.T) {
|
t.Run("sandbox", func(t *testing.T) {
|
||||||
proxyName := dbus.ProxyName
|
proxyName := dbus.ProxyName
|
||||||
dbus.ProxyName = os.Args[0]
|
dbus.ProxyName = os.Args[0]
|
||||||
@ -112,7 +119,7 @@ func TestProxy_Start_Wait_Close_String(t *testing.T) {
|
|||||||
t.Run("direct", func(t *testing.T) { testProxyStartWaitCloseString(t, false) })
|
t.Run("direct", func(t *testing.T) { testProxyStartWaitCloseString(t, false) })
|
||||||
}
|
}
|
||||||
|
|
||||||
func testProxyStartWaitCloseString(t *testing.T, sandbox bool) {
|
func testProxyStartWaitCloseString(t *testing.T, useSandbox bool) {
|
||||||
for id, tc := range testCasePairs() {
|
for id, tc := range testCasePairs() {
|
||||||
// this test does not test errors
|
// this test does not test errors
|
||||||
if tc[0].wantErr {
|
if tc[0].wantErr {
|
||||||
@ -130,25 +137,28 @@ func testProxyStartWaitCloseString(t *testing.T, sandbox bool) {
|
|||||||
|
|
||||||
t.Run("proxy for "+id, func(t *testing.T) {
|
t.Run("proxy for "+id, func(t *testing.T) {
|
||||||
p := dbus.New(tc[0].bus, tc[1].bus)
|
p := dbus.New(tc[0].bus, tc[1].bus)
|
||||||
p.CmdF = func(cmd *exec.Cmd) {
|
p.CommandContext = func(ctx context.Context) (cmd *exec.Cmd) {
|
||||||
wantArgv0 := dbus.ProxyName
|
return exec.CommandContext(ctx, os.Args[0], "-test.v",
|
||||||
if sandbox {
|
"-test.run=TestHelperInit", "--", "init")
|
||||||
wantArgv0 = "bwrap"
|
}
|
||||||
}
|
p.CmdF = func(v any) {
|
||||||
if cmd.Args[0] != wantArgv0 {
|
if useSandbox {
|
||||||
panic(fmt.Sprintf("unexpected argv0 %q", os.Args[0]))
|
container := v.(*sandbox.Container)
|
||||||
}
|
if container.Args[0] != dbus.ProxyName {
|
||||||
cmd.Err = nil
|
panic(fmt.Sprintf("unexpected argv0 %q", os.Args[0]))
|
||||||
cmd.Path = os.Args[0]
|
}
|
||||||
|
container.Args = append([]string{os.Args[0], "-test.run=TestHelperStub", "--"}, container.Args[1:]...)
|
||||||
if sandbox {
|
|
||||||
cmd.Args = append([]string{os.Args[0], "-test.run=TestHelperStub", "--"},
|
|
||||||
append(cmd.Args[:5], append([]string{"-test.run=TestHelperStub", "--"}, cmd.Args[5:]...)...)...)
|
|
||||||
cmd.Env = append(cmd.Env, "GO_TEST_FORTIFY_BWRAP_STUB_TYPE=dbus")
|
|
||||||
} else {
|
} else {
|
||||||
|
cmd := v.(*exec.Cmd)
|
||||||
|
if cmd.Args[0] != dbus.ProxyName {
|
||||||
|
panic(fmt.Sprintf("unexpected argv0 %q", os.Args[0]))
|
||||||
|
}
|
||||||
|
cmd.Err = nil
|
||||||
|
cmd.Path = os.Args[0]
|
||||||
cmd.Args = append([]string{os.Args[0], "-test.run=TestHelperStub", "--"}, cmd.Args[1:]...)
|
cmd.Args = append([]string{os.Args[0], "-test.run=TestHelperStub", "--"}, cmd.Args[1:]...)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
p.FilterF = func(v []byte) []byte { return bytes.SplitN(v, []byte("TestHelperInit\n"), 2)[1] }
|
||||||
output := new(strings.Builder)
|
output := new(strings.Builder)
|
||||||
|
|
||||||
t.Run("unsealed", func(t *testing.T) {
|
t.Run("unsealed", func(t *testing.T) {
|
||||||
@ -163,7 +173,7 @@ func testProxyStartWaitCloseString(t *testing.T, sandbox bool) {
|
|||||||
|
|
||||||
t.Run("start", func(t *testing.T) {
|
t.Run("start", func(t *testing.T) {
|
||||||
want := "proxy not sealed"
|
want := "proxy not sealed"
|
||||||
if err := p.Start(context.Background(), nil, sandbox); err == nil || err.Error() != want {
|
if err := p.Start(context.Background(), nil, useSandbox); err == nil || err.Error() != want {
|
||||||
t.Errorf("Start() error = %v, wantErr %q",
|
t.Errorf("Start() error = %v, wantErr %q",
|
||||||
err, errors.New(want))
|
err, errors.New(want))
|
||||||
return
|
return
|
||||||
@ -200,18 +210,15 @@ func testProxyStartWaitCloseString(t *testing.T, sandbox bool) {
|
|||||||
ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
|
ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
|
||||||
defer cancel()
|
defer cancel()
|
||||||
|
|
||||||
if err := p.Start(ctx, output, sandbox); err != nil {
|
if err := p.Start(ctx, output, useSandbox); err != nil {
|
||||||
t.Fatalf("Start(nil, nil) error = %v",
|
t.Fatalf("Start(nil, nil) error = %v",
|
||||||
err)
|
err)
|
||||||
}
|
}
|
||||||
|
|
||||||
t.Run("string", func(t *testing.T) {
|
t.Run("string", func(t *testing.T) {
|
||||||
wantSubstr := fmt.Sprintf("%s -test.run=TestHelperStub -- --args=3 --fd=4", os.Args[0])
|
wantSubstr := fmt.Sprintf("%s -test.run=TestHelperStub -- --args=3 --fd=4", os.Args[0])
|
||||||
if sandbox {
|
if useSandbox {
|
||||||
wantSubstr = fmt.Sprintf(
|
wantSubstr = fmt.Sprintf(`argv: ["%s" "-test.run=TestHelperStub" "--" "--args=3" "--fd=4"], flags: 0x0, seccomp: 0x3e`, os.Args[0])
|
||||||
"%s -test.run=TestHelperStub -- bwrap --args 6 -- %s -test.run=TestHelperStub -- --args=3 --fd=4",
|
|
||||||
os.Args[0], os.Args[0],
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
if got := p.String(); !strings.Contains(got, wantSubstr) {
|
if got := p.String(); !strings.Contains(got, wantSubstr) {
|
||||||
t.Errorf("String() = %v, want %v",
|
t.Errorf("String() = %v, want %v",
|
||||||
@ -232,3 +239,10 @@ func testProxyStartWaitCloseString(t *testing.T, sandbox bool) {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestHelperInit(t *testing.T) {
|
||||||
|
if len(os.Args) != 5 || os.Args[4] != "init" {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
sandbox.Init(internal.Exit)
|
||||||
|
}
|
||||||
|
138
dbus/proc.go
138
dbus/proc.go
@ -14,12 +14,13 @@ import (
|
|||||||
"syscall"
|
"syscall"
|
||||||
|
|
||||||
"git.gensokyo.uk/security/fortify/helper"
|
"git.gensokyo.uk/security/fortify/helper"
|
||||||
"git.gensokyo.uk/security/fortify/helper/bwrap"
|
"git.gensokyo.uk/security/fortify/internal/sandbox"
|
||||||
"git.gensokyo.uk/security/fortify/ldd"
|
"git.gensokyo.uk/security/fortify/ldd"
|
||||||
|
"git.gensokyo.uk/security/fortify/seccomp"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Start launches the D-Bus proxy.
|
// Start launches the D-Bus proxy.
|
||||||
func (p *Proxy) Start(ctx context.Context, output io.Writer, sandbox bool) error {
|
func (p *Proxy) Start(ctx context.Context, output io.Writer, useSandbox bool) error {
|
||||||
p.lock.Lock()
|
p.lock.Lock()
|
||||||
defer p.lock.Unlock()
|
defer p.lock.Unlock()
|
||||||
|
|
||||||
@ -30,11 +31,15 @@ func (p *Proxy) Start(ctx context.Context, output io.Writer, sandbox bool) error
|
|||||||
var h helper.Helper
|
var h helper.Helper
|
||||||
|
|
||||||
c, cancel := context.WithCancelCause(ctx)
|
c, cancel := context.WithCancelCause(ctx)
|
||||||
if !sandbox {
|
if !useSandbox {
|
||||||
h = helper.NewDirect(c, p.name, p.seal, true, argF, func(cmd *exec.Cmd) {
|
h = helper.NewDirect(c, p.name, p.seal, true, argF, func(cmd *exec.Cmd) {
|
||||||
cmdF(cmd, output, p.CmdF)
|
if p.CmdF != nil {
|
||||||
|
p.CmdF(cmd)
|
||||||
// xdg-dbus-proxy does not need to inherit the environment
|
}
|
||||||
|
if output != nil {
|
||||||
|
cmd.Stdout, cmd.Stderr = output, output
|
||||||
|
}
|
||||||
|
cmd.SysProcAttr = &syscall.SysProcAttr{Setpgid: true}
|
||||||
cmd.Env = make([]string, 0)
|
cmd.Env = make([]string, 0)
|
||||||
}, nil)
|
}, nil)
|
||||||
} else {
|
} else {
|
||||||
@ -47,64 +52,65 @@ func (p *Proxy) Start(ctx context.Context, output io.Writer, sandbox bool) error
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bc := &bwrap.Config{
|
var libPaths []string
|
||||||
Hostname: "fortify-dbus",
|
if entries, err := ldd.ExecFilter(ctx, p.CommandContext, p.FilterF, toolPath); err != nil {
|
||||||
Chdir: "/",
|
return err
|
||||||
Syscall: &bwrap.SyscallPolicy{DenyDevel: true, Multiarch: true},
|
} else {
|
||||||
Clearenv: true,
|
libPaths = ldd.Path(entries)
|
||||||
NewSession: true,
|
|
||||||
DieWithParent: true,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// these lib paths are unpredictable, so mount them first so they cannot cover anything
|
h = helper.New(
|
||||||
if toolPath != os.Args[0] {
|
c, toolPath,
|
||||||
if entries, err := ldd.Exec(ctx, toolPath); err != nil {
|
|
||||||
return err
|
|
||||||
} else {
|
|
||||||
for _, name := range ldd.Path(entries) {
|
|
||||||
bc.Bind(name, name)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// upstream bus directories
|
|
||||||
upstreamPaths := make([]string, 0, 2)
|
|
||||||
for _, as := range []string{p.session[0], p.system[0]} {
|
|
||||||
if len(as) > 0 && strings.HasPrefix(as, "unix:path=/") {
|
|
||||||
// leave / intact
|
|
||||||
upstreamPaths = append(upstreamPaths, path.Dir(as[10:]))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
slices.Sort(upstreamPaths)
|
|
||||||
upstreamPaths = slices.Compact(upstreamPaths)
|
|
||||||
for _, name := range upstreamPaths {
|
|
||||||
bc.Bind(name, name)
|
|
||||||
}
|
|
||||||
|
|
||||||
// parent directories of bind paths
|
|
||||||
sockDirPaths := make([]string, 0, 2)
|
|
||||||
if d := path.Dir(p.session[1]); path.IsAbs(d) {
|
|
||||||
sockDirPaths = append(sockDirPaths, d)
|
|
||||||
}
|
|
||||||
if d := path.Dir(p.system[1]); path.IsAbs(d) {
|
|
||||||
sockDirPaths = append(sockDirPaths, d)
|
|
||||||
}
|
|
||||||
slices.Sort(sockDirPaths)
|
|
||||||
sockDirPaths = slices.Compact(sockDirPaths)
|
|
||||||
for _, name := range sockDirPaths {
|
|
||||||
bc.Bind(name, name, false, true)
|
|
||||||
}
|
|
||||||
|
|
||||||
// xdg-dbus-proxy bin path
|
|
||||||
binPath := path.Dir(toolPath)
|
|
||||||
bc.Bind(binPath, binPath)
|
|
||||||
h = helper.MustNewBwrap(c, toolPath,
|
|
||||||
p.seal, true,
|
p.seal, true,
|
||||||
argF, func(cmd *exec.Cmd) { cmdF(cmd, output, p.CmdF) },
|
argF, func(container *sandbox.Container) {
|
||||||
nil,
|
container.Seccomp |= seccomp.FlagMultiarch
|
||||||
bc, nil,
|
container.Hostname = "fortify-dbus"
|
||||||
)
|
container.CommandContext = p.CommandContext
|
||||||
p.bwrap = bc
|
if output != nil {
|
||||||
|
container.Stdout, container.Stderr = output, output
|
||||||
|
}
|
||||||
|
|
||||||
|
if p.CmdF != nil {
|
||||||
|
p.CmdF(container)
|
||||||
|
}
|
||||||
|
|
||||||
|
// these lib paths are unpredictable, so mount them first so they cannot cover anything
|
||||||
|
for _, name := range libPaths {
|
||||||
|
container.Bind(name, name, 0)
|
||||||
|
}
|
||||||
|
|
||||||
|
// upstream bus directories
|
||||||
|
upstreamPaths := make([]string, 0, 2)
|
||||||
|
for _, as := range []string{p.session[0], p.system[0]} {
|
||||||
|
if len(as) > 0 && strings.HasPrefix(as, "unix:path=/") {
|
||||||
|
// leave / intact
|
||||||
|
upstreamPaths = append(upstreamPaths, path.Dir(as[10:]))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
slices.Sort(upstreamPaths)
|
||||||
|
upstreamPaths = slices.Compact(upstreamPaths)
|
||||||
|
for _, name := range upstreamPaths {
|
||||||
|
container.Bind(name, name, 0)
|
||||||
|
}
|
||||||
|
|
||||||
|
// parent directories of bind paths
|
||||||
|
sockDirPaths := make([]string, 0, 2)
|
||||||
|
if d := path.Dir(p.session[1]); path.IsAbs(d) {
|
||||||
|
sockDirPaths = append(sockDirPaths, d)
|
||||||
|
}
|
||||||
|
if d := path.Dir(p.system[1]); path.IsAbs(d) {
|
||||||
|
sockDirPaths = append(sockDirPaths, d)
|
||||||
|
}
|
||||||
|
slices.Sort(sockDirPaths)
|
||||||
|
sockDirPaths = slices.Compact(sockDirPaths)
|
||||||
|
for _, name := range sockDirPaths {
|
||||||
|
container.Bind(name, name, sandbox.BindWritable)
|
||||||
|
}
|
||||||
|
|
||||||
|
// xdg-dbus-proxy bin path
|
||||||
|
binPath := path.Dir(toolPath)
|
||||||
|
container.Bind(binPath, binPath, 0)
|
||||||
|
}, nil)
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := h.Start(); err != nil {
|
if err := h.Start(); err != nil {
|
||||||
@ -170,13 +176,3 @@ func argF(argsFd, statFd int) []string {
|
|||||||
return []string{"--args=" + strconv.Itoa(argsFd), "--fd=" + strconv.Itoa(statFd)}
|
return []string{"--args=" + strconv.Itoa(argsFd), "--fd=" + strconv.Itoa(statFd)}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func cmdF(cmd *exec.Cmd, output io.Writer, cmdF func(cmd *exec.Cmd)) {
|
|
||||||
cmd.SysProcAttr = &syscall.SysProcAttr{Setpgid: true}
|
|
||||||
if output != nil {
|
|
||||||
cmd.Stdout, cmd.Stderr = output, output
|
|
||||||
}
|
|
||||||
if cmdF != nil {
|
|
||||||
cmdF(cmd)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
@ -9,7 +9,6 @@ import (
|
|||||||
"sync"
|
"sync"
|
||||||
|
|
||||||
"git.gensokyo.uk/security/fortify/helper"
|
"git.gensokyo.uk/security/fortify/helper"
|
||||||
"git.gensokyo.uk/security/fortify/helper/bwrap"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// ProxyName is the file name or path to the proxy program.
|
// ProxyName is the file name or path to the proxy program.
|
||||||
@ -20,16 +19,18 @@ var ProxyName = "xdg-dbus-proxy"
|
|||||||
// Once sealed, configuration changes will no longer be possible and attempting to do so will result in a panic.
|
// Once sealed, configuration changes will no longer be possible and attempting to do so will result in a panic.
|
||||||
type Proxy struct {
|
type Proxy struct {
|
||||||
helper helper.Helper
|
helper helper.Helper
|
||||||
bwrap *bwrap.Config
|
|
||||||
ctx context.Context
|
ctx context.Context
|
||||||
cancel context.CancelCauseFunc
|
cancel context.CancelCauseFunc
|
||||||
|
|
||||||
name string
|
name string
|
||||||
session [2]string
|
session [2]string
|
||||||
system [2]string
|
system [2]string
|
||||||
CmdF func(cmd *exec.Cmd)
|
CmdF func(any)
|
||||||
sysP bool
|
sysP bool
|
||||||
|
|
||||||
|
CommandContext func(ctx context.Context) (cmd *exec.Cmd)
|
||||||
|
FilterF func([]byte) []byte
|
||||||
|
|
||||||
seal io.WriterTo
|
seal io.WriterTo
|
||||||
lock sync.RWMutex
|
lock sync.RWMutex
|
||||||
}
|
}
|
||||||
|
@ -7,9 +7,9 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
sampleHostPath = "/run/user/1971/bus"
|
sampleHostPath = "/tmp/bus"
|
||||||
sampleHostAddr = "unix:path=" + sampleHostPath
|
sampleHostAddr = "unix:path=" + sampleHostPath
|
||||||
sampleBindPath = "/tmp/fortify.1971/12622d846cc3fe7b4c10359d01f0eb47/bus"
|
sampleBindPath = "/tmp/proxied_bus"
|
||||||
)
|
)
|
||||||
|
|
||||||
var samples = []dbusTestCase{
|
var samples = []dbusTestCase{
|
||||||
|
@ -5,7 +5,6 @@ import (
|
|||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
"os"
|
"os"
|
||||||
"path"
|
|
||||||
"strconv"
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
"syscall"
|
"syscall"
|
||||||
@ -137,27 +136,7 @@ func bwrapStub() {
|
|||||||
AsInit: true,
|
AsInit: true,
|
||||||
}
|
}
|
||||||
|
|
||||||
efp := new(proc.ExtraFilesPre)
|
if _, err := MustNewCheckedArgs(sc.Args(nil, new(proc.ExtraFilesPre), new([]proc.File))).
|
||||||
if t, ok := os.LookupEnv("GO_TEST_FORTIFY_BWRAP_STUB_TYPE"); ok {
|
|
||||||
switch t {
|
|
||||||
case "dbus":
|
|
||||||
sc.Net = false
|
|
||||||
sc.Hostname = "fortify-dbus"
|
|
||||||
sc.Chdir = "/"
|
|
||||||
sc.Syscall = &bwrap.SyscallPolicy{DenyDevel: true, Multiarch: true}
|
|
||||||
sc.AsInit = false
|
|
||||||
sc.
|
|
||||||
Bind("/run/user/1971", "/run/user/1971").
|
|
||||||
Bind("/tmp/fortify.1971/12622d846cc3fe7b4c10359d01f0eb47", "/tmp/fortify.1971/12622d846cc3fe7b4c10359d01f0eb47", false, true).
|
|
||||||
Bind(path.Dir(os.Args[0]), path.Dir(os.Args[0]))
|
|
||||||
|
|
||||||
// manipulate extra files list so fd ends up as 5
|
|
||||||
efp.Append()
|
|
||||||
efp.Append()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if _, err := MustNewCheckedArgs(sc.Args(nil, efp, new([]proc.File))).
|
|
||||||
WriteTo(want); err != nil {
|
WriteTo(want); err != nil {
|
||||||
panic("cannot read want: " + err.Error())
|
panic("cannot read want: " + err.Error())
|
||||||
}
|
}
|
||||||
|
@ -88,7 +88,7 @@ func (d *DBus) apply(sys *I) error {
|
|||||||
return sys.wrapErrSuffix(err,
|
return sys.wrapErrSuffix(err,
|
||||||
"cannot start message bus proxy:")
|
"cannot start message bus proxy:")
|
||||||
}
|
}
|
||||||
sys.println("starting message bus proxy:", d.proxy)
|
sys.println("starting message bus proxy", d.proxy)
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -139,7 +139,15 @@ func (s *scanToFmsg) write(p []byte, a int) (int, error) {
|
|||||||
return a + n, nil
|
return a + n, nil
|
||||||
} else {
|
} else {
|
||||||
n, _ := s.msg.Write(p[:i])
|
n, _ := s.msg.Write(p[:i])
|
||||||
s.msgbuf = append(s.msgbuf, s.msg.String())
|
|
||||||
|
// 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()
|
s.msg.Reset()
|
||||||
return s.write(p[i+1:], a+n+1)
|
return s.write(p[i+1:], a+n+1)
|
||||||
}
|
}
|
||||||
@ -148,7 +156,7 @@ func (s *scanToFmsg) write(p []byte, a int) (int, error) {
|
|||||||
func (s *scanToFmsg) Dump() {
|
func (s *scanToFmsg) Dump() {
|
||||||
s.mu.RLock()
|
s.mu.RLock()
|
||||||
for _, msg := range s.msgbuf {
|
for _, msg := range s.msgbuf {
|
||||||
log.Println(msg)
|
log.Println("(dbus) " + msg)
|
||||||
}
|
}
|
||||||
s.mu.RUnlock()
|
s.mu.RUnlock()
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user