github.com/google/syzkaller@v0.0.0-20240517125934-c0f1611a36d6/sys/syz-extract/linux.go (about) 1 // Copyright 2017 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 main 5 6 import ( 7 "fmt" 8 "path/filepath" 9 "runtime" 10 "strings" 11 "time" 12 13 "github.com/google/syzkaller/pkg/build" 14 "github.com/google/syzkaller/pkg/compiler" 15 "github.com/google/syzkaller/pkg/osutil" 16 ) 17 18 type linux struct{} 19 20 func (*linux) prepare(sourcedir string, build bool, arches []*Arch) error { 21 if build { 22 // Run 'make mrproper', otherwise out-of-tree build fails. 23 // However, it takes unreasonable amount of time, 24 // so first check few files and if they are missing hope for best. 25 for _, a := range arches { 26 arch := a.target.KernelArch 27 if osutil.IsExist(filepath.Join(sourcedir, ".config")) || 28 osutil.IsExist(filepath.Join(sourcedir, "init/main.o")) || 29 osutil.IsExist(filepath.Join(sourcedir, "include/config")) || 30 osutil.IsExist(filepath.Join(sourcedir, "include/generated/compile.h")) || 31 osutil.IsExist(filepath.Join(sourcedir, "arch", arch, "include", "generated")) { 32 fmt.Printf("make mrproper ARCH=%v\n", arch) 33 out, err := osutil.RunCmd(time.Hour, sourcedir, "make", "mrproper", "ARCH="+arch, 34 "-j", fmt.Sprint(runtime.NumCPU())) 35 if err != nil { 36 return fmt.Errorf("make mrproper failed: %w\n%s", err, out) 37 } 38 } 39 } 40 } else { 41 if len(arches) > 1 { 42 return fmt.Errorf("more than 1 arch is invalid without -build") 43 } 44 } 45 return nil 46 } 47 48 func (*linux) prepareArch(arch *Arch) error { 49 // Kernel misses these headers on some arches. 50 // So we create empty stubs in buildDir/syzkaller and add -IbuildDir/syzkaller 51 // as the last flag so it won't override real kernel headers. 52 for hdr, data := range map[string]string{ 53 // This is the only compiler header kernel uses, 54 // need to provide it since we use -nostdinc below. 55 "stdarg.h": ` 56 #pragma once 57 #define va_list __builtin_va_list 58 #define va_start __builtin_va_start 59 #define va_end __builtin_va_end 60 #define va_arg __builtin_va_arg 61 #define va_copy __builtin_va_copy 62 #define __va_copy __builtin_va_copy 63 `, 64 "asm/a.out.h": "", 65 "asm/prctl.h": "", 66 "asm/mce.h": "", 67 "asm/msr.h": "", 68 "uapi/asm/msr.h": "", 69 } { 70 fullPath := filepath.Join(arch.buildDir, "syzkaller", hdr) 71 if err := osutil.MkdirAll(filepath.Dir(fullPath)); err != nil { 72 return err 73 } 74 if err := osutil.WriteFile(fullPath, []byte(data)); err != nil { 75 return nil 76 } 77 } 78 if !arch.build { 79 return nil 80 } 81 kernelDir := arch.sourceDir 82 makeArgs := build.LinuxMakeArgs(arch.target, "", "", "", arch.buildDir) 83 out, err := osutil.RunCmd(time.Hour, kernelDir, "make", append(makeArgs, "defconfig")...) 84 if err != nil { 85 return fmt.Errorf("make defconfig failed: %w\n%s", err, out) 86 } 87 _, err = osutil.RunCmd(time.Minute, arch.buildDir, filepath.Join(kernelDir, "scripts", "config"), 88 // powerpc arch is configured to be big-endian by default, but we want little-endian powerpc. 89 // Since all of our archs are little-endian for now, we just blindly switch it. 90 "-d", "CPU_BIG_ENDIAN", "-e", "CPU_LITTLE_ENDIAN", 91 // s390 enables BTF in defconfig, but our packaged toolchains can't build it. 92 "-d", "DEBUG_INFO_BTF", 93 // Without CONFIG_NETFILTER kernel does not build. 94 "-e", "NETFILTER", 95 // include/net/mptcp.h is the only header in kernel that guards some 96 // of the consts with own config, so we need to enable CONFIG_MPTCP. 97 "-e", "MPTCP", 98 // security/smack/smack.h requires this to build. 99 "-e", "SECURITY", 100 "-e", "SECURITY_SMACK", 101 // include/net/nl802154.h does not define some consts without this. 102 "-e", "IEEE802154", "-e", "IEEE802154_NL802154_EXPERIMENTAL", 103 ) 104 if err != nil { 105 return err 106 } 107 out, err = osutil.RunCmd(time.Hour, kernelDir, "make", append(makeArgs, "olddefconfig")...) 108 if err != nil { 109 return fmt.Errorf("make olddefconfig failed: %w\n%s", err, out) 110 } 111 out, err = osutil.RunCmd(time.Hour, kernelDir, "make", append(makeArgs, "init/main.o")...) 112 if err != nil { 113 return fmt.Errorf("make failed: %w\n%s", err, out) 114 } 115 return nil 116 } 117 118 // nolint: goconst 119 func (*linux) processFile(arch *Arch, info *compiler.ConstInfo) (map[string]uint64, map[string]bool, error) { 120 headerArch := arch.target.KernelHeaderArch 121 sourceDir := arch.sourceDir 122 buildDir := arch.buildDir 123 args := []string{ 124 // This makes the build completely hermetic, only kernel headers are used. 125 "-nostdinc", 126 "-w", "-fmessage-length=0", 127 "-O3", // required to get expected values for some __builtin_constant_p 128 "-I.", 129 "-D__KERNEL__", 130 "-DKBUILD_MODNAME=\"-\"", 131 "-I" + sourceDir + "/arch/" + headerArch + "/include", 132 "-I" + buildDir + "/arch/" + headerArch + "/include/generated/uapi", 133 "-I" + buildDir + "/arch/" + headerArch + "/include/generated", 134 "-I" + sourceDir + "/arch/" + headerArch + "/include/asm/mach-malta", 135 "-I" + sourceDir + "/arch/" + headerArch + "/include/asm/mach-generic", 136 "-I" + buildDir + "/include", 137 "-I" + sourceDir + "/include", 138 "-I" + sourceDir + "/arch/" + headerArch + "/include/uapi", 139 "-I" + sourceDir + "/include/uapi", 140 "-I" + buildDir + "/include/generated/uapi", 141 "-I" + sourceDir, 142 "-I" + sourceDir + "/include/linux", 143 "-I" + buildDir + "/syzkaller", 144 "-include", sourceDir + "/include/linux/kconfig.h", 145 } 146 args = append(args, arch.target.CFlags...) 147 for _, incdir := range info.Incdirs { 148 args = append(args, "-I"+sourceDir+"/"+incdir) 149 } 150 if arch.includeDirs != "" { 151 for _, dir := range strings.Split(arch.includeDirs, ",") { 152 args = append(args, "-I"+dir) 153 } 154 } 155 params := &extractParams{ 156 AddSource: "#include <asm/unistd.h>", 157 ExtractFromELF: true, 158 TargetEndian: arch.target.HostEndian, 159 } 160 cc := arch.target.CCompiler 161 res, undeclared, err := extract(info, cc, args, params) 162 if err != nil { 163 return nil, nil, err 164 } 165 if arch.target.PtrSize == 4 { 166 // mmap syscall on i386/arm is translated to old_mmap and has different signature. 167 // As a workaround fix it up to mmap2, which has signature that we expect. 168 // pkg/csource has the same hack. 169 const mmap = "__NR_mmap" 170 const mmap2 = "__NR_mmap2" 171 if res[mmap] != 0 || undeclared[mmap] { 172 if res[mmap2] == 0 { 173 return nil, nil, fmt.Errorf("%v is missing", mmap2) 174 } 175 res[mmap] = res[mmap2] 176 delete(undeclared, mmap) 177 } 178 } 179 return res, undeclared, nil 180 }