args.rs 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325
  1. // aarch64 uses user_pt_regs instead of pt_regs
  2. #[cfg(not(any(bpf_target_arch = "aarch64", bpf_target_arch = "riscv64")))]
  3. use crate::bindings::pt_regs;
  4. #[cfg(bpf_target_arch = "aarch64")]
  5. use crate::bindings::user_pt_regs as pt_regs;
  6. #[cfg(bpf_target_arch = "riscv64")]
  7. use crate::bindings::user_regs_struct as pt_regs;
  8. use crate::{cty::c_void, helpers::bpf_probe_read};
  9. /// A trait that indicates a valid type for an argument which can be coerced from a BTF
  10. /// context.
  11. ///
  12. /// Users should not implement this trait.
  13. ///
  14. /// SAFETY: This trait is _only_ safe to implement on primitive types that can fit into
  15. /// a `u64`. For example, integers and raw pointers may be coerced from a BTF context.
  16. pub unsafe trait FromBtfArgument: Sized {
  17. /// Coerces a `T` from the `n`th argument from a BTF context where `n` starts
  18. /// at 0 and increases by 1 for each successive argument.
  19. ///
  20. /// SAFETY: This function is deeply unsafe, as we are reading raw pointers into kernel
  21. /// memory. In particular, the value of `n` must not exceed the number of function
  22. /// arguments. Moreover, `ctx` must be a valid pointer to a BTF context, and `T` must
  23. /// be the right type for the given argument.
  24. unsafe fn from_argument(ctx: *const c_void, n: usize) -> Self;
  25. }
  26. unsafe impl<T> FromBtfArgument for *const T {
  27. unsafe fn from_argument(ctx: *const c_void, n: usize) -> *const T {
  28. // BTF arguments are exposed as an array of `usize` where `usize` can
  29. // either be treated as a pointer or a primitive type
  30. *(ctx as *const usize).add(n) as _
  31. }
  32. }
  33. /// Helper macro to implement [`FromBtfArgument`] for a primitive type.
  34. macro_rules! unsafe_impl_from_btf_argument {
  35. ($type:ident) => {
  36. unsafe impl FromBtfArgument for $type {
  37. unsafe fn from_argument(ctx: *const c_void, n: usize) -> Self {
  38. // BTF arguments are exposed as an array of `usize` where `usize` can
  39. // either be treated as a pointer or a primitive type
  40. *(ctx as *const usize).add(n) as _
  41. }
  42. }
  43. };
  44. }
  45. unsafe_impl_from_btf_argument!(u8);
  46. unsafe_impl_from_btf_argument!(u16);
  47. unsafe_impl_from_btf_argument!(u32);
  48. unsafe_impl_from_btf_argument!(u64);
  49. unsafe_impl_from_btf_argument!(i8);
  50. unsafe_impl_from_btf_argument!(i16);
  51. unsafe_impl_from_btf_argument!(i32);
  52. unsafe_impl_from_btf_argument!(i64);
  53. unsafe_impl_from_btf_argument!(usize);
  54. unsafe_impl_from_btf_argument!(isize);
  55. pub struct PtRegs {
  56. regs: *mut pt_regs,
  57. }
  58. /// A portable wrapper around pt_regs, user_pt_regs and user_regs_struct.
  59. impl PtRegs {
  60. pub fn new(regs: *mut pt_regs) -> Self {
  61. PtRegs { regs }
  62. }
  63. /// Returns the value of the register used to pass arg `n`.
  64. pub fn arg<T: FromPtRegs>(&self, n: usize) -> Option<T> {
  65. T::from_argument(unsafe { &*self.regs }, n)
  66. }
  67. /// Returns the value of the register used to pass the return value.
  68. pub fn ret<T: FromPtRegs>(&self) -> Option<T> {
  69. T::from_retval(unsafe { &*self.regs })
  70. }
  71. /// Returns a pointer to the wrapped value.
  72. pub fn as_ptr(&self) -> *mut pt_regs {
  73. self.regs
  74. }
  75. }
  76. /// A trait that indicates a valid type for an argument which can be coerced from
  77. /// a pt_regs context.
  78. ///
  79. /// Any implementation of this trait is strictly architecture-specific and depends on the
  80. /// layout of the underlying pt_regs struct and the target processor's calling
  81. /// conventions. Users should not implement this trait.
  82. pub trait FromPtRegs: Sized {
  83. /// Coerces a `T` from the `n`th argument of a pt_regs context where `n` starts
  84. /// at 0 and increases by 1 for each successive argument.
  85. fn from_argument(ctx: &pt_regs, n: usize) -> Option<Self>;
  86. /// Coerces a `T` from the return value of a pt_regs context.
  87. fn from_retval(ctx: &pt_regs) -> Option<Self>;
  88. }
  89. #[cfg(bpf_target_arch = "x86_64")]
  90. impl<T> FromPtRegs for *const T {
  91. fn from_argument(ctx: &pt_regs, n: usize) -> Option<Self> {
  92. match n {
  93. 0 => unsafe { bpf_probe_read(&ctx.rdi).map(|v| v as *const _).ok() },
  94. 1 => unsafe { bpf_probe_read(&ctx.rsi).map(|v| v as *const _).ok() },
  95. 2 => unsafe { bpf_probe_read(&ctx.rdx).map(|v| v as *const _).ok() },
  96. 3 => unsafe { bpf_probe_read(&ctx.rcx).map(|v| v as *const _).ok() },
  97. 4 => unsafe { bpf_probe_read(&ctx.r8).map(|v| v as *const _).ok() },
  98. 5 => unsafe { bpf_probe_read(&ctx.r9).map(|v| v as *const _).ok() },
  99. _ => None,
  100. }
  101. }
  102. fn from_retval(ctx: &pt_regs) -> Option<Self> {
  103. unsafe { bpf_probe_read(&ctx.rax).map(|v| v as *const _).ok() }
  104. }
  105. }
  106. #[cfg(bpf_target_arch = "arm")]
  107. impl<T> FromPtRegs for *const T {
  108. fn from_argument(ctx: &pt_regs, n: usize) -> Option<Self> {
  109. if n <= 6 {
  110. unsafe { bpf_probe_read(&ctx.uregs[n]).map(|v| v as *const _).ok() }
  111. } else {
  112. None
  113. }
  114. }
  115. fn from_retval(ctx: &pt_regs) -> Option<Self> {
  116. unsafe { bpf_probe_read(&ctx.uregs[0]).map(|v| v as *const _).ok() }
  117. }
  118. }
  119. #[cfg(bpf_target_arch = "aarch64")]
  120. impl<T> FromPtRegs for *const T {
  121. fn from_argument(ctx: &pt_regs, n: usize) -> Option<Self> {
  122. if n <= 7 {
  123. unsafe { bpf_probe_read(&ctx.regs[n]).map(|v| v as *const _).ok() }
  124. } else {
  125. None
  126. }
  127. }
  128. fn from_retval(ctx: &pt_regs) -> Option<Self> {
  129. unsafe { bpf_probe_read(&ctx.regs[0]).map(|v| v as *const _).ok() }
  130. }
  131. }
  132. #[cfg(bpf_target_arch = "riscv64")]
  133. impl<T> FromPtRegs for *const T {
  134. fn from_argument(ctx: &pt_regs, n: usize) -> Option<Self> {
  135. match n {
  136. 0 => unsafe { bpf_probe_read(&ctx.a0).map(|v| v as *const _).ok() },
  137. 1 => unsafe { bpf_probe_read(&ctx.a1).map(|v| v as *const _).ok() },
  138. 2 => unsafe { bpf_probe_read(&ctx.a2).map(|v| v as *const _).ok() },
  139. 3 => unsafe { bpf_probe_read(&ctx.a3).map(|v| v as *const _).ok() },
  140. 4 => unsafe { bpf_probe_read(&ctx.a4).map(|v| v as *const _).ok() },
  141. 5 => unsafe { bpf_probe_read(&ctx.a5).map(|v| v as *const _).ok() },
  142. 6 => unsafe { bpf_probe_read(&ctx.a6).map(|v| v as *const _).ok() },
  143. 7 => unsafe { bpf_probe_read(&ctx.a7).map(|v| v as *const _).ok() },
  144. _ => None,
  145. }
  146. }
  147. fn from_retval(ctx: &pt_regs) -> Option<Self> {
  148. unsafe { bpf_probe_read(&ctx.ra).map(|v| v as *const _).ok() }
  149. }
  150. }
  151. #[cfg(bpf_target_arch = "x86_64")]
  152. impl<T> FromPtRegs for *mut T {
  153. fn from_argument(ctx: &pt_regs, n: usize) -> Option<Self> {
  154. match n {
  155. 0 => unsafe { bpf_probe_read(&ctx.rdi).map(|v| v as *mut _).ok() },
  156. 1 => unsafe { bpf_probe_read(&ctx.rsi).map(|v| v as *mut _).ok() },
  157. 2 => unsafe { bpf_probe_read(&ctx.rdx).map(|v| v as *mut _).ok() },
  158. 3 => unsafe { bpf_probe_read(&ctx.rcx).map(|v| v as *mut _).ok() },
  159. 4 => unsafe { bpf_probe_read(&ctx.r8).map(|v| v as *mut _).ok() },
  160. 5 => unsafe { bpf_probe_read(&ctx.r9).map(|v| v as *mut _).ok() },
  161. _ => None,
  162. }
  163. }
  164. fn from_retval(ctx: &pt_regs) -> Option<Self> {
  165. unsafe { bpf_probe_read(&ctx.rax).map(|v| v as *mut _).ok() }
  166. }
  167. }
  168. #[cfg(bpf_target_arch = "arm")]
  169. impl<T> FromPtRegs for *mut T {
  170. fn from_argument(ctx: &pt_regs, n: usize) -> Option<Self> {
  171. if n <= 6 {
  172. unsafe { bpf_probe_read(&ctx.uregs[n]).map(|v| v as *mut _).ok() }
  173. } else {
  174. None
  175. }
  176. }
  177. fn from_retval(ctx: &pt_regs) -> Option<Self> {
  178. unsafe { bpf_probe_read(&ctx.uregs[0]).map(|v| v as *mut _).ok() }
  179. }
  180. }
  181. #[cfg(bpf_target_arch = "aarch64")]
  182. impl<T> FromPtRegs for *mut T {
  183. fn from_argument(ctx: &pt_regs, n: usize) -> Option<Self> {
  184. if n <= 7 {
  185. unsafe { bpf_probe_read(&ctx.regs[n]).map(|v| v as *mut _).ok() }
  186. } else {
  187. None
  188. }
  189. }
  190. fn from_retval(ctx: &pt_regs) -> Option<Self> {
  191. unsafe { bpf_probe_read(&ctx.regs[0]).map(|v| v as *mut _).ok() }
  192. }
  193. }
  194. #[cfg(bpf_target_arch = "riscv64")]
  195. impl<T> FromPtRegs for *mut T {
  196. fn from_argument(ctx: &pt_regs, n: usize) -> Option<Self> {
  197. match n {
  198. 0 => unsafe { bpf_probe_read(&ctx.a0).map(|v| v as *mut _).ok() },
  199. 1 => unsafe { bpf_probe_read(&ctx.a1).map(|v| v as *mut _).ok() },
  200. 2 => unsafe { bpf_probe_read(&ctx.a2).map(|v| v as *mut _).ok() },
  201. 3 => unsafe { bpf_probe_read(&ctx.a3).map(|v| v as *mut _).ok() },
  202. 4 => unsafe { bpf_probe_read(&ctx.a4).map(|v| v as *mut _).ok() },
  203. 5 => unsafe { bpf_probe_read(&ctx.a5).map(|v| v as *mut _).ok() },
  204. 6 => unsafe { bpf_probe_read(&ctx.a6).map(|v| v as *mut _).ok() },
  205. 7 => unsafe { bpf_probe_read(&ctx.a7).map(|v| v as *mut _).ok() },
  206. _ => None,
  207. }
  208. }
  209. fn from_retval(ctx: &pt_regs) -> Option<Self> {
  210. unsafe { bpf_probe_read(&ctx.ra).map(|v| v as *mut _).ok() }
  211. }
  212. }
  213. /// Helper macro to implement [`FromPtRegs`] for a primitive type.
  214. macro_rules! impl_from_pt_regs {
  215. ($type:ident) => {
  216. #[cfg(bpf_target_arch = "x86_64")]
  217. impl FromPtRegs for $type {
  218. fn from_argument(ctx: &pt_regs, n: usize) -> Option<Self> {
  219. match n {
  220. 0 => Some(ctx.rdi as *const $type as _),
  221. 1 => Some(ctx.rsi as *const $type as _),
  222. 2 => Some(ctx.rdx as *const $type as _),
  223. 3 => Some(ctx.rcx as *const $type as _),
  224. 4 => Some(ctx.r8 as *const $type as _),
  225. 5 => Some(ctx.r9 as *const $type as _),
  226. _ => None,
  227. }
  228. }
  229. fn from_retval(ctx: &pt_regs) -> Option<Self> {
  230. Some(ctx.rax as *const $type as _)
  231. }
  232. }
  233. #[cfg(bpf_target_arch = "arm")]
  234. impl FromPtRegs for $type {
  235. fn from_argument(ctx: &pt_regs, n: usize) -> Option<Self> {
  236. if n <= 6 {
  237. Some(ctx.uregs[n] as *const $type as _)
  238. } else {
  239. None
  240. }
  241. }
  242. fn from_retval(ctx: &pt_regs) -> Option<Self> {
  243. Some(ctx.uregs[0] as *const $type as _)
  244. }
  245. }
  246. #[cfg(bpf_target_arch = "aarch64")]
  247. impl FromPtRegs for $type {
  248. fn from_argument(ctx: &pt_regs, n: usize) -> Option<Self> {
  249. if n <= 7 {
  250. Some(ctx.regs[n] as *const $type as _)
  251. } else {
  252. None
  253. }
  254. }
  255. fn from_retval(ctx: &pt_regs) -> Option<Self> {
  256. Some(ctx.regs[0] as *const $type as _)
  257. }
  258. }
  259. #[cfg(bpf_target_arch = "riscv64")]
  260. impl FromPtRegs for $type {
  261. fn from_argument(ctx: &pt_regs, n: usize) -> Option<Self> {
  262. match n {
  263. 0 => Some(ctx.a0 as *const $type as _),
  264. 1 => Some(ctx.a1 as *const $type as _),
  265. 2 => Some(ctx.a2 as *const $type as _),
  266. 3 => Some(ctx.a3 as *const $type as _),
  267. 4 => Some(ctx.a4 as *const $type as _),
  268. 5 => Some(ctx.a5 as *const $type as _),
  269. 6 => Some(ctx.a6 as *const $type as _),
  270. 7 => Some(ctx.a7 as *const $type as _),
  271. _ => None,
  272. }
  273. }
  274. fn from_retval(ctx: &pt_regs) -> Option<Self> {
  275. Some(ctx.ra as *const $type as _)
  276. }
  277. }
  278. };
  279. }
  280. impl_from_pt_regs!(u8);
  281. impl_from_pt_regs!(u16);
  282. impl_from_pt_regs!(u32);
  283. impl_from_pt_regs!(u64);
  284. impl_from_pt_regs!(i8);
  285. impl_from_pt_regs!(i16);
  286. impl_from_pt_regs!(i32);
  287. impl_from_pt_regs!(i64);
  288. impl_from_pt_regs!(usize);
  289. impl_from_pt_regs!(isize);