github.com/google/syzkaller@v0.0.0-20251211124644-a066d2bc4b02/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/kvm.h": ` 65 struct kvm_debug_exit_arch {}; 66 struct kvm_guest_debug_arch {}; 67 struct kvm_sync_regs {}; 68 `, 69 "asm/a.out.h": "", 70 "asm/prctl.h": "", 71 "asm/mce.h": "", 72 "asm/msr.h": "", 73 "uapi/asm/msr.h": "", 74 } { 75 fullPath := filepath.Join(arch.buildDir, "syzkaller", hdr) 76 if err := osutil.MkdirAll(filepath.Dir(fullPath)); err != nil { 77 return err 78 } 79 if err := osutil.WriteFile(fullPath, []byte(data)); err != nil { 80 return nil 81 } 82 } 83 if !arch.build { 84 return nil 85 } 86 kernelDir := arch.sourceDir 87 makeArgs := build.LinuxMakeArgs(arch.target, "", "", "", arch.buildDir, runtime.NumCPU()) 88 if arch.configFile != "" { 89 err := osutil.CopyFile(arch.configFile, filepath.Join(arch.buildDir, ".config")) 90 if err != nil { 91 return fmt.Errorf("failed to copy config file: %w", err) 92 } 93 } else { 94 out, err := osutil.RunCmd(time.Hour, kernelDir, "make", append(makeArgs, "defconfig")...) 95 if err != nil { 96 return fmt.Errorf("make defconfig failed: %w\n%s", err, out) 97 } 98 } 99 _, err := osutil.RunCmd(time.Minute, arch.buildDir, filepath.Join(kernelDir, "scripts", "config"), 100 // powerpc arch is configured to be big-endian by default, but we want little-endian powerpc. 101 // Since all of our archs are little-endian for now, we just blindly switch it. 102 "-d", "CPU_BIG_ENDIAN", "-e", "CPU_LITTLE_ENDIAN", 103 // s390 enables BTF in defconfig, but our packaged toolchains can't build it. 104 "-d", "DEBUG_INFO_BTF", 105 // Without CONFIG_NETFILTER kernel does not build. 106 "-e", "NETFILTER", 107 // include/net/mptcp.h is the only header in kernel that guards some 108 // of the consts with own config, so we need to enable CONFIG_MPTCP. 109 "-e", "MPTCP", 110 // security/smack/smack.h requires this to build. 111 "-e", "SECURITY", 112 "-e", "SECURITY_SMACK", 113 // include/net/nl802154.h does not define some consts without this. 114 "-e", "IEEE802154", "-e", "IEEE802154_NL802154_EXPERIMENTAL", 115 ) 116 if err != nil { 117 return err 118 } 119 out, err := osutil.RunCmd(time.Hour, kernelDir, "make", append(makeArgs, "olddefconfig")...) 120 if err != nil { 121 return fmt.Errorf("make olddefconfig failed: %w\n%s", err, out) 122 } 123 out, err = osutil.RunCmd(time.Hour, kernelDir, "make", append(makeArgs, "init/main.o")...) 124 if err != nil { 125 return fmt.Errorf("make failed: %w\n%s", err, out) 126 } 127 return nil 128 } 129 130 func (*linux) processFile(arch *Arch, info *compiler.ConstInfo) (map[string]uint64, map[string]bool, error) { 131 headerArch := arch.target.KernelHeaderArch 132 sourceDir := arch.sourceDir 133 buildDir := arch.buildDir 134 args := []string{ 135 // EFI kernel headers use wide character constants. 136 "-fshort-wchar", 137 // Avoid implicit declaration errors. 138 "-Wno-implicit-function-declaration", 139 // This makes the build completely hermetic, only kernel headers are used. 140 "-nostdinc", 141 "-w", "-fmessage-length=0", 142 "-O3", // required to get expected values for some __builtin_constant_p 143 "-I.", 144 "-D__KERNEL__", 145 "-DKBUILD_MODNAME=\"-\"", 146 "-DKBUILD_MODFILE=\"-\"", 147 "-D__LINUX_ARM_ARCH__=7", // arm does not build w/o this 148 "-I" + sourceDir + "/arch/" + headerArch + "/include", 149 "-I" + buildDir + "/arch/" + headerArch + "/include/generated/uapi", 150 "-I" + buildDir + "/arch/" + headerArch + "/include/generated", 151 "-I" + sourceDir + "/arch/" + headerArch + "/include/asm/mach-malta", 152 "-I" + sourceDir + "/arch/" + headerArch + "/include/asm/mach-generic", 153 "-I" + buildDir + "/include", 154 "-I" + sourceDir + "/include", 155 "-I" + sourceDir + "/arch/" + headerArch + "/include/uapi", 156 "-I" + sourceDir + "/include/uapi", 157 "-I" + buildDir + "/include/generated/uapi", 158 "-I" + sourceDir, 159 "-I" + sourceDir + "/include/linux", 160 "-I" + buildDir + "/syzkaller", 161 "-include", sourceDir + "/include/linux/kconfig.h", 162 } 163 args = append(args, arch.target.CFlags...) 164 for _, incdir := range info.Incdirs { 165 args = append(args, "-I"+sourceDir+"/"+incdir) 166 } 167 if arch.includeDirs != "" { 168 for _, dir := range strings.Split(arch.includeDirs, ",") { 169 args = append(args, "-I"+dir) 170 } 171 } 172 params := &extractParams{ 173 AddSource: "#include <asm/unistd.h>", 174 ExtractFromELF: true, 175 TargetEndian: arch.target.HostEndian, 176 } 177 cc := arch.target.CCompiler 178 res, undeclared, err := extract(info, cc, args, params) 179 if err != nil { 180 return nil, nil, err 181 } 182 if arch.target.PtrSize == 4 { 183 // mmap syscall on i386/arm is translated to old_mmap and has different signature. 184 // As a workaround fix it up to mmap2, which has signature that we expect. 185 // pkg/csource has the same hack. 186 const mmap = "__NR_mmap" 187 const mmap2 = "__NR_mmap2" 188 if res[mmap] != 0 || undeclared[mmap] { 189 if res[mmap2] == 0 { 190 return nil, nil, fmt.Errorf("%v is missing", mmap2) 191 } 192 res[mmap] = res[mmap2] 193 delete(undeclared, mmap) 194 } 195 } 196 return res, undeclared, nil 197 }