github.com/google/syzkaller@v0.0.0-20240517125934-c0f1611a36d6/pkg/build/cuttlefish.go (about)

     1  // Copyright 2022 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  	"archive/tar"
     8  	"compress/gzip"
     9  	"fmt"
    10  	"io"
    11  	"os"
    12  	"path/filepath"
    13  	"strings"
    14  	"time"
    15  
    16  	"github.com/google/syzkaller/pkg/osutil"
    17  )
    18  
    19  const (
    20  	kernelConfig = "common/build.config.gki_kasan.x86_64"
    21  	moduleConfig = "common-modules/virtual-device/build.config.virtual_device_kasan.x86_64"
    22  	bazelTarget  = "//common-modules/virtual-device:virtual_device_x86_64_dist"
    23  )
    24  
    25  type cuttlefish struct{}
    26  
    27  func (c cuttlefish) runBuild(kernelDir, buildConfig string) error {
    28  	cmd := osutil.Command("build/build.sh")
    29  	cmd.Dir = kernelDir
    30  	cmd.Env = append(cmd.Env, "OUT_DIR=out", "DIST_DIR=dist", fmt.Sprintf("BUILD_CONFIG=%s", buildConfig))
    31  
    32  	_, err := osutil.Run(time.Hour, cmd)
    33  	return err
    34  }
    35  
    36  func (c cuttlefish) runBazel(kernelDir string) error {
    37  	cmd := osutil.Command("tools/bazel", "run", "--kasan", bazelTarget, "--", "--dist_dir=dist")
    38  	if err := osutil.Sandbox(cmd, true, false); err != nil {
    39  		return fmt.Errorf("failed to sandbox build command: %w", err)
    40  	}
    41  	cmd.Dir = kernelDir
    42  	_, err := osutil.Run(time.Hour, cmd)
    43  	return err
    44  }
    45  
    46  func (c cuttlefish) readCompiler(archivePath string) (string, error) {
    47  	f, err := os.Open(archivePath)
    48  	if err != nil {
    49  		return "", err
    50  	}
    51  	defer f.Close()
    52  
    53  	gr, err := gzip.NewReader(f)
    54  	if err != nil {
    55  		return "", err
    56  	}
    57  	defer gr.Close()
    58  
    59  	tr := tar.NewReader(gr)
    60  
    61  	h, err := tr.Next()
    62  	for ; err == nil; h, err = tr.Next() {
    63  		if filepath.Base(h.Name) == "compile.h" {
    64  			bytes, err := io.ReadAll(tr)
    65  			if err != nil {
    66  				return "", err
    67  			}
    68  			result := linuxCompilerRegexp.FindSubmatch(bytes)
    69  			if result == nil {
    70  				return "", fmt.Errorf("include/generated/compile.h does not contain build information")
    71  			}
    72  
    73  			return string(result[1]), nil
    74  		}
    75  	}
    76  
    77  	return "", fmt.Errorf("archive %s doesn't contain include/generated/compile.h", archivePath)
    78  }
    79  
    80  func (c cuttlefish) build(params Params) (ImageDetails, error) {
    81  	var details ImageDetails
    82  
    83  	if params.CmdlineFile != "" {
    84  		return details, fmt.Errorf("cmdline file is not supported for android cuttlefish images")
    85  	}
    86  	if params.SysctlFile != "" {
    87  		return details, fmt.Errorf("sysctl file is not supported for android cuttlefish images")
    88  	}
    89  
    90  	var config string
    91  	var err error
    92  	// Clean output directory if it exists.
    93  	if err := osutil.RemoveAll(filepath.Join(params.KernelDir, "out")); err != nil {
    94  		return details, fmt.Errorf("failed to clean before kernel build: %w", err)
    95  	}
    96  	// Default to build.sh if compiler is not specified.
    97  	if params.Compiler == "bazel" {
    98  		if err := c.runBazel(params.KernelDir); err != nil {
    99  			return details, fmt.Errorf("failed to build kernel: %w", err)
   100  		}
   101  		// Find the .config file; it is placed in a temporary output directory during the build.
   102  		cmd := osutil.Command("find", ".", "-regex", ".*virtual_device_x86_64_config.*/\\.config")
   103  		cmd.Dir = params.KernelDir
   104  		configBytes, err := osutil.Run(time.Minute, cmd)
   105  		if err != nil {
   106  			return details, fmt.Errorf("failed to find build config: %w", err)
   107  		}
   108  		config = filepath.Join(params.KernelDir, strings.TrimSpace(string(configBytes)))
   109  	} else {
   110  		if err := c.runBuild(params.KernelDir, kernelConfig); err != nil {
   111  			return details, fmt.Errorf("failed to build kernel: %w", err)
   112  		}
   113  		if err := c.runBuild(params.KernelDir, moduleConfig); err != nil {
   114  			return details, fmt.Errorf("failed to build modules: %w", err)
   115  		}
   116  		config = filepath.Join(params.KernelDir, "out", "common", ".config")
   117  	}
   118  
   119  	buildDistDir := filepath.Join(params.KernelDir, "dist")
   120  	bzImage := filepath.Join(buildDistDir, "bzImage")
   121  	vmlinux := filepath.Join(buildDistDir, "vmlinux")
   122  	initramfs := filepath.Join(buildDistDir, "initramfs.img")
   123  
   124  	details.CompilerID, err = c.readCompiler(filepath.Join(buildDistDir, "kernel-headers.tar.gz"))
   125  	if err != nil {
   126  		return details, err
   127  	}
   128  
   129  	if err := embedFiles(params, func(mountDir string) error {
   130  		homeDir := filepath.Join(mountDir, "root")
   131  
   132  		if err := osutil.CopyFile(bzImage, filepath.Join(homeDir, "bzImage")); err != nil {
   133  			return err
   134  		}
   135  		if err := osutil.CopyFile(vmlinux, filepath.Join(homeDir, "vmlinux")); err != nil {
   136  			return err
   137  		}
   138  		if err := osutil.CopyFile(initramfs, filepath.Join(homeDir, "initramfs.img")); err != nil {
   139  			return err
   140  		}
   141  
   142  		return nil
   143  	}); err != nil {
   144  		return details, err
   145  	}
   146  
   147  	if err := osutil.CopyFile(vmlinux, filepath.Join(params.OutputDir, "obj", "vmlinux")); err != nil {
   148  		return details, err
   149  	}
   150  	if err := osutil.CopyFile(initramfs, filepath.Join(params.OutputDir, "obj", "initrd")); err != nil {
   151  		return details, err
   152  	}
   153  	if err := osutil.CopyFile(config, filepath.Join(params.OutputDir, "kernel.config")); err != nil {
   154  		return details, err
   155  	}
   156  
   157  	details.Signature, err = elfBinarySignature(vmlinux, params.Tracer)
   158  	if err != nil {
   159  		return details, fmt.Errorf("failed to generate signature: %w", err)
   160  	}
   161  
   162  	return details, nil
   163  }
   164  
   165  func (c cuttlefish) clean(kernelDir, targetArch string) error {
   166  	if err := osutil.RemoveAll(filepath.Join(kernelDir, "out")); err != nil {
   167  		return err
   168  	}
   169  	return osutil.RemoveAll(filepath.Join(kernelDir, "dist"))
   170  }