1#![allow(clippy::arithmetic_side_effects)]
2use crate::{ebpf, program::SBPFVersion, vm::Config};
16use thiserror::Error;
17
18#[derive(Debug, Error, Eq, PartialEq)]
20pub enum VerifierError {
21 #[error("program length must be a multiple of {} octets", ebpf::INSN_SIZE)]
23 ProgramLengthNotMultiple,
24 #[error("Deprecated")]
26 ProgramTooLarge(usize),
27 #[error("no program set, call prog_set() to load one")]
29 NoProgram,
30 #[error("division by 0 (insn #{0})")]
32 DivisionByZero(usize),
33 #[error("unsupported argument for LE/BE (insn #{0})")]
35 UnsupportedLEBEArgument(usize),
36 #[error("LD_DW instruction cannot be last in program")]
38 LDDWCannotBeLast,
39 #[error("incomplete LD_DW instruction (insn #{0})")]
41 IncompleteLDDW(usize),
42 #[error("infinite loop (insn #{0})")]
44 InfiniteLoop(usize),
45 #[error("jump out of code to #{0} (insn #{1})")]
47 JumpOutOfCode(usize, usize),
48 #[error("jump to middle of LD_DW at #{0} (insn #{1})")]
50 JumpToMiddleOfLDDW(usize, usize),
51 #[error("invalid source register (insn #{0})")]
53 InvalidSourceRegister(usize),
54 #[error("cannot write into register r10 (insn #{0})")]
56 CannotWriteR10(usize),
57 #[error("invalid destination register (insn #{0})")]
59 InvalidDestinationRegister(usize),
60 #[error("unknown eBPF opcode {0:#2x} (insn #{1:?})")]
62 UnknownOpCode(u8, usize),
63 #[error("Shift with overflow of {0}-bit value by {1} (insn #{2:?})")]
65 ShiftWithOverflow(u64, u64, usize),
66 #[error("Invalid register specified at instruction {0}")]
68 InvalidRegister(usize),
69 #[error("Invalid function at instruction {0}")]
71 InvalidFunction(usize),
72 #[error("Invalid syscall code {0}")]
74 InvalidSyscall(u32),
75 #[error("Unaligned immediate (insn #{0})")]
77 UnalignedImmediate(usize),
78}
79
80pub trait Verifier {
82 fn verify(prog: &[u8], config: &Config, sbpf_version: SBPFVersion)
91 -> Result<(), VerifierError>;
92}
93
94fn check_prog_len(prog: &[u8]) -> Result<(), VerifierError> {
95 if prog.len().checked_rem(ebpf::INSN_SIZE) != Some(0) {
96 return Err(VerifierError::ProgramLengthNotMultiple);
97 }
98 if prog.is_empty() {
99 return Err(VerifierError::NoProgram);
100 }
101 Ok(())
102}
103
104fn check_imm_nonzero(insn: &ebpf::Insn, insn_ptr: usize) -> Result<(), VerifierError> {
105 if insn.imm == 0 {
106 return Err(VerifierError::DivisionByZero(insn_ptr));
107 }
108 Ok(())
109}
110
111fn check_imm_endian(insn: &ebpf::Insn, insn_ptr: usize) -> Result<(), VerifierError> {
112 match insn.imm {
113 16 | 32 | 64 => Ok(()),
114 _ => Err(VerifierError::UnsupportedLEBEArgument(insn_ptr)),
115 }
116}
117
118fn check_imm_aligned(
119 insn: &ebpf::Insn,
120 insn_ptr: usize,
121 alignment: i64,
122) -> Result<(), VerifierError> {
123 if (insn.imm & (alignment - 1)) == 0 {
124 Ok(())
125 } else {
126 Err(VerifierError::UnalignedImmediate(insn_ptr))
127 }
128}
129
130fn check_load_dw(prog: &[u8], insn_ptr: usize) -> Result<(), VerifierError> {
131 if (insn_ptr + 1) * ebpf::INSN_SIZE >= prog.len() {
132 return Err(VerifierError::LDDWCannotBeLast);
134 }
135 let next_insn = ebpf::get_insn(prog, insn_ptr + 1);
136 if next_insn.opc != 0 {
137 return Err(VerifierError::IncompleteLDDW(insn_ptr));
138 }
139 Ok(())
140}
141
142fn check_jmp_offset(
143 prog: &[u8],
144 insn_ptr: usize,
145 program_range: &std::ops::Range<usize>,
146) -> Result<(), VerifierError> {
147 let insn = ebpf::get_insn(prog, insn_ptr);
148
149 let dst_insn_ptr = insn_ptr as isize + 1 + insn.off as isize;
150 if dst_insn_ptr < 0 || !program_range.contains(&(dst_insn_ptr as usize)) {
151 return Err(VerifierError::JumpOutOfCode(
152 dst_insn_ptr as usize,
153 insn_ptr,
154 ));
155 }
156 let dst_insn = ebpf::get_insn(prog, dst_insn_ptr as usize);
157 if dst_insn.opc == 0 {
158 return Err(VerifierError::JumpToMiddleOfLDDW(
159 dst_insn_ptr as usize,
160 insn_ptr,
161 ));
162 }
163 Ok(())
164}
165
166fn check_registers(
167 insn: &ebpf::Insn,
168 store: bool,
169 insn_ptr: usize,
170 sbpf_version: SBPFVersion,
171) -> Result<(), VerifierError> {
172 if insn.src > 10 {
173 return Err(VerifierError::InvalidSourceRegister(insn_ptr));
174 }
175
176 match (insn.dst, store) {
177 (0..=9, _) | (10, true) => Ok(()),
178 (10, false) if sbpf_version.manual_stack_frame_bump() && insn.opc == ebpf::ADD64_IMM => {
179 Ok(())
180 }
181 (10, false) => Err(VerifierError::CannotWriteR10(insn_ptr)),
182 (_, _) => Err(VerifierError::InvalidDestinationRegister(insn_ptr)),
183 }
184}
185
186fn check_imm_shift(insn: &ebpf::Insn, insn_ptr: usize, imm_bits: u64) -> Result<(), VerifierError> {
188 let shift_by = insn.imm as u64;
189 if insn.imm < 0 || shift_by >= imm_bits {
190 return Err(VerifierError::ShiftWithOverflow(
191 shift_by, imm_bits, insn_ptr,
192 ));
193 }
194 Ok(())
195}
196
197fn check_callx_register(
199 insn: &ebpf::Insn,
200 insn_ptr: usize,
201 sbpf_version: SBPFVersion,
202) -> Result<(), VerifierError> {
203 let reg = if sbpf_version.callx_uses_src_reg() {
204 insn.src as i64
205 } else if sbpf_version.callx_uses_dst_reg() {
206 insn.dst as i64
207 } else {
208 insn.imm
209 };
210 if !(0..10).contains(®) {
211 return Err(VerifierError::InvalidRegister(insn_ptr));
212 }
213 Ok(())
214}
215
216#[derive(Debug)]
218pub struct RequisiteVerifier {}
219impl Verifier for RequisiteVerifier {
220 #[rustfmt::skip]
222 fn verify(prog: &[u8], _config: &Config, sbpf_version: SBPFVersion) -> Result<(), VerifierError> {
223 check_prog_len(prog)?;
224
225 let program_range = 0..prog.len() / ebpf::INSN_SIZE;
226 let mut insn_ptr: usize = 0;
227 while (insn_ptr + 1) * ebpf::INSN_SIZE <= prog.len() {
228 let insn = ebpf::get_insn(prog, insn_ptr);
229 let mut store = false;
230
231 match insn.opc {
232 ebpf::LD_DW_IMM if !sbpf_version.disable_lddw() => {
233 check_load_dw(prog, insn_ptr)?;
234 insn_ptr += 1;
235 },
236
237 ebpf::LD_B_REG if !sbpf_version.move_memory_instruction_classes() => {},
239 ebpf::LD_H_REG if !sbpf_version.move_memory_instruction_classes() => {},
240 ebpf::LD_W_REG if !sbpf_version.move_memory_instruction_classes() => {},
241 ebpf::LD_DW_REG if !sbpf_version.move_memory_instruction_classes() => {},
242
243 ebpf::ST_B_IMM if !sbpf_version.move_memory_instruction_classes() => store = true,
245 ebpf::ST_H_IMM if !sbpf_version.move_memory_instruction_classes() => store = true,
246 ebpf::ST_W_IMM if !sbpf_version.move_memory_instruction_classes() => store = true,
247 ebpf::ST_DW_IMM if !sbpf_version.move_memory_instruction_classes() => store = true,
248
249 ebpf::ST_B_REG if !sbpf_version.move_memory_instruction_classes() => store = true,
251 ebpf::ST_H_REG if !sbpf_version.move_memory_instruction_classes() => store = true,
252 ebpf::ST_W_REG if !sbpf_version.move_memory_instruction_classes() => store = true,
253 ebpf::ST_DW_REG if !sbpf_version.move_memory_instruction_classes() => store = true,
254
255 ebpf::ADD32_IMM => {},
257 ebpf::ADD32_REG => {},
258 ebpf::SUB32_IMM => {},
259 ebpf::SUB32_REG => {},
260 ebpf::MUL32_IMM if !sbpf_version.enable_pqr() => {},
261 ebpf::MUL32_REG if !sbpf_version.enable_pqr() => {},
262 ebpf::LD_1B_REG if sbpf_version.move_memory_instruction_classes() => {},
263 ebpf::DIV32_IMM if !sbpf_version.enable_pqr() => { check_imm_nonzero(&insn, insn_ptr)?; },
264 ebpf::DIV32_REG if !sbpf_version.enable_pqr() => {},
265 ebpf::LD_2B_REG if sbpf_version.move_memory_instruction_classes() => {},
266 ebpf::OR32_IMM => {},
267 ebpf::OR32_REG => {},
268 ebpf::AND32_IMM => {},
269 ebpf::AND32_REG => {},
270 ebpf::LSH32_IMM => { check_imm_shift(&insn, insn_ptr, 32)?; },
271 ebpf::LSH32_REG => {},
272 ebpf::RSH32_IMM => { check_imm_shift(&insn, insn_ptr, 32)?; },
273 ebpf::RSH32_REG => {},
274 ebpf::NEG32 if !sbpf_version.disable_neg() => {},
275 ebpf::LD_4B_REG if sbpf_version.move_memory_instruction_classes() => {},
276 ebpf::MOD32_IMM if !sbpf_version.enable_pqr() => { check_imm_nonzero(&insn, insn_ptr)?; },
277 ebpf::MOD32_REG if !sbpf_version.enable_pqr() => {},
278 ebpf::LD_8B_REG if sbpf_version.move_memory_instruction_classes() => {},
279 ebpf::XOR32_IMM => {},
280 ebpf::XOR32_REG => {},
281 ebpf::MOV32_IMM => {},
282 ebpf::MOV32_REG => {},
283 ebpf::ARSH32_IMM => { check_imm_shift(&insn, insn_ptr, 32)?; },
284 ebpf::ARSH32_REG => {},
285 ebpf::LE if !sbpf_version.disable_le() => { check_imm_endian(&insn, insn_ptr)?; },
286 ebpf::BE => { check_imm_endian(&insn, insn_ptr)?; },
287
288 ebpf::ADD64_IMM if insn.dst == ebpf::FRAME_PTR_REG as u8 && sbpf_version.manual_stack_frame_bump() => {
290 check_imm_aligned(&insn, insn_ptr, 64)?;
291 },
292 ebpf::ADD64_IMM => {},
293 ebpf::ADD64_REG => {},
294 ebpf::SUB64_IMM => {},
295 ebpf::SUB64_REG => {},
296 ebpf::MUL64_IMM if !sbpf_version.enable_pqr() => {},
297 ebpf::ST_1B_IMM if sbpf_version.move_memory_instruction_classes() => store = true,
298 ebpf::MUL64_REG if !sbpf_version.enable_pqr() => {},
299 ebpf::ST_1B_REG if sbpf_version.move_memory_instruction_classes() => store = true,
300 ebpf::DIV64_IMM if !sbpf_version.enable_pqr() => { check_imm_nonzero(&insn, insn_ptr)?; },
301 ebpf::ST_2B_IMM if sbpf_version.move_memory_instruction_classes() => store = true,
302 ebpf::DIV64_REG if !sbpf_version.enable_pqr() => {},
303 ebpf::ST_2B_REG if sbpf_version.move_memory_instruction_classes() => store = true,
304 ebpf::OR64_IMM => {},
305 ebpf::OR64_REG => {},
306 ebpf::AND64_IMM => {},
307 ebpf::AND64_REG => {},
308 ebpf::LSH64_IMM => { check_imm_shift(&insn, insn_ptr, 64)?; },
309 ebpf::LSH64_REG => {},
310 ebpf::RSH64_IMM => { check_imm_shift(&insn, insn_ptr, 64)?; },
311 ebpf::RSH64_REG => {},
312 ebpf::ST_4B_IMM if sbpf_version.move_memory_instruction_classes() => store = true,
313 ebpf::NEG64 if !sbpf_version.disable_neg() => {},
314 ebpf::ST_4B_REG if sbpf_version.move_memory_instruction_classes() => store = true,
315 ebpf::MOD64_IMM if !sbpf_version.enable_pqr() => { check_imm_nonzero(&insn, insn_ptr)?; },
316 ebpf::ST_8B_IMM if sbpf_version.move_memory_instruction_classes() => store = true,
317 ebpf::MOD64_REG if !sbpf_version.enable_pqr() => {},
318 ebpf::ST_8B_REG if sbpf_version.move_memory_instruction_classes() => store = true,
319 ebpf::XOR64_IMM => {},
320 ebpf::XOR64_REG => {},
321 ebpf::MOV64_IMM => {},
322 ebpf::MOV64_REG => {},
323 ebpf::ARSH64_IMM => { check_imm_shift(&insn, insn_ptr, 64)?; },
324 ebpf::ARSH64_REG => {},
325 ebpf::HOR64_IMM if sbpf_version.disable_lddw() => {},
326
327 ebpf::LMUL32_IMM if sbpf_version.enable_pqr() => {},
329 ebpf::LMUL32_REG if sbpf_version.enable_pqr() => {},
330 ebpf::LMUL64_IMM if sbpf_version.enable_pqr() => {},
331 ebpf::LMUL64_REG if sbpf_version.enable_pqr() => {},
332 ebpf::UHMUL64_IMM if sbpf_version.enable_pqr() => {},
333 ebpf::UHMUL64_REG if sbpf_version.enable_pqr() => {},
334 ebpf::SHMUL64_IMM if sbpf_version.enable_pqr() => {},
335 ebpf::SHMUL64_REG if sbpf_version.enable_pqr() => {},
336 ebpf::UDIV32_IMM if sbpf_version.enable_pqr() => { check_imm_nonzero(&insn, insn_ptr)?; },
337 ebpf::UDIV32_REG if sbpf_version.enable_pqr() => {},
338 ebpf::UDIV64_IMM if sbpf_version.enable_pqr() => { check_imm_nonzero(&insn, insn_ptr)?; },
339 ebpf::UDIV64_REG if sbpf_version.enable_pqr() => {},
340 ebpf::UREM32_IMM if sbpf_version.enable_pqr() => { check_imm_nonzero(&insn, insn_ptr)?; },
341 ebpf::UREM32_REG if sbpf_version.enable_pqr() => {},
342 ebpf::UREM64_IMM if sbpf_version.enable_pqr() => { check_imm_nonzero(&insn, insn_ptr)?; },
343 ebpf::UREM64_REG if sbpf_version.enable_pqr() => {},
344 ebpf::SDIV32_IMM if sbpf_version.enable_pqr() => { check_imm_nonzero(&insn, insn_ptr)?; },
345 ebpf::SDIV32_REG if sbpf_version.enable_pqr() => {},
346 ebpf::SDIV64_IMM if sbpf_version.enable_pqr() => { check_imm_nonzero(&insn, insn_ptr)?; },
347 ebpf::SDIV64_REG if sbpf_version.enable_pqr() => {},
348 ebpf::SREM32_IMM if sbpf_version.enable_pqr() => { check_imm_nonzero(&insn, insn_ptr)?; },
349 ebpf::SREM32_REG if sbpf_version.enable_pqr() => {},
350 ebpf::SREM64_IMM if sbpf_version.enable_pqr() => { check_imm_nonzero(&insn, insn_ptr)?; },
351 ebpf::SREM64_REG if sbpf_version.enable_pqr() => {},
352
353 ebpf::JEQ32_IMM
355 | ebpf::JEQ32_REG
356 | ebpf::JGT32_IMM
357 | ebpf::JGT32_REG
358 | ebpf::JGE32_IMM
359 | ebpf::JGE32_REG
360 | ebpf::JLT32_IMM
361 | ebpf::JLT32_REG
362 | ebpf::JLE32_IMM
363 | ebpf::JLE32_REG
364 | ebpf::JSET32_IMM
365 | ebpf::JSET32_REG
366 | ebpf::JNE32_IMM
367 | ebpf::JNE32_REG
368 | ebpf::JSGT32_IMM
369 | ebpf::JSGT32_REG
370 | ebpf::JSGE32_IMM
371 | ebpf::JSGE32_REG
372 | ebpf::JSLT32_IMM
373 | ebpf::JSLT32_REG
374 | ebpf::JSLE32_IMM
375 | ebpf::JSLE32_REG if sbpf_version.enable_jmp32() => { check_jmp_offset(prog, insn_ptr, &program_range)?; },
376
377 ebpf::JA
379 | ebpf::JEQ64_IMM
380 | ebpf::JEQ64_REG
381 | ebpf::JGT64_IMM
382 | ebpf::JGT64_REG
383 | ebpf::JGE64_IMM
384 | ebpf::JGE64_REG
385 | ebpf::JLT64_IMM
386 | ebpf::JLT64_REG
387 | ebpf::JLE64_IMM
388 | ebpf::JLE64_REG
389 | ebpf::JSET64_IMM
390 | ebpf::JSET64_REG
391 | ebpf::JNE64_IMM
392 | ebpf::JNE64_REG
393 | ebpf::JSGT64_IMM
394 | ebpf::JSGT64_REG
395 | ebpf::JSGE64_IMM
396 | ebpf::JSGE64_REG
397 | ebpf::JSLT64_IMM
398 | ebpf::JSLT64_REG
399 | ebpf::JSLE64_IMM
400 | ebpf::JSLE64_REG => { check_jmp_offset(prog, insn_ptr, &program_range)?; },
401 ebpf::CALL_IMM => {},
402 ebpf::CALL_REG => { check_callx_register(&insn, insn_ptr, sbpf_version)?; },
403 ebpf::EXIT => {},
404
405 _ => {
406 return Err(VerifierError::UnknownOpCode(insn.opc, insn_ptr));
407 }
408 }
409
410 check_registers(&insn, store, insn_ptr, sbpf_version)?;
411
412 insn_ptr += 1;
413 }
414
415 if insn_ptr != prog.len() / ebpf::INSN_SIZE {
417 return Err(VerifierError::JumpOutOfCode(insn_ptr, insn_ptr));
418 }
419
420 Ok(())
421 }
422}