89 lines
3.2 KiB
Rust
89 lines
3.2 KiB
Rust
use std::{env, fs, path::PathBuf, process::Command};
|
|
|
|
fn main() {
|
|
println!("cargo:rerun-if-changed=../runtime-proxy.c");
|
|
println!("cargo:rerun-if-env-changed=ARCHY_RUNTIME_PROXY_CC");
|
|
let output = PathBuf::from(env::var_os("OUT_DIR").unwrap()).join("archipelago-runtime-proxy");
|
|
let arch = env::var("CARGO_CFG_TARGET_ARCH").unwrap();
|
|
if env::var("CARGO_CFG_TARGET_OS").unwrap() != "linux"
|
|
|| env::var("CARGO_CFG_TARGET_ENDIAN").unwrap() != "little"
|
|
|| !matches!(arch.as_str(), "x86_64" | "aarch64")
|
|
{
|
|
fs::write(output, []).unwrap();
|
|
return; // Protected activation explicitly refuses unavailable artifacts.
|
|
}
|
|
let compiler = env::var("ARCHY_RUNTIME_PROXY_CC").unwrap_or_else(|_| {
|
|
if env::var("HOST").unwrap() == env::var("TARGET").unwrap() {
|
|
"/usr/bin/cc".into()
|
|
} else if arch == "aarch64" {
|
|
"/usr/bin/aarch64-linux-gnu-gcc".into()
|
|
} else {
|
|
"/usr/bin/x86_64-linux-gnu-gcc".into()
|
|
}
|
|
});
|
|
assert!(
|
|
std::path::Path::new(&compiler).is_absolute(),
|
|
"ARCHY_RUNTIME_PROXY_CC must be an absolute executable path"
|
|
);
|
|
println!("cargo:rerun-if-changed={compiler}");
|
|
let source =
|
|
PathBuf::from(env::var_os("CARGO_MANIFEST_DIR").unwrap()).join("../runtime-proxy.c");
|
|
let status = Command::new(&compiler)
|
|
.env_clear()
|
|
.env("PATH", "/usr/bin:/bin")
|
|
.env("LC_ALL", "C")
|
|
.args([
|
|
"-std=c11",
|
|
"-O2",
|
|
"-static-pie",
|
|
"-fstack-protector-strong",
|
|
"-D_FORTIFY_SOURCE=3",
|
|
"-Wl,-z,relro,-z,now",
|
|
"-Wall",
|
|
"-Wextra",
|
|
"-Werror",
|
|
"-fno-ident",
|
|
])
|
|
.arg(source)
|
|
.arg("-o")
|
|
.arg(&output)
|
|
.status()
|
|
.expect("compile static runtime proxy");
|
|
assert!(status.success(), "static runtime proxy compilation failed");
|
|
let bytes = fs::read(output).unwrap();
|
|
assert!(
|
|
bytes.len() >= 64
|
|
&& bytes.len() <= 8 * 1024 * 1024
|
|
&& &bytes[..4] == b"\x7fELF"
|
|
&& bytes[4] == 2
|
|
&& bytes[5] == 1,
|
|
"runtime proxy must be a bounded little-endian ELF64 executable"
|
|
);
|
|
let machine = u16::from_le_bytes(bytes[18..20].try_into().unwrap());
|
|
assert_eq!(
|
|
machine,
|
|
if arch == "x86_64" { 62 } else { 183 },
|
|
"runtime proxy target differs from backend"
|
|
);
|
|
let offset = usize::try_from(u64::from_le_bytes(bytes[32..40].try_into().unwrap())).unwrap();
|
|
let size = u16::from_le_bytes(bytes[54..56].try_into().unwrap()) as usize;
|
|
let count = u16::from_le_bytes(bytes[56..58].try_into().unwrap()) as usize;
|
|
assert!(
|
|
size == 56
|
|
&& count > 0
|
|
&& count <= 128
|
|
&& offset.checked_add(size * count).unwrap() <= bytes.len()
|
|
);
|
|
for index in 0..count {
|
|
assert_ne!(
|
|
u32::from_le_bytes(
|
|
bytes[offset + index * size..offset + index * size + 4]
|
|
.try_into()
|
|
.unwrap()
|
|
),
|
|
3,
|
|
"runtime proxy must have no injectable ELF interpreter"
|
|
);
|
|
}
|
|
}
|