github.com/google/syzkaller@v0.0.0-20240517125934-c0f1611a36d6/pkg/build/fuchsia.go (about) 1 // Copyright 2018 syzkaller project authors. All rights reserved. 2 // Use of this source code is governed by Apache 2 LICENSE that can be found in the LICENSE file. 3 4 package build 5 6 import ( 7 "errors" 8 "fmt" 9 "os" 10 "path/filepath" 11 "runtime" 12 "time" 13 14 "github.com/google/syzkaller/pkg/osutil" 15 "github.com/google/syzkaller/sys/targets" 16 ) 17 18 type fuchsia struct{} 19 20 // syzRoot returns $GOPATH/src/github.com/google/syzkaller. 21 func syzRoot() (string, error) { 22 _, selfPath, _, ok := runtime.Caller(0) 23 if !ok { 24 return "", errors.New("runtime.Caller failed") 25 } 26 27 return filepath.Abs(filepath.Join(filepath.Dir(selfPath), "../..")) 28 } 29 30 // nolint: goconst // to ignore "out/" 31 func (fu fuchsia) build(params Params) (ImageDetails, error) { 32 syzDir, err := syzRoot() 33 if err != nil { 34 return ImageDetails{}, err 35 } 36 37 sysTarget := targets.Get(targets.Fuchsia, params.TargetArch) 38 if sysTarget == nil { 39 return ImageDetails{}, fmt.Errorf("unsupported fuchsia arch %v", params.TargetArch) 40 } 41 arch := sysTarget.KernelHeaderArch 42 product := fmt.Sprintf("%s.%s", "core", arch) 43 if _, err := runSandboxed(time.Hour, params.KernelDir, 44 "scripts/fx", "--dir", "out/"+arch, 45 "set", product, 46 "--args", fmt.Sprintf(`syzkaller_dir="%s"`, syzDir), 47 "--with-base", "//bundles/tools", 48 "--with-base", "//src/testing/fuzzing/syzkaller", 49 "--variant", "kasan", 50 "--no-goma", 51 ); err != nil { 52 return ImageDetails{}, err 53 } 54 if _, err := runSandboxed(time.Hour*2, params.KernelDir, "scripts/fx", "clean-build"); err != nil { 55 return ImageDetails{}, err 56 } 57 58 // Add ssh keys to the zbi image so syzkaller can access the fuchsia vm. 59 _, sshKeyPub, err := genSSHKeys(params.OutputDir) 60 if err != nil { 61 return ImageDetails{}, err 62 } 63 64 sshZBI := filepath.Join(params.OutputDir, "initrd") 65 kernelZBI := filepath.Join(params.KernelDir, "out", arch, "fuchsia.zbi") 66 authorizedKeys := fmt.Sprintf("data/ssh/authorized_keys=%s", sshKeyPub) 67 68 if _, err := osutil.RunCmd(time.Minute, params.KernelDir, "out/"+arch+"/host_x64/zbi", 69 "-o", sshZBI, kernelZBI, "--entry", authorizedKeys); err != nil { 70 return ImageDetails{}, err 71 } 72 73 // Copy and extend the fvm. 74 fvmTool := filepath.Join("out", arch, "host_x64", "fvm") 75 fvmDst := filepath.Join(params.OutputDir, "image") 76 fvmSrc := filepath.Join(params.KernelDir, "out", arch, "obj", "build", "images", "fuchsia", "fuchsia", "fvm.blk") 77 if err := osutil.CopyFile(fvmSrc, fvmDst); err != nil { 78 return ImageDetails{}, err 79 } 80 if _, err := osutil.RunCmd(time.Minute*5, params.KernelDir, fvmTool, fvmDst, "extend", "--length", "3G"); err != nil { 81 return ImageDetails{}, err 82 } 83 84 for src, dst := range map[string]string{ 85 "out/" + arch + "/kernel_" + arch + "-kasan/zircon.elf": "obj/zircon.elf", 86 "out/" + arch + "/multiboot.bin": "kernel", 87 } { 88 fullSrc := filepath.Join(params.KernelDir, filepath.FromSlash(src)) 89 fullDst := filepath.Join(params.OutputDir, filepath.FromSlash(dst)) 90 if err := osutil.CopyFile(fullSrc, fullDst); err != nil { 91 return ImageDetails{}, fmt.Errorf("failed to copy %v: %w", src, err) 92 } 93 } 94 return ImageDetails{}, nil 95 } 96 97 func (fu fuchsia) clean(kernelDir, targetArch string) error { 98 // We always do clean build because incremental build is frequently broken. 99 // So no need to clean separately. 100 return nil 101 } 102 103 func runSandboxed(timeout time.Duration, dir, command string, arg ...string) ([]byte, error) { 104 cmd := osutil.Command(command, arg...) 105 cmd.Dir = dir 106 if err := osutil.Sandbox(cmd, true, false); err != nil { 107 return nil, err 108 } 109 return osutil.Run(timeout, cmd) 110 } 111 112 // genSSHKeys generates a pair of ssh keys inside the given directory, named key and key.pub. 113 // If both files already exist, this function does nothing. 114 // The function returns the path to both keys. 115 func genSSHKeys(dir string) (privKey, pubKey string, err error) { 116 privKey = filepath.Join(dir, "key") 117 pubKey = filepath.Join(dir, "key.pub") 118 119 os.Remove(privKey) 120 os.Remove(pubKey) 121 122 if _, err := osutil.RunCmd(time.Minute*5, dir, "ssh-keygen", "-t", "rsa", "-b", "2048", 123 "-N", "", "-C", "syzkaller-ssh", "-f", privKey); err != nil { 124 return "", "", err 125 } 126 return privKey, pubKey, nil 127 }