mirror of
https://github.com/lune-org/lune.git
synced 2025-04-13 06:50:54 +01:00
feat: store magic signature as a meaningful constant
This commit is contained in:
parent
94b27d81d1
commit
3c2464d3ce
3 changed files with 33 additions and 30 deletions
|
@ -8,6 +8,11 @@ use tokio::{
|
||||||
use anyhow::Result;
|
use anyhow::Result;
|
||||||
use mlua::Compiler as LuaCompiler;
|
use mlua::Compiler as LuaCompiler;
|
||||||
|
|
||||||
|
// The signature which separates indicates the presence of bytecode to execute
|
||||||
|
// If a binary contains this magic signature as the last 8 bytes, that must mean
|
||||||
|
// it is a standalone binary
|
||||||
|
pub const MAGIC: &[u8; 8] = b"cr3sc3nt";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
Compiles and embeds the bytecode of a requested lua file to form a standalone binary,
|
Compiles and embeds the bytecode of a requested lua file to form a standalone binary,
|
||||||
then writes it to an output file, with the required permissions.
|
then writes it to an output file, with the required permissions.
|
||||||
|
@ -32,10 +37,6 @@ pub async fn build_standalone<T: AsRef<Path>>(
|
||||||
let mut patched_bin = fs::read(env::current_exe()?).await?;
|
let mut patched_bin = fs::read(env::current_exe()?).await?;
|
||||||
let base_bin_offset = u64::try_from(patched_bin.len())?;
|
let base_bin_offset = u64::try_from(patched_bin.len())?;
|
||||||
|
|
||||||
// The signature which separates indicates the presence of bytecode to execute
|
|
||||||
// If a binary contains this signature, that must mean it is a standalone binary
|
|
||||||
let signature: Vec<u8> = vec![0x4f, 0x3e, 0xf8, 0x41, 0xc3, 0x3a, 0x52, 0x16];
|
|
||||||
|
|
||||||
// Compile luau input into bytecode
|
// Compile luau input into bytecode
|
||||||
let bytecode = LuaCompiler::new()
|
let bytecode = LuaCompiler::new()
|
||||||
.set_optimization_level(2)
|
.set_optimization_level(2)
|
||||||
|
@ -45,18 +46,18 @@ pub async fn build_standalone<T: AsRef<Path>>(
|
||||||
|
|
||||||
println!(" {bytecode_prefix} {script_path}");
|
println!(" {bytecode_prefix} {script_path}");
|
||||||
|
|
||||||
patched_bin.append(&mut bytecode.clone());
|
patched_bin.extend(&bytecode);
|
||||||
|
|
||||||
let mut meta = base_bin_offset.to_ne_bytes().to_vec();
|
let mut meta = base_bin_offset.to_ne_bytes().to_vec(); // Start with the base bytecode offset
|
||||||
|
|
||||||
// Include metadata in the META chunk, each field is 8 bytes
|
// Include metadata in the META chunk, each field is 8 bytes
|
||||||
meta.append(&mut (bytecode.len() as u64).to_ne_bytes().to_vec()); // Size of bytecode, used to calculate end offset at runtime
|
meta.extend((bytecode.len() as u64).to_ne_bytes()); // Size of bytecode, used to calculate end offset at runtime
|
||||||
meta.append(&mut 1_u64.to_ne_bytes().to_vec()); // Number of files, padded with null bytes - for future use
|
meta.extend(1_u64.to_ne_bytes()); // Number of files, padded with null bytes - for future use
|
||||||
|
|
||||||
patched_bin.append(&mut meta);
|
patched_bin.extend(meta);
|
||||||
|
|
||||||
// Append the signature to the base binary
|
// Append the magic signature to the base binary
|
||||||
patched_bin.append(&mut signature.clone());
|
patched_bin.extend(MAGIC);
|
||||||
|
|
||||||
// Write the compiled binary to file
|
// Write the compiled binary to file
|
||||||
#[cfg(target_family = "unix")]
|
#[cfg(target_family = "unix")]
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
use std::{env, ops::ControlFlow, process::ExitCode};
|
use std::{env, ops::ControlFlow, process::ExitCode};
|
||||||
|
|
||||||
|
use crate::cli::build::MAGIC;
|
||||||
use lune::Lune;
|
use lune::Lune;
|
||||||
|
|
||||||
use anyhow::Result;
|
use anyhow::Result;
|
||||||
|
@ -9,10 +10,7 @@ use tokio::fs::read as read_to_vec;
|
||||||
Returns information about whether the execution environment is standalone
|
Returns information about whether the execution environment is standalone
|
||||||
or not, the standalone binary signature, and the contents of the binary.
|
or not, the standalone binary signature, and the contents of the binary.
|
||||||
*/
|
*/
|
||||||
pub async fn check_env() -> (bool, Vec<u8>, Vec<u8>) {
|
pub async fn check_env() -> (bool, Vec<u8>) {
|
||||||
// Signature which is only present in standalone lune binaries
|
|
||||||
let signature: Vec<u8> = vec![0x4f, 0x3e, 0xf8, 0x41, 0xc3, 0x3a, 0x52, 0x16];
|
|
||||||
|
|
||||||
// Read the current lune binary to memory
|
// Read the current lune binary to memory
|
||||||
let bin = if let Ok(contents) = read_to_vec(
|
let bin = if let Ok(contents) = read_to_vec(
|
||||||
env::current_exe().expect("failed to get path to current running lune executable"),
|
env::current_exe().expect("failed to get path to current running lune executable"),
|
||||||
|
@ -24,20 +22,21 @@ pub async fn check_env() -> (bool, Vec<u8>, Vec<u8>) {
|
||||||
Vec::new()
|
Vec::new()
|
||||||
};
|
};
|
||||||
|
|
||||||
let is_standalone = !bin.is_empty() && bin[bin.len() - signature.len()..bin.len()] == signature;
|
let is_standalone =
|
||||||
|
!bin.is_empty() && bin[bin.len() - MAGIC.len()..bin.len()] == MAGIC.to_vec();
|
||||||
|
|
||||||
(is_standalone, signature, bin)
|
(is_standalone, bin)
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
Discovers, loads and executes the bytecode contained in a standalone binary.
|
Discovers, loads and executes the bytecode contained in a standalone binary.
|
||||||
*/
|
*/
|
||||||
pub async fn run_standalone(signature: Vec<u8>, bin: Vec<u8>) -> Result<ExitCode> {
|
pub async fn run_standalone(bin: Vec<u8>) -> Result<ExitCode> {
|
||||||
let mut bytecode_offset = 0;
|
let mut bytecode_offset = 0;
|
||||||
let mut bytecode_size = 0;
|
let mut bytecode_size = 0;
|
||||||
|
|
||||||
// standalone binary structure (reversed, 8 bytes per field)
|
// standalone binary structure (reversed, 8 bytes per field)
|
||||||
// [0] => signature
|
// [0] => magic signature
|
||||||
// ----------------
|
// ----------------
|
||||||
// -- META Chunk --
|
// -- META Chunk --
|
||||||
// [1] => file count
|
// [1] => file count
|
||||||
|
@ -47,21 +46,21 @@ pub async fn run_standalone(signature: Vec<u8>, bin: Vec<u8>) -> Result<ExitCode
|
||||||
// -- MISC Chunk --
|
// -- MISC Chunk --
|
||||||
// [4..n] => bytecode (variable size)
|
// [4..n] => bytecode (variable size)
|
||||||
// ----------------
|
// ----------------
|
||||||
// NOTE: All integers are 8 byte unsigned 64 bit (u64's).
|
// NOTE: All integers are 8 byte, padded, unsigned & 64 bit (u64's).
|
||||||
|
|
||||||
// The rchunks will have unequally sized sections in the beginning
|
// The rchunks will have unequally sized sections in the beginning
|
||||||
// but that doesn't matter to us because we don't need anything past the
|
// but that doesn't matter to us because we don't need anything past the
|
||||||
// middle chunks where the bytecode is stored
|
// middle chunks where the bytecode is stored
|
||||||
bin.rchunks(signature.len())
|
bin.rchunks(MAGIC.len())
|
||||||
.enumerate()
|
.enumerate()
|
||||||
.try_for_each(|(idx, chunk)| {
|
.try_for_each(|(idx, chunk)| {
|
||||||
if bytecode_offset != 0 && bytecode_size != 0 {
|
if bytecode_offset != 0 && bytecode_size != 0 {
|
||||||
return ControlFlow::Break(());
|
return ControlFlow::Break(());
|
||||||
}
|
}
|
||||||
|
|
||||||
if idx == 0 && chunk != signature {
|
if idx == 0 && chunk != MAGIC {
|
||||||
// Binary is guaranteed to be standalone, we've confirmed this before
|
// Binary is guaranteed to be standalone, we've confirmed this before
|
||||||
unreachable!("expected proper signature for standalone binary")
|
unreachable!("expected proper magic signature for standalone binary")
|
||||||
}
|
}
|
||||||
|
|
||||||
if idx == 3 {
|
if idx == 3 {
|
||||||
|
@ -78,16 +77,19 @@ pub async fn run_standalone(signature: Vec<u8>, bin: Vec<u8>) -> Result<ExitCode
|
||||||
// If we were able to retrieve the required metadata, we load
|
// If we were able to retrieve the required metadata, we load
|
||||||
// and execute the bytecode
|
// and execute the bytecode
|
||||||
|
|
||||||
|
// println!("offset: {}", bytecode_offset);
|
||||||
|
// println!("size: {}", bytecode_size);
|
||||||
|
|
||||||
// Skip the first argument which is the path to current executable
|
// Skip the first argument which is the path to current executable
|
||||||
let args = env::args().skip(1).collect::<Vec<_>>();
|
let args = env::args().skip(1).collect::<Vec<_>>();
|
||||||
|
let bytecode =
|
||||||
|
&bin[usize::try_from(bytecode_offset)?..usize::try_from(bytecode_offset + bytecode_size)?];
|
||||||
|
|
||||||
|
// println!("bytecode: {:?}", bytecode);
|
||||||
|
|
||||||
let result = Lune::new()
|
let result = Lune::new()
|
||||||
.with_args(args)
|
.with_args(args)
|
||||||
.run(
|
.run("STANDALONE", bytecode)
|
||||||
"STANDALONE",
|
|
||||||
&bin[usize::try_from(bytecode_offset)?
|
|
||||||
..usize::try_from(bytecode_offset + bytecode_size)?],
|
|
||||||
)
|
|
||||||
.await;
|
.await;
|
||||||
|
|
||||||
Ok(match result {
|
Ok(match result {
|
||||||
|
|
|
@ -28,12 +28,12 @@ async fn main() -> ExitCode {
|
||||||
.with_level(true)
|
.with_level(true)
|
||||||
.init();
|
.init();
|
||||||
|
|
||||||
let (is_standalone, signature, bin) = executor::check_env().await;
|
let (is_standalone, bin) = executor::check_env().await;
|
||||||
|
|
||||||
if is_standalone {
|
if is_standalone {
|
||||||
// It's fine to unwrap here since we don't want to continue
|
// It's fine to unwrap here since we don't want to continue
|
||||||
// if something fails
|
// if something fails
|
||||||
return executor::run_standalone(signature, bin).await.unwrap();
|
return executor::run_standalone(bin).await.unwrap();
|
||||||
}
|
}
|
||||||
|
|
||||||
match Cli::parse().run().await {
|
match Cli::parse().run().await {
|
||||||
|
|
Loading…
Add table
Reference in a new issue