Berkeley Packet Filter (BPF) assembler.
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

vm.go 2.3KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105
  1. // Copyright (c) 2019 Wijnand Modderman-Lenstra. All rights reserved.
  2. // Copyright (c) 2016 The Go Authors. All rights reserved.
  3. // Use of this source code is governed by a BSD-style
  4. // license that can be found in the LICENSE file.
  5. package bpf
  6. import (
  7. "fmt"
  8. "golang.org/x/net/bpf"
  9. )
  10. // A VM is an emulated BPF virtual machine.
  11. type VM struct {
  12. // Extensions are optional callback to load extensions. Note that the
  13. // "len" extension is always provided by the VM.
  14. Extensions map[bpf.Extension]func(*Registers) uint32
  15. program Program
  16. }
  17. func NewVM(program Program) *VM {
  18. return &VM{
  19. program: program,
  20. }
  21. }
  22. // Verify runs sanity checks on the loaded program.
  23. func (vm *VM) Verify() error {
  24. if err := vm.program.Verify(); err != nil {
  25. return err
  26. }
  27. // Verify extensions.
  28. for _, ins := range vm.program {
  29. if ext, ok := ins.(bpf.LoadExtension); ok {
  30. switch ext.Num {
  31. case bpf.ExtLen:
  32. continue
  33. default:
  34. if _, ok = vm.Extensions[ext.Num]; !ok {
  35. return fmt.Errorf("extension %d is not available", ext.Num)
  36. }
  37. }
  38. }
  39. }
  40. return nil
  41. }
  42. func (vm *VM) Run(in []byte) (verdict uint32, err error) {
  43. var (
  44. reg = new(Registers)
  45. end = uint32(len(vm.program))
  46. ok = true
  47. )
  48. for ok && reg.PC < end {
  49. debugf("ins=%s (%T) reg=%+v -> ", vm.program[reg.PC], vm.program[reg.PC], reg)
  50. switch ins := vm.program[reg.PC].(type) {
  51. case bpf.ALUOpConstant:
  52. reg.aluOpConstant(ins)
  53. case bpf.ALUOpX:
  54. ok = reg.aluOpX(ins)
  55. case bpf.Jump:
  56. reg.PC += uint32(ins.Skip)
  57. case bpf.JumpIf:
  58. reg.jumpIf(ins)
  59. case bpf.JumpIfX:
  60. reg.jumpIfX(ins)
  61. case bpf.LoadAbsolute:
  62. ok = reg.loadAbsolute(ins, in)
  63. case bpf.LoadConstant:
  64. reg.loadConstant(ins)
  65. case bpf.LoadExtension:
  66. reg.loadExtension(ins, in, vm.Extensions)
  67. case bpf.LoadIndirect:
  68. ok = reg.loadIndirect(ins, in)
  69. case bpf.LoadMemShift:
  70. ok = reg.loadMemShift(ins, in)
  71. case bpf.LoadScratch:
  72. reg.loadScratch(ins)
  73. case bpf.RetA:
  74. return reg.A, nil
  75. case bpf.RetConstant:
  76. return ins.Val, nil
  77. case bpf.StoreScratch:
  78. reg.storeScratch(ins)
  79. case bpf.TAX:
  80. reg.X = reg.A
  81. case bpf.TXA:
  82. reg.A = reg.X
  83. case bpf.NegateA:
  84. reg.A = uint32(-int32(reg.A))
  85. default:
  86. return 0, fmt.Errorf("bpf: unknown instruction at pc=%d: %T", reg.PC-1, ins)
  87. }
  88. debugf("reg=%+v\n", reg)
  89. reg.PC++
  90. }
  91. return
  92. }