Skip to content

Commit

Permalink
Support indirect read
Browse files Browse the repository at this point in the history
  • Loading branch information
jschwinger233 committed Oct 10, 2023
1 parent 7f32348 commit e993000
Show file tree
Hide file tree
Showing 3 changed files with 113 additions and 29 deletions.
102 changes: 91 additions & 11 deletions compile.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,26 +24,55 @@ const (
MAXIMUM_SNAPLEN = 262144
)

func CompileEbpf(expr string, opts cbpfc.EBPFOpts) (insts asm.Instructions, err error) {
cbpfInsts, err := CompileCbpf(expr)
type StackOffset int

const (
BpfReadKernelOffset StackOffset = -8*(iota+1) - 80
R1Offset
R2Offset
R3Offset
R4Offset
R5Offset
AvailableOffset
)

func CompileEbpf(expr string, opts Options) (insts asm.Instructions, err error) {
if expr == "__reject_all__" {
return asm.Instructions{
asm.Mov.Reg(asm.R4, asm.R5), // r4 = r5 (data = data_end)
}, nil
}
cbpfInsts, err := CompileCbpf(expr, opts.L2Skb)
if err != nil {
return
}

ebpfInsts, err := cbpfc.ToEBPF(cbpfInsts, opts)
ebpfInsts, err := cbpfc.ToEBPF(cbpfInsts, cbpfc.EBPFOpts{
PacketStart: asm.R4,
PacketEnd: asm.R5,
Result: opts.result(),
ResultLabel: opts.resultLabel(),
Working: [4]asm.Register{asm.R0, asm.R1, asm.R2, asm.R3},
LabelPrefix: opts.labelPrefix(),
StackOffset: -int(AvailableOffset),
})
if err != nil {
return
}

return adjustEbpf(ebpfInsts, opts)
}

func CompileCbpf(expr string) (insts []bpf.Instruction, err error) {
func CompileCbpf(expr string, l2 bool) (insts []bpf.Instruction, err error) {
if len(expr) == 0 {
return
}

pcap := C.pcap_open_dead(C.DLT_EN10MB, MAXIMUM_SNAPLEN)
pcapType := C.DLT_RAW
if l2 {
pcapType = C.DLT_EN10MB
}
pcap := C.pcap_open_dead(C.int(pcapType), MAXIMUM_SNAPLEN)
if pcap == nil {
return nil, fmt.Errorf("failed to pcap_open_dead: %+v\n", C.PCAP_ERROR)
}
Expand All @@ -69,13 +98,64 @@ func CompileCbpf(expr string) (insts []bpf.Instruction, err error) {
return
}

func adjustEbpf(insts asm.Instructions, opts cbpfc.EBPFOpts) (newInsts asm.Instructions, err error) {
insts = append(insts,
asm.Mov.Imm(asm.R1, 0).WithSymbol(opts.ResultLabel),
func adjustEbpf(insts asm.Instructions, opts Options) (newInsts asm.Instructions, err error) {
if !opts.DirectRead {
replaceIdx := []int{}
replaceInsts := map[int]asm.Instructions{}
for idx, inst := range insts {
if inst.OpCode.Class().IsLoad() {
replaceIdx = append(replaceIdx, idx)
replaceInsts[idx] = append(replaceInsts[idx],

asm.StoreMem(asm.RFP, int16(R1Offset), asm.R1, asm.DWord),
asm.StoreMem(asm.RFP, int16(R2Offset), asm.R2, asm.DWord),
asm.StoreMem(asm.RFP, int16(R3Offset), asm.R3, asm.DWord),

asm.Mov.Reg(asm.R1, asm.RFP),
asm.Add.Imm(asm.R1, int32(BpfReadKernelOffset)),
asm.Mov.Imm(asm.R2, int32(inst.OpCode.Size().Sizeof())),
asm.Mov.Reg(asm.R3, inst.Src),
asm.Add.Imm(asm.R3, int32(inst.Offset)),
asm.FnProbeReadKernel.Call(),

asm.LoadMem(inst.Dst, asm.RFP, int16(BpfReadKernelOffset), inst.OpCode.Size()),

asm.LoadMem(asm.R4, asm.RFP, int16(R4Offset), asm.DWord),
asm.LoadMem(asm.R5, asm.RFP, int16(R5Offset), asm.DWord),
)

restoreInsts := asm.Instructions{
asm.LoadMem(asm.R1, asm.RFP, int16(R1Offset), asm.DWord),
asm.LoadMem(asm.R2, asm.RFP, int16(R2Offset), asm.DWord),
asm.LoadMem(asm.R3, asm.RFP, int16(R3Offset), asm.DWord),
}

switch inst.Dst {
case asm.R1, asm.R2, asm.R3:
restoreInsts = append(restoreInsts[:inst.Dst-1], restoreInsts[inst.Dst:]...)
}

replaceInsts[idx] = append(replaceInsts[idx], restoreInsts...)
replaceInsts[idx][0].Metadata = inst.Metadata
}
}

for i := len(replaceIdx) - 1; i >= 0; i-- {
idx := replaceIdx[i]
insts = append(insts[:idx], append(replaceInsts[idx], insts[idx+1:]...)...)
}

insts = append([]asm.Instruction{
asm.StoreMem(asm.RFP, int16(R4Offset), asm.R4, asm.DWord),
asm.StoreMem(asm.RFP, int16(R5Offset), asm.R5, asm.DWord),
}, insts...)
}

return append(insts,
asm.Mov.Imm(asm.R1, 0).WithSymbol(opts.resultLabel()),
asm.Mov.Imm(asm.R2, 0),
asm.Mov.Imm(asm.R3, 0),
asm.Mov.Reg(asm.R4, opts.Result),
asm.Mov.Reg(asm.R4, opts.result()),
asm.Mov.Imm(asm.R5, 0),
)
return insts, nil
), nil
}
22 changes: 5 additions & 17 deletions elibpcap.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@ import (
"fmt"

"github.com/cilium/ebpf/asm"
"github.com/cloudflare/cbpfc"
)

func Inject(filter string, insns asm.Instructions, opts Options) (_ asm.Instructions, err error) {
Expand All @@ -20,28 +19,17 @@ func Inject(filter string, insns asm.Instructions, opts Options) (_ asm.Instruct
}
}
if injectIdx == -1 {
err = fmt.Errorf("Cannot find bpf2bpf: %s", opts.AtBpf2Bpf)
return
return insns, fmt.Errorf("Cannot find bpf2bpf: %s", opts.AtBpf2Bpf)
}

filterInsns, err := CompileEbpf(filter, cbpfc.EBPFOpts{
PacketStart: asm.R4,
PacketEnd: asm.R5,
Result: asm.R0,
ResultLabel: "result",
Working: [4]asm.Register{asm.R0, asm.R1, asm.R2, asm.R3},
LabelPrefix: "filter",
StackOffset: 80,
})
filterInsns, err := CompileEbpf(filter, opts)
if err != nil {
return
return insns, err
}

filterInsns[0] = filterInsns[0].WithMetadata(insns[injectIdx].Metadata)
insns[injectIdx] = insns[injectIdx].WithMetadata(asm.Metadata{})
insns = append(insns[:injectIdx],
return append(insns[:injectIdx],
append(filterInsns, insns[injectIdx:]...)...,
)

return insns, nil
), nil
}
18 changes: 17 additions & 1 deletion options.go
Original file line number Diff line number Diff line change
@@ -1,5 +1,21 @@
package elibpcap

import "github.com/cilium/ebpf/asm"

type Options struct {
AtBpf2Bpf string
AtBpf2Bpf string
DirectRead bool
L2Skb bool
}

func (o Options) resultLabel() string {
return "_result_" + o.AtBpf2Bpf
}

func (o Options) labelPrefix() string {
return "_prefix_" + o.AtBpf2Bpf
}

func (o Options) result() asm.Register {
return asm.R0
}

0 comments on commit e993000

Please sign in to comment.