diff options
| author | Dmitry Vyukov <dvyukov@google.com> | 2019-12-02 14:36:47 +0100 |
|---|---|---|
| committer | Dmitry Vyukov <dvyukov@google.com> | 2019-12-02 14:36:47 +0100 |
| commit | 3aa380090f35529e58e4a393e8e0dee79dd0d491 (patch) | |
| tree | 90f8fd02769965193155c22056f61afcd3786a52 /sys | |
| parent | f879db37f90dcefb681897d2e486c11d8298cb72 (diff) | |
sys/syz-extract: extract constants from ELF
Add a second mode that extracts constant values from
ELF object, instead of running the executable.
This allows to not (1) link binaries, (2) use proper cross-compiler.
It finally fixes 386/arm extracts for my distro.
Hopefully not makes things worse for others,
should generally be safer/more reliable.
The current mode is left b/c I can't test all OSes,
windows binaries are not ELF, so we may need it anyway.
But later we may switch more OSes to this new mode
if they break (fuchsia?).
Diffstat (limited to 'sys')
| -rw-r--r-- | sys/syz-extract/akaros.go | 5 | ||||
| -rw-r--r-- | sys/syz-extract/extract.go | 4 | ||||
| -rw-r--r-- | sys/syz-extract/fetch.go | 114 | ||||
| -rw-r--r-- | sys/syz-extract/freebsd.go | 6 | ||||
| -rw-r--r-- | sys/syz-extract/fuchsia.go | 6 | ||||
| -rw-r--r-- | sys/syz-extract/linux.go | 30 | ||||
| -rw-r--r-- | sys/syz-extract/netbsd.go | 5 | ||||
| -rw-r--r-- | sys/syz-extract/openbsd.go | 5 | ||||
| -rw-r--r-- | sys/syz-extract/trusty.go | 5 | ||||
| -rw-r--r-- | sys/syz-extract/windows.go | 5 |
10 files changed, 123 insertions, 62 deletions
diff --git a/sys/syz-extract/akaros.go b/sys/syz-extract/akaros.go index 294152e4f..00375f195 100644 --- a/sys/syz-extract/akaros.go +++ b/sys/syz-extract/akaros.go @@ -41,5 +41,8 @@ func (*akaros) processFile(arch *Arch, info *compiler.ConstInfo) (map[string]uin args = append(args, "-I"+dir) } } - return extract(info, "gcc", args, "", true, false) + params := &extractParams{ + DeclarePrintf: true, + } + return extract(info, "gcc", args, params) } diff --git a/sys/syz-extract/extract.go b/sys/syz-extract/extract.go index 70c203b8d..64776bb96 100644 --- a/sys/syz-extract/extract.go +++ b/sys/syz-extract/extract.go @@ -13,7 +13,6 @@ import ( "runtime" "sort" "strings" - "sync" "github.com/google/syzkaller/pkg/ast" "github.com/google/syzkaller/pkg/compiler" @@ -39,9 +38,6 @@ type Arch struct { files []*File err error done chan bool - // Used by OS implementations: - once sync.Once - cc string } type File struct { diff --git a/sys/syz-extract/fetch.go b/sys/syz-extract/fetch.go index 58910d577..405b0167f 100644 --- a/sys/syz-extract/fetch.go +++ b/sys/syz-extract/fetch.go @@ -5,7 +5,10 @@ package main import ( "bytes" + "debug/elf" + "encoding/binary" "fmt" + "io/ioutil" "os" "regexp" "strconv" @@ -16,15 +19,20 @@ import ( "github.com/google/syzkaller/pkg/osutil" ) -func extract(info *compiler.ConstInfo, cc string, args []string, addSource string, declarePrintf, defineGlibcUse bool) ( +type extractParams struct { + AddSource string + DeclarePrintf bool + DefineGlibcUse bool // workaround for incorrect flags to clang for fuchsia. + ExtractFromELF bool +} + +func extract(info *compiler.ConstInfo, cc string, args []string, params *extractParams) ( map[string]uint64, map[string]bool, error) { data := &CompileData{ - AddSource: addSource, - Defines: info.Defines, - Includes: info.Includes, - Values: info.Consts, - DeclarePrintf: declarePrintf, - DefineGlibcUse: defineGlibcUse, + extractParams: params, + Defines: info.Defines, + Includes: info.Includes, + Values: info.Consts, } undeclared := make(map[string]bool) bin, out, err := compile(cc, args, data) @@ -59,19 +67,20 @@ func extract(info *compiler.ConstInfo, cc string, args []string, addSource strin } bin, out, err = compile(cc, args, data) if err != nil { - return nil, nil, fmt.Errorf("failed to run compiler: %v %v\n%v\n%v", - cc, args, err, string(out)) + return nil, nil, fmt.Errorf("failed to run compiler: %v %v\n%v\n%s", + cc, args, err, out) } } defer os.Remove(bin) - out, err = osutil.Command(bin).CombinedOutput() - if err != nil { - return nil, nil, fmt.Errorf("failed to run flags binary: %v\n%v", err, string(out)) + var flagVals []uint64 + if data.ExtractFromELF { + flagVals, err = extractFromELF(bin) + } else { + flagVals, err = extractFromExecutable(bin) } - flagVals := strings.Split(string(out), " ") - if len(out) == 0 { - flagVals = nil + if err != nil { + return nil, nil, err } if len(flagVals) != len(data.Values) { return nil, nil, fmt.Errorf("fetched wrong number of values %v, want != %v", @@ -79,26 +88,19 @@ func extract(info *compiler.ConstInfo, cc string, args []string, addSource strin } res := make(map[string]uint64) for i, name := range data.Values { - val := flagVals[i] - n, err := strconv.ParseUint(val, 10, 64) - if err != nil { - return nil, nil, fmt.Errorf("failed to parse value: %v (%v)", err, val) - } - res[name] = n + res[name] = flagVals[i] } return res, undeclared, nil } type CompileData struct { - AddSource string - Defines map[string]string - Includes []string - Values []string - DeclarePrintf bool - DefineGlibcUse bool // workaround for incorrect flags to clang for fuchsia. + *extractParams + Defines map[string]string + Includes []string + Values []string } -func compile(cc string, args []string, data *CompileData) (bin string, out []byte, err error) { +func compile(cc string, args []string, data *CompileData) (string, []byte, error) { src := new(bytes.Buffer) if err := srcTemplate.Execute(src, data); err != nil { return "", nil, fmt.Errorf("failed to generate source: %v", err) @@ -112,6 +114,9 @@ func compile(cc string, args []string, data *CompileData) (bin string, out []byt "-o", binFile, "-w", }...) + if data.ExtractFromELF { + args = append(args, "-c") + } cmd := osutil.Command(cc, args...) cmd.Stdin = src if out, err := cmd.CombinedOutput(); err != nil { @@ -121,6 +126,51 @@ func compile(cc string, args []string, data *CompileData) (bin string, out []byt return binFile, nil, nil } +func extractFromExecutable(binFile string) ([]uint64, error) { + out, err := osutil.Command(binFile).CombinedOutput() + if err != nil { + return nil, fmt.Errorf("failed to run flags binary: %v\n%s", err, out) + } + if len(out) == 0 { + return nil, nil + } + var vals []uint64 + for _, val := range strings.Split(string(out), " ") { + n, err := strconv.ParseUint(val, 10, 64) + if err != nil { + return nil, fmt.Errorf("failed to parse value: %v (%v)", err, val) + } + vals = append(vals, n) + } + return vals, nil +} + +func extractFromELF(binFile string) ([]uint64, error) { + f, err := os.Open(binFile) + if err != nil { + return nil, err + } + ef, err := elf.NewFile(f) + if err != nil { + return nil, err + } + for _, sec := range ef.Sections { + if sec.Name != "syz_extract_data" { + continue + } + data, err := ioutil.ReadAll(sec.Open()) + if err != nil { + return nil, err + } + vals := make([]uint64, len(data)/8) + if err := binary.Read(bytes.NewReader(data), binary.LittleEndian, &vals); err != nil { + return nil, err + } + return vals, nil + } + return nil, fmt.Errorf("did not find syz_extract_data section") +} + var srcTemplate = template.Must(template.New("").Parse(` #define __asm__(...) @@ -146,6 +196,13 @@ var srcTemplate = template.Must(template.New("").Parse(` int printf(const char *format, ...); {{end}} +{{if .ExtractFromELF}} +__attribute__((section("syz_extract_data"))) +unsigned long long vals[] = { + {{range $val := $.Values}}(unsigned long long){{$val}}, + {{end}} +}; +{{else}} int main() { int i; unsigned long long vals[] = { @@ -159,4 +216,5 @@ int main() { } return 0; } +{{end}} `)) diff --git a/sys/syz-extract/freebsd.go b/sys/syz-extract/freebsd.go index e5256521b..7bd02afeb 100644 --- a/sys/syz-extract/freebsd.go +++ b/sys/syz-extract/freebsd.go @@ -56,5 +56,9 @@ func (*freebsd) processFile(arch *Arch, info *compiler.ConstInfo) (map[string]ui args = append(args, "-I"+dir) } } - return extract(info, "gcc", args, "#include <sys/syscall.h>", true, false) + params := &extractParams{ + AddSource: "#include <sys/syscall.h>", + DeclarePrintf: true, + } + return extract(info, "gcc", args, params) } diff --git a/sys/syz-extract/fuchsia.go b/sys/syz-extract/fuchsia.go index a2be49202..6c0a41e88 100644 --- a/sys/syz-extract/fuchsia.go +++ b/sys/syz-extract/fuchsia.go @@ -37,5 +37,9 @@ func (*fuchsia) processFile(arch *Arch, info *compiler.ConstInfo) (map[string]ui for _, incdir := range info.Incdirs { args = append(args, "-I"+filepath.Join(dir, incdir)) } - return extract(info, cc, args, "", true, true) + params := &extractParams{ + DeclarePrintf: true, + DefineGlibcUse: true, + } + return extract(info, cc, args, params) } diff --git a/sys/syz-extract/linux.go b/sys/syz-extract/linux.go index 4c759a19d..b4bfd0b1e 100644 --- a/sys/syz-extract/linux.go +++ b/sys/syz-extract/linux.go @@ -5,7 +5,6 @@ package main import ( "fmt" - "os/exec" "path/filepath" "runtime" "strings" @@ -111,13 +110,6 @@ func (*linux) prepareArch(arch *Arch) error { } func (*linux) processFile(arch *Arch, info *compiler.ConstInfo) (map[string]uint64, map[string]bool, error) { - arch.once.Do(func() { - arch.cc = "gcc" - if !checkCompiler("gcc", arch.target.CFlags) && - checkCompiler("clang", arch.target.CFlags) { - arch.cc = "clang" - } - }) headerArch := arch.target.KernelHeaderArch sourceDir := arch.sourceDir buildDir := arch.buildDir @@ -143,7 +135,7 @@ func (*linux) processFile(arch *Arch, info *compiler.ConstInfo) (map[string]uint "-I" + buildDir + "/syzkaller", "-include", sourceDir + "/include/linux/kconfig.h", } - args = append(args, arch.target.CFlags...) + args = append(args, arch.target.CrossCFlags...) for _, incdir := range info.Incdirs { args = append(args, "-I"+sourceDir+"/"+incdir) } @@ -152,14 +144,12 @@ func (*linux) processFile(arch *Arch, info *compiler.ConstInfo) (map[string]uint args = append(args, "-I"+dir) } } - const addSource = ` -#include <asm/unistd.h> -unsigned long phys_base; -#ifndef __phys_addr -unsigned long __phys_addr(unsigned long addr) { return 0; } -#endif -` - res, undeclared, err := extract(info, arch.cc, args, addSource, true, false) + params := &extractParams{ + AddSource: "#include <asm/unistd.h>", + ExtractFromELF: true, + } + cc := arch.target.CCompilerPrefix + "gcc" + res, undeclared, err := extract(info, cc, args, params) if err != nil { return nil, nil, err } @@ -179,9 +169,3 @@ unsigned long __phys_addr(unsigned long addr) { return 0; } } return res, undeclared, nil } - -func checkCompiler(cc string, args []string) bool { - cmd := exec.Command(cc, append(args, "-x", "c", "-", "-o", "/dev/null")...) - cmd.Stdin = strings.NewReader("int main(){}") - return cmd.Run() == nil -} diff --git a/sys/syz-extract/netbsd.go b/sys/syz-extract/netbsd.go index 0ff12680d..61c4716cd 100644 --- a/sys/syz-extract/netbsd.go +++ b/sys/syz-extract/netbsd.go @@ -91,7 +91,10 @@ func (*netbsd) processFile(arch *Arch, info *compiler.ConstInfo) (map[string]uin info.Consts = append(info.Consts, compat) } } - res, undeclared, err := extract(info, "gcc", args, "#include <sys/syscall.h>", false, false) + params := &extractParams{ + AddSource: "#include <sys/syscall.h>", + } + res, undeclared, err := extract(info, "gcc", args, params) for orig, compats := range compatNames { for _, compat := range compats { if undeclared[orig] && !undeclared[compat] { diff --git a/sys/syz-extract/openbsd.go b/sys/syz-extract/openbsd.go index 1a56c18db..715131f28 100644 --- a/sys/syz-extract/openbsd.go +++ b/sys/syz-extract/openbsd.go @@ -76,7 +76,10 @@ func (*openbsd) processFile(arch *Arch, info *compiler.ConstInfo) (map[string]ui info.Consts = append(info.Consts, compat) } } - res, undeclared, err := extract(info, "gcc", args, "#include <sys/syscall.h>", false, false) + params := &extractParams{ + AddSource: "#include <sys/syscall.h>", + } + res, undeclared, err := extract(info, "gcc", args, params) for orig, compats := range compatNames { for _, compat := range compats { if undeclared[orig] && !undeclared[compat] { diff --git a/sys/syz-extract/trusty.go b/sys/syz-extract/trusty.go index 6bd5d6bfa..d9d78dded 100644 --- a/sys/syz-extract/trusty.go +++ b/sys/syz-extract/trusty.go @@ -39,5 +39,8 @@ func (*trusty) processFile(arch *Arch, info *compiler.ConstInfo) (map[string]uin args = append(args, "-I"+dir) } } - return extract(info, "gcc", args, "", true, false) + params := &extractParams{ + DeclarePrintf: true, + } + return extract(info, "gcc", args, params) } diff --git a/sys/syz-extract/windows.go b/sys/syz-extract/windows.go index d74ef505d..d4f86f60e 100644 --- a/sys/syz-extract/windows.go +++ b/sys/syz-extract/windows.go @@ -18,5 +18,8 @@ func (*windows) prepareArch(arch *Arch) error { } func (*windows) processFile(arch *Arch, info *compiler.ConstInfo) (map[string]uint64, map[string]bool, error) { - return extract(info, "cl", nil, "", true, false) + params := &extractParams{ + DeclarePrintf: true, + } + return extract(info, "cl", nil, params) } |
