blob: 6394dd4a0aaf8add0bd7f8594793794d1c8561cc [file] [log] [blame]
// Copyright 2018 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 (
"github.com/google/syzkaller/prog"
)
// DetectSupportedSyscalls returns list on supported and unsupported syscalls on the host.
// For unsupported syscalls it also returns reason as to why it is unsupported.
func DetectSupportedSyscalls(target *prog.Target, sandbox string) (
map[*prog.Syscall]bool, map[*prog.Syscall]string, error) {
supported := make(map[*prog.Syscall]bool)
unsupported := make(map[*prog.Syscall]string)
// Akaros does not have own host and parasitizes on some other OS.
if target.OS == "akaros" || target.OS == "test" {
for _, c := range target.Syscalls {
supported[c] = true
}
return supported, unsupported, nil
}
for _, c := range target.Syscalls {
ok, reason := isSupported(c, sandbox)
if ok {
supported[c] = true
} else {
if reason == "" {
reason = "unknown"
}
unsupported[c] = reason
}
}
return supported, unsupported, nil
}
var testFallback = false
const (
FeatureCoverage = iota
FeatureComparisons
FeatureSandboxSetuid
FeatureSandboxNamespace
FeatureFaultInjection
FeatureLeakChecking
FeatureNetworkInjection
FeatureNetworkDevices
numFeatures
)
type Feature struct {
Name string
Enabled bool
Reason string
}
type Features [numFeatures]Feature
var checkFeature [numFeatures]func() string
var setupFeature [numFeatures]func() error
var callbFeature [numFeatures]func()
func unconditionallyEnabled() string { return "" }
// Check detects features supported on the host.
// Empty string for a feature means the feature is supported,
// otherwise the string contains the reason why the feature is not supported.
func Check(target *prog.Target) (*Features, error) {
const unsupported = "support is not implemented in syzkaller"
res := &Features{
FeatureCoverage: {Name: "code coverage", Reason: unsupported},
FeatureComparisons: {Name: "comparison tracing", Reason: unsupported},
FeatureSandboxSetuid: {Name: "setuid sandbox", Reason: unsupported},
FeatureSandboxNamespace: {Name: "namespace sandbox", Reason: unsupported},
FeatureFaultInjection: {Name: "fault injection", Reason: unsupported},
FeatureLeakChecking: {Name: "leak checking", Reason: unsupported},
FeatureNetworkInjection: {Name: "net packed injection", Reason: unsupported},
FeatureNetworkDevices: {Name: "net device setup", Reason: unsupported},
}
if target.OS == "akaros" || target.OS == "test" {
return res, nil
}
for n, check := range checkFeature {
if check == nil {
continue
}
if reason := check(); reason == "" {
res[n].Enabled = true
res[n].Reason = "enabled"
} else {
res[n].Reason = reason
}
}
return res, nil
}
// Setup enables and does any one-time setup for the requested features on the host.
// Note: this can be called multiple times and must be idempotent.
func Setup(target *prog.Target, features *Features) (func(), error) {
if target.OS == "akaros" || target.OS == "test" {
return nil, nil
}
var callback func()
for n, setup := range setupFeature {
if setup == nil || !features[n].Enabled {
continue
}
if err := setup(); err != nil {
return nil, err
}
cb := callbFeature[n]
if cb != nil {
prev := callback
callback = func() {
cb()
if prev != nil {
prev()
}
}
}
}
return callback, nil
}