Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

prog: support optional resources #4580

Draft
wants to merge 1 commit into
base: master
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
25 changes: 25 additions & 0 deletions docs/syscall_descriptions_syntax.md
Original file line number Diff line number Diff line change
Expand Up @@ -263,6 +263,31 @@ Each resource type must be "produced" (used as an output) by at least one syscal
(outside of unions and optional pointers) and "consumed" (used as an input)
by at least one syscall.

This restriction helps automatically determine the dependent syscalls there's no reason
to fuzz. But in some cases one might not need such a strict validation. For example,
consider the following minimalistic syzlang description:

```
resource inout_resource[int32]: 0

test$use_resource(a ptr[inout, inout_resource_struct])

inout_resource_struct {
field inout_resource
}
```

Syzkaller would conclude that there's no way to construct `inout_resource` (which is
necessary to generate `inout_resource_struct`) and disable the `test$use_resource` call.
However, the resource is obviously not mandatory here.

To indicate this to syzkaller, you may mark the resource as optional:

```
resource inout_resource[int32, opt]
```


## Type Aliases

Complex types that are often repeated can be given short type aliases using the
Expand Down
1 change: 1 addition & 0 deletions pkg/ast/ast.go
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,7 @@ type Resource struct {
Name *Ident
Base *Type
Values []*Int
Args []*Type
}

func (n *Resource) Info() (Pos, string, string) {
Expand Down
1 change: 1 addition & 0 deletions pkg/ast/clone.go
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,7 @@ func (n *Resource) Clone() Node {
Name: n.Name.Clone().(*Ident),
Base: n.Base.Clone().(*Type),
Values: cloneInts(n.Values),
Args: cloneTypes(n.Args),
}
}

Expand Down
7 changes: 6 additions & 1 deletion pkg/ast/format.go
Original file line number Diff line number Diff line change
Expand Up @@ -95,7 +95,12 @@ func (n *Define) serialize(w io.Writer) {
}

