ebpf.rs 27 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635
  1. // SPDX-License-Identifier: (Apache-2.0 OR MIT)
  2. // Copyright 2016 6WIND S.A. <quentin.monnet@6wind.com>
  3. //! This module contains all the definitions related to eBPF, and some functions permitting to
  4. //! manipulate eBPF instructions.
  5. //!
  6. //! The number of bytes in an instruction, the maximum number of instructions in a program, and
  7. //! also all operation codes are defined here as constants.
  8. //!
  9. //! The structure for an instruction used by this crate, as well as the function to extract it from
  10. //! a program, is also defined in the module.
  11. //!
  12. //! To learn more about these instructions, see the Linux kernel documentation:
  13. //! <https://www.kernel.org/doc/Documentation/networking/filter.txt>, or for a shorter version of
  14. //! the list of the operation codes: <https://github.com/iovisor/bpf-docs/blob/master/eBPF.md>
  15. #![cfg_attr(rustfmt, rustfmt_skip)]
  16. use crate::lib::*;
  17. use byteorder::{ByteOrder, LittleEndian};
  18. /// Maximum number of instructions in an eBPF program.
  19. pub const PROG_MAX_INSNS: usize = 1000000;
  20. /// Size of an eBPF instructions, in bytes.
  21. pub const INSN_SIZE: usize = 8;
  22. /// Maximum size of an eBPF program, in bytes.
  23. pub const PROG_MAX_SIZE: usize = PROG_MAX_INSNS * INSN_SIZE;
  24. /// Stack for the eBPF stack, in bytes.
  25. pub const STACK_SIZE: usize = 512;
  26. /// The default stack size for the eBPF program if there is some eBPF to eBPF calls.
  27. pub const LOCAL_FUNCTION_STACK_SIZE: u16 = 256;
  28. /// Maximum number of eBPF to eBPF call depth.
  29. pub const MAX_CALL_DEPTH: usize = 8;
  30. // eBPF op codes.
  31. // See also https://www.kernel.org/doc/Documentation/networking/filter.txt
  32. // Three least significant bits are operation class:
  33. /// BPF operation class: load from immediate.
  34. pub const BPF_LD : u8 = 0x00;
  35. /// BPF operation class: load from register.
  36. pub const BPF_LDX : u8 = 0x01;
  37. /// BPF operation class: store immediate.
  38. pub const BPF_ST : u8 = 0x02;
  39. /// BPF operation class: store value from register.
  40. pub const BPF_STX : u8 = 0x03;
  41. /// BPF operation class: 32 bits arithmetic operation.
  42. pub const BPF_ALU : u8 = 0x04;
  43. /// BPF operation class: jump (64-bit wide operands for comparisons).
  44. pub const BPF_JMP : u8 = 0x05;
  45. /// BPF operation class: jump (32-bit wide operands for comparisons).
  46. pub const BPF_JMP32 : u8 = 0x06;
  47. // [ class 6 unused, reserved for future use ]
  48. /// BPF operation class: 64 bits arithmetic operation.
  49. pub const BPF_ALU64 : u8 = 0x07;
  50. // For load and store instructions:
  51. // +------------+--------+------------+
  52. // | 3 bits | 2 bits | 3 bits |
  53. // | mode | size | insn class |
  54. // +------------+--------+------------+
  55. // (MSB) (LSB)
  56. // Size modifiers:
  57. /// BPF size modifier: word (4 bytes).
  58. pub const BPF_W : u8 = 0x00;
  59. /// BPF size modifier: half-word (2 bytes).
  60. pub const BPF_H : u8 = 0x08;
  61. /// BPF size modifier: byte (1 byte).
  62. pub const BPF_B : u8 = 0x10;
  63. /// BPF size modifier: double word (8 bytes).
  64. pub const BPF_DW : u8 = 0x18;
  65. // Mode modifiers:
  66. /// BPF mode modifier: immediate value.
  67. pub const BPF_IMM : u8 = 0x00;
  68. /// BPF mode modifier: absolute load.
  69. pub const BPF_ABS : u8 = 0x20;
  70. /// BPF mode modifier: indirect load.
  71. pub const BPF_IND : u8 = 0x40;
  72. /// BPF mode modifier: load from / store to memory.
  73. pub const BPF_MEM : u8 = 0x60;
  74. // [ 0x80 reserved ]
  75. // [ 0xa0 reserved ]
  76. /// BPF mode modifier: exclusive add.
  77. pub const BPF_XADD : u8 = 0xc0;
  78. // For arithmetic (BPF_ALU/BPF_ALU64) and jump (BPF_JMP) instructions:
  79. // +----------------+--------+--------+
  80. // | 4 bits |1 b.| 3 bits |
  81. // | operation code | src| insn class |
  82. // +----------------+----+------------+
  83. // (MSB) (LSB)
  84. // Source modifiers:
  85. /// BPF source operand modifier: 32-bit immediate value.
  86. pub const BPF_K : u8 = 0x00;
  87. /// BPF source operand modifier: `src` register.
  88. pub const BPF_X : u8 = 0x08;
  89. // Operation codes -- BPF_ALU or BPF_ALU64 classes:
  90. /// BPF ALU/ALU64 operation code: addition.
  91. pub const BPF_ADD : u8 = 0x00;
  92. /// BPF ALU/ALU64 operation code: subtraction.
  93. pub const BPF_SUB : u8 = 0x10;
  94. /// BPF ALU/ALU64 operation code: multiplication.
  95. pub const BPF_MUL : u8 = 0x20;
  96. /// BPF ALU/ALU64 operation code: division.
  97. pub const BPF_DIV : u8 = 0x30;
  98. /// BPF ALU/ALU64 operation code: or.
  99. pub const BPF_OR : u8 = 0x40;
  100. /// BPF ALU/ALU64 operation code: and.
  101. pub const BPF_AND : u8 = 0x50;
  102. /// BPF ALU/ALU64 operation code: left shift.
  103. pub const BPF_LSH : u8 = 0x60;
  104. /// BPF ALU/ALU64 operation code: right shift.
  105. pub const BPF_RSH : u8 = 0x70;
  106. /// BPF ALU/ALU64 operation code: negation.
  107. pub const BPF_NEG : u8 = 0x80;
  108. /// BPF ALU/ALU64 operation code: modulus.
  109. pub const BPF_MOD : u8 = 0x90;
  110. /// BPF ALU/ALU64 operation code: exclusive or.
  111. pub const BPF_XOR : u8 = 0xa0;
  112. /// BPF ALU/ALU64 operation code: move.
  113. pub const BPF_MOV : u8 = 0xb0;
  114. /// BPF ALU/ALU64 operation code: sign extending right shift.
  115. pub const BPF_ARSH : u8 = 0xc0;
  116. /// BPF ALU/ALU64 operation code: endianness conversion.
  117. pub const BPF_END : u8 = 0xd0;
  118. // Operation codes -- BPF_JMP or BPF_JMP32 classes:
  119. /// BPF JMP operation code: jump.
  120. pub const BPF_JA : u8 = 0x00;
  121. /// BPF JMP operation code: jump if equal.
  122. pub const BPF_JEQ : u8 = 0x10;
  123. /// BPF JMP operation code: jump if greater than.
  124. pub const BPF_JGT : u8 = 0x20;
  125. /// BPF JMP operation code: jump if greater or equal.
  126. pub const BPF_JGE : u8 = 0x30;
  127. /// BPF JMP operation code: jump if `src` & `reg`.
  128. pub const BPF_JSET : u8 = 0x40;
  129. /// BPF JMP operation code: jump if not equal.
  130. pub const BPF_JNE : u8 = 0x50;
  131. /// BPF JMP operation code: jump if greater than (signed).
  132. pub const BPF_JSGT : u8 = 0x60;
  133. /// BPF JMP operation code: jump if greater or equal (signed).
  134. pub const BPF_JSGE : u8 = 0x70;
  135. /// BPF JMP operation code: helper function call.
  136. pub const BPF_CALL : u8 = 0x80;
  137. /// BPF JMP operation code: return from program.
  138. pub const BPF_EXIT : u8 = 0x90;
  139. /// BPF JMP operation code: jump if lower than.
  140. pub const BPF_JLT : u8 = 0xa0;
  141. /// BPF JMP operation code: jump if lower or equal.
  142. pub const BPF_JLE : u8 = 0xb0;
  143. /// BPF JMP operation code: jump if lower than (signed).
  144. pub const BPF_JSLT : u8 = 0xc0;
  145. /// BPF JMP operation code: jump if lower or equal (signed).
  146. pub const BPF_JSLE : u8 = 0xd0;
  147. // Op codes
  148. // (Following operation names are not “official”, but may be proper to rbpf; Linux kernel only
  149. // combines above flags and does not attribute a name per operation.)
  150. /// BPF opcode: `ldabsb src, dst, imm`.
  151. pub const LD_ABS_B : u8 = BPF_LD | BPF_ABS | BPF_B;
  152. /// BPF opcode: `ldabsh src, dst, imm`.
  153. pub const LD_ABS_H : u8 = BPF_LD | BPF_ABS | BPF_H;
  154. /// BPF opcode: `ldabsw src, dst, imm`.
  155. pub const LD_ABS_W : u8 = BPF_LD | BPF_ABS | BPF_W;
  156. /// BPF opcode: `ldabsdw src, dst, imm`.
  157. pub const LD_ABS_DW : u8 = BPF_LD | BPF_ABS | BPF_DW;
  158. /// BPF opcode: `ldindb src, dst, imm`.
  159. pub const LD_IND_B : u8 = BPF_LD | BPF_IND | BPF_B;
  160. /// BPF opcode: `ldindh src, dst, imm`.
  161. pub const LD_IND_H : u8 = BPF_LD | BPF_IND | BPF_H;
  162. /// BPF opcode: `ldindw src, dst, imm`.
  163. pub const LD_IND_W : u8 = BPF_LD | BPF_IND | BPF_W;
  164. /// BPF opcode: `ldinddw src, dst, imm`.
  165. pub const LD_IND_DW : u8 = BPF_LD | BPF_IND | BPF_DW;
  166. /// BPF opcode: `lddw dst, imm` /// `dst = imm`.
  167. pub const LD_DW_IMM : u8 = BPF_LD | BPF_IMM | BPF_DW;
  168. /// BPF opcode: `ldxb dst, [src + off]` /// `dst = (src + off) as u8`.
  169. pub const LD_B_REG : u8 = BPF_LDX | BPF_MEM | BPF_B;
  170. /// BPF opcode: `ldxh dst, [src + off]` /// `dst = (src + off) as u16`.
  171. pub const LD_H_REG : u8 = BPF_LDX | BPF_MEM | BPF_H;
  172. /// BPF opcode: `ldxw dst, [src + off]` /// `dst = (src + off) as u32`.
  173. pub const LD_W_REG : u8 = BPF_LDX | BPF_MEM | BPF_W;
  174. /// BPF opcode: `ldxdw dst, [src + off]` /// `dst = (src + off) as u64`.
  175. pub const LD_DW_REG : u8 = BPF_LDX | BPF_MEM | BPF_DW;
  176. /// BPF opcode: `stb [dst + off], imm` /// `(dst + offset) as u8 = imm`.
  177. pub const ST_B_IMM : u8 = BPF_ST | BPF_MEM | BPF_B;
  178. /// BPF opcode: `sth [dst + off], imm` /// `(dst + offset) as u16 = imm`.
  179. pub const ST_H_IMM : u8 = BPF_ST | BPF_MEM | BPF_H;
  180. /// BPF opcode: `stw [dst + off], imm` /// `(dst + offset) as u32 = imm`.
  181. pub const ST_W_IMM : u8 = BPF_ST | BPF_MEM | BPF_W;
  182. /// BPF opcode: `stdw [dst + off], imm` /// `(dst + offset) as u64 = imm`.
  183. pub const ST_DW_IMM : u8 = BPF_ST | BPF_MEM | BPF_DW;
  184. /// BPF opcode: `stxb [dst + off], src` /// `(dst + offset) as u8 = src`.
  185. pub const ST_B_REG : u8 = BPF_STX | BPF_MEM | BPF_B;
  186. /// BPF opcode: `stxh [dst + off], src` /// `(dst + offset) as u16 = src`.
  187. pub const ST_H_REG : u8 = BPF_STX | BPF_MEM | BPF_H;
  188. /// BPF opcode: `stxw [dst + off], src` /// `(dst + offset) as u32 = src`.
  189. pub const ST_W_REG : u8 = BPF_STX | BPF_MEM | BPF_W;
  190. /// BPF opcode: `stxdw [dst + off], src` /// `(dst + offset) as u64 = src`.
  191. pub const ST_DW_REG : u8 = BPF_STX | BPF_MEM | BPF_DW;
  192. /// BPF opcode: `stxxaddw [dst + off], src`.
  193. pub const ST_W_XADD : u8 = BPF_STX | BPF_XADD | BPF_W;
  194. /// BPF opcode: `stxxadddw [dst + off], src`.
  195. pub const ST_DW_XADD : u8 = BPF_STX | BPF_XADD | BPF_DW;
  196. /// BPF opcode: `add32 dst, imm` /// `dst += imm`.
  197. pub const ADD32_IMM : u8 = BPF_ALU | BPF_K | BPF_ADD;
  198. /// BPF opcode: `add32 dst, src` /// `dst += src`.
  199. pub const ADD32_REG : u8 = BPF_ALU | BPF_X | BPF_ADD;
  200. /// BPF opcode: `sub32 dst, imm` /// `dst -= imm`.
  201. pub const SUB32_IMM : u8 = BPF_ALU | BPF_K | BPF_SUB;
  202. /// BPF opcode: `sub32 dst, src` /// `dst -= src`.
  203. pub const SUB32_REG : u8 = BPF_ALU | BPF_X | BPF_SUB;
  204. /// BPF opcode: `mul32 dst, imm` /// `dst *= imm`.
  205. pub const MUL32_IMM : u8 = BPF_ALU | BPF_K | BPF_MUL;
  206. /// BPF opcode: `mul32 dst, src` /// `dst *= src`.
  207. pub const MUL32_REG : u8 = BPF_ALU | BPF_X | BPF_MUL;
  208. /// BPF opcode: `div32 dst, imm` /// `dst /= imm`.
  209. pub const DIV32_IMM : u8 = BPF_ALU | BPF_K | BPF_DIV;
  210. /// BPF opcode: `div32 dst, src` /// `dst /= src`.
  211. pub const DIV32_REG : u8 = BPF_ALU | BPF_X | BPF_DIV;
  212. /// BPF opcode: `or32 dst, imm` /// `dst |= imm`.
  213. pub const OR32_IMM : u8 = BPF_ALU | BPF_K | BPF_OR;
  214. /// BPF opcode: `or32 dst, src` /// `dst |= src`.
  215. pub const OR32_REG : u8 = BPF_ALU | BPF_X | BPF_OR;
  216. /// BPF opcode: `and32 dst, imm` /// `dst &= imm`.
  217. pub const AND32_IMM : u8 = BPF_ALU | BPF_K | BPF_AND;
  218. /// BPF opcode: `and32 dst, src` /// `dst &= src`.
  219. pub const AND32_REG : u8 = BPF_ALU | BPF_X | BPF_AND;
  220. /// BPF opcode: `lsh32 dst, imm` /// `dst <<= imm`.
  221. pub const LSH32_IMM : u8 = BPF_ALU | BPF_K | BPF_LSH;
  222. /// BPF opcode: `lsh32 dst, src` /// `dst <<= src`.
  223. pub const LSH32_REG : u8 = BPF_ALU | BPF_X | BPF_LSH;
  224. /// BPF opcode: `rsh32 dst, imm` /// `dst >>= imm`.
  225. pub const RSH32_IMM : u8 = BPF_ALU | BPF_K | BPF_RSH;
  226. /// BPF opcode: `rsh32 dst, src` /// `dst >>= src`.
  227. pub const RSH32_REG : u8 = BPF_ALU | BPF_X | BPF_RSH;
  228. /// BPF opcode: `neg32 dst` /// `dst = -dst`.
  229. pub const NEG32 : u8 = BPF_ALU | BPF_NEG;
  230. /// BPF opcode: `mod32 dst, imm` /// `dst %= imm`.
  231. pub const MOD32_IMM : u8 = BPF_ALU | BPF_K | BPF_MOD;
  232. /// BPF opcode: `mod32 dst, src` /// `dst %= src`.
  233. pub const MOD32_REG : u8 = BPF_ALU | BPF_X | BPF_MOD;
  234. /// BPF opcode: `xor32 dst, imm` /// `dst ^= imm`.
  235. pub const XOR32_IMM : u8 = BPF_ALU | BPF_K | BPF_XOR;
  236. /// BPF opcode: `xor32 dst, src` /// `dst ^= src`.
  237. pub const XOR32_REG : u8 = BPF_ALU | BPF_X | BPF_XOR;
  238. /// BPF opcode: `mov32 dst, imm` /// `dst = imm`.
  239. pub const MOV32_IMM : u8 = BPF_ALU | BPF_K | BPF_MOV;
  240. /// BPF opcode: `mov32 dst, src` /// `dst = src`.
  241. pub const MOV32_REG : u8 = BPF_ALU | BPF_X | BPF_MOV;
  242. /// BPF opcode: `arsh32 dst, imm` /// `dst >>= imm (arithmetic)`.
  243. ///
  244. /// <https://en.wikipedia.org/wiki/Arithmetic_shift>
  245. pub const ARSH32_IMM : u8 = BPF_ALU | BPF_K | BPF_ARSH;
  246. /// BPF opcode: `arsh32 dst, src` /// `dst >>= src (arithmetic)`.
  247. ///
  248. /// <https://en.wikipedia.org/wiki/Arithmetic_shift>
  249. pub const ARSH32_REG : u8 = BPF_ALU | BPF_X | BPF_ARSH;
  250. /// BPF opcode: `le dst` /// `dst = htole<imm>(dst), with imm in {16, 32, 64}`.
  251. pub const LE : u8 = BPF_ALU | BPF_K | BPF_END;
  252. /// BPF opcode: `be dst` /// `dst = htobe<imm>(dst), with imm in {16, 32, 64}`.
  253. pub const BE : u8 = BPF_ALU | BPF_X | BPF_END;
  254. /// BPF opcode: `add64 dst, imm` /// `dst += imm`.
  255. pub const ADD64_IMM : u8 = BPF_ALU64 | BPF_K | BPF_ADD;
  256. /// BPF opcode: `add64 dst, src` /// `dst += src`.
  257. pub const ADD64_REG : u8 = BPF_ALU64 | BPF_X | BPF_ADD;
  258. /// BPF opcode: `sub64 dst, imm` /// `dst -= imm`.
  259. pub const SUB64_IMM : u8 = BPF_ALU64 | BPF_K | BPF_SUB;
  260. /// BPF opcode: `sub64 dst, src` /// `dst -= src`.
  261. pub const SUB64_REG : u8 = BPF_ALU64 | BPF_X | BPF_SUB;
  262. /// BPF opcode: `div64 dst, imm` /// `dst /= imm`.
  263. pub const MUL64_IMM : u8 = BPF_ALU64 | BPF_K | BPF_MUL;
  264. /// BPF opcode: `div64 dst, src` /// `dst /= src`.
  265. pub const MUL64_REG : u8 = BPF_ALU64 | BPF_X | BPF_MUL;
  266. /// BPF opcode: `div64 dst, imm` /// `dst /= imm`.
  267. pub const DIV64_IMM : u8 = BPF_ALU64 | BPF_K | BPF_DIV;
  268. /// BPF opcode: `div64 dst, src` /// `dst /= src`.
  269. pub const DIV64_REG : u8 = BPF_ALU64 | BPF_X | BPF_DIV;
  270. /// BPF opcode: `or64 dst, imm` /// `dst |= imm`.
  271. pub const OR64_IMM : u8 = BPF_ALU64 | BPF_K | BPF_OR;
  272. /// BPF opcode: `or64 dst, src` /// `dst |= src`.
  273. pub const OR64_REG : u8 = BPF_ALU64 | BPF_X | BPF_OR;
  274. /// BPF opcode: `and64 dst, imm` /// `dst &= imm`.
  275. pub const AND64_IMM : u8 = BPF_ALU64 | BPF_K | BPF_AND;
  276. /// BPF opcode: `and64 dst, src` /// `dst &= src`.
  277. pub const AND64_REG : u8 = BPF_ALU64 | BPF_X | BPF_AND;
  278. /// BPF opcode: `lsh64 dst, imm` /// `dst <<= imm`.
  279. pub const LSH64_IMM : u8 = BPF_ALU64 | BPF_K | BPF_LSH;
  280. /// BPF opcode: `lsh64 dst, src` /// `dst <<= src`.
  281. pub const LSH64_REG : u8 = BPF_ALU64 | BPF_X | BPF_LSH;
  282. /// BPF opcode: `rsh64 dst, imm` /// `dst >>= imm`.
  283. pub const RSH64_IMM : u8 = BPF_ALU64 | BPF_K | BPF_RSH;
  284. /// BPF opcode: `rsh64 dst, src` /// `dst >>= src`.
  285. pub const RSH64_REG : u8 = BPF_ALU64 | BPF_X | BPF_RSH;
  286. /// BPF opcode: `neg64 dst, imm` /// `dst = -dst`.
  287. pub const NEG64 : u8 = BPF_ALU64 | BPF_NEG;
  288. /// BPF opcode: `mod64 dst, imm` /// `dst %= imm`.
  289. pub const MOD64_IMM : u8 = BPF_ALU64 | BPF_K | BPF_MOD;
  290. /// BPF opcode: `mod64 dst, src` /// `dst %= src`.
  291. pub const MOD64_REG : u8 = BPF_ALU64 | BPF_X | BPF_MOD;
  292. /// BPF opcode: `xor64 dst, imm` /// `dst ^= imm`.
  293. pub const XOR64_IMM : u8 = BPF_ALU64 | BPF_K | BPF_XOR;
  294. /// BPF opcode: `xor64 dst, src` /// `dst ^= src`.
  295. pub const XOR64_REG : u8 = BPF_ALU64 | BPF_X | BPF_XOR;
  296. /// BPF opcode: `mov64 dst, imm` /// `dst = imm`.
  297. pub const MOV64_IMM : u8 = BPF_ALU64 | BPF_K | BPF_MOV;
  298. /// BPF opcode: `mov64 dst, src` /// `dst = src`.
  299. pub const MOV64_REG : u8 = BPF_ALU64 | BPF_X | BPF_MOV;
  300. /// BPF opcode: `arsh64 dst, imm` /// `dst >>= imm (arithmetic)`.
  301. ///
  302. /// <https://en.wikipedia.org/wiki/Arithmetic_shift>
  303. pub const ARSH64_IMM : u8 = BPF_ALU64 | BPF_K | BPF_ARSH;
  304. /// BPF opcode: `arsh64 dst, src` /// `dst >>= src (arithmetic)`.
  305. ///
  306. /// <https://en.wikipedia.org/wiki/Arithmetic_shift>
  307. pub const ARSH64_REG : u8 = BPF_ALU64 | BPF_X | BPF_ARSH;
  308. /// BPF opcode: `ja +off` /// `PC += off`.
  309. pub const JA : u8 = BPF_JMP | BPF_JA;
  310. /// BPF opcode: `jeq dst, imm, +off` /// `PC += off if dst == imm`.
  311. pub const JEQ_IMM : u8 = BPF_JMP | BPF_K | BPF_JEQ;
  312. /// BPF opcode: `jeq dst, src, +off` /// `PC += off if dst == src`.
  313. pub const JEQ_REG : u8 = BPF_JMP | BPF_X | BPF_JEQ;
  314. /// BPF opcode: `jgt dst, imm, +off` /// `PC += off if dst > imm`.
  315. pub const JGT_IMM : u8 = BPF_JMP | BPF_K | BPF_JGT;
  316. /// BPF opcode: `jgt dst, src, +off` /// `PC += off if dst > src`.
  317. pub const JGT_REG : u8 = BPF_JMP | BPF_X | BPF_JGT;
  318. /// BPF opcode: `jge dst, imm, +off` /// `PC += off if dst >= imm`.
  319. pub const JGE_IMM : u8 = BPF_JMP | BPF_K | BPF_JGE;
  320. /// BPF opcode: `jge dst, src, +off` /// `PC += off if dst >= src`.
  321. pub const JGE_REG : u8 = BPF_JMP | BPF_X | BPF_JGE;
  322. /// BPF opcode: `jlt dst, imm, +off` /// `PC += off if dst < imm`.
  323. pub const JLT_IMM : u8 = BPF_JMP | BPF_K | BPF_JLT;
  324. /// BPF opcode: `jlt dst, src, +off` /// `PC += off if dst < src`.
  325. pub const JLT_REG : u8 = BPF_JMP | BPF_X | BPF_JLT;
  326. /// BPF opcode: `jle dst, imm, +off` /// `PC += off if dst <= imm`.
  327. pub const JLE_IMM : u8 = BPF_JMP | BPF_K | BPF_JLE;
  328. /// BPF opcode: `jle dst, src, +off` /// `PC += off if dst <= src`.
  329. pub const JLE_REG : u8 = BPF_JMP | BPF_X | BPF_JLE;
  330. /// BPF opcode: `jset dst, imm, +off` /// `PC += off if dst & imm`.
  331. pub const JSET_IMM : u8 = BPF_JMP | BPF_K | BPF_JSET;
  332. /// BPF opcode: `jset dst, src, +off` /// `PC += off if dst & src`.
  333. pub const JSET_REG : u8 = BPF_JMP | BPF_X | BPF_JSET;
  334. /// BPF opcode: `jne dst, imm, +off` /// `PC += off if dst != imm`.
  335. pub const JNE_IMM : u8 = BPF_JMP | BPF_K | BPF_JNE;
  336. /// BPF opcode: `jne dst, src, +off` /// `PC += off if dst != src`.
  337. pub const JNE_REG : u8 = BPF_JMP | BPF_X | BPF_JNE;
  338. /// BPF opcode: `jsgt dst, imm, +off` /// `PC += off if dst > imm (signed)`.
  339. pub const JSGT_IMM : u8 = BPF_JMP | BPF_K | BPF_JSGT;
  340. /// BPF opcode: `jsgt dst, src, +off` /// `PC += off if dst > src (signed)`.
  341. pub const JSGT_REG : u8 = BPF_JMP | BPF_X | BPF_JSGT;
  342. /// BPF opcode: `jsge dst, imm, +off` /// `PC += off if dst >= imm (signed)`.
  343. pub const JSGE_IMM : u8 = BPF_JMP | BPF_K | BPF_JSGE;
  344. /// BPF opcode: `jsge dst, src, +off` /// `PC += off if dst >= src (signed)`.
  345. pub const JSGE_REG : u8 = BPF_JMP | BPF_X | BPF_JSGE;
  346. /// BPF opcode: `jslt dst, imm, +off` /// `PC += off if dst < imm (signed)`.
  347. pub const JSLT_IMM : u8 = BPF_JMP | BPF_K | BPF_JSLT;
  348. /// BPF opcode: `jslt dst, src, +off` /// `PC += off if dst < src (signed)`.
  349. pub const JSLT_REG : u8 = BPF_JMP | BPF_X | BPF_JSLT;
  350. /// BPF opcode: `jsle dst, imm, +off` /// `PC += off if dst <= imm (signed)`.
  351. pub const JSLE_IMM : u8 = BPF_JMP | BPF_K | BPF_JSLE;
  352. /// BPF opcode: `jsle dst, src, +off` /// `PC += off if dst <= src (signed)`.
  353. pub const JSLE_REG : u8 = BPF_JMP | BPF_X | BPF_JSLE;
  354. /// BPF opcode: `jeq dst, imm, +off` /// `PC += off if (dst as u32) == imm`.
  355. pub const JEQ_IMM32 : u8 = BPF_JMP32 | BPF_K | BPF_JEQ;
  356. /// BPF opcode: `jeq dst, src, +off` /// `PC += off if (dst as u32) == (src as u32)`.
  357. pub const JEQ_REG32 : u8 = BPF_JMP32 | BPF_X | BPF_JEQ;
  358. /// BPF opcode: `jgt dst, imm, +off` /// `PC += off if (dst as u32) > imm`.
  359. pub const JGT_IMM32 : u8 = BPF_JMP32 | BPF_K | BPF_JGT;
  360. /// BPF opcode: `jgt dst, src, +off` /// `PC += off if (dst as u32) > (src as u32)`.
  361. pub const JGT_REG32 : u8 = BPF_JMP32 | BPF_X | BPF_JGT;
  362. /// BPF opcode: `jge dst, imm, +off` /// `PC += off if (dst as u32) >= imm`.
  363. pub const JGE_IMM32 : u8 = BPF_JMP32 | BPF_K | BPF_JGE;
  364. /// BPF opcode: `jge dst, src, +off` /// `PC += off if (dst as u32) >= (src as u32)`.
  365. pub const JGE_REG32 : u8 = BPF_JMP32 | BPF_X | BPF_JGE;
  366. /// BPF opcode: `jlt dst, imm, +off` /// `PC += off if (dst as u32) < imm`.
  367. pub const JLT_IMM32 : u8 = BPF_JMP32 | BPF_K | BPF_JLT;
  368. /// BPF opcode: `jlt dst, src, +off` /// `PC += off if (dst as u32) < (src as u32)`.
  369. pub const JLT_REG32 : u8 = BPF_JMP32 | BPF_X | BPF_JLT;
  370. /// BPF opcode: `jle dst, imm, +off` /// `PC += off if (dst as u32) <= imm`.
  371. pub const JLE_IMM32 : u8 = BPF_JMP32 | BPF_K | BPF_JLE;
  372. /// BPF opcode: `jle dst, src, +off` /// `PC += off if (dst as u32) <= (src as u32)`.
  373. pub const JLE_REG32 : u8 = BPF_JMP32 | BPF_X | BPF_JLE;
  374. /// BPF opcode: `jset dst, imm, +off` /// `PC += off if (dst as u32) & imm`.
  375. pub const JSET_IMM32 : u8 = BPF_JMP32 | BPF_K | BPF_JSET;
  376. /// BPF opcode: `jset dst, src, +off` /// `PC += off if (dst as u32) & (src as u32)`.
  377. pub const JSET_REG32 : u8 = BPF_JMP32 | BPF_X | BPF_JSET;
  378. /// BPF opcode: `jne dst, imm, +off` /// `PC += off if (dst as u32) != imm`.
  379. pub const JNE_IMM32 : u8 = BPF_JMP32 | BPF_K | BPF_JNE;
  380. /// BPF opcode: `jne dst, src, +off` /// `PC += off if (dst as u32) != (src as u32)`.
  381. pub const JNE_REG32 : u8 = BPF_JMP32 | BPF_X | BPF_JNE;
  382. /// BPF opcode: `jsgt dst, imm, +off` /// `PC += off if (dst as i32) > imm (signed)`.
  383. pub const JSGT_IMM32 : u8 = BPF_JMP32 | BPF_K | BPF_JSGT;
  384. /// BPF opcode: `jsgt dst, src, +off` /// `PC += off if (dst as i32) > (src as i32) (signed)`.
  385. pub const JSGT_REG32 : u8 = BPF_JMP32 | BPF_X | BPF_JSGT;
  386. /// BPF opcode: `jsge dst, imm, +off` /// `PC += off if (dst as i32) >= imm (signed)`.
  387. pub const JSGE_IMM32 : u8 = BPF_JMP32 | BPF_K | BPF_JSGE;
  388. /// BPF opcode: `jsge dst, src, +off` /// `PC += off if (dst as i32) >= (src as i32) (signed)`.
  389. pub const JSGE_REG32 : u8 = BPF_JMP32 | BPF_X | BPF_JSGE;
  390. /// BPF opcode: `jslt dst, imm, +off` /// `PC += off if (dst as i32) < imm (signed)`.
  391. pub const JSLT_IMM32 : u8 = BPF_JMP32 | BPF_K | BPF_JSLT;
  392. /// BPF opcode: `jslt dst, src, +off` /// `PC += off if (dst as i32) < (src as i32) (signed)`.
  393. pub const JSLT_REG32 : u8 = BPF_JMP32 | BPF_X | BPF_JSLT;
  394. /// BPF opcode: `jsle dst, imm, +off` /// `PC += off if (dst as i32) <= imm (signed)`.
  395. pub const JSLE_IMM32 : u8 = BPF_JMP32 | BPF_K | BPF_JSLE;
  396. /// BPF opcode: `jsle dst, src, +off` /// `PC += off if (dst as i32) <= (src as i32) (signed)`.
  397. pub const JSLE_REG32 : u8 = BPF_JMP32 | BPF_X | BPF_JSLE;
  398. /// BPF opcode: `call imm` /// helper function call to helper with key `imm`.
  399. pub const CALL : u8 = BPF_JMP | BPF_CALL;
  400. /// BPF opcode: tail call.
  401. pub const TAIL_CALL : u8 = BPF_JMP | BPF_X | BPF_CALL;
  402. /// BPF opcode: `exit` /// `return r0`.
  403. pub const EXIT : u8 = BPF_JMP | BPF_EXIT;
  404. // Used in JIT
  405. /// Mask to extract the operation class from an operation code.
  406. pub const BPF_CLS_MASK : u8 = 0x07;
  407. /// Mask to extract the arithmetic operation code from an instruction operation code.
  408. pub const BPF_ALU_OP_MASK : u8 = 0xf0;
  409. /// Prototype of an eBPF helper function.
  410. pub type Helper = fn (u64, u64, u64, u64, u64) -> u64;
  411. /// An eBPF instruction.
  412. ///
  413. /// See <https://www.kernel.org/doc/Documentation/networking/filter.txt> for the Linux kernel
  414. /// documentation about eBPF, or <https://github.com/iovisor/bpf-docs/blob/master/eBPF.md> for a
  415. /// more concise version.
  416. #[derive(Debug, PartialEq, Eq, Clone)]
  417. pub struct Insn {
  418. /// Operation code.
  419. pub opc: u8,
  420. /// Destination register operand.
  421. pub dst: u8,
  422. /// Source register operand.
  423. pub src: u8,
  424. /// Offset operand.
  425. pub off: i16,
  426. /// Immediate value operand.
  427. pub imm: i32,
  428. }
  429. impl Insn {
  430. /// Turn an `Insn` back into an array of bytes.
  431. ///
  432. /// # Examples
  433. ///
  434. /// ```
  435. /// use rbpf::ebpf;
  436. ///
  437. /// let prog: &[u8] = &[
  438. /// 0xb7, 0x12, 0x56, 0x34, 0xde, 0xbc, 0x9a, 0x78,
  439. /// ];
  440. /// let insn = ebpf::Insn {
  441. /// opc: 0xb7,
  442. /// dst: 2,
  443. /// src: 1,
  444. /// off: 0x3456,
  445. /// imm: 0x789abcde
  446. /// };
  447. /// assert_eq!(insn.to_array(), prog);
  448. /// ```
  449. pub fn to_array(&self) -> [u8; INSN_SIZE] {
  450. [
  451. self.opc,
  452. self.src.wrapping_shl(4) | self.dst,
  453. (self.off & 0xff) as u8,
  454. self.off.wrapping_shr(8) as u8,
  455. (self.imm & 0xff) as u8,
  456. (self.imm & 0xff_00).wrapping_shr(8) as u8,
  457. (self.imm as u32 & 0xff_00_00).wrapping_shr(16) as u8,
  458. (self.imm as u32 & 0xff_00_00_00).wrapping_shr(24) as u8,
  459. ]
  460. }
  461. /// Turn an `Insn` into an vector of bytes.
  462. ///
  463. /// # Examples
  464. ///
  465. /// ```
  466. /// use rbpf::ebpf;
  467. ///
  468. /// let prog: Vec<u8> = vec![
  469. /// 0xb7, 0x12, 0x56, 0x34, 0xde, 0xbc, 0x9a, 0x78,
  470. /// ];
  471. /// let insn = ebpf::Insn {
  472. /// opc: 0xb7,
  473. /// dst: 2,
  474. /// src: 1,
  475. /// off: 0x3456,
  476. /// imm: 0x789abcde
  477. /// };
  478. /// assert_eq!(insn.to_vec(), prog);
  479. /// ```
  480. pub fn to_vec(&self) -> Vec<u8> {
  481. vec![
  482. self.opc,
  483. self.src.wrapping_shl(4) | self.dst,
  484. (self.off & 0xff) as u8,
  485. self.off.wrapping_shr(8) as u8,
  486. (self.imm & 0xff) as u8,
  487. (self.imm & 0xff_00).wrapping_shr(8) as u8,
  488. (self.imm as u32 & 0xff_00_00).wrapping_shr(16) as u8,
  489. (self.imm as u32 & 0xff_00_00_00).wrapping_shr(24) as u8,
  490. ]
  491. }
  492. }
  493. /// Get the instruction at `idx` of an eBPF program. `idx` is the index (number) of the
  494. /// instruction (not a byte offset). The first instruction has index 0.
  495. ///
  496. /// # Panics
  497. ///
  498. /// Panics if it is not possible to get the instruction (if idx is too high, or last instruction is
  499. /// incomplete).
  500. ///
  501. /// # Examples
  502. ///
  503. /// ```
  504. /// use rbpf::ebpf;
  505. ///
  506. /// let prog = &[
  507. /// 0xb7, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  508. /// 0x95, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
  509. /// ];
  510. /// let insn = ebpf::get_insn(prog, 1);
  511. /// assert_eq!(insn.opc, 0x95);
  512. /// ```
  513. ///
  514. /// The example below will panic, since the last instruction is not complete and cannot be loaded.
  515. ///
  516. /// ```rust,should_panic
  517. /// use rbpf::ebpf;
  518. ///
  519. /// let prog = &[
  520. /// 0xb7, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  521. /// 0x95, 0x00, 0x00, 0x00, 0x00, 0x00 // two bytes missing
  522. /// ];
  523. /// let insn = ebpf::get_insn(prog, 1);
  524. /// ```
  525. pub fn get_insn(prog: &[u8], idx: usize) -> Insn {
  526. // This guard should not be needed in most cases, since the verifier already checks the program
  527. // size, and indexes should be fine in the interpreter/JIT. But this function is publicly
  528. // available and user can call it with any `idx`, so we have to check anyway.
  529. if (idx + 1) * INSN_SIZE > prog.len() {
  530. panic!(
  531. "Error: cannot reach instruction at index {:?} in program containing {:?} bytes",
  532. idx,
  533. prog.len()
  534. );
  535. }
  536. Insn {
  537. opc: prog[INSN_SIZE * idx],
  538. dst: prog[INSN_SIZE * idx + 1] & 0x0f,
  539. src: (prog[INSN_SIZE * idx + 1] & 0xf0) >> 4,
  540. off: LittleEndian::read_i16(&prog[(INSN_SIZE * idx + 2)..]),
  541. imm: LittleEndian::read_i32(&prog[(INSN_SIZE * idx + 4)..]),
  542. }
  543. }
  544. /// Return a vector of `struct Insn` built from a program.
  545. ///
  546. /// This is provided as a convenience for users wishing to manipulate a vector of instructions, for
  547. /// example for dumping the program instruction after instruction with a custom format.
  548. ///
  549. /// Note that the two parts of `LD_DW_IMM` instructions (spanning on 64 bits) are considered as two
  550. /// distinct instructions.
  551. ///
  552. /// # Examples
  553. ///
  554. /// ```
  555. /// use rbpf::ebpf;
  556. ///
  557. /// let prog = &[
  558. /// 0x18, 0x00, 0x00, 0x00, 0x88, 0x77, 0x66, 0x55,
  559. /// 0x00, 0x00, 0x00, 0x00, 0x44, 0x33, 0x22, 0x11,
  560. /// 0x95, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
  561. /// ];
  562. ///
  563. /// let v = ebpf::to_insn_vec(prog);
  564. /// assert_eq!(v, vec![
  565. /// ebpf::Insn {
  566. /// opc: 0x18,
  567. /// dst: 0,
  568. /// src: 0,
  569. /// off: 0,
  570. /// imm: 0x55667788
  571. /// },
  572. /// ebpf::Insn {
  573. /// opc: 0,
  574. /// dst: 0,
  575. /// src: 0,
  576. /// off: 0,
  577. /// imm: 0x11223344
  578. /// },
  579. /// ebpf::Insn {
  580. /// opc: 0x95,
  581. /// dst: 0,
  582. /// src: 0,
  583. /// off: 0,
  584. /// imm: 0
  585. /// },
  586. /// ]);
  587. /// ```
  588. pub fn to_insn_vec(prog: &[u8]) -> Vec<Insn> {
  589. if prog.len() % INSN_SIZE != 0 {
  590. panic!(
  591. "Error: eBPF program length must be a multiple of {:?} octets",
  592. INSN_SIZE
  593. );
  594. }
  595. let mut res = vec![];
  596. let mut insn_ptr: usize = 0;
  597. while insn_ptr * INSN_SIZE < prog.len() {
  598. let insn = get_insn(prog, insn_ptr);
  599. res.push(insn);
  600. insn_ptr += 1;
  601. }
  602. res
  603. }