aboutsummaryrefslogtreecommitdiffstats
path: root/pkg/aflow/flow/assessment/moderation.go
diff options
context:
space:
mode:
Diffstat (limited to 'pkg/aflow/flow/assessment/moderation.go')
-rw-r--r--pkg/aflow/flow/assessment/moderation.go114
1 files changed, 114 insertions, 0 deletions
diff --git a/pkg/aflow/flow/assessment/moderation.go b/pkg/aflow/flow/assessment/moderation.go
new file mode 100644
index 000000000..4b78f901c
--- /dev/null
+++ b/pkg/aflow/flow/assessment/moderation.go
@@ -0,0 +1,114 @@
+// Copyright 2026 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 assessmenet
+
+import (
+ "fmt"
+
+ "github.com/google/syzkaller/pkg/aflow"
+ "github.com/google/syzkaller/pkg/aflow/action/kernel"
+ "github.com/google/syzkaller/pkg/aflow/ai"
+ "github.com/google/syzkaller/pkg/aflow/tool/codesearcher"
+ "github.com/google/syzkaller/pkg/report/crash"
+)
+
+type moderationInputs struct {
+ BugTitle string
+ CrashReport string
+ KernelRepo string
+ KernelCommit string
+ KernelConfig string
+ CodesearchToolBin string
+}
+
+type moderationOutputs struct {
+ Confident bool
+ Actionable bool
+ Explanation string
+}
+
+func init() {
+ aflow.Register[moderationInputs, moderationOutputs](
+ ai.WorkflowModeration,
+ "assess if a bug report is consistent and actionable or not",
+ &aflow.Flow{
+ Root: &aflow.Pipeline{
+ Actions: []aflow.Action{
+ aflow.NewFuncAction("extract-crash-type", extractCrashType),
+ kernel.Checkout,
+ kernel.Build,
+ codesearcher.PrepareIndex,
+ &aflow.LLMAgent{
+ Name: "expert",
+ Reply: "Explanation",
+ Outputs: aflow.LLMOutputs[struct {
+ Confident bool `jsonschema:"If you are confident in the verdict of the analysis or not."`
+ Actionable bool `jsonschema:"If the report is actionable or not."`
+ }](),
+ Temperature: 1,
+ Instruction: moderationInstruction,
+ Prompt: moderationPrompt,
+ Tools: codesearcher.Tools,
+ },
+ },
+ },
+ },
+ )
+}
+
+const moderationInstruction = `
+You are an experienced Linux kernel developer tasked with determining if the given kernel bug
+report is actionable or not. Actionable means that it contains enough info to root cause
+the underlying bug, and that the report is self-consistent and makes sense, rather than
+e.g. a one-off nonsensical crash induced by a previous memory corruption.
+
+{{if .IsUAF}}
+The bug report is about a use-after-free bug generated by KASAN tool.
+It should contain 3 stack traces: the bad memory access stack, the heap block allocation stack,
+and the heap block free stack. If the report does not contain 3 stacks, it's not actionable.
+
+All 3 stack traces should be related to the same object type,
+and usually be in the same kernel subsystem (at least leaf stack frames).
+An example of an actionable and consistent report would be: first access stack relates
+to an access to a field of struct Foo, allocation/free stacks relate to allocation/free
+of the struct Foo.
+In inconsistent/nonsensical reports an access may be to a struct Foo, but allocation
+stack allocates a different structure in a different subsystem.
+Look for other suspicious signals/inconsistencies that can make this report hard to
+debug/understand.
+{{end}}
+
+In the final reply explain why you think the report is self-consistent and actionable,
+or why it's inconsistent and/or not actionable.
+
+Use the provided tools to confirm any assumptions, variables/fields being accessed, etc.
+In particular, don't make assumptions about the kernel source code,
+use codesearch tools to read the actual source code.
+`
+
+const moderationPrompt = `
+The bug report is:
+
+{{.CrashReport}}
+`
+
+type extractArgs struct {
+ BugTitle string
+}
+
+type extractResult struct {
+ IsUAF bool
+}
+
+func extractCrashType(ctx *aflow.Context, args extractArgs) (extractResult, error) {
+ var res extractResult
+ typ := crash.TitleToType(args.BugTitle)
+ switch {
+ case typ.IsUAF():
+ res.IsUAF = true
+ default:
+ return res, fmt.Errorf("unsupported bug type")
+ }
+ return res, nil
+}