diff options
| author | Dmitry Vyukov <dvyukov@google.com> | 2024-12-02 10:57:36 +0100 |
|---|---|---|
| committer | Dmitry Vyukov <dvyukov@google.com> | 2024-12-11 15:22:17 +0000 |
| commit | 59267911909f7e749367f87d62448d7daa87b1b5 (patch) | |
| tree | 02bf0a5d9e6012a8b6cb237fed7789f61aca6cc2 /tools | |
| parent | c756ba4e975097bf74b952367e2cd1a8db466c69 (diff) | |
tools/syz-declextract: generate file_operations descriptions
Emit descriptions for special files in /dev, /sys, /proc, and ./.
pkg/declextract combines file_operations info produced by the clang tool
with the dynamic probing info produced by pkg/ifaceprobe in order
to produce complete descriptions for special files.
Diffstat (limited to 'tools')
| -rw-r--r-- | tools/syz-declextract/README.md | 6 | ||||
| -rw-r--r-- | tools/syz-declextract/declextract.go | 45 | ||||
| -rw-r--r-- | tools/syz-declextract/declextract_test.go | 12 | ||||
| -rw-r--r-- | tools/syz-declextract/testdata/file_operations.c.probe | 15 | ||||
| -rw-r--r-- | tools/syz-declextract/testdata/file_operations.c.txt | 16 | ||||
| -rw-r--r-- | tools/syz-declextract/testdata/manual.txt | 6 |
6 files changed, 96 insertions, 4 deletions
diff --git a/tools/syz-declextract/README.md b/tools/syz-declextract/README.md index cab397192..934059810 100644 --- a/tools/syz-declextract/README.md +++ b/tools/syz-declextract/README.md @@ -45,3 +45,9 @@ make -j`nproc` syz-declextract go run tools/syz-declextract -binary=$LLVM_BUILD/bin/syz-declextract -config=manager.cfg syz-env make extract SOURCEDIR=$KERNEL ``` + +The tool caches results of static kernel analysis in manager.workdir/declextract.cache, +and results of the dynamic kernel probing in manager.workdir/interfaces.json. +These can be examined for debugging purposes, and reused separately by passing +-cache-extract and -cache-probe flags. Caching greatly saves time if only part +of the system has changed. If only the Go tool has changed, then both caches can be reused. diff --git a/tools/syz-declextract/declextract.go b/tools/syz-declextract/declextract.go index 7bf6d6081..5fe1edf52 100644 --- a/tools/syz-declextract/declextract.go +++ b/tools/syz-declextract/declextract.go @@ -6,6 +6,7 @@ package main import ( "bufio" "bytes" + "encoding/json" "flag" "fmt" "io/fs" @@ -13,11 +14,13 @@ import ( "path/filepath" "slices" "strings" + "time" "github.com/google/syzkaller/pkg/ast" "github.com/google/syzkaller/pkg/clangtool" "github.com/google/syzkaller/pkg/compiler" "github.com/google/syzkaller/pkg/declextract" + "github.com/google/syzkaller/pkg/ifaceprobe" "github.com/google/syzkaller/pkg/mgrconfig" "github.com/google/syzkaller/pkg/osutil" "github.com/google/syzkaller/pkg/subsystem" @@ -35,13 +38,19 @@ func main() { flagBinary = flag.String("binary", "syz-declextract", "path to syz-declextract binary") flagCacheExtract = flag.Bool("cache-extract", false, "use cached extract results if present"+ " (cached in manager.workdir/declextract.cache)") + flagCacheProbe = flag.Bool("cache-probe", false, "use cached probe results if present"+ + " (cached in manager.workdir/interfaces.json)") ) defer tool.Init()() cfg, err := mgrconfig.LoadFile(*flagConfig) if err != nil { tool.Fail(err) } - if err := run(filepath.FromSlash("sys/linux/auto.txt"), &clangtool.Config{ + probeInfo, err := probe(cfg, *flagConfig, *flagCacheProbe) + if err != nil { + tool.Failf("kernel probing failed: %v", err) + } + if err := run(filepath.FromSlash("sys/linux/auto.txt"), probeInfo, &clangtool.Config{ ToolBin: *flagBinary, KernelSrc: cfg.KernelSrc, KernelObj: cfg.KernelObj, @@ -52,7 +61,7 @@ func main() { } } -func run(autoFile string, cfg *clangtool.Config) error { +func run(autoFile string, probeInfo *ifaceprobe.Info, cfg *clangtool.Config) error { syscallRename, err := buildSyscallRenameMap(cfg.KernelSrc) if err != nil { return fmt.Errorf("failed to build syscall rename map: %w", err) @@ -61,7 +70,7 @@ func run(autoFile string, cfg *clangtool.Config) error { if err != nil { return err } - descriptions, interfaces, err := declextract.Run(out, syscallRename) + descriptions, interfaces, err := declextract.Run(out, probeInfo, syscallRename) if err != nil { return err } @@ -107,6 +116,36 @@ func run(autoFile string, cfg *clangtool.Config) error { return osutil.WriteFile(autoFile, formatted) } +func probe(cfg *mgrconfig.Config, cfgFile string, cache bool) (*ifaceprobe.Info, error) { + cacheFile := filepath.Join(cfg.Workdir, "interfaces.json") + if cache { + info, err := readProbeResult(cacheFile) + if err == nil { + return info, nil + } + } + _, err := osutil.RunCmd(30*time.Minute, "", filepath.Join(cfg.Syzkaller, "bin", "syz-manager"), + "-config", cfgFile, "-mode", "iface-probe") + if err != nil { + return nil, err + } + return readProbeResult(cacheFile) +} + +func readProbeResult(file string) (*ifaceprobe.Info, error) { + data, err := os.ReadFile(file) + if err != nil { + return nil, err + } + dec := json.NewDecoder(bytes.NewReader(data)) + dec.DisallowUnknownFields() + info := new(ifaceprobe.Info) + if err := dec.Decode(info); err != nil { + return nil, fmt.Errorf("failed to unmarshal interfaces.json: %w", err) + } + return info, nil +} + func errorHandler() (func(pos ast.Pos, msg string), *bytes.Buffer) { errors := new(bytes.Buffer) eh := func(pos ast.Pos, msg string) { diff --git a/tools/syz-declextract/declextract_test.go b/tools/syz-declextract/declextract_test.go index b93a6dcbf..e6f8da464 100644 --- a/tools/syz-declextract/declextract_test.go +++ b/tools/syz-declextract/declextract_test.go @@ -15,6 +15,7 @@ import ( "github.com/google/syzkaller/pkg/ast" "github.com/google/syzkaller/pkg/clangtool" "github.com/google/syzkaller/pkg/compiler" + "github.com/google/syzkaller/pkg/ifaceprobe" "github.com/google/syzkaller/pkg/osutil" ) @@ -53,8 +54,17 @@ func TestDeclextract(t *testing.T) { t.Fatal(err) } cfg.ToolBin = "this-is-not-supposed-to-run" + probeInfo := new(ifaceprobe.Info) + probeFile := filepath.Join(cfg.KernelSrc, filepath.Base(file)+".probe") + if osutil.IsExist(probeFile) { + var err error + probeInfo, err = readProbeResult(probeFile) + if err != nil { + t.Fatal(err) + } + } autoFile := filepath.Join(cfg.KernelObj, filepath.Base(file)+".txt") - if err := run(autoFile, cfg); err != nil { + if err := run(autoFile, probeInfo, cfg); err != nil { if *flagUpdate { osutil.CopyFile(autoFile, file+".txt") osutil.CopyFile(autoFile+".info", file+".info") diff --git a/tools/syz-declextract/testdata/file_operations.c.probe b/tools/syz-declextract/testdata/file_operations.c.probe new file mode 100644 index 000000000..6ff4a213a --- /dev/null +++ b/tools/syz-declextract/testdata/file_operations.c.probe @@ -0,0 +1,15 @@ +{ + "Files": [ + { + "Name": "/dev/foo", + "Cover": [1, 2, 3, 4, 5] + } + ], + "PCs": [ + {"PC": 1, "Func": "foo_open"}, + {"PC": 2, "Func": "foo_read"}, + {"PC": 3, "Func": "foo_write"}, + {"PC": 4, "Func": "foo_mmap"}, + {"PC": 5, "Func": "foo_ioctl"} + ] +} diff --git a/tools/syz-declextract/testdata/file_operations.c.txt b/tools/syz-declextract/testdata/file_operations.c.txt index f2fb3ed1c..e812350a3 100644 --- a/tools/syz-declextract/testdata/file_operations.c.txt +++ b/tools/syz-declextract/testdata/file_operations.c.txt @@ -8,3 +8,19 @@ include <vdso/bits.h> include <linux/types.h> include <net/netlink.h> include <include/uapi/file_operations.h> + +resource fd_foo_file_operations[fd] +openat$auto_foo_file_operations(fd const[AT_FDCWD], file ptr[in, string["/dev/foo"]], flags flags[open_flags], mode const[0]) fd_foo_file_operations +read$auto_foo_file_operations(fd fd_foo_file_operations, buf ptr[out, array[int8]], len bytesize[buf]) +write$auto_foo_file_operations(fd fd_foo_file_operations, buf ptr[in, array[int8]], len bytesize[buf]) +mmap$auto_foo_file_operations(addr vma, len len[addr], prot flags[mmap_prot], flags flags[mmap_flags], fd fd_foo_file_operations, offset fileoff) +ioctl$auto_FOO_IOCTL1(fd fd_foo_file_operations, cmd const[FOO_IOCTL1], arg const[0]) +ioctl$auto_FOO_IOCTL2(fd fd_foo_file_operations, cmd const[FOO_IOCTL2], arg ptr[in, int32]) +ioctl$auto_FOO_IOCTL3(fd fd_foo_file_operations, cmd const[FOO_IOCTL3], arg ptr[in, foo_ioctl_arg$auto]) +ioctl$auto_FOO_IOCTL4(fd fd_foo_file_operations, cmd const[FOO_IOCTL4], arg ptr[inout, foo_ioctl_arg$auto]) +ioctl$auto_FOO_IOCTL5(fd fd_foo_file_operations, cmd const[FOO_IOCTL5], arg ptr[inout, foo_ioctl_arg$auto]) + +foo_ioctl_arg$auto { + a int32 + b int32 +} diff --git a/tools/syz-declextract/testdata/manual.txt b/tools/syz-declextract/testdata/manual.txt index 31ab63c9c..51ff3230c 100644 --- a/tools/syz-declextract/testdata/manual.txt +++ b/tools/syz-declextract/testdata/manual.txt @@ -21,6 +21,9 @@ use { f3 nlattr[1, int32] f4 nlnest[1, int32] f5 nl_generic_attr + f6 flags[open_flags, int32] + f7 flags[mmap_prot, int32] + f8 flags[mmap_flags, int32] } @@ -47,4 +50,7 @@ type nlnest[ATTR, TYPE] nlattr[ATTR, TYPE] type nl_generic_attr int32 +open_flags = 1, 2 +mmap_prot = 1, 2 +mmap_flags = 1, 2 send_flags = 1, 2 |
