falco_plugin/plugin/tables/vtable/
reader.rs

1use crate::plugin::error::last_error::LastError;
2use crate::plugin::tables::vtable::TableError;
3use crate::plugin::tables::vtable::TableError::BadVtable;
4use falco_plugin_api::{
5    ss_plugin_bool, ss_plugin_rc, ss_plugin_state_data, ss_plugin_table_entry_t,
6    ss_plugin_table_field_t, ss_plugin_table_iterator_func_t, ss_plugin_table_iterator_state_t,
7    ss_plugin_table_reader_vtable_ext, ss_plugin_table_t,
8};
9use std::marker::PhantomData;
10
11/// A vtable containing table read access methods
12///
13/// It's used as a token to prove you're allowed to read tables in a particular context.
14/// The default implementation is [`crate::tables::LazyTableReader`].
15pub trait TableReader: private::TableReaderImpl {}
16
17impl<T: private::TableReaderImpl> TableReader for T {}
18
19pub(crate) mod private {
20    use super::*;
21    pub trait TableReaderImpl {
22        type Error: std::error::Error + Send + Sync + 'static;
23
24        unsafe fn get_table_name(
25            &self,
26            t: *mut ss_plugin_table_t,
27        ) -> Result<*const ::std::os::raw::c_char, Self::Error>;
28
29        unsafe fn get_table_size(&self, t: *mut ss_plugin_table_t) -> Result<u64, Self::Error>;
30
31        unsafe fn get_table_entry(
32            &self,
33            t: *mut ss_plugin_table_t,
34            key: *const ss_plugin_state_data,
35        ) -> Result<*mut ss_plugin_table_entry_t, Self::Error>;
36
37        unsafe fn read_entry_field(
38            &self,
39            t: *mut ss_plugin_table_t,
40            e: *mut ss_plugin_table_entry_t,
41            f: *const ss_plugin_table_field_t,
42            out: *mut ss_plugin_state_data,
43        ) -> Result<ss_plugin_rc, Self::Error>;
44
45        fn release_table_entry_fn(
46            &self,
47        ) -> Option<
48            unsafe extern "C-unwind" fn(t: *mut ss_plugin_table_t, e: *mut ss_plugin_table_entry_t),
49        >;
50
51        fn iterate_entries_fn(
52            &self,
53        ) -> Result<
54            unsafe extern "C-unwind" fn(
55                t: *mut ss_plugin_table_t,
56                it: ss_plugin_table_iterator_func_t,
57                s: *mut ss_plugin_table_iterator_state_t,
58            ) -> ss_plugin_bool,
59            Self::Error,
60        >;
61
62        fn last_error(&self) -> &LastError;
63    }
64}
65
66/// A TableReader that performs validation on demand
67///
68/// This has no overhead when not actively using tables, but after a few accesses
69/// the repeated null checks might add up
70#[derive(Debug)]
71pub struct LazyTableReader<'t> {
72    reader_ext: &'t ss_plugin_table_reader_vtable_ext,
73    pub(in crate::plugin::tables) last_error: LastError,
74}
75
76impl<'t> LazyTableReader<'t> {
77    pub(crate) fn new(
78        reader_ext: &'t ss_plugin_table_reader_vtable_ext,
79        last_error: LastError,
80    ) -> Self {
81        LazyTableReader {
82            reader_ext,
83            last_error,
84        }
85    }
86
87    /// Validate all vtable entries and skip further NULL checks
88    ///
89    /// This method validates all possible vtable methods to make future
90    /// table accesses faster. If your plugin method does more than a few
91    /// (say, 10) calls to methods that take a `TableReader`, it might be
92    /// faster to get a `ValidatedTableReader`
93    pub fn validate(&self) -> Result<ValidatedTableReader, TableError> {
94        Ok(ValidatedTableReader {
95            get_table_name: self
96                .reader_ext
97                .get_table_name
98                .ok_or(BadVtable("get_table_name"))?,
99            get_table_size: self
100                .reader_ext
101                .get_table_size
102                .ok_or(BadVtable("get_table_size"))?,
103            get_table_entry: self
104                .reader_ext
105                .get_table_entry
106                .ok_or(BadVtable("get_table_entry"))?,
107            read_entry_field: self
108                .reader_ext
109                .read_entry_field
110                .ok_or(BadVtable("read_entry_field"))?,
111            release_table_entry: self
112                .reader_ext
113                .release_table_entry
114                .ok_or(BadVtable("release_table_entry"))?,
115            iterate_entries: self
116                .reader_ext
117                .iterate_entries
118                .ok_or(BadVtable("iterate_entries"))?,
119            last_error: self.last_error.clone(),
120            lifetime: PhantomData,
121        })
122    }
123}
124
125impl private::TableReaderImpl for LazyTableReader<'_> {
126    type Error = TableError;
127
128    unsafe fn get_table_name(
129        &self,
130        t: *mut ss_plugin_table_t,
131    ) -> Result<*const ::std::os::raw::c_char, Self::Error> {
132        Ok(unsafe {
133            self.reader_ext
134                .get_table_name
135                .ok_or(BadVtable("get_table_name"))?(t)
136        })
137    }
138
139    unsafe fn get_table_size(&self, t: *mut ss_plugin_table_t) -> Result<u64, Self::Error> {
140        Ok(unsafe {
141            self.reader_ext
142                .get_table_size
143                .ok_or(BadVtable("get_table_size"))?(t)
144        })
145    }
146
147    unsafe fn get_table_entry(
148        &self,
149        t: *mut ss_plugin_table_t,
150        key: *const ss_plugin_state_data,
151    ) -> Result<*mut ss_plugin_table_entry_t, Self::Error> {
152        Ok(unsafe {
153            self.reader_ext
154                .get_table_entry
155                .ok_or(BadVtable("get_table_entry"))?(t, key)
156        })
157    }
158
159    unsafe fn read_entry_field(
160        &self,
161        t: *mut ss_plugin_table_t,
162        e: *mut ss_plugin_table_entry_t,
163        f: *const ss_plugin_table_field_t,
164        out: *mut ss_plugin_state_data,
165    ) -> Result<ss_plugin_rc, Self::Error> {
166        Ok(unsafe {
167            self.reader_ext
168                .read_entry_field
169                .ok_or(BadVtable("read_entry_field"))?(t, e, f, out)
170        })
171    }
172
173    fn release_table_entry_fn(
174        &self,
175    ) -> Option<
176        unsafe extern "C-unwind" fn(t: *mut ss_plugin_table_t, e: *mut ss_plugin_table_entry_t),
177    > {
178        self.reader_ext.release_table_entry
179    }
180
181    fn iterate_entries_fn(
182        &self,
183    ) -> Result<
184        unsafe extern "C-unwind" fn(
185            t: *mut ss_plugin_table_t,
186            it: ss_plugin_table_iterator_func_t,
187            s: *mut ss_plugin_table_iterator_state_t,
188        ) -> ss_plugin_bool,
189        TableError,
190    > {
191        self.reader_ext
192            .iterate_entries
193            .ok_or(BadVtable("iterate_entries"))
194    }
195
196    fn last_error(&self) -> &LastError {
197        &self.last_error
198    }
199}
200
201/// A TableReader that performs validation when created, with no subsequent checks
202///
203/// This implementation has some overhead when creating, but all subsequent table accesses
204/// should be ever so slightly faster due to skipped NULL checks.
205#[derive(Debug)]
206pub struct ValidatedTableReader<'t> {
207    pub(in crate::plugin::tables) get_table_name:
208        unsafe extern "C-unwind" fn(t: *mut ss_plugin_table_t) -> *const ::std::os::raw::c_char,
209    pub(in crate::plugin::tables) get_table_size:
210        unsafe extern "C-unwind" fn(t: *mut ss_plugin_table_t) -> u64,
211    pub(in crate::plugin::tables) get_table_entry:
212        unsafe extern "C-unwind" fn(
213            t: *mut ss_plugin_table_t,
214            key: *const ss_plugin_state_data,
215        ) -> *mut ss_plugin_table_entry_t,
216    pub(in crate::plugin::tables) read_entry_field: unsafe extern "C-unwind" fn(
217        t: *mut ss_plugin_table_t,
218        e: *mut ss_plugin_table_entry_t,
219        f: *const ss_plugin_table_field_t,
220        out: *mut ss_plugin_state_data,
221    )
222        -> ss_plugin_rc,
223    pub(in crate::plugin::tables) release_table_entry:
224        unsafe extern "C-unwind" fn(t: *mut ss_plugin_table_t, e: *mut ss_plugin_table_entry_t),
225    pub(in crate::plugin::tables) iterate_entries: unsafe extern "C-unwind" fn(
226        t: *mut ss_plugin_table_t,
227        it: ss_plugin_table_iterator_func_t,
228        s: *mut ss_plugin_table_iterator_state_t,
229    )
230        -> ss_plugin_bool,
231
232    pub(in crate::plugin::tables) last_error: LastError,
233    lifetime: PhantomData<&'t ()>,
234}
235
236impl private::TableReaderImpl for ValidatedTableReader<'_> {
237    type Error = std::convert::Infallible;
238
239    unsafe fn get_table_name(
240        &self,
241        t: *mut ss_plugin_table_t,
242    ) -> Result<*const ::std::os::raw::c_char, Self::Error> {
243        unsafe { Ok((self.get_table_name)(t)) }
244    }
245
246    unsafe fn get_table_size(&self, t: *mut ss_plugin_table_t) -> Result<u64, Self::Error> {
247        unsafe { Ok((self.get_table_size)(t)) }
248    }
249
250    unsafe fn get_table_entry(
251        &self,
252        t: *mut ss_plugin_table_t,
253        key: *const ss_plugin_state_data,
254    ) -> Result<*mut ss_plugin_table_entry_t, Self::Error> {
255        unsafe { Ok((self.get_table_entry)(t, key)) }
256    }
257
258    unsafe fn read_entry_field(
259        &self,
260        t: *mut ss_plugin_table_t,
261        e: *mut ss_plugin_table_entry_t,
262        f: *const ss_plugin_table_field_t,
263        out: *mut ss_plugin_state_data,
264    ) -> Result<ss_plugin_rc, Self::Error> {
265        unsafe { Ok((self.read_entry_field)(t, e, f, out)) }
266    }
267
268    fn release_table_entry_fn(
269        &self,
270    ) -> Option<unsafe extern "C-unwind" fn(*mut ss_plugin_table_t, *mut ss_plugin_table_entry_t)>
271    {
272        Some(self.release_table_entry)
273    }
274
275    fn iterate_entries_fn(
276        &self,
277    ) -> Result<
278        unsafe extern "C-unwind" fn(
279            *mut ss_plugin_table_t,
280            ss_plugin_table_iterator_func_t,
281            *mut ss_plugin_table_iterator_state_t,
282        ) -> ss_plugin_bool,
283        Self::Error,
284    > {
285        Ok(self.iterate_entries)
286    }
287
288    fn last_error(&self) -> &LastError {
289        &self.last_error
290    }
291}