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_scratch_test.go 4.8KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246
  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_test
  6. import (
  7. "testing"
  8. "golang.org/x/net/bpf"
  9. )
  10. func TestVMStoreScratchInvalidScratchRegisterTooSmall(t *testing.T) {
  11. _, err := testVM(t, []bpf.Instruction{
  12. bpf.StoreScratch{
  13. Src: bpf.RegA,
  14. N: -1,
  15. },
  16. bpf.RetA{},
  17. })
  18. if errStr(err) != "assembling instruction 1: invalid scratch slot -1" {
  19. t.Fatalf("unexpected error: %v", err)
  20. }
  21. }
  22. func TestVMStoreScratchInvalidScratchRegisterTooLarge(t *testing.T) {
  23. _, err := testVM(t, []bpf.Instruction{
  24. bpf.StoreScratch{
  25. Src: bpf.RegA,
  26. N: 16,
  27. },
  28. bpf.RetA{},
  29. })
  30. if errStr(err) != "assembling instruction 1: invalid scratch slot 16" {
  31. t.Fatalf("unexpected error: %v", err)
  32. }
  33. }
  34. func TestVMStoreScratchUnknownSourceRegister(t *testing.T) {
  35. _, err := testVM(t, []bpf.Instruction{
  36. bpf.StoreScratch{
  37. Src: 100,
  38. N: 0,
  39. },
  40. bpf.RetA{},
  41. })
  42. if errStr(err) != "assembling instruction 1: invalid source register 100" {
  43. t.Fatalf("unexpected error: %v", err)
  44. }
  45. }
  46. func TestVMLoadScratchInvalidScratchRegisterTooSmall(t *testing.T) {
  47. _, err := testVM(t, []bpf.Instruction{
  48. bpf.LoadScratch{
  49. Dst: bpf.RegX,
  50. N: -1,
  51. },
  52. bpf.RetA{},
  53. })
  54. if errStr(err) != "assembling instruction 1: invalid scratch slot -1" {
  55. t.Fatalf("unexpected error: %v", err)
  56. }
  57. }
  58. func TestVMLoadScratchInvalidScratchRegisterTooLarge(t *testing.T) {
  59. _, err := testVM(t, []bpf.Instruction{
  60. bpf.LoadScratch{
  61. Dst: bpf.RegX,
  62. N: 16,
  63. },
  64. bpf.RetA{},
  65. })
  66. if errStr(err) != "assembling instruction 1: invalid scratch slot 16" {
  67. t.Fatalf("unexpected error: %v", err)
  68. }
  69. }
  70. func TestVMLoadScratchUnknownDestinationRegister(t *testing.T) {
  71. _, err := testVM(t, []bpf.Instruction{
  72. bpf.LoadScratch{
  73. Dst: 100,
  74. N: 0,
  75. },
  76. bpf.RetA{},
  77. })
  78. if errStr(err) != "assembling instruction 1: invalid target register 100" {
  79. t.Fatalf("unexpected error: %v", err)
  80. }
  81. }
  82. func TestVMStoreScratchLoadScratchOneValue(t *testing.T) {
  83. vm, err := testVM(t, []bpf.Instruction{
  84. // Load byte 255
  85. bpf.LoadAbsolute{
  86. Off: 8,
  87. Size: 1,
  88. },
  89. // Copy to X and store in scratch[0]
  90. bpf.TAX{},
  91. bpf.StoreScratch{
  92. Src: bpf.RegX,
  93. N: 0,
  94. },
  95. // Load byte 1
  96. bpf.LoadAbsolute{
  97. Off: 9,
  98. Size: 1,
  99. },
  100. // Overwrite 1 with 255 from scratch[0]
  101. bpf.LoadScratch{
  102. Dst: bpf.RegA,
  103. N: 0,
  104. },
  105. // Return 255
  106. bpf.RetA{},
  107. })
  108. if err != nil {
  109. t.Fatalf("failed to load BPF program: %v", err)
  110. }
  111. out, err := vm.Run([]byte{
  112. 0xff, 0xff, 0xff, 0xff,
  113. 0xff, 0xff, 0xff, 0xff,
  114. 255, 1, 2,
  115. })
  116. if err != nil {
  117. t.Fatalf("unexpected error while running program: %v", err)
  118. }
  119. if want, got := uint32(3), out; want != got {
  120. t.Fatalf("unexpected number of output bytes:\n- want: %d\n- got: %d",
  121. want, got)
  122. }
  123. }
  124. func TestVMStoreScratchLoadScratchMultipleValues(t *testing.T) {
  125. vm, err := testVM(t, []bpf.Instruction{
  126. // Load byte 10
  127. bpf.LoadAbsolute{
  128. Off: 8,
  129. Size: 1,
  130. },
  131. // Store in scratch[0]
  132. bpf.StoreScratch{
  133. Src: bpf.RegA,
  134. N: 0,
  135. },
  136. // Load byte 20
  137. bpf.LoadAbsolute{
  138. Off: 9,
  139. Size: 1,
  140. },
  141. // Store in scratch[1]
  142. bpf.StoreScratch{
  143. Src: bpf.RegA,
  144. N: 1,
  145. },
  146. // Load byte 30
  147. bpf.LoadAbsolute{
  148. Off: 10,
  149. Size: 1,
  150. },
  151. // Store in scratch[2]
  152. bpf.StoreScratch{
  153. Src: bpf.RegA,
  154. N: 2,
  155. },
  156. // Load byte 1
  157. bpf.LoadAbsolute{
  158. Off: 11,
  159. Size: 1,
  160. },
  161. // Store in scratch[3]
  162. bpf.StoreScratch{
  163. Src: bpf.RegA,
  164. N: 3,
  165. },
  166. // Load in byte 10 to X
  167. bpf.LoadScratch{
  168. Dst: bpf.RegX,
  169. N: 0,
  170. },
  171. // Copy X -> A
  172. bpf.TXA{},
  173. // Verify value is 10
  174. bpf.JumpIf{
  175. Cond: bpf.JumpEqual,
  176. Val: 10,
  177. SkipTrue: 1,
  178. },
  179. // Fail test if incorrect
  180. bpf.RetConstant{
  181. Val: 0,
  182. },
  183. // Load in byte 20 to A
  184. bpf.LoadScratch{
  185. Dst: bpf.RegA,
  186. N: 1,
  187. },
  188. // Verify value is 20
  189. bpf.JumpIf{
  190. Cond: bpf.JumpEqual,
  191. Val: 20,
  192. SkipTrue: 1,
  193. },
  194. // Fail test if incorrect
  195. bpf.RetConstant{
  196. Val: 0,
  197. },
  198. // Load in byte 30 to A
  199. bpf.LoadScratch{
  200. Dst: bpf.RegA,
  201. N: 2,
  202. },
  203. // Verify value is 30
  204. bpf.JumpIf{
  205. Cond: bpf.JumpEqual,
  206. Val: 30,
  207. SkipTrue: 1,
  208. },
  209. // Fail test if incorrect
  210. bpf.RetConstant{
  211. Val: 0,
  212. },
  213. // Return first two bytes on success
  214. bpf.RetConstant{
  215. Val: 10,
  216. },
  217. })
  218. if err != nil {
  219. t.Fatalf("failed to load BPF program: %v", err)
  220. }
  221. out, err := vm.Run([]byte{
  222. 0xff, 0xff, 0xff, 0xff,
  223. 0xff, 0xff, 0xff, 0xff,
  224. 10, 20, 30, 1,
  225. })
  226. if err != nil {
  227. t.Fatalf("unexpected error while running program: %v", err)
  228. }
  229. if want, got := uint32(2), out; want != got {
  230. t.Fatalf("unexpected number of output bytes:\n- want: %d\n- got: %d",
  231. want, got)
  232. }
  233. }