You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
When looking at a reproducer such as https://syzkaller.appspot.com/text?tag=ReproSyz&x=112d9a08e80000 the bpf$PROG_LOAD syscall is used with a [@ANYBLOB="18000000000000000000000000000000611200000000000095000000000000001383[...]"] argument that contains BPF bytecode.
It would be cool to extract the content of that buffer and pass it through objdump to extract the BPF instructions and upload them as assets to the dashboard, a bit like what we do for mounted file systems and fsck reports already.
This is not super high priority for me so I don't really intend to work on it but I wanted to write the idea down somewhere... :)
Also, here is a small poc that can be slapped into prog/bpf_disas_test.go. This is hacked together but goes as far as my curiosity could lead me:
// Copyright 2024 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 prog_test
import (
"fmt"
"os"
"os/exec"
"strings"
"testing"
"github.com/google/syzkaller/prog"
"github.com/google/syzkaller/sys/targets"
)
func Disassemble(insn []byte) (string, error) {
tempFile, err := os.CreateTemp("", "*.bpf")
if err != nil {
return "", fmt.Errorf("failed to create temporary file: %w", err)
}
defer os.Remove(tempFile.Name())
if _, err := tempFile.Write(insn); err != nil {
return "", fmt.Errorf("failed to write bytecode to temporary file: %w", err)
}
if err := tempFile.Close(); err != nil {
return "", fmt.Errorf("failed to close temporary file: %w", err)
}
cmd := exec.Command(
"/usr/lib/bpf/bin/objdump", // Distributed by the binutils-bpf debian package
"-D",
"-b", "binary",
"-m", "bpf",
tempFile.Name(),
)
output, err := cmd.CombinedOutput()
if err != nil {
return "", fmt.Errorf("error running llvm-objdump: %w, output: %s", err, output)
}
// Strip off the header and last line
lines := strings.Split(string(output), "\n")
strippedOutput := ""
if len(lines) > 7 {
strippedOutput = strings.Join(lines[7:len(lines)-1], "\n")
}
return strippedOutput, nil
}
func TestBpfDisas(t *testing.T) {
target, err := prog.GetTarget(targets.Linux, targets.AMD64)
if err != nil {
t.Fatal(err)
}
tests := []struct {
prog string
disas string
}{
{
`r0 = bpf$PROG_LOAD(0x5, &(0x7f0000000080)={0x9, 0x4, &(0x7f0000000700)=ANY=[@ANYBLOB="18000000000000000000000000000000611200000000000095000000000000001383096e16281fd43e588cf7a1e65f316e5e5600f1fb642cb352b9d4c50ae8366e5cadf97f4e52fdb37bdab01f9f6cc297b10500c98ea973fbaf38f9d47c5702c2bd9ebf0134b54dbee7458404277462d8ac80053e629d28aa5b25e324fd54d237d7921ff7b52f78ad9692619113594630a9eb6490c61332499f4861a57120ea351e61ca79b452a2bffd133c9ce1b4049b537a6310d0ee13db80ad6553ed19a04679d0d66bf61277501f370105113bd565ae2e766f9a79e314ecbc4000b4702ecfcaed9cb384edf20b1d3e7011bd384577a5a78efdd8687e0574465e490aa62e217fa49e4167d7edcd030c20937155d065ee7bb686bffcf28ec73d58a1d795c358c5aee99cae4c959ba2b9a78b4e231c46f8030523faf5b79ef84c5201a69d776df2041ae3d19a3d03fb1f2913fdd3fef24c94f1e224f872c1bebc0a7622231b2be88508a13a5b74e417cdad2076dd0ccdf44daf7404337f84783856b8582065669a46c1d570cdf4d6ce259d39fdc6bc4f066eb27ba18fc0110ebf3eb081d09b8587c911260c2ca2f49825e10b20733735ec2f4a80308c92dac2cac1608cbd739d385703e2933fda0dde43f3270d7170a7f5ce1dad0a2ae4691cc8487e113b89df89fd1d3c51723d79966e8c2eae12cf2dcfa7c09b15de3f494c5bfc35a8ac8124fb66066b2b3c7db6585b2fe802e86d2794d885c779de4ab1a0999fcedaea0b0497927b536e120212681673509f2aa7ad0875d5be6fa5f5812dd7966978f435924026737b78156906c3faf9e84f0cfb70a8d326262ce7ceadf4f95a7afb2bdf8250af753f32"], &(0x7f0000000100)='GPL\x00'}, 0x70)`,
` 0: 18 00 00 00 00 00 00 00 lddw %r0,0
8: 00 00 00 00 00 00 00 00
10: 61 12 00 00 00 00 00 00 ldxw %r1,[%r2+0]
18: 95 00 00 00 00 00 00 00 exit`,
},
}
for i, test := range tests {
t.Run(fmt.Sprint(i), func(t *testing.T) {
p, err := target.Deserialize([]byte(test.prog), prog.NonStrict)
if err != nil {
t.Fatalf("failed to deserialize prog: %v", err)
}
structPtrArg := p.Calls[0].Args[1].(*prog.PointerArg)
structGrpArg := structPtrArg.Res.(*prog.GroupArg)
insnCntArg := structGrpArg.Inner[1].(*prog.ConstArg)
insnCnt := int(insnCntArg.Val)
insnPtrArg := structGrpArg.Inner[2].(*prog.PointerArg)
insnGrpArg := insnPtrArg.Res.(*prog.GroupArg)
insnUnionArg := insnGrpArg.Inner[0].(*prog.UnionArg)
insnArg := insnUnionArg.Option.(*prog.DataArg)
insn := insnArg.Data()[:insnCnt*8]
disas, err := Disassemble(insn)
if disas != test.disas {
t.Fatalf("bad disas result:\n%v\nwant:\n%v", disas, test.disas)
}
})
}
}
The text was updated successfully, but these errors were encountered:
When looking at a reproducer such as https://syzkaller.appspot.com/text?tag=ReproSyz&x=112d9a08e80000 the
bpf$PROG_LOAD
syscall is used with a[@ANYBLOB="18000000000000000000000000000000611200000000000095000000000000001383[...]"]
argument that contains BPF bytecode.It would be cool to extract the content of that buffer and pass it through
objdump
to extract the BPF instructions and upload them as assets to the dashboard, a bit like what we do for mounted file systems and fsck reports already.This is not super high priority for me so I don't really intend to work on it but I wanted to write the idea down somewhere... :)
Also, here is a small poc that can be slapped into
prog/bpf_disas_test.go
. This is hacked together but goes as far as my curiosity could lead me:The text was updated successfully, but these errors were encountered: