vm_load_test.go 5.6 KB

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