Skip to content

pkg/fuzzer/job.go: triageJob.minimize not starting with cloned program from triageJob.handleCall #5878

@BitsByWill

Description

@BitsByWill

Describe the bug
I originally sent this on the mailing list but it didn't seem to make it through moderation.

I'm experimenting with augmenting Syzkaller signal/coverage data with additional feedback metrics based upon static analysis and noticed a quirk about triageJob.minimize and triageJob.handleCall. At

p := job.p.Clone()
from triageJob.run, the program for handleCall is cloned from job.p, yet minimize still uses the original job.p here
p, call := prog.Minimize(job.p, call, mode, func(p1 *prog.Prog, call1 int) bool {
.

Shouldn't this use the newly cloned program p? Otherwise, if no minimizations occur from prog/minimization.go, minimize returns the original job.p.

I don't believe this causes any issues currently, but this logic doesn't seem to match the intent of the Clone.

To Reproduce

I noticed this because my experiments added some additional post-processing data to Prog as I assumed uniqueness at this point, and a race condition popped up between two handleCall goroutines that processed programs without successful minimizations (hence the same job.p)

Expected behavior
The intent of clone should be matched and minimize should use the cloned program rather than the Prog pointer from the job struct.

Additional context
Here is a sample fix:

diff --git a/pkg/fuzzer/job.go b/pkg/fuzzer/job.go
index 7b06bc97f..e0c2e9772 100644
--- a/pkg/fuzzer/job.go
+++ b/pkg/fuzzer/job.go
@@ -168,7 +168,7 @@ func (job *triageJob) handleCall(call int, info *triageCall) {

        p := job.p.Clone()
        if job.flags&ProgMinimized == 0 {
-               p, call = job.minimize(call, info)
+               p, call = job.minimize(p, call, info)
                if p == nil {
                        return
                }
@@ -340,7 +340,7 @@ func (job *triageJob) stopDeflake(run, needRuns int, noNewSignal bool) bool {
        return false
 }

-func (job *triageJob) minimize(call int, info *triageCall) (*prog.Prog, int) {
+func (job *triageJob) minimize(p *prog.Prog, call int, info *triageCall) (*prog.Prog, int) {
        job.info.Logf("[call #%d] minimize started", call)
        minimizeAttempts := 3
        if job.fuzzer.Config.Snapshot {
@@ -351,7 +351,7 @@ func (job *triageJob) minimize(call int, info *triageCall) (*prog.Prog, int) {
        if job.fuzzer.Config.PatchTest {
                mode = prog.MinimizeCallsOnly
        }
-       p, call := prog.Minimize(job.p, call, mode, func(p1 *prog.Prog, call1 int) bool {
+       p, call = prog.Minimize(p, call, mode, func(p1 *prog.Prog, call1 int) bool {
                if stop {
                        return false
                }

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugBug in the syzkaller project (e.g. a crash or misbehavior).

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions