bpf: disasm load extension to type LoadExtension
Load extension in BPF is an overload of the load absolute
instruction with a 'negative offset'. Disassemble load
absolute instructions to load extension, if the offset
is 'negative', respectively > (0xFFFFFFFF - 0x1000).
Fixes golang/go#18469
Change-Id: I13af8f5af89ce26b13a35d2b06879dd6e1c7434e
Reviewed-on: https://go-review.googlesource.com/34771
Run-TryBot: Mikio Hara <mikioh.mikioh@gmail.com>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Mikio Hara <mikioh.mikioh@gmail.com>
diff --git a/bpf/constants.go b/bpf/constants.go
index 2c8bbab..ccf6ada 100644
--- a/bpf/constants.go
+++ b/bpf/constants.go
@@ -70,6 +70,9 @@
// Extension functions available in the Linux kernel.
const (
+ // extOffset is the negative maximum number of instructions used
+ // to load instructions by overloading the K argument.
+ extOffset = -0x1000
// ExtLen returns the length of the packet.
ExtLen Extension = 1
// ExtProto returns the packet's L3 protocol type.
diff --git a/bpf/instructions.go b/bpf/instructions.go
index 762a0f4..0bb4082 100644
--- a/bpf/instructions.go
+++ b/bpf/instructions.go
@@ -57,6 +57,9 @@
}
return LoadScratch{Dst: reg, N: int(ri.K)}
case opAddrModeAbsolute:
+ if ri.K > extOffset+0xffffffff {
+ return LoadExtension{Num: Extension(-extOffset + ri.K)}
+ }
return LoadAbsolute{Size: sz, Off: ri.K}
case opAddrModeIndirect:
return LoadIndirect{Size: sz, Off: ri.K}
@@ -259,7 +262,7 @@
if a.Num == ExtLen {
return assembleLoad(RegA, 4, opAddrModePacketLen, 0)
}
- return assembleLoad(RegA, 4, opAddrModeAbsolute, uint32(-0x1000+a.Num))
+ return assembleLoad(RegA, 4, opAddrModeAbsolute, uint32(extOffset+a.Num))
}
// StoreScratch stores register Src into scratch[N].
diff --git a/bpf/instructions_test.go b/bpf/instructions_test.go
index f9335dc..f3478eb 100644
--- a/bpf/instructions_test.go
+++ b/bpf/instructions_test.go
@@ -197,3 +197,18 @@
}
}
}
+
+func TestDisasmExtensions(t *testing.T) {
+ for _, instr := range allInstructions {
+ if extInstr, ok := instr.(LoadExtension); ok {
+ gotAsm, err := extInstr.Assemble()
+ if err != nil {
+ t.Fatalf("assembly of '%#v' failed: %s", extInstr, err)
+ }
+ got := gotAsm.Disassemble()
+ if !reflect.DeepEqual(extInstr, got) {
+ t.Errorf("program mutated by disassembly, expected: %#v, got: %#v", extInstr, got)
+ }
+ }
+ }
+}