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