aboutsummaryrefslogtreecommitdiffstats
path: root/syz-cluster
diff options
context:
space:
mode:
authorAleksandr Nogikh <nogikh@google.com>2025-09-03 20:07:34 +0200
committerAleksandr Nogikh <nogikh@google.com>2025-10-01 20:14:51 +0000
commita90d2b19fb0b8b7526a51b8bbeb9b887b84503e6 (patch)
tree300c974e4a6dcc5f07ed429f65b196469496db40 /syz-cluster
parent9a988f5c94cd83b07d5b39f6c1225333c0715d8d (diff)
syz-cluster: pass fuzz config to the fuzz step as json
Instead of passing the values individually, save the FuzzConfig object as JSON and pass it as an artifact. This will simplify adding more new fields.
Diffstat (limited to 'syz-cluster')
-rw-r--r--syz-cluster/pkg/workflow/template.yaml30
-rw-r--r--syz-cluster/workflow/fuzz-step/main.go51
-rw-r--r--syz-cluster/workflow/fuzz-step/workflow-template.yaml12
3 files changed, 52 insertions, 41 deletions
diff --git a/syz-cluster/pkg/workflow/template.yaml b/syz-cluster/pkg/workflow/template.yaml
index 515adbd68..c253187e4 100644
--- a/syz-cluster/pkg/workflow/template.yaml
+++ b/syz-cluster/pkg/workflow/template.yaml
@@ -54,7 +54,7 @@ spec:
- name: element
steps:
- - name: save-base-req
- template: extract-request
+ template: convert-artifact
arguments:
parameters:
- name: data
@@ -71,12 +71,12 @@ spec:
value: "{{workflow.parameters.session-id}}"
artifacts:
- name: request
- from: "{{steps.save-base-req.outputs.artifacts.request}}"
+ from: "{{steps.save-base-req.outputs.artifacts.artifact}}"
- - name: abort-if-base-build-failed
template: exit-workflow
when: "{{=jsonpath(steps['base-build'].outputs.parameters.result, '$.success') == false}}"
- - name: save-patched-req
- template: extract-request
+ template: convert-artifact
arguments:
parameters:
- name: data
@@ -113,7 +113,7 @@ spec:
value: "{{workflow.parameters.session-id}}"
artifacts:
- name: request
- from: "{{steps.save-patched-req.outputs.artifacts.request}}"
+ from: "{{steps.save-patched-req.outputs.artifacts.artifact}}"
- - name: abort-if-patched-build-failed
template: exit-workflow
when: "{{=jsonpath(steps['patched-build'].outputs.parameters.result, '$.success') == false}}"
@@ -137,39 +137,41 @@ spec:
- - name: abort-if-patched-boot-failed
template: exit-workflow
when: "{{=jsonpath(steps['boot-test-patched'].outputs.parameters.result, '$.success') == false}}"
+ - - name: save-fuzz-config
+ template: convert-artifact
+ arguments:
+ parameters:
+ - name: data
+ value: "{{=jsonpath(inputs.parameters.element, '$')}}"
- - name: fuzz
templateRef:
name: fuzz-step-template
template: fuzz-step
arguments:
parameters:
- - name: config
- value: "{{=jsonpath(inputs.parameters.element, '$.config')}}"
- name: patched-build-id
value: "{{=jsonpath(steps['patched-build'].outputs.parameters.result, '$.build_id')}}"
- name: base-build-id
value: "{{=jsonpath(steps['base-build'].outputs.parameters.result, '$.build_id')}}"
- - name: corpus-url
- value: "{{=jsonpath(inputs.parameters.element, '$.corpus_url')}}"
- - name: skip-cover-check
- value: "{{=jsonpath(inputs.parameters.element, '$.skip_cover_check')}}"
artifacts:
- name: base-kernel
from: "{{steps.base-build.outputs.artifacts.kernel}}"
- name: patched-kernel
from: "{{steps.patched-build.outputs.artifacts.kernel}}"
- - name: extract-request
+ - name: config
+ from: "{{steps.save-fuzz-config.outputs.artifacts.artifact}}"
+ - name: convert-artifact
inputs:
parameters:
- name: data
outputs:
artifacts:
- - name: request
- path: /tmp/request.json
+ - name: artifact
+ path: /tmp/artifact
container:
image: alpine:latest
command: [sh, -c]
- args: ["echo '{{inputs.parameters.data}}' > /tmp/request.json"]
+ args: ["echo '{{inputs.parameters.data}}' > /tmp/artifact"]
- name: exit-workflow
inputs:
parameters:
diff --git a/syz-cluster/workflow/fuzz-step/main.go b/syz-cluster/workflow/fuzz-step/main.go
index 8704d1d73..fa690dc93 100644
--- a/syz-cluster/workflow/fuzz-step/main.go
+++ b/syz-cluster/workflow/fuzz-step/main.go
@@ -29,14 +29,12 @@ import (
)
var (
- flagConfig = flag.String("config", "", "syzkaller config")
- flagSession = flag.String("session", "", "session ID")
- flagBaseBuild = flag.String("base_build", "", "base build ID")
- flagPatchedBuild = flag.String("patched_build", "", "patched build ID")
- flagTime = flag.String("time", "1h", "how long to fuzz")
- flagWorkdir = flag.String("workdir", "/workdir", "base workdir path")
- flagCorpusURL = flag.String("corpus_url", "", "an URL to download corpus from")
- flagSkipCoverCheck = flag.Bool("skip_cover_check", false, "don't check whether we reached the patched code")
+ flagConfig = flag.String("config", "", "path to the fuzz config")
+ flagSession = flag.String("session", "", "session ID")
+ flagBaseBuild = flag.String("base_build", "", "base build ID")
+ flagPatchedBuild = flag.String("patched_build", "", "patched build ID")
+ flagTime = flag.String("time", "1h", "how long to fuzz")
+ flagWorkdir = flag.String("workdir", "/workdir", "base workdir path")
)
const testName = "Fuzzing"
@@ -54,6 +52,8 @@ func main() {
if !prog.GitRevisionKnown() {
log.Fatalf("the binary is built without the git revision information")
}
+
+ config := readFuzzConfig()
ctx := context.Background()
if err := reportStatus(ctx, client, api.TestRunning, nil); err != nil {
app.Fatalf("failed to report the test: %v", err)
@@ -67,7 +67,7 @@ func main() {
// the final test result back.
runCtx, cancel := context.WithTimeout(context.Background(), d)
defer cancel()
- err = run(runCtx, client, d, store)
+ err = run(runCtx, config, client, d, store)
status := api.TestPassed // TODO: what about TestFailed?
if errors.Is(err, errSkipFuzzing) {
status = api.TestSkipped
@@ -82,6 +82,21 @@ func main() {
}
}
+func readFuzzConfig() *api.FuzzConfig {
+ raw, err := os.ReadFile(*flagConfig)
+ if err != nil {
+ app.Fatalf("failed to read config: %v", err)
+ return nil
+ }
+ var req api.FuzzConfig
+ err = json.Unmarshal(raw, &req)
+ if err != nil {
+ app.Fatalf("failed to unmarshal request: %v, %s", err, raw)
+ return nil
+ }
+ return &req
+}
+
func logFinalState(store *manager.DiffFuzzerStore) {
log.Logf(0, "status at the end:\n%s", store.PlainTextDump())
@@ -98,8 +113,8 @@ func logFinalState(store *manager.DiffFuzzerStore) {
var errSkipFuzzing = errors.New("skip")
-func run(baseCtx context.Context, client *api.Client, timeout time.Duration,
- store *manager.DiffFuzzerStore) error {
+func run(baseCtx context.Context, config *api.FuzzConfig, client *api.Client,
+ timeout time.Duration, store *manager.DiffFuzzerStore) error {
series, err := client.GetSessionSeries(baseCtx, *flagSession)
if err != nil {
return fmt.Errorf("failed to query the series info: %w", err)
@@ -110,7 +125,7 @@ func run(baseCtx context.Context, client *api.Client, timeout time.Duration,
const MB = 1000000
log.EnableLogCaching(100000, 10*MB)
- base, patched, err := loadConfigs("/configs", *flagConfig, true)
+ base, patched, err := loadConfigs("/configs", config.Config, true)
if err != nil {
return fmt.Errorf("failed to load configs: %w", err)
}
@@ -125,12 +140,12 @@ func run(baseCtx context.Context, client *api.Client, timeout time.Duration,
}
manager.PatchFocusAreas(patched, series.PatchBodies(), baseSymbols.Text, patchedSymbols.Text)
- if *flagCorpusURL != "" {
- err := downloadCorpus(baseCtx, patched.Workdir, *flagCorpusURL)
+ if config.CorpusURL != "" {
+ err := downloadCorpus(baseCtx, patched.Workdir, config.CorpusURL)
if err != nil {
return fmt.Errorf("failed to download the corpus: %w", err)
} else {
- log.Logf(0, "downloaded the corpus from %s", *flagCorpusURL)
+ log.Logf(0, "downloaded the corpus from %s", config.CorpusURL)
}
}
@@ -167,7 +182,7 @@ func run(baseCtx context.Context, client *api.Client, timeout time.Duration,
BaseCrashes: baseCrashes,
Store: store,
MaxTriageTime: timeout / 2,
- FuzzToReachPatched: fuzzToReachPatched(),
+ FuzzToReachPatched: fuzzToReachPatched(config),
BaseCrashKnown: func(ctx context.Context, title string) (bool, error) {
ret, err := client.BaseFindingStatus(ctx, &api.BaseFindingInfo{
BuildID: *flagBaseBuild,
@@ -396,8 +411,8 @@ func readSectionHashes(file string) (build.SectionHashes, error) {
return data, nil
}
-func fuzzToReachPatched() time.Duration {
- if *flagSkipCoverCheck {
+func fuzzToReachPatched(config *api.FuzzConfig) time.Duration {
+ if config.SkipCoverCheck {
return 0
}
// Allow up to 30 minutes after the corpus triage to reach the patched code.
diff --git a/syz-cluster/workflow/fuzz-step/workflow-template.yaml b/syz-cluster/workflow/fuzz-step/workflow-template.yaml
index 460659a61..5cf77e6b4 100644
--- a/syz-cluster/workflow/fuzz-step/workflow-template.yaml
+++ b/syz-cluster/workflow/fuzz-step/workflow-template.yaml
@@ -10,33 +10,27 @@ spec:
- name: fuzz-step
inputs:
parameters:
- - name: config
- value: ""
- name: base-build-id
value: ""
- name: patched-build-id
value: ""
- - name: corpus-url
- value: ""
- - name: skip-cover-check
- value: "false"
artifacts:
- name: base-kernel
path: /base
- name: patched-kernel
path: /patched
+ - name: config
+ path: /tmp/config.json
timeout: 4h
container:
image: ${IMAGE_PREFIX}fuzz-step:${IMAGE_TAG}
imagePullPolicy: IfNotPresent
command: ["/bin/fuzz-step"]
args: [
- "--config", "{{inputs.parameters.config}}",
+ "--config", "/tmp/config.json",
"--session", "{{workflow.parameters.session-id}}",
"--base_build", "{{inputs.parameters.base-build-id}}",
"--patched_build", "{{inputs.parameters.patched-build-id}}",
- "--corpus_url", "{{inputs.parameters.corpus-url}}",
- "--skip_cover_check={{inputs.parameters.skip-cover-check}}",
"--time", "3h",
"--workdir", "/workdir",
"--vv", "1"