test_align.c 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458
  1. #include <asm/types.h>
  2. #include <linux/types.h>
  3. #include <stdint.h>
  4. #include <stdio.h>
  5. #include <stdlib.h>
  6. #include <unistd.h>
  7. #include <errno.h>
  8. #include <string.h>
  9. #include <stddef.h>
  10. #include <stdbool.h>
  11. #include <sys/resource.h>
  12. #include <linux/unistd.h>
  13. #include <linux/filter.h>
  14. #include <linux/bpf_perf_event.h>
  15. #include <linux/bpf.h>
  16. #include <bpf/bpf.h>
  17. #include "../../../include/linux/filter.h"
  18. #ifndef ARRAY_SIZE
  19. # define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0]))
  20. #endif
  21. #define MAX_INSNS 512
  22. #define MAX_MATCHES 16
  23. struct bpf_align_test {
  24. const char *descr;
  25. struct bpf_insn insns[MAX_INSNS];
  26. enum {
  27. UNDEF,
  28. ACCEPT,
  29. REJECT
  30. } result;
  31. enum bpf_prog_type prog_type;
  32. const char *matches[MAX_MATCHES];
  33. };
  34. static struct bpf_align_test tests[] = {
  35. {
  36. .descr = "mov",
  37. .insns = {
  38. BPF_MOV64_IMM(BPF_REG_3, 2),
  39. BPF_MOV64_IMM(BPF_REG_3, 4),
  40. BPF_MOV64_IMM(BPF_REG_3, 8),
  41. BPF_MOV64_IMM(BPF_REG_3, 16),
  42. BPF_MOV64_IMM(BPF_REG_3, 32),
  43. BPF_MOV64_IMM(BPF_REG_0, 0),
  44. BPF_EXIT_INSN(),
  45. },
  46. .prog_type = BPF_PROG_TYPE_SCHED_CLS,
  47. .matches = {
  48. "1: R1=ctx R3=imm2,min_value=2,max_value=2,min_align=2 R10=fp",
  49. "2: R1=ctx R3=imm4,min_value=4,max_value=4,min_align=4 R10=fp",
  50. "3: R1=ctx R3=imm8,min_value=8,max_value=8,min_align=8 R10=fp",
  51. "4: R1=ctx R3=imm16,min_value=16,max_value=16,min_align=16 R10=fp",
  52. "5: R1=ctx R3=imm32,min_value=32,max_value=32,min_align=32 R10=fp",
  53. },
  54. },
  55. {
  56. .descr = "shift",
  57. .insns = {
  58. BPF_MOV64_IMM(BPF_REG_3, 1),
  59. BPF_ALU64_IMM(BPF_LSH, BPF_REG_3, 1),
  60. BPF_ALU64_IMM(BPF_LSH, BPF_REG_3, 1),
  61. BPF_ALU64_IMM(BPF_LSH, BPF_REG_3, 1),
  62. BPF_ALU64_IMM(BPF_LSH, BPF_REG_3, 1),
  63. BPF_ALU64_IMM(BPF_RSH, BPF_REG_3, 4),
  64. BPF_MOV64_IMM(BPF_REG_4, 32),
  65. BPF_ALU64_IMM(BPF_RSH, BPF_REG_4, 1),
  66. BPF_ALU64_IMM(BPF_RSH, BPF_REG_4, 1),
  67. BPF_ALU64_IMM(BPF_RSH, BPF_REG_4, 1),
  68. BPF_ALU64_IMM(BPF_RSH, BPF_REG_4, 1),
  69. BPF_MOV64_IMM(BPF_REG_0, 0),
  70. BPF_EXIT_INSN(),
  71. },
  72. .prog_type = BPF_PROG_TYPE_SCHED_CLS,
  73. .matches = {
  74. "1: R1=ctx R3=imm1,min_value=1,max_value=1,min_align=1 R10=fp",
  75. "2: R1=ctx R3=imm2,min_value=2,max_value=2,min_align=2 R10=fp",
  76. "3: R1=ctx R3=imm4,min_value=4,max_value=4,min_align=4 R10=fp",
  77. "4: R1=ctx R3=imm8,min_value=8,max_value=8,min_align=8 R10=fp",
  78. "5: R1=ctx R3=imm16,min_value=16,max_value=16,min_align=16 R10=fp",
  79. "6: R1=ctx R3=imm1,min_value=1,max_value=1,min_align=1 R10=fp",
  80. "7: R1=ctx R3=imm1,min_value=1,max_value=1,min_align=1 R4=imm32,min_value=32,max_value=32,min_align=32 R10=fp",
  81. "8: R1=ctx R3=imm1,min_value=1,max_value=1,min_align=1 R4=imm16,min_value=16,max_value=16,min_align=16 R10=fp",
  82. "9: R1=ctx R3=imm1,min_value=1,max_value=1,min_align=1 R4=imm8,min_value=8,max_value=8,min_align=8 R10=fp",
  83. "10: R1=ctx R3=imm1,min_value=1,max_value=1,min_align=1 R4=imm4,min_value=4,max_value=4,min_align=4 R10=fp",
  84. "11: R1=ctx R3=imm1,min_value=1,max_value=1,min_align=1 R4=imm2,min_value=2,max_value=2,min_align=2 R10=fp",
  85. },
  86. },
  87. {
  88. .descr = "addsub",
  89. .insns = {
  90. BPF_MOV64_IMM(BPF_REG_3, 4),
  91. BPF_ALU64_IMM(BPF_ADD, BPF_REG_3, 4),
  92. BPF_ALU64_IMM(BPF_ADD, BPF_REG_3, 2),
  93. BPF_MOV64_IMM(BPF_REG_4, 8),
  94. BPF_ALU64_IMM(BPF_ADD, BPF_REG_4, 4),
  95. BPF_ALU64_IMM(BPF_ADD, BPF_REG_4, 2),
  96. BPF_MOV64_IMM(BPF_REG_0, 0),
  97. BPF_EXIT_INSN(),
  98. },
  99. .prog_type = BPF_PROG_TYPE_SCHED_CLS,
  100. .matches = {
  101. "1: R1=ctx R3=imm4,min_value=4,max_value=4,min_align=4 R10=fp",
  102. "2: R1=ctx R3=imm8,min_value=8,max_value=8,min_align=4 R10=fp",
  103. "3: R1=ctx R3=imm10,min_value=10,max_value=10,min_align=2 R10=fp",
  104. "4: R1=ctx R3=imm10,min_value=10,max_value=10,min_align=2 R4=imm8,min_value=8,max_value=8,min_align=8 R10=fp",
  105. "5: R1=ctx R3=imm10,min_value=10,max_value=10,min_align=2 R4=imm12,min_value=12,max_value=12,min_align=4 R10=fp",
  106. "6: R1=ctx R3=imm10,min_value=10,max_value=10,min_align=2 R4=imm14,min_value=14,max_value=14,min_align=2 R10=fp",
  107. },
  108. },
  109. {
  110. .descr = "mul",
  111. .insns = {
  112. BPF_MOV64_IMM(BPF_REG_3, 7),
  113. BPF_ALU64_IMM(BPF_MUL, BPF_REG_3, 1),
  114. BPF_ALU64_IMM(BPF_MUL, BPF_REG_3, 2),
  115. BPF_ALU64_IMM(BPF_MUL, BPF_REG_3, 4),
  116. BPF_MOV64_IMM(BPF_REG_0, 0),
  117. BPF_EXIT_INSN(),
  118. },
  119. .prog_type = BPF_PROG_TYPE_SCHED_CLS,
  120. .matches = {
  121. "1: R1=ctx R3=imm7,min_value=7,max_value=7,min_align=1 R10=fp",
  122. "2: R1=ctx R3=imm7,min_value=7,max_value=7,min_align=1 R10=fp",
  123. "3: R1=ctx R3=imm14,min_value=14,max_value=14,min_align=2 R10=fp",
  124. "4: R1=ctx R3=imm56,min_value=56,max_value=56,min_align=4 R10=fp",
  125. },
  126. },
  127. #define PREP_PKT_POINTERS \
  128. BPF_LDX_MEM(BPF_W, BPF_REG_2, BPF_REG_1, \
  129. offsetof(struct __sk_buff, data)), \
  130. BPF_LDX_MEM(BPF_W, BPF_REG_3, BPF_REG_1, \
  131. offsetof(struct __sk_buff, data_end))
  132. #define LOAD_UNKNOWN(DST_REG) \
  133. PREP_PKT_POINTERS, \
  134. BPF_MOV64_REG(BPF_REG_0, BPF_REG_2), \
  135. BPF_ALU64_IMM(BPF_ADD, BPF_REG_0, 8), \
  136. BPF_JMP_REG(BPF_JGE, BPF_REG_3, BPF_REG_0, 1), \
  137. BPF_EXIT_INSN(), \
  138. BPF_LDX_MEM(BPF_B, DST_REG, BPF_REG_2, 0)
  139. {
  140. .descr = "unknown shift",
  141. .insns = {
  142. LOAD_UNKNOWN(BPF_REG_3),
  143. BPF_ALU64_IMM(BPF_LSH, BPF_REG_3, 1),
  144. BPF_ALU64_IMM(BPF_LSH, BPF_REG_3, 1),
  145. BPF_ALU64_IMM(BPF_LSH, BPF_REG_3, 1),
  146. BPF_ALU64_IMM(BPF_LSH, BPF_REG_3, 1),
  147. LOAD_UNKNOWN(BPF_REG_4),
  148. BPF_ALU64_IMM(BPF_LSH, BPF_REG_4, 5),
  149. BPF_ALU64_IMM(BPF_RSH, BPF_REG_4, 1),
  150. BPF_ALU64_IMM(BPF_RSH, BPF_REG_4, 1),
  151. BPF_ALU64_IMM(BPF_RSH, BPF_REG_4, 1),
  152. BPF_ALU64_IMM(BPF_RSH, BPF_REG_4, 1),
  153. BPF_MOV64_IMM(BPF_REG_0, 0),
  154. BPF_EXIT_INSN(),
  155. },
  156. .prog_type = BPF_PROG_TYPE_SCHED_CLS,
  157. .matches = {
  158. "7: R0=pkt(id=0,off=8,r=8) R1=ctx R2=pkt(id=0,off=0,r=8) R3=inv56 R10=fp",
  159. "8: R0=pkt(id=0,off=8,r=8) R1=ctx R2=pkt(id=0,off=0,r=8) R3=inv55,min_align=2 R10=fp",
  160. "9: R0=pkt(id=0,off=8,r=8) R1=ctx R2=pkt(id=0,off=0,r=8) R3=inv54,min_align=4 R10=fp",
  161. "10: R0=pkt(id=0,off=8,r=8) R1=ctx R2=pkt(id=0,off=0,r=8) R3=inv53,min_align=8 R10=fp",
  162. "11: R0=pkt(id=0,off=8,r=8) R1=ctx R2=pkt(id=0,off=0,r=8) R3=inv52,min_align=16 R10=fp",
  163. "18: R0=pkt(id=0,off=8,r=8) R1=ctx R2=pkt(id=0,off=0,r=8) R3=pkt_end R4=inv56 R10=fp",
  164. "19: R0=pkt(id=0,off=8,r=8) R1=ctx R2=pkt(id=0,off=0,r=8) R3=pkt_end R4=inv51,min_align=32 R10=fp",
  165. "20: R0=pkt(id=0,off=8,r=8) R1=ctx R2=pkt(id=0,off=0,r=8) R3=pkt_end R4=inv52,min_align=16 R10=fp",
  166. "21: R0=pkt(id=0,off=8,r=8) R1=ctx R2=pkt(id=0,off=0,r=8) R3=pkt_end R4=inv53,min_align=8 R10=fp",
  167. "22: R0=pkt(id=0,off=8,r=8) R1=ctx R2=pkt(id=0,off=0,r=8) R3=pkt_end R4=inv54,min_align=4 R10=fp",
  168. "23: R0=pkt(id=0,off=8,r=8) R1=ctx R2=pkt(id=0,off=0,r=8) R3=pkt_end R4=inv55,min_align=2 R10=fp",
  169. },
  170. },
  171. {
  172. .descr = "unknown mul",
  173. .insns = {
  174. LOAD_UNKNOWN(BPF_REG_3),
  175. BPF_MOV64_REG(BPF_REG_4, BPF_REG_3),
  176. BPF_ALU64_IMM(BPF_MUL, BPF_REG_4, 1),
  177. BPF_MOV64_REG(BPF_REG_4, BPF_REG_3),
  178. BPF_ALU64_IMM(BPF_MUL, BPF_REG_4, 2),
  179. BPF_MOV64_REG(BPF_REG_4, BPF_REG_3),
  180. BPF_ALU64_IMM(BPF_MUL, BPF_REG_4, 4),
  181. BPF_MOV64_REG(BPF_REG_4, BPF_REG_3),
  182. BPF_ALU64_IMM(BPF_MUL, BPF_REG_4, 8),
  183. BPF_ALU64_IMM(BPF_MUL, BPF_REG_4, 2),
  184. BPF_MOV64_IMM(BPF_REG_0, 0),
  185. BPF_EXIT_INSN(),
  186. },
  187. .prog_type = BPF_PROG_TYPE_SCHED_CLS,
  188. .matches = {
  189. "7: R0=pkt(id=0,off=8,r=8) R1=ctx R2=pkt(id=0,off=0,r=8) R3=inv56 R10=fp",
  190. "8: R0=pkt(id=0,off=8,r=8) R1=ctx R2=pkt(id=0,off=0,r=8) R3=inv56 R4=inv56 R10=fp",
  191. "9: R0=pkt(id=0,off=8,r=8) R1=ctx R2=pkt(id=0,off=0,r=8) R3=inv56 R4=inv55,min_align=1 R10=fp",
  192. "10: R0=pkt(id=0,off=8,r=8) R1=ctx R2=pkt(id=0,off=0,r=8) R3=inv56 R4=inv56 R10=fp",
  193. "11: R0=pkt(id=0,off=8,r=8) R1=ctx R2=pkt(id=0,off=0,r=8) R3=inv56 R4=inv54,min_align=2 R10=fp",
  194. "12: R0=pkt(id=0,off=8,r=8) R1=ctx R2=pkt(id=0,off=0,r=8) R3=inv56 R4=inv56 R10=fp",
  195. "13: R0=pkt(id=0,off=8,r=8) R1=ctx R2=pkt(id=0,off=0,r=8) R3=inv56 R4=inv53,min_align=4 R10=fp",
  196. "14: R0=pkt(id=0,off=8,r=8) R1=ctx R2=pkt(id=0,off=0,r=8) R3=inv56 R4=inv56 R10=fp",
  197. "15: R0=pkt(id=0,off=8,r=8) R1=ctx R2=pkt(id=0,off=0,r=8) R3=inv56 R4=inv52,min_align=8 R10=fp",
  198. "16: R0=pkt(id=0,off=8,r=8) R1=ctx R2=pkt(id=0,off=0,r=8) R3=inv56 R4=inv50,min_align=8 R10=fp"
  199. },
  200. },
  201. {
  202. .descr = "packet const offset",
  203. .insns = {
  204. PREP_PKT_POINTERS,
  205. BPF_MOV64_REG(BPF_REG_5, BPF_REG_2),
  206. BPF_MOV64_IMM(BPF_REG_0, 0),
  207. /* Skip over ethernet header. */
  208. BPF_ALU64_IMM(BPF_ADD, BPF_REG_5, 14),
  209. BPF_MOV64_REG(BPF_REG_4, BPF_REG_5),
  210. BPF_ALU64_IMM(BPF_ADD, BPF_REG_4, 4),
  211. BPF_JMP_REG(BPF_JGE, BPF_REG_3, BPF_REG_4, 1),
  212. BPF_EXIT_INSN(),
  213. BPF_LDX_MEM(BPF_B, BPF_REG_4, BPF_REG_5, 0),
  214. BPF_LDX_MEM(BPF_B, BPF_REG_4, BPF_REG_5, 1),
  215. BPF_LDX_MEM(BPF_B, BPF_REG_4, BPF_REG_5, 2),
  216. BPF_LDX_MEM(BPF_B, BPF_REG_4, BPF_REG_5, 3),
  217. BPF_LDX_MEM(BPF_H, BPF_REG_4, BPF_REG_5, 0),
  218. BPF_LDX_MEM(BPF_H, BPF_REG_4, BPF_REG_5, 2),
  219. BPF_LDX_MEM(BPF_W, BPF_REG_4, BPF_REG_5, 0),
  220. BPF_MOV64_IMM(BPF_REG_0, 0),
  221. BPF_EXIT_INSN(),
  222. },
  223. .prog_type = BPF_PROG_TYPE_SCHED_CLS,
  224. .matches = {
  225. "4: R0=imm0,min_value=0,max_value=0,min_align=2147483648 R1=ctx R2=pkt(id=0,off=0,r=0) R3=pkt_end R5=pkt(id=0,off=0,r=0) R10=fp",
  226. "5: R0=imm0,min_value=0,max_value=0,min_align=2147483648 R1=ctx R2=pkt(id=0,off=0,r=0) R3=pkt_end R5=pkt(id=0,off=14,r=0) R10=fp",
  227. "6: R0=imm0,min_value=0,max_value=0,min_align=2147483648 R1=ctx R2=pkt(id=0,off=0,r=0) R3=pkt_end R4=pkt(id=0,off=14,r=0) R5=pkt(id=0,off=14,r=0) R10=fp",
  228. "10: R0=imm0,min_value=0,max_value=0,min_align=2147483648 R1=ctx R2=pkt(id=0,off=0,r=18) R3=pkt_end R4=inv56 R5=pkt(id=0,off=14,r=18) R10=fp",
  229. "14: R0=imm0,min_value=0,max_value=0,min_align=2147483648 R1=ctx R2=pkt(id=0,off=0,r=18) R3=pkt_end R4=inv48 R5=pkt(id=0,off=14,r=18) R10=fp",
  230. "15: R0=imm0,min_value=0,max_value=0,min_align=2147483648 R1=ctx R2=pkt(id=0,off=0,r=18) R3=pkt_end R4=inv48 R5=pkt(id=0,off=14,r=18) R10=fp",
  231. },
  232. },
  233. {
  234. .descr = "packet variable offset",
  235. .insns = {
  236. LOAD_UNKNOWN(BPF_REG_6),
  237. BPF_ALU64_IMM(BPF_LSH, BPF_REG_6, 2),
  238. /* First, add a constant to the R5 packet pointer,
  239. * then a variable with a known alignment.
  240. */
  241. BPF_MOV64_REG(BPF_REG_5, BPF_REG_2),
  242. BPF_ALU64_IMM(BPF_ADD, BPF_REG_5, 14),
  243. BPF_ALU64_REG(BPF_ADD, BPF_REG_5, BPF_REG_6),
  244. BPF_MOV64_REG(BPF_REG_4, BPF_REG_5),
  245. BPF_ALU64_IMM(BPF_ADD, BPF_REG_4, 4),
  246. BPF_JMP_REG(BPF_JGE, BPF_REG_3, BPF_REG_4, 1),
  247. BPF_EXIT_INSN(),
  248. BPF_LDX_MEM(BPF_W, BPF_REG_4, BPF_REG_5, 0),
  249. /* Now, test in the other direction. Adding first
  250. * the variable offset to R5, then the constant.
  251. */
  252. BPF_MOV64_REG(BPF_REG_5, BPF_REG_2),
  253. BPF_ALU64_REG(BPF_ADD, BPF_REG_5, BPF_REG_6),
  254. BPF_ALU64_IMM(BPF_ADD, BPF_REG_5, 14),
  255. BPF_MOV64_REG(BPF_REG_4, BPF_REG_5),
  256. BPF_ALU64_IMM(BPF_ADD, BPF_REG_4, 4),
  257. BPF_JMP_REG(BPF_JGE, BPF_REG_3, BPF_REG_4, 1),
  258. BPF_EXIT_INSN(),
  259. BPF_LDX_MEM(BPF_W, BPF_REG_4, BPF_REG_5, 0),
  260. /* Test multiple accumulations of unknown values
  261. * into a packet pointer.
  262. */
  263. BPF_MOV64_REG(BPF_REG_5, BPF_REG_2),
  264. BPF_ALU64_IMM(BPF_ADD, BPF_REG_5, 14),
  265. BPF_ALU64_REG(BPF_ADD, BPF_REG_5, BPF_REG_6),
  266. BPF_ALU64_IMM(BPF_ADD, BPF_REG_5, 4),
  267. BPF_ALU64_REG(BPF_ADD, BPF_REG_5, BPF_REG_6),
  268. BPF_MOV64_REG(BPF_REG_4, BPF_REG_5),
  269. BPF_ALU64_IMM(BPF_ADD, BPF_REG_4, 4),
  270. BPF_JMP_REG(BPF_JGE, BPF_REG_3, BPF_REG_4, 1),
  271. BPF_EXIT_INSN(),
  272. BPF_LDX_MEM(BPF_W, BPF_REG_4, BPF_REG_5, 0),
  273. BPF_MOV64_IMM(BPF_REG_0, 0),
  274. BPF_EXIT_INSN(),
  275. },
  276. .prog_type = BPF_PROG_TYPE_SCHED_CLS,
  277. .matches = {
  278. /* Calculated offset in R6 has unknown value, but known
  279. * alignment of 4.
  280. */
  281. "8: R0=pkt(id=0,off=8,r=8) R1=ctx R2=pkt(id=0,off=0,r=8) R3=pkt_end R6=inv54,min_align=4 R10=fp",
  282. /* Offset is added to packet pointer R5, resulting in known
  283. * auxiliary alignment and offset.
  284. */
  285. "11: R0=pkt(id=0,off=8,r=8) R1=ctx R2=pkt(id=0,off=0,r=8) R3=pkt_end R5=pkt(id=1,off=0,r=0),aux_off=14,aux_off_align=4 R6=inv54,min_align=4 R10=fp",
  286. /* At the time the word size load is performed from R5,
  287. * it's total offset is NET_IP_ALIGN + reg->off (0) +
  288. * reg->aux_off (14) which is 16. Then the variable
  289. * offset is considered using reg->aux_off_align which
  290. * is 4 and meets the load's requirements.
  291. */
  292. "15: R0=pkt(id=0,off=8,r=8) R1=ctx R2=pkt(id=0,off=0,r=8) R3=pkt_end R4=pkt(id=1,off=4,r=4),aux_off=14,aux_off_align=4 R5=pkt(id=1,off=0,r=4),aux_off=14,aux_off_align=4 R6=inv54,min_align=4 R10=fp",
  293. /* Variable offset is added to R5 packet pointer,
  294. * resulting in auxiliary alignment of 4.
  295. */
  296. "18: R0=pkt(id=0,off=8,r=8) R1=ctx R2=pkt(id=0,off=0,r=8) R3=pkt_end R4=inv,aux_off=14,aux_off_align=4 R5=pkt(id=2,off=0,r=0),aux_off_align=4 R6=inv54,min_align=4 R10=fp",
  297. /* Constant offset is added to R5, resulting in
  298. * reg->off of 14.
  299. */
  300. "19: R0=pkt(id=0,off=8,r=8) R1=ctx R2=pkt(id=0,off=0,r=8) R3=pkt_end R4=inv,aux_off=14,aux_off_align=4 R5=pkt(id=2,off=14,r=0),aux_off_align=4 R6=inv54,min_align=4 R10=fp",
  301. /* At the time the word size load is performed from R5,
  302. * it's total offset is NET_IP_ALIGN + reg->off (14) which
  303. * is 16. Then the variable offset is considered using
  304. * reg->aux_off_align which is 4 and meets the load's
  305. * requirements.
  306. */
  307. "23: R0=pkt(id=0,off=8,r=8) R1=ctx R2=pkt(id=0,off=0,r=8) R3=pkt_end R4=pkt(id=2,off=18,r=18),aux_off_align=4 R5=pkt(id=2,off=14,r=18),aux_off_align=4 R6=inv54,min_align=4 R10=fp",
  308. /* Constant offset is added to R5 packet pointer,
  309. * resulting in reg->off value of 14.
  310. */
  311. "26: R0=pkt(id=0,off=8,r=8) R1=ctx R2=pkt(id=0,off=0,r=8) R3=pkt_end R4=inv,aux_off_align=4 R5=pkt(id=0,off=14,r=8) R6=inv54,min_align=4 R10=fp",
  312. /* Variable offset is added to R5, resulting in an
  313. * auxiliary offset of 14, and an auxiliary alignment of 4.
  314. */
  315. "27: R0=pkt(id=0,off=8,r=8) R1=ctx R2=pkt(id=0,off=0,r=8) R3=pkt_end R4=inv,aux_off_align=4 R5=pkt(id=3,off=0,r=0),aux_off=14,aux_off_align=4 R6=inv54,min_align=4 R10=fp",
  316. /* Constant is added to R5 again, setting reg->off to 4. */
  317. "28: R0=pkt(id=0,off=8,r=8) R1=ctx R2=pkt(id=0,off=0,r=8) R3=pkt_end R4=inv,aux_off_align=4 R5=pkt(id=3,off=4,r=0),aux_off=14,aux_off_align=4 R6=inv54,min_align=4 R10=fp",
  318. /* And once more we add a variable, which causes an accumulation
  319. * of reg->off into reg->aux_off_align, with resulting value of
  320. * 18. The auxiliary alignment stays at 4.
  321. */
  322. "29: R0=pkt(id=0,off=8,r=8) R1=ctx R2=pkt(id=0,off=0,r=8) R3=pkt_end R4=inv,aux_off_align=4 R5=pkt(id=4,off=0,r=0),aux_off=18,aux_off_align=4 R6=inv54,min_align=4 R10=fp",
  323. /* At the time the word size load is performed from R5,
  324. * it's total offset is NET_IP_ALIGN + reg->off (0) +
  325. * reg->aux_off (18) which is 20. Then the variable offset
  326. * is considered using reg->aux_off_align which is 4 and meets
  327. * the load's requirements.
  328. */
  329. "33: R0=pkt(id=0,off=8,r=8) R1=ctx R2=pkt(id=0,off=0,r=8) R3=pkt_end R4=pkt(id=4,off=4,r=4),aux_off=18,aux_off_align=4 R5=pkt(id=4,off=0,r=4),aux_off=18,aux_off_align=4 R6=inv54,min_align=4 R10=fp",
  330. },
  331. },
  332. };
  333. static int probe_filter_length(const struct bpf_insn *fp)
  334. {
  335. int len;
  336. for (len = MAX_INSNS - 1; len > 0; --len)
  337. if (fp[len].code != 0 || fp[len].imm != 0)
  338. break;
  339. return len + 1;
  340. }
  341. static char bpf_vlog[32768];
  342. static int do_test_single(struct bpf_align_test *test)
  343. {
  344. struct bpf_insn *prog = test->insns;
  345. int prog_type = test->prog_type;
  346. int prog_len, i;
  347. int fd_prog;
  348. int ret;
  349. prog_len = probe_filter_length(prog);
  350. fd_prog = bpf_verify_program(prog_type ? : BPF_PROG_TYPE_SOCKET_FILTER,
  351. prog, prog_len, 1, "GPL", 0,
  352. bpf_vlog, sizeof(bpf_vlog), 2);
  353. if (fd_prog < 0) {
  354. printf("Failed to load program.\n");
  355. printf("%s", bpf_vlog);
  356. ret = 1;
  357. } else {
  358. ret = 0;
  359. for (i = 0; i < MAX_MATCHES; i++) {
  360. const char *t, *m = test->matches[i];
  361. if (!m)
  362. break;
  363. t = strstr(bpf_vlog, m);
  364. if (!t) {
  365. printf("Failed to find match: %s\n", m);
  366. ret = 1;
  367. printf("%s", bpf_vlog);
  368. break;
  369. }
  370. }
  371. close(fd_prog);
  372. }
  373. return ret;
  374. }
  375. static int do_test(unsigned int from, unsigned int to)
  376. {
  377. int all_pass = 0;
  378. int all_fail = 0;
  379. unsigned int i;
  380. for (i = from; i < to; i++) {
  381. struct bpf_align_test *test = &tests[i];
  382. int fail;
  383. printf("Test %3d: %s ... ",
  384. i, test->descr);
  385. fail = do_test_single(test);
  386. if (fail) {
  387. all_fail++;
  388. printf("FAIL\n");
  389. } else {
  390. all_pass++;
  391. printf("PASS\n");
  392. }
  393. }
  394. printf("Results: %d pass %d fail\n",
  395. all_pass, all_fail);
  396. return all_fail ? EXIT_FAILURE : EXIT_SUCCESS;
  397. }
  398. int main(int argc, char **argv)
  399. {
  400. unsigned int from = 0, to = ARRAY_SIZE(tests);
  401. struct rlimit rinf = { RLIM_INFINITY, RLIM_INFINITY };
  402. setrlimit(RLIMIT_MEMLOCK, &rinf);
  403. if (argc == 3) {
  404. unsigned int l = atoi(argv[argc - 2]);
  405. unsigned int u = atoi(argv[argc - 1]);
  406. if (l < to && u < to) {
  407. from = l;
  408. to = u + 1;
  409. }
  410. } else if (argc == 2) {
  411. unsigned int t = atoi(argv[argc - 1]);
  412. if (t < to) {
  413. from = t;
  414. to = t + 1;
  415. }
  416. }
  417. return do_test(from, to);
  418. }