func (n *Resource) serialize(w io.Writer) {
fmt.Fprintf(w, "resource %v[%v]", n.Name.Name, fmtType(n.Base))
fmt.Fprintf(w, "resource %v[%v", n.Name.Name, fmtType(n.Base))
for _, a := range n.Args {
fmt.Fprintf(w, ", ")
a.serialize(w)
}
fmt.Fprintf(w, "]")
for i, v := range n.Values {
fmt.Fprintf(w, "%v%v", comma(i, ": "), fmtInt(v))
}
Expand Down
5 changes: 5 additions & 0 deletions pkg/ast/parser.go
Original file line number Diff line number Diff line change
Expand Up @@ -242,6 +242,10 @@ func (p *parser) parseResource() *Resource {
name := p.parseIdent()
p.consume(tokLBrack)
base := p.parseType()
var args []*Type
if p.tryConsume(tokComma) {
args = append(args, p.parseType())
}
p.consume(tokRBrack)
var values []*Int
if p.tryConsume(tokColon) {
Expand All @@ -254,6 +258,7 @@ func (p *parser) parseResource() *Resource {
Pos: pos0,
Name: name,
Base: base,
Args: args,
Values: values,
}
}
Expand Down
2 changes: 2 additions & 0 deletions pkg/ast/testdata/all.txt
Original file line number Diff line number Diff line change
Expand Up @@ -30,3 +30,5 @@ condFields {
f3 int16 (out, if[val[mask] & SOME_CONST & OTHER_CONST == val[mask] & CONST_X])
f4 int16 (out, if[val[flags] & SOME_CONST])
}

resource some_resource[int32, opt]
3 changes: 3 additions & 0 deletions pkg/ast/walk.go
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,9 @@ func (n *Resource) walk(cb func(Node)) {
for _, v := range n.Values {
cb(v)
}
for _, a := range n.Args {
cb(a)
}
}

func (n *TypeDef) walk(cb func(Node)) {
Expand Down
10 changes: 9 additions & 1 deletion pkg/compiler/check.go
Original file line number Diff line number Diff line change
Expand Up @@ -304,6 +304,7 @@ func (comp *compiler) checkTypes() {
switch n := decl.(type) {
case *ast.Resource:
comp.checkType(checkCtx{}, n.Base, checkIsResourceBase)
comp.checkResource(n)
case *ast.Struct:
comp.checkStruct(checkCtx{}, n)
case *ast.Call:
Expand All @@ -312,6 +313,13 @@ func (comp *compiler) checkTypes() {
}
}

func (comp *compiler) checkResource(n *ast.Resource) {
args, _ := removeOpt(n.Args)
if len(args) > 0 {
comp.error(n.Pos, "unexpected resource arguments, only opt is supported now")
}
}

func (comp *compiler) checkTypeValues() {
for _, decl := range comp.desc.Nodes {
switch n := decl.(type) {
Expand Down Expand Up @@ -1104,7 +1112,7 @@ func (comp *compiler) checkTypeBasic(t *ast.Type, desc *typeDesc, flags checkFla
}

func (comp *compiler) checkTypeArgs(t *ast.Type, desc *typeDesc, flags checkFlags) []*ast.Type {
args, opt := removeOpt(t)
args, opt := removeOpt(t.Args)
if opt != nil {
if len(opt.Args) != 0 {
comp.error(opt.Pos, "opt can't have arguments")
Expand Down
5 changes: 2 additions & 3 deletions pkg/compiler/compiler.go
Original file line number Diff line number Diff line change
Expand Up @@ -306,7 +306,7 @@ func (comp *compiler) getArgsBase(t *ast.Type, isArg bool) (*typeDesc, []*ast.Ty
if desc == nil {
panic(fmt.Sprintf("no type desc for %#v", *t))
}
args, opt := removeOpt(t)
args, opt := removeOpt(t.Args)
com := genCommon(t.Ident, sizeUnassigned, opt != nil)
base := genIntCommon(com, 0, false)
if desc.NeedBase {
Expand Down Expand Up @@ -366,8 +366,7 @@ func (comp *compiler) foreachSubType(t *ast.Type, isArg bool,
}
}

func removeOpt(t *ast.Type) ([]*ast.Type, *ast.Type) {
args := t.Args
func removeOpt(args []*ast.Type) ([]*ast.Type, *ast.Type) {
if last := len(args) - 1; last >= 0 && args[last].Ident == "opt" {
return args[:last], args[last]
}
Expand Down
3 changes: 3 additions & 0 deletions pkg/compiler/gen.go
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,9 @@ func (comp *compiler) genResource(n *ast.Resource) *prog.ResourceDesc {
res := &prog.ResourceDesc{
Name: n.Name.Name,
}
if _, opt := removeOpt(n.Args); opt != nil {
res.Optional = true
}
for n != nil {
res.Values = append(genIntArray(n.Values), res.Values...)
res.Kind = append([]string{n.Name.Name}, res.Kind...)
Expand Down
8 changes: 8 additions & 0 deletions pkg/compiler/testdata/all.txt
Original file line number Diff line number Diff line change
Expand Up @@ -369,3 +369,11 @@ union$conditional3 [
]

conditional(a ptr[in, struct$conditional])

resource opt_resource[int32, opt]

test$use_optional_resource(a ptr[inout, opt_resource_struct])

opt_resource_struct {
f opt_resource
}
2 changes: 2 additions & 0 deletions pkg/compiler/testdata/errors.txt
Original file line number Diff line number Diff line change
Expand Up @@ -507,3 +507,5 @@ conditional_fields_union2 [
u2 int32 ### either no fields have conditions or all except the last
u3 int32
]

resource opt_resource[int32, custom_arg] ### unexpected resource arguments, only opt is supported now
2 changes: 1 addition & 1 deletion prog/resources.go
Original file line number Diff line number Diff line change
Expand Up @@ -151,7 +151,7 @@ func (target *Target) getInputResources(c *Syscall) []*ResourceDesc {
}
switch typ1 := typ.(type) {
case *ResourceType:
if !ctx.Optional && !dedup[typ1.Desc] {
if !ctx.Optional && !dedup[typ1.Desc] && !typ1.Desc.Optional {
dedup[typ1.Desc] = true
resources = append(resources, typ1.Desc)
}
Expand Down
9 changes: 5 additions & 4 deletions prog/types.go
Original file line number Diff line number Diff line change
Expand Up @@ -310,10 +310,11 @@ type FlagDesc struct {
}

type ResourceDesc struct {
Name string
Kind []string
Values []uint64
Ctors []ResourceCtor
Name string
Optional bool
Kind []string
Values []uint64
Ctors []ResourceCtor
}

type ResourceCtor struct {
Expand Down
8 changes: 8 additions & 0 deletions sys/test/test.txt
Original file line number Diff line number Diff line change
Expand Up @@ -774,6 +774,14 @@ syz_use_missing {
a1 syz_missing_const_struct
}

resource inout_resource[fd, opt]

test$use_resource(a ptr[inout, inout_resource_struct])

inout_resource_struct {
field inout_resource
}

# Hints tests.

test$hint_int(a0 ptr[in, hint_ints])
Expand Down
Loading