diff --git a/kernel/Cargo.toml b/kernel/Cargo.toml index 414df828b..1b30dbafd 100644 --- a/kernel/Cargo.toml +++ b/kernel/Cargo.toml @@ -10,7 +10,7 @@ edition = "2021" crate-type = ["staticlib"] [workspace] -members = [ +members = [ "crates/*", ] diff --git a/kernel/src/libs/elf.rs b/kernel/src/libs/elf.rs index 7cbfdb918..9c35ecf4e 100644 --- a/kernel/src/libs/elf.rs +++ b/kernel/src/libs/elf.rs @@ -7,10 +7,10 @@ use core::{ use alloc::vec::Vec; use elf::{ - abi::{PT_GNU_PROPERTY, PT_INTERP}, + abi::{ET_DYN, ET_EXEC, PT_GNU_PROPERTY, PT_INTERP, PT_LOAD}, endian::AnyEndian, file::FileHeader, - segment::ProgramHeader, + segment::{ProgramHeader, SegmentTable}, }; use log::error; use system_error::SystemError; @@ -18,7 +18,6 @@ use system_error::SystemError; use crate::{ arch::{CurrentElfArch, MMArch}, driver::base::block::SeekFrom, - filesystem::vfs::file::File, libs::align::page_align_up, mm::{ allocator::page_frame::{PageFrameCount, VirtPageFrame}, @@ -28,7 +27,9 @@ use crate::{ }, process::{ abi::AtType, - exec::{BinaryLoader, BinaryLoaderResult, ExecError, ExecLoadMode, ExecParam}, + exec::{ + BinaryLoader, BinaryLoaderResult, ExecError, ExecLoadMode, ExecParam, ExecParamFlags, + }, ProcessFlags, ProcessManager, }, syscall::user_access::{clear_user, copy_to_user}, @@ -121,8 +122,8 @@ impl ElfLoader { end: VirtAddr, prot_flags: ProtFlags, ) -> Result<(), ExecError> { - let start = self.elf_page_start(start); - let end = self.elf_page_align_up(end); + let start = Self::elf_page_start(start); + let end = Self::elf_page_align_up(end); // debug!("set_elf_brk: start={:?}, end={:?}", start, end); if end > start { let r = user_vm_guard.map_anonymous( @@ -145,15 +146,15 @@ impl ElfLoader { } /// 计算addr在ELF PAGE内的偏移 - fn elf_page_offset(&self, addr: VirtAddr) -> usize { + fn elf_page_offset(addr: VirtAddr) -> usize { addr.data() & (CurrentElfArch::ELF_PAGE_SIZE - 1) } - fn elf_page_start(&self, addr: VirtAddr) -> VirtAddr { + fn elf_page_start(addr: VirtAddr) -> VirtAddr { VirtAddr::new(addr.data() & (!(CurrentElfArch::ELF_PAGE_SIZE - 1))) } - fn elf_page_align_up(&self, addr: VirtAddr) -> VirtAddr { + fn elf_page_align_up(addr: VirtAddr) -> VirtAddr { VirtAddr::new( (addr.data() + CurrentElfArch::ELF_PAGE_SIZE - 1) & (!(CurrentElfArch::ELF_PAGE_SIZE - 1)), @@ -161,7 +162,7 @@ impl ElfLoader { } /// 根据ELF的p_flags生成对应的ProtFlags - fn make_prot(&self, p_flags: u32, _has_interpreter: bool, _is_interpreter: bool) -> ProtFlags { + fn make_prot(p_flags: u32, _has_interpreter: bool, _is_interpreter: bool) -> ProtFlags { let mut prot = ProtFlags::empty(); if p_flags & elf::abi::PF_R != 0 { prot |= ProtFlags::PROT_READ; @@ -198,7 +199,6 @@ impl ElfLoader { /// - `Ok((VirtAddr, bool))`:如果成功加载,则bool值为true,否则为false. VirtAddr为加载的地址 #[allow(clippy::too_many_arguments)] fn load_elf_segment( - &self, user_vm_guard: &mut RwLockWriteGuard<'_, InnerAddressSpace>, param: &mut ExecParam, phent: &ProgramHeader, @@ -210,11 +210,11 @@ impl ElfLoader { // debug!("load_elf_segment: addr_to_map={:?}", addr_to_map); // 映射位置的偏移量(页内偏移) - let beginning_page_offset = self.elf_page_offset(addr_to_map); - addr_to_map = self.elf_page_start(addr_to_map); + let beginning_page_offset = Self::elf_page_offset(addr_to_map); + addr_to_map = Self::elf_page_start(addr_to_map); // 计算要映射的内存的大小 let map_size = phent.p_filesz as usize + beginning_page_offset; - let map_size = self.elf_page_align_up(VirtAddr::new(map_size)).data(); + let map_size = Self::elf_page_align_up(VirtAddr::new(map_size)).data(); // 当前段在文件中的大小 let seg_in_file_size = phent.p_filesz as usize; // 当前段在文件中的偏移量 @@ -253,7 +253,9 @@ impl ElfLoader { // So we first map the 'big' image - and unmap the remainder at // the end. (which unmap is needed for ELF images with holes.) if total_size != 0 { - let total_size = self.elf_page_align_up(VirtAddr::new(total_size)).data(); + let total_size = Self::elf_page_align_up(VirtAddr::new(total_size)).data(); + + // log::debug!("total_size={}", total_size); map_addr = user_vm_guard .map_anonymous(addr_to_map, total_size, tmp_prot, *map_flags, false, true) @@ -269,7 +271,7 @@ impl ElfLoader { )?; // 加载文件到内存 - self.do_load_file( + Self::do_load_file( map_addr + beginning_page_offset, seg_in_file_size, file_offset, @@ -294,7 +296,7 @@ impl ElfLoader { // ); // 加载文件到内存 - self.do_load_file( + Self::do_load_file( map_addr + beginning_page_offset, seg_in_file_size, file_offset, @@ -313,6 +315,152 @@ impl ElfLoader { return Ok((map_addr, true)); } + /// 加载elf动态链接器 + /// + /// ## 参数 + /// + /// - `interp_elf_ex`:动态链接器 + /// - `load_bias`偏移量 + /// + /// ## TODO + /// + /// 添加一个Arch state抽象,描述架构相关的elf state(参考 https://code.dragonos.org.cn/xref/linux-6.1.9/fs/binfmt_elf.c#592) + fn load_elf_interp( + interp_elf_ex: &mut ExecParam, + load_bias: usize, + ) -> Result { + // log::debug!("loading elf interp"); + let mut head_buf = [0u8; 512]; + interp_elf_ex + .file_mut() + .lseek(SeekFrom::SeekSet(0)) + .map_err(|_| ExecError::NotSupported)?; + let _bytes = interp_elf_ex + .file_mut() + .read(512, &mut head_buf) + .map_err(|_| ExecError::NotSupported)?; + let interp_hdr = + Self::parse_ehdr(head_buf.as_ref()).map_err(|_| ExecError::NotExecutable)?; + if interp_hdr.e_type != ET_EXEC && interp_hdr.e_type != ET_DYN { + return Err(ExecError::NotExecutable); + } + let mut phdr_buf = Vec::new(); + let phdr_table = Self::parse_segments(interp_elf_ex, &interp_hdr, &mut phdr_buf) + .map_err(|_| ExecError::ParseError)? + .ok_or(ExecError::ParseError)?; + //TODO 架构相关检查 https://code.dragonos.org.cn/xref/linux-6.1.9/fs/binfmt_elf.c#610 + let mut total_size = Self::total_mapping_size(&phdr_table); + + if total_size == 0 { + return Err(ExecError::InvalidParemeter); + } + + let mut load_addr_set = false; + let mut load_addr: VirtAddr = VirtAddr::new(0); + let mut elf_bss: VirtAddr = VirtAddr::new(0); + let mut last_bss: VirtAddr = VirtAddr::new(0); + let mut bss_prot: Option = None; + for section in phdr_table { + if section.p_type == PT_LOAD { + // log::debug!("loading {:?}", section); + let mut elf_type = MapFlags::MAP_PRIVATE; + let elf_prot = Self::make_prot(section.p_flags, true, true); + let vaddr = TryInto::::try_into(section.p_vaddr).unwrap(); + let mut addr_to_map = load_addr + vaddr; + if interp_hdr.e_type == ET_EXEC || load_addr_set { + elf_type.insert(MapFlags::MAP_FIXED) //TODO 应当为MapFlags::MAP_FIXED,暂时未支持 + } else if load_bias != 0 && interp_hdr.e_type == ET_DYN { + addr_to_map = VirtAddr::new(0); + } + let map_addr = Self::load_elf_segment( + &mut interp_elf_ex.vm().clone().write(), + interp_elf_ex, + §ion, + addr_to_map, + &elf_prot, + &elf_type, + total_size, + ) + .map_err(|e| { + log::error!("Failed to load elf interpreter :{:?}", e); + return ExecError::InvalidParemeter; + })?; + if !map_addr.1 { + return Err(ExecError::BadAddress(Some(map_addr.0))); + } + let map_addr = map_addr.0; + total_size = 0; + if !load_addr_set && interp_hdr.e_type == ET_DYN { + load_addr = + VirtAddr::new(map_addr - Self::elf_page_start(VirtAddr::new(vaddr))); + load_addr_set = true; + } + let addr = load_addr + TryInto::::try_into(section.p_vaddr).unwrap(); + if addr >= MMArch::USER_END_VADDR + || section.p_filesz > section.p_memsz + || TryInto::::try_into(section.p_memsz).unwrap() + > MMArch::USER_END_VADDR.data() + || MMArch::USER_END_VADDR - TryInto::::try_into(section.p_memsz).unwrap() + < addr + { + return Err(ExecError::OutOfMemory); + } + + let addr = load_addr + + TryInto::::try_into(section.p_vaddr + section.p_filesz).unwrap(); + if addr > elf_bss { + elf_bss = addr; + } + + let addr = load_addr + + TryInto::::try_into(section.p_vaddr + section.p_memsz).unwrap(); + if addr > last_bss { + last_bss = addr; + bss_prot = Some(elf_prot); + } + } + } + Self::pad_zero(elf_bss).map_err(|_| return ExecError::BadAddress(Some(elf_bss)))?; + elf_bss = Self::elf_page_align_up(elf_bss); + last_bss = Self::elf_page_align_up(last_bss); + if last_bss > elf_bss { + if bss_prot.is_none() { + return Err(ExecError::InvalidParemeter); + } + let mut bss_prot = bss_prot.unwrap(); + if bss_prot.contains(ProtFlags::PROT_EXEC) { + bss_prot = ProtFlags::PROT_EXEC; + } else { + bss_prot = ProtFlags::PROT_NONE; + } + interp_elf_ex + .vm() + .clone() + .write() + .map_anonymous( + elf_bss, + last_bss - elf_bss, + bss_prot, + MapFlags::MAP_ANONYMOUS | MapFlags::MAP_FIXED_NOREPLACE, + false, + true, + ) + .map_err(|e| match e { + SystemError::EINVAL => ExecError::InvalidParemeter, + SystemError::ENOMEM => ExecError::OutOfMemory, + _ => return ExecError::InvalidParemeter, + })?; + } + load_addr += TryInto::::try_into(interp_hdr.e_entry).unwrap(); + if load_addr > MMArch::USER_END_VADDR { + return Err(ExecError::BadAddress(Some( + load_addr + TryInto::::try_into(interp_hdr.e_entry).unwrap(), + ))); + } + // log::debug!("sucessfully load elf interp"); + return Ok(BinaryLoaderResult::new(load_addr)); + } + /// 加载ELF文件到用户空间 /// /// ## 参数 @@ -322,7 +470,6 @@ impl ElfLoader { /// - `offset_in_file`:在文件内的偏移量 /// - `param`:执行参数 fn do_load_file( - &self, mut vaddr: VirtAddr, size: usize, offset_in_file: usize, @@ -354,8 +501,8 @@ impl ElfLoader { } /// 我们需要显式的把数据段之后剩余的内存页都清零。 - fn pad_zero(&self, elf_bss: VirtAddr) -> Result<(), SystemError> { - let nbyte = self.elf_page_offset(elf_bss); + fn pad_zero(elf_bss: VirtAddr) -> Result<(), SystemError> { + let nbyte = Self::elf_page_offset(elf_bss); if nbyte > 0 { let nbyte = CurrentElfArch::ELF_PAGE_SIZE - nbyte; unsafe { clear_user(elf_bss, nbyte).map_err(|_| SystemError::EFAULT) }?; @@ -363,6 +510,37 @@ impl ElfLoader { return Ok(()); } + /// 参考https://code.dragonos.org.cn/xref/linux-6.1.9/fs/binfmt_elf.c#1158,获取要加载的total_size + fn total_mapping_size(ehdr_table: &SegmentTable<'_, AnyEndian>) -> usize { + let mut has_load = false; + let mut min_address = VirtAddr::new(usize::MAX); + let mut max_address = VirtAddr::new(0usize); + let loadable_sections = ehdr_table + .into_iter() + .filter(|seg| seg.p_type == elf::abi::PT_LOAD); + for seg_to_load in loadable_sections { + min_address = min( + min_address, + Self::elf_page_start(VirtAddr::new(seg_to_load.p_vaddr.try_into().unwrap())), + ); + max_address = max( + max_address, + VirtAddr::new( + (seg_to_load.p_vaddr + seg_to_load.p_memsz) + .try_into() + .unwrap(), + ), + ); + has_load = true; + } + let total_size = if has_load { + max_address - min_address + } else { + 0 + }; + return total_size; + } + /// 创建auxv /// /// ## 参数 @@ -542,7 +720,7 @@ impl BinaryLoader for ElfLoader { .map_err(|_| ExecError::ParseError)? .ok_or(ExecError::ParseError)?; let mut _gnu_property_data: Option = None; - let interpreter: Option = None; + let mut interpreter: Option = None; for seg in phdr_table { if seg.p_type == PT_GNU_PROPERTY { _gnu_property_data = Some(seg); @@ -558,22 +736,43 @@ impl BinaryLoader for ElfLoader { if seg.p_filesz > 4096 || seg.p_filesz < 2 { return Err(ExecError::NotExecutable); } - - let interpreter_ptr = unsafe { - core::slice::from_raw_parts( - seg.p_offset as *const u8, + // log::debug!("seg:{:?}", seg); + let mut buffer = vec![0; seg.p_filesz.try_into().unwrap()]; + let r = param + .file_mut() + .pread( + seg.p_offset.try_into().unwrap(), seg.p_filesz.try_into().unwrap(), + buffer.as_mut_slice(), ) - }; - let _interpreter_path = core::str::from_utf8(interpreter_ptr).map_err(|e| { + .map_err(|e| { + log::error!("Failed to load interpreter :{:?}", e); + return ExecError::NotSupported; + })?; + if r != seg.p_filesz.try_into().unwrap() { + log::error!("Failed to load interpreter "); + return Err(ExecError::NotSupported); + } + let interpreter_path = core::str::from_utf8( + &buffer[0..TryInto::::try_into(seg.p_filesz).unwrap() - 1], // + ) + .map_err(|e| { ExecError::Other(format!( "Failed to parse the path of dynamic linker with error {}", e )) })?; - - //TODO 加入对动态链接器的加载,参照 https://code.dragonos.org.cn/xref/linux-6.1.9/fs/binfmt_elf.c#890 + // log::debug!("opening interpreter at :{}", interpreter_path); + interpreter = Some( + ExecParam::new(interpreter_path, param.vm().clone(), ExecParamFlags::EXEC) + .map_err(|e| { + log::error!("Failed to load interpreter :{:?}", e); + return ExecError::NotSupported; + })?, + ); } + //TODO 缺少一部分逻辑 https://code.dragonos.org.cn/xref/linux-6.1.9/fs/binfmt_elf.c#931 + if interpreter.is_some() { /* Some simple consistency checks for the interpreter */ // 参考 https://code.dragonos.org.cn/xref/linux-6.1.9/fs/binfmt_elf.c#950 @@ -595,39 +794,14 @@ impl BinaryLoader for ElfLoader { // program header的虚拟地址 let mut phdr_vaddr: Option = None; let mut _reloc_func_desc = 0usize; - // 参考https://code.dragonos.org.cn/xref/linux-6.1.9/fs/binfmt_elf.c#1158,获取要加载的total_size - let mut has_load = false; - let mut min_address = VirtAddr::new(usize::MAX); - let mut max_address = VirtAddr::new(0usize); - let loadable_sections = phdr_table - .into_iter() - .filter(|seg| seg.p_type == elf::abi::PT_LOAD); - for seg_to_load in loadable_sections { - min_address = min( - min_address, - self.elf_page_start(VirtAddr::new(seg_to_load.p_vaddr.try_into().unwrap())), - ); - max_address = max( - max_address, - VirtAddr::new( - (seg_to_load.p_vaddr + seg_to_load.p_memsz) - .try_into() - .unwrap(), - ), - ); - has_load = true; - } - let total_size = if has_load { - max_address - min_address - } else { - 0 - }; + let total_size = Self::total_mapping_size(&phdr_table); let loadable_sections = phdr_table .into_iter() .filter(|seg| seg.p_type == elf::abi::PT_LOAD); + for seg_to_load in loadable_sections { - // debug!("seg_to_load = {:?}", seg_to_load); + // log::debug!("seg_to_load = {:?}", seg_to_load); if unlikely(elf_brk > elf_bss) { // debug!( // "to set brk, elf_brk = {:?}, elf_bss = {:?}", @@ -640,7 +814,7 @@ impl BinaryLoader for ElfLoader { elf_brk + load_bias, bss_prot_flags, )?; - let nbyte = self.elf_page_offset(elf_bss); + let nbyte = Self::elf_page_offset(elf_bss); if nbyte > 0 { let nbyte = min(CurrentElfArch::ELF_PAGE_SIZE - nbyte, elf_brk - elf_bss); unsafe { @@ -652,7 +826,7 @@ impl BinaryLoader for ElfLoader { } // 生成ProtFlags. - let elf_prot_flags = self.make_prot(seg_to_load.p_flags, interpreter.is_some(), false); + let elf_prot_flags = Self::make_prot(seg_to_load.p_flags, interpreter.is_some(), false); let mut elf_map_flags = MapFlags::MAP_PRIVATE; @@ -681,37 +855,33 @@ impl BinaryLoader for ElfLoader { load_bias = 0; } } - load_bias = self - .elf_page_start(VirtAddr::new( - load_bias - TryInto::::try_into(seg_to_load.p_vaddr).unwrap(), - )) - .data(); + load_bias = Self::elf_page_start(VirtAddr::new( + load_bias - TryInto::::try_into(seg_to_load.p_vaddr).unwrap(), + )) + .data(); if total_size == 0 { return Err(ExecError::InvalidParemeter); } } // 加载这个段到用户空间 - // debug!("to load elf segment"); - let e = self - .load_elf_segment( - &mut user_vm, - param, - &seg_to_load, - vaddr + load_bias, - &elf_prot_flags, - &elf_map_flags, - total_size, - ) - .map_err(|e| { - error!("load_elf_segment failed: {:?}", e); - match e { - SystemError::EFAULT => ExecError::BadAddress(None), - SystemError::ENOMEM => ExecError::OutOfMemory, - _ => ExecError::Other(format!("load_elf_segment failed: {:?}", e)), - } - })?; + // log::debug!("bias: {load_bias}"); + let e = Self::load_elf_segment( + &mut user_vm, + param, + &seg_to_load, + vaddr + load_bias, + &elf_prot_flags, + &elf_map_flags, + total_size, + ) + .map_err(|e| match e { + SystemError::EFAULT => ExecError::BadAddress(None), + SystemError::ENOMEM => ExecError::OutOfMemory, + _ => ExecError::Other(format!("load_elf_segment failed: {:?}", e)), + })?; + // log::debug!("e.0={:?}", e.0); // 如果地址不对,那么就报错 if !e.1 { return Err(ExecError::BadAddress(Some(e.0))); @@ -722,12 +892,10 @@ impl BinaryLoader for ElfLoader { if elf_type == ElfType::DSO { // todo: 在这里增加对load_bias和reloc_func_desc的更新代码 load_bias += e.0.data() - - self - .elf_page_start(VirtAddr::new( - load_bias - + TryInto::::try_into(seg_to_load.p_vaddr).unwrap(), - )) - .data(); + - Self::elf_page_start(VirtAddr::new( + load_bias + TryInto::::try_into(seg_to_load.p_vaddr).unwrap(), + )) + .data(); _reloc_func_desc = load_bias; } } @@ -761,7 +929,7 @@ impl BinaryLoader for ElfLoader { // 如果程序段要加载的目标地址不在用户空间内,或者是其他不合法的情况,那么就报错 if !p_vaddr.check_user() || seg_to_load.p_filesz > seg_to_load.p_memsz - || self.elf_page_align_up(p_vaddr + seg_to_load.p_memsz as usize) + || Self::elf_page_align_up(p_vaddr + seg_to_load.p_memsz as usize) >= MMArch::USER_END_VADDR { // debug!("ERR: p_vaddr={p_vaddr:?}"); @@ -769,7 +937,7 @@ impl BinaryLoader for ElfLoader { } // end vaddr of this segment(code+data+bss) - let seg_end_vaddr_f = self.elf_page_align_up(VirtAddr::new( + let seg_end_vaddr_f = Self::elf_page_align_up(VirtAddr::new( (seg_to_load.p_vaddr + seg_to_load.p_filesz) as usize, )); @@ -807,7 +975,7 @@ impl BinaryLoader for ElfLoader { end_code = end_code.map(|v| v + load_bias); start_data = start_data.map(|v| v + load_bias); end_data = end_data.map(|v| v + load_bias); - + let mut interp_load_addr: Option = None; // debug!( // "to set brk: elf_bss: {:?}, elf_brk: {:?}, bss_prot_flags: {:?}", // elf_bss, @@ -816,16 +984,27 @@ impl BinaryLoader for ElfLoader { // ); self.set_elf_brk(&mut user_vm, elf_bss, elf_brk, bss_prot_flags)?; - if likely(elf_bss != elf_brk) && unlikely(self.pad_zero(elf_bss).is_err()) { + if likely(elf_bss != elf_brk) && unlikely(Self::pad_zero(elf_bss).is_err()) { // debug!("elf_bss = {elf_bss:?}, elf_brk = {elf_brk:?}"); return Err(ExecError::BadAddress(Some(elf_bss))); } - if interpreter.is_some() { - // TODO 添加对动态加载器的处理 + drop(user_vm); + if let Some(mut interpreter) = interpreter { // 参考 https://code.dragonos.org.cn/xref/linux-6.1.9/fs/binfmt_elf.c#1249 + let elf_entry = Self::load_elf_interp(&mut interpreter, load_bias)?.entry_point(); + interp_load_addr = Some(elf_entry); + _reloc_func_desc = elf_entry.data(); + //参考 https://code.dragonos.org.cn/xref/linux-6.1.9/fs/binfmt_elf.c#1269 + //TODO allow_write_access(interpreter); + ProcessManager::current_pcb() + .fd_table() + .write() + .alloc_fd(interpreter.file(), None) + .map(|fd| fd as usize) + .map_err(|_| ExecError::InvalidParemeter)?; } // debug!("to create auxv"); - + let mut user_vm = binding.write(); self.create_auxv(param, program_entrypoint, phdr_vaddr, &ehdr)?; // debug!("auxv create ok"); @@ -834,8 +1013,8 @@ impl BinaryLoader for ElfLoader { user_vm.start_data = start_data.unwrap_or(VirtAddr::new(0)); user_vm.end_data = end_data.unwrap_or(VirtAddr::new(0)); - let result = BinaryLoaderResult::new(program_entrypoint); - // debug!("elf load OK!!!"); + let result = BinaryLoaderResult::new(interp_load_addr.unwrap_or(program_entrypoint)); + // kdebug!("elf load OK!!!"); return Ok(result); } } diff --git a/kernel/src/libs/rand.rs b/kernel/src/libs/rand.rs index 581a04654..ff5210fa9 100644 --- a/kernel/src/libs/rand.rs +++ b/kernel/src/libs/rand.rs @@ -1,3 +1,5 @@ +use crate::arch::rand::rand; + bitflags! { pub struct GRandFlags: u8{ const GRND_NONBLOCK = 0x0001; @@ -5,3 +7,43 @@ bitflags! { const GRND_INSECURE = 0x0004; } } + +/// Generates an array of random bytes of size `N`. +/// +/// This function fills an array of size `N` with random bytes by repeatedly +/// generating random numbers and converting them to little-endian byte arrays. +/// The function ensures that the entire array is filled with random bytes, +/// even if the size of the array is not a multiple of the size of `usize`. +/// +/// # Type Parameters +/// +/// * `N`: The size of the array to be filled with random bytes. +/// +/// # Returns +/// +/// An array of size `N` filled with random bytes. +/// +/// # Example +/// +/// ```rust +/// let random_bytes = rand_bytes::<16>(); +/// assert_eq!(random_bytes.len(), 16); +/// ``` +pub fn rand_bytes() -> [u8; N] { + let mut bytes = [0u8; N]; + let mut remaining = N; + let mut index = 0; + + while remaining > 0 { + let random_num = rand(); + let random_bytes = random_num.to_le_bytes(); + + let to_copy = core::cmp::min(remaining, size_of::()); + bytes[index..index + to_copy].copy_from_slice(&random_bytes[..to_copy]); + + index += to_copy; + remaining -= to_copy; + } + + bytes +} diff --git a/kernel/src/mm/fault.rs b/kernel/src/mm/fault.rs index e0aa1622a..60dcf7945 100644 --- a/kernel/src/mm/fault.rs +++ b/kernel/src/mm/fault.rs @@ -334,7 +334,6 @@ impl PageFaultHandler { cache_page.read_irqsave().page_cache(), cache_page.read_irqsave().index(), ); - ret = ret.union(Self::finish_fault(pfm)); ret diff --git a/kernel/src/mm/page.rs b/kernel/src/mm/page.rs index f3d900697..ee35b08d0 100644 --- a/kernel/src/mm/page.rs +++ b/kernel/src/mm/page.rs @@ -150,6 +150,7 @@ fn page_reclaim_thread() -> i32 { page_reclaimer_lock_irqsave().flush_dirty_pages(); // 休眠5秒 // log::info!("sleep"); + let _ = nanosleep(PosixTimeSpec::new(5, 0)); } } diff --git a/kernel/src/mm/ucontext.rs b/kernel/src/mm/ucontext.rs index 81abd4b0c..9f94b69c1 100644 --- a/kernel/src/mm/ucontext.rs +++ b/kernel/src/mm/ucontext.rs @@ -354,6 +354,11 @@ impl InnerAddressSpace { let len = page_align_up(len); + let vm_flags = VmFlags::from(prot_flags) + | VmFlags::from(map_flags) + | VmFlags::VM_MAYREAD + | VmFlags::VM_MAYWRITE + | VmFlags::VM_MAYEXEC; // debug!("map_anonymous: len = {}", len); let binding = ProcessManager::current_pcb().fd_table(); @@ -450,8 +455,7 @@ impl InnerAddressSpace { // 找到未使用的区域 let region = match addr { Some(vaddr) => { - self.mappings - .find_free_at(self.mmap_min, vaddr, page_count.bytes(), map_flags)? + self.find_free_at(self.mmap_min, vaddr, page_count.bytes(), map_flags)? } None => self .mappings @@ -798,6 +802,56 @@ impl InnerAddressSpace { return self.set_brk(new_brk); } + + pub fn find_free_at( + &mut self, + min_vaddr: VirtAddr, + vaddr: VirtAddr, + size: usize, + flags: MapFlags, + ) -> Result { + // 如果没有指定地址,那么就在当前进程的地址空间中寻找一个空闲的虚拟内存范围。 + if vaddr == VirtAddr::new(0) { + return self + .mappings + .find_free(min_vaddr, size) + .ok_or(SystemError::ENOMEM); + } + + // 如果指定了地址,那么就检查指定的地址是否可用。 + let requested = VirtRegion::new(vaddr, size); + + if requested.end() >= MMArch::USER_END_VADDR || !vaddr.check_aligned(MMArch::PAGE_SIZE) { + return Err(SystemError::EINVAL); + } + + let intersect_vma = self.mappings.conflicts(requested).next(); + if let Some(vma) = intersect_vma { + if flags.contains(MapFlags::MAP_FIXED_NOREPLACE) { + // 如果指定了 MAP_FIXED_NOREPLACE 标志,由于所指定的地址无法成功建立映射,则放弃映射,不对地址做修正 + return Err(SystemError::EEXIST); + } + + if flags.contains(MapFlags::MAP_FIXED) { + // 对已有的VMA进行覆盖 + let intersect_region = vma.lock().region.intersect(&requested).unwrap(); + self.munmap( + VirtPageFrame::new(intersect_region.start), + PageFrameCount::from_bytes(intersect_region.size).unwrap(), + )?; + return Ok(requested); + } + + // 如果没有指定MAP_FIXED标志,那么就对地址做修正 + let requested = self + .mappings + .find_free(min_vaddr, size) + .ok_or(SystemError::ENOMEM)?; + return Ok(requested); + } + + return Ok(requested); + } } impl Drop for InnerAddressSpace { @@ -949,45 +1003,6 @@ impl UserMappings { return Some(region); } - pub fn find_free_at( - &self, - min_vaddr: VirtAddr, - vaddr: VirtAddr, - size: usize, - flags: MapFlags, - ) -> Result { - // 如果没有指定地址,那么就在当前进程的地址空间中寻找一个空闲的虚拟内存范围。 - if vaddr == VirtAddr::new(0) { - return self.find_free(min_vaddr, size).ok_or(SystemError::ENOMEM); - } - - // 如果指定了地址,那么就检查指定的地址是否可用。 - - let requested = VirtRegion::new(vaddr, size); - - if requested.end() >= MMArch::USER_END_VADDR || !vaddr.check_aligned(MMArch::PAGE_SIZE) { - return Err(SystemError::EINVAL); - } - - if let Some(_x) = self.conflicts(requested).next() { - if flags.contains(MapFlags::MAP_FIXED_NOREPLACE) { - // 如果指定了 MAP_FIXED_NOREPLACE 标志,由于所指定的地址无法成功建立映射,则放弃映射,不对地址做修正 - return Err(SystemError::EEXIST); - } - - if flags.contains(MapFlags::MAP_FIXED) { - // todo: 支持MAP_FIXED标志对已有的VMA进行覆盖 - return Err(SystemError::ENOSYS); - } - - // 如果没有指定MAP_FIXED标志,那么就对地址做修正 - let requested = self.find_free(min_vaddr, size).ok_or(SystemError::ENOMEM)?; - return Ok(requested); - } - - return Ok(requested); - } - /// 在当前进程的地址空间中,保留一个指定大小的区域,使得该区域不在空洞中。 /// 该函数会修改vm_holes中的空洞信息。 /// diff --git a/kernel/src/process/abi.rs b/kernel/src/process/abi.rs index cbaab9d0a..a39f4ff3a 100644 --- a/kernel/src/process/abi.rs +++ b/kernel/src/process/abi.rs @@ -38,7 +38,7 @@ pub enum AtType { /// Frequency at which times() increments. ClkTck, /// Secure mode boolean. - Secure, + Secure = 23, /// String identifying real platform, may differ from AT_PLATFORM. BasePlatform, /// Address of 16 random bytes. @@ -46,7 +46,7 @@ pub enum AtType { /// Extension of AT_HWCAP. HwCap2, /// Filename of program. - ExecFn, + ExecFn = 31, /// Minimal stack size for signal delivery. MinSigStackSize, } diff --git a/kernel/src/process/exec.rs b/kernel/src/process/exec.rs index 12af4c339..9d0cba351 100644 --- a/kernel/src/process/exec.rs +++ b/kernel/src/process/exec.rs @@ -159,6 +159,11 @@ impl ExecParam { pub fn file_mut(&mut self) -> &mut File { &mut self.file } + + /// 获取File的所有权,用于将动态链接器加入文件描述符表中 + pub fn file(self) -> File { + self.file + } } /// ## 加载二进制文件 @@ -201,6 +206,7 @@ pub struct ProcInitInfo { pub args: Vec, pub envs: Vec, pub auxv: BTreeMap, + pub rand_num: [u8; 16], } impl ProcInitInfo { @@ -210,6 +216,7 @@ impl ProcInitInfo { args: Vec::new(), envs: Vec::new(), auxv: BTreeMap::new(), + rand_num: [0u8; 16], } } @@ -220,7 +227,7 @@ impl ProcInitInfo { /// /// 返回值是一个元组,第一个元素是最终的用户栈顶地址,第二个元素是环境变量pointer数组的起始地址 pub unsafe fn push_at( - &self, + &mut self, ustack: &mut UserStack, ) -> Result<(VirtAddr, VirtAddr), SystemError> { // 先把程序的名称压入栈中 @@ -235,6 +242,7 @@ impl ProcInitInfo { ustack.sp() }) .collect::>(); + // 然后把参数压入栈中 let argps = self .args @@ -245,6 +253,20 @@ impl ProcInitInfo { }) .collect::>(); + // 压入随机数,把指针放入auxv + self.push_slice(ustack, &[self.rand_num])?; + self.auxv + .insert(super::abi::AtType::Random as u8, ustack.sp().data()); + + // 实现栈的16字节对齐 + // 用当前栈顶地址减去后续要压栈的长度,得到的压栈后的栈顶地址与0xF按位与操作得到对齐要填充的字节数 + let length_to_push = (self.auxv.len() + envps.len() + 1 + argps.len() + 1 + 1) + * core::mem::align_of::(); + self.push_slice( + ustack, + &vec![0u8; (ustack.sp().data() - length_to_push) & 0xF], + )?; + // 压入auxv self.push_slice(ustack, &[null::(), null::()])?; for (&k, &v) in self.auxv.iter() { @@ -258,7 +280,6 @@ impl ProcInitInfo { // 把参数指针压入栈中 self.push_slice(ustack, &[null::()])?; self.push_slice(ustack, argps.as_slice())?; - let argv_ptr = ustack.sp(); // 把argc压入栈中 diff --git a/kernel/src/process/syscall.rs b/kernel/src/process/syscall.rs index ddcb96202..11572ab07 100644 --- a/kernel/src/process/syscall.rs +++ b/kernel/src/process/syscall.rs @@ -25,6 +25,7 @@ use crate::{ procfs::procfs_register_pid, vfs::{file::FileDescriptorVec, MAX_PATHLEN}, }, + libs::rand::rand_bytes, mm::{ ucontext::{AddressSpace, UserStack}, verify_area, MemoryManagementArch, VirtAddr, @@ -171,6 +172,8 @@ impl Syscall { // debug!("argv: {:?}, envp: {:?}", argv, envp); param.init_info_mut().args = argv; param.init_info_mut().envs = envp; + // // 生成16字节随机数 + param.init_info_mut().rand_num = rand_bytes::<16>(); // 把proc_init_info写到用户栈上 let mut ustack_message = unsafe { @@ -182,7 +185,7 @@ impl Syscall { }; let (user_sp, argv_ptr) = unsafe { param - .init_info() + .init_info_mut() .push_at( // address_space // .write() @@ -271,7 +274,7 @@ impl Syscall { } /// @brief 获取当前进程的父进程id /// - /// 若为initproc则ppid设置为0 + /// 若为initproc则ppid设置为0 pub fn getppid() -> Result { let current_pcb = ProcessManager::current_pcb(); return Ok(current_pcb.basic().ppid()); diff --git a/kernel/src/syscall/mod.rs b/kernel/src/syscall/mod.rs index 45dd2efa6..0f05c07b4 100644 --- a/kernel/src/syscall/mod.rs +++ b/kernel/src/syscall/mod.rs @@ -894,8 +894,10 @@ impl Syscall { } SYS_EXIT_GROUP => { - warn!("SYS_EXIT_GROUP has not yet been implemented"); - Ok(0) + let exit_code = args[0]; + Self::exit(exit_code) + // warn!("SYS_EXIT_GROUP has not yet been implemented"); + // Ok(0) } SYS_MADVISE => { diff --git a/user/apps/clear/Makefile b/user/apps/clear/Makefile index 0d1403539..71b0da988 100644 --- a/user/apps/clear/Makefile +++ b/user/apps/clear/Makefile @@ -10,12 +10,12 @@ else endif ifeq ($(ARCH), x86_64) - export RUST_TARGET=x86_64-unknown-linux-musl + export RUST_TARGET=x86_64-unknown-linux-gnu else ifeq ($(ARCH), riscv64) export RUST_TARGET=riscv64gc-unknown-linux-gnu -else +else # 默认为x86_86,用于本地编译 - export RUST_TARGET=x86_64-unknown-linux-musl + export RUST_TARGET=x86_64-unknown-linux-gnu endif run: diff --git a/user/apps/glibc/.gitignore b/user/apps/glibc/.gitignore new file mode 100644 index 000000000..55c62eee1 --- /dev/null +++ b/user/apps/glibc/.gitignore @@ -0,0 +1,2 @@ +glibc-2.35 +glibc-2.35.tar.gz \ No newline at end of file diff --git a/user/apps/glibc/Makefile b/user/apps/glibc/Makefile new file mode 100644 index 000000000..8146a8b91 --- /dev/null +++ b/user/apps/glibc/Makefile @@ -0,0 +1,2 @@ +install: + bash exec.sh \ No newline at end of file diff --git a/user/apps/glibc/default_configure.sh b/user/apps/glibc/default_configure.sh new file mode 100644 index 000000000..8535927b5 --- /dev/null +++ b/user/apps/glibc/default_configure.sh @@ -0,0 +1,19 @@ +mkdir -p build +mkdir -p install +if [ -z "$ARCH" ] || [ "$ARCH" != "x86_64" ] && [ "$ARCH" != "riscv64" ] && [ "$ARCH" != "aarch64" ]; then + echo "No ARCH specified, use x86_64 as default" + export ARCH="x86_64" +fi +if [ "$ARCH" == "x86_64" ] || [ "$ARCH" == "riscv64" ] || [ "$ARCH" == "aarch64" ]; then + export TRIPLET=${ARCH}-linux-gnu +fi +export BUILD=`uname -m` +cd build +../configure \ + --prefix=/ \ + --host=${TRIPLET} \ + --build=${BUILD}-linux-gnu \ + CC="${TRIPLET}-gcc -m64" \ + CXX="${TRIPLET}-g++ -m64" \ + CFLAGS="-O2" \ + CXXFLAGS="-O2" \ No newline at end of file diff --git a/user/apps/glibc/exec.sh b/user/apps/glibc/exec.sh new file mode 100644 index 000000000..cb88d61fb --- /dev/null +++ b/user/apps/glibc/exec.sh @@ -0,0 +1,17 @@ +if [ ! -f "glibc-2.35.tar.gz" ]; then + wget https://ftp.gnu.org/gnu/glibc/glibc-2.35.tar.gz +fi +if [ ! -d "glibc-2.35" ]; then + tar -xvf glibc-2.35.tar.gz + cp ./install_deps.sh ./glibc-2.35/ + cp ./default_configure.sh ./glibc-2.35/ +fi +cd glibc-2.35 +bash install_deps.sh +bash default_configure.sh +cd build +make -j $(nproc) +DESTDIR=$DADK_CURRENT_BUILD_DIR make install -j $(nproc) + +mkdir -p $DADK_CURRENT_BUILD_DIR/lib64 +cp -r $DADK_CURRENT_BUILD_DIR/lib/* $DADK_CURRENT_BUILD_DIR/lib64 \ No newline at end of file diff --git a/user/apps/glibc/install_deps.sh b/user/apps/glibc/install_deps.sh new file mode 100644 index 000000000..97d09956b --- /dev/null +++ b/user/apps/glibc/install_deps.sh @@ -0,0 +1,17 @@ +sudo apt-get install -y make gdb +sudo apt-get install -y texinfo gawk bison sed +sudo apt-get install -y python3-dev python-is-python3 +if [ -z "$ARCH" ] || [ "$ARCH" != "x86_64" ] && [ "$ARCH" != "riscv" ] && [ "$ARCH" != "aarch64" ]; then + echo "No ARCH specified, use x86_64 as default" + export ARCH="x86_64" +fi + +if [ "$ARCH" == "riscv" ] || [ "$ARCH" == "aarch64" ]; then + export TRIPLET=${ARCH}-linux-gnu +fi + +if [ "$ARCH" == "x86_64" ] ; then + export TRIPLET=x86-64-linux-gnu +fi + +sudo apt-get install -y gcc-${TRIPLET} \ No newline at end of file diff --git a/user/apps/libgcc/Makefile b/user/apps/libgcc/Makefile new file mode 100644 index 000000000..1a15d2447 --- /dev/null +++ b/user/apps/libgcc/Makefile @@ -0,0 +1,2 @@ +install: + cp -r lib $(DADK_CURRENT_BUILD_DIR) \ No newline at end of file diff --git a/user/apps/libgcc/lib/libgcc_s.so.1 b/user/apps/libgcc/lib/libgcc_s.so.1 new file mode 100644 index 000000000..f758425ae Binary files /dev/null and b/user/apps/libgcc/lib/libgcc_s.so.1 differ diff --git a/user/apps/test-backlog/Makefile b/user/apps/test-backlog/Makefile index 99b095d51..13482ec17 100644 --- a/user/apps/test-backlog/Makefile +++ b/user/apps/test-backlog/Makefile @@ -10,13 +10,13 @@ else endif ifeq ($(ARCH), x86_64) - export RUST_TARGET=x86_64-unknown-linux-musl - export CC=x86_64-linux-musl-gcc + export RUST_TARGET=x86_64-unknown-linux-gnu + export CC=x86_64-linux-gnu-gcc else ifeq ($(ARCH), riscv64) export RUST_TARGET=riscv64gc-unknown-linux-gnu -else +else # 默认为x86_86,用于本地编译 - export RUST_TARGET=x86_64-unknown-linux-musl + export RUST_TARGET=x86_64-unknown-linux-gnu endif run: diff --git a/user/apps/test-for-robustfutex/Makefile b/user/apps/test-for-robustfutex/Makefile index 352c0562c..cedb5e1d3 100644 --- a/user/apps/test-for-robustfutex/Makefile +++ b/user/apps/test-for-robustfutex/Makefile @@ -10,12 +10,12 @@ else endif ifeq ($(ARCH), x86_64) - export RUST_TARGET=x86_64-unknown-linux-musl + export RUST_TARGET=x86_64-unknown-linux-gnu else ifeq ($(ARCH), riscv64) export RUST_TARGET=riscv64gc-unknown-linux-gnu -else +else # 默认为x86_86,用于本地编译 - export RUST_TARGET=x86_64-unknown-linux-musl + export RUST_TARGET=x86_64-unknown-linux-gnu endif run: diff --git a/user/apps/test-mount/Makefile b/user/apps/test-mount/Makefile index 352c0562c..cedb5e1d3 100644 --- a/user/apps/test-mount/Makefile +++ b/user/apps/test-mount/Makefile @@ -10,12 +10,12 @@ else endif ifeq ($(ARCH), x86_64) - export RUST_TARGET=x86_64-unknown-linux-musl + export RUST_TARGET=x86_64-unknown-linux-gnu else ifeq ($(ARCH), riscv64) export RUST_TARGET=riscv64gc-unknown-linux-gnu -else +else # 默认为x86_86,用于本地编译 - export RUST_TARGET=x86_64-unknown-linux-musl + export RUST_TARGET=x86_64-unknown-linux-gnu endif run: diff --git a/user/apps/test_alarm/Makefile b/user/apps/test_alarm/Makefile index 352c0562c..cedb5e1d3 100644 --- a/user/apps/test_alarm/Makefile +++ b/user/apps/test_alarm/Makefile @@ -10,12 +10,12 @@ else endif ifeq ($(ARCH), x86_64) - export RUST_TARGET=x86_64-unknown-linux-musl + export RUST_TARGET=x86_64-unknown-linux-gnu else ifeq ($(ARCH), riscv64) export RUST_TARGET=riscv64gc-unknown-linux-gnu -else +else # 默认为x86_86,用于本地编译 - export RUST_TARGET=x86_64-unknown-linux-musl + export RUST_TARGET=x86_64-unknown-linux-gnu endif run: diff --git a/user/apps/test_lo/Makefile b/user/apps/test_lo/Makefile index 7522ea16c..775904d9d 100644 --- a/user/apps/test_lo/Makefile +++ b/user/apps/test_lo/Makefile @@ -10,12 +10,12 @@ else endif ifeq ($(ARCH), x86_64) - export RUST_TARGET=x86_64-unknown-linux-musl + export RUST_TARGET=x86_64-unknown-linux-gnu else ifeq ($(ARCH), riscv64) export RUST_TARGET=riscv64gc-unknown-linux-gnu -else +else # 默认为x86_86,用于本地编译 - export RUST_TARGET=x86_64-unknown-linux-musl + export RUST_TARGET=x86_64-unknown-linux-gnu endif run: diff --git a/user/apps/test_socket/Makefile b/user/apps/test_socket/Makefile index 352c0562c..cedb5e1d3 100644 --- a/user/apps/test_socket/Makefile +++ b/user/apps/test_socket/Makefile @@ -10,12 +10,12 @@ else endif ifeq ($(ARCH), x86_64) - export RUST_TARGET=x86_64-unknown-linux-musl + export RUST_TARGET=x86_64-unknown-linux-gnu else ifeq ($(ARCH), riscv64) export RUST_TARGET=riscv64gc-unknown-linux-gnu -else +else # 默认为x86_86,用于本地编译 - export RUST_TARGET=x86_64-unknown-linux-musl + export RUST_TARGET=x86_64-unknown-linux-gnu endif run: diff --git a/user/apps/test_statx/Makefile b/user/apps/test_statx/Makefile index 0d1403539..71b0da988 100644 --- a/user/apps/test_statx/Makefile +++ b/user/apps/test_statx/Makefile @@ -10,12 +10,12 @@ else endif ifeq ($(ARCH), x86_64) - export RUST_TARGET=x86_64-unknown-linux-musl + export RUST_TARGET=x86_64-unknown-linux-gnu else ifeq ($(ARCH), riscv64) export RUST_TARGET=riscv64gc-unknown-linux-gnu -else +else # 默认为x86_86,用于本地编译 - export RUST_TARGET=x86_64-unknown-linux-musl + export RUST_TARGET=x86_64-unknown-linux-gnu endif run: diff --git a/user/apps/test_tokio/Makefile b/user/apps/test_tokio/Makefile index 352c0562c..cedb5e1d3 100644 --- a/user/apps/test_tokio/Makefile +++ b/user/apps/test_tokio/Makefile @@ -10,12 +10,12 @@ else endif ifeq ($(ARCH), x86_64) - export RUST_TARGET=x86_64-unknown-linux-musl + export RUST_TARGET=x86_64-unknown-linux-gnu else ifeq ($(ARCH), riscv64) export RUST_TARGET=riscv64gc-unknown-linux-gnu -else +else # 默认为x86_86,用于本地编译 - export RUST_TARGET=x86_64-unknown-linux-musl + export RUST_TARGET=x86_64-unknown-linux-gnu endif run: diff --git a/user/apps/user-manage/Makefile b/user/apps/user-manage/Makefile index b1691ea47..16b153ced 100644 --- a/user/apps/user-manage/Makefile +++ b/user/apps/user-manage/Makefile @@ -13,12 +13,12 @@ endif ifeq ($(ARCH), x86_64) - export RUST_TARGET=x86_64-unknown-linux-musl + export RUST_TARGET=x86_64-unknown-linux-gnu else ifeq ($(ARCH), riscv64) export RUST_TARGET=riscv64gc-unknown-linux-gnu -else +else # 默认为x86_86,用于本地编译 - export RUST_TARGET=x86_64-unknown-linux-musl + export RUST_TARGET=x86_64-unknown-linux-gnu endif build: diff --git a/user/dadk/config/glibc-2.40.9.dadk b/user/dadk/config/glibc-2.40.9.dadk new file mode 100644 index 000000000..f366d5331 --- /dev/null +++ b/user/dadk/config/glibc-2.40.9.dadk @@ -0,0 +1,26 @@ +{ + "name": "glibc", + "version": "2.40.9", + "description": "glibc", + "rust_target": null, + "task_type": { + "BuildFromSource": { + "Local": { + "path": "apps/glibc" + } + } + }, + "depends": [], + "build": { + "build_command": "make install" + }, + "install": { + "in_dragonos_path": "/" + }, + "clean": { + "clean_command": "cd build & make clean" + }, + "envs": [], + "build_once": true, + "install_once": true +} diff --git a/user/dadk/config/libgcc.dadk b/user/dadk/config/libgcc.dadk new file mode 100644 index 000000000..a350285cd --- /dev/null +++ b/user/dadk/config/libgcc.dadk @@ -0,0 +1,24 @@ +{ + "name": "libgcc", + "version": "0.1.0", + "description": "gcc lib", + "rust_target": null, + "task_type": { + "BuildFromSource": { + "Local": { + "path": "apps/libgcc" + } + } + }, + "depends": [], + "build": { + "build_command": "make install" + }, + "install": { + "in_dragonos_path": "/" + }, + "clean": { + "clean_command": "cd build & make clean" + }, + "envs": [] +} \ No newline at end of file