From 487e0cdd15ef06e360e3f506eda7aeedcce106ba Mon Sep 17 00:00:00 2001 From: Zhang Junyang Date: Wed, 13 Dec 2023 16:25:16 +0800 Subject: [PATCH] Recognize kernel memory regions in the Linux boot path --- .github/workflows/integration_test.yml | 14 ++-- .../src/arch/x86/boot/multiboot/mod.rs | 4 +- .../src/arch/x86/boot/multiboot2/mod.rs | 4 +- .../aster-frame/src/arch/x86/timer/apic.rs | 4 +- .../aster-frame/src/vm/frame_allocator.rs | 5 +- .../libs/boot-wrapper/wrapper/src/loader.rs | 1 + .../wrapper/src/x86/amd64_efi/efi.rs | 60 ++++++++--------- .../src/process/credentials/credentials_.rs | 66 +++++++++++++++---- .../aster-std/src/process/posix_thread/mod.rs | 11 +++- .../libs/aster-std/src/process/signal/mod.rs | 2 +- .../libs/aster-std/src/syscall/sigaltstack.rs | 4 +- 11 files changed, 117 insertions(+), 58 deletions(-) diff --git a/.github/workflows/integration_test.yml b/.github/workflows/integration_test.yml index 44e9a070f..215b23a63 100644 --- a/.github/workflows/integration_test.yml +++ b/.github/workflows/integration_test.yml @@ -24,16 +24,14 @@ jobs: id: boot_test_mb2 run: make run AUTO_TEST=boot ENABLE_KVM=0 BOOT_PROTOCOL=multiboot2 RELEASE_MODE=1 - # FIXME: Syscall test under Linux Boot Protocol fails at JobControlTest - # We should re-enable syscall tests after fixing the bug. + - name: Boot Test (MicroVM) + id: boot_test_microvm + run: make run AUTO_TEST=boot ENABLE_KVM=0 BOOT_METHOD=microvm RELEASE_MODE=1 + - name: Boot Test (Linux Boot Protocol) id: boot_test_linux run: make run AUTO_TEST=boot ENABLE_KVM=0 BOOT_PROTOCOL=linux RELEASE_MODE=1 - - name: Regression Test (Multiboot2) - id: regression_test_linux - run: make run AUTO_TEST=regression ENABLE_KVM=0 BOOT_PROTOCOL=multiboot2 RELEASE_MODE=1 - - name: Syscall Test (MicroVM) id: syscall_test_microvm run: make run AUTO_TEST=syscall ENABLE_KVM=0 BOOT_METHOD=microvm RELEASE_MODE=1 @@ -45,3 +43,7 @@ jobs: - name: Syscall Test at Ext2 (MicroVM) id: syscall_test_at_ext2_microvm run: make run AUTO_TEST=syscall SYSCALL_TEST_DIR=/ext2 ENABLE_KVM=0 BOOT_METHOD=microvm RELEASE_MODE=1 + + - name: Regression Test (Linux Boot Protocol) + id: regression_test_linux + run: make run AUTO_TEST=regression ENABLE_KVM=0 BOOT_PROTOCOL=linux RELEASE_MODE=1 diff --git a/framework/aster-frame/src/arch/x86/boot/multiboot/mod.rs b/framework/aster-frame/src/arch/x86/boot/multiboot/mod.rs index 3a27a515f..fb6652d6d 100644 --- a/framework/aster-frame/src/arch/x86/boot/multiboot/mod.rs +++ b/framework/aster-frame/src/arch/x86/boot/multiboot/mod.rs @@ -5,7 +5,9 @@ use spin::Once; use crate::{ boot::{ kcmdline::KCmdlineArg, - memory_region::{non_overlapping_regions_from, MemoryRegion, MemoryRegionType}, + memory_region::{ + non_overlapping_regions_from, MemoryRegion, MemoryRegionType, + }, BootloaderAcpiArg, BootloaderFramebufferArg, }, config::PHYS_OFFSET, diff --git a/framework/aster-frame/src/arch/x86/boot/multiboot2/mod.rs b/framework/aster-frame/src/arch/x86/boot/multiboot2/mod.rs index ff8f9b191..685b12b19 100644 --- a/framework/aster-frame/src/arch/x86/boot/multiboot2/mod.rs +++ b/framework/aster-frame/src/arch/x86/boot/multiboot2/mod.rs @@ -6,7 +6,9 @@ use multiboot2::{BootInformation, BootInformationHeader, MemoryAreaType}; use crate::boot::{ kcmdline::KCmdlineArg, - memory_region::{non_overlapping_regions_from, MemoryRegion, MemoryRegionType}, + memory_region::{ + non_overlapping_regions_from, MemoryRegion, MemoryRegionType, + }, BootloaderAcpiArg, BootloaderFramebufferArg, }; use spin::Once; diff --git a/framework/aster-frame/src/arch/x86/timer/apic.rs b/framework/aster-frame/src/arch/x86/timer/apic.rs index 2707068d6..81441e5e3 100644 --- a/framework/aster-frame/src/arch/x86/timer/apic.rs +++ b/framework/aster-frame/src/arch/x86/timer/apic.rs @@ -56,7 +56,7 @@ fn init_tsc_mode() { fn determine_tsc_freq_via_pit() -> u64 { let mut irq = IrqLine::alloc_specific(super::TIMER_IRQ_NUM.load(Ordering::Relaxed)).unwrap(); irq.on_active(pit_callback); - let mut io_apic = IO_APIC.get().unwrap().get(0).unwrap().lock(); + let mut io_apic = IO_APIC.get().unwrap().first().unwrap().lock(); debug_assert_eq!(io_apic.interrupt_base(), 0); io_apic.enable(2, irq.clone()).unwrap(); drop(io_apic); @@ -87,7 +87,7 @@ fn determine_tsc_freq_via_pit() -> u64 { IN_TIME += 1; return; } - let mut io_apic = IO_APIC.get().unwrap().get(0).unwrap().lock(); + let mut io_apic = IO_APIC.get().unwrap().first().unwrap().lock(); io_apic.disable(2).unwrap(); drop(io_apic); let tsc_count = _rdtsc(); diff --git a/framework/aster-frame/src/vm/frame_allocator.rs b/framework/aster-frame/src/vm/frame_allocator.rs index 0d15281f8..34fb73e45 100644 --- a/framework/aster-frame/src/vm/frame_allocator.rs +++ b/framework/aster-frame/src/vm/frame_allocator.rs @@ -84,9 +84,12 @@ pub(crate) fn init(regions: &[MemoryRegion]) { let mut allocator = FrameAllocator::<32>::new(); for region in regions.iter() { if region.typ() == MemoryRegionType::Usable { - // Make the memory region page-aligned + // Make the memory region page-aligned, and skip if it is too small. let start = region.base().align_up(PAGE_SIZE) / PAGE_SIZE; let end = (region.base() + region.len()).align_down(PAGE_SIZE) / PAGE_SIZE; + if end <= start { + continue; + } allocator.add_frame(start, end); info!( "Found usable region, start:{:x}, end:{:x}", diff --git a/framework/libs/boot-wrapper/wrapper/src/loader.rs b/framework/libs/boot-wrapper/wrapper/src/loader.rs index e4a0558c5..4344ef20b 100644 --- a/framework/libs/boot-wrapper/wrapper/src/loader.rs +++ b/framework/libs/boot-wrapper/wrapper/src/loader.rs @@ -12,6 +12,7 @@ unsafe fn memcpy(dst: *mut u8, src: *const u8, size: usize) { } } +/// Load the kernel ELF payload to memory. pub fn load_elf(file: &[u8]) { let elf = xmas_elf::ElfFile::new(file).unwrap(); diff --git a/framework/libs/boot-wrapper/wrapper/src/x86/amd64_efi/efi.rs b/framework/libs/boot-wrapper/wrapper/src/x86/amd64_efi/efi.rs index 84b6eec15..d2ee4e56c 100644 --- a/framework/libs/boot-wrapper/wrapper/src/x86/amd64_efi/efi.rs +++ b/framework/libs/boot-wrapper/wrapper/src/x86/amd64_efi/efi.rs @@ -39,7 +39,7 @@ extern "sysv64" fn efi_handover_entry( fn efi_phase_boot( handle: Handle, system_table: SystemTable, - boot_params: *mut BootParams, + boot_params_ptr: *mut BootParams, ) -> ! { // Safety: this init function is only called once. unsafe { crate::console::init() }; @@ -50,7 +50,7 @@ fn efi_phase_boot( uefi_services::println!("[EFI stub] Relocations applied."); uefi_services::println!("[EFI stub] Loading payload."); - let payload = unsafe { crate::get_payload(&*boot_params) }; + let payload = unsafe { crate::get_payload(&*boot_params_ptr) }; crate::loader::load_elf(payload); uefi_services::println!("[EFI stub] Exiting EFI boot services."); @@ -63,7 +63,7 @@ fn efi_phase_boot( }; let (system_table, memory_map) = system_table.exit_boot_services(memory_type); - efi_phase_runtime(system_table, memory_map, boot_params); + efi_phase_runtime(system_table, memory_map, boot_params_ptr); } fn efi_phase_runtime( @@ -75,36 +75,10 @@ fn efi_phase_runtime( crate::console::print_str("[EFI stub] Entered runtime services.\n"); } - let boot_params = unsafe { &mut *boot_params_ptr }; - - // Write memory map to e820 table in boot_params. - let e820_table = &mut boot_params.e820_table; - let mut e820_entries = 0; - for md in memory_map.entries() { - if e820_entries >= e820_table.len() || e820_entries >= 128 { - break; - } - e820_table[e820_entries] = linux_boot_params::BootE820Entry { - addr: md.phys_start as u64, - size: md.page_count as u64 * 4096, - typ: match md.ty { - uefi::table::boot::MemoryType::CONVENTIONAL => linux_boot_params::E820Type::Ram, - uefi::table::boot::MemoryType::RESERVED => linux_boot_params::E820Type::Reserved, - uefi::table::boot::MemoryType::ACPI_RECLAIM => linux_boot_params::E820Type::Acpi, - uefi::table::boot::MemoryType::ACPI_NON_VOLATILE => { - linux_boot_params::E820Type::Nvs - } - _ => linux_boot_params::E820Type::Reserved, - }, - }; - e820_entries += 1; - } - boot_params.e820_entries = e820_entries as u8; - #[cfg(feature = "debug_print")] unsafe { use crate::console::{print_hex, print_str}; - print_str("[EFI stub debug] Memory map:\n"); + print_str("[EFI stub debug] EFI Memory map:\n"); for md in memory_map.entries() { // crate::println!(" [{:#x}] {:#x} ({:#x})", md.ty.0, md.phys_start, md.page_count); print_str(" ["); @@ -120,6 +94,32 @@ fn efi_phase_runtime( } } + let boot_params = unsafe { &mut *boot_params_ptr }; + + // Write memory map to e820 table in boot_params. + let e820_table = &mut boot_params.e820_table; + let mut e820_entries = 0usize; + for md in memory_map.entries() { + if e820_entries >= e820_table.len() || e820_entries >= 128 { + break; + } + e820_table[e820_entries] = linux_boot_params::BootE820Entry { + addr: md.phys_start as u64, + size: md.page_count as u64 * 4096, + typ: match md.ty { + uefi::table::boot::MemoryType::CONVENTIONAL => linux_boot_params::E820Type::Ram, + uefi::table::boot::MemoryType::RESERVED => linux_boot_params::E820Type::Reserved, + uefi::table::boot::MemoryType::ACPI_RECLAIM => linux_boot_params::E820Type::Acpi, + uefi::table::boot::MemoryType::ACPI_NON_VOLATILE => { + linux_boot_params::E820Type::Nvs + } + _ => linux_boot_params::E820Type::Unusable, + }, + }; + e820_entries += 1; + } + boot_params.e820_entries = e820_entries as u8; + unsafe { use crate::console::{print_hex, print_str}; print_str("[EFI stub] Entering Jinux entrypoint at "); diff --git a/services/libs/aster-std/src/process/credentials/credentials_.rs b/services/libs/aster-std/src/process/credentials/credentials_.rs index 6b4f32e28..6edd77758 100644 --- a/services/libs/aster-std/src/process/credentials/credentials_.rs +++ b/services/libs/aster-std/src/process/credentials/credentials_.rs @@ -158,16 +158,37 @@ impl Credentials_ { return Ok(()); } - if let Some(ruid) = ruid && *ruid != self.ruid() && *ruid != self.euid() && (!ruid_may_be_old_suid || *ruid != self.suid()) { - return_errno_with_message!(Errno::EPERM, "ruid can only be one of old ruid, old euid (and old suid)."); + if let Some(ruid) = ruid + && *ruid != self.ruid() + && *ruid != self.euid() + && (!ruid_may_be_old_suid || *ruid != self.suid()) + { + return_errno_with_message!( + Errno::EPERM, + "ruid can only be one of old ruid, old euid (and old suid)." + ); } - if let Some(euid) = euid && *euid != self.ruid() && *euid != self.euid() && *euid != self.suid() { - return_errno_with_message!(Errno::EPERM, "euid can only be one of old ruid, old euid and old suid.") + if let Some(euid) = euid + && *euid != self.ruid() + && *euid != self.euid() + && *euid != self.suid() + { + return_errno_with_message!( + Errno::EPERM, + "euid can only be one of old ruid, old euid and old suid." + ) } - if let Some(suid) = suid && *suid != self.ruid() && *suid != self.euid() && *suid != self.suid() { - return_errno_with_message!(Errno::EPERM, "suid can only be one of old ruid, old euid and old suid.") + if let Some(suid) = suid + && *suid != self.ruid() + && *suid != self.euid() + && *suid != self.suid() + { + return_errno_with_message!( + Errno::EPERM, + "suid can only be one of old ruid, old euid and old suid." + ) } Ok(()) @@ -291,16 +312,37 @@ impl Credentials_ { return Ok(()); } - if let Some(rgid) = rgid && *rgid != self.rgid() && *rgid != self.egid() && (!rgid_may_be_old_sgid || *rgid != self.sgid()) { - return_errno_with_message!(Errno::EPERM, "rgid can only be one of old rgid, old egid (and old sgid)."); + if let Some(rgid) = rgid + && *rgid != self.rgid() + && *rgid != self.egid() + && (!rgid_may_be_old_sgid || *rgid != self.sgid()) + { + return_errno_with_message!( + Errno::EPERM, + "rgid can only be one of old rgid, old egid (and old sgid)." + ); } - if let Some(egid) = egid && *egid != self.rgid() && *egid != self.egid() && *egid != self.sgid() { - return_errno_with_message!(Errno::EPERM, "egid can only be one of old rgid, old egid and old sgid.") + if let Some(egid) = egid + && *egid != self.rgid() + && *egid != self.egid() + && *egid != self.sgid() + { + return_errno_with_message!( + Errno::EPERM, + "egid can only be one of old rgid, old egid and old sgid." + ) } - if let Some(sgid) = sgid && *sgid != self.rgid() && *sgid != self.egid() && *sgid != self.sgid() { - return_errno_with_message!(Errno::EPERM, "sgid can only be one of old rgid, old egid and old sgid.") + if let Some(sgid) = sgid + && *sgid != self.rgid() + && *sgid != self.egid() + && *sgid != self.sgid() + { + return_errno_with_message!( + Errno::EPERM, + "sgid can only be one of old rgid, old egid and old sgid." + ) } Ok(()) diff --git a/services/libs/aster-std/src/process/posix_thread/mod.rs b/services/libs/aster-std/src/process/posix_thread/mod.rs index e936663f7..4679efe92 100644 --- a/services/libs/aster-std/src/process/posix_thread/mod.rs +++ b/services/libs/aster-std/src/process/posix_thread/mod.rs @@ -101,12 +101,17 @@ impl PosixThread { return Ok(()); } - if let Some(signum) = signum && *signum == SIGCONT { + if let Some(signum) = signum + && *signum == SIGCONT + { let receiver_sid = self.process().session().unwrap().sid(); if receiver_sid == sender.sid() { - return Ok(()) + return Ok(()); } else { - return_errno_with_message!(Errno::EPERM, "sigcont requires that sender and receiver belongs to the same session"); + return_errno_with_message!( + Errno::EPERM, + "sigcont requires that sender and receiver belongs to the same session" + ); } } diff --git a/services/libs/aster-std/src/process/signal/mod.rs b/services/libs/aster-std/src/process/signal/mod.rs index 6415374fe..950479d58 100644 --- a/services/libs/aster-std/src/process/signal/mod.rs +++ b/services/libs/aster-std/src/process/signal/mod.rs @@ -14,7 +14,7 @@ pub mod signals; pub use events::{SigEvents, SigEventsFilter}; pub use pauser::Pauser; pub use poll::{Pollee, Poller}; -pub use sig_stack::{SigStack, SigStackFlags, SigStackStatus}; +pub use sig_stack::{SigStack, SigStackFlags}; use align_ext::AlignExt; use aster_frame::cpu::UserContext; diff --git a/services/libs/aster-std/src/syscall/sigaltstack.rs b/services/libs/aster-std/src/syscall/sigaltstack.rs index 22f291f1a..e64679937 100644 --- a/services/libs/aster-std/src/syscall/sigaltstack.rs +++ b/services/libs/aster-std/src/syscall/sigaltstack.rs @@ -49,7 +49,9 @@ fn set_new_stack(sig_stack_addr: Vaddr, old_stack: Option<&SigStack>) -> Result< return Ok(()); } - if let Some(old_stack) = old_stack && old_stack.is_active() { + if let Some(old_stack) = old_stack + && old_stack.is_active() + { return_errno_with_message!(Errno::EPERM, "the old stack is active now"); }