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.

program.go 2.0KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576
  1. package bpf
  2. import (
  3. "errors"
  4. "fmt"
  5. "golang.org/x/net/bpf"
  6. )
  7. // Program is an assembled program.
  8. type Program []bpf.Instruction
  9. func (p Program) Assemble() ([]bpf.RawInstruction, error) {
  10. return bpf.Assemble(p)
  11. }
  12. // Verify the program doing bounary checks and detecting division by zero
  13. // errors.
  14. func (p Program) Verify() error {
  15. l := len(p)
  16. if l == 0 {
  17. return errors.New("bpf: no instructions in program")
  18. }
  19. for i, ins := range p {
  20. check := l - (i + 1)
  21. switch ins := ins.(type) {
  22. // Check for out-of-bounds jumps in instructions
  23. case bpf.Jump:
  24. if check <= int(ins.Skip) {
  25. return fmt.Errorf("bpf: cannot jump %d instructions; jumping past program bounds", ins.Skip)
  26. }
  27. case bpf.JumpIf:
  28. if check <= int(ins.SkipTrue) {
  29. return fmt.Errorf("bpf: cannot jump %d instructions in true case; jumping past program bounds", ins.SkipTrue)
  30. }
  31. if check <= int(ins.SkipFalse) {
  32. return fmt.Errorf("bpf: cannot jump %d instructions in false case; jumping past program bounds", ins.SkipFalse)
  33. }
  34. case bpf.JumpIfX:
  35. if check <= int(ins.SkipTrue) {
  36. return fmt.Errorf("bpf: cannot jump %d instructions in true case; jumping past program bounds", ins.SkipTrue)
  37. }
  38. if check <= int(ins.SkipFalse) {
  39. return fmt.Errorf("bpf: cannot jump %d instructions in false case; jumping past program bounds", ins.SkipFalse)
  40. }
  41. // Check for division or modulus by zero
  42. case bpf.ALUOpConstant:
  43. if ins.Val != 0 {
  44. break
  45. }
  46. switch ins.Op {
  47. case bpf.ALUOpDiv, bpf.ALUOpMod:
  48. return errors.New("cannot divide by zero using ALUOpConstant")
  49. }
  50. }
  51. }
  52. // Make sure last instruction is a return instruction
  53. switch p[l-1].(type) {
  54. case bpf.RetA, bpf.RetConstant:
  55. default:
  56. return errors.New("bpf: program must end with RetA or RetConstant")
  57. }
  58. // Though our VM works using disassembled instructions, we
  59. // attempt to assemble the input filter anyway to ensure it is compatible
  60. // with an operating system VM.
  61. _, err := bpf.Assemble(p)
  62. return err
  63. }