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.

496 lines
9.4KB

  1. package bpf_test
  2. import (
  3. "testing"
  4. "golang.org/x/net/bpf"
  5. )
  6. func TestVMALUOpAdd(t *testing.T) {
  7. vm, err := testVM(t, []bpf.Instruction{
  8. bpf.LoadAbsolute{
  9. Off: 8,
  10. Size: 1,
  11. },
  12. bpf.ALUOpConstant{
  13. Op: bpf.ALUOpAdd,
  14. Val: 3,
  15. },
  16. bpf.RetA{},
  17. })
  18. if err != nil {
  19. t.Fatalf("failed to load BPF program: %v", err)
  20. }
  21. out, err := vm.Run([]byte{
  22. 0xff, 0xff, 0xff, 0xff,
  23. 0xff, 0xff, 0xff, 0xff,
  24. 8, 2, 3,
  25. })
  26. if err != nil {
  27. t.Fatalf("unexpected error while running program: %v", err)
  28. }
  29. if want, got := uint32(3), out; want != got {
  30. t.Fatalf("unexpected number of output bytes:\n- want: %d\n- got: %d",
  31. want, got)
  32. }
  33. }
  34. func TestVMALUOpSub(t *testing.T) {
  35. vm, err := testVM(t, []bpf.Instruction{
  36. bpf.LoadAbsolute{
  37. Off: 8,
  38. Size: 1,
  39. },
  40. bpf.TAX{},
  41. bpf.ALUOpX{
  42. Op: bpf.ALUOpSub,
  43. },
  44. bpf.RetA{},
  45. })
  46. if err != nil {
  47. t.Fatalf("failed to load BPF program: %v", err)
  48. }
  49. out, err := vm.Run([]byte{
  50. 0xff, 0xff, 0xff, 0xff,
  51. 0xff, 0xff, 0xff, 0xff,
  52. 1, 2, 3,
  53. })
  54. if err != nil {
  55. t.Fatalf("unexpected error while running program: %v", err)
  56. }
  57. if want, got := uint32(0), out; want != got {
  58. t.Fatalf("unexpected number of output bytes:\n- want: %d\n- got: %d",
  59. want, got)
  60. }
  61. }
  62. func TestVMALUOpMul(t *testing.T) {
  63. vm, err := testVM(t, []bpf.Instruction{
  64. bpf.LoadAbsolute{
  65. Off: 8,
  66. Size: 1,
  67. },
  68. bpf.ALUOpConstant{
  69. Op: bpf.ALUOpMul,
  70. Val: 2,
  71. },
  72. bpf.RetA{},
  73. })
  74. if err != nil {
  75. t.Fatalf("failed to load BPF program: %v", err)
  76. }
  77. out, err := vm.Run([]byte{
  78. 0xff, 0xff, 0xff, 0xff,
  79. 0xff, 0xff, 0xff, 0xff,
  80. 6, 2, 3, 4,
  81. })
  82. if err != nil {
  83. t.Fatalf("unexpected error while running program: %v", err)
  84. }
  85. if want, got := uint32(4), out; want != got {
  86. t.Fatalf("unexpected number of output bytes:\n- want: %d\n- got: %d",
  87. want, got)
  88. }
  89. }
  90. func TestVMALUOpDiv(t *testing.T) {
  91. vm, err := testVM(t, []bpf.Instruction{
  92. bpf.LoadAbsolute{
  93. Off: 8,
  94. Size: 1,
  95. },
  96. bpf.ALUOpConstant{
  97. Op: bpf.ALUOpDiv,
  98. Val: 2,
  99. },
  100. bpf.RetA{},
  101. })
  102. if err != nil {
  103. t.Fatalf("failed to load BPF program: %v", err)
  104. }
  105. out, err := vm.Run([]byte{
  106. 0xff, 0xff, 0xff, 0xff,
  107. 0xff, 0xff, 0xff, 0xff,
  108. 20, 2, 3, 4,
  109. })
  110. if err != nil {
  111. t.Fatalf("unexpected error while running program: %v", err)
  112. }
  113. if want, got := uint32(2), out; want != got {
  114. t.Fatalf("unexpected number of output bytes:\n- want: %d\n- got: %d",
  115. want, got)
  116. }
  117. }
  118. func TestVMALUOpDivByZeroALUOpConstant(t *testing.T) {
  119. _, err := testVM(t, []bpf.Instruction{
  120. bpf.ALUOpConstant{
  121. Op: bpf.ALUOpDiv,
  122. Val: 0,
  123. },
  124. bpf.RetA{},
  125. })
  126. if errStr(err) != "cannot divide by zero using ALUOpConstant" {
  127. t.Fatalf("failed to load BPF program: %v", err)
  128. }
  129. }
  130. func TestVMALUOpDivByZeroALUOpX(t *testing.T) {
  131. vm, err := testVM(t, []bpf.Instruction{
  132. // Load byte 0 into X
  133. bpf.LoadAbsolute{
  134. Off: 8,
  135. Size: 1,
  136. },
  137. bpf.TAX{},
  138. // Load byte 1 into A
  139. bpf.LoadAbsolute{
  140. Off: 9,
  141. Size: 1,
  142. },
  143. // Attempt to perform 1/0
  144. bpf.ALUOpX{
  145. Op: bpf.ALUOpDiv,
  146. },
  147. // Return 4 bytes if program does not terminate
  148. bpf.LoadConstant{
  149. Val: 12,
  150. },
  151. bpf.RetA{},
  152. })
  153. if err != nil {
  154. t.Fatalf("failed to load BPF program: %v", err)
  155. }
  156. out, err := vm.Run([]byte{
  157. 0xff, 0xff, 0xff, 0xff,
  158. 0xff, 0xff, 0xff, 0xff,
  159. 0, 1, 3, 4,
  160. })
  161. if err != nil {
  162. t.Fatalf("unexpected error while running program: %v", err)
  163. }
  164. if want, got := uint32(0), out; want != got {
  165. t.Fatalf("unexpected number of output bytes:\n- want: %d\n- got: %d",
  166. want, got)
  167. }
  168. }
  169. func TestVMALUOpOr(t *testing.T) {
  170. vm, err := testVM(t, []bpf.Instruction{
  171. bpf.LoadAbsolute{
  172. Off: 8,
  173. Size: 2,
  174. },
  175. bpf.ALUOpConstant{
  176. Op: bpf.ALUOpOr,
  177. Val: 0x01,
  178. },
  179. bpf.RetA{},
  180. })
  181. if err != nil {
  182. t.Fatalf("failed to load BPF program: %v", err)
  183. }
  184. out, err := vm.Run([]byte{
  185. 0xff, 0xff, 0xff, 0xff,
  186. 0xff, 0xff, 0xff, 0xff,
  187. 0x00, 0x10, 0x03, 0x04,
  188. 0x05, 0x06, 0x07, 0x08,
  189. 0x09, 0xff,
  190. })
  191. if err != nil {
  192. t.Fatalf("unexpected error while running program: %v", err)
  193. }
  194. if want, got := uint32(9), out; want != got {
  195. t.Fatalf("unexpected number of output bytes:\n- want: %d\n- got: %d",
  196. want, got)
  197. }
  198. }
  199. func TestVMALUOpAnd(t *testing.T) {
  200. vm, err := testVM(t, []bpf.Instruction{
  201. bpf.LoadAbsolute{
  202. Off: 8,
  203. Size: 2,
  204. },
  205. bpf.ALUOpConstant{
  206. Op: bpf.ALUOpAnd,
  207. Val: 0x0019,
  208. },
  209. bpf.RetA{},
  210. })
  211. if err != nil {
  212. t.Fatalf("failed to load BPF program: %v", err)
  213. }
  214. out, err := vm.Run([]byte{
  215. 0xff, 0xff, 0xff, 0xff,
  216. 0xff, 0xff, 0xff, 0xff,
  217. 0xaa, 0x09,
  218. })
  219. if err != nil {
  220. t.Fatalf("unexpected error while running program: %v", err)
  221. }
  222. if want, got := uint32(1), out; want != got {
  223. t.Fatalf("unexpected number of output bytes:\n- want: %d\n- got: %d",
  224. want, got)
  225. }
  226. }
  227. func TestVMALUOpShiftLeft(t *testing.T) {
  228. vm, err := testVM(t, []bpf.Instruction{
  229. bpf.LoadAbsolute{
  230. Off: 8,
  231. Size: 1,
  232. },
  233. bpf.ALUOpConstant{
  234. Op: bpf.ALUOpShiftLeft,
  235. Val: 0x01,
  236. },
  237. bpf.JumpIf{
  238. Cond: bpf.JumpEqual,
  239. Val: 0x02,
  240. SkipTrue: 1,
  241. },
  242. bpf.RetConstant{
  243. Val: 0,
  244. },
  245. bpf.RetConstant{
  246. Val: 9,
  247. },
  248. })
  249. if err != nil {
  250. t.Fatalf("failed to load BPF program: %v", err)
  251. }
  252. out, err := vm.Run([]byte{
  253. 0xff, 0xff, 0xff, 0xff,
  254. 0xff, 0xff, 0xff, 0xff,
  255. 0x01, 0xaa,
  256. })
  257. if err != nil {
  258. t.Fatalf("unexpected error while running program: %v", err)
  259. }
  260. if want, got := uint32(1), out; want != got {
  261. t.Fatalf("unexpected number of output bytes:\n- want: %d\n- got: %d",
  262. want, got)
  263. }
  264. }
  265. func TestVMALUOpShiftRight(t *testing.T) {
  266. vm, err := testVM(t, []bpf.Instruction{
  267. bpf.LoadAbsolute{
  268. Off: 8,
  269. Size: 1,
  270. },
  271. bpf.ALUOpConstant{
  272. Op: bpf.ALUOpShiftRight,
  273. Val: 0x01,
  274. },
  275. bpf.JumpIf{
  276. Cond: bpf.JumpEqual,
  277. Val: 0x04,
  278. SkipTrue: 1,
  279. },
  280. bpf.RetConstant{
  281. Val: 0,
  282. },
  283. bpf.RetConstant{
  284. Val: 9,
  285. },
  286. })
  287. if err != nil {
  288. t.Fatalf("failed to load BPF program: %v", err)
  289. }
  290. out, err := vm.Run([]byte{
  291. 0xff, 0xff, 0xff, 0xff,
  292. 0xff, 0xff, 0xff, 0xff,
  293. 0x08, 0xff, 0xff,
  294. })
  295. if err != nil {
  296. t.Fatalf("unexpected error while running program: %v", err)
  297. }
  298. if want, got := uint32(1), out; want != got {
  299. t.Fatalf("unexpected number of output bytes:\n- want: %d\n- got: %d",
  300. want, got)
  301. }
  302. }
  303. func TestVMALUOpMod(t *testing.T) {
  304. vm, err := testVM(t, []bpf.Instruction{
  305. bpf.LoadAbsolute{
  306. Off: 8,
  307. Size: 1,
  308. },
  309. bpf.ALUOpConstant{
  310. Op: bpf.ALUOpMod,
  311. Val: 20,
  312. },
  313. bpf.RetA{},
  314. })
  315. if err != nil {
  316. t.Fatalf("failed to load BPF program: %v", err)
  317. }
  318. out, err := vm.Run([]byte{
  319. 0xff, 0xff, 0xff, 0xff,
  320. 0xff, 0xff, 0xff, 0xff,
  321. 30, 0, 0,
  322. })
  323. if err != nil {
  324. t.Fatalf("unexpected error while running program: %v", err)
  325. }
  326. if want, got := uint32(2), out; want != got {
  327. t.Fatalf("unexpected number of output bytes:\n- want: %d\n- got: %d",
  328. want, got)
  329. }
  330. }
  331. func TestVMALUOpModByZeroALUOpConstant(t *testing.T) {
  332. _, err := testVM(t, []bpf.Instruction{
  333. bpf.LoadAbsolute{
  334. Off: 8,
  335. Size: 1,
  336. },
  337. bpf.ALUOpConstant{
  338. Op: bpf.ALUOpMod,
  339. Val: 0,
  340. },
  341. bpf.RetA{},
  342. })
  343. if errStr(err) != "cannot divide by zero using ALUOpConstant" {
  344. t.Fatalf("unexpected error: %v", err)
  345. }
  346. }
  347. func TestVMALUOpModByZeroALUOpX(t *testing.T) {
  348. vm, err := testVM(t, []bpf.Instruction{
  349. // Load byte 0 into X
  350. bpf.LoadAbsolute{
  351. Off: 8,
  352. Size: 1,
  353. },
  354. bpf.TAX{},
  355. // Load byte 1 into A
  356. bpf.LoadAbsolute{
  357. Off: 9,
  358. Size: 1,
  359. },
  360. // Attempt to perform 1%0
  361. bpf.ALUOpX{
  362. Op: bpf.ALUOpMod,
  363. },
  364. // Return 4 bytes if program does not terminate
  365. bpf.LoadConstant{
  366. Val: 12,
  367. },
  368. bpf.RetA{},
  369. })
  370. if err != nil {
  371. t.Fatalf("failed to load BPF program: %v", err)
  372. }
  373. out, err := vm.Run([]byte{
  374. 0xff, 0xff, 0xff, 0xff,
  375. 0xff, 0xff, 0xff, 0xff,
  376. 0, 1, 3, 4,
  377. })
  378. if err != nil {
  379. t.Fatalf("unexpected error while running program: %v", err)
  380. }
  381. if want, got := uint32(0), out; want != got {
  382. t.Fatalf("unexpected number of output bytes:\n- want: %d\n- got: %d",
  383. want, got)
  384. }
  385. }
  386. func TestVMALUOpXor(t *testing.T) {
  387. vm, err := testVM(t, []bpf.Instruction{
  388. bpf.LoadAbsolute{
  389. Off: 8,
  390. Size: 1,
  391. },
  392. bpf.ALUOpConstant{
  393. Op: bpf.ALUOpXor,
  394. Val: 0x0a,
  395. },
  396. bpf.JumpIf{
  397. Cond: bpf.JumpEqual,
  398. Val: 0x01,
  399. SkipTrue: 1,
  400. },
  401. bpf.RetConstant{
  402. Val: 0,
  403. },
  404. bpf.RetConstant{
  405. Val: 9,
  406. },
  407. })
  408. if err != nil {
  409. t.Fatalf("failed to load BPF program: %v", err)
  410. }
  411. out, err := vm.Run([]byte{
  412. 0xff, 0xff, 0xff, 0xff,
  413. 0xff, 0xff, 0xff, 0xff,
  414. 0x0b, 0x00, 0x00, 0x00,
  415. })
  416. if err != nil {
  417. t.Fatalf("unexpected error while running program: %v", err)
  418. }
  419. if want, got := uint32(1), out; want != got {
  420. t.Fatalf("unexpected number of output bytes:\n- want: %d\n- got: %d",
  421. want, got)
  422. }
  423. }
  424. func TestVMALUOpUnknown(t *testing.T) {
  425. vm, err := testVM(t, []bpf.Instruction{
  426. bpf.LoadAbsolute{
  427. Off: 8,
  428. Size: 1,
  429. },
  430. bpf.ALUOpConstant{
  431. Op: bpf.ALUOpAdd,
  432. Val: 1,
  433. },
  434. // Verify that an unknown operation is a no-op
  435. bpf.ALUOpConstant{
  436. Op: 100,
  437. },
  438. bpf.JumpIf{
  439. Cond: bpf.JumpEqual,
  440. Val: 0x02,
  441. SkipTrue: 1,
  442. },
  443. bpf.RetConstant{
  444. Val: 0,
  445. },
  446. bpf.RetConstant{
  447. Val: 9,
  448. },
  449. })
  450. if err != nil {
  451. t.Fatalf("failed to load BPF program: %v", err)
  452. }
  453. out, err := vm.Run([]byte{
  454. 0xff, 0xff, 0xff, 0xff,
  455. 0xff, 0xff, 0xff, 0xff,
  456. 1,
  457. })
  458. if err != nil {
  459. t.Fatalf("unexpected error while running program: %v", err)
  460. }
  461. if want, got := uint32(1), out; want != got {
  462. t.Fatalf("unexpected number of output bytes:\n- want: %d\n- got: %d",
  463. want, got)
  464. }
  465. }