memfd-runner
A minimal Linux library for executing in-memory ELF files using memfd_create and execve.
Overview
memfd-runner provides a simple interface to load and execute ELF binaries directly from memory without writing them to disk. It uses Linux's memfd_create system call to create an anonymous file in memory, writes the ELF data to it, then executes it via the /proc/self/fd/ interface.
Features
- Minimal - <400 lines of code, 1 dependency (syscaller)
- Two execution modes - fork child process or replace current process
- Command line arguments - pass custom arguments to executed programs
- Environment variables - set custom environment for executed programs
- Custom argv[0] - control how the program sees its own name
no_std- works in embedded and kernel environments- Basic ELF validation - validates magic bytes and minimum size
Platform Support
- Linux only - requires
memfd_createsystem call (Linux 3.17+) - x86_64 - tested on x86_64 architecture
Installation
Or add this to your Cargo.toml:
[]
= "0.1.1"
Quick Start
Simple Execution (Fork Mode)
use run;
// Read an ELF binary
let elf_bytes = read.unwrap;
// Execute it and get the exit code
let exit_code = run.unwrap;
println!;
Replace Current Process
use ;
let elf_bytes = read.unwrap;
let options = new.with_replace;
// This will replace the current process - does not return on success
run_with_options.unwrap;
Passing Arguments
use ;
let elf_bytes = read.unwrap;
let options = new
.with_args; // Just the arguments, not the program name
let exit_code = run_with_options.unwrap;
// Executes: /proc/self/fd/X "Hello" "World!"
Custom Program Name (argv[0])
use ;
let elf_bytes = read.unwrap;
let options = new
.with_argv0 // Custom program name
.with_args;
let exit_code = run_with_options.unwrap;
// The program sees argv[0] as "my-echo" instead of "/proc/self/fd/X"
Environment Variables
use ;
let elf_bytes = read.unwrap;
let options = new
.with_env;
let exit_code = run_with_options.unwrap;
Error Handling
use ;
let invalid_data = b"not an elf file";
match run
API Reference
Functions
-
run<B: AsRef<[u8]>>(bytes: B) -> Result<i32, RunError>- Execute ELF bytes in fork mode, returns child exit code
-
run_with_options<B: AsRef<[u8]>>(bytes: B, options: RunOptions) -> Result<i32, RunError>- Execute ELF bytes with custom options
Types
-
RunOptions- Configuration for executionnew()- Create default options (fork mode)with_replace(bool)- Set replace mode (true = replace process, false = fork child)with_args(&[&str])- Set command line arguments (max 32 args, 256 chars each)with_env(&[&str])- Set environment variables (max 64 vars, 256 chars each)with_argv0(&str)- Set custom program name (argv[0])
-
RunError- Error types with contextFdCreationFailed(i32)- Failed to create memory file descriptorBytesNotWritten(usize, usize)- Write operation failed (written, expected)ExecError(i32)- execve system call failedForkError(i32)- fork system call failedWaitError(i32)- wait4 system call failedInvalidElfFormat- ELF validation failedTooManyArgs- Too many command line arguments (limit: 32)TooManyEnvVars- Too many environment variables (limit: 64)ArgTooLong- Command line argument too long (limit: 256 chars)EnvVarTooLong- Environment variable too long (limit: 256 chars)
How It Works
- Validate ELF: Checks magic bytes (0x7f, 'E', 'L', 'F') and minimum size
- Create Memory FD: Uses
memfd_create()to create an anonymous file in memory - Write Data: Writes the ELF bytes to the memory file descriptor
- Prepare Arguments: Builds argv and envp arrays with provided options
- Execute: Uses
execve()with/proc/self/fd/<fd>path to execute the in-memory file - Wait for Child: In fork mode, waits for child process and returns exit code
Limitations
- Linux-specific - requires
memfd_createsystem call (Linux 3.17+) - Maximum 32 command line arguments (256 characters each)
- Maximum 64 environment variables (256 characters each)
- Basic ELF validation only - validates magic bytes and minimum size
- No complex ELF features - no support for dynamic linking validation
Development
Building
Testing
Linting
Contributing
- Fork the repository
- Create a feature branch
- Make your changes
- Add tests if applicable
- Run
cargo testandcargo clippy - Submit a pull request
License
This project is dual-licensed under the MIT OR Apache-2.0 license. See LICENSE-MIT and LICENSE-APACHE files for details.