mirror of
https://github.com/asterinas/asterinas.git
synced 2025-06-24 18:03:25 +00:00
Introduce the boot trojan
This commit is contained in:
committed by
Tate, Hongliang Tian
parent
ddca4fb2fc
commit
953ff66fcc
@ -7,6 +7,6 @@ edition = "2021"
|
||||
[dependencies]
|
||||
anyhow = "1.0.32"
|
||||
clap = { version = "4.3.19", features = ["derive"] }
|
||||
glob = "0.3.1"
|
||||
aster-boot-trojan-builder = { path = "../framework/libs/boot-trojan/builder" }
|
||||
rand = "0.8.5"
|
||||
xmas-elf = "0.8.0"
|
||||
|
@ -1,4 +1,4 @@
|
||||
mod linux_boot;
|
||||
use aster_boot_trojan_builder::{build_linux_setup_header_from_trojan, make_bzimage};
|
||||
|
||||
use std::{
|
||||
fs,
|
||||
@ -8,8 +8,6 @@ use std::{
|
||||
|
||||
use crate::BootProtocol;
|
||||
|
||||
use glob::glob;
|
||||
|
||||
macro_rules! ovmf_prefix {
|
||||
() => {
|
||||
// There are 3 optional OVMF builds at your service in the dev image
|
||||
@ -70,13 +68,12 @@ pub const GRUB_PREFIX: &str = "/usr/local/grub";
|
||||
pub const GRUB_VERSION: &str = "x86_64-efi";
|
||||
|
||||
pub fn create_bootdev_image(
|
||||
atser_path: PathBuf,
|
||||
aster_path: PathBuf,
|
||||
initramfs_path: PathBuf,
|
||||
grub_cfg: String,
|
||||
protocol: BootProtocol,
|
||||
release_mode: bool,
|
||||
) -> PathBuf {
|
||||
let target_dir = atser_path.parent().unwrap();
|
||||
let target_dir = aster_path.parent().unwrap();
|
||||
let iso_root = target_dir.join("iso_root");
|
||||
|
||||
// Clear or make the iso dir.
|
||||
@ -94,26 +91,22 @@ pub fn create_bootdev_image(
|
||||
|
||||
let target_path = match protocol {
|
||||
BootProtocol::Linux => {
|
||||
// Find the setup header in the build script output directory.
|
||||
let bs_out_dir = if release_mode {
|
||||
glob("target/x86_64-custom/release/build/aster-frame-*").unwrap()
|
||||
} else {
|
||||
glob("target/x86_64-custom/debug/build/aster-frame-*").unwrap()
|
||||
};
|
||||
let header_path = Path::new(bs_out_dir.into_iter().next().unwrap().unwrap().as_path())
|
||||
.join("out")
|
||||
.join("bin")
|
||||
.join("aster-frame-x86-boot-linux-setup");
|
||||
let trojan_install_dir = Path::new("target/-boot-trojan");
|
||||
build_linux_setup_header_from_trojan(
|
||||
Path::new("framework/libs/boot-trojan/trojan"),
|
||||
trojan_install_dir,
|
||||
)
|
||||
.unwrap();
|
||||
let header_path = trojan_install_dir.join("bin").join("aster-boot-trojan");
|
||||
// Make the `bzImage`-compatible kernel image and place it in the boot directory.
|
||||
let target_path = iso_root.join("boot").join("asterinaz");
|
||||
linux_boot::make_bzimage(&target_path, &atser_path.as_path(), &header_path.as_path())
|
||||
.unwrap();
|
||||
make_bzimage(&target_path, &aster_path.as_path(), &header_path.as_path()).unwrap();
|
||||
target_path
|
||||
}
|
||||
BootProtocol::Multiboot | BootProtocol::Multiboot2 => {
|
||||
// Copy the kernel image to the boot directory.
|
||||
let target_path = iso_root.join("boot").join("atserinas");
|
||||
fs::copy(&atser_path, &target_path).unwrap();
|
||||
fs::copy(&aster_path, &target_path).unwrap();
|
||||
target_path
|
||||
}
|
||||
};
|
@ -1,98 +0,0 @@
|
||||
use std::{
|
||||
fs::File,
|
||||
io::{Read, Write},
|
||||
path::Path,
|
||||
};
|
||||
|
||||
use xmas_elf::program::{ProgramHeader, SegmentData};
|
||||
|
||||
// We chose the legacy setup sections to be 7 so that the setup header
|
||||
// is page-aligned and the legacy setup section size would be 0x1000.
|
||||
const LEGACY_SETUP_SECS: usize = 7;
|
||||
const LEGACY_SETUP_SEC_SIZE: usize = 0x200 * (LEGACY_SETUP_SECS + 1);
|
||||
const SETUP32_LMA: usize = 0x100000;
|
||||
|
||||
/// We need a binary which satisfies `LMA == File_Offset`, and objcopy
|
||||
/// does not satisfy us well, so we should parse the ELF and do our own
|
||||
/// objcopy job.
|
||||
///
|
||||
/// Interstingly, the resulting binary should be the same as the memory
|
||||
/// dump of the kernel setup header when it's loaded by the bootloader.
|
||||
fn header_to_raw_binary(elf_file: &[u8]) -> Vec<u8> {
|
||||
let elf = xmas_elf::ElfFile::new(&elf_file).unwrap();
|
||||
let mut bin = Vec::<u8>::new();
|
||||
|
||||
for ph in elf.program_iter() {
|
||||
let ProgramHeader::Ph32(program) = ph else {
|
||||
panic!("Unexpected program header type");
|
||||
};
|
||||
if program.get_type().unwrap() == xmas_elf::program::Type::Load {
|
||||
let SegmentData::Undefined(header_data) = program.get_data(&elf).unwrap() else {
|
||||
panic!("Unexpected segment data type");
|
||||
};
|
||||
let dst_file_offset =
|
||||
program.virtual_addr as usize + LEGACY_SETUP_SEC_SIZE - SETUP32_LMA;
|
||||
let dst_file_length = program.file_size as usize;
|
||||
if bin.len() < dst_file_offset + dst_file_length {
|
||||
bin.resize(dst_file_offset + dst_file_length, 0);
|
||||
}
|
||||
let dest_slice = bin[dst_file_offset..dst_file_offset + dst_file_length].as_mut();
|
||||
dest_slice.copy_from_slice(header_data);
|
||||
}
|
||||
}
|
||||
|
||||
bin
|
||||
}
|
||||
|
||||
/// This function sould be used when generating the Linux x86 Boot setup header.
|
||||
/// Some fields in the Linux x86 Boot setup header should be filled after assembled.
|
||||
/// And the filled fields must have the bytes with values of 0xAB. See
|
||||
/// `framework/aster-frame/src/arch/x86/boot/linux_boot/setup/src/header.S` for more
|
||||
/// info on this mechanism.
|
||||
fn fill_header_field(header: &mut [u8], offset: usize, value: &[u8]) {
|
||||
let size = value.len();
|
||||
assert_eq!(
|
||||
&header[offset..offset + size],
|
||||
vec![0xABu8; size].as_slice()
|
||||
);
|
||||
header[offset..offset + size].copy_from_slice(value);
|
||||
}
|
||||
|
||||
pub fn make_bzimage(path: &Path, kernel_path: &Path, header_path: &Path) -> std::io::Result<()> {
|
||||
let mut header = Vec::new();
|
||||
File::open(header_path)?.read_to_end(&mut header)?;
|
||||
let mut header = header_to_raw_binary(&header);
|
||||
// Pad the header to let the payload starts with 8-byte alignment.
|
||||
header.resize((header.len() + 7) & !7, 0x00);
|
||||
|
||||
let mut kernel = Vec::new();
|
||||
File::open(kernel_path)?.read_to_end(&mut kernel)?;
|
||||
|
||||
let header_len = header.len();
|
||||
let kernel_len = kernel.len();
|
||||
|
||||
let payload_offset = header_len - LEGACY_SETUP_SEC_SIZE + SETUP32_LMA;
|
||||
fill_header_field(
|
||||
&mut header,
|
||||
0x248, /* payload_offset */
|
||||
&(payload_offset as u32).to_le_bytes(),
|
||||
);
|
||||
|
||||
fill_header_field(
|
||||
&mut header,
|
||||
0x24C, /* payload_length */
|
||||
&(kernel_len as u32).to_le_bytes(),
|
||||
);
|
||||
|
||||
fill_header_field(
|
||||
&mut header,
|
||||
0x260, /* init_size */
|
||||
&((header_len + kernel_len) as u32).to_le_bytes(),
|
||||
);
|
||||
|
||||
let mut kernel_image = File::create(path)?;
|
||||
kernel_image.write_all(&header)?;
|
||||
kernel_image.write_all(&kernel)?;
|
||||
|
||||
Ok(())
|
||||
}
|
@ -79,10 +79,6 @@ struct Args {
|
||||
/// Run a GDB client instead of running the kernel.
|
||||
#[arg(long, default_value_t = false)]
|
||||
run_gdb_client: bool,
|
||||
|
||||
/// Run in the release mode.
|
||||
#[arg(long, default_value_t = false)]
|
||||
release_mode: bool,
|
||||
}
|
||||
|
||||
pub const COMMON_ARGS: &[&str] = &[
|
||||
@ -201,7 +197,6 @@ fn main() {
|
||||
initramfs_path,
|
||||
grub_cfg,
|
||||
args.boot_protocol,
|
||||
args.release_mode,
|
||||
);
|
||||
qemu_cmd.arg("-cdrom");
|
||||
qemu_cmd.arg(bootdev_image.as_os_str());
|
||||
|
Reference in New Issue
Block a user