diff options
| author | Dmitry Vyukov <dvyukov@google.com> | 2017-09-25 08:47:15 +0200 |
|---|---|---|
| committer | Dmitry Vyukov <dvyukov@google.com> | 2017-09-25 08:47:48 +0200 |
| commit | e9c477a5b3a05a614d9a0c68ba9724762a363784 (patch) | |
| tree | a89fbfd6c3f8543f0b86a4c8c68c365a53a40ba1 /sys/syz-extract/linux.go | |
| parent | 8f8cf20bd23a37aaf4ac3a7ec3fab2370ef2a755 (diff) | |
sys/syz-extract: support fuchsia
Diffstat (limited to 'sys/syz-extract/linux.go')
| -rw-r--r-- | sys/syz-extract/linux.go | 228 |
1 files changed, 228 insertions, 0 deletions
diff --git a/sys/syz-extract/linux.go b/sys/syz-extract/linux.go new file mode 100644 index 000000000..8c38c75ee --- /dev/null +++ b/sys/syz-extract/linux.go @@ -0,0 +1,228 @@ +// Copyright 2017 syzkaller project authors. All rights reserved. +// Use of this source code is governed by Apache 2 LICENSE that can be found in the LICENSE file. + +package main + +import ( + "fmt" + "io/ioutil" + "os" + "os/exec" + "regexp" + "strconv" + "strings" + "time" + + "github.com/google/syzkaller/pkg/compiler" + "github.com/google/syzkaller/pkg/osutil" + "github.com/google/syzkaller/sys/targets" +) + +type linux struct{} + +func (*linux) prepare(sourcedir string, build bool, arches []string) error { + if build { + // Otherwise out-of-tree build fails. + fmt.Printf("make mrproper\n") + out, err := osutil.RunCmd(time.Hour, sourcedir, "make", "mrproper") + if err != nil { + return fmt.Errorf("make mrproper failed: %v\n%s\n", err, out) + } + } else { + if len(arches) > 1 { + return fmt.Errorf("more than 1 arch is invalid without -build") + } + } + return nil +} + +func (*linux) prepareArch(arch *Arch) error { + if !arch.build { + return nil + } + target := arch.target + kernelDir := arch.sourceDir + buildDir := arch.buildDir + makeArgs := []string{ + "ARCH=" + target.KernelArch, + "CROSS_COMPILE=" + target.CCompilerPrefix, + "CFLAGS=" + strings.Join(target.CrossCFlags, " "), + "O=" + buildDir, + } + out, err := osutil.RunCmd(time.Hour, kernelDir, "make", append(makeArgs, "defconfig")...) + if err != nil { + return fmt.Errorf("make defconfig failed: %v\n%s\n", err, out) + } + // Without CONFIG_NETFILTER kernel does not build. + out, err = osutil.RunCmd(time.Minute, buildDir, "sed", "-i", + "s@# CONFIG_NETFILTER is not set@CONFIG_NETFILTER=y@g", ".config") + if err != nil { + return fmt.Errorf("sed .config failed: %v\n%s\n", err, out) + } + out, err = osutil.RunCmd(time.Hour, kernelDir, "make", append(makeArgs, "olddefconfig")...) + if err != nil { + return fmt.Errorf("make olddefconfig failed: %v\n%s\n", err, out) + } + out, err = osutil.RunCmd(time.Hour, kernelDir, "make", append(makeArgs, "init/main.o")...) + if err != nil { + return fmt.Errorf("make failed: %v\n%s\n", err, out) + } + return nil +} + +func (*linux) processFile(arch *Arch, info *compiler.ConstInfo) (map[string]uint64, map[string]bool, error) { + vals := info.Consts + includes := append(info.Includes, "asm/unistd.h") + bin, out, err := linuxCompile(arch.target, arch.sourceDir, arch.buildDir, nil, + includes, info.Incdirs, nil, nil) + if err != nil { + return nil, nil, fmt.Errorf("failed to run gcc: %v\n%v", err, string(out)) + } + os.Remove(bin) + + valMap := make(map[string]bool) + for _, val := range vals { + valMap[val] = true + } + + undeclared := make(map[string]bool) + bin, out, err = linuxCompile(arch.target, arch.sourceDir, arch.buildDir, vals, + includes, info.Incdirs, info.Defines, undeclared) + if err != nil { + for _, errMsg := range []string{ + "error: ‘([a-zA-Z0-9_]+)’ undeclared", + "note: in expansion of macro ‘([a-zA-Z0-9_]+)’", + } { + re := regexp.MustCompile(errMsg) + matches := re.FindAllSubmatch(out, -1) + for _, match := range matches { + val := string(match[1]) + if !undeclared[val] && valMap[val] { + undeclared[val] = true + } + } + } + bin, out, err = linuxCompile(arch.target, arch.sourceDir, arch.buildDir, vals, + includes, info.Incdirs, info.Defines, undeclared) + if err != nil { + return nil, nil, fmt.Errorf("failed to run gcc: %v\n%v", err, string(out)) + } + } + defer os.Remove(bin) + + out, err = exec.Command(bin).CombinedOutput() + if err != nil { + return nil, nil, fmt.Errorf("failed to run flags binary: %v\n%v", err, string(out)) + } + + flagVals := strings.Split(string(out), " ") + if len(out) == 0 { + flagVals = nil + } + if len(flagVals) != len(vals)-len(undeclared) { + return nil, nil, fmt.Errorf("fetched wrong number of values %v != %v - %v\nflagVals: %q\nvals: %q\nundeclared: %q", + len(flagVals), len(vals), len(undeclared), + flagVals, vals, undeclared) + } + res := make(map[string]uint64) + j := 0 + for _, v := range flagVals { + name := vals[j] + j++ + for undeclared[name] { + name = vals[j] + j++ + } + n, err := strconv.ParseUint(v, 10, 64) + if err != nil { + return nil, nil, fmt.Errorf("failed to parse value: %v (%v)", err, v) + } + res[name] = n + } + return res, undeclared, nil +} + +func linuxCompile(target *targets.Target, kernelDir, buildDir string, vals, includes, incdirs []string, defines map[string]string, undeclared map[string]bool) (bin string, out []byte, err error) { + includeText := "" + for _, inc := range includes { + includeText += fmt.Sprintf("#include <%v>\n", inc) + } + definesText := "" + for k, v := range defines { + definesText += fmt.Sprintf("#ifndef %v\n#define %v %v\n#endif\n", k, k, v) + } + valsText := "" + for _, v := range vals { + if undeclared[v] { + continue + } + if valsText != "" { + valsText += "," + } + valsText += v + } + src := strings.Replace(linuxSrc, "[[INCLUDES]]", includeText, 1) + src = strings.Replace(src, "[[DEFAULTS]]", definesText, 1) + src = strings.Replace(src, "[[VALS]]", valsText, 1) + binFile, err := ioutil.TempFile("", "") + if err != nil { + return "", nil, fmt.Errorf("failed to create temp file: %v", err) + } + binFile.Close() + + arch := target.KernelHeaderArch + args := []string{"-x", "c", "-", "-o", binFile.Name(), "-fmessage-length=0"} + args = append(args, target.CFlags...) + args = append(args, []string{ + // This would be useful to ensure that we don't include any host headers, + // but kernel includes at least <stdarg.h> + // "-nostdinc", + "-w", + "-O3", // required to get expected values for some __builtin_constant_p + "-I.", + "-D__KERNEL__", + "-DKBUILD_MODNAME=\"-\"", + "-I" + kernelDir + "/arch/" + arch + "/include", + "-I" + buildDir + "/arch/" + arch + "/include/generated/uapi", + "-I" + buildDir + "/arch/" + arch + "/include/generated", + "-I" + buildDir + "/include", + "-I" + kernelDir + "/include", + "-I" + kernelDir + "/arch/" + arch + "/include/uapi", + "-I" + buildDir + "/arch/" + arch + "/include/generated/uapi", + "-I" + kernelDir + "/include/uapi", + "-I" + buildDir + "/include/generated/uapi", + "-I" + kernelDir, + "-include", kernelDir + "/include/linux/kconfig.h", + }...) + for _, incdir := range incdirs { + args = append(args, "-I"+kernelDir+"/"+incdir) + } + cmd := exec.Command("gcc", args...) + cmd.Stdin = strings.NewReader(src) + out, err = cmd.CombinedOutput() + if err != nil { + os.Remove(binFile.Name()) + return "", out, err + } + return binFile.Name(), nil, nil +} + +var linuxSrc = ` +[[INCLUDES]] +[[DEFAULTS]] +int printf(const char *format, ...); +unsigned long phys_base; +#ifndef __phys_addr +unsigned long __phys_addr(unsigned long addr) { return 0; } +#endif +int main() { + int i; + unsigned long long vals[] = {[[VALS]]}; + for (i = 0; i < sizeof(vals)/sizeof(vals[0]); i++) { + if (i != 0) + printf(" "); + printf("%llu", vals[i]); + } + return 0; +} +` |
