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_registers.go 3.9KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188
  1. package bpf
  2. import (
  3. "encoding/binary"
  4. "fmt"
  5. "golang.org/x/net/bpf"
  6. )
  7. // Registers for a BPF virtual machine.
  8. type Registers struct {
  9. PC uint32 // Program Counter
  10. A uint32 // Accumulator
  11. X uint32 //
  12. R [16]uint32 // Scratch
  13. }
  14. func (reg *Registers) aluOpConstant(ins bpf.ALUOpConstant) {
  15. reg.A = reg.aluOpCommon(ins.Op, ins.Val)
  16. }
  17. func (reg *Registers) aluOpX(ins bpf.ALUOpX) bool {
  18. // Guard against division or modulus by zero by terminating
  19. // the program, as the OS BPF VM does
  20. if reg.X == 0 {
  21. switch ins.Op {
  22. case bpf.ALUOpDiv, bpf.ALUOpMod:
  23. reg.A = 0
  24. return false
  25. }
  26. }
  27. reg.A = reg.aluOpCommon(ins.Op, reg.X)
  28. return true
  29. }
  30. func (reg *Registers) aluOpCommon(op bpf.ALUOp, value uint32) uint32 {
  31. switch op {
  32. case bpf.ALUOpAdd:
  33. return reg.A + value
  34. case bpf.ALUOpSub:
  35. return reg.A - value
  36. case bpf.ALUOpMul:
  37. return reg.A * value
  38. case bpf.ALUOpDiv:
  39. return reg.A / value
  40. case bpf.ALUOpMod:
  41. return reg.A % value
  42. case bpf.ALUOpAnd:
  43. return reg.A & value
  44. case bpf.ALUOpOr:
  45. return reg.A | value
  46. case bpf.ALUOpXor:
  47. return reg.A ^ value
  48. case bpf.ALUOpShiftLeft:
  49. return reg.A << value
  50. case bpf.ALUOpShiftRight:
  51. return reg.A >> value
  52. default:
  53. return reg.A
  54. }
  55. }
  56. func (reg *Registers) jumpIf(ins bpf.JumpIf) {
  57. reg.jumpIfCommon(ins.Cond, ins.SkipTrue, ins.SkipFalse, ins.Val)
  58. }
  59. func (reg *Registers) jumpIfX(ins bpf.JumpIfX) {
  60. reg.jumpIfCommon(ins.Cond, ins.SkipTrue, ins.SkipFalse, reg.X)
  61. }
  62. func (reg *Registers) jumpIfCommon(cond bpf.JumpTest, skipTrue, skipFalse uint8, value uint32) {
  63. var ok bool
  64. switch cond {
  65. case bpf.JumpEqual:
  66. ok = reg.A == value
  67. case bpf.JumpNotEqual:
  68. ok = reg.A != value
  69. case bpf.JumpGreaterThan:
  70. ok = reg.A > value
  71. case bpf.JumpLessThan:
  72. ok = reg.A < value
  73. case bpf.JumpGreaterOrEqual:
  74. ok = reg.A >= value
  75. case bpf.JumpLessOrEqual:
  76. ok = reg.A <= value
  77. case bpf.JumpBitsSet:
  78. ok = (reg.A & value) != 0
  79. case bpf.JumpBitsNotSet:
  80. ok = (reg.A & value) == 0
  81. }
  82. if ok {
  83. reg.PC += uint32(skipTrue)
  84. } else {
  85. reg.PC += uint32(skipFalse)
  86. }
  87. }
  88. func (reg *Registers) loadAbsolute(ins bpf.LoadAbsolute, in []byte) (ok bool) {
  89. offset := int(ins.Off)
  90. size := int(ins.Size)
  91. reg.A, ok = loadCommon(in, offset, size)
  92. return
  93. }
  94. func (reg *Registers) loadConstant(ins bpf.LoadConstant) {
  95. switch ins.Dst {
  96. case bpf.RegA:
  97. reg.A = ins.Val
  98. case bpf.RegX:
  99. reg.X = ins.Val
  100. }
  101. }
  102. func (reg *Registers) loadExtension(ins bpf.LoadExtension, in []byte, ext map[bpf.Extension]func(*Registers) uint32) uint32 {
  103. switch ins.Num {
  104. case bpf.ExtLen:
  105. // Builtin
  106. return uint32(len(in))
  107. default:
  108. if ext != nil {
  109. if fn, ok := ext[ins.Num]; ok {
  110. return fn(reg)
  111. }
  112. }
  113. panic(fmt.Sprintf("unimplemented extension: %d", ins.Num))
  114. }
  115. }
  116. func (reg *Registers) loadIndirect(ins bpf.LoadIndirect, in []byte) (ok bool) {
  117. offset := int(ins.Off) + int(reg.X)
  118. size := int(ins.Size)
  119. reg.A, ok = loadCommon(in, offset, size)
  120. return
  121. }
  122. func (reg *Registers) loadMemShift(ins bpf.LoadMemShift, in []byte) (ok bool) {
  123. offset := int(ins.Off)
  124. if !inBounds(len(in), offset, 0) {
  125. return false
  126. }
  127. // Mask off high 4 bits and multiply low 4 bits by 4
  128. reg.X, ok = uint32(in[offset]&0x0f)*4, true
  129. return
  130. }
  131. func inBounds(inLen int, offset int, size int) bool {
  132. return offset+size <= inLen
  133. }
  134. func loadCommon(in []byte, offset int, size int) (uint32, bool) {
  135. if !inBounds(len(in), offset, size) {
  136. return 0, false
  137. }
  138. switch size {
  139. case 1:
  140. return uint32(in[offset]), true
  141. case 2:
  142. return uint32(binary.BigEndian.Uint16(in[offset : offset+size])), true
  143. case 4:
  144. return uint32(binary.BigEndian.Uint32(in[offset : offset+size])), true
  145. default:
  146. panic(fmt.Sprintf("invalid load size: %d", size))
  147. }
  148. }
  149. func (reg *Registers) loadScratch(ins bpf.LoadScratch) {
  150. switch ins.Dst {
  151. case bpf.RegA:
  152. reg.A = reg.R[ins.N]
  153. case bpf.RegX:
  154. reg.X = reg.R[ins.N]
  155. }
  156. }
  157. func (reg *Registers) storeScratch(ins bpf.StoreScratch) {
  158. switch ins.Src {
  159. case bpf.RegA:
  160. reg.R[ins.N] = reg.A
  161. case bpf.RegX:
  162. reg.R[ins.N] = reg.X
  163. }
  164. }