diff --git a/kernel/src/task/exec.rs b/kernel/src/task/exec.rs index f3b742f7f..3890664ef 100644 --- a/kernel/src/task/exec.rs +++ b/kernel/src/task/exec.rs @@ -11,6 +11,7 @@ use crate::mm::vm::VMFileMappingFlags; use crate::mm::USER_MEM_END; use crate::task::{create_user_task, current_task, schedule}; use crate::types::PAGE_SIZE; +use crate::utils::align_up; use elf::{Elf64File, Elf64PhdrFlags}; fn convert_elf_phdr_flags(flags: Elf64PhdrFlags) -> VMFileMappingFlags { @@ -53,14 +54,26 @@ pub fn exec_user(binary: &str) -> Result<(), SvsmError> { let virt_end = VirtAddr::from(seg.vaddr_range.vaddr_end).align_up(PAGE_SIZE); let file_offset = seg.file_range.offset_begin; let len = virt_end - virt_start; + let file_size = seg.file_range.offset_end - seg.file_range.offset_begin; let flags = convert_elf_phdr_flags(seg.flags); - if !virt_start.is_aligned(PAGE_SIZE) { - return Err(SvsmError::Mem); - } - if file_offset > 0 { - task.mmap_user(virt_start, Some(&fh), file_offset, len, flags)?; + if file_size > len { + return Err(SvsmError::Elf(elf::ElfError::InvalidFileRange)); + } + + // Handle unaligned VirtAddr and Offset + let start_aligned = virt_start.page_align(); + let offset = file_offset - virt_start.page_offset(); + let size = file_size + virt_start.page_offset(); + task.mmap_user(start_aligned, Some(&fh), offset, size, flags)?; + + let size_aligned = align_up(size, PAGE_SIZE); + if size_aligned < len { + let start_anon = start_aligned.const_add(size_aligned); + let remaining_len = len - size_aligned; + task.mmap_user(start_anon, None, 0, remaining_len, flags)?; + } } else { task.mmap_user(virt_start, None, 0, len, flags)?; }