diff options
| author | Ethan Graham <ethangraham@google.com> | 2025-09-19 15:44:59 +0000 |
|---|---|---|
| committer | Aleksandr Nogikh <nogikh@google.com> | 2025-09-22 09:11:54 +0000 |
| commit | 490f32238051336d5a498cbc3ecc47140052b502 (patch) | |
| tree | b2baa30374181952a39000373a0cf1c5952d21fe /prog/encodingexec.go | |
| parent | c9f0a99247f6d9a6df877720609cbce3dca73b55 (diff) | |
kfuzztest: introduce syz_kfuzztest_run pseudo-syscall
Add syz_kfuzztest_run pseudo-syscall, KFuzzTest attribute, and encoding
logic.
KFuzzTest targets, which are invoked in the executor with the new
syz_kfuzztest_run pseudo-syscall, require specialized encoding. To
differentiate KFuzzTest calls from standard syzkaller calls, we
introduce a new attribute called KFuzzTest or "kfuzz_test" in syzkaller
descriptions that can be used to annotate calls.
Signed-off-by: Ethan Graham <ethangraham@google.com>
Diffstat (limited to 'prog/encodingexec.go')
| -rw-r--r-- | prog/encodingexec.go | 59 |
1 files changed, 59 insertions, 0 deletions
diff --git a/prog/encodingexec.go b/prog/encodingexec.go index fb8e5fbaf..f3b48924c 100644 --- a/prog/encodingexec.go +++ b/prog/encodingexec.go @@ -88,6 +88,14 @@ func (p *Prog) SerializeForExec() ([]byte, error) { } func (w *execContext) serializeCall(c *Call) { + // We introduce special serialization logic for kfuzztest targets, which + // require special handling due to their use of relocation tables to copy + // entire blobs of data into the kenrel. + if c.Meta.Attrs.KFuzzTest { + w.serializeKFuzzTestCall(c) + return + } + // Calculate arg offsets within structs. // Generate copyin instructions that fill in data into pointer arguments. w.writeCopyin(c) @@ -119,6 +127,57 @@ func (w *execContext) serializeCall(c *Call) { w.writeCopyout(c) } +// KFuzzTest targets require special handling due to their use of relocation +// tables for serializing all data (including pointed-to data) into a +// continuous blob that can be passed into the kernel. +func (w *execContext) serializeKFuzzTestCall(c *Call) { + if !c.Meta.Attrs.KFuzzTest { + // This is a specialized function that shouldn't be called on anything + // other than an instance of a syz_kfuzztest_run$* syscall + panic("serializeKFuzzTestCall called on an invalid syscall") + } + + // Write the initial string argument (test name) normally. + w.writeCopyin(&Call{Meta: c.Meta, Args: []Arg{c.Args[0]}}) + + // Args[1] is the second argument to syz_kfuzztest_run, which is a pointer + // to some struct input. This is the data that must be flattened and sent + // to the fuzzing driver with a relocation table. + dataArg := c.Args[1].(*PointerArg) + finalBlob := MarshallKFuzztestArg(dataArg.Res) + + // Reuse the memory address that was pre-allocated for the original struct + // argument. This avoids needing to hook into the memory allocation which + // is done at a higher level than the serialization. This relies on the + // original buffer being large enough + blobAddress := w.target.PhysicalAddr(dataArg) - w.target.DataOffset + + // Write the entire marshalled blob as a raw byte array. + w.write(execInstrCopyin) + w.write(blobAddress) + w.write(execArgData) + w.write(uint64(len(finalBlob))) + w.buf = append(w.buf, finalBlob...) + + // Update the value of the length arg which should now match the length of + // the byte array that we created. Previously, it contained the bytesize + // of the struct argument passed into the pseudo-syscall. + lenArg := c.Args[2].(*ConstArg) + lenArg.Val = uint64(len(finalBlob)) + + // Generate the final syscall instruction with the update arguments. + kFuzzTestRunID, err := w.target.KFuzzTestRunID() + if err != nil { + panic(err) + } + w.write(uint64(kFuzzTestRunID)) + w.write(ExecNoCopyout) + w.write(uint64(len(c.Args))) + for _, arg := range c.Args { + w.writeArg(arg) + } +} + type execContext struct { target *Target buf []byte |
