xref: /DragonOS/kernel/src/bpf/prog/util.rs (revision 7b0ef10895108a0de5ff5ef3d2f93f40cf2e33a5)
1 use crate::include::bindings::linux_bpf::{bpf_attach_type, bpf_attr, bpf_prog_type};
2 use crate::syscall::user_access::{check_and_clone_cstr, UserBufferReader};
3 use alloc::string::{String, ToString};
4 use alloc::vec::Vec;
5 use core::ffi::CStr;
6 use core::fmt::Debug;
7 use num_traits::FromPrimitive;
8 use system_error::SystemError;
9 
10 bitflags::bitflags! {
11 
12     pub struct VerifierLogLevel: u32 {
13         /// Sets no verifier logging.
14         const DISABLE = 0;
15         /// Enables debug verifier logging.
16         const DEBUG = 1;
17         /// Enables verbose verifier logging.
18         const VERBOSE = 2 | Self::DEBUG.bits();
19         /// Enables verifier stats.
20         const STATS = 4;
21     }
22 }
23 
24 #[derive(Debug)]
25 pub struct BpfProgVerifierInfo {
26     /// This attribute specifies the level/detail of the log output. Valid values are.
27     pub log_level: VerifierLogLevel,
28     /// This attributes indicates the size of the memory region in bytes
29     /// indicated by `log_buf` which can safely be written to by the kernel.
30     pub _log_buf_size: u32,
31     /// This attributes can be set to a pointer to a memory region
32     /// allocated/reservedby the loader process where the verifier log will
33     /// be written to.
34     /// The detail of the log is set by log_level. The verifier log
35     /// is often the only indication in addition to the error code of
36     /// why the syscall command failed to load the program.
37     ///
38     /// The log is also written to on success. If the kernel runs out of
39     /// space in the buffer while loading, the loading process will fail
40     /// and the command will return with an error code of -ENOSPC. So it
41     /// is important to correctly size the buffer when enabling logging.
42     pub _log_buf_ptr: usize,
43 }
44 
45 impl From<&bpf_attr> for BpfProgVerifierInfo {
46     fn from(attr: &bpf_attr) -> Self {
47         unsafe {
48             let u = &attr.__bindgen_anon_3;
49             Self {
50                 log_level: VerifierLogLevel::from_bits_truncate(u.log_level),
51                 _log_buf_size: u.log_size,
52                 _log_buf_ptr: u.log_buf as usize,
53             }
54         }
55     }
56 }
57 
58 pub struct BpfProgMeta {
59     pub prog_flags: u32,
60     pub prog_type: bpf_prog_type,
61     pub expected_attach_type: bpf_attach_type,
62     pub insns: Vec<u8>,
63     pub license: String,
64     pub kern_version: u32,
65     pub name: String,
66 }
67 
68 impl Debug for BpfProgMeta {
69     fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
70         f.debug_struct("BpfProgMeta")
71             .field("prog_flags", &self.prog_flags)
72             .field("prog_type", &self.prog_type)
73             .field("expected_attach_type", &self.expected_attach_type)
74             .field("insns_len", &(self.insns.len() / 8))
75             .field("license", &self.license)
76             .field("kern_version", &self.kern_version)
77             .field("name", &self.name)
78             .finish()
79     }
80 }
81 
82 impl TryFrom<&bpf_attr> for BpfProgMeta {
83     type Error = SystemError;
84     fn try_from(attr: &bpf_attr) -> Result<Self, Self::Error> {
85         let u = unsafe { &attr.__bindgen_anon_3 };
86         let prog_type = bpf_prog_type::from_u32(u.prog_type).ok_or(SystemError::EINVAL)?;
87         let expected_attach_type =
88             bpf_attach_type::from_u32(u.expected_attach_type).ok_or(SystemError::EINVAL)?;
89         unsafe {
90             let insns_buf =
91                 UserBufferReader::new(u.insns as *mut u8, u.insn_cnt as usize * 8, true)?;
92             let insns = insns_buf.read_from_user::<u8>(0)?.to_vec();
93             let name_slice =
94                 core::slice::from_raw_parts(u.prog_name.as_ptr() as *const u8, u.prog_name.len());
95             let prog_name = CStr::from_bytes_until_nul(name_slice)
96                 .map_err(|_| SystemError::EINVAL)?
97                 .to_str()
98                 .map_err(|_| SystemError::EINVAL)?
99                 .to_string();
100             let license = check_and_clone_cstr(u.license as *const u8, None)?;
101             Ok(Self {
102                 prog_flags: u.prog_flags,
103                 prog_type,
104                 expected_attach_type,
105                 insns,
106                 license: license.into_string().map_err(|_| SystemError::EINVAL)?,
107                 kern_version: u.kern_version,
108                 name: prog_name,
109             })
110         }
111     }
112 }
113