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}