lsm.rs 3.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125
  1. use std::borrow::Cow;
  2. use proc_macro2::TokenStream;
  3. use quote::quote;
  4. use syn::{ItemFn, Result};
  5. use crate::args::{err_on_unknown_args, pop_bool_arg, pop_string_arg};
  6. pub(crate) struct Lsm {
  7. item: ItemFn,
  8. hook: Option<String>,
  9. sleepable: bool,
  10. }
  11. impl Lsm {
  12. pub(crate) fn parse(attrs: TokenStream, item: TokenStream) -> Result<Self> {
  13. let item = syn::parse2(item)?;
  14. let mut args = syn::parse2(attrs)?;
  15. let hook = pop_string_arg(&mut args, "hook");
  16. let sleepable = pop_bool_arg(&mut args, "sleepable");
  17. err_on_unknown_args(&args)?;
  18. Ok(Self {
  19. item,
  20. hook,
  21. sleepable,
  22. })
  23. }
  24. pub(crate) fn expand(&self) -> TokenStream {
  25. let Self {
  26. item,
  27. hook,
  28. sleepable,
  29. } = self;
  30. let ItemFn {
  31. attrs: _,
  32. vis,
  33. sig,
  34. block: _,
  35. } = item;
  36. let section_prefix = if *sleepable { "lsm.s" } else { "lsm" };
  37. let section_name: Cow<'_, _> = if let Some(hook) = hook {
  38. format!("{}/{}", section_prefix, hook).into()
  39. } else {
  40. section_prefix.into()
  41. };
  42. // LSM probes need to return an integer corresponding to the correct
  43. // policy decision. Therefore we do not simply default to a return value
  44. // of 0 as in other program types.
  45. let fn_name = &sig.ident;
  46. quote! {
  47. #[unsafe(no_mangle)]
  48. #[unsafe(link_section = #section_name)]
  49. #vis fn #fn_name(ctx: *mut ::core::ffi::c_void) -> i32 {
  50. return #fn_name(::aya_ebpf::programs::LsmContext::new(ctx));
  51. #item
  52. }
  53. }
  54. }
  55. }
  56. #[cfg(test)]
  57. mod tests {
  58. use syn::parse_quote;
  59. use super::*;
  60. #[test]
  61. fn test_lsm_sleepable() {
  62. let prog = Lsm::parse(
  63. parse_quote! {
  64. sleepable,
  65. hook = "bprm_committed_creds"
  66. },
  67. parse_quote! {
  68. fn bprm_committed_creds(ctx: &mut ::aya_ebpf::programs::LsmContext) -> i32 {
  69. 0
  70. }
  71. },
  72. )
  73. .unwrap();
  74. let expanded = prog.expand();
  75. let expected = quote! {
  76. #[unsafe(no_mangle)]
  77. #[unsafe(link_section = "lsm.s/bprm_committed_creds")]
  78. fn bprm_committed_creds(ctx: *mut ::core::ffi::c_void) -> i32 {
  79. return bprm_committed_creds(::aya_ebpf::programs::LsmContext::new(ctx));
  80. fn bprm_committed_creds(ctx: &mut ::aya_ebpf::programs::LsmContext) -> i32 {
  81. 0
  82. }
  83. }
  84. };
  85. assert_eq!(expected.to_string(), expanded.to_string());
  86. }
  87. #[test]
  88. fn test_lsm() {
  89. let prog = Lsm::parse(
  90. parse_quote! {
  91. hook = "bprm_committed_creds"
  92. },
  93. parse_quote! {
  94. fn bprm_committed_creds(ctx: &mut ::aya_ebpf::programs::LsmContext) -> i32 {
  95. 0
  96. }
  97. },
  98. )
  99. .unwrap();
  100. let expanded = prog.expand();
  101. let expected = quote! {
  102. #[unsafe(no_mangle)]
  103. #[unsafe(link_section = "lsm/bprm_committed_creds")]
  104. fn bprm_committed_creds(ctx: *mut ::core::ffi::c_void) -> i32 {
  105. return bprm_committed_creds(::aya_ebpf::programs::LsmContext::new(ctx));
  106. fn bprm_committed_creds(ctx: &mut ::aya_ebpf::programs::LsmContext) -> i32 {
  107. 0
  108. }
  109. }
  110. };
  111. assert_eq!(expected.to_string(), expanded.to_string());
  112. }
  113. }