diff options
| author | Dmitry Vyukov <dvyukov@google.com> | 2025-01-17 10:39:49 +0100 |
|---|---|---|
| committer | Dmitry Vyukov <dvyukov@google.com> | 2025-01-22 17:12:18 +0000 |
| commit | 8aaf5d60aa0b3ddb05e117f52c0e30ec246b7aad (patch) | |
| tree | 63ddc4520d1e4b865925a014d3401b5e15c1fed3 /pkg/declextract/fileops.go | |
| parent | ac680c7cc91ea82316471433537f3101c2af39ea (diff) | |
tools/syz-declextract: support function scopes
Extract info about function scopes formed by switch'es on function arguments.
For example if we have:
void foo(..., int cmd, ...)
{
...
switch (cmd) {
case FOO:
... block 1 ...
case BAR:
... block 2 ...
}
...
}
We record that any data flow within block 1 is only relevant
when foo's arg cmd has value FOO, similarly for block 2 and BAR.
This allows to do 3 things:
1. Locate ioctl commands that are switched on within transitively
called functions.
2. Infer return value for each ioctl command.
3. Infer argument type when it's not specified in _IO macro.
This will also allow to infer other multiplexed syscalls.
Descriptions generated on Linux commit c4b9570cfb63501.
Diffstat (limited to 'pkg/declextract/fileops.go')
| -rw-r--r-- | pkg/declextract/fileops.go | 47 |
1 files changed, 32 insertions, 15 deletions
diff --git a/pkg/declextract/fileops.go b/pkg/declextract/fileops.go index d28c48337..cacdcaa9e 100644 --- a/pkg/declextract/fileops.go +++ b/pkg/declextract/fileops.go @@ -12,6 +12,9 @@ import ( // TODO: also emit interface entry for file_operations. func (ctx *context) serializeFileOps() { + for _, ioctl := range ctx.Ioctls { + ctx.ioctls[ioctl.Name] = ioctl.Type + } fopsToFiles := ctx.mapFopsToFiles() for _, fops := range ctx.FileOps { files := fopsToFiles[fops] @@ -52,22 +55,36 @@ func (ctx *context) createFops(fops *FileOps, files []string) { " flags flags[mmap_flags], fd %v, offset fileoff)\n", suffix, fdt) } if fops.Ioctl != "" { - if len(fops.IoctlCmds) == 0 { - ctx.fmt("ioctl%v(fd %v, cmd intptr, arg ptr[in, array[int8]])\n", suffix, fdt) - } else { - for _, cmd := range sortAndDedupSlice(fops.IoctlCmds) { - name := ctx.uniqualize("ioctl cmd", cmd.Name) - f := &Field{ - Name: strings.ToLower(cmd.Name), - Type: cmd.Type, - } - typ := ctx.fieldType(f, nil, "", false) - ctx.fmt("ioctl%v_%v(fd %v, cmd const[%v], arg %v)\n", - autoSuffix, name, fdt, cmd.Name, typ) + ctx.createIoctls(fops, suffix, fdt) + } + ctx.fmt("\n") +} + +func (ctx *context) createIoctls(fops *FileOps, suffix, fdt string) { + const defaultArgType = "ptr[in, array[int8]]" + cmds := ctx.inferCommandVariants(fops.Ioctl, fops.SourceFile, 1) + if len(cmds) == 0 { + retType := ctx.inferReturnType(fops.Ioctl, fops.SourceFile) + argType := ctx.inferArgType(fops.Ioctl, fops.SourceFile, 2) + if argType == "" { + argType = defaultArgType + } + ctx.fmt("ioctl%v(fd %v, cmd intptr, arg %v) %v\n", suffix, fdt, argType, retType) + return + } + for _, cmd := range cmds { + argType := defaultArgType + if typ := ctx.ioctls[cmd]; typ != nil { + f := &Field{ + Name: strings.ToLower(cmd), + Type: typ, } + argType = ctx.fieldType(f, nil, "", false) } + name := ctx.uniqualize("ioctl cmd", cmd) + ctx.fmt("ioctl%v_%v(fd %v, cmd const[%v], arg %v)\n", + autoSuffix, name, fdt, cmd, argType) } - ctx.fmt("\n") } // mapFopsToFiles maps file_operations to actual file names. @@ -176,14 +193,14 @@ func (ctx *context) mapFileToFops(funcs map[string]bool, funcToFops map[string][ // An example of an excessive case is if we have 2 file_operations with just read+write, // currently we emit generic read/write operations, so we would emit completly equal // descriptions for both. Ioctl commands is the only non-generic descriptions we emit now, - // so if a file_operations has any commands, it won't be considered excessive. + // so if a file_operations has an ioctl handler, it won't be considered excessive. // Note that if we generate specialized descriptions for read/write/mmap in future, // then these won't be considered excessive as well. excessive := make(map[*FileOps]bool) for i := 0; i < len(best); i++ { for j := i + 1; j < len(best); j++ { a, b := best[i], best[j] - if (a.Ioctl == b.Ioctl || len(a.IoctlCmds)+len(b.IoctlCmds) == 0) && + if (a.Ioctl == b.Ioctl) && (a.Read == "") == (b.Read == "") && (a.Write == "") == (b.Write == "") && (a.Mmap == "") == (b.Mmap == "") && |
