Files

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"
);
}
}