verifier.rs 12 KB

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