From 01041a5d8a713c032fadfd5755334685835cddcd Mon Sep 17 00:00:00 2001 From: 4lDO2 <4lDO2@protonmail.com> Date: Wed, 8 Jul 2020 20:49:16 +0200 Subject: [PATCH 01/11] Implement (mostly) fmap2 for `memory:` --- src/context/memory.rs | 6 +++ src/scheme/memory.rs | 99 ++++++++++++++++++++++++++++++++++++------- syscall | 2 +- 3 files changed, 90 insertions(+), 17 deletions(-) diff --git a/src/context/memory.rs b/src/context/memory.rs index 39303da..554fefc 100644 --- a/src/context/memory.rs +++ b/src/context/memory.rs @@ -196,10 +196,16 @@ impl Grant { pub fn start_address(&self) -> VirtualAddress { self.start } + pub unsafe fn set_start_address(&mut self, start: VirtualAddress) { + self.start = start; + } pub fn size(&self) -> usize { self.size } + pub unsafe fn set_size(&mut self, size: usize) { + self.size = size; + } pub fn flags(&self) -> EntryFlags { self.flags diff --git a/src/scheme/memory.rs b/src/scheme/memory.rs index f9f7496..c397142 100644 --- a/src/scheme/memory.rs +++ b/src/scheme/memory.rs @@ -1,11 +1,11 @@ use crate::context; use crate::context::memory::Grant; -use crate::memory::{free_frames, used_frames}; +use crate::memory::{free_frames, used_frames, PAGE_SIZE}; use crate::paging::VirtualAddress; use crate::paging::entry::EntryFlags; -use crate::syscall::data::{Map, StatVfs}; +use crate::syscall::data::{Map, Map2, StatVfs}; use crate::syscall::error::*; -use crate::syscall::flag::{PROT_EXEC, PROT_READ, PROT_WRITE}; +use crate::syscall::flag::{MapFlags, PROT_EXEC, PROT_READ, PROT_WRITE}; use crate::syscall::scheme::Scheme; pub struct MemoryScheme; @@ -24,7 +24,7 @@ impl Scheme for MemoryScheme { let used = used_frames() as u64; let free = free_frames() as u64; - stat.f_bsize = 4096; + stat.f_bsize = PAGE_SIZE as u32; stat.f_blocks = used + free; stat.f_bfree = free; stat.f_bavail = stat.f_bfree; @@ -32,7 +32,7 @@ impl Scheme for MemoryScheme { Ok(0) } - fn fmap(&self, _id: usize, map: &Map) -> Result { + fn fmap2(&self, _id: usize, map: &Map2) -> Result { //TODO: Abstract with other grant creation if map.size == 0 { Ok(0) @@ -41,10 +41,19 @@ impl Scheme for MemoryScheme { let context_lock = contexts.current().ok_or(Error::new(ESRCH))?; let context = context_lock.read(); + let fixed = map.flags.contains(MapFlags::MAP_FIXED); + let fixed_noreplace = map.flags.contains(MapFlags::MAP_FIXED_NOREPLACE); + let mut grants = context.grants.lock(); - let full_size = ((map.size + 4095)/4096) * 4096; - let mut to_address = crate::USER_GRANT_OFFSET; + let full_size = ((map.size + PAGE_SIZE - 1) / PAGE_SIZE) * PAGE_SIZE; + + let mut to_address = if map.address == 0 { crate::USER_GRANT_OFFSET } else { + if map.address < crate::USER_GRANT_OFFSET || map.address + map.size > crate::USER_GRANT_OFFSET + crate::PML4_SIZE || map.address % PAGE_SIZE != 0 { + return Err(Error::new(EINVAL)); + } + map.address + }; let mut entry_flags = EntryFlags::PRESENT | EntryFlags::USER_ACCESSIBLE; if !map.flags.contains(PROT_EXEC) { @@ -58,27 +67,85 @@ impl Scheme for MemoryScheme { } let mut i = 0; - while i < grants.len() { - let start = grants[i].start_address().get(); - if to_address + full_size < start { - break; + + while i < grants.len() { + let grant = &mut grants[i]; + + let mut grant_start = grant.start_address().get(); + let mut grant_len = ((grant.size() + PAGE_SIZE - 1) / PAGE_SIZE) * PAGE_SIZE; + let mut grant_end = grant_start + grant_len; + + if grant_end <= to_address { + // grant has nothing to do with the memory to map, and thus we can safely just + // go on to the next one. + + if !fixed { + to_address = grant_end; + } + i += 1; + + continue; + } + + // check whether this grant overlaps with the memory range to use, by checking that + // the start and end of the grant is not within the memory range to map + if grant_start <= to_address && grant_end > to_address || grant_start <= to_address + full_size && grant_end > to_address + full_size { + // the range overlaps, thus we'll have to continue to the next grant, or to + // insert a new grant at the end (if not MapFlags::MAP_FIXED). + + if fixed_noreplace { + return Err(Error::new(EEXIST)); + } else if fixed { + /* + // shrink the grant, removing it if necessary. since the to_address isn't + // changed at all when mapping to a fixed address, we can just continue to + // the next grant and shrink or remove that one if it was also overlapping. + if to_address + full_size > grant_start { + let new_start = core::cmp::min(grant_end, to_address + full_size); + + let new_size = grant.size() - (new_start - grant_start); + unsafe { grant.set_size(new_size) }; + grant_len = ((new_size + PAGE_SIZE - 1) / PAGE_SIZE) * PAGE_SIZE; + + let new_start = VirtualAddress::new(new_start); + unsafe { grant.set_start_address(new_start) }; + grant_start = new_start; + + grant_end = grant_start + grant_len; + } + */ + // TODO + return Err(Error::new(EOPNOTSUPP)); + } else { + to_address = grant_end; + i += 1; + } + continue; } - let pages = (grants[i].size() + 4095) / 4096; - let end = start + pages * 4096; - to_address = end; - i += 1; } grants.insert(i, Grant::map( VirtualAddress::new(to_address), full_size, - entry_flags + entry_flags, )); Ok(to_address) } } + fn fmap(&self, id: usize, map: &Map) -> Result { + if map.flags.contains(MapFlags::MAP_FIXED) { + // not supported for fmap, which lacks the address argument. + return Err(Error::new(EINVAL)); + } + self.fmap2(id, &Map2 { + offset: map.offset, + size: map.size, + flags: map.flags, + address: 0, + }) + } fn fcntl(&self, _id: usize, _cmd: usize, _arg: usize) -> Result { Ok(0) diff --git a/syscall b/syscall index 1228788..27fcecb 160000 --- a/syscall +++ b/syscall @@ -1 +1 @@ -Subproject commit 122878874d3f4fee0fd1f19b8dc2b07d84d5df8b +Subproject commit 27fcecb30fb3154a9b45f66756d64f8f48281a7b From 3430eadc9ae67cdbe53571a347071ad92da38ab5 Mon Sep 17 00:00:00 2001 From: jD91mZM2 Date: Fri, 10 Jul 2020 12:10:40 +0200 Subject: [PATCH 02/11] Add auxiliery vector --- src/lib.rs | 2 +- src/syscall/process.rs | 185 ++++++++++++++++++++++++----------------- syscall | 2 +- 3 files changed, 111 insertions(+), 78 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index 8627940..2966c1b 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -186,7 +186,7 @@ pub extern fn userspace_init() { } } - syscall::fexec_kernel(fd, args.into_boxed_slice(), vars.into_boxed_slice(), None).expect("failed to execute init"); + syscall::fexec_kernel(fd, args.into_boxed_slice(), vars.into_boxed_slice(), None, None).expect("failed to execute init"); panic!("init returned"); } diff --git a/src/syscall/process.rs b/src/syscall/process.rs index 2da33bd..9c794de 100644 --- a/src/syscall/process.rs +++ b/src/syscall/process.rs @@ -23,11 +23,11 @@ use crate::scheme::FileHandle; use crate::start::usermode; use crate::syscall::data::{SigAction, Stat}; use crate::syscall::error::*; -use crate::syscall::flag::{wifcontinued, wifstopped, CloneFlags, CLONE_FILES, - CLONE_FS, CLONE_SIGHAND, CLONE_STACK, CLONE_VFORK, CLONE_VM, MapFlags, - PROT_EXEC, PROT_READ, PROT_WRITE, PTRACE_EVENT_CLONE, PTRACE_STOP_EXIT, - SigActionFlags, SIG_BLOCK, SIG_DFL, SIG_SETMASK, SIG_UNBLOCK, SIGCONT, SIGTERM, - WaitFlags, WCONTINUED, WNOHANG,WUNTRACED}; +use crate::syscall::flag::{wifcontinued, wifstopped, AT_ENTRY, AT_NULL, CloneFlags, + CLONE_FILES, CLONE_FS, CLONE_SIGHAND, CLONE_STACK, CLONE_VFORK, CLONE_VM, + MapFlags, PROT_EXEC, PROT_READ, PROT_WRITE, PTRACE_EVENT_CLONE, + PTRACE_STOP_EXIT, SigActionFlags, SIG_BLOCK, SIG_DFL, SIG_SETMASK, SIG_UNBLOCK, + SIGCONT, SIGTERM, WaitFlags, WCONTINUED, WNOHANG, WUNTRACED}; use crate::syscall::ptrace_event; use crate::syscall::validate::{validate_slice, validate_slice_mut}; @@ -657,7 +657,8 @@ fn fexec_noreturn( name: Box<[u8]>, data: Box<[u8]>, args: Box<[Box<[u8]>]>, - vars: Box<[Box<[u8]>]> + vars: Box<[Box<[u8]>]>, + auxv: Box<[usize]>, ) -> ! { let entry; let singlestep; @@ -809,27 +810,40 @@ fn fexec_noreturn( context.tls = Some(tls); } + let mut push = |arg| { + sp -= mem::size_of::(); + unsafe { *(sp as *mut usize) = arg; } + }; + + // Push auxiliery vector + push(AT_NULL); + for &arg in auxv.iter().rev() { + push(arg); + } + + // drop(auxv); // no longer required + let mut arg_size = 0; - // Push arguments and variables + // Push environment variables and arguments for iter in &[&vars, &args] { // Push null-terminator - sp -= mem::size_of::(); - unsafe { *(sp as *mut usize) = 0; } + push(0); - // Push content + // Push pointer to content for arg in iter.iter().rev() { - sp -= mem::size_of::(); - unsafe { *(sp as *mut usize) = crate::USER_ARG_OFFSET + arg_size; } - + push(crate::USER_ARG_OFFSET + arg_size); arg_size += arg.len() + 1; } } - // Push arguments length - sp -= mem::size_of::(); - unsafe { *(sp as *mut usize) = args.len(); } + // For some reason, Linux pushes the argument count here (in + // addition to being null-terminated), but not the environment + // variable count. + // TODO: Push more counts? Less? Stop having null-termination? + push(args.len()); + // Write environment and argument pointers to USER_ARG_OFFSET if arg_size > 0 { let mut memory = context::memory::Memory::new( VirtualAddress::new(crate::USER_ARG_OFFSET), @@ -858,8 +872,9 @@ fn fexec_noreturn( context.image.push(memory.to_shared()); } - // Args no longer required, can deallocate + // Args and vars no longer required, can deallocate drop(args); + drop(vars); context.actions = Arc::new(Mutex::new(vec![( SigAction { @@ -908,7 +923,7 @@ fn fexec_noreturn( unsafe { usermode(entry, sp, 0, singlestep) } } -pub fn fexec_kernel(fd: FileHandle, args: Box<[Box<[u8]>]>, vars: Box<[Box<[u8]>]>, name_override_opt: Option>) -> Result { +pub fn fexec_kernel(fd: FileHandle, args: Box<[Box<[u8]>]>, vars: Box<[Box<[u8]>]>, name_override_opt: Option>, auxv: Option>) -> Result { let (uid, gid) = { let contexts = context::contexts(); let context_lock = contexts.current().ok_or(Error::new(ESRCH))?; @@ -980,72 +995,90 @@ pub fn fexec_kernel(fd: FileHandle, args: Box<[Box<[u8]>]>, vars: Box<[Box<[u8]> return Err(Error::new(E2BIG)); } - match elf::Elf::from(&data) { - Ok(elf) => { - // We check the validity of all loadable sections here - for segment in elf.segments() { - match segment.p_type { - program_header::PT_INTERP => { - //TODO: length restraint, parse interp earlier - let mut interp = vec![0; segment.p_memsz as usize]; - unsafe { - intrinsics::copy((elf.data.as_ptr() as usize + segment.p_offset as usize) as *const u8, - interp.as_mut_ptr(), - segment.p_filesz as usize); - } - - let mut i = 0; - while i < interp.len() { - if interp[i] == 0 { - break; - } - i += 1; - } - interp.truncate(i); - - println!(" interpreter: {:?}", ::core::str::from_utf8(&interp)); - - let interp_fd = super::fs::open(&interp, super::flag::O_RDONLY | super::flag::O_CLOEXEC)?; - - let mut args_vec = Vec::from(args); - args_vec.insert(0, interp.into_boxed_slice()); - //TODO: pass file handle in auxv - let name_override = name.into_boxed_slice(); - args_vec[1] = name_override.clone(); - - return fexec_kernel( - interp_fd, - args_vec.into_boxed_slice(), - vars, - Some(name_override), - ); - }, - program_header::PT_LOAD => { - let voff = segment.p_vaddr as usize % PAGE_SIZE; - let vaddr = segment.p_vaddr as usize - voff; - - // Due to the Userspace and kernel TLS bases being located right above 2GB, - // limit any loadable sections to lower than that. Eventually we will need - // to replace this with a more intelligent TLS address - if vaddr >= 0x8000_0000 { - println!("exec: invalid section address {:X}", segment.p_vaddr); - return Err(Error::new(ENOEXEC)); - } - }, - _ => (), - } - } - }, + let elf = match elf::Elf::from(&data) { + Ok(elf) => elf, Err(err) => { println!("fexec: failed to execute {}: {}", fd.into(), err); return Err(Error::new(ENOEXEC)); } + }; + + // `fexec_kernel` can recurse if an interpreter is found. We get the + // auxiliery vector from the first invocation, which is passed via an + // argument, or if this is the first one we create it. + let auxv = if let Some(auxv) = auxv { + auxv + } else { + let mut auxv = Vec::with_capacity(3); + + auxv.push(AT_ENTRY); + auxv.push(elf.entry()); + + auxv.into_boxed_slice() + }; + + // We check the validity of all loadable sections here + for segment in elf.segments() { + match segment.p_type { + program_header::PT_INTERP => { + //TODO: length restraint, parse interp earlier + let mut interp = vec![0; segment.p_memsz as usize]; + unsafe { + intrinsics::copy((elf.data.as_ptr() as usize + segment.p_offset as usize) as *const u8, + interp.as_mut_ptr(), + segment.p_filesz as usize); + } + + let mut i = 0; + while i < interp.len() { + if interp[i] == 0 { + break; + } + i += 1; + } + interp.truncate(i); + + println!(" interpreter: {:?}", ::core::str::from_utf8(&interp)); + + let interp_fd = super::fs::open(&interp, super::flag::O_RDONLY | super::flag::O_CLOEXEC)?; + + let mut args_vec = Vec::from(args); + args_vec.insert(0, interp.into_boxed_slice()); + //TODO: pass file handle in auxv + let name_override = name.into_boxed_slice(); + args_vec[1] = name_override.clone(); + + // Drop variables, since fexec_kernel probably won't return + drop(elf); + + return fexec_kernel( + interp_fd, + args_vec.into_boxed_slice(), + vars, + Some(name_override), + Some(auxv), + ); + }, + program_header::PT_LOAD => { + let voff = segment.p_vaddr as usize % PAGE_SIZE; + let vaddr = segment.p_vaddr as usize - voff; + + // Due to the Userspace and kernel TLS bases being located right above 2GB, + // limit any loadable sections to lower than that. Eventually we will need + // to replace this with a more intelligent TLS address + if vaddr >= 0x8000_0000 { + println!("exec: invalid section address {:X}", segment.p_vaddr); + return Err(Error::new(ENOEXEC)); + } + }, + _ => (), + } } // This is the point of no return, quite literaly. Any checks for validity need // to be done before, and appropriate errors returned. Otherwise, we have nothing // to return to. - fexec_noreturn(setuid, setgid, name.into_boxed_slice(), data.into_boxed_slice(), args, vars); + fexec_noreturn(setuid, setgid, name.into_boxed_slice(), data.into_boxed_slice(), args, vars, auxv); } pub fn fexec(fd: FileHandle, arg_ptrs: &[[usize; 2]], var_ptrs: &[[usize; 2]]) -> Result { @@ -1066,7 +1099,7 @@ pub fn fexec(fd: FileHandle, arg_ptrs: &[[usize; 2]], var_ptrs: &[[usize; 2]]) - // Neither arg_ptrs nor var_ptrs should be used after this point, the kernel // now has owned copies in args and vars - fexec_kernel(fd, args.into_boxed_slice(), vars.into_boxed_slice(), None) + fexec_kernel(fd, args.into_boxed_slice(), vars.into_boxed_slice(), None, None) } pub fn exit(status: usize) -> ! { diff --git a/syscall b/syscall index 27fcecb..10994ea 160000 --- a/syscall +++ b/syscall @@ -1 +1 @@ -Subproject commit 27fcecb30fb3154a9b45f66756d64f8f48281a7b +Subproject commit 10994eaa96e92890d945bec77023378fe374a114 From 4b8d2e45c6643ec2c9af68f6c2d56d28ca6d2b4e Mon Sep 17 00:00:00 2001 From: jD91mZM2 Date: Fri, 10 Jul 2020 12:48:40 +0200 Subject: [PATCH 03/11] Add AT_PHDR --- src/elf.rs | 5 +++++ src/syscall/process.rs | 12 +++++++----- syscall | 2 +- 3 files changed, 13 insertions(+), 6 deletions(-) diff --git a/src/elf.rs b/src/elf.rs index 123d44d..183ed84 100644 --- a/src/elf.rs +++ b/src/elf.rs @@ -73,6 +73,11 @@ impl<'a> Elf<'a> { pub fn entry(&self) -> usize { self.header.e_entry as usize } + + /// Get the program header offset + pub fn program_headers(&self) -> usize { + self.header.e_phoff as usize + } } pub struct ElfSections<'a> { diff --git a/src/syscall/process.rs b/src/syscall/process.rs index 9c794de..4c3277b 100644 --- a/src/syscall/process.rs +++ b/src/syscall/process.rs @@ -23,7 +23,7 @@ use crate::scheme::FileHandle; use crate::start::usermode; use crate::syscall::data::{SigAction, Stat}; use crate::syscall::error::*; -use crate::syscall::flag::{wifcontinued, wifstopped, AT_ENTRY, AT_NULL, CloneFlags, +use crate::syscall::flag::{wifcontinued, wifstopped, AT_ENTRY, AT_NULL, AT_PHDR, CloneFlags, CLONE_FILES, CLONE_FS, CLONE_SIGHAND, CLONE_STACK, CLONE_VFORK, CLONE_VM, MapFlags, PROT_EXEC, PROT_READ, PROT_WRITE, PTRACE_EVENT_CLONE, PTRACE_STOP_EXIT, SigActionFlags, SIG_BLOCK, SIG_DFL, SIG_SETMASK, SIG_UNBLOCK, @@ -821,7 +821,7 @@ fn fexec_noreturn( push(arg); } - // drop(auxv); // no longer required + drop(auxv); // no longer required let mut arg_size = 0; @@ -923,7 +923,7 @@ fn fexec_noreturn( unsafe { usermode(entry, sp, 0, singlestep) } } -pub fn fexec_kernel(fd: FileHandle, args: Box<[Box<[u8]>]>, vars: Box<[Box<[u8]>]>, name_override_opt: Option>, auxv: Option>) -> Result { +pub fn fexec_kernel(fd: FileHandle, args: Box<[Box<[u8]>]>, vars: Box<[Box<[u8]>]>, name_override_opt: Option>, auxv: Option>) -> Result { let (uid, gid) = { let contexts = context::contexts(); let context_lock = contexts.current().ok_or(Error::new(ESRCH))?; @@ -1013,8 +1013,10 @@ pub fn fexec_kernel(fd: FileHandle, args: Box<[Box<[u8]>]>, vars: Box<[Box<[u8]> auxv.push(AT_ENTRY); auxv.push(elf.entry()); + auxv.push(AT_PHDR); + auxv.push(elf.program_headers()); - auxv.into_boxed_slice() + auxv }; // We check the validity of all loadable sections here @@ -1078,7 +1080,7 @@ pub fn fexec_kernel(fd: FileHandle, args: Box<[Box<[u8]>]>, vars: Box<[Box<[u8]> // This is the point of no return, quite literaly. Any checks for validity need // to be done before, and appropriate errors returned. Otherwise, we have nothing // to return to. - fexec_noreturn(setuid, setgid, name.into_boxed_slice(), data.into_boxed_slice(), args, vars, auxv); + fexec_noreturn(setuid, setgid, name.into_boxed_slice(), data.into_boxed_slice(), args, vars, auxv.into_boxed_slice()); } pub fn fexec(fd: FileHandle, arg_ptrs: &[[usize; 2]], var_ptrs: &[[usize; 2]]) -> Result { diff --git a/syscall b/syscall index 10994ea..6346fd6 160000 --- a/syscall +++ b/syscall @@ -1 +1 @@ -Subproject commit 10994eaa96e92890d945bec77023378fe374a114 +Subproject commit 6346fd671ef6e1650062a8cd3097c0b0d17c92cb From ec2c42dc6656501b0e069c41b3dd932453c606d1 Mon Sep 17 00:00:00 2001 From: jD91mZM2 Date: Mon, 13 Jul 2020 12:48:29 +0200 Subject: [PATCH 04/11] WIP: Work around fmap quirks --- src/scheme/memory.rs | 6 ++++-- src/syscall/mod.rs | 14 ++------------ 2 files changed, 6 insertions(+), 14 deletions(-) diff --git a/src/scheme/memory.rs b/src/scheme/memory.rs index c397142..d652019 100644 --- a/src/scheme/memory.rs +++ b/src/scheme/memory.rs @@ -49,8 +49,9 @@ impl Scheme for MemoryScheme { let full_size = ((map.size + PAGE_SIZE - 1) / PAGE_SIZE) * PAGE_SIZE; let mut to_address = if map.address == 0 { crate::USER_GRANT_OFFSET } else { - if map.address < crate::USER_GRANT_OFFSET || map.address + map.size > crate::USER_GRANT_OFFSET + crate::PML4_SIZE || map.address % PAGE_SIZE != 0 { - return Err(Error::new(EINVAL)); + if // map.address < crate::USER_GRANT_OFFSET || map.address + map.size > crate::USER_GRANT_OFFSET + crate::PML4_SIZE || + map.address % PAGE_SIZE != 0 { + return Err(Error::new(EINVAL)); } map.address }; @@ -123,6 +124,7 @@ impl Scheme for MemoryScheme { continue; } + i += 1; } grants.insert(i, Grant::map( diff --git a/src/syscall/mod.rs b/src/syscall/mod.rs index bb01f60..886865f 100644 --- a/src/syscall/mod.rs +++ b/src/syscall/mod.rs @@ -163,21 +163,14 @@ pub fn syscall(a: usize, b: usize, c: usize, d: usize, e: usize, f: usize, bp: u } } - /* let debug = { let contexts = crate::context::contexts(); if let Some(context_lock) = contexts.current() { let context = context_lock.read(); let name_raw = context.name.lock(); let name = unsafe { core::str::from_utf8_unchecked(&name_raw) }; - if name == "file:/bin/cargo" || name == "file:/bin/rustc" { - if a == SYS_CLOCK_GETTIME { - false - } else if (a == SYS_WRITE || a == SYS_FSYNC) && (b == 1 || b == 2) { - false - } else { - true - } + if name == "file:/lib/ld64.so.1" || name == "file:/home/user/test" { + true } else { false } @@ -195,7 +188,6 @@ pub fn syscall(a: usize, b: usize, c: usize, d: usize, e: usize, f: usize, bp: u println!("{}", debug::format_call(a, b, c, d, e, f)); } - */ // The next lines set the current syscall in the context struct, then once the inner() function // completes, we set the current syscall to none. @@ -220,7 +212,6 @@ pub fn syscall(a: usize, b: usize, c: usize, d: usize, e: usize, f: usize, bp: u } } - /* if debug { let contexts = crate::context::contexts(); if let Some(context_lock) = contexts.current() { @@ -239,7 +230,6 @@ pub fn syscall(a: usize, b: usize, c: usize, d: usize, e: usize, f: usize, bp: u } } } - */ // errormux turns Result into -errno Error::mux(result) From 2d63009ba416e11ebbabe1ec3a1e8a70d8e9f9e7 Mon Sep 17 00:00:00 2001 From: jD91mZM2 Date: Sat, 18 Jul 2020 13:40:12 +0200 Subject: [PATCH 05/11] Add debug entry for fmap2 --- src/scheme/memory.rs | 5 +++-- src/syscall/debug.rs | 10 +++++++++- 2 files changed, 12 insertions(+), 3 deletions(-) diff --git a/src/scheme/memory.rs b/src/scheme/memory.rs index d652019..88f9db3 100644 --- a/src/scheme/memory.rs +++ b/src/scheme/memory.rs @@ -50,8 +50,9 @@ impl Scheme for MemoryScheme { let mut to_address = if map.address == 0 { crate::USER_GRANT_OFFSET } else { if // map.address < crate::USER_GRANT_OFFSET || map.address + map.size > crate::USER_GRANT_OFFSET + crate::PML4_SIZE || - map.address % PAGE_SIZE != 0 { - return Err(Error::new(EINVAL)); + map.address % PAGE_SIZE != 0 + { + return Err(Error::new(EINVAL)); } map.address }; diff --git a/src/syscall/debug.rs b/src/syscall/debug.rs index 8b42526..e883ca3 100644 --- a/src/syscall/debug.rs +++ b/src/syscall/debug.rs @@ -2,7 +2,7 @@ use core::{ascii, mem}; use alloc::string::String; use alloc::vec::Vec; -use super::data::{Map, Stat, TimeSpec}; +use super::data::{Map, Map2, Stat, TimeSpec}; use super::flag::*; use super::number::*; use super::validate::*; @@ -114,6 +114,14 @@ pub fn format_call(a: usize, b: usize, c: usize, d: usize, e: usize, f: usize) - d/mem::size_of::() ), ), + SYS_FMAP2 => format!( + "fmap2({}, {:?})", + b, + validate_slice( + c as *const Map2, + d/mem::size_of::() + ), + ), SYS_FUNMAP => format!( "funmap({:#X})", b From ff5354b5b596dd936c74bc651ab09afc3ea5a1de Mon Sep 17 00:00:00 2001 From: jD91mZM2 Date: Sat, 18 Jul 2020 15:03:23 +0200 Subject: [PATCH 06/11] Fix mmap when using out-of-place address --- src/scheme/memory.rs | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/src/scheme/memory.rs b/src/scheme/memory.rs index 88f9db3..4bb7506 100644 --- a/src/scheme/memory.rs +++ b/src/scheme/memory.rs @@ -73,15 +73,16 @@ impl Scheme for MemoryScheme { while i < grants.len() { let grant = &mut grants[i]; - let mut grant_start = grant.start_address().get(); - let mut grant_len = ((grant.size() + PAGE_SIZE - 1) / PAGE_SIZE) * PAGE_SIZE; - let mut grant_end = grant_start + grant_len; + let grant_start = grant.start_address().get(); + let grant_len = ((grant.size() + PAGE_SIZE - 1) / PAGE_SIZE) * PAGE_SIZE; + let grant_end = grant_start + grant_len; - if grant_end <= to_address { + if to_address < grant_start || grant_end <= to_address { // grant has nothing to do with the memory to map, and thus we can safely just // go on to the next one. - if !fixed { + if grant_start >= crate::USER_GRANT_OFFSET && !fixed { + // don't ignore addresses outside of the automatic grant offset to_address = grant_end; } i += 1; @@ -96,6 +97,7 @@ impl Scheme for MemoryScheme { // insert a new grant at the end (if not MapFlags::MAP_FIXED). if fixed_noreplace { + println!("grant: conflicts with: {:#x} - {:#x}", grant_start, grant_end); return Err(Error::new(EEXIST)); } else if fixed { /* From 07baf70c7a12ea3ed50f8d703178043100ddd7b2 Mon Sep 17 00:00:00 2001 From: jD91mZM2 Date: Mon, 20 Jul 2020 11:09:56 +0200 Subject: [PATCH 07/11] Don't push interpreter as argv[0] --- src/syscall/mod.rs | 2 +- src/syscall/process.rs | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/syscall/mod.rs b/src/syscall/mod.rs index bee91ab..d8f131d 100644 --- a/src/syscall/mod.rs +++ b/src/syscall/mod.rs @@ -169,7 +169,7 @@ pub fn syscall(a: usize, b: usize, c: usize, d: usize, e: usize, f: usize, bp: u let context = context_lock.read(); let name_raw = context.name.lock(); let name = unsafe { core::str::from_utf8_unchecked(&name_raw) }; - if name == "file:/lib/ld64.so.1" || name == "file:/home/user/test" { + if name == "file:/lib/ld64.so.1" || name == "file:/bin/ld" { true } else { false diff --git a/src/syscall/process.rs b/src/syscall/process.rs index 1dd447c..2d39956 100644 --- a/src/syscall/process.rs +++ b/src/syscall/process.rs @@ -1043,13 +1043,13 @@ pub fn fexec_kernel(fd: FileHandle, args: Box<[Box<[u8]>]>, vars: Box<[Box<[u8]> let interp_fd = super::fs::open(&interp, super::flag::O_RDONLY | super::flag::O_CLOEXEC)?; let mut args_vec = Vec::from(args); - args_vec.insert(0, interp.into_boxed_slice()); //TODO: pass file handle in auxv let name_override = name.into_boxed_slice(); - args_vec[1] = name_override.clone(); + args_vec[0] = name_override.clone(); // Drop variables, since fexec_kernel probably won't return drop(elf); + drop(interp); return fexec_kernel( interp_fd, From cf709783d66df39fe6aba8b7be32e54e2436a0ba Mon Sep 17 00:00:00 2001 From: jD91mZM2 Date: Mon, 20 Jul 2020 11:17:36 +0200 Subject: [PATCH 08/11] Reverse mod/syscall.rs --- src/syscall/mod.rs | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/src/syscall/mod.rs b/src/syscall/mod.rs index d8f131d..b21b9d2 100644 --- a/src/syscall/mod.rs +++ b/src/syscall/mod.rs @@ -163,14 +163,21 @@ pub fn syscall(a: usize, b: usize, c: usize, d: usize, e: usize, f: usize, bp: u } } + /* let debug = { let contexts = crate::context::contexts(); if let Some(context_lock) = contexts.current() { let context = context_lock.read(); let name_raw = context.name.lock(); let name = unsafe { core::str::from_utf8_unchecked(&name_raw) }; - if name == "file:/lib/ld64.so.1" || name == "file:/bin/ld" { - true + if name == "file:/bin/cargo" || name == "file:/bin/rustc" { + if a == SYS_CLOCK_GETTIME { + false + } else if (a == SYS_WRITE || a == SYS_FSYNC) && (b == 1 || b == 2) { + false + } else { + true + } } else { false } @@ -188,6 +195,7 @@ pub fn syscall(a: usize, b: usize, c: usize, d: usize, e: usize, f: usize, bp: u println!("{}", debug::format_call(a, b, c, d, e, f)); } + */ // The next lines set the current syscall in the context struct, then once the inner() function // completes, we set the current syscall to none. @@ -212,6 +220,7 @@ pub fn syscall(a: usize, b: usize, c: usize, d: usize, e: usize, f: usize, bp: u } } + /* if debug { let contexts = crate::context::contexts(); if let Some(context_lock) = contexts.current() { @@ -230,6 +239,7 @@ pub fn syscall(a: usize, b: usize, c: usize, d: usize, e: usize, f: usize, bp: u } } } + */ // errormux turns Result into -errno Error::mux(result) From 5dc65a920fce471f0ba160e43158888a4d637de1 Mon Sep 17 00:00:00 2001 From: jD91mZM2 Date: Tue, 21 Jul 2020 15:52:12 +0200 Subject: [PATCH 09/11] Add restrictions on fmap --- src/scheme/memory.rs | 37 ++++++++++++++++++++++++------------- 1 file changed, 24 insertions(+), 13 deletions(-) diff --git a/src/scheme/memory.rs b/src/scheme/memory.rs index 4bb7506..5efb025 100644 --- a/src/scheme/memory.rs +++ b/src/scheme/memory.rs @@ -1,7 +1,8 @@ +use core::cmp; use crate::context; use crate::context::memory::Grant; use crate::memory::{free_frames, used_frames, PAGE_SIZE}; -use crate::paging::VirtualAddress; +use crate::paging::{ActivePageTable, Page, VirtualAddress}; use crate::paging::entry::EntryFlags; use crate::syscall::data::{Map, Map2, StatVfs}; use crate::syscall::error::*; @@ -49,8 +50,9 @@ impl Scheme for MemoryScheme { let full_size = ((map.size + PAGE_SIZE - 1) / PAGE_SIZE) * PAGE_SIZE; let mut to_address = if map.address == 0 { crate::USER_GRANT_OFFSET } else { - if // map.address < crate::USER_GRANT_OFFSET || map.address + map.size > crate::USER_GRANT_OFFSET + crate::PML4_SIZE || - map.address % PAGE_SIZE != 0 + if + map.address + full_size >= crate::PML4_SIZE * 256 // There are 256 PML4 entries reserved for userspace + && map.address % PAGE_SIZE != 0 { return Err(Error::new(EINVAL)); } @@ -81,9 +83,12 @@ impl Scheme for MemoryScheme { // grant has nothing to do with the memory to map, and thus we can safely just // go on to the next one. - if grant_start >= crate::USER_GRANT_OFFSET && !fixed { - // don't ignore addresses outside of the automatic grant offset - to_address = grant_end; + if !fixed { + // Use the default grant offset, or if we've already passed it, anything after that. + to_address = cmp::max( + cmp::max(crate::USER_GRANT_OFFSET, grant_end), + to_address, + ); } i += 1; @@ -126,15 +131,21 @@ impl Scheme for MemoryScheme { } continue; } - - i += 1; } - grants.insert(i, Grant::map( - VirtualAddress::new(to_address), - full_size, - entry_flags, - )); + let start_address = VirtualAddress::new(to_address); + let end_address = VirtualAddress::new(to_address + full_size); + + // Make sure it's absolutely not mapped already + let active_table = unsafe { ActivePageTable::new() }; + + for page in Page::range_inclusive(Page::containing_address(start_address), Page::containing_address(end_address)) { + if active_table.translate_page(page).is_some() { + return Err(Error::new(EEXIST)) + } + } + + grants.insert(i, Grant::map(start_address, full_size, entry_flags)); Ok(to_address) } From 2782a5a7a9533c92a44be45a9d2aeb1c9f9ab6d0 Mon Sep 17 00:00:00 2001 From: jD91mZM2 Date: Tue, 21 Jul 2020 14:10:43 +0000 Subject: [PATCH 10/11] Apply suggestion to src/syscall/process.rs --- src/syscall/process.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/syscall/process.rs b/src/syscall/process.rs index 2d39956..ae0f72a 100644 --- a/src/syscall/process.rs +++ b/src/syscall/process.rs @@ -813,7 +813,7 @@ fn fexec_noreturn( unsafe { *(sp as *mut usize) = arg; } }; - // Push auxiliery vector + // Push auxiliary vector push(AT_NULL); for &arg in auxv.iter().rev() { push(arg); From 9c41424d3ab969fd8bc72378cb1284d685514f29 Mon Sep 17 00:00:00 2001 From: jD91mZM2 Date: Tue, 21 Jul 2020 14:10:58 +0000 Subject: [PATCH 11/11] Apply suggestion to src/syscall/process.rs --- src/syscall/process.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/syscall/process.rs b/src/syscall/process.rs index ae0f72a..cc3bce3 100644 --- a/src/syscall/process.rs +++ b/src/syscall/process.rs @@ -1002,7 +1002,7 @@ pub fn fexec_kernel(fd: FileHandle, args: Box<[Box<[u8]>]>, vars: Box<[Box<[u8]> }; // `fexec_kernel` can recurse if an interpreter is found. We get the - // auxiliery vector from the first invocation, which is passed via an + // auxiliary vector from the first invocation, which is passed via an // argument, or if this is the first one we create it. let auxv = if let Some(auxv) = auxv { auxv