aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAlexander Potapenko <glider@google.com>2024-12-05 15:45:00 +0100
committerAlexander Potapenko <glider@google.com>2024-12-06 07:54:04 +0000
commit637acba36dcf8a7d2a71ee856f5f6f36c612525c (patch)
tree7ec5d415bef802bf1bcc8cabf30453f3ed404349
parentfb1cc4d5036e3321687190e067576046b75b9401 (diff)
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.
-rw-r--r--pkg/runtest/executor_test.go57
1 files changed, 50 insertions, 7 deletions
diff --git a/pkg/runtest/executor_test.go b/pkg/runtest/executor_test.go
index bb830e885..5655f5ea4 100644
--- a/pkg/runtest/executor_test.go
+++ b/pkg/runtest/executor_test.go
@@ -8,6 +8,8 @@ import (
"fmt"
"math/rand"
"os"
+ "os/exec"
+ "path/filepath"
"runtime"
"strings"
"testing"
@@ -24,6 +26,42 @@ import (
"github.com/google/syzkaller/sys/targets"
)
+// Find the corresponding QEMU binary for the target arch, if needed.
+func qemuBinary(arch string) (string, error) {
+ qarch, ok := map[string]string{
+ "386": "i386",
+ "amd64": "x86_64",
+ "arm64": "aarch64",
+ "arm": "arm",
+ "mips64le": "mips64el",
+ "ppc64le": "ppc64le",
+ "riscv64": "riscv64",
+ "s390x": "s390x",
+ }[arch]
+ if !ok {
+ return "", fmt.Errorf("unsupported architecture: %s", arch)
+ }
+
+ qemuBinary := "qemu-" + qarch
+ path, err := exec.LookPath(qemuBinary)
+ if err != nil {
+ return "", fmt.Errorf("qemu binary not found in PATH: %s", qemuBinary)
+ }
+
+ return filepath.Base(path), nil
+}
+
+// If the tests are running on CI, or if there is an assertion failure in the executor,
+// report a fatal error. Otherwise, assume cross-arch execution does not work, and skip
+// the test.
+func handleCrossArchError(t *testing.T, err error) {
+ if os.Getenv("CI") != "" || strings.Contains(err.Error(), "SYZFAIL:") {
+ t.Fatal(err)
+ } else {
+ t.Skipf("skipping, cross-arch execution failed: %v", err)
+ }
+}
+
// TestExecutor runs all internal executor unit tests.
// We do it here because we already build executor binary here.
func TestExecutor(t *testing.T) {
@@ -41,15 +79,20 @@ func TestExecutor(t *testing.T) {
t.Fatal(err)
}
bin := csource.BuildExecutor(t, target, "../..")
- // qemu-user may allow us to run some cross-arch binaries.
- if _, err := osutil.RunCmd(time.Minute, dir, bin, "test"); err != nil {
- if sysTarget.Arch == runtime.GOARCH || sysTarget.VMArch == runtime.GOARCH {
+ if sysTarget.Arch == runtime.GOARCH || sysTarget.VMArch == runtime.GOARCH {
+ // Execute the tests natively.
+ if _, err := osutil.RunCmd(time.Minute, dir, bin, "test"); err != nil {
t.Fatal(err)
}
- if os.Getenv("CI") != "" || strings.Contains(err.Error(), "SYZFAIL:") {
- t.Fatal(err)
- } else {
- t.Skipf("skipping, cross-arch binary failed: %v", err)
+ } else {
+ // Get QEMU binary for the target arch. This code might run inside Docker, so it cannot
+ // rely on binfmt_misc handlers provided by qemu-user.
+ qemu, err := qemuBinary(sysTarget.Arch)
+ if err != nil {
+ handleCrossArchError(t, err)
+ }
+ if _, err := osutil.RunCmd(time.Minute, dir, qemu, bin, "test"); err != nil {
+ handleCrossArchError(t, err)
}
}
})