mirror of
https://github.com/reactos/syzkaller.git
synced 2025-02-17 10:10:08 +00:00
prog: add implementation for resource centric
This commit is contained in:
parent
8d48456885
commit
dbd627eb61
@ -15,6 +15,7 @@ import (
|
|||||||
type state struct {
|
type state struct {
|
||||||
target *Target
|
target *Target
|
||||||
ct *ChoiceTable
|
ct *ChoiceTable
|
||||||
|
corpus []*Prog
|
||||||
files map[string]bool
|
files map[string]bool
|
||||||
resources map[string][]*ResultArg
|
resources map[string][]*ResultArg
|
||||||
strings map[string]bool
|
strings map[string]bool
|
||||||
@ -23,8 +24,8 @@ type state struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// analyze analyzes the program p up to but not including call c.
|
// analyze analyzes the program p up to but not including call c.
|
||||||
func analyze(ct *ChoiceTable, p *Prog, c *Call) *state {
|
func analyze(ct *ChoiceTable, corpus []*Prog, p *Prog, c *Call) *state {
|
||||||
s := newState(p.Target, ct)
|
s := newState(p.Target, ct, corpus)
|
||||||
resources := true
|
resources := true
|
||||||
for _, c1 := range p.Calls {
|
for _, c1 := range p.Calls {
|
||||||
if c1 == c {
|
if c1 == c {
|
||||||
@ -35,10 +36,11 @@ func analyze(ct *ChoiceTable, p *Prog, c *Call) *state {
|
|||||||
return s
|
return s
|
||||||
}
|
}
|
||||||
|
|
||||||
func newState(target *Target, ct *ChoiceTable) *state {
|
func newState(target *Target, ct *ChoiceTable, corpus []*Prog) *state {
|
||||||
s := &state{
|
s := &state{
|
||||||
target: target,
|
target: target,
|
||||||
ct: ct,
|
ct: ct,
|
||||||
|
corpus: corpus,
|
||||||
files: make(map[string]bool),
|
files: make(map[string]bool),
|
||||||
resources: make(map[string][]*ResultArg),
|
resources: make(map[string][]*ResultArg),
|
||||||
strings: make(map[string]bool),
|
strings: make(map[string]bool),
|
||||||
|
@ -20,7 +20,7 @@ func TestIsComplexPtr(t *testing.T) {
|
|||||||
compl := make(map[string]bool)
|
compl := make(map[string]bool)
|
||||||
for _, meta := range target.Syscalls {
|
for _, meta := range target.Syscalls {
|
||||||
for i := 0; i < iters; i++ {
|
for i := 0; i < iters; i++ {
|
||||||
s := newState(target, nil)
|
s := newState(target, nil, nil)
|
||||||
calls := r.generateParticularCall(s, meta)
|
calls := r.generateParticularCall(s, meta)
|
||||||
p := &Prog{Target: target, Calls: calls}
|
p := &Prog{Target: target, Calls: calls}
|
||||||
for _, arg := range p.complexPtrs() {
|
for _, arg := range p.complexPtrs() {
|
||||||
|
@ -961,7 +961,7 @@ func (p *parser) auto(arg Arg) Arg {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (p *parser) fixupAutos(prog *Prog) {
|
func (p *parser) fixupAutos(prog *Prog) {
|
||||||
s := analyze(nil, prog, nil)
|
s := analyze(nil, nil, prog, nil)
|
||||||
for _, c := range prog.Calls {
|
for _, c := range prog.Calls {
|
||||||
p.target.assignSizesArray(c.Args, p.autos)
|
p.target.assignSizesArray(c.Args, p.autos)
|
||||||
ForeachArg(c, func(arg Arg, _ *ArgCtx) {
|
ForeachArg(c, func(arg Arg, _ *ArgCtx) {
|
||||||
|
@ -14,7 +14,7 @@ func (target *Target) Generate(rs rand.Source, ncalls int, ct *ChoiceTable) *Pro
|
|||||||
Target: target,
|
Target: target,
|
||||||
}
|
}
|
||||||
r := newRand(target, rs)
|
r := newRand(target, rs)
|
||||||
s := newState(target, ct)
|
s := newState(target, ct, nil)
|
||||||
for len(p.Calls) < ncalls {
|
for len(p.Calls) < ncalls {
|
||||||
calls := r.generateCall(s, p)
|
calls := r.generateCall(s, p)
|
||||||
for _, c := range calls {
|
for _, c := range calls {
|
||||||
|
@ -112,7 +112,7 @@ func (ctx *mutator) squashAny() bool {
|
|||||||
arg.data = mutateData(r, arg.Data(), 0, maxBlobLen)
|
arg.data = mutateData(r, arg.Data(), 0, maxBlobLen)
|
||||||
// Update base pointer if size has increased.
|
// Update base pointer if size has increased.
|
||||||
if baseSize < base.Res.Size() {
|
if baseSize < base.Res.Size() {
|
||||||
s := analyze(ctx.ct, p, p.Calls[0])
|
s := analyze(ctx.ct, ctx.corpus, p, p.Calls[0])
|
||||||
newArg := r.allocAddr(s, base.Type(), base.Res.Size(), base.Res)
|
newArg := r.allocAddr(s, base.Type(), base.Res.Size(), base.Res)
|
||||||
*base = *newArg
|
*base = *newArg
|
||||||
}
|
}
|
||||||
@ -131,8 +131,9 @@ func (ctx *mutator) insertCall() bool {
|
|||||||
if idx < len(p.Calls) {
|
if idx < len(p.Calls) {
|
||||||
c = p.Calls[idx]
|
c = p.Calls[idx]
|
||||||
}
|
}
|
||||||
s := analyze(ctx.ct, p, c)
|
s := analyze(ctx.ct, ctx.corpus, p, c)
|
||||||
calls := r.generateCall(s, p)
|
calls := r.generateCall(s, p)
|
||||||
|
// TODO: the program might have more than ncalls
|
||||||
p.insertBefore(c, calls)
|
p.insertBefore(c, calls)
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
@ -158,7 +159,7 @@ func (ctx *mutator) mutateArg() bool {
|
|||||||
if len(c.Args) == 0 {
|
if len(c.Args) == 0 {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
s := analyze(ctx.ct, p, c)
|
s := analyze(ctx.ct, ctx.corpus, p, c)
|
||||||
updateSizes := true
|
updateSizes := true
|
||||||
for stop, ok := false, false; !stop; stop = ok && r.oneOf(3) {
|
for stop, ok := false, false; !stop; stop = ok && r.oneOf(3) {
|
||||||
ok = true
|
ok = true
|
||||||
|
@ -74,7 +74,7 @@ func TestVmaType(t *testing.T) {
|
|||||||
r := newRand(target, rs)
|
r := newRand(target, rs)
|
||||||
pageSize := target.PageSize
|
pageSize := target.PageSize
|
||||||
for i := 0; i < iters; i++ {
|
for i := 0; i < iters; i++ {
|
||||||
s := newState(target, nil)
|
s := newState(target, nil, nil)
|
||||||
calls := r.generateParticularCall(s, meta)
|
calls := r.generateParticularCall(s, meta)
|
||||||
c := calls[len(calls)-1]
|
c := calls[len(calls)-1]
|
||||||
if c.Meta.Name != "test$vma0" {
|
if c.Meta.Name != "test$vma0" {
|
||||||
@ -198,7 +198,7 @@ func TestSpecialStructs(t *testing.T) {
|
|||||||
if typ == nil {
|
if typ == nil {
|
||||||
t.Fatal("can't find struct description")
|
t.Fatal("can't find struct description")
|
||||||
}
|
}
|
||||||
g := &Gen{newRand(target, rs), newState(target, nil)}
|
g := &Gen{newRand(target, rs), newState(target, nil, nil)}
|
||||||
for i := 0; i < iters/len(target.SpecialTypes); i++ {
|
for i := 0; i < iters/len(target.SpecialTypes); i++ {
|
||||||
arg, _ := gen(g, typ, nil)
|
arg, _ := gen(g, typ, nil)
|
||||||
gen(g, typ, arg)
|
gen(g, typ, arg)
|
||||||
|
87
prog/rand.go
87
prog/rand.go
@ -302,7 +302,7 @@ func (r *randGen) createResource(s *state, res *ResourceType) (arg Arg, calls []
|
|||||||
// Generate one of them.
|
// Generate one of them.
|
||||||
meta := metas[r.Intn(len(metas))]
|
meta := metas[r.Intn(len(metas))]
|
||||||
calls := r.generateParticularCall(s, meta)
|
calls := r.generateParticularCall(s, meta)
|
||||||
s1 := newState(r.target, s.ct)
|
s1 := newState(r.target, s.ct, nil)
|
||||||
s1.analyze(calls[len(calls)-1])
|
s1.analyze(calls[len(calls)-1])
|
||||||
// Now see if we have what we want.
|
// Now see if we have what we want.
|
||||||
var allres []*ResultArg
|
var allres []*ResultArg
|
||||||
@ -480,7 +480,7 @@ func (target *Target) GenerateAllSyzProg(rs rand.Source) *Prog {
|
|||||||
Target: target,
|
Target: target,
|
||||||
}
|
}
|
||||||
r := newRand(target, rs)
|
r := newRand(target, rs)
|
||||||
s := newState(target, nil)
|
s := newState(target, nil, nil)
|
||||||
handled := make(map[string]bool)
|
handled := make(map[string]bool)
|
||||||
for _, meta := range target.Syscalls {
|
for _, meta := range target.Syscalls {
|
||||||
if !strings.HasPrefix(meta.CallName, "syz_") || handled[meta.CallName] {
|
if !strings.HasPrefix(meta.CallName, "syz_") || handled[meta.CallName] {
|
||||||
@ -589,7 +589,14 @@ func (r *randGen) generateArgImpl(s *state, typ Type, ignoreSpecial bool) (arg A
|
|||||||
|
|
||||||
func (a *ResourceType) generate(r *randGen, s *state) (arg Arg, calls []*Call) {
|
func (a *ResourceType) generate(r *randGen, s *state) (arg Arg, calls []*Call) {
|
||||||
switch {
|
switch {
|
||||||
case r.nOutOf(1000, 1011):
|
case r.nOutOf(2, 5):
|
||||||
|
var res *ResultArg
|
||||||
|
res, calls = resourceCentric(a, s, r)
|
||||||
|
if res == nil {
|
||||||
|
return r.createResource(s, a)
|
||||||
|
}
|
||||||
|
arg = MakeResultArg(a, res, 0)
|
||||||
|
case r.nOutOf(1, 2):
|
||||||
// Get an existing resource.
|
// Get an existing resource.
|
||||||
alltypes := make([][]*ResultArg, 0, len(s.resources))
|
alltypes := make([][]*ResultArg, 0, len(s.resources))
|
||||||
for _, res1 := range s.resources {
|
for _, res1 := range s.resources {
|
||||||
@ -611,7 +618,7 @@ func (a *ResourceType) generate(r *randGen, s *state) (arg Arg, calls []*Call) {
|
|||||||
} else {
|
} else {
|
||||||
arg, calls = r.createResource(s, a)
|
arg, calls = r.createResource(s, a)
|
||||||
}
|
}
|
||||||
case r.nOutOf(10, 11):
|
case r.nOutOf(2, 3):
|
||||||
// Create a new resource.
|
// Create a new resource.
|
||||||
arg, calls = r.createResource(s, a)
|
arg, calls = r.createResource(s, a)
|
||||||
default:
|
default:
|
||||||
@ -754,3 +761,75 @@ func (a *CsumType) generate(r *randGen, s *state) (arg Arg, calls []*Call) {
|
|||||||
// Filled at runtime by executor.
|
// Filled at runtime by executor.
|
||||||
return MakeConstArg(a, 0), nil
|
return MakeConstArg(a, 0), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Finds a compatible resource with the type `t` and the calls that initialize that resource.
|
||||||
|
func resourceCentric(t *ResourceType, s *state, r *randGen) (resource *ResultArg, calls []*Call) {
|
||||||
|
var p *Prog
|
||||||
|
for idx := range r.Perm(len(s.corpus)) {
|
||||||
|
p = s.corpus[idx].Clone()
|
||||||
|
resources := getCompatibleResources(p, t.TypeName, r)
|
||||||
|
if len(resources) > 0 {
|
||||||
|
resource = resources[r.Intn(len(resources))]
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// No compatible resource was found.
|
||||||
|
if resource == nil {
|
||||||
|
return nil, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set that stores the resources that appear in the same calls with the selected resource.
|
||||||
|
relatedRes := map[*ResultArg]bool{resource: true}
|
||||||
|
|
||||||
|
// Remove unrelated calls from the program.
|
||||||
|
for idx := len(p.Calls) - 1; idx >= 0; idx-- {
|
||||||
|
includeCall := false
|
||||||
|
var newResources []*ResultArg
|
||||||
|
ForeachArg(p.Calls[idx], func(arg Arg, _ *ArgCtx) {
|
||||||
|
if a, ok := arg.(*ResultArg); ok {
|
||||||
|
if a.Res != nil && !relatedRes[a.Res] {
|
||||||
|
newResources = append(newResources, a.Res)
|
||||||
|
}
|
||||||
|
if relatedRes[a] || relatedRes[a.Res] {
|
||||||
|
includeCall = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
if !includeCall {
|
||||||
|
p.removeCall(idx)
|
||||||
|
} else {
|
||||||
|
for _, res := range newResources {
|
||||||
|
relatedRes[res] = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Selects a biased random length of the returned calls (more calls could offer more
|
||||||
|
// interesting programs). The values returned (n = len(calls): n, n-1, ..., 2.
|
||||||
|
biasedLen := 2 + r.biasedRand(len(calls)-1, 10)
|
||||||
|
|
||||||
|
// Removes the references that are not used anymore.
|
||||||
|
for i := biasedLen; i < len(calls); i++ {
|
||||||
|
p.removeCall(i)
|
||||||
|
}
|
||||||
|
|
||||||
|
return resource, p.Calls
|
||||||
|
}
|
||||||
|
|
||||||
|
func getCompatibleResources(p *Prog, resourceType string, r *randGen) (resources []*ResultArg) {
|
||||||
|
for _, c := range p.Calls {
|
||||||
|
ForeachArg(c, func(arg Arg, _ *ArgCtx) {
|
||||||
|
// Collect only initialized resources (the ones that are already used in other calls).
|
||||||
|
a, ok := arg.(*ResultArg)
|
||||||
|
if !ok || len(a.uses) == 0 || a.typ.Dir() != DirOut {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if !r.target.isCompatibleResource(resourceType, a.typ.Name()) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
resources = append(resources, a)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
return resources
|
||||||
|
}
|
||||||
|
@ -14,6 +14,7 @@ import (
|
|||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
"github.com/google/syzkaller/pkg/db"
|
||||||
"github.com/google/syzkaller/pkg/mgrconfig"
|
"github.com/google/syzkaller/pkg/mgrconfig"
|
||||||
"github.com/google/syzkaller/prog"
|
"github.com/google/syzkaller/prog"
|
||||||
_ "github.com/google/syzkaller/sys"
|
_ "github.com/google/syzkaller/sys"
|
||||||
@ -25,6 +26,7 @@ var (
|
|||||||
flagSeed = flag.Int("seed", -1, "prng seed")
|
flagSeed = flag.Int("seed", -1, "prng seed")
|
||||||
flagLen = flag.Int("len", 30, "number of calls in programs")
|
flagLen = flag.Int("len", 30, "number of calls in programs")
|
||||||
flagEnable = flag.String("enable", "", "comma-separated list of enabled syscalls")
|
flagEnable = flag.String("enable", "", "comma-separated list of enabled syscalls")
|
||||||
|
flagCorpus = flag.String("corpus", "", "name of the corpus file")
|
||||||
)
|
)
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
@ -56,8 +58,12 @@ func main() {
|
|||||||
if *flagSeed != -1 {
|
if *flagSeed != -1 {
|
||||||
seed = int64(*flagSeed)
|
seed = int64(*flagSeed)
|
||||||
}
|
}
|
||||||
|
var corpus []*prog.Prog
|
||||||
|
if *flagCorpus != "" {
|
||||||
|
corpus = readCorpus(*flagCorpus, target)
|
||||||
|
}
|
||||||
rs := rand.NewSource(seed)
|
rs := rand.NewSource(seed)
|
||||||
prios := target.CalculatePriorities(nil)
|
prios := target.CalculatePriorities(corpus)
|
||||||
ct := target.BuildChoiceTable(prios, syscalls)
|
ct := target.BuildChoiceTable(prios, syscalls)
|
||||||
var p *prog.Prog
|
var p *prog.Prog
|
||||||
if flag.NArg() == 0 {
|
if flag.NArg() == 0 {
|
||||||
@ -73,7 +79,24 @@ func main() {
|
|||||||
fmt.Fprintf(os.Stderr, "failed to deserialize the program: %v\n", err)
|
fmt.Fprintf(os.Stderr, "failed to deserialize the program: %v\n", err)
|
||||||
os.Exit(1)
|
os.Exit(1)
|
||||||
}
|
}
|
||||||
p.Mutate(rs, *flagLen, ct, nil)
|
p.Mutate(rs, *flagLen, ct, corpus)
|
||||||
}
|
}
|
||||||
fmt.Printf("%s\n", p.Serialize())
|
fmt.Printf("%s\n", p.Serialize())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func readCorpus(filename string, target *prog.Target) (corpus []*prog.Prog) {
|
||||||
|
dbObj, err := db.Open(filename)
|
||||||
|
if err != nil {
|
||||||
|
fmt.Fprintf(os.Stderr, "failed to open the corpus file: %v\n", err)
|
||||||
|
os.Exit(1)
|
||||||
|
}
|
||||||
|
for _, v := range dbObj.Records {
|
||||||
|
p, err := target.Deserialize(v.Val, prog.NonStrict)
|
||||||
|
if err != nil {
|
||||||
|
fmt.Fprintf(os.Stderr, "failed to deserialize the program: %v\n", err)
|
||||||
|
os.Exit(1)
|
||||||
|
}
|
||||||
|
corpus = append(corpus, p)
|
||||||
|
}
|
||||||
|
return corpus
|
||||||
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user