From 6e7ddb2d2ec6b163dc2c178bc4d73b5943f51206 Mon Sep 17 00:00:00 2001
From: Ophestra <cat@gensokyo.uk>
Date: Sat, 15 Mar 2025 23:57:44 +0900
Subject: [PATCH] helper: eliminate commandContext replacement

This is done more cleanly by modifying Args in cmdF.

Signed-off-by: Ophestra <cat@gensokyo.uk>
---
 dbus/dbus_test.go        | 66 +++++++++++++++++++------------
 dbus/{run.go => proc.go} | 85 ++++++++++++++++++++++++----------------
 dbus/proxy.go            |  2 +
 dbus/samples_test.go     | 37 ++++++++++-------
 dbus/stub_test.go        |  4 +-
 helper/bwrap_test.go     | 41 +++++++++++--------
 helper/cmd.go            |  2 +-
 helper/cmd_test.go       | 15 ++++---
 helper/helper.go         |  7 +---
 helper/helper_test.go    | 18 +++++----
 helper/stub.go           | 72 +++++++++++++++++++---------------
 helper/stub_test.go      |  4 +-
 12 files changed, 205 insertions(+), 148 deletions(-)
 rename dbus/{run.go => proc.go} (67%)

diff --git a/dbus/dbus_test.go b/dbus/dbus_test.go
index 57a441a..0b264dc 100644
--- a/dbus/dbus_test.go
+++ b/dbus/dbus_test.go
@@ -3,6 +3,9 @@ package dbus_test
 import (
 	"context"
 	"errors"
+	"fmt"
+	"os"
+	"os/exec"
 	"strings"
 	"testing"
 	"time"
@@ -100,12 +103,13 @@ func TestProxy_Seal(t *testing.T) {
 }
 
 func TestProxy_Start_Wait_Close_String(t *testing.T) {
-	t.Run("sandboxed", func(t *testing.T) {
+	t.Run("sandbox", func(t *testing.T) {
+		proxyName := dbus.ProxyName
+		dbus.ProxyName = os.Args[0]
+		t.Cleanup(func() { dbus.ProxyName = proxyName })
 		testProxyStartWaitCloseString(t, true)
 	})
-	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) {
@@ -125,14 +129,30 @@ func testProxyStartWaitCloseString(t *testing.T, sandbox bool) {
 		})
 
 		t.Run("proxy for "+id, func(t *testing.T) {
-			helper.InternalReplaceExecCommand(t)
-			overridePath(t)
-
 			p := dbus.New(tc[0].bus, tc[1].bus)
+			p.CmdF = func(cmd *exec.Cmd) {
+				wantArgv0 := dbus.ProxyName
+				if sandbox {
+					wantArgv0 = "bwrap"
+				}
+				if cmd.Args[0] != wantArgv0 {
+					panic(fmt.Sprintf("unexpected argv0 %q", os.Args[0]))
+				}
+				cmd.Err = nil
+				cmd.Path = os.Args[0]
+
+				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 {
+					cmd.Args = append([]string{os.Args[0], "-test.run=TestHelperStub", "--"}, cmd.Args[1:]...)
+				}
+			}
 			output := new(strings.Builder)
 
-			t.Run("unsealed behaviour of "+id, func(t *testing.T) {
-				t.Run("unsealed string of "+id, func(t *testing.T) {
+			t.Run("unsealed", func(t *testing.T) {
+				t.Run("string", func(t *testing.T) {
 					want := "(unsealed dbus proxy)"
 					if got := p.String(); got != want {
 						t.Errorf("String() = %v, want %v",
@@ -141,7 +161,7 @@ func testProxyStartWaitCloseString(t *testing.T, sandbox bool) {
 					}
 				})
 
-				t.Run("unsealed start of "+id, func(t *testing.T) {
+				t.Run("start", func(t *testing.T) {
 					want := "proxy not sealed"
 					if err := p.Start(context.Background(), nil, sandbox); err == nil || err.Error() != want {
 						t.Errorf("Start() error = %v, wantErr %q",
@@ -150,7 +170,7 @@ func testProxyStartWaitCloseString(t *testing.T, sandbox bool) {
 					}
 				})
 
-				t.Run("unsealed wait of "+id, func(t *testing.T) {
+				t.Run("wait", func(t *testing.T) {
 					wantErr := "dbus: not started"
 					if err := p.Wait(); err == nil || err.Error() != wantErr {
 						t.Errorf("Wait() error = %v, wantErr %v",
@@ -168,7 +188,7 @@ func testProxyStartWaitCloseString(t *testing.T, sandbox bool) {
 				}
 			})
 
-			t.Run("sealed behaviour of "+id, func(t *testing.T) {
+			t.Run("sealed", func(t *testing.T) {
 				want := strings.Join(append(tc[0].want, tc[1].want...), " ")
 				if got := p.String(); got != want {
 					t.Errorf("String() = %v, want %v",
@@ -176,7 +196,7 @@ func testProxyStartWaitCloseString(t *testing.T, sandbox bool) {
 					return
 				}
 
-				t.Run("sealed start of "+id, func(t *testing.T) {
+				t.Run("start", func(t *testing.T) {
 					ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
 					defer cancel()
 
@@ -185,8 +205,14 @@ func testProxyStartWaitCloseString(t *testing.T, sandbox bool) {
 							err)
 					}
 
-					t.Run("started string of "+id, func(t *testing.T) {
-						wantSubstr := dbus.ProxyName + " --args="
+					t.Run("string", func(t *testing.T) {
+						wantSubstr := fmt.Sprintf("%s -test.run=TestHelperStub -- --args=3 --fd=4", os.Args[0])
+						if sandbox {
+							wantSubstr = fmt.Sprintf(
+								"%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) {
 							t.Errorf("String() = %v, want %v",
 								p.String(), wantSubstr)
@@ -194,7 +220,7 @@ func testProxyStartWaitCloseString(t *testing.T, sandbox bool) {
 						}
 					})
 
-					t.Run("started wait of "+id, func(t *testing.T) {
+					t.Run("wait", func(t *testing.T) {
 						p.Close()
 						if err := p.Wait(); err != nil {
 							t.Errorf("Wait() error = %v\noutput: %s",
@@ -206,11 +232,3 @@ func testProxyStartWaitCloseString(t *testing.T, sandbox bool) {
 		})
 	}
 }
-
-func overridePath(t *testing.T) {
-	proxyName := dbus.ProxyName
-	dbus.ProxyName = "/nonexistent-xdg-dbus-proxy"
-	t.Cleanup(func() {
-		dbus.ProxyName = proxyName
-	})
-}
diff --git a/dbus/run.go b/dbus/proc.go
similarity index 67%
rename from dbus/run.go
rename to dbus/proc.go
index 30b06f4..379f9fd 100644
--- a/dbus/run.go
+++ b/dbus/proc.go
@@ -8,6 +8,7 @@ import (
 	"os/exec"
 	"path"
 	"path/filepath"
+	"slices"
 	"strconv"
 	"strings"
 	"syscall"
@@ -26,25 +27,12 @@ func (p *Proxy) Start(ctx context.Context, output io.Writer, sandbox bool) error
 		return errors.New("proxy not sealed")
 	}
 
-	var (
-		h helper.Helper
-
-		argF = func(argsFd, statFd int) []string {
-			if statFd == -1 {
-				return []string{"--args=" + strconv.Itoa(argsFd)}
-			} else {
-				return []string{"--args=" + strconv.Itoa(argsFd), "--fd=" + strconv.Itoa(statFd)}
-			}
-		}
-	)
+	var h helper.Helper
 
 	c, cancel := context.WithCancelCause(ctx)
 	if !sandbox {
 		h = helper.NewDirect(c, p.name, p.seal, true, argF, func(cmd *exec.Cmd) {
-			cmd.SysProcAttr = &syscall.SysProcAttr{Setpgid: true}
-			if output != nil {
-				cmd.Stdout, cmd.Stderr = output, output
-			}
+			cmdF(cmd, output, p.CmdF)
 
 			// xdg-dbus-proxy does not need to inherit the environment
 			cmd.Env = make([]string, 0)
@@ -62,7 +50,7 @@ func (p *Proxy) Start(ctx context.Context, output io.Writer, sandbox bool) error
 
 		// resolve libraries by parsing ldd output
 		var proxyDeps []*ldd.Entry
-		if toolPath != "/nonexistent-xdg-dbus-proxy" {
+		if toolPath != os.Args[0] {
 			if l, err := ldd.Exec(ctx, toolPath); err != nil {
 				return err
 			} else {
@@ -71,7 +59,6 @@ func (p *Proxy) Start(ctx context.Context, output io.Writer, sandbox bool) error
 		}
 
 		bc := &bwrap.Config{
-			Unshare:       nil,
 			Hostname:      "fortify-dbus",
 			Chdir:         "/",
 			Syscall:       &bwrap.SyscallPolicy{DenyDevel: true, Multiarch: true},
@@ -81,28 +68,35 @@ func (p *Proxy) Start(ctx context.Context, output io.Writer, sandbox bool) error
 		}
 
 		// resolve proxy socket directories
-		bindTarget := make(map[string]struct{}, 2)
+		bindTargetM := make(map[string]struct{}, 2)
+
 		for _, ps := range []string{p.session[1], p.system[1]} {
 			if pd := path.Dir(ps); len(pd) > 0 {
 				if pd[0] == '/' {
-					bindTarget[pd] = struct{}{}
+					bindTargetM[pd] = struct{}{}
 				}
 			}
 		}
-		for k := range bindTarget {
-			bc.Bind(k, k, false, true)
+
+		bindTarget := make([]string, 0, len(bindTargetM))
+		for k := range bindTargetM {
+			bindTarget = append(bindTarget, k)
+		}
+		slices.Sort(bindTarget)
+		for _, name := range bindTarget {
+			bc.Bind(name, name, false, true)
 		}
 
-		roBindTarget := make(map[string]struct{}, 2+1+len(proxyDeps))
+		roBindTargetM := make(map[string]struct{}, 2+1+len(proxyDeps))
 
 		// xdb-dbus-proxy bin and dependencies
-		roBindTarget[path.Dir(toolPath)] = struct{}{}
+		roBindTargetM[path.Dir(toolPath)] = struct{}{}
 		for _, ent := range proxyDeps {
 			if path.IsAbs(ent.Path) {
-				roBindTarget[path.Dir(ent.Path)] = struct{}{}
+				roBindTargetM[path.Dir(ent.Path)] = struct{}{}
 			}
 			if path.IsAbs(ent.Name) {
-				roBindTarget[path.Dir(ent.Name)] = struct{}{}
+				roBindTargetM[path.Dir(ent.Name)] = struct{}{}
 			}
 		}
 
@@ -110,20 +104,25 @@ func (p *Proxy) Start(ctx context.Context, output io.Writer, sandbox bool) error
 		for _, as := range []string{p.session[0], p.system[0]} {
 			if len(as) > 0 && strings.HasPrefix(as, "unix:path=/") {
 				// leave / intact
-				roBindTarget[path.Dir(as[10:])] = struct{}{}
+				roBindTargetM[path.Dir(as[10:])] = struct{}{}
 			}
 		}
 
-		for k := range roBindTarget {
-			bc.Bind(k, k)
+		roBindTarget := make([]string, 0, len(roBindTargetM))
+		for k := range roBindTargetM {
+			roBindTarget = append(roBindTarget, k)
+		}
+		slices.Sort(roBindTarget)
+		for _, name := range roBindTarget {
+			bc.Bind(name, name)
 		}
 
-		h = helper.MustNewBwrap(c, toolPath, p.seal, true, argF, func(cmd *exec.Cmd) {
-			cmd.SysProcAttr = &syscall.SysProcAttr{Setpgid: true}
-			if output != nil {
-				cmd.Stdout, cmd.Stderr = output, output
-			}
-		}, nil, bc, nil)
+		h = helper.MustNewBwrap(c, toolPath,
+			p.seal, true,
+			argF, func(cmd *exec.Cmd) { cmdF(cmd, output, p.CmdF) },
+			nil,
+			bc, nil,
+		)
 		p.bwrap = bc
 	}
 
@@ -182,3 +181,21 @@ func (p *Proxy) Close() {
 	p.cancel(proxyClosed)
 	p.cancel = nil
 }
+
+func argF(argsFd, statFd int) []string {
+	if statFd == -1 {
+		return []string{"--args=" + strconv.Itoa(argsFd)}
+	} else {
+		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)
+	}
+}
diff --git a/dbus/proxy.go b/dbus/proxy.go
index 5e92e34..e7785fd 100644
--- a/dbus/proxy.go
+++ b/dbus/proxy.go
@@ -5,6 +5,7 @@ import (
 	"errors"
 	"fmt"
 	"io"
+	"os/exec"
 	"sync"
 
 	"git.gensokyo.uk/security/fortify/helper"
@@ -26,6 +27,7 @@ type Proxy struct {
 	name    string
 	session [2]string
 	system  [2]string
+	CmdF    func(cmd *exec.Cmd)
 	sysP    bool
 
 	seal io.WriterTo
diff --git a/dbus/samples_test.go b/dbus/samples_test.go
index 653a02f..75ed022 100644
--- a/dbus/samples_test.go
+++ b/dbus/samples_test.go
@@ -6,6 +6,12 @@ import (
 	"git.gensokyo.uk/security/fortify/dbus"
 )
 
+const (
+	sampleHostPath = "/run/user/1971/bus"
+	sampleHostAddr = "unix:path=" + sampleHostPath
+	sampleBindPath = "/tmp/fortify.1971/12622d846cc3fe7b4c10359d01f0eb47/bus"
+)
+
 var samples = []dbusTestCase{
 	{
 		"org.chromium.Chromium", &dbus.Config{
@@ -19,10 +25,10 @@ var samples = []dbusTestCase{
 			Log:       false,
 			Filter:    true,
 		}, false, false,
-		[2]string{"unix:path=/run/user/1971/bus", "/tmp/fortify.1971/12622d846cc3fe7b4c10359d01f0eb47/bus"},
+		[2]string{sampleHostAddr, sampleBindPath},
 		[]string{
-			"unix:path=/run/user/1971/bus",
-			"/tmp/fortify.1971/12622d846cc3fe7b4c10359d01f0eb47/bus",
+			sampleHostAddr,
+			sampleBindPath,
 			"--filter",
 			"--talk=org.freedesktop.Notifications",
 			"--talk=org.freedesktop.FileManager1",
@@ -48,9 +54,10 @@ var samples = []dbusTestCase{
 			Log:       false,
 			Filter:    true,
 		}, false, false,
-		[2]string{"unix:path=/run/dbus/system_bus_socket", "/tmp/fortify.1971/12622d846cc3fe7b4c10359d01f0eb47/system_bus_socket"},
-		[]string{"unix:path=/run/dbus/system_bus_socket",
-			"/tmp/fortify.1971/12622d846cc3fe7b4c10359d01f0eb47/system_bus_socket",
+		[2]string{sampleHostAddr, sampleBindPath},
+		[]string{
+			sampleHostAddr,
+			sampleBindPath,
 			"--filter",
 			"--talk=org.bluez",
 			"--talk=org.freedesktop.Avahi",
@@ -68,10 +75,10 @@ var samples = []dbusTestCase{
 			Log:       false,
 			Filter:    true,
 		}, false, false,
-		[2]string{"unix:path=/run/user/1971/bus", "/tmp/fortify.1971/34c24f16a0d791d28835ededaf446033/bus"},
+		[2]string{sampleHostAddr, sampleBindPath},
 		[]string{
-			"unix:path=/run/user/1971/bus",
-			"/tmp/fortify.1971/34c24f16a0d791d28835ededaf446033/bus",
+			sampleHostAddr,
+			sampleBindPath,
 			"--filter",
 			"--talk=org.freedesktop.Notifications",
 			"--talk=org.kde.StatusNotifierWatcher",
@@ -91,10 +98,10 @@ var samples = []dbusTestCase{
 			Log:       true,
 			Filter:    true,
 		}, false, false,
-		[2]string{"unix:path=/run/user/1971/bus", "/tmp/fortify.1971/5da7845287a936efbc2fa75d7d81e501/bus"},
+		[2]string{sampleHostAddr, sampleBindPath},
 		[]string{
-			"unix:path=/run/user/1971/bus",
-			"/tmp/fortify.1971/5da7845287a936efbc2fa75d7d81e501/bus",
+			sampleHostAddr,
+			sampleBindPath,
 			"--filter",
 			"--see=uk.gensokyo.CrashTestDummy1",
 			"--talk=org.freedesktop.Notifications",
@@ -114,10 +121,10 @@ var samples = []dbusTestCase{
 			Log:       true,
 			Filter:    true,
 		}, false, true,
-		[2]string{"unix:path=/run/user/1971/bus", "/tmp/fortify.1971/5da7845287a936efbc2fa75d7d81e501/bus"},
+		[2]string{sampleHostAddr, sampleBindPath},
 		[]string{
-			"unix:path=/run/user/1971/bus",
-			"/tmp/fortify.1971/5da7845287a936efbc2fa75d7d81e501/bus",
+			sampleHostAddr,
+			sampleBindPath,
 			"--filter",
 			"--see=uk.gensokyo.CrashTestDummy",
 			"--talk=org.freedesktop.Notifications",
diff --git a/dbus/stub_test.go b/dbus/stub_test.go
index b83deb2..13a7d1d 100644
--- a/dbus/stub_test.go
+++ b/dbus/stub_test.go
@@ -6,6 +6,4 @@ import (
 	"git.gensokyo.uk/security/fortify/helper"
 )
 
-func TestHelperChildStub(t *testing.T) {
-	helper.InternalChildStub()
-}
+func TestHelperStub(t *testing.T) { helper.InternalHelperStub() }
diff --git a/helper/bwrap_test.go b/helper/bwrap_test.go
index 550ff34..be0a465 100644
--- a/helper/bwrap_test.go
+++ b/helper/bwrap_test.go
@@ -3,6 +3,8 @@ package helper_test
 import (
 	"context"
 	"errors"
+	"fmt"
+	"io"
 	"os"
 	"os/exec"
 	"strings"
@@ -17,7 +19,7 @@ func TestBwrap(t *testing.T) {
 	sc := &bwrap.Config{
 		Net:           true,
 		Hostname:      "localhost",
-		Chdir:         "/nonexistent",
+		Chdir:         "/proc/nonexistent",
 		Clearenv:      true,
 		NewSession:    true,
 		DieWithParent: true,
@@ -26,14 +28,12 @@ func TestBwrap(t *testing.T) {
 
 	t.Run("nonexistent bwrap name", func(t *testing.T) {
 		bubblewrapName := helper.BubblewrapName
-		helper.BubblewrapName = "/nonexistent"
-		t.Cleanup(func() {
-			helper.BubblewrapName = bubblewrapName
-		})
+		helper.BubblewrapName = "/proc/nonexistent"
+		t.Cleanup(func() { helper.BubblewrapName = bubblewrapName })
 
 		h := helper.MustNewBwrap(
 			context.Background(),
-			"fortify",
+			"false",
 			argsWt, false,
 			argF, nil,
 			nil,
@@ -49,14 +49,14 @@ func TestBwrap(t *testing.T) {
 	t.Run("valid new helper nil check", func(t *testing.T) {
 		if got := helper.MustNewBwrap(
 			context.TODO(),
-			"fortify",
+			"false",
 			argsWt, false,
 			argF, nil,
 			nil,
 			sc, nil,
 		); got == nil {
 			t.Errorf("MustNewBwrap(%#v, %#v, %#v) got nil",
-				sc, argsWt, "fortify")
+				sc, argsWt, "false")
 			return
 		}
 	})
@@ -72,7 +72,7 @@ func TestBwrap(t *testing.T) {
 
 		helper.MustNewBwrap(
 			context.TODO(),
-			"fortify",
+			"false",
 			argsWt, false,
 			argF, nil,
 			nil,
@@ -81,15 +81,13 @@ func TestBwrap(t *testing.T) {
 	})
 
 	t.Run("start without pipes", func(t *testing.T) {
-		helper.InternalReplaceExecCommand(t)
-
 		ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
 		defer cancel()
 		stdout, stderr := new(strings.Builder), new(strings.Builder)
 		h := helper.MustNewBwrap(
-			ctx, "crash-test-dummy",
+			ctx, os.Args[0],
 			nil, false,
-			argFChecked, func(cmd *exec.Cmd) { cmd.Stdout, cmd.Stderr = stdout, stderr },
+			argFChecked, func(cmd *exec.Cmd) { cmd.Stdout, cmd.Stderr = stdout, stderr; hijackBwrap(cmd) },
 			nil,
 			sc, nil,
 		)
@@ -107,14 +105,23 @@ func TestBwrap(t *testing.T) {
 	})
 
 	t.Run("implementation compliance", func(t *testing.T) {
-		testHelper(t, func(ctx context.Context, cmdF func(cmd *exec.Cmd), stat bool) helper.Helper {
+		testHelper(t, func(ctx context.Context, setOutput func(stdoutP, stderrP *io.Writer), stat bool) helper.Helper {
 			return helper.MustNewBwrap(
-				ctx, "crash-test-dummy",
+				ctx, os.Args[0],
 				argsWt, stat,
-				argF, cmdF,
+				argF, func(cmd *exec.Cmd) { setOutput(&cmd.Stdout, &cmd.Stderr); hijackBwrap(cmd) },
 				nil,
 				sc, nil,
 			)
-		})
+		}, "exec")
 	})
 }
+
+func hijackBwrap(cmd *exec.Cmd) {
+	if cmd.Args[0] != "bwrap" {
+		panic(fmt.Sprintf("unexpected argv0 %q", cmd.Args[0]))
+	}
+	cmd.Err = nil
+	cmd.Path = os.Args[0]
+	cmd.Args = append([]string{os.Args[0], "-test.run=TestHelperStub", "--"}, cmd.Args...)
+}
diff --git a/helper/cmd.go b/helper/cmd.go
index 5b66afe..4fe978a 100644
--- a/helper/cmd.go
+++ b/helper/cmd.go
@@ -42,7 +42,7 @@ func newHelperCmd(
 ) (cmd *helperCmd, args []string) {
 	cmd = new(helperCmd)
 	cmd.helperFiles, args = newHelperFiles(ctx, wt, stat, argF, extraFiles)
-	cmd.Cmd = commandContext(ctx, name)
+	cmd.Cmd = exec.CommandContext(ctx, name)
 	cmd.Cmd.Cancel = func() error { return cmd.Process.Signal(syscall.SIGTERM) }
 	cmd.WaitDelay = WaitDelay
 	return
diff --git a/helper/cmd_test.go b/helper/cmd_test.go
index 60c0caf..9c64098 100644
--- a/helper/cmd_test.go
+++ b/helper/cmd_test.go
@@ -3,6 +3,7 @@ package helper_test
 import (
 	"context"
 	"errors"
+	"io"
 	"os"
 	"os/exec"
 	"testing"
@@ -10,9 +11,9 @@ import (
 	"git.gensokyo.uk/security/fortify/helper"
 )
 
-func TestDirect(t *testing.T) {
+func TestCmd(t *testing.T) {
 	t.Run("start non-existent helper path", func(t *testing.T) {
-		h := helper.NewDirect(context.Background(), "/nonexistent", argsWt, false, argF, nil, nil)
+		h := helper.NewDirect(context.Background(), "/proc/nonexistent", argsWt, false, argF, nil, nil)
 
 		if err := h.Start(); !errors.Is(err, os.ErrNotExist) {
 			t.Errorf("Start: error = %v, wantErr %v",
@@ -22,15 +23,17 @@ func TestDirect(t *testing.T) {
 
 	t.Run("valid new helper nil check", func(t *testing.T) {
 		if got := helper.NewDirect(context.TODO(), "fortify", argsWt, false, argF, nil, nil); got == nil {
-			t.Errorf("New(%q, %q) got nil",
+			t.Errorf("NewDirect(%q, %q) got nil",
 				argsWt, "fortify")
 			return
 		}
 	})
 
 	t.Run("implementation compliance", func(t *testing.T) {
-		testHelper(t, func(ctx context.Context, cmdF func(cmd *exec.Cmd), stat bool) helper.Helper {
-			return helper.NewDirect(ctx, "crash-test-dummy", argsWt, stat, argF, cmdF, nil)
-		})
+		testHelper(t, func(ctx context.Context, setOutput func(stdoutP, stderrP *io.Writer), stat bool) helper.Helper {
+			return helper.NewDirect(ctx, os.Args[0], argsWt, stat, argF, func(cmd *exec.Cmd) {
+				setOutput(&cmd.Stdout, &cmd.Stderr)
+			}, nil)
+		}, "exec")
 	})
 }
diff --git a/helper/helper.go b/helper/helper.go
index ac45ac7..8a25fee 100644
--- a/helper/helper.go
+++ b/helper/helper.go
@@ -6,17 +6,12 @@ import (
 	"fmt"
 	"io"
 	"os"
-	"os/exec"
 	"time"
 
 	"git.gensokyo.uk/security/fortify/helper/proc"
 )
 
-var (
-	WaitDelay = 2 * time.Second
-
-	commandContext = exec.CommandContext
-)
+var WaitDelay = 2 * time.Second
 
 const (
 	// FortifyHelper is set to 1 when args fd is enabled and 0 otherwise.
diff --git a/helper/helper_test.go b/helper/helper_test.go
index 3274fe5..4bc98b5 100644
--- a/helper/helper_test.go
+++ b/helper/helper_test.go
@@ -4,7 +4,7 @@ import (
 	"context"
 	"errors"
 	"fmt"
-	"os/exec"
+	"io"
 	"strconv"
 	"strings"
 	"testing"
@@ -36,7 +36,8 @@ func argF(argsFd, statFd int) []string {
 }
 
 func argFChecked(argsFd, statFd int) (args []string) {
-	args = make([]string, 0, 4)
+	args = make([]string, 0, 6)
+	args = append(args, "-test.run=TestHelperStub", "--")
 	if argsFd > -1 {
 		args = append(args, "--args", strconv.Itoa(argsFd))
 	}
@@ -47,13 +48,14 @@ func argFChecked(argsFd, statFd int) (args []string) {
 }
 
 // this function tests an implementation of the helper.Helper interface
-func testHelper(t *testing.T, createHelper func(ctx context.Context, cmdF func(cmd *exec.Cmd), stat bool) helper.Helper) {
-	helper.InternalReplaceExecCommand(t)
-
+func testHelper(t *testing.T,
+	createHelper func(ctx context.Context, setOutput func(stdoutP, stderrP *io.Writer), stat bool) helper.Helper,
+	prefix string,
+) {
 	t.Run("start helper with status channel and wait", func(t *testing.T) {
 		ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
 		stdout, stderr := new(strings.Builder), new(strings.Builder)
-		h := createHelper(ctx, func(cmd *exec.Cmd) { cmd.Stdout, cmd.Stderr = stdout, stderr }, true)
+		h := createHelper(ctx, func(stdoutP, stderrP *io.Writer) { *stdoutP, *stderrP = stdout, stderr }, true)
 
 		t.Run("wait not yet started helper", func(t *testing.T) {
 			defer func() {
@@ -75,7 +77,7 @@ func testHelper(t *testing.T, createHelper func(ctx context.Context, cmdF func(c
 		cancel()
 
 		t.Run("start already started helper", func(t *testing.T) {
-			wantErr := "exec: already started"
+			wantErr := prefix + ": already started"
 			if err := h.Start(); err != nil && err.Error() != wantErr {
 				t.Errorf("Start: error = %v, wantErr %v",
 					err, wantErr)
@@ -108,7 +110,7 @@ func testHelper(t *testing.T, createHelper func(ctx context.Context, cmdF func(c
 		ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
 		defer cancel()
 		stdout, stderr := new(strings.Builder), new(strings.Builder)
-		h := createHelper(ctx, func(cmd *exec.Cmd) { cmd.Stdout, cmd.Stderr = stdout, stderr }, false)
+		h := createHelper(ctx, func(stdoutP, stderrP *io.Writer) { *stdoutP, *stderrP = stdout, stderr }, false)
 
 		if err := h.Start(); err != nil {
 			t.Errorf("Start() error = %v",
diff --git a/helper/stub.go b/helper/stub.go
index 12daa9f..f64263c 100644
--- a/helper/stub.go
+++ b/helper/stub.go
@@ -1,25 +1,24 @@
 package helper
 
 import (
-	"context"
 	"flag"
 	"fmt"
 	"io"
 	"os"
-	"os/exec"
+	"path"
+	"slices"
 	"strconv"
 	"strings"
 	"syscall"
-	"testing"
 
 	"git.gensokyo.uk/security/fortify/helper/bwrap"
 	"git.gensokyo.uk/security/fortify/helper/proc"
 	"git.gensokyo.uk/security/fortify/internal"
 )
 
-// InternalChildStub is an internal function but exported because it is cross-package;
+// InternalHelperStub is an internal function but exported because it is cross-package;
 // it is part of the implementation of the helper stub.
-func InternalChildStub() {
+func InternalHelperStub() {
 	// this test mocks the helper process
 	var ap, sp string
 	if v, ok := os.LookupEnv(FortifyHelper); !ok {
@@ -33,32 +32,15 @@ func InternalChildStub() {
 		sp = v
 	}
 
-	switch os.Args[3] {
-	case "bwrap":
+	if len(os.Args) > 3 && os.Args[3] == "bwrap" {
 		bwrapStub()
-	default:
-		genericStub(flagRestoreFiles(4, ap, sp))
+	} else {
+		genericStub(flagRestoreFiles(3, ap, sp))
 	}
 
 	internal.Exit(0)
 }
 
-// InternalReplaceExecCommand is an internal function but exported because it is cross-package;
-// it is part of the implementation of the helper stub.
-func InternalReplaceExecCommand(t *testing.T) {
-	t.Cleanup(func() { commandContext = exec.CommandContext })
-
-	// replace execCommand to have the resulting *exec.Cmd launch TestHelperChildStub
-	commandContext = func(ctx context.Context, name string, arg ...string) *exec.Cmd {
-		// pass through nonexistent path
-		if name == "/nonexistent" && len(arg) == 0 {
-			return exec.CommandContext(ctx, name)
-		}
-
-		return exec.CommandContext(ctx, os.Args[0], append([]string{"-test.run=TestHelperChildStub", "--", name}, arg...)...)
-	}
-}
-
 func newFile(fd int, name, p string) *os.File {
 	present := false
 	switch p {
@@ -149,26 +131,54 @@ func bwrapStub() {
 		sc := &bwrap.Config{
 			Net:           true,
 			Hostname:      "localhost",
-			Chdir:         "/nonexistent",
+			Chdir:         "/proc/nonexistent",
 			Clearenv:      true,
 			NewSession:    true,
 			DieWithParent: true,
 			AsInit:        true,
 		}
-		if _, err := MustNewCheckedArgs(sc.Args(nil, new(proc.ExtraFilesPre), new([]proc.File))).
+
+		efp := new(proc.ExtraFilesPre)
+		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
+
+				bindTarget := []string{"/tmp/fortify.1971/12622d846cc3fe7b4c10359d01f0eb47"}
+				slices.Sort(bindTarget)
+				for _, name := range bindTarget {
+					sc.Bind(name, name, false, true)
+				}
+				roBindTarget := []string{"/run/user/1971", path.Dir(os.Args[0])}
+				slices.Sort(roBindTarget)
+				for _, name := range roBindTarget {
+					sc.Bind(name, name)
+				}
+
+				// 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 {
 			panic("cannot read want: " + err.Error())
 		}
 
-		if len(flag.CommandLine.Args()) > 0 && flag.CommandLine.Args()[0] == "crash-test-dummy" && got.String() != want.String() {
+		if got.String() != want.String() {
 			panic("bad bwrap args\ngot: " + got.String() + "\nwant: " + want.String())
 		}
 	}()
 
 	if err := syscall.Exec(
-		os.Args[0],
-		append([]string{os.Args[0], "-test.run=TestHelperChildStub", "--"}, flag.CommandLine.Args()...),
+		flag.CommandLine.Args()[0],
+		flag.CommandLine.Args(),
 		os.Environ()); err != nil {
-		panic("cannot start general stub: " + err.Error())
+		panic("cannot start helper stub: " + err.Error())
 	}
 }
diff --git a/helper/stub_test.go b/helper/stub_test.go
index 7720c0e..1de830e 100644
--- a/helper/stub_test.go
+++ b/helper/stub_test.go
@@ -6,6 +6,4 @@ import (
 	"git.gensokyo.uk/security/fortify/helper"
 )
 
-func TestHelperChildStub(t *testing.T) {
-	helper.InternalChildStub()
-}
+func TestHelperStub(t *testing.T) { helper.InternalHelperStub() }