aboutsummaryrefslogtreecommitdiffstats
path: root/tools
diff options
context:
space:
mode:
authorDmitry Vyukov <dvyukov@google.com>2024-04-25 13:51:51 +0200
committerDmitry Vyukov <dvyukov@google.com>2024-05-02 16:24:59 +0000
commit22ee48a2879809608f79cc23c914859fa2335d59 (patch)
treeaa2b496eb81823999a8b48be011575ee7c650fff /tools
parent3c7bb2247f61c5218d4cd58a558dc2496fba53a4 (diff)
pkg/vminfo: check enabled syscalls on the host
Move the syscall checking logic to the host. Diffing sets of disabled syscalls before/after this change in different configurations (none/setuid sandboxes, amd64/386 arches, large/small kernel configs) shows only some improvements/bug fixes. 1. socket$inet[6]_icmp are now enabled. Previously they were disabled due to net.ipv4.ping_group_range sysctl in the init namespace which prevented creation of ping sockets. In the new net namespace the sysctl gets default value which allows creation. 2. get_thread_area and set_thread_area are now disabled on amd64. They are available only in 32-bit mode, but they are present in /proc/kallsyms, so we enabled them always. 3. socket$bt_{bnep, cmtp, hidp, rfcomm} are now disabled. They cannot be created in non init net namespace. bt_sock_create() checks init_net and returns EAFNOSUPPORT immediately. This is a bug in descriptions we need to fix. Now we see it due to more precise checks. 4. fstat64/fstatat64/lstat64/stat64 are now enabled in 32-bit mode. They are not present in /proc/kallsyms as syscalls, so we have not enabled them. But they are available in 32-bit mode. 5. 78 openat variants + 10 socket variants + mount are now disabled with setuid sandbox. They are not permitted w/o root permissions, but we ignored that. This additionally leads to 700 transitively disabled syscalls. In all cases checking in the actual executor context/sandbox looks very positive, esp. for more restrictive sandboxes. Android sandbox should benefit as well. The additional benefit is full testability of the new code. The change includes only a basic test that covers all checks, and ensures the code does not crash/hang, all generated programs parse successfully, etc. But it's possible to unit-test every condition now. The new version also parallelizes checking across VMs, checking on a slow emulated qemu drops from 210 seconds to 140 seconds.
Diffstat (limited to 'tools')
-rw-r--r--tools/syz-runtest/empty.go6
-rw-r--r--tools/syz-runtest/runtest.go32
2 files changed, 28 insertions, 10 deletions
diff --git a/tools/syz-runtest/empty.go b/tools/syz-runtest/empty.go
new file mode 100644
index 000000000..588c0c9e8
--- /dev/null
+++ b/tools/syz-runtest/empty.go
@@ -0,0 +1,6 @@
+// Copyright 2024 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 main
+
+func main() {}
diff --git a/tools/syz-runtest/runtest.go b/tools/syz-runtest/runtest.go
index 3e410630b..5849131eb 100644
--- a/tools/syz-runtest/runtest.go
+++ b/tools/syz-runtest/runtest.go
@@ -1,6 +1,10 @@
// 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.
+// This is broken for now.
+
+//go:build ignore
+
// Runtest runs syzkaller test programs in sys/*/test/*. Start as:
// $ syz-runtest -config manager.config
// Also see pkg/runtest docs.
@@ -24,6 +28,7 @@ import (
"github.com/google/syzkaller/pkg/report"
"github.com/google/syzkaller/pkg/rpctype"
"github.com/google/syzkaller/pkg/runtest"
+ "github.com/google/syzkaller/pkg/vminfo"
"github.com/google/syzkaller/prog"
_ "github.com/google/syzkaller/sys"
"github.com/google/syzkaller/vm"
@@ -53,6 +58,7 @@ func main() {
mgr := &Manager{
cfg: cfg,
vmPool: vmPool,
+ checker: vminfo.New(cfg),
reporter: reporter,
debug: *flagDebug,
requests: make(chan *runtest.RunRequest, 2*vmPool.Count()),
@@ -62,7 +68,7 @@ func main() {
reqMap: make(map[int]*runtest.RunRequest),
lastReq: make(map[string]int),
}
- s, err := rpctype.NewRPCServer(cfg.RPC, "Manager", mgr, true)
+ s, err := rpctype.NewRPCServer(cfg.RPC, "Manager", mgr, false)
if err != nil {
log.Fatalf("failed to create rpc server: %v", err)
}
@@ -93,14 +99,16 @@ func main() {
checkResult := <-mgr.checkResultC
mgr.checkFeatures = checkResult.Features
close(mgr.checkFeaturesReady)
- enabledCalls := make(map[string]map[*prog.Syscall]bool)
- for sandbox, ids := range checkResult.EnabledCalls {
- calls := make(map[*prog.Syscall]bool)
- for _, id := range ids {
- calls[cfg.Target.Syscalls[id]] = true
- }
- enabledCalls[sandbox] = calls
+ calls, _, err := mgr.checker.Check(checkResult.Files, checkResult.CheckProgs)
+ if err != nil {
+ log.Fatalf("failed to detect enabled syscalls: %v", err)
}
+ calls, _ = cfg.Target.TransitivelyEnabledCalls(calls)
+ enabledCalls := make(map[string]map[*prog.Syscall]bool)
+ // TODO: restore checking/testing of all other sandboxes (we used to test them).
+ // Note: syz_emit_ethernet/syz_extract_tcp_res were manually disabled for "" ("no") sandbox,
+ // b/c tun is not setup without sandbox.
+ enabledCalls[mgr.cfg.Sandbox] = calls
for _, feat := range checkResult.Features.Supported() {
fmt.Printf("%-24v: %v\n", feat.Name, feat.Reason)
}
@@ -133,6 +141,7 @@ func main() {
type Manager struct {
cfg *mgrconfig.Config
vmPool *vm.Pool
+ checker *vminfo.Checker
reporter *report.Reporter
requests chan *runtest.RunRequest
checkFeatures *host.Features
@@ -221,16 +230,19 @@ func (mgr *Manager) finishRequest(name string, rep *report.Report) error {
}
func (mgr *Manager) Connect(a *rpctype.ConnectArgs, r *rpctype.ConnectRes) error {
- r.AllSandboxes = true
select {
case <-mgr.checkFeaturesReady:
r.Features = mgr.checkFeatures
default:
+ infoFiles, checkFiles, checkProgs := mgr.checker.RequiredThings()
+ r.ReadFiles = append(infoFiles, checkFiles...)
+ r.ReadGlobs = mgr.cfg.Target.RequiredGlobs()
+ r.CheckProgs = checkProgs
}
return nil
}
-func (mgr *Manager) Check(a *rpctype.CheckArgs, r *int) error {
+func (mgr *Manager) Check(a *rpctype.CheckArgs, r *rpctype.CheckRes) error {
if a.Error != "" {
log.Fatalf("machine check: %v", a.Error)
}