4
0

ebpf.rs 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262
  1. // Copyright 2016 6WIND S.A. <quentin.monnet@6wind.com>
  2. //
  3. // Licensed under the Apache License, Version 2.0 <http://www.apache.org/licenses/LICENSE-2.0> or
  4. // the MIT license <http://opensource.org/licenses/MIT>, at your option. This file may not be
  5. // copied, modified, or distributed except according to those terms.
  6. //! This module contains all the definitions related to eBPF.
  7. //!
  8. //! The number of bytes in an instruction, the maximum number of instructions in a program, and
  9. //! also all operation codes are defined here as constants.
  10. //!
  11. //! The structure for an instruction used by this crate, as well as the function to extract it from
  12. //! a program, is also defined in the module.
  13. //!
  14. //! To learn more about these instructions, see the Linux kernel documentation:
  15. //! <https://www.kernel.org/doc/Documentation/networking/filter.txt>, or for a shorter version of
  16. //! the list of the operation codes: <https://github.com/iovisor/bpf-docs/blob/master/eBPF.md>
  17. use std;
  18. /// Maximum number of instructions in an eBPF program.
  19. pub const PROG_MAX_INSNS: usize = 4096;
  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. // eBPF op codes.
  27. // See also https://www.kernel.org/doc/Documentation/networking/filter.txt
  28. // Three least significant bits are operation class:
  29. pub const BPF_LD : u8 = 0x00;
  30. pub const BPF_LDX : u8 = 0x01;
  31. pub const BPF_ST : u8 = 0x02;
  32. pub const BPF_STX : u8 = 0x03;
  33. pub const BPF_ALU : u8 = 0x04;
  34. pub const BPF_JMP : u8 = 0x05;
  35. // [ class 6 unused, reserved for future use ]
  36. pub const BPF_ALU64 : u8 = 0x07;
  37. // For load and store instructions:
  38. // +------------+--------+------------+
  39. // | 3 bits | 2 bits | 3 bits |
  40. // | mode | size | insn class |
  41. // +------------+--------+------------+
  42. // (MSB) (LSB)
  43. // Size modifiers:
  44. pub const BPF_W : u8 = 0x00; // word
  45. pub const BPF_H : u8 = 0x08; // half-word
  46. pub const BPF_B : u8 = 0x10; // byte
  47. pub const BPF_DW : u8 = 0x18; // double word
  48. // Mode modifiers:
  49. pub const BPF_IMM : u8 = 0x00;
  50. pub const BPF_ABS : u8 = 0x20;
  51. pub const BPF_IND : u8 = 0x40;
  52. pub const BPF_MEM : u8 = 0x60;
  53. // [ 0x80 reserved ]
  54. // [ 0xa0 reserved ]
  55. pub const BPF_XADD : u8 = 0xc0; // exclusive add
  56. // For arithmetic (BPF_ALU/BPF_ALU64) and jump (BPF_JMP) instructions:
  57. // +----------------+--------+--------+
  58. // | 4 bits |1 b.| 3 bits |
  59. // | operation code | src| insn class |
  60. // +----------------+----+------------+
  61. // (MSB) (LSB)
  62. // Source modifiers:
  63. pub const BPF_K : u8 = 0x00; // use 32-bit immediate as source operand
  64. pub const BPF_X : u8 = 0x08; // use `src` register as source operand
  65. // Operation codes -- BPF_ALU or BPF_ALU64 classes:
  66. pub const BPF_ADD : u8 = 0x00;
  67. pub const BPF_SUB : u8 = 0x10;
  68. pub const BPF_MUL : u8 = 0x20;
  69. pub const BPF_DIV : u8 = 0x30;
  70. pub const BPF_OR : u8 = 0x40;
  71. pub const BPF_AND : u8 = 0x50;
  72. pub const BPF_LSH : u8 = 0x60;
  73. pub const BPF_RSH : u8 = 0x70;
  74. pub const BPF_NEG : u8 = 0x80;
  75. pub const BPF_MOD : u8 = 0x90;
  76. pub const BPF_XOR : u8 = 0xa0;
  77. pub const BPF_MOV : u8 = 0xb0; // mov reg to reg
  78. pub const BPF_ARSH : u8 = 0xc0; // sign extending shift right
  79. pub const BPF_END : u8 = 0xd0; // endianness conversion
  80. // Operation codes -- BPF_JMP class:
  81. pub const BPF_JA : u8 = 0x00;
  82. pub const BPF_JEQ : u8 = 0x10;
  83. pub const BPF_JGT : u8 = 0x20;
  84. pub const BPF_JGE : u8 = 0x30;
  85. pub const BPF_JSET : u8 = 0x40;
  86. pub const BPF_JNE : u8 = 0x50; // jump !=
  87. pub const BPF_JSGT : u8 = 0x60; // signed '>'
  88. pub const BPF_JSGE : u8 = 0x70; // signed '>='
  89. pub const BPF_CALL : u8 = 0x80; // function call
  90. pub const BPF_EXIT : u8 = 0x90; // function return
  91. // Op codes
  92. // (Following operation names are not “official”, but may be proper to rbpf; Linux kernel only
  93. // combines above flags and does not attribute a name per operation.)
  94. pub const LD_ABS_B : u8 = BPF_LD | BPF_ABS | BPF_B;
  95. pub const LD_ABS_H : u8 = BPF_LD | BPF_ABS | BPF_H;
  96. pub const LD_ABS_W : u8 = BPF_LD | BPF_ABS | BPF_W;
  97. pub const LD_ABS_DW : u8 = BPF_LD | BPF_ABS | BPF_DW;
  98. pub const LD_IND_B : u8 = BPF_LD | BPF_IND | BPF_B;
  99. pub const LD_IND_H : u8 = BPF_LD | BPF_IND | BPF_H;
  100. pub const LD_IND_W : u8 = BPF_LD | BPF_IND | BPF_W;
  101. pub const LD_IND_DW : u8 = BPF_LD | BPF_IND | BPF_DW;
  102. pub const LD_DW_IMM : u8 = BPF_LD | BPF_IMM | BPF_DW;
  103. pub const LD_B_REG : u8 = BPF_LDX | BPF_MEM | BPF_B;
  104. pub const LD_H_REG : u8 = BPF_LDX | BPF_MEM | BPF_H;
  105. pub const LD_W_REG : u8 = BPF_LDX | BPF_MEM | BPF_W;
  106. pub const LD_DW_REG : u8 = BPF_LDX | BPF_MEM | BPF_DW;
  107. pub const ST_B_IMM : u8 = BPF_ST | BPF_MEM | BPF_B;
  108. pub const ST_H_IMM : u8 = BPF_ST | BPF_MEM | BPF_H;
  109. pub const ST_W_IMM : u8 = BPF_ST | BPF_MEM | BPF_W;
  110. pub const ST_DW_IMM : u8 = BPF_ST | BPF_MEM | BPF_DW;
  111. pub const ST_B_REG : u8 = BPF_STX | BPF_MEM | BPF_B;
  112. pub const ST_H_REG : u8 = BPF_STX | BPF_MEM | BPF_H;
  113. pub const ST_W_REG : u8 = BPF_STX | BPF_MEM | BPF_W;
  114. pub const ST_DW_REG : u8 = BPF_STX | BPF_MEM | BPF_DW;
  115. pub const ST_W_XADD : u8 = BPF_STX | BPF_XADD | BPF_W;
  116. pub const ST_DW_XADD : u8 = BPF_STX | BPF_XADD | BPF_DW;
  117. pub const ADD32_IMM : u8 = BPF_ALU | BPF_K | BPF_ADD;
  118. pub const ADD32_REG : u8 = BPF_ALU | BPF_X | BPF_ADD;
  119. pub const SUB32_IMM : u8 = BPF_ALU | BPF_K | BPF_SUB;
  120. pub const SUB32_REG : u8 = BPF_ALU | BPF_X | BPF_SUB;
  121. pub const MUL32_IMM : u8 = BPF_ALU | BPF_K | BPF_MUL;
  122. pub const MUL32_REG : u8 = BPF_ALU | BPF_X | BPF_MUL;
  123. pub const DIV32_IMM : u8 = BPF_ALU | BPF_K | BPF_DIV;
  124. pub const DIV32_REG : u8 = BPF_ALU | BPF_X | BPF_DIV;
  125. pub const OR32_IMM : u8 = BPF_ALU | BPF_K | BPF_OR;
  126. pub const OR32_REG : u8 = BPF_ALU | BPF_X | BPF_OR;
  127. pub const AND32_IMM : u8 = BPF_ALU | BPF_K | BPF_AND;
  128. pub const AND32_REG : u8 = BPF_ALU | BPF_X | BPF_AND;
  129. pub const LSH32_IMM : u8 = BPF_ALU | BPF_K | BPF_LSH;
  130. pub const LSH32_REG : u8 = BPF_ALU | BPF_X | BPF_LSH;
  131. pub const RSH32_IMM : u8 = BPF_ALU | BPF_K | BPF_RSH;
  132. pub const RSH32_REG : u8 = BPF_ALU | BPF_X | BPF_RSH;
  133. pub const NEG32 : u8 = BPF_ALU | BPF_NEG;
  134. pub const MOD32_IMM : u8 = BPF_ALU | BPF_K | BPF_MOD;
  135. pub const MOD32_REG : u8 = BPF_ALU | BPF_X | BPF_MOD;
  136. pub const XOR32_IMM : u8 = BPF_ALU | BPF_K | BPF_XOR;
  137. pub const XOR32_REG : u8 = BPF_ALU | BPF_X | BPF_XOR;
  138. pub const MOV32_IMM : u8 = BPF_ALU | BPF_K | BPF_MOV;
  139. pub const MOV32_REG : u8 = BPF_ALU | BPF_X | BPF_MOV;
  140. pub const ARSH32_IMM : u8 = BPF_ALU | BPF_K | BPF_ARSH;
  141. pub const ARSH32_REG : u8 = BPF_ALU | BPF_X | BPF_ARSH;
  142. pub const LE : u8 = BPF_ALU | BPF_K | BPF_END;
  143. pub const BE : u8 = BPF_ALU | BPF_X | BPF_END;
  144. pub const ADD64_IMM : u8 = BPF_ALU64 | BPF_K | BPF_ADD;
  145. pub const ADD64_REG : u8 = BPF_ALU64 | BPF_X | BPF_ADD;
  146. pub const SUB64_IMM : u8 = BPF_ALU64 | BPF_K | BPF_SUB;
  147. pub const SUB64_REG : u8 = BPF_ALU64 | BPF_X | BPF_SUB;
  148. pub const MUL64_IMM : u8 = BPF_ALU64 | BPF_K | BPF_MUL;
  149. pub const MUL64_REG : u8 = BPF_ALU64 | BPF_X | BPF_MUL;
  150. pub const DIV64_IMM : u8 = BPF_ALU64 | BPF_K | BPF_DIV;
  151. pub const DIV64_REG : u8 = BPF_ALU64 | BPF_X | BPF_DIV;
  152. pub const OR64_IMM : u8 = BPF_ALU64 | BPF_K | BPF_OR;
  153. pub const OR64_REG : u8 = BPF_ALU64 | BPF_X | BPF_OR;
  154. pub const AND64_IMM : u8 = BPF_ALU64 | BPF_K | BPF_AND;
  155. pub const AND64_REG : u8 = BPF_ALU64 | BPF_X | BPF_AND;
  156. pub const LSH64_IMM : u8 = BPF_ALU64 | BPF_K | BPF_LSH;
  157. pub const LSH64_REG : u8 = BPF_ALU64 | BPF_X | BPF_LSH;
  158. pub const RSH64_IMM : u8 = BPF_ALU64 | BPF_K | BPF_RSH;
  159. pub const RSH64_REG : u8 = BPF_ALU64 | BPF_X | BPF_RSH;
  160. pub const NEG64 : u8 = BPF_ALU64 | BPF_NEG;
  161. pub const MOD64_IMM : u8 = BPF_ALU64 | BPF_K | BPF_MOD;
  162. pub const MOD64_REG : u8 = BPF_ALU64 | BPF_X | BPF_MOD;
  163. pub const XOR64_IMM : u8 = BPF_ALU64 | BPF_K | BPF_XOR;
  164. pub const XOR64_REG : u8 = BPF_ALU64 | BPF_X | BPF_XOR;
  165. pub const MOV64_IMM : u8 = BPF_ALU64 | BPF_K | BPF_MOV;
  166. pub const MOV64_REG : u8 = BPF_ALU64 | BPF_X | BPF_MOV;
  167. pub const ARSH64_IMM : u8 = BPF_ALU64 | BPF_K | BPF_ARSH;
  168. pub const ARSH64_REG : u8 = BPF_ALU64 | BPF_X | BPF_ARSH;
  169. pub const JA : u8 = BPF_JMP | BPF_JA;
  170. pub const JEQ_IMM : u8 = BPF_JMP | BPF_K | BPF_JEQ;
  171. pub const JEQ_REG : u8 = BPF_JMP | BPF_X | BPF_JEQ;
  172. pub const JGT_IMM : u8 = BPF_JMP | BPF_K | BPF_JGT;
  173. pub const JGT_REG : u8 = BPF_JMP | BPF_X | BPF_JGT;
  174. pub const JGE_IMM : u8 = BPF_JMP | BPF_K | BPF_JGE;
  175. pub const JGE_REG : u8 = BPF_JMP | BPF_X | BPF_JGE;
  176. pub const JSET_IMM : u8 = BPF_JMP | BPF_K | BPF_JSET;
  177. pub const JSET_REG : u8 = BPF_JMP | BPF_X | BPF_JSET;
  178. pub const JNE_IMM : u8 = BPF_JMP | BPF_K | BPF_JNE;
  179. pub const JNE_REG : u8 = BPF_JMP | BPF_X | BPF_JNE;
  180. pub const JSGT_IMM : u8 = BPF_JMP | BPF_K | BPF_JSGT;
  181. pub const JSGT_REG : u8 = BPF_JMP | BPF_X | BPF_JSGT;
  182. pub const JSGE_IMM : u8 = BPF_JMP | BPF_K | BPF_JSGE;
  183. pub const JSGE_REG : u8 = BPF_JMP | BPF_X | BPF_JSGE;
  184. pub const CALL : u8 = BPF_JMP | BPF_CALL;
  185. pub const TAIL_CALL : u8 = BPF_JMP | BPF_X | BPF_CALL;
  186. pub const EXIT : u8 = BPF_JMP | BPF_EXIT;
  187. // Used in JIT
  188. pub const BPF_CLS_MASK : u8 = 0x07;
  189. pub const BPF_ALU_OP_MASK : u8 = 0xf0;
  190. /// An eBPF instruction. See <https://www.kernel.org/doc/Documentation/networking/filter.txt> for
  191. /// the Linux kernel documentation about eBPF, or
  192. /// <https://github.com/iovisor/bpf-docs/blob/master/eBPF.md> for a more concise version.
  193. #[derive(Debug)]
  194. pub struct Insn {
  195. /// Operation code.
  196. pub opc: u8,
  197. /// Destination register operand.
  198. pub dst: u8,
  199. /// Source register operand.
  200. pub src: u8,
  201. /// Offset operand.
  202. pub off: i16,
  203. /// Immediate value operand.
  204. pub imm: i32,
  205. }
  206. /// Get the instruction at `idx` of an eBPF program. `idx` is the index (number) of the
  207. /// instruction (not a byte offset). The first instruction has index 0.
  208. ///
  209. /// # Examples
  210. ///
  211. /// ```
  212. /// use rbpf::ebpf;
  213. ///
  214. /// let prog = vec![
  215. /// 0xb7, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  216. /// 0x95, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
  217. /// ];
  218. /// let insn = ebpf::get_insn(&prog, 1);
  219. /// assert_eq!(insn.opc, 0x95);
  220. /// ```
  221. pub fn get_insn(prog: &std::vec::Vec<u8>, idx: usize) -> Insn {
  222. // TODO panic if size problem? Should have been checked by verifier, though.
  223. // Update: this function is publicly available and user can call it with any idx, so we should
  224. // definitely add a guard here.
  225. let insn = Insn {
  226. opc: prog[INSN_SIZE * idx],
  227. dst: prog[INSN_SIZE * idx + 1] & 0x0f,
  228. src: (prog[INSN_SIZE * idx + 1] & 0xf0) >> 4,
  229. off: unsafe {
  230. let x = prog.as_ptr().offset((INSN_SIZE * idx + 2) as isize) as *const i16; *x
  231. },
  232. imm: unsafe {
  233. let x = prog.as_ptr().offset((INSN_SIZE * idx + 4) as isize) as *const i32; *x
  234. },
  235. };
  236. insn
  237. }