diff options
Diffstat (limited to 'pkg/host/features_linux.go')
| -rw-r--r-- | pkg/host/features_linux.go | 355 |
1 files changed, 0 insertions, 355 deletions
diff --git a/pkg/host/features_linux.go b/pkg/host/features_linux.go deleted file mode 100644 index 393617e45..000000000 --- a/pkg/host/features_linux.go +++ /dev/null @@ -1,355 +0,0 @@ -// Copyright 2015 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 host - -import ( - "fmt" - "os" - "os/exec" - "regexp" - "runtime" - "runtime/debug" - "strconv" - "syscall" - "unsafe" - - "github.com/google/syzkaller/pkg/osutil" - "github.com/google/syzkaller/prog" - "github.com/google/syzkaller/sys/linux" - "golang.org/x/sys/unix" -) - -func init() { - checkFeature[FeatureCoverage] = checkCoverage - checkFeature[FeatureComparisons] = checkComparisons - checkFeature[FeatureExtraCoverage] = checkExtraCoverage - checkFeature[FeatureDelayKcovMmap] = checkDelayKcovMmap - checkFeature[FeatureSandboxSetuid] = unconditionallyEnabled - checkFeature[FeatureSandboxNamespace] = checkSandboxNamespace - checkFeature[FeatureSandboxAndroid] = checkSandboxAndroid - checkFeature[FeatureFault] = checkFault - checkFeature[FeatureLeak] = checkLeak - checkFeature[FeatureNetInjection] = checkNetInjection - checkFeature[FeatureNetDevices] = unconditionallyEnabled - checkFeature[FeatureKCSAN] = checkKCSAN - checkFeature[FeatureDevlinkPCI] = checkDevlinkPCI - checkFeature[FeatureNicVF] = checkNicVF - checkFeature[FeatureUSBEmulation] = checkUSBEmulation - checkFeature[FeatureVhciInjection] = checkVhciInjection - checkFeature[FeatureWifiEmulation] = checkWifiEmulation - checkFeature[Feature802154Emulation] = check802154Emulation - checkFeature[FeatureSwap] = checkSwap -} - -func checkCoverage() string { - if reason := checkDebugFS(); reason != "" { - return reason - } - if !osutil.IsExist("/sys/kernel/debug/kcov") { - return "CONFIG_KCOV is not enabled" - } - if err := osutil.IsAccessible("/sys/kernel/debug/kcov"); err != nil { - return err.Error() - } - return "" -} - -func checkComparisons() (reason string) { - return checkCoverageFeature(FeatureComparisons) -} - -func checkExtraCoverage() (reason string) { - return checkCoverageFeature(FeatureExtraCoverage) -} - -func checkDelayKcovMmap() string { - // The kcov implementation in Linux (currently) does not adequately handle subsequent - // mmap invocations on the same descriptor. When that problem is fixed, we want - // syzkaller to differentiate between distributions as this allows to noticeably speed - // up fuzzing. - return checkCoverageFeature(FeatureDelayKcovMmap) -} - -func kcovTestMmap(fd int, coverSize uintptr) (reason string) { - mem, err := syscall.Mmap(fd, 0, int(coverSize*unsafe.Sizeof(uintptr(0))), - syscall.PROT_READ|syscall.PROT_WRITE, syscall.MAP_SHARED) - if err != nil { - return fmt.Sprintf("KCOV mmap failed: %v", err) - } - defer func() { - if err := syscall.Munmap(mem); err != nil { - reason = fmt.Sprintf("munmap failed: %v", err) - } - }() - // Now the tricky part - mmap may say it has succeeded, but the memory is - // in fact not allocated. - // We try to access it. If go does not panic, everything is fine. - prevValue := debug.SetPanicOnFault(true) - defer debug.SetPanicOnFault(prevValue) - defer func() { - if r := recover(); r != nil { - reason = "mmap returned an invalid pointer" - } - }() - mem[0] = 0 - return "" -} - -func checkCoverageFeature(feature int) (reason string) { - if reason = checkDebugFS(); reason != "" { - return reason - } - // TODO(dvyukov): this should run under target arch. - // E.g. KCOV ioctls were initially not supported on 386 (missing compat_ioctl), - // and a 386 executor won't be able to use them, but an amd64 fuzzer will be. - fd, err := syscall.Open("/sys/kernel/debug/kcov", syscall.O_RDWR, 0) - if err != nil { - return "CONFIG_KCOV is not enabled" - } - defer syscall.Close(fd) - // Trigger host target lazy initialization, it will fill linux.KCOV_INIT_TRACE. - // It's all wrong and needs to be refactored. - if _, err := prog.GetTarget(runtime.GOOS, runtime.GOARCH); err != nil { - return fmt.Sprintf("failed to get target: %v", err) - } - coverSize := uintptr(64 << 10) - _, _, errno := syscall.Syscall( - syscall.SYS_IOCTL, uintptr(fd), linux.KCOV_INIT_TRACE, coverSize) - if errno != 0 { - return fmt.Sprintf("ioctl(KCOV_INIT_TRACE) failed: %v", errno) - } - if reason = kcovTestMmap(fd, coverSize); reason != "" { - return reason - } - disableKcov := func() { - _, _, errno = syscall.Syscall(syscall.SYS_IOCTL, uintptr(fd), linux.KCOV_DISABLE, 0) - if errno != 0 { - reason = fmt.Sprintf("ioctl(KCOV_DISABLE) failed: %v", errno) - } - } - switch feature { - case FeatureComparisons: - _, _, errno = syscall.Syscall(syscall.SYS_IOCTL, - uintptr(fd), linux.KCOV_ENABLE, linux.KCOV_TRACE_CMP) - if errno != 0 { - if errno == 524 { // ENOTSUPP - return "CONFIG_KCOV_ENABLE_COMPARISONS is not enabled" - } - return fmt.Sprintf("ioctl(KCOV_TRACE_CMP) failed: %v", errno) - } - defer disableKcov() - case FeatureExtraCoverage: - arg := KcovRemoteArg{ - TraceMode: uint32(linux.KCOV_TRACE_PC), - AreaSize: uint32(coverSize * unsafe.Sizeof(uintptr(0))), - NumHandles: 0, - CommonHandle: 0, - } - _, _, errno = syscall.Syscall(syscall.SYS_IOCTL, - uintptr(fd), linux.KCOV_REMOTE_ENABLE, uintptr(unsafe.Pointer(&arg))) - if errno != 0 { - if errno == 25 { // ENOTTY - return "extra coverage is not supported by the kernel" - } - return fmt.Sprintf("ioctl(KCOV_REMOTE_ENABLE) failed: %v", errno) - } - defer disableKcov() - case FeatureDelayKcovMmap: - if reason = kcovTestMmap(fd, coverSize); reason != "" { - return reason - } - default: - panic("unknown feature in checkCoverageFeature") - } - return "" -} - -type KcovRemoteArg struct { - TraceMode uint32 - AreaSize uint32 - NumHandles uint32 - _ uint32 - CommonHandle uint64 - // Handles []uint64 goes here. -} - -func checkFault() string { - if err := osutil.IsAccessible("/proc/self/make-it-fail"); err != nil { - return "CONFIG_FAULT_INJECTION is not enabled" - } - if err := osutil.IsAccessible("/proc/thread-self/fail-nth"); err != nil { - return "kernel does not have systematic fault injection support" - } - if reason := checkDebugFS(); reason != "" { - return reason - } - if err := osutil.IsAccessible("/sys/kernel/debug/failslab/ignore-gfp-wait"); err != nil { - return "CONFIG_FAULT_INJECTION_DEBUG_FS or CONFIG_FAILSLAB are not enabled" - } - return "" -} - -func checkLeak() string { - if reason := checkDebugFS(); reason != "" { - return reason - } - fd, err := syscall.Open("/sys/kernel/debug/kmemleak", syscall.O_RDWR, 0) - if err != nil { - return "CONFIG_DEBUG_KMEMLEAK is not enabled" - } - defer syscall.Close(fd) - if _, err := syscall.Write(fd, []byte("scan=off")); err != nil { - if err == syscall.EBUSY { - return "KMEMLEAK disabled: increase CONFIG_DEBUG_KMEMLEAK_EARLY_LOG_SIZE or unset CONFIG_DEBUG_KMEMLEAK_DEFAULT_OFF" - } - return fmt.Sprintf("/sys/kernel/debug/kmemleak write failed: %v", err) - } - return "" -} - -func checkSandboxNamespace() string { - if err := osutil.IsAccessible("/proc/self/ns/user"); err != nil { - return err.Error() - } - return "" -} - -func checkSandboxAndroid() string { - if err := osutil.IsAccessible("/sys/fs/selinux/policy"); err != nil { - return err.Error() - } - return "" -} - -func checkNetInjection() string { - if err := osutil.IsAccessible("/dev/net/tun"); err != nil { - return err.Error() - } - return "" -} - -func checkUSBEmulation() string { - if err := osutil.IsAccessible("/dev/raw-gadget"); err != nil { - return err.Error() - } - return "" -} - -func checkVhciInjection() string { - if err := osutil.IsAccessible("/dev/vhci"); err != nil { - return err.Error() - } - return "" -} - -func checkDebugFS() string { - if err := osutil.IsAccessible("/sys/kernel/debug"); err != nil { - return "debugfs is not enabled or not mounted" - } - return "" -} - -func checkKCSAN() string { - if err := osutil.IsAccessible("/sys/kernel/debug/kcsan"); err != nil { - return err.Error() - } - return "" -} - -func checkDevlinkPCI() string { - if err := osutil.IsAccessible("/sys/bus/pci/devices/0000:00:10.0/"); err != nil { - return "PCI device 0000:00:10.0 is not available" - } - if err := osutil.IsAccessible("/proc/self/ns/net"); err != nil { - // Initialize_devlink_pci in executor fails w/o this. - return "/proc/self/ns/net does not exist" - } - return "" -} - -func checkNicVF() string { - if err := osutil.IsAccessible("/sys/bus/pci/devices/0000:00:11.0/"); err != nil { - return "PCI device 0000:00:11.0 is not available" - } - return "" -} - -func checkWifiEmulation() string { - if err := osutil.IsAccessible("/sys/class/mac80211_hwsim/"); err != nil { - return err.Error() - } - // We use HWSIM_ATTR_PERM_ADDR which was added in 4.17. - return requireKernel(4, 17) -} - -func check802154Emulation() string { - if err := osutil.IsAccessible("/sys/bus/platform/devices/mac802154_hwsim"); err != nil { - return err.Error() - } - return "" -} - -func checkSwap() string { - if err := osutil.IsAccessible("/proc/swaps"); err != nil { - return err.Error() - } - if _, err := exec.LookPath("mkswap"); err != nil { - return "mkswap is not available" - } - // We use fallocate in syz-executor, so let's check if the filesystem supports it. - // /tmp might not always be the best choice for this - // (on some systems, a different filesystem might be used for /tmp). - dir, err := os.UserHomeDir() - if err != nil { - return fmt.Sprintf("failed to get home dir: %v", err) - } - f, err := os.CreateTemp(dir, "any-file") - if err != nil { - return fmt.Sprintf("failed to create temp file: %v", err) - } - defer os.Remove(f.Name()) - err = syscall.Fallocate(int(f.Fd()), unix.FALLOC_FL_ZERO_RANGE, 0, 2048) - if err != nil { - return fmt.Sprintf("fallocate failed: %v", err) - } - return "" -} - -func requireKernel(x, y int) string { - info := new(unix.Utsname) - if err := unix.Uname(info); err != nil { - return fmt.Sprintf("uname failed: %v", err) - } - ver := string(info.Release[:]) - if ok, bad := matchKernelVersion(ver, x, y); bad { - return fmt.Sprintf("failed to parse kernel version (%v)", ver) - } else if !ok { - return fmt.Sprintf("kernel %v.%v required (have %v)", x, y, ver) - } - return "" -} - -func matchKernelVersion(ver string, x, y int) (bool, bool) { - match := kernelVersionRe.FindStringSubmatch(ver) - if match == nil { - return false, true - } - major, err := strconv.Atoi(match[1]) - if err != nil { - return false, true - } - if major <= 0 || major > 999 { - return false, true - } - minor, err := strconv.Atoi(match[2]) - if err != nil { - return false, true - } - if minor <= 0 || minor > 999 { - return false, true - } - return major*1000+minor >= x*1000+y, false -} - -var kernelVersionRe = regexp.MustCompile(`^([0-9]+)\.([0-9]+)`) |
