pkg/csource: support archs other than x86_64

This commit is contained in:
Dmitry Vyukov 2017-09-14 21:27:56 +02:00
parent 52a33fd516
commit 19f9bc13d3
12 changed files with 109 additions and 39 deletions

View File

@ -268,9 +268,10 @@ int main(int argc, char** argv)
install_segv_handler();
use_temporary_dir();
#ifdef __i386__
// mmap syscall on i386 is translated to old_mmap and has different signature.
#if defined(__i386__) || defined(__arm__)
// mmap syscall on i386/arm is translated to old_mmap and has different signature.
// As a workaround fix it up to mmap2, which has signature that we expect.
// pkg/csource has the same hack.
for (size_t i = 0; i < sizeof(syscalls) / sizeof(syscalls[0]); i++) {
if (syscalls[i].sys_nr == __NR_mmap)
syscalls[i].sys_nr = __NR_mmap2;

View File

@ -20,7 +20,7 @@ import (
"unsafe"
"github.com/google/syzkaller/prog"
_ "github.com/google/syzkaller/sys"
"github.com/google/syzkaller/sys"
)
type Options struct {
@ -83,24 +83,34 @@ func Write(p *prog.Prog, opts Options) ([]byte, error) {
for _, c := range p.Calls {
handled[c.Meta.CallName] = c.Meta.NR
}
for name, nr := range handled {
// Only generate defines for new syscalls (added after commit 8a1ab3155c2ac on 2012-10-04).
// TODO: the syscall number 313 implies that we're dealing with linux/amd64.
if nr >= 313 && !strings.HasPrefix(name, "syz_") {
fmt.Fprintf(w, "#ifndef __NR_%v\n", name)
fmt.Fprintf(w, "#define __NR_%v %v\n", name, nr)
fmt.Fprintf(w, "#endif\n")
}
}
fmt.Fprintf(w, "\n")
hdr, err := preprocessCommonHeader(opts, handled, prog.RequiresBitmasks(p), prog.RequiresChecksums(p))
hdr, err := preprocessCommonHeader(p.Target, opts, handled, prog.RequiresBitmasks(p), prog.RequiresChecksums(p))
if err != nil {
return nil, err
}
fmt.Fprint(w, hdr)
fmt.Fprint(w, "\n")
for name, nr := range handled {
if strings.HasPrefix(name, "syz_") {
continue
}
if p.Target.OS == "linux" && p.Target.Arch == "amd64" && nr < 313 {
// Only generate defines for new syscalls (added after commit 8a1ab3155c2ac on 2012-10-04).
continue
}
fmt.Fprintf(w, "#ifndef __NR_%v\n", name)
fmt.Fprintf(w, "#define __NR_%v %v\n", name, nr)
fmt.Fprintf(w, "#endif\n")
}
if p.Target.OS == "linux" && p.Target.PtrSize == 4 {
// This is a dirty hack.
// On 32-bit linux mmap translated to old_mmap syscall which has a different signature.
// mmap2 has the right signature. executor translates mmap to mmap2, do the same here.
fmt.Fprintf(w, "#undef __NR_mmap\n")
fmt.Fprintf(w, "#define __NR_mmap __NR_mmap2\n")
}
fmt.Fprintf(w, "\n")
calls, nvar := generateCalls(p.Target, exec, opts)
fmt.Fprintf(w, "long r[%v];\n", nvar)
@ -420,7 +430,7 @@ loop:
return calls, n
}
func preprocessCommonHeader(opts Options, handled map[string]uint64, useBitmasks, useChecksums bool) (string, error) {
func preprocessCommonHeader(target *prog.Target, opts Options, handled map[string]uint64, useBitmasks, useChecksums bool) (string, error) {
var defines []string
if useBitmasks {
defines = append(defines, "SYZ_USE_BITMASKS")
@ -470,8 +480,9 @@ func preprocessCommonHeader(opts Options, handled map[string]uint64, useBitmasks
for name, _ := range handled {
defines = append(defines, "__NR_"+name)
}
// TODO: need to know target arch + do cross-compilation
defines = append(defines, "__x86_64__")
sysTarget := sys.Targets[target.OS][target.Arch]
defines = append(defines, sysTarget.CArch...)
cmd := exec.Command("cpp", "-nostdinc", "-undef", "-fdirectives-only", "-dDI", "-E", "-P", "-")
for _, def := range defines {
@ -512,25 +523,42 @@ func preprocessCommonHeader(opts Options, handled map[string]uint64, useBitmasks
// Build builds a C/C++ program from source src and returns name of the resulting binary.
// lang can be "c" or "c++".
func Build(lang, src string) (string, error) {
func Build(target *prog.Target, lang, src string) (string, error) {
bin, err := ioutil.TempFile("", "syzkaller")
if err != nil {
return "", fmt.Errorf("failed to create temp file: %v", err)
}
bin.Close()
out, err := exec.Command("gcc", "-x", lang, "-Wall", "-Werror", src, "-o", bin.Name(), "-pthread", "-static", "-O1", "-g").CombinedOutput()
sysTarget := sys.Targets[target.OS][target.Arch]
compiler := sysTarget.CCompilerPrefix + "gcc"
if _, err := exec.LookPath(compiler); err != nil {
return "", NoCompilerErr
}
flags := []string{
"-x", lang, "-Wall", "-Werror", "-O1", "-g", "-o", bin.Name(),
src, "-pthread",
}
flags = append(flags, sysTarget.CrossCFlags...)
if sysTarget.PtrSize == 4 {
// We do generate uint64's for syscall arguments that overflow longs on 32-bit archs.
flags = append(flags, "-Wno-overflow")
}
out, err := exec.Command(compiler, append(flags, "-static")...).CombinedOutput()
if err != nil {
// Some distributions don't have static libraries.
out, err = exec.Command("gcc", "-x", lang, "-Wall", "-Werror", src, "-o", bin.Name(), "-pthread", "-O1", "-g").CombinedOutput()
out, err = exec.Command(compiler, flags...).CombinedOutput()
}
if err != nil {
os.Remove(bin.Name())
data, _ := ioutil.ReadFile(src)
return "", fmt.Errorf("failed to build program:\n%s\n%s", data, out)
return "", fmt.Errorf("failed to build program:\n%s\n%s\ncompiler invocation: %v %v\n",
data, out, compiler, flags)
}
return bin.Name(), nil
}
var NoCompilerErr = errors.New("no target compiler")
// Format reformats C source using clang-format.
func Format(src []byte) ([]byte, error) {
stdout, stderr := new(bytes.Buffer), new(bytes.Buffer)

View File

@ -89,7 +89,7 @@ func allOptionsPermutations() []Options {
}
func TestOne(t *testing.T) {
target, rs, _ := initTest(t)
t.Parallel()
opts := Options{
Threaded: true,
Collide: true,
@ -99,8 +99,21 @@ func TestOne(t *testing.T) {
Repro: true,
UseTmpDir: true,
}
p := target.GenerateAllSyzProg(rs)
testOne(t, p, opts)
for _, target := range prog.AllTargets() {
target := target
t.Run(target.OS+"/"+target.Arch, func(t *testing.T) {
if target.OS == "linux" && target.Arch == "arm" {
// This currently fails (at least with my arm-linux-gnueabihf-gcc-4.8) with:
// Assembler messages:
// Error: alignment too large: 15 assumed
t.Skip("broken")
}
t.Parallel()
rs := rand.NewSource(0)
p := target.GenerateAllSyzProg(rs)
testOne(t, p, opts)
})
}
}
func TestOptions(t *testing.T) {
@ -142,7 +155,10 @@ func testOne(t *testing.T, p *prog.Prog, opts Options) {
t.Fatalf("%v", err)
}
defer os.Remove(srcf)
bin, err := Build("c", srcf)
bin, err := Build(p.Target, "c", srcf)
if err == NoCompilerErr {
t.Skip(err)
}
if err != nil {
t.Logf("program:\n%s\n", p.Serialize())
t.Fatalf("%v", err)

View File

@ -19,21 +19,21 @@ import (
const timeout = 10 * time.Second
func buildExecutor(t *testing.T) string {
return buildProgram(t, filepath.FromSlash("../../executor/executor.cc"))
func buildExecutor(t *testing.T, target *prog.Target) string {
return buildProgram(t, target, filepath.FromSlash("../../executor/executor.cc"))
}
func buildSource(t *testing.T, src []byte) string {
func buildSource(t *testing.T, target *prog.Target, src []byte) string {
tmp, err := osutil.WriteTempFile(src)
if err != nil {
t.Fatalf("%v", err)
}
defer os.Remove(tmp)
return buildProgram(t, tmp)
return buildProgram(t, target, tmp)
}
func buildProgram(t *testing.T, src string) string {
bin, err := csource.Build("c++", src)
func buildProgram(t *testing.T, target *prog.Target, src string) string {
bin, err := csource.Build(target, "c++", src)
if err != nil {
t.Fatalf("%v", err)
}
@ -53,7 +53,12 @@ func initTest(t *testing.T) (rand.Source, int) {
}
func TestEmptyProg(t *testing.T) {
bin := buildExecutor(t)
target, err := prog.GetTarget("linux", runtime.GOARCH)
if err != nil {
t.Fatal(err)
}
bin := buildExecutor(t, target)
defer os.Remove(bin)
cfg := Config{
@ -88,7 +93,7 @@ func TestExecute(t *testing.T) {
t.Fatal(err)
}
bin := buildExecutor(t)
bin := buildExecutor(t, target)
defer os.Remove(bin)
for _, flag := range flags {

View File

@ -558,7 +558,7 @@ func (ctx *context) testCProg(p *prog.Prog, duration time.Duration, opts csource
if err != nil {
return false, err
}
bin, err := csource.Build("c", srcf)
bin, err := csource.Build(p.Target, "c", srcf)
if err != nil {
return false, err
}

View File

@ -5,6 +5,7 @@ package prog
import (
"fmt"
"sort"
)
// Target describes target OS/arch pair.
@ -72,12 +73,26 @@ func GetTarget(OS, arch string) (*Target, error) {
for _, t := range targets {
supported = append(supported, fmt.Sprintf("%v/%v", t.OS, t.Arch))
}
sort.Strings(supported)
return nil, fmt.Errorf("unknown target: %v (supported: %v)", key, supported)
}
return target, nil
}
func AllTargets() []*Target {
var res []*Target
for _, t := range targets {
res = append(res, t)
}
sort.Slice(res, func(i, j int) bool {
if res[i].OS != res[j].OS {
return res[i].OS < res[j].OS
}
return res[i].Arch < res[j].Arch
})
return res
}
func initTarget(target *Target) {
target.SyscallMap = make(map[string]*Syscall)
for _, c := range target.Syscalls {

View File

@ -17031,6 +17031,7 @@ var consts_386 = []ConstValue{
{Name: "__NR_mlock2", Value: 376},
{Name: "__NR_mlockall", Value: 152},
{Name: "__NR_mmap", Value: 90},
{Name: "__NR_mmap2", Value: 192},
{Name: "__NR_modify_ldt", Value: 123},
{Name: "__NR_mount", Value: 21},
{Name: "__NR_move_pages", Value: 317},

View File

@ -16976,6 +16976,7 @@ var consts_arm = []ConstValue{
{Name: "__NR_mlock2", Value: 9437574},
{Name: "__NR_mlockall", Value: 9437336},
{Name: "__NR_mmap", Value: 9437274},
{Name: "__NR_mmap2", Value: 9437376},
{Name: "__NR_mount", Value: 9437205},
{Name: "__NR_move_pages", Value: 9437528},
{Name: "__NR_mprotect", Value: 9437309},

View File

@ -54,6 +54,7 @@ include <linux/memfd.h>
include <uapi/linux/module.h>
include <asm/prctl.h>
include <linux/ioprio.h>
include <uapi/linux/kcov.h>
resource fd[int32]: 0xffffffffffffffff, AT_FDCWD
resource fd_dir[fd]
@ -1017,14 +1018,14 @@ getrandom_flags = GRND_NONBLOCK, GRND_RANDOM
uffdio_features = UFFD_FEATURE_PAGEFAULT_FLAG_WP, UFFD_FEATURE_EVENT_FORK, UFFD_FEATURE_EVENT_REMAP, UFFD_FEATURE_EVENT_REMOVE, UFFD_FEATURE_MISSING_HUGETLBFS, UFFD_FEATURE_MISSING_SHMEM, UFFD_FEATURE_EVENT_UNMAP
clone_flags = CLONE_VM, CLONE_FS, CLONE_FILES, CLONE_SIGHAND, CLONE_PTRACE, CLONE_VFORK, CLONE_PARENT, CLONE_THREAD, CLONE_NEWNS, CLONE_SYSVSEM, CLONE_SETTLS, CLONE_PARENT_SETTID, CLONE_CHILD_CLEARTID, CLONE_UNTRACED, CLONE_CHILD_SETTID, CLONE_NEWCGROUP, CLONE_NEWUTS, CLONE_NEWIPC, CLONE_NEWUSER, CLONE_NEWPID, CLONE_NEWNET, CLONE_IO
include <uapi/linux/kcov.h>
kcov_ioctls = KCOV_INIT_TRACE, KCOV_ENABLE
kcov_modes = KCOV_TRACE_PC, KCOV_TRACE_CMP
# TODO: remove once the const is present in kernel headers.
define KCOV_TRACE_PC 0
define KCOV_TRACE_CMP 1
legacy_mmap_number = __NR_mmap2
# Not yet implemented syscalls
#define __NR_umask 95
#define __NR_vhangup 153

View File

@ -714,6 +714,7 @@ __NR_mlock = 150
__NR_mlock2 = 376
__NR_mlockall = 152
__NR_mmap = 90
__NR_mmap2 = 192
__NR_modify_ldt = 123
__NR_mount = 21
__NR_move_pages = 317

View File

@ -704,6 +704,7 @@ __NR_mlock = 9437334
__NR_mlock2 = 9437574
__NR_mlockall = 9437336
__NR_mmap = 9437274
__NR_mmap2 = 9437376
__NR_mount = 9437205
__NR_move_pages = 9437528
__NR_mprotect = 9437309

View File

@ -48,7 +48,7 @@ var Targets = map[string]map[string]*Target{
"arm": {
PtrSize: 4,
CArch: []string{"__arm__"},
CFlags: []string{"-D__LINUX_ARM_ARCH__=6", "-m32"},
CFlags: []string{"-D__LINUX_ARM_ARCH__=6"},
CrossCFlags: []string{"-march=armv6t2"},
CCompilerPrefix: "arm-linux-gnueabihf-",
KernelArch: "arm",