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_alu_test.go 9.6KB

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