mirror of
https://github.com/reactos/syzkaller.git
synced 2024-11-23 19:39:40 +00:00
269 lines
8.3 KiB
Go
269 lines
8.3 KiB
Go
// Copyright 2015 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 prog
|
|
|
|
import (
|
|
"bytes"
|
|
"fmt"
|
|
"testing"
|
|
)
|
|
|
|
func TestClone(t *testing.T) {
|
|
rs, iters := initTest(t)
|
|
for i := 0; i < iters; i++ {
|
|
p := Generate(rs, 10, nil)
|
|
p1 := p.Clone()
|
|
data := p.Serialize()
|
|
data1 := p1.Serialize()
|
|
if !bytes.Equal(data, data1) {
|
|
t.Fatalf("program changed after clone\noriginal:\n%s\n\nnew:\n%s\n", data, data1)
|
|
}
|
|
}
|
|
}
|
|
|
|
func TestMutate(t *testing.T) {
|
|
rs, iters := initTest(t)
|
|
next:
|
|
for i := 0; i < iters; i++ {
|
|
p := Generate(rs, 10, nil)
|
|
data0 := p.Serialize()
|
|
p1 := p.Clone()
|
|
// There is a chance that mutation will produce the same program.
|
|
// So we check that at least 1 out of 10 mutations actually change the program.
|
|
for try := 0; try < 10; try++ {
|
|
p1.Mutate(rs, 10, nil)
|
|
data := p.Serialize()
|
|
if !bytes.Equal(data0, data) {
|
|
t.Fatalf("program changed after clone/mutate\noriginal:\n%s\n\nnew:\n%s\n", data0, data)
|
|
}
|
|
data1 := p1.Serialize()
|
|
if !bytes.Equal(data, data1) {
|
|
continue next
|
|
}
|
|
}
|
|
t.Fatalf("mutation does not change program")
|
|
}
|
|
}
|
|
|
|
func TestMutateTable(t *testing.T) {
|
|
if testing.Short() {
|
|
t.Skip("skipping in short mode")
|
|
}
|
|
tests := [][2]string{
|
|
// Insert calls.
|
|
{
|
|
"mmap(&(0x7f0000000000)=nil, (0x1000), 0x3, 0x32, 0xffffffffffffffff, 0x0)\n" +
|
|
"pipe2(&(0x7f0000000000)={0x0, 0x0}, 0x0)\n",
|
|
|
|
"mmap(&(0x7f0000000000)=nil, (0x1000), 0x3, 0x32, 0xffffffffffffffff, 0x0)\n" +
|
|
"sched_yield()\n" +
|
|
"pipe2(&(0x7f0000000000)={0x0, 0x0}, 0x0)\n",
|
|
},
|
|
// Remove calls and update args.
|
|
{
|
|
"r0 = open(&(0x7f0000001000)=\"2e2f66696c653000\", 0x22c0, 0x1)\n" +
|
|
"sched_yield()\n" +
|
|
"read(r0, &(0x7f0000000000)=0x0, 0x1)\n" +
|
|
"sched_yield()\n",
|
|
|
|
"sched_yield()\n" +
|
|
"read(0xffffffffffffffff, &(0x7f0000000000)=0x0, 0x1)\n" +
|
|
"sched_yield()\n",
|
|
},
|
|
// Mutate flags.
|
|
{
|
|
"r0 = open(&(0x7f0000001000)=\"2e2f66696c653000\", 0x22c0, 0x1)\n" +
|
|
"sched_yield()\n" +
|
|
"read(r0, &(0x7f0000000000)=0x0, 0x1)\n" +
|
|
"sched_yield()\n",
|
|
|
|
"r0 = open(&(0x7f0000001000)=\"2e2f66696c653000\", 0x22c0, 0x2)\n" +
|
|
"sched_yield()\n" +
|
|
"read(r0, &(0x7f0000000000)=0x0, 0x1)\n" +
|
|
"sched_yield()\n",
|
|
},
|
|
// Mutate data (delete byte and update size).
|
|
{
|
|
"r0 = open(&(0x7f0000001000)=\"2e2f66696c653000\", 0x22c0, 0x1)\n" +
|
|
"write(r0, &(0x7f0000000000)=\"11223344\", 0x4)\n",
|
|
|
|
"r0 = open(&(0x7f0000001000)=\"2e2f66696c653000\", 0x22c0, 0x1)\n" +
|
|
"write(r0, &(0x7f0000000000)=\"112244\", 0x3)\n",
|
|
},
|
|
// Mutate data (insert byte and update size).
|
|
{
|
|
"r0 = open(&(0x7f0000001000)=\"2e2f66696c653000\", 0x22c0, 0x1)\n" +
|
|
"write(r0, &(0x7f0000000000)=\"1122\", 0x2)\n",
|
|
|
|
"r0 = open(&(0x7f0000001000)=\"2e2f66696c653000\", 0x22c0, 0x1)\n" +
|
|
"write(r0, &(0x7f0000000000)=\"112255\", 0x3)\n",
|
|
},
|
|
// Mutate data (change byte).
|
|
{
|
|
"r0 = open(&(0x7f0000001000)=\"2e2f66696c653000\", 0x22c0, 0x1)\n" +
|
|
"write(r0, &(0x7f0000000000)=\"1122\", 0x2)\n",
|
|
|
|
"r0 = open(&(0x7f0000001000)=\"2e2f66696c653000\", 0x22c0, 0x1)\n" +
|
|
"write(r0, &(0x7f0000000000)=\"1155\", 0x2)\n",
|
|
},
|
|
// Change filename.
|
|
{
|
|
"open(&(0x7f0000001000)=\"2e2f66696c653000\", 0x22c0, 0x1)\n" +
|
|
"r0 = open(&(0x7f0000001000)=\"2e2f66696c653000\", 0x22c0, 0x1)\n" +
|
|
"write(r0, &(0x7f0000000000)=\"\", 0x0)\n",
|
|
|
|
"open(&(0x7f0000001000)=\"2e2f66696c653000\", 0x22c0, 0x1)\n" +
|
|
"r0 = open(&(0x7f0000001000)=\"2e2f66696c653100\", 0x22c0, 0x1)\n" +
|
|
"write(r0, &(0x7f0000000000)=\"\", 0x0)\n",
|
|
},
|
|
// Extend an array.
|
|
{
|
|
"r0 = open(&(0x7f0000001000)=\"2e2f66696c653000\", 0x22c0, 0x1)\n" +
|
|
"readv(r0, &(0x7f0000000000)={{&(0x7f0000001000)=nil, 0x1}, {&(0x7f0000002000)=nil, 0x2}}, 0x2)\n",
|
|
|
|
"mmap(&(0x7f0000000000)=nil, (0x1000), 0x3, 0x32, 0xffffffffffffffff, 0x0)\n" +
|
|
"r0 = open(&(0x7f0000001000)=\"2e2f66696c653000\", 0x22c0, 0x1)\n" +
|
|
"readv(r0, &(0x7f0000000000)={{&(0x7f0000001000)=nil, 0x1}, {&(0x7f0000002000)=nil, 0x2}, {&(0x7f0000000000)=nil, 0x3}}, 0x3)\n",
|
|
},
|
|
}
|
|
rs, _ := initTest(t)
|
|
nextTest:
|
|
for ti, test := range tests {
|
|
p, err := Deserialize([]byte(test[0]))
|
|
if err != nil {
|
|
t.Fatalf("failed to deserialize original program: %v", err)
|
|
}
|
|
for i := 0; i < 1e6; i++ {
|
|
p1 := p.Clone()
|
|
p1.Mutate(rs, 30, nil)
|
|
data1 := p1.Serialize()
|
|
if string(data1) == test[1] {
|
|
t.Logf("test #%v: success on iter %v", ti, i)
|
|
continue nextTest
|
|
}
|
|
_ = fmt.Printf
|
|
}
|
|
t.Fatalf("failed to achieve mutation goal\noriginal:\n%s\n\ngoal:\n%s\n", test[0], test[1])
|
|
}
|
|
}
|
|
|
|
func TestMinimize(t *testing.T) {
|
|
tests := []struct {
|
|
orig string
|
|
callIndex int
|
|
pred func(*Prog, int) bool
|
|
result string
|
|
}{
|
|
// Predicate always returns false, so must get the same program.
|
|
{
|
|
"mmap(&(0x7f0000000000)=nil, (0x1000), 0x3, 0x32, 0xffffffffffffffff, 0x0)\n" +
|
|
"sched_yield()\n" +
|
|
"pipe2(&(0x7f0000000000)={0x0, 0x0}, 0x0)\n",
|
|
2,
|
|
func(p *Prog, callIndex int) bool {
|
|
if len(p.Calls) == 0 {
|
|
t.Fatalf("got an empty program")
|
|
}
|
|
if p.Calls[len(p.Calls)-1].Meta.Name != "pipe2" {
|
|
t.Fatalf("last call is removed")
|
|
}
|
|
return false
|
|
},
|
|
"mmap(&(0x7f0000000000)=nil, (0x1000), 0x3, 0x32, 0xffffffffffffffff, 0x0)\n" +
|
|
"sched_yield()\n" +
|
|
"pipe2(&(0x7f0000000000)={0x0, 0x0}, 0x0)\n",
|
|
},
|
|
// Remove a call.
|
|
{
|
|
"mmap(&(0x7f0000000000)=nil, (0x1000), 0x3, 0x32, 0xffffffffffffffff, 0x0)\n" +
|
|
"sched_yield()\n" +
|
|
"pipe2(&(0x7f0000000000)={0x0, 0x0}, 0x0)\n",
|
|
2,
|
|
func(p *Prog, callIndex int) bool {
|
|
// Aim at removal of sched_yield.
|
|
return len(p.Calls) == 2 && p.Calls[0].Meta.Name == "mmap" && p.Calls[1].Meta.Name == "pipe2"
|
|
},
|
|
"mmap(&(0x7f0000000000)=nil, (0x1000), 0x3, 0x32, 0xffffffffffffffff, 0x0)\n" +
|
|
"pipe2(&(0x7f0000000000)={0x0, 0x0}, 0x0)\n",
|
|
},
|
|
// Remove two dependent calls.
|
|
{
|
|
"mmap(&(0x7f0000000000)=nil, (0x1000), 0x3, 0x32, 0xffffffffffffffff, 0x0)\n" +
|
|
"pipe2(&(0x7f0000000000)={0x0, 0x0}, 0x0)\n" +
|
|
"sched_yield()\n",
|
|
2,
|
|
func(p *Prog, callIndex int) bool {
|
|
// Aim at removal of pipe2 and then mmap.
|
|
if len(p.Calls) == 2 && p.Calls[0].Meta.Name == "mmap" && p.Calls[1].Meta.Name == "sched_yield" {
|
|
return true
|
|
}
|
|
if len(p.Calls) == 1 && p.Calls[0].Meta.Name == "sched_yield" {
|
|
return true
|
|
}
|
|
return false
|
|
},
|
|
"sched_yield()\n",
|
|
},
|
|
// Remove a call and replace results.
|
|
{
|
|
"mmap(&(0x7f0000000000)=nil, (0x1000), 0x3, 0x32, 0xffffffffffffffff, 0x0)\n" +
|
|
"pipe2(&(0x7f0000000000)={[r0=]0x0, 0x0}, 0x0)\n" +
|
|
"write(r0, &(0x7f0000000000)=\"1155\", 0x2)\n" +
|
|
"sched_yield()\n",
|
|
3,
|
|
func(p *Prog, callIndex int) bool {
|
|
return p.String() == "mmap-write-sched_yield"
|
|
},
|
|
"mmap(&(0x7f0000000000)=nil, (0x1000), 0x3, 0x32, 0xffffffffffffffff, 0x0)\n" +
|
|
"write(0xffffffffffffffff, &(0x7f0000000000)=\"1155\", 0x2)\n" +
|
|
"sched_yield()\n",
|
|
},
|
|
// Remove a call and replace results.
|
|
{
|
|
"mmap(&(0x7f0000000000)=nil, (0x1000), 0x3, 0x32, 0xffffffffffffffff, 0x0)\n" +
|
|
"r0=open(&(0x7f0000000000)=\"1155\", 0x0, 0x0)\n" +
|
|
"write(r0, &(0x7f0000000000)=\"1155\", 0x2)\n" +
|
|
"sched_yield()\n",
|
|
3,
|
|
func(p *Prog, callIndex int) bool {
|
|
return p.String() == "mmap-write-sched_yield"
|
|
},
|
|
"mmap(&(0x7f0000000000)=nil, (0x1000), 0x3, 0x32, 0xffffffffffffffff, 0x0)\n" +
|
|
"write(0xffffffffffffffff, &(0x7f0000000000)=\"1155\", 0x2)\n" +
|
|
"sched_yield()\n",
|
|
},
|
|
}
|
|
for ti, test := range tests {
|
|
p, err := Deserialize([]byte(test.orig))
|
|
if err != nil {
|
|
t.Fatalf("failed to deserialize original program: %v", err)
|
|
}
|
|
p1, _ := Minimize(p, test.callIndex, test.pred)
|
|
res := p1.Serialize()
|
|
if string(res) != test.result {
|
|
t.Fatalf("minimization produced wrong result #%v\norig:\n%v\nexpect:\n%v\ngot:\n%v\n",
|
|
ti, test.orig, test.result, string(res))
|
|
}
|
|
}
|
|
}
|
|
|
|
func TestMinimizeRandom(t *testing.T) {
|
|
rs, iters := initTest(t)
|
|
for i := 0; i < iters; i++ {
|
|
p := Generate(rs, 10, nil)
|
|
Minimize(p, len(p.Calls)-1, func(p1 *Prog, callIndex int) bool {
|
|
if err := p1.validate(); err != nil {
|
|
t.Fatalf("invalid program: %v", err)
|
|
}
|
|
return false
|
|
})
|
|
Minimize(p, len(p.Calls)-1, func(p1 *Prog, callIndex int) bool {
|
|
if err := p1.validate(); err != nil {
|
|
t.Fatalf("invalid program: %v", err)
|
|
}
|
|
return true
|
|
})
|
|
}
|
|
}
|