Skip to content

Commit 637acba

Browse files
pkg/runtest: use qemu-<arch> binaries to run cross-compiled tests
When running the executor tests, do not rely on qemu-user providing binfmt_misc handlers for alien arches (e.g. arm64 on x86), because binfmt_misc cannot be mounted inside the Docker container. Instead, explicitly run the cross-compiled executor under the corresponding QEMU binary.
1 parent fb1cc4d commit 637acba

File tree

1 file changed

+50
-7
lines changed

1 file changed

+50
-7
lines changed

pkg/runtest/executor_test.go

Lines changed: 50 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,8 @@ import (
88
"fmt"
99
"math/rand"
1010
"os"
11+
"os/exec"
12+
"path/filepath"
1113
"runtime"
1214
"strings"
1315
"testing"
@@ -24,6 +26,42 @@ import (
2426
"github.com/google/syzkaller/sys/targets"
2527
)
2628

29+
// Find the corresponding QEMU binary for the target arch, if needed.
30+
func qemuBinary(arch string) (string, error) {
31+
qarch, ok := map[string]string{
32+
"386": "i386",
33+
"amd64": "x86_64",
34+
"arm64": "aarch64",
35+
"arm": "arm",
36+
"mips64le": "mips64el",
37+
"ppc64le": "ppc64le",
38+
"riscv64": "riscv64",
39+
"s390x": "s390x",
40+
}[arch]
41+
if !ok {
42+
return "", fmt.Errorf("unsupported architecture: %s", arch)
43+
}
44+
45+
qemuBinary := "qemu-" + qarch
46+
path, err := exec.LookPath(qemuBinary)
47+
if err != nil {
48+
return "", fmt.Errorf("qemu binary not found in PATH: %s", qemuBinary)
49+
}
50+
51+
return filepath.Base(path), nil
52+
}
53+
54+
// If the tests are running on CI, or if there is an assertion failure in the executor,
55+
// report a fatal error. Otherwise, assume cross-arch execution does not work, and skip
56+
// the test.
57+
func handleCrossArchError(t *testing.T, err error) {
58+
if os.Getenv("CI") != "" || strings.Contains(err.Error(), "SYZFAIL:") {
59+
t.Fatal(err)
60+
} else {
61+
t.Skipf("skipping, cross-arch execution failed: %v", err)
62+
}
63+
}
64+
2765
// TestExecutor runs all internal executor unit tests.
2866
// We do it here because we already build executor binary here.
2967
func TestExecutor(t *testing.T) {
@@ -41,15 +79,20 @@ func TestExecutor(t *testing.T) {
4179
t.Fatal(err)
4280
}
4381
bin := csource.BuildExecutor(t, target, "../..")
44-
// qemu-user may allow us to run some cross-arch binaries.
45-
if _, err := osutil.RunCmd(time.Minute, dir, bin, "test"); err != nil {
46-
if sysTarget.Arch == runtime.GOARCH || sysTarget.VMArch == runtime.GOARCH {
82+
if sysTarget.Arch == runtime.GOARCH || sysTarget.VMArch == runtime.GOARCH {
83+
// Execute the tests natively.
84+
if _, err := osutil.RunCmd(time.Minute, dir, bin, "test"); err != nil {
4785
t.Fatal(err)
4886
}
49-
if os.Getenv("CI") != "" || strings.Contains(err.Error(), "SYZFAIL:") {
50-
t.Fatal(err)
51-
} else {
52-
t.Skipf("skipping, cross-arch binary failed: %v", err)
87+
} else {
88+
// Get QEMU binary for the target arch. This code might run inside Docker, so it cannot
89+
// rely on binfmt_misc handlers provided by qemu-user.
90+
qemu, err := qemuBinary(sysTarget.Arch)
91+
if err != nil {
92+
handleCrossArchError(t, err)
93+
}
94+
if _, err := osutil.RunCmd(time.Minute, dir, qemu, bin, "test"); err != nil {
95+
handleCrossArchError(t, err)
5396
}
5497
}
5598
})

0 commit comments

Comments
 (0)