helpers.rs 8.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273
  1. // Copyright 2015 Big Switch Networks, Inc
  2. // (Algorithms for uBPF helpers, originally in C)
  3. // Copyright 2016 6WIND S.A. <quentin.monnet@6wind.com>
  4. // (Translation to Rust, other helpers)
  5. //
  6. // Licensed under the Apache License, Version 2.0 <http://www.apache.org/licenses/LICENSE-2.0> or
  7. // the MIT license <http://opensource.org/licenses/MIT>, at your option. This file may not be
  8. // copied, modified, or distributed except according to those terms.
  9. //! This module implements some built-in helpers that can be called from within an eBPF program.
  10. //!
  11. //! These helpers may originate from several places:
  12. //!
  13. //! * Some of them mimic the helpers available in the Linux kernel.
  14. //! * Some of them were proposed as example helpers in uBPF and they were adapted here.
  15. //! * Other helpers may be specific to rbpf.
  16. //!
  17. //! The prototype for helpers is always the same: five `u64` as arguments, and a `u64` as a return
  18. //! value. Hence some helpers have unused arguments, or return a 0 value in all cases, in order to
  19. //! respect this convention.
  20. extern crate libc;
  21. use std::u64;
  22. use time;
  23. // Helpers associated to kernel helpers
  24. // See also linux/include/uapi/linux/bpf.h in Linux kernel sources.
  25. // bpf_ktime_getns()
  26. /// Index of helper `bpf_ktime_getns()`, equivalent to `bpf_time_getns()`, in Linux kernel, see
  27. /// <https://git.kernel.org/cgit/linux/kernel/git/torvalds/linux.git/tree/include/uapi/linux/bpf.h>.
  28. pub const BPF_KTIME_GETNS_IDX: u32 = 5;
  29. /// Get monotonic time (since boot time) in nanoseconds. All arguments are unused.
  30. ///
  31. /// # Examples
  32. ///
  33. /// ```
  34. /// use rbpf::helpers;
  35. ///
  36. /// let t = helpers::bpf_time_getns(0, 0, 0, 0, 0);
  37. /// let d = t / 10u64.pow(9) / 60 / 60 / 24;
  38. /// let h = (t / 10u64.pow(9) / 60 / 60) % 24;
  39. /// let m = (t / 10u64.pow(9) / 60 ) % 60;
  40. /// let s = (t / 10u64.pow(9)) % 60;
  41. /// let ns = t % 10u64.pow(9);
  42. /// println!("Uptime: {:#x} == {} days {}:{}:{}, {} ns", t, d, h, m, s, ns);
  43. /// ```
  44. #[allow(dead_code)]
  45. #[allow(unused_variables)]
  46. pub fn bpf_time_getns (unused1: u64, unused2: u64, unused3: u64, unused4: u64, unused5: u64) -> u64 {
  47. time::precise_time_ns()
  48. }
  49. // bpf_trace_printk()
  50. /// Index of helper `bpf_trace_printk()`, equivalent to `bpf_trace_printf()`, in Linux kernel, see
  51. /// <https://git.kernel.org/cgit/linux/kernel/git/torvalds/linux.git/tree/include/uapi/linux/bpf.h>.
  52. pub const BPF_TRACE_PRINTK_IDX: u32 = 6;
  53. /// Prints its **last three** arguments to standard output. The **first two** arguments are
  54. /// **unused**. Returns the number of bytes written.
  55. ///
  56. /// By ignoring the first two arguments, it creates a helper that will have a behavior similar to
  57. /// the one of the equivalent helper `bpf_trace_printk()` from Linux kernel.
  58. ///
  59. /// # Examples
  60. ///
  61. /// ```
  62. /// use rbpf::helpers;
  63. ///
  64. /// let res = helpers::bpf_trace_printf(0, 0, 1, 15, 32);
  65. /// assert_eq!(res as usize, "bpf_trace_printf: 0x1, 0xf, 0x20\n".len());
  66. /// ```
  67. ///
  68. /// This will print `bpf_trace_printf: 0x1, 0xf, 0x20`.
  69. ///
  70. /// The eBPF code needed to perform the call in this example would be nearly identical to the code
  71. /// obtained by compiling the following code from C to eBPF with clang:
  72. ///
  73. /// ```c
  74. /// #include <linux/bpf.h>
  75. /// #include "path/to/linux/samples/bpf/bpf_helpers.h"
  76. ///
  77. /// int main(struct __sk_buff *skb)
  78. /// {
  79. /// // Only %d %u %x %ld %lu %lx %lld %llu %llx %p %s conversion specifiers allowed.
  80. /// // See <https://git.kernel.org/cgit/linux/kernel/git/torvalds/linux.git/tree/kernel/trace/bpf_trace.c>.
  81. /// char *fmt = "bpf_trace_printk %llx, %llx, %llx\n";
  82. /// return bpf_trace_printk(fmt, sizeof(fmt), 1, 15, 32);
  83. /// }
  84. /// ```
  85. ///
  86. /// This would equally print the three numbers in `/sys/kernel/debug/tracing` file each time the
  87. /// program is run.
  88. #[allow(dead_code)]
  89. #[allow(unused_variables)]
  90. pub fn bpf_trace_printf (unused1: u64, unused2: u64, arg3: u64, arg4: u64, arg5: u64) -> u64 {
  91. println!("bpf_trace_printf: {:#x}, {:#x}, {:#x}", arg3, arg4, arg5);
  92. let size_arg = | x | {
  93. if x == 0 {
  94. 1
  95. } else {
  96. (x as f64).log(16.0).floor() as u64 + 1
  97. }
  98. };
  99. "bpf_trace_printf: 0x, 0x, 0x\n".len() as u64
  100. + size_arg(arg3) + size_arg(arg4) + size_arg(arg5)
  101. }
  102. // Helpers coming from uBPF <https://github.com/iovisor/ubpf/blob/master/vm/test.c>
  103. /// The idea is to assemble five bytes into a single `u64`. For compatibility with the helpers API,
  104. /// each argument must be a `u64`.
  105. ///
  106. /// # Examples
  107. ///
  108. /// ```
  109. /// use rbpf::helpers;
  110. ///
  111. /// let gathered = helpers::gather_bytes(0x11, 0x22, 0x33, 0x44, 0x55);
  112. /// assert_eq!(gathered, 0x1122334455);
  113. /// ```
  114. pub fn gather_bytes (arg1: u64, arg2: u64, arg3: u64, arg4: u64, arg5: u64) -> u64 {
  115. arg1.wrapping_shl(32) |
  116. arg2.wrapping_shl(24) |
  117. arg3.wrapping_shl(16) |
  118. arg4.wrapping_shl(8) |
  119. arg5
  120. }
  121. /// Same as `void *memfrob(void *s, size_t n);` in `string.h` in C. See the GNU manual page (in
  122. /// section 3) for `memfrob`. The memory is directly modified, and the helper returns 0 in all
  123. /// cases. Arguments 3 to 5 are unused.
  124. ///
  125. /// # Examples
  126. ///
  127. /// ```
  128. /// use rbpf::helpers;
  129. ///
  130. /// let val: u64 = 0x112233;
  131. /// let val_ptr = &val as *const u64;
  132. ///
  133. /// helpers::memfrob(val_ptr as u64, 8, 0, 0, 0);
  134. /// assert_eq!(val, 0x2a2a2a2a2a3b0819);
  135. /// helpers::memfrob(val_ptr as u64, 8, 0, 0, 0);
  136. /// assert_eq!(val, 0x112233);
  137. /// ```
  138. #[allow(unused_variables)]
  139. pub fn memfrob (ptr: u64, len: u64, unused3: u64, unused4: u64, unused5: u64) -> u64 {
  140. for i in 0..len {
  141. unsafe {
  142. let mut p = (ptr + i) as *mut u8;
  143. *p ^= 0b101010;
  144. }
  145. }
  146. 0
  147. }
  148. // TODO: Try again when asm!() is available in stable Rust.
  149. // #![feature(asm)]
  150. // #[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
  151. // #[allow(unused_variables)]
  152. // pub fn memfrob (ptr: u64, len: u64, arg3: u64, arg4: u64, arg5: u64) -> u64 {
  153. // unsafe {
  154. // asm!(
  155. // "mov $0xf0, %rax"
  156. // ::: "mov $0xf1, %rcx"
  157. // ::: "mov $0xf2, %rdx"
  158. // ::: "mov $0xf3, %rsi"
  159. // ::: "mov $0xf4, %rdi"
  160. // ::: "mov $0xf5, %r8"
  161. // ::: "mov $0xf6, %r9"
  162. // ::: "mov $0xf7, %r10"
  163. // ::: "mov $0xf8, %r11"
  164. // );
  165. // }
  166. // 0
  167. // }
  168. /// Compute and return the square root of argument 1, cast as a float. Arguments 2 to 5 are
  169. /// unused.
  170. ///
  171. /// # Examples
  172. ///
  173. /// ```
  174. /// use rbpf::helpers;
  175. ///
  176. /// let x = helpers::sqrti(9, 0, 0, 0, 0);
  177. /// assert_eq!(x, 3);
  178. /// ```
  179. #[allow(dead_code)]
  180. #[allow(unused_variables)]
  181. pub fn sqrti (arg1: u64, unused2: u64, unused3: u64, unused4: u64, unused5: u64) -> u64 {
  182. (arg1 as f64).sqrt() as u64
  183. }
  184. /// C-like `strcmp`, return 0 if the strings are equal, and a non-null value otherwise.
  185. ///
  186. /// # Examples
  187. ///
  188. /// ```
  189. /// use rbpf::helpers;
  190. ///
  191. /// let foo = "This is a string.".as_ptr() as u64;
  192. /// let bar = "This is another sting.".as_ptr() as u64;
  193. ///
  194. /// assert!(helpers::strcmp(foo, foo, 0, 0, 0) == 0);
  195. /// assert!(helpers::strcmp(foo, bar, 0, 0, 0) != 0);
  196. /// ```
  197. #[allow(dead_code)]
  198. #[allow(unused_variables)]
  199. pub fn strcmp (arg1: u64, arg2: u64, arg3: u64, unused4: u64, unused5: u64) -> u64 {
  200. // C-like strcmp, maybe shorter than converting the bytes to string and comparing?
  201. if arg1 == 0 || arg2 == 0 {
  202. return u64::MAX;
  203. }
  204. let mut a = arg1;
  205. let mut b = arg2;
  206. unsafe {
  207. let mut a_val = *(a as *const u8);
  208. let mut b_val = *(b as *const u8);
  209. while a_val == b_val && a_val != 0 && b_val != 0 {
  210. a +=1 ;
  211. b +=1 ;
  212. a_val = *(a as *const u8);
  213. b_val = *(b as *const u8);
  214. }
  215. if a_val >= b_val {
  216. (a_val - b_val) as u64
  217. } else {
  218. (b_val - a_val) as u64
  219. }
  220. }
  221. }
  222. // Some additional helpers
  223. /// Returns a random u64 value comprised between `min` and `max` values (inclusive). Arguments 3 to
  224. /// 5 are unused.
  225. ///
  226. /// Relies on `rand()` function from libc, so `libc::srand()` should be called once before this
  227. /// helper is used.
  228. ///
  229. /// # Examples
  230. ///
  231. /// ```
  232. /// extern crate libc;
  233. /// extern crate rbpf;
  234. /// extern crate time;
  235. ///
  236. /// unsafe {
  237. /// libc::srand(time::precise_time_ns() as u32)
  238. /// }
  239. ///
  240. /// let n = rbpf::helpers::rand(3, 6, 0, 0, 0);
  241. /// assert!(3 <= n && n <= 6);
  242. /// ```
  243. #[allow(dead_code)]
  244. #[allow(unused_variables)]
  245. pub fn rand (min: u64, max: u64, unused3: u64, unused4: u64, unused5: u64) -> u64 {
  246. let mut n = unsafe {
  247. (libc::rand() as u64).wrapping_shl(32) + libc::rand() as u64
  248. };
  249. if min < max {
  250. n = n % (max + 1 - min) + min;
  251. };
  252. n
  253. }