aboutsummaryrefslogtreecommitdiffstats
path: root/pkg/fuzzer/queue
diff options
context:
space:
mode:
authorDmitry Vyukov <dvyukov@google.com>2024-11-27 17:23:09 +0100
committerDmitry Vyukov <dvyukov@google.com>2024-12-11 15:22:17 +0000
commit299ee674e6c124a35f1cf258df4f0f3c6e1db1f3 (patch)
tree416b515e959a1d0a64a9516b1524a062ae63ba7d /pkg/fuzzer/queue
parentff949d2512c5ac33d0407d26d80f1df77b2de0e7 (diff)
executor: query globs in the test program context
We query globs for 2 reasons: 1. Expand glob types in syscall descriptions. 2. Dynamic file probing for automatic descriptions generation. In both of these contexts are are interested in files that will be present during test program execution (rather than normal unsandboxed execution). For example, some files may not be accessible to test programs after pivot root. On the other hand, we create and link some additional files for the test program that don't normally exist. Add a new request type for querying of globs that are executed in the test program context.
Diffstat (limited to 'pkg/fuzzer/queue')
-rw-r--r--pkg/fuzzer/queue/queue.go67
-rw-r--r--pkg/fuzzer/queue/queue_test.go7
2 files changed, 63 insertions, 11 deletions
diff --git a/pkg/fuzzer/queue/queue.go b/pkg/fuzzer/queue/queue.go
index 1d25cbc8a..05d9cfbed 100644
--- a/pkg/fuzzer/queue/queue.go
+++ b/pkg/fuzzer/queue/queue.go
@@ -9,6 +9,7 @@ import (
"encoding/gob"
"fmt"
"math/rand"
+ "strings"
"sync"
"sync/atomic"
@@ -20,8 +21,15 @@ import (
)
type Request struct {
- Prog *prog.Prog
- ExecOpts flatrpc.ExecOpts
+ // Type of the request.
+ // RequestTypeProgram executes Prog, and is used by most requests (also the default zero value).
+ // RequestTypeBinary executes binary with file name stored in Data.
+ // RequestTypeGlob expands glob pattern stored in Data.
+ Type flatrpc.RequestType
+ ExecOpts flatrpc.ExecOpts
+ Prog *prog.Prog // for RequestTypeProgram
+ BinaryFile string // for RequestTypeBinary
+ GlobPattern string // for RequestTypeGlob
// If specified, the resulting signal for call SignalFilterCall
// will include subset of it even if it's not new.
@@ -36,9 +44,6 @@ type Request struct {
// This stat will be incremented on request completion.
Stat *stat.Val
- // Options needed by runtest.
- BinaryFile string // If set, it's executed instead of Prog.
-
// Important requests will be retried even from crashed VMs.
Important bool
@@ -123,20 +128,51 @@ func (r *Request) Validate() error {
if (collectComps) && (collectSignal || collectCover) {
return fmt.Errorf("hint collection is mutually exclusive with signal/coverage")
}
- sandboxes := flatrpc.ExecEnvSandboxNone | flatrpc.ExecEnvSandboxSetuid |
- flatrpc.ExecEnvSandboxNamespace | flatrpc.ExecEnvSandboxAndroid
- if r.BinaryFile == "" && r.ExecOpts.EnvFlags&sandboxes == 0 {
- return fmt.Errorf("no sandboxes set")
+ switch r.Type {
+ case flatrpc.RequestTypeProgram:
+ if r.Prog == nil {
+ return fmt.Errorf("program is not set")
+ }
+ sandboxes := flatrpc.ExecEnvSandboxNone | flatrpc.ExecEnvSandboxSetuid |
+ flatrpc.ExecEnvSandboxNamespace | flatrpc.ExecEnvSandboxAndroid
+ if r.ExecOpts.EnvFlags&sandboxes == 0 {
+ return fmt.Errorf("no sandboxes set")
+ }
+ case flatrpc.RequestTypeBinary:
+ if r.BinaryFile == "" {
+ return fmt.Errorf("binary file name is not set")
+ }
+ case flatrpc.RequestTypeGlob:
+ if r.GlobPattern == "" {
+ return fmt.Errorf("glob pattern is not set")
+ }
+ default:
+ return fmt.Errorf("unknown request type")
}
return nil
}
func (r *Request) hash() hash.Sig {
buf := new(bytes.Buffer)
- if err := gob.NewEncoder(buf).Encode(r.ExecOpts); err != nil {
+ enc := gob.NewEncoder(buf)
+ if err := enc.Encode(r.Type); err != nil {
+ panic(err)
+ }
+ if err := enc.Encode(r.ExecOpts); err != nil {
panic(err)
}
- return hash.Hash(r.Prog.Serialize(), buf.Bytes())
+ var data []byte
+ switch r.Type {
+ case flatrpc.RequestTypeProgram:
+ data = r.Prog.Serialize()
+ case flatrpc.RequestTypeBinary:
+ data = []byte(r.BinaryFile)
+ case flatrpc.RequestTypeGlob:
+ data = []byte(r.GlobPattern)
+ default:
+ panic("unknown request type")
+ }
+ return hash.Hash(data, buf.Bytes())
}
func (r *Request) initChannel() {
@@ -172,6 +208,15 @@ func (r *Result) Stop() bool {
}
}
+// Globs returns result of RequestTypeGlob.
+func (r *Result) GlobFiles() []string {
+ out := strings.Trim(string(r.Output), "\000")
+ if out == "" {
+ return nil
+ }
+ return strings.Split(out, "\000")
+}
+
type Status int
const (
diff --git a/pkg/fuzzer/queue/queue_test.go b/pkg/fuzzer/queue/queue_test.go
index 5b6a03ed0..d1909e50c 100644
--- a/pkg/fuzzer/queue/queue_test.go
+++ b/pkg/fuzzer/queue/queue_test.go
@@ -43,3 +43,10 @@ func TestPrioQueue(t *testing.T) {
assert.Equal(t, req4, pq.Next())
assert.Equal(t, req3, pq.Next())
}
+
+func TestGlobFiles(t *testing.T) {
+ r := &Result{}
+ assert.Equal(t, r.GlobFiles(), []string(nil))
+ r.Output = []byte{'a', 'b', 0, 'c', 0}
+ assert.Equal(t, r.GlobFiles(), []string{"ab", "c"})
+}