verifier.rs 9.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243
  1. // Derived from uBPF <https://github.com/iovisor/ubpf>
  2. // Copyright 2015 Big Switch Networks, Inc
  3. // (uBPF: safety checks, originally in C)
  4. // Copyright 2016 Quentin Monnet <quentin.monnet@6wind.com>
  5. // (Translation to Rust)
  6. //
  7. // Licensed under the Apache License, Version 2.0 <http://www.apache.org/licenses/LICENSE-2.0> or
  8. // the MIT license <http://opensource.org/licenses/MIT>, at your option. This file may not be
  9. // copied, modified, or distributed except according to those terms.
  10. // This “verifier” performs simple checks when the eBPF program is loaded into the VM (before it is
  11. // interpreted or JIT-compiled). It has nothing to do with the much more elaborated verifier inside
  12. // Linux kernel. There is no verification regarding the program flow control (should be a Direct
  13. // Acyclic Graph) or the consistency for registers usage (the verifier of the kernel assigns types
  14. // to the registers and is much stricter).
  15. //
  16. // On the other hand, rbpf is not expected to run in kernel space.
  17. //
  18. // Improving the verifier would be nice, but this is not trivial (and Linux kernel is under GPL
  19. // license, so we cannot copy it).
  20. //
  21. // Contrary to the verifier of the Linux kernel, this one does not modify the bytecode at all.
  22. use ebpf;
  23. use std;
  24. fn check_prog_len(prog: &std::vec::Vec<u8>) {
  25. if prog.len() % ebpf::INSN_SIZE != 0 {
  26. panic!("[Verifier] Error: eBPF program length must be a multiple of {:?} octets",
  27. ebpf::INSN_SIZE);
  28. }
  29. if prog.len() > ebpf::PROG_MAX_SIZE {
  30. panic!("[Verifier] Error: eBPF program length limited to {:?}, here {:?}",
  31. ebpf::PROG_MAX_INSNS, prog.len() / ebpf::INSN_SIZE);
  32. }
  33. if prog.len() == 0 {
  34. panic!("[Verifier] Error: program does not end with “EXIT” instruction");
  35. }
  36. let last_insn = ebpf::get_insn(prog, (prog.len() / ebpf::INSN_SIZE) - 1);
  37. if last_insn.opc != ebpf::EXIT {
  38. panic!("[Verifier] Error: program does not end with “EXIT” instruction");
  39. }
  40. }
  41. fn check_imm_nonzero(insn: &ebpf::Insn, insn_ptr: usize) {
  42. if insn.imm == 0 {
  43. panic!("[Verifier] Error: division by 0 (insn #{:?})", insn_ptr);
  44. }
  45. }
  46. fn check_imm_endian(insn: &ebpf::Insn, insn_ptr: usize) {
  47. match insn.imm {
  48. 16 | 32 | 64 => return,
  49. _ => panic!("[Verifier] Error: unsupported argument for LE/BE (insn #{:?})", insn_ptr)
  50. }
  51. }
  52. fn check_load_dw(prog: &std::vec::Vec<u8>, insn_ptr: usize) {
  53. // We know we can reach next insn since we enforce an EXIT insn at the end of program, while
  54. // this function should be called only for LD_DW insn, that cannot be last in program.
  55. let next_insn = ebpf::get_insn(prog, insn_ptr + 1);
  56. if next_insn.opc != 0 {
  57. panic!("[Verifier] Error: incomplete LD_DW instruction (insn #{:?})", insn_ptr);
  58. }
  59. }
  60. fn check_jmp_offset(prog: &std::vec::Vec<u8>, insn_ptr: usize) {
  61. let insn = ebpf::get_insn(prog, insn_ptr);
  62. if insn.off == -1 {
  63. panic!("[Verifier] Error: infinite loop (insn #{:?})", insn_ptr);
  64. }
  65. let dst_insn_ptr = insn_ptr as isize + 1 + insn.off as isize;
  66. if dst_insn_ptr < 0 || dst_insn_ptr as usize >= (prog.len() / ebpf::INSN_SIZE) {
  67. panic!("[Verifier] Error: jump out of code to #{:?} (insn #{:?})",
  68. dst_insn_ptr, insn_ptr);
  69. }
  70. let dst_insn = ebpf::get_insn(prog, dst_insn_ptr as usize);
  71. if dst_insn.opc == 0 {
  72. panic!("[Verifier] Error: jump to middle of LD_DW at #{:?} (insn #{:?})",
  73. dst_insn_ptr, insn_ptr);
  74. }
  75. }
  76. fn check_registers(insn: &ebpf::Insn, store: bool, insn_ptr: usize) {
  77. if insn.src > 10 {
  78. panic!("[Verifier] Error: invalid source register (insn #{:?})", insn_ptr);
  79. }
  80. match (insn.dst, store) {
  81. (0 ... 9, _) => {},
  82. (10, true) => {},
  83. (10, false) => panic!("[Verifier] Error: cannot write into register r10 (insn #{:?})",
  84. insn_ptr),
  85. (_, _) => panic!("[Verifier] Error: invalid destination register (insn #{:?})",
  86. insn_ptr)
  87. }
  88. }
  89. pub fn check(prog: &std::vec::Vec<u8>) -> bool {
  90. check_prog_len(prog);
  91. let mut insn_ptr:usize = 0;
  92. while insn_ptr * ebpf::INSN_SIZE < prog.len() {
  93. let insn = ebpf::get_insn(prog, insn_ptr);
  94. let mut store = false;
  95. match insn.opc {
  96. // BPF_LD class
  97. ebpf::LD_ABS_B => { unimplemented!(); },
  98. ebpf::LD_ABS_H => { unimplemented!(); },
  99. ebpf::LD_ABS_W => { unimplemented!(); },
  100. ebpf::LD_ABS_DW => { unimplemented!(); },
  101. ebpf::LD_IND_B => { unimplemented!(); },
  102. ebpf::LD_IND_H => { unimplemented!(); },
  103. ebpf::LD_IND_W => { unimplemented!(); },
  104. ebpf::LD_IND_DW => { unimplemented!(); },
  105. // BPF_LDX class
  106. ebpf::LD_DW_IMM => {
  107. store = true;
  108. check_load_dw(prog, insn_ptr);
  109. insn_ptr += 1;
  110. },
  111. ebpf::LD_B_REG => {},
  112. ebpf::LD_H_REG => {},
  113. ebpf::LD_W_REG => {},
  114. ebpf::LD_DW_REG => {},
  115. // BPF_ST class
  116. ebpf::ST_B_IMM => store = true,
  117. ebpf::ST_H_IMM => store = true,
  118. ebpf::ST_W_IMM => store = true,
  119. ebpf::ST_DW_IMM => store = true,
  120. // BPF_STX class
  121. ebpf::ST_B_REG => store = true,
  122. ebpf::ST_H_REG => store = true,
  123. ebpf::ST_W_REG => store = true,
  124. ebpf::ST_DW_REG => store = true,
  125. ebpf::ST_W_XADD => { unimplemented!(); },
  126. ebpf::ST_DW_XADD => { unimplemented!(); },
  127. // BPF_ALU class
  128. ebpf::ADD32_IMM => {},
  129. ebpf::ADD32_REG => {},
  130. ebpf::SUB32_IMM => {},
  131. ebpf::SUB32_REG => {},
  132. ebpf::MUL32_IMM => {},
  133. ebpf::MUL32_REG => {},
  134. ebpf::DIV32_IMM => { check_imm_nonzero(&insn, insn_ptr); },
  135. ebpf::DIV32_REG => {},
  136. ebpf::OR32_IMM => {},
  137. ebpf::OR32_REG => {},
  138. ebpf::AND32_IMM => {},
  139. ebpf::AND32_REG => {},
  140. ebpf::LSH32_IMM => {},
  141. ebpf::LSH32_REG => {},
  142. ebpf::RSH32_IMM => {},
  143. ebpf::RSH32_REG => {},
  144. ebpf::NEG32 => {},
  145. ebpf::MOD32_IMM => { check_imm_nonzero(&insn, insn_ptr); },
  146. ebpf::MOD32_REG => {},
  147. ebpf::XOR32_IMM => {},
  148. ebpf::XOR32_REG => {},
  149. ebpf::MOV32_IMM => {},
  150. ebpf::MOV32_REG => {},
  151. ebpf::ARSH32_IMM => {},
  152. ebpf::ARSH32_REG => {},
  153. ebpf::LE => { check_imm_endian(&insn, insn_ptr); },
  154. ebpf::BE => { check_imm_endian(&insn, insn_ptr); },
  155. // BPF_ALU64 class
  156. ebpf::ADD64_IMM => {},
  157. ebpf::ADD64_REG => {},
  158. ebpf::SUB64_IMM => {},
  159. ebpf::SUB64_REG => {},
  160. ebpf::MUL64_IMM => { check_imm_nonzero(&insn, insn_ptr); },
  161. ebpf::MUL64_REG => {},
  162. ebpf::DIV64_IMM => { check_imm_nonzero(&insn, insn_ptr); },
  163. ebpf::DIV64_REG => {},
  164. ebpf::OR64_IMM => {},
  165. ebpf::OR64_REG => {},
  166. ebpf::AND64_IMM => {},
  167. ebpf::AND64_REG => {},
  168. ebpf::LSH64_IMM => {},
  169. ebpf::LSH64_REG => {},
  170. ebpf::RSH64_IMM => {},
  171. ebpf::RSH64_REG => {},
  172. ebpf::NEG64 => {},
  173. ebpf::MOD64_IMM => {},
  174. ebpf::MOD64_REG => {},
  175. ebpf::XOR64_IMM => {},
  176. ebpf::XOR64_REG => {},
  177. ebpf::MOV64_IMM => {},
  178. ebpf::MOV64_REG => {},
  179. ebpf::ARSH64_IMM => {},
  180. ebpf::ARSH64_REG => {},
  181. // BPF_JMP class
  182. ebpf::JA => { check_jmp_offset(prog, insn_ptr); },
  183. ebpf::JEQ_IMM => { check_jmp_offset(prog, insn_ptr); },
  184. ebpf::JEQ_REG => { check_jmp_offset(prog, insn_ptr); },
  185. ebpf::JGT_IMM => { check_jmp_offset(prog, insn_ptr); },
  186. ebpf::JGT_REG => { check_jmp_offset(prog, insn_ptr); },
  187. ebpf::JGE_IMM => { check_jmp_offset(prog, insn_ptr); },
  188. ebpf::JGE_REG => { check_jmp_offset(prog, insn_ptr); },
  189. ebpf::JSET_IMM => { check_jmp_offset(prog, insn_ptr); },
  190. ebpf::JSET_REG => { check_jmp_offset(prog, insn_ptr); },
  191. ebpf::JNE_IMM => { check_jmp_offset(prog, insn_ptr); },
  192. ebpf::JNE_REG => { check_jmp_offset(prog, insn_ptr); },
  193. ebpf::JSGT_IMM => { check_jmp_offset(prog, insn_ptr); },
  194. ebpf::JSGT_REG => { check_jmp_offset(prog, insn_ptr); },
  195. ebpf::JSGE_IMM => { check_jmp_offset(prog, insn_ptr); },
  196. ebpf::JSGE_REG => { check_jmp_offset(prog, insn_ptr); },
  197. ebpf::CALL => {},
  198. ebpf::TAIL_CALL => { unimplemented!() },
  199. ebpf::EXIT => {},
  200. _ => {
  201. panic!("[Verifier] Error: unknown eBPF opcode {:#2x} (insn #{:?})",
  202. insn.opc, insn_ptr);
  203. },
  204. }
  205. check_registers(&insn, store, insn_ptr);
  206. insn_ptr += 1;
  207. }
  208. // insn_ptr should now be equal to number of instructions.
  209. if insn_ptr != prog.len() / ebpf::INSN_SIZE {
  210. panic!("[Verifier] Error: jumped out of code to #{:?}", insn_ptr);
  211. }
  212. true
  213. }