syzkaller/pkg/host/features_linux.go
Andrey Konovalov 09ff5abc02 csource, executor: add usb emulation feature
The feature gets enabled when /dev/raw-gadget is present and accessible.
With this feature enabled, executor will do chmod 0666 /dev/raw-gadget on
startup, which makes it possible to do USB fuzzing in setuid and namespace
sandboxes. There should be no backwards compatibility issues with syz
reproducers that don't explicitly enable this feature, as they currently only
work in none sandbox.
2020-04-03 12:42:06 +02:00

214 lines
6.1 KiB
Go

// 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"
"runtime"
"syscall"
"unsafe"
"github.com/google/syzkaller/pkg/osutil"
"github.com/google/syzkaller/prog"
"github.com/google/syzkaller/sys/linux"
)
func init() {
checkFeature[FeatureCoverage] = checkCoverage
checkFeature[FeatureComparisons] = checkComparisons
checkFeature[FeatureExtraCoverage] = checkExtraCoverage
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[FeatureUSBEmulation] = checkUSBEmulation
}
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 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)
}
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)
}
}()
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)
}
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)
}
default:
panic("unknown feature in checkCoverageFeature")
}
defer 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)
}
}()
return ""
}
type KcovRemoteArg struct {
TraceMode uint32
AreaSize uint32
NumHandles 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 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"
}
return ""
}