memflow_ffi/plugins/mod.rs
1use std::ffi::CStr;
2use std::os::raw::c_char;
3use std::path::PathBuf;
4
5use memflow::plugins::Inventory;
6use memflow::plugins::{
7 connector::{ConnectorInstanceArcBox, MuConnectorInstanceArcBox},
8 os::{MuOsInstanceArcBox, OsInstanceArcBox},
9};
10
11use crate::util::*;
12use memflow::cglue::result::IntResult;
13
14use log::trace;
15
16/// Create a new connector inventory
17///
18/// This function will try to find connectors using PATH environment variable
19///
20/// Note that all functions go through each directories, and look for a `memflow` directory,
21/// and search for libraries in those.
22///
23/// # Safety
24///
25/// Inventory is inherently unsafe, because it loads shared libraries which can not be
26/// guaranteed to be safe.
27#[no_mangle]
28pub unsafe extern "C" fn inventory_scan() -> &'static mut Inventory {
29 to_heap(Inventory::scan())
30}
31
32/// Create a new inventory with custom path string
33///
34/// # Safety
35///
36/// `path` must be a valid null terminated string
37#[no_mangle]
38pub unsafe extern "C" fn inventory_scan_path(
39 path: *const c_char,
40) -> Option<&'static mut Inventory> {
41 let rpath = CStr::from_ptr(path).to_string_lossy();
42 Inventory::scan_path(rpath.to_string())
43 .map_err(inspect_err)
44 .ok()
45 .map(to_heap)
46}
47
48/// Add a directory to an existing inventory
49///
50/// # Safety
51///
52/// `dir` must be a valid null terminated string
53#[no_mangle]
54pub unsafe extern "C" fn inventory_add_dir(inv: &mut Inventory, dir: *const c_char) -> i32 {
55 let rdir = CStr::from_ptr(dir).to_string_lossy();
56
57 inv.add_dir(PathBuf::from(rdir.to_string()))
58 .into_int_result()
59}
60
61/// Create a connector with given arguments
62///
63/// This creates an instance of `ConnectorInstance`.
64///
65/// This instance needs to be dropped using `connector_drop`.
66///
67/// # Arguments
68///
69/// * `name` - name of the connector to use
70/// * `args` - arguments to be passed to the connector upon its creation
71///
72/// # Safety
73///
74/// Both `name`, and `args` must be valid null terminated strings.
75///
76/// Any error strings returned by the connector must not be outputed after the connector gets
77/// freed, because that operation could cause the underlying shared library to get unloaded.
78#[no_mangle]
79pub unsafe extern "C" fn inventory_create_connector(
80 inv: &mut Inventory,
81 name: *const c_char,
82 args: *const c_char,
83 out: &mut MuConnectorInstanceArcBox<'static>,
84) -> i32 {
85 let rname = CStr::from_ptr(name).to_string_lossy();
86
87 if args.is_null() {
88 inv.create_connector(&rname, None, None)
89 .map_err(inspect_err)
90 .into_int_out_result(out)
91 } else {
92 let rargs = CStr::from_ptr(args).to_string_lossy();
93 str::parse(&rargs)
94 .map_err(inspect_err)
95 .and_then(|args| inv.create_connector(&rname, None, Some(&args)))
96 .map_err(inspect_err)
97 .into_int_out_result(out)
98 }
99}
100
101/// Create a OS instance with given arguments
102///
103/// This creates an instance of `KernelInstance`.
104///
105/// This instance needs to be freed using `os_drop`.
106///
107/// # Arguments
108///
109/// * `name` - name of the OS to use
110/// * `args` - arguments to be passed to the connector upon its creation
111/// * `mem` - a previously initialized connector instance
112/// * `out` - a valid memory location that will contain the resulting os-instance
113///
114/// # Remarks
115///
116/// The `mem` connector instance is being _moved_ into the os layer.
117/// This means upon calling `os_drop` it is not unnecessary to call `connector_drop` anymore.
118///
119/// # Safety
120///
121/// Both `name`, and `args` must be valid null terminated strings.
122///
123/// Any error strings returned by the connector must not be outputed after the connector gets
124/// freed, because that operation could cause the underlying shared library to get unloaded.
125#[no_mangle]
126pub unsafe extern "C" fn inventory_create_os(
127 inv: &mut Inventory,
128 name: *const c_char,
129 args: *const c_char,
130 mem: *mut ConnectorInstanceArcBox<'static>,
131 out: &mut MuOsInstanceArcBox<'static>,
132) -> i32 {
133 let rname = CStr::from_ptr(name).to_string_lossy();
134 let _args = CStr::from_ptr(args).to_string_lossy();
135
136 let mem_obj = if mem.is_null() {
137 None
138 } else {
139 let mem_obj = mem.read();
140 // Zero out the data so that any automatic destructors on the other side do nothing.
141 std::ptr::write_bytes(mem, 0, 1);
142 Some(mem_obj)
143 };
144
145 if args.is_null() {
146 inv.create_os(&rname, mem_obj, None)
147 .map_err(inspect_err)
148 .into_int_out_result(out)
149 } else {
150 let rargs = CStr::from_ptr(args).to_string_lossy();
151 str::parse(&rargs)
152 .map_err(inspect_err)
153 .and_then(|args| inv.create_os(&rname, mem_obj, Some(&args)))
154 .map_err(inspect_err)
155 .into_int_out_result(out)
156 }
157}
158
159/// Free a os plugin
160///
161/// # Safety
162///
163/// `os` must point to a valid `OsInstance` that was created using one of the provided
164/// functions.
165#[no_mangle]
166pub unsafe extern "C" fn os_drop(os: &mut OsInstanceArcBox<'static>) {
167 trace!("connector_drop: {:?}", os as *mut _);
168 std::ptr::drop_in_place(os);
169}
170
171/// Clone a connector
172///
173/// This method is useful when needing to perform multithreaded operations, as a connector is not
174/// guaranteed to be thread safe. Every single cloned instance also needs to be dropped using
175/// `connector_drop`.
176///
177/// # Safety
178///
179/// `conn` has to point to a a valid `CloneablePhysicalMemory` created by one of the provided
180/// functions.
181#[no_mangle]
182pub unsafe extern "C" fn connector_clone(
183 conn: &ConnectorInstanceArcBox<'static>,
184 out: &mut MuConnectorInstanceArcBox<'static>,
185) {
186 trace!("connector_clone: {:?}", conn as *const _);
187 *out.as_mut_ptr() = conn.clone();
188}
189
190/// Free a connector instance
191///
192/// # Safety
193///
194/// `conn` has to point to a valid [`ConnectorInstance`](ConnectorInstanceArcBox) created by one of the provided
195/// functions.
196///
197/// There has to be no instance of `PhysicalMemory` created from the input `conn`, because they
198/// will become invalid.
199#[no_mangle]
200pub unsafe extern "C" fn connector_drop(conn: &mut ConnectorInstanceArcBox<'static>) {
201 trace!("connector_drop: {:?}", conn as *mut _);
202 std::ptr::drop_in_place(conn)
203}
204
205/// Free a connector inventory
206///
207/// # Safety
208///
209/// `inv` must point to a valid `Inventory` that was created using one of the provided
210/// functions.
211#[no_mangle]
212pub unsafe extern "C" fn inventory_free(inv: &'static mut Inventory) {
213 trace!("inventory_free: {:?}", inv as *mut _);
214 let _ = Box::from_raw(inv);
215}