1*fae6e9adSlinfeng // SPDX-License-Identifier: (Apache-2.0 OR MIT)
2*fae6e9adSlinfeng // Derived from uBPF <https://github.com/iovisor/ubpf>
3*fae6e9adSlinfeng // Copyright 2015 Big Switch Networks, Inc
4*fae6e9adSlinfeng // (uBPF: safety checks, originally in C)
5*fae6e9adSlinfeng // Copyright 2016 6WIND S.A. <quentin.monnet@6wind.com>
6*fae6e9adSlinfeng // (Translation to Rust)
7*fae6e9adSlinfeng
8*fae6e9adSlinfeng // This “verifier” performs simple checks when the eBPF program is loaded into the VM (before it is
9*fae6e9adSlinfeng // interpreted or JIT-compiled). It has nothing to do with the much more elaborated verifier inside
10*fae6e9adSlinfeng // Linux kernel. There is no verification regarding the program flow control (should be a Direct
11*fae6e9adSlinfeng // Acyclic Graph) or the consistency for registers usage (the verifier of the kernel assigns types
12*fae6e9adSlinfeng // to the registers and is much stricter).
13*fae6e9adSlinfeng //
14*fae6e9adSlinfeng // On the other hand, rbpf is not expected to run in kernel space.
15*fae6e9adSlinfeng //
16*fae6e9adSlinfeng // Improving the verifier would be nice, but this is not trivial (and Linux kernel is under GPL
17*fae6e9adSlinfeng // license, so we cannot copy it).
18*fae6e9adSlinfeng //
19*fae6e9adSlinfeng // Contrary to the verifier of the Linux kernel, this one does not modify the bytecode at all.
20*fae6e9adSlinfeng
21*fae6e9adSlinfeng use alloc::format;
22*fae6e9adSlinfeng
23*fae6e9adSlinfeng use crate::{ebpf, Error, ErrorKind};
24*fae6e9adSlinfeng
reject<S: AsRef<str>>(msg: S) -> Result<(), Error>25*fae6e9adSlinfeng fn reject<S: AsRef<str>>(msg: S) -> Result<(), Error> {
26*fae6e9adSlinfeng let full_msg = format!("[Verifier] Error: {}", msg.as_ref());
27*fae6e9adSlinfeng Err(Error::new(ErrorKind::Other, full_msg))
28*fae6e9adSlinfeng }
29*fae6e9adSlinfeng
check_prog_len(prog: &[u8]) -> Result<(), Error>30*fae6e9adSlinfeng fn check_prog_len(prog: &[u8]) -> Result<(), Error> {
31*fae6e9adSlinfeng if prog.len() % ebpf::INSN_SIZE != 0 {
32*fae6e9adSlinfeng reject(format!(
33*fae6e9adSlinfeng "eBPF program length must be a multiple of {:?} octets",
34*fae6e9adSlinfeng ebpf::INSN_SIZE
35*fae6e9adSlinfeng ))?;
36*fae6e9adSlinfeng }
37*fae6e9adSlinfeng if prog.len() > ebpf::PROG_MAX_SIZE {
38*fae6e9adSlinfeng reject(format!(
39*fae6e9adSlinfeng "eBPF program length limited to {:?}, here {:?}",
40*fae6e9adSlinfeng ebpf::PROG_MAX_INSNS,
41*fae6e9adSlinfeng prog.len() / ebpf::INSN_SIZE
42*fae6e9adSlinfeng ))?;
43*fae6e9adSlinfeng }
44*fae6e9adSlinfeng
45*fae6e9adSlinfeng if prog.is_empty() {
46*fae6e9adSlinfeng reject("no program set, call set_program() to load one")?;
47*fae6e9adSlinfeng }
48*fae6e9adSlinfeng let last_opc = ebpf::get_insn(prog, (prog.len() / ebpf::INSN_SIZE) - 1).opc;
49*fae6e9adSlinfeng if last_opc & ebpf::BPF_CLS_MASK != ebpf::BPF_JMP {
50*fae6e9adSlinfeng reject("program does not end with “EXIT” instruction")?;
51*fae6e9adSlinfeng }
52*fae6e9adSlinfeng
53*fae6e9adSlinfeng Ok(())
54*fae6e9adSlinfeng }
55*fae6e9adSlinfeng
check_imm_endian(insn: &ebpf::Insn, insn_ptr: usize) -> Result<(), Error>56*fae6e9adSlinfeng fn check_imm_endian(insn: &ebpf::Insn, insn_ptr: usize) -> Result<(), Error> {
57*fae6e9adSlinfeng match insn.imm {
58*fae6e9adSlinfeng 16 | 32 | 64 => Ok(()),
59*fae6e9adSlinfeng _ => reject(format!(
60*fae6e9adSlinfeng "unsupported argument for LE/BE (insn #{insn_ptr:?})"
61*fae6e9adSlinfeng )),
62*fae6e9adSlinfeng }
63*fae6e9adSlinfeng }
64*fae6e9adSlinfeng
check_load_dw(prog: &[u8], insn_ptr: usize) -> Result<(), Error>65*fae6e9adSlinfeng fn check_load_dw(prog: &[u8], insn_ptr: usize) -> Result<(), Error> {
66*fae6e9adSlinfeng // We know we can reach next insn since we enforce an EXIT insn at the end of program, while
67*fae6e9adSlinfeng // this function should be called only for LD_DW insn, that cannot be last in program.
68*fae6e9adSlinfeng let next_insn = ebpf::get_insn(prog, insn_ptr + 1);
69*fae6e9adSlinfeng if next_insn.opc != 0 {
70*fae6e9adSlinfeng reject(format!("incomplete LD_DW instruction (insn #{insn_ptr:?})"))?;
71*fae6e9adSlinfeng }
72*fae6e9adSlinfeng
73*fae6e9adSlinfeng Ok(())
74*fae6e9adSlinfeng }
75*fae6e9adSlinfeng
check_jmp_offset(prog: &[u8], insn_ptr: usize) -> Result<(), Error>76*fae6e9adSlinfeng fn check_jmp_offset(prog: &[u8], insn_ptr: usize) -> Result<(), Error> {
77*fae6e9adSlinfeng let insn = ebpf::get_insn(prog, insn_ptr);
78*fae6e9adSlinfeng if insn.off == -1 {
79*fae6e9adSlinfeng reject(format!("infinite loop (insn #{insn_ptr:?})"))?;
80*fae6e9adSlinfeng }
81*fae6e9adSlinfeng
82*fae6e9adSlinfeng let dst_insn_ptr = insn_ptr as isize + 1 + insn.off as isize;
83*fae6e9adSlinfeng if dst_insn_ptr < 0 || dst_insn_ptr as usize >= (prog.len() / ebpf::INSN_SIZE) {
84*fae6e9adSlinfeng reject(format!(
85*fae6e9adSlinfeng "jump out of code to #{dst_insn_ptr:?} (insn #{insn_ptr:?})"
86*fae6e9adSlinfeng ))?;
87*fae6e9adSlinfeng }
88*fae6e9adSlinfeng
89*fae6e9adSlinfeng let dst_insn = ebpf::get_insn(prog, dst_insn_ptr as usize);
90*fae6e9adSlinfeng if dst_insn.opc == 0 {
91*fae6e9adSlinfeng reject(format!(
92*fae6e9adSlinfeng "jump to middle of LD_DW at #{dst_insn_ptr:?} (insn #{insn_ptr:?})"
93*fae6e9adSlinfeng ))?;
94*fae6e9adSlinfeng }
95*fae6e9adSlinfeng
96*fae6e9adSlinfeng Ok(())
97*fae6e9adSlinfeng }
98*fae6e9adSlinfeng
check_registers(insn: &ebpf::Insn, store: bool, insn_ptr: usize) -> Result<(), Error>99*fae6e9adSlinfeng fn check_registers(insn: &ebpf::Insn, store: bool, insn_ptr: usize) -> Result<(), Error> {
100*fae6e9adSlinfeng if insn.src > 10 {
101*fae6e9adSlinfeng reject(format!("invalid source register (insn #{insn_ptr:?})"))?;
102*fae6e9adSlinfeng }
103*fae6e9adSlinfeng
104*fae6e9adSlinfeng match (insn.dst, store) {
105*fae6e9adSlinfeng (0..=9, _) | (10, true) => Ok(()),
106*fae6e9adSlinfeng (10, false) => reject(format!(
107*fae6e9adSlinfeng "cannot write into register r10 (insn #{insn_ptr:?})"
108*fae6e9adSlinfeng )),
109*fae6e9adSlinfeng (_, _) => reject(format!("invalid destination register (insn #{insn_ptr:?})")),
110*fae6e9adSlinfeng }
111*fae6e9adSlinfeng }
112*fae6e9adSlinfeng
check(prog: &[u8]) -> Result<(), Error>113*fae6e9adSlinfeng pub fn check(prog: &[u8]) -> Result<(), Error> {
114*fae6e9adSlinfeng check_prog_len(prog)?;
115*fae6e9adSlinfeng
116*fae6e9adSlinfeng let mut insn_ptr: usize = 0;
117*fae6e9adSlinfeng while insn_ptr * ebpf::INSN_SIZE < prog.len() {
118*fae6e9adSlinfeng let insn = ebpf::get_insn(prog, insn_ptr);
119*fae6e9adSlinfeng let mut store = false;
120*fae6e9adSlinfeng
121*fae6e9adSlinfeng match insn.opc {
122*fae6e9adSlinfeng // BPF_LD class
123*fae6e9adSlinfeng ebpf::LD_ABS_B => {}
124*fae6e9adSlinfeng ebpf::LD_ABS_H => {}
125*fae6e9adSlinfeng ebpf::LD_ABS_W => {}
126*fae6e9adSlinfeng ebpf::LD_ABS_DW => {}
127*fae6e9adSlinfeng ebpf::LD_IND_B => {}
128*fae6e9adSlinfeng ebpf::LD_IND_H => {}
129*fae6e9adSlinfeng ebpf::LD_IND_W => {}
130*fae6e9adSlinfeng ebpf::LD_IND_DW => {}
131*fae6e9adSlinfeng
132*fae6e9adSlinfeng ebpf::LD_DW_IMM => {
133*fae6e9adSlinfeng store = true;
134*fae6e9adSlinfeng check_load_dw(prog, insn_ptr)?;
135*fae6e9adSlinfeng insn_ptr += 1;
136*fae6e9adSlinfeng }
137*fae6e9adSlinfeng
138*fae6e9adSlinfeng // BPF_LDX class
139*fae6e9adSlinfeng ebpf::LD_B_REG => {}
140*fae6e9adSlinfeng ebpf::LD_H_REG => {}
141*fae6e9adSlinfeng ebpf::LD_W_REG => {}
142*fae6e9adSlinfeng ebpf::LD_DW_REG => {}
143*fae6e9adSlinfeng
144*fae6e9adSlinfeng // BPF_ST class
145*fae6e9adSlinfeng ebpf::ST_B_IMM => store = true,
146*fae6e9adSlinfeng ebpf::ST_H_IMM => store = true,
147*fae6e9adSlinfeng ebpf::ST_W_IMM => store = true,
148*fae6e9adSlinfeng ebpf::ST_DW_IMM => store = true,
149*fae6e9adSlinfeng
150*fae6e9adSlinfeng // BPF_STX class
151*fae6e9adSlinfeng ebpf::ST_B_REG => store = true,
152*fae6e9adSlinfeng ebpf::ST_H_REG => store = true,
153*fae6e9adSlinfeng ebpf::ST_W_REG => store = true,
154*fae6e9adSlinfeng ebpf::ST_DW_REG => store = true,
155*fae6e9adSlinfeng ebpf::ST_W_XADD => {
156*fae6e9adSlinfeng unimplemented!();
157*fae6e9adSlinfeng }
158*fae6e9adSlinfeng ebpf::ST_DW_XADD => {
159*fae6e9adSlinfeng unimplemented!();
160*fae6e9adSlinfeng }
161*fae6e9adSlinfeng
162*fae6e9adSlinfeng // BPF_ALU class
163*fae6e9adSlinfeng ebpf::ADD32_IMM => {}
164*fae6e9adSlinfeng ebpf::ADD32_REG => {}
165*fae6e9adSlinfeng ebpf::SUB32_IMM => {}
166*fae6e9adSlinfeng ebpf::SUB32_REG => {}
167*fae6e9adSlinfeng ebpf::MUL32_IMM => {}
168*fae6e9adSlinfeng ebpf::MUL32_REG => {}
169*fae6e9adSlinfeng ebpf::DIV32_IMM => {}
170*fae6e9adSlinfeng ebpf::DIV32_REG => {}
171*fae6e9adSlinfeng ebpf::OR32_IMM => {}
172*fae6e9adSlinfeng ebpf::OR32_REG => {}
173*fae6e9adSlinfeng ebpf::AND32_IMM => {}
174*fae6e9adSlinfeng ebpf::AND32_REG => {}
175*fae6e9adSlinfeng ebpf::LSH32_IMM => {}
176*fae6e9adSlinfeng ebpf::LSH32_REG => {}
177*fae6e9adSlinfeng ebpf::RSH32_IMM => {}
178*fae6e9adSlinfeng ebpf::RSH32_REG => {}
179*fae6e9adSlinfeng ebpf::NEG32 => {}
180*fae6e9adSlinfeng ebpf::MOD32_IMM => {}
181*fae6e9adSlinfeng ebpf::MOD32_REG => {}
182*fae6e9adSlinfeng ebpf::XOR32_IMM => {}
183*fae6e9adSlinfeng ebpf::XOR32_REG => {}
184*fae6e9adSlinfeng ebpf::MOV32_IMM => {}
185*fae6e9adSlinfeng ebpf::MOV32_REG => {}
186*fae6e9adSlinfeng ebpf::ARSH32_IMM => {}
187*fae6e9adSlinfeng ebpf::ARSH32_REG => {}
188*fae6e9adSlinfeng ebpf::LE => {
189*fae6e9adSlinfeng check_imm_endian(&insn, insn_ptr)?;
190*fae6e9adSlinfeng }
191*fae6e9adSlinfeng ebpf::BE => {
192*fae6e9adSlinfeng check_imm_endian(&insn, insn_ptr)?;
193*fae6e9adSlinfeng }
194*fae6e9adSlinfeng
195*fae6e9adSlinfeng // BPF_ALU64 class
196*fae6e9adSlinfeng ebpf::ADD64_IMM => {}
197*fae6e9adSlinfeng ebpf::ADD64_REG => {}
198*fae6e9adSlinfeng ebpf::SUB64_IMM => {}
199*fae6e9adSlinfeng ebpf::SUB64_REG => {}
200*fae6e9adSlinfeng ebpf::MUL64_IMM => {}
201*fae6e9adSlinfeng ebpf::MUL64_REG => {}
202*fae6e9adSlinfeng ebpf::DIV64_IMM => {}
203*fae6e9adSlinfeng ebpf::DIV64_REG => {}
204*fae6e9adSlinfeng ebpf::OR64_IMM => {}
205*fae6e9adSlinfeng ebpf::OR64_REG => {}
206*fae6e9adSlinfeng ebpf::AND64_IMM => {}
207*fae6e9adSlinfeng ebpf::AND64_REG => {}
208*fae6e9adSlinfeng ebpf::LSH64_IMM => {}
209*fae6e9adSlinfeng ebpf::LSH64_REG => {}
210*fae6e9adSlinfeng ebpf::RSH64_IMM => {}
211*fae6e9adSlinfeng ebpf::RSH64_REG => {}
212*fae6e9adSlinfeng ebpf::NEG64 => {}
213*fae6e9adSlinfeng ebpf::MOD64_IMM => {}
214*fae6e9adSlinfeng ebpf::MOD64_REG => {}
215*fae6e9adSlinfeng ebpf::XOR64_IMM => {}
216*fae6e9adSlinfeng ebpf::XOR64_REG => {}
217*fae6e9adSlinfeng ebpf::MOV64_IMM => {}
218*fae6e9adSlinfeng ebpf::MOV64_REG => {}
219*fae6e9adSlinfeng ebpf::ARSH64_IMM => {}
220*fae6e9adSlinfeng ebpf::ARSH64_REG => {}
221*fae6e9adSlinfeng
222*fae6e9adSlinfeng // BPF_JMP class
223*fae6e9adSlinfeng ebpf::JA => {
224*fae6e9adSlinfeng check_jmp_offset(prog, insn_ptr)?;
225*fae6e9adSlinfeng }
226*fae6e9adSlinfeng ebpf::JEQ_IMM => {
227*fae6e9adSlinfeng check_jmp_offset(prog, insn_ptr)?;
228*fae6e9adSlinfeng }
229*fae6e9adSlinfeng ebpf::JEQ_REG => {
230*fae6e9adSlinfeng check_jmp_offset(prog, insn_ptr)?;
231*fae6e9adSlinfeng }
232*fae6e9adSlinfeng ebpf::JGT_IMM => {
233*fae6e9adSlinfeng check_jmp_offset(prog, insn_ptr)?;
234*fae6e9adSlinfeng }
235*fae6e9adSlinfeng ebpf::JGT_REG => {
236*fae6e9adSlinfeng check_jmp_offset(prog, insn_ptr)?;
237*fae6e9adSlinfeng }
238*fae6e9adSlinfeng ebpf::JGE_IMM => {
239*fae6e9adSlinfeng check_jmp_offset(prog, insn_ptr)?;
240*fae6e9adSlinfeng }
241*fae6e9adSlinfeng ebpf::JGE_REG => {
242*fae6e9adSlinfeng check_jmp_offset(prog, insn_ptr)?;
243*fae6e9adSlinfeng }
244*fae6e9adSlinfeng ebpf::JLT_IMM => {
245*fae6e9adSlinfeng check_jmp_offset(prog, insn_ptr)?;
246*fae6e9adSlinfeng }
247*fae6e9adSlinfeng ebpf::JLT_REG => {
248*fae6e9adSlinfeng check_jmp_offset(prog, insn_ptr)?;
249*fae6e9adSlinfeng }
250*fae6e9adSlinfeng ebpf::JLE_IMM => {
251*fae6e9adSlinfeng check_jmp_offset(prog, insn_ptr)?;
252*fae6e9adSlinfeng }
253*fae6e9adSlinfeng ebpf::JLE_REG => {
254*fae6e9adSlinfeng check_jmp_offset(prog, insn_ptr)?;
255*fae6e9adSlinfeng }
256*fae6e9adSlinfeng ebpf::JSET_IMM => {
257*fae6e9adSlinfeng check_jmp_offset(prog, insn_ptr)?;
258*fae6e9adSlinfeng }
259*fae6e9adSlinfeng ebpf::JSET_REG => {
260*fae6e9adSlinfeng check_jmp_offset(prog, insn_ptr)?;
261*fae6e9adSlinfeng }
262*fae6e9adSlinfeng ebpf::JNE_IMM => {
263*fae6e9adSlinfeng check_jmp_offset(prog, insn_ptr)?;
264*fae6e9adSlinfeng }
265*fae6e9adSlinfeng ebpf::JNE_REG => {
266*fae6e9adSlinfeng check_jmp_offset(prog, insn_ptr)?;
267*fae6e9adSlinfeng }
268*fae6e9adSlinfeng ebpf::JSGT_IMM => {
269*fae6e9adSlinfeng check_jmp_offset(prog, insn_ptr)?;
270*fae6e9adSlinfeng }
271*fae6e9adSlinfeng ebpf::JSGT_REG => {
272*fae6e9adSlinfeng check_jmp_offset(prog, insn_ptr)?;
273*fae6e9adSlinfeng }
274*fae6e9adSlinfeng ebpf::JSGE_IMM => {
275*fae6e9adSlinfeng check_jmp_offset(prog, insn_ptr)?;
276*fae6e9adSlinfeng }
277*fae6e9adSlinfeng ebpf::JSGE_REG => {
278*fae6e9adSlinfeng check_jmp_offset(prog, insn_ptr)?;
279*fae6e9adSlinfeng }
280*fae6e9adSlinfeng ebpf::JSLT_IMM => {
281*fae6e9adSlinfeng check_jmp_offset(prog, insn_ptr)?;
282*fae6e9adSlinfeng }
283*fae6e9adSlinfeng ebpf::JSLT_REG => {
284*fae6e9adSlinfeng check_jmp_offset(prog, insn_ptr)?;
285*fae6e9adSlinfeng }
286*fae6e9adSlinfeng ebpf::JSLE_IMM => {
287*fae6e9adSlinfeng check_jmp_offset(prog, insn_ptr)?;
288*fae6e9adSlinfeng }
289*fae6e9adSlinfeng ebpf::JSLE_REG => {
290*fae6e9adSlinfeng check_jmp_offset(prog, insn_ptr)?;
291*fae6e9adSlinfeng }
292*fae6e9adSlinfeng
293*fae6e9adSlinfeng // BPF_JMP32 class
294*fae6e9adSlinfeng ebpf::JEQ_IMM32 => {
295*fae6e9adSlinfeng check_jmp_offset(prog, insn_ptr)?;
296*fae6e9adSlinfeng }
297*fae6e9adSlinfeng ebpf::JEQ_REG32 => {
298*fae6e9adSlinfeng check_jmp_offset(prog, insn_ptr)?;
299*fae6e9adSlinfeng }
300*fae6e9adSlinfeng ebpf::JGT_IMM32 => {
301*fae6e9adSlinfeng check_jmp_offset(prog, insn_ptr)?;
302*fae6e9adSlinfeng }
303*fae6e9adSlinfeng ebpf::JGT_REG32 => {
304*fae6e9adSlinfeng check_jmp_offset(prog, insn_ptr)?;
305*fae6e9adSlinfeng }
306*fae6e9adSlinfeng ebpf::JGE_IMM32 => {
307*fae6e9adSlinfeng check_jmp_offset(prog, insn_ptr)?;
308*fae6e9adSlinfeng }
309*fae6e9adSlinfeng ebpf::JGE_REG32 => {
310*fae6e9adSlinfeng check_jmp_offset(prog, insn_ptr)?;
311*fae6e9adSlinfeng }
312*fae6e9adSlinfeng ebpf::JLT_IMM32 => {
313*fae6e9adSlinfeng check_jmp_offset(prog, insn_ptr)?;
314*fae6e9adSlinfeng }
315*fae6e9adSlinfeng ebpf::JLT_REG32 => {
316*fae6e9adSlinfeng check_jmp_offset(prog, insn_ptr)?;
317*fae6e9adSlinfeng }
318*fae6e9adSlinfeng ebpf::JLE_IMM32 => {
319*fae6e9adSlinfeng check_jmp_offset(prog, insn_ptr)?;
320*fae6e9adSlinfeng }
321*fae6e9adSlinfeng ebpf::JLE_REG32 => {
322*fae6e9adSlinfeng check_jmp_offset(prog, insn_ptr)?;
323*fae6e9adSlinfeng }
324*fae6e9adSlinfeng ebpf::JSET_IMM32 => {
325*fae6e9adSlinfeng check_jmp_offset(prog, insn_ptr)?;
326*fae6e9adSlinfeng }
327*fae6e9adSlinfeng ebpf::JSET_REG32 => {
328*fae6e9adSlinfeng check_jmp_offset(prog, insn_ptr)?;
329*fae6e9adSlinfeng }
330*fae6e9adSlinfeng ebpf::JNE_IMM32 => {
331*fae6e9adSlinfeng check_jmp_offset(prog, insn_ptr)?;
332*fae6e9adSlinfeng }
333*fae6e9adSlinfeng ebpf::JNE_REG32 => {
334*fae6e9adSlinfeng check_jmp_offset(prog, insn_ptr)?;
335*fae6e9adSlinfeng }
336*fae6e9adSlinfeng ebpf::JSGT_IMM32 => {
337*fae6e9adSlinfeng check_jmp_offset(prog, insn_ptr)?;
338*fae6e9adSlinfeng }
339*fae6e9adSlinfeng ebpf::JSGT_REG32 => {
340*fae6e9adSlinfeng check_jmp_offset(prog, insn_ptr)?;
341*fae6e9adSlinfeng }
342*fae6e9adSlinfeng ebpf::JSGE_IMM32 => {
343*fae6e9adSlinfeng check_jmp_offset(prog, insn_ptr)?;
344*fae6e9adSlinfeng }
345*fae6e9adSlinfeng ebpf::JSGE_REG32 => {
346*fae6e9adSlinfeng check_jmp_offset(prog, insn_ptr)?;
347*fae6e9adSlinfeng }
348*fae6e9adSlinfeng ebpf::JSLT_IMM32 => {
349*fae6e9adSlinfeng check_jmp_offset(prog, insn_ptr)?;
350*fae6e9adSlinfeng }
351*fae6e9adSlinfeng ebpf::JSLT_REG32 => {
352*fae6e9adSlinfeng check_jmp_offset(prog, insn_ptr)?;
353*fae6e9adSlinfeng }
354*fae6e9adSlinfeng ebpf::JSLE_IMM32 => {
355*fae6e9adSlinfeng check_jmp_offset(prog, insn_ptr)?;
356*fae6e9adSlinfeng }
357*fae6e9adSlinfeng ebpf::JSLE_REG32 => {
358*fae6e9adSlinfeng check_jmp_offset(prog, insn_ptr)?;
359*fae6e9adSlinfeng }
360*fae6e9adSlinfeng
361*fae6e9adSlinfeng ebpf::CALL => {}
362*fae6e9adSlinfeng ebpf::TAIL_CALL => {
363*fae6e9adSlinfeng unimplemented!()
364*fae6e9adSlinfeng }
365*fae6e9adSlinfeng ebpf::EXIT => {}
366*fae6e9adSlinfeng
367*fae6e9adSlinfeng _ => {
368*fae6e9adSlinfeng reject(format!(
369*fae6e9adSlinfeng "unknown eBPF opcode {:#2x} (insn #{insn_ptr:?})",
370*fae6e9adSlinfeng insn.opc
371*fae6e9adSlinfeng ))?;
372*fae6e9adSlinfeng }
373*fae6e9adSlinfeng }
374*fae6e9adSlinfeng
375*fae6e9adSlinfeng check_registers(&insn, store, insn_ptr)?;
376*fae6e9adSlinfeng
377*fae6e9adSlinfeng insn_ptr += 1;
378*fae6e9adSlinfeng }
379*fae6e9adSlinfeng
380*fae6e9adSlinfeng // insn_ptr should now be equal to number of instructions.
381*fae6e9adSlinfeng if insn_ptr != prog.len() / ebpf::INSN_SIZE {
382*fae6e9adSlinfeng reject(format!("jumped out of code to #{insn_ptr:?}"))?;
383*fae6e9adSlinfeng }
384*fae6e9adSlinfeng
385*fae6e9adSlinfeng Ok(())
386*fae6e9adSlinfeng }
387