Allow cloning of kernel threads. Userspace breaks potentially due to stack aliasing

This commit is contained in:
Jeremy Soller 2016-09-13 20:06:39 -06:00
parent 4341a2d725
commit ce50faf7ca
6 changed files with 109 additions and 38 deletions

View file

@ -6,7 +6,7 @@ use core::sync::atomic::{AtomicBool, ATOMIC_BOOL_INIT, Ordering};
/// This must be done, as no locks can be held on the stack during switch
pub static CONTEXT_SWITCH_LOCK: AtomicBool = ATOMIC_BOOL_INIT;
#[derive(Debug)]
#[derive(Clone, Debug)]
pub struct Context {
/// Page table pointer
cr3: usize,
@ -96,5 +96,7 @@ impl Context {
// Unset global lock, set inside of kernel
CONTEXT_SWITCH_LOCK.store(false, Ordering::SeqCst);
asm!("xchg bx, bx" : : : : "intel", "volatile");
}
}

View file

@ -3,7 +3,7 @@ pub unsafe extern fn syscall() {
#[inline(never)]
unsafe fn inner() {
extern {
fn syscall(a: usize, b: usize, c: usize, d: usize, e: usize, f: usize) -> usize;
fn syscall(a: usize, b: usize, c: usize, d: usize, e: usize, f: usize, stack: usize) -> usize;
}
let mut a;
@ -13,10 +13,11 @@ pub unsafe extern fn syscall() {
let d;
let e;
let f;
asm!("" : "={rax}"(a), "={rbx}"(b), "={rcx}"(c), "={rdx}"(d), "={rsi}"(e), "={rdi}"(f)
let stack;
asm!("" : "={rax}"(a), "={rbx}"(b), "={rcx}"(c), "={rdx}"(d), "={rsi}"(e), "={rdi}"(f), "={rbp}"(stack)
: : : "intel", "volatile");
a = syscall(a, b, c, d, e, f);
a = syscall(a, b, c, d, e, f, stack);
}
asm!("" : : "{rax}"(a) : : "intel", "volatile");
@ -36,3 +37,10 @@ pub unsafe extern fn syscall() {
iretq"
: : : : "intel", "volatile");
}
#[naked]
pub unsafe extern fn clone_ret() -> usize {
asm!("pop rbp"
: : : : "intel", "volatile");
0
}

View file

@ -187,8 +187,7 @@ pub unsafe extern fn kstart_ap(cpu_id: usize, page_table: usize, stack_start: us
pub unsafe fn usermode(ip: usize, sp: usize) -> ! {
// Go to usermode
asm!("xchg bx, bx
mov ds, ax
asm!("mov ds, ax
mov es, ax
mov fs, ax
mov gs, ax
@ -201,7 +200,7 @@ pub unsafe fn usermode(ip: usize, sp: usize) -> ! {
: // No output because it never returns
: "{rax}"(gdt::GDT_USER_DATA << 3 | 3), // Stack segment
"{rbx}"(sp), // Stack pointer
"{rcx}"(3 << 12 | 1 << 9), // Flags - Set IOPL and interrupt enable flag
"{rcx}"(3 << 12/* | 1 << 9*/), // Flags - Set IOPL and interrupt enable flag
"{rdx}"(gdt::GDT_USER_CODE << 3 | 3), // Code segment
"{rsi}"(ip) // IP
: // No clobers because it never returns

View file

@ -141,13 +141,27 @@ pub unsafe fn switch() {
let mut to_ptr = 0 as *mut Context;
for (_pid, context_lock) in contexts().map.iter() {
for (pid, context_lock) in contexts().map.iter() {
if *pid > (*from_ptr).id {
let mut context = context_lock.write();
if ! context.running && ! context.blocked && ! context.exited {
to_ptr = context.deref_mut() as *mut Context;
break;
}
}
}
if to_ptr as usize == 0 {
for (pid, context_lock) in contexts().map.iter() {
if *pid < (*from_ptr).id {
let mut context = context_lock.write();
if ! context.running && ! context.blocked && ! context.exited {
to_ptr = context.deref_mut() as *mut Context;
break;
}
}
}
}
if to_ptr as usize == 0 {
// TODO: Sleep, wait for interrupt
@ -159,6 +173,9 @@ pub unsafe fn switch() {
(&mut *from_ptr).running = false;
(&mut *to_ptr).running = true;
if let Some(ref stack) = (*to_ptr).kstack {
arch::gdt::TSS.rsp[0] = (stack.as_ptr() as usize + stack.len() - 256) as u64;
}
CONTEXT_ID.store((&mut *to_ptr).id, Ordering::SeqCst);
(&mut *from_ptr).arch.switch_to(&mut (&mut *to_ptr).arch);

View file

@ -105,7 +105,10 @@ pub fn convert_slice_mut<T>(ptr: *mut T, len: usize) -> Result<&'static mut [T]>
Ok(unsafe { slice::from_raw_parts_mut(ptr, len) })
}
pub fn handle(a: usize, b: usize, c: usize, d: usize, e: usize, _f: usize) -> Result<usize> {
#[no_mangle]
pub extern fn syscall(a: usize, b: usize, c: usize, d: usize, e: usize, f: usize, stack: usize) -> usize {
#[inline(always)]
fn inner(a: usize, b: usize, c: usize, d: usize, e: usize, _f: usize, stack: usize) -> Result<usize> {
match Call::from(a) {
Ok(call) => match call {
Call::Exit => exit(b),
@ -118,7 +121,7 @@ pub fn handle(a: usize, b: usize, c: usize, d: usize, e: usize, _f: usize) -> Re
Call::Dup => dup(b),
Call::Brk => brk(b),
Call::Iopl => iopl(b),
Call::Clone => clone(b),
Call::Clone => clone(b, stack),
Call::SchedYield => sched_yield()
},
Err(err) => {
@ -128,9 +131,7 @@ pub fn handle(a: usize, b: usize, c: usize, d: usize, e: usize, _f: usize) -> Re
}
}
#[no_mangle]
pub extern fn syscall(a: usize, b: usize, c: usize, d: usize, e: usize, f: usize) -> usize {
match handle(a, b, c, d, e, f) {
match inner(a, b, c, d, e, f, stack) {
Ok(value) => value,
Err(value) => (-(value as isize)) as usize
}

View file

@ -1,5 +1,6 @@
///! Process syscalls
use core::mem;
use core::str;
use arch;
@ -42,9 +43,52 @@ pub fn brk(address: usize) -> Result<usize> {
}
}
pub fn clone(flags: usize) -> Result<usize> {
println!("Clone {:X}", flags);
Ok(0)
pub fn clone(flags: usize, stack_base: usize) -> Result<usize> {
println!("Clone {:X}: {:X}", flags, stack_base);
let arch;
let mut stack_option = None;
let mut offset = 0;
// Copy from old process
{
let contexts = context::contexts();
let context_lock = contexts.current().ok_or(Error::NoProcess)?;
let context = context_lock.read();
arch = context.arch.clone();
if let Some(ref stack) = context.kstack {
offset = stack_base - stack.as_ptr() as usize - mem::size_of::<usize>(); // Add clone ret
let mut new_stack = stack.clone();
unsafe {
let func_ptr = new_stack.as_mut_ptr().offset(offset as isize);
*(func_ptr as *mut usize) = arch::interrupt::syscall::clone_ret as usize;
}
stack_option = Some(new_stack);
}
}
// Set up new process
let pid;
{
let mut contexts = context::contexts_mut();
let context_lock = contexts.new_context()?;
let mut context = context_lock.write();
context.arch = arch;
if let Some(stack) = stack_option.take() {
context.arch.set_stack(stack.as_ptr() as usize + offset);
context.kstack = Some(stack);
}
context.blocked = false;
pid = context.id;
}
println!("Clone {}", pid);
unsafe { asm!("xchg bx, bx" : : : : "intel", "volatile"); }
unsafe { context::switch(); }
Ok(pid)
}
pub fn exit(status: usize) -> ! {