Skip to content

Commit e993000

Browse files
committed
Support indirect read
1 parent 7f32348 commit e993000

File tree

3 files changed

+113
-29
lines changed

3 files changed

+113
-29
lines changed

compile.go

Lines changed: 91 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -24,26 +24,55 @@ const (
2424
MAXIMUM_SNAPLEN = 262144
2525
)
2626

27-
func CompileEbpf(expr string, opts cbpfc.EBPFOpts) (insts asm.Instructions, err error) {
28-
cbpfInsts, err := CompileCbpf(expr)
27+
type StackOffset int
28+
29+
const (
30+
BpfReadKernelOffset StackOffset = -8*(iota+1) - 80
31+
R1Offset
32+
R2Offset
33+
R3Offset
34+
R4Offset
35+
R5Offset
36+
AvailableOffset
37+
)
38+
39+
func CompileEbpf(expr string, opts Options) (insts asm.Instructions, err error) {
40+
if expr == "__reject_all__" {
41+
return asm.Instructions{
42+
asm.Mov.Reg(asm.R4, asm.R5), // r4 = r5 (data = data_end)
43+
}, nil
44+
}
45+
cbpfInsts, err := CompileCbpf(expr, opts.L2Skb)
2946
if err != nil {
3047
return
3148
}
3249

33-
ebpfInsts, err := cbpfc.ToEBPF(cbpfInsts, opts)
50+
ebpfInsts, err := cbpfc.ToEBPF(cbpfInsts, cbpfc.EBPFOpts{
51+
PacketStart: asm.R4,
52+
PacketEnd: asm.R5,
53+
Result: opts.result(),
54+
ResultLabel: opts.resultLabel(),
55+
Working: [4]asm.Register{asm.R0, asm.R1, asm.R2, asm.R3},
56+
LabelPrefix: opts.labelPrefix(),
57+
StackOffset: -int(AvailableOffset),
58+
})
3459
if err != nil {
3560
return
3661
}
3762

3863
return adjustEbpf(ebpfInsts, opts)
3964
}
4065

41-
func CompileCbpf(expr string) (insts []bpf.Instruction, err error) {
66+
func CompileCbpf(expr string, l2 bool) (insts []bpf.Instruction, err error) {
4267
if len(expr) == 0 {
4368
return
4469
}
4570

46-
pcap := C.pcap_open_dead(C.DLT_EN10MB, MAXIMUM_SNAPLEN)
71+
pcapType := C.DLT_RAW
72+
if l2 {
73+
pcapType = C.DLT_EN10MB
74+
}
75+
pcap := C.pcap_open_dead(C.int(pcapType), MAXIMUM_SNAPLEN)
4776
if pcap == nil {
4877
return nil, fmt.Errorf("failed to pcap_open_dead: %+v\n", C.PCAP_ERROR)
4978
}
@@ -69,13 +98,64 @@ func CompileCbpf(expr string) (insts []bpf.Instruction, err error) {
6998
return
7099
}
71100

72-
func adjustEbpf(insts asm.Instructions, opts cbpfc.EBPFOpts) (newInsts asm.Instructions, err error) {
73-
insts = append(insts,
74-
asm.Mov.Imm(asm.R1, 0).WithSymbol(opts.ResultLabel),
101+
func adjustEbpf(insts asm.Instructions, opts Options) (newInsts asm.Instructions, err error) {
102+
if !opts.DirectRead {
103+
replaceIdx := []int{}
104+
replaceInsts := map[int]asm.Instructions{}
105+
for idx, inst := range insts {
106+
if inst.OpCode.Class().IsLoad() {
107+
replaceIdx = append(replaceIdx, idx)
108+
replaceInsts[idx] = append(replaceInsts[idx],
109+
110+
asm.StoreMem(asm.RFP, int16(R1Offset), asm.R1, asm.DWord),
111+
asm.StoreMem(asm.RFP, int16(R2Offset), asm.R2, asm.DWord),
112+
asm.StoreMem(asm.RFP, int16(R3Offset), asm.R3, asm.DWord),
113+
114+
asm.Mov.Reg(asm.R1, asm.RFP),
115+
asm.Add.Imm(asm.R1, int32(BpfReadKernelOffset)),
116+
asm.Mov.Imm(asm.R2, int32(inst.OpCode.Size().Sizeof())),
117+
asm.Mov.Reg(asm.R3, inst.Src),
118+
asm.Add.Imm(asm.R3, int32(inst.Offset)),
119+
asm.FnProbeReadKernel.Call(),
120+
121+
asm.LoadMem(inst.Dst, asm.RFP, int16(BpfReadKernelOffset), inst.OpCode.Size()),
122+
123+
asm.LoadMem(asm.R4, asm.RFP, int16(R4Offset), asm.DWord),
124+
asm.LoadMem(asm.R5, asm.RFP, int16(R5Offset), asm.DWord),
125+
)
126+
127+
restoreInsts := asm.Instructions{
128+
asm.LoadMem(asm.R1, asm.RFP, int16(R1Offset), asm.DWord),
129+
asm.LoadMem(asm.R2, asm.RFP, int16(R2Offset), asm.DWord),
130+
asm.LoadMem(asm.R3, asm.RFP, int16(R3Offset), asm.DWord),
131+
}
132+
133+
switch inst.Dst {
134+
case asm.R1, asm.R2, asm.R3:
135+
restoreInsts = append(restoreInsts[:inst.Dst-1], restoreInsts[inst.Dst:]...)
136+
}
137+
138+
replaceInsts[idx] = append(replaceInsts[idx], restoreInsts...)
139+
replaceInsts[idx][0].Metadata = inst.Metadata
140+
}
141+
}
142+
143+
for i := len(replaceIdx) - 1; i >= 0; i-- {
144+
idx := replaceIdx[i]
145+
insts = append(insts[:idx], append(replaceInsts[idx], insts[idx+1:]...)...)
146+
}
147+
148+
insts = append([]asm.Instruction{
149+
asm.StoreMem(asm.RFP, int16(R4Offset), asm.R4, asm.DWord),
150+
asm.StoreMem(asm.RFP, int16(R5Offset), asm.R5, asm.DWord),
151+
}, insts...)
152+
}
153+
154+
return append(insts,
155+
asm.Mov.Imm(asm.R1, 0).WithSymbol(opts.resultLabel()),
75156
asm.Mov.Imm(asm.R2, 0),
76157
asm.Mov.Imm(asm.R3, 0),
77-
asm.Mov.Reg(asm.R4, opts.Result),
158+
asm.Mov.Reg(asm.R4, opts.result()),
78159
asm.Mov.Imm(asm.R5, 0),
79-
)
80-
return insts, nil
160+
), nil
81161
}

elibpcap.go

Lines changed: 5 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,6 @@ import (
44
"fmt"
55

66
"github.com/cilium/ebpf/asm"
7-
"github.com/cloudflare/cbpfc"
87
)
98

109
func Inject(filter string, insns asm.Instructions, opts Options) (_ asm.Instructions, err error) {
@@ -20,28 +19,17 @@ func Inject(filter string, insns asm.Instructions, opts Options) (_ asm.Instruct
2019
}
2120
}
2221
if injectIdx == -1 {
23-
err = fmt.Errorf("Cannot find bpf2bpf: %s", opts.AtBpf2Bpf)
24-
return
22+
return insns, fmt.Errorf("Cannot find bpf2bpf: %s", opts.AtBpf2Bpf)
2523
}
2624

27-
filterInsns, err := CompileEbpf(filter, cbpfc.EBPFOpts{
28-
PacketStart: asm.R4,
29-
PacketEnd: asm.R5,
30-
Result: asm.R0,
31-
ResultLabel: "result",
32-
Working: [4]asm.Register{asm.R0, asm.R1, asm.R2, asm.R3},
33-
LabelPrefix: "filter",
34-
StackOffset: 80,
35-
})
25+
filterInsns, err := CompileEbpf(filter, opts)
3626
if err != nil {
37-
return
27+
return insns, err
3828
}
3929

4030
filterInsns[0] = filterInsns[0].WithMetadata(insns[injectIdx].Metadata)
4131
insns[injectIdx] = insns[injectIdx].WithMetadata(asm.Metadata{})
42-
insns = append(insns[:injectIdx],
32+
return append(insns[:injectIdx],
4333
append(filterInsns, insns[injectIdx:]...)...,
44-
)
45-
46-
return insns, nil
34+
), nil
4735
}

options.go

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,21 @@
11
package elibpcap
22

3+
import "github.com/cilium/ebpf/asm"
4+
35
type Options struct {
4-
AtBpf2Bpf string
6+
AtBpf2Bpf string
7+
DirectRead bool
8+
L2Skb bool
9+
}
10+
11+
func (o Options) resultLabel() string {
12+
return "_result_" + o.AtBpf2Bpf
13+
}
14+
15+
func (o Options) labelPrefix() string {
16+
return "_prefix_" + o.AtBpf2Bpf
17+
}
18+
19+
func (o Options) result() asm.Register {
20+
return asm.R0
521
}

0 commit comments

Comments
 (0)