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_load_test.go 4.9KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235
  1. package bpf_test
  2. import (
  3. "net"
  4. "testing"
  5. "golang.org/x/net/bpf"
  6. "golang.org/x/net/ipv4"
  7. )
  8. func TestVMLoadAbsoluteOffsetOutOfBounds(t *testing.T) {
  9. vm, err := testVM(t, []bpf.Instruction{
  10. bpf.LoadAbsolute{
  11. Off: 100,
  12. Size: 2,
  13. },
  14. bpf.RetA{},
  15. })
  16. if err != nil {
  17. t.Fatalf("failed to load BPF program: %v", err)
  18. }
  19. out, err := vm.Run([]byte{
  20. 0xff, 0xff, 0xff, 0xff,
  21. 0xff, 0xff, 0xff, 0xff,
  22. 0, 1, 2, 3,
  23. })
  24. if err != nil {
  25. t.Fatalf("unexpected error while running program: %v", err)
  26. }
  27. if want, got := uint32(0), out; want != got {
  28. t.Fatalf("unexpected number of output bytes:\n- want: %d\n- got: %d",
  29. want, got)
  30. }
  31. }
  32. func TestVMLoadAbsoluteOffsetPlusSizeOutOfBounds(t *testing.T) {
  33. vm, err := testVM(t, []bpf.Instruction{
  34. bpf.LoadAbsolute{
  35. Off: 8,
  36. Size: 2,
  37. },
  38. bpf.RetA{},
  39. })
  40. if err != nil {
  41. t.Fatalf("failed to load BPF program: %v", err)
  42. }
  43. out, err := vm.Run([]byte{
  44. 0xff, 0xff, 0xff, 0xff,
  45. 0xff, 0xff, 0xff, 0xff,
  46. 0,
  47. })
  48. if err != nil {
  49. t.Fatalf("unexpected error while running program: %v", err)
  50. }
  51. if want, got := uint32(0), out; want != got {
  52. t.Fatalf("unexpected number of output bytes:\n- want: %d\n- got: %d",
  53. want, got)
  54. }
  55. }
  56. func TestVMLoadAbsoluteBadInstructionSize(t *testing.T) {
  57. _, err := testVM(t, []bpf.Instruction{
  58. bpf.LoadAbsolute{
  59. Size: 5,
  60. },
  61. bpf.RetA{},
  62. })
  63. if errStr(err) != "assembling instruction 1: invalid load byte length 0" {
  64. t.Fatalf("unexpected error: %v", err)
  65. }
  66. }
  67. func TestVMLoadConstantOK(t *testing.T) {
  68. vm, err := testVM(t, []bpf.Instruction{
  69. bpf.LoadConstant{
  70. Dst: bpf.RegX,
  71. Val: 9,
  72. },
  73. bpf.TXA{},
  74. bpf.RetA{},
  75. })
  76. if err != nil {
  77. t.Fatalf("failed to load BPF program: %v", err)
  78. }
  79. out, err := vm.Run([]byte{
  80. 0xff, 0xff, 0xff, 0xff,
  81. 0xff, 0xff, 0xff, 0xff,
  82. 0,
  83. })
  84. if err != nil {
  85. t.Fatalf("unexpected error while running program: %v", err)
  86. }
  87. if want, got := uint32(1), out; want != got {
  88. t.Fatalf("unexpected number of output bytes:\n- want: %d\n- got: %d",
  89. want, got)
  90. }
  91. }
  92. func TestVMLoadIndirectOutOfBounds(t *testing.T) {
  93. vm, err := testVM(t, []bpf.Instruction{
  94. bpf.LoadIndirect{
  95. Off: 100,
  96. Size: 1,
  97. },
  98. bpf.RetA{},
  99. })
  100. if err != nil {
  101. t.Fatalf("failed to load BPF program: %v", err)
  102. }
  103. out, err := vm.Run([]byte{
  104. 0xff, 0xff, 0xff, 0xff,
  105. 0xff, 0xff, 0xff, 0xff,
  106. 0,
  107. })
  108. if err != nil {
  109. t.Fatalf("unexpected error while running program: %v", err)
  110. }
  111. if want, got := uint32(0), out; want != got {
  112. t.Fatalf("unexpected number of output bytes:\n- want: %d\n- got: %d",
  113. want, got)
  114. }
  115. }
  116. func TestVMLoadMemShiftOutOfBounds(t *testing.T) {
  117. vm, err := testVM(t, []bpf.Instruction{
  118. bpf.LoadMemShift{
  119. Off: 100,
  120. },
  121. bpf.RetA{},
  122. })
  123. if err != nil {
  124. t.Fatalf("failed to load BPF program: %v", err)
  125. }
  126. out, err := vm.Run([]byte{
  127. 0xff, 0xff, 0xff, 0xff,
  128. 0xff, 0xff, 0xff, 0xff,
  129. 0,
  130. })
  131. if err != nil {
  132. t.Fatalf("unexpected error while running program: %v", err)
  133. }
  134. if want, got := uint32(0), out; want != got {
  135. t.Fatalf("unexpected number of output bytes:\n- want: %d\n- got: %d",
  136. want, got)
  137. }
  138. }
  139. const (
  140. dhcp4Port = 53
  141. )
  142. func TestVMLoadMemShiftLoadIndirectNoResult(t *testing.T) {
  143. vm, in := testDHCPv4(t)
  144. // Append mostly empty UDP header with incorrect DHCPv4 port
  145. in = append(in, []byte{
  146. 0, 0,
  147. 0, dhcp4Port + 1,
  148. 0, 0,
  149. 0, 0,
  150. }...)
  151. out, err := vm.Run(in)
  152. if err != nil {
  153. t.Fatalf("unexpected error while running program: %v", err)
  154. }
  155. if want, got := uint32(0), out; want != got {
  156. t.Fatalf("unexpected number of output bytes:\n- want: %d\n- got: %d",
  157. want, got)
  158. }
  159. }
  160. func TestVMLoadMemShiftLoadIndirectOK(t *testing.T) {
  161. vm, in := testDHCPv4(t)
  162. // Append mostly empty UDP header with correct DHCPv4 port
  163. in = append(in, []byte{
  164. 0, 0,
  165. 0, dhcp4Port,
  166. 0, 0,
  167. 0, 0,
  168. }...)
  169. out, err := vm.Run(in)
  170. if err != nil {
  171. t.Fatalf("unexpected error while running program: %v", err)
  172. }
  173. if want, got := uint32(len(in)-8), out; want != got {
  174. t.Fatalf("unexpected number of output bytes:\n- want: %d\n- got: %d",
  175. want, got)
  176. }
  177. }
  178. func testDHCPv4(t *testing.T) (*testVirtualMachine, []byte) {
  179. // DHCPv4 test data courtesy of David Anderson:
  180. // https://github.com/google/netboot/blob/master/dhcp4/conn_linux.go#L59-L70
  181. vm, err := testVM(t, []bpf.Instruction{
  182. // Load IPv4 packet length
  183. bpf.LoadMemShift{Off: 8},
  184. // Get UDP dport
  185. bpf.LoadIndirect{Off: 8 + 2, Size: 2},
  186. // Correct dport?
  187. bpf.JumpIf{Cond: bpf.JumpEqual, Val: dhcp4Port, SkipFalse: 1},
  188. // Accept
  189. bpf.RetConstant{Val: 1500},
  190. // Ignore
  191. bpf.RetConstant{Val: 0},
  192. })
  193. if err != nil {
  194. t.Fatalf("failed to load BPF program: %v", err)
  195. }
  196. // Minimal requirements to make a valid IPv4 header
  197. h := &ipv4.Header{
  198. Len: ipv4.HeaderLen,
  199. Src: net.IPv4(192, 168, 1, 1),
  200. Dst: net.IPv4(192, 168, 1, 2),
  201. }
  202. hb, err := h.Marshal()
  203. if err != nil {
  204. t.Fatalf("failed to marshal IPv4 header: %v", err)
  205. }
  206. hb = append([]byte{
  207. 0xff, 0xff, 0xff, 0xff,
  208. 0xff, 0xff, 0xff, 0xff,
  209. }, hb...)
  210. return vm, hb
  211. }