mirror of
https://github.com/Astatin3/unshell.git
synced 2026-06-09 06:47:59 -06:00
Load ELF from memory using memfd_create
This commit is contained in:
Generated
+7
@@ -0,0 +1,7 @@
|
||||
# This file is automatically @generated by Cargo.
|
||||
# It is not intended for manual editing.
|
||||
version = 4
|
||||
|
||||
[[package]]
|
||||
name = "testproj"
|
||||
version = "0.1.0"
|
||||
@@ -0,0 +1,22 @@
|
||||
cargo-features = ["trim-paths"]
|
||||
|
||||
[package]
|
||||
name = "testproj"
|
||||
version = "0.1.0"
|
||||
edition = "2024"
|
||||
|
||||
|
||||
[lib]
|
||||
crate-type = ["cdylib"]
|
||||
|
||||
[dependencies]
|
||||
|
||||
|
||||
[profile.release]
|
||||
strip = true # Strip symbols from the binary
|
||||
opt-level = "z" # Optimize for size
|
||||
lto = true # Link tree optimization
|
||||
codegen-units = 1
|
||||
panic = "abort"
|
||||
debug = false # Remove debug
|
||||
trim-paths="all"
|
||||
@@ -0,0 +1,30 @@
|
||||
#![no_std]
|
||||
#![crate_type = "cdylib"]
|
||||
|
||||
use core::panic::PanicInfo;
|
||||
|
||||
#[panic_handler]
|
||||
fn panic(_info: &PanicInfo) -> ! {
|
||||
loop {}
|
||||
}
|
||||
|
||||
#[unsafe(no_mangle)]
|
||||
fn a() -> i32 {
|
||||
1
|
||||
}
|
||||
|
||||
#[repr(C)]
|
||||
pub struct S {
|
||||
a: u64,
|
||||
b: u32,
|
||||
c: u16,
|
||||
d: u8,
|
||||
}
|
||||
|
||||
#[unsafe(no_mangle)]
|
||||
pub extern "C" fn test_identity_struct(x: S) -> S {
|
||||
x
|
||||
}
|
||||
|
||||
#[unsafe(no_mangle)]
|
||||
pub static HELLO: &str = "Hello!";
|
||||
Generated
+60
@@ -315,6 +315,15 @@ version = "1.21.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "42f5e15c9953c5e4ccceeb2e7382a716482c34515315f7b03532b8b4e8393d2d"
|
||||
|
||||
[[package]]
|
||||
name = "ppv-lite86"
|
||||
version = "0.2.21"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "85eae3c4ed2f50dcfe72643da4befc30deadb458a9b590d720cde2f2b1e97da9"
|
||||
dependencies = [
|
||||
"zerocopy",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "proc-macro2"
|
||||
version = "1.0.103"
|
||||
@@ -339,6 +348,35 @@ version = "5.3.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "69cdb34c158ceb288df11e18b4bd39de994f6657d83847bdffdbd7f346754b0f"
|
||||
|
||||
[[package]]
|
||||
name = "rand"
|
||||
version = "0.9.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6db2770f06117d490610c7488547d543617b21bfa07796d7a12f6f1bd53850d1"
|
||||
dependencies = [
|
||||
"rand_chacha",
|
||||
"rand_core",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rand_chacha"
|
||||
version = "0.9.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d3022b5f1df60f26e1ffddd6c66e8aa15de382ae63b3a0c1bfc0e4d3e3f325cb"
|
||||
dependencies = [
|
||||
"ppv-lite86",
|
||||
"rand_core",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rand_core"
|
||||
version = "0.9.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "99d9a13982dcf210057a8a78572b2217b667c3beacbf3a0d8b454f6f82837d38"
|
||||
dependencies = [
|
||||
"getrandom",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "regex"
|
||||
version = "1.12.2"
|
||||
@@ -490,7 +528,9 @@ version = "0.0.0"
|
||||
dependencies = [
|
||||
"bincode",
|
||||
"chrono",
|
||||
"libc",
|
||||
"libloading",
|
||||
"rand",
|
||||
"serde",
|
||||
"serde_json",
|
||||
"unshell-obfuscate",
|
||||
@@ -642,3 +682,23 @@ name = "wit-bindgen"
|
||||
version = "0.46.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f17a85883d4e6d00e8a97c586de764dabcc06133f7f1d55dce5cdc070ad7fe59"
|
||||
|
||||
[[package]]
|
||||
name = "zerocopy"
|
||||
version = "0.8.28"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "43fa6694ed34d6e57407afbccdeecfa268c470a7d2a5b0cf49ce9fcc345afb90"
|
||||
dependencies = [
|
||||
"zerocopy-derive",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "zerocopy-derive"
|
||||
version = "0.8.28"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c640b22cd9817fae95be82f0d2f90b11f7605f6c319d16705c459b27ac2cbc26"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
]
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
// Behold! The world's most sophisticated shared library! (it has no code)
|
||||
|
||||
#![no_main]
|
||||
|
||||
pub use unshell_lib::get_components;
|
||||
|
||||
Generated
+60
@@ -315,6 +315,15 @@ version = "1.21.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "42f5e15c9953c5e4ccceeb2e7382a716482c34515315f7b03532b8b4e8393d2d"
|
||||
|
||||
[[package]]
|
||||
name = "ppv-lite86"
|
||||
version = "0.2.21"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "85eae3c4ed2f50dcfe72643da4befc30deadb458a9b590d720cde2f2b1e97da9"
|
||||
dependencies = [
|
||||
"zerocopy",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "proc-macro2"
|
||||
version = "1.0.103"
|
||||
@@ -339,6 +348,35 @@ version = "5.3.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "69cdb34c158ceb288df11e18b4bd39de994f6657d83847bdffdbd7f346754b0f"
|
||||
|
||||
[[package]]
|
||||
name = "rand"
|
||||
version = "0.9.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6db2770f06117d490610c7488547d543617b21bfa07796d7a12f6f1bd53850d1"
|
||||
dependencies = [
|
||||
"rand_chacha",
|
||||
"rand_core",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rand_chacha"
|
||||
version = "0.9.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d3022b5f1df60f26e1ffddd6c66e8aa15de382ae63b3a0c1bfc0e4d3e3f325cb"
|
||||
dependencies = [
|
||||
"ppv-lite86",
|
||||
"rand_core",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rand_core"
|
||||
version = "0.9.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "99d9a13982dcf210057a8a78572b2217b667c3beacbf3a0d8b454f6f82837d38"
|
||||
dependencies = [
|
||||
"getrandom",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "regex"
|
||||
version = "1.12.2"
|
||||
@@ -483,7 +521,9 @@ version = "0.0.0"
|
||||
dependencies = [
|
||||
"bincode",
|
||||
"chrono",
|
||||
"libc",
|
||||
"libloading",
|
||||
"rand",
|
||||
"serde",
|
||||
"serde_json",
|
||||
"unshell-obfuscate",
|
||||
@@ -635,3 +675,23 @@ name = "wit-bindgen"
|
||||
version = "0.46.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f17a85883d4e6d00e8a97c586de764dabcc06133f7f1d55dce5cdc070ad7fe59"
|
||||
|
||||
[[package]]
|
||||
name = "zerocopy"
|
||||
version = "0.8.28"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "43fa6694ed34d6e57407afbccdeecfa268c470a7d2a5b0cf49ce9fcc345afb90"
|
||||
dependencies = [
|
||||
"zerocopy-derive",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "zerocopy-derive"
|
||||
version = "0.8.28"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c640b22cd9817fae95be82f0d2f90b11f7605f6c319d16705c459b27ac2cbc26"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
]
|
||||
|
||||
@@ -23,3 +23,5 @@ chrono = "0.4.42"
|
||||
|
||||
serde = {version = "1.0.228", features=["derive"]}
|
||||
serde_json = "1.0.145"
|
||||
libc = "0.2.177"
|
||||
rand = "0.9.2"
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
use std::collections::HashMap;
|
||||
use std::{collections::HashMap, fmt::Debug};
|
||||
|
||||
// use bincode::{Decode, Encode};
|
||||
// use serde::{Deserialize, Serialize};
|
||||
@@ -40,6 +40,16 @@ pub struct NamedComponent {
|
||||
),
|
||||
}
|
||||
|
||||
impl Debug for NamedComponent {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
f.debug_struct("NamedComponent")
|
||||
.field("name", &self.name)
|
||||
// .field("get_interface", &self.get_interface)
|
||||
// .field("start_runtime", &self.start_runtime)
|
||||
.finish()
|
||||
}
|
||||
}
|
||||
|
||||
/// Trait that wraps the get_interface<T>() function inside of components
|
||||
pub trait InterfaceWrapper: Send + Sync {
|
||||
fn get_interface<T: 'static>(&self) -> Option<T>
|
||||
|
||||
@@ -10,7 +10,7 @@ mod components;
|
||||
pub use components::get_components;
|
||||
|
||||
mod announcement;
|
||||
use std::fmt;
|
||||
use std::fmt::{self, Debug};
|
||||
|
||||
pub use announcement::Announcement;
|
||||
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
mod manager;
|
||||
mod module;
|
||||
|
||||
mod proc_load;
|
||||
|
||||
// use std::any::Any;
|
||||
|
||||
// pub use logger::setup_logger;
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
use libloading::{Library, Symbol};
|
||||
|
||||
use crate::module::proc_load::memfd_create_dlopen;
|
||||
use crate::{ModuleError, logger::SetupLogger, logger::logger};
|
||||
|
||||
use crate::*;
|
||||
@@ -22,26 +23,27 @@ impl Module {
|
||||
|
||||
Ok(this)
|
||||
}
|
||||
|
||||
// TODO: Implement actual reflective ELF loading (possibly even custom format)
|
||||
// Look at https://github.com/weizhiao/rust-elfloader
|
||||
pub fn new_bytes(bytes: &[u8]) -> Result<Self, ModuleError> {
|
||||
let lib =
|
||||
memfd_create_dlopen(bytes).map_err(|e| ModuleError::Error(e.to_string().into()))?;
|
||||
|
||||
let this = Self { lib };
|
||||
|
||||
if let Ok(setup_logger) = this.get_symbol::<SetupLogger>(b"setup_logger") {
|
||||
setup_logger(logger());
|
||||
} else {
|
||||
warn!("setup_logger not found");
|
||||
}
|
||||
|
||||
Ok(this)
|
||||
}
|
||||
pub fn get_symbol<T>(&self, symbol: &[u8]) -> Result<Symbol<'_, T>, ModuleError> {
|
||||
let symbol = unsafe { self.lib.get::<T>(symbol) }
|
||||
.map_err(|e| ModuleError::LinkError(format!("Failed to load symbol: {}", e)))?;
|
||||
|
||||
Ok(symbol)
|
||||
}
|
||||
// pub fn get_id(&self) -> &str {
|
||||
// self.id
|
||||
// }
|
||||
// pub fn get_interface<T>(&self) -> Result<T, ModuleError> {
|
||||
// if let Ok(interface_function) = self.get_symbol::<fn() -> T>(b"interface") {
|
||||
// Ok(interface_function())
|
||||
// } else {
|
||||
// Err(ModuleError::LinkError(format!(
|
||||
// "Interface function not found!"
|
||||
// )))
|
||||
// }
|
||||
// }
|
||||
}
|
||||
|
||||
// extern "C" fn test1234() {
|
||||
// info!("Test1234!");
|
||||
// }
|
||||
|
||||
@@ -0,0 +1,56 @@
|
||||
// Load a shared object by saving bytes to a filesystem in /proc
|
||||
|
||||
use std::{error::Error, ffi::CString, io}; // 0.8
|
||||
|
||||
use libloading::Library;
|
||||
|
||||
use crate::debug;
|
||||
|
||||
// The `memfd_create` syscall flags (MFD_CLOEXEC is common and good practice)
|
||||
const MFD_CLOEXEC: u32 = 0x0001;
|
||||
const MFD_ALLOW_SEALING: u32 = 0x0002;
|
||||
|
||||
pub fn memfd_create_dlopen(payload: &[u8]) -> Result<Library, Box<dyn Error>> {
|
||||
use rand::distr::{Alphanumeric, SampleString};
|
||||
|
||||
let string = Alphanumeric.sample_string(&mut rand::rng(), 16);
|
||||
|
||||
// 1. Create the anonymous in-memory file descriptor using the raw syscall
|
||||
let c_name = CString::new(string).expect("CString conversion failed");
|
||||
|
||||
let fd = unsafe { libc::memfd_create(c_name.as_ptr(), MFD_CLOEXEC | MFD_ALLOW_SEALING) };
|
||||
|
||||
if fd < 0 {
|
||||
return Err(io::Error::last_os_error().to_string().into());
|
||||
}
|
||||
|
||||
// 2. Write the payload bytes to the in-memory file
|
||||
let bytes_written =
|
||||
unsafe { libc::write(fd, payload.as_ptr() as *const libc::c_void, payload.len()) };
|
||||
|
||||
if bytes_written != payload.len() as isize {
|
||||
// If write fails or is incomplete, clean up the file descriptor
|
||||
unsafe {
|
||||
libc::close(fd);
|
||||
}
|
||||
return Err("Failed to write full payload to memfd".into());
|
||||
}
|
||||
|
||||
// Optional: Seal the file to prevent modification, common for security/integrity
|
||||
// Note: The MFD_ALLOW_SEALING flag must be set during creation for this to work.
|
||||
let seals = libc::F_SEAL_GROW | libc::F_SEAL_SHRINK | libc::F_SEAL_WRITE;
|
||||
if unsafe { libc::fcntl(fd, libc::F_ADD_SEALS, seals) } == -1 {
|
||||
// Log a warning but continue if sealing fails (e.g., due to permissions)
|
||||
debug!(
|
||||
"memfd_create_dlopen: Failed to apply seals. Error: {}",
|
||||
io::Error::last_os_error()
|
||||
);
|
||||
}
|
||||
|
||||
// 3. Construct the virtual path to the in-memory file
|
||||
// This path is necessary for dlopen to work, as dlopen expects a filesystem path.
|
||||
let dl_path = format!("/proc/self/fd/{}", fd);
|
||||
|
||||
// 4. Use dlopen (via libloading) on the virtual path
|
||||
Ok(unsafe { Library::new(&dl_path)? })
|
||||
}
|
||||
Generated
+60
@@ -321,6 +321,15 @@ version = "1.21.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "42f5e15c9953c5e4ccceeb2e7382a716482c34515315f7b03532b8b4e8393d2d"
|
||||
|
||||
[[package]]
|
||||
name = "ppv-lite86"
|
||||
version = "0.2.21"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "85eae3c4ed2f50dcfe72643da4befc30deadb458a9b590d720cde2f2b1e97da9"
|
||||
dependencies = [
|
||||
"zerocopy",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "proc-macro2"
|
||||
version = "1.0.103"
|
||||
@@ -345,6 +354,35 @@ version = "5.3.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "69cdb34c158ceb288df11e18b4bd39de994f6657d83847bdffdbd7f346754b0f"
|
||||
|
||||
[[package]]
|
||||
name = "rand"
|
||||
version = "0.9.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6db2770f06117d490610c7488547d543617b21bfa07796d7a12f6f1bd53850d1"
|
||||
dependencies = [
|
||||
"rand_chacha",
|
||||
"rand_core",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rand_chacha"
|
||||
version = "0.9.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d3022b5f1df60f26e1ffddd6c66e8aa15de382ae63b3a0c1bfc0e4d3e3f325cb"
|
||||
dependencies = [
|
||||
"ppv-lite86",
|
||||
"rand_core",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rand_core"
|
||||
version = "0.9.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "99d9a13982dcf210057a8a78572b2217b667c3beacbf3a0d8b454f6f82837d38"
|
||||
dependencies = [
|
||||
"getrandom",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "regex"
|
||||
version = "1.12.2"
|
||||
@@ -489,7 +527,9 @@ version = "0.0.0"
|
||||
dependencies = [
|
||||
"bincode",
|
||||
"chrono",
|
||||
"libc",
|
||||
"libloading",
|
||||
"rand",
|
||||
"serde",
|
||||
"serde_json",
|
||||
"unshell-obfuscate",
|
||||
@@ -650,3 +690,23 @@ name = "wit-bindgen"
|
||||
version = "0.46.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f17a85883d4e6d00e8a97c586de764dabcc06133f7f1d55dce5cdc070ad7fe59"
|
||||
|
||||
[[package]]
|
||||
name = "zerocopy"
|
||||
version = "0.8.28"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "43fa6694ed34d6e57407afbccdeecfa268c470a7d2a5b0cf49ce9fcc345afb90"
|
||||
dependencies = [
|
||||
"zerocopy-derive",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "zerocopy-derive"
|
||||
version = "0.8.28"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c640b22cd9817fae95be82f0d2f90b11f7605f6c319d16705c459b27ac2cbc26"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
]
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
use std::collections::HashMap;
|
||||
use std::fs::File;
|
||||
use std::{collections::HashMap, io::Read};
|
||||
|
||||
use lazy_static::lazy_static;
|
||||
use unshell_lib::{
|
||||
@@ -38,7 +39,15 @@ fn main() {
|
||||
let mut modules = Vec::new();
|
||||
for arg in args.skip(1) {
|
||||
debug!("Loading module: {}", arg);
|
||||
modules.push(Module::new(&arg)?)
|
||||
|
||||
let mut file = File::open(arg).map_err(|e| ModuleError::Error(e.to_string().into()))?;
|
||||
let mut buffer = Vec::new();
|
||||
file.read_to_end(&mut buffer)
|
||||
.map_err(|e| ModuleError::Error(e.to_string().into()))?;
|
||||
|
||||
modules.push(Module::new_bytes(&buffer)?)
|
||||
|
||||
// modules.push(Module::new(&arg)?)
|
||||
}
|
||||
|
||||
// Run the manager, this is blocking.
|
||||
|
||||
Reference in New Issue
Block a user