Compare commits
2 Commits
main
...
elf-packin
Author | SHA1 | Date | |
---|---|---|---|
bd0d114145 | |||
f07dab1b4b |
103
Cargo.lock
generated
103
Cargo.lock
generated
@ -2,6 +2,23 @@
|
|||||||
# It is not intended for manual editing.
|
# It is not intended for manual editing.
|
||||||
version = 3
|
version = 3
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "adler"
|
||||||
|
version = "1.0.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "ahash"
|
||||||
|
version = "0.7.6"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "fcb51a0695d8f838b1ee009b3fbf66bda078cd64590202a864a8f3e8c4315c47"
|
||||||
|
dependencies = [
|
||||||
|
"getrandom",
|
||||||
|
"once_cell",
|
||||||
|
"version_check",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "aho-corasick"
|
name = "aho-corasick"
|
||||||
version = "0.7.18"
|
version = "0.7.18"
|
||||||
@ -28,6 +45,15 @@ version = "1.1.0"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa"
|
checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "bincode"
|
||||||
|
version = "1.3.3"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "b1f45e9417d87227c7a56d22e471c6206462cba514c7590c09aff4cf6d1ddcad"
|
||||||
|
dependencies = [
|
||||||
|
"serde",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "bitflags"
|
name = "bitflags"
|
||||||
version = "1.3.2"
|
version = "1.3.2"
|
||||||
@ -112,6 +138,7 @@ dependencies = [
|
|||||||
name = "clone-shim"
|
name = "clone-shim"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
|
"bincode",
|
||||||
"clap 3.1.15",
|
"clap 3.1.15",
|
||||||
"close_fds",
|
"close_fds",
|
||||||
"criterion",
|
"criterion",
|
||||||
@ -121,6 +148,7 @@ dependencies = [
|
|||||||
"libc",
|
"libc",
|
||||||
"log",
|
"log",
|
||||||
"nix",
|
"nix",
|
||||||
|
"object",
|
||||||
"serde",
|
"serde",
|
||||||
"serde_json",
|
"serde_json",
|
||||||
"tempfile",
|
"tempfile",
|
||||||
@ -137,6 +165,15 @@ dependencies = [
|
|||||||
"libc",
|
"libc",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "crc32fast"
|
||||||
|
version = "1.3.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "b540bd8bc810d3885c6ea91e2018302f68baba2129ab3e88f32389ee9370880d"
|
||||||
|
dependencies = [
|
||||||
|
"cfg-if",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "criterion"
|
name = "criterion"
|
||||||
version = "0.3.5"
|
version = "0.3.5"
|
||||||
@ -274,6 +311,29 @@ dependencies = [
|
|||||||
"instant",
|
"instant",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "flate2"
|
||||||
|
version = "1.0.23"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "b39522e96686d38f4bc984b9198e3a0613264abaebaff2c5c918bfa6b6da09af"
|
||||||
|
dependencies = [
|
||||||
|
"cfg-if",
|
||||||
|
"crc32fast",
|
||||||
|
"libc",
|
||||||
|
"miniz_oxide",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "getrandom"
|
||||||
|
version = "0.2.5"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "d39cd93900197114fa1fcb7ae84ca742095eed9442088988ae74fa744e930e77"
|
||||||
|
dependencies = [
|
||||||
|
"cfg-if",
|
||||||
|
"libc",
|
||||||
|
"wasi",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "half"
|
name = "half"
|
||||||
version = "1.8.2"
|
version = "1.8.2"
|
||||||
@ -285,6 +345,9 @@ name = "hashbrown"
|
|||||||
version = "0.11.2"
|
version = "0.11.2"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "ab5ef0d4909ef3724cc8cce6ccc8572c5c817592e9285f5464f8e86f8bd3726e"
|
checksum = "ab5ef0d4909ef3724cc8cce6ccc8572c5c817592e9285f5464f8e86f8bd3726e"
|
||||||
|
dependencies = [
|
||||||
|
"ahash",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "hermit-abi"
|
name = "hermit-abi"
|
||||||
@ -395,6 +458,15 @@ dependencies = [
|
|||||||
"autocfg",
|
"autocfg",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "miniz_oxide"
|
||||||
|
version = "0.5.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "d2b29bd4bc3f33391105ebee3589c19197c4271e3e5a9ec9bfe8127eeff8f082"
|
||||||
|
dependencies = [
|
||||||
|
"adler",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "nix"
|
name = "nix"
|
||||||
version = "0.23.1"
|
version = "0.23.1"
|
||||||
@ -427,6 +499,25 @@ dependencies = [
|
|||||||
"libc",
|
"libc",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "object"
|
||||||
|
version = "0.28.3"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "40bec70ba014595f99f7aa110b84331ffe1ee9aece7fe6f387cc7e3ecda4d456"
|
||||||
|
dependencies = [
|
||||||
|
"crc32fast",
|
||||||
|
"flate2",
|
||||||
|
"hashbrown",
|
||||||
|
"indexmap",
|
||||||
|
"memchr",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "once_cell"
|
||||||
|
version = "1.10.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "87f3e037eac156d1775da914196f0f37741a274155e34a0b7e427c35d2a2ecb9"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "oorandom"
|
name = "oorandom"
|
||||||
version = "11.1.3"
|
version = "11.1.3"
|
||||||
@ -725,6 +816,12 @@ version = "0.2.2"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "8ccb82d61f80a663efe1f787a51b16b5a51e3314d6ac365b08639f52387b33f3"
|
checksum = "8ccb82d61f80a663efe1f787a51b16b5a51e3314d6ac365b08639f52387b33f3"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "version_check"
|
||||||
|
version = "0.9.4"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "walkdir"
|
name = "walkdir"
|
||||||
version = "2.3.2"
|
version = "2.3.2"
|
||||||
@ -736,6 +833,12 @@ dependencies = [
|
|||||||
"winapi-util",
|
"winapi-util",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "wasi"
|
||||||
|
version = "0.10.2+wasi-snapshot-preview1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "fd6fbd9a79829dd1ad0cc20627bf1ed606756a7f77edff7b66b7064f9cb327c6"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "wasm-bindgen"
|
name = "wasm-bindgen"
|
||||||
version = "0.2.79"
|
version = "0.2.79"
|
||||||
|
@ -14,6 +14,7 @@ exitcode = "1"
|
|||||||
|
|
||||||
serde = { version = "1.0", features = ["derive"] }
|
serde = { version = "1.0", features = ["derive"] }
|
||||||
serde_json = "1.0"
|
serde_json = "1.0"
|
||||||
|
bincode = "1.3"
|
||||||
ipnetwork = "0.18"
|
ipnetwork = "0.18"
|
||||||
|
|
||||||
libc = "0.2.117"
|
libc = "0.2.117"
|
||||||
@ -21,6 +22,7 @@ nix = "0.23.1"
|
|||||||
|
|
||||||
close_fds = "0.3.2"
|
close_fds = "0.3.2"
|
||||||
tempfile = "3.3"
|
tempfile = "3.3"
|
||||||
|
object = { version = "0.28", features = ["write_core"] }
|
||||||
|
|
||||||
[dev-dependencies]
|
[dev-dependencies]
|
||||||
criterion = "0.3"
|
criterion = "0.3"
|
||||||
|
14
src/error.rs
14
src/error.rs
@ -15,13 +15,25 @@ pub enum Error {
|
|||||||
#[error("json: {0}")]
|
#[error("json: {0}")]
|
||||||
Json(#[from] serde_json::Error),
|
Json(#[from] serde_json::Error),
|
||||||
|
|
||||||
|
#[error("bincode: {0}")]
|
||||||
|
Bincode(#[from] bincode::Error),
|
||||||
|
|
||||||
|
#[error("elf: read: {0}")]
|
||||||
|
ElfRead(#[from] object::read::Error),
|
||||||
|
|
||||||
|
#[error("elf: write: {0}")]
|
||||||
|
ElfWrite(#[from] object::write::Error),
|
||||||
|
|
||||||
#[error("bad pipe specification: a pipe must have exactly one reader and one writer: {0}")]
|
#[error("bad pipe specification: a pipe must have exactly one reader and one writer: {0}")]
|
||||||
BadPipe(String),
|
BadPipe(String),
|
||||||
|
|
||||||
#[error("bad socket specification: a socket must have exactly one reader and one writer: {0}")]
|
#[error("bad socket specification: a socket must have exactly one reader and one writer: {0}")]
|
||||||
BadFileSocket(String),
|
BadFileSocket(String),
|
||||||
|
|
||||||
#[error("bad specification type: only .json files are supported")]
|
#[error("no specification provided")]
|
||||||
|
NoSpecification,
|
||||||
|
|
||||||
|
#[error("bad specification type: only json files are supported")]
|
||||||
BadSpecType,
|
BadSpecType,
|
||||||
|
|
||||||
#[error("bad trigger argument: this entrypoint is not triggered by something with arguments")]
|
#[error("bad trigger argument: this entrypoint is not triggered by something with arguments")]
|
||||||
|
24
src/lib.rs
24
src/lib.rs
@ -2,6 +2,7 @@ use log::{debug, info};
|
|||||||
|
|
||||||
pub mod clone;
|
pub mod clone;
|
||||||
mod error;
|
mod error;
|
||||||
|
mod pack;
|
||||||
mod spawner;
|
mod spawner;
|
||||||
mod specification;
|
mod specification;
|
||||||
mod void;
|
mod void;
|
||||||
@ -18,6 +19,22 @@ use std::path::Path;
|
|||||||
use nix::fcntl::OFlag;
|
use nix::fcntl::OFlag;
|
||||||
use nix::sys::socket;
|
use nix::sys::socket;
|
||||||
use nix::unistd;
|
use nix::unistd;
|
||||||
|
pub struct PackArgs<'a> {
|
||||||
|
pub spec: &'a Path,
|
||||||
|
pub binary: &'a Path,
|
||||||
|
pub output: &'a Path,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn pack(args: &PackArgs) -> Result<()> {
|
||||||
|
let spec: Specification = if args.spec.extension().map(|e| e == "json") == Some(true) {
|
||||||
|
let f = std::fs::File::open(args.spec)?;
|
||||||
|
Ok(serde_json::from_reader(f)?)
|
||||||
|
} else {
|
||||||
|
Err(Error::BadSpecType)
|
||||||
|
}?;
|
||||||
|
|
||||||
|
pack::pack_binary(args.binary, &spec, args.output)
|
||||||
|
}
|
||||||
|
|
||||||
pub struct RunArgs<'a> {
|
pub struct RunArgs<'a> {
|
||||||
pub spec: Option<&'a Path>,
|
pub spec: Option<&'a Path>,
|
||||||
@ -37,7 +54,12 @@ pub fn run(args: &RunArgs) -> Result<()> {
|
|||||||
Err(Error::BadSpecType)
|
Err(Error::BadSpecType)
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
unimplemented!("reading spec from the elf is unimplemented")
|
let spec = pack::extract_specification(args.binary)?;
|
||||||
|
if let Some(s) = spec {
|
||||||
|
Ok(s)
|
||||||
|
} else {
|
||||||
|
Err(Error::NoSpecification)
|
||||||
|
}
|
||||||
}?;
|
}?;
|
||||||
|
|
||||||
debug!("specification read: {:?}", &spec);
|
debug!("specification read: {:?}", &spec);
|
||||||
|
59
src/main.rs
59
src/main.rs
@ -1,6 +1,6 @@
|
|||||||
use log::{error, info};
|
use log::{error, info};
|
||||||
|
|
||||||
use clone_shim::{run, RunArgs};
|
use clone_shim::{pack, run, PackArgs, RunArgs};
|
||||||
|
|
||||||
use std::path::Path;
|
use std::path::Path;
|
||||||
|
|
||||||
@ -12,12 +12,39 @@ fn main() {
|
|||||||
.version(env!("GIT_HASH"))
|
.version(env!("GIT_HASH"))
|
||||||
.author("Jake Hillion <jake@hillion.co.uk>")
|
.author("Jake Hillion <jake@hillion.co.uk>")
|
||||||
.about("Launch a void process application.")
|
.about("Launch a void process application.")
|
||||||
|
.subcommand_negates_reqs(true)
|
||||||
.trailing_var_arg(true)
|
.trailing_var_arg(true)
|
||||||
|
.subcommand(
|
||||||
|
Command::new("pack")
|
||||||
.arg(
|
.arg(
|
||||||
Arg::new("spec")
|
Arg::new("spec")
|
||||||
.long("specification")
|
.long("specification")
|
||||||
.short('s')
|
.short('s')
|
||||||
.help("Provide the specification as an external JSON file.")
|
.help("Provide the specification to pack as an external JSON file.")
|
||||||
|
.takes_value(true)
|
||||||
|
.required(true),
|
||||||
|
)
|
||||||
|
.arg(
|
||||||
|
Arg::new("binary")
|
||||||
|
.long("binary")
|
||||||
|
.short('b')
|
||||||
|
.help("Provide the binary to pack.")
|
||||||
|
.takes_value(true)
|
||||||
|
.required(true),
|
||||||
|
)
|
||||||
|
.arg(
|
||||||
|
Arg::new("output")
|
||||||
|
.long("out")
|
||||||
|
.short('o')
|
||||||
|
.help("Location of the output file")
|
||||||
|
.takes_value(true),
|
||||||
|
),
|
||||||
|
)
|
||||||
|
.arg(
|
||||||
|
Arg::new("spec")
|
||||||
|
.long("specification")
|
||||||
|
.short('s')
|
||||||
|
.help("Provide the specification to launch as an external JSON file.")
|
||||||
.takes_value(true),
|
.takes_value(true),
|
||||||
)
|
)
|
||||||
.arg(
|
.arg(
|
||||||
@ -55,8 +82,30 @@ fn main() {
|
|||||||
env_logger::init_from_env(env);
|
env_logger::init_from_env(env);
|
||||||
|
|
||||||
// launch process
|
// launch process
|
||||||
|
|
||||||
|
let code = if let Some(matches) = matches.subcommand_matches("pack") {
|
||||||
|
// execute binary packing procedure
|
||||||
|
let args = PackArgs {
|
||||||
|
spec: Path::new(matches.value_of("spec").expect("spec required")),
|
||||||
|
binary: Path::new(matches.value_of("binary").expect("binary required")),
|
||||||
|
output: matches
|
||||||
|
.value_of("output")
|
||||||
|
.map(Path::new)
|
||||||
|
.unwrap_or_else(|| Path::new("a.out")),
|
||||||
|
};
|
||||||
|
|
||||||
|
match pack(&args) {
|
||||||
|
Ok(_) => {
|
||||||
|
info!("binary packed successfully");
|
||||||
|
exitcode::OK
|
||||||
|
}
|
||||||
|
Err(e) => {
|
||||||
|
error!("error packing binary: {}", e);
|
||||||
|
1
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
// execute shimmed process
|
// execute shimmed process
|
||||||
std::process::exit({
|
|
||||||
let (binary, binary_args) = {
|
let (binary, binary_args) = {
|
||||||
let mut argv = matches.values_of("binary").unwrap();
|
let mut argv = matches.values_of("binary").unwrap();
|
||||||
|
|
||||||
@ -83,5 +132,7 @@ fn main() {
|
|||||||
-1
|
-1
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
})
|
};
|
||||||
|
|
||||||
|
std::process::exit(code);
|
||||||
}
|
}
|
||||||
|
75
src/pack.rs
Normal file
75
src/pack.rs
Normal file
@ -0,0 +1,75 @@
|
|||||||
|
use crate::{Result, Specification};
|
||||||
|
|
||||||
|
use std::fs::File;
|
||||||
|
use std::path::Path;
|
||||||
|
|
||||||
|
use bincode::Options;
|
||||||
|
use object::endian::Endianness;
|
||||||
|
use object::read::ReadCache;
|
||||||
|
use object::read::{Object, ObjectSection};
|
||||||
|
use object::write::{StandardSegment, StreamingBuffer};
|
||||||
|
use object::SectionKind;
|
||||||
|
|
||||||
|
const SPECIFICATION_SECTION_NAME: &str = "void_specification";
|
||||||
|
|
||||||
|
pub(crate) fn pack_binary(binary: &Path, spec: &Specification, output: &Path) -> Result<()> {
|
||||||
|
let binary = File::open(binary)?;
|
||||||
|
let binary = ReadCache::new(binary);
|
||||||
|
|
||||||
|
let output = File::create(output)?;
|
||||||
|
let mut output = StreamingBuffer::new(output);
|
||||||
|
|
||||||
|
let input_object = object::File::parse(&binary)?;
|
||||||
|
|
||||||
|
let format = input_object.format();
|
||||||
|
let architecture = input_object.architecture();
|
||||||
|
let endianness = if input_object.is_little_endian() {
|
||||||
|
Endianness::Little
|
||||||
|
} else {
|
||||||
|
Endianness::Big
|
||||||
|
};
|
||||||
|
|
||||||
|
let mut output_object = object::write::Object::new(format, architecture, endianness);
|
||||||
|
|
||||||
|
for input_section in input_object.sections() {
|
||||||
|
let output_section = output_object.add_section(
|
||||||
|
input_section.segment_name_bytes()?.unwrap_or(&[]).to_vec(),
|
||||||
|
input_section.name_bytes()?.to_vec(),
|
||||||
|
input_section.kind(),
|
||||||
|
);
|
||||||
|
|
||||||
|
output_object.set_section_data(output_section, input_section.data()?, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
let spec_section = output_object.add_section(
|
||||||
|
output_object.segment_name(StandardSegment::Debug).to_vec(),
|
||||||
|
SPECIFICATION_SECTION_NAME.to_string().into(),
|
||||||
|
SectionKind::Other,
|
||||||
|
);
|
||||||
|
|
||||||
|
let spec = bincode_options().serialize(spec)?;
|
||||||
|
output_object.set_section_data(spec_section, spec, 0);
|
||||||
|
|
||||||
|
output_object.emit(&mut output)?;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) fn extract_specification(binary: &Path) -> Result<Option<Specification>> {
|
||||||
|
let binary = File::open(binary)?;
|
||||||
|
let binary = ReadCache::new(binary);
|
||||||
|
let input_object = object::File::parse(&binary)?;
|
||||||
|
|
||||||
|
let spec_section = if let Some(s) = input_object.section_by_name(SPECIFICATION_SECTION_NAME) {
|
||||||
|
s
|
||||||
|
} else {
|
||||||
|
return Ok(None);
|
||||||
|
};
|
||||||
|
|
||||||
|
let spec_data = spec_section.data()?;
|
||||||
|
|
||||||
|
Ok(Some(bincode_options().deserialize(spec_data)?))
|
||||||
|
}
|
||||||
|
|
||||||
|
fn bincode_options() -> impl bincode::Options {
|
||||||
|
bincode::DefaultOptions::new()
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user