helpers.rs 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488
  1. // SPDX-License-Identifier: (Apache-2.0 OR MIT)
  2. // Copyright 2015 Big Switch Networks, Inc
  3. // (Algorithms for uBPF helpers, originally in C)
  4. // Copyright 2016 6WIND S.A. <quentin.monnet@6wind.com>
  5. // (Translation to Rust, other helpers)
  6. //! This module implements some built-in helpers that can be called from within an eBPF program.
  7. //!
  8. //! These helpers may originate from several places:
  9. //!
  10. //! * Some of them mimic the helpers available in the Linux kernel.
  11. //! * Some of them were proposed as example helpers in uBPF and they were adapted here.
  12. //! * Other helpers may be specific to rbpf.
  13. //!
  14. //! The prototype for helpers is always the same: five `u64` as arguments, and a `u64` as a return
  15. //! value. Hence some helpers have unused arguments, or return a 0 value in all cases, in order to
  16. //! respect this convention.
  17. // Helpers associated to kernel helpers
  18. // See also linux/include/uapi/linux/bpf.h in Linux kernel sources.
  19. // bpf_ktime_getns()
  20. /// Index of helper `bpf_ktime_getns()`, equivalent to `bpf_time_getns()`, in Linux kernel, see
  21. /// <https://git.kernel.org/cgit/linux/kernel/git/torvalds/linux.git/tree/include/uapi/linux/bpf.h>.
  22. pub const BPF_KTIME_GETNS_IDX: u32 = 5;
  23. /// Get monotonic time (since boot time) in nanoseconds. All arguments are unused.
  24. ///
  25. /// # Examples
  26. ///
  27. /// ```
  28. /// use rbpf::helpers;
  29. ///
  30. /// let t = helpers::bpf_time_getns(0, 0, 0, 0, 0);
  31. /// let d = t / 10u64.pow(9) / 60 / 60 / 24;
  32. /// let h = (t / 10u64.pow(9) / 60 / 60) % 24;
  33. /// let m = (t / 10u64.pow(9) / 60 ) % 60;
  34. /// let s = (t / 10u64.pow(9)) % 60;
  35. /// let ns = t % 10u64.pow(9);
  36. /// println!("Uptime: {:#x} == {} days {}:{}:{}, {} ns", t, d, h, m, s, ns);
  37. /// ```
  38. #[allow(dead_code)]
  39. #[allow(unused_variables)]
  40. #[allow(deprecated)]
  41. #[cfg(feature = "std")]
  42. pub fn bpf_time_getns(unused1: u64, unused2: u64, unused3: u64, unused4: u64, unused5: u64) -> u64 {
  43. time::precise_time_ns()
  44. }
  45. // bpf_trace_printk()
  46. /// Index of helper `bpf_trace_printk()`, equivalent to `bpf_trace_printf()`, in Linux kernel, see
  47. /// <https://git.kernel.org/cgit/linux/kernel/git/torvalds/linux.git/tree/include/uapi/linux/bpf.h>.
  48. pub const BPF_TRACE_PRINTK_IDX: u32 = 6;
  49. /// Prints its **last three** arguments to standard output. The **first two** arguments are
  50. /// **unused**. Returns the number of bytes written.
  51. ///
  52. /// By ignoring the first two arguments, it creates a helper that will have a behavior similar to
  53. /// the one of the equivalent helper `bpf_trace_printk()` from Linux kernel.
  54. ///
  55. /// # Examples
  56. ///
  57. /// ```
  58. /// use rbpf::helpers;
  59. ///
  60. /// let res = helpers::bpf_trace_printf(0, 0, 1, 15, 32);
  61. /// assert_eq!(res as usize, "bpf_trace_printf: 0x1, 0xf, 0x20\n".len());
  62. /// ```
  63. ///
  64. /// This will print `bpf_trace_printf: 0x1, 0xf, 0x20`.
  65. ///
  66. /// The eBPF code needed to perform the call in this example would be nearly identical to the code
  67. /// obtained by compiling the following code from C to eBPF with clang:
  68. ///
  69. /// ```c
  70. /// #include <linux/bpf.h>
  71. /// #include "path/to/linux/samples/bpf/bpf_helpers.h"
  72. ///
  73. /// int main(struct __sk_buff *skb)
  74. /// {
  75. /// // Only %d %u %x %ld %lu %lx %lld %llu %llx %p %s conversion specifiers allowed.
  76. /// // See <https://git.kernel.org/cgit/linux/kernel/git/torvalds/linux.git/tree/kernel/trace/bpf_trace.c>.
  77. /// char *fmt = "bpf_trace_printk %llx, %llx, %llx\n";
  78. /// return bpf_trace_printk(fmt, sizeof(fmt), 1, 15, 32);
  79. /// }
  80. /// ```
  81. ///
  82. /// This would equally print the three numbers in `/sys/kernel/debug/tracing` file each time the
  83. /// program is run.
  84. #[allow(dead_code)]
  85. #[allow(unused_variables)]
  86. #[cfg(feature = "std")]
  87. pub fn bpf_trace_printf(unused1: u64, unused2: u64, arg3: u64, arg4: u64, arg5: u64) -> u64 {
  88. println!("bpf_trace_printf: {arg3:#x}, {arg4:#x}, {arg5:#x}");
  89. let size_arg = |x| {
  90. if x == 0 {
  91. 1
  92. } else {
  93. (x as f64).log(16.0).floor() as u64 + 1
  94. }
  95. };
  96. "bpf_trace_printf: 0x, 0x, 0x\n".len() as u64 + size_arg(arg3) + size_arg(arg4) + size_arg(arg5)
  97. }
  98. // Helpers coming from uBPF <https://github.com/iovisor/ubpf/blob/master/vm/test.c>
  99. /// The idea is to assemble five bytes into a single `u64`. For compatibility with the helpers API,
  100. /// each argument must be a `u64`.
  101. ///
  102. /// # Examples
  103. ///
  104. /// ```
  105. /// use rbpf::helpers;
  106. ///
  107. /// let gathered = helpers::gather_bytes(0x11, 0x22, 0x33, 0x44, 0x55);
  108. /// assert_eq!(gathered, 0x1122334455);
  109. /// ```
  110. pub fn gather_bytes(arg1: u64, arg2: u64, arg3: u64, arg4: u64, arg5: u64) -> u64 {
  111. arg1.wrapping_shl(32)
  112. | arg2.wrapping_shl(24)
  113. | arg3.wrapping_shl(16)
  114. | arg4.wrapping_shl(8)
  115. | arg5
  116. }
  117. /// Same as `void *memfrob(void *s, size_t n);` in `string.h` in C. See the GNU manual page (in
  118. /// section 3) for `memfrob`. The memory is directly modified, and the helper returns 0 in all
  119. /// cases. Arguments 3 to 5 are unused.
  120. ///
  121. /// # Examples
  122. ///
  123. /// ```
  124. /// use rbpf::helpers;
  125. ///
  126. /// let val: u64 = 0x112233;
  127. /// let val_ptr = &val as *const u64;
  128. ///
  129. /// helpers::memfrob(val_ptr as u64, 8, 0, 0, 0);
  130. /// assert_eq!(val, 0x2a2a2a2a2a3b0819);
  131. /// helpers::memfrob(val_ptr as u64, 8, 0, 0, 0);
  132. /// assert_eq!(val, 0x112233);
  133. /// ```
  134. #[allow(unused_variables)]
  135. pub fn memfrob(ptr: u64, len: u64, unused3: u64, unused4: u64, unused5: u64) -> u64 {
  136. for i in 0..len {
  137. unsafe {
  138. let mut p = (ptr + i) as *mut u8;
  139. *p ^= 0b101010;
  140. }
  141. }
  142. 0
  143. }
  144. // TODO: Try again when asm!() is available in stable Rust.
  145. // #![feature(asm)]
  146. // #[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
  147. // #[allow(unused_variables)]
  148. // pub fn memfrob (ptr: u64, len: u64, arg3: u64, arg4: u64, arg5: u64) -> u64 {
  149. // unsafe {
  150. // asm!(
  151. // "mov $0xf0, %rax"
  152. // ::: "mov $0xf1, %rcx"
  153. // ::: "mov $0xf2, %rdx"
  154. // ::: "mov $0xf3, %rsi"
  155. // ::: "mov $0xf4, %rdi"
  156. // ::: "mov $0xf5, %r8"
  157. // ::: "mov $0xf6, %r9"
  158. // ::: "mov $0xf7, %r10"
  159. // ::: "mov $0xf8, %r11"
  160. // );
  161. // }
  162. // 0
  163. // }
  164. /// Compute and return the square root of argument 1, cast as a float. Arguments 2 to 5 are
  165. /// unused.
  166. ///
  167. /// # Examples
  168. ///
  169. /// ```
  170. /// use rbpf::helpers;
  171. ///
  172. /// let x = helpers::sqrti(9, 0, 0, 0, 0);
  173. /// assert_eq!(x, 3);
  174. /// ```
  175. #[allow(dead_code)]
  176. #[allow(unused_variables)]
  177. #[cfg(feature = "std")] // sqrt is only available when using `std`
  178. pub fn sqrti(arg1: u64, unused2: u64, unused3: u64, unused4: u64, unused5: u64) -> u64 {
  179. (arg1 as f64).sqrt() as u64
  180. }
  181. /// C-like `strcmp`, return 0 if the strings are equal, and a non-null value otherwise.
  182. ///
  183. /// # Examples
  184. ///
  185. /// ```
  186. /// use rbpf::helpers;
  187. ///
  188. /// let foo = "This is a string.\0".as_ptr() as u64;
  189. /// let bar = "This is another sting.\0".as_ptr() as u64;
  190. ///
  191. /// assert!(helpers::strcmp(foo, foo, 0, 0, 0) == 0);
  192. /// assert!(helpers::strcmp(foo, bar, 0, 0, 0) != 0);
  193. /// ```
  194. #[allow(dead_code)]
  195. #[allow(unused_variables)]
  196. pub fn strcmp(arg1: u64, arg2: u64, arg3: u64, unused4: u64, unused5: u64) -> u64 {
  197. // C-like strcmp, maybe shorter than converting the bytes to string and comparing?
  198. if arg1 == 0 || arg2 == 0 {
  199. return u64::MAX;
  200. }
  201. let mut a = arg1;
  202. let mut b = arg2;
  203. unsafe {
  204. let mut a_val = *(a as *const u8);
  205. let mut b_val = *(b as *const u8);
  206. while a_val == b_val && a_val != 0 && b_val != 0 {
  207. a += 1;
  208. b += 1;
  209. a_val = *(a as *const u8);
  210. b_val = *(b as *const u8);
  211. }
  212. if a_val >= b_val {
  213. (a_val - b_val) as u64
  214. } else {
  215. (b_val - a_val) as u64
  216. }
  217. }
  218. }
  219. // Some additional helpers
  220. /// Returns a random u64 value comprised between `min` and `max` values (inclusive). Arguments 3 to
  221. /// 5 are unused.
  222. ///
  223. /// Relies on `rand()` function from libc, so `libc::srand()` should be called once before this
  224. /// helper is used.
  225. ///
  226. /// # Examples
  227. ///
  228. /// ```
  229. /// extern crate libc;
  230. /// extern crate rbpf;
  231. /// extern crate time;
  232. ///
  233. /// unsafe {
  234. /// libc::srand(time::precise_time_ns() as u32)
  235. /// }
  236. ///
  237. /// let n = rbpf::helpers::rand(3, 6, 0, 0, 0);
  238. /// assert!(3 <= n && n <= 6);
  239. /// ```
  240. #[allow(dead_code)]
  241. #[allow(unused_variables)]
  242. #[cfg(feature = "std")]
  243. pub fn rand(min: u64, max: u64, unused3: u64, unused4: u64, unused5: u64) -> u64 {
  244. let mut n = unsafe { (libc::rand() as u64).wrapping_shl(32) + libc::rand() as u64 };
  245. if min < max {
  246. n = n % (max + 1 - min) + min;
  247. };
  248. n
  249. }
  250. /// Prints the helper functions name and it's index.
  251. #[cfg(feature = "std")]
  252. pub fn show_helper() {
  253. for (index, name) in BPF_FUNC_MAPPER.iter().enumerate() {
  254. println!("{}:{}", index, name);
  255. }
  256. }
  257. /// See https://github.com/torvalds/linux/blob/master/include/uapi/linux/bpf.h
  258. pub const BPF_FUNC_MAPPER: &[&str] = &[
  259. "unspec",
  260. "map_lookup_elem",
  261. "map_update_elem",
  262. "map_delete_elem",
  263. "probe_read",
  264. "ktime_get_ns",
  265. "trace_printk",
  266. "get_prandom_u32",
  267. "get_smp_processor_id",
  268. "skb_store_bytes",
  269. "l3_csum_replace",
  270. "l4_csum_replace",
  271. "tail_call",
  272. "clone_redirect",
  273. "get_current_pid_tgid",
  274. "get_current_uid_gid",
  275. "get_current_comm",
  276. "get_cgroup_classid",
  277. "skb_vlan_push",
  278. "skb_vlan_pop",
  279. "skb_get_tunnel_key",
  280. "skb_set_tunnel_key",
  281. "perf_event_read",
  282. "redirect",
  283. "get_route_realm",
  284. "perf_event_output",
  285. "skb_load_bytes",
  286. "get_stackid",
  287. "csum_diff",
  288. "skb_get_tunnel_opt",
  289. "skb_set_tunnel_opt",
  290. "skb_change_proto",
  291. "skb_change_type",
  292. "skb_under_cgroup",
  293. "get_hash_recalc",
  294. "get_current_task",
  295. "probe_write_user",
  296. "current_task_under_cgroup",
  297. "skb_change_tail",
  298. "skb_pull_data",
  299. "csum_update",
  300. "set_hash_invalid",
  301. "get_numa_node_id",
  302. "skb_change_head",
  303. "xdp_adjust_head",
  304. "probe_read_str",
  305. "get_socket_cookie",
  306. "get_socket_uid",
  307. "set_hash",
  308. "setsockopt",
  309. "skb_adjust_room",
  310. "redirect_map",
  311. "sk_redirect_map",
  312. "sock_map_update",
  313. "xdp_adjust_meta",
  314. "perf_event_read_value",
  315. "perf_prog_read_value",
  316. "getsockopt",
  317. "override_return",
  318. "sock_ops_cb_flags_set",
  319. "msg_redirect_map",
  320. "msg_apply_bytes",
  321. "msg_cork_bytes",
  322. "msg_pull_data",
  323. "bind",
  324. "xdp_adjust_tail",
  325. "skb_get_xfrm_state",
  326. "get_stack",
  327. "skb_load_bytes_relative",
  328. "fib_lookup",
  329. "sock_hash_update",
  330. "msg_redirect_hash",
  331. "sk_redirect_hash",
  332. "lwt_push_encap",
  333. "lwt_seg6_store_bytes",
  334. "lwt_seg6_adjust_srh",
  335. "lwt_seg6_action",
  336. "rc_repeat",
  337. "rc_keydown",
  338. "skb_cgroup_id",
  339. "get_current_cgroup_id",
  340. "get_local_storage",
  341. "sk_select_reuseport",
  342. "skb_ancestor_cgroup_id",
  343. "sk_lookup_tcp",
  344. "sk_lookup_udp",
  345. "sk_release",
  346. "map_push_elem",
  347. "map_pop_elem",
  348. "map_peek_elem",
  349. "msg_push_data",
  350. "msg_pop_data",
  351. "rc_pointer_rel",
  352. "spin_lock",
  353. "spin_unlock",
  354. "sk_fullsock",
  355. "tcp_sock",
  356. "skb_ecn_set_ce",
  357. "get_listener_sock",
  358. "skc_lookup_tcp",
  359. "tcp_check_syncookie",
  360. "sysctl_get_name",
  361. "sysctl_get_current_value",
  362. "sysctl_get_new_value",
  363. "sysctl_set_new_value",
  364. "strtol",
  365. "strtoul",
  366. "sk_storage_get",
  367. "sk_storage_delete",
  368. "send_signal",
  369. "tcp_gen_syncookie",
  370. "skb_output",
  371. "probe_read_user",
  372. "probe_read_kernel",
  373. "probe_read_user_str",
  374. "probe_read_kernel_str",
  375. "tcp_send_ack",
  376. "send_signal_thread",
  377. "jiffies64",
  378. "read_branch_records",
  379. "get_ns_current_pid_tgid",
  380. "xdp_output",
  381. "get_netns_cookie",
  382. "get_current_ancestor_cgroup_id",
  383. "sk_assign",
  384. "ktime_get_boot_ns",
  385. "seq_printf",
  386. "seq_write",
  387. "sk_cgroup_id",
  388. "sk_ancestor_cgroup_id",
  389. "ringbuf_output",
  390. "ringbuf_reserve",
  391. "ringbuf_submit",
  392. "ringbuf_discard",
  393. "ringbuf_query",
  394. "csum_level",
  395. "skc_to_tcp6_sock",
  396. "skc_to_tcp_sock",
  397. "skc_to_tcp_timewait_sock",
  398. "skc_to_tcp_request_sock",
  399. "skc_to_udp6_sock",
  400. "get_task_stack",
  401. "load_hdr_opt",
  402. "store_hdr_opt",
  403. "reserve_hdr_opt",
  404. "inode_storage_get",
  405. "inode_storage_delete",
  406. "d_path",
  407. "copy_from_user",
  408. "snprintf_btf",
  409. "seq_printf_btf",
  410. "skb_cgroup_classid",
  411. "redirect_neigh",
  412. "per_cpu_ptr",
  413. "this_cpu_ptr",
  414. "redirect_peer",
  415. "task_storage_get",
  416. "task_storage_delete",
  417. "get_current_task_btf",
  418. "bprm_opts_set",
  419. "ktime_get_coarse_ns",
  420. "ima_inode_hash",
  421. "sock_from_file",
  422. "check_mtu",
  423. "for_each_map_elem",
  424. "snprintf",
  425. "sys_bpf",
  426. "btf_find_by_name_kind",
  427. "sys_close",
  428. "timer_init",
  429. "timer_set_callback",
  430. "timer_start",
  431. "timer_cancel",
  432. "get_func_ip",
  433. "get_attach_cookie",
  434. "task_pt_regs",
  435. "get_branch_snapshot",
  436. "trace_vprintk",
  437. "skc_to_unix_sock",
  438. "kallsyms_lookup_name",
  439. "find_vma",
  440. "loop",
  441. "strncmp",
  442. "get_func_arg",
  443. "get_func_ret",
  444. "get_func_arg_cnt",
  445. "get_retval",
  446. "set_retval",
  447. "xdp_get_buff_len",
  448. "xdp_load_bytes",
  449. "xdp_store_bytes",
  450. "copy_from_user_task",
  451. "skb_set_tstamp",
  452. "ima_file_hash",
  453. "kptr_xchg",
  454. "map_lookup_percpu_elem",
  455. "skc_to_mptcp_sock",
  456. "dynptr_from_mem",
  457. "ringbuf_reserve_dynptr",
  458. "ringbuf_submit_dynptr",
  459. "ringbuf_discard_dynptr",
  460. "dynptr_read",
  461. "dynptr_write",
  462. "dynptr_data",
  463. "tcp_raw_gen_syncookie_ipv4",
  464. "tcp_raw_gen_syncookie_ipv6",
  465. "tcp_raw_check_syncookie_ipv4",
  466. "tcp_raw_check_syncookie_ipv6",
  467. "ktime_get_tai_ns",
  468. "user_ringbuf_drain",
  469. "cgrp_storage_get",
  470. "cgrp_storage_delete",
  471. ];