Skip to content

Commit 08d24dc

Browse files
Merge branch 'master' into syzos-md
2 parents 5c1613a + c97f8d0 commit 08d24dc

File tree

9 files changed

+245
-52
lines changed

9 files changed

+245
-52
lines changed

dashboard/app/ai.go

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ import (
1616
"github.com/google/syzkaller/dashboard/app/aidb"
1717
"github.com/google/syzkaller/dashboard/dashapi"
1818
"github.com/google/syzkaller/pkg/aflow/ai"
19+
"github.com/google/syzkaller/pkg/report/crash"
1920
"github.com/google/syzkaller/pkg/vcs"
2021
db "google.golang.org/appengine/v2/datastore"
2122
)
@@ -322,6 +323,7 @@ func bugJobCreate(ctx context.Context, workflow string, typ ai.WorkflowType, bug
322323
Description: bug.displayTitle(),
323324
Link: fmt.Sprintf("/bug?id=%v", bug.keyHash(ctx)),
324325
Args: spanner.NullJSON{Valid: true, Value: map[string]any{
326+
"BugTitle": bug.Title,
325327
"ReproOpts": string(crash.ReproOpts),
326328
"ReproSyzID": crash.ReproSyz,
327329
"ReproCID": crash.ReproC,
@@ -423,11 +425,21 @@ const currentAIJobCheckSeq = 1
423425

424426
func workflowsForBug(bug *Bug, manual bool) map[ai.WorkflowType]bool {
425427
workflows := make(map[ai.WorkflowType]bool)
426-
if strings.HasPrefix(bug.Title, "KCSAN: data-race") {
428+
typ := crash.TitleToType(bug.Title)
429+
// UAF bugs stuck in last but one reporting.
430+
if typ.IsUAF() && len(bug.Reporting) > 1 &&
431+
bug.Reporting[len(bug.Reporting)-1].Reported.IsZero() &&
432+
!bug.Reporting[len(bug.Reporting)-2].Reported.IsZero() {
433+
workflows[ai.WorkflowModeration] = true
434+
}
435+
if typ == crash.KCSANDataRace {
427436
workflows[ai.WorkflowAssessmentKCSAN] = true
428437
}
429438
if manual {
430439
// Types we don't create automatically yet, but can be created manually.
440+
if typ.IsUAF() {
441+
workflows[ai.WorkflowModeration] = true
442+
}
431443
if bug.HeadReproLevel > dashapi.ReproLevelNone {
432444
workflows[ai.WorkflowPatching] = true
433445
}

dashboard/app/ai_test.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -124,6 +124,7 @@ func TestAIJob(t *testing.T) {
124124
require.NotEqual(t, resp.ID, "")
125125
require.Equal(t, resp.Workflow, "assessment-kcsan")
126126
require.Equal(t, resp.Args, map[string]any{
127+
"BugTitle": "KCSAN: data-race in foo / bar",
127128
"CrashReport": "report1",
128129
"KernelRepo": "repo1",
129130
"KernelCommit": "1111111111111111111111111111111111111111",

pkg/aflow/ai/ai.go

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,10 @@ package ai
66

77
type WorkflowType string
88

9+
// Note: don't change string values of these types w/o a good reason.
10+
// They are stored in the dashboard database as strings.
911
const (
1012
WorkflowPatching = WorkflowType("patching")
13+
WorkflowModeration = WorkflowType("moderation")
1114
WorkflowAssessmentKCSAN = WorkflowType("assessment-kcsan")
1215
)

pkg/aflow/flow/assessment/assessment.go

Lines changed: 0 additions & 13 deletions
This file was deleted.

pkg/aflow/flow/assessment/kcsan.go

Lines changed: 34 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -10,13 +10,22 @@ import (
1010
"github.com/google/syzkaller/pkg/aflow/tool/codesearcher"
1111
)
1212

13-
type KCSANOutputs struct {
13+
type kcsanInputs struct {
14+
CrashReport string
15+
KernelRepo string
16+
KernelCommit string
17+
KernelConfig string
18+
CodesearchToolBin string
19+
}
20+
21+
type kcsanOutputs struct {
22+
Confident bool
1423
Benign bool
1524
Explanation string
1625
}
1726

1827
func init() {
19-
aflow.Register[Inputs, KCSANOutputs](
28+
aflow.Register[kcsanInputs, kcsanOutputs](
2029
ai.WorkflowAssessmentKCSAN,
2130
"assess if a KCSAN report is about a benign race that only needs annotations or not",
2231
&aflow.Flow{
@@ -29,11 +38,12 @@ func init() {
2938
Name: "expert",
3039
Reply: "Explanation",
3140
Outputs: aflow.LLMOutputs[struct {
32-
Benign bool `jsonschema:"If the data race is benign or not."`
41+
Confident bool `jsonschema:"If you are confident in the verdict of the analysis or not."`
42+
Benign bool `jsonschema:"If the data race is benign or not."`
3343
}](),
3444
Temperature: 1,
35-
Instruction: instruction,
36-
Prompt: prompt,
45+
Instruction: kcsanInstruction,
46+
Prompt: kcsanPrompt,
3747
Tools: codesearcher.Tools,
3848
},
3949
},
@@ -42,35 +52,33 @@ func init() {
4252
)
4353
}
4454

45-
const instruction = `
46-
You are an experienced Linux kernel developer tasked with determining if the given kernel bug
47-
report is actionable or not. Actionable means that it contains enough info to root cause
48-
the underlying bug, and that the report is self-consistent and makes sense, rather than
49-
a one-off nonsensical crash induced by a previous memory corruption.
50-
51-
Use the provided tools to confirm any assumptions, what variables/fields being accessed, etc.
52-
In particular, don't make assumptions about the kernel source code,
53-
use codesearch tools to read the actual source code.
54-
55-
The bug report is a data race report from KCSAN tool.
55+
const kcsanInstruction = `
56+
You are an experienced Linux kernel developer tasked with determining if the given kernel
57+
data race is benign or not. The data race report is from KCSAN tool.
5658
It contains 2 stack traces of the memory accesses that constitute a data race.
57-
The report would be inconsistent, if the stacks point to different subsystems,
58-
or if they access different fields.
59-
The report would be non-actionable, if the underlysing data race is "benign".
60-
That is, the race is on a simple int/bool or similar field, and the accesses
61-
are not supposed to be protected by any mutual exclusion primitives.
59+
60+
A "benign" data races are on a simple int/bool variable or similar field,
61+
and the accesses are not supposed to be protected by any mutual exclusion primitives.
6262
Common examples of such "benign" data races are accesses to various flags fields,
63-
statistics counters, and similar.
64-
An actionable race is "harmful", that is can lead to corruption/crash even with
63+
statistics counters, and similar. A "benign" data race does not lead to memory corruption/crash
64+
with a conservative compiler that compiles memory accesses to primitive types
65+
effectively as atomic.
66+
67+
A non-benign (or "harmful" data race) can lead to corruption/crash even with
6568
a conservative compiler that compiles memory accesses to primitive types
6669
effectively as atomic. A common example of a "harmful" data races is race on
6770
a complex container (list/hashmap/etc), where accesses are supposed to be protected
6871
by a mutual exclusion primitive.
69-
In the final reply explain why you think the report is consistent and the data race is harmful.
72+
73+
In the final reply explain why you think the given data race is benign or is harmful.
74+
75+
Use the provided tools to confirm any assumptions, variables/fields being accessed, etc.
76+
In particular, don't make assumptions about the kernel source code,
77+
use codesearch tools to read the actual source code.
7078
`
7179

72-
const prompt = `
73-
The bug report is:
80+
const kcsanPrompt = `
81+
The data race report is:
7482
7583
{{.CrashReport}}
7684
`
Lines changed: 114 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,114 @@
1+
// Copyright 2026 syzkaller project authors. All rights reserved.
2+
// Use of this source code is governed by Apache 2 LICENSE that can be found in the LICENSE file.
3+
4+
package assessmenet
5+
6+
import (
7+
"fmt"
8+
9+
"github.com/google/syzkaller/pkg/aflow"
10+
"github.com/google/syzkaller/pkg/aflow/action/kernel"
11+
"github.com/google/syzkaller/pkg/aflow/ai"
12+
"github.com/google/syzkaller/pkg/aflow/tool/codesearcher"
13+
"github.com/google/syzkaller/pkg/report/crash"
14+
)
15+
16+
type moderationInputs struct {
17+
BugTitle string
18+
CrashReport string
19+
KernelRepo string
20+
KernelCommit string
21+
KernelConfig string
22+
CodesearchToolBin string
23+
}
24+
25+
type moderationOutputs struct {
26+
Confident bool
27+
Actionable bool
28+
Explanation string
29+
}
30+
31+
func init() {
32+
aflow.Register[moderationInputs, moderationOutputs](
33+
ai.WorkflowModeration,
34+
"assess if a bug report is consistent and actionable or not",
35+
&aflow.Flow{
36+
Root: &aflow.Pipeline{
37+
Actions: []aflow.Action{
38+
aflow.NewFuncAction("extract-crash-type", extractCrashType),
39+
kernel.Checkout,
40+
kernel.Build,
41+
codesearcher.PrepareIndex,
42+
&aflow.LLMAgent{
43+
Name: "expert",
44+
Reply: "Explanation",
45+
Outputs: aflow.LLMOutputs[struct {
46+
Confident bool `jsonschema:"If you are confident in the verdict of the analysis or not."`
47+
Actionable bool `jsonschema:"If the report is actionable or not."`
48+
}](),
49+
Temperature: 1,
50+
Instruction: moderationInstruction,
51+
Prompt: moderationPrompt,
52+
Tools: codesearcher.Tools,
53+
},
54+
},
55+
},
56+
},
57+
)
58+
}
59+
60+
const moderationInstruction = `
61+
You are an experienced Linux kernel developer tasked with determining if the given kernel bug
62+
report is actionable or not. Actionable means that it contains enough info to root cause
63+
the underlying bug, and that the report is self-consistent and makes sense, rather than
64+
e.g. a one-off nonsensical crash induced by a previous memory corruption.
65+
66+
{{if .IsUAF}}
67+
The bug report is about a use-after-free bug generated by KASAN tool.
68+
It should contain 3 stack traces: the bad memory access stack, the heap block allocation stack,
69+
and the heap block free stack. If the report does not contain 3 stacks, it's not actionable.
70+
71+
All 3 stack traces should be related to the same object type,
72+
and usually be in the same kernel subsystem (at least leaf stack frames).
73+
An example of an actionable and consistent report would be: first access stack relates
74+
to an access to a field of struct Foo, allocation/free stacks relate to allocation/free
75+
of the struct Foo.
76+
In inconsistent/nonsensical reports an access may be to a struct Foo, but allocation
77+
stack allocates a different structure in a different subsystem.
78+
Look for other suspicious signals/inconsistencies that can make this report hard to
79+
debug/understand.
80+
{{end}}
81+
82+
In the final reply explain why you think the report is self-consistent and actionable,
83+
or why it's inconsistent and/or not actionable.
84+
85+
Use the provided tools to confirm any assumptions, variables/fields being accessed, etc.
86+
In particular, don't make assumptions about the kernel source code,
87+
use codesearch tools to read the actual source code.
88+
`
89+
90+
const moderationPrompt = `
91+
The bug report is:
92+
93+
{{.CrashReport}}
94+
`
95+
96+
type extractArgs struct {
97+
BugTitle string
98+
}
99+
100+
type extractResult struct {
101+
IsUAF bool
102+
}
103+
104+
func extractCrashType(ctx *aflow.Context, args extractArgs) (extractResult, error) {
105+
var res extractResult
106+
typ := crash.TitleToType(args.BugTitle)
107+
switch {
108+
case typ.IsUAF():
109+
res.IsUAF = true
110+
default:
111+
return res, fmt.Errorf("unsupported bug type")
112+
}
113+
return res, nil
114+
}

pkg/report/crash/types.go

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -79,6 +79,10 @@ func (t Type) IsKASAN() bool {
7979
KASANUseAfterFreeRead, KASANUseAfterFreeWrite, KASANInvalidFree, KASANUnknown}, t)
8080
}
8181

82+
func (t Type) IsUAF() bool {
83+
return slices.Contains([]Type{KASANUseAfterFreeRead, KASANUseAfterFreeWrite}, t)
84+
}
85+
8286
func (t Type) IsKMSAN() bool {
8387
return slices.Contains([]Type{
8488
KMSANUninitValue, KMSANInfoLeak, KMSANUseAfterFreeRead, KMSANUnknown}, t)

tools/docker/syzbot/Dockerfile

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ RUN DEBIAN_FRONTEND=noninteractive apt-get install -y -q \
2222
util-linux dosfstools ocfs2-tools reiserfsprogs xfsprogs erofs-utils \
2323
exfatprogs gfs2-utils \
2424
# Needed for buiding gVisor.
25-
crossbuild-essential-amd64 crossbuild-essential-arm64 libbpf-dev
25+
crossbuild-essential-amd64 crossbuild-essential-arm64 libbpf-dev binutils-gold
2626
RUN test "$(uname -m)" != x86_64 && exit 0 || \
2727
DEBIAN_FRONTEND=noninteractive apt-get install -y -q \
2828
libc6-dev-i386 libc6-dev-i386-amd64-cross lib32gcc-14-dev lib32stdc++-14-dev \

0 commit comments

Comments
 (0